Browse Source

Basic monochrome example OK.

v0.9.4
Guy Turcotte 2 years ago
parent
commit
532fe2a39b
  1. 48
      README.md
  2. 2
      lib/drivers/src/eink.hpp
  3. 242
      lib/drivers/src/eink_10.cpp
  4. 5
      lib/drivers/src/eink_10.hpp
  5. 117
      lib/drivers/src/eink_6.cpp
  6. 2
      lib/drivers/src/inkplate_platform.hpp
  7. 28
      lib/graphical/src/graphics.cpp
  8. 6
      lib/graphical/src/graphics.hpp
  9. 249
      lib/graphical/src/shapes_polygon.cpp
  10. 336
      src/image.hpp
  11. 357
      src/main.cpp

48
README.md

@ -1,4 +1,4 @@
# ESP-IDF-InkPlate
# ESP-IDF-InkPlate Version 0.9.0
A porting effort to the ESP-IDF framework for the e-Radionica InkPlate software that can be find [here](https://github.com/e-radionicacom/Inkplate-Arduino-library).
@ -6,7 +6,7 @@ A porting effort to the ESP-IDF framework for the e-Radionica InkPlate software
Beware that these classes are **not** re-entrant. That means that it is not possible to use them in a multi-thread context without proper mutual exclusion access control.
This project is a working example. You can build it using PlatformIO. It will draw a square and a straight line on the device display.
This project is a working example. You can build it using PlatformIO.
## Modifications done to the Arduino Inkplate Source code
@ -33,11 +33,33 @@ Some of these changes have been done partially and will be completed in subseque
- variables and method names are in lower_case
- all graphical libraries and class remains with their Arduino naming convention
- classes inheritence are reduced to insure independance of usage of the drivers group. By design, the grapphical portion remains as defined for the Arduino framework with some internal transformation to be more inline with C++.
- A TAG is added in the protected/private portion of driver classes in support of the ESP-IDF Logging mechanism (ESP_LOGX defines)
- A TAG is added in the protected/private portion of driver classes in support of the ESP-IDF Logging mechanism (ESP_LOGx defines)
- min() definition replaced with std::min()
- _swap...() definitions replaced with std::swap()
- String replaced with std::string (No PROGMEM support required with the ESP32)
### defines.hpp
The content is now at a bare minimum: DisplayMode enum class that defines both INKPLATE_1BIT and INKPLATE_3BIT modes. Also, BLACK and WHITE values for INKPLATE_1BIT mode.
As the DisplayMode is an enum class, it is then required to access the values as follow:
- DisplayMode::INKPLATE_1BIT
- DisplayMode::INKPLATE_3BIT
### graphics (.hpp, .cpp)
The class is now the owner of the _partial and DMemory4Bit frame buffers. As such, methods that where defined in Inkplate.hpp are relocated into that class, namely:
- clearDisplay()
- display()
- preloadScreen()
- partialUpdate()
They select the appropriate frame buffer and call the e_ink class methods.
This change is mostly transparent for the user application.
### SdCard
- The module is used only to initialize the ESP-IDF drivers (SPI and FAT filesystem are used). The card can then be accessed through the standard C++/C capabilities. All filenames located on the card must be prefixed with `/sdcard/`.
@ -48,6 +70,26 @@ Some of these changes have been done partially and will be completed in subseque
- the `bool drawXXXXFromSd(SdFile *p, ...)` methods are renamed `bool drawXXXXFromFile(FILE *p, ...)`. This allow for accessing files located in a SPIFFS partition (using `/spiffs/` filename prefix) as well as SDCard files (using `/sdcard/` filename prefix) or any other file system integrated with ESP-IDF.
- functions-like related to image / pixel manipulation present in `defines.h` have been migrated here. Namely: RED, BLUE, GREEN, READ32, READ16, ROWSIZE, RGB8BIT, RGB3BIT. They are now inline functions with appropriate types named red, blue, green, read32, read16, rowSize, rgb8Bit, rgb3Bit.
### mcp23017 (.hpp, .cpp)
This class is implementing a generic MCP23017 driver. It is instanciated in the inkplate_platform.hpp, depending on the type of Inkplate device:
- as mcp_int (for all Inkplate devices)
- as mcp_ext (for the Inkplate-10, and Inkplate-6).
### battery, touch_keys (.hpp, .cpp)
Those classes implement basic access to the battery and touch keys state.
### system class renamed InkplatePlatform
This name reflect more what it is. This class will is currently under eavy changes.
### FrameBuffer classes
A hierarchy of frame buffer classes has been added. These allow for flexible adaptation to the different
geometry of devices and pixel sizes.
## ESP-IDF configuration specifics for InkPlate devices
An InkPlate application requires some functionalities to be properly set up within the ESP-IDF. The following elements have been done for this project and can be used as a reference for other projects:

2
lib/drivers/src/eink.hpp

@ -85,6 +85,8 @@ class EInk
uint8_t * p_buffer;
FrameBuffer1Bit * d_memory_new;
uint32_t * GLUT;
uint32_t * GLUT2;
const MCP23017::Pin OE = MCP23017::Pin::IOPIN_0;
const MCP23017::Pin GMOD = MCP23017::Pin::IOPIN_1;

242
lib/drivers/src/eink_10.cpp

@ -3,7 +3,7 @@ eink.cpp
Inkplate 10 ESP-IDF
Modified by Guy Turcotte
December 23, 2020
December 27, 2020
from the Arduino Library:
@ -20,7 +20,7 @@ If you have any questions about licensing, please contact techsupport@e-radionic
Distributed as-is; no warranty is given.
*/
#ifdef INKPLATE_10
#if defined(INKPLATE_10)
#define __EINK10__ 1
#include "eink_10.hpp"
@ -39,12 +39,6 @@ const uint8_t EInk10::WAVEFORM_3BIT[8][8] = {
{0, 2, 1, 2, 2, 2, 1, 0}, {2, 2, 2, 2, 2, 2, 1, 0},
{0, 0, 0, 0, 2, 1, 2, 0}, {0, 0, 2, 2, 2, 2, 2, 0}};
// {
// {0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0},
// {0, 1, 2, 1, 1, 2, 1, 0}, {0, 2, 1, 2, 1, 2, 1, 0},
// {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0},
// {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0} };
const uint8_t EInk10::LUT2[16] = {
0xAA, 0xA9, 0xA6, 0xA5, 0x9A, 0x99, 0x96, 0x95,
0x6A, 0x69, 0x66, 0x65, 0x5A, 0x59, 0x56, 0x55 };
@ -100,6 +94,21 @@ EInk10::setup()
wakeup_clear();
// Set all pins of seconds I/O expander to outputs, low.
// For some reason, it draw more current in deep sleep when pins are set as inputs...
for (int i = 0; i < 15; i++) {
mcp_ext.set_direction((MCP23017::Pin) i, MCP23017::PinMode::OUTPUT);
mcp_ext.digital_write((MCP23017::Pin) i, MCP23017::SignalLevel::LOW);
}
// For same reason, unused pins of first I/O expander have to be also set as outputs, low.
mcp_int.set_direction(MCP23017::Pin::IOPIN_13, MCP23017::PinMode::OUTPUT);
mcp_int.set_direction(MCP23017::Pin::IOPIN_14, MCP23017::PinMode::OUTPUT);
mcp_int.set_direction(MCP23017::Pin::IOPIN_15, MCP23017::PinMode::OUTPUT);
mcp_int.digital_write(MCP23017::Pin::IOPIN_13, MCP23017::SignalLevel::LOW);
mcp_int.digital_write(MCP23017::Pin::IOPIN_14, MCP23017::SignalLevel::LOW);
mcp_int.digital_write(MCP23017::Pin::IOPIN_15, MCP23017::SignalLevel::LOW);
// CONTROL PINS
gpio_set_direction(GPIO_NUM_0, GPIO_MODE_OUTPUT);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
@ -121,24 +130,36 @@ EInk10::setup()
gpio_set_direction(GPIO_NUM_27, GPIO_MODE_OUTPUT); // D7
d_memory_new = new_frame_buffer_1bit();
p_buffer = (uint8_t *) ESP::ps_malloc(120000);
p_buffer = (uint8_t *) malloc(BITMAP_SIZE_1BIT * 2);
GLUT = (uint32_t *) malloc(256 * 8 * sizeof(uint32_t));
GLUT2 = (uint32_t *) malloc(256 * 8 * sizeof(uint32_t));
ESP_LOGD(TAG, "Memory allocation for bitmap buffers.");
ESP_LOGD(TAG, "d_memory_new: %08x p_buffer: %08x.", (unsigned int)d_memory_new, (unsigned int)p_buffer);
if ((d_memory_new == nullptr) ||
(p_buffer == nullptr)) {
do {
ESP_LOGE(TAG, "Unable to complete buffers allocation");
ESP::delay(10000);
} while (true);
(p_buffer == nullptr) ||
(GLUT == nullptr) ||
(GLUT2 == nullptr)) {
return false;
}
Wire::leave();
d_memory_new->clear();
memset(p_buffer, 0, 120000);
memset(p_buffer, 0, BITMAP_SIZE_1BIT * 2);
for (int i = 0; i < 8; ++i) {
for (uint32_t j = 0; j < 256; ++j) {
uint8_t z = (WAVEFORM_3BIT[j & 0x07][i] << 2) | (WAVEFORM_3BIT[(j >> 4) & 0x07][i]);
GLUT[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
(((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
z = ((WAVEFORM_3BIT[j & 0x07][i] << 2) | (WAVEFORM_3BIT[(j >> 4) & 0x07][i])) << 4;
GLUT2[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
(((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
}
}
initialized = true;
@ -148,104 +169,53 @@ EInk10::setup()
void
EInk10::update(FrameBuffer1Bit & frame_buffer)
{
ESP_LOGD(TAG, "update_1bit...");
ESP_LOGD(TAG, "1bit Update...");
const uint8_t * ptr;
uint32_t send;
uint8_t dram;
Wire::enter();
turn_on();
clean_fast(0, 1);
clean_fast(1, 21);
clean_fast(2, 1);
clean_fast(0, 12);
clean_fast(2, 1);
clean_fast(1, 21);
clean_fast(2, 1);
clean_fast(0, 12);
clean_fast(0, 10);
clean_fast(1, 10);
clean_fast(0, 10);
clean_fast(1, 10);
uint8_t * data = frame_buffer.get_data();
for (int8_t k = 0; k < 4; k++) {
for (int k = 0; k < 5; k++) {
ptr = &data[BITMAP_SIZE_1BIT - 1];
vscan_start();
for (uint16_t i = 0; i < HEIGHT; i++) {
dram = *ptr--;
send = PIN_LUT[LUTB[dram >> 4]];
hscan_start(send);
send = PIN_LUT[LUTB[dram & 0x0F]];
GPIO.out_w1ts = CL | send;
for (int i = 0; i < HEIGHT; i++) {
dram = ~(*ptr--);
hscan_start(PIN_LUT[LUTW[(dram >> 4) & 0x0F]]);
GPIO.out_w1ts = CL | PIN_LUT[LUTW[dram & 0x0F]];
GPIO.out_w1tc = CL | DATA;
for (uint16_t j = 0; j < LINE_SIZE_1BIT - 1; j++) {
dram = *ptr--;
send = PIN_LUT[LUTB[dram >> 4]];
GPIO.out_w1ts = CL | send;
for (int j = 0; j < (LINE_SIZE_1BIT - 1); j++) {
dram = ~(*ptr--);
GPIO.out_w1ts = CL | PIN_LUT[LUTW[(dram >> 4) & 0x0F]];
GPIO.out_w1tc = CL | DATA;
send = PIN_LUT[LUTB[dram & 0x0F]];
GPIO.out_w1ts = CL | send;
GPIO.out_w1ts = CL | PIN_LUT[LUTW[dram & 0x0F]];
GPIO.out_w1tc = CL | DATA;
}
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
GPIO.out_w1ts = CL;
GPIO.out_w1tc = CL| DATA;
vscan_end();
}
ESP::delay_microseconds(230);
}
ptr = &data[BITMAP_SIZE_1BIT - 1];
vscan_start();
for (uint16_t i = 0; i < HEIGHT; i++) {
dram = *ptr--;
send = PIN_LUT[LUT2[dram >> 4]];
hscan_start(send);
send = PIN_LUT[LUT2[dram & 0x0F]];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
for (uint16_t j = 0; j < LINE_SIZE_1BIT - 1; j++) {
dram = *ptr--;
send = PIN_LUT[LUT2[dram >> 4]];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
send = PIN_LUT[LUT2[dram & 0x0F]];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
}
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
vscan_end();
}
ESP::delay_microseconds(230);
vscan_start();
send = PIN_LUT[0];
for (uint16_t i = 0; i < HEIGHT; i++) {
hscan_start(send);
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
for (int j = 0; j < LINE_SIZE_1BIT - 1; j++) {
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
}
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
vscan_end();
}
ESP::delay_microseconds(230);
clean_fast(2, 2);
clean_fast(3, 1);
vscan_start();
turn_off();
@ -256,91 +226,48 @@ EInk10::update(FrameBuffer1Bit & frame_buffer)
partial_allowed = true;
}
void
void IRAM_ATTR
EInk10::update(FrameBuffer3Bit & frame_buffer)
{
ESP_LOGD(TAG, "Update_3bit...");
ESP_LOGD(TAG, "3bit Update...");
Wire::enter();
turn_on();
clean_fast(0, 1);
clean_fast(1, 21);
clean_fast(2, 1);
clean_fast(0, 12);
clean_fast(2, 1);
clean_fast(1, 21);
clean_fast(2, 1);
clean_fast(0, 12);
clean_fast(0, 10);
clean_fast(1, 10);
clean_fast(0, 10);
clean_fast(1, 10);
uint8_t * data = frame_buffer.get_data();
for (int k = 0; k < 8; k++) {
const uint8_t * dp = &data[BITMAP_SIZE_3BIT - 1];
uint32_t send;
uint8_t pix1;
uint8_t pix2;
uint8_t pix3;
uint8_t pix4;
uint8_t pixel;
uint8_t pixel2;
vscan_start();
for (int i = 0; i < HEIGHT; i++) {
pixel = 0;
pixel2 = 0;
pix1 = *(dp--);
pix2 = *(dp--);
pix3 = *(dp--);
pix4 = *(dp--);
pixel |= (WAVEFORM_3BIT[ pix1 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix1 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix2 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix2 >> 4) & 0x07][k] << 0);
pixel2 |= (WAVEFORM_3BIT[ pix3 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix3 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix4 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix4 >> 4) & 0x07][k] << 0);
send = PIN_LUT[pixel];
hscan_start(send);
send = PIN_LUT[pixel2];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
for (int j = 0; j < (LINE_SIZE_3BIT >> 2) - 1; j++) {
pixel = 0;
pixel2 = 0;
pix1 = *(dp--);
pix2 = *(dp--);
pix3 = *(dp--);
pix4 = *(dp--);
pixel |= (WAVEFORM_3BIT[ pix1 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix1 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix2 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix2 >> 4) & 0x07][k] << 0);
pixel2 |= (WAVEFORM_3BIT[ pix3 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix3 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix4 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix4 >> 4) & 0x07][k] << 0);
send = PIN_LUT[pixel];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
hscan_start((GLUT2[k * 256 + (*(dp - 1))] | GLUT[k * 256 + (*(dp - 2))]));
dp -= 2;
send = PIN_LUT[pixel2];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
GPIO.out_w1ts = CL | (GLUT2[k * 256 + (*(dp - 1))] | GLUT[k * 256 + (*(dp - 2))]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
for (int j = 0; j < ((WIDTH / 8) - 1); j++) {
GPIO.out_w1ts = CL | (GLUT2[k * 256 + (*(dp - 1))] | GLUT[k * 256 + (*(dp - 2))]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
GPIO.out_w1ts = CL | (GLUT2[k * 256 + (*(dp - 1))] | GLUT[k * 256 + (*(dp - 2))]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
}
GPIO.out_w1ts = CL | send;
GPIO.out_w1ts = CL;
GPIO.out_w1tc = CL | DATA;
vscan_end();
}
@ -366,8 +293,7 @@ EInk10::partial_update(FrameBuffer1Bit & frame_buffer, bool force)
ESP_LOGD(TAG, "Partial update...");
uint32_t send;
uint32_t n = 119999;
uint32_t n = BITMAP_SIZE_1BIT * 2 - 1;
uint32_t pos = BITMAP_SIZE_1BIT - 1;
uint8_t diffw, diffb;
@ -388,13 +314,13 @@ EInk10::partial_update(FrameBuffer1Bit & frame_buffer, bool force)
for (int k = 0; k < 5; k++) {
vscan_start();
n = 119999;
n = BITMAP_SIZE_1BIT * 2 - 1;
for (int i = 0; i < HEIGHT; i++) {
send = PIN_LUT[p_buffer[n--]];
uint32_t send = PIN_LUT[p_buffer[n--]];
hscan_start(send);
for (int j = 0; j < 199; j++) {
for (int j = 0; j < ((WIDTH / 4) - 1); j++) {
send = PIN_LUT[p_buffer[n--]];
GPIO.out_w1ts = send | CL;
GPIO.out_w1tc = DATA | CL;

5
lib/drivers/src/eink_10.hpp

@ -46,7 +46,7 @@ Distributed as-is; no warranty is given.
class EInk10 : public EInk, NonCopyable
{
public:
EInk10(MCP23017 & mcp) : EInk(mcp)
EInk10(MCP23017 & mcp_i, MCP23017 & mcp_e) : EInk(mcp_i), mcp_ext(mcp_e)
{ } // Private constructor
static const uint16_t WIDTH = 1200; // In pixels
@ -59,7 +59,6 @@ class EInk10 : public EInk, NonCopyable
inline int16_t get_width() { return WIDTH; }
inline int16_t get_height() { return HEIGHT; }
inline PanelState get_panel_state() { return panel_state; }
inline bool is_initialized() { return initialized; }
@ -86,6 +85,8 @@ class EInk10 : public EInk, NonCopyable
private:
static constexpr char const * TAG = "EInk10";
MCP23017 & mcp_ext;
class FrameBuffer1BitX : public FrameBuffer1Bit {
private:
uint8_t data[BITMAP_SIZE_1BIT];

117
lib/drivers/src/eink_6.cpp

@ -20,7 +20,7 @@ If you have any questions about licensing, please contact techsupport@e-radionic
Distributed as-is; no warranty is given.
*/
#ifdef INKPLATE_6
#if defined(INKPLATE_6)
#define __EINK6__ 1
#include "eink_6.hpp"
@ -39,12 +39,6 @@ const uint8_t EInk6::WAVEFORM_3BIT[8][8] = {
{2, 1, 1, 1, 2, 1, 2, 0}, {2, 2, 1, 1, 2, 1, 2, 0},
{1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}};
// {
// {0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0},
// {0, 1, 2, 1, 1, 2, 1, 0}, {0, 2, 1, 2, 1, 2, 1, 0},
// {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0},
// {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}};
const uint8_t EInk6::LUT2[16] = {
0xAA, 0xA9, 0xA6, 0xA5, 0x9A, 0x99, 0x96, 0x95,
0x6A, 0x69, 0x66, 0x65, 0x5A, 0x59, 0x56, 0x55 };
@ -121,24 +115,36 @@ EInk6::setup()
gpio_set_direction(GPIO_NUM_27, GPIO_MODE_OUTPUT); // D7
d_memory_new = new_frame_buffer_1bit();
p_buffer = (uint8_t *) ESP::ps_malloc(120000);
p_buffer = (uint8_t *) ESP::ps_malloc(BITMAP_SIZE_1BIT * 2);
GLUT = (uint32_t *)malloc(256 * 8 * sizeof(uint32_t));
GLUT2 = (uint32_t *)malloc(256 * 8 * sizeof(uint32_t));
ESP_LOGD(TAG, "Memory allocation for bitmap buffers.");
ESP_LOGD(TAG, "Memory allocation for frame/bitmap buffers.");
ESP_LOGD(TAG, "d_memory_new: %08x p_buffer: %08x.", (unsigned int)d_memory_new, (unsigned int)p_buffer);
if ((d_memory_new == nullptr) ||
(p_buffer == nullptr)) {
do {
ESP_LOGE(TAG, "Unable to complete buffers allocation");
ESP::delay(10000);
} while (true);
(p_buffer == nullptr) ||
(GLUT == nullptr) ||
(GLUT2 == nullptr)) {
return false;
}
Wire::leave();
d_memory_new->clear();
memset(p_buffer, 0, 120000);
memset(p_buffer, 0, BITMAP_SIZE_1BIT * 2);
for (int i = 0; i < 8; ++i) {
for (uint32_t j = 0; j < 256; ++j) {
uint8_t z = (WAVEFORM_3BIT[j & 0x07][i] << 2) | (WAVEFORM_3BIT[(j >> 4) & 0x07][i]);
GLUT[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
(((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
z = ((WAVEFORM_3BIT[j & 0x07][i] << 2) | (WAVEFORM_3BIT[(j >> 4) & 0x07][i])) << 4;
GLUT2[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
(((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
}
}
initialized = true;
@ -148,7 +154,7 @@ EInk6::setup()
void
EInk6::update(FrameBuffer1Bit & frame_buffer)
{
ESP_LOGD(TAG, "update_1bit...");
ESP_LOGD(TAG, "1bit Update...");
const uint8_t * ptr;
uint32_t send;
@ -259,7 +265,7 @@ EInk6::update(FrameBuffer1Bit & frame_buffer)
void
EInk6::update(FrameBuffer3Bit & frame_buffer)
{
ESP_LOGD(TAG, "Update_3bit...");
ESP_LOGD(TAG, "3bit Update...");
Wire::enter();
turn_on();
@ -278,69 +284,30 @@ EInk6::update(FrameBuffer3Bit & frame_buffer)
for (int k = 0; k < 8; k++) {
const uint8_t * dp = &data[BITMAP_SIZE_3BIT - 1];
uint32_t send;
uint8_t pix1;
uint8_t pix2;
uint8_t pix3;
uint8_t pix4;
uint8_t pixel;
uint8_t pixel2;
vscan_start();
for (int i = 0; i < HEIGHT; i++) {
pixel = 0;
pixel2 = 0;
pix1 = *(dp--);
pix2 = *(dp--);
pix3 = *(dp--);
pix4 = *(dp--);
pixel |= (WAVEFORM_3BIT[ pix1 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix1 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix2 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix2 >> 4) & 0x07][k] << 0);
pixel2 |= (WAVEFORM_3BIT[ pix3 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix3 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix4 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix4 >> 4) & 0x07][k] << 0);
send = PIN_LUT[pixel];
hscan_start(send);
send = PIN_LUT[pixel2];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
for (int j = 0; j < (LINE_SIZE_3BIT >> 2) - 1; j++) {
pixel = 0;
pixel2 = 0;
pix1 = *(dp--);
pix2 = *(dp--);
pix3 = *(dp--);
pix4 = *(dp--);
pixel |= (WAVEFORM_3BIT[ pix1 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix1 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix2 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix2 >> 4) & 0x07][k] << 0);
pixel2 |= (WAVEFORM_3BIT[ pix3 & 0x07][k] << 6) |
(WAVEFORM_3BIT[(pix3 >> 4) & 0x07][k] << 4) |
(WAVEFORM_3BIT[ pix4 & 0x07][k] << 2) |
(WAVEFORM_3BIT[(pix4 >> 4) & 0x07][k] << 0);
send = PIN_LUT[pixel];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
hscan_start((GLUT2[k * 256 + *(dp - 1)] | GLUT[k * 256 + *(dp - 2)]));
dp -= 2;
send = PIN_LUT[pixel2];
GPIO.out_w1ts = CL | send;
GPIO.out_w1tc = CL | DATA;
GPIO.out_w1ts = CL | (GLUT2[k * 256 + (*(dp - 1))] | GLUT[k * 256 + *(dp - 2)]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
for (int j = 0; j < ((WIDTH / 8) - 1); j++) {
GPIO.out_w1ts = CL | (GLUT2[k * 256 + *(dp - 1)] | GLUT[k * 256 + *(dp - 2)]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
GPIO.out_w1ts = CL | (GLUT2[k * 256 + *(dp - 1)] | GLUT[k * 256 + *(dp - 2)]);
GPIO.out_w1tc = CL | DATA;
dp -= 2;
}
GPIO.out_w1ts = CL | send;
GPIO.out_w1ts = CL;
GPIO.out_w1tc = CL | DATA;
vscan_end();
}
@ -367,7 +334,7 @@ EInk6::partial_update(FrameBuffer1Bit & frame_buffer, bool force)
ESP_LOGD(TAG, "Partial update...");
uint32_t send;
uint32_t n = 119999;
uint32_t n = BITMAP_SIZE_1BIT * 2 - 1;
uint16_t pos = BITMAP_SIZE_1BIT - 1;
uint8_t diffw, diffb;
@ -388,13 +355,13 @@ EInk6::partial_update(FrameBuffer1Bit & frame_buffer, bool force)
for (int k = 0; k < 5; k++) {
vscan_start();
n = 119999;
n = BITMAP_SIZE_1BIT * 2 - 1;
for (int i = 0; i < HEIGHT; i++) {
send = PIN_LUT[p_buffer[n--]];
hscan_start(send);
for (int j = 0; j < 199; j++) {
for (int j = 0; j < ((WIDTH / 4) - 1); j++) {
send = PIN_LUT[p_buffer[n--]];
GPIO.out_w1ts = send | CL;
GPIO.out_w1tc = DATA | CL;

2
lib/drivers/src/inkplate_platform.hpp

@ -38,7 +38,7 @@ Distributed as-is; no warranty is given.
EInk6 e_ink(mcp_int);
#elif defined(INKPLATE_10)
MCP23017 mcp_ext(0x22);
EInk10 e_ink(mcp_int);
EInk10 e_ink(mcp_int, mcp_ext);
#else
#error "One of INKPLATE_6, INKPLATE_10 must be defined."
#endif

28
lib/graphical/src/graphics.cpp

@ -129,11 +129,11 @@ void Graphics::endWrite()
void Graphics::selectDisplayMode(DisplayMode mode)
{
if (mode != _displayMode)
if (mode != display_mode)
{
_displayMode = mode;
display_mode = mode;
if (_displayMode == DisplayMode::INKPLATE_1BIT)
if (display_mode == DisplayMode::INKPLATE_1BIT)
_partial->clear();
else
DMemory4Bit->clear();
@ -144,7 +144,7 @@ void Graphics::selectDisplayMode(DisplayMode mode)
void Graphics::clearDisplay()
{
if (_displayMode == DisplayMode::INKPLATE_1BIT)
if (display_mode == DisplayMode::INKPLATE_1BIT)
_partial->clear();
else
DMemory4Bit->clear();
@ -152,22 +152,26 @@ void Graphics::clearDisplay()
void Graphics::display()
{
if (_displayMode == DisplayMode::INKPLATE_1BIT)
if (display_mode == DisplayMode::INKPLATE_1BIT) {
ESP_LOGD(TAG, "Update 1Bit frame buffer");
e_ink.update(*_partial);
else
}
else {
ESP_LOGD(TAG, "Update 3Bit frame buffer");
e_ink.update(*DMemory4Bit);
}
}
void Graphics::preloadScreen()
{
if (_displayMode == DisplayMode::INKPLATE_1BIT) {
if (display_mode == DisplayMode::INKPLATE_1BIT) {
e_ink.preload_screen(*_partial);
}
}
void Graphics::partialUpdate(bool _forced)
{
if (_displayMode == DisplayMode::INKPLATE_1BIT) {
if (display_mode == DisplayMode::INKPLATE_1BIT) {
e_ink.partial_update(*_partial, _forced);
}
}
@ -207,15 +211,15 @@ void Graphics::writePixel(int16_t x0, int16_t y0, uint16_t color)
{
int x = x0 >> 3;
int x_sub = x0 & 7;
uint8_t temp = _partial->get_data()[100 * y0 + x];
_partial->get_data()[100 * y0 + x] = (~pixelMaskLUT[x_sub] & temp) | (color ? pixelMaskLUT[x_sub] : 0);
uint8_t * p = &_partial->get_data()[_partial->get_line_size() * y0 + x];
*p = (~pixelMaskLUT[x_sub] & *p) | (color ? pixelMaskLUT[x_sub] : 0);
}
else
{
color &= 7;
int x = x0 >> 1;
int x_sub = x0 & 1;
uint8_t temp = DMemory4Bit->get_data()[400 * y0 + x];
DMemory4Bit->get_data()[400 * y0 + x] = (pixelMaskGLUT[x_sub] & temp) | (x_sub ? color : color << 4);
uint8_t * p = &DMemory4Bit->get_data()[DMemory4Bit->get_line_size() * y0 + x];
*p = (pixelMaskGLUT[x_sub] & *p) | (x_sub ? color : color << 4);
}
}

6
lib/graphical/src/graphics.hpp

@ -51,8 +51,8 @@ class Graphics : public Shapes, public Image
void setRotation(uint8_t r);
uint8_t getRotation();
void drawPixel(int16_t x, int16_t y, uint16_t color) override;
void selectDisplayMode(DisplayMode _mode);
void setDisplayMode(DisplayMode _mode) { display_mode = _mode; }
void selectDisplayMode(DisplayMode mode);
void setDisplayMode(DisplayMode mode) { display_mode = mode; }
DisplayMode getDisplayMode() { return display_mode; }
void clearDisplay();
@ -82,8 +82,6 @@ class Graphics : public Shapes, public Image
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) override;
void endWrite(void) override;
DisplayMode _displayMode = DisplayMode::INKPLATE_1BIT;
};
#endif

249
lib/graphical/src/shapes_polygon.cpp

@ -0,0 +1,249 @@
/*
shapes_polygon.cpp
Inkplate 6 Arduino library
David Zovko, Borna Biro, Denis Vajak, Zvonimir Haramustek @ e-radionica.com
September 24, 2020
https://github.com/e-radionicacom/Inkplate-6-Arduino-library
For support, please reach over forums: forum.e-radionica.com/en
For more info about the product, please check: www.inkplate.io
This code is released under the GNU Lesser General Public License v3.0: https://www.gnu.org/licenses/lgpl-3.0.en.html
Please review the LICENSE file included with this example.
If you have any questions about licensing, please contact techsupport@e-radionica.com
Distributed as-is; no warranty is given.
*/
#include "shapes.hpp"
void Shapes::initedgeTable()
{
int i;
for (i = 0; i < maxHt; i++)
edgeTable[i].countEdgeBucket = 0;
activeEdgeTuple.countEdgeBucket = 0;
}
void Shapes::insertionSort(edgeTableTuple *ett)
{
int i, j;
EdgeBucket temp;
for (i = 1; i < ett->countEdgeBucket; i++)
{
temp.ymax = ett->buckets[i].ymax;
temp.xofymin = ett->buckets[i].xofymin;
temp.slopeinverse = ett->buckets[i].slopeinverse;
j = i - 1;
while ((temp.xofymin < ett->buckets[j].xofymin) && (j >= 0))
{
ett->buckets[j + 1].ymax = ett->buckets[j].ymax;
ett->buckets[j + 1].xofymin = ett->buckets[j].xofymin;
ett->buckets[j + 1].slopeinverse = ett->buckets[j].slopeinverse;
j = j - 1;
}
ett->buckets[j + 1].ymax = temp.ymax;
ett->buckets[j + 1].xofymin = temp.xofymin;
ett->buckets[j + 1].slopeinverse = temp.slopeinverse;
}
}
void Shapes::storeEdgeInTuple(edgeTableTuple *receiver, int ym, int xm, float slopInv)
{
(receiver->buckets[(receiver)->countEdgeBucket]).ymax = ym;
(receiver->buckets[(receiver)->countEdgeBucket]).xofymin = (float)xm;
(receiver->buckets[(receiver)->countEdgeBucket]).slopeinverse = slopInv;
insertionSort(receiver);
(receiver->countEdgeBucket)++;
}
void Shapes::storeEdgeInTable(int x1, int y1, int x2, int y2)
{
float m, minv;
int ymaxTS, xwithyminTS, scanline; // ts stands for to store
if (x2 == x1)
{
minv = 0.000000;
}
else
{
m = ((float)(y2 - y1)) / ((float)(x2 - x1));
if (y2 == y1)
return;
minv = (float)1.0 / m;
}
if (y1 > y2)
{
scanline = y2;
ymaxTS = y1;
xwithyminTS = x2;
}
else
{
scanline = y1;
ymaxTS = y2;
xwithyminTS = x1;
}
storeEdgeInTuple(&edgeTable[scanline], ymaxTS, xwithyminTS, minv);
}
void Shapes::removeEdgeByYmax(edgeTableTuple *tup, int yy)
{
int i, j;
for (i = 0; i < tup->countEdgeBucket; i++)
{
if (tup->buckets[i].ymax == yy)
{
for (j = i; j < tup->countEdgeBucket - 1; j++)
{
tup->buckets[j].ymax = tup->buckets[j + 1].ymax;
tup->buckets[j].xofymin = tup->buckets[j + 1].xofymin;
tup->buckets[j].slopeinverse = tup->buckets[j + 1].slopeinverse;
}
tup->countEdgeBucket--;
i--;
}
}
}
void Shapes::updatexbyslopeinv(edgeTableTuple *tup)
{
int i;
for (i = 0; i < tup->countEdgeBucket; i++)
{
(tup->buckets[i]).xofymin = (tup->buckets[i]).xofymin + (tup->buckets[i]).slopeinverse;
}
}
void Shapes::scanlineFill(uint8_t c)
{
int i, j, x1, ymax1, x2, ymax2, FillFlag = 0, coordCount;
for (i = 0; i < maxHt; i++)
{
for (j = 0; j < edgeTable[i].countEdgeBucket; j++)
storeEdgeInTuple(&activeEdgeTuple, edgeTable[i].buckets[j].ymax, edgeTable[i].buckets[j].xofymin,
edgeTable[i].buckets[j].slopeinverse);
removeEdgeByYmax(&activeEdgeTuple, i);
insertionSort(&activeEdgeTuple);
j = 0;
FillFlag = 0;
coordCount = 0;
x1 = 0;
x2 = 0;
ymax1 = 0;
ymax2 = 0;
while (j < activeEdgeTuple.countEdgeBucket)
{
if (coordCount % 2 == 0)
{
x1 = (int)(activeEdgeTuple.buckets[j].xofymin);
ymax1 = activeEdgeTuple.buckets[j].ymax;
if (x1 == x2)
{
if (((x1 == ymax1) && (x2 != ymax2)) || ((x1 != ymax1) && (x2 == ymax2)))
{
x2 = x1;
ymax2 = ymax1;
}
else
{
coordCount++;
}
}
else
{
coordCount++;
}
}
else
{
x2 = (int)activeEdgeTuple.buckets[j].xofymin;
ymax2 = activeEdgeTuple.buckets[j].ymax;
FillFlag = 0;
if (x1 == x2)
{
if (((x1 == ymax1) && (x2 != ymax2)) || ((x1 != ymax1) && (x2 == ymax2)))
{
x1 = x2;
ymax1 = ymax2;
}
else
{
coordCount++;
FillFlag = 1;
}
}
else
{
coordCount++;
FillFlag = 1;
}
if (FillFlag)
{
// Serial.println(x1);
// Serial.println(x2);
// Serial.println();
drawLine(x1, i, x2, i, c);
}
}
j++;
}
updatexbyslopeinv(&activeEdgeTuple);
}
}
void Shapes::drawPolygon(int *x, int *y, int n, int color)
{
for (int i = 0; i < n; ++i)
drawLine(x[i], y[i], x[(i + 1) % n], y[(i + 1) % n], color);
}
void Shapes::fillPolygon(int *x, int *y, int n, int color)
{
edgeTable = (edgeTableTuple *) malloc(maxHt * sizeof(edgeTableTuple));
initedgeTable();
int count = 0, x1, y1, x2, y2;
x1 = y1 = x2 = y2 = 0;
for (int i = 0; i < n + 1; ++i)
{
count++;
if (count > 2)
{
x1 = x2;
y1 = y2;
count = 2;
}
if (count == 1)
{
x1 = x[i % n];
y1 = y[i % n];
}
else
{
x2 = x[i % n];
y2 = y[i % n];
drawLine(x1, y1, x2, y2, color);
storeEdgeInTable(x1, y1, x2, y2);
}
}
scanlineFill(color);
free(edgeTable);
}

336
src/image.hpp

@ -0,0 +1,336 @@
//Array that holds data for grayscale image of 500x332 pixels. You can convert your own image using LCD image Converter.
//Image source: https://www.peakpx.com/583083/grayscale-photo-of-lighthouse
const uint8_t picture1[] = {
0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xba, 0xaa, 0xaa, 0x99, 0x99, 0x89, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x87, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xa9, 0x99, 0x99, 0xaa, 0xab, 0xba, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x98, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0x9a, 0xaa, 0xaa, 0xba, 0xaa, 0xba, 0x9a, 0xba, 0xaa, 0xa9, 0x98, 0x88, 0x87, 0x77, 0x88, 0x88, 0x77, 0x88, 0x88, 0x88, 0x87, 0x88, 0x88, 0x78, 0x88, 0x87, 0x77, 0x77,
0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xaa, 0xaa, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x66, 0x67, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x67, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x99, 0x9a, 0xa9, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xba, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x88, 0x89, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0xa9, 0x99, 0xaa, 0x99, 0x99, 0x9a, 0xa9, 0xaa, 0xa9, 0x88, 0x88, 0x77, 0x77, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0x67, 0x77, 0x88, 0x77, 0x77, 0x66, 0x66,
0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xcc, 0xbc, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xba, 0xaa, 0xa9, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x87, 0x77, 0x76, 0x66, 0x66, 0x67, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x87, 0x77, 0x77, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xba, 0xab, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x89, 0x98, 0x98, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0xaa, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xba, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xbb, 0xaa, 0xaa, 0xba, 0xaa, 0x99, 0x89, 0x9a, 0xaa, 0x99, 0x99, 0x99, 0x9a, 0xa9, 0x88, 0x88, 0x87, 0x88, 0x77, 0x77, 0x88, 0x77, 0x76, 0x66, 0x66, 0x66, 0x66, 0x67, 0x77, 0x66, 0x66, 0x55, 0x55,
0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xbc, 0xcc, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x76, 0x66, 0x66, 0x67, 0x77, 0x77, 0x77, 0x77, 0x87, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0xaa, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xba, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xab, 0xaa, 0xba, 0xaa, 0x99, 0x89, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0x99, 0x88, 0x97, 0x88, 0x77, 0x87, 0x77, 0x87, 0x77, 0x66, 0x65, 0x55, 0x55, 0x66, 0x66, 0x66, 0x65, 0x55, 0x55, 0x45,
0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x98, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xcc, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x88, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66, 0x67, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x99, 0x88, 0x89, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xcc, 0xbb, 0xbb, 0xbc, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xa9, 0x98, 0x88, 0x89, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xab, 0xba, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xba, 0xba, 0xaa, 0xaa, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x87, 0x78, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x77, 0x76, 0x65, 0x55, 0x55, 0x55, 0x56, 0x66, 0x66, 0x65, 0x55, 0x55, 0x45,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbb, 0xbb, 0xbc, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xa9, 0x99, 0x99, 0x88, 0x88, 0x88, 0x87, 0x77, 0x77, 0x76, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x89, 0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbc, 0xbc, 0xcb, 0xcb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xa9, 0x9a, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xaa, 0xa9, 0x99, 0x99, 0x99, 0x9a, 0xa9, 0x99, 0x99, 0x99, 0x99, 0xa9, 0x9a, 0xaa, 0xba, 0xaa, 0xaa, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xba, 0xbb, 0xbb, 0xab, 0xba, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xaa, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0x98, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0x98, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0x76, 0x65, 0x55, 0x55, 0x55, 0x55, 0x56, 0x66, 0x65, 0x55, 0x55, 0x55, 0x55,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x88, 0x88, 0x88, 0x88, 0x98, 0x89, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x77, 0x77, 0x76, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x98, 0x88, 0x87, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0xaa, 0x9a, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0x99, 0x99, 0x9a, 0x99, 0xaa, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xbb, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xab, 0xbb, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0x99, 0x9a, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x88, 0x87, 0x77, 0x87, 0x78, 0x77, 0x77, 0x77, 0x76, 0x66, 0x66, 0x65, 0x55, 0x55, 0x55, 0x56, 0x66, 0x55, 0x55, 0x55, 0x66, 0x55,
0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x88, 0x88, 0x88, 0x88, 0x89, 0x98, 0x88, 0x88, 0x88, 0x88, 0x98, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xab, 0xba, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xba, 0xaa, 0xa9, 0x99, 0x99, 0x88, 0x88, 0x87, 0x77, 0x77, 0x76, 0x77, 0x66, 0x66, 0x66, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x9a, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xaa, 0xa9, 0x99, 0x9a, 0x99, 0x99, 0xaa, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbc, 0xba, 0xaa, 0xbb, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcb, 0xbb, 0xcc, 0xcb, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xa9, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xa9, 0x88, 0x97, 0x77, 0x77, 0x87, 0x88, 0x77, 0x67, 0x76, 0x66, 0x66, 0x66, 0x66, 0x65, 0x55, 0x56, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65,
0x77, 0x87, 0x77, 0x77, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xab, 0xba, 0xbb, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xbc, 0xbb, 0xbc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xa9, 0x98, 0x88, 0x87, 0x77, 0x77, 0x77, 0x66, 0x66, 0x67, 0x76, 0x67, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x87, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x9a, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xab, 0xaa, 0xab, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xcc, 0xdc, 0xcb, 0xbb, 0xbc, 0xcc, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xba, 0xab, 0xbb, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x98, 0x88, 0x99, 0x9a, 0xa9, 0x99, 0x99, 0x9a, 0xa9, 0x99, 0x88, 0x87, 0x77, 0x77, 0x77, 0x88, 0x87, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x65, 0x56, 0x65, 0x66, 0x66, 0x67, 0x76, 0x66, 0x65, 0x56,
0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xa9, 0x98, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x66, 0x67, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xba, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xa9, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xdd, 0xdc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbc, 0xbb, 0xbb, 0xcb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xa9, 0xa9, 0x99, 0x88, 0x88, 0x99, 0xaa, 0x99, 0xa9, 0x98, 0x99, 0x98, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x78, 0x87, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x65, 0x55, 0x55, 0x66, 0x66, 0x77, 0x76, 0x66, 0x66, 0x79,
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x98, 0x88, 0x88, 0x87, 0x77, 0x66, 0x66, 0x67, 0x77, 0x77, 0x88, 0x89, 0x99, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xba, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xa9, 0xaa, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xab, 0xbc, 0xcc, 0xcb, 0xcc, 0xcc, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x98, 0x89, 0xaa, 0xa9, 0xaa, 0x99, 0x99, 0x88, 0x88, 0x77, 0x77, 0x77, 0x87, 0x77, 0x77, 0x77, 0x78, 0x87, 0x78, 0x87, 0x77, 0x77, 0x76, 0x66, 0x55, 0x56, 0x66, 0x66, 0x76, 0x66, 0x66, 0x67, 0x78, 0x8a,
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x9a, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0x88, 0x88, 0x87, 0x77, 0x66, 0x66, 0x67, 0x77, 0x77, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x99, 0x99, 0x99, 0x88, 0x98, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xbb, 0xbb, 0xaa, 0xaa, 0xba, 0xab, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xbb, 0xbc, 0xcc, 0xcc, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xbb, 0xba, 0xab, 0xba, 0xbb, 0xbb, 0xbb, 0xbc, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x89, 0x99, 0x98, 0x99, 0x98, 0x99, 0x88, 0x77, 0x77, 0x76, 0x67, 0x88, 0x77, 0x77, 0x87, 0x77, 0x77, 0x77, 0x77, 0x76, 0x66, 0x66, 0x55, 0x66, 0x66, 0x76, 0x67, 0x66, 0x67, 0x77, 0x78, 0x99, 0xaa,
0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x66, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x98, 0x88, 0x88, 0x77, 0x77, 0x66, 0x66, 0x77, 0x77, 0x77, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x99, 0x99, 0x98, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcb, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xbb, 0xcc, 0xcc, 0xcb, 0xba, 0xaa, 0xa9, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x87, 0x77, 0x78, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x78, 0x77, 0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x56, 0x66, 0x67, 0x76, 0x67, 0x77, 0x78, 0x88, 0x88, 0x99, 0xaa,
0x66, 0x66, 0x67, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x66, 0x67, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbc, 0xcb, 0xbb, 0xcc, 0xbc, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0x99, 0x98, 0x88, 0x88, 0x87, 0x77, 0x77, 0x66, 0x77, 0x77, 0x77, 0x78, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0x99, 0x99, 0x9a, 0xaa, 0xbb, 0xbb, 0xbb, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x98, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbb, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xa9, 0xaa, 0x99, 0x88, 0x88, 0x88, 0x87, 0x77, 0x77, 0x88, 0x88, 0x88, 0x87, 0x77, 0x87, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x77, 0x77, 0x67, 0x77, 0x77, 0x77, 0x66, 0x66, 0x65, 0x56, 0x66, 0x66, 0x78, 0x77, 0x89, 0x98, 0x99, 0x99, 0x99, 0x9a, 0xaa,
0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x77, 0x67, 0x67, 0x66, 0x67, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xcb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xa9, 0x98, 0x88, 0x88, 0x77, 0x77, 0x77, 0x67, 0x77, 0x77, 0x77, 0x78, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0xaa, 0xbb, 0xbb, 0xbb, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xaa, 0xab, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x88, 0x87, 0x77, 0x77, 0x76, 0x67, 0x77, 0x88, 0x88, 0x87, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x56, 0x65, 0x65, 0x66, 0x66, 0x67, 0x88, 0x88, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb,
0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x67, 0x66, 0x66, 0x67, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0x9a, 0xa9, 0x98, 0x88, 0x88, 0x88, 0x77, 0x77, 0x67, 0x77, 0x77, 0x77, 0x77, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x88, 0x88, 0x88, 0x88, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcb, 0xcc, 0xcb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0xaa, 0xba, 0xbb, 0xbb, 0xbb, 0xab, 0xaa, 0xaa, 0xa9, 0x9a, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xbb, 0xbc, 0xcc, 0xcb, 0xcb, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xcc, 0xbc, 0xcb, 0xbb, 0xbb, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x87, 0x77, 0x77, 0x77, 0x76, 0x67, 0x78, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x87, 0x87, 0x77, 0x67, 0x77, 0x77, 0x66, 0x55, 0x55, 0x55, 0x55, 0x66, 0x67, 0x77, 0x78, 0x89, 0x99, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcb,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x98, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0x99, 0x99, 0x99, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x88, 0x88, 0x88, 0x78, 0x77, 0x77, 0x77, 0x77, 0x87, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xab, 0xbb, 0xbb, 0xab, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xba, 0xaa, 0xa9, 0x99, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0xaa, 0x9a, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcb, 0xbb, 0xbc, 0xcb, 0xbb, 0xbb, 0xcc, 0xbb, 0xcb, 0xbb, 0xbc, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xba, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0x89, 0x89, 0x98, 0x88, 0x77, 0x77, 0x67, 0x76, 0x66, 0x68, 0x88, 0x77, 0x77, 0x77, 0x77, 0x77, 0x89, 0x99, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x66, 0x77, 0x66, 0x56, 0x66, 0x66, 0x66, 0x77, 0x88, 0x78, 0x99, 0x99, 0x9a, 0xaa, 0xaa, 0xbb, 0xbb, 0xbc, 0xcb, 0xbc,
0x66, 0x66, 0x66, 0x67, 0x77, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xcb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xaa, 0xa9, 0x99, 0x99, 0x98, 0x88, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x88, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x87, 0x88, 0x88, 0x88, 0x99, 0x88, 0x99, 0x99, 0x89, 0x99, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0x9a, 0x99, 0xaa, 0xaa, 0xaa, 0xab, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xcb, 0xbb, 0xbb, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xbb, 0xaa, 0xaa, 0x99, 0x99, 0x88, 0x88, 0x88, 0x89, 0x99, 0x98, 0x87, 0x77, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x67, 0x77, 0x78, 0x88, 0x89, 0x88, 0x88, 0x87, 0x77, 0x66, 0x77, 0x77, 0x66, 0x76, 0x66, 0x67, 0x66, 0x67, 0x78, 0x89, 0x98, 0x89, 0x99, 0x99, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc,
0x66, 0x66, 0x66, 0x67, 0x76, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x88, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x99, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbb, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xaa, 0xbb, 0xaa, 0xaa, 0xaa, 0x9a, 0x99, 0x99, 0x98, 0x98, 0x88, 0x87, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x88, 0x88, 0x88, 0x88, 0x88, 0x98, 0x89, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88, 0x87, 0x77, 0x77, 0x78, 0x88, 0x99, 0x99, 0x88, 0x88, 0x88, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xbb, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xaa, 0xaa, 0xab, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xba, 0xba, 0xaa, 0xaa, 0xaa</