From 2eb7a58e1ca30604b05efd69881d74693aaf33ea Mon Sep 17 00:00:00 2001 From: Rene Zeldenthuis Date: Sun, 18 Feb 2024 12:47:17 +0100 Subject: [PATCH] Work in progress --- lib/micro-jpg/include/jpg.h | 18 ++ lib/micro-jpg/include/jpg_section.h | 103 ++++++++++++ lib/micro-jpg/library.json | 14 ++ lib/micro-jpg/src/jpg.cpp | 90 ++++++++++ lib/micro-jpg/src/jpg_section.cpp | 154 +++++++++++++++++ .../include/micro_rtsp_jpeg.h | 35 ---- .../include/micro_rtsp_streamer.h | 15 ++ .../include/micro_rtssp_streamer.h | 6 - lib/micro-rtsp-server/library.json | 1 + lib/micro-rtsp-server/src/micro_rtsp_jpeg.cpp | 101 ----------- .../src/micro_rtsp_requests.cpp | 2 + .../src/micro_rtsp_streamer.cpp | 157 ++++++++++++++++++ .../src/micro_rtssp_streamer.cpp | 1 - test/test_main.cpp | 46 +++-- 14 files changed, 585 insertions(+), 158 deletions(-) create mode 100644 lib/micro-jpg/include/jpg.h create mode 100644 lib/micro-jpg/include/jpg_section.h create mode 100644 lib/micro-jpg/library.json create mode 100644 lib/micro-jpg/src/jpg.cpp create mode 100644 lib/micro-jpg/src/jpg_section.cpp delete mode 100644 lib/micro-rtsp-server/include/micro_rtsp_jpeg.h create mode 100644 lib/micro-rtsp-server/include/micro_rtsp_streamer.h delete mode 100644 lib/micro-rtsp-server/include/micro_rtssp_streamer.h delete mode 100644 lib/micro-rtsp-server/src/micro_rtsp_jpeg.cpp create mode 100644 lib/micro-rtsp-server/src/micro_rtsp_streamer.cpp delete mode 100644 lib/micro-rtsp-server/src/micro_rtssp_streamer.cpp diff --git a/lib/micro-jpg/include/jpg.h b/lib/micro-jpg/include/jpg.h new file mode 100644 index 0000000..b0a5b95 --- /dev/null +++ b/lib/micro-jpg/include/jpg.h @@ -0,0 +1,18 @@ +#include + +#include "jpg_section.h" + +class jpg +{ +public: + bool decode(const uint8_t *jpg, size_t size); + + const struct jpg_section *quantization_table_0_; + const struct jpg_section *quantization_table_1_; + + const uint8_t *jpeg_data_start; + const uint8_t *jpeg_data_end; + +private: + static const jpg_section *find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section::jpg_section_flag flag); +}; \ No newline at end of file diff --git a/lib/micro-jpg/include/jpg_section.h b/lib/micro-jpg/include/jpg_section.h new file mode 100644 index 0000000..2f10a0e --- /dev/null +++ b/lib/micro-jpg/include/jpg_section.h @@ -0,0 +1,103 @@ +#pragma once + +#include + +struct __attribute__((packed)) jpg_section +{ + enum jpg_section_flag : uint8_t + { + DATA = 0x00, + SOF0 = 0xc0, + SOF1 = 0xc1, + SOF2 = 0xc2, + SOF3 = 0xc3, + DHT = 0xc4, + SOF5 = 0xc5, + SOF6 = 0xc6, + SOF7 = 0xc7, + JPG = 0xc8, + SOF9 = 0xc9, + SOF10 = 0xca, + SOF11 = 0xcb, + DAC = 0xcc, + SOF13 = 0xcd, + SOF14 = 0xce, + SOF15 = 0xcf, + RST0 = 0xd0, + RST1 = 0xd1, + RST2 = 0xd2, + RST3 = 0xd3, + RST4 = 0xd4, + RST5 = 0xd5, + RST6 = 0xd6, + RST7 = 0xd7, + SOI = 0xd8, + EOI = 0xd9, + SOS = 0xda, + DQT = 0xdb, + DNL = 0xdc, + DRI = 0xdd, + DHP = 0xde, + EXP = 0xdf, + APP0 = 0xe0, + APP1 = 0xe1, + APP2 = 0xe2, + APP3 = 0xe3, + APP4 = 0xe4, + APP5 = 0xe5, + APP6 = 0xe6, + APP7 = 0xe7, + APP8 = 0xe8, + APP9 = 0xe9, + APP10 = 0xea, + APP11 = 0xeb, + APP12 = 0xec, + APP13 = 0xed, + APP14 = 0xee, + APP15 = 0xef, + JPG0 = 0xf0, + JPG1 = 0xf1, + JPG2 = 0xf2, + JPG3 = 0xf3, + JPG4 = 0xf4, + JPG5 = 0xf5, + JPG6 = 0xf6, + JPG7 = 0xf7, + JPG8 = 0xf8, + JPG9 = 0xf9, + COM = 0xfe, + JPG10 = 0xfa, + JPG11 = 0xfb, + JPG12 = 0xfc, + JPG13 = 0xfd + }; + + const uint8_t framing; // 0xff + const jpg_section_flag flag; + const uint8_t length_msb; + const uint8_t length_lsb; + const uint8_t data[]; + + static bool is_valid_flag(const jpg_section_flag flag); + static const char *flag_name(const jpg_section_flag flag); + uint16_t data_length() const; + uint16_t section_length() const; +}; + +struct __attribute__((packed)) jpg_section_app0 // 0xffe0 +{ + char identifier[5] = {'J', 'F', 'I', 'F', 0}; // JFIF identifier, zero-terminated + uint8_t version_major = 1; + uint8_t version_minor = 1; // JFIF version 1.1 + uint8_t density_units = 0; // no density units specified + uint16_t density_hor = 1; + uint16_t density_ver = 1; // density: 1 pixel "per pixel" horizontally and vertically + uint8_t thumbnail_hor = 0; + uint8_t thumbnail_ver = 0; // no thumbnail (size 0 x 0) +}; + +struct __attribute__((packed)) jpg_section_dqt // 0xffdb +{ + uint8_t id; // 0= quantLuminance, 1= quantChrominance + uint8_t data[64]; +}; \ No newline at end of file diff --git a/lib/micro-jpg/library.json b/lib/micro-jpg/library.json new file mode 100644 index 0000000..83bfb51 --- /dev/null +++ b/lib/micro-jpg/library.json @@ -0,0 +1,14 @@ +{ + "name": "micro-jpg", + "version": "1.0.0", + "description": "JPEG library", + "keywords": "", + "repository": { + "type": "git", + "url": "https://github.com/rzeldent/" + }, + "build": { + "srcDir": "src/", + "includeDir": "include/" + } +} \ No newline at end of file diff --git a/lib/micro-jpg/src/jpg.cpp b/lib/micro-jpg/src/jpg.cpp new file mode 100644 index 0000000..9fa9a40 --- /dev/null +++ b/lib/micro-jpg/src/jpg.cpp @@ -0,0 +1,90 @@ +#include +#include "jpg.h" + +const jpg_section *jpg::find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section::jpg_section_flag flag) +{ + log_d("find_jpeg_section 0x%02x (%s)", flag, jpg_section::flag_name(flag)); + while (*ptr < end) + { + // flag, len MSB, len LSB + auto section = reinterpret_cast((*ptr)); + if (section->framing != 0xff) + { + log_e("Expected framing 0xff but found: 0x%02x", section->framing); + break; + } + + if (!jpg_section::is_valid_flag(section->flag)) + { + log_d("Unknown section 0x%02x", flag); + return nullptr; + } + + // Advance pointer section has a length, so not SOI (0xd8) and EOI (0xd9) + *ptr += section->section_length(); + if (section->flag == flag) + { + log_d("Found section 0x%02x (%s), %d bytes", flag, jpg_section::flag_name(section->flag), section->section_length()); + return section; + } + + log_d("Skipping section: 0x%02x (%s), %d bytes", section->flag, jpg_section::flag_name(section->flag), section->section_length()); + } + + // Not found + return nullptr; +} + +// See https://create.stephan-brumme.com/toojpeg/ +bool jpg::decode(const uint8_t *data, size_t size) +{ + log_d("decode_jpeg"); + // Look for start jpeg file (0xd8) + auto ptr = data; + auto end = ptr + size; + + // Check for SOI (start of image) 0xff, 0xd8 + if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::SOI)) + { + log_e("No valid start of image marker found"); + return false; + } + + // First quantization table (Luminance - black & white images) + if (!(quantization_table_0_ = find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::DQT))) + { + log_e("No quantization table 0 section found"); + return false; + } + + // Second quantization table (Chrominance - color images) + if (!(quantization_table_1_ = find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::DQT))) + log_w("No quantization table 1 section found"); + + // Start of scan + if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::SOS)) + { + log_e("No start of scan section found"); + return false; + } + + // Start of the data sections + jpeg_data_start = ptr; + + log_d("Skipping over data sections"); + // Scan over all the sections. 0xff followed by not zero, is a new section + while (ptr < end - 1 && (ptr[0] != 0xff || ptr[1] == 0)) + ptr++; + + // Check if marker is an end of image marker + if (!find_jpg_section(&ptr, end, jpg_section::jpg_section_flag::EOI)) + { + log_e("No end of image marker found"); + return false; + } + + jpeg_data_size = ptr; + log_d("Total jpeg data = %d bytes", jpeg_data_end - jpeg_data_start); + + return true; +} diff --git a/lib/micro-jpg/src/jpg_section.cpp b/lib/micro-jpg/src/jpg_section.cpp new file mode 100644 index 0000000..882bbde --- /dev/null +++ b/lib/micro-jpg/src/jpg_section.cpp @@ -0,0 +1,154 @@ +#include "jpg_section.h" + +uint16_t jpg_section::data_length() const +{ + return (length_msb << 8) + length_lsb - sizeof(jpg_section::length_msb)- sizeof(jpg_section::length_lsb); +} + +uint16_t jpg_section::section_length() const +{ + return flag == SOI || flag == EOI ? sizeof(jpg_section::framing) + sizeof(jpg_section::flag) : sizeof(jpg_section::framing) + sizeof(jpg_section::flag) + (length_msb << 8) + length_lsb; +} + +bool jpg_section::is_valid_flag(const jpg_section_flag flag) +{ + return flag >= SOF0 && flag <= COM; +} + +// from: https://www.disktuna.com/list-of-jpeg-markers/ +const char *jpg_section::flag_name(const jpg_section_flag flag) +{ + switch (flag) + { + case DATA: + return "DATA"; // DATA + case SOF0: + return "SOF0"; // Start of Frame 0 Baseline DCT + case SOF1: + return "SOF1"; // Start of Frame 1 Extended Sequential DCT + case SOF2: + return "SOF2"; // Start of Frame 2 Progressive DCT + case SOF3: + return "SOF3"; // Start of Frame 3 Lossless (sequential) + case DHT: + return "DHT"; // Define Huffman Table + case SOF5: + return "SOF5"; // Start of Frame 5 Differential sequential DCT + case SOF6: + return "SOF6"; // Start of Frame 6 Differential progressive DCT + case SOF7: + return "SOF7"; // Start of Frame 7 Differential lossless (sequential) + case JPG: + return "JPG"; // JPEG Extensions + case SOF9: + return "SOF9"; // Start of Frame 9 Extended sequential DCT, Arithmetic coding + case SOF10: + return "SOF10"; // Start of Frame 10 Progressive DCT, Arithmetic coding + case SOF11: + return "SOF11"; // Start of Frame 11 Lossless (sequential), Arithmetic coding + case DAC: + return "DAC"; // Define Arithmetic Coding + case SOF13: + return "SOF13"; // Start of Frame 13 Differential sequential DCT, Arithmetic coding + case SOF14: + return "SOF14"; // Start of Frame 14 Differential progressive DCT, Arithmetic coding + case SOF15: + return "SOF15"; // Start of Frame 15 Differential lossless (sequential), Arithmetic coding + case RST0: + return "RST0"; // Restart Marker 0 + case RST1: + return "RST1"; // Restart Marker 1 + case RST2: + return "RST2"; // Restart Marker 2 + case RST3: + return "RST3"; // Restart Marker 3 + case RST4: + return "RST4"; // Restart Marker 4 + case RST5: + return "RST5"; // Restart Marker 5 + case RST6: + return "RST6"; // Restart Marker 6 + case RST7: + return "RST7"; // Restart Marker 7 + case SOI: + return "SOI"; // Start of Image + case EOI: + return "EOI"; // End of Image + case SOS: + return "SOS"; // Start of Scan + case DQT: + return "DQT"; // Define Quantization Table + case DNL: + return "DNL"; // Define Number of Lines (Not common) + case DRI: + return "DRI"; // Define Restart Interval + case DHP: + return "DHP"; // Define Hierarchical Progression (Not common) + case EXP: + return "EXP"; // Expand Reference Component (Not common) + case APP0: + return "APP0"; // Application Segment 0 JFIF – JFIF JPEG image, AVI1 – Motion JPEG (MJPG) + case APP1: + return "APP1"; // Application Segment 1 EXIF Metadata, TIFF IFD format, JPEG Thumbnail (160×120) Adobe XMP + case APP2: + return "APP2"; // Application Segment 2 ICC color profile, FlashPix + case APP3: + return "APP3"; // Application Segment 3 (Not common) JPS Tag for Stereoscopic JPEG images + case APP4: + return "APP4"; // Application Segment 4 (Not common) + case APP5: + return "APP5"; // Application Segment 5 (Not common) + case APP6: + return "APP6"; // Application Segment 6 (Not common) NITF Lossles profile + case APP7: + return "APP7"; // Application Segment 7 (Not common) + case APP8: + return "APP8"; // Application Segment 8 (Not common) + case APP9: + return "APP9"; // Application Segment 9 (Not common) + case APP10: + return "APP10"; // Application Segment 10 PhoTags (Not common) ActiveObject (multimedia messages / captions) + case APP11: + return "APP11"; // Application Segment 11 (Not common) HELIOS JPEG Resources (OPI Postscript) + case APP12: + return "APP12"; // Application Segment 12 Picture Info (older digicams), Photoshop Save for Web: Ducky + case APP13: + return "APP13"; // Application Segment 13 Photoshop Save As: IRB, 8BIM, IPTC + case APP14: + return "APP14"; // Application Segment 14 (Not common) + case APP15: + return "APP15"; // Application Segment 15 (Not common) + case JPG0: + return "JPG0"; // JPEG Extension 0 + case JPG1: + return "JPG1"; // JPEG Extension 1 + case JPG2: + return "JPG2"; // JPEG Extension 2 + case JPG3: + return "JPG3"; // JPEG Extension 3 + case JPG4: + return "JPG4"; // JPEG Extension 4 + case JPG5: + return "JPG5"; // JPEG Extension 5 + case JPG6: + return "JPG6"; // JPEG Extension 6 + case JPG7: + return "JPG7"; // SOF48 JPEG Extension 7 JPEG-LS Lossless JPEG + case JPG8: + return "JPG8"; // LSE JPEG Extension 8 JPEG-LS Extension Lossless JPEG Extension Parameters + case JPG9: + return "JPG9"; // JPEG Extension 9 (Not common) + case JPG10: + return "JPG10"; // JPEG Extension 10 (Not common) + case JPG11: + return "JPG11"; // JPEG Extension 11 (Not common) + case JPG12: + return "JPG12"; // JPEG Extension 12 (Not common) + case JPG13: + return "JPG13"; // JPEG Extension 13 (Not common) + case COM: + return "COM"; // Comment + } + + return "Unknown"; +} diff --git a/lib/micro-rtsp-server/include/micro_rtsp_jpeg.h b/lib/micro-rtsp-server/include/micro_rtsp_jpeg.h deleted file mode 100644 index 60ba9ea..0000000 --- a/lib/micro-rtsp-server/include/micro_rtsp_jpeg.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -class micro_rtsp_jpeg -{ -public: - bool decode_jpeg(const uint8_t *jpg, size_t size); - - class __attribute__ ((packed)) jpg_section - { - public: - uint8_t flag() const { return section_flag; } - const char *flag_name() const; - uint16_t section_length() const { return section_flag == 0xd8 || section_flag == 0xd9 ? 0 : (section_length_msb << 8) + section_length_lsb; } - const uint8_t *data() const { return reinterpret_cast(§ion_data[1]); } - uint16_t data_length() const { return section_length() - 3; } - - private: - const uint8_t section_flag; - const uint8_t section_length_msb; - const uint8_t section_length_lsb; - const uint8_t section_data[]; - }; - - const jpg_section *quantization_table_0_; - const jpg_section *quantization_table_1_; - - const uint8_t *jpeg_data_start; - const uint8_t *jpeg_data_end; - -private: - static const jpg_section *find_jpeg_section(const uint8_t **ptr, const uint8_t *end, uint8_t flag); -}; \ No newline at end of file diff --git a/lib/micro-rtsp-server/include/micro_rtsp_streamer.h b/lib/micro-rtsp-server/include/micro_rtsp_streamer.h new file mode 100644 index 0000000..80e3cfc --- /dev/null +++ b/lib/micro-rtsp-server/include/micro_rtsp_streamer.h @@ -0,0 +1,15 @@ +#pragma once + +#include + + +class micro_rtsp_streamer +{ +public: + micro_rtsp_streamer(); + void create_jpg_packet(const jpg jpg, uint32_t timestamp); + private : + + uint32_t ssrc_; + uint16_t sequenceNumber_; +}; \ No newline at end of file diff --git a/lib/micro-rtsp-server/include/micro_rtssp_streamer.h b/lib/micro-rtsp-server/include/micro_rtssp_streamer.h deleted file mode 100644 index 0b7c316..0000000 --- a/lib/micro-rtsp-server/include/micro_rtssp_streamer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -class micro_rtsp_streamer -{ -public: -}; \ No newline at end of file diff --git a/lib/micro-rtsp-server/library.json b/lib/micro-rtsp-server/library.json index 2ec1def..9bb0a5f 100644 --- a/lib/micro-rtsp-server/library.json +++ b/lib/micro-rtsp-server/library.json @@ -14,6 +14,7 @@ }, "dependencies": { + "micro-jpg": "^1.0.0", "espressif/esp32-camera": "^2.0.4" } } \ No newline at end of file diff --git a/lib/micro-rtsp-server/src/micro_rtsp_jpeg.cpp b/lib/micro-rtsp-server/src/micro_rtsp_jpeg.cpp deleted file mode 100644 index 26d8200..0000000 --- a/lib/micro-rtsp-server/src/micro_rtsp_jpeg.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include - -#include "micro_rtsp_jpeg.h" - -const char *micro_rtsp_jpeg::jpg_section::flag_name() const -{ - switch (section_flag) - { - case 0xd8: - return "SOI"; // start of image - case 0xd9: - return "EOI"; // end of image - case 0xe0: - return "APP0"; - case 0xdb: - return "DQT"; // define quantization table - case 0xc4: - return "DHT"; // define Huffman table - case 0xc0: - return "SOF"; // start of frame - case 0xda: - return "SOS"; // start of scan - } - return "Unknown"; -} - -const micro_rtsp_jpeg::jpg_section *micro_rtsp_jpeg::find_jpeg_section(const uint8_t **ptr, const uint8_t *end, uint8_t flag) -{ - log_d("find_jpeg_section 0x%02x", flag); - while (*ptr < end) - { - auto framing = *((*ptr)++); - if (framing != 0xff) - { - log_e("Expected framing 0xff but found: 0x%02x", framing); - break; - } - - // framing = 0xff, flag, len MSB, len LSB - auto section = reinterpret_cast((*ptr)++); - // Advance pointer section has a length, so not SOI (0xd8) and EOI (0xd9) - *ptr += section->section_length(); - if (section->flag() == flag) - { - log_d("Found section 0x%02x (%s), %d bytes", flag, section->flag_name(), section->section_length()); - return section; - } - - log_d("Skipping section: 0x%02x (%s), %d bytes", section->flag(), section->flag_name(), section->section_length()); - } - - // Not found - return nullptr; -} - -// See https://create.stephan-brumme.com/toojpeg/ -bool micro_rtsp_jpeg::decode_jpeg(const uint8_t *data, size_t size) -{ - log_d("decode_jpeg"); - // Look for start jpeg file (0xd8) - auto ptr = data; - auto end = ptr + size; - - // Check for SOI (start of image) 0xff, 0xd8 - if (!find_jpeg_section(&ptr, end, 0xd8)) - { - log_e("No valid start of image marker found"); - return false; - } - - // First quantization table - if (!(quantization_table_0_ = find_jpeg_section(&ptr, end, 0xdb))) - log_e("No quantization table 0 section found"); - - // Second quantization table (for color images) - if (!(quantization_table_1_ = find_jpeg_section(&ptr, end, 0xdb))) - log_w("No quantization table 1 section found"); - - // Start of scan - if (!find_jpeg_section(&ptr, end, 0xda)) - log_e("No start of scan section found"); - - // Start of the data sections - jpeg_data_start = ptr; - - // Scan over all the sections. 0xff followed by not zero, is a new section - while (ptr < end - 1 && (ptr[0] != 0xff || ptr[1] == 0)) - ptr++; - - // Check if marker is an end of image marker - if (!find_jpeg_section(&ptr, end, 0xd9)) - { - log_e("No end of image marker found"); - return false; - } - - jpeg_data_end = ptr; - log_d("Total jpeg data = %d bytes", jpeg_data_end - jpeg_data_start); - - return true; -} diff --git a/lib/micro-rtsp-server/src/micro_rtsp_requests.cpp b/lib/micro-rtsp-server/src/micro_rtsp_requests.cpp index a258967..5759eb3 100644 --- a/lib/micro-rtsp-server/src/micro_rtsp_requests.cpp +++ b/lib/micro-rtsp-server/src/micro_rtsp_requests.cpp @@ -3,6 +3,8 @@ #include #include "micro_rtsp_requests.h" +// https://datatracker.ietf.org/doc/html/rfc2326 + micro_rtsp_requests::rtsp_command micro_rtsp_requests::parse_command(const std::string &request) { log_i("parse_command"); diff --git a/lib/micro-rtsp-server/src/micro_rtsp_streamer.cpp b/lib/micro-rtsp-server/src/micro_rtsp_streamer.cpp new file mode 100644 index 0000000..f411be7 --- /dev/null +++ b/lib/micro-rtsp-server/src/micro_rtsp_streamer.cpp @@ -0,0 +1,157 @@ +#include "micro_rtsp_streamer.h" + +#include "rtp_payloads.h" + +#include + +#include "esp_random.h" + +// https://github.com/txgcwm/Linux-C-Examples/blob/master/h264/h264dec/rtcp.h + +// RTP data header (http://www.ietf.org/rfc/rfc3550.txt) +struct rtp_hdr +{ + uint version : 2; // protocol version + uint p : 1; // padding flag + uint x : 1; // header extension flag + uint cc : 4; // CSRC count + uint m : 1; // marker bit + uint pt : 7; // payload type + uint seq : 16; // sequence number + uint32_t ts; // timestamp + uint32_t ssrc; // synchronization source + uint32_t csrc[]; // optional CSRC list +} rtp_hdr; + +// https://datatracker.ietf.org/doc/html/rfc2435 + +// The following definition is from RFC1890 +#define RTP_PT_JPEG 26 + +struct jpeghdr +{ + uint322_t tspec : 8; // type-specific field + uint322_t off : 24; // fragment byte offset + uint8_t type; // id of jpeg decoder params + uint8_t q; // quantization factor (or table id) + uint8_t width; // frame width in 8 pixel blocks + uint8_t height; // frame height in 8 pixel blocks +}; + +struct jpeghdr_rst +{ + uint16_t dri; + uint16_t f : 1; + uint16_t l : 1; + uint16_t count : 14; +}; + +struct jpeghdr_qtable +{ + uint8_t mbz; + uint8_t precision; + uint16_t length; +}; + +#define RTP_JPEG_RESTART 0x40 + +micro_rtsp_streamer::micro_rtsp_streamer() +{ + // Random number + ssrc_ = esp_random(); + sequenceNumber_ = 0; +} + +#define MAX_ESP32_MTU 1440 + +size_t micro_rtsp_streamer::create_jpg_packet(const uint8_t *jpg, const uint8_t *jpg_end, uint32_t timestamp) +{ + int fragmentLen = MAX_FRAGMENT_SIZE; + if (fragmentLen + fragmentOffset > jpegLen) // Shrink last fragment if needed + fragmentLen = jpegLen - fragmentOffset; + + bool isLastFragment = (fragmentOffset + fragmentLen) == jpegLen; + + struct rtp_header header = { + .version = 2, + .seq = sequenceNumber_, + .marker = 1, // TODO = 1 if last fragfment + .pt = rtp_payload.JPEG, + .ts = timestamp, + .ssrc = ssrc_}; + + struct jpeghdr jpghdr = { + .tspec = 0, // type-specific field + .off = offset, // fragment byte offset + .type = 0, // id of jpeg decoder params + .q = 0x5e, // quantization factor (or table id) + .width = width >> 3, // frame width in 8 pixel blocks + .height = height >> 3 // frame height in 8 pixel blocks + }; + + memset(RtpBuf, 0x00, sizeof(RtpBuf)); + // Prepare the first 4 byte of the packet. This is the Rtp over Rtsp header in case of TCP based transport + RtpBuf[0] = '$'; // magic number + RtpBuf[1] = 0; // number of multiplexed subchannel on RTPS connection - here the RTP channel + RtpBuf[2] = (RtpPacketSize & 0x0000FF00) >> 8; + RtpBuf[3] = (RtpPacketSize & 0x000000FF); + // Prepare the 12 byte RTP header + RtpBuf[4] = 0x80; // RTP version + RtpBuf[5] = 0x1a | (isLastFragment ? 0x80 : 0x00); // JPEG payload (26) and marker bit + RtpBuf[7] = m_SequenceNumber & 0x0FF; // each packet is counted with a sequence counter + RtpBuf[6] = m_SequenceNumber >> 8; + RtpBuf[8] = (m_Timestamp & 0xFF000000) >> 24; // each image gets a timestamp + RtpBuf[9] = (m_Timestamp & 0x00FF0000) >> 16; + RtpBuf[10] = (m_Timestamp & 0x0000FF00) >> 8; + RtpBuf[11] = (m_Timestamp & 0x000000FF); + RtpBuf[12] = 0x13; // 4 byte SSRC (sychronization source identifier) + RtpBuf[13] = 0xf9; // we just an arbitrary number here to keep it simple + RtpBuf[14] = 0x7e; + RtpBuf[15] = 0x67; + + // Prepare the 8 byte payload JPEG header + RtpBuf[16] = 0x00; // type specific + RtpBuf[17] = (fragmentOffset & 0x00FF0000) >> 16; // 3 byte fragmentation offset for fragmented images + RtpBuf[18] = (fragmentOffset & 0x0000FF00) >> 8; + RtpBuf[19] = (fragmentOffset & 0x000000FF); + + /* These sampling factors indicate that the chrominance components of + type 0 video is downsampled horizontally by 2 (often called 4:2:2) + while the chrominance components of type 1 video are downsampled both + horizontally and vertically by 2 (often called 4:2:0). */ + RtpBuf[20] = 0x00; // type (fixme might be wrong for camera data) https://tools.ietf.org/html/rfc2435 + RtpBuf[21] = q; // quality scale factor was 0x5e + RtpBuf[22] = m_width / 8; // width / 8 + RtpBuf[23] = m_height / 8; // height / 8 + + int headerLen = 24; // Inlcuding jpeg header but not qant table header + if (includeQuantTbl) + { // we need a quant header - but only in first packet of the frame + // printf("inserting quanttbl\n"); + RtpBuf[24] = 0; // MBZ + RtpBuf[25] = 0; // 8 bit precision + RtpBuf[26] = 0; // MSB of lentgh + + int numQantBytes = 64; // Two 64 byte tables + RtpBuf[27] = 2 * numQantBytes; // LSB of length + + headerLen += 4; + + memcpy(RtpBuf + headerLen, quant0tbl, numQantBytes); + headerLen += numQantBytes; + + memcpy(RtpBuf + headerLen, quant1tbl, numQantBytes); + headerLen += numQantBytes; + } + // printf("Sending timestamp %d, seq %d, fragoff %d, fraglen %d, jpegLen %d\n", m_Timestamp, m_SequenceNumber, fragmentOffset, fragmentLen, jpegLen); + + // append the JPEG scan data to the RTP buffer + memcpy(RtpBuf + headerLen, jpeg + fragmentOffset, fragmentLen); + fragmentOffset += fragmentLen; + + m_SequenceNumber++; // prepare the packet counter for the next packet + + IPADDRESS otherip; + IPPORT otherport; + socketpeeraddr(m_Client, &otherip, &otherport); +} \ No newline at end of file diff --git a/lib/micro-rtsp-server/src/micro_rtssp_streamer.cpp b/lib/micro-rtsp-server/src/micro_rtssp_streamer.cpp deleted file mode 100644 index e785ed5..0000000 --- a/lib/micro-rtsp-server/src/micro_rtssp_streamer.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "micro_rtssp_streamer.h" \ No newline at end of file diff --git a/test/test_main.cpp b/test/test_main.cpp index ca712a0..7faadff 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -3,24 +3,37 @@ #include #include -#include +#include static unsigned char jpeg[8468] = { - 0xff, 0xd8, // SOI - 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // APP00 - 0xff, 0xdb, 0x00, 0x43, 0x00, 0x0e, 0x0a, 0x0b, 0x0c, 0x0b, 0x09, 0x0e, 0x0c, 0x0b, 0x0c, 0x10, 0x0f, 0x0e, 0x11, 0x15, 0x23, 0x17, 0x15, 0x13, 0x13, 0x15, 0x2b, 0x1f, 0x20, 0x19, 0x23, 0x33, 0x2d, 0x35, 0x35, 0x32, 0x2d, 0x31, 0x30, 0x38, 0x3f, 0x51, 0x44, 0x38, 0x3c, 0x4c, 0x3c, 0x30, 0x31, 0x46, 0x5f, 0x47, 0x4c, 0x53, 0x56, 0x5a, 0x5b, 0x5a, 0x36, 0x43, 0x63, 0x6a, 0x62, 0x58, 0x69, 0x51, 0x58, 0x5a, 0x57, // DQT - 0xff, 0xdb, 0x00, 0x43, 0x01, 0x0f, 0x10, 0x10, 0x15, 0x12, 0x15, 0x29, 0x17, 0x17, 0x29, 0x57, 0x3a, 0x31, 0x3a, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, // DQT + // SOI + 0xff, 0xd8, + // APP00 + 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // DQT + 0xff, 0xdb, 0x00, 0x43, 0x00, 0x0e, 0x0a, 0x0b, 0x0c, 0x0b, 0x09, 0x0e, 0x0c, 0x0b, 0x0c, 0x10, 0x0f, 0x0e, 0x11, 0x15, 0x23, 0x17, 0x15, 0x13, 0x13, 0x15, 0x2b, 0x1f, 0x20, 0x19, 0x23, 0x33, 0x2d, 0x35, 0x35, 0x32, 0x2d, 0x31, 0x30, 0x38, 0x3f, 0x51, 0x44, 0x38, 0x3c, 0x4c, 0x3c, 0x30, 0x31, 0x46, 0x5f, 0x47, 0x4c, 0x53, 0x56, 0x5a, 0x5b, 0x5a, 0x36, 0x43, 0x63, 0x6a, 0x62, 0x58, 0x69, 0x51, 0x58, 0x5a, 0x57, + // DQT + 0xff, 0xdb, 0x00, 0x43, 0x01, 0x0f, 0x10, 0x10, 0x15, 0x12, 0x15, 0x29, 0x17, 0x17, 0x29, 0x57, 0x3a, 0x31, 0x3a, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + // DHT 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + // DHT 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, + // DHT 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + // DHT 0xff, 0xc4, 0x00, 0xb5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, + // SOF 0xff, 0xc0, 0x00, 0x11, 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, + // SOS 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, + // SOF7 0xe0, 0xc7, 0xd6, 0x91, 0xb8, 0xae, 0x9d, 0x6e, 0x02, 0xf3, 0xcf, 0x14, 0x87, 0x93, 0x48, 0x61, 0xec, 0x29, 0x7a, 0x8a, 0x77, 0x01, 0x07, 0xbd, 0x2d, 0x16, 0xd0, 0x42, 0x67, 0x8a, 0x52, 0x3d, 0x29, 0x0c, 0x4c, 0xd0, 0x28, 0x10, 0x94, 0x67, 0x9a, 0x90, 0x0f, 0xa9, 0xa2, 0xa1, 0x80, 0x1c, 0xf6, 0xa4, 0xe6, 0x95, 0xd8, 0x07, 0x22, 0x8a, 0xa1, 0x05, 0x25, 0x3b, 0x08, 0x3a, 0xd1, 0xc5, 0x46, 0xa5, 0x05, 0x1e, 0xf4, 0x05, 0x83, 0xeb, 0x45, 0x20, 0x0a, 0x29, 0x80, 0x94, 0x53, 0xb9, 0x23, 0x7b, 0xd3, 0xa9, 0x5c, 0x62, 0x52, 0xd2, 0xb7, 0x50, 0x13, 0xb5, 0x2f, 0xd2, 0x8b, 0x0c, 0x4a, 0x2a, 0xc0, 0x28, 0xa8, 0x01, 0x0d, 0x2d, 0x02, 0xb0, 0x1a, 0x28, 0x00, 0xa4, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xcd, 0x3b, 0x00, 0x51, 0x48, 0x02, 0x92, 0x80, 0x0a, 0x29, 0x8d, 0x8b, 0x45, 0x21, 0x05, 0x25, 0x26, 0xc4, 0x14, 0x53, 0x1a, 0x0a, 0x28, 0x01, 0x29, 0x69, 0x30, 0x0a, 0x29, 0x8c, 0x28, 0xa6, 0x20, 0xa2, 0x95, 0xc0, 0x28, 0xa0, 0x61, 0x49, 0x48, 0x41, 0x4b, 0x55, 0x6d, 0x40, 0x9e, 0x90, 0x74, 0xfb, 0xbc, 0xd6, 0xbe, 0x85, 0xb6, 0x3b, 0xb5, 0x25, 0x4f, 0x28, 0x85, 0xe3, 0xbd, 0x27, 0x5a, 0xab, 0x00, 0xb4, 0x7d, 0x4d, 0x24, 0x21, 0xb9, 0x3c, 0x53, 0xb3, 0xf9, 0xd3, 0xea, 0x02, 0x0a, 0x3d, 0xe8, 0xf3, 0x00, 0xa3, 0x1c, 0x73, 0x4a, 0xe0, 0x27, 0x4e, 0x94, 0x95, 0x31, 0xdc, 0x10, 0xb4, 0x74, 0xa0, 0x5d, 0x42, 0x93, 0xbd, 0x00, 0x03, 0xbd, 0x1d, 0xe8, 0xbe, 0xa2, 0x13, 0x22, 0x8a, 0x43, 0x03, 0xed, 0x45, 0x00, 0x25, 0x2d, 0x21, 0xdc, 0x28, 0xa0, 0x42, 0x76, 0xa2, 0x98, 0x82, 0x8a, 0x82, 0x83, 0xb5, 0x25, 0x55, 0xc4, 0x2d, 0x25, 0x20, 0x0a, 0x2a, 0x80, 0x28, 0xa4, 0xd0, 0x05, 0x14, 0xba, 0x00, 0x51, 0x4d, 0x0c, 0x4a, 0x28, 0x10, 0x51, 0x48, 0x00, 0xd2, 0x53, 0x01, 0xd4, 0x95, 0x3b, 0x0c, 0x4a, 0x5a, 0xab, 0xe8, 0x01, 0x49, 0x48, 0x02, 0x96, 0x81, 0x09, 0x4b, 0x40, 0xc2, 0x92, 0x80, 0x0a, 0x28, 0x10, 0x52, 0x52, 0x01, 0x68, 0xaa, 0x4c, 0x02, 0x8a, 0x4c, 0x61, 0x49, 0x40, 0x85, 0xa4, 0xa0, 0x62, 0xd2, 0x50, 0xc0, 0x28, 0xa6, 0x04, 0xfd, 0x39, 0xa5, 0x23, 0xb1, 0xad, 0xb6, 0x29, 0x89, 0xcd, 0x2e, 0x72, 0x39, 0xa3, 0xa8, 0xb7, 0x17, 0x3b, 0x47, 0x19, 0xa3, 0xee, 0xd0, 0xb6, 0x0f, 0x20, 0x14, 0x50, 0xdf, 0x40, 0x13, 0xbd, 0x15, 0x1c, 0xc2, 0xd8, 0x4a, 0x75, 0x00, 0x27, 0x38, 0xa4, 0xcd, 0x3f, 0x30, 0x0a, 0x4a, 0x3a, 0x80, 0x51, 0x4a, 0xdd, 0x44, 0x14, 0x94, 0xb7, 0x43, 0x0c, 0xd2, 0x9a, 0x04, 0x27, 0x1d, 0xa9, 0x4f, 0x4a, 0x81, 0x8d, 0xa5, 0xaa, 0xb3, 0x60, 0x1d, 0x29, 0x28, 0x42, 0x0c, 0xd1, 0x54, 0x30, 0xea, 0x28, 0x3d, 0x6a, 0x40, 0x28, 0xa4, 0x21, 0x28, 0xa5, 0x61, 0x0b, 0x49, 0xda, 0x99, 0x41, 0x47, 0xb5, 0x02, 0x0a, 0x4a, 0x18, 0x5c, 0x28, 0xa6, 0x21, 0x45, 0x25, 0x41, 0x42, 0xd2, 0x55, 0x08, 0x4a, 0x29, 0x00, 0xb4, 0x50, 0x01, 0x45, 0x08, 0x62, 0x51, 0x4c, 0x42, 0xd1, 0x4a, 0xe0, 0x36, 0x96, 0x9b, 0x06, 0x06, 0x81, 0x40, 0xec, 0x14, 0x52, 0x00, 0xa2, 0x80, 0x12, 0x96, 0x98, 0x82, 0x92, 0x80, 0x0a, 0x2a, 0x40, 0x28, 0xa6, 0x30, 0xa5, 0xa0, 0x04, 0xa2, 0x90, 0x05, 0x2d, 0x0c, 0x44, + // DATA 0xff, 0x00, 0xef, 0x50, 0x79, 0xf6, 0xad, 0xca, 0x02, 0x4e, 0x68, 0xce, 0x3f, 0x1a, 0x3a, 0x00, 0x52, 0x9a, 0x00, 0x4a, 0x3b, 0x73, 0x49, 0x5c, 0x4c, 0x28, 0xe3, 0x27, 0x8a, 0x6f, 0xde, 0x00, 0xa2, 0x80, 0x0a, 0x4a, 0x56, 0x00, 0xcd, 0x14, 0x00, 0x9d, 0x0d, 0x2d, 0x20, 0x12, 0x93, 0xa5, 0x00, 0x1f, 0x4a, 0x3b, 0x54, 0x5c, 0x03, 0xaf, 0x5a, 0x28, 0xbe, 0x80, 0x14, 0x52, 0x00, 0x14, 0x94, 0xc5, 0x60, 0xef, 0x49, 0x4f, 0xcc, 0x2e, 0x2d, 0x14, 0x6e, 0x21, 0x05, 0x2d, 0x21, 0x89, 0xde, 0x8a, 0x43, 0x0a, 0x3b, 0x55, 0x31, 0x05, 0x25, 0x48, 0x05, 0x2d, 0x30, 0xb0, 0x51, 0x48, 0x62, 0x51, 0x54, 0x21, 0x45, 0x25, 0x48, 0x05, 0x25, 0x00, 0x2d, 0x1d, 0xe9, 0x80, 0x51, 0x40, 0x09, 0x45, 0x00, 0x14, 0x52, 0x01, 0x29, 0x69, 0xb6, 0x02, 0x50, 0x28, 0x18, 0xb4, 0x54, 0x88, 0x28, 0xaa, 0x01, 0x29, 0x69, 0x0c, 0x4a, 0x29, 0x80, 0xb4, 0x95, 0x22, 0x16, 0x8a, 0x06, 0x25, 0x2d, 0x50, 0x84, 0xa2, 0xa4, 0x02, 0x8a, 0xa0, 0x27, 0xe3, 0x34, 0xbf, 0x4a, 0xd7, 0x52, 0xac, 0x1d, 0xa8, 0xcf, 0xcb, 0x46, 0xa1, 0x71, 0x39, 0xa7, 0x52, 0x60, 0x27, 0x7c, 0x51, 0xda, 0x85, 0x27, 0xb0, 0x05, 0x27, 0x6a, 0x42, 0x0a, 0x28, 0xdc, 0x42, 0x52, 0xf5, 0xa6, 0xf4, 0x18, 0x9f, 0x5a, 0x3b, 0xd2, 0xbd, 0xc0, 0x28, 0xa9, 0x00, 0xa4, 0xcd, 0x35, 0xb8, 0x00, 0xa2, 0x95, 0x80, 0x4e, 0xd4, 0x53, 0x5d, 0x80, 0x07, 0x5a, 0x5a, 0x5d, 0x44, 0x14, 0x94, 0x0c, 0x28, 0xa4, 0x48, 0x76, 0xa4, 0xa7, 0xe6, 0x50, 0x51, 0x52, 0x84, 0x14, 0x53, 0xb0, 0x09, 0x4b, 0x52, 0x02, 0x52, 0xd3, 0x01, 0x33, 0x41, 0xa1, 0x00, 0x51, 0x4c, 0x62, 0x51, 0x53, 0x60, 0x0a, 0x5a, 0xa1, 0x05, 0x14, 0xac, 0x21, 0x29, 0x68, 0x28, 0x4a, 0x29, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x00, 0x28, 0xa6, 0x31, 0x29, 0x69, 0x88, 0x4a, 0x28, 0x01, 0x68, 0xa4, 0x21, 0x29, 0x68, 0x18, 0x94, 0xb4, 0x6e, 0x31, 0x28, 0xa4, 0x20, 0xa2, 0x98, 0xc2, 0x96, 0x90, 0x84, 0xa2, 0x80, 0x0a, 0x28, 0x02, 0x7a, 0x3d, 0xc5, 0x6e, 0x8a, 0x0a, 0x32, 0xdd, 0xcd, 0x2f, 0x21, 0x8a, 0x7a, 0x8a, 0x5e, 0xf4, 0xed, 0xa5, 0xc9, 0x10, 0x52, 0x7f, 0x0d, 0x48, 0xc3, 0x14, 0xa0, 0xe4, 0x50, 0xc4, 0x14, 0x53, 0xb8, 0x86, 0xd2, 0xfd, 0x69, 0x75, 0x18, 0x94, 0x52, 0x00, 0xcd, 0x25, 0x56, 0xc0, 0x2d, 0x1d, 0xba, 0xd4, 0x30, 0x0a, 0x4a, 0x60, 0x14, 0x94, 0xae, 0x02, 0xd1, 0x40, 0x84, 0xa2, 0x90, 0xc2, 0x92, 0x98, 0x82, 0x8e, 0xb4, 0x98, 0x05, 0x14, 0xac, 0x01, 0x45, 0x00, 0x14, 0x95, 0x40, 0x1d, 0xa8, 0xa4, 0x02, 0xd2, 0x51, 0x60, 0x0a, 0x28, 0xd8, 0x6c, 0x29, 0x69, 0x08, 0x4a, 0x4a, 0x18, 0x0b, 0x49, 0x40, 0x05, 0x14, 0x75, 0x00, 0xa2, 0x90, 0x05, 0x2d, 0x36, 0xc0, 0x29, 0x28, 0x40, 0x14, 0x50, 0x01, 0x49, 0x4c, 0x02, 0x96, 0x90, 0xc2, 0x8a, 0x42, 0x12, 0x94, 0xd1, 0xd4, 0x04, 0xa2, 0x98, 0xc2, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x00, 0x14, 0x53, 0xb8, 0x09, 0x4b, 0x53, 0x61, 0x96, 0x0f, 0xe9, 0x4b, 0xf8, 0x56, 0xe3, 0x7f, 0x10, 0x9e, 0xbe, 0x94, 0x63, 0x1d, 0x69, 0xd8, 0xa0, 0xf7, 0xa4, 0xa9, 0x49, 0x80, 0xb8, 0xa3, 0xb5, 0x1b, 0xb2, 0x58, 0x94, 0xbf, 0x51, 0x40, 0x84, 0x1e, 0xf4, 0x51, 0xb8, 0x09, 0xd6, 0x97, 0x15, 0x2c, 0x41, 0x49, 0x48, 0x61, 0x49, 0xd2, 0xa8, 0x04, 0xef, 0x4b, 0x54, 0xed, 0xb0, 0x85, 0xa4, 0xac, 0xc6, 0x21, 0xa5, 0xa0, 0x04, 0xa2, 0x90, 0x05, 0x27, 0x6a, 0xab, 0x80, 0xa2, 0x8a, 0x57, 0x24, 0x4a, 0x4a, 0x2c, 0x31, 0x7f, 0x9d, 0x1d, 0x68, 0x00, 0xa4, 0xa4, 0x31, 0x69, 0x3b, 0xd2, 0x10, 0xb4, 0x94, 0x5c, 0x04, 0xa5, 0xa0, 0x62, 0x52, 0xd5, 0x00, 0x51, 0x48, 0x56, 0x0f, 0xa5, 0x25, 0x20, 0x17, 0x34, 0x51, 0xb0, 0xec, 0x25, 0x14, 0x84, 0x1c, 0x51, 0x4c, 0x02, 0x8a, 0x77, 0x18, 0x51, 0x48, 0x42, 0x52, 0xd2, 0x01, 0x28, 0xa6, 0x01, 0x45, 0x00, 0x2d, 0x25, 0x2e, 0xa2, 0x0a, 0x29, 0xb1, 0x85, 0x14, 0x86, 0x14, 0x53, 0x10, 0x51, 0x4a, 0xe3, 0x0a, 0x28, 0x00, 0xa2, 0xa8, 0x02, 0x8a, 0x40, 0x58, 0xcf, 0xd2, 0x92, 0xb7, 0xe8, 0x31, 0x69, 0x33, 0xc7, 0x3d, 0x2a, 0x53, 0xd4, 0x63, 0xb8, 0xff, 0x00, 0x22, 0x8e, 0xf5, 0x4f, 0x41, 0x07, 0x6c, 0xd1, 0x53, 0xd0, 0x06, 0xd1, 0x49, 0x00, 0x6e, 0xf4, 0xa2, 0xa9, 0x08, 0x4a, 0x5f, 0x6a, 0x18, 0x08, 0x68, 0x3d, 0x6b, 0x30, 0x0a, 0x2a, 0x56, 0x82, 0x0a, 0x4a, 0xa1, 0x8b, 0x49, 0x40, 0x05, 0x27, 0x6a, 0x37, 0x24, 0x28, 0xa9, 0x18, 0x0a, 0x4e, 0xf4, 0xc6, 0x2d, 0x14, 0x08, 0x4a, 0x29, 0x00, 0x51, 0x4d, 0x8e, 0xc1, 0x49, 0x40, 0x07, 0x7a, 0x28, 0x10, 0x51, 0x4b, 0xcc, 0x61, 0x45, 0x00, 0x14, 0x53, 0xea, 0x01, 0x45, 0x2b, 0x80, 0x94, 0xb4, 0xc0, 0x4a, 0x2a, 0x58, 0x05, 0x14, 0xc1, 0x85, 0x14, 0x00, 0x51, 0x40, 0x84, 0xa5, 0xa0, 0x61, 0x45, 0x0c, 0x02, 0x92, 0x80, 0x0a, 0x29, 0x08, 0x28, 0xa0, 0x61, 0x4b, 0x40, 0x84, 0xa2, 0x81, 0x85, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x53, 0x42, 0x0a, 0x4a, 0x06, 0x58, 0xcf, 0x34, 0x56, 0xa3, 0x03, 0xeb, 0x4b, 0xcf, 0xa5, 0x02, 0x0c, 0xfa, 0xf5, 0xa5, 0xa7, 0xd0, 0x62, 0x0f, 0x94, 0x60, 0xf5, 0xf6, 0xa2, 0x90, 0x07, 0xbf, 0x14, 0x9d, 0x0e, 0x69, 0x08, 0x4c, 0xfc, 0xb8, 0xed, 0x46, 0x45, 0x56, 0xc1, 0xd0, 0x77, 0xd2, 0x92, 0xa1, 0x82, 0x13, 0xde, 0x8e, 0xf4, 0xc0, 0x4f, 0xc6, 0x97, 0xa5, 0x26, 0x01, 0x9a, 0x4a, 0x00, 0x3b, 0x62, 0x93, 0x8a, 0x00, 0x3a, 0x51, 0x43, 0x10, 0x51, 0xd6, 0x95, 0x80, 0x33, 0x49, 0x48, 0x02, 0x8a, 0x40, 0x14, 0x53, 0xb5, 0x86, 0x1e, 0xf4, 0x53, 0x00, 0x14, 0x94, 0x80, 0x5a, 0x4a, 0x56, 0x00, 0xa2, 0x99, 0x21, 0x45, 0x00, 0x14, 0x50, 0xd0, 0xc4, 0xa2, 0x90, 0xc2, 0x8a, 0x04, 0x14, 0x50, 0x30, 0xa2, 0x90, 0x82, 0x92, 0xa8, 0x05, 0xa2, 0x90, 0xc2, 0x92, 0x84, 0x20, 0xa2, 0x81, 0x85, 0x2d, 0x20, 0x12, 0x8a, 0x04, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x53, 0x18, 0x52, 0x52, 0x04, 0x2d, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x02, 0x0a, 0x28, 0x02, 0x7f, 0xe7, 0x49, 0x5b, 0xdf, 0xa1, 0x43, 0x85, 0x14, 0x84, 0xc3, 0x14, 0x77, 0xaa, 0xb8, 0xfa, 0x09, 0xed, 0x4b, 0xf5, 0xa5, 0x61, 0x58, 0x4a, 0x05, 0x24, 0x98, 0x07, 0x6a, 0x4a, 0x4c, 0x04, 0xcd, 0x2d, 0x16, 0x00, 0xa4, 0xa2, 0xfa, 0x00, 0x51, 0x4e, 0xf7, 0x06, 0x14, 0x66, 0x93, 0x01, 0x29, 0x7b, 0x54, 0xb0, 0x12, 0x8a, 0x04, 0x14, 0x1a, 0x2c, 0x30, 0xa2, 0x95, 0x84, 0x25, 0x19, 0xa6, 0x30, 0xa2, 0xa5, 0xea, 0x02, 0x52, 0xd0, 0x80, 0x4c, 0xd1, 0x4c, 0x02, 0x8a, 0x56, 0xd0, 0x02, 0x8a, 0x62, 0x0a, 0x29, 0x0c, 0x29, 0x28, 0x10, 0x51, 0x54, 0x01, 0x45, 0x21, 0x85, 0x2d, 0x48, 0x84, 0xa2, 0x80, 0x0a, 0x28, 0x18, 0x94, 0xa6, 0xa8, 0x04, 0xa5, 0xa0, 0x04, 0xa2, 0x90, 0x82, 0x8a, 0x06, 0x14, 0x52, 0x00, 0xa2, 0x98, 0x05, 0x14, 0xac, 0x21, 0x29, 0x69, 0x80, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x4a, 0x28, 0x10, 0x51, 0x48, 0x61, 0x4b, 0x42, 0x11, 0x3f, 0xae, 0x3f, 0x3c, 0x52, 0x0e, 0xb5, 0xd2, 0xf4, 0x2c, 0x77, 0x1d, 0xe9, 0x3d, 0xfb, 0xd4, 0xfc, 0x44, 0x8b, 0xef, 0x47, 0x7a, 0x4c, 0x62, 0x52, 0xd3, 0x60, 0xc3, 0xbd, 0x25, 0x17, 0x10, 0x99, 0xe3, 0xa5, 0x29, 0xa9, 0x01, 0x28, 0xa0, 0x02, 0x8e, 0xf5, 0x20, 0xc4, 0xa2, 0x9d, 0xc0, 0x3b, 0x51, 0xde, 0x86, 0x21, 0x3a, 0x52, 0xd2, 0xb0, 0xc2, 0x8a, 0x91, 0x09, 0x45, 0x50, 0xee, 0x25, 0x2d, 0x26, 0x24, 0xc4, 0xa2, 0x98, 0xc2, 0x8a, 0x01, 0x85, 0x02, 0x81, 0x05, 0x25, 0x48, 0x09, 0x4b, 0x4d, 0xea, 0x30, 0xa2, 0x95, 0xc4, 0x14, 0x50, 0xc0, 0x4a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0x08, 0x29, 0x29, 0x8c, 0x29, 0x69, 0x08, 0x28, 0xa0, 0x02, 0x92, 0x81, 0x85, 0x14, 0x00, 0xb4, 0x94, 0x80, 0x5a, 0x4a, 0x60, 0x14, 0x94, 0x00, 0xb4, 0x52, 0x00, 0xa4, 0xaa, 0x01, 0x68, 0xa9, 0x10, 0x51, 0x4c, 0x61, 0x49, 0x48, 0x02, 0x96, 0x81, 0x05, 0x25, 0x03, 0x16, 0x8a, 0x60, 0x4d, 0x47, 0xd0, 0xf1, 0x5b, 0xee, 0x01, 0x9a, 0x5e, 0x3d, 0x39, 0xa4, 0xd1, 0x42, 0xff, 0x00, 0xbc, 0x0d, 0x26, 0x7d, 0x72, 0x4d, 0x16, 0x10, 0x51, 0xdb, 0xaf, 0xe1, 0x45, 0x98, 0x80, 0xfb, 0xd1, 0xde, 0x93, 0x77, 0x00, 0xa2, 0x92, 0xb0, 0x0d, 0xa5, 0xa0, 0x02, 0x9b, 0x53, 0xb0, 0x0b, 0x45, 0x0f, 0x50, 0x12, 0x96, 0x9f, 0x51, 0x09, 0x4b, 0x40, 0xc4, 0xa4, 0xa9, 0x01, 0x68, 0xa2, 0xe2, 0x12, 0x8a, 0x60, 0x14, 0x52, 0xb8, 0xc4, 0xa2, 0x98, 0x82, 0x96, 0xa4, 0x04, 0xa2, 0x80, 0x0a, 0x29, 0xa1, 0x85, 0x14, 0xee, 0x20, 0xa4, 0xa9, 0x10, 0xb4, 0x94, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x3a, 0x80, 0x51, 0x54, 0x02, 0x51, 0x52, 0x31, 0x68, 0xa4, 0x20, 0xa2, 0x80, 0x12, 0x8a, 0xa0, 0x0a, 0x29, 0x0c, 0x28, 0xa6, 0x21, 0x29, 0x69, 0x00, 0x51, 0x48, 0x02, 0x92, 0xa8, 0x62, 0xd1, 0x52, 0x02, 0x51, 0x4c, 0x02, 0x96, 0x93, 0x10, 0x94, 0x50, 0x01, 0x45, 0x31, 0x8b, 0x49, 0x48, 0x0b, 0x14, 0x71, 0xda, 0xba, 0x2f, 0xa8, 0xb5, 0x13, 0xf0, 0xa0, 0x03, 0x4b, 0x41, 0x80, 0xfa, 0x73, 0x4e, 0x34, 0xdf, 0x98, 0x58, 0x4c, 0x77, 0xa4, 0xa0, 0x61, 0x4b, 0xd2, 0x96, 0x9b, 0x08, 0x29, 0x31, 0xcf, 0x15, 0x28, 0x40, 0x7a, 0x51, 0x49, 0xa1, 0x85, 0x26, 0x79, 0xa7, 0x60, 0xdc, 0x33, 0xed, 0x49, 0x49, 0x21, 0x05, 0x2d, 0x48, 0x09, 0x45, 0x31, 0x05, 0x15, 0x23, 0x0a, 0x4a, 0x43, 0x0a, 0x4a, 0xae, 0xa2, 0x16, 0x92, 0x98, 0x0b, 0x45, 0x20, 0x13, 0xa5, 0x14, 0x00, 0x51, 0x40, 0x0b, 0x49, 0x48, 0x04, 0xa2, 0x80, 0x0a, 0x29, 0x80, 0x51, 0xd2, 0xa4, 0x61, 0x45, 0x31, 0x06, 0x68, 0xa0, 0x62, 0x51, 0x4c, 0x41, 0x4b, 0x43, 0x00, 0xa4, 0xa4, 0x01, 0x45, 0x16, 0x18, 0x51, 0x48, 0x41, 0x45, 0x17, 0x00, 0xa2, 0x98, 0x05, 0x14, 0x80, 0x28, 0xa6, 0x08, 0x4a, 0x29, 0x0c, 0x5a, 0x4a, 0xa4, 0x20, 0xa2, 0x90, 0x05, 0x2d, 0x20, 0x12, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x00, 0x58, 0xf7, 0x34, 0x0a, 0xe8, 0x4b, 0xb8, 0x07, 0x7a, 0x1b, 0x35, 0x25, 0x59, 0x0b, 0xda, 0x90, 0x50, 0xd9, 0x22, 0xd1, 0xd3, 0xad, 0x08, 0x63, 0x7e, 0x94, 0xb4, 0x48, 0x57, 0x0e, 0x94, 0x94, 0x90, 0x85, 0xa4, 0xfc, 0x31, 0x4b, 0x71, 0x85, 0x25, 0x00, 0x2d, 0x25, 0x2f, 0x31, 0x09, 0x47, 0x5a, 0x63, 0x0a, 0x0d, 0x48, 0x09, 0x4b, 0x4c, 0x02, 0x92, 0xa5, 0x08, 0x28, 0xcd, 0x30, 0x0a, 0x2a, 0x6f, 0x70, 0x0a, 0x4a, 0xa0, 0x0a, 0x28, 0x40, 0x14, 0x50, 0x01, 0x49, 0x48, 0x05, 0xa4, 0xa6, 0x01, 0x45, 0x21, 0x85, 0x14, 0x5c, 0x41, 0x45, 0x31, 0x85, 0x14, 0x84, 0x14, 0x94, 0xc0, 0x29, 0x68, 0x01, 0x28, 0xa4, 0x01, 0xde, 0x8a, 0x06, 0x14, 0x52, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0xb8, 0x82, 0x8a, 0x00, 0x29, 0x28, 0x18, 0xb4, 0x94, 0x08, 0x5a, 0x4a, 0x00, 0x28, 0xa6, 0x01, 0x4b, 0x48, 0x62, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x13, 0x9e, 0x28, 0xae, 0x9d, 0xc0, 0x76, 0x3b, 0x75, 0xa4, 0x1c, 0x74, 0xac, 0xb6, 0x1e, 0xe1, 0xf5, 0xa3, 0xad, 0x34, 0x20, 0xa3, 0x8e, 0xd5, 0x43, 0x13, 0xbd, 0x28, 0xa0, 0x42, 0x52, 0x51, 0xa0, 0xc2, 0x8a, 0x97, 0xdc, 0x42, 0xf7, 0xa2, 0xa4, 0x42, 0x51, 0x4c, 0x02, 0x92, 0x90, 0x05, 0x27, 0x7a, 0x00, 0x29, 0x69, 0x00, 0x94, 0x66, 0x98, 0x82, 0x93, 0x14, 0x0c, 0x5a, 0x4a, 0x2e, 0x31, 0x69, 0x29, 0x5c, 0x41, 0x45, 0x03, 0x0a, 0x4a, 0x40, 0x2d, 0x25, 0x21, 0x05, 0x14, 0xc0, 0x28, 0xa0, 0x61, 0x45, 0x02, 0x0a, 0x28, 0x01, 0x29, 0x69, 0x0c, 0x4a, 0x29, 0xbd, 0x44, 0x14, 0x53, 0x00, 0xa2, 0xa4, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x63, 0x0a, 0x4a, 0x40, 0x2d, 0x25, 0x02, 0x16, 0x8a, 0x00, 0x29, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0xc4, 0x14, 0x52, 0x00, 0xa2, 0x80, 0x0a, 0x29, 0x80, 0x51, 0x48, 0x09, 0xcd, 0x19, 0xcf, 0xb5, 0x6c, 0x3b, 0x0b, 0xc6, 0x39, 0xa0, 0x9e, 0x6a, 0x6c, 0x0c, 0x4e, 0xb4, 0xbc, 0x77, 0xab, 0xf2, 0x18, 0x7b, 0x8a, 0x29, 0x08, 0x4a, 0x28, 0x00, 0xe3, 0x3c, 0xd0, 0x3d, 0xe9, 0x00, 0x51, 0xd6, 0x9d, 0xec, 0x21, 0x28, 0xa8, 0x63, 0x0a, 0x42, 0x7d, 0x69, 0x21, 0x05, 0x14, 0x00, 0x52, 0x53, 0xf3, 0x01, 0x69, 0x29, 0x74, 0x18, 0x51, 0x4e, 0xcc, 0x41, 0x45, 0x00, 0x82, 0x92, 0x81, 0x8b, 0x45, 0x40, 0x09, 0x45, 0x50, 0x98, 0x94, 0x50, 0xc1, 0x0b, 0x49, 0x52, 0x01, 0x45, 0x03, 0x0a, 0x4a, 0x60, 0x14, 0xb4, 0xc0, 0x4a, 0x29, 0x00, 0x52, 0xd0, 0x01, 0x49, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa2, 0xe3, 0x0a, 0x29, 0x08, 0x28, 0xa0, 0x02, 0x92, 0x98, 0xc5, 0xa2, 0x95, 0x80, 0x4a, 0x28, 0x01, 0x68, 0xa0, 0x04, 0xa2, 0x80, 0x0a, 0x29, 0x88, 0x28, 0xa4, 0x01, 0x45, 0x00, 0x14, 0x51, 0x61, 0x85, 0x14, 0x08, 0x28, 0xa0, 0x09, 0xe8, 0xef, 0xed, 0x5b, 0x96, 0x2f, 0x1e, 0x99, 0xa3, 0x8a, 0x57, 0x00, 0xa2, 0x9e, 0x9d, 0x45, 0x60, 0xf7, 0xc5, 0x2f, 0x3f, 0x4a, 0x91, 0x0d, 0xfc, 0x28, 0xa6, 0x01, 0x45, 0x21, 0xa1, 0x3b, 0xd1, 0x48, 0x41, 0x47, 0x5a, 0x4c, 0x02, 0x86, 0xc6, 0x6a, 0x6c, 0x20, 0xa4, 0xaa, 0x00, 0xa3, 0x35, 0x23, 0x12, 0x8a, 0xa0, 0x0a, 0x4a, 0x9b, 0x88, 0x5a, 0x2a, 0xae, 0x31, 0x28, 0x34, 0xac, 0x84, 0x14, 0x53, 0x18, 0x51, 0x52, 0xc4, 0x14, 0x50, 0x24, 0x25, 0x14, 0xb7, 0x18, 0x51, 0x43, 0x18, 0x51, 0x4c, 0x02, 0x8a, 0x42, 0x0a, 0x4a, 0x06, 0x14, 0x53, 0xb8, 0x82, 0x8a, 0x43, 0x0a, 0x29, 0x88, 0x28, 0xa0, 0x02, 0x8a, 0x06, 0x25, 0x2d, 0x00, 0x25, 0x14, 0x80, 0x5a, 0x4a, 0x04, 0x14, 0x53, 0x00, 0xa5, 0xa4, 0x02, 0x51, 0x40, 0xc2, 0x8a, 0x04, 0x14, 0x50, 0x01, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x94, 0xb4, 0x0c, 0x28, 0xa0, 0x09, 0xe9, 0x47, 0x4a, 0xd9, 0x26, 0x0c, 0x4e, 0x29, 0x69, 0x94, 0x18, 0xf4, 0xa4, 0xa5, 0x70, 0xb8, 0xb4, 0x62, 0x91, 0x22, 0x51, 0x4f, 0x60, 0x17, 0xda, 0x9b, 0xea, 0x45, 0x00, 0x29, 0xa2, 0xa3, 0xa8, 0x09, 0x45, 0x27, 0xb8, 0x05, 0x25, 0x3b, 0xd8, 0x42, 0x8a, 0x29, 0x75, 0x18, 0x86, 0x83, 0x47, 0x90, 0x09, 0x45, 0x17, 0x10, 0x51, 0x49, 0x0c, 0x28, 0xa7, 0x64, 0x21, 0x3a, 0x8a, 0x2a, 0x46, 0x14, 0x55, 0x00, 0x51, 0x48, 0x42, 0x52, 0xe6, 0x81, 0x89, 0x45, 0x20, 0x0a, 0x28, 0x00, 0xa4, 0xa6, 0x01, 0x4b, 0x4c, 0x42, 0x51, 0x48, 0x61, 0x47, 0x7a, 0x40, 0x14, 0x50, 0x01, 0x45, 0x30, 0x0a, 0x29, 0x80, 0x51, 0x48, 0x04, 0xa5, 0xa0, 0x41, 0x49, 0x40, 0x0b, 0x45, 0x20, 0x0a, 0x4a, 0x06, 0x14, 0xb4, 0x00, 0x94, 0x53, 0x10, 0x51, 0x48, 0x02, 0x8a, 0x63, 0x12, 0x96, 0x90, 0x05, 0x25, 0x02, 0x16, 0x8a, 0x2e, 0x30, 0xa2, 0x80, 0x45, 0x8a, 0x4a, 0xda, 0xe5, 0x06, 0x29, 0x68, 0x24, 0x28, 0xa0, 0x62, 0x7f, 0x4a, 0x5a, 0x00, 0x5f, 0xc6, 0x9b, 0xf8, 0x54, 0x8a, 0xe1, 0xd2, 0x8e, 0x28, 0x40, 0x14, 0x99, 0xa9, 0xf3, 0x00, 0xa2, 0x81, 0x01, 0xef, 0x49, 0x4c, 0x61, 0x45, 0x01, 0x70, 0xa4, 0xa4, 0x01, 0x45, 0x31, 0x05, 0x15, 0x00, 0x25, 0x15, 0x48, 0x61, 0x45, 0x20, 0x0a, 0x29, 0x88, 0x4a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x4a, 0x06, 0x2d, 0x14, 0x00, 0x94, 0x52, 0xb0, 0x0b, 0x45, 0x21, 0x09, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x42, 0x00, 0xa2, 0x80, 0x0a, 0x4a, 0x00, 0x5a, 0x4a, 0x06, 0x14, 0xb4, 0x00, 0x94, 0x53, 0x10, 0x51, 0x48, 0x02, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x08, 0x41, 0x45, 0x03, 0x0a, 0x4a, 0x00, 0x5a, 0x29, 0x80, 0x94, 0x52, 0x10, 0x52, 0xd0, 0x02, 0x51, 0x42, 0x19, 0x63, 0xf0, 0xa3, 0x8a, 0xd9, 0x68, 0x86, 0x03, 0x34, 0xb4, 0x86, 0xc4, 0xa2, 0x84, 0x98, 0xba, 0x8b, 0xda, 0x8e, 0xd4, 0x00, 0x52, 0x53, 0x62, 0x0a, 0x2a, 0x76, 0x00, 0xa4, 0xc5, 0x00, 0x14, 0x94, 0x00, 0x51, 0x52, 0x20, 0xa4, 0xaa, 0x43, 0x17, 0xa7, 0xbd, 0x14, 0x79, 0x80, 0x94, 0x54, 0x88, 0x29, 0x28, 0x18, 0xb4, 0x94, 0x08, 0x28, 0xa2, 0xe3, 0x0a, 0x28, 0x15, 0x84, 0xa2, 0x93, 0x00, 0xa2, 0x95, 0xc0, 0x28, 0xa0, 0x02, 0x92, 0xaa, 0xe3, 0x16, 0x93, 0x34, 0x98, 0x85, 0xa4, 0xa0, 0x02, 0x96, 0x90, 0x09, 0x45, 0x31, 0x85, 0x14, 0x08, 0x29, 0x29, 0x00, 0x52, 0xd0, 0x02, 0x51, 0x4f, 0xa0, 0xc2, 0x96, 0x90, 0x05, 0x25, 0x02, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0xc4, 0x14, 0x52, 0x00, 0xa4, 0xa0, 0x61, 0x4b, 0x40, 0x05, 0x14, 0x30, 0x12, 0x8a, 0x00, 0x5a, 0x4a, 0x04, 0x14, 0x50, 0x05, 0x8f, 0xad, 0x06, 0xb6, 0x2d, 0xad, 0x40, 0x71, 0x47, 0xa9, 0xeb, 0x43, 0x42, 0x17, 0xd8, 0x7d, 0xda, 0x4f, 0x6a, 0x7e, 0x62, 0x0a, 0x5a, 0x96, 0x86, 0x27, 0x7a, 0x28, 0xd0, 0x18, 0x1e, 0x68, 0xa2, 0xe2, 0x13, 0xbd, 0x2d, 0x20, 0x12, 0x8a, 0x00, 0x29, 0x29, 0x75, 0x00, 0xa2, 0x86, 0x01, 0x49, 0x47, 0x5b, 0x00, 0x51, 0x48, 0x41, 0x45, 0x1d, 0x40, 0x4a, 0x29, 0x0c, 0x5a, 0x4a, 0x04, 0x14, 0x51, 0x71, 0x85, 0x25, 0x02, 0x0a, 0x29, 0xd8, 0x02, 0x8a, 0x40, 0x14, 0x50, 0x31, 0x29, 0x69, 0xb1, 0x09, 0x46, 0x69, 0x31, 0x85, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x21, 0x09, 0x4b, 0x40, 0x09, 0x45, 0x00, 0x14, 0xb4, 0x0c, 0x4a, 0x29, 0x88, 0x28, 0xa5, 0xb0, 0x05, 0x14, 0x0c, 0x28, 0xa6, 0x01, 0x45, 0x2b, 0x80, 0x51, 0x4c, 0x41, 0x45, 0x21, 0x89, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x58, 0x34, 0xa2, 0xb5, 0x1b, 0x0a, 0x3f, 0x4a, 0x02, 0xe1, 0xcf, 0xe7, 0x47, 0xe9, 0x54, 0x02, 0x52, 0xd0, 0x20, 0xa4, 0x34, 0x80, 0x29, 0x2a, 0x58, 0x0b, 0xde, 0x8a, 0x57, 0x10, 0x94, 0x50, 0x30, 0xa4, 0x34, 0x05, 0x82, 0x93, 0x9a, 0x5e, 0x4c, 0x02, 0x8a, 0x00, 0x28, 0xa6, 0x01, 0x49, 0x48, 0x42, 0x8a, 0x4a, 0x96, 0x01, 0x49, 0x54, 0x80, 0x29, 0x68, 0xb0, 0xd8, 0x94, 0x52, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x00, 0x51, 0x42, 0x60, 0x14, 0x50, 0x31, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x04, 0xa2, 0x90, 0x05, 0x15, 0x5d, 0x00, 0x28, 0xa4, 0x21, 0x69, 0x29, 0x00, 0x51, 0x40, 0x05, 0x14, 0xc6, 0x14, 0x52, 0x00, 0xa2, 0x81, 0x05, 0x25, 0x03, 0x16, 0x8a, 0x00, 0x4a, 0x5a, 0x00, 0x29, 0x28, 0x01, 0x69, 0x28, 0x00, 0xa2, 0x81, 0x0b, 0x49, 0x40, 0x05, 0x2d, 0x00, 0x4f, 0xf8, 0x51, 0xf4, 0xad, 0x99, 0x57, 0x0c, 0x51, 0x4d, 0x08, 0x38, 0x3c, 0x51, 0x8e, 0xdd, 0xe9, 0x8c, 0x06, 0x7b, 0xd1, 0x49, 0xb1, 0x01, 0xa3, 0xad, 0x21, 0x8b, 0x4d, 0xa9, 0x62, 0xd8, 0x4a, 0x3a, 0x52, 0xb0, 0xae, 0x2d, 0x14, 0x90, 0xc4, 0xef, 0x45, 0x50, 0x08, 0x69, 0x6a, 0x5f, 0x71, 0x58, 0x4a, 0x29, 0x8c, 0x28, 0xe9, 0x52, 0x01, 0x48, 0x6a, 0x84, 0x2d, 0x25, 0x20, 0x12, 0x8a, 0x06, 0x2d, 0x25, 0x2b, 0x88, 0x28, 0xa0, 0x61, 0x49, 0x4c, 0x42, 0xd1, 0x52, 0x02, 0x52, 0xd5, 0x0c, 0x4a, 0x29, 0x00, 0x51, 0x4d, 0x08, 0x28, 0xa4, 0x30, 0xa2, 0x98, 0x84, 0xa5, 0xa4, 0x80, 0x4a, 0x5a, 0x06, 0x25, 0x14, 0x84, 0x14, 0x50, 0xc6, 0x14, 0x50, 0x01, 0x45, 0x1a, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x60, 0x14, 0x52, 0xdc, 0x61, 0x45, 0x31, 0x09, 0x45, 0x20, 0x0a, 0x28, 0x18, 0xb4, 0x94, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x53, 0x02, 0xcf, 0x7a, 0x4a, 0xdd, 0xbb, 0xb1, 0x87, 0xf4, 0xa3, 0x9a, 0x5b, 0x08, 0x05, 0x14, 0x5f, 0x51, 0xd8, 0x28, 0x35, 0x37, 0xbb, 0x00, 0xfa, 0xd2, 0xd3, 0xb8, 0x34, 0x25, 0x15, 0x3a, 0x88, 0x29, 0x28, 0xd8, 0x42, 0x51, 0x48, 0x61, 0x45, 0x31, 0x05, 0x1c, 0x54, 0x83, 0x62, 0x51, 0x54, 0x30, 0xa2, 0xa0, 0x04, 0xa5, 0xa1, 0x80, 0x94, 0x50, 0x20, 0xa4, 0xa0, 0x61, 0x4b, 0x40, 0x09, 0xda, 0x8a, 0x62, 0x0a, 0x29, 0x00, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x29, 0x28, 0x60, 0x14, 0x52, 0x00, 0xa2, 0x98, 0x05, 0x25, 0x20, 0x16, 0x92, 0x98, 0x31, 0x69, 0x28, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x28, 0xa4, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x00, 0x4a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x20, 0xa2, 0x81, 0x96, 0x3f, 0x1a, 0x4a, 0xdb, 0xd0, 0xab, 0x75, 0x16, 0x8f, 0x4a, 0x44, 0x85, 0x2f, 0xb5, 0x3d, 0xc0, 0x69, 0xf4, 0xa7, 0x1e, 0x4d, 0x3b, 0x68, 0x02, 0x51, 0x52, 0x80, 0x28, 0xa0, 0x04, 0xa0, 0xd4, 0x85, 0x84, 0xa2, 0xa8, 0x02, 0x97, 0x23, 0xb5, 0x2b, 0x00, 0xda, 0x5a, 0x04, 0x25, 0x14, 0x98, 0xc2, 0x8a, 0x35, 0x10, 0x94, 0xb4, 0x98, 0x05, 0x21, 0xa0, 0x62, 0x52, 0xd2, 0x62, 0x10, 0xd1, 0x40, 0xc4, 0xa5, 0xaa, 0xd0, 0x41, 0x45, 0x2d, 0xc6, 0x25, 0x2d, 0x48, 0x84, 0xa2, 0x9e, 0xc3, 0x0a, 0x28, 0x00, 0xa2, 0x90, 0x05, 0x14, 0xc0, 0x29, 0x29, 0x00, 0xb4, 0x94, 0xc4, 0x14, 0x52, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x09, 0x45, 0x02, 0x16, 0x92, 0x81, 0x85, 0x14, 0x08, 0x29, 0x68, 0x01, 0x28, 0xa6, 0xc6, 0x14, 0x50, 0x01, 0x45, 0x20, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x2c, 0x52, 0x9c, 0x81, 0x9a, 0xde, 0xe9, 0xb1, 0xbd, 0xc6, 0xf1, 0x4b, 0x93, 0x48, 0x57, 0x0c, 0xd1, 0xc7, 0x5a, 0x9e, 0x5e, 0xa0, 0x00, 0xf3, 0xd2, 0x93, 0xa5, 0x30, 0x0a, 0x33, 0x4a, 0xf7, 0x00, 0xcd, 0x03, 0xa6, 0x68, 0x18, 0x52, 0xd3, 0x10, 0x9d, 0xe8, 0xa1, 0xea, 0x02, 0x52, 0xfe, 0x14, 0x81, 0x89, 0x49, 0x40, 0x58, 0x5e, 0xb4, 0x94, 0xac, 0x16, 0x0a, 0x29, 0x80, 0x0a, 0x28, 0x0b, 0x09, 0x45, 0x48, 0x05, 0x15, 0x40, 0x14, 0x54, 0x80, 0x52, 0x50, 0x80, 0x5a, 0x4a, 0x2c, 0x01, 0x45, 0x16, 0x01, 0x29, 0x69, 0xd8, 0x02, 0x92, 0x95, 0x80, 0x29, 0x69, 0x00, 0x52, 0x53, 0xb0, 0x05, 0x18, 0xa0, 0x02, 0x8a, 0x2c, 0x01, 0x45, 0x16, 0x00, 0xa4, 0xa5, 0x60, 0xb0, 0xb4, 0x94, 0xc0, 0x28, 0xa5, 0x60, 0x0a, 0x29, 0x00, 0x51, 0x54, 0x01, 0x45, 0x20, 0x0a, 0x29, 0xda, 0xe0, 0x14, 0x52, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x2c, 0x01, 0x45, 0x00, 0x25, 0x2d, 0x20, 0x12, 0x96, 0x98, 0x09, 0x4b, 0x40, 0x13, 0xf4, 0xa4, 0xad, 0x36, 0x41, 0xb8, 0x51, 0xdb, 0x14, 0xb9, 0x47, 0x61, 0x68, 0xa7, 0xb0, 0x05, 0x1d, 0x0d, 0x55, 0x84, 0x1d, 0x69, 0x2a, 0x7c, 0x80, 0x28, 0xa4, 0x30, 0xa2, 0x98, 0x82, 0x92, 0x8b, 0x80, 0x51, 0xef, 0x48, 0x04, 0xa2, 0xa4, 0x02, 0x8a, 0x3a, 0x05, 0xc2, 0x8a, 0x77, 0xb0, 0x05, 0x25, 0x20, 0xb8, 0xb4, 0x94, 0x00, 0x51, 0x48, 0x04, 0xa2, 0x98, 0x05, 0x14, 0x00, 0x66, 0x8a, 0x40, 0x14, 0x50, 0xc0, 0x29, 0x28, 0x00, 0xa0, 0x53, 0x00, 0xa2, 0x90, 0x82, 0x8a, 0x43, 0x0a, 0x28, 0x00, 0xa4, 0xa0, 0x05, 0xa4, 0xa6, 0x01, 0x45, 0x00, 0x14, 0x50, 0x20, 0xa4, 0xa4, 0x30, 0xa5, 0xa0, 0x02, 0x8a, 0x00, 0x4a, 0x5a, 0x00, 0x4a, 0x29, 0x80, 0x52, 0xd0, 0x20, 0xa4, 0xa4, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x27, 0x3c, 0xd2, 0xd6, 0xb7, 0x18, 0x94, 0x67, 0xd6, 0x8d, 0xc0, 0x5a, 0x0f, 0x5a, 0x62, 0x0c, 0xd1, 0x4b, 0x50, 0xb0, 0x52, 0x54, 0xb0, 0x03, 0xd6, 0x92, 0x98, 0xc2, 0x96, 0x90, 0xae, 0x21, 0xa2, 0x9a, 0x00, 0xa2, 0x80, 0x12, 0x8a, 0x97, 0xa8, 0x05, 0x14, 0x58, 0x04, 0xa2, 0x9e, 0xe0, 0x14, 0x95, 0x20, 0x2d, 0x14, 0x00, 0x52, 0x52, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x77, 0x10, 0x52, 0x52, 0x18, 0x52, 0xd5, 0x00, 0x94, 0x50, 0x20, 0xa2, 0xa4, 0x41, 0x49, 0x40, 0xc5, 0xa2, 0x81, 0x85, 0x14, 0x08, 0x29, 0x29, 0x80, 0x51, 0x48, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x63, 0x0a, 0x4a, 0x57, 0x10, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x5a, 0x4a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x60, 0x25, 0x2d, 0x20, 0x0a, 0x29, 0x81, 0x39, 0xa2, 0xac, 0x76, 0x0e, 0xb4, 0x53, 0x18, 0xa2, 0x93, 0x9a, 0x68, 0x05, 0x1d, 0x28, 0xa0, 0x90, 0xa2, 0xa2, 0xe0, 0x25, 0x14, 0xc0, 0x29, 0x29, 0x05, 0x84, 0xa5, 0xaa, 0x00, 0xa3, 0x1e, 0xd5, 0x9f, 0x41, 0x09, 0xd6, 0x8a, 0x77, 0x18, 0x51, 0x4c, 0x04, 0xa5, 0xa5, 0x71, 0x09, 0x49, 0x4c, 0x05, 0xa2, 0x90, 0xc4, 0xa2, 0x95, 0xc4, 0x14, 0x51, 0xb8, 0x01, 0x34, 0x53, 0x00, 0xa2, 0x90, 0x09, 0x45, 0x03, 0x0a, 0x29, 0x08, 0x4a, 0x5a, 0x60, 0x14, 0x66, 0x90, 0x58, 0x4a, 0x5a, 0x06, 0x25, 0x14, 0x08, 0x28, 0xa0, 0x02, 0x8a, 0x60, 0x25, 0x2d, 0x20, 0x12, 0x96, 0x80, 0x12, 0x96, 0x81, 0x89, 0x45, 0x31, 0x05, 0x14, 0x80, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x20, 0xa2, 0x81, 0x85, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x4e, 0x7a, 0x51, 0xda, 0xb7, 0x28, 0x3e, 0x94, 0x71, 0xef, 0x4c, 0x41, 0x4e, 0xa9, 0x01, 0xb4, 0xb4, 0xc4, 0x27, 0xe1, 0x45, 0x26, 0x3b, 0x85, 0x1d, 0xe9, 0x08, 0x28, 0xa9, 0xea, 0x02, 0x52, 0x73, 0x43, 0x01, 0x71, 0x4a, 0x38, 0x6a, 0x42, 0x1b, 0xd2, 0x8a, 0x10, 0xc4, 0x34, 0xb4, 0x58, 0x04, 0xa2, 0x98, 0x82, 0x92, 0x86, 0xc6, 0x2d, 0x25, 0x48, 0x82, 0x8a, 0x12, 0x18, 0x51, 0x4c, 0x41, 0x45, 0x48, 0x09, 0x45, 0x31, 0x85, 0x14, 0x08, 0x28, 0xa4, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x10, 0x94, 0x50, 0x01, 0x40, 0xa0, 0x61, 0x45, 0x02, 0x0a, 0x29, 0x8c, 0x29, 0x29, 0x00, 0x51, 0x4c, 0x02, 0x8a, 0x40, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0xb4, 0x08, 0x4a, 0x28, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x20, 0xa2, 0x80, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x09, 0x4b, 0x40, 0x13, 0xe6, 0x96, 0xb4, 0xb8, 0x75, 0x13, 0x22, 0x8e, 0xf5, 0x6b, 0x51, 0x8b, 0xc7, 0x6a, 0x4a, 0xa6, 0x01, 0x4b, 0x51, 0xcc, 0x02, 0x51, 0x9a, 0x62, 0xb0, 0x94, 0xb5, 0x37, 0x00, 0xa4, 0xa4, 0x01, 0x45, 0x27, 0xdc, 0x04, 0xa5, 0xa6, 0x02, 0x52, 0xd2, 0x01, 0x28, 0xa4, 0x02, 0x51, 0x40, 0x05, 0x14, 0x9e, 0xa0, 0x14, 0x94, 0x02, 0x0a, 0x28, 0x60, 0x25, 0x2d, 0x3d, 0x01, 0x89, 0x45, 0x21, 0x20, 0xa2, 0x81, 0x85, 0x14, 0x80, 0x28, 0xa0, 0x41, 0x45, 0x30, 0x0a, 0x29, 0x00, 0x94, 0x53, 0x00, 0xa2, 0x8b, 0x8c, 0x28, 0xa6, 0x20, 0xa4, 0xa9, 0x18, 0x52, 0xd3, 0xb0, 0x82, 0x92, 0x90, 0x05, 0x2d, 0x03, 0x12, 0x96, 0x80, 0x12, 0x8a, 0x04, 0x14, 0x50, 0x01, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x2c, 0x02, 0x51, 0x40, 0x85, 0xa2, 0x81, 0x89, 0x45, 0x00, 0x2d, 0x14, 0xc0, 0x9f, 0x14, 0xbd, 0xaa, 0x86, 0x1c, 0xfe, 0x14, 0x55, 0xa6, 0x98, 0x84, 0xa2, 0xa8, 0x62, 0x8e, 0x3a, 0x52, 0x54, 0xdd, 0x08, 0x28, 0xa0, 0x04, 0xa5, 0xa0, 0x04, 0x34, 0xb5, 0x20, 0x25, 0x15, 0x37, 0x01, 0x29, 0x4d, 0x30, 0x1b, 0x47, 0xb5, 0x48, 0x0b, 0x49, 0x4f, 0xa0, 0x07, 0x7a, 0x28, 0x40, 0x14, 0x53, 0x0b, 0x85, 0x15, 0x20, 0x25, 0x14, 0xc4, 0x14, 0x50, 0x30, 0xa4, 0xa0, 0x41, 0x4b, 0x53, 0x61, 0x89, 0x45, 0x00, 0x14, 0x50, 0x21, 0x29, 0x69, 0x80, 0x94, 0x50, 0x02, 0xd2, 0x52, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x00, 0x28, 0xa6, 0x30, 0xa4, 0xa4, 0x01, 0x4b, 0x40, 0x09, 0x45, 0x02, 0x0a, 0x28, 0x00, 0xa2, 0x98, 0xc2, 0x8a, 0x42, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x4a, 0x5a, 0x00, 0x28, 0xa0, 0x62, 0x52, 0xd0, 0x05, 0x8f, 0xf3, 0xd2, 0x93, 0xad, 0x6a, 0xc0, 0x29, 0x6a, 0x96, 0xa5, 0x07, 0x6a, 0x3b, 0x54, 0x8a, 0xc0, 0x28, 0xa3, 0x46, 0x21, 0x29, 0x6a, 0xb6, 0x0b, 0x09, 0x49, 0x51, 0x70, 0x0a, 0x0d, 0x34, 0x01, 0xda, 0x92, 0x96, 0x80, 0x14, 0xb5, 0x3d, 0x44, 0x25, 0x14, 0xf4, 0x18, 0x94, 0x52, 0x00, 0xa2, 0x86, 0xc0, 0x29, 0x28, 0xb0, 0x82, 0x8a, 0x2c, 0x01, 0x45, 0x0c, 0x02, 0x92, 0x80, 0x16, 0x8a, 0x90, 0x12, 0x8a, 0x01, 0x85, 0x14, 0xc0, 0x28, 0xa0, 0x04, 0xa2, 0x90, 0xc2, 0x8a, 0x04, 0x14, 0x50, 0x30, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x4a, 0x5a, 0x00, 0x4a, 0x28, 0x01, 0x69, 0x28, 0x10, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x92, 0x81, 0x0b, 0x45, 0x03, 0x0a, 0x4a, 0x00, 0x5a, 0x4a, 0x00, 0xb1, 0xf8, 0x52, 0x56, 0xdb, 0x0c, 0x5c, 0x8e, 0x98, 0xa5, 0xa4, 0x02, 0x52, 0xd1, 0x21, 0x05, 0x14, 0xc6, 0x25, 0x14, 0x08, 0x05, 0x15, 0x3d, 0x00, 0x4a, 0x2a, 0x77, 0x00, 0xe6, 0x93, 0xbd, 0x08, 0x05, 0xa6, 0xd5, 0x74, 0x04, 0x2d, 0x21, 0xa3, 0x70, 0x0a, 0x2a, 0x40, 0x28, 0xa6, 0x20, 0xa2, 0xa6, 0xe0, 0x14, 0x94, 0x20, 0x0a, 0x29, 0xb0, 0x0a, 0x4a, 0x40, 0x2d, 0x25, 0x00, 0x14, 0x52, 0x18, 0x94, 0xb4, 0xc4, 0x14, 0x50, 0x31, 0x29, 0x69, 0x00, 0x94, 0x50, 0x80, 0x28, 0xa0, 0x02, 0x8a, 0x60, 0x14, 0x52, 0x10, 0x51, 0x40, 0x09, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x04, 0x14, 0x53, 0x18, 0x51, 0x40, 0x05, 0x14, 0x84, 0x14, 0x50, 0x30, 0xa4, 0xa6, 0x01, 0x45, 0x20, 0x16, 0x8a, 0x00, 0x29, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x96, 0x80, 0x27, 0xed, 0x49, 0xfc, 0xeb, 0x6e, 0x50, 0x1d, 0x8a, 0x2a, 0x47, 0x71, 0x28, 0xa7, 0xa0, 0xc0, 0xd1, 0x54, 0x20, 0xa2, 0x90, 0x82, 0x8a, 0x86, 0x80, 0x4c, 0xd1, 0x4e, 0xc8, 0x41, 0x45, 0x21, 0x89, 0x45, 0x00, 0x14, 0x52, 0x01, 0x28, 0xa0, 0x41, 0x45, 0x00, 0x14, 0x94, 0x0d, 0x05, 0x14, 0xac, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x00, 0xa4, 0xa4, 0x01, 0x45, 0x30, 0x0a, 0x28, 0x00, 0xa4, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x20, 0xa2, 0x90, 0xc2, 0x8a, 0x62, 0x0a, 0x4a, 0x40, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x31, 0x69, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x92, 0x80, 0x16, 0x8a, 0x04, 0x25, 0x14, 0x00, 0x51, 0x40, 0x0b, 0x49, 0x40, 0xc5, 0xa4, 0xa0, 0x09, 0xf3, 0x45, 0x6c, 0x31, 0x7b, 0x52, 0xd4, 0xe8, 0x21, 0x28, 0xe9, 0xd6, 0x98, 0xc2, 0x96, 0x9d, 0xc4, 0x26, 0x68, 0xa4, 0x08, 0x4a, 0x5e, 0xd4, 0xae, 0x02, 0x51, 0x4d, 0x87, 0x50, 0xa4, 0xa4, 0x01, 0x49, 0x4b, 0xa8, 0x85, 0xa4, 0xa4, 0x3b, 0x85, 0x14, 0x20, 0x0a, 0x4a, 0x4c, 0x05, 0xa4, 0xa0, 0x41, 0x4b, 0x40, 0xc4, 0xa4, 0xa7, 0xd0, 0x02, 0x8a, 0x04, 0x2d, 0x25, 0x20, 0x0a, 0x29, 0x00, 0x51, 0x4c, 0x62, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x48, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x42, 0x51, 0x4c, 0x62, 0xd2, 0x52, 0x10, 0xb4, 0x94, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x04, 0x14, 0x50, 0x30, 0xa2, 0x80, 0x12, 0x96, 0x80, 0x0a, 0x28, 0x10, 0x94, 0x50, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x16, 0x92, 0x80, 0x16, 0x92, 0x81, 0x05, 0x14, 0x01, 0x63, 0x14, 0x56, 0xf7, 0x28, 0x28, 0xa8, 0x96, 0xa2, 0x61, 0xdf, 0xa5, 0x2f, 0xd0, 0x53, 0xb0, 0xc4, 0x3d, 0x28, 0xe2, 0x9f, 0x40, 0x0a, 0x2a, 0x44, 0x25, 0x2d, 0x30, 0x12, 0x8a, 0x4c, 0x03, 0x34, 0x94, 0x96, 0xc0, 0x2e, 0x68, 0xa9, 0x01, 0x29, 0x2a, 0xd0, 0x05, 0x14, 0x80, 0x28, 0xa4, 0x02, 0x52, 0xd2, 0x01, 0x29, 0x69, 0x80, 0x94, 0x52, 0x10, 0x94, 0xb4, 0x0c, 0x4a, 0x28, 0x10, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x42, 0x52, 0xd2, 0x01, 0x28, 0xa0, 0x61, 0x45, 0x1d, 0x44, 0x14, 0x53, 0xb8, 0xc2, 0x92, 0x90, 0x82, 0x8a, 0x2e, 0x31, 0x68, 0xa0, 0x42, 0x51, 0x40, 0xc2, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x10, 0x52, 0x50, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x0b, 0x49, 0x40, 0xc5, 0xa4, 0xa0, 0x0b, 0x14, 0x66, 0xb5, 0x2b, 0x40, 0xa2, 0x90, 0x82, 0x8a, 0x16, 0xe2, 0xe8, 0x1d, 0x28, 0xa7, 0xb8, 0x21, 0x29, 0x73, 0x47, 0x40, 0x0a, 0x4a, 0x40, 0x14, 0x76, 0xa0, 0x62, 0x0a, 0x5a, 0x91, 0x09, 0x45, 0x08, 0x02, 0x83, 0x40, 0x09, 0x45, 0x31, 0x05, 0x15, 0x37, 0x01, 0x28, 0xa0, 0x05, 0xa4, 0xa2, 0xe0, 0x14, 0x53, 0x18, 0x52, 0x52, 0x00, 0xa2, 0x90, 0x05, 0x15, 0x42, 0x0a, 0x4a, 0x00, 0x29, 0x69, 0x00, 0x94, 0x50, 0x01, 0x45, 0x21, 0x89, 0x4b, 0x40, 0x82, 0x8a, 0x00, 0x4a, 0x5a, 0x06, 0x25, 0x14, 0x08, 0x28, 0xa0, 0x02, 0x8a, 0x06, 0x2d, 0x25, 0x02, 0x0a, 0x4a, 0x06, 0x2d, 0x14, 0x00, 0x94, 0xb4, 0x00, 0x51, 0x40, 0x09, 0x4b, 0x40, 0x05, 0x14, 0x08, 0x4a, 0x28, 0x18, 0x51, 0x40, 0x82, 0x96, 0x81, 0x89, 0x45, 0x02, 0x16, 0x92, 0x84, 0x32, 0xc6, 0x73, 0x47, 0xe1, 0x5a, 0xdc, 0x04, 0xfd, 0x68, 0xa2, 0xe3, 0x16, 0x96, 0x95, 0xf5, 0x00, 0xa4, 0xaa, 0x10, 0x66, 0x8a, 0x40, 0x14, 0x52, 0x01, 0x28, 0xa4, 0x02, 0x52, 0xd0, 0x02, 0x1a, 0x0d, 0x20, 0x12, 0x96, 0x9b, 0x01, 0x28, 0xa4, 0x01, 0x45, 0x02, 0x12, 0x96, 0x90, 0xc2, 0x92, 0x90, 0x82, 0x8a, 0x60, 0x14, 0x94, 0x74, 0x18, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x48, 0x04, 0xa5, 0xa0, 0x42, 0x51, 0x4c, 0x62, 0xd2, 0x52, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x00, 0x51, 0x4c, 0x62, 0x51, 0x48, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x4a, 0x5a, 0x42, 0x12, 0x8a, 0x63, 0x0a, 0x5a, 0x00, 0x4a, 0x28, 0x00, 0xa2, 0x81, 0x05, 0x14, 0xc0, 0x28, 0xa4, 0x01, 0x45, 0x03, 0x2c, 0x1a, 0x4a, 0xd7, 0xa0, 0x0b, 0x45, 0x30, 0x13, 0x3e, 0xd4, 0x53, 0xb0, 0x05, 0x2d, 0x20, 0xb8, 0x94, 0x53, 0xbe, 0x80, 0x14, 0x54, 0xd8, 0x02, 0x92, 0x97, 0x40, 0x0a, 0x5a, 0x40, 0x25, 0x19, 0xa0, 0x04, 0xa5, 0xa5, 0x60, 0x13, 0x14, 0x1a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x20, 0x12, 0x8a, 0x63, 0x0a, 0x28, 0x62, 0x12, 0x8a, 0x06, 0x14, 0x52, 0x10, 0x51, 0x4c, 0x04, 0xa5, 0xa9, 0x60, 0x25, 0x2d, 0x03, 0x12, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x92, 0x84, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x85, 0x14, 0x00, 0x51, 0x40, 0x84, 0xa2, 0x80, 0x16, 0x8a, 0x00, 0x4a, 0x5a, 0x06, 0x25, 0x14, 0x08, 0x28, 0xa0, 0x02, 0x96, 0x81, 0x85, 0x25, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x04, 0xff, 0x00, 0x5a, 0x2b, 0x50, 0x16, 0x92, 0x81, 0x85, 0x2d, 0x50, 0x07, 0xe1, 0x49, 0x48, 0x48, 0x5f, 0xc2, 0x8a, 0x4c, 0x04, 0xa2, 0x90, 0x20, 0xa4, 0xa5, 0x6b, 0x00, 0xb4, 0x50, 0x02, 0x52, 0x51, 0x70, 0x0a, 0x29, 0x00, 0x51, 0x45, 0x80, 0x28, 0xa0, 0x04, 0xa2, 0x90, 0x05, 0x14, 0x00, 0x94, 0xb4, 0x80, 0x29, 0x29, 0x88, 0x28, 0xa0, 0x61, 0x45, 0x02, 0x12, 0x96, 0x90, 0xc4, 0xa2, 0x9d, 0xc4, 0x14, 0x53, 0x00, 0xa2, 0xa4, 0x61, 0x49, 0x40, 0x05, 0x2d, 0x30, 0x0a, 0x4a, 0x04, 0x14, 0x52, 0x00, 0xa2, 0x81, 0x85, 0x14, 0x00, 0x52, 0x50, 0x21, 0x68, 0xa0, 0x02, 0x8a, 0x00, 0x29, 0x28, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x20, 0xa2, 0x80, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x22, 0xc5, 0x27, 0x7a, 0xd0, 0x6c, 0x28, 0xaa, 0x00, 0x3d, 0xa8, 0xa0, 0x05, 0xa2, 0x8e, 0x83, 0x0a, 0x4a, 0x95, 0xb8, 0x82, 0x8a, 0x00, 0x4a, 0x5a, 0x64, 0x85, 0x25, 0x49, 0x41, 0x45, 0x26, 0x02, 0x51, 0x4c, 0x02, 0x92, 0x80, 0x16, 0x8a, 0x90, 0x12, 0x8a, 0x04, 0x14, 0x50, 0x00, 0x69, 0x28, 0x43, 0x0a, 0x29, 0x88, 0x5a, 0x4a, 0x43, 0x0a, 0x28, 0xb0, 0x05, 0x25, 0x00, 0x14, 0x52, 0x10, 0xb4, 0x94, 0x0c, 0x28, 0xa0, 0x41, 0x49, 0x40, 0xc5, 0xa2, 0x80, 0x12, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x4a, 0x5a, 0x00, 0x28, 0xa0, 0x04, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x5a, 0x4a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x9f, 0x14, 0x56, 0xc3, 0x0a, 0x5e, 0x94, 0x5c, 0x42, 0x52, 0xf5, 0xa2, 0xe0, 0x27, 0x7a, 0x5a, 0x43, 0x13, 0x34, 0xb4, 0x6c, 0x21, 0x29, 0x29, 0x6e, 0x02, 0xd1, 0x48, 0x2e, 0x25, 0x25, 0x30, 0x16, 0x92, 0x90, 0x0b, 0x49, 0x49, 0x80, 0x51, 0x49, 0x00, 0x94, 0x55, 0x00, 0x51, 0x48, 0x02, 0x8a, 0x00, 0x29, 0x29, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x49, 0x40, 0x05, 0x14, 0x00, 0x51, 0x48, 0x02, 0x8a, 0x00, 0x4a, 0x28, 0x00, 0xa5, 0xa0, 0x42, 0x51, 0x40, 0x05, 0x14, 0xc6, 0x14, 0x52, 0x10, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x29, 0x29, 0x88, 0x29, 0x69, 0x0c, 0x28, 0xa0, 0x42, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x9e, 0x8e, 0x2b, 0x60, 0x0a, 0x5a, 0x00, 0x28, 0x14, 0x00, 0x94, 0xb4, 0x0c, 0x4a, 0x29, 0x07, 0x40, 0xa2, 0xa4, 0x42, 0x1a, 0x3e, 0x94, 0xc0, 0x28, 0xa9, 0xd8, 0x04, 0xa5, 0xa6, 0x02, 0x51, 0xd6, 0x96, 0xe0, 0x14, 0x52, 0xb0, 0x05, 0x25, 0x30, 0x0a, 0x28, 0xb0, 0x0b, 0x49, 0x48, 0x02, 0x92, 0x8e, 0x80, 0x14, 0x52, 0x10, 0x51, 0x4c, 0x02, 0x8a, 0x40, 0x25, 0x2d, 0x03, 0x12, 0x8a, 0x60, 0x14, 0x50, 0x01, 0x45, 0x20, 0x0a, 0x28, 0x01, 0x29, 0x68, 0x10, 0x94, 0x50, 0x30, 0xa2, 0x80, 0x0a, 0x29, 0x80, 0x51, 0x40, 0x84, 0xa5, 0xa4, 0x30, 0xa2, 0x80, 0x12, 0x8a, 0x00, 0x5a, 0x4a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x40, 0xc2, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x02, 0xc5, 0x15, 0xb3, 0x18, 0x52, 0x52, 0x10, 0xb4, 0x53, 0x60, 0x14, 0x94, 0x0c, 0x3b, 0x51, 0x4a, 0xe2, 0x0a, 0x29, 0x00, 0x94, 0x51, 0x6b, 0x80, 0x51, 0x48, 0x02, 0x8a, 0x40, 0x25, 0x14, 0xd8, 0x05, 0x15, 0x20, 0x25, 0x14, 0xc0, 0x28, 0xa0, 0x02, 0x8a, 0x9b, 0x08, 0x4a, 0x2a, 0x80, 0x28, 0xa9, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x01, 0x29, 0x68, 0x01, 0x28, 0xa0, 0x02, 0x8a, 0x63, 0x0a, 0x28, 0x10, 0x94, 0x52, 0x18, 0xb4, 0x94, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x02, 0x12, 0x8a, 0x06, 0x14, 0xb4, 0x00, 0x94, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x20, 0xa2, 0x81, 0x93, 0xd1, 0x5a, 0xbe, 0xc8, 0x1e, 0xa1, 0x4b, 0xde, 0x82, 0x83, 0x34, 0x11, 0x48, 0x91, 0x05, 0x1d, 0xe9, 0xb1, 0x86, 0x69, 0x29, 0xd8, 0x42, 0xd1, 0x51, 0x24, 0x02, 0x51, 0x54, 0x01, 0x45, 0x4d, 0xc0, 0x29, 0x29, 0x00, 0x51, 0x45, 0xc0, 0x4e, 0xf4, 0x52, 0x00, 0xa2, 0xa8, 0x02, 0x8a, 0x80, 0x12, 0x8a, 0xa0, 0x0a, 0x28, 0x00, 0xa2, 0x90, 0x05, 0x14, 0x82, 0xe1, 0x45, 0x08, 0x04, 0xa2, 0x98, 0x05, 0x14, 0x84, 0x14, 0x50, 0x30, 0xa4, 0xa0, 0x02, 0x8a, 0x04, 0x14, 0xb4, 0x0c, 0x4a, 0x5a, 0x04, 0x25, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0xc4, 0xa5, 0xa0, 0x42, 0x52, 0xd0, 0x31, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x09, 0xfa, 0xd2, 0xf7, 0xad, 0x87, 0x70, 0xdb, 0xf9, 0x52, 0x51, 0xab, 0x00, 0xa5, 0xa6, 0x3b, 0x09, 0x45, 0x40, 0x98, 0x51, 0xf5, 0xa6, 0x02, 0x51, 0x48, 0x42, 0xf5, 0xa2, 0x92, 0x01, 0x28, 0xa3, 0xa0, 0x82, 0x92, 0x90, 0xc2, 0x83, 0x43, 0x42, 0x0a, 0x4a, 0x43, 0x0a, 0x4a, 0x60, 0x14, 0xb4, 0x08, 0x29, 0x2a, 0x6e, 0x01, 0x45, 0x0c, 0x61, 0x45, 0x31, 0x05, 0x14, 0x80, 0x29, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x29, 0x80, 0x51, 0x48, 0x02, 0x92, 0x86, 0x01, 0x45, 0x17, 0x18, 0x52, 0xd0, 0x02, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x4a, 0x5a, 0x06, 0x25, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x20, 0xa2, 0x81, 0x93, 0xe2, 0x8a, 0xd6, 0x21, 0x71, 0x28, 0xaa, 0x60, 0x85, 0xcd, 0x15, 0x2c, 0x62, 0xd2, 0x66, 0x81, 0x58, 0x28, 0xa0, 0x02, 0x92, 0x90, 0x05, 0x14, 0x00, 0x52, 0x50, 0x01, 0x45, 0x20, 0x0a, 0x29, 0x00, 0x94, 0x55, 0x00, 0x51, 0x52, 0x01, 0x45, 0x00, 0x25, 0x2d, 0x48, 0x09, 0x45, 0x00, 0x14, 0x53, 0x00, 0xa2, 0x80, 0x0a, 0x4a, 0x40, 0x14, 0x53, 0x00, 0xa2, 0x80, 0x0a, 0x4a, 0x40, 0x14, 0x53, 0x00, 0xa2, 0x90, 0x05, 0x14, 0xc0, 0x28, 0xa4, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x0c, 0x41, 0x49, 0x40, 0xc2, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x04, 0x14, 0x50, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x27, 0xa3, 0x81, 0x5a, 0xa6, 0x02, 0x52, 0xd2, 0xb8, 0x0b, 0x45, 0x58, 0xc6, 0x9a, 0x5a, 0x42, 0x0a, 0x2a, 0x40, 0x29, 0x28, 0x00, 0xa2, 0x8d, 0x80, 0x28, 0xa4, 0x02, 0x51, 0x40, 0x05, 0x14, 0x84, 0x25, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x3a, 0x80, 0x51, 0x52, 0x02, 0x51, 0x4c, 0x02, 0x8a, 0x04, 0x14, 0x52, 0x01, 0x28, 0xa6, 0x30, 0xa2, 0x81, 0x0b, 0x49, 0x48, 0x62, 0x52, 0xd0, 0x20, 0xa2, 0x80, 0x12, 0x96, 0x81, 0x89, 0x45, 0x17, 0x00, 0xa2, 0x81, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x52, 0x50, 0x31, 0x69, 0x28, 0x00, 0xa5, 0xa0, 0x04, 0xa2, 0x81, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x02, 0x6a, 0x5e, 0xd5, 0xa8, 0xd8, 0x94, 0xb4, 0xd8, 0x82, 0x8f, 0xad, 0x03, 0x0a, 0x2a, 0x6e, 0x21, 0x29, 0x68, 0x01, 0x28, 0xa1, 0x80, 0xb4, 0xda, 0x40, 0x2d, 0x25, 0x00, 0x14, 0x52, 0x00, 0xc5, 0x14, 0x00, 0x94, 0x55, 0x00, 0x51, 0x52, 0x17, 0x0a, 0x28, 0x60, 0x25, 0x14, 0x80, 0x29, 0x69, 0x88, 0x4a, 0x29, 0x0c, 0x28, 0xa4, 0x21, 0x29, 0x69, 0x8c, 0x4a, 0x28, 0x00, 0xa2, 0x90, 0x84, 0xa5, 0xa6, 0x01, 0x45, 0x20, 0x12, 0x96, 0x80, 0x12, 0x8a, 0x06, 0x14, 0x50, 0x20, 0xa2, 0x98, 0x05, 0x14, 0x86, 0x25, 0x2d, 0x00, 0x14, 0x94, 0x00, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x04, 0xf4, 0x13, 0xcd, 0x5e, 0xec, 0x61, 0xde, 0x8a, 0xad, 0x04, 0xc5, 0xa2, 0x9a, 0x01, 0x28, 0xe6, 0x98, 0x05, 0x15, 0x20, 0x26, 0x28, 0xa4, 0x01, 0x45, 0x4e, 0x80, 0x14, 0x94, 0xc0, 0x28, 0xa0, 0x41, 0x49, 0x4a, 0xc3, 0x16, 0x92, 0x90, 0x05, 0x14, 0x72, 0x80, 0x51, 0x40, 0x84, 0xa2, 0x80, 0x0a, 0x29, 0x80, 0x52, 0x52, 0x18, 0xb4, 0x1a, 0x42, 0x12, 0x96, 0x81, 0x89, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x4a, 0x00, 0x28, 0xa0, 0x61, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x52, 0x50, 0x02, 0xd1, 0x40, 0x82, 0x92, 0x81, 0x8b, 0x49, 0x40, 0x82, 0x8a, 0x00, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x58, 0xa4, 0xed, 0x5a, 0x80, 0xbd, 0xe9, 0x29, 0xa0, 0x61, 0x45, 0x26, 0x09, 0x05, 0x1d, 0x29, 0x80, 0x51, 0x52, 0x02, 0x51, 0x40, 0x05, 0x25, 0x00, 0x2e, 0x68, 0xa4, 0x21, 0x29, 0x69, 0x0c, 0x4a, 0x4a, 0x2e, 0x80, 0x5a, 0x29, 0x08, 0x4a, 0x28, 0x18, 0x51, 0x40, 0x09, 0x45, 0x30, 0x0a, 0x29, 0x00, 0x51, 0x40, 0x82, 0x92, 0x90, 0xc2, 0x96, 0x98, 0x84, 0xa2, 0x86, 0x01, 0x45, 0x03, 0x0a, 0x29, 0x00, 0x94, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x85, 0x25, 0x00, 0x14, 0xb4, 0x00, 0x94, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x00, 0xa2, 0x81, 0x85, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x01, 0x35, 0x2d, 0x6b, 0xb8, 0x30, 0xa2, 0x9a, 0xd0, 0x02, 0x8a, 0x40, 0x1d, 0xe8, 0xa0, 0x02, 0x8a, 0x24, 0xae, 0x01, 0x49, 0x40, 0x05, 0x14, 0x98, 0x05, 0x21, 0xa3, 0x60, 0x0a, 0x2a, 0x1b, 0xd4, 0x41, 0x49, 0x48, 0x05, 0xa4, 0xa0, 0x02, 0x8a, 0x63, 0x0a, 0x28, 0x10, 0x94, 0x50, 0x30, 0xa2, 0x93, 0x10, 0x51, 0x40, 0xc2, 0x92, 0x81, 0x05, 0x14, 0xc0, 0x28, 0xa0, 0x02, 0x8a, 0x4c, 0x61, 0x45, 0x00, 0x14, 0x94, 0xc0, 0x28, 0xa0, 0x02, 0x8a, 0x42, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x25, 0x00, 0x2d, 0x25, 0x02, 0x0a, 0x5a, 0x06, 0x14, 0x94, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x22, 0x7a, 0x53, 0x5a, 0x49, 0x8c, 0x4a, 0x28, 0x40, 0x14, 0x55, 0x0c, 0x4a, 0x5a, 0x04, 0xc4, 0xa5, 0xa9, 0xe6, 0x18, 0x51, 0x52, 0x98, 0x84, 0xa2, 0x98, 0x05, 0x25, 0x20, 0x0e, 0xd4, 0x50, 0x84, 0x25, 0x2d, 0x00, 0x25, 0x14, 0x0c, 0x28, 0xa4, 0x20, 0xa4, 0xaa, 0x18, 0x51, 0x52, 0xc4, 0x14, 0x52, 0x00, 0xa4, 0xa6, 0x31, 0x69, 0x29, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x63, 0x0a, 0x28, 0x10, 0x94, 0xb4, 0x0c, 0x4a, 0x29, 0x00, 0x51, 0x40, 0x82, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x49, 0x40, 0x0b, 0x49, 0x40, 0x0b, 0x49, 0x40, 0x85, 0xa2, 0x81, 0x89, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x4c, 0x69, 0xdf, 0x85, 0x69, 0x60, 0xe8, 0x37, 0xa7, 0x4a, 0x3a, 0x55, 0x00, 0xb4, 0x51, 0x60, 0x0a, 0x2a, 0x6c, 0x01, 0x9a, 0x4a, 0x56, 0xb3, 0x00, 0xa3, 0xa5, 0x30, 0x0a, 0x29, 0x08, 0x29, 0x28, 0x00, 0xa2, 0x90, 0x05, 0x14, 0x86, 0x14, 0x94, 0xc0, 0x28, 0xa4, 0x02, 0x52, 0xd0, 0x02, 0x51, 0x4c, 0x42, 0x52, 0xd2, 0x00, 0xa2, 0x93, 0x04, 0x14, 0x94, 0xc6, 0x2d, 0x25, 0x21, 0x05, 0x14, 0x0c, 0x4a, 0x5a, 0x04, 0x25, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x00, 0x14, 0x50, 0x01, 0x49, 0x40, 0xc2, 0x8a, 0x00, 0x5a, 0x4a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x0a, 0x28, 0x10, 0x51, 0x40, 0x05, 0x14, 0x0c, 0x28, 0xa0, 0x02, 0x8a, 0x04, 0x14, 0x50, 0x30, 0xa2, 0x80, 0x27, 0xa2, 0xb5, 0x18, 0x94, 0xb4, 0x06, 0xe1, 0x4b, 0xda, 0x90, 0x31, 0x29, 0x7b, 0xd0, 0x21, 0x28, 0xa1, 0x80, 0x94, 0x52, 0xb0, 0x05, 0x14, 0xc0, 0x33, 0x49, 0x4b, 0xd0, 0x2c, 0x14, 0x52, 0x12, 0x0a, 0x4a, 0x06, 0x14, 0x52, 0x60, 0x14, 0x52, 0xb0, 0x05, 0x25, 0x16, 0x00, 0xa2, 0x98, 0x82, 0x8a, 0x40, 0x14, 0x50, 0x01, 0x49, 0x40, 0xc2, 0x8a, 0x04, 0x14, 0x50, 0x01, 0x45, 0x03, 0x12, 0x96, 0x80, 0x12, 0x8a, 0x04, 0x14, 0x50, 0x01, 0x45, 0x00, 0x14, 0x50, 0x30, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x12, 0x8a, 0x04, 0x2d, 0x25, 0x03, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x27, 0xa0, 0x55, 0x94, 0x06, 0x92, 0xa8, 0x42, 0xd1, 0x9a, 0x34, 0x00, 0xa2, 0x86, 0x84, 0x25, 0x2d, 0x17, 0x01, 0x28, 0xa4, 0x01, 0x49, 0x46, 0xc0, 0x14, 0x52, 0x00, 0xa2, 0x90, 0x09, 0x45, 0x48, 0x05, 0x15, 0x40, 0x14, 0x52, 0x00, 0xa4, 0xa3, 0x98, 0x41, 0x45, 0x3b, 0x80, 0x51, 0x9a, 0x40, 0x14, 0x52, 0x18, 0x94, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x51, 0x4c, 0x04, 0xa5, 0xa0, 0x02, 0x92, 0x90, 0x82, 0x8a, 0x00, 0x28, 0xa0, 0x61, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x52, 0x50, 0x20, 0xa5, 0xa0, 0x61, 0x49, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x4d, 0x4b, 0x5a, 0x80, 0x51, 0x46, 0xc0, 0x25, 0x2d, 0x49, 0x48, 0x28, 0xa6, 0x26, 0x25, 0x2d, 0x21, 0x09, 0x45, 0x3b, 0x80, 0x51, 0x50, 0xc0, 0x4a, 0x28, 0x00, 0xa2, 0x98, 0x09, 0x45, 0x3e, 0x82, 0x0a, 0x2a, 0x6c, 0x30, 0xa2, 0x98, 0x09, 0x45, 0x48, 0x82, 0x8a, 0x63, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x12, 0x96, 0x80, 0x12, 0x8a, 0x5d, 0x40, 0x28, 0xa6, 0x01, 0x49, 0x48, 0x05, 0xa4, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x41, 0x45, 0x03, 0x12, 0x96, 0x80, 0x0a, 0x28, 0x00, 0xa2, 0x80, 0x0a, 0x28, 0x01, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x28, 0xa0, 0x02, 0x8a, 0x00, 0x9f, 0x9a, 0x2b, 0x5b, 0x8f, 0x70, 0xa2, 0x8b, 0x00, 0x52, 0x50, 0x90, 0x82, 0x96, 0x95, 0x80, 0x43, 0xcd, 0x2d, 0x00, 0x25, 0x14, 0x80, 0x28, 0xa0, 0x04, 0xa2, 0x81, 0x05, 0x14, 0x86, 0x14, 0x50, 0x02, 0x51, 0x4c, 0x02, 0x8a, 0x86, 0x01, 0x49, 0x46, 0xc2, 0x0a, 0x29, 0x8c, 0x28, 0xa0, 0x02, 0x92, 0x98, 0x82, 0x8a, 0x06, 0x14, 0x54, 0x88, 0x28, 0xa6, 0x30, 0xa4, 0xa4, 0x21, 0x68, 0xa0, 0x62, 0x51, 0x40, 0x85, 0xa4, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x21, 0x29, 0x68, 0x18, 0x51, 0x40, 0x05, 0x14, 0x08, 0x29, 0x28, 0x18, 0xb4, 0x94, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x4c, 0x7d, 0xe9, 0x7d, 0xaa, 0xef, 0xd8, 0x02, 0x8a, 0xae, 0x80, 0x14, 0xb4, 0x7a, 0x00, 0x9d, 0xa9, 0x0d, 0x2b, 0x80, 0xb4, 0x50, 0x02, 0x51, 0xd2, 0x90, 0x05, 0x14, 0x80, 0x29, 0x2a, 0x80, 0x31, 0x45, 0x20, 0x0a, 0x29, 0x00, 0x94, 0x52, 0x60, 0x25, 0x28, 0xa4, 0x02, 0x52, 0x55, 0x5c, 0x05, 0xa2, 0x90, 0x05, 0x14, 0xc0, 0x28, 0xa4, 0x01, 0x49, 0x40, 0x05, 0x14, 0x84, 0x14, 0x50, 0x01, 0x45, 0x17, 0x18, 0x52, 0x50, 0x20, 0xa2, 0x81, 0x85, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x82, 0x92, 0x81, 0x85, 0x2d, 0x02, 0x12, 0x8a, 0x06, 0x14, 0x50, 0x01, 0x45, 0x02, 0x0a, 0x28, 0x18, 0x51, 0x40, 0x05, 0x14, 0x00, 0x51, 0x40, 0x05, 0x14, 0x08, 0x28, 0xa0, 0x61, 0x45, 0x00, 0x14, 0x50, 0x01, 0x45, 0x00, 0x7f, + // EOI 0xff, 0xd9}; // 21:15:35.200 > unexpected jpeg typecode 0xd8 // 21:15:35.203 > unexpected jpeg typecode 0xd8 @@ -50,18 +63,21 @@ void tearDown(void) // clean stuff up here } -void test_decode() +void test_jpg_decode() { - micro_rtsp_jpeg mr_jpeg; - TEST_ASSERT_TRUE(mr_jpeg.decode_jpeg(reinterpret_cast(jpeg), sizeof(jpeg))); + jpg mr_jpeg; + TEST_ASSERT_TRUE(mr_jpeg.decode(reinterpret_cast(jpeg), sizeof(jpeg))); TEST_ASSERT_EQUAL_INT32(sizeof(jpeg_data), mr_jpeg.jpeg_data_end - mr_jpeg.jpeg_data_start); - TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_data, mr_jpeg.jpeg_data_start, sizeof(jpeg_data)); + TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_data, mr_jpeg.jpeg_data_start, sizeof(jpeg_data)); - TEST_ASSERT_EQUAL_INT32(sizeof(jpeg_qtable0), mr_jpeg.quantization_table_0_->data_length()); - TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_qtable0, mr_jpeg.quantization_table_0_->data(), sizeof(jpeg_qtable0)); - - TEST_ASSERT_EQUAL_INT32(sizeof(jpeg_qtable1), mr_jpeg.quantization_table_1_->data_length()); - TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_qtable1, mr_jpeg.quantization_table_1_->data(), sizeof(jpeg_qtable1)); + // Id is not stored + TEST_ASSERT_EQUAL_INT32(sizeof(jpg_section_dqt::id) + sizeof(jpeg_qtable0), mr_jpeg.quantization_table_0_->data_length()); + auto jpg_section_dqt_luminance = reinterpret_cast(mr_jpeg.quantization_table_0_->data); + TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_qtable0, jpg_section_dqt_luminance->data, sizeof(jpeg_qtable0)); + // Id is not stored + TEST_ASSERT_EQUAL_INT32(sizeof(jpg_section_dqt::id) + sizeof(jpeg_qtable1), mr_jpeg.quantization_table_1_->data_length()); + auto jpg_section_dqt_chrominance = reinterpret_cast(mr_jpeg.quantization_table_1_->data); + TEST_ASSERT_EQUAL_UINT8_ARRAY(jpeg_qtable1, jpg_section_dqt_chrominance->data, sizeof(jpeg_qtable1)); } void setup() @@ -73,7 +89,7 @@ void setup() Serial.setDebugOutput(true); UNITY_BEGIN(); - RUN_TEST(test_decode); + RUN_TEST(test_jpg_decode); UNITY_END(); }