change motor driver + joystick

This commit is contained in:
2023-11-08 16:32:37 +01:00
parent 41828b9a20
commit eebb355f59
18 changed files with 1060 additions and 243 deletions

2
FW/lib/Cdrv8833/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

1
FW/lib/Cdrv8833/.piopm Normal file
View File

@@ -0,0 +1 @@
{"type": "library", "name": "Cdrv8833", "version": "1.0.1", "spec": {"owner": "shurillu", "id": 14351, "name": "Cdrv8833", "requirements": null, "uri": null}}

21
FW/lib/Cdrv8833/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Stefano Ledda
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.

109
FW/lib/Cdrv8833/README.md Normal file
View File

@@ -0,0 +1,109 @@
# Cdrv8833
<img src="https://github.com/shurillu/Cdrv8833/blob/f3dccc3f0448b2a2071de1e72d5ad1d12b7a835d/images/DRV8833.jpg" alt="DRV8833 module" width="180"/>
### Introduction
Cdrv883 is a wrapper class for using modules based on DRV8833 H-bridge from Texas Instruments.
### News
+ First public version released.
### Simple usage
See the drv8833Tester example provided in the [examples folder](https://github.com/shurillu/Cdrv8833/tree/main/examples/drv8833Tester).
### Changelog
+ 1.0.0 Initial version.
<hr>
### Reference
#### `Cdrv8833()`
Default constructor. The object is NOT initialized: the `init` member function must be called. Decay mode is set to SLOW.
<br><br>
#### `Cdrv8833(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection = false)`
Specialized constructor. Decay mode is set to SLOW.
input:
+ `in1Pin`: DRV8833 AIN1/BIN1
+ `in2Pin`: DRV8833 AIN2/BIN2
+ `channel`: ESP32 PWM channel (0..15) - ESP32 ledc functions
+ `swapDirection`: swap motor rotation direction
There are 16 independent channels for PWM modulation inside the ESP32 SOC. Every motor need to have its own channel in order to work independently each other.
Swapping the motor rotation direction is useful (for example):
+ wrong cabling
+ using two motors to drive a two wheels vehicle (left wheel, right wheel).
<br><br>
#### `bool init(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection = false)`
Initialize the object. Decay mode is set to SLOW.
input:
+ `in1Pin`: DRV8833 AIN1/BIN1
+ `in2Pin`: DRV8833 AIN2/BIN2
+ `channel`: ESP32 PWM channel (0..15) - ESP32 ledc functions
+ `swapDirection`: swap motor rotation direction
Return `true` if no error occurs.
There are 16 independent channels for PWM modulation inside the ESP32 SOC. Every motor need to have its own channel in order to work independently each other.
Swapping the motor rotation direction is useful (for example):
+ wrong cabling
+ using two motors to drive a two wheels vehicle (left wheel, right wheel).
<br><br>
#### `bool move(int8_t power)`
Set motor rotation direction/speed.
input:
+ `power`: rotation power. -100..100
Return `true` if no error occurs.
The `power` parameter set the rotation speed and the direction. Negative values means reverse rotation direction. Value span to -100 (full speed reverse direction) to 100 (full speed forward direction).
Zero stop the motor rotation.
<br><br>
#### `bool stop()`
Stop the motor, using fast decay mode.
Return `true` if no error occurs.
<br><br>
#### `bool brake()`
Stop the motor, using slow decay mode.
Return `true` if no error occurs.
<br><br>
#### `void setDecayMode(drv8833DecayMode decayMode)`
Set the decay mode. Default decay mode is set to SLOW.
input:
+ `decayMode`: new decay mode. Values are
+ `drv8833DecaySlow` good torque, but high power consumption
+ `drv8833DecayFast` poor torque, but low power consumption
<br><br>
#### `void setFrequency(uint32_t frequency)`
Set the frequency used for the PWM modulation(for ESP32 ledc functions). Default value is 5000Hz. Allowed values are 1Hz..50000Hz.
input:
+ `frequency`: new frequency in Hertz. 1..50000Hz
<br><br>
#### `void swapDirection(bool swapDirection)`
Swap the motor rotation direction.
Useful for wrong cabling / driving two opposite motors (left wheel and right wheel of a vehicle)
input:
+ `swapDirection`: swap/unswap the motor rotation direction
+ `true`: swap rotation direction
+ `false`: default rotation direction

View File

@@ -0,0 +1,83 @@
/*
Name: drv8833Tester.ino
Created: 16/08/2022 10:06:02
Author: Stefano Ledda
Email: shurillu@tiscalinet.it
GitHub: https://github.com/shurillu/Cdrv8833
Note: Simple sketch to test the DRV8833 H-Bridge
- connect the GPIO 12 to the xIN1 of the DRV8833 module
- connect the GPIO 13 to the xIN2 of the DRV8833 module
- connect the positive pole of the motor to the xOUT1 of the DRV8833 module
- connect the negative pole of the motor to the xOUT2 of the DRV8833 module
- power the DRV8833 module (if the motor is small, 5V and <500mA, you can power
the module pulling the 5V and GND from the ESP32 board)
- load the sketch
- use the serial console to send commands
*/
#include "Cdrv8833.h"
#define IN1_PIN 12 // in1 pin from one of the two DRV8833 H-bridge
#define IN2_PIN 13 // in2 pin from one of the two DRV8833 H-bridge
#define CHANNEL 0 // there are 16 unique PWM channels (0..15)
#define SWAP false // swap motor rotation direction
Cdrv8833 myMotor; // default constructor
// you can initialize the object directly with the specialized constructor:
// Cdrv8833 myMotor2(IN1_PIN, IN2_PIN, CHANNEL, SWAP);
void setup()
{
Serial.begin(115200);
Serial.println("\n");
Serial.println("DRV8833 tester");
Serial.println("--------------");
Serial.printf("IN1 pin: %u\nIN2 pin: %u\n\n", IN1_PIN, IN2_PIN);
Serial.println("SWAP - swap motor rotation direction.");
Serial.println("NOSWAP - restore motor rotation direction.");
Serial.println("SLOW - decay mode SLOW - good torque, high power consumption.");
Serial.println("FAST - decay mode FAST - poor torque, low power consumption.");
Serial.println("MOVEXXX - start rotation (XXX = -100..100).");
Serial.println("STOP - stop the motor.");
// initialize the object. Not needed if the initialization is done with the specialized constructor
myMotor.init(IN1_PIN, IN2_PIN, CHANNEL, SWAP);
}
void loop()
{
String command;
if (Serial.available()) { // check Serial for new command
command = Serial.readString(); // read the new command from Serial
command.toLowerCase(); // convert it to lowercase
if (command.equals("swap")) {
myMotor.swapDirection(true); // swap rotation direction
Serial.println("--> swapped rotation direction.");
}
else if (command.equals("noswap")) {
myMotor.swapDirection(false); // default rotation direction
Serial.println("--> default rotation direction.");
}
else if (command.equals("slow")) {
myMotor.setDecayMode(drv8833DecaySlow); // decay mode SLOW
Serial.println("--> Decay mode SLOW - good torque.");
}
else if (command.equals("fast")) {
myMotor.setDecayMode(drv8833DecayFast); // decay mode FAST
Serial.println("--> Decay mode FAST - poor torque.");
}
else if (command.equals("stop")) {
myMotor.stop(); // stop moto rotation
Serial.println("--> Motor stopped.");
}
else if (command.startsWith("move")) {
command.replace("move", ""); // remove the word "move"
command.replace(" ", ""); // remove spaces (if present)
myMotor.move(command.toInt()); // start rotation at desired speed
Serial.printf("--> Motor rotation speed: %ld.\n", command.toInt());
}
}
}

View File

@@ -0,0 +1,14 @@
Cdrv8833 KEYWORD1
init KEYWORD2
move KEYWORD2
stop KEYWORD2
brake KEYWORD2
setDecayMode KEYWORD2
setFrequency KEYWORD2
swapDirection KEYWORD2
drv8833DecayMode KEYWORD3
drv8833DecaySlow LITERAL1
drv8833DecayFast LITERAL1

View File

@@ -0,0 +1,19 @@
{
"name": "Cdrv8833",
"keywords": "DRV8833, motor driver, ESP32, h-bridge",
"description": "ESP32 class for the TI DRV8833 motor driver. Designed for unipolar (DC) motors only (not stepper).",
"homepage": "https://github.com/shurillu/Cdrv8833",
"repository": {
"type": "git",
"url": "https://github.com/shurillu/Cdrv8833.git"
},
"version": "1.0.1",
"authors": {
"name": "Stefano Ledda",
"email": "shurillu@tiscalinet.it"
},
"frameworks": "arduino",
"platforms": "esp32",
"dependencies": {
}
}

View File

@@ -0,0 +1,9 @@
name=Cdrv8833
version=1.0.1
author=Stefano Ledda <shurillu@tiscalinet.it>
maintainer=Stefano Ledda <shurillu@tiscalinet.it>
sentence=ESP32 class for the TI DRV8833 motor driver. Designed for unipolar (DC) motors only (not stepper).
paragraph=An easy to use class for driving DC motors with the Texas Instruments DRV8833 driver. Designed only for ESP32 platform.
category=Communication
url=https://github.com/shurillu/Cdrv8833
architectures=esp32

View File

@@ -0,0 +1,138 @@
#include "Cdrv8833.h"
#include "esp32-hal-gpio.h"
Cdrv8833::Cdrv8833() {
// not initialized
m_in1Pin = -1;
m_in2Pin = -1;
m_power = 0;
m_swapDirection = false;
m_decayMode = drv8833DecaySlow;
}
Cdrv8833::Cdrv8833(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection) {
init(in1Pin, in2Pin, channel, swapDirection);
}
Cdrv8833::~Cdrv8833() {
stop();
}
bool Cdrv8833::init(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection) {
if (channel > 15)
return false;
if ((m_in1Pin != -1) && (m_in2Pin != -1))
stop();
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
m_in1Pin = in1Pin;
m_in2Pin = in2Pin;
m_power = 0;
m_swapDirection = swapDirection;
m_channel = channel;
m_decayMode = drv8833DecaySlow;
ledcSetup(channel, PWM_FREQUENCY, PWM_BIT_RESOLUTION);
return true;
}
bool Cdrv8833::move(int8_t power) {
if (-1 == m_in1Pin)
return false;
if (-1 == m_in2Pin)
return false;
if (0 == power) {
stop();
return true;
}
if (power > 100)
power = 100;
if (power < -100)
power = -100;
m_power = power;
if (m_swapDirection)
power = -power;
float value = (float)((1 << PWM_BIT_RESOLUTION) - 1) * ((float)abs(power))/100.0;
uint32_t dutyCycle;
if ((value - trunc(value)) < 0.5)
dutyCycle = value;
else
dutyCycle = value + 1;
if (drv8833DecaySlow == m_decayMode)
dutyCycle = ((1 << PWM_BIT_RESOLUTION) - 1) - dutyCycle;
if (power > 0) { // forward
if (drv8833DecayFast == m_decayMode) {
// forward fast decay
ledcDetachPin(m_in2Pin);
digitalWrite(m_in2Pin, LOW);
ledcAttachPin(m_in1Pin, m_channel);
}
else {
// forward slow decay
ledcDetachPin(m_in1Pin);
digitalWrite(m_in1Pin, HIGH);
ledcAttachPin(m_in2Pin, m_channel);
}
}
else { // reverse
if (drv8833DecayFast == m_decayMode) {
// reverse fast decay
ledcDetachPin(m_in1Pin);
digitalWrite(m_in1Pin, LOW);
ledcAttachPin(m_in2Pin, m_channel);
}
else {
// reverse slow decay
ledcDetachPin(m_in2Pin);
digitalWrite(m_in2Pin, HIGH);
ledcAttachPin(m_in1Pin, m_channel);
}
}
ledcWrite(m_channel, dutyCycle);
return true;
}
bool Cdrv8833::stop() {
if (-1 == m_in1Pin)
return false;
if (-1 == m_in2Pin)
return false;
ledcDetachPin(m_in1Pin);
ledcDetachPin(m_in2Pin);
digitalWrite(m_in1Pin, LOW);
digitalWrite(m_in2Pin, LOW);
m_power = 0;
return true;
}
bool Cdrv8833::brake() {
if (-1 == m_in1Pin)
return false;
if (-1 == m_in2Pin)
return false;
ledcDetachPin(m_in1Pin);
ledcDetachPin(m_in2Pin);
digitalWrite(m_in1Pin, HIGH);
digitalWrite(m_in2Pin, HIGH);
m_power = 0;
return true;
}
void Cdrv8833::setDecayMode(drv8833DecayMode decayMode) {
stop();
m_decayMode = decayMode;
}
void Cdrv8833::setFrequency(uint32_t frequency) {
stop();
ledcChangeFrequency(m_channel, frequency, PWM_BIT_RESOLUTION);
}
void Cdrv8833::swapDirection(bool swapDirection) {
stop();
m_swapDirection = swapDirection;
}

View File

@@ -0,0 +1,91 @@
#ifndef DRV8833_H
#define DRV8833_H
#include <stdint.h>
// default values
#define PWM_FREQUENCY 5000 // 1 - 50000 Hz
#define PWM_BIT_RESOLUTION 8 // pwm bit resolution
// https://learn.adafruit.com/improve-brushed-dc-motor-performance/choosing-decay-mode-and-pwm-frequency
// DRV8833 PWM: min - 1Hz, max - 50KHz (provare 100-500Hz)
// PWM utilizzare le funzioni ledc
// slow decay -> good torque, high power consumption
// fast decay -> poor torque, low power consumption
enum drv8833DecayMode {
drv8833DecaySlow = 0,
drv8833DecayFast = 1
};
class Cdrv8833 {
public:
// default constructor. Default decay mode: SLOW
Cdrv8833();
// Specialized constructor. Default decay mode: SLOW
// input:
// in1Pin : DRV8833 AIN1/BIN1
// in2Pin : DRV8833 AIN2/BIN2
// channel : ESP32 PWM channel (0..15) - ESP32 ledc functions
// swapDirection: swap motor rotation direction
Cdrv8833(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection = false);
~Cdrv8833();
// Initialize the DRV8833 object. Default decay mode: SLOW
// input:
// in1Pin : DRV8833 AIN1/BIN1
// in2Pin : DRV8833 AIN2/BIN2
// channel : ESP32 PWM channel (0..15) - ESP32 ledc functions
// swapDirection: swap motor rotation direction
// return:
// true if no error occurs.
bool init(uint8_t in1Pin, uint8_t in2Pin, uint8_t channel, bool swapDirection = false);
// Set motor rotation direction/speed
// input:
// power: rotation power. -100..100
// Negative numbers mean reverse rotation; positive numbers mean forward direction.
// Zero stop the rotation
// return:
// true if no error occurs.
bool move(int8_t power); // use fast decay -> smooth movement
// Stop the motor, using fast decay mode
// return:
// true if no error occurs.
bool stop();
// Stop the motor, using slow decay mode
// return:
// true if no error occurs.
bool brake();
// Set the decay mode. Default decay mode: SLOW
// input:
// decayMode: new decay mode. Values are
// drv8833DecaySlow - good torque, high power consumption
// drv8833DecayFast - poor torque, low power consumption
void setDecayMode(drv8833DecayMode decayMode);
// Set the PWM frequency (for ESP32 ledc functions)
// input:
// frequency: new frequency in Hertz. 1..50000Hz.
void setFrequency(uint32_t frequency);
// Swap the motor rotation direction.
// Useful for wrong cabling / driving two opposite motors (left wheel + right wheel motor of a vehicle)
// input:
// swapDirection: true -> swap rotation direction
void swapDirection(bool swapDirection);
private:
int8_t m_in1Pin;
int8_t m_in2Pin;
bool m_swapDirection;
drv8833DecayMode m_decayMode;
uint8_t m_channel;
int8_t m_power;
};
#endif

View File

@@ -18,9 +18,8 @@ lib_deps =
ottowinter/ESPAsyncWebServer-esphome@^3.1.0 ottowinter/ESPAsyncWebServer-esphome@^3.1.0
ArduinoWebsockets ArduinoWebsockets
AsyncTCP AsyncTCP
joaolopesf/ESP32MotorControl@^0.1.0 shurillu/Cdrv8833@^1.0.1
build_flags = build_flags =
-DCORE_DEBUG_LEVEL=3 -DCORE_DEBUG_LEVEL=3
-DNDEF_DEBUG=1 -DNDEF_DEBUG=1
upload_protocol = espota ;esptool upload_protocol = esptool
upload_port = MiniSkidi.local

View File

@@ -5,35 +5,14 @@ bool removeArmMomentum = false;
Servo bucketServo; Servo bucketServo;
Servo auxServo; Servo auxServo;
void motor::drive(int dirspeed)
{
if (dirspeed == 0)
{
motorStop(motorindex);
}
if (dirspeed > 0)
{
// map(value, fromLow, fromHigh, toLow, toHigh)
uint8_t speed = map(dirspeed, -255, 0, 0, 100);
log_i("motor(%u) forward", m_index);
motorForward(motorindex, speed);
}
else
{
uint8_t speed = map(dirspeed, 0, 255, 0, 100);
log_i("motor(%u) reverse", m_index);
motorReverse(motorindex, speed);
}
}
std::vector<MOTOR_PINS> motorPins = std::vector<MOTOR_PINS> motorPins =
{ {
{RMOTOR_IN1, RMOTOR_IN2}, // RIGHT_MOTOR Pins (IN1, IN2) {RMOTOR_IN1, RMOTOR_IN2}, // RIGHT_MOTOR Pins (IN1, IN2)
{LMOTOR_IN1, LMOTOR_IN2}, // LEFT_MOTOR Pins {LMOTOR_IN1, LMOTOR_IN2}, // LEFT_MOTOR Pins
// {ARM_IN1, ARM_IN2}, //ARM_MOTOR pins {ARM_IN1, ARM_IN2}, //ARM_MOTOR pins
}; };
#define NUMMOTORS 2 #define NUMMOTORS 3
motor motors[NUMMOTORS]; motor motors[NUMMOTORS];
void setupmotors() void setupmotors()
@@ -41,30 +20,76 @@ void setupmotors()
for (int i = 0; i < NUMMOTORS; i++) for (int i = 0; i < NUMMOTORS; i++)
{ {
log_i("motor(%u) initialized", motors[i].m_index); motors[i].init(motorPins[i].pinIN1, motorPins[i].pinIN2, i+2, false); // pinMode(motorPins[i].pinIN1, OUTPUT);
motors[i].attachMotor(motorPins[i].pinIN1, motorPins[i].pinIN2); // pinMode(motorPins[i].pinIN1, OUTPUT); motors[i].stop();
motors[i].motorStop(0);
motors[i].setindex(i); motors[i].setindex(i);
log_i("motor(%d) initialized", i);
delay(50);
} }
bucketServo.attach(bucketServoPin); bucketServo.attach(bucketServoPin);
auxServo.attach(auxServoPin); //auxServo.attach(auxServoPin);
auxControl(default_auxControl); //auxControl(default_auxControl);
bucketTilt(default_bucketTilt); bucketServo.write(default_bucketTilt);
} }
void drivemotor(uint8_t num, int dirspeed) void drivemotor(uint8_t num, int dirspeed)
{ {
if (num < motorPins.size()) if (num <= motorPins.size())
{ {
log_i("drive motor %u, speed %d", num, dirspeed); if(dirspeed == 0)
motors[num].drive(dirspeed); {
motors[num].stop();
log_v("stop");
}
else
{
log_i("drive motor %u, speed %d", num, dirspeed);
uint8_t speed = map(dirspeed, -255, 255, -100, 100);
motors[num].move(speed);
motors[num].prevsetpoint = dirspeed;
}
}
else
{
log_e("invalid motor num %d", num);
}
}
int prevBucketAngle = 0;
uint32_t lastbuckettimer = 0;
void bucketTilt(int bucketServoValue)
{
if(millis()- lastbuckettimer > BUCKETTIMER)
{
int servo = 0;
if(bucketServoValue == 0)
{
return;
}
else if(bucketServoValue > 0)
{
servo = prevBucketAngle + SERVOSTEP;
log_i("bucket UP (%d)", servo);
}
else
{
servo = prevBucketAngle - SERVOSTEP;
log_i("bucket DOWN (%d)", servo);
}
if(servo > SERVOMAX) servo = SERVOMAX;
if(servo < SERVOMIN) servo = SERVOMIN;
bucketServo.write(servo);
lastbuckettimer = millis();
} }
} }
void bucketTilt(int bucketServoValue) void AbsBucketTilt(int bucketServoValue)
{ {
bucketServo.write(bucketServoValue); bucketServo.write(bucketServoValue);
} }
void auxControl(int auxServoValue) void auxControl(int auxServoValue)
{ {
auxServo.write(auxServoValue); auxServo.write(auxServoValue);

View File

@@ -2,186 +2,199 @@
//https://mischianti.org/online-converter-file-to-cpp-gzip-byte-array-3/ //https://mischianti.org/online-converter-file-to-cpp-gzip-byte-array-3/
//File: web_smars.html.gz, Size: 2875
const uint8_t web_smars_html_gz[] PROGMEM = { const uint8_t web_smars_html_gz[] PROGMEM = {
0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC5, 0x1A, 0x6B, 0x6F, 0xDB, 0x46, 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE5, 0x1A, 0xFD, 0x6F, 0xDB, 0x36,
0xF2, 0xBB, 0x7F, 0xC5, 0x44, 0xC1, 0xD5, 0x54, 0x2C, 0x51, 0x0F, 0x37, 0x6D, 0x6A, 0x59, 0x2E, 0xF6, 0xF7, 0xFE, 0x15, 0xAC, 0x8B, 0x5B, 0xE5, 0xC4, 0x96, 0xBF, 0xD6, 0xAD, 0xCB, 0xE2, 0x14,
0x1C, 0xDB, 0x71, 0x53, 0x38, 0xAD, 0x61, 0xF9, 0xEA, 0x18, 0x87, 0x83, 0xB1, 0x22, 0x57, 0xD2, 0x69, 0x92, 0x66, 0x1D, 0x92, 0x2D, 0x88, 0x73, 0x4B, 0x8D, 0xC3, 0x21, 0xA0, 0x25, 0xDA, 0x66,
0x26, 0x4B, 0x2E, 0xB1, 0x5C, 0x4A, 0x72, 0x5B, 0xFF, 0xF7, 0x9B, 0x59, 0xBE, 0x29, 0xC9, 0x49, 0x2B, 0x89, 0x82, 0x44, 0xF9, 0x63, 0x5B, 0xFE, 0xF7, 0x7B, 0x8F, 0x94, 0x64, 0xC9, 0xA2, 0xEC,
0x0E, 0x38, 0x9C, 0x80, 0x58, 0xE4, 0xEC, 0xCC, 0xEC, 0xEC, 0xBC, 0x67, 0x95, 0xE3, 0x17, 0xE7, 0xA4, 0xB7, 0x03, 0x0E, 0x98, 0xB0, 0xA5, 0x26, 0xDF, 0x07, 0x1F, 0xDF, 0x37, 0x29, 0x1D, 0xBF,
0xBF, 0x9F, 0xDD, 0xDE, 0x5F, 0x5F, 0xC0, 0xC2, 0x04, 0xF2, 0x64, 0x6F, 0xEF, 0xB8, 0xF8, 0xE6, 0x3C, 0xFF, 0xF5, 0xEC, 0x6E, 0x7C, 0x73, 0x41, 0xE6, 0xD2, 0xF7, 0x4E, 0x5E, 0xBC, 0x38, 0xD6,
0xCC, 0x3F, 0xD9, 0x03, 0xFC, 0x1C, 0x07, 0xDC, 0x30, 0x08, 0x59, 0xC0, 0xC7, 0xFB, 0x4B, 0xC1, 0xFF, 0x12, 0x78, 0x8E, 0xE7, 0x8C, 0xBA, 0xFA, 0xA7, 0x1A, 0xFA, 0x4C, 0x52, 0x12, 0x50, 0x9F,
0x57, 0x91, 0xD2, 0x66, 0x1F, 0x3C, 0x15, 0x1A, 0x1E, 0x9A, 0xF1, 0xFE, 0x4A, 0xF8, 0x66, 0x31, 0x0D, 0x1B, 0x0B, 0xCE, 0x96, 0xA1, 0x88, 0x64, 0x83, 0x38, 0x22, 0x90, 0x2C, 0x90, 0xC3, 0xC6,
0xF6, 0xF9, 0x52, 0x78, 0xBC, 0x6B, 0x5F, 0x3A, 0x90, 0x7F, 0x44, 0x28, 0x8C, 0x60, 0xB2, 0x1B, 0x92, 0xBB, 0x72, 0x3E, 0x74, 0xD9, 0x82, 0x3B, 0xAC, 0xAD, 0x06, 0xAD, 0x8C, 0x92, 0xF0, 0x80,
0x7B, 0x4C, 0xF2, 0xF1, 0xC0, 0xED, 0x97, 0x4B, 0x49, 0xCC, 0xB5, 0x85, 0xB3, 0x29, 0x2E, 0x85, 0x4B, 0x4E, 0xBD, 0x76, 0xEC, 0x50, 0x8F, 0x0D, 0x7B, 0x76, 0x77, 0x03, 0x4A, 0x62, 0x16, 0xA9,
0x6A, 0x1F, 0x7A, 0xD5, 0xED, 0xBC, 0x05, 0xD3, 0x31, 0x37, 0xE3, 0x56, 0x62, 0x66, 0xDD, 0x37, 0x79, 0x3A, 0x01, 0x50, 0x20, 0x1A, 0xA4, 0xB3, 0xBD, 0xA4, 0x33, 0xA7, 0x51, 0xCC, 0x60, 0x89,
0x2D, 0x5A, 0xDC, 0x4B, 0x97, 0x8D, 0x30, 0x92, 0x9F, 0xFC, 0xAA, 0x1E, 0x63, 0x23, 0xBC, 0xCF, 0x44, 0x4E, 0xDB, 0x6F, 0x15, 0xC2, 0x06, 0x43, 0x72, 0xE9, 0xB1, 0x93, 0x6B, 0x58, 0x81, 0x8C,
0x60, 0x78, 0x6C, 0x8E, 0x7B, 0x29, 0x30, 0x47, 0x89, 0xCD, 0x23, 0xBD, 0xE5, 0x5B, 0xBD, 0x24, 0xBE, 0x70, 0x97, 0x1F, 0x77, 0xF4, 0x4C, 0x01, 0x25, 0x96, 0x6B, 0x9C, 0x20, 0x85, 0xA7, 0x73,
0x59, 0x99, 0x08, 0xB9, 0x86, 0xBF, 0x0A, 0x20, 0x7D, 0xAC, 0xB4, 0x47, 0x30, 0xE8, 0xF7, 0xFF, 0x40, 0x5E, 0xA1, 0xE4, 0x94, 0x07, 0x2C, 0x22, 0x7F, 0x94, 0x60, 0xF8, 0x28, 0xF9, 0x8F, 0x48,
0x31, 0xAA, 0x2D, 0x2C, 0xB8, 0x98, 0x2F, 0xCC, 0x11, 0x7C, 0xFF, 0xD3, 0x72, 0x51, 0x5F, 0x99, 0xAF, 0xDB, 0xFD, 0xC7, 0x8F, 0x15, 0xE0, 0x9C, 0xF1, 0xD9, 0x5C, 0x1E, 0x91, 0x6F, 0x7F, 0x58,
0x32, 0xEF, 0xF3, 0x5C, 0xAB, 0x24, 0xF4, 0xBB, 0x9E, 0x92, 0x4A, 0x1F, 0xC1, 0xCB, 0xC3, 0xC3, 0xCC, 0xAB, 0xD0, 0x09, 0x75, 0xBE, 0xCC, 0x22, 0x91, 0x04, 0x6E, 0xDB, 0x11, 0x9E, 0x88, 0x8E,
0xC3, 0x3A, 0x8E, 0x2F, 0xE2, 0x48, 0xB2, 0xC7, 0x23, 0x98, 0x49, 0xBE, 0xAE, 0x2F, 0x31, 0x29, 0xC8, 0xAB, 0xC1, 0x60, 0x50, 0xC5, 0x73, 0x79, 0x1C, 0x7A, 0x74, 0x7D, 0x44, 0xA6, 0x1E, 0x5B,
0xE6, 0x61, 0x57, 0x18, 0x1E, 0xC4, 0x47, 0xE0, 0xA1, 0xFE, 0xB8, 0xAE, 0x23, 0x7C, 0x4A, 0xF0, 0x55, 0xC1, 0xD4, 0xE3, 0xB3, 0xA0, 0xCD, 0x25, 0xF3, 0xE3, 0x23, 0xE2, 0x80, 0x86, 0x59, 0x54,
0x58, 0xB3, 0xC7, 0x6E, 0xA6, 0xDE, 0xED, 0x48, 0x6A, 0xC9, 0xF5, 0x4C, 0xAA, 0xD5, 0x11, 0x2C, 0x45, 0xFA, 0x9C, 0xC4, 0x92, 0x4F, 0xD7, 0xED, 0xD4, 0x08, 0xF5, 0x88, 0x62, 0xC1, 0xA2, 0xA9,
0x84, 0xEF, 0xF3, 0xB0, 0x21, 0xA2, 0xD2, 0x3E, 0xEA, 0x56, 0x33, 0x5F, 0x24, 0xB8, 0xCB, 0x8F, 0x27, 0x96, 0x47, 0x64, 0xCE, 0x5D, 0x97, 0x05, 0x06, 0xB1, 0x45, 0xE4, 0x82, 0x25, 0x22, 0xEA,
0x51, 0x43, 0x06, 0xA3, 0x12, 0x6F, 0xD1, 0x65, 0x9E, 0x11, 0x2A, 0x3C, 0x82, 0x50, 0x85, 0xBC, 0xF2, 0x04, 0x56, 0xFC, 0x3E, 0x34, 0xC8, 0x24, 0x45, 0xE2, 0xCC, 0xDB, 0xD4, 0x91, 0x5C, 0x04,
0x5C, 0x7F, 0xDA, 0x2B, 0xB5, 0x46, 0x52, 0xEE, 0x54, 0x58, 0x93, 0x69, 0xAE, 0xB1, 0x2D, 0x4B, 0x47, 0x24, 0x10, 0x01, 0x2B, 0xE3, 0x3C, 0x92, 0x83, 0x4E, 0x69, 0xE2, 0x95, 0x48, 0x40, 0x9C,
0x9B, 0x2A, 0xD3, 0xF3, 0xA9, 0x33, 0xFC, 0xFE, 0x75, 0x07, 0x86, 0x87, 0xE8, 0x11, 0x3F, 0xFD, 0xB3, 0x1D, 0x8A, 0xDE, 0xA3, 0x85, 0x4C, 0xD5, 0x60, 0x08, 0x93, 0xAE, 0x9F, 0xBC, 0xFF, 0xBD,
0xD4, 0xDE, 0x76, 0x00, 0xE2, 0x15, 0xAD, 0x21, 0x56, 0x52, 0xF8, 0x44, 0xC1, 0x9C, 0xC1, 0xE1, 0xDA, 0x7C, 0x7C, 0x51, 0x1A, 0xDA, 0x1E, 0x6B, 0x03, 0x6B, 0xE7, 0x4B, 0xBD, 0x6F, 0xF4, 0xBB,
0x0F, 0x1D, 0x28, 0xFF, 0xB8, 0xAF, 0xB7, 0xD2, 0x15, 0x07, 0x7F, 0xDD, 0xB4, 0xEA, 0x73, 0x07, 0x5D, 0xD0, 0x11, 0xA9, 0x15, 0x59, 0xC3, 0x77, 0x2C, 0x02, 0x3E, 0x48, 0x5E, 0xA1, 0x48, 0x3B,
0xA7, 0x4F, 0xEA, 0x92, 0x5C, 0x72, 0xCF, 0x7C, 0x49, 0x2F, 0x47, 0xC4, 0x65, 0xC9, 0x1B, 0xEA, 0xFD, 0xCF, 0x64, 0x87, 0x82, 0x56, 0x4C, 0xE0, 0xAA, 0x07, 0x46, 0xB3, 0x89, 0xD5, 0xFF, 0xF6,
0xD9, 0x7A, 0x52, 0x94, 0xFB, 0x87, 0x37, 0x78, 0xD4, 0x01, 0xFD, 0x19, 0xE2, 0x79, 0x31, 0x0C, 0x4D, 0x8B, 0xF4, 0x07, 0x10, 0x7A, 0x3F, 0xFC, 0xD0, 0xAC, 0xB3, 0x3F, 0xF2, 0x0C, 0x57, 0x24,
0xFA, 0xED, 0x67, 0x58, 0x2F, 0xC8, 0xBC, 0x0D, 0xCE, 0x5E, 0xA2, 0x63, 0xE2, 0x17, 0x29, 0xB1, 0x16, 0x1E, 0x77, 0x91, 0x8A, 0x5A, 0xBD, 0xC1, 0x77, 0x2D, 0xB2, 0xF9, 0xD3, 0xB5, 0xDF, 0xD4,
0xE9, 0x0E, 0xD9, 0xB9, 0x33, 0xE3, 0x0C, 0x6B, 0x06, 0xA8, 0x72, 0x67, 0x9A, 0xB3, 0x06, 0xDF, 0x12, 0xE7, 0xCE, 0xF3, 0xC6, 0x14, 0x35, 0xFB, 0x9C, 0x07, 0x1F, 0x9D, 0x0C, 0x98, 0xC7, 0x1C,
0x48, 0xC5, 0x22, 0x55, 0xC7, 0x4C, 0xAC, 0xB9, 0x5F, 0xE7, 0xAB, 0x53, 0x93, 0xF6, 0x9B, 0x5A, 0x69, 0xF4, 0xAF, 0xB2, 0x91, 0x94, 0xF2, 0x8E, 0x90, 0xE3, 0x82, 0x19, 0x74, 0x68, 0x54, 0x03,
0x8C, 0x6A, 0xB0, 0xA7, 0x34, 0xE6, 0x7A, 0x59, 0xD0, 0xE5, 0x21, 0xE8, 0x69, 0x11, 0x19, 0x30, 0x6C, 0xE8, 0xBB, 0xB7, 0xA0, 0x87, 0x1E, 0xFE, 0xE9, 0x83, 0x32, 0x7A, 0xCD, 0x27, 0xAC, 0x31,
0x8F, 0x11, 0x1F, 0xB7, 0x0C, 0x5F, 0x9B, 0xDE, 0x27, 0xB6, 0x64, 0x29, 0xB4, 0x55, 0x86, 0xE6, 0xC7, 0xF8, 0x31, 0x2C, 0xE1, 0x24, 0x51, 0x8C, 0x8C, 0x43, 0xC1, 0xCD, 0x7E, 0x97, 0x2A, 0x26,
0x92, 0x69, 0xC0, 0x50, 0x9E, 0xD8, 0x50, 0x1E, 0xC3, 0x2C, 0x09, 0xAD, 0x75, 0xC0, 0x31, 0x1D, 0x77, 0x99, 0xDD, 0x1E, 0x41, 0x5E, 0xD1, 0x88, 0x51, 0xC3, 0x3A, 0xA1, 0x88, 0xB9, 0xD6, 0xDB,
0xE0, 0x6D, 0xF8, 0xCB, 0x22, 0x08, 0x5C, 0x59, 0x2A, 0xF4, 0x82, 0x3E, 0x8C, 0xC7, 0x63, 0x70, 0x94, 0xAF, 0x98, 0x5B, 0x5D, 0x27, 0xD2, 0x0E, 0xD1, 0x35, 0xA9, 0x3D, 0xAC, 0xCC, 0x97, 0xE2,
0x38, 0xBE, 0x73, 0xF8, 0xFB, 0x6F, 0xF8, 0xEB, 0xA9, 0xED, 0xDA, 0xC8, 0x87, 0x9F, 0xA1, 0xF5, 0xF4, 0xB8, 0x93, 0xE6, 0xC7, 0x42, 0xC2, 0x74, 0x22, 0x1E, 0x4A, 0x22, 0xD7, 0x21, 0xA4, 0x7A,
0x29, 0xCB, 0x08, 0x2D, 0x38, 0x02, 0x9E, 0x82, 0x3B, 0x10, 0xD6, 0x49, 0xB9, 0x6B, 0x95, 0x84, 0xC9, 0x56, 0xB2, 0xF3, 0x99, 0x2E, 0xA8, 0x9E, 0x6D, 0x94, 0x13, 0xE9, 0x82, 0x46, 0xE4, 0x67,
0xE8, 0x7D, 0x8B, 0x95, 0xA5, 0x2B, 0xD5, 0xC4, 0x4A, 0xBD, 0xB9, 0x40, 0x4B, 0x5F, 0x3B, 0xB0, 0xB1, 0x1E, 0xA9, 0x58, 0x19, 0x92, 0x69, 0x12, 0x28, 0x03, 0x13, 0x4B, 0xB6, 0x08, 0x6B, 0x1A,
0x68, 0xE2, 0x59, 0x63, 0x84, 0x4C, 0xBE, 0x13, 0x52, 0x9E, 0x91, 0xC5, 0x49, 0x90, 0x97, 0xFD, 0xB6, 0x82, 0x04, 0x1C, 0x30, 0x17, 0x02, 0x3C, 0xAC, 0x4B, 0x86, 0xC3, 0x21, 0xB1, 0x18, 0x8C,
0xFE, 0xE9, 0x69, 0xBF, 0x9F, 0xCA, 0xB1, 0x81, 0xD1, 0x01, 0xBD, 0x8B, 0xCB, 0x15, 0xA6, 0xA8, 0x19, 0xF9, 0xF3, 0x4F, 0xF2, 0xC7, 0x63, 0xD3, 0x56, 0xE9, 0x9B, 0xBC, 0x23, 0x8D, 0xCF, 0x62,
0xBB, 0x4C, 0xBE, 0x61, 0x8D, 0xBA, 0x58, 0xE9, 0x80, 0xBF, 0x8B, 0x7A, 0x62, 0xB4, 0xFA, 0xCC, 0xAD, 0x42, 0xB0, 0x41, 0x8E, 0x08, 0xD3, 0xD3, 0xAD, 0x0A, 0x3B, 0x7C, 0x82, 0x32, 0x3B, 0x66,
0xAB, 0x52, 0x1C, 0x1E, 0x36, 0xA5, 0xA8, 0xE0, 0x74, 0x80, 0x35, 0x39, 0xA1, 0x95, 0x76, 0xC8, 0x2B, 0x75, 0x03, 0x8B, 0xAE, 0xA2, 0xD4, 0xB5, 0xC8, 0x48, 0x29, 0xB6, 0x29, 0x75, 0x64, 0xE5,
0xB1, 0xB1, 0xD2, 0x01, 0xB9, 0x8B, 0x7A, 0x53, 0x8E, 0x37, 0xFD, 0x5C, 0x8E, 0x2D, 0x38, 0x1D, 0xA4, 0x7A, 0x68, 0xA6, 0x9D, 0x6F, 0xD3, 0x2A, 0x17, 0x08, 0xA8, 0xF7, 0x81, 0x7B, 0xDE, 0x19,
0xF0, 0x90, 0x93, 0xAF, 0xBC, 0x24, 0xC0, 0x4C, 0xE7, 0xCE, 0xB9, 0xB9, 0x90, 0x9C, 0x1E, 0xDF, 0x3A, 0x1C, 0x6E, 0xE2, 0x55, 0xB7, 0x7B, 0x7A, 0xDA, 0xED, 0xEA, 0x3D, 0x54, 0x30, 0xCC, 0x9C,
0x3E, 0xBE, 0xF7, 0x1D, 0xD3, 0xEE, 0x40, 0x52, 0x5D, 0xF7, 0xD0, 0x87, 0x0D, 0xCF, 0x50, 0x9C, 0xA3, 0x3A, 0xCE, 0x57, 0x90, 0x44, 0xEF, 0xD3, 0xBD, 0xF5, 0x4B, 0x1C, 0x73, 0x88, 0x99, 0xA3,
0x96, 0xC7, 0x42, 0xF4, 0xAA, 0x56, 0x7B, 0x04, 0x89, 0x2B, 0x48, 0x35, 0xA2, 0x63, 0x05, 0x42, 0x5B, 0xC7, 0x71, 0x24, 0x23, 0xF1, 0x85, 0x15, 0xA5, 0x1D, 0x0C, 0xB6, 0xA5, 0x2D, 0xE0, 0x98,
0xC3, 0x7F, 0xF7, 0x1D, 0x38, 0x64, 0x7E, 0xCF, 0xF5, 0xA4, 0x40, 0x64, 0x2B, 0x77, 0x3B, 0x5B, 0xB9, 0xD3, 0x6D, 0xEE, 0xE0, 0x31, 0x35, 0xF2, 0x56, 0x20, 0x66, 0x8E, 0x5E, 0x1D, 0xC7, 0xAA,
0x56, 0x76, 0x59, 0x55, 0x96, 0x7F, 0xB1, 0x36, 0xA6, 0xED, 0x32, 0x1F, 0x41, 0x1E, 0xF4, 0x92, 0xBC, 0x6F, 0xBB, 0x99, 0xBC, 0x06, 0x1C, 0x33, 0x77, 0x07, 0xB8, 0xBB, 0xC2, 0x49, 0x7C, 0xA8,
0xB9, 0x02, 0x92, 0xA0, 0xA4, 0x2E, 0x8B, 0x22, 0x1E, 0xFA, 0x67, 0x0B, 0x21, 0x7D, 0x27, 0xC1, 0x03, 0xF6, 0x8C, 0xC9, 0x0B, 0x8F, 0xE1, 0xCF, 0xF7, 0xEB, 0x8F, 0xAE, 0x25, 0x9B, 0x66, 0x9A,
0x5D, 0xC9, 0x3D, 0x63, 0x5C, 0x4C, 0x48, 0xF0, 0x33, 0xCA, 0xD9, 0x6B, 0x94, 0x6A, 0xE8, 0xB7, 0xA4, 0x48, 0xE3, 0x40, 0x94, 0x4A, 0x96, 0x92, 0x59, 0x0D, 0x87, 0x06, 0x10, 0x1D, 0x0D, 0x43,
0x90, 0xD1, 0x0C, 0xE1, 0x18, 0xEE, 0x4B, 0xFC, 0x1A, 0xC2, 0x2B, 0xF8, 0xC0, 0xCC, 0xC2, 0xBD, 0x5E, 0xB4, 0x12, 0x9B, 0xA3, 0xEE, 0x79, 0xB3, 0xA5, 0xB6, 0x02, 0xAE, 0xFA, 0xCD, 0x37, 0xC4,
0x7E, 0xDF, 0x81, 0x39, 0x02, 0x9C, 0x7C, 0x97, 0x2E, 0x0C, 0x06, 0xFD, 0x36, 0xF4, 0x60, 0xD8, 0x42, 0x87, 0x75, 0x6C, 0xC7, 0xE3, 0x40, 0xAE, 0xB4, 0x90, 0x81, 0x85, 0x02, 0x8B, 0x02, 0xF8,
0x81, 0x15, 0x2E, 0xCC, 0xE1, 0x00, 0x30, 0x31, 0x9E, 0x65, 0x8F, 0x94, 0x1F, 0x03, 0xCB, 0x3F, 0x27, 0xE5, 0x81, 0x00, 0x07, 0x56, 0xDA, 0xAD, 0x81, 0x89, 0x1E, 0xA6, 0xBE, 0x0A, 0x54, 0x30,
0x45, 0xB7, 0x78, 0x91, 0x05, 0x64, 0x82, 0x59, 0xC8, 0x55, 0x0D, 0x65, 0x80, 0x44, 0x17, 0x08, 0x76, 0x6C, 0x1A, 0x86, 0x2C, 0x70, 0xCF, 0xE6, 0xDC, 0x73, 0xAD, 0xC4, 0x20, 0x0B, 0x06, 0x5E,
0xE9, 0x0E, 0x70, 0xDB, 0xAB, 0x0E, 0x4C, 0xEA, 0xF8, 0xB4, 0xFC, 0x39, 0x5F, 0x9E, 0x74, 0xE0, 0x0C, 0xD8, 0x09, 0x6E, 0x19, 0x4B, 0x32, 0xE8, 0xCB, 0x6A, 0xF4, 0xDD, 0x46, 0xCD, 0x8E, 0xA7,
0x0E, 0x9F, 0x83, 0x0E, 0x5C, 0xE2, 0x57, 0x34, 0x2A, 0x43, 0x70, 0xED, 0x50, 0xFC, 0xC5, 0xEE, 0x80, 0xDB, 0x35, 0x83, 0x16, 0x00, 0xEA, 0x93, 0x03, 0x72, 0x4D, 0xE5, 0xDC, 0xBE, 0xF9, 0x68,
0x94, 0xCF, 0x45, 0x78, 0x8D, 0xC2, 0x3B, 0x78, 0xA6, 0xD8, 0x65, 0xDA, 0x73, 0x10, 0x3B, 0x42, 0x46, 0x9A, 0x01, 0x52, 0x2E, 0x74, 0x9B, 0xF4, 0x7A, 0xDD, 0x26, 0xE9, 0x90, 0xBE, 0x19, 0x79,
0x19, 0x3B, 0xF6, 0x78, 0x1D, 0x78, 0x31, 0xB0, 0x2B, 0xB2, 0x70, 0x9B, 0x31, 0x30, 0x02, 0xC4, 0x09, 0xC8, 0x33, 0x72, 0x48, 0xDE, 0x98, 0xC1, 0x67, 0x29, 0x78, 0x50, 0x23, 0x90, 0xAF, 0xF6,
0xD6, 0xCA, 0x13, 0xCA, 0x0B, 0x08, 0x92, 0x25, 0x08, 0x39, 0x3F, 0x95, 0x1B, 0x3D, 0x6E, 0xDB, 0xA5, 0x97, 0xAA, 0x5D, 0x23, 0x54, 0x48, 0xA9, 0xD6, 0x6A, 0xB1, 0xAE, 0x4A, 0xAC, 0x7A, 0x35,
0xE8, 0x0E, 0x8E, 0x51, 0x01, 0x64, 0x24, 0x12, 0x6F, 0x65, 0x21, 0x07, 0x08, 0x39, 0x29, 0xCE, 0x0B, 0x5E, 0x00, 0x56, 0xBB, 0x07, 0x2A, 0xB8, 0x32, 0xC3, 0x47, 0xE5, 0xB5, 0xEA, 0xD8, 0x7C,
0x99, 0xAF, 0x95, 0x9A, 0x24, 0xAC, 0xCB, 0x82, 0xEE, 0x32, 0xA3, 0xBB, 0x2C, 0xE8, 0x32, 0x0D, 0xC9, 0xD8, 0x8C, 0xCC, 0xF0, 0x7B, 0x80, 0xFB, 0x66, 0xD0, 0x25, 0x80, 0xC2, 0xAA, 0x95, 0xF3,
0xE4, 0x8B, 0x05, 0x20, 0xA5, 0x4C, 0x8F, 0x76, 0x87, 0x04, 0x68, 0xA2, 0xCA, 0xD1, 0x52, 0x23, 0x04, 0xBC, 0xB2, 0x4C, 0xD9, 0x17, 0x9F, 0xD8, 0x9E, 0xB0, 0x19, 0x0F, 0x6E, 0xC0, 0x78, 0x16,
0x93, 0x07, 0xC4, 0x99, 0xF7, 0xDD, 0x60, 0x81, 0x61, 0xF2, 0x92, 0xEA, 0x0C, 0x39, 0x61, 0xAA, 0x78, 0x4E, 0x6C, 0xD3, 0xC8, 0xB1, 0xFC, 0x16, 0x09, 0x5B, 0xE4, 0x0C, 0xFC, 0xB0, 0x45, 0x16,
0x0D, 0x34, 0x5A, 0xFA, 0x30, 0xA4, 0xEC, 0x0E, 0xC6, 0x65, 0xBE, 0x6F, 0x1D, 0x7C, 0x82, 0x09, 0x2D, 0xF2, 0xB2, 0x87, 0x3E, 0x16, 0xDB, 0x5E, 0x1E, 0xC1, 0x43, 0x42, 0xF5, 0x54, 0xAC, 0xC2,
0xD3, 0x41, 0x6E, 0xE4, 0x7B, 0x0D, 0xE8, 0x00, 0xC3, 0xD9, 0xEE, 0x3C, 0xC3, 0xEC, 0x90, 0xEB, 0x6B, 0x84, 0x35, 0x03, 0x26, 0x3D, 0xC5, 0x41, 0xCF, 0x59, 0x06, 0xAF, 0x7B, 0xAC, 0x97, 0x70,
0xC9, 0xE4, 0x00, 0x67, 0x43, 0xAB, 0x7A, 0x53, 0xAB, 0x7E, 0x43, 0xAB, 0x2D, 0xF4, 0x41, 0x2A, 0xFD, 0x54, 0x09, 0xEF, 0xC9, 0x31, 0x58, 0x1F, 0x23, 0x03, 0xF5, 0xB1, 0x54, 0x33, 0x87, 0x30,
0x73, 0xB1, 0x61, 0xDA, 0xB4, 0xB0, 0x01, 0x2B, 0x43, 0x27, 0x7F, 0xC8, 0x82, 0x07, 0x83, 0x13, 0x73, 0x92, 0x1B, 0x2A, 0x83, 0x6D, 0xDC, 0x0D, 0xB1, 0x2E, 0x73, 0xBA, 0xCB, 0x94, 0xEE, 0x32,
0xBD, 0x10, 0xE5, 0xB9, 0x58, 0xE2, 0xDB, 0x95, 0x88, 0xB1, 0xDF, 0xE0, 0xDA, 0x69, 0x55, 0xC8, 0xA7, 0x4B, 0x4D, 0x93, 0x01, 0xF3, 0x09, 0x4D, 0xA9, 0x75, 0x72, 0x0F, 0x04, 0x2D, 0x32, 0x2B,
0x3B, 0xD5, 0x84, 0x4C, 0x46, 0x22, 0x97, 0x1E, 0xC0, 0x53, 0x66, 0xF2, 0x9D, 0xD4, 0x01, 0x56, 0xE8, 0xA4, 0xBA, 0x3F, 0x7C, 0x30, 0xB2, 0x30, 0x0E, 0xE3, 0x34, 0x31, 0xDC, 0x42, 0x1B, 0x44,
0xB0, 0x4D, 0x62, 0xE3, 0x46, 0x9A, 0x13, 0xF6, 0x39, 0x9F, 0xB1, 0x44, 0x1A, 0x3A, 0xDF, 0x80, 0xBD, 0x4B, 0xEC, 0x86, 0x30, 0x3F, 0x68, 0xD5, 0x42, 0xF3, 0xA5, 0x7F, 0x40, 0x5F, 0x58, 0xC3,
0x82, 0x71, 0x56, 0xD8, 0xD2, 0xB8, 0x96, 0x9E, 0xC7, 0xFF, 0xEA, 0xFF, 0xDB, 0x8D, 0xD8, 0x9C, 0x47, 0xDA, 0xD4, 0x75, 0x55, 0xDE, 0x1A, 0x41, 0xD5, 0xB6, 0x60, 0x55, 0x4C, 0x0C, 0x5B, 0xB3,
0x7F, 0x4C, 0xFD, 0x72, 0x03, 0x7E, 0x4F, 0xFE, 0xD0, 0x25, 0x1B, 0xAA, 0xD9, 0x0C, 0xFB, 0xC4, 0xBD, 0x16, 0x71, 0xB5, 0x21, 0xA6, 0x50, 0x45, 0x32, 0x33, 0x48, 0x25, 0x34, 0xCE, 0x58, 0x55,
0x2B, 0x3E, 0x33, 0x84, 0x5A, 0x01, 0xDD, 0xAA, 0x88, 0x74, 0xE3, 0x49, 0xCE, 0xF4, 0x0D, 0x96, 0xC3, 0x45, 0x26, 0xC3, 0xB9, 0xCF, 0x36, 0x5C, 0x03, 0x72, 0x06, 0xF6, 0x70, 0xB1, 0xA4, 0x78,
0x74, 0xB2, 0x41, 0xBF, 0x08, 0xEF, 0x32, 0xB4, 0x51, 0x8A, 0x35, 0x89, 0x82, 0x6E, 0xD8, 0xFE, 0xF0, 0xE3, 0xC1, 0x26, 0x21, 0x66, 0x3F, 0xD2, 0x94, 0x68, 0xDC, 0xDD, 0x3B, 0xCC, 0x06, 0xB0,
0xF2, 0xD1, 0x30, 0xFA, 0xB7, 0xAB, 0xA5, 0x5F, 0x0F, 0xA4, 0x6F, 0xDD, 0x3A, 0xDB, 0xB9, 0x8D, 0x95, 0x8B, 0x05, 0x60, 0x5C, 0xF1, 0x18, 0x1A, 0x76, 0x16, 0x59, 0x46, 0xD4, 0x74, 0xBD, 0xC2,
0x69, 0x72, 0xAB, 0x55, 0x02, 0x85, 0xDD, 0x89, 0xAF, 0x56, 0xE1, 0x7F, 0x63, 0x14, 0x4B, 0xBC, 0x6A, 0xE6, 0x18, 0xD0, 0x4F, 0xA1, 0xE7, 0xA8, 0x73, 0xA8, 0x02, 0x32, 0x6C, 0xBD, 0x67, 0x56,
0xDD, 0x28, 0x1B, 0x06, 0xA8, 0x69, 0xFD, 0xFF, 0xA5, 0x6A, 0x2B, 0x70, 0x12, 0xFD, 0x4F, 0x35, 0xBF, 0x7E, 0x1E, 0x77, 0x2D, 0xF5, 0xB2, 0x57, 0x03, 0xAC, 0xC9, 0xA1, 0x50, 0x37, 0xBE, 0x62,
0x5D, 0x42, 0x30, 0x2E, 0x17, 0x22, 0x76, 0x2F, 0xB9, 0xC9, 0x03, 0xAD, 0xDC, 0x95, 0x36, 0xD5, 0xCB, 0x3E, 0x74, 0x9B, 0x7F, 0xDD, 0x8E, 0xA5, 0x1D, 0x46, 0x0C, 0x05, 0x38, 0x67, 0x53, 0x9A,
0xDC, 0x24, 0x3A, 0x2C, 0x12, 0xCD, 0x53, 0x89, 0xFF, 0x4B, 0x5E, 0x1C, 0x76, 0x10, 0x64, 0x09, 0x78, 0x12, 0x1D, 0xA4, 0x87, 0xC5, 0x66, 0xAA, 0xBC, 0x5F, 0xC5, 0x8D, 0xB4, 0xD5, 0xC2, 0x2C,
0xA6, 0x42, 0x71, 0xAD, 0xE2, 0x8F, 0xBB, 0xF0, 0xEF, 0x1A, 0x88, 0xF7, 0xBB, 0x10, 0x2F, 0xAB, 0xFE, 0x57, 0xF7, 0xDF, 0x76, 0x48, 0x67, 0xEC, 0x13, 0xBA, 0xCC, 0xA5, 0x09, 0x32, 0x46, 0xC8,
0x88, 0x3B, 0xD9, 0x39, 0x68, 0xD1, 0x2E, 0x04, 0x54, 0x5C, 0x56, 0x98, 0xE9, 0xB1, 0x33, 0xC7, 0x3D, 0x69, 0x63, 0xCC, 0x88, 0xE9, 0x14, 0xCE, 0xE5, 0x57, 0x6C, 0x2A, 0x35, 0x7A, 0x61, 0xF2,
0x6E, 0x49, 0xBD, 0xA3, 0x3E, 0x2F, 0xD5, 0x42, 0xCE, 0x61, 0xE7, 0x3E, 0x0E, 0xE6, 0xC9, 0x2E, 0x4E, 0x84, 0xCA, 0xC1, 0x1C, 0x8F, 0xD1, 0xE8, 0x16, 0xFA, 0x79, 0x74, 0x67, 0xF8, 0x2F, 0x8D,
0x44, 0x15, 0x0E, 0xF8, 0xB7, 0x3B, 0xD8, 0xC1, 0xE6, 0x5C, 0xE8, 0x0D, 0x46, 0x79, 0xEA, 0x6C, 0xD0, 0x56, 0x1E, 0x71, 0x80, 0xB5, 0x42, 0x91, 0x20, 0x1B, 0xD4, 0x84, 0x85, 0x7E, 0xFE, 0x0F,
0xA1, 0x29, 0x29, 0x5D, 0x59, 0x89, 0x3A, 0xB6, 0xA3, 0xB3, 0xAC, 0x47, 0xF9, 0x56, 0x02, 0x4E, 0xEC, 0x02, 0xE5, 0xF5, 0xAF, 0x33, 0x8B, 0xA5, 0xEA, 0xAB, 0x56, 0x26, 0x24, 0xF9, 0x4C, 0xDF,
0xC6, 0x58, 0x95, 0xD0, 0x0F, 0x05, 0x1C, 0x8F, 0xB1, 0x64, 0x91, 0x47, 0x5A, 0xCA, 0x33, 0xAA, 0xCF, 0xD7, 0xDA, 0xFF, 0x40, 0x69, 0x4D, 0x23, 0xE0, 0xE8, 0xD9, 0x01, 0xEC, 0x0B, 0x38, 0xD0,
0xA5, 0x08, 0x4C, 0x57, 0x53, 0xD8, 0x6F, 0x29, 0xEC, 0xA4, 0x8A, 0x37, 0x21, 0x18, 0x47, 0xBC, 0xB9, 0x62, 0x19, 0xFC, 0x6D, 0xE2, 0x57, 0xED, 0xF8, 0xAF, 0x8D, 0xDF, 0x6A, 0xAC, 0x6E, 0x05,
0x0B, 0x0B, 0x43, 0x3A, 0x72, 0x6D, 0x4A, 0x73, 0x76, 0xF9, 0x8E, 0x3A, 0x10, 0x03, 0x07, 0xF6, 0xE8, 0xDF, 0x37, 0x2A, 0x95, 0xB6, 0x93, 0xF0, 0x6F, 0x12, 0x94, 0x66, 0x32, 0x5C, 0xD1, 0x08,
0xD1, 0x62, 0x9E, 0x60, 0xD9, 0xDC, 0x86, 0x79, 0x51, 0x62, 0x5E, 0x10, 0x26, 0xDA, 0x0F, 0x9E, 0x58, 0xD7, 0x01, 0x2C, 0x39, 0xE7, 0xB1, 0x7D, 0xC9, 0x64, 0xD6, 0x1F, 0x6C, 0x54, 0xB4, 0x4B,
0x46, 0x79, 0x97, 0x6B, 0x3B, 0xD8, 0x93, 0xBD, 0xE3, 0x5E, 0x3A, 0x20, 0xE3, 0xA4, 0x3C, 0x55, 0x43, 0x11, 0x93, 0x49, 0x14, 0x64, 0xBB, 0x36, 0x6F, 0xF0, 0x71, 0xDF, 0x92, 0x3F, 0x65, 0x67,
0xFE, 0xE3, 0x49, 0xD6, 0xF6, 0xFA, 0x62, 0x09, 0xC2, 0x1F, 0xEF, 0xAB, 0x04, 0x1B, 0x9D, 0xB3, 0x96, 0x67, 0xAE, 0xA9, 0x15, 0xFC, 0x95, 0x8B, 0xDE, 0x88, 0xF8, 0xD3, 0x73, 0x97, 0xBC, 0xFF,
0x7C, 0xEC, 0xDC, 0x2F, 0x1B, 0x5E, 0x8B, 0x61, 0x5B, 0xE5, 0x71, 0xAB, 0x98, 0x32, 0xFB, 0x38, 0xFA, 0xB5, 0xC6, 0xCF, 0x5D, 0xEB, 0xF2, 0x2B, 0xD7, 0x7A, 0xF6, 0xA6, 0x2C, 0xCC, 0x20, 0x6D,
0x65, 0xB6, 0x4E, 0x8E, 0x7B, 0xB8, 0xD6, 0xC0, 0x44, 0x5E, 0xD4, 0xD8, 0x9E, 0x8B, 0x65, 0x2B, 0xF0, 0x6B, 0x38, 0x92, 0x2C, 0x9B, 0x70, 0xEC, 0xE8, 0x41, 0x2F, 0x0A, 0x05, 0xFE, 0x03, 0x5E,
0xA7, 0x4A, 0xDB, 0xFC, 0xA1, 0x9D, 0xB3, 0x32, 0x0E, 0xE9, 0x4B, 0xC0, 0x34, 0x16, 0xD0, 0x23, 0x2A, 0xD5, 0x39, 0xED, 0x5E, 0x31, 0x9E, 0xBD, 0x5F, 0x10, 0x03, 0xB2, 0x12, 0x44, 0x55, 0x41,
0x96, 0x18, 0x55, 0x72, 0xCB, 0xC4, 0xAE, 0x3C, 0xE7, 0x27, 0x28, 0x07, 0x03, 0x9C, 0x35, 0x63, 0x0C, 0xF8, 0xDB, 0xEE, 0xFD, 0xF7, 0xB2, 0x9C, 0xF3, 0xE8, 0xC9, 0xD2, 0x64, 0x6D, 0x7B, 0x63,
0x03, 0x34, 0xDA, 0x3F, 0xD3, 0x89, 0xED, 0x63, 0x91, 0xE1, 0x2C, 0xD8, 0xAF, 0x4C, 0x2E, 0x29, 0x67, 0xFE, 0x20, 0x04, 0xBB, 0x65, 0xA5, 0xB6, 0xDD, 0x68, 0x78, 0xA9, 0xA5, 0xB6, 0x55, 0x1F,
0xDD, 0xDD, 0xE4, 0xE1, 0x9F, 0x37, 0xD4, 0x80, 0xB4, 0x56, 0xF1, 0x51, 0xAF, 0xD7, 0xC2, 0x72, 0xFB, 0xE9, 0xFE, 0x39, 0x39, 0x19, 0xC2, 0xD1, 0x0F, 0x32, 0x3A, 0x27, 0xC7, 0x43, 0x38, 0x2B,
0xBB, 0x12, 0x21, 0xA6, 0x2A, 0x57, 0x2A, 0x8F, 0x91, 0x2B, 0xB8, 0x0B, 0x85, 0x78, 0x07, 0xD0, 0x62, 0x6E, 0x57, 0x92, 0x9C, 0xC1, 0x61, 0x1C, 0x27, 0x35, 0x54, 0xCF, 0xFD, 0xA2, 0xE7, 0x4E,
0x3A, 0x7A, 0x33, 0x6C, 0x35, 0xC9, 0x57, 0xD4, 0x3E, 0x85, 0xB8, 0xF5, 0x1D, 0x9F, 0x4E, 0x94, 0x8A, 0x78, 0x23, 0x9C, 0x63, 0x80, 0x77, 0xA1, 0xE6, 0x80, 0x0E, 0x8B, 0x04, 0xDE, 0x5B, 0x69,
0xF7, 0x99, 0x1B, 0x27, 0xE5, 0x88, 0x1B, 0x15, 0xA8, 0xAB, 0xD8, 0x55, 0x61, 0xC0, 0xE3, 0x18, 0xF8, 0x7D, 0xA3, 0x89, 0xE5, 0x5A, 0x92, 0x43, 0x3D, 0x50, 0xD8, 0x27, 0x70, 0xB6, 0x35, 0x62,
0xF3, 0x11, 0x85, 0x7E, 0xFE, 0x74, 0xD2, 0x18, 0x67, 0xC4, 0x0C, 0x9C, 0x6C, 0xD1, 0xF5, 0x99, 0x5F, 0x14, 0xB1, 0x2F, 0x14, 0x76, 0x6D, 0xA8, 0x6D, 0x5D, 0x24, 0x6E, 0x86, 0xC7, 0x1D, 0x7D,
0x61, 0x58, 0xFF, 0xB0, 0x92, 0x85, 0x1E, 0x57, 0x33, 0x78, 0x2B, 0xD5, 0xB4, 0xDD, 0xC0, 0xCF, 0x3F, 0x98, 0xBE, 0x3A, 0xEA, 0xE8, 0x77, 0x47, 0x7A, 0x30, 0x11, 0xEE, 0xBA, 0xF0, 0x52, 0xC7,
0x47, 0x90, 0x44, 0xCB, 0xDF, 0xA7, 0x9F, 0x30, 0x7F, 0x20, 0x73, 0xDC, 0x3A, 0xAB, 0xF3, 0x29, 0xE5, 0x0B, 0xC2, 0xDD, 0x61, 0xA3, 0xFC, 0x72, 0x60, 0xEB, 0x62, 0xF1, 0xF8, 0x65, 0xBB, 0xAD,
0x08, 0xDF, 0x6B, 0x3C, 0x1B, 0x43, 0xA7, 0x65, 0x81, 0xAA, 0x73, 0x63, 0x4D, 0x8D, 0x6C, 0xC1, 0x51, 0xD5, 0xF5, 0xE4, 0xB0, 0x91, 0xBF, 0x75, 0xC1, 0x37, 0x01, 0x8D, 0x93, 0xE3, 0x0E, 0xC0,
0xA9, 0x8E, 0xF5, 0x54, 0x8E, 0x4B, 0xA3, 0x8A, 0xE6, 0x69, 0x6F, 0xC9, 0x62, 0x73, 0x8B, 0x6D, 0x4E, 0x48, 0xBB, 0xBD, 0x45, 0x96, 0x31, 0xFF, 0x2C, 0xD6, 0xD7, 0x58, 0x87, 0x89, 0xE3, 0xD1,
0x63, 0xC7, 0x3E, 0x4D, 0xB0, 0xC0, 0x60, 0x46, 0xC3, 0xBF, 0xB7, 0x22, 0xE0, 0xE8, 0x46, 0x25, 0x38, 0x1E, 0x36, 0xB2, 0x0B, 0xFD, 0x06, 0x49, 0x49, 0x6B, 0xC9, 0xDE, 0x27, 0xCE, 0x17, 0x26,
0x9F, 0x5E, 0x0F, 0xA4, 0x08, 0x84, 0xB1, 0xAB, 0x22, 0x9C, 0xE3, 0x24, 0x06, 0x38, 0xA4, 0x16, 0xAB, 0x84, 0xDB, 0x74, 0xE9, 0x70, 0xFB, 0xDA, 0xB4, 0xCC, 0xD8, 0x11, 0x41, 0x2C, 0x09, 0xBE,
0xDA, 0xC0, 0xDA, 0xAA, 0x1F, 0xB1, 0x63, 0x84, 0x20, 0xAE, 0xD2, 0x2C, 0x8C, 0x89, 0xC8, 0x30, 0x2E, 0xDB, 0x71, 0xE9, 0xD4, 0x80, 0x63, 0x18, 0xA3, 0xFE, 0xF6, 0x0D, 0x92, 0xA6, 0xBD, 0x1F,
0x73, 0x61, 0x16, 0xC9, 0xD4, 0xF5, 0x54, 0xD0, 0x0B, 0xB9, 0x0A, 0x05, 0xA6, 0xD8, 0x9E, 0x54, 0x3D, 0xFC, 0xF3, 0x16, 0x6F, 0x25, 0x1A, 0xCB, 0xF8, 0xA8, 0xD3, 0x69, 0xC0, 0x11, 0x76, 0xC9,
0xAB, 0x4F, 0xF1, 0x03, 0x8F, 0xA3, 0xC3, 0xE1, 0x03, 0x5F, 0xB3, 0x20, 0x92, 0x3C, 0xEE, 0x4D, 0x03, 0xE8, 0xAA, 0x6C, 0x4F, 0x38, 0x14, 0xDD, 0xDC, 0x9E, 0x0B, 0xC0, 0x3B, 0x24, 0x8D, 0xA3,
0x51, 0x51, 0xBD, 0x00, 0x65, 0xE1, 0xBA, 0xC0, 0x7C, 0xC0, 0x8D, 0x7A, 0x1E, 0x97, 0x32, 0x5A, 0xB7, 0xFD, 0x86, 0x89, 0xC5, 0x12, 0xEF, 0x7D, 0x02, 0x10, 0xE1, 0x9E, 0x4D, 0x46, 0x02, 0x77,
0xE0, 0xD3, 0x03, 0xDD, 0x4E, 0x68, 0x25, 0x25, 0xF7, 0x1F, 0xB4, 0xF7, 0xE0, 0x31, 0xDD, 0x5B, 0x67, 0x69, 0xAE, 0xB0, 0x60, 0x09, 0x7D, 0x19, 0xDB, 0x22, 0xF0, 0x59, 0x1C, 0x43, 0x4B, 0x81,
0xAD, 0x56, 0x3D, 0xB4, 0x3A, 0x5F, 0xBB, 0x74, 0x81, 0x54, 0xEC, 0x5F, 0x64, 0x03, 0x92, 0xD9, 0xD7, 0x37, 0xE9, 0xCF, 0x26, 0x19, 0x9E, 0x18, 0x02, 0x89, 0x4F, 0x73, 0x0C, 0xDB, 0xA5, 0x92,
0x31, 0x6B, 0xD3, 0xB4, 0x00, 0x69, 0x20, 0x54, 0xAB, 0xCC, 0x07, 0xCE, 0x51, 0xEB, 0x4E, 0x9B, 0xC2, 0x91, 0x10, 0x4E, 0x6B, 0x81, 0xC3, 0xC4, 0x94, 0xBC, 0xF7, 0xC4, 0xA4, 0x2E, 0xF8, 0x30,
0x5C, 0x8F, 0x4E, 0xEF, 0x34, 0x54, 0x4D, 0xD6, 0xCD, 0x75, 0x64, 0x87, 0x0E, 0x1C, 0xB4, 0xF9, 0xF0, 0x92, 0xC8, 0xFB, 0x75, 0xF2, 0x19, 0x8A, 0x29, 0x2C, 0x03, 0x82, 0xA4, 0x27, 0x67, 0x3D,
0x0C, 0x03, 0xCC, 0xA7, 0x61, 0x90, 0xB8, 0x74, 0x0B, 0x1D, 0x52, 0x3A, 0x39, 0xEC, 0x6F, 0xB3, 0x05, 0xE3, 0x12, 0xDF, 0xBA, 0x63, 0x37, 0x28, 0xD5, 0x8E, 0x23, 0xBC, 0xCD, 0xCB, 0xB9, 0xED,
0xB7, 0x41, 0x25, 0x6D, 0x42, 0xE9, 0x83, 0x5E, 0x56, 0x88, 0xB9, 0x69, 0x64, 0xFA, 0x94, 0xBB, 0x3B, 0xC7, 0x3E, 0x6E, 0x6D, 0x18, 0x45, 0x01, 0x33, 0xCB, 0x3B, 0xB6, 0x92, 0x2D, 0xF5, 0x6B,
0x7F, 0x85, 0xB8, 0xF9, 0x27, 0xCD, 0x70, 0x9B, 0x6B, 0x4F, 0x80, 0xE1, 0xE1, 0x2D, 0x70, 0x9E, 0x04, 0x5D, 0x3E, 0x54, 0x7B, 0xF8, 0x7B, 0xC7, 0x7D, 0x06, 0x2E, 0x5A, 0x66, 0xD9, 0xE9, 0x10,
0xDD, 0x26, 0x26, 0x7D, 0x28, 0x42, 0x94, 0xE4, 0x18, 0x48, 0x73, 0x44, 0xDA, 0xC2, 0x61, 0x87, 0x8F, 0xFB, 0x5C, 0x2A, 0x0C, 0x1E, 0xCC, 0x88, 0x14, 0x44, 0x04, 0x8C, 0x64, 0x4A, 0x83, 0x93,
0x8F, 0xE5, 0xA2, 0x92, 0x5B, 0x51, 0x1D, 0x5F, 0x9B, 0x4D, 0x45, 0xBE, 0xA8, 0xF8, 0xD8, 0xAE, 0x56, 0xB4, 0x26, 0x83, 0x2E, 0xF1, 0xE3, 0x6D, 0xBA, 0xB9, 0x94, 0x21, 0x5A, 0x70, 0xC6, 0xE5,
0xB0, 0x08, 0x28, 0x36, 0x8B, 0x33, 0xBF, 0xA8, 0x69, 0xFC, 0x67, 0xF2, 0xB4, 0x2E, 0x8E, 0x58, 0x3C, 0x99, 0xD8, 0x8E, 0xF0, 0x3B, 0x01, 0x13, 0x01, 0x87, 0x26, 0xA6, 0xE3, 0x89, 0xE5, 0xE7,
0x35, 0xB5, 0x53, 0xFF, 0x72, 0xD8, 0xDF, 0x94, 0xD4, 0x06, 0x66, 0x8C, 0xC9, 0xB9, 0xDF, 0xDE, 0xF8, 0x81, 0xC5, 0xE1, 0xA0, 0xFF, 0xC0, 0x56, 0xD4, 0x0F, 0x3D, 0x16, 0x77, 0x26, 0xA0, 0xC3,
0x7A, 0x52, 0xBB, 0xD3, 0x16, 0xBA, 0x8A, 0x90, 0xD4, 0x80, 0xA7, 0x8A, 0xC6, 0x17, 0x07, 0xAB, 0x8E, 0x0F, 0x32, 0xB1, 0x28, 0xC7, 0x7C, 0x80, 0xC5, 0x3A, 0x0E, 0xF3, 0xBC, 0x70, 0x0E, 0xBF,
0xCB, 0x46, 0xF4, 0x6F, 0x27, 0x0A, 0x13, 0x29, 0xB7, 0x1B, 0xC6, 0x1A, 0x3B, 0xD7, 0xD3, 0x36, 0x1E, 0xF0, 0xC5, 0x57, 0x24, 0x3C, 0x8F, 0xB9, 0x0F, 0x91, 0xF3, 0xE0, 0xD0, 0xA8, 0xB3, 0x5C,
0xF5, 0x62, 0x4B, 0x1F, 0xB7, 0x77, 0x06, 0x72, 0x9E, 0x5B, 0xCB, 0x92, 0x90, 0x55, 0x82, 0xAF, 0x2E, 0x3B, 0xE0, 0x1E, 0x6C, 0x65, 0xE3, 0x8B, 0xDC, 0x92, 0x0C, 0x79, 0x5A, 0x44, 0xD9, 0x2D,
0xB9, 0xFC, 0xC0, 0xC0, 0x3C, 0xB3, 0x49, 0xA6, 0xBC, 0xFE, 0x50, 0x69, 0x06, 0xC2, 0x59, 0x5D, 0xB9, 0x32, 0x36, 0x44, 0xA8, 0x91, 0x40, 0x2C, 0x53, 0x87, 0x39, 0x07, 0xA3, 0x58, 0x4D, 0xF4,
0x61, 0x4D, 0xE5, 0x70, 0xFE, 0xFE, 0x0F, 0xD8, 0x4F, 0x93, 0xFF, 0xFE, 0x5E, 0x6E, 0x12, 0x7C, 0x57, 0xD4, 0x86, 0x29, 0x2D, 0xA3, 0x13, 0x64, 0x7A, 0x53, 0x97, 0xB5, 0x09, 0x2C, 0x3E, 0x85,
0xCF, 0x9C, 0x2F, 0xA7, 0x73, 0x72, 0x9C, 0x4C, 0x52, 0x7B, 0x63, 0x12, 0x46, 0x49, 0xDE, 0x6A, 0x80, 0x76, 0xF1, 0x42, 0x1F, 0x39, 0xB5, 0x73, 0xBD, 0x62, 0xDE, 0x1B, 0x74, 0xEB, 0xDC, 0x42,
0xEC, 0x4A, 0xE8, 0x2D, 0xBA, 0xFB, 0xF9, 0x13, 0x63, 0x93, 0x7F, 0x6C, 0x6D, 0x21, 0xBD, 0xFF, 0x82, 0xE2, 0xEA, 0xB3, 0x35, 0xB8, 0x66, 0x2E, 0x76, 0x7D, 0x86, 0xDD, 0x48, 0xF2, 0x44, 0xF1,
0x2A, 0xD2, 0xFB, 0x2A, 0xA9, 0x2F, 0x34, 0xB7, 0xD0, 0xE7, 0x48, 0x0B, 0xA4, 0x2A, 0xE5, 0x2C, 0xB3, 0x47, 0xA7, 0xE6, 0x9A, 0xAC, 0x47, 0x20, 0xCE, 0x9C, 0x39, 0xB1, 0x8C, 0x2F, 0x34, 0xB2,
0xE1, 0xFA, 0x4F, 0xF6, 0xFE, 0x39, 0xBA, 0x0C, 0x65, 0x93, 0xEA, 0xFC, 0xCB, 0x54, 0xE7, 0x55, 0x07, 0x43, 0x4D, 0x78, 0x0C, 0xA2, 0x72, 0x06, 0x88, 0x35, 0x9C, 0x9E, 0x70, 0xCD, 0x92, 0xB9,
0xAA, 0xF5, 0x73, 0xF8, 0x35, 0x55, 0x3C, 0x3E, 0x87, 0x69, 0x4F, 0xBE, 0x97, 0xE5, 0xF2, 0x5E, 0x23, 0xF6, 0xF6, 0x2B, 0x83, 0x43, 0xA3, 0xC2, 0x5F, 0x16, 0xFC, 0x73, 0x57, 0x94, 0xF9, 0x18,
0x6F, 0x62, 0x38, 0xD7, 0x94, 0x94, 0xB3, 0xD4, 0x08, 0x91, 0x56, 0x73, 0xCD, 0xB0, 0xD7, 0x99, 0xF8, 0xB9, 0x4E, 0x5E, 0x96, 0xAC, 0xF3, 0x0E, 0xBD, 0xB4, 0x4D, 0xAC, 0xB2, 0x89, 0xB0, 0x12,
0x32, 0x6C, 0xDC, 0x31, 0x51, 0xC3, 0x51, 0x6E, 0xF8, 0x73, 0x31, 0x9B, 0x71, 0x8D, 0x9C, 0x70, 0x0C, 0x0C, 0xAF, 0x91, 0xB2, 0x95, 0x81, 0xE3, 0x31, 0x74, 0xC8, 0x9A, 0x73, 0x0D, 0x5E, 0x41,
0x8A, 0x84, 0x82, 0xB0, 0xB8, 0xD1, 0x3E, 0x95, 0x73, 0xA5, 0x31, 0x59, 0x07, 0x39, 0x3E, 0xC0, 0x38, 0xBC, 0x15, 0xD3, 0xCA, 0x87, 0x81, 0x65, 0xD5, 0x24, 0x12, 0x33, 0x61, 0x90, 0x78, 0x5E,
0xF4, 0x11, 0xCE, 0x98, 0x5C, 0xE2, 0x34, 0xF7, 0x0B, 0x8B, 0xE3, 0x12, 0x9E, 0xE7, 0x76, 0xCC, 0xBD, 0xC1, 0x94, 0x33, 0x64, 0xBA, 0xAA, 0x53, 0x77, 0x0B, 0xE4, 0xDC, 0x7B, 0xB7, 0xB5, 0x19,
0xBE, 0xAE, 0x08, 0xA2, 0x44, 0xC6, 0xD8, 0x94, 0x50, 0x2B, 0x9D, 0x68, 0x6E, 0x33, 0x3D, 0x5D, 0x6D, 0xD7, 0x30, 0x5D, 0xB7, 0xF4, 0xE0, 0x89, 0xEF, 0xC4, 0x20, 0xCE, 0xCF, 0x54, 0x2A, 0xDB,
0x66, 0xF6, 0x52, 0x19, 0x8B, 0x54, 0x8C, 0x27, 0x49, 0xD5, 0xE2, 0x84, 0xB8, 0x27, 0xF6, 0xFA, 0xBC, 0x15, 0x13, 0x3A, 0xCF, 0xF1, 0x00, 0x52, 0x85, 0x9C, 0x33, 0x72, 0xFE, 0xF1, 0x37, 0xF2,
0xF4, 0x75, 0x5F, 0xCD, 0x01, 0x36, 0x29, 0x7F, 0x50, 0xE6, 0x83, 0x58, 0x5F, 0x8D, 0xB6, 0x41, 0x1A, 0xEA, 0xCC, 0x39, 0x5F, 0xBC, 0xCE, 0xE9, 0x94, 0xB5, 0xA0, 0x5E, 0xA5, 0x8E, 0x9B, 0x11,
0x6F, 0xEA, 0xD0, 0xD9, 0xB5, 0x58, 0xDE, 0x5F, 0xD9, 0xDA, 0x84, 0x59, 0x77, 0xE8, 0xF6, 0x47, 0x5B, 0x79, 0x1D, 0x2B, 0x6C, 0x03, 0x71, 0x27, 0xAA, 0x48, 0x99, 0xB0, 0xD3, 0xF2, 0xD5, 0x2C,
0x28, 0xDE, 0x2D, 0xBA, 0xB0, 0x59, 0x68, 0x1E, 0x2F, 0x94, 0xF4, 0x81, 0x61, 0xA5, 0x5F, 0x08, 0x8A, 0xA4, 0x5E, 0xBA, 0x05, 0x61, 0x92, 0xB5, 0xC2, 0xB5, 0x85, 0x08, 0x5F, 0x34, 0xFE, 0x0E,
0xCC, 0x76, 0xE4, 0xD9, 0x91, 0x58, 0x2A, 0x03, 0x2C, 0xAB, 0x0C, 0x34, 0x6A, 0xD6, 0x2A, 0x56, 0x29, 0x82, 0x7D, 0x2A, 0x2E, 0xB8, 0xC5, 0x61, 0xFC, 0x24, 0x0E, 0x63, 0x03, 0x07, 0x97, 0x47,
0xE3, 0x73, 0x8B, 0xFD, 0x65, 0x85, 0x13, 0xBE, 0x04, 0x9C, 0xC5, 0x78, 0x42, 0x9F, 0xC6, 0xDB, 0x4C, 0x01, 0x77, 0x71, 0xC8, 0x91, 0x0C, 0x0C, 0xA6, 0x09, 0x8B, 0x7E, 0xA7, 0x1F, 0x77, 0x91,
0x24, 0x14, 0x26, 0x26, 0xF5, 0x12, 0xE3, 0xFB, 0x2E, 0x5B, 0x8B, 0xE7, 0x78, 0xB1, 0x15, 0x7B, 0xA7, 0x28, 0xB5, 0xC4, 0xE7, 0xFB, 0x89, 0xCF, 0x0D, 0xC4, 0xAB, 0x5D, 0x64, 0x26, 0x6D, 0xAD,
0x84, 0x99, 0x56, 0x81, 0x45, 0xFF, 0x68, 0xD1, 0xC1, 0xB9, 0x1F, 0x63, 0x6B, 0x0C, 0xA7, 0x30, 0x77, 0x11, 0x28, 0xE5, 0x14, 0x28, 0x46, 0x92, 0xB1, 0x08, 0xCB, 0x49, 0x9A, 0xD0, 0x49, 0x18,
0xB7, 0x11, 0xA9, 0xF1, 0x4C, 0x32, 0xE1, 0xD8, 0xC5, 0x48, 0x09, 0xA8, 0x6E, 0x31, 0x0F, 0x9F, 0x89, 0x59, 0x44, 0xFD, 0x16, 0x99, 0xD0, 0x18, 0x82, 0x15, 0x92, 0xF6, 0x51, 0x71, 0x81, 0x73,
0xE1, 0x18, 0x28, 0xCD, 0x01, 0xDB, 0x0B, 0xE2, 0x97, 0x5F, 0x41, 0xEE, 0xC7, 0xA0, 0x59, 0x88, 0x3E, 0x9D, 0xB2, 0x08, 0xD8, 0x71, 0xEA, 0x91, 0x9C, 0xF8, 0xE7, 0xF4, 0x8D, 0x29, 0x39, 0xF5,
0x25, 0x19, 0x23, 0xB9, 0x7A, 0xD6, 0xD8, 0x7D, 0x86, 0xD1, 0xA9, 0xC4, 0x6A, 0x4C, 0x3F, 0x86, 0x66, 0x22, 0x82, 0x32, 0xE3, 0x17, 0x69, 0x08, 0x99, 0xAC, 0xC9, 0x19, 0xF5, 0x16, 0x3C, 0x20,
0xA4, 0xB4, 0x38, 0x07, 0xF6, 0x5D, 0xF7, 0x60, 0x30, 0xFC, 0xB1, 0xBD, 0x57, 0xA5, 0xBA, 0xBD, 0x3F, 0x41, 0x6B, 0x53, 0x86, 0x65, 0xD5, 0x09, 0xEA, 0x87, 0xCD, 0xFD, 0x30, 0xF1, 0x62, 0x68,
0xF8, 0x70, 0x0D, 0x7F, 0x9C, 0xDE, 0xBC, 0x3F, 0x7D, 0x7B, 0x75, 0x31, 0xD9, 0x30, 0xCE, 0xB5, 0xE0, 0xF0, 0x24, 0x9E, 0x44, 0x4C, 0xD5, 0x2A, 0x7C, 0x2B, 0xDF, 0xD9, 0xC8, 0x9C, 0x17, 0x13,
0xE6, 0x01, 0x59, 0x2D, 0xC3, 0x46, 0x88, 0xD2, 0x58, 0x35, 0x71, 0x66, 0x6B, 0x03, 0xFA, 0x24, 0xD8, 0x5A, 0x48, 0x41, 0xD4, 0xD8, 0x42, 0x3F, 0x05, 0x11, 0x3E, 0xB5, 0x48, 0xFA, 0x6B, 0xDC,
0x2D, 0x92, 0x37, 0x26, 0x06, 0xA3, 0x3C, 0xA7, 0x75, 0xBA, 0x83, 0xE1, 0x9B, 0x7C, 0xAF, 0xED, 0x4A, 0xFD, 0x54, 0xCF, 0xE6, 0xBF, 0xC7, 0xDB, 0x39, 0x4B, 0x15, 0x9D, 0x6B, 0x21, 0xAF, 0xF9,
0x0C, 0x6F, 0x1A, 0x0C, 0xED, 0xD5, 0x70, 0xFB, 0xDB, 0x19, 0xA2, 0xA3, 0x4C, 0x22, 0xCE, 0xFD, 0xEA, 0xEA, 0xC7, 0x3A, 0xC8, 0x6D, 0x15, 0x32, 0xBD, 0xE1, 0x8B, 0xF1, 0x95, 0xAA, 0xC7, 0x50,
0x51, 0x71, 0x9E, 0x6B, 0xAB, 0x1F, 0x0B, 0x6C, 0x6A, 0xA4, 0xFC, 0xEC, 0x64, 0x48, 0x9E, 0x37, 0x59, 0xFA, 0x76, 0xF7, 0x47, 0xD8, 0xCC, 0x1D, 0xC4, 0x98, 0x9C, 0x47, 0x2C, 0x9E, 0x0B, 0xCF,
0xA1, 0x1F, 0x97, 0x46, 0xA5, 0x86, 0xDE, 0x32, 0x49, 0x2D, 0x1F, 0xD8, 0x1F, 0x9D, 0x60, 0xDA, 0x25, 0x14, 0xDA, 0x9F, 0x39, 0x87, 0xEC, 0x8D, 0xA1, 0x17, 0xF2, 0x85, 0x90, 0x84, 0xA6, 0x55,
0x5B, 0x81, 0xAF, 0xE9, 0xAE, 0x9E, 0x61, 0x0D, 0x4B, 0xAD, 0x41, 0x1C, 0xF1, 0x1F, 0xEA, 0x77, 0x10, 0x6F, 0x96, 0x2B, 0x55, 0x7A, 0xEB, 0xB9, 0x83, 0x83, 0x45, 0x81, 0x1B, 0x0C, 0x7C, 0x46,
0x80, 0x5F, 0x75, 0xFD, 0x62, 0x9C, 0x79, 0x89, 0xA4, 0xC4, 0x7C, 0x6E, 0xA9, 0x6E, 0x69, 0x3A, 0x63, 0xD0, 0x89, 0x8B, 0x17, 0xE0, 0x49, 0xC0, 0x65, 0x8C, 0xC6, 0x41, 0xE6, 0xE3, 0x36, 0x5D,
0xC9, 0x8E, 0xE7, 0x27, 0xD6, 0xA4, 0x45, 0xA4, 0x7E, 0x4C, 0xB3, 0x65, 0x41, 0x4E, 0x55, 0xCE, 0xF1, 0x7D, 0xFC, 0xE8, 0x92, 0xAE, 0xC9, 0x34, 0x12, 0xBE, 0x22, 0xF9, 0xA4, 0x48, 0x88, 0x35,
0x06, 0x13, 0x75, 0x1F, 0x1B, 0xCD, 0x07, 0x32, 0x7F, 0xA7, 0xF4, 0x8A, 0x69, 0xBF, 0x06, 0xAE, 0x1E, 0xC2, 0x39, 0x8C, 0x9C, 0x92, 0x99, 0x4A, 0x1D, 0x11, 0xEC, 0xCD, 0x4B, 0x18, 0xB4, 0x79,
0x58, 0x8D, 0x2E, 0x06, 0x6D, 0x4C, 0x5A, 0x7A, 0x2C, 0xB1, 0x38, 0x71, 0xB9, 0x74, 0x05, 0x9D, 0x9E, 0x47, 0xC0, 0x50, 0x7C, 0x16, 0xEC, 0xE1, 0xEA, 0x8B, 0x88, 0x11, 0xE8, 0xBA, 0x90, 0x67,
0x7E, 0x1F, 0x40, 0x44, 0x3F, 0x8A, 0xBD, 0x93, 0x8A, 0x99, 0x14, 0xAF, 0xDD, 0xA8, 0x4E, 0x15, 0xF6, 0xDA, 0xFC, 0x75, 0x4C, 0x22, 0x1A, 0x40, 0x4B, 0x02, 0x69, 0xA7, 0xB8, 0xEF, 0xD8, 0xDE,
0x83, 0xED, 0xE0, 0xD5, 0x85, 0x14, 0x98, 0xF1, 0xAC, 0xFE, 0x0E, 0x01, 0x1C, 0xD3, 0xC7, 0xA6, 0xC3, 0xEC, 0xD4, 0x83, 0x6E, 0x04, 0xBF, 0xC6, 0xD2, 0xF4, 0x70, 0x32, 0xE8, 0xDA, 0xF6, 0x61,
0xCC, 0x37, 0xD4, 0x57, 0xC6, 0xFC, 0x1B, 0x65, 0xDE, 0xBD, 0xCF, 0xD7, 0xC9, 0xF9, 0x75, 0x67, 0xAF, 0xFF, 0x7D, 0xF3, 0xC5, 0x36, 0xE5, 0xDD, 0xC5, 0xF5, 0x0D, 0xF9, 0xED, 0xF4, 0xF6, 0xE3,
0x7E, 0xAA, 0x99, 0xCE, 0x3A, 0x42, 0x66, 0xB6, 0x1D, 0x16, 0xBB, 0x4F, 0x2D, 0x86, 0x23, 0xE3, 0xE9, 0xFB, 0xAB, 0x8B, 0x91, 0xD1, 0x70, 0x37, 0x11, 0xF3, 0xD1, 0xAA, 0x88, 0x0E, 0x43, 0x11,
0x42, 0x2B, 0x63, 0x24, 0x2F, 0xDD, 0xA9, 0x7E, 0xA6, 0xEA, 0xDB, 0xAB, 0x34, 0x43, 0xDA, 0xAB, 0x41, 0xBB, 0x80, 0x57, 0x53, 0x04, 0x5C, 0x1C, 0x21, 0xE8, 0xDC, 0x89, 0x84, 0xC4, 0x92, 0x11,
0x53, 0x94, 0x69, 0xB4, 0x85, 0xE4, 0xA6, 0x46, 0x72, 0xB3, 0x49, 0x52, 0x95, 0xF3, 0x37, 0x6C, 0x5A, 0xED, 0x5E, 0xFF, 0x6D, 0xB6, 0x60, 0x3D, 0xC7, 0xDB, 0x22, 0x47, 0xF5, 0xF9, 0x43, 0xF3,
0x99, 0xBC, 0xC2, 0xCD, 0xB2, 0x04, 0x11, 0xA8, 0x24, 0x34, 0x55, 0xAC, 0x2E, 0x96, 0x06, 0x2C, 0xEB, 0x38, 0x82, 0x0B, 0x8D, 0x42, 0xC6, 0x5C, 0xC5, 0xEF, 0x46, 0x29, 0x4A, 0x8D, 0xB7, 0xD5,
0x12, 0x73, 0xB3, 0xA0, 0xF4, 0x92, 0x62, 0x39, 0x45, 0x00, 0xB5, 0xCB, 0xBA, 0xB2, 0xD3, 0x1D, 0xB2, 0x79, 0x76, 0xF2, 0x43, 0x97, 0x1C, 0xE1, 0x67, 0x6E, 0x8A, 0xDF, 0x7B, 0xEA, 0x61, 0x43,
0x2D, 0x93, 0xB7, 0x32, 0x9B, 0x16, 0x0A, 0x26, 0xCB, 0x38, 0x0B, 0x08, 0xA7, 0x88, 0x9E, 0x6D, 0x4C, 0xD4, 0x87, 0x6F, 0x64, 0xD2, 0x59, 0x12, 0x37, 0xC2, 0xAF, 0x55, 0x28, 0x94, 0x63, 0x6D,
0xDC, 0xEE, 0x1B, 0xDC, 0x8A, 0xAD, 0xE9, 0xA8, 0x64, 0x88, 0x52, 0x0F, 0x05, 0x1F, 0x32, 0xA6, 0x14, 0xE4, 0x07, 0xFF, 0x83, 0x8A, 0x7B, 0xF0, 0x4F, 0x55, 0xC5, 0x10, 0xB0, 0x4E, 0xE2, 0x61,
0xBD, 0xE7, 0x66, 0xD3, 0xD8, 0xC9, 0xCA, 0xCA, 0x49, 0xA5, 0x3C, 0xB4, 0xE9, 0x27, 0x15, 0x6B, 0x41, 0x39, 0x57, 0x94, 0x77, 0x78, 0x82, 0x4C, 0xF7, 0xE7, 0x26, 0xCA, 0xBA, 0x79, 0xD8, 0x7F,
0x5D, 0x67, 0x60, 0x9D, 0xA4, 0x89, 0xDC, 0xAB, 0x22, 0x8F, 0x76, 0x04, 0x26, 0x36, 0xA0, 0x58, 0xD2, 0x29, 0xBA, 0xC4, 0x02, 0x8B, 0x76, 0x16, 0x8E, 0xD8, 0x7F, 0x19, 0xDB, 0x2F, 0x58, 0xE7,
0x38, 0x51, 0xCF, 0x74, 0xA6, 0xF3, 0x22, 0xB6, 0x6D, 0x26, 0xA9, 0xD9, 0xE6, 0x43, 0xE6, 0x9F, 0x83, 0x88, 0x96, 0x34, 0x72, 0x2B, 0xA0, 0x82, 0x0D, 0x21, 0xC6, 0xB2, 0x10, 0x57, 0x9C, 0xA0,
0xE9, 0x5E, 0x95, 0xD3, 0xBE, 0xAA, 0xD9, 0xF7, 0xA0, 0x72, 0x80, 0x57, 0x55, 0x1D, 0x8F, 0x9A, 0x85, 0x80, 0x93, 0xBB, 0x8D, 0x9F, 0x4A, 0xE8, 0x7F, 0x0F, 0x49, 0x88, 0x5F, 0xEA, 0x7D, 0xF0,
0xDC, 0x6E, 0xBE, 0xC8, 0xED, 0xA6, 0xC9, 0xAD, 0x5B, 0x65, 0xB7, 0x57, 0x99, 0xFD, 0xB2, 0x8B, 0x04, 0x95, 0x79, 0x36, 0x30, 0xD4, 0xDF, 0x82, 0x15, 0x6B, 0x79, 0xB6, 0x37, 0xF3, 0x29, 0xFB,
0x0F, 0xAB, 0x01, 0xFB, 0x9B, 0xA1, 0x53, 0x88, 0xFC, 0x0A, 0x86, 0xEE, 0xEB, 0xD7, 0x6D, 0x1A, 0xED, 0x6F, 0x58, 0x18, 0xA4, 0x28, 0xF3, 0x5E, 0x6E, 0xB1, 0x0B, 0x8F, 0xD9, 0x57, 0xED, 0x65,
0x99, 0x3B, 0x34, 0x4F, 0x6F, 0xE2, 0xDC, 0xE4, 0x38, 0xA3, 0x54, 0x39, 0x54, 0x6C, 0x8B, 0x02, 0xDF, 0xBA, 0x4F, 0x95, 0xFF, 0x39, 0x3A, 0x79, 0xAC, 0x58, 0x5D, 0x79, 0x50, 0x6A, 0xF1, 0x1A,
0x9F, 0x72, 0x8E, 0xD3, 0x52, 0xAB, 0x95, 0x9F, 0x60, 0x57, 0x49, 0xD6, 0x1F, 0xA4, 0x29, 0x70, 0x63, 0x8F, 0xB5, 0xB1, 0xF1, 0xEE, 0x23, 0x12, 0x52, 0x7A, 0xAC, 0xEC, 0x8B, 0xE5, 0xBD, 0x5A,
0xB8, 0x57, 0x09, 0x1D, 0x6C, 0xA9, 0xDF, 0xD3, 0x8F, 0x43, 0x58, 0xF2, 0x9C, 0xFA, 0xD5, 0x8D, 0xC5, 0xE1, 0x41, 0x9E, 0x9F, 0x9B, 0xEA, 0xDD, 0x74, 0x65, 0x8F, 0xE5, 0xFD, 0x59, 0xC5, 0xA1,
0xED, 0x8E, 0xCB, 0x5E, 0x01, 0x6B, 0x9B, 0xBD, 0x6D, 0xA2, 0xEB, 0xB2, 0xEC, 0xF9, 0xDE, 0x69, 0x91, 0x76, 0x5B, 0xFA, 0x5F, 0xA0, 0xA5, 0x74, 0x72, 0xBF, 0x4D, 0x93, 0x8F, 0x2F, 0x92, 0xAD,
0x63, 0x30, 0x52, 0x9B, 0x7C, 0x68, 0x7F, 0xD1, 0xDC, 0x2B, 0x7B, 0x61, 0xBA, 0x1F, 0xA1, 0xFF, 0x37, 0x83, 0x80, 0xD9, 0x86, 0xE2, 0x05, 0x65, 0x6C, 0x26, 0xE7, 0x98, 0xBE, 0x34, 0xA6, 0x95,
0x48, 0xF0, 0x1F, 0x50, 0x6D, 0xCF, 0xB3, 0x60, 0x20, 0x00, 0x00 0x87, 0x64, 0x73, 0x53, 0xFD, 0x76, 0xFA, 0xB8, 0x62, 0xF4, 0xDE, 0x4B, 0x4F, 0x64, 0x39, 0xA3,
0x45, 0x9C, 0x46, 0x9B, 0x95, 0x07, 0xA5, 0x89, 0xE3, 0xD8, 0xC0, 0x31, 0x17, 0xA1, 0x60, 0xDF,
0xB2, 0x8E, 0x72, 0x96, 0x88, 0x81, 0xDF, 0x41, 0xD0, 0x49, 0x5E, 0x01, 0x41, 0x37, 0x27, 0xC5,
0xDA, 0xF4, 0x8E, 0xA4, 0x1E, 0xA1, 0xFD, 0xAB, 0x8A, 0xDD, 0x29, 0x60, 0x57, 0xD5, 0xB9, 0x49,
0x01, 0xD0, 0xB9, 0x43, 0xBD, 0x07, 0x43, 0xE0, 0x26, 0xCF, 0xF3, 0x4C, 0xA2, 0xB2, 0x56, 0xC5,
0x82, 0xD7, 0xA9, 0xE9, 0xF5, 0xAA, 0x05, 0x15, 0x1C, 0x94, 0x9C, 0xE3, 0xB0, 0xB0, 0x95, 0x83,
0x42, 0x3A, 0x34, 0xF1, 0xBB, 0xDD, 0xCB, 0xEF, 0x76, 0x8B, 0x5F, 0xBB, 0xC0, 0xB0, 0xC4, 0x31,
0xBD, 0x0B, 0x53, 0xCA, 0x50, 0x1F, 0xE9, 0x59, 0xB9, 0xCC, 0x07, 0xA4, 0x6F, 0xBF, 0x79, 0xD3,
0xC4, 0x1B, 0x8D, 0x16, 0x5E, 0x77, 0x54, 0x71, 0x6E, 0x2B, 0x38, 0x9B, 0x3E, 0xA3, 0x3A, 0x35,
0x56, 0xA9, 0x18, 0xDB, 0x82, 0xBC, 0x69, 0xD1, 0xAB, 0xC7, 0xBA, 0x29, 0x88, 0x84, 0x9B, 0x40,
0x83, 0x8E, 0x7E, 0xD3, 0xD3, 0x99, 0xB9, 0x9F, 0x8B, 0x5A, 0x08, 0x4D, 0x38, 0xC8, 0x7C, 0xC4,
0x4F, 0xA2, 0xA0, 0x38, 0x5B, 0xF5, 0x37, 0x8C, 0xEA, 0x5C, 0xB2, 0xE9, 0x89, 0xB0, 0xA7, 0x57,
0x77, 0xB5, 0xF8, 0x62, 0x20, 0x1B, 0x8C, 0x71, 0xA0, 0xC5, 0xCB, 0x61, 0x9B, 0x21, 0x40, 0x8B,
0x2F, 0x5D, 0xE0, 0x10, 0x33, 0xC8, 0x3F, 0x19, 0xD8, 0x9C, 0x50, 0x8E, 0x3B, 0xFA, 0x43, 0xED,
0xFF, 0x00, 0x02, 0x3A, 0x03, 0x88, 0xC1, 0x2D, 0x00, 0x00
}; };

View File

@@ -2,5 +2,5 @@
#include <Arduino.h> #include <Arduino.h>
//declare here, define in cpp to prevent multiple declarations //declare here, define in cpp to prevent multiple declarations
#define web_smars_html_gz_len 2875 #define web_smars_html_gz_len 3098
extern const uint8_t web_smars_html_gz[] PROGMEM; extern const uint8_t web_smars_html_gz[] PROGMEM;

View File

@@ -2,7 +2,8 @@
#include <Arduino.h> #include <Arduino.h>
#include <vector> #include <vector>
#include "ESP32MotorControl.h" //#include "ESP32MotorControl.h"
#include "Cdrv8833.h"
#include <ESP32Servo.h> //by Kevin Harrington #include <ESP32Servo.h> //by Kevin Harrington
@@ -12,17 +13,12 @@
#define LEFT_MOTOR 0 #define LEFT_MOTOR 0
#define ARM_MOTOR 2 #define ARM_MOTOR 2
#define FORWARD 1
#define BACKWARD -1
#define UP 1 #define SERVOSTEP 5
#define DOWN 2 #define SERVOMIN 0
#define LEFT 3 #define SERVOMAX 180
#define RIGHT 4
#define ARMUP 5
#define ARMDOWN 6
#define STOP 0
#define BUCKETTIMER 100
struct MOTOR_PINS struct MOTOR_PINS
{ {
@@ -33,11 +29,6 @@ struct MOTOR_PINS
//general functions //general functions
void setupmotors(); void setupmotors();
void loop_motors(); void loop_motors();
//void moveCar(int inputValue, bool horizontal);
//motor functions
//void rotateMotor(int motorNumber, int motorDirection);
//void setMomentum(bool val);
void drivemotor(uint8_t num, int dirspeed); void drivemotor(uint8_t num, int dirspeed);
@@ -45,12 +36,20 @@ void drivemotor(uint8_t num, int dirspeed);
//Servo functions //Servo functions
void bucketTilt(int bucketServoValue); void bucketTilt(int bucketServoValue);
void auxControl(int auxServoValue); void auxControl(int auxServoValue);
void AbsBucketTilt(int bucketServoValue);
class motor: public ESP32MotorControl
class motor: public Cdrv8833
{ {
const uint8_t motorindex = 0; const uint8_t motorindex = 0;
public: public:
uint8_t m_index;
uint8_t m_index;
int prevsetpoint = 0;
void drive(int dirspeed); void drive(int dirspeed);
void setindex(uint8_t index) void setindex(uint8_t index)

View File

@@ -5,15 +5,24 @@ WebsocketsServer server;
AsyncWebServer webserver(80); AsyncWebServer webserver(80);
WebsocketsClient client; WebsocketsClient client;
int LValue, RValue, commaIndex; //int LValue, RValue, ArmValue, commaIndex;
// handle http messages // handle http messages
void handle_message(WebsocketsMessage msg) { void handle_message(WebsocketsMessage msg) {
commaIndex = msg.data().indexOf(','); log_i("%s", msg.data());
LValue = msg.data().substring(0, commaIndex).toInt(); uint8_t commaIndex = msg.data().indexOf(',');
RValue = msg.data().substring(commaIndex + 1).toInt(); int LValue = msg.data().substring(0, commaIndex).toInt();
commaIndex = msg.data().indexOf(',',commaIndex+1);
int RValue = msg.data().substring(commaIndex + 1).toInt();
commaIndex = msg.data().indexOf(',',commaIndex+1);
int ArmValue = msg.data().substring(commaIndex + 1).toInt();
commaIndex = msg.data().indexOf(',',commaIndex+1);
int bucketValue = msg.data().substring(commaIndex + 1).toInt();
drivemotor(0, LValue); drivemotor(0, LValue);
drivemotor(1, RValue); drivemotor(1, RValue);
drivemotor(2, ArmValue);
bucketTilt(bucketValue);
} }
void setup_webserver() void setup_webserver()
@@ -35,11 +44,17 @@ void setup_webserver()
} }
uint32_t webservertimer = 0;
void loop_webserver() void loop_webserver()
{ {
if (client.available()) { if(millis() - webservertimer > WEBSERVER_LOOP)
client.poll(); {
delay(50); if (client.available())
{
client.poll();
}
webservertimer = millis();
} }
} }

View File

@@ -11,6 +11,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#define WEBSERVER_LOOP 50
void loop_webserver(); void loop_webserver();
void setup_webserver(); void setup_webserver();

278
FW/web_smars.html Normal file
View File

@@ -0,0 +1,278 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta charset="utf-8" />
<title>Mini Skidi</title>
<style>
/* #container {
width: 100%;
height: 49vh;
background-color: #333;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border-radius: 7px;
touch-action: none;
} */
#outerContainer {
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
.le-stick {
width: 300px;
height: 300px;
}
/* #item {
width: 100px;
height: 100px;
background-color: rgb(245, 230, 99);
border: 10px solid rgba(136, 136, 136, 0.5);
border-radius: 50%;
touch-action: none;
user-select: none;
}
#item:active {
background-color: rgba(168, 218, 220, 1);
}
#item:hover {
cursor: pointer;
border-width: 20px;
}
#area {
position: fixed;
right: 0;
top: 0;
} */
</style>
<script type="text/javascript">
var JoyStick = function (t, e) {
var i = void 0 === (e = e || {}).title ? "joystick" : e.title,
n = void 0 === e.width ? 0 : e.width,
o = void 0 === e.height ? 0 : e.height,
h = void 0 === e.internalFillColor ? "#00AA00" : e.internalFillColor,
r = void 0 === e.internalLineWidth ? 2 : e.internalLineWidth,
d = void 0 === e.internalStrokeColor ? "#003300" : e.internalStrokeColor,
a = void 0 === e.externalLineWidth ? 2 : e.externalLineWidth,
l = void 0 === e.externalStrokeColor ? "#008000" : e.externalStrokeColor,
c = document.getElementById(t),
u = document.createElement("canvas");
(u.id = i), 0 == n && (n = c.clientWidth), 0 == o && (o = c.clientHeight), (u.width = n), (u.height = o), c.appendChild(u);
var s = u.getContext("2d"),
f = 0,
v = 2 * Math.PI,
g = (u.width - 110) / 2,
w = g + 5,
C = g + 30,
m = u.width / 2,
p = u.height / 2,
L = u.width / 10,
E = -1 * L,
S = u.height / 10,
k = -1 * S,
W = m,
G = p;
function x() {
s.beginPath(), s.arc(m, p, C, 0, v, !1), (s.lineWidth = a), (s.strokeStyle = l), s.stroke();
}
function y() {
s.beginPath(), W < g && (W = w), W + g > u.width && (W = u.width - w), G < g && (G = w), G + g > u.height && (G = u.height - w), s.arc(W, G, g, 0, v, !1);
var t = s.createRadialGradient(m, p, 5, m, p, 200);
t.addColorStop(0, h), t.addColorStop(1, d), (s.fillStyle = t), s.fill(), (s.lineWidth = r), (s.strokeStyle = d), s.stroke();
}
"ontouchstart" in document.documentElement
? (u.addEventListener(
"touchstart",
function (t) {
f = 1;
},
!1
),
u.addEventListener(
"touchmove",
function (t) {
t.preventDefault(), 1 == f && ((W = t.touches[0].pageX), (G = t.touches[0].pageY), (W -= u.offsetLeft), (G -= u.offsetTop), s.clearRect(0, 0, u.width, u.height), x(), y());
},
!1
),
u.addEventListener(
"touchend",
function (t) {
(f = 0), (W = m), (G = p), s.clearRect(0, 0, u.width, u.height), x(), y();
},
!1
))
: (u.addEventListener(
"mousedown",
function (t) {
f = 1;
},
!1
),
u.addEventListener(
"mousemove",
function (t) {
1 == f && ((W = t.pageX), (G = t.pageY), (W -= u.offsetLeft), (G -= u.offsetTop), s.clearRect(0, 0, u.width, u.height), x(), y());
},
!1
),
u.addEventListener(
"mouseup",
function (t) {
(f = 0), (W = m), (G = p), s.clearRect(0, 0, u.width, u.height), x(), y();
},
!1
)),
x(),
y(),
(this.GetWidth = function () {
return u.width;
}),
(this.GetHeight = function () {
return u.height;
}),
(this.GetPosX = function () {
return W;
}),
(this.GetPosY = function () {
return G;
}),
(this.GetX = function () {
return (((W - m) / w) * 100).toFixed();
}),
(this.GetY = function () {
return (((G - p) / w) * 100 * -1).toFixed();
}),
(this.GetDir = function () {
var t = "",
e = W - m,
i = G - p;
return i >= k && i <= S && (t = "C"), i < k && (t = "N"), i > S && (t = "S"), e < E && ("C" == t ? (t = "W") : (t += "W")), e > L && ("C" == t ? (t = "E") : (t += "E")), t;
});
};
</script>
</head>
<body>
<div id="outerContainer">
<!-- <div style="height: 40vh;"></div> -->
<div id="joyMove" class="le-stick" ></div>
<div id="joyBucket" class="le-stick"></div>
</div>
<script>
const view = document.getElementById("stream");
const WS_URL = "ws://" + window.location.host + ":82";
const ws = new WebSocket(WS_URL);
ws.onmessage = (message) => {
if (message.data instanceof Blob) {
var urlObject = URL.createObjectURL(message.data);
view.src = urlObject;
}
};
var lastText, lastSend, sendTimeout;
// limit sending to one message every 30 ms
// https://github.com/neonious/lowjs_esp32_examples/blob/master/neonious_one/cellphone_controlled_rc_car/www/index.html
function send(txt) {
var now = new Date().getTime();
if (lastSend === undefined || now - lastSend >= 30) {
try {
ws.send(txt);
lastSend = new Date().getTime();
return;
} catch (e) {
console.log(e);
}
}
lastText = txt;
if (!sendTimeout) {
var ms = lastSend !== undefined ? 30 - (now - lastSend) : 30;
if (ms < 0) ms = 0;
sendTimeout = setTimeout(() => {
sendTimeout = null;
send(lastText);
}, ms);
}
}
</script>
</body>
<script type="text/javascript">
// Create JoyStick object into the DIV 'joyDiv'
var move = new JoyStick("joyMove");
var bucket = new JoyStick("joyBucket")
// var inputPosX = document.getElementById("posizioneX");
// var inputPosY = document.getElementById("posizioneY");
// var direzione = document.getElementById("direzione");
// var fuerzaI = document.getElementById("fuerzaI");
// var fuerzaD = document.getElementById("fuerzaD");
// var x = document.getElementById("X");
// var y = document.getElementById("Y");
//Steering control program, based on :
// Differential Steering Joystick Algorithm
// by Calvin Hass
// https://www.impulseadventure.com/elec/
function getparams(MoveJoyX, MoveJoyY, bucketJoyX, bucketJoyY) {
var nMotMixL;
var nMotMixR;
var fPivYLimit = 32.0; //The threshold at which the pivot action starts
// This threshold is measured in units on the Y-axis
// away from the X-axis (Y=0). A greater value will assign
// more of the joystick's range to pivot actions.
// Allowable range: (0..+127)
// TEMP VARIABLES
var nMotPremixL; // Motor (left) premixed output (-128..+127)
var nMotPremixR; // Motor (right) premixed output (-128..+127)
var nPivSpeed; // Pivot Speed (-128..+127)
var fPivScale; // Balance scale b/w drive and pivot ( 0..1 )
// Calculate Drive Turn output due to Joystick X input
if (MoveJoyY >= 0) {
// Forward
nMotPremixL = MoveJoyX >= 0 ? 100.0 : 100.0 + parseFloat(MoveJoyX);
nMotPremixR = MoveJoyX >= 0 ? 100.0 - MoveJoyX : 100.0;
} else {
// Reverse
nMotPremixL = MoveJoyX >= 0 ? 100.0 - MoveJoyX : 100.0;
nMotPremixR = MoveJoyX >= 0 ? 100.0 : 100.0 + parseFloat(MoveJoyX);
}
// Scale Drive output due to Joystick Y input (throttle)
nMotPremixL = (nMotPremixL * MoveJoyY) / 100.0;
nMotPremixR = (nMotPremixR * MoveJoyY) / 100.0;
// Now calculate pivot amount
// - Strength of pivot (nPivSpeed) based on Joystick X input
// - Blending of pivot vs drive (fPivScale) based on Joystick Y input
nPivSpeed = MoveJoyX;
fPivScale = Math.abs(MoveJoyY) > fPivYLimit ? 0.0 : 1.0 - Math.abs(MoveJoyY) / fPivYLimit;
// Calculate final mix of Drive and Pivot
nMotMixL = (1.0 - fPivScale) * nMotPremixL + fPivScale * nPivSpeed;
nMotMixR = (1.0 - fPivScale) * nMotPremixR + fPivScale * -nPivSpeed;
return Math.round(nMotMixL * 2.55) + "," + Math.round(nMotMixR * 2.55) + "," + bucketJoyX + "," + bucketJoyY; // The function returns the product of p1 and p2
}
setInterval(function () {
send(getparams(move.GetX(), move.GetY(), bucket.GetX(), bucket.GetY()));
}, 300);
</script>
</html>