Compare commits

...
Author SHA1 Message Date
J. Nick Koston 2df80fbf71 Merge branch 'dev' into ota-inflate-table-decode 2026-10-25 23:49:16 -10:00
J. Nick Koston 470f7eb51d [esphome] Read a stored byte before advancing the OTA output cursor
C leaves the order of *d->dest++ and the read on the right of the
assignment open, so dest could move first; a read that needs input
flushes the output up to dest where the ack follows the write, and
would write the byte before it was stored. The test harness can now
take the output inside the read callback the same way, and every
stream runs through it.
2026-10-25 23:05:30 -10:00
J. Nick Koston e7b2dfed57 Merge branch 'dev' into ota-inflate-table-decode 2026-10-25 22:51:40 -10:00
J. Nick Koston 83080c4560 [esphome] Wrap OTA back references as an index and test stored blocks after Huffman ones
Forming a pointer before the ring is undefined behaviour even when it is
wrapped before use; wrap the ring position instead. A new test stream
puts stored blocks after dynamic ones, so they start with read ahead
bits in the bit buffer.
2026-10-25 21:52:28 -10:00
J. Nick Koston 104cb09475 [esphome] Update the inflate session size in its comment 2026-10-25 21:44:28 -10:00
J. Nick Koston a7824ed4e7 [esphome] Trim the OTA decoder's flash and heap
The careful path, which only decodes the last few bytes of each read,
uses the canonical decoder alone instead of the lookup table too. The
canonical decoder accumulates each length's first code and symbol index
as it walks, so the trees no longer store them, and the trans bound
check, which the symbol count already guarantees, goes with the size
field. 94 bytes less flash and 132 bytes less heap on a BK72xx, same
speed on a BK7238.
2026-10-25 21:43:44 -10:00
J. Nick Koston 6420db90b1 [esphome] Let the OTA decoder own its ring and finish each window in the fast loop
The decoder now starts dest at the ring and starts it over once a call
has filled it, so callers no longer set the output bounds and cannot
point them outside the ring. The fast loop runs to the end of the ring,
leaving a match that does not fit to the resume path, instead of handing
the last 258 bytes of every window to the careful path; match copies
run in at most two pieces instead of testing for the wrap on every byte.

The careful path decodes long codes through the same canonical decoder
as the fast loop, the distance lookup table is 6 bits for a 30 symbol
alphabet (1.3 KB more heap than before this change instead of 2.2 KB),
and the tests share one stream table.
2026-10-25 21:33:18 -10:00
J. Nick Koston d3c2a7c734 [esphome] Decode OTA deflate with lookup tables and a fast loop
Inflating dominated compressed uploads on slow chips: the uzlib decoder
read every Huffman code one bit at a time. Decode from a 32 bit bit
buffer through 9 bit lookup tables, run a fast loop with the bit buffer
and cursors in locals while a whole symbol fits in the input and the
output, and write each output byte once, into the ring window.

About 5 times faster on a BK7231N, a BK7238 and an ESP32, for about
830 bytes of flash and 2.2 KB more heap while a compressed upload runs.
2026-10-25 21:05:35 -10:00
5 changed files with 898 additions and 204 deletions

No files matched your search

@@ -373,7 +373,7 @@ void ESPHomeOTAComponent::handle_handshake_() {
// Value initialized: a corrupt stream that back references the
// window before it is filled then copies zeros, never stale memory.
// Default placement, PSRAM first where present: the session lives for one
// upload and keeps 4.9 KB of internal heap free while it runs
// upload and keeps 6.0 KB of internal heap free while it runs
this->inflate_ = RAMAllocator<InflateSession>().make_unique();
if (this->inflate_ != nullptr) {
this->handshake_buf_[1] |= SERVER_FEATURE_SUPPORTS_DEFLATE;
@@ -36,7 +36,10 @@
* Altered for ESPHome: this is the raw deflate decoder from uzlib's
* tinflate.c (v2.9.5) with the gzip/zlib header parsers, checksums,
* runtime table builder and in-memory (non ring window) output path
* removed, and the public names prefixed with ota_inflate.
* removed, and the public names prefixed with ota_inflate. Symbols are
* decoded from a 32 bit bit buffer through 9 bit lookup tables, with a
* fast loop for when a whole symbol fits in both the input and the output,
* and the output is written straight into the ring window.
*/
#include "ota_esphome_inflate.h"
@@ -49,16 +52,6 @@
#define TINF_DICT_ERROR OTA_INFLATE_DICT_ERROR
#define TINF_DATA struct OtaInflateState
#define TINF_TREE struct OtaInflateTree
#define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
/* every output byte also goes into the ring window */
#define TINF_PUT(d, c) \
{ \
*d->dest++ = c; \
d->dict_ring[d->dict_idx++] = c; \
if (d->dict_idx == d->dict_size) \
d->dict_idx = 0; \
}
/* --------------------------------------------------- *
* -- constant tables (upstream builds them at runtime) -- *
@@ -82,34 +75,52 @@ static const unsigned char CLCIDX[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4,
* -- utility functions -- *
* ----------------------- */
/* given an array of code lengths, build a tree */
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num) {
unsigned short offs[16];
unsigned int i, sum;
enum {
LIT_FAST_BITS = OTA_INFLATE_LIT_FAST_BITS,
DIST_FAST_BITS = OTA_INFLATE_DIST_FAST_BITS,
/* a lookup table entry is (code length << SYM_BITS) | symbol; 0 marks a longer code */
SYM_BITS = 9,
SYM_MASK = (1 << SYM_BITS) - 1,
/* input bytes one pass of the fast loop may take: three refills of up to 4 bytes */
FAST_IN_MIN = 12,
};
/* given an array of code lengths, build a tree and its lookup table */
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num, unsigned int fast_bits) {
const unsigned int fast_size = 1u << fast_bits;
unsigned short offs[16], next[16];
unsigned int i, sum, code;
/* clear code length count table */
for (i = 0; i < 16; ++i)
t->table[i] = 0;
/* scan symbol lengths, and sum code length counts */
for (i = 0; i < num; ++i)
t->table[lengths[i]]++;
/* In the lengths array, 0 means unused code. So, t->table[0] now contains
number of unused codes. But table's purpose is to contain # of codes of
particular length, and there're 0 codes of length 0. */
t->table[0] = 0;
/* compute offset table for distribution sort */
for (sum = 0, i = 0; i < 16; ++i) {
for (sum = 0, code = 0, i = 0; i < 16; ++i) {
offs[i] = sum;
sum += t->table[i];
if (i > 0)
code = (code + t->table[i - 1]) << 1;
next[i] = code;
}
/* create code->symbol translation table (symbols sorted by code) */
for (i = 0; i < fast_size; ++i)
t->fast[i] = 0;
for (i = 0; i < num; ++i) {
if (lengths[i])
t->trans[offs[lengths[i]]++] = i;
unsigned int len = lengths[i];
if (!len)
continue;
t->trans[offs[len]++] = i;
if (len <= fast_bits) {
/* codes arrive MSB first, the bit buffer is LSB first */
unsigned int c = next[len]++, rev = 0, j;
for (j = 0; j < len; ++j, c >>= 1)
rev = (rev << 1) | (c & 1);
for (j = rev; j < fast_size; j += 1u << len)
t->fast[j] = (unsigned short) ((len << SYM_BITS) | i);
}
}
}
@@ -117,89 +128,78 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned
* -- decode functions -- *
* ---------------------- */
static unsigned char uzlib_get_byte(TINF_DATA *d) {
/* If end of source buffer is not reached, return next byte from source
buffer. */
if (d->source < d->source_limit) {
return *d->source++;
/* top the bit buffer up from the input buffer, without blocking for more */
static inline void tinf_refill(TINF_DATA *d) {
while (d->bitcount <= 24 && d->source < d->source_limit) {
d->tag |= (unsigned int) *d->source++ << d->bitcount;
d->bitcount += 8;
}
/* Otherwise if there's callback and we haven't seen EOF yet, try to
read next byte using it. (Note: the callback can also update ->source
and ->source_limit). */
if (!d->eof) {
int val = d->source_read_cb(d);
if (val >= 0) {
return (unsigned char) val;
}
}
/* Otherwise, we hit EOF (either from ->source_read_cb() or from exhaustion
of the buffer), and it will be "sticky", i.e. further calls to this
function will end up here too. */
d->eof = true;
return 0;
}
/* get one bit from source stream */
static int tinf_getbit(TINF_DATA *d) {
unsigned int bit;
/* check if tag is empty */
if (!d->bitcount--) {
/* load next tag */
d->tag = uzlib_get_byte(d);
d->bitcount = 7;
/* make at least num (<= 16) bits available; past the end of input reads zeros and sets eof */
static inline void tinf_need(TINF_DATA *d, unsigned int num) {
while (d->bitcount < num) {
int val = -1;
if (d->source < d->source_limit) {
val = *d->source++;
} else if (!d->eof) {
val = d->source_read_cb(d);
}
if (val < 0) {
d->eof = true;
val = 0;
}
d->tag |= (unsigned int) val << d->bitcount;
d->bitcount += 8;
}
}
/* shift bit out of tag */
bit = d->tag & 0x01;
d->tag >>= 1;
return bit;
static inline unsigned int tinf_take(TINF_DATA *d, unsigned int num) {
unsigned int val = d->tag & ((1u << num) - 1);
d->tag >>= num;
d->bitcount -= num;
return val;
}
/* read a num bit value from a stream and add base */
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base) {
unsigned int val = 0;
/* read num bits */
if (num) {
unsigned int limit = 1 << (num);
unsigned int mask;
for (mask = 1; mask < limit; mask *= 2)
if (tinf_getbit(d))
val += mask;
}
return val + base;
static inline unsigned int tinf_read_bits(TINF_DATA *d, unsigned int num, unsigned int base) {
tinf_need(d, num);
return tinf_take(d, num) + base;
}
/* given a data stream and a tree, decode a symbol */
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t) {
int sum = 0, cur = 0, len = 0;
/* get more bits while code value is above sum */
do {
cur = 2 * cur + tinf_getbit(d);
if (++len == TINF_ARRAY_SIZE(t->table)) {
return TINF_DATA_ERROR;
/* canonical decode of the code at the bottom of tag; len gets the code length.
The trans index stays below the tree's symbol count, which trans always holds */
static int tinf_decode_long(const TINF_TREE *t, unsigned int tag, unsigned int *len) {
unsigned int code = 0, first = 0, index = 0, l;
for (l = 1; l < 16; ++l, tag >>= 1) {
unsigned int count = t->table[l];
code |= tag & 1;
if (code - first < count) {
*len = l;
return t->trans[index + code - first];
}
sum += t->table[len];
cur -= t->table[len];
} while (cur >= 0);
sum += cur;
if (sum < 0 || sum >= t->size) {
return TINF_DATA_ERROR;
index += count;
first = (first + count) << 1;
code <<= 1;
}
return TINF_DATA_ERROR;
}
return t->trans[sum];
/* decode a symbol, reading more input only while the code is not all in the bit
buffer; bits above bitcount are zero, so a code no longer than bitcount is real */
static int tinf_decode_symbol(TINF_DATA *d, const TINF_TREE *t) {
tinf_refill(d);
for (;;) {
unsigned int len;
int sym = tinf_decode_long(t, d->tag, &len);
if (sym >= 0 && len <= d->bitcount) {
tinf_take(d, len);
return sym;
}
if (d->bitcount >= 15)
return TINF_DATA_ERROR;
tinf_need(d, d->bitcount + 1);
}
}
/* given a data stream, decode dynamic trees from it */
@@ -230,7 +230,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
}
/* build code length tree, temporarily use length tree */
tinf_build_tree(lt, lengths, 19);
tinf_build_tree(lt, lengths, 19, LIT_FAST_BITS);
/* decode code lengths for the dynamic trees */
hlimit = hlit + hdist;
@@ -282,8 +282,8 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
}
/* build dynamic trees */
tinf_build_tree(lt, lengths, hlit);
tinf_build_tree(dt, lengths + hlit, hdist);
tinf_build_tree(lt, lengths, hlit, LIT_FAST_BITS);
tinf_build_tree(dt, lengths + hlit, hdist, DIST_FAST_BITS);
return TINF_OK;
}
@@ -302,84 +302,189 @@ static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt) {
lengths[i] = 7;
for (; i < 288; ++i)
lengths[i] = 8;
tinf_build_tree(lt, lengths, 288);
tinf_build_tree(lt, lengths, 288, LIT_FAST_BITS);
for (i = 0; i < 32; ++i)
lengths[i] = 5;
tinf_build_tree(dt, lengths, 32);
tinf_build_tree(dt, lengths, 32, DIST_FAST_BITS);
}
/* inflate with the bit buffer and both cursors in locals while the input holds a
whole symbol; a match that runs past the end of the ring is left in curlen */
static int tinf_inflate_fast(TINF_DATA *d, const TINF_TREE *lt, const TINF_TREE *dt) {
const unsigned char *src = d->source;
const unsigned char *const src_end = d->source_limit;
unsigned char *const ring = d->dict_ring;
unsigned char *const ring_end = ring + d->dict_size;
unsigned char *out = d->dest;
const uint16_t *const lfast = lt->fast;
const uint16_t *const dfast = dt->fast;
unsigned int tag = d->tag, bits = d->bitcount;
int res = TINF_OK;
#define REFILL() \
while (bits <= 24) { \
tag |= (unsigned int) *src++ << bits; \
bits += 8; \
}
#define DROP(n) (tag >>= (n), bits -= (n))
while (src_end - src >= FAST_IN_MIN && out < ring_end) {
unsigned int e, len;
int sym;
REFILL();
e = lfast[tag & ((1u << LIT_FAST_BITS) - 1)];
if (e) {
len = e >> SYM_BITS;
sym = e & SYM_MASK;
} else {
sym = tinf_decode_long(lt, tag, &len);
if (sym < 0) {
res = sym;
break;
}
}
DROP(len);
if (sym < 256) {
*out++ = sym;
continue;
}
if (sym == 256) {
res = TINF_DONE;
break;
}
sym -= 257;
if (sym >= 29) {
res = TINF_DATA_ERROR;
break;
}
/* the lit/len code and its extra bits fit the refilled buffer together */
unsigned int length = LENGTH_BASE[sym] + (tag & ((1u << LENGTH_BITS[sym]) - 1));
DROP(LENGTH_BITS[sym]);
REFILL();
e = dfast[tag & ((1u << DIST_FAST_BITS) - 1)];
if (e) {
len = e >> SYM_BITS;
sym = e & SYM_MASK;
} else {
sym = tinf_decode_long(dt, tag, &len);
}
if (sym < 0 || sym >= 30) {
res = TINF_DATA_ERROR;
break;
}
DROP(len);
REFILL();
unsigned int offs = DIST_BASE[sym] + (tag & ((1u << DIST_BITS[sym]) - 1));
DROP(DIST_BITS[sym]);
if (offs > d->dict_size) {
res = TINF_DICT_ERROR;
break;
}
/* wrap as an index: a pointer before the ring would be undefined */
unsigned int at = out - ring;
const unsigned char *from = ring + (at >= offs ? at - offs : at + d->dict_size - offs);
unsigned int n = ring_end - out;
if (n > length)
n = length;
length -= n;
/* at most two runs: up to the end of the ring, then on from its start */
while (n) {
unsigned int run = ring_end - from;
if (run > n)
run = n;
n -= run;
do {
*out++ = *from++;
} while (--run);
if (from == ring_end)
from = ring;
}
if (length) {
d->curlen = length;
d->lz_off = from - ring;
}
}
#undef REFILL
#undef DROP
d->source = src;
d->dest = out;
d->tag = tag;
d->bitcount = bits;
return res;
}
/* ----------------------------- *
* -- block inflate functions -- *
* ----------------------------- */
/* given a stream and two trees, inflate next chunk of output (a byte or more) */
/* given a stream and two trees, inflate until the ring is full or the block ends */
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) {
if (d->curlen == 0) {
unsigned char *const ring_end = d->dict_ring + d->dict_size;
while (d->dest < ring_end) {
if (d->curlen != 0) {
unsigned int n = ring_end - d->dest;
if (n > d->curlen)
n = d->curlen;
d->curlen -= n;
do {
*d->dest++ = d->dict_ring[d->lz_off];
if ((unsigned) ++d->lz_off == d->dict_size)
d->lz_off = 0;
} while (--n);
continue;
}
if (d->source_limit - d->source >= FAST_IN_MIN) {
int res = tinf_inflate_fast(d, lt, dt);
if (res != TINF_OK)
return res;
continue;
}
unsigned int offs;
int dist;
int sym = tinf_decode_symbol(d, lt);
if (d->eof) {
if (d->eof)
return TINF_DATA_ERROR;
}
if (sym < 0) {
if (sym < 0)
return sym;
}
/* literal byte */
if (sym < 256) {
TINF_PUT(d, sym);
return TINF_OK;
*d->dest++ = sym;
continue;
}
/* end of block */
if (sym == 256) {
if (sym == 256)
return TINF_DONE;
}
/* substring from sliding dictionary */
sym -= 257;
if (sym >= 29) {
if (sym >= 29)
return TINF_DATA_ERROR;
}
/* possibly get more bits from length code */
d->curlen = tinf_read_bits(d, LENGTH_BITS[sym], LENGTH_BASE[sym]);
dist = tinf_decode_symbol(d, dt);
if (dist < 0 || dist >= 30) {
if (dist < 0 || dist >= 30)
return TINF_DATA_ERROR;
}
/* possibly get more bits from distance code */
offs = tinf_read_bits(d, DIST_BITS[dist], DIST_BASE[dist]);
/* calculate and validate actual LZ offset to use */
if (offs > d->dict_size) {
if (offs > d->dict_size)
return TINF_DICT_ERROR;
}
/* Note: we don't try to catch offset which points to not yet filled
part of the dictionary here. Doing so would require keeping another
variable to track "filled in" size of the dictionary. Appearance of
such an offset cannot lead to accessing memory outside of the
dictionary buffer, and clients which don't want to leak unrelated
information, should explicitly initialize dictionary buffer passed
to uzlib. */
d->lz_off = d->dict_idx - offs;
if (d->lz_off < 0) {
d->lz_off = (int) (d->dest - d->dict_ring) - (int) offs;
if (d->lz_off < 0)
d->lz_off += d->dict_size;
}
}
/* copy next byte from dict substring */
TINF_PUT(d, d->dict_ring[d->lz_off]);
if ((unsigned) ++d->lz_off == d->dict_size) {
d->lz_off = 0;
}
d->curlen--;
return TINF_OK;
}
@@ -388,30 +493,22 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d) {
if (d->curlen == 0) {
unsigned int length, invlength;
/* get length */
length = uzlib_get_byte(d);
length += 256 * uzlib_get_byte(d);
/* get one's complement of length */
invlength = uzlib_get_byte(d);
invlength += 256 * uzlib_get_byte(d);
/* check length */
/* the block starts on a byte boundary */
tinf_take(d, d->bitcount & 7);
length = tinf_read_bits(d, 16, 0);
invlength = tinf_read_bits(d, 16, 0);
if (length != (~invlength & 0x0000ffff))
return TINF_DATA_ERROR;
/* increment length to properly return TINF_DONE below, without
producing data at the same time */
d->curlen = length + 1;
/* make sure we start next block on a byte boundary */
d->bitcount = 0;
}
if (--d->curlen == 0) {
if (--d->curlen == 0)
return TINF_DONE;
}
unsigned char c = uzlib_get_byte(d);
TINF_PUT(d, c);
/* read first: a read that needs input may flush the output up to dest */
unsigned char c = tinf_read_bits(d, 8, 0);
*d->dest++ = c;
return TINF_OK;
}
@@ -419,10 +516,10 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d) {
* -- public functions -- *
* ---------------------- */
/* initialize decompression structure */
void ota_inflate_init(TINF_DATA *d, unsigned char *dict, unsigned int dict_len) {
d->source = NULL;
d->source_limit = NULL;
d->dest = dict;
d->tag = 0;
d->eof = 0;
d->bitcount = 0;
@@ -431,68 +528,56 @@ void ota_inflate_init(TINF_DATA *d, unsigned char *dict, unsigned int dict_len)
d->btype = -1;
d->dict_size = dict_len;
d->dict_ring = dict;
d->dict_idx = 0;
d->curlen = 0;
d->ltree.trans = d->ltrans;
d->ltree.size = TINF_ARRAY_SIZE(d->ltrans);
d->ltree.fast = d->lfast;
d->dtree.trans = d->dtrans;
d->dtree.size = TINF_ARRAY_SIZE(d->dtrans);
d->dtree.fast = d->dfast;
}
/* inflate next output bytes from compressed stream */
int ota_inflate(TINF_DATA *d) {
/* the caller has taken the previous ringful */
if (d->dest == d->dict_ring + d->dict_size)
d->dest = d->dict_ring;
do {
int res;
/* start a new block */
if (d->btype == -1) {
int old_btype;
next_blk:
old_btype = d->btype;
/* read final block flag */
d->bfinal = tinf_getbit(d);
/* read block type (2 bits) */
d->bfinal = tinf_read_bits(d, 1, 0);
d->btype = tinf_read_bits(d, 2, 0);
if (d->btype == 1 && old_btype != 1) {
/* build fixed huffman trees */
tinf_build_fixed_trees(&d->ltree, &d->dtree);
} else if (d->btype == 2) {
/* decode trees from stream */
res = tinf_decode_trees(d, &d->ltree, &d->dtree);
if (res != TINF_OK) {
if (res != TINF_OK)
return res;
}
}
}
/* process current block */
switch (d->btype) {
case 0:
/* decompress uncompressed block */
res = tinf_inflate_uncompressed_block(d);
break;
case 1:
case 2:
/* decompress block with fixed/dynamic huffman trees */
/* trees were decoded previously, so it's the same routine for both */
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
break;
default:
return TINF_DATA_ERROR;
}
if (res == TINF_DONE && !d->bfinal) {
/* the block has ended (without producing more data), but we
can't return without data, so start procesing next block */
if (res == TINF_DONE && !d->bfinal)
goto next_blk;
}
if (res != TINF_OK) {
if (res != TINF_OK)
return res;
}
} while (d->dest < d->dest_limit);
} while (d->dest < d->dict_ring + d->dict_size);
return TINF_OK;
}
@@ -16,10 +16,14 @@ enum OtaInflateResult {
OTA_INFLATE_DICT_ERROR = -5,
};
/* Code bits each lookup table resolves; longer codes take the canonical decode.
The distance alphabet has 30 symbols, so its table is kept small */
enum { OTA_INFLATE_LIT_FAST_BITS = 9, OTA_INFLATE_DIST_FAST_BITS = 6 };
struct OtaInflateTree {
uint16_t table[16]; /* table of code length counts */
uint16_t *trans; /* code -> symbol translation table, size entries */
uint16_t size;
uint16_t *fast; /* (len << 9) | symbol by the next input bits, 0 = longer code */
uint16_t *trans; /* code -> symbol translation table */
};
struct OtaInflateState {
@@ -29,9 +33,8 @@ struct OtaInflateState {
/* Called when source is exhausted; returns the next byte or -1 at EOF.
It may refill source/source_limit for buffered operation. */
int (*source_read_cb)(struct OtaInflateState *d);
/* Output cursor and one past the end of the output buffer */
/* Output cursor in dict_ring: each call fills the ring from here */
unsigned char *dest;
unsigned char *dest_limit;
/* Ring window holding the last dict_size output bytes for back references */
unsigned char *dict_ring;
@@ -39,9 +42,8 @@ struct OtaInflateState {
unsigned int curlen;
int lz_off;
unsigned int dict_size;
unsigned int dict_idx;
/* One word: btype is -1 between blocks, bitcount never exceeds 7 */
/* btype is -1 between blocks; bitcount is the number of valid bits in tag (<= 32) */
int8_t btype;
uint8_t bfinal;
uint8_t bitcount;
@@ -51,13 +53,15 @@ struct OtaInflateState {
struct OtaInflateTree dtree; /* dynamic distance tree */
uint16_t ltrans[288];
uint16_t dtrans[32]; /* the distance alphabet has 30 symbols, so the tree is kept small */
uint16_t lfast[1 << OTA_INFLATE_LIT_FAST_BITS];
uint16_t dfast[1 << OTA_INFLATE_DIST_FAST_BITS];
};
/* dict must cover the encoder's window (its largest back reference) */
void ota_inflate_init(struct OtaInflateState *d, unsigned char *dict, unsigned int dict_len);
/* Fills dest up to dest_limit (OK) or to the end of the stream (DONE). dest may
alias dict only if dest_limit - dest == dict_len and dest is reset to dict
exactly when a call returns OK, so the ring index and dest stay in lockstep */
/* Inflates into dict until it is full (OK) or the stream ends (DONE); the output
is dict up to dest. The next call after OK starts dict over, so take its
contents first */
int ota_inflate(struct OtaInflateState *d);
#ifdef __cplusplus
@@ -65,16 +65,15 @@ ota::OTAResponseTypes ESPHomeOTAComponent::inflate_data_(uint8_t *in, size_t ima
};
int res;
session.flushed = 0;
do {
// The ring index wrapped to 0 exactly when the window filled
session.dest = session.window;
session.dest_limit = session.window + OTA_INFLATE_WINDOW_SIZE;
session.flushed = 0;
res = ota_inflate(&session);
// A stored block keeps emitting zeros after a failed read, hence eof
if (res < 0 || session.eof)
break;
session.error = this->inflate_flush_(session);
// A full window is all in flash; the next call starts it over
session.flushed = 0;
} while (res != OTA_INFLATE_DONE && session.error == ota::OTA_RESPONSE_OK);
// Transport and flash failures are logged where they happen
+616 -10
View File
@@ -11,6 +11,14 @@ namespace esphome::testing {
// build_plain() compressed with the CLI's window (espota2.DEFLATE_WINDOW_BITS):
// DEFLATED = zlib.compress(plain, 9, wbits=-12)
// STORED = zlib.compress(plain[:300], 0, wbits=-12)
// c = zlib.compressobj(9, zlib.DEFLATED, -12, 9, zlib.Z_FIXED)
// FIXED = c.compress(plain) + c.flush()
// and build_skewed(), whose rare bytes get codes longer than the lookup tables:
// SKEWED = zlib.compress(skewed, 9, wbits=-12)
// and build_mixed() in three parts, so stored blocks follow Huffman blocks:
// c = zlib.compressobj(9, zlib.DEFLATED, -12)
// MIXED = (c.compress(text) + c.flush(zlib.Z_SYNC_FLUSH) + c.compress(noise)
// + c.flush(zlib.Z_SYNC_FLUSH) + c.compress(tail) + c.flush())
static const uint8_t DEFLATED[] = {
0xed, 0xc8, 0xf7, 0x3f, 0xd4, 0x0f, 0x03, 0x00, 0x70, 0x67, 0xaf, 0x4b, 0x67, 0x66, 0x9f, 0x90, 0x91, 0x11, 0xc2,
0x11, 0x91, 0xb8, 0xb3, 0xf7, 0x3a, 0xd9, 0x5f, 0x4e, 0x99, 0x67, 0x1e, 0xce, 0x8a, 0xac, 0xec, 0x59, 0xb8, 0xc2,
@@ -201,6 +209,532 @@ static const uint8_t STORED[] = {
0x68, 0x6f, 0x6d, 0x65, 0x20, 0x6f, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x20,
};
static const uint8_t FIXED[] = {
0x4b, 0x2d, 0x2e, 0xc8, 0xc8, 0xcf, 0x4d, 0x55, 0xc8, 0x2f, 0x49, 0x54, 0x48, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49,
0x55, 0x48, 0x1d, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b,
0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15,
0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x23, 0x49, 0xec, 0x58, 0x5d, 0x63, 0xb6, 0xf7, 0xef,
0x47, 0xbf, 0x43, 0xbe, 0xed, 0xbd, 0x5f, 0x23, 0xf3, 0xb0, 0x9d, 0x71, 0xbf, 0xe1, 0xbd, 0xb0, 0x22, 0x7e, 0xf7,
0xf4, 0xb4, 0xf6, 0xc8, 0x55, 0x1d, 0x36, 0x91, 0xaf, 0xc2, 0x84, 0xab, 0x2f, 0xb5, 0x2e, 0xbc, 0x61, 0x13, 0x12,
0xaa, 0x6f, 0xbe, 0x2e, 0x35, 0xfa, 0x16, 0x53, 0xe5, 0x8c, 0x33, 0x8f, 0xa5, 0xca, 0xfa, 0xe2, 0x6f, 0xce, 0xec,
0x97, 0xb7, 0x37, 0x7b, 0xe7, 0x5c, 0xe1, 0xcb, 0xfb, 0x6b, 0xdf, 0xb2, 0x5b, 0x4f, 0xda, 0xfa, 0xee, 0x68, 0xe6,
0xfa, 0xfd, 0x0f, 0x7b, 0x58, 0xa0, 0xf0, 0xbb, 0x7f, 0x63, 0x04, 0xeb, 0x84, 0xa3, 0x9c, 0x77, 0x82, 0xcf, 0xae,
0xb2, 0xf6, 0x98, 0x19, 0x74, 0x39, 0x68, 0x2e, 0xdb, 0xfc, 0x57, 0x5b, 0x0f, 0xb1, 0x09, 0xcf, 0xf0, 0xdc, 0xc4,
0x28, 0xb7, 0xc6, 0xa8, 0xc3, 0x70, 0x4e, 0x90, 0xdb, 0xd4, 0x42, 0xb3, 0xfe, 0xf0, 0x6f, 0x96, 0xb2, 0x62, 0xbf,
0x3a, 0x4a, 0xbe, 0xce, 0xa8, 0x11, 0x8f, 0x71, 0xdc, 0x9d, 0x5b, 0xd8, 0xc7, 0x5f, 0x10, 0x79, 0x9c, 0x51, 0x5a,
0xdf, 0xd8, 0x76, 0xe2, 0x01, 0xd9, 0xa5, 0xbc, 0xbc, 0xab, 0x8d, 0x7b, 0xeb, 0xe2, 0xfa, 0xed, 0x9e, 0x65, 0x94,
0x2c, 0xb3, 0xda, 0x78, 0x78, 0xb2, 0xe0, 0x8a, 0x94, 0xe3, 0xb7, 0x4f, 0x3d, 0x48, 0x78, 0xf8, 0x79, 0x3f, 0x27,
0x43, 0xfa, 0xa2, 0xc7, 0xaa, 0x0b, 0x14, 0x0d, 0xdb, 0xaf, 0x26, 0x1d, 0x5d, 0xe1, 0x5f, 0xa7, 0xc7, 0x99, 0x3d,
0x65, 0xfe, 0x86, 0xdc, 0x95, 0xf3, 0xa2, 0xb8, 0xdd, 0x0a, 0x1a, 0xb6, 0x9d, 0x77, 0xe7, 0x59, 0xb6, 0x54, 0xeb,
0xc6, 0x9a, 0xdf, 0x0b, 0x5e, 0x6f, 0xaf, 0x54, 0x29, 0x52, 0x9e, 0xe4, 0xd1, 0x70, 0x74, 0xd9, 0xf2, 0xd6, 0xed,
0xd7, 0x7b, 0x26, 0x3c, 0x59, 0x9d, 0xec, 0x12, 0x94, 0xf6, 0x78, 0x8e, 0xb1, 0xea, 0xcf, 0xb8, 0x55, 0xbb, 0x8a,
0x13, 0x62, 0xbd, 0x0b, 0xeb, 0xf6, 0xad, 0xec, 0x09, 0x97, 0x2c, 0x3c, 0x7c, 0x2a, 0xee, 0xa9, 0x96, 0xf1, 0x9a,
0x8e, 0xc0, 0xb4, 0x85, 0xd5, 0xa5, 0xe9, 0x29, 0xb3, 0x32, 0xdf, 0xe7, 0x87, 0x39, 0x2d, 0x90, 0x0d, 0x3c, 0xca,
0xf4, 0x7d, 0xf7, 0x24, 0xd7, 0x7d, 0xf9, 0xbc, 0xdb, 0x2c, 0xce, 0x08, 0xfc, 0xdd, 0x1d, 0x12, 0x28, 0x53, 0xcd,
0x3e, 0x45, 0x7d, 0x72, 0xed, 0xa4, 0xc3, 0x57, 0x8e, 0x2d, 0x4d, 0x0c, 0x64, 0xb4, 0xb0, 0x58, 0xbe, 0xff, 0x23,
0x0b, 0xaf, 0xe8, 0xec, 0x06, 0xf9, 0xe6, 0xab, 0x4b, 0x32, 0x3b, 0x6a, 0xe6, 0x6f, 0x63, 0xbc, 0x35, 0x59, 0xdc,
0xb5, 0x5b, 0x68, 0x13, 0x93, 0x71, 0x4c, 0xc0, 0xb5, 0x87, 0x61, 0x4b, 0xd6, 0x3a, 0x79, 0xc5, 0xdc, 0x6d, 0x4b,
0x7c, 0xc9, 0x2c, 0xf4, 0x90, 0x7f, 0xf6, 0x2b, 0x35, 0x9d, 0xc4, 0x3b, 0x49, 0x1e, 0xd9, 0xb9, 0x22, 0x0f, 0x98,
0x5b, 0xbd, 0x8a, 0xdc, 0x6e, 0x4d, 0x3b, 0x51, 0x2b, 0x73, 0x91, 0xd5, 0xee, 0xe9, 0xa4, 0x02, 0xe7, 0xf8, 0x1c,
0x66, 0xd6, 0xcd, 0xaf, 0x37, 0x2b, 0x98, 0xfa, 0xd6, 0xa5, 0x05, 0x30, 0x9a, 0x1d, 0x30, 0x7e, 0xc8, 0x7f, 0xd2,
0x42, 0xef, 0xa5, 0xa6, 0xa4, 0x7f, 0xdc, 0xc6, 0x8b, 0x9e, 0xdd, 0xd6, 0xc1, 0x7f, 0xe7, 0xdb, 0xbf, 0x53, 0x55,
0x35, 0xad, 0xe6, 0x15, 0x5c, 0xef, 0x23, 0xd8, 0x63, 0x74, 0xe5, 0x56, 0xfd, 0x0d, 0xb1, 0xf0, 0x87, 0xcb, 0xce,
0xd5, 0x1e, 0x5c, 0x97, 0xb4, 0x5f, 0xf8, 0x49, 0xbb, 0x8f, 0xd5, 0xc1, 0xcd, 0x3c, 0x91, 0x33, 0xdd, 0x23, 0xa2,
0xf6, 0x56, 0xd4, 0xec, 0x0a, 0x60, 0x7c, 0x2b, 0xfd, 0xaa, 0xcb, 0xb3, 0xe3, 0xdd, 0x35, 0x91, 0xd6, 0xd5, 0x1b,
0x74, 0xee, 0x99, 0x4e, 0x16, 0xd4, 0x65, 0x94, 0xb9, 0xae, 0xe1, 0x6c, 0xf0, 0x7c, 0x03, 0xc7, 0xdb, 0xca, 0x99,
0xc2, 0x81, 0x97, 0xac, 0xca, 0xd7, 0xda, 0x6e, 0xf9, 0x71, 0xfc, 0x14, 0xb3, 0xd2, 0xa5, 0x93, 0xc7, 0xd4, 0xf9,
0x59, 0xce, 0x55, 0xd9, 0x1f, 0xc8, 0xd0, 0x39, 0x5f, 0x94, 0xc5, 0x79, 0xc8, 0x89, 0xa1, 0x28, 0xce, 0xd1, 0xe4,
0xc7, 0xb4, 0x4c, 0xfb, 0xbd, 0x56, 0x11, 0x13, 0xbb, 0x1f, 0x9e, 0x59, 0xb4, 0x71, 0xd2, 0xdd, 0xf2, 0x85, 0xa6,
0xff, 0x3e, 0x7b, 0xef, 0xd9, 0xf8, 0xd8, 0x5c, 0x90, 0xf7, 0x78, 0xea, 0xbe, 0x8f, 0x89, 0x4f, 0xe3, 0xd8, 0xfe,
0x9b, 0x1e, 0x2f, 0xeb, 0x8c, 0xfd, 0x92, 0xe7, 0x75, 0x66, 0x6b, 0x48, 0xdd, 0x47, 0xd1, 0x13, 0x0b, 0x66, 0xf6,
0xc7, 0x14, 0x70, 0xbf, 0x17, 0x39, 0xf6, 0x94, 0x6b, 0x8e, 0xe4, 0x16, 0x59, 0x9f, 0x73, 0x61, 0x6c, 0x77, 0x9c,
0x04, 0x55, 0x9f, 0x4f, 0xcb, 0xe7, 0x57, 0xb4, 0xbd, 0xff, 0x33, 0xdc, 0x9d, 0xf7, 0xbe, 0x76, 0xd6, 0x9f, 0xf2,
0xde, 0xab, 0x2f, 0x6f, 0xfe, 0xdc, 0xfa, 0xe0, 0x75, 0x51, 0x8b, 0x54, 0x9f, 0x93, 0x88, 0x6c, 0x57, 0x5e, 0xfc,
0x24, 0xab, 0xdf, 0xdc, 0x4f, 0xbf, 0x3d, 0x39, 0x30, 0xdf, 0xf5, 0x9a, 0x56, 0xf3, 0xfe, 0x8d, 0x67, 0xb3, 0x8e,
0xec, 0xef, 0xb9, 0x77, 0x7f, 0xd3, 0xf7, 0xca, 0xef, 0x09, 0xe1, 0x7f, 0xac, 0x6d, 0xab, 0xf5, 0x4e, 0xcf, 0x71,
0xac, 0x56, 0x5f, 0xfa, 0xd8, 0x23, 0x42, 0x94, 0x5d, 0xfc, 0xc1, 0xce, 0xd6, 0xf8, 0xe4, 0x15, 0xdf, 0x34, 0x85,
0x9c, 0x19, 0xb2, 0x6e, 0xbf, 0x4b, 0x51, 0x09, 0xea, 0x3e, 0x62, 0x1d, 0xbb, 0xdb, 0x54, 0x62, 0xd1, 0xe5, 0xce,
0xff, 0x9b, 0x16, 0x44, 0x1a, 0x7c, 0xba, 0x7d, 0xf5, 0xa0, 0x6f, 0x96, 0xb7, 0xd9, 0x9c, 0xd8, 0x8a, 0x67, 0x17,
0x16, 0x4f, 0xe2, 0x7d, 0x3a, 0x41, 0x70, 0x43, 0x1b, 0xbf, 0xa3, 0x49, 0xc3, 0xb2, 0xce, 0xbd, 0x2f, 0xf5, 0x2b,
0xdc, 0x79, 0x03, 0xa6, 0xb6, 0x4b, 0xef, 0x7f, 0x5c, 0x3f, 0xc5, 0xdc, 0xec, 0x49, 0xbe, 0xa5, 0x85, 0x3e, 0x4f,
0xb3, 0x55, 0xeb, 0xfd, 0xc0, 0x3d, 0x1e, 0x37, 0xc3, 0x76, 0x57, 0x4e, 0xad, 0xdc, 0x7b, 0xc5, 0x23, 0x60, 0xee,
0xca, 0xd4, 0x58, 0xf1, 0x1a, 0x61, 0x6e, 0xa1, 0x18, 0xff, 0xf4, 0x0d, 0x2c, 0x0f, 0xe7, 0x49, 0x6c, 0x66, 0xb0,
0xfa, 0x77, 0xfa, 0x88, 0xcc, 0x77, 0xed, 0x00, 0x8b, 0x3a, 0xbf, 0xdd, 0xc2, 0x47, 0x15, 0x0e, 0xff, 0xb3, 0x5d,
0x62, 0xc0, 0xff, 0xc4, 0x9d, 0xeb, 0x49, 0x10, 0x63, 0x95, 0x78, 0xa3, 0x61, 0x43, 0x43, 0xbc, 0x69, 0x94, 0xae,
0xe8, 0x99, 0x0d, 0x4a, 0xa2, 0xba, 0x0d, 0x17, 0x9f, 0x3d, 0x39, 0x13, 0xb1, 0x3e, 0x9f, 0xb5, 0xb6, 0x75, 0x8e,
0x69, 0x56, 0xc9, 0x82, 0x0f, 0x1a, 0xfe, 0xdf, 0x7f, 0xde, 0xb1, 0x60, 0xd8, 0x7c, 0xe4, 0x5d, 0x88, 0xdf, 0xc7,
0x9b, 0xaf, 0xd6, 0x1e, 0xba, 0xfe, 0x5a, 0x52, 0xe5, 0x48, 0xd8, 0x8a, 0xee, 0xd3, 0x21, 0xd9, 0xeb, 0x0b, 0x22,
0xa2, 0xd8, 0x23, 0xff, 0x31, 0xb0, 0xdd, 0x5f, 0xf8, 0x4c, 0x22, 0x72, 0xd7, 0xc1, 0x68, 0xe5, 0x3f, 0xd1, 0x72,
0x05, 0x06, 0x4e, 0x52, 0x57, 0x2e, 0x18, 0x15, 0x4d, 0x48, 0x73, 0xca, 0x99, 0xbb, 0xe8, 0xe2, 0xdb, 0x72, 0x3b,
0x83, 0x6d, 0xeb, 0x26, 0xf1, 0x26, 0xea, 0x7d, 0x5b, 0x24, 0xe5, 0x79, 0x7b, 0xa1, 0x6c, 0xe7, 0x8a, 0x7b, 0x9f,
0x2c, 0xc2, 0x76, 0x65, 0xaf, 0x3e, 0x15, 0x1c, 0x15, 0xfc, 0x2d, 0x57, 0xb8, 0x71, 0x9d, 0xfc, 0xd2, 0x3f, 0x5e,
0xb6, 0xd7, 0x5d, 0x19, 0x3b, 0x9f, 0x2c, 0x61, 0x98, 0xf1, 0xed, 0xb7, 0x6f, 0x5b, 0x8a, 0x5b, 0x7c, 0xe4, 0x9a,
0xaf, 0x95, 0x66, 0xfa, 0xaf, 0x4e, 0xb9, 0xad, 0x0f, 0x70, 0x4b, 0xeb, 0x54, 0x74, 0x9a, 0xb8, 0xb1, 0xec, 0x12,
0x6f, 0x51, 0xef, 0xe3, 0x88, 0xc7, 0x73, 0xc4, 0x2f, 0x6a, 0x44, 0x24, 0xab, 0xe7, 0xb9, 0x64, 0x37, 0x2d, 0xd9,
0x35, 0xa3, 0xf8, 0xd7, 0xee, 0xff, 0x73, 0xa4, 0xca, 0x3e, 0xc9, 0x6b, 0xce, 0x4c, 0x3a, 0x51, 0x13, 0xfd, 0xfb,
0xa7, 0x94, 0xdb, 0xdf, 0xc8, 0x6f, 0x47, 0x6f, 0xdb, 0xbc, 0x2c, 0x9c, 0x76, 0xa1, 0x50, 0xe6, 0x06, 0xaf, 0xce,
0xcc, 0x0b, 0x51, 0x42, 0x81, 0x17, 0x18, 0x4a, 0xdb, 0x57, 0xf8, 0xef, 0x4a, 0x3b, 0x30, 0xe9, 0xea, 0x85, 0xef,
0x5b, 0xda, 0x9e, 0xda, 0xaf, 0x0f, 0x0d, 0xfd, 0xba, 0xc3, 0x2f, 0x8d, 0x51, 0xa7, 0xf6, 0xc8, 0x26, 0x0b, 0x0d,
0x9e, 0x30, 0xef, 0xf3, 0xe2, 0x73, 0x6c, 0x9f, 0xb0, 0xaf, 0xb6, 0xf1, 0x12, 0xfa, 0x57, 0x3d, 0x41, 0x90, 0x6d,
0xe6, 0xab, 0xe3, 0xb5, 0x17, 0x3f, 0x7f, 0xea, 0x79, 0xae, 0x2a, 0x32, 0xe7, 0x9c, 0xc8, 0xbf, 0x3f, 0x92, 0xb9,
0x8a, 0xe6, 0x1a, 0x9b, 0xa6, 0x18, 0xf3, 0x6f, 0x7e, 0xc2, 0xe5, 0x7a, 0x7a, 0xfe, 0x0a, 0xc1, 0x07, 0xf3, 0x35,
0xb7, 0x48, 0x88, 0xbf, 0x0f, 0x8f, 0x89, 0x6f, 0xdb, 0xdc, 0x5b, 0x6f, 0xd9, 0xd4, 0x59, 0x5b, 0xb8, 0xf2, 0x4e,
0xfa, 0x05, 0x25, 0x37, 0x79, 0xc1, 0xd5, 0x1f, 0x5f, 0xce, 0x33, 0xc8, 0xdf, 0xf6, 0xee, 0x67, 0xa9, 0xde, 0xd2,
0x29, 0x91, 0xf5, 0x99, 0x0d, 0xbe, 0x2f, 0x5a, 0xe7, 0x45, 0xb2, 0x38, 0x44, 0x48, 0x5d, 0xff, 0xdd, 0x67, 0x33,
0x8b, 0xd7, 0x75, 0xa7, 0x5b, 0x3c, 0xdf, 0xb9, 0x47, 0xc7, 0x2c, 0x0e, 0xf5, 0xaa, 0x6c, 0x0d, 0xf3, 0xb6, 0x3d,
0xcb, 0xdd, 0x1f, 0xd9, 0x22, 0xd6, 0x33, 0xff, 0x8c, 0x8a, 0x8d, 0x4e, 0xf6, 0x39, 0xdd, 0x6f, 0xab, 0x6e, 0xf1,
0xa5, 0x1c, 0x36, 0xff, 0xbb, 0x92, 0x63, 0x7b, 0xdf, 0x93, 0xcb, 0x5d, 0xb3, 0x7f, 0x1a, 0xd6, 0x9d, 0xd3, 0xf5,
0xfd, 0xf1, 0xbe, 0x79, 0xde, 0xc6, 0x77, 0xb7, 0x2e, 0x18, 0x6d, 0x38, 0x5c, 0xcc, 0x3b, 0x4b, 0x25, 0xed, 0xe1,
0xbd, 0x3e, 0x26, 0xee, 0x8e, 0x58, 0x36, 0x1d, 0xf7, 0xa9, 0xae, 0xf1, 0x7f, 0xca, 0x05, 0xcd, 0x59, 0x9e, 0xa5,
0x55, 0xbb, 0xd5, 0x5e, 0x5b, 0xf8, 0x3b, 0xd7, 0x82, 0xdb, 0x41, 0x5c, 0x80, 0x39, 0x36, 0x77, 0x6f, 0xc5, 0x65,
0xce, 0xd4, 0x32, 0x75, 0xae, 0x85, 0xe9, 0x85, 0x9b, 0x9e, 0x73, 0x2f, 0x3e, 0xb0, 0xdb, 0x72, 0x56, 0xdf, 0xd4,
0xe0, 0x67, 0xaf, 0x27, 0x76, 0x45, 0x6d, 0xbb, 0x79, 0x3d, 0xc8, 0xfe, 0xd2, 0x96, 0xe3, 0xb1, 0x9c, 0xf3, 0x44,
0xfc, 0xef, 0xf8, 0xb4, 0x06, 0xbf, 0x58, 0xb3, 0x94, 0xc3, 0x6c, 0x91, 0x4b, 0x8b, 0x4a, 0x83, 0x97, 0xa9, 0xa8,
0xb3, 0x7d, 0xc5, 0x8d, 0xc9, 0xd3, 0x7e, 0xdf, 0xac, 0xdc, 0x73, 0x99, 0xeb, 0xde, 0xd3, 0x98, 0xfe, 0xe3, 0x13,
0xaf, 0xe8, 0x04, 0x3d, 0xd8, 0x9e, 0x5f, 0x30, 0xfb, 0xc6, 0xdc, 0x84, 0x7f, 0x2e, 0xb1, 0xef, 0xdd, 0xaf, 0xa9,
0x15, 0xfe, 0x9f, 0x95, 0x55, 0xcb, 0xfd, 0xa8, 0x3e, 0xa7, 0x50, 0x2b, 0x68, 0xc2, 0xeb, 0xb5, 0xa7, 0x4c, 0xf5,
0x0e, 0xff, 0x8d, 0xfc, 0xce, 0x28, 0xaa, 0x75, 0x8b, 0x9f, 0xd1, 0xe5, 0x94, 0xfb, 0xed, 0xe5, 0xe9, 0xc2, 0x32,
0x55, 0xdc, 0xcc, 0x4d, 0x8d, 0x93, 0x37, 0xee, 0x49, 0x78, 0x1b, 0x7a, 0xbb, 0x37, 0x4d, 0xbd, 0x52, 0x6c, 0x63,
0xc5, 0x72, 0x89, 0x6d, 0xfd, 0x33, 0x7e, 0x2b, 0xb8, 0xf0, 0xe5, 0x2d, 0x8d, 0xeb, 0x50, 0x13, 0x59, 0xa7, 0x11,
0xa6, 0xf0, 0x22, 0xed, 0xed, 0x3b, 0x97, 0xf2, 0x49, 0x09, 0x37, 0xaa, 0x13, 0xe4, 0xb7, 0x64, 0x26, 0x66, 0xef,
0xde, 0x7d, 0x66, 0x91, 0xcb, 0xcd, 0x7f, 0x13, 0x4b, 0xdc, 0xac, 0xea, 0x22, 0x7b, 0x14, 0x3f, 0x1e, 0x7f, 0xf1,
0xc1, 0xed, 0xf3, 0xb6, 0xea, 0x2f, 0x17, 0x67, 0xbf, 0x9d, 0xad, 0x5b, 0x62, 0x7b, 0xbe, 0x9b, 0x31, 0x7f, 0xf9,
0x81, 0xc0, 0x7e, 0x16, 0xdf, 0xb7, 0x79, 0x0b, 0xeb, 0x8e, 0x48, 0xdf, 0x77, 0xbf, 0xa5, 0xe0, 0x77, 0x73, 0x7d,
0xd3, 0x6f, 0xf6, 0x82, 0xb2, 0x9a, 0x98, 0x07, 0x8f, 0xf7, 0xfc, 0x60, 0x99, 0xd3, 0xae, 0x3f, 0x31, 0xea, 0xca,
0x03, 0xb1, 0xaa, 0x6b, 0x53, 0x5f, 0xd6, 0x1c, 0x8c, 0xbf, 0x6c, 0x1e, 0x93, 0x5f, 0x7d, 0xd7, 0xbb, 0x64, 0xf2,
0x66, 0xa9, 0x1d, 0x47, 0x7a, 0x39, 0x7f, 0x45, 0x71, 0xcd, 0xe2, 0x5c, 0x3f, 0xf5, 0xb6, 0x6a, 0xa4, 0x78, 0x89,
0xa8, 0x70, 0x4d, 0x3e, 0x47, 0xce, 0x9b, 0x53, 0x3a, 0x86, 0xc7, 0xf6, 0x09, 0xcc, 0x8e, 0x39, 0xbb, 0xcb, 0xb2,
0xb0, 0xaf, 0x63, 0x4e, 0xb1, 0xc5, 0xf1, 0x23, 0x15, 0x1f, 0x44, 0x7d, 0x7f, 0x5f, 0x2a, 0x8f, 0x0c, 0x3e, 0x68,
0x69, 0xf3, 0xfd, 0x7d, 0xe7, 0xab, 0x62, 0xed, 0x4b, 0x8a, 0x9a, 0xef, 0x6e, 0x86, 0x9d, 0x50, 0x99, 0x95, 0xd8,
0xb7, 0xeb, 0xc1, 0x0b, 0xdb, 0xd7, 0xcb, 0xbb, 0xef, 0x79, 0x1b, 0x5e, 0xb1, 0x9c, 0xf0, 0xea, 0x2e, 0xbf, 0xf2,
0xdf, 0x7d, 0x72, 0xd9, 0x9b, 0xf6, 0x5e, 0xba, 0xd2, 0x67, 0x7a, 0x7a, 0xa1, 0xa6, 0x93, 0x70, 0xf9, 0x59, 0x23,
0xe9, 0xa5, 0x97, 0x57, 0x57, 0x99, 0xec, 0x9b, 0x93, 0xb6, 0x49, 0xe4, 0xc9, 0xbb, 0xfd, 0x0c, 0x47, 0xff, 0x86,
0xac, 0x64, 0xe7, 0xbf, 0x16, 0xf0, 0x66, 0xc3, 0x7d, 0x9d, 0xeb, 0x3b, 0x8f, 0xb3, 0xee, 0xf6, 0xfa, 0x32, 0xc9,
0xa5, 0xed, 0xd9, 0x94, 0x13, 0x82, 0x8c, 0xeb, 0xdf, 0x78, 0x4b, 0x72, 0x8b, 0x79, 0x1e, 0x58, 0x37, 0x6d, 0xba,
0xff, 0xf4, 0xc9, 0x1b, 0xb6, 0xce, 0xde, 0x6e, 0xc5, 0xc4, 0x38, 0x8b, 0x69, 0xd3, 0x9d, 0x0f, 0xbb, 0x76, 0x69,
0x17, 0x96, 0x84, 0x6c, 0xec, 0xbe, 0xdb, 0x3d, 0xf5, 0x94, 0x55, 0xeb, 0x2e, 0x66, 0x95, 0x29, 0x77, 0x5c, 0x98,
0x7f, 0xe7, 0x57, 0xfb, 0x34, 0x58, 0xbc, 0xac, 0xda, 0xb6, 0xc2, 0xe5, 0x1c, 0xfb, 0xef, 0xf5, 0xc7, 0x9a, 0x45,
0xa3, 0x62, 0x73, 0xc4, 0x7f, 0x72, 0xd4, 0x1e, 0x79, 0x96, 0xfb, 0x6f, 0xba, 0xe8, 0xc3, 0xce, 0x05, 0xbb, 0x57,
0xcc, 0x54, 0xda, 0xf7, 0xe6, 0xc6, 0xbb, 0xdb, 0x95, 0xaa, 0x75, 0x33, 0xed, 0xd2, 0x2f, 0x7c, 0x6c, 0x11, 0xe1,
0xd8, 0xf5, 0xba, 0xe1, 0xe8, 0x35, 0xcd, 0x67, 0xf6, 0xf2, 0x4d, 0x16, 0xaa, 0xfc, 0xec, 0xcb, 0x2c, 0x0c, 0xfb,
0x3e, 0x2c, 0xf7, 0x2e, 0xcd, 0xd1, 0xf4, 0x10, 0xbb, 0x76, 0xf7, 0x05, 0xc7, 0xed, 0x87, 0x6a, 0xd2, 0x29, 0x5b,
0x72, 0x84, 0x16, 0xfb, 0x54, 0xca, 0xdd, 0xfb, 0xc6, 0x27, 0xff, 0xef, 0x53, 0xcc, 0xac, 0x6b, 0xa7, 0x74, 0x2b,
0x4c, 0xcb, 0xae, 0xb4, 0xac, 0x32, 0xbc, 0xb6, 0x48, 0x4a, 0x32, 0xf4, 0x02, 0x73, 0xa7, 0xc3, 0xbd, 0x5e, 0x73,
0x9b, 0xb7, 0xa1, 0x3c, 0x81, 0x2b, 0x7f, 0x1e, 0x0b, 0x75, 0x4b, 0x0e, 0x90, 0xb4, 0xb9, 0x76, 0x27, 0xf4, 0xe0,
0xae, 0x63, 0xc1, 0xdc, 0xea, 0x9a, 0x71, 0x4e, 0xc6, 0xb6, 0xaf, 0xdc, 0xff, 0x94, 0x37, 0xa8, 0x97, 0xc4, 0x15,
0xc4, 0xbe, 0xd7, 0x37, 0x39, 0x9d, 0x67, 0xb0, 0xac, 0x7c, 0xe5, 0x95, 0x47, 0x6c, 0xf7, 0xa6, 0xfc, 0xfc, 0x19,
0xd3, 0x11, 0xb5, 0xf2, 0xdc, 0x71, 0x46, 0x66, 0x8f, 0x96, 0x58, 0x16, 0xe1, 0xa7, 0x4c, 0x9f, 0x2d, 0x17, 0x09,
0x27, 0x9d, 0x4f, 0xca, 0x7d, 0xc4, 0x7a, 0x6d, 0x4a, 0xe7, 0xfb, 0x89, 0x71, 0xaa, 0x02, 0xeb, 0x12, 0x6d, 0x57,
0x2b, 0xc8, 0x9e, 0x3e, 0x75, 0xfd, 0xd5, 0x1e, 0xee, 0x19, 0x0b, 0x94, 0x75, 0x67, 0x72, 0x38, 0xc6, 0xdd, 0x67,
0x35, 0x73, 0x8a, 0x68, 0x6a, 0x3e, 0xbc, 0x43, 0xda, 0x7d, 0xb6, 0x48, 0xb7, 0xe9, 0x62, 0xfb, 0x1b, 0x11, 0x37,
0x5f, 0x38, 0xb4, 0x19, 0x15, 0x3c, 0x5c, 0xaa, 0xda, 0xa3, 0xb3, 0xf0, 0xcb, 0x7c, 0x0e, 0xcd, 0x1d, 0x57, 0x8e,
0xea, 0x98, 0xfc, 0x3f, 0x2e, 0x1e, 0x66, 0xf8, 0xfe, 0x74, 0x8f, 0xec, 0x89, 0x84, 0xb3, 0x7a, 0x65, 0x73, 0x92,
0x52, 0xe2, 0x0d, 0x2b, 0x3e, 0x4d, 0xdb, 0x95, 0x3e, 0x93, 0xa7, 0xe4, 0xc0, 0xa1, 0xd2, 0x3d, 0x92, 0x71, 0xbf,
0x7d, 0xa6, 0xd7, 0x2d, 0x33, 0x75, 0xd8, 0xd8, 0x36, 0xe7, 0x9f, 0xe2, 0x52, 0x93, 0xa2, 0x9c, 0x0d, 0xf5, 0x75,
0xce, 0xf1, 0x47, 0x26, 0x1e, 0x5d, 0x75, 0x7e, 0xe3, 0xcc, 0x55, 0xd9, 0x5e, 0x67, 0xfd, 0x17, 0xec, 0x28, 0x3a,
0xbe, 0x76, 0xda, 0x97, 0x95, 0x47, 0x8e, 0x58, 0x3d, 0xed, 0xb0, 0x6a, 0xcc, 0x75, 0x9f, 0xf0, 0x63, 0xfe, 0x77,
0x4f, 0x99, 0xca, 0x4f, 0x8f, 0x2f, 0x55, 0x17, 0xce, 0x77, 0x8b, 0x3e, 0x25, 0xd0, 0x9a, 0x9d, 0x99, 0x76, 0xe7,
0xf4, 0x84, 0x8a, 0x0f, 0x7e, 0xe7, 0x26, 0xcf, 0xd2, 0x75, 0x60, 0xe9, 0xc8, 0xeb, 0x4e, 0x9f, 0x2a, 0x34, 0x75,
0xdd, 0x63, 0x46, 0xb6, 0x0f, 0xfb, 0xb6, 0x35, 0x7d, 0x37, 0x58, 0xb5, 0xb8, 0x23, 0xa5, 0x69, 0x47, 0xc1, 0xee,
0xef, 0xf6, 0xc1, 0x1b, 0x3a, 0x55, 0x4c, 0x72, 0x1e, 0xef, 0x38, 0xac, 0xc1, 0x5b, 0x90, 0xe5, 0x1e, 0x92, 0x24,
0xa6, 0xff, 0xb3, 0xfe, 0xd8, 0xeb, 0x39, 0x13, 0xaf, 0x34, 0xa5, 0x7d, 0x61, 0x13, 0xf9, 0x29, 0x12, 0xb2, 0x4b,
0x72, 0x55, 0xb9, 0xb4, 0xf8, 0x56, 0xb3, 0x73, 0x8c, 0x56, 0x05, 0x25, 0xdd, 0x7b, 0x5e, 0x4c, 0xd8, 0x53, 0x7d,
0x59, 0x37, 0x22, 0x47, 0x59, 0x4f, 0xf0, 0xf7, 0xc4, 0xe2, 0x9c, 0xe6, 0xdc, 0x8d, 0x25, 0x9d, 0xaa, 0x7c, 0x4a,
0x7b, 0xa6, 0xd7, 0xb7, 0xaf, 0x15, 0x7b, 0xb4, 0xdf, 0xcf, 0xee, 0xd6, 0x34, 0x9d, 0x8a, 0xbc, 0xef, 0x39, 0x3e,
0x89, 0x92, 0xed, 0x59, 0xfe, 0xe9, 0x47, 0xcb, 0x7a, 0x8c, 0xab, 0xa7, 0xed, 0x91, 0x66, 0xd9, 0x6b, 0x64, 0xde,
0xb0, 0x8d, 0x93, 0xc3, 0xff, 0x03, 0xab, 0x82, 0x0f, 0x8f, 0xfa, 0xc4, 0x93, 0xea, 0x42, 0x62, 0xfe, 0xcf, 0x15,
0x58, 0x84, 0xdc, 0x9d, 0xdf, 0x99, 0x29, 0xcf, 0x93, 0x3e, 0xd2, 0x7c, 0x7f, 0x65, 0xd6, 0xf2, 0xa4, 0xda, 0x6f,
0xd7, 0xd8, 0x3f, 0x4d, 0x7c, 0x7e, 0xde, 0x76, 0x77, 0x8f, 0xe5, 0x22, 0xae, 0xa4, 0xf8, 0x88, 0x45, 0x3b, 0xcf,
0xdb, 0x16, 0x2b, 0x6b, 0x59, 0x99, 0xed, 0xab, 0x2f, 0x51, 0x75, 0x4c, 0x35, 0xaf, 0x3d, 0x79, 0x6b, 0xf1, 0x96,
0xc4, 0xfb, 0x22, 0x55, 0xc1, 0xe7, 0x83, 0x8b, 0x0c, 0x9b, 0xeb, 0xd6, 0x2e, 0xd2, 0xd8, 0xfe, 0xfa, 0xdd, 0xed,
0xfe, 0x09, 0xee, 0x9c, 0x86, 0xe9, 0x77, 0x3b, 0xfd, 0xa4, 0x16, 0x94, 0x9d, 0xc9, 0xbd, 0x7c, 0x4e, 0xcf, 0x2e,
0xf4, 0xcc, 0x41, 0xdb, 0x75, 0xac, 0x3d, 0xd9, 0x77, 0x5c, 0xbe, 0x86, 0xdc, 0x51, 0x37, 0xe6, 0xfe, 0x5e, 0x56,
0xfe, 0xea, 0xa2, 0xdb, 0x2d, 0x76, 0xe3, 0x4b, 0xac, 0xa5, 0x93, 0x45, 0x16, 0xd9, 0x67, 0xaa, 0xb7, 0xa9, 0x1a,
0xc6, 0xcc, 0x16, 0xb1, 0x93, 0xeb, 0x4f, 0x77, 0x6d, 0xb3, 0x7b, 0xb0, 0x74, 0xef, 0x83, 0x94, 0x72, 0xd1, 0x4f,
0x55, 0x51, 0xcf, 0x9e, 0x36, 0xfd, 0xd6, 0xea, 0xdc, 0x9a, 0x7e, 0xc3, 0xe2, 0x81, 0x00, 0xe3, 0xa1, 0x07, 0x0b,
0x56, 0xcb, 0xdc, 0x69, 0x2c, 0x3c, 0xee, 0xaa, 0x79, 0x9d, 0xa9, 0x5f, 0x2d, 0x6f, 0xfd, 0x9a, 0xb7, 0xab, 0x59,
0x7d, 0x93, 0x3a, 0x7e, 0x5f, 0x57, 0xbf, 0x51, 0xa0, 0xbe, 0x34, 0x5b, 0x8a, 0xed, 0xf6, 0x53, 0xd3, 0xec, 0x97,
0xf1, 0xcf, 0x8b, 0xa3, 0x77, 0x97, 0x2a, 0x9a, 0x1d, 0xd7, 0xb8, 0x7a, 0x54, 0xf2, 0x6f, 0x9f, 0xc2, 0x12, 0xfe,
0xfb, 0x8d, 0x72, 0x47, 0x37, 0xb9, 0x09, 0xed, 0x3e, 0x70, 0xf4, 0x48, 0xd1, 0x99, 0x2b, 0x27, 0xb6, 0x2d, 0x12,
0x4e, 0xbc, 0x7c, 0x99, 0x61, 0x56, 0xb9, 0xee, 0x0e, 0xb5, 0xd4, 0xbf, 0x7d, 0x3f, 0xef, 0xb3, 0xf8, 0x2e, 0xbe,
0x60, 0xe5, 0x9b, 0xbf, 0xd7, 0xc5, 0xc2, 0x3e, 0x6b, 0xfb, 0x2c, 0x55, 0x1f, 0x2e, 0xad, 0x43, 0x9b, 0x62, 0x6f,
0xc5, 0x6f, 0x7c, 0xb3, 0xe0, 0xec, 0x95, 0x40, 0xa6, 0x3f, 0x0d, 0xb5, 0x29, 0x71, 0x9a, 0xa5, 0x82, 0x3f, 0xcd,
0xcf, 0x70, 0xfb, 0x6d, 0x7b, 0x32, 0xf9, 0xdd, 0x81, 0xc7, 0xe5, 0x57, 0x57, 0x95, 0xcb, 0xf5, 0x7e, 0xf4, 0x0a,
0x61, 0x7e, 0xec, 0x72, 0x4d, 0x83, 0xb7, 0x65, 0xae, 0x7b, 0x86, 0xcc, 0x6b, 0x4d, 0xa7, 0x3e, 0xb1, 0x57, 0xef,
0xb8, 0xc4, 0x67, 0x6a, 0xa7, 0x5e, 0x9a, 0x1c, 0x7a, 0x53, 0x79, 0x8e, 0x6f, 0xfd, 0x9a, 0x43, 0x9a, 0xbd, 0x89,
0x9f, 0xe6, 0xf8, 0x5f, 0x08, 0x57, 0x79, 0x6e, 0x58, 0xf6, 0xed, 0x88, 0x11, 0xf7, 0xca, 0xc7, 0xf5, 0x0b, 0x97,
0x9c, 0x10, 0xfe, 0xec, 0x69, 0xed, 0xc8, 0x7a, 0xef, 0x70, 0x23, 0x93, 0xc3, 0x93, 0xdf, 0x57, 0xdc, 0xc4, 0xaf,
0xb6, 0x7e, 0xeb, 0xb5, 0x8d, 0xcc, 0x5a, 0x62, 0xba, 0xbc, 0x41, 0x4d, 0xa9, 0xda, 0xd5, 0x45, 0xe8, 0x9d, 0x7c,
0xe8, 0x05, 0x87, 0x3d, 0x7e, 0xab, 0x76, 0xed, 0x63, 0xf8, 0xeb, 0xa6, 0x2c, 0xda, 0x7a, 0xaa, 0xec, 0x44, 0x9a,
0xe7, 0xf6, 0xf4, 0x9f, 0x3b, 0xb9, 0xbb, 0xc2, 0x17, 0x29, 0x0b, 0xae, 0xa8, 0xce, 0xbb, 0xaf, 0x79, 0xe4, 0x5f,
0xc4, 0xbf, 0x47, 0xd6, 0xb3, 0xf7, 0xee, 0xf7, 0xaa, 0xdf, 0x26, 0x67, 0xed, 0xcf, 0xb2, 0xef, 0xab, 0x5b, 0xa8,
0xd9, 0xc3, 0x93, 0x95, 0xdd, 0x91, 0x69, 0xab, 0x27, 0x9d, 0x9f, 0xb0, 0x88, 0x73, 0xaf, 0x44, 0x78, 0x71, 0x40,
0xf6, 0xd4, 0xed, 0x57, 0xfa, 0x9c, 0xca, 0xef, 0xdd, 0xca, 0x37, 0xb4, 0x2e, 0x57, 0x94, 0x98, 0x33, 0xf3, 0xee,
0x86, 0xbf, 0xb5, 0x5f, 0x75, 0x6e, 0x29, 0x4d, 0x6d, 0x17, 0x3c, 0xd1, 0x9b, 0x32, 0x55, 0xeb, 0xce, 0xf2, 0x9b,
0x55, 0x0c, 0xe7, 0xbf, 0x29, 0x30, 0x48, 0x2d, 0x32, 0x36, 0x0d, 0xbf, 0xb8, 0xe5, 0x4e, 0xa7, 0x46, 0x6f, 0xac,
0x83, 0x9a, 0x4f, 0xe4, 0x76, 0xa1, 0x79, 0x65, 0xeb, 0x16, 0xf5, 0xbd, 0x62, 0x2b, 0xa8, 0x3e, 0x21, 0x27, 0x7b,
0x9b, 0xf7, 0x83, 0xd3, 0xa6, 0xac, 0x57, 0xd2, 0x17, 0xce, 0xf7, 0x7e, 0x3a, 0xbb, 0xe7, 0xb8, 0xef, 0x51, 0x77,
0xc1, 0xeb, 0x57, 0xde, 0x78, 0xf0, 0x07, 0x88, 0xfb, 0x6c, 0x3a, 0x59, 0x1c, 0xfd, 0xf2, 0xd0, 0x07, 0x6d, 0x23,
0x9d, 0x69, 0x27, 0x05, 0x96, 0xf1, 0x9a, 0x14, 0x95, 0xbf, 0xd8, 0xf1, 0xd4, 0x7d, 0x2b, 0x4f, 0xc5, 0x82, 0xa3,
0xda, 0xc5, 0x1a, 0x7b, 0x3e, 0x6f, 0x9f, 0x73, 0xbd, 0xee, 0x73, 0x0f, 0x83, 0x4b, 0xcf, 0xcd, 0xc9, 0x6f, 0x3d,
0xdf, 0xbd, 0xfb, 0x7e, 0xe8, 0xe0, 0x6e, 0x9e, 0xb6, 0x8e, 0xbf, 0x0a, 0xfc, 0x36, 0xb7, 0xfd, 0xd2, 0xce, 0xeb,
0x17, 0x4c, 0xd3, 0x39, 0xd7, 0x70, 0xe9, 0xd3, 0xd4, 0x4d, 0xa9, 0x1f, 0x2c, 0x7c, 0xe3, 0x12, 0x4e, 0xf9, 0x7e,
0x7f, 0xc2, 0xb3, 0xeb, 0xa4, 0x53, 0xe9, 0xb1, 0x4d, 0xf7, 0x58, 0x57, 0x36, 0xfd, 0x3e, 0x65, 0x9b, 0xb1, 0x91,
0x61, 0x14, 0x8c, 0x82, 0x51, 0x30, 0x0a, 0x46, 0xc1, 0x28, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x8c, 0x82, 0x51, 0x30,
0x0a, 0x46, 0xc1, 0x28, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x8c, 0x82, 0x51, 0x40, 0x73, 0x90, 0x5a, 0x5c, 0x90, 0x91,
0x9f, 0x9b, 0xaa, 0x90, 0x5f, 0x92, 0xa8, 0x90, 0x92, 0x9a, 0x96, 0x93, 0x58, 0x92, 0xaa, 0x30, 0x2a, 0x36, 0x2a,
0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0x2a, 0x36, 0xb4, 0xc4, 0x00,
};
static const uint8_t SKEWED[] = {
0x2d, 0x97, 0x79, 0xf0, 0x97, 0x55, 0x15, 0xc6, 0x2d, 0x0a, 0xc5, 0x25, 0x25, 0x1b, 0x9d, 0x6c, 0xcc, 0xe3, 0xd8,
0xf0, 0x07, 0x4c, 0x8e, 0x96, 0x63, 0xe2, 0x16, 0x90, 0x26, 0x6a, 0x35, 0x14, 0x2a, 0xc5, 0xe8, 0xc8, 0x35, 0xaf,
0x7a, 0x5d, 0xce, 0x51, 0xba, 0x1a, 0x82, 0x4c, 0x63, 0x2a, 0x69, 0xa6, 0xe0, 0xa8, 0x8c, 0xb8, 0x11, 0x1a, 0x03,
0x29, 0x2e, 0x29, 0xa2, 0x69, 0x2e, 0x8c, 0x1a, 0x05, 0x3f, 0xad, 0x46, 0x74, 0xc4, 0x22, 0xb7, 0x18, 0xd3, 0x16,
0x74, 0x10, 0xd1, 0x98, 0xac, 0xe7, 0x73, 0xbe, 0xf2, 0x63, 0xbe, 0xdf, 0xef, 0xfb, 0xbe, 0xf7, 0xbd, 0xf7, 0x2c,
0xcf, 0x79, 0xce, 0x73, 0xa2, 0x37, 0xf3, 0x62, 0xad, 0xd6, 0xe2, 0xbd, 0x4d, 0xa8, 0x2d, 0xfa, 0x3e, 0xde, 0x7b,
0x6b, 0xd6, 0xad, 0xb8, 0x7b, 0x09, 0xd7, 0xf3, 0x28, 0xad, 0x78, 0x44, 0xf3, 0x68, 0x25, 0xf4, 0x82, 0x45, 0xd7,
0xb3, 0xda, 0x43, 0x1f, 0xc5, 0x9e, 0xd0, 0x97, 0x5d, 0x5a, 0xb4, 0x4b, 0x58, 0x78, 0xdb, 0xb7, 0x9b, 0xf5, 0x28,
0xd6, 0x3b, 0xaf, 0x15, 0xf3, 0x1e, 0xb5, 0xd9, 0x5c, 0x8f, 0xd7, 0xa2, 0x0f, 0xd5, 0xf2, 0x78, 0xf7, 0x56, 0xce,
0x2a, 0x5e, 0x6a, 0xad, 0xad, 0x1e, 0xe3, 0x75, 0xad, 0x47, 0xd1, 0xda, 0xd6, 0xf4, 0x15, 0xd3, 0x2d, 0x22, 0x7a,
0x75, 0x5d, 0x55, 0x1d, 0x12, 0xd5, 0x8e, 0x73, 0x0f, 0xed, 0x50, 0xb4, 0x58, 0xdb, 0x37, 0x9d, 0x58, 0xe3, 0x56,
0xad, 0xd7, 0x06, 0xa1, 0x45, 0xd3, 0x4b, 0x2d, 0xda, 0x5f, 0x26, 0xb4, 0xae, 0x9d, 0xab, 0x75, 0xad, 0xd3, 0x6b,
0xf2, 0xa6, 0xd7, 0xa8, 0xdd, 0xc7, 0x58, 0x95, 0xd9, 0xba, 0x3b, 0x24, 0xdf, 0x46, 0xba, 0x95, 0x16, 0xb2, 0x4b,
0xe7, 0x45, 0x9b, 0x6e, 0xde, 0xfc, 0xf6, 0x43, 0xd7, 0x85, 0xc9, 0xab, 0xf6, 0x57, 0x59, 0xed, 0xc3, 0x65, 0x83,
0xce, 0x97, 0x2d, 0xda, 0x42, 0xeb, 0x88, 0x40, 0x8f, 0xc7, 0xe4, 0xbb, 0x36, 0x6d, 0xae, 0xa8, 0x5c, 0x25, 0xc3,
0xaa, 0x36, 0xd0, 0x6f, 0xfd, 0x23, 0x78, 0x66, 0x55, 0x6e, 0x1e, 0xd1, 0x8b, 0x2c, 0xb2, 0x1f, 0xd6, 0xbd, 0xcc,
0x1e, 0x96, 0xe9, 0x17, 0xd6, 0x3e, 0x59, 0x2b, 0x4d, 0xd1, 0xd2, 0x4a, 0xc5, 0xad, 0x17, 0x1f, 0x5a, 0xad, 0x6d,
0x0c, 0x7f, 0x74, 0xb7, 0xee, 0xf8, 0xf6, 0x07, 0xeb, 0xe3, 0x06, 0xed, 0x2b, 0x03, 0xf1, 0xae, 0x6a, 0xaf, 0xbf,
0xeb, 0xd0, 0x62, 0xda, 0x68, 0x92, 0x5e, 0xf3, 0xd2, 0x74, 0x4f, 0x6e, 0x34, 0x57, 0x30, 0xc2, 0x8f, 0xd4, 0x16,
0x79, 0x75, 0x4f, 0x9d, 0x17, 0x25, 0xec, 0xe4, 0x6a, 0x6b, 0x6b, 0xd7, 0xa2, 0x8a, 0xf7, 0x85, 0xe8, 0xcb, 0x74,
0x9d, 0x75, 0x80, 0x0e, 0xab, 0x3b, 0xe8, 0x51, 0x89, 0x47, 0x9b, 0x55, 0xe5, 0x58, 0x36, 0x12, 0x54, 0x65, 0xf0,
0x4c, 0x25, 0xd7, 0xdb, 0x24, 0x8f, 0xcc, 0xb0, 0x16, 0x7b, 0xb5, 0x6a, 0xed, 0x70, 0xc5, 0xa5, 0x96, 0x6e, 0x3a,
0x82, 0x5c, 0x2b, 0xca, 0xfd, 0xc5, 0xee, 0x33, 0x5d, 0x89, 0x5e, 0x14, 0x32, 0x6e, 0x8a, 0xde, 0x7f, 0x49, 0x56,
0x0a, 0x14, 0xe5, 0x90, 0x57, 0x3d, 0xd6, 0x44, 0xf8, 0x6d, 0x5d, 0x89, 0x7b, 0x5b, 0x10, 0x50, 0x34, 0x2f, 0x2d,
0x44, 0x5e, 0xdb, 0x3d, 0x7b, 0x7f, 0x08, 0x4e, 0x0a, 0x6c, 0x74, 0x23, 0x64, 0xe5, 0x12, 0xf9, 0x6f, 0x02, 0xcb,
0x2b, 0x3e, 0x96, 0xa0, 0xd6, 0xae, 0x84, 0x68, 0x1d, 0x59, 0xd1, 0x8b, 0x24, 0x64, 0xa1, 0x1c, 0x2f, 0x56, 0xff,
0xe6, 0xb1, 0x8d, 0x70, 0xb1, 0x61, 0x85, 0x96, 0x09, 0x72, 0x7e, 0x94, 0x37, 0x6b, 0x06, 0x0e, 0x14, 0x7d, 0xfd,
0x92, 0x8f, 0x02, 0x80, 0x11, 0x97, 0x32, 0xbb, 0x5d, 0xa8, 0x3c, 0x29, 0x09, 0x72, 0xf2, 0xa1, 0xe2, 0xb7, 0x2a,
0xd0, 0x4a, 0xaf, 0x7d, 0x17, 0x58, 0xcc, 0x27, 0x9d, 0x2c, 0x55, 0x4c, 0x46, 0xc9, 0x26, 0x85, 0x4c, 0xc0, 0xe8,
0x3b, 0xd7, 0x2a, 0x70, 0xe9, 0x52, 0x5b, 0x96, 0x8f, 0x57, 0x21, 0xb4, 0xbc, 0x25, 0x2c, 0xb5, 0xf2, 0x9c, 0xff,
0x51, 0xe9, 0x39, 0x5e, 0x89, 0x57, 0xfe, 0xea, 0xeb, 0x42, 0xb6, 0x82, 0x25, 0xe0, 0xcb, 0x4a, 0x61, 0x8f, 0x57,
0x0a, 0xa0, 0x53, 0xd2, 0xff, 0x22, 0x8b, 0xfa, 0xdd, 0x72, 0x40, 0xc7, 0x78, 0x4c, 0xee, 0xd6, 0xfa, 0xaf, 0x65,
0x41, 0xd4, 0xe3, 0x48, 0x30, 0xc1, 0xaf, 0x8d, 0x78, 0xbb, 0x71, 0xbe, 0x16, 0x0d, 0x70, 0x54, 0xfa, 0x52, 0x59,
0x17, 0x53, 0x74, 0x5f, 0xb1, 0x68, 0xf2, 0xb5, 0x39, 0x15, 0xa2, 0xed, 0xbb, 0xa0, 0xa3, 0x20, 0xe6, 0xb7, 0x1e,
0x29, 0xdc, 0x05, 0xa4, 0x7b, 0xfb, 0x9f, 0xf2, 0xd8, 0x95, 0x5b, 0x25, 0x24, 0xfa, 0xfe, 0xbe, 0x1f, 0x96, 0xd4,
0xb4, 0xa4, 0xb7, 0x45, 0xed, 0x04, 0x53, 0xaa, 0x04, 0x13, 0xcb, 0xc8, 0x28, 0x91, 0x9d, 0xca, 0xd8, 0x55, 0x38,
0x71, 0x30, 0xe7, 0x27, 0x5a, 0x98, 0x91, 0xda, 0xe7, 0x14, 0x34, 0x6a, 0xa9, 0xe0, 0x80, 0x5d, 0x5f, 0x41, 0xae,
0xd0, 0xe8, 0x32, 0xec, 0x88, 0xba, 0x84, 0x0a, 0x97, 0xa7, 0xbc, 0x4b, 0xa2, 0x7d, 0x27, 0x2a, 0xa6, 0x6f, 0x92,
0x05, 0x06, 0x20, 0x95, 0x6a, 0xb9, 0xda, 0xff, 0xa5, 0x7a, 0xac, 0xfd, 0x61, 0x2d, 0x15, 0xc2, 0xde, 0x95, 0xad,
0xde, 0xee, 0x28, 0xb6, 0xc8, 0x6f, 0x96, 0xcd, 0xb7, 0x41, 0x0b, 0x20, 0xba, 0x53, 0x57, 0x0d, 0xcb, 0xbb, 0xbd,
0xaf, 0x13, 0x40, 0x78, 0x91, 0xed, 0x72, 0x6f, 0x34, 0x29, 0x93, 0x8f, 0xa5, 0x43, 0x33, 0x8b, 0x65, 0xd9, 0x5a,
0xd5, 0xbe, 0x3f, 0x2f, 0x83, 0x74, 0x2b, 0xca, 0x51, 0x14, 0x97, 0x78, 0x42, 0x68, 0xa1, 0x98, 0x14, 0x7e, 0xaf,
0xfb, 0xc3, 0x49, 0xf2, 0x5e, 0x99, 0x14, 0x88, 0x47, 0x0a, 0x26, 0x7d, 0xc2, 0x09, 0x8a, 0x4d, 0x5c, 0x11, 0xa7,
0xc8, 0xb1, 0x7b, 0xea, 0x5b, 0x02, 0x77, 0x07, 0xc4, 0x03, 0x94, 0x41, 0x20, 0xfe, 0x61, 0xc7, 0x9a, 0x58, 0x63,
0x13, 0xb4, 0x9e, 0xa4, 0xab, 0x30, 0x15, 0xa2, 0x42, 0xc9, 0xad, 0x57, 0x88, 0x27, 0xea, 0x96, 0x58, 0xc1, 0x6d,
0x7b, 0x45, 0xc4, 0xa1, 0x88, 0x0a, 0xe0, 0x15, 0xe0, 0xe3, 0xbb, 0x3c, 0x6d, 0xf6, 0x16, 0x27, 0x1c, 0xff, 0x4d,
0xed, 0xa5, 0xd7, 0xbe, 0xe6, 0xd4, 0xa4, 0x00, 0xac, 0x10, 0x29, 0x2a, 0xba, 0xb5, 0x97, 0x98, 0x61, 0x8d, 0xa2,
0x2e, 0x5c, 0x89, 0x01, 0xcb, 0x37, 0x14, 0x59, 0x5d, 0xc8, 0x42, 0x31, 0x4e, 0xf2, 0x64, 0x83, 0x7b, 0xa6, 0xba,
0x70, 0x11, 0x5b, 0x29, 0x58, 0x41, 0x41, 0xa1, 0xd3, 0xe9, 0x04, 0xe6, 0xd9, 0xcf, 0x6a, 0xb9, 0x4a, 0x4d, 0x0f,
0xeb, 0x07, 0x3a, 0xff, 0x0c, 0x3f, 0x6c, 0xc4, 0x91, 0xef, 0x4d, 0x2d, 0x49, 0x06, 0xd0, 0xa4, 0x7c, 0x50, 0x14,
0xb5, 0xb9, 0xf2, 0x13, 0x00, 0xfb, 0x5e, 0x08, 0xb0, 0x2b, 0xec, 0xbe, 0xa0, 0x1c, 0xf4, 0x7b, 0xef, 0x38, 0x13,
0x31, 0x8a, 0x78, 0x2b, 0x7e, 0x49, 0x54, 0x54, 0xc7, 0x54, 0x59, 0xd7, 0x37, 0x34, 0x10, 0x58, 0x4f, 0x25, 0xce,
0x61, 0x73, 0xec, 0x41, 0x85, 0x06, 0x8e, 0xcd, 0x5c, 0xaa, 0xd0, 0x55, 0x6e, 0xc2, 0xa8, 0x8a, 0x4d, 0x41, 0x16,
0x5b, 0xe8, 0xae, 0x51, 0x84, 0x14, 0xc7, 0x17, 0xa1, 0x0e, 0x51, 0x9d, 0x5c, 0x15, 0xaa, 0xb4, 0xae, 0xe8, 0x42,
0x68, 0xb6, 0xef, 0x28, 0x09, 0xa7, 0xcd, 0x50, 0x00, 0x94, 0x93, 0x00, 0xd9, 0x09, 0x4f, 0x19, 0xa8, 0xe0, 0x89,
0x08, 0xc0, 0xa7, 0x56, 0xee, 0xec, 0x6d, 0x27, 0xfb, 0x4d, 0x87, 0x44, 0x28, 0x93, 0x78, 0x5a, 0x34, 0x54, 0x49,
0x8d, 0x90, 0x29, 0xb7, 0x2d, 0x46, 0x97, 0xb2, 0x8e, 0x3e, 0x21, 0x9f, 0xaf, 0x55, 0xc8, 0xa8, 0x0c, 0x19, 0x14,
0xb7, 0xc3, 0x9b, 0xca, 0xc0, 0x79, 0x25, 0x39, 0x8c, 0x7e, 0x22, 0x20, 0x2b, 0x5e, 0x43, 0x24, 0x75, 0x48, 0xc7,
0xb6, 0x8b, 0x2b, 0x99, 0x80, 0xe1, 0xe5, 0x6c, 0xeb, 0xe7, 0x89, 0x69, 0x74, 0xa8, 0xf2, 0x6f, 0x97, 0x90, 0x59,
0x48, 0xb8, 0x7d, 0x0b, 0xc2, 0x83, 0xc6, 0x8c, 0x8e, 0x62, 0x47, 0x44, 0x8c, 0x59, 0xdb, 0xab, 0x7d, 0x99, 0x1e,
0x46, 0xfe, 0xa8, 0x61, 0x71, 0xa8, 0x01, 0x08, 0xd5, 0x5f, 0xc1, 0x85, 0x68, 0xf7, 0x0a, 0x59, 0x22, 0xe9, 0x42,
0xd4, 0x5a, 0x9b, 0x53, 0xff, 0xdb, 0x62, 0x83, 0x2e, 0x5a, 0x6c, 0xce, 0x9a, 0xac, 0x90, 0x81, 0x12, 0xd3, 0x6f,
0x86, 0x94, 0xa9, 0x90, 0xce, 0x16, 0x01, 0xc3, 0x41, 0x66, 0xad, 0xff, 0xc9, 0xe1, 0x69, 0xba, 0x0c, 0xdc, 0x65,
0x49, 0x39, 0xb0, 0xa3, 0x9c, 0x9f, 0x50, 0x20, 0xf9, 0x3d, 0x45, 0x73, 0x76, 0x1f, 0xcc, 0x01, 0x78, 0x94, 0xaa,
0x37, 0xf4, 0x65, 0xdb, 0x38, 0xf1, 0x83, 0x26, 0xba, 0xbd, 0x53, 0xa8, 0xaf, 0xfa, 0x3b, 0xac, 0x52, 0x68, 0x2b,
0x9b, 0xe0, 0x1b, 0xb4, 0x12, 0x2d, 0xe9, 0x60, 0xb9, 0xa2, 0xaa, 0x2a, 0x73, 0x18, 0xbe, 0x72, 0x50, 0xc0, 0x87,
0xb2, 0x99, 0x66, 0x4b, 0x16, 0x1d, 0x24, 0xf6, 0x3a, 0xc2, 0xc1, 0xd6, 0xe7, 0x68, 0xd5, 0x72, 0x79, 0x17, 0xed,
0x73, 0xb7, 0xd8, 0x87, 0x64, 0x8a, 0x80, 0xee, 0xa1, 0xcd, 0x71, 0x42, 0x9b, 0x5a, 0xe9, 0x2a, 0x7a, 0x00, 0x0b,
0x0b, 0x4a, 0x9f, 0xc2, 0xba, 0xb0, 0x9b, 0x08, 0x30, 0x68, 0x10, 0x54, 0xa7, 0x7d, 0x66, 0xdd, 0x83, 0x59, 0x39,
0x49, 0xb7, 0xf2, 0x50, 0x49, 0x2c, 0xf8, 0x79, 0x83, 0xac, 0xd7, 0x2a, 0x6d, 0x9f, 0x0c, 0x40, 0x3f, 0xa9, 0xfe,
0x3a, 0x8c, 0x5f, 0x29, 0x9d, 0xa3, 0xe9, 0x1c, 0xda, 0x53, 0x15, 0xb0, 0x27, 0x85, 0x29, 0x9b, 0x15, 0x7a, 0xca,
0x83, 0xcc, 0x68, 0x47, 0xc5, 0xe4, 0x2c, 0xa1, 0x8a, 0xfa, 0x1b, 0x05, 0x97, 0xc9, 0x21, 0x03, 0x4c, 0x0e, 0x9a,
0x74, 0xdb, 0xe3, 0x05, 0xc2, 0x57, 0xa7, 0x72, 0x9e, 0xf6, 0x39, 0x5c, 0xd4, 0x01, 0x3e, 0xb2, 0xa9, 0x26, 0x11,
0x5b, 0xbf, 0xd1, 0x07, 0xbc, 0x1a, 0x20, 0x85, 0xf8, 0x08, 0xa7, 0xe9, 0x18, 0x0d, 0x43, 0x49, 0xd0, 0xa3, 0x8d,
0x49, 0xe9, 0xf4, 0xe6, 0xcc, 0x8a, 0xbe, 0xe9, 0x6a, 0x38, 0x22, 0x82, 0xb0, 0x91, 0x9d, 0xf2, 0x4b, 0x97, 0x94,
0x7d, 0x2a, 0x4f, 0xb8, 0x85, 0x04, 0x10, 0x11, 0x75, 0x58, 0xb4, 0x5b, 0xe0, 0x28, 0x80, 0xd2, 0xe9, 0xd2, 0x73,
0x4b, 0x79, 0xb9, 0xb3, 0x99, 0x32, 0x55, 0x00, 0xfc, 0x53, 0xc9, 0x71, 0x85, 0x64, 0xf4, 0x8d, 0x2a, 0xc8, 0x96,
0x04, 0xa6, 0xe3, 0x75, 0xe4, 0xae, 0x75, 0x97, 0x93, 0x14, 0xb6, 0x5c, 0x2b, 0x32, 0x85, 0xf1, 0xaf, 0x6d, 0x74,
0x25, 0x79, 0x48, 0xcf, 0x53, 0x52, 0xc7, 0xc9, 0x7a, 0x10, 0x93, 0x92, 0x45, 0x31, 0xfc, 0x27, 0x0c, 0xa4, 0xe0,
0x42, 0x42, 0x60, 0x44, 0xb1, 0x2a, 0xd9, 0xec, 0x00, 0x66, 0x87, 0xcd, 0xb2, 0x22, 0x9d, 0x3d, 0x69, 0xe9, 0xa5,
0x3e, 0x04, 0xa9, 0xb6, 0x74, 0xce, 0x11, 0x1c, 0x5b, 0xb5, 0xab, 0x4a, 0x18, 0xaa, 0x69, 0x3b, 0x8b, 0x82, 0x5f,
0xe6, 0x80, 0x0a, 0x92, 0x9d, 0xaa, 0x26, 0x4d, 0x22, 0xd2, 0xb9, 0x7a, 0x33, 0x61, 0xcc, 0x8b, 0x9e, 0xdf, 0xfd,
0xa3, 0xb6, 0x28, 0x03, 0xf6, 0x03, 0x85, 0x08, 0xb2, 0xd9, 0xaa, 0xf2, 0x02, 0xa3, 0xd8, 0x35, 0x4e, 0x14, 0x3b,
0xf2, 0xad, 0x95, 0xbd, 0x91, 0x2e, 0x78, 0x0f, 0x83, 0xaf, 0x90, 0x3c, 0xd0, 0x0f, 0x27, 0x6d, 0x47, 0x09, 0x9a,
0x72, 0x58, 0x2d, 0x93, 0x76, 0xad, 0xc3, 0xfe, 0x1c, 0x33, 0x54, 0xf9, 0x2d, 0x93, 0x83, 0xa4, 0xa9, 0x10, 0x38,
0x50, 0xa5, 0x70, 0x2f, 0x30, 0xff, 0xe4, 0x1d, 0xc5, 0x97, 0x2d, 0x2e, 0xbf, 0x2c, 0x33, 0xe5, 0xce, 0x23, 0xdd,
0x16, 0x54, 0xb4, 0x03, 0x10, 0x8a, 0x64, 0x2a, 0x42, 0x1f, 0x64, 0x9f, 0x28, 0x25, 0x21, 0xb5, 0xd8, 0xcd, 0x7c,
0x42, 0xd0, 0x34, 0x91, 0x83, 0x3f, 0xc2, 0x1e, 0x05, 0x53, 0xb6, 0xa8, 0x5c, 0xfe, 0xd1, 0x32, 0xc1, 0x14, 0x21,
0x25, 0xa1, 0x07, 0xb3, 0xa1, 0xd7, 0x8c, 0x61, 0xf3, 0xff, 0xe8, 0x65, 0x98, 0xab, 0xc5, 0x39, 0xbe, 0x55, 0x61,
0xae, 0x3d, 0x63, 0x5a, 0xb6, 0xa8, 0x21, 0x5c, 0xde, 0x92, 0xc1, 0x2b, 0x42, 0x47, 0xd8, 0x38, 0x87, 0x2e, 0x58,
0x3f, 0x86, 0x0e, 0xdb, 0x6c, 0x75, 0x5e, 0x6d, 0xe7, 0x88, 0x5e, 0xeb, 0x89, 0x9c, 0x22, 0xc3, 0x6f, 0x27, 0xe5,
0x38, 0x08, 0xe3, 0x02, 0x47, 0xfe, 0xb7, 0xc5, 0x6d, 0x2c, 0x85, 0xb4, 0xad, 0x21, 0x95, 0xfd, 0x5c, 0x7b, 0xc5,
0x4f, 0x87, 0xf6, 0xba, 0xbf, 0xc1, 0x2a, 0xa4, 0x09, 0x1d, 0x11, 0x2a, 0x4f, 0xc7, 0x94, 0x8f, 0xd1, 0x54, 0xaf,
0x12, 0x80, 0xfe, 0x2a, 0x94, 0x90, 0xdb, 0x95, 0x15, 0x7a, 0x48, 0x23, 0x56, 0xf9, 0xd5, 0x0d, 0xa8, 0xa2, 0xc6,
0x9e, 0x04, 0x7f, 0x14, 0x3e, 0x02, 0xa8, 0x53, 0xe0, 0x70, 0x06, 0x0d, 0xa5, 0xd7, 0xe5, 0xb6, 0xfc, 0x8a, 0xf2,
0x25, 0x2e, 0xe1, 0xcf, 0x98, 0x1c, 0x7d, 0x8b, 0xb6, 0x98, 0xee, 0x71, 0x12, 0xe6, 0x86, 0x1d, 0x27, 0x98, 0xdf,
0x58, 0x10, 0x43, 0x1d, 0x1e, 0x1d, 0x26, 0x42, 0xda, 0xaf, 0x67, 0xd3, 0x97, 0x04, 0x5e, 0x2d, 0x8c, 0x4d, 0x84,
0x7f, 0x55, 0x7a, 0x00, 0x8f, 0x0c, 0x93, 0x38, 0xa9, 0x21, 0x52, 0x10, 0x68, 0x36, 0xbf, 0x18, 0xe3, 0x75, 0xe0,
0x2a, 0x3e, 0x07, 0x55, 0xe5, 0xd9, 0x58, 0x69, 0x4c, 0x28, 0x51, 0x79, 0x0f, 0x05, 0x06, 0x10, 0xf3, 0x3e, 0x1f,
0xf5, 0x90, 0x35, 0x78, 0x97, 0x70, 0xb4, 0x5e, 0x71, 0xfe, 0x05, 0xd5, 0xa8, 0x3b, 0x47, 0xd5, 0x14, 0x1e, 0x34,
0x13, 0x8a, 0x96, 0xb0, 0xf8, 0x19, 0xb1, 0x14, 0xe9, 0x95, 0x22, 0x5a, 0x31, 0xa5, 0x71, 0xd3, 0xcd, 0xe4, 0xa1,
0xb5, 0x6b, 0x8c, 0x93, 0xea, 0x99, 0xd1, 0x95, 0x9f, 0x71, 0x14, 0x8e, 0x63, 0x8f, 0xc2, 0x5a, 0x76, 0x03, 0xcb,
0xf4, 0xf3, 0x2b, 0xe9, 0x8f, 0x11, 0x29, 0x0c, 0x5b, 0x1b, 0x66, 0x30, 0xb2, 0x4f, 0xcf, 0xf6, 0xc1, 0x5f, 0xc9,
0x41, 0xc6, 0x53, 0x49, 0x44, 0x96, 0xb5, 0xce, 0x38, 0x15, 0x6e, 0xe8, 0xe3, 0x22, 0x99, 0x38, 0x45, 0xaa, 0x0a,
0x17, 0x25, 0x4a, 0x57, 0xf9, 0x1e, 0x42, 0x0f, 0x78, 0x7b, 0x5d, 0xc2, 0xe9, 0xc8, 0x64, 0x18, 0x09, 0x25, 0x84,
0x16, 0x8e, 0x24, 0xf6, 0x65, 0x17, 0x55, 0x94, 0x37, 0x08, 0xc2, 0xf9, 0x82, 0x2a, 0xef, 0x67, 0xab, 0xb5, 0x55,
0x14, 0x7a, 0x63, 0x9a, 0x50, 0xf2, 0x52, 0x71, 0x8b, 0x55, 0xd0, 0x99, 0x46, 0xa7, 0x3d, 0x2b, 0x05, 0x59, 0x50,
0xb3, 0xe0, 0x77, 0xa3, 0x4c, 0x2f, 0x91, 0x93, 0x05, 0x3c, 0x4a, 0x8f, 0x41, 0x6d, 0xc6, 0xd2, 0x24, 0xa8, 0x8e,
0x92, 0x54, 0x43, 0x15, 0xd8, 0x53, 0x79, 0x56, 0x4b, 0x06, 0xa8, 0x36, 0x5b, 0x76, 0xb4, 0xd7, 0x10, 0x82, 0x8c,
0x63, 0x5f, 0xad, 0xcf, 0x2b, 0x67, 0x4b, 0xe4, 0xff, 0xb7, 0xa3, 0xbc, 0xaf, 0x9b, 0x2a, 0xaf, 0x1c, 0x80, 0xbe,
0x1f, 0x7e, 0x05, 0xf4, 0x8a, 0xb8, 0x13, 0x10, 0xa8, 0x02, 0x05, 0xf7, 0xee, 0xc1, 0x89, 0x54, 0x7d, 0xc1, 0x4e,
0x5a, 0x80, 0x38, 0x80, 0x09, 0x49, 0x86, 0xd6, 0xe1, 0x0b, 0x2b, 0x73, 0x13, 0x9a, 0xb0, 0xd0, 0xe6, 0x15, 0xa8,
0xb9, 0x6e, 0x89, 0xbc, 0x8e, 0x2c, 0x73, 0x95, 0x9c, 0xe4, 0x91, 0x3c, 0xde, 0x74, 0x26, 0x49, 0xac, 0x7b, 0x24,
0xa3, 0x50, 0x61, 0xa7, 0x88, 0xb6, 0xb5, 0xe5, 0x3c, 0xcb, 0xde, 0x94, 0x7d, 0x0a, 0x91, 0x91, 0x50, 0x3a, 0xd8,
0x50, 0xed, 0x2b, 0xc8, 0x84, 0xcc, 0x11, 0x3d, 0xaf, 0x67, 0xd0, 0x84, 0x9a, 0x0a, 0x95, 0xe1, 0xc8, 0x87, 0xed,
0xe5, 0xff, 0xaf, 0x12, 0xc6, 0x57, 0x5d, 0x27, 0x2a, 0x2a, 0x28, 0x93, 0xb6, 0x03, 0x1c, 0xb0, 0x97, 0x36, 0x3b,
0xa6, 0xd3, 0x57, 0x82, 0x49, 0x42, 0x5f, 0x9b, 0xd4, 0x7b, 0x37, 0xdb, 0x16, 0x71, 0x1d, 0xec, 0xd7, 0xe2, 0x52,
0x20, 0x93, 0xfa, 0x27, 0xd1, 0xd4, 0xfd, 0x19, 0x21, 0x46, 0xc7, 0x5c, 0x8c, 0x1a, 0x56, 0x3e, 0x0f, 0xf4, 0x36,
0xda, 0x99, 0x55, 0xc1, 0x74, 0xaa, 0xf5, 0xdd, 0x0d, 0x4e, 0xfb, 0x50, 0x3e, 0xa5, 0x16, 0x52, 0xe4, 0x67, 0x20,
0x38, 0xd4, 0x0a, 0x0e, 0xa9, 0x7e, 0xf6, 0xf9, 0xe8, 0x1f, 0xa8, 0xf7, 0xeb, 0xaa, 0xfc, 0x41, 0x93, 0xe8, 0xe5,
0xae, 0xda, 0x6f, 0x53, 0x90, 0xb6, 0x3c, 0xb5, 0x0c, 0x6f, 0x7e, 0x2c, 0xbf, 0x17, 0x40, 0xd4, 0x3d, 0xfb, 0x85,
0xaa, 0x78, 0xb8, 0xf8, 0x6d, 0x5f, 0xc6, 0x4c, 0x79, 0x5e, 0x9e, 0xce, 0x96, 0xc7, 0xe8, 0x0a, 0x39, 0xfa, 0x81,
0x25, 0xcf, 0x6b, 0xe8, 0xd8, 0x3d, 0x60, 0x64, 0xc4, 0x73, 0x6a, 0x94, 0x96, 0x1d, 0x0c, 0xfe, 0xfc, 0x4a, 0x49,
0xdd, 0xf3, 0x80, 0x32, 0x4f, 0x47, 0xb4, 0xf1, 0x72, 0x59, 0x79, 0xfc, 0x81, 0xcc, 0xe8, 0x39, 0xbe, 0x4a, 0xc2,
0x3c, 0x3e, 0x4d, 0xe9, 0xbb, 0x2c, 0x36, 0x32, 0xed, 0xc2, 0xc2, 0x29, 0x4d, 0xfa, 0xad, 0x88, 0xb2, 0x1c, 0x25,
0x9c, 0x91, 0x64, 0xd0, 0x61, 0x69, 0x97, 0x66, 0x57, 0xfb, 0xb3, 0x43, 0xfa, 0x75, 0x2c, 0x22, 0x06, 0x0c, 0xd2,
0xac, 0xcb, 0x41, 0x07, 0x0e, 0x14, 0x45, 0x1a, 0x81, 0xf6, 0x43, 0x19, 0xe5, 0xdf, 0x24, 0x00, 0xac, 0x20, 0x5e,
0x17, 0xc9, 0x01, 0x28, 0xe6, 0x9c, 0x9e, 0x88, 0x29, 0x9d, 0xc7, 0x52, 0xda, 0x72, 0xa5, 0x7d, 0x90, 0x31, 0x22,
0xe0, 0x29, 0xc2, 0xb3, 0x50, 0x40, 0xff, 0x70, 0xde, 0xb1, 0xc8, 0xe1, 0x65, 0xd2, 0x95, 0x07, 0x97, 0x0d, 0x6d,
0x26, 0xda, 0x1e, 0x61, 0xf2, 0x9a, 0x80, 0x07, 0x71, 0x32, 0xee, 0xd5, 0xd8, 0xda, 0x08, 0x35, 0xda, 0x8a, 0x72,
0x40, 0x91, 0xff, 0x5c, 0x8e, 0x31, 0xce, 0x40, 0x6d, 0x32, 0xff, 0x32, 0xec, 0xaf, 0x4c, 0x79, 0x42, 0xd0, 0x6f,
0xb3, 0xcd, 0x8b, 0xca, 0x73, 0x42, 0xc0, 0x03, 0x85, 0x78, 0xf5, 0x89, 0x93, 0x99, 0x19, 0x7d, 0x39, 0x13, 0xe1,
0x4b, 0x63, 0xc0, 0x90, 0x10, 0xb5, 0x8f, 0xd3, 0xf2, 0x8e, 0x1d, 0x05, 0x55, 0xb5, 0xfa, 0xcc, 0x9c, 0xec, 0xee,
0x6a, 0x6c, 0xe6, 0x39, 0x61, 0xda, 0x9d, 0x6d, 0xd9, 0x4d, 0x0c, 0x48, 0xd3, 0x30, 0xbe, 0xc2, 0x61, 0xac, 0x97,
0x07, 0xa4, 0x12, 0x7f, 0xca, 0x23, 0xc0, 0xb7, 0x33, 0xe8, 0x65, 0xf7, 0x98, 0xd8, 0x16, 0x67, 0x8a, 0x21, 0x5b,
0xea, 0x96, 0x1e, 0xa7, 0x64, 0xa2, 0xdc, 0xcb, 0x4a, 0xfa, 0xb0, 0xd8, 0xbc, 0xa6, 0x6c, 0x44, 0x77, 0x0f, 0xc4,
0x98, 0xbc, 0x9f, 0xf5, 0x62, 0x20, 0x81, 0xa9, 0xab, 0xeb, 0xeb, 0xcf, 0x50, 0x67, 0x8c, 0x35, 0x3d, 0x27, 0x2a,
0x79, 0xda, 0x11, 0xbb, 0x6d, 0xf4, 0x2a, 0x55, 0xcc, 0xd0, 0x11, 0x8b, 0xf5, 0x73, 0x72, 0xf8, 0x58, 0x26, 0x9e,
0x32, 0xa4, 0x8a, 0x38, 0x0d, 0x14, 0x6b, 0xc3, 0x4a, 0x67, 0xf5, 0x72, 0x7f, 0xed, 0x2b, 0x4b, 0x8a, 0x26, 0x54,
0xcb, 0x44, 0xb2, 0x45, 0x50, 0xc9, 0xb2, 0x22, 0x76, 0xaa, 0x82, 0xae, 0xa7, 0x57, 0x09, 0x11, 0x36, 0x8b, 0x99,
0x32, 0x49, 0xa5, 0x51, 0xe6, 0x9c, 0x14, 0xc9, 0x4e, 0x9e, 0x33, 0x5e, 0x30, 0xdb, 0xc9, 0xa4, 0x43, 0x54, 0xdc,
0x0f, 0x28, 0xed, 0xa7, 0xe9, 0x41, 0x4f, 0xd0, 0xe4, 0x54, 0x58, 0xdf, 0xe5, 0x95, 0x31, 0x35, 0x91, 0x10, 0x82,
0xf0, 0xb0, 0xd8, 0x1b, 0x19, 0xdf, 0xb7, 0xb6, 0xb5, 0xad, 0xaf, 0x93, 0xff, 0x4c, 0xb3, 0xf2, 0x7e, 0x3b, 0xd1,
0xea, 0x13, 0x36, 0x07, 0x09, 0x5c, 0x6d, 0xdb, 0x6c, 0xef, 0xb2, 0x05, 0x31, 0x4a, 0xff, 0x32, 0x3e, 0x2e, 0x8a,
0x96, 0xbd, 0x1b, 0x01, 0x24, 0xac, 0x9c, 0x2b, 0x60, 0x8c, 0x64, 0x36, 0x64, 0x0a, 0x55, 0xa0, 0xb7, 0x11, 0x64,
0xda, 0x82, 0x5a, 0x2e, 0xa8, 0x34, 0x13, 0x5f, 0xfd, 0x66, 0x1c, 0x8d, 0x2c, 0xe0, 0x55, 0xc5, 0xf6, 0x0f, 0x1d,
0x9d, 0x8d, 0xed, 0x71, 0xfa, 0x8e, 0x1e, 0x2f, 0x7b, 0x4d, 0x72, 0xbe, 0xb9, 0x41, 0xc1, 0x0a, 0xde, 0x7c, 0x5d,
0x31, 0x5d, 0xd1, 0x47, 0x4a, 0xb6, 0x6e, 0x06, 0x83, 0xb5, 0xde, 0xde, 0x24, 0x65, 0xed, 0x30, 0x79, 0xfb, 0xf8,
0xa0, 0x23, 0xd4, 0x72, 0x2f, 0x9b, 0x36, 0xba, 0x05, 0x50, 0x0b, 0xbf, 0x3f, 0x72, 0xb0, 0xd1, 0x3b, 0x8f, 0xf9,
0x1a, 0xf8, 0x38, 0x67, 0xb2, 0x32, 0xe0, 0xc1, 0x27, 0x43, 0x42, 0x1d, 0x0d, 0x29, 0x79, 0x54, 0x88, 0xbe, 0x98,
0x02, 0xc5, 0xe5, 0xf1, 0x53, 0x44, 0x0d, 0xcc, 0xad, 0x3b, 0x10, 0x86, 0xbd, 0xdf, 0x6c, 0xdb, 0x7e, 0x17, 0x4d,
0xec, 0x1a, 0x2d, 0xa5, 0x09, 0xa8, 0x60, 0xc6, 0x78, 0x2a, 0x0f, 0xed, 0xc9, 0xa5, 0x12, 0x0e, 0xfc, 0x8e, 0xd5,
0x79, 0x75, 0xba, 0xb8, 0x2f, 0xa9, 0x5c, 0x0b, 0x27, 0x19, 0x5c, 0x2b, 0x07, 0x56, 0x45, 0x49, 0x31, 0x55, 0xb9,
0x8f, 0x0a, 0xa5, 0x22, 0x05, 0xb4, 0x4f, 0x35, 0x5f, 0xa7, 0x84, 0x30, 0xc7, 0x6a, 0xab, 0xf1, 0x34, 0x9a, 0x32,
0x3e, 0xc6, 0x56, 0xdb, 0xb1, 0x93, 0xaf, 0x93, 0x99, 0x35, 0x10, 0x85, 0xf7, 0x31, 0xee, 0x22, 0xd4, 0xf5, 0x81,
0xe8, 0xf1, 0x3d, 0x39, 0xcf, 0x62, 0x8a, 0x00, 0xaf, 0xb4, 0x97, 0x32, 0x2f, 0xd5, 0x44, 0x5d, 0x9d, 0xa5, 0x64,
0xa9, 0x6d, 0x65, 0x52, 0x6a, 0x70, 0x79, 0x6b, 0x7e, 0x19, 0x40, 0xb1, 0x9d, 0x98, 0x6a, 0x8b, 0x2d, 0x41, 0x82,
0xd0, 0x97, 0x67, 0x31, 0x09, 0xf9, 0x41, 0xb1, 0xc9, 0x63, 0x4b, 0xd4, 0x5d, 0x27, 0xaa, 0x27, 0xd5, 0xcf, 0x3f,
0x11, 0xf3, 0x0d, 0xc9, 0x81, 0x9b, 0xb2, 0xe7, 0x55, 0x27, 0xbe, 0x72, 0xe3, 0xd3, 0xd9, 0x9e, 0x64, 0x06, 0xcf,
0x56, 0xde, 0xd2, 0x61, 0x3f, 0xa4, 0x68, 0x4b, 0xda, 0x22, 0x43, 0x8c, 0xb9, 0xba, 0xfb, 0x62, 0x4f, 0x7e, 0x13,
0x0c, 0xed, 0x27, 0x08, 0x88, 0x54, 0x11, 0x71, 0x3e, 0x30, 0xd5, 0xff, 0x19, 0x49, 0x20, 0xb3, 0x0c, 0x09, 0xdc,
0x46, 0xc4, 0x10, 0xb2, 0xd6, 0x60, 0xb7, 0xde, 0xdf, 0x73, 0x92, 0xc3, 0x4f, 0x6d, 0xe4, 0xe3, 0x69, 0x56, 0xda,
0xa8, 0x6e, 0x96, 0x1b, 0xb4, 0x35, 0x32, 0xa8, 0xfb, 0x1b, 0x6a, 0x56, 0x7e, 0x21, 0x6e, 0xdc, 0xeb, 0xb0, 0x51,
0x36, 0x49, 0x4d, 0x99, 0x35, 0x72, 0xe6, 0xea, 0x54, 0xf8, 0x64, 0x56, 0x33, 0x73, 0x22, 0x4b, 0x20, 0x33, 0x01,
0x56, 0xb6, 0xee, 0xa3, 0xc8, 0x13, 0x16, 0xf9, 0xa2, 0x58, 0x28, 0x2b, 0x1f, 0xfa, 0x17, 0x7c, 0x4b, 0x1f, 0xa7,
0xe2, 0xf0, 0xfb, 0xe4, 0x21, 0xbd, 0x59, 0x5e, 0x26, 0x6d, 0x54, 0x3a, 0x97, 0xdd, 0x04, 0x86, 0x6b, 0x8c, 0x49,
0x9a, 0x1c, 0xa8, 0x68, 0xac, 0xa9, 0x31, 0x98, 0x52, 0xe5, 0xea, 0x47, 0x03, 0xaa, 0x68, 0x1c, 0x4a, 0x69, 0x14,
0x8a, 0xd3, 0x84, 0x5a, 0xbb, 0x9c, 0x79, 0x92, 0x81, 0xcc, 0x92, 0x31, 0x73, 0xb0, 0x75, 0x5a, 0xb7, 0xaf, 0x04,
0x26, 0x00, 0x16, 0x92, 0x69, 0x03, 0x7a, 0x61, 0x5a, 0x41, 0xd5, 0x97, 0x63, 0x00, 0x5f, 0x63, 0x30, 0x85, 0xcc,
0x6b, 0x8e, 0x8a, 0xbb, 0xa3, 0xff, 0x25, 0x15, 0x54, 0x49, 0x76, 0x0d, 0x9a, 0xb2, 0xd9, 0x70, 0x04, 0x9f, 0xbe,
0xfd, 0x25, 0x81, 0x50, 0x87, 0xcc, 0x54, 0x8d, 0x34, 0x32, 0x2b, 0x10, 0xc8, 0x82, 0x43, 0x11, 0x3a, 0xe0, 0x91,
0xb4, 0xc7, 0xa3, 0x8c, 0x98, 0xfa, 0x59, 0x72, 0x9a, 0x92, 0x15, 0x0b, 0x03, 0x93, 0x0c, 0xee, 0xd0, 0x2e, 0x15,
0xa7, 0x19, 0xcc, 0x62, 0x84, 0xce, 0xab, 0x19, 0x62, 0xa5, 0xf3, 0x01, 0x6d, 0xd4, 0x21, 0x6e, 0xe5, 0x9d, 0xe6,
0x87, 0x56, 0xa5, 0x43, 0x40, 0x93, 0xa8, 0x09, 0xbd, 0x95, 0xfa, 0x87, 0xd6, 0x30, 0xb9, 0xf4, 0x65, 0x35, 0x07,
0x93, 0xd4, 0x85, 0x9e, 0xa3, 0x98, 0x62, 0xb7, 0x0d, 0x81, 0xc4, 0xf2, 0xca, 0x1c, 0x02, 0x70, 0x73, 0x5c, 0x11,
0xae, 0xac, 0x1e, 0x20, 0x4c, 0xac, 0x18, 0xe8, 0xa4, 0x14, 0xbf, 0x0a, 0x09, 0x3e, 0xf7, 0xd8, 0x2e, 0x07, 0xc1,
0x9e, 0x13, 0x90, 0xce, 0xa6, 0x69, 0xdb, 0x5a, 0xf8, 0x47, 0x60, 0x1c, 0x4c, 0x71, 0xef, 0xd8, 0x8d, 0x7d, 0x11,
0xbd, 0xce, 0x10, 0x1f, 0x8e, 0xf8, 0xa4, 0x58, 0x30, 0xad, 0xa1, 0xe3, 0xca, 0xb3, 0x2d, 0xc7, 0xd4, 0x52, 0xfe,
0x8d, 0x18, 0xab, 0xd3, 0x22, 0x49, 0x6b, 0xa5, 0x8a, 0xcd, 0xec, 0x5d, 0x66, 0x2e, 0x1d, 0x88, 0xa6, 0xef, 0x03,
0x15, 0x4c, 0x47, 0x47, 0x27, 0xd1, 0x9c, 0x91, 0x27, 0x8d, 0x2f, 0x14, 0x15, 0x0a, 0x8f, 0x03, 0x69, 0xba, 0xed,
0x4e, 0x6b, 0x4b, 0x0b, 0x83, 0xec, 0xf9, 0x54, 0x08, 0x9a, 0xaa, 0xbc, 0x50, 0x18, 0x65, 0xd1, 0x37, 0x23, 0xda,
0x28, 0x44, 0x7e, 0xb7, 0x4f, 0xe4, 0x80, 0xa8, 0xf8, 0x2f, 0xdc, 0xad, 0xaf, 0xb4, 0xfa, 0x7f,
};
static const uint8_t MIXED[] = {
0x4a, 0x2d, 0x2e, 0xc8, 0xc8, 0xcf, 0x4d, 0x55, 0xc8, 0x2f, 0x49, 0x54, 0x48, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49,
0x55, 0x48, 0x1d, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x84, 0x62, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0xb8, 0x0b, 0x47, 0xf4, 0x53, 0xc3, 0x7d, 0x78, 0x8e, 0xb4, 0x4d, 0xb7, 0x48, 0x2f, 0x6d, 0x46, 0x3d, 0x19,
0xe5, 0x70, 0x24, 0x4c, 0xbb, 0xa0, 0xe3, 0x58, 0xfc, 0x78, 0x74, 0xfa, 0x8c, 0xb1, 0x95, 0x5c, 0xaf, 0xb5, 0x32,
0x12, 0x53, 0xfe, 0x93, 0xd1, 0x23, 0x2c, 0x45, 0xed, 0x4c, 0xe9, 0xc9, 0x99, 0x0d, 0x7d, 0xff, 0xdc, 0x01, 0x30,
0x51, 0x55, 0x2c, 0x63, 0xa0, 0xb0, 0xc7, 0x6d, 0xee, 0xe4, 0xcc, 0x36, 0xd0, 0x32, 0x40, 0x96, 0x91, 0xdd, 0x43,
0x6b, 0x26, 0xaa, 0xd8, 0x7c, 0xd6, 0x16, 0x75, 0x11, 0xa6, 0x5a, 0x4a, 0x4e, 0x86, 0x1f, 0x51, 0x53, 0x3c, 0x01,
0x1a, 0x16, 0x14, 0xc6, 0x54, 0xfb, 0x44, 0x5b, 0x1a, 0x38, 0x21, 0x92, 0x03, 0xeb, 0x04, 0x9d, 0xe8, 0xf8, 0xfa,
0x4a, 0x73, 0xa4, 0x2f, 0xfc, 0x6d, 0xf3, 0x18, 0x6d, 0xc4, 0xc1, 0x62, 0x25, 0x5d, 0xa3, 0x9d, 0xb9, 0x9f, 0x7b,
0xa8, 0xc4, 0xbb, 0xdd, 0xdb, 0xa7, 0xbd, 0x25, 0xf7, 0x00, 0x54, 0x54, 0xce, 0xeb, 0x61, 0xaf, 0xb2, 0xfb, 0x42,
0x16, 0x9f, 0xf7, 0xdb, 0x25, 0x28, 0x54, 0x68, 0x0c, 0x22, 0x76, 0x06, 0x2f, 0x12, 0xa7, 0xfa, 0x7c, 0x57, 0xd3,
0xc8, 0x90, 0x17, 0x09, 0xf5, 0x89, 0xea, 0xb2, 0x96, 0xa9, 0x49, 0x8f, 0xa1, 0xb0, 0xb5, 0x74, 0xf0, 0xf6, 0xa7,
0xc6, 0x14, 0x4a, 0x3a, 0xb6, 0xdf, 0x8d, 0x9a, 0x3a, 0xb0, 0x0e, 0x2c, 0xd0, 0x7c, 0xa5, 0x7b, 0xf2, 0xa1, 0x8e,
0xe5, 0x58, 0x6b, 0x0b, 0x0a, 0xf0, 0x62, 0xb8, 0xf0, 0x9e, 0x59, 0xac, 0xf6, 0xb3, 0x38, 0x54, 0x7f, 0x2f, 0x84,
0x10, 0x5a, 0xb7, 0xb3, 0x8a, 0xf3, 0x54, 0x32, 0xdb, 0x3b, 0xf1, 0x32, 0x5c, 0x59, 0x93, 0x36, 0x4c, 0x0d, 0x56,
0x5e, 0x26, 0xe8, 0x2b, 0x71, 0xc0, 0x2e, 0x53, 0xab, 0x23, 0x86, 0x9a, 0x4c, 0x2e, 0x68, 0x54, 0xdd, 0xe9, 0x43,
0x19, 0x40, 0xaa, 0x71, 0x40, 0x7f, 0xea, 0xdb, 0x1c, 0x51, 0xe4, 0x6c, 0xf9, 0x6b, 0xf3, 0x37, 0xd4, 0x8d, 0xa9,
0x67, 0xde, 0x48, 0xae, 0xea, 0xaf, 0x8f, 0x5f, 0xdd, 0x4a, 0x05, 0x22, 0xb6, 0xd5, 0x00, 0x8b, 0x33, 0x15, 0x60,
0x30, 0x06, 0xab, 0x13, 0x4c, 0x3d, 0x10, 0x63, 0x16, 0x73, 0x52, 0x06, 0xdf, 0xb8, 0x8c, 0xe4, 0xee, 0x41, 0x26,
0xa6, 0x1c, 0xd0, 0xd2, 0x03, 0x2e, 0xe2, 0x41, 0xc9, 0xf5, 0x9a, 0xa9, 0xad, 0x27, 0x70, 0xf8, 0xd4, 0xfc, 0x99,
0xd5, 0x1d, 0x88, 0x35, 0x5b, 0x35, 0xdb, 0x3b, 0x94, 0x58, 0xda, 0x24, 0xb7, 0xe7, 0xdc, 0x5a, 0x22, 0xaf, 0x04,
0x5f, 0x16, 0xf3, 0x61, 0xbd, 0x34, 0x3f, 0xc6, 0xb2, 0xbb, 0xec, 0x6a, 0x97, 0x7f, 0x72, 0x40, 0x14, 0xa8, 0x70,
0x15, 0x06, 0x30, 0x7d, 0x6b, 0x2b, 0x1a, 0xac, 0x17, 0x93, 0x73, 0xe1, 0x9c, 0xc7, 0x0a, 0xd7, 0x46, 0xb6, 0xee,
0xed, 0x06, 0x63, 0xac, 0xb3, 0x11, 0x50, 0x45, 0x38, 0x37, 0xa9, 0xf1, 0x11, 0x04, 0x31, 0x97, 0x2a, 0x98, 0xed,
0x07, 0x4c, 0x46, 0x92, 0xfd, 0x72, 0xef, 0xb0, 0xd6, 0xcb, 0x1d, 0x9b, 0x10, 0x8f, 0xde, 0x1c, 0x83, 0x82, 0x66,
0xdc, 0x61, 0x49, 0x64, 0x8c, 0xef, 0x70, 0x20, 0xd5, 0x00, 0x37, 0x59, 0x03, 0x36, 0x1f, 0xe1, 0x71, 0xf8, 0x39,
0xf4, 0xb2, 0x32, 0x29, 0x5d, 0x84, 0xcf, 0xfd, 0x47, 0x75, 0xf8, 0xb0, 0xe4, 0x53, 0x09, 0x7c, 0xbf, 0x55, 0x58,
0xe3, 0xe2, 0x0a, 0xa5, 0x7c, 0xa7, 0x05, 0x5f, 0x7e, 0x5e, 0x45, 0x9c, 0x0e, 0xa4, 0x67, 0xd6, 0x48, 0x7e, 0x8b,
0x66, 0x0f, 0x38, 0x06, 0xc2, 0x95, 0x00, 0xcc, 0x77, 0xa9, 0x41, 0x9b, 0xe4, 0xc3, 0xc1, 0xe8, 0xbc, 0xd1, 0x79,
0x8a, 0x39, 0xbf, 0x38, 0x29, 0x21, 0xc9, 0xf6, 0x65, 0x7a, 0x80, 0xf9, 0xc6, 0x0c, 0x9d, 0xaa, 0x66, 0x9b, 0x89,
0x34, 0x60, 0xe1, 0xa8, 0xe2, 0xf7, 0x4d, 0x69, 0x35, 0x86, 0x7e, 0x0f, 0xc8, 0x2c, 0x7e, 0x3c, 0xe4, 0x33, 0xbf,
0x42, 0xe3, 0x44, 0xd6, 0x29, 0x45, 0x4d, 0xf9, 0x80, 0x94, 0x2e, 0x3a, 0xe4, 0xf8, 0x26, 0x80, 0x52, 0x99, 0x00,
0x4a, 0x2c, 0xb7, 0xfd, 0x24, 0x0c, 0x8b, 0x80, 0xe5, 0x4c, 0xdd, 0x7c, 0xad, 0x52, 0x62, 0x9e, 0xa2, 0x9c, 0xdb,
0x3a, 0x65, 0x8f, 0xee, 0xf6, 0x56, 0xff, 0xc3, 0x38, 0x8d, 0x7d, 0x5e, 0x50, 0x93, 0x64, 0xbf, 0x65, 0xe4, 0xa2,
0xbb, 0x21, 0x25, 0x47, 0x98, 0x1c, 0x25, 0xcf, 0x6b, 0x09, 0x95, 0x30, 0x32, 0xa3, 0x87, 0xa2, 0xb1, 0x55, 0xa9,
0x30, 0x0d, 0xac, 0x3e, 0x03, 0x29, 0x7d, 0xe0, 0x69, 0xc4, 0xd5, 0xf7, 0xa8, 0x4f, 0xa5, 0xf8, 0x85, 0x8f, 0x2a,
0x5e, 0x93, 0xf7, 0x1e, 0x69, 0x3c, 0xc3, 0xa0, 0x99, 0x91, 0xd4, 0xe4, 0xe9, 0xd1, 0x4f, 0x9a, 0xcc, 0xbb, 0xf4,
0x1f, 0xe8, 0x94, 0x3e, 0x66, 0x95, 0xf7, 0x3f, 0xa5, 0x14, 0x5f, 0x3a, 0xbf, 0x8f, 0x75, 0xfe, 0x74, 0xd5, 0x1a,
0x05, 0x4b, 0xd2, 0x34, 0x50, 0x3b, 0xcf, 0x39, 0x00, 0x1c, 0x6f, 0x7d, 0xb4, 0xd0, 0x65, 0x3b, 0xa6, 0x30, 0xf6,
0x65, 0x84, 0xb8, 0x32, 0x2c, 0x10, 0xf3, 0xf2, 0x4e, 0x76, 0xa5, 0x90, 0x22, 0x71, 0xba, 0x69, 0x64, 0x1c, 0xf1,
0x14, 0xc1, 0x98, 0x48, 0x5f, 0x21, 0x63, 0x26, 0x0d, 0xb8, 0x73, 0x4b, 0x52, 0xcc, 0x16, 0x78, 0x0a, 0x44, 0x89,
0xdd, 0xbd, 0xf4, 0x5a, 0x47, 0x54, 0xaa, 0x7e, 0x06, 0x97, 0xf8, 0x31, 0x9f, 0x6e, 0xbf, 0x91, 0x36, 0xd4, 0x80,
0xf9, 0xba, 0x9a, 0x62, 0x1e, 0xce, 0xe1, 0x03, 0xec, 0x7a, 0x55, 0xff, 0x1e, 0x96, 0x2a, 0x41, 0x9f, 0xf2, 0xd7,
0x0c, 0xa4, 0x46, 0x95, 0xc8, 0x86, 0xdd, 0x96, 0x8d, 0x60, 0x00, 0x06, 0x71, 0x6d, 0x23, 0xc2, 0x91, 0x1e, 0xd2,
0xdb, 0xe2, 0xfe, 0x59, 0xc9, 0xb5, 0x46, 0x36, 0x6f, 0x0b, 0x3f, 0x3f, 0xd2, 0x9e, 0x5c, 0x93, 0x99, 0xac, 0x13,
0x42, 0x44, 0x82, 0x7f, 0xbc, 0x2c, 0xcc, 0xb7, 0xfa, 0x3f, 0x9e, 0xec, 0x6e, 0x77, 0x41, 0x44, 0xab, 0x1f, 0xbe,
0x7a, 0xd4, 0xc5, 0x2c, 0x32, 0xc6, 0xfe, 0xba, 0x1d, 0x05, 0xdc, 0x7c, 0xd1, 0x67, 0x30, 0xf6, 0x65, 0x83, 0x80,
0x69, 0xd0, 0xd7, 0xc7, 0xdf, 0xff, 0xbb, 0xef, 0xf8, 0xb8, 0x09, 0x0f, 0x73, 0x31, 0x89, 0x64, 0x7c, 0x6f, 0x1f,
0x11, 0xb8, 0x60, 0xb4, 0x97, 0x11, 0xb7, 0xe4, 0x12, 0x41, 0x8b, 0x6c, 0x39, 0x20, 0xaf, 0x51, 0x13, 0xae, 0xcf,
0xd1, 0x7a, 0xe0, 0x4f, 0x0b, 0x51, 0x2b, 0xe3, 0x6d, 0x84, 0xd1, 0xee, 0xe1, 0xc4, 0xee, 0x9c, 0xb7, 0x00, 0x41,
0xbe, 0x51, 0xa2, 0xbb, 0x68, 0x90, 0x8e, 0xca, 0x4c, 0x02, 0xdb, 0x62, 0xd5, 0xc8, 0x4f, 0xd0, 0x03, 0x48, 0x9d,
0x3e, 0x09, 0x98, 0x5d, 0x05, 0xa8, 0xa5, 0xcf, 0xb6, 0x4a, 0x27, 0x50, 0xe6, 0xdd, 0x45, 0x98, 0xbd, 0x75, 0x07,
0xb9, 0x3d, 0xa0, 0x7f, 0xd7, 0x53, 0x88, 0xb7, 0xa8, 0xa0, 0xcc, 0x59, 0xab, 0x04, 0x1b, 0x21, 0x27, 0xee, 0x94,
0x03, 0xea, 0x66, 0xe1, 0x1b, 0xbf, 0xd7, 0x0d, 0x59, 0xac, 0x9e, 0x29, 0xe9, 0xf0, 0x53, 0xa3, 0x63, 0xbf, 0xda,
0x61, 0xb7, 0xbb, 0x28, 0xa0, 0xd6, 0x32, 0xd5, 0x90, 0x21, 0x1a, 0x66, 0xab, 0x92, 0xcd, 0x58, 0xd9, 0xad, 0x85,
0xec, 0x45, 0x24, 0x95, 0xb6, 0xfd, 0x4d, 0x6d, 0xe3, 0x4c, 0x44, 0x4b, 0x4d, 0xd7, 0xe0, 0xc2, 0x40, 0x7a, 0x56,
0xec, 0x0a, 0xe0, 0xaf, 0x6e, 0x45, 0xe4, 0xeb, 0x30, 0xe3, 0xab, 0xf3, 0xd9, 0xfe, 0x7e, 0x40, 0x0d, 0x5d, 0x68,
0x4c, 0x66, 0xc5, 0x93, 0xbb, 0x33, 0x06, 0x63, 0x49, 0xf3, 0xc1, 0x4f, 0x73, 0x90, 0xfa, 0x84, 0xe5, 0x5b, 0x61,
0x38, 0xa6, 0xcb, 0x60, 0xce, 0x05, 0xf5, 0xe3, 0xaf, 0x43, 0xcb, 0xeb, 0xe2, 0xfd, 0x14, 0xd2, 0x71, 0x60, 0x2f,
0x5c, 0x7c, 0x0b, 0x87, 0x81, 0x1a, 0xc2, 0xd5, 0xfd, 0xf3, 0xd9, 0x19, 0x93, 0x9e, 0x5b, 0x56, 0x25, 0xbb, 0xfd,
0x10, 0x75, 0xd0, 0xc5, 0x86, 0xb9, 0xe4, 0x7a, 0xb0, 0xe0, 0xdd, 0xca, 0xf7, 0xa7, 0x9a, 0x3e, 0xb6, 0x5a, 0xd0,
0xde, 0x75, 0x6b, 0xa5, 0xa3, 0xdf, 0xb4, 0x0e, 0xa1, 0x89, 0x8c, 0xe9, 0xf1, 0x62, 0x8b, 0xda, 0x5f, 0xf8, 0x1d,
0xe6, 0xd9, 0x70, 0xc9, 0xd0, 0x92, 0x42, 0x3f, 0x36, 0xf9, 0xb9, 0x23, 0x6b, 0x5d, 0x26, 0x9c, 0x14, 0x5d, 0xe7,
0x9b, 0x81, 0x11, 0x1b, 0xec, 0xd1, 0xf9, 0x22, 0xfe, 0xc4, 0xa9, 0xd7, 0x71, 0x5e, 0x32, 0x8d, 0x64, 0x41, 0x50,
0xca, 0x7c, 0xc8, 0x55, 0xc6, 0xb5, 0xe3, 0xd8, 0xa1, 0xe8, 0xb5, 0x1c, 0x68, 0x20, 0xef, 0x42, 0xc6, 0x9d, 0xea,
0x2f, 0x8a, 0xa4, 0x87, 0x3b, 0xdc, 0x0c, 0xc7, 0x9f, 0x3f, 0x89, 0x29, 0x9b, 0x46, 0xb7, 0xc7, 0x6a, 0x16, 0xe6,
0x2f, 0xe6, 0x9f, 0xa8, 0x02, 0xfb, 0x99, 0x1b, 0x4f, 0xcd, 0x40, 0xf7, 0xad, 0xa9, 0xd0, 0x56, 0x1a, 0xad, 0xc0,
0x47, 0x96, 0x36, 0xbe, 0x11, 0x7f, 0x0c, 0x6d, 0x47, 0xab, 0x4f, 0xe1, 0x90, 0x47, 0x21, 0xd6, 0x33, 0x72, 0x11,
0xb4, 0x65, 0x99, 0x4a, 0x43, 0x52, 0x90, 0x80, 0x2e, 0xed, 0x75, 0x96, 0x39, 0x78, 0x45, 0x0f, 0x42, 0xd2, 0x3b,
0x3b, 0xf9, 0x84, 0xed, 0x1d, 0x5e, 0x8a, 0x24, 0x1f, 0xff, 0xe1, 0x7e, 0x75, 0xef, 0xd4, 0xc5, 0x51, 0x85, 0x07,
0x0e, 0xcb, 0xda, 0x40, 0x92, 0x8e, 0x00, 0xf9, 0x4c, 0x44, 0x03, 0xa6, 0x56, 0xbf, 0xa0, 0xc6, 0x04, 0xec, 0xc7,
0xac, 0xbd, 0x78, 0xd2, 0x0a, 0x9d, 0x3f, 0x83, 0x42, 0xcc, 0x79, 0xc0, 0x6d, 0x9d, 0xa3, 0x0d, 0x27, 0x66, 0x2f,
0xcd, 0x21, 0x22, 0xeb, 0x38, 0x64, 0xc7, 0x31, 0x1b, 0x66, 0x68, 0xd4, 0x53, 0xce, 0x0b, 0xc5, 0x07, 0x07, 0x48,
0x89, 0xa9, 0x86, 0xa6, 0x5b, 0xaa, 0xdc, 0xb5, 0x20, 0x00, 0x7b, 0xeb, 0x0f, 0x58, 0x48, 0x3f, 0x1d, 0x1b, 0xe4,
0x87, 0x29, 0x23, 0xba, 0x92, 0xec, 0x3a, 0xc8, 0x05, 0x9e, 0x56, 0x2e, 0xf6, 0x69, 0x97, 0x79, 0x4a, 0x8f, 0xfc,
0xac, 0xcf, 0x5a, 0xe9, 0x12, 0x18, 0xc7, 0x59, 0xc6, 0x1c, 0xf1, 0xe3, 0xfe, 0x8d, 0x3f, 0x6e, 0x1c, 0xfa, 0x4d,
0xb3, 0x73, 0xa4, 0x9b, 0x77, 0xd9, 0x20, 0xf8, 0x86, 0xf1, 0xb0, 0xac, 0x6e, 0x35, 0x62, 0x68, 0x01, 0xc6, 0xe6,
0xee, 0x88, 0xf3, 0x30, 0x80, 0xc7, 0x8b, 0xd2, 0x0a, 0xb5, 0xe3, 0x17, 0x0e, 0xf8, 0xa6, 0xdf, 0x53, 0x22, 0x5f,
0x3d, 0x4d, 0xae, 0xc7, 0xd1, 0x4b, 0xb9, 0xd0, 0xe6, 0x63, 0x80, 0x6e, 0x4c, 0x1d, 0x9d, 0x28, 0xf4, 0xe2, 0x01,
0x62, 0x4d, 0x23, 0xb0, 0x67, 0x61, 0x49, 0x3f, 0x39, 0xae, 0x5f, 0x0f, 0x18, 0xc5, 0x81, 0x47, 0xd4, 0xa5, 0x04,
0x93, 0xd3, 0xd5, 0x63, 0x9e, 0xe2, 0x43, 0xec, 0x50, 0xbc, 0xdf, 0x2e, 0xc7, 0x5a, 0xf7, 0x21, 0x17, 0x00, 0x51,
0x14, 0xc2, 0x04, 0x0a, 0x57, 0xf6, 0x5d, 0x31, 0xac, 0x89, 0xef, 0x22, 0x6e, 0xb5, 0x98, 0xa4, 0x7f, 0x93, 0xfa,
0xc2, 0xf3, 0x58, 0x07, 0x6a, 0x7e, 0x53, 0x4e, 0xc7, 0x9e, 0xa2, 0x07, 0x5e, 0x87, 0xb7, 0xdf, 0xea, 0xd3, 0x8f,
0x84, 0xf8, 0xe6, 0xac, 0xf0, 0x42, 0x22, 0xd7, 0x76, 0xcd, 0xd0, 0x97, 0x8e, 0xc1, 0xc9, 0x6f, 0x61, 0x0c, 0xe8,
0xdb, 0x13, 0xb5, 0x2f, 0x09, 0xd2, 0x00, 0xbc, 0x58, 0xa3, 0x47, 0x6a, 0x91, 0xe7, 0x93, 0x46, 0xe7, 0xb0, 0xfd,
0xb8, 0xb0, 0xc6, 0xc7, 0x6d, 0xe1, 0x77, 0x39, 0x07, 0x4c, 0x22, 0x3d, 0x84, 0x98, 0x82, 0xba, 0x6f, 0x04, 0xbb,
0xb0, 0xc9, 0xdb, 0x26, 0x18, 0xb4, 0xb6, 0xdd, 0x79, 0xe5, 0x74, 0x05, 0x4a, 0xc7, 0xfa, 0xde, 0x0b, 0x70, 0xab,
0x8c, 0x22, 0x45, 0xa6, 0xa3, 0x76, 0x6b, 0xc2, 0x74, 0xcd, 0xf4, 0x4b, 0x19, 0xe6, 0xc6, 0x79, 0x42, 0x56, 0x4b,
0xb4, 0xbe, 0x23, 0xdb, 0x8a, 0xc9, 0x22, 0xe9, 0x6c, 0x18, 0x10, 0xef, 0x2c, 0xa5, 0x73, 0x1a, 0x37, 0x3a, 0x2e,
0xb5, 0x92, 0xc0, 0xe7, 0x57, 0x95, 0x45, 0x19, 0xcd, 0x6a, 0xce, 0xf8, 0xc5, 0x45, 0xe2, 0x08, 0x3f, 0x61, 0xd3,
0x7b, 0xb3, 0xbe, 0xcb, 0x4f, 0x03, 0x9b, 0x9a, 0x24, 0x1f, 0xb5, 0x41, 0xde, 0x7a, 0x3e, 0x3e, 0xff, 0x30, 0x9c,
0x95, 0xc1, 0xf4, 0xe6, 0xa3, 0xf6, 0xbb, 0x1f, 0xa2, 0xa0, 0x2a, 0x30, 0xfb, 0x50, 0xc0, 0xa7, 0x4f, 0x3f, 0xc3,
0x32, 0x43, 0x2e, 0xec, 0xd9, 0x0f, 0xfd, 0xd1, 0xff, 0xc6, 0x0d, 0x16, 0x17, 0x63, 0x57, 0x53, 0x25, 0x97, 0x49,
0xc4, 0xfb, 0x55, 0x64, 0xb4, 0x31, 0x19, 0x97, 0xa6, 0xe1, 0xfc, 0x59, 0x48, 0x27, 0x79, 0x88, 0x18, 0x5c, 0xfd,
0x04, 0xd3, 0x0d, 0x30, 0x0a, 0xa2, 0xbd, 0x06, 0x52, 0x04, 0x5f, 0x84, 0xe8, 0x7a, 0x92, 0x52, 0xcc, 0xf4, 0x9a,
0x06, 0x48, 0xfe, 0x22, 0x2a, 0x13, 0xaa, 0xb4, 0x13, 0x2a, 0x3c, 0xf4, 0x61, 0x6a, 0x98, 0xa0, 0x55, 0xee, 0x6c,
0x48, 0xd6, 0x2b, 0x1d, 0xcc, 0x41, 0xcc, 0x73, 0x9a, 0xf4, 0x4e, 0x03, 0xa4, 0x98, 0x5c, 0x60, 0x24, 0x32, 0xe8,
0x00, 0x0f, 0xe9, 0x0d, 0xf0, 0x5a, 0x95, 0xa8, 0x38, 0xef, 0x0b, 0xb0, 0x0c, 0x6e, 0x2b, 0x59, 0xb7, 0xa4, 0xa6,
0xed, 0x47, 0xcc, 0x90, 0x65, 0xf9, 0x88, 0xa9, 0xca, 0x63, 0x9d, 0x6b, 0x4e, 0x64, 0x71, 0xd3, 0x29, 0xcb, 0x46,
0xf0, 0x34, 0xca, 0x34, 0x2c, 0x48, 0x19, 0xe8, 0x5d, 0x55, 0xe9, 0x1f, 0x8b, 0x41, 0x8f, 0xe0, 0x7f, 0x86, 0xed,
0x7c, 0x10, 0x8a, 0xa0, 0x46, 0x2d, 0xbd, 0xeb, 0x13, 0xa9, 0x75, 0x66, 0x70, 0xca, 0x89, 0x66, 0xa6, 0x8f, 0xaf,
0x2b, 0x6e, 0xc5, 0x96, 0xcd, 0x74, 0xc8, 0xc2, 0xe3, 0x8e, 0x1a, 0x2b, 0xf8, 0xb9, 0xa5, 0x95, 0xaf, 0xd8, 0xd0,
0xae, 0xb0, 0x2b, 0x44, 0xe9, 0x59, 0x90, 0x7b, 0x1d, 0x26, 0x7d, 0x0d, 0xdc, 0xdc, 0xb9, 0xba, 0x94, 0x78, 0xdd,
0x36, 0x68, 0xdb, 0x8e, 0xb8, 0xcc, 0x32, 0x77, 0x41, 0xe3, 0x27, 0x09, 0xac, 0x98, 0xc9, 0xf2, 0x7a, 0x7e, 0x3c,
0x5e, 0x5b, 0x68, 0x20, 0xf0, 0x7c, 0xc8, 0xc2, 0x7f, 0x94, 0xc8, 0x05, 0x91, 0xac, 0x2a, 0x0e, 0x98, 0xb1, 0xe0,
0xb3, 0xee, 0xba, 0x6a, 0xa1, 0x92, 0x1a, 0xf3, 0x4f, 0xa0, 0x25, 0x2b, 0xa6, 0x92, 0xc3, 0xe3, 0x6d, 0x39, 0xb6,
0x6a, 0x76, 0x79, 0xab, 0xa9, 0x8a, 0xc7, 0x02, 0x00, 0x15, 0x64, 0x5d, 0xdf, 0x92, 0x56, 0xea, 0x25, 0xb5, 0x2b,
0x71, 0x39, 0x5a, 0x6d, 0x1c, 0xe9, 0x30, 0xe4, 0x0a, 0x05, 0x24, 0x8e, 0x92, 0xba, 0x90, 0x5f, 0x57, 0xb0, 0x20,
0xb9, 0x10, 0xe3, 0x88, 0xa9, 0x14, 0x42, 0xe8, 0xe7, 0xa8, 0x09, 0xfa, 0x8c, 0x09, 0xdf, 0x01, 0x91, 0x38, 0xaf,
0x71, 0x0b, 0x88, 0x46, 0x5f, 0x29, 0xe8, 0xb1, 0xa7, 0xe9, 0xf1, 0x54, 0xdf, 0x9d, 0xae, 0xca, 0xff, 0x21, 0x2f,
0x80, 0xcc, 0xd9, 0xcc, 0x11, 0x09, 0x6d, 0x3a, 0x5f, 0x5d, 0x44, 0x4f, 0x75, 0x03, 0xc1, 0x95, 0x1f, 0x33, 0x40,
0x90, 0x47, 0x54, 0xcf, 0xcf, 0x0e, 0xde, 0xac, 0xb5, 0xae, 0x11, 0x83, 0x05, 0x12, 0x57, 0x64, 0x2f, 0x32, 0x7a,
0x86, 0x5c, 0x30, 0x86, 0xbe, 0x3b, 0x34, 0x7c, 0xbd, 0x89, 0x08, 0xbb, 0x0c, 0x63, 0x72, 0x2e, 0xc9, 0x4b, 0x55,
0x36, 0x1f, 0xfc, 0x86, 0x56, 0x86, 0xed, 0x6f, 0xa1, 0xc0, 0xa7, 0x66, 0xe4, 0x8f, 0xc7, 0xcb, 0x93, 0x36, 0xd2,
0xe4, 0x74, 0xb6, 0xbd, 0x78, 0x0d, 0xc5, 0x37, 0x2d, 0xcf, 0x8e, 0xbc, 0xa1, 0xff, 0x2c, 0x5a, 0x4b, 0x68, 0xe4,
0x42, 0x10, 0xc2, 0x24, 0x0e, 0xa5, 0xe0, 0x3f, 0xd4, 0xa7, 0x9d, 0xe6, 0xee, 0x7b, 0x85, 0x66, 0x87, 0xe7, 0x42,
0xa4, 0xe6, 0x6d, 0xcd, 0xd8, 0x7a, 0x6b, 0x50, 0x0c, 0xaa, 0xf4, 0xdd, 0x53, 0x59, 0x6c, 0xd1, 0xca, 0x3b, 0xe6,
0x06, 0x50, 0xda, 0x3d, 0xbc, 0x05, 0x67, 0xf4, 0x45, 0x83, 0x41, 0xce, 0x72, 0xdf, 0x47, 0x2c, 0xc0, 0x5e, 0xde,
0x2b, 0x42, 0xf7, 0xc1, 0x7a, 0x4e, 0x8d, 0x8b, 0xfc, 0xe7, 0xe9, 0x06, 0x21, 0xee, 0x79, 0x31, 0x04, 0x07, 0xca,
0x13, 0x44, 0x4c, 0xc7, 0x42, 0xa4, 0xb4, 0xaf, 0x32, 0x62, 0x42, 0xd7, 0x3f, 0x58, 0xed, 0x25, 0x78, 0xd3, 0x52,
0x48, 0x31, 0x36, 0x1c, 0xb8, 0x47, 0x4f, 0x2f, 0x71, 0x31, 0x75, 0x97, 0x6f, 0xcc, 0x66, 0x34, 0xe8, 0xe3, 0xe2,
0x21, 0x4c, 0x7f, 0x06, 0xe9, 0xfd, 0xf4, 0x6a, 0x69, 0xce, 0xa8, 0xfa, 0x83, 0x3d, 0xa2, 0x95, 0x87, 0x70, 0xd6,
0x67, 0x62, 0xf2, 0x33, 0x06, 0x84, 0x2a, 0x68, 0x4f, 0x93, 0x9f, 0x7a, 0xff, 0xd1, 0xee, 0x07, 0x10, 0x4d, 0x86,
0x57, 0xda, 0xcd, 0x2a, 0x28, 0xe5, 0x77, 0x24, 0x36, 0x8f, 0x41, 0x4a, 0x8c, 0x62, 0x1e, 0xb2, 0x8d, 0x32, 0xe6,
0x34, 0xc1, 0xf9, 0x01, 0xa4, 0x61, 0x73, 0xdb, 0xcc, 0xa1, 0x79, 0x08, 0x2c, 0xc0, 0x1f, 0x32, 0x71, 0xd0, 0x8c,
0xc6, 0xb5, 0x45, 0x9c, 0x62, 0x7c, 0x40, 0x37, 0xfd, 0x6a, 0x99, 0x6f, 0xd4, 0xc6, 0xae, 0x5c, 0x18, 0xaf, 0xef,
0xb7, 0x59, 0x20, 0x25, 0x39, 0xb0, 0xa5, 0x85, 0xb1, 0xaf, 0xda, 0x78, 0xe8, 0x09, 0xa9, 0x28, 0x34, 0x02, 0x3f,
0xca, 0xde, 0x95, 0xd3, 0xae, 0x35, 0x67, 0x16, 0x08, 0x6f, 0x6e, 0x78, 0x7c, 0x43, 0x60, 0x21, 0x6b, 0x46, 0xde,
0xaa, 0x00, 0x09, 0x5d, 0x9f, 0xf8, 0xf0, 0xd8, 0xb6, 0x35, 0xd1, 0x38, 0xcc, 0x02, 0x50, 0x7e, 0xa3, 0x24, 0xfd,
0xb6, 0x5d, 0xa5, 0x2a, 0x9c, 0xb7, 0x60, 0x8d, 0x0b, 0x07, 0x4b, 0x9b, 0x29, 0xf4, 0x87, 0x9f, 0x54, 0xf7, 0x29,
0x9c, 0xcb, 0x94, 0xc6, 0xe8, 0x1d, 0x59, 0xc1, 0x85, 0x52, 0x93, 0x54, 0x3e, 0xda, 0xd3, 0x5f, 0x86, 0x39, 0x24,
0xf3, 0x10, 0x70, 0x09, 0x9e, 0x2d, 0x2a, 0x39, 0x74, 0xea, 0xac, 0x19, 0xe2, 0xe5, 0x79, 0xfd, 0x32, 0xf3, 0xc8,
0x1f, 0xdd, 0x74, 0xa7, 0x5b, 0x94, 0x70, 0xeb, 0xb0, 0x0d, 0x7a, 0xde, 0x77, 0x8e, 0x41, 0xa8, 0x61, 0x3a, 0xf6,
0x79, 0x32, 0x1e, 0x62, 0x7c, 0x3f, 0xfb, 0xc3, 0x7b, 0xa8, 0xd1, 0x6a, 0x52, 0x56, 0x30, 0x15, 0x15, 0xb3, 0x3e,
0x0d, 0x01, 0x2c, 0x87, 0xff, 0x23, 0x68, 0x88, 0x9b, 0xca, 0x45, 0xf9, 0xee, 0xae, 0x97, 0xde, 0x80, 0xdd, 0x9f,
0x4c, 0x2d, 0x69, 0x4d, 0xfc, 0xc3, 0xd3, 0x36, 0x91, 0x61, 0x36, 0x53, 0xa9, 0x8a, 0x33, 0x7f, 0xa5, 0x0c, 0xa0,
0xaf, 0x39, 0x93, 0xef, 0xee, 0xb2, 0x0c, 0x60, 0x20, 0x0a, 0xbb, 0xe7, 0x73, 0xad, 0x1b, 0xdb, 0xa4, 0x09, 0x79,
0x63, 0xf7, 0xd8, 0x4f, 0xa0, 0xf3, 0x2d, 0x61, 0x9a, 0xe1, 0x40, 0x99, 0xec, 0x03, 0xf9, 0xa3, 0x2f, 0x95, 0x3d,
0x48, 0x28, 0x85, 0xfc, 0x8b, 0xb1, 0xf1, 0xf7, 0x86, 0x68, 0x64, 0x52, 0x01, 0x19, 0xd0, 0xdd, 0xd7, 0xec, 0x4b,
0x22, 0x09, 0x4e, 0x8a, 0x2e, 0x9f, 0xa0, 0x1e, 0x20, 0x43, 0xa2, 0x70, 0x73, 0x9b, 0x9e, 0x7d, 0x0b, 0x69, 0x54,
0x52, 0x01, 0x65, 0xa8, 0x47, 0x2e, 0xd6, 0x0e, 0xfb, 0x79, 0xf2, 0xb1, 0x13, 0xe1, 0xfb, 0x66, 0xb1, 0x49, 0x16,
0x54, 0xb6, 0x07, 0xe9, 0x5f, 0xb8, 0x2a, 0xfc, 0x59, 0xc2, 0x8f, 0xcd, 0xe8, 0xce, 0xa3, 0xb0, 0x35, 0x03, 0xf5,
0x6d, 0x59, 0xaf, 0x83, 0x98, 0x88, 0x03, 0xc0, 0xae, 0xfb, 0x90, 0x68, 0xf4, 0x9f, 0x85, 0x04, 0x10, 0x7f, 0xa5,
0x3c, 0x64, 0xf2, 0x0b, 0xe0, 0x2e, 0x84, 0x9e, 0xb5, 0x60, 0xa5, 0x52, 0xff, 0x40, 0x14, 0x23, 0xd3, 0xc0, 0x09,
0xd2, 0x19, 0x9b, 0x25, 0x5e, 0x63, 0x34, 0x1a, 0x41, 0x71, 0x2e, 0x1a, 0x70, 0x80, 0xca, 0x01, 0x10, 0x57, 0x04,
0x41, 0xf8, 0x0f, 0x6d, 0x91, 0xea, 0xa5, 0xc7, 0x55, 0x91, 0x41, 0x62, 0xcc, 0x3a, 0x43, 0x39, 0xfb, 0x52, 0x13,
0xcb, 0x5d, 0xa4, 0xa5, 0xbb, 0x47, 0x4f, 0xce, 0x27, 0x1d, 0x88, 0x4a, 0xc8, 0x37, 0x15, 0x89, 0xce, 0x90, 0x84,
0x3e, 0x79, 0x34, 0x2f, 0xa5, 0x77, 0x68, 0xf1, 0x96, 0x01, 0x96, 0xa6, 0x4e, 0xb3, 0xff, 0x64, 0xf9, 0x2f, 0x1f,
0x7b, 0xff, 0x72, 0xdf, 0x2d, 0x13, 0xf1, 0x7d, 0x2d, 0xfc, 0x7b, 0x3c, 0xd9, 0x21, 0xce, 0xcb, 0x37, 0xd7, 0xf6,
0x76, 0xb1, 0x6b, 0x69, 0x0e, 0x90, 0xee, 0xe4, 0x99, 0x3a, 0xc3, 0x04, 0xba, 0x2b, 0xe9, 0xa3, 0xdf, 0xb5, 0x09,
0xf8, 0x2c, 0x78, 0x3f, 0x6d, 0x2b, 0x9f, 0xa8, 0x3f, 0x30, 0xdf, 0xb0, 0xd8, 0x8d, 0x30, 0x19, 0xec, 0x7b, 0x4a,
0xca, 0x55, 0xc3, 0xde, 0x5d, 0xaf, 0x2f, 0x99, 0x66, 0xb3, 0xb4, 0xda, 0x84, 0x54, 0x5c, 0x2d, 0x2a, 0x9b, 0xf5,
0x8f, 0x2b, 0x43, 0x7c, 0x61, 0x07, 0x14, 0x46, 0x28, 0xf7, 0x00, 0xf4, 0x0a, 0xba, 0xff, 0x14, 0x08, 0x1e, 0xaa,
0x97, 0xfc, 0x4d, 0x99, 0xf7, 0x52, 0xdd, 0x7e, 0x25, 0x86, 0x95, 0xfe, 0x33, 0x61, 0x00, 0x53, 0xc6, 0xf3, 0xb4,
0xa2, 0x39, 0x4f, 0x5f, 0x1d, 0x92, 0x09, 0x96, 0xd8, 0x25, 0x70, 0x5e, 0x6c, 0x0a, 0x8c, 0x76, 0x4e, 0x40, 0xd6,
0x6a, 0xed, 0x9e, 0xba, 0x59, 0x8d, 0x7d, 0xcd, 0x81, 0xe6, 0x27, 0xce, 0x8f, 0x7b, 0xfe, 0x5e, 0xa8, 0xbc, 0x6c,
0x7f, 0x37, 0xdb, 0x8e, 0xce, 0x75, 0x6e, 0xa0, 0x80, 0xb9, 0xc9, 0x27, 0x1e, 0x85, 0x19, 0xe0, 0x00, 0x4c, 0x41,
0x6b, 0x8b, 0x05, 0x74, 0xb7, 0x2a, 0x70, 0x97, 0x2c, 0x0d, 0x2b, 0x54, 0x9b, 0xa4, 0x74, 0xfe, 0xe7, 0xda, 0xbb,
0x27, 0x70, 0x12, 0xef, 0x03, 0x43, 0xe2, 0x85, 0x7b, 0x02, 0x92, 0x48, 0x11, 0x94, 0x53, 0xe4, 0x76, 0x8d, 0x3f,
0x30, 0xed, 0x5c, 0x15, 0x3e, 0x5d, 0x37, 0xb0, 0x24, 0x39, 0xc7, 0x4c, 0x89, 0x10, 0x93, 0x79, 0xef, 0xf3, 0x2d,
0xdb, 0xc2, 0x8a, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xed, 0xbb, 0x8c, 0x8a, 0x8d, 0x8a, 0xe1, 0x16, 0x03, 0x00,
};
static constexpr size_t WINDOW = 4096;
static constexpr size_t PLAIN_SIZE = 16000;
@@ -223,18 +757,55 @@ static std::vector<uint8_t> build_plain() {
return plain;
}
// Text, incompressible noise that zlib stores, then text again
static std::vector<uint8_t> build_mixed() {
std::vector<uint8_t> plain;
const char *text = "esphome ota deflate ";
for (int i = 0; i < 60; i++)
plain.insert(plain.end(), text, text + strlen(text));
uint32_t x = 3;
for (int i = 0; i < 3000; i++)
plain.push_back(lcg_next(x));
for (int i = 0; i < 40; i++)
plain.insert(plain.end(), text, text + strlen(text));
return plain;
}
static std::vector<uint8_t> build_skewed() {
std::vector<uint8_t> plain;
const char *common = "etaoin ";
uint32_t x = 7;
for (int i = 0; i < 6000; i++) {
uint8_t r = lcg_next(x);
plain.push_back(r < 230 ? common[r % 7] : lcg_next(x));
}
return plain;
}
// Mirrors the OTA session: chunked input through the read callback, window as output
struct Session : OtaInflateState {
const uint8_t *in;
size_t in_len;
size_t in_pos;
size_t chunk;
// Like the session where the ack follows the write: output is taken
// before each read, up to dest
bool flush_in_read;
size_t flushed;
std::vector<uint8_t> out;
uint8_t window[WINDOW];
};
static void take_output(Session &s) {
const size_t produced = s.dest - s.window;
s.out.insert(s.out.end(), s.window + s.flushed, s.window + produced);
s.flushed = produced;
}
static int read_cb(OtaInflateState *d) {
auto *s = static_cast<Session *>(d);
if (s->flush_in_read)
take_output(*s);
if (s->in_pos >= s->in_len)
return -1;
size_t n = std::min(s->chunk, s->in_len - s->in_pos);
@@ -245,23 +816,26 @@ static int read_cb(OtaInflateState *d) {
}
// Inflates the whole input; returns the decoder result and fills s.out
static int inflate_all(Session &s, const uint8_t *in, size_t in_len, size_t chunk) {
static int inflate_all(Session &s, const uint8_t *in, size_t in_len, size_t chunk, bool flush_in_read = false) {
s.in = in;
s.in_len = in_len;
s.in_pos = 0;
s.chunk = chunk;
s.flush_in_read = flush_in_read;
s.flushed = 0;
s.out.clear();
memset(s.window, 0, sizeof(s.window));
ota_inflate_init(&s, s.window, WINDOW);
s.source_read_cb = read_cb;
int res;
do {
s.dest = s.window;
s.dest_limit = s.window + WINDOW;
// Starts the window over once the previous call filled it
res = ota_inflate(&s);
if (res < 0 || s.eof)
return res < 0 ? res : OTA_INFLATE_DATA_ERROR;
s.out.insert(s.out.end(), s.window, s.dest);
take_output(s);
// A full window is taken; the next call starts it over
s.flushed = 0;
if (s.out.size() > PLAIN_SIZE)
return OTA_INFLATE_DATA_ERROR;
} while (res != OTA_INFLATE_DONE);
@@ -289,6 +863,36 @@ TEST(OtaInflate, StoredBlock) {
EXPECT_EQ(s->out, plain);
}
// Dynamic blocks, fixed Huffman blocks, codes longer than the lookup tables, and
// stored blocks that start with read ahead bits in the bit buffer
struct Stream {
const uint8_t *data;
size_t len;
std::vector<uint8_t> (*plain)();
};
static const Stream STREAMS[] = {{DEFLATED, sizeof(DEFLATED), build_plain},
{FIXED, sizeof(FIXED), build_plain},
{SKEWED, sizeof(SKEWED), build_skewed},
{MIXED, sizeof(MIXED), build_mixed}};
TEST(OtaInflate, EveryReadSizeGivesTheSameOutput) {
// 1 byte reads never leave enough input for the fast loop, 11 to 13 straddle
// its threshold, and the larger ones run it across read and window boundaries
auto s = std::make_unique<Session>();
for (const auto &stream : STREAMS) {
const auto plain = stream.plain();
for (bool flush_in_read : {false, true}) {
for (size_t chunk : {size_t{1}, size_t{11}, size_t{12}, size_t{13}, size_t{300}, size_t{1040}, stream.len}) {
ASSERT_EQ(inflate_all(*s, stream.data, stream.len, chunk, flush_in_read), OTA_INFLATE_DONE)
<< "stream of " << stream.len << " B, read size " << chunk << ", flush in read " << flush_in_read;
EXPECT_EQ(s->out, plain) << "stream of " << stream.len << " B, read size " << chunk << ", flush in read "
<< flush_in_read;
EXPECT_EQ(s->in_pos, stream.len);
}
}
}
}
TEST(OtaInflate, TruncatedStreamFails) {
auto s = std::make_unique<Session>();
for (size_t cut : {size_t{1}, size_t{100}, size_t{1000}, sizeof(DEFLATED) - 1}) {
@@ -305,12 +909,14 @@ TEST(OtaInflate, TruncatedStoredBlockFails) {
TEST(OtaInflate, CorruptStreamsNeverEscapeTheWindow) {
// Flipped bytes and garbage; the sanitizers check the decoder stays in bounds
auto s = std::make_unique<Session>();
std::vector<uint8_t> bad(DEFLATED, DEFLATED + sizeof(DEFLATED));
// A coarse, non-aligned stride: neighbouring offsets hit the same paths
for (size_t i = 0; i < bad.size(); i += 29) {
bad[i] ^= 0x5a;
inflate_all(*s, bad.data(), bad.size(), 1040);
bad[i] ^= 0x5a;
for (const auto &stream : STREAMS) {
std::vector<uint8_t> bad(stream.data, stream.data + stream.len);
// A coarse, non-aligned stride: neighbouring offsets hit the same paths
for (size_t i = 0; i < bad.size(); i += 29) {
bad[i] ^= 0x5a;
inflate_all(*s, bad.data(), bad.size(), 1040);
bad[i] ^= 0x5a;
}
}
uint32_t x = 99;
std::vector<uint8_t> garbage(2000);