From 218b5101b4a1c4b078cdce97226051c242b9ddc0 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 16 Feb 2021 11:33:22 +0100 Subject: [PATCH] update sendmail --- lib/lib_div/lib_mail/.github/FUNDING.yml | 12 + lib/lib_div/lib_mail/.github/stale.yml | 17 + .../lib_mail}/LICENSE | 42 +- lib/lib_div/lib_mail/README.md | 258 + lib/lib_div/lib_mail/_config.yml | 1 + .../examples/Copy_Messages/Copy_Messsages.ino | 130 + .../Delete_Messages/Delete_Messsages.ino | 125 + .../Read_Email_Access_Token.ino | 370 + .../Read_Single_Email/Read_Single_Email.ino | 349 + .../Read_Single_Email_Loop.ino | 376 + .../examples/Search_Emails/Search_Emails.ino | 387 + .../Send_Access_Token/Send_Access_Token.ino | 200 + .../Send_Attachment_Blob.ino | 268 + .../examples/Send_Attachment_Blob/image.h | 1851 ++++ .../Send_Attachment_File.ino | 391 + .../Send_Embedded_Message.ino | 203 + .../Send_Enriched_Text/Send_Enriched_Text.ino | 187 + .../lib_mail/examples/Send_HTML/Send_HTML.ino | 189 + .../Send_Parallel_Attachment.ino | 227 + .../examples/Send_Parallel_Attachment/data.h | 1957 ++++ .../Send_RFC822_Attachment.ino | 252 + .../examples/Send_RFC822_Attachment/image.h | 1851 ++++ .../Send_Reuse_Session/Send_Reuse_Session.ino | 245 + .../lib_mail/examples/Send_Text/Send_Text.ino | 185 + .../Send_Text_Flowed/Send_Text_Flowed.ino | 197 + .../lib_mail/examples/Set_Flags/Set_Flags.ino | 363 + lib/lib_div/lib_mail/keywords.txt | 126 + lib/lib_div/lib_mail/library.json | 16 + lib/lib_div/lib_mail/library.properties | 9 + .../lib_mail/media/images/esp-mail-client.png | Bin 0 -> 13006 bytes .../lib_mail/media/images/esp-mail-client.svg | 48 + lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp | 8203 +++++++++++++++++ lib/lib_div/lib_mail/src/ESP_Mail_Client.h | 2582 ++++++ lib/lib_div/lib_mail/src/README.md | 1949 ++++ .../lib_mail/src/extras/ESPTimeHelper.cpp | 279 + .../lib_mail/src/extras/ESPTimeHelper.h | 191 + .../lib_mail/src/extras/ESP_Mail_Client_FS.h | 8 + lib/lib_div/lib_mail/src/extras/MIMEInfo.h | 65 + .../lib_mail/src/extras}/RFC2047.cpp | 27 +- .../lib_mail/src/extras}/RFC2047.h | 9 +- .../src/wcs/esp32/ESP_Mail_HTTPClient32.cpp | 247 + .../src/wcs/esp32/ESP_Mail_HTTPClient32.h | 179 + .../lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp | 553 ++ .../lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h} | 73 +- .../src/wcs/esp32/esp_mail_ssl_client32.cpp} | 246 +- .../src/wcs/esp32/esp_mail_ssl_client32.h | 105 + .../wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp | 1108 +++ .../src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h | 200 + .../wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp | 238 + .../wcs/esp8266/ESP_Mail_CertStoreBearSSL.h | 72 + .../src/wcs/esp8266/ESP_Mail_HTTPClient.cpp | 277 + .../src/wcs/esp8266/ESP_Mail_HTTPClient.h | 151 + .../lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp | 2119 +++++ .../lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h | 306 + lib/libesp32/ESP32-Mail-Client/README.md | 2138 ----- .../examples/Receive_email/Receive_email.ino | 278 - .../examples/Send_email/Send_email.ino | 180 - .../examples/Send_email/image.h | 1074 --- .../examples/Set_flag/Set_flag.ino | 70 - .../ESP32-Mail-Client/examples/Time/Time.ino | 136 - lib/libesp32/ESP32-Mail-Client/keywords.txt | 166 - lib/libesp32/ESP32-Mail-Client/library.json | 8 - .../ESP32-Mail-Client/library.properties | 9 - .../media/images/esp32-mail.jpg | Bin 10499 -> 0 bytes .../media/images/esp32-mail.png | Bin 12582 -> 0 bytes .../src/ESP32MailHTTPClient.cpp | 200 - .../src/ESP32MailHTTPClient.h | 107 - .../ESP32-Mail-Client/src/ESP32TimeHelper.cpp | 191 - .../ESP32-Mail-Client/src/ESP32TimeHelper.h | 73 - .../src/ESP32_MailClient.cpp | 4917 ---------- .../ESP32-Mail-Client/src/ESP32_MailClient.h | 1912 ---- .../src/WiFiClientSecureESP32.cpp | 397 - .../ESP32-Mail-Client/src/ssl_client32.h | 116 - tasmota/sendemail_ESP32.ino | 325 + tasmota/{sendemail.h => sendemail_ESP8266.h} | 14 - .../{sendemail.ino => sendemail_ESP8266.ino} | 417 +- 76 files changed, 30120 insertions(+), 12627 deletions(-) create mode 100755 lib/lib_div/lib_mail/.github/FUNDING.yml create mode 100755 lib/lib_div/lib_mail/.github/stale.yml rename lib/{libesp32/ESP32-Mail-Client => lib_div/lib_mail}/LICENSE (95%) create mode 100755 lib/lib_div/lib_mail/README.md create mode 100755 lib/lib_div/lib_mail/_config.yml create mode 100755 lib/lib_div/lib_mail/examples/Copy_Messages/Copy_Messsages.ino create mode 100755 lib/lib_div/lib_mail/examples/Delete_Messages/Delete_Messsages.ino create mode 100755 lib/lib_div/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino create mode 100755 lib/lib_div/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino create mode 100755 lib/lib_div/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino create mode 100755 lib/lib_div/lib_mail/examples/Search_Emails/Search_Emails.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Attachment_Blob/image.h create mode 100755 lib/lib_div/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_HTML/Send_HTML.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/data.h create mode 100755 lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/image.h create mode 100755 lib/lib_div/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Text/Send_Text.ino create mode 100755 lib/lib_div/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino create mode 100755 lib/lib_div/lib_mail/examples/Set_Flags/Set_Flags.ino create mode 100755 lib/lib_div/lib_mail/keywords.txt create mode 100755 lib/lib_div/lib_mail/library.json create mode 100755 lib/lib_div/lib_mail/library.properties create mode 100755 lib/lib_div/lib_mail/media/images/esp-mail-client.png create mode 100755 lib/lib_div/lib_mail/media/images/esp-mail-client.svg create mode 100755 lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp create mode 100755 lib/lib_div/lib_mail/src/ESP_Mail_Client.h create mode 100755 lib/lib_div/lib_mail/src/README.md create mode 100755 lib/lib_div/lib_mail/src/extras/ESPTimeHelper.cpp create mode 100755 lib/lib_div/lib_mail/src/extras/ESPTimeHelper.h create mode 100755 lib/lib_div/lib_mail/src/extras/ESP_Mail_Client_FS.h create mode 100755 lib/lib_div/lib_mail/src/extras/MIMEInfo.h rename lib/{libesp32/ESP32-Mail-Client/src => lib_div/lib_mail/src/extras}/RFC2047.cpp (86%) rename lib/{libesp32/ESP32-Mail-Client/src => lib_div/lib_mail/src/extras}/RFC2047.h (93%) create mode 100755 lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp create mode 100755 lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h create mode 100755 lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp rename lib/{libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h => lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h} (71%) rename lib/{libesp32/ESP32-Mail-Client/src/ssl_client32.cpp => lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp} (75%) create mode 100755 lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp create mode 100755 lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h delete mode 100755 lib/libesp32/ESP32-Mail-Client/README.md delete mode 100755 lib/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino delete mode 100755 lib/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino delete mode 100755 lib/libesp32/ESP32-Mail-Client/examples/Send_email/image.h delete mode 100755 lib/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino delete mode 100755 lib/libesp32/ESP32-Mail-Client/examples/Time/Time.ino delete mode 100755 lib/libesp32/ESP32-Mail-Client/keywords.txt delete mode 100644 lib/libesp32/ESP32-Mail-Client/library.json delete mode 100755 lib/libesp32/ESP32-Mail-Client/library.properties delete mode 100755 lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg delete mode 100755 lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp delete mode 100755 lib/libesp32/ESP32-Mail-Client/src/ssl_client32.h create mode 100644 tasmota/sendemail_ESP32.ino rename tasmota/{sendemail.h => sendemail_ESP8266.h} (76%) rename tasmota/{sendemail.ino => sendemail_ESP8266.ino} (55%) diff --git a/lib/lib_div/lib_mail/.github/FUNDING.yml b/lib/lib_div/lib_mail/.github/FUNDING.yml new file mode 100755 index 000000000..be11a746d --- /dev/null +++ b/lib/lib_div/lib_mail/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ["https://www.paypal.me/mobizt"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/lib/lib_div/lib_mail/.github/stale.yml b/lib/lib_div/lib_mail/.github/stale.yml new file mode 100755 index 000000000..cbcef3e96 --- /dev/null +++ b/lib/lib_div/lib_mail/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 20 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 5 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/lib/libesp32/ESP32-Mail-Client/LICENSE b/lib/lib_div/lib_mail/LICENSE similarity index 95% rename from lib/libesp32/ESP32-Mail-Client/LICENSE rename to lib/lib_div/lib_mail/LICENSE index 2b2f9d774..80d1893d3 100755 --- a/lib/libesp32/ESP32-Mail-Client/LICENSE +++ b/lib/lib_div/lib_mail/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2019 mobizt - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 mobizt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/lib_div/lib_mail/README.md b/lib/lib_div/lib_mail/README.md new file mode 100755 index 000000000..87ba8e72d --- /dev/null +++ b/lib/lib_div/lib_mail/README.md @@ -0,0 +1,258 @@ +# Mail Client Arduino Library for ESP32 and ESP8266 v 1.0.13 + +[![Join the chat at https://gitter.im/mobizt/ESP_Mail_Client](https://badges.gitter.im/mobizt/ESP_Mail_Client.svg)](https://gitter.im/mobizt/ESP_Mail_Client?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +The complete and secure Mail Client for ESP32 and ESP8266 devices for sending and reading the Email through the SMTP and IMAP servers. + +With this library, the devices can both send and read the Email with many types of attachments supported and provides more reliable and flexibilities of usages. + +The library was tested and work well with ESP32s and ESP8266s based modules. + +This library was developed to replace the deprecated ESP32 Mail Client library with more options and features, better reliability and also conforms to the RFC standards. + +![ESP32 Mail](/media/images/esp-mail-client.svg) + +Copyright (c) 2021 K. Suwatchai (Mobizt). + +# Features + +* Support Espressif ESP32 and ESP8266 MCUs based devices. +* Support TCP session reusage. +* Support PLAIN, LOGIN and XOAUTH2 authentication mechanisms. +* Secured connection with SSL and TLS. +* Support mailbox selection for Email reading and searching. +* Support the content encodings e.g. quoted-printable and base64. +* Support the content decodings e.g. base64, UTF-8, UTF-7, quoted-printable, ISO-8859-1 (latin1) and ISO-8859-11 (Thai). +* Support many types of embedded contents e.g. inline images, attachments, parallel media attachments and RFC822 message. +* Support full debuging. +* Support SPIFFS and SD card for file storages. +* Support Ethernet (ESP32). +* Customizable operating configurations (see the examples for the usages) + +## Tested Devices + +This following devices were tested. + + * Sparkfun ESP32 Thing + * NodeMCU-32 + * WEMOS LOLIN32 + * TTGO T8 V1.8 + * M5Stack ESP32 + * NodeMCU ESP8266 + * Wemos D1 Mini (ESP8266) + + + +## Prerequisites + + +The library requires Arduino's ESP32 or ESP8266 Core SDK to be installed based on the platform. + +The latest Core SDK is recommended. For ESP8266, the Core SDK version 2.6.3 or later is recommended. + +The ESP8266 Core SDK version 2.5.x and earlier are not supported. + + + +## Instalation + + +Click on **Clone or download** dropdown at the top of repository, select **Download ZIP** and save file on your computer. + +From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP-Mail-Client-master.zip** that previously downloaded. + +Go to menu **Files** -> **Examples** -> **ESP-Mail-Client-master** and choose one from examples + + + +## Usage + + +See [Full Examples](/examples) for complete usages. + +See [Function Description](/src/README.md) for all available functions. + + +The following examples showed the minimum usage which many options are not configured. + +The examples in the examples folder provide the full options usages. + + +### Send the Email + + +```C++ + +// Include ESP Mail Client library (this library) +#include + + +// Define the SMTP Session object which used for SMTP transsport +SMTPSession smtp; + +// Define the session config data which used to store the TCP session configuration +ESP_Mail_Session session; + +// Set the session config +session.server.host_name = "smtp.office365.com"; //for outlook.com +session.server.port = 587; +session.login.email = "your Email address"; //set to empty for no SMTP Authentication +session.login.password = "your Email password"; //set to empty for no SMTP Authentication +session.login.user_domain = "client domain or ip e.g. mydomain.com"; + +// Define the SMTP_Message class variable to handle to message being transport +SMTP_Message message; + +// Set the message headers +message.sender.name = "My Mail"; +message.sender.email = "sender or your Email address"; +message.subject = "Test sending Email"; +message.addRecipient("name1", "email1"); +message.addRecipient("name2", "email2"); + +message.addCc("email3"); +message.addBcc("email4"); + +// Set the message content +message.text.content = "This is simple plain text message"; + +//Base64 data of image +const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; + +// Define the attachment data +SMTP_Attachment att; + +// Set the attatchment info +att.descr.filename = "green.png"; +att.descr.mime = "image/png"; +att.blob.data = (uint8_t *)greenImg; +att.blob.size = strlen(greenImg); +// Set the transfer encoding to base64 +att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; +// We set the content encoding to match the above greenImage data +att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; + +// Add attachment to the message +message.addAttachment(att); + +// Connect to server with the session config +smtp.connect(&session); + +// Start sending Email and close the session +if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); + + +``` + + +### Read the Email + + +```C++ + +// Include ESP Mail Client library (this library) +#include + + +// Define the IMAP Session object which used for IMAP transsport +IMAP_Config config; + + +// Define the session config data which used to store the TCP session configuration +ESP_Mail_Session session; + +// Set the session config +session.server.host_name = "outlook.office365.com"; //for outlook.com +session.server.port = 993; +session.login.email = "your Email address"; +session.login.password = "your Email password"; + +// Define the config class variable for searching or fetching operation and store the messsagess data +IMAP_Config config; + +// Define the message UID which required to fetch or read the message +config.fetch.uid = "100"; + +// Define the empty search criteria to disable the messsage search +config.search.criteria = ""; + +// Set to enable the message content which will be stored in the IMAP_Config data +config.enable.html = true; +config.enable.text = true; + + +// Connect to the server with the defined session and options +imap.connect(&session, &config); + +// Open or select the mailbox folder to read the message +imap.selectFolder("INBOX"); + + +// Read the Email and close the session +MailClient.readMail(&imap); + + +// Get the message(s) list +IMAP_MSG_List msgList = imap.data(); + +for (size_t i = 0; i < msgList.msgItems.size(); i++) +{ + // Iterate to get each message data through the message item data + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + // If the message body is available + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + } +} + +``` + + + +## License + +The MIT License (MIT) + +Copyright (c) 2021 K. Suwatchai (Mobizt) + + +Permission is hereby granted, free of charge, to any person returning a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/lib_div/lib_mail/_config.yml b/lib/lib_div/lib_mail/_config.yml new file mode 100755 index 000000000..c4192631f --- /dev/null +++ b/lib/lib_div/lib_mail/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/lib/lib_div/lib_mail/examples/Copy_Messages/Copy_Messsages.ino b/lib/lib_div/lib_mail/examples/Copy_Messages/Copy_Messsages.ino new file mode 100755 index 000000000..769443230 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Copy_Messages/Copy_Messsages.ino @@ -0,0 +1,130 @@ +/** + * This example showed how to copy messages from the opened mailbox folder to other folder. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* Define the MessageList class to add the message to copy */ + MessageList toCopy; + + /* Add message uid to copy to the list */ + toCopy.add(3); + toCopy.add(4); + + //imap.createFolder("test"); + + /* Copy all messages in the list to the folder "test" */ + if (imap.deleteMessages(&toCopy, "test")) + Serial.println("Messages copied"); + + /* Delete all messages in the list from the opened folder (move to trash) */ + //imap.deleteMessages(&toCopy); + + //imap.deleteolder("test"); +} + +void loop() +{ + +} diff --git a/lib/lib_div/lib_mail/examples/Delete_Messages/Delete_Messsages.ino b/lib/lib_div/lib_mail/examples/Delete_Messages/Delete_Messsages.ino new file mode 100755 index 000000000..ae65b188d --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Delete_Messages/Delete_Messsages.ino @@ -0,0 +1,125 @@ +/** + * This example showed how to delete messages from the opened mailbox folder. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* Define the MessageList class to add the message to delete */ + MessageList toDelete; + /* Add message uid to delete to the list */ + toDelete.add(10); + toDelete.add(12); + + /* Delete all messages in the list (move to trash) */ + if(imap.deleteMessages(&toDelete)) + Serial.println("Messages deeted"); + + /* Delete all messages permanently by assign the second param to true*/ + //imap.deleteMessages(&toDelete, true); +} + +void loop() +{ + +} diff --git a/lib/lib_div/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino b/lib/lib_div/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino new file mode 100755 index 000000000..ae9d7cc39 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino @@ -0,0 +1,370 @@ +/** + * This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The user Email for OAuth2.0 access token */ +#define AUTHOR_EMAIL "################" + +/** The OAuth2.0 access token + * The generation, exchange and refresh of the access token are not available + * in this library. + * + * To test this using GMail, get the OAuth2.0 access token from this web site + * https://developers.google.com/oauthplayground/ + * + * 1. Select the following scope (in Step 1) from Gmail API V1 + * https://mail.google.com/ + * https://mail.google.com/ + * + * 2. Click Authorize APIs button. + * 3. Cick Exchangeauthorization code for tokens. + * 4. From the response, look at access_token from the JSON payload node. + * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. + * + * The token will be expired in 3600 seconds (1 Hr). + * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. +*/ +#define AUTHOR_ACCESS_TOKEN "################" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* Print all messages from the message list */ +void printMessages(IMAPSession &imap); + +/* Print all rfc822 messages included in the message */ +void printRFC822Messages(IMAP_MSG_Item &msg); + +/* Print all attachments info from the message */ +void printAttacements(IMAP_MSG_Item &msg); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.accessToken = AUTHOR_ACCESS_TOKEN; + + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Message UID to fetch or read e.g. 100 */ + config.fetch.uid = "100"; + + /* Set seen flag*/ + //config.fetch.set_seen = true; + + /* Search criteria */ + config.search.criteria = ""; + + /* Also search the unseen message */ + config.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + config.storage.saved_path = "/email_data"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + config.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download heades, text and html messaeges, + * attachments and inline images respectively. + */ + config.download.header = true; + config.download.text = true; + config.download.html = true; + config.download.attachment = true; + config.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option config.limit.msg_size. + * The whole message can be download through config.download.text + * or config.download.html which not depends on these enable options. + */ + config.enable.html = true; + config.enable.text = true; + + /* Set to enable the sort the result by message UID in the ascending order */ + config.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + config.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + config.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + config.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + config.limit.attachment_size = 1024 * 1024 * 5; + + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* {Optional] */ + printSelectedMailboxInfo(imap); + + /* Read or search the Email and close the session */ + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ + +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + printMessages(imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + Serial.printf("Free Heap: %d", ESP.getFreeHeap()); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + /* Show the mailbox info */ + Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); +} + +void printRFC822Messages(IMAP_MSG_Item &msg) +{ + Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + for (size_t j = 0; j < msg.rfc822.size(); j++) + { + IMAP_MSG_Item rfc822 = msg.rfc822[j]; + Serial.printf("%d. \n", j + 1); + Serial.printf("Messsage ID: %s\n", rfc822.messageID); + Serial.printf("From: %s\n", rfc822.from); + Serial.printf("Sender: %s\n", rfc822.sender); + Serial.printf("To: %s\n", rfc822.to); + Serial.printf("CC: %s\n", rfc822.cc); + Serial.printf("Subject: %s\n", rfc822.subject); + Serial.printf("Date: %s\n", rfc822.date); + Serial.printf("Reply-To: %s\n", rfc822.reply_to); + Serial.printf("Return-Path: %s\n", rfc822.return_path); + Serial.printf("Comment: %s\n", rfc822.comment); + Serial.printf("Keyword: %s\n", rfc822.keyword); + Serial.printf("Text Message: %s\n", rfc822.text.content); + Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", rfc822.html.content); + Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); + + if (rfc822.attachments.size() > 0) + printAttacements(rfc822); + } +} + +void printAttacements(IMAP_MSG_Item &msg) +{ + Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); + for (size_t j = 0; j < msg.attachments.size(); j++) + { + IMAP_Attach_Item att = msg.attachments[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); + } + Serial.println(); +} + +void printMessages(IMAPSession &imap) +{ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + for (size_t i = 0; i < msgList.msgItems.size(); i++) + { + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + /* If the result contains the message info (Fetch mode) */ + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.attachments.size() > 0) + printAttacements(msg); + + if (msg.rfc822.size() > 0) + printRFC822Messages(msg); + } + + Serial.println(); + } +} diff --git a/lib/lib_div/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino b/lib/lib_div/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino new file mode 100755 index 000000000..c03babfe8 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino @@ -0,0 +1,349 @@ +/** + * This example will fetch or read the Email which the known message UID + * was used for fetching. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* Print all messages from the message list */ +void printMessages(IMAPSession &imap); + +/* Print all rfc822 messages included in the message */ +void printRFC822Messages(IMAP_MSG_Item &msg); + +/* Print all attachments info from the message */ +void printAttacements(IMAP_MSG_Item &msg); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Message UID to fetch or read e.g. 100 */ + config.fetch.uid = "100"; + + /* Set seen flag */ + //config.fetch.set_seen = true; + + /* Search criteria */ + config.search.criteria = ""; + + /* Also search the unseen message */ + config.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + config.storage.saved_path = "/email_data"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + config.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download heades, text and html messaeges, + * attachments and inline images respectively. + */ + config.download.header = true; + config.download.text = true; + config.download.html = true; + config.download.attachment = true; + config.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option config.limit.msg_size. + * The whole message can be download through config.download.text + * or config.download.html which not depends on these enable options. + */ + config.enable.html = true; + config.enable.text = true; + + /* Set to enable the sort the result by message UID in the ascending order */ + config.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + config.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + config.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + config.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + config.limit.attachment_size = 1024 * 1024 * 5; + + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* {Optional] */ + printSelectedMailboxInfo(imap); + + /* Read or search the Email and close the session */ + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ + +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + printMessages(imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + Serial.printf("Free Heap: %d", ESP.getFreeHeap()); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + /* Show the mailbox info */ + Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); +} + +void printRFC822Messages(IMAP_MSG_Item &msg) +{ + Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + for (size_t j = 0; j < msg.rfc822.size(); j++) + { + IMAP_MSG_Item rfc822 = msg.rfc822[j]; + Serial.printf("%d. \n", j + 1); + Serial.printf("Messsage ID: %s\n", rfc822.messageID); + Serial.printf("From: %s\n", rfc822.from); + Serial.printf("Sender: %s\n", rfc822.sender); + Serial.printf("To: %s\n", rfc822.to); + Serial.printf("CC: %s\n", rfc822.cc); + Serial.printf("Subject: %s\n", rfc822.subject); + Serial.printf("Date: %s\n", rfc822.date); + Serial.printf("Reply-To: %s\n", rfc822.reply_to); + Serial.printf("Return-Path: %s\n", rfc822.return_path); + Serial.printf("Comment: %s\n", rfc822.comment); + Serial.printf("Keyword: %s\n", rfc822.keyword); + Serial.printf("Text Message: %s\n", rfc822.text.content); + Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", rfc822.html.content); + Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); + + if (rfc822.attachments.size() > 0) + printAttacements(rfc822); + } +} + +void printAttacements(IMAP_MSG_Item &msg) +{ + Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); + for (size_t j = 0; j < msg.attachments.size(); j++) + { + IMAP_Attach_Item att = msg.attachments[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); + } + Serial.println(); +} + +void printMessages(IMAPSession &imap) +{ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + for (size_t i = 0; i < msgList.msgItems.size(); i++) + { + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + /* If the result contains the message info (Fetch mode) */ + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.attachments.size() > 0) + printAttacements(msg); + + if (msg.rfc822.size() > 0) + printRFC822Messages(msg); + } + + Serial.println(); + } +} diff --git a/lib/lib_div/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino b/lib/lib_div/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino new file mode 100755 index 000000000..c3452e7bc --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino @@ -0,0 +1,376 @@ +/** + * This example will repeatedly fetch or read the Email via the loop function + * using the predict next message UID as the starting count down message UID. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* Print all messages from the message list */ +void printMessages(IMAPSession &imap); + +/* Print all rfc822 messages included in the message */ +void printRFC822Messages(IMAP_MSG_Item &msg); + +/* Print all attachments info from the message */ +void printAttacements(IMAP_MSG_Item &msg); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + +unsigned long readMillis = 0; + +int nextMsgUID = 0; +int msgUID = 0; +int sign = -1; + +/* Declare the session config data */ +ESP_Mail_Session session; + +/* Setup the configuration for searching or fetching operation and its result */ +IMAP_Config config; + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + + /* Message UID to fetch or read */ + config.fetch.uid = ""; + + /* Search criteria */ + config.search.criteria = ""; + + /* Also search the unseen message */ + config.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + config.storage.saved_path = "/email_data"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + config.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download heades, text and html messaeges, + * attachments and inline images respectively. + */ + config.download.header = false; + config.download.text = false; + config.download.html = false; + config.download.attachment = false; + config.download.inlineImg = false; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option config.limit.msg_size. + * The whole message can be download through config.download.text + * or config.download.html which not depends on these enable options. + */ + config.enable.html = true; + config.enable.text = true; + + /* Set to enable the sort the result by message UID in the ascending order */ + config.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + config.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + config.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + config.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + config.limit.attachment_size = 1024 * 1024 * 5; + + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* {Optional] */ + printSelectedMailboxInfo(imap); +} + +void loop() +{ + if (millis() - readMillis > 10000 || readMillis == 0) + { + readMillis = millis(); + + if (msgUID == 0) + sign = 1; + else if (msgUID >= nextMsgUID) + sign = -1; + + msgUID += sign; + + String uid = String(msgUID); + + /* Message UID to fetch or read */ + config.fetch.uid = uid.c_str(); + + /* Set seen flag */ + //config.fetch.set_seen = true; + + /** Read or search the Email and keep the TCP session to open + * The second parameter is for close the session. + */ + MailClient.readMail(&imap, false); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + printMessages(imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + Serial.printf("Free Heap: %d", ESP.getFreeHeap()); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + nextMsgUID = sFolder.nextUID(); + msgUID = nextMsgUID; + + /* Show the mailbox info */ + Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); +} + +void printRFC822Messages(IMAP_MSG_Item &msg) +{ + Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + for (size_t j = 0; j < msg.rfc822.size(); j++) + { + IMAP_MSG_Item rfc822 = msg.rfc822[j]; + Serial.printf("%d. \n", j + 1); + Serial.printf("Messsage ID: %s\n", rfc822.messageID); + Serial.printf("From: %s\n", rfc822.from); + Serial.printf("Sender: %s\n", rfc822.sender); + Serial.printf("To: %s\n", rfc822.to); + Serial.printf("CC: %s\n", rfc822.cc); + Serial.printf("Subject: %s\n", rfc822.subject); + Serial.printf("Date: %s\n", rfc822.date); + Serial.printf("Reply-To: %s\n", rfc822.reply_to); + Serial.printf("Return-Path: %s\n", rfc822.return_path); + Serial.printf("Comment: %s\n", rfc822.comment); + Serial.printf("Keyword: %s\n", rfc822.keyword); + Serial.printf("Text Message: %s\n", rfc822.text.content); + Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", rfc822.html.content); + Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); + + if (rfc822.attachments.size() > 0) + printAttacements(rfc822); + } +} + +void printAttacements(IMAP_MSG_Item &msg) +{ + Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); + for (size_t j = 0; j < msg.attachments.size(); j++) + { + IMAP_Attach_Item att = msg.attachments[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); + } + Serial.println(); +} + +void printMessages(IMAPSession &imap) +{ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + for (size_t i = 0; i < msgList.msgItems.size(); i++) + { + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + /* If the result contains the message info (Fetch mode) */ + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.attachments.size() > 0) + printAttacements(msg); + + if (msg.rfc822.size() > 0) + printRFC822Messages(msg); + } + + Serial.println(); + } +} diff --git a/lib/lib_div/lib_mail/examples/Search_Emails/Search_Emails.ino b/lib/lib_div/lib_mail/examples/Search_Emails/Search_Emails.ino new file mode 100755 index 000000000..5840441bd --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Search_Emails/Search_Emails.ino @@ -0,0 +1,387 @@ +/** + * This example will search all Emails in the opened mailbox folder. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* Print all messages from the message list */ +void printMessages(IMAPSession &imap); + +/* Print all rfc822 messages included in the message */ +void printRFC822Messages(IMAP_MSG_Item &msg); + +/* Print all attachments info from the message */ +void printAttacements(IMAP_MSG_Item &msg); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Message UID to fetch or read */ + config.fetch.uid = ""; + + /** Search criteria + * + * A search key can also be a parenthesized list of one or more search keys + * (e.g., for use with the OR and NOT keys). + * + * Since IMAP protocol uses Polish notation, the search criteria which in the polish notation form can be. + * + * To search the message from "someone@email.com" with the subject "my subject" since 1 Jan 2021, your search criteria can be + * UID SEARCH (OR SUBJECT "my subject" FROM "someone@email.com") SINCE "Fri, 1 Jan 2021 21:52:25 -0800" + * + * To search the message from "mail1@domain.com" or from "mail2@domain.com", the search criteria will be + * UID SEARCH OR FROM mail1@domain.com FROM mail2@domain.com + * + * For more details on using parentheses, AND, OR and NOT search keys in search criteria. + * https://www.limilabs.com/blog/imap-search-requires-parentheses + * + * + */ + config.search.criteria = "UID SEARCH ALL"; + + /* Also search the unseen message */ + config.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + config.storage.saved_path = "/email_data"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + config.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download heades, text and html messaeges, + * attachments and inline images respectively. + */ + config.download.header = true; + config.download.text = true; + config.download.html = true; + config.download.attachment = true; + config.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option config.limit.msg_size. + * The whole message can be download through config.download.text + * or config.download.html which not depends on these enable options. + */ + config.enable.html = true; + config.enable.text = true; + + /* Set to enable the sort the result by message UID in the ascending order */ + config.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + config.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + config.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + config.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + config.limit.attachment_size = 1024 * 1024 * 5; + + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* {Optional] */ + printSelectedMailboxInfo(imap); + + /** Read or search the Email and keep the TCP session to open + * The second parameter is for close the session. + */ + MailClient.readMail(&imap, false); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + /** Open or select other mailbox folder + * The folder that previousely opened will be closed + */ + if (imap.selectFolder("Junk")) + { + /* {Optional] */ + printSelectedMailboxInfo(imap); + + /* Config to search all messages in the opened mailboax (Search mode) */ + config.search.criteria = "UID SEARCH ALL"; + + /* No message UID provide for fetching */ + config.fetch.uid = ""; + + /* Search the Email and close the session */ + MailClient.readMail(&imap); + } + + /* Close the seeion in case the session is still open */ + imap.closeSession(); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + printMessages(imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + /* Show the mailbox info */ + Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); +} + +void printRFC822Messages(IMAP_MSG_Item &msg) +{ + Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + for (size_t j = 0; j < msg.rfc822.size(); j++) + { + IMAP_MSG_Item rfc822 = msg.rfc822[j]; + Serial.printf("%d. \n", j + 1); + Serial.printf("Messsage ID: %s\n", rfc822.messageID); + Serial.printf("From: %s\n", rfc822.from); + Serial.printf("Sender: %s\n", rfc822.sender); + Serial.printf("To: %s\n", rfc822.to); + Serial.printf("CC: %s\n", rfc822.cc); + Serial.printf("Subject: %s\n", rfc822.subject); + Serial.printf("Date: %s\n", rfc822.date); + Serial.printf("Reply-To: %s\n", rfc822.reply_to); + Serial.printf("Return-Path: %s\n", rfc822.return_path); + Serial.printf("Comment: %s\n", rfc822.comment); + Serial.printf("Keyword: %s\n", rfc822.keyword); + Serial.printf("Text Message: %s\n", rfc822.text.content); + Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", rfc822.html.content); + Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); + + if (rfc822.attachments.size() > 0) + printAttacements(rfc822); + } +} + +void printAttacements(IMAP_MSG_Item &msg) +{ + Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); + for (size_t j = 0; j < msg.attachments.size(); j++) + { + IMAP_Attach_Item att = msg.attachments[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); + } + Serial.println(); +} + +void printMessages(IMAPSession &imap) +{ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + for (size_t i = 0; i < msgList.msgItems.size(); i++) + { + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + /* If the result contains the message info (Fetch mode) */ + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.attachments.size() > 0) + printAttacements(msg); + + if (msg.rfc822.size() > 0) + printRFC822Messages(msg); + } + + Serial.println(); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino b/lib/lib_div/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino new file mode 100755 index 000000000..5a2cbe41b --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino @@ -0,0 +1,200 @@ + + +/** + *This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + + +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The user Email for OAuth2.0 access token */ +#define AUTHOR_EMAIL "################" + +/** The OAuth2.0 access token + * The generation, exchange and refresh of the access token are not available + * in this library. + * + * To test this using GMail, get the OAuth2.0 access token from this web site + * https://developers.google.com/oauthplayground/ + * + * 1. Select the following scope (in Step 1) from Gmail API V1 + * https://mail.google.com/ + * https://mail.google.com/ + * + * 2. Click Authorize APIs button. + * 3. Cick Exchangeauthorization code for tokens. + * 4. From the response, look at access_token from the JSON payload node. + * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. + * + * The token will be expired in 3600 seconds (1 Hr). + * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. +*/ +#define AUTHOR_ACCESS_TOKEN "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.accessToken = AUTHOR_ACCESS_TOKEN; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending Email using Access token"; + message.addRecipient("Admin", "####@#####_dot_com"); + + message.text.content = "This is simple plain text message"; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino b/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino new file mode 100755 index 000000000..139c8c42c --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino @@ -0,0 +1,268 @@ + + +/** + * This example will send the Email with attachments and + * inline images stored in heap and flash memories. + * + * The html and text version messages will be sent. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +/* This is for attachment data */ +#include "image.h" + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + + message.subject = "Test sending Email with attachments and inline images"; + message.addRecipient("user1", "####@#####_dot_com"); + + message.html.content = "This message contains 3 inline images and 1 attachment file.

"; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "utf-8"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = "This message contains 3 inline images and 1 attachment file.\r\nThe inline images were not shown in the plain text message."; + message.text.charSet = "utf-8"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* The attachment data item */ + SMTP_Attachment att; + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size, + * transfer encoding (should be base64 for inline image) + */ + att.descr.filename = "firebase_logo.png"; + att.descr.mime = "image/png"; + att.blob.data = firebase_png; + att.blob.size = sizeof(firebase_png); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "tree.gif"; + att.descr.mime = "image/gif"; + att.blob.data = tree_gif; + att.blob.size = sizeof(tree_gif); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "bird.gif"; + att.descr.mime = "image/gif"; + att.blob.data = bird_gif; + att.blob.size = sizeof(bird_gif); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /* Prepare the attachment data (from ram) */ + uint8_t *a = new uint8_t[512]; + int j = 0; + + for (int i = 0; i < 512; i++) + { + a[i] = j; + j++; + if (j > 255) + j = 0; + } + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "test.dat"; + att.descr.mime = "application/octet-stream"; + att.blob.data = a; + att.blob.size = 512; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + /* Add attachment to the message */ + message.addAttachment(att); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/image.h b/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/image.h new file mode 100755 index 000000000..5ddd6829b --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Attachment_Blob/image.h @@ -0,0 +1,1851 @@ +#include + +static const uint8_t firebase_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, + 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, + 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, + 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, + 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, + 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, + 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, + 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, + 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, + 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, + 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, + 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, + 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, + 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, + 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, + 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, + 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, + 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, + 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, + 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, + 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, + 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, + 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, + 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, + 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, + 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, + 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, + 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, + 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, + 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, + 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, + 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, + 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, + 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, + 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, + 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, + 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, + 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, + 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, + 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, + 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, + 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, + 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, + 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, + 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, + 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, + 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, + 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, + 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, + 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, + 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, + 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, + 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, + 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, + 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, + 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, + 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, + 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, + 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, + 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, + 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, + 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, + 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, + 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, + 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, + 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, + 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, + 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, + 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, + 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, + 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, + 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, + 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, + 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, + 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, + 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, + 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, + 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, + 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, + 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, + 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, + 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, + 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, + 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, + 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, + 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, + 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, + 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, + 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, + 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, + 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, + 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, + 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, + 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, + 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, + 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, + 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, + 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, + 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, + 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, + 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, + 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, + 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, + 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, + 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, + 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, + 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, + 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, + 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, + 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, + 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, + 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, + 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, + 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, + 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, + 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, + 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, + 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, + 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, + 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, + 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, + 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, + 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, + 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, + 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, + 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, + 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, + 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, + 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, + 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, + 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, + 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, + 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, + 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, + 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, + 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, + 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, + 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, + 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, + 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, + 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, + 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, + 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, + 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, + 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, + 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, + 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, + 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, + 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, + 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, + 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, + 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, + 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, + 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, + 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, + 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, + 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, + 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, + 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, + 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, + 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, + 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, + 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, + 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, + 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, + 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, + 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, + 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, + 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, + 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, + 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, + 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, + 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, + 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, + 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, + 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, + 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, + 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, + 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, + 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, + 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, + 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, + 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, + 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, + 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, + 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, + 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, + 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, + 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, + 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, + 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, + 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, + 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, + 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, + 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, + 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, + 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, + 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, + 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, + 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, + 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, + 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, + 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, + 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, + 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, + 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, + 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, + 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, + 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, + 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, + 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, + 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, + 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, + 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, + 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, + 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, + 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, + 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, + 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, + 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, + 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, + 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, + 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, + 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, + 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, + 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, + 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, + 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, + 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, + 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, + 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, + 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, + 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, + 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, + 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, + 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, + 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, + 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, + 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, + 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, + 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, + 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, + 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, + 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, + 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, + 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, + 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, + 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, + 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, + 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, + 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, + 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, + 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, + 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, + 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, + 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, + 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, + 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, + 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, + 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, + 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, + 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, + 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, + 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, + 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, + 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, + 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, + 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, + 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, + 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, + 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, + 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, + 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, + 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, + 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, + 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, + 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, + 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, + 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, + 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, + 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, + 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, + 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, + 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, + 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, + 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, + 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, + 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, + 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, + 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, + 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, + 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, + 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, + 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, + 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, + 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, + 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, + 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, + 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, + 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, + 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, + 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, + 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, + 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, + 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, + 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, + 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, + 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, + 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, + 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, + 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, + 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, + 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, + 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, + 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, + 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, + 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, + 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, + 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, + 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, + 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, + 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, + 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, + 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, + 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, + 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, + 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, + 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, + 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, + 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, + 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, + 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, + 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, + 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, + 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, + 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, + 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, + 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, + 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, + 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, + 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, + 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, + 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, + 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, + 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, + 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, + 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, + 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, + 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, + 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, + 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, + 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, + 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, + 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, + 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, + 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, + 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, + 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, + 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, + 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, + 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, + 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, + 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, + 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, + 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, + 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, + 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, + 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, + 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, + 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, + 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, + 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, + 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, + 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, + 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, + 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, + 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, + 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, + 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, + 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, + 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, + 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, + 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, + 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, + 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, + 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, + 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, + 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, + 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, + 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, + 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, + 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, + 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, + 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, + 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, + 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, + 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, + 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, + 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, + 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, + 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, + 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, + 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, + 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, + 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, + 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, + 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, + 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, + 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, + 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, + 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, + 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, + 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, + 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, + 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, + 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, + 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, + 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, + 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, + 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, + 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, + 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, + 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, + 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, + 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, + 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, + 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, + 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, + 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, + 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, + 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, + 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, + 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, + 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, + 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, + 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, + 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, + 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, + 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, + 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, + 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, + 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, + 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, + 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, + 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, + 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, + 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, + 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, + 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, + 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, + 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, + 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, + 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, + 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, + 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, + 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, + 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, + 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, + 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, + 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, + 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, + 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, + 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, + 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, + 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, + 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, + 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, + 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, + 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, + 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, + 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, + 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, + 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, + 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, + 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, + 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, + 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, + 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, + 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, + 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, + 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, + 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, + 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, + 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, + 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, + 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, + 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, + 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, + 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, + 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, + 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, + 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, + 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, + 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, + 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, + 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, + 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, + 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, + 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, + 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, + 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, + 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, + 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, + 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, + 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, + 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, + 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, + 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, + 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, + 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, + 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, + 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, + 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, + 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, + 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, + 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, + 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, + 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, + 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, + 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, + 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, + 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, + 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, + 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, + 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, + 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, + 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, + 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, + 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, + 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, + 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, + 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, + 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, + 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, + 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, + 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, + 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, + 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, + 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, + 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, + 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, + 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, + 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, + 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, + 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, + 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, + 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, + 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, + 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, + 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, + 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, + 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, + 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, + 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, + 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, + 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, + 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, + 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, + 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, + 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, + 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, + 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, + 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, + 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, + 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, + 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, + 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, + 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, + 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, + 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, + 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, + 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, + 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, + 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, + 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, + 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, + 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, + 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, + 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, + 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, + 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, + 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, + 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, + 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, + 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, + 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, + 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, + 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, + 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, + 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, + 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, + 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, + 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, + 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, + 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, + 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, + 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, + 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, + 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, + 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, + 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, + 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, + 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, + 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, + 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, + 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, + 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, + 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, + 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, + 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, + 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, + 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, + 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, + 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, + 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, + 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, + 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, + 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, + 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, + 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, + 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, + 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, + 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, + 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, + 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, + 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, + 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, + 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, + 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, + 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, + 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, + 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, + 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, + 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, + 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, + 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, + 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, + 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, + 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, + 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, + 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, + 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, + 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, + 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, + 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, + 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, + 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, + 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, + 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, + 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, + 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, + 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, + 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, + 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, + 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, + 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, + 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, + 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, + 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, + 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, + 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, + 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, + 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, + 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, + 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, + 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, + 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, + 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, + 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, + 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, + 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, + 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, + 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, + 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, + 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, + 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, + 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, + 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, + 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, + 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, + 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, + 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, + 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, + 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, + 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, + 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, + 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, + 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, + 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, + 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, + 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, + 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, + 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, + 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, + 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, + 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, + 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, + 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, + 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, + 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, + 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, + 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, + 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, + 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, + 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, + 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, + 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, + 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, + 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, + 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, + 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, + 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, + 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, + 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, + 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, + 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, + 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, + 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, + 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, + 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, + 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, + 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, + 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, + 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, + 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, + 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, + 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, + 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, + 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, + 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, + 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, + 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, + 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, + 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, + 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, + 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, + 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, + 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, + 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, + 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, + 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, + 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, + 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, + 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, + 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, + 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, + 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, + 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, + 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, + 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, + 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, + 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, + 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, + 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, + 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, + 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, + 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, + 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, + 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, + 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, + 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, + 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, + 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, + 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, + 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, + 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, + 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, + 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, + 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, + 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, + 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, + 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, + 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, + 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, + 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, + 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, + 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, + 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, + 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, + 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, + 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, + 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, + 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, + 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, + 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, + 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, + 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, + 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, + 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, + 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, + 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, + 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, + 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, + 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, + 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, + 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, + 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, + 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, + 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, + 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, + 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, + 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, + 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, + 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, + 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, + 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, + 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, + 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, + 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, + 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, + 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, + 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, + 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, + 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, + 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, + 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, + 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, + 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, + 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, + 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, + 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, + 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, + 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, + 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, + 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, + 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, + 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, + 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, + 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, + 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, + 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, + 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, + 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, + 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, + 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, + 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, + 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, + 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, + 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, + 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, + 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, + 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, + 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, + 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, + 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, + 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, + 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, + 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, + 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, + 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, + 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, + 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, + 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, + 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, + 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, + 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, + 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, + 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, + 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, + 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, + 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, + 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, + 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, + 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, + 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, + 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, + 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, + 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, + 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, + 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, + 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, + 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, + 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, + 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, + 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, + 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, + 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, + 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, + 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, + 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, + 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, + 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, + 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, + 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, + 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, + 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, + 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, + 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, + 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, + 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, + 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, + 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, + 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, + 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, + 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, + 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, + 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, + 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, + 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, + 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, + 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, + 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, + 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, + 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, + 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, + 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, + 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, + 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, + 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, + 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, + 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, + 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, + 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, + 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, + 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, + 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, + 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, + 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, + 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, + 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, + 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, + 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, + 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, + 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, + 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, + 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, + 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, + 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, + 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, + 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, + 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, + 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, + 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, + 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, + 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, + 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, + 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, + 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, + 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, + 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, + 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, + 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, + 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, + 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, + 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, + 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, + 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, + 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, + 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, + 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, + 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, + 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, + 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, + 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, + 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, + 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, + 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, + 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, + 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, + 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, + 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, + 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, + 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, + 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, + 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, + 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, + 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, + 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, + 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, + 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, + 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, + 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, + 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, + 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, + 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, + 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, + 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, + 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, + 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, + 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, + 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, + 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, + 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, + 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, + 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, + 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, + 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, + 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, + 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, + 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, + 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, + 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, + 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, + 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, + 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, + 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, + 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, + 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, + 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, + 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, + 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, + 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, + 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, + 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, + 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, + 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, + 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, + 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, + 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, + 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, + 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, + 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, + 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, + 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, + 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, + 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, + 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, + 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, + 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, + 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, + 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, + 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, + 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, + 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, + 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, + 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, + 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, + 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, + 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, + 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, + 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, + 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, + 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, + 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, + 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, + 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, + 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, + 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, + 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, + 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, + 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, + 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, + 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, + 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, + 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, + 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, + 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, + 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, + 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, + 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, + 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, + 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, + 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, + 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, + 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, + 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, + 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, + 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, + 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, + 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, + 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, + 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, + 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, + 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, + 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, + 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, + 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, + 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, + 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, + 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, + 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, + 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, + 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, + 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, + 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, + 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, + 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, + 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, + 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, + 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, + 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, + 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, + 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, + 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, + 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, + 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, + 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, + 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, + 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, + 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, + 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, + 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, + 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, + 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, + 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, + 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, + 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, + 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, + 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, + 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, + 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, + 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, + 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, + 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, + 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, + 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, + 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, + 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, + 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, + 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, + 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, + 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, + 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, + 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, + 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, + 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, + 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, + 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, + 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, + 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, + 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, + 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, + 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, + 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, + 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, + 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, + 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, + 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, + 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, + 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, + 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, + 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, + 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, + 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, + 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, + 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, + 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, + 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, + 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, + 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; + +static const uint8_t tree_gif[] PROGMEM = { + + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, + 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, + 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, + 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, + 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, + 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, + 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, + 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, + 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, + 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, + 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, + 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, + 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, + 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, + 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, + 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, + 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, + 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, + 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, + 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, + 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, + 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, + 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, + 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, + 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, + 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, + 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, + 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, + 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, + 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, + 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, + 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, + 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, + 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, + 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, + 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, + 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, + 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, + 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, + 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, + 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, + 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, + 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, + 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, + 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, + 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, + 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, + 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, + 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, + 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, + 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, + 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, + 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, + 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, + 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, + 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, + 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, + 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, + 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, + 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, + 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, + 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, + 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, + 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, + 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, + 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, + 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, + 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, + 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, + 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, + 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, + 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, + 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, + 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, + 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, + 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, + 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, + 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, + 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, + 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, + 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, + 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, + 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, + 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, + 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, + 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, + 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, + 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, + 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, + 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, + 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, + 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, + 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, + 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, + 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, + 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, + 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, + 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, + 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, + 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, + 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, + 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, + 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, + 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, + 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, + 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, + 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, + 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, + 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, + 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, + 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, + 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, + 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, + 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, + 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, + 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, + 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, + 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, + 0x00, 0x3B + +}; + +static const uint8_t bird_gif[] PROGMEM = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, + 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, + 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, + 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, + 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, + 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, + 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, + 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, + 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, + 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, + 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, + 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, + 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, + 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, + 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, + 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, + 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, + 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, + 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, + 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, + 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, + 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, + 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, + 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, + 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, + 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, + 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, + 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, + 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, + 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, + 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, + 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, + 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, + 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, + 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, + 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, + 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, + 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, + 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, + 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, + 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, + 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, + 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, + 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, + 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, + 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, + 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, + 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, + 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, + 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, + 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, + 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, + 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, + 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, + 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, + 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, + 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, + 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, + 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, + 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, + 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, + 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, + 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, + 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, + 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, + 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, + 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, + 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, + 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, + 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, + 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, + 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, + 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, + 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, + 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, + 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, + 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, + 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, + 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, + 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, + 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, + 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, + 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, + 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, + 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, + 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, + 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, + 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, + 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, + 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, + 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, + 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, + 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, + 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, + 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, + 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, + 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, + 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, + 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, + 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, + 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, + 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, + 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, + 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, + 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, + 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, + 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, + 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, + 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, + 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, + 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, + 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, + 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, + 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, + 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, + 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, + 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, + 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, + 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, + 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, + 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, + 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, + 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, + 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, + 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, + 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, + 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, + 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, + 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, + 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, + 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, + 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, + 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, + 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, + 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, + 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, + 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, + 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, + 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, + 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, + 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, + 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, + 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, + 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, + 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, + 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, + 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, + 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, + 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, + 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, + 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, + 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, + 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, + 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, + 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, + 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, + 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, + 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, + 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, + 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, + 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, + 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, + 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, + 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, + 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, + 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, + 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, + 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, + 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, + 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, + 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, + 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, + 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, + 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, + 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, + 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, + 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, + 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, + 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, + 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, + 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, + 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, + 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, + 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, + 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, + 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, + 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, + 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, + 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, + 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, + 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, + 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, + 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, + 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, + 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, + 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, + 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, + 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, + 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, + 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, + 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, + 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, + 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, + 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, + 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, + 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, + 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, + 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, + 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, + 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, + 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, + 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, + 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, + 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, + 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, + 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, + 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, + 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, + 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, + 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, + 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, + 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, + 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x3B}; diff --git a/lib/lib_div/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino b/lib/lib_div/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino new file mode 100755 index 000000000..1977ca6e0 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino @@ -0,0 +1,391 @@ + + +/** + * This example will send the Email with attachments and + * inline images stored in flash and SD card. + * + * The html and text version messages will be sent. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + static uint8_t buf[512]; + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + Serial.println("Mounting SD Card..."); + +#if defined(ESP32) + if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8 +#elif defined(ESP8266) + if (SD.begin(15)) +#endif + { + + if (SD.exists("/orange.png")) + SD.remove("/orange.png"); + if (SD.exists("/bin1.dat")) + SD.remove("/bin1.dat"); + + Serial.println("Preparing SD file attachments..."); + + const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII="; + + File file = SD.open("/orange.png", FILE_WRITE); + file.print(orangeImg); + file.close(); + + file = SD.open("/bin1.dat", FILE_WRITE); + + buf[0] = 'H'; + buf[1] = 'E'; + buf[2] = 'A'; + buf[3] = 'D'; + file.write(buf, 4); + + size_t i; + + for (i = 0; i < 4; i++) + { + memset(buf, i + 1, 512); + file.write(buf, 512); + } + + buf[0] = 'T'; + buf[1] = 'A'; + buf[2] = 'I'; + buf[3] = 'L'; + file.write(buf, 4); + file.close(); + } + else + { + Serial.println("SD Card Monting Failed"); + } + + Serial.println("Mounting SPIFFS..."); + +#if defined(ESP32) + if (SPIFFS.begin(true)) +#elif defined(ESP8266) + if (SPIFFS.begin()) +#endif + { + //SPIFFS.format(); + + if (SPIFFS.exists("/green.png")) + SPIFFS.remove("/green.png"); + if (SPIFFS.exists("/bin2.dat")) + SPIFFS.remove("/bin2.dat"); + + Serial.println("Preparing SPIFFS attachments..."); + + const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; + +#if defined(ESP32) + File file = SPIFFS.open("/green.png", FILE_WRITE); +#elif defined(ESP8266) + File file = SPIFFS.open("/green.png", "w"); +#endif + + file.print(greenImg); + file.close(); + +#if defined(ESP32) + file = SPIFFS.open("/bin2.dat", FILE_WRITE); +#elif defined(ESP8266) + file = SPIFFS.open("/bin2.dat", "w"); +#endif + + buf[0] = 'H'; + buf[1] = 'E'; + buf[2] = 'L'; + buf[3] = 'L'; + buf[4] = 'O'; + file.write(buf, 5); + + size_t i; + for (i = 0; i < 4; i++) + { + memset(buf, i + 1, 512); + file.write(buf, 512); + } + + buf[0] = 'G'; + buf[1] = 'O'; + buf[2] = 'O'; + buf[3] = 'D'; + buf[4] = 'B'; + buf[5] = 'Y'; + buf[6] = 'E'; + file.write(buf, 7); + file.close(); + } + else + { + Serial.println("SPIFFS Monting Failed"); + } + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + + message.subject = "Test sending Email with attachments and inline images from SD card and Flash"; + message.addRecipient("user1", "####@#####_dot_com"); + + /** Two alternative content versions are sending in this example e.g. plain text and html */ + message.html.content = "This message contains 2 inline images and 2 attachment files.

"; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "utf-8"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = "This message contains 2 inline images and 2 attachment files.\r\nThe inline images were not shown in the plain text message."; + message.text.charSet = "utf-8"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* The attachment data item */ + SMTP_Attachment att; + + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att.descr.filename = "orange.png"; + att.descr.mime = "image/png"; + att.file.path = "/orange.png"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + att.file.storage_type = esp_mail_file_storage_type_sd; + + /* Need to be base64 transfer encoding for inline image */ + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The orange.png file is already base64 encoded file. + * Then set the content encoding to match the transfer encoding + * which no encoding was taken place prior to sending. + */ + att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "bin1.dat"; + att.descr.mime = "application/octet-stream"; //binary data + att.file.path = "/bin1.dat"; + att.file.storage_type = esp_mail_file_storage_type_sd; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add attachment to the message */ + message.addAttachment(att); + + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "green.png"; + att.descr.mime = "image/png"; + att.file.path = "/green.png"; + att.file.storage_type = esp_mail_file_storage_type_flash; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; + message.addInlineImage(att); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "bin2.dat"; + att.descr.mime = "application/octet-stream"; + att.file.path = "/bin2.dat"; + att.file.storage_type = esp_mail_file_storage_type_flash; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.addAttachment(att); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino b/lib/lib_div/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino new file mode 100755 index 000000000..99ba2f737 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino @@ -0,0 +1,203 @@ + + +/** + * This example will send the Email which the + * message html and text body will be embedded as + * attachment or inline content. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending message as embedded files"; + message.addRecipient("Admin", "####@#####_dot_com"); + + message.html.content = "This is html message"; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "utf-8"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + /* Enable to send this message body as file */ + message.html.embed.enable = true; + + /* The name of embedded file */ + message.html.embed.filename = "test.html"; + + /** The embedded type + * esp_mail_smtp_embed_message_type_attachment or 0 + * esp_mail_smtp_embed_message_type_inline or 1 + */ + message.html.embed.type = esp_mail_smtp_embed_message_type_attachment; + + + + message.text.content = "This is simple plain text message"; + message.text.charSet = "utf-8"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.text.embed.enable = true; + message.text.embed.filename = "test.txt"; + message.text.embed.type = esp_mail_smtp_embed_message_type_inline; + + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino b/lib/lib_div/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino new file mode 100755 index 000000000..bcdfcf6a4 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino @@ -0,0 +1,187 @@ + + +/** + * This example will send the Email in enriched text version. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending enriched text Email"; + message.addRecipient("Someone", "####@#####_dot_com"); + + message.text.content = "This is enriched as defined in RFC 1896\r\n\r\nIsn't it cool?"; + + message.text.content_type = "text/enriched"; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_HTML/Send_HTML.ino b/lib/lib_div/lib_mail/examples/Send_HTML/Send_HTML.ino new file mode 100755 index 000000000..1f8794690 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_HTML/Send_HTML.ino @@ -0,0 +1,189 @@ + + +/** + * This example will send the Email in + * the html version. + * + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending html Email"; + message.addRecipient("Admin", "####@#####_dot_com"); + + message.html.content = "

This is the html text message.

The message was sent via ESP device.

"; + + /** The html text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino b/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino new file mode 100755 index 000000000..491e14152 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino @@ -0,0 +1,227 @@ + + +/** + * This example will send the Email with media as parallen attachments + * e.g. audio and images and play or display them simultaneously on the Email client. + * + * This depends on the Mail client supports. + * + * The html and text version messages will be sent. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +/* This is for attachment data */ +#include "data.h" + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + + message.subject = "Test sending Email with parallel attachments"; + message.addRecipient("user1", "####@#####_dot_com"); + + message.html.content = "This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "utf-8"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = "This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."; + message.text.charSet = "us-ascii"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* The attachment data item */ + SMTP_Attachment att; + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att.descr.filename = "haun.png"; + att.descr.mime = "image/png"; + att.blob.data = shaun_png; + att.blob.size = sizeof(shaun_png); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.addParallelAttachment(att); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "mu_law.wav"; + att.descr.mime = "audio/basic"; + att.blob.data = mu_law_wave; + att.blob.size = sizeof(mu_law_wave); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + message.addParallelAttachment(att); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/data.h b/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/data.h new file mode 100755 index 000000000..c7a88aeab --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Parallel_Attachment/data.h @@ -0,0 +1,1957 @@ +#include + +static const uint8_t mu_law_wave[] PROGMEM = { +0x52, 0x49, 0x46, 0x46, 0x84, 0x5D, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, +0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, +0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5D, +0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5D, 0x00, 0x00, 0xFB, 0xFD, 0xFF, 0xFE, 0xFF, 0x7F, +0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7C, 0x7D, +0x7C, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7E, 0xFF, 0x7F, +0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7C, 0x7C, 0x7B, +0x7B, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x79, 0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7E, 0xFF, 0xFE, 0xFE, +0xFF, 0x7E, 0x7C, 0x7D, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x79, 0x78, 0x79, +0x7A, 0x79, 0x78, 0x78, 0x78, 0x77, 0x78, 0x78, 0x79, 0x79, 0x78, 0x77, 0x77, 0x78, 0x78, 0x79, +0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, +0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, +0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFB, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, +0xFF, 0xFF, 0xFE, 0x7E, 0x7D, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, +0x7B, 0x7A, 0x79, 0x79, 0x79, 0x77, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x79, +0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, +0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7A, 0x79, +0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, 0xFB, 0xFC, +0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, +0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, +0x7C, 0x7B, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7C, 0x79, 0x79, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7C, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFE, +0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, +0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x78, 0x78, 0x77, 0x77, 0x77, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, 0x72, 0x73, 0x73, +0x74, 0x74, 0x74, 0x75, 0x77, 0x78, 0x78, 0x77, 0x76, 0x77, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, +0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7E, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFD, 0xFE, 0x7F, 0xFF, +0x7F, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7D, 0x7F, +0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7D, +0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFC, 0xFC, 0xFD, +0xFC, 0xFB, 0xFB, 0xFC, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFE, +0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x79, +0x78, 0x78, 0x78, 0x76, 0x74, 0x74, 0x73, 0x72, 0x75, 0x77, 0x77, 0x76, 0x75, 0x75, 0x76, 0x77, +0x77, 0x76, 0x74, 0x74, 0x74, 0x74, 0x76, 0x76, 0x76, 0x77, 0x75, 0x76, 0x78, 0x79, 0x77, 0x77, +0x79, 0x7B, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFE, +0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7F, 0x7F, 0x7D, 0x7E, 0xFF, 0x7F, +0x7F, 0xFF, 0x7F, 0x7E, 0x7D, 0x7E, 0xFF, 0x7E, 0x7F, 0x7F, 0x7C, 0x7D, 0x7F, 0x7D, 0x7E, 0x7E, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x7D, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, +0x7D, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, +0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, +0x78, 0x79, 0x78, 0x75, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x73, 0x74, 0x73, 0x72, 0x73, +0x75, 0x75, 0x74, 0x76, 0x74, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x77, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7C, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, +0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, +0xFE, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0xFF, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7D, 0x7C, 0x7C, +0x7D, 0x7C, 0x7C, 0x7E, 0x7E, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, +0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFB, +0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0x7E, 0x7E, 0x7E, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7F, +0x7D, 0x7B, 0x7C, 0x7C, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7E, +0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x74, 0x73, +0x72, 0x73, 0x74, 0x75, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x79, 0x79, +0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, +0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, +0x7D, 0x7E, 0xFF, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, +0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7C, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x78, +0x78, 0x77, 0x77, 0x76, 0x75, 0x74, 0x74, 0x74, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x76, 0x75, +0x74, 0x75, 0x77, 0x78, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, +0xF8, 0xFA, 0xF8, 0xF6, 0xF7, 0xF7, 0xF8, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFD, 0xFE, 0xFF, +0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, +0x7D, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x78, 0x79, 0x78, 0x77, 0x76, +0x76, 0x75, 0x73, 0x74, 0x73, 0x71, 0x70, 0x70, 0x71, 0x72, 0x71, 0x71, 0x70, 0x6F, 0x6F, 0x6F, +0x70, 0x71, 0x71, 0x72, 0x73, 0x74, 0x74, 0x74, 0x76, 0x77, 0x76, 0x78, 0x79, 0x79, 0x79, 0x78, +0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7C, 0x7A, 0x78, 0x79, 0x78, 0x77, +0x76, 0x78, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7E, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, 0xFA, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, +0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFD, 0xFD, +0xFC, 0xFD, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, +0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x75, 0x76, 0x76, 0x75, 0x76, 0x77, +0x78, 0x79, 0x7B, 0x7B, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7A, 0x7B, 0x7B, 0x7A, +0x7B, 0x7D, 0x7E, 0x7B, 0x7C, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFE, 0xFF, +0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7D, 0x7F, 0x7F, 0x7C, 0x7B, +0x7A, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7C, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7C, 0x7C, +0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0xFE, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF9, 0xF8, 0xF5, 0xF4, 0xF7, 0xF8, +0xF8, 0xF8, 0xF9, 0xFB, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x78, 0x78, 0x77, 0x76, 0x76, 0x75, 0x76, 0x76, 0x76, 0x77, 0x75, 0x75, +0x76, 0x75, 0x76, 0x76, 0x78, 0x78, 0x77, 0x78, 0x76, 0x74, 0x75, 0x77, 0x79, 0x7A, 0x7A, 0x7B, +0x7C, 0x7D, 0x7D, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, +0xFE, 0x7F, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0xFF, 0xFD, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, +0x7B, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7E, 0x7E, 0xFF, +0xFF, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0xFF, 0x7E, 0x7C, 0x7D, 0xFF, 0xFF, 0xFF, 0xFD, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, 0x7E, +0x7F, 0x7E, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x79, +0x77, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7C, 0x7D, 0x7D, 0x7E, 0xFD, 0xFD, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFC, 0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFF, 0xFF, 0xFD, 0xFC, 0xFD, 0xFD, 0xFC, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7C, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, +0x7B, 0x7C, 0x7D, 0x7B, 0x7B, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x75, 0x73, 0x72, +0x72, 0x72, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x74, +0x75, 0x76, 0x76, 0x76, 0x77, 0x78, 0x77, 0x78, 0x79, 0x77, 0x78, 0x78, 0x79, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x77, 0x76, 0x76, 0x78, 0x78, 0x77, 0x77, 0x77, 0x75, 0x74, 0x74, 0x75, 0x75, 0x76, +0x79, 0x79, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7D, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFE, 0xFC, +0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF4, 0xF6, 0xF8, 0xF7, 0xF7, 0xF9, 0xF9, +0xF9, 0xF8, 0xF8, 0xFB, 0xFA, 0xF9, 0xFA, 0xFB, 0xFC, 0xFE, 0xFC, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, +0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, +0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7F, 0xFE, 0xFE, 0xFD, 0xFD, +0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFB, 0xFC, +0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7B, 0x7C, 0x79, 0x79, 0x79, 0x78, 0x76, 0x75, 0x76, 0x78, 0x77, 0x76, 0x76, 0x77, +0x76, 0x74, 0x74, 0x75, 0x75, 0x75, 0x74, 0x74, 0x76, 0x77, 0x78, 0x7A, 0x7C, 0x7B, 0x7A, 0x7D, +0x7E, 0x7E, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, +0xFF, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFE, 0xFD, 0xFC, 0xFE, +0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7F, 0xFE, 0xFC, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0x7F, 0x7E, 0xFF, +0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, +0x7E, 0x7D, 0x7E, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7B, 0x7B, +0x7D, 0x7E, 0x7E, 0x7D, 0xFF, 0xFF, 0x7F, 0x7F, 0x7E, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x74, 0x74, 0x75, 0x74, 0x72, 0x74, +0x76, 0x74, 0x74, 0x76, 0x76, 0x74, 0x73, 0x73, 0x72, 0x73, 0x74, 0x76, 0x77, 0x75, 0x73, 0x75, +0x77, 0x78, 0x75, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7B, +0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7C, 0x7F, +0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x79, 0x77, 0x77, +0x78, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7B, 0x7C, 0x7B, 0x7C, 0x7D, 0xFF, +0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, +0xFA, 0xF9, 0xF9, 0xF7, 0xF7, 0xF7, 0xF4, 0xF4, 0xF4, 0xF2, 0xEF, 0xEE, 0xEF, 0xF2, 0xF2, 0xF1, +0xF2, 0xF5, 0xF5, 0xF3, 0xF1, 0xF2, 0xF5, 0xF7, 0xF8, 0xFA, 0xFB, 0xFC, 0xFC, 0xFB, 0xFC, 0xFC, +0xFD, 0xFF, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, 0x78, 0x77, 0x76, 0x75, 0x75, 0x74, 0x71, 0x70, 0x71, +0x71, 0x71, 0x70, 0x6F, 0x71, 0x71, 0x71, 0x73, 0x75, 0x77, 0x77, 0x76, 0x79, 0x7A, 0x79, 0x79, +0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0x7E, 0x7D, 0x7E, 0x7E, 0x7D, 0x7D, +0x7E, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x78, +0x7A, 0x7C, 0x7C, 0x7A, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7D, 0x7C, +0x7C, 0x7E, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7E, +0x7D, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xFC, 0xFD, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, +0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7F, 0x7F, 0x7E, 0x7D, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7C, 0x7C, 0x7A, 0x78, 0x78, 0x7B, 0x7A, 0x77, 0x75, 0x76, 0x75, 0x76, 0x76, 0x76, 0x76, +0x78, 0x79, 0x78, 0x75, 0x75, 0x76, 0x77, 0x7A, 0x7D, 0xFF, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFA, +0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0x7E, 0x78, 0x76, 0x72, 0x70, 0x71, 0x75, 0x77, 0x77, 0x79, 0x7A, +0x7A, 0x7A, 0x7B, 0xFF, 0xFB, 0xFA, 0xF9, 0xFB, 0xFD, 0xFE, 0x7E, 0x7F, 0xFF, 0xFC, 0xF6, 0xF3, +0xF7, 0xFC, 0xFF, 0x7A, 0x73, 0x6E, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x74, 0x73, 0x72, +0x75, 0x7A, 0x7D, 0x7D, 0xFF, 0xFF, 0x7C, 0x7C, 0x7D, 0x7B, 0x7A, 0x79, 0x7B, 0xFF, 0xFF, 0x7D, +0x7C, 0xFF, 0xFE, 0x7D, 0xFC, 0xF3, 0xF6, 0xFC, 0xFE, 0xFE, 0xFF, 0x78, 0x75, 0x79, 0x7A, 0x7E, +0xF8, 0xF6, 0xF6, 0xF2, 0xEF, 0xEE, 0xF0, 0xF7, 0xFD, 0xFE, 0xFD, 0x7B, 0x77, 0x7C, 0xFF, 0xFB, +0xFD, 0x7D, 0xFF, 0x7C, 0x78, 0x7A, 0x7A, 0xFF, 0xF9, 0xF5, 0xF1, 0xF4, 0xFA, 0xFC, 0xFC, 0xFA, +0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFF, 0x7D, 0x7B, 0x7D, 0x7E, 0x7A, 0x76, 0x76, 0x75, +0x72, 0x75, 0x7B, 0x7D, 0x7A, 0x7A, 0x7D, 0xFF, 0x7C, 0x7C, 0xFF, 0x7D, 0x7A, 0x7B, 0x7C, 0x7E, +0xFC, 0xFC, 0x7F, 0xFE, 0xFD, 0xFE, 0xFC, 0xF8, 0xF9, 0xFA, 0xFB, 0xFE, 0x7E, 0x79, 0x72, 0x72, +0x74, 0x76, 0x78, 0x76, 0x78, 0x7A, 0x75, 0x76, 0x77, 0x75, 0x73, 0x73, 0x73, 0x73, 0x74, 0x73, +0x73, 0x77, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x73, 0x73, 0x7B, 0x7C, 0x7C, 0xFC, 0xFC, 0xFE, 0x7F, +0x76, 0x73, 0x76, 0x73, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0x7D, 0x7B, 0x7B, +0x7C, 0x7A, 0x78, 0x7B, 0x7B, 0x7D, 0x7F, 0x7A, 0x77, 0x73, 0x6F, 0x70, 0x72, 0x73, 0x72, 0x72, +0x73, 0x74, 0x74, 0x76, 0x7D, 0xFE, 0x7D, 0x7C, 0x7C, 0x78, 0x76, 0x77, 0x79, 0x7B, 0xFF, 0xFD, +0xFE, 0x7E, 0x7B, 0x7A, 0x78, 0x78, 0x7B, 0x7C, 0x7C, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x79, 0x7B, +0xFF, 0xFA, 0xF9, 0xFD, 0x7E, 0x7D, 0x7C, 0x7B, 0x7E, 0xFE, 0xFC, 0xFF, 0x7E, 0xFE, 0xFD, 0xFE, +0xFD, 0xFC, 0xFB, 0xFC, 0xFC, 0xFD, 0xF9, 0xF3, 0xF2, 0xF3, 0xF4, 0xF6, 0xF6, 0xF8, 0xFA, 0xFC, +0xFB, 0xF7, 0xF9, 0xFC, 0xFC, 0xFD, 0xFD, 0x7E, 0x7C, 0x7F, 0xFF, 0x7D, 0x7A, 0x7A, 0x7B, 0x78, +0x78, 0x78, 0x75, 0x75, 0x76, 0x79, 0x7A, 0x79, 0x7C, 0x7F, 0xFD, 0xFF, 0x7E, 0xFF, 0x7D, 0x79, +0x77, 0x78, 0x79, 0x78, 0x79, 0x7C, 0x7D, 0x7F, 0x7E, 0x7E, 0xFE, 0xFC, 0xF8, 0xF7, 0xFA, 0xFB, +0xFC, 0xFD, 0xFF, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, 0x7B, 0x7D, 0xFE, 0xF9, 0xF5, 0xF6, 0xF6, 0xF4, +0xF6, 0xFA, 0xFE, 0x7D, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFF, 0xFF, 0xFA, 0xFA, 0xFE, +0x7C, 0x75, 0x71, 0x72, 0x74, 0x75, 0x74, 0x75, 0x75, 0x77, 0x79, 0x79, 0x77, 0x74, 0x74, 0x74, +0x72, 0x71, 0x70, 0x71, 0x70, 0x6F, 0x72, 0x73, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7A, 0x78, +0x77, 0x77, 0x76, 0x74, 0x73, 0x72, 0x70, 0x71, 0x75, 0x78, 0x7B, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, +0x7E, 0xFF, 0xFD, 0x7F, 0x7C, 0x7B, 0x7F, 0xFD, 0xFF, 0xFE, 0xFC, 0xFE, 0xFD, 0xFC, 0xFA, 0xF7, +0xF7, 0xFB, 0xFD, 0xFE, 0x7E, 0x7C, 0x7B, 0x7A, 0x7B, 0x79, 0x75, 0x75, 0x76, 0x78, 0x7D, 0xFF, +0x7E, 0x7D, 0x7E, 0x7C, 0x77, 0x75, 0x76, 0x76, 0x78, 0x7E, 0xFD, 0xFB, 0xFC, 0xFD, 0xFE, 0x7C, +0x78, 0x78, 0x7A, 0x7B, 0x7E, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x78, 0x79, 0x7B, 0x7A, 0x7D, 0xFC, +0xFD, 0x7E, 0xFF, 0xFB, 0xF7, 0xF6, 0xF7, 0xF7, 0xF6, 0xFA, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0xFF, +0xFC, 0xFB, 0xF9, 0xFD, 0xFE, 0xFD, 0x7E, 0x79, 0x76, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x72, 0x76, +0x7A, 0x7E, 0xFF, 0xFF, 0x7C, 0x7B, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7E, 0xFF, 0xFF, 0x7E, 0x7D, +0x7D, 0x7E, 0x7C, 0x78, 0x79, 0x7A, 0x7B, 0xFF, 0xFF, 0x7F, 0x7E, 0x7B, 0x79, 0x79, 0x76, 0x72, +0x73, 0x7B, 0xFF, 0xFE, 0xFB, 0xFA, 0xFA, 0xFC, 0x7D, 0x78, 0x77, 0x78, 0x79, 0x79, 0x78, 0x79, +0x77, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7A, 0x7B, 0x7F, 0xFD, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0x7C, +0x78, 0x78, 0x7B, 0x7B, 0x7A, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0x7E, 0xFF, 0xFD, 0xFC, 0xF9, 0xF5, +0xF2, 0xF0, 0xF2, 0xF3, 0xF0, 0xF1, 0xF2, 0xF1, 0xF4, 0xF7, 0xF8, 0xFC, 0xFC, 0xF6, 0xF3, 0xF4, +0xF5, 0xF5, 0xF6, 0xFB, 0xFF, 0xFF, 0xFF, 0x7D, 0x7D, 0x7E, 0x7D, 0x79, 0x75, 0x74, 0x75, 0x72, +0x72, 0x75, 0x75, 0x74, 0x77, 0x7A, 0x7A, 0x7A, 0x7A, 0x77, 0x74, 0x73, 0x72, 0x74, 0x75, 0x76, +0x77, 0x74, 0x74, 0x77, 0x79, 0x79, 0x79, 0x78, 0x77, 0x74, 0x70, 0x6F, 0x70, 0x6F, 0x6E, 0x6E, +0x6E, 0x6F, 0x6F, 0x72, 0x75, 0x72, 0x74, 0x79, 0x7B, 0x7B, 0x7B, 0x7D, 0xFF, 0x7E, 0x7F, 0xFE, +0xFE, 0x7F, 0x7D, 0x7D, 0xFF, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7E, 0x7C, 0x79, 0x77, 0x75, 0x76, +0x77, 0x78, 0x78, 0x74, 0x75, 0x7A, 0x7F, 0xFB, 0xF9, 0xF9, 0xF8, 0xFD, 0x7E, 0x7B, 0x76, 0x78, +0x7B, 0x7C, 0x7E, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7C, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0x7D, 0x7B, +0x7B, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0x7F, 0x7F, 0xFF, 0xFD, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0x7D, +0x7C, 0x7F, 0xFB, 0xF7, 0xF6, 0xFC, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0x7C, +0x76, 0x74, 0x74, 0x79, 0x79, 0x76, 0x77, 0x79, 0x7C, 0x7D, 0x7B, 0x7B, 0x7B, 0x7E, 0xFD, 0xFB, +0xF9, 0xF9, 0xFE, 0x7C, 0x79, 0x79, 0x77, 0x76, 0x79, 0x7B, 0x7D, 0x7C, 0x7C, 0x7D, 0x7C, 0x78, +0x75, 0x74, 0x72, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0x7F, 0x7F, 0x7D, +0x7A, 0x78, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x7B, 0xFF, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, +0xF8, 0xF9, 0xFE, 0x7E, 0xFF, 0xFE, 0xFE, 0x7D, 0x7A, 0x78, 0x75, 0x75, 0x77, 0x7A, 0x7A, 0x79, +0x7B, 0x7D, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF7, +0xF8, 0xFA, 0xF8, 0xF9, 0xFC, 0xFD, 0xFD, 0xFC, 0xF9, 0xF7, 0xF8, 0xFC, 0x7E, 0x7B, 0x7A, 0x7A, +0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x77, 0x72, 0x72, 0x74, 0x76, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, +0x7D, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, +0x7A, 0x7A, 0x77, 0x75, 0x75, 0x74, 0x73, 0x70, 0x6E, 0x6E, 0x6E, 0x6F, 0x72, 0x75, 0x77, 0x7A, +0x7D, 0x7D, 0x7D, 0x7E, 0xFF, 0x7D, 0x7A, 0x7A, 0x7A, 0x7B, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, +0x7D, 0x7B, 0x78, 0x75, 0x73, 0x74, 0x75, 0x75, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7D, 0xFE, 0xFC, +0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, 0xF6, 0xF8, 0xFB, 0xFC, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7C, 0x7B, 0x79, 0x79, 0x7A, 0x79, 0x76, 0x74, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, +0x78, 0x78, 0x78, 0x77, 0x76, 0x75, 0x75, 0x78, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, +0xFE, 0xFC, 0xFC, 0xFC, 0xFA, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF5, 0xF5, 0xF5, 0xF4, 0xF5, 0xF6, +0xF7, 0xF8, 0xF9, 0xFB, 0xFE, 0x7F, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7D, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x79, 0x77, 0x76, +0x77, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7B, +0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0xFE, +0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, 0x77, 0x79, +0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7D, 0x7B, 0x7B, 0x7D, 0x7C, 0x7D, 0xFF, 0x7E, +0xFF, 0xFD, 0xFB, 0xF9, 0xF8, 0xF9, 0xF9, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF3, 0xF5, 0xF6, 0xF6, +0xF7, 0xF9, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFC, 0xFB, 0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xF8, +0xF8, 0xF9, 0xFB, 0xFD, 0x7E, 0x7B, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x76, 0x75, 0x75, +0x73, 0x71, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x6E, 0x6E, 0x6E, 0x6D, +0x6D, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x79, 0x7C, 0x7D, 0x7E, 0xFF, +0xFF, 0xFF, 0xFD, 0xFC, 0xFA, 0xF9, 0xFB, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0x7E, 0x7B, 0x7A, +0x79, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7C, 0x7B, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x7C, +0x7E, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0xFD, +0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFB, 0xFB, +0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFD, 0xFC, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7D, 0x7C, 0x7C, +0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x78, 0x77, 0x76, 0x75, 0x75, 0x75, 0x76, 0x76, 0x75, 0x76, +0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, +0xFD, 0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0x7F, 0x7E, 0x7C, 0x7C, 0x7B, +0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7F, 0xFD, 0x7D, 0x79, 0xFE, +0xFA, 0xFE, 0xFC, 0xF8, 0xFC, 0xFF, 0xFF, 0xFE, 0xFB, 0xFC, 0x7F, 0xFF, 0x7F, 0x7C, 0x7D, 0x7D, +0x7E, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, +0x7D, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, +0x7D, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x74, 0x73, +0x74, 0x75, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x77, 0x77, 0x79, 0x7B, 0x7C, 0x7D, +0x7D, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFB, 0xFC, 0xFD, +0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, +0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7D, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x77, 0x78, 0x76, 0x76, 0x78, 0x7A, 0x78, 0x78, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x75, 0x77, 0x77, 0x76, 0x74, 0x74, 0x75, 0x76, 0x75, 0x76, 0x76, +0x75, 0x76, 0x76, 0x75, 0x74, 0x73, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x78, 0x7A, 0x7A, 0x7B, +0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFD, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFE, +0xFE, 0xFE, 0x7F, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, +0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFE, 0xFC, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, +0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0xFE, 0xFF, 0x7F, 0xFF, 0x7E, 0x7D, 0x7B, 0x79, 0x79, 0x7B, 0x7C, +0x7C, 0x7D, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x78, 0x75, 0x75, 0x76, 0x76, +0x78, 0x75, 0x76, 0x77, 0x73, 0x75, 0x73, 0x77, 0x76, 0x73, 0x78, 0x73, 0x78, 0x77, 0x75, 0x7B, +0x70, 0x7E, 0x68, 0x5B, 0xE4, 0xD9, 0x77, 0x66, 0x5F, 0x6B, 0xEB, 0x78, 0x6B, 0xEC, 0xE9, 0x67, +0x5A, 0x62, 0xF8, 0xE2, 0xF1, 0x6B, 0x6F, 0x72, 0x6E, 0x6D, 0x72, 0xEF, 0xE7, 0xF7, 0x6D, 0x6A, +0x70, 0x7B, 0xFC, 0xF5, 0xED, 0xEF, 0x7D, 0x71, 0x70, 0xFF, 0xEE, 0xEF, 0xF8, 0xFC, 0x7B, 0x73, +0x6F, 0x71, 0x7E, 0xF2, 0xF2, 0x76, 0x67, 0x68, 0x78, 0xF7, 0xF5, 0xFC, 0x7E, 0x7B, 0x73, 0x70, +0x79, 0xF4, 0xEB, 0xEC, 0xF8, 0x7C, 0x7B, 0xFF, 0xF6, 0xEF, 0xEF, 0xF4, 0xF8, 0xFE, 0x7D, 0xFE, +0xF8, 0xF4, 0xF4, 0xF9, 0xFE, 0x7E, 0x7C, 0x7C, 0xFD, 0xF8, 0xF8, 0xFD, 0x7D, 0x7A, 0x79, 0x7C, +0xFF, 0xFD, 0xFB, 0xFC, 0x7D, 0x7B, 0x7D, 0x7F, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7A, 0x79, 0x7C, +0x7E, 0x7D, 0x7D, 0x7B, 0x78, 0x79, 0x7B, 0x7A, 0x78, 0x79, 0x77, 0x76, 0x78, 0x71, 0x70, 0x78, +0x7E, 0xF6, 0xFE, 0x67, 0x68, 0xF4, 0xEF, 0x74, 0x69, 0x6A, 0xFF, 0x7E, 0x6E, 0xF2, 0xFB, 0x69, +0x66, 0x69, 0xDD, 0xD9, 0x71, 0x7B, 0x74, 0x5F, 0x69, 0x61, 0x6A, 0xE6, 0xEC, 0x66, 0x55, 0x50, +0x5C, 0xFB, 0xED, 0xF5, 0xFA, 0x6F, 0x6E, 0x7B, 0xE8, 0xCF, 0xC7, 0xC6, 0xCA, 0xCB, 0xDB, 0x3A, +0x2E, 0x49, 0xBD, 0xB7, 0xC6, 0x4D, 0x41, 0x4B, 0x49, 0x4D, 0xD9, 0xBF, 0xC2, 0xFD, 0x3F, 0x3D, +0x51, 0xDF, 0xCD, 0xCC, 0xD5, 0xF4, 0x50, 0x46, 0x4D, 0xF0, 0xCB, 0xCA, 0xDA, 0x61, 0x51, 0x52, +0x5B, 0xE6, 0xD0, 0xCE, 0xDC, 0x5D, 0x53, 0x51, 0x6A, 0xF9, 0x48, 0x67, 0xC2, 0xE0, 0x5F, 0x5B, +0x4C, 0x71, 0xFA, 0x6E, 0xCE, 0xCF, 0x7A, 0x64, 0x79, 0xD8, 0xCE, 0xD1, 0xCD, 0xC3, 0xC5, 0xCD, +0xC7, 0xDC, 0x42, 0x3E, 0x53, 0xD2, 0xC0, 0xDE, 0x44, 0x48, 0x58, 0x53, 0x59, 0xFA, 0xD9, 0xD6, +0x5E, 0x43, 0x47, 0x61, 0xE1, 0xD8, 0xEA, 0x64, 0x46, 0x3C, 0x51, 0x7F, 0x77, 0xD0, 0xF6, 0x4B, +0x4B, 0x4A, 0x6F, 0xCA, 0xC6, 0xC9, 0xC7, 0xC2, 0xC8, 0xBD, 0xB0, 0xAB, 0xBB, 0x1F, 0x19, 0x5F, +0xA3, 0xA5, 0xBA, 0x30, 0x30, 0x47, 0x31, 0x37, 0xBC, 0xAB, 0xB8, 0x3D, 0x2B, 0x30, 0x4E, 0xBD, +0xB4, 0xC4, 0x5D, 0x3F, 0x38, 0x41, 0x6E, 0xC8, 0xC1, 0xDC, 0x4B, 0x3B, 0x3F, 0xE5, 0xBF, 0xBC, +0xC8, 0xE5, 0xDE, 0xC0, 0xAE, 0xAD, 0xAF, 0xC1, 0x20, 0x1A, 0x63, 0xA8, 0xA7, 0xB5, 0x36, 0x2E, +0x3D, 0x32, 0x3F, 0xBD, 0xB1, 0xC1, 0x39, 0x2E, 0x42, 0xE8, 0xCA, 0xC3, 0xDB, 0x5F, 0x47, 0x39, +0x47, 0xD5, 0xCB, 0xD1, 0x70, 0x4B, 0x4D, 0xF0, 0xC1, 0xB3, 0xAE, 0xB4, 0xBE, 0xB8, 0xB8, 0x34, +0x1C, 0x27, 0xB6, 0xA3, 0xAC, 0x4F, 0x2C, 0x32, 0x3B, 0x3E, 0xEB, 0xB9, 0xBB, 0x45, 0x2E, 0x39, +0x60, 0xC3, 0xBB, 0xD8, 0x4D, 0x45, 0x41, 0x57, 0xD6, 0xDE, 0x79, 0x5D, 0x50, 0x5B, 0xDB, 0xBE, +0xB4, 0xB3, 0xBC, 0xC4, 0xB6, 0xAC, 0xC2, 0x26, 0x1A, 0x30, 0xAB, 0xA9, 0xBB, 0x61, 0x33, 0x30, +0x36, 0x39, 0xCF, 0xB9, 0x64, 0x41, 0x42, 0x3E, 0x5E, 0xD3, 0xCF, 0xC4, 0xEC, 0x47, 0x56, 0x5C, +0x50, 0x57, 0x62, 0xDF, 0xD2, 0xD3, 0xC4, 0xB6, 0xB3, 0xBA, 0xB8, 0xAD, 0xAF, 0x3C, 0x1C, 0x1E, +0xCB, 0xA1, 0xA9, 0xFE, 0x2D, 0x2C, 0x39, 0x3D, 0x64, 0xBE, 0xD5, 0x4B, 0x42, 0x3A, 0x40, 0xEC, +0xC4, 0xBE, 0xD1, 0x4A, 0x3E, 0x47, 0x62, 0xE4, 0xD7, 0xD6, 0xDC, 0xDE, 0xCD, 0xB6, 0xAD, 0xAE, +0xAC, 0xAD, 0xE6, 0x22, 0x19, 0x2E, 0xA6, 0x9E, 0xB2, 0x39, 0x28, 0x2D, 0x39, 0x4E, 0xC2, 0xBE, +0x5B, 0x3E, 0x3B, 0x3C, 0x58, 0xC6, 0xBD, 0xC7, 0x60, 0x3F, 0x3F, 0x51, 0xED, 0xCF, 0xC8, 0xD1, +0xE0, 0xD9, 0xBC, 0xAC, 0xAB, 0xAB, 0xA9, 0xC2, 0x25, 0x17, 0x22, 0xAE, 0x9D, 0xA9, 0x47, 0x26, +0x29, 0x34, 0x47, 0xC5, 0xBB, 0x77, 0x3F, 0x3A, 0x38, 0x4E, 0xC6, 0xBC, 0xBE, 0xE6, 0x3D, 0x39, +0x43, 0x67, 0xCE, 0xC7, 0xD6, 0xED, 0xD9, 0xBD, 0xAB, 0xAB, 0xAE, 0xA9, 0xB4, 0x30, 0x1A, 0x1B, +0xD5, 0x9D, 0xA3, 0xDA, 0x2A, 0x26, 0x31, 0x3C, 0x6C, 0xBF, 0xCE, 0x5E, 0x42, 0x32, 0x3C, 0xD6, +0xBC, 0xB8, 0xCC, 0x3F, 0x37, 0x3B, 0x51, 0xCC, 0xC1, 0xCC, 0xE2, 0xDE, 0xBD, 0xAC, 0xAA, 0xA9, +0xA7, 0xC5, 0x26, 0x18, 0x1F, 0xB7, 0x9D, 0xA6, 0xDF, 0x2B, 0x26, 0x2D, 0x37, 0xEB, 0xBA, 0xCB, +0x5E, 0x3C, 0x30, 0x44, 0xC9, 0xBB, 0xB8, 0xCF, 0x3D, 0x34, 0x3B, 0x5F, 0xC1, 0xBE, 0xCE, 0xD6, +0xCE, 0xB8, 0xAB, 0xAA, 0xA4, 0xA8, 0x42, 0x1C, 0x18, 0x31, 0xA4, 0x9F, 0xAF, 0x48, 0x29, 0x28, +0x2C, 0x37, 0xCC, 0xBA, 0xC7, 0x57, 0x30, 0x31, 0x5A, 0xC6, 0xB6, 0xB7, 0x5F, 0x38, 0x34, 0x3D, +0xE2, 0xBD, 0xBD, 0xC7, 0xD2, 0xCA, 0xB2, 0xAB, 0xA7, 0xA2, 0xB3, 0x29, 0x18, 0x1C, 0xD2, 0x9F, +0xA5, 0xBC, 0x3A, 0x2A, 0x29, 0x2A, 0x3E, 0xC3, 0xBB, 0xC1, 0x43, 0x2D, 0x3A, 0xF5, 0xC1, 0xB5, +0xBE, 0x4F, 0x36, 0x32, 0x3F, 0xD2, 0xBB, 0xBA, 0xBE, 0xC5, 0xBF, 0xB1, 0xAB, 0xA4, 0xA7, 0x75, +0x1F, 0x18, 0x27, 0xAE, 0xA2, 0xAD, 0xD6, 0x36, 0x2B, 0x28, 0x2C, 0x4E, 0xC2, 0xB8, 0xC9, 0x35, +0x2F, 0x42, 0x71, 0xBA, 0xB4, 0xD2, 0x44, 0x34, 0x34, 0x4C, 0xCD, 0xBE, 0xBB, 0xB9, 0xBC, 0xB3, +0xAE, 0xAB, 0xA3, 0xB0, 0x2C, 0x1A, 0x1C, 0x5F, 0xA4, 0xA9, 0xBA, 0x6F, 0x34, 0x28, 0x26, 0x32, +0x77, 0xB9, 0xB3, 0x5E, 0x32, 0x38, 0x40, 0xD8, 0xB6, 0xBE, 0xF4, 0x40, 0x34, 0x3A, 0x5B, 0xC7, +0xB7, 0xB4, 0xB7, 0xB4, 0xB2, 0xAE, 0xA5, 0xAB, 0x3B, 0x1D, 0x1B, 0x34, 0xAE, 0xAA, 0xB4, 0xC7, +0x42, 0x2C, 0x25, 0x2B, 0x43, 0xCF, 0xB5, 0xBE, 0x3F, 0x38, 0x3D, 0x4D, 0xC4, 0xBD, 0xCF, 0x5D, +0x3E, 0x38, 0x43, 0xE4, 0xBF, 0xB4, 0xAF, 0xB0, 0xAF, 0xAE, 0xA8, 0xA7, 0xF6, 0x21, 0x1A, 0x27, +0xBA, 0xAC, 0xB5, 0xB9, 0xE2, 0x36, 0x26, 0x25, 0x33, 0x4E, 0xBA, 0xB2, 0x64, 0x41, 0x3F, 0x3D, +0xE6, 0xC6, 0xCD, 0xD4, 0x50, 0x3D, 0x3C, 0x48, 0xD4, 0xB9, 0xAF, 0xAD, 0xAE, 0xAE, 0xAA, 0xA7, +0xC0, 0x2A, 0x1B, 0x1F, 0x65, 0xAF, 0xB5, 0xB5, 0xBF, 0x4C, 0x2C, 0x23, 0x2A, 0x37, 0xE6, 0xAF, +0xBC, 0x5B, 0x4B, 0x3B, 0x49, 0xCF, 0xCE, 0xD0, 0xDE, 0x4F, 0x40, 0x3F, 0x57, 0xC7, 0xB3, 0xAA, +0xA9, 0xAC, 0xAE, 0xA9, 0xAE, 0x3B, 0x1E, 0x1E, 0x37, 0xBA, 0xB7, 0xB7, 0xB5, 0xC9, 0x3A, 0x26, +0x27, 0x2E, 0x37, 0xC1, 0xB1, 0xCA, 0xE8, 0x49, 0x3E, 0x62, 0x78, 0xEF, 0xD7, 0x69, 0x4F, 0x44, +0x48, 0xFB, 0xC5, 0xAF, 0xA9, 0xA8, 0xAA, 0xAB, 0xAA, 0xCF, 0x26, 0x1C, 0x22, 0x4A, 0xBD, 0xBB, +0xAF, 0xB1, 0xD7, 0x31, 0x25, 0x27, 0x28, 0x38, 0xB9, 0xB6, 0xC3, 0xCB, 0x4B, 0x45, 0x4E, 0x47, +0x62, 0xE0, 0xF9, 0x5C, 0x4C, 0x5C, 0xE4, 0xBF, 0xAD, 0xA8, 0xA5, 0xA7, 0xA9, 0xB2, 0x36, 0x20, +0x1E, 0x29, 0x56, 0xCC, 0xB8, 0xAC, 0xB5, 0xFA, 0x2F, 0x28, 0x25, 0x25, 0x45, 0xBE, 0xBF, 0xB8, +0xC5, 0x5F, 0x54, 0x41, 0x43, 0x4F, 0x56, 0x75, 0x70, 0xFE, 0xE2, 0xD3, 0xB9, 0xAD, 0xA8, 0xA6, +0xA6, 0xA8, 0xCA, 0x2D, 0x22, 0x21, 0x2E, 0x47, 0x77, 0xB4, 0xAD, 0xB7, 0xDC, 0x39, 0x2D, 0x24, +0x28, 0x40, 0x5A, 0xC7, 0xB5, 0xBD, 0xC0, 0xDB, 0x4E, 0x4C, 0x40, 0x44, 0x4E, 0x56, 0xDA, 0xCC, +0xC0, 0xB1, 0xAC, 0xA7, 0xA5, 0xA6, 0xAD, 0x4F, 0x2A, 0x23, 0x25, 0x2F, 0x39, 0x6C, 0xB6, 0xB1, +0xB7, 0xD6, 0x43, 0x2F, 0x26, 0x2C, 0x35, 0x3A, 0xDF, 0xC7, 0xBE, 0xBA, 0xCB, 0xD4, 0x6E, 0x48, +0x44, 0x3E, 0x4A, 0x6C, 0xD6, 0xB9, 0xB0, 0xA8, 0xA4, 0xA5, 0xA4, 0xB5, 0x42, 0x2C, 0x23, 0x27, +0x2B, 0x2E, 0x55, 0xC2, 0xB9, 0xB6, 0xC5, 0xF4, 0x3C, 0x32, 0x34, 0x2F, 0x37, 0x4A, 0x5B, 0xCF, +0xC9, 0xC6, 0xC0, 0xCA, 0xCF, 0xF4, 0x52, 0x51, 0x4E, 0xF8, 0xC4, 0xB7, 0xAD, 0xA9, 0xA6, 0xA7, +0xB8, 0x5D, 0x38, 0x2F, 0x2E, 0x2B, 0x2C, 0x35, 0x42, 0x5D, 0x7D, 0xE3, 0xDF, 0x6F, 0x73, 0x5A, +0x4D, 0x55, 0x4F, 0x4F, 0x58, 0x5C, 0x6E, 0xFA, 0xE2, 0xD4, 0xD4, 0xD6, 0xD9, 0xD6, 0xCC, 0xC6, +0xBF, 0xBB, 0xB8, 0xB6, 0xBC, 0xC9, 0xDC, 0x60, 0x59, 0x53, 0x4A, 0x49, 0x46, 0x45, 0x46, 0x43, +0x45, 0x45, 0x49, 0x56, 0x5A, 0x5D, 0x6E, 0x72, 0x7C, 0x74, 0x6D, 0x7A, 0x7A, 0xFC, 0xED, 0xE8, +0xEB, 0xFF, 0xFD, 0xEC, 0xDE, 0xD2, 0xCC, 0xC7, 0xC5, 0xCA, 0xD2, 0xD9, 0xDB, 0xD4, 0xCF, 0xD1, +0xD9, 0xE7, 0xFC, 0x6E, 0x60, 0x57, 0x50, 0x4C, 0x49, 0x47, 0x46, 0x45, 0x47, 0x4A, 0x4D, 0x4F, +0x4F, 0x53, 0x5A, 0x5F, 0x62, 0x60, 0x62, 0x6B, 0x77, 0xEC, 0xD8, 0xCC, 0xC7, 0xC7, 0xCB, 0xCF, +0xD3, 0xD3, 0xCE, 0xCB, 0xCA, 0xCC, 0xCF, 0xD4, 0xD9, 0xDF, 0xEB, 0xFE, 0x6A, 0x58, 0x4D, 0x46, +0x43, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x52, 0x54, 0x55, 0x54, 0x57, 0x5C, 0x61, 0x72, 0xE5, +0xD4, 0xCC, 0xCB, 0xCD, 0xD0, 0xD4, 0xD3, 0xD1, 0xD0, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD9, 0xDB, +0xDB, 0xDD, 0xEC, 0x6B, 0x59, 0x53, 0x54, 0x57, 0x59, 0x58, 0x57, 0x5A, 0x5C, 0x5A, 0x55, 0x52, +0x52, 0x51, 0x51, 0x57, 0x61, 0xFC, 0xE3, 0xDF, 0xE0, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDD, 0xDE, +0xDD, 0xDF, 0xE0, 0xDF, 0xDC, 0xD9, 0xDC, 0xE7, 0x7E, 0x6B, 0x6D, 0x7C, 0xEE, 0xE6, 0xE7, 0xEA, +0xEC, 0xF5, 0x7A, 0x6A, 0x61, 0x5A, 0x51, 0x4F, 0x50, 0x55, 0x5D, 0x62, 0x63, 0x60, 0x5F, 0x61, +0x65, 0x68, 0x6D, 0x75, 0xFA, 0xF1, 0xF1, 0xEE, 0xE6, 0xDD, 0xDB, 0xDE, 0xEB, 0x79, 0x6B, 0x6F, +0xF7, 0xE2, 0xDC, 0xDB, 0xDA, 0xDA, 0xDC, 0xDD, 0xDE, 0xE0, 0xF1, 0x6B, 0x5F, 0x5F, 0x66, 0x6B, +0x6A, 0x65, 0x5E, 0x5B, 0x5A, 0x59, 0x5A, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x68, 0xFC, 0xE8, 0xE5, +0xEB, 0xFB, 0x71, 0x6D, 0x78, 0xEE, 0xE2, 0xDE, 0xDD, 0xDC, 0xDE, 0xDF, 0xDC, 0xD9, 0xD9, 0xE0, +0xED, 0xF0, 0xEC, 0xE4, 0xE2, 0xE6, 0xEE, 0x7C, 0x6D, 0x65, 0x5E, 0x5E, 0x62, 0x64, 0x61, 0x5C, +0x5B, 0x5F, 0x70, 0xF7, 0xF8, 0x78, 0x6B, 0x65, 0x61, 0x69, 0xFA, 0xE9, 0xE5, 0xE2, 0xE5, 0xEA, +0xED, 0xEB, 0xE5, 0xE5, 0xED, 0xF9, 0xFC, 0xEF, 0xE3, 0xDE, 0xDE, 0xE1, 0xE9, 0xF4, 0x74, 0x6A, +0x6B, 0x6F, 0x6F, 0x67, 0x5E, 0x5C, 0x5F, 0x6A, 0x6F, 0x6C, 0x66, 0x5F, 0x5D, 0x5E, 0x64, 0x6F, +0xFE, 0xEF, 0xEC, 0xF2, 0xFD, 0x7E, 0xFB, 0xF6, 0xFF, 0x6F, 0x6A, 0x6A, 0x74, 0xF4, 0xE9, 0xE4, +0xE7, 0xEE, 0x7D, 0x6A, 0x69, 0x6F, 0xFE, 0xF7, 0x7B, 0x6B, 0x68, 0x6E, 0x79, 0x78, 0x6F, 0x69, +0x62, 0x5F, 0x60, 0x66, 0x72, 0xF6, 0xEB, 0xEC, 0xF3, 0xFC, 0xFA, 0xF2, 0xF2, 0xFE, 0x70, 0x69, +0x69, 0x71, 0xF7, 0xE8, 0xE3, 0xE4, 0xED, 0x76, 0x69, 0x6A, 0x6F, 0x7E, 0xFB, 0x7D, 0x75, 0x73, +0x7C, 0xFB, 0xFC, 0x7D, 0x73, 0x6D, 0x6A, 0x69, 0x6F, 0xFD, 0xEC, 0xE8, 0xED, 0xF6, 0xF7, 0xF1, +0xED, 0xEF, 0xF6, 0x7E, 0x76, 0x78, 0xFB, 0xEC, 0xE2, 0xDE, 0xE0, 0xEB, 0xFE, 0x73, 0x73, 0x7E, +0xFA, 0xFC, 0xFF, 0x7B, 0x7D, 0xFC, 0xFE, 0x7B, 0x74, 0x6F, 0x6D, 0x6C, 0x6E, 0x77, 0xFA, 0xEE, +0xED, 0xF6, 0x7A, 0x73, 0x77, 0x7B, 0x7C, 0x78, 0x6E, 0x6B, 0x6F, 0x7C, 0xEF, 0xE7, 0xE2, 0xE6, +0xF2, 0x7A, 0x71, 0x75, 0x7D, 0xFE, 0xFD, 0xFD, 0xFB, 0xF5, 0xF7, 0xFE, 0x77, 0x6E, 0x6A, 0x67, +0x67, 0x6C, 0x76, 0xF7, 0xEE, 0xEF, 0xFA, 0x7B, 0x78, 0x7B, 0xFF, 0x7F, 0x78, 0x6F, 0x6C, 0x6C, +0x72, 0xFE, 0xEF, 0xEC, 0xEF, 0xFD, 0x76, 0x70, 0x71, 0x75, 0x7A, 0x7E, 0x7E, 0xFF, 0xFC, 0xFD, +0x7C, 0x73, 0x6D, 0x69, 0x65, 0x63, 0x65, 0x6B, 0x79, 0xFB, 0xFD, 0x78, 0x70, 0x70, 0x74, 0x79, +0x7C, 0x7B, 0x79, 0x77, 0x78, 0x7F, 0xF4, 0xED, 0xED, 0xF2, 0xFB, 0x7A, 0x74, 0x74, 0x76, 0x7A, +0x7F, 0xFB, 0xF5, 0xF4, 0xF6, 0xFA, 0x7D, 0x75, 0x6E, 0x6B, 0x6B, 0x6F, 0x7D, 0xF3, 0xEF, 0xF4, +0x7E, 0x78, 0x7A, 0xFF, 0xFA, 0xF7, 0xF5, 0xF4, 0xF4, 0xF1, 0xED, 0xE9, 0xE6, 0xE8, 0xEE, 0xF8, +0x7F, 0x7C, 0x7A, 0x7A, 0x7B, 0x7D, 0xFD, 0xF8, 0xF8, 0xF9, 0xFC, 0x7D, 0x74, 0x6C, 0x69, 0x69, +0x6C, 0x76, 0xFA, 0xF6, 0xFD, 0x78, 0x71, 0x6F, 0x6F, 0x6F, 0x71, 0x74, 0x77, 0x7C, 0xFD, 0xF5, +0xEC, 0xE9, 0xEA, 0xEF, 0xFB, 0x7A, 0x74, 0x73, 0x73, 0x73, 0x73, 0x78, 0x7E, 0xFE, 0xFD, 0xFE, +0x7B, 0x74, 0x6D, 0x68, 0x66, 0x69, 0x6F, 0x7B, 0x7F, 0x7C, 0x77, 0x73, 0x72, 0x6F, 0x6D, 0x6D, +0x6D, 0x6D, 0x6E, 0x72, 0x7A, 0xFA, 0xF1, 0xEE, 0xEF, 0xF6, 0xFD, 0x7D, 0x7B, 0x7A, 0x78, 0x78, +0x79, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7D, 0x77, 0x70, 0x6E, 0x71, 0x79, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7D, 0x7C, 0x7A, 0x78, 0x76, 0x74, 0x73, 0x75, 0x7A, 0xFC, 0xF6, 0xF4, 0xF4, 0xF6, 0xF6, +0xF6, 0xF9, 0xF9, 0xF7, 0xF5, 0xF3, 0xF1, 0xF1, 0xF3, 0xF5, 0xF7, 0xFA, 0x7B, 0x6F, 0x6D, 0x6D, +0x6F, 0x6F, 0x6E, 0x6E, 0x70, 0x70, 0x71, 0x74, 0x78, 0x7C, 0x7D, 0x7E, 0x7D, 0xFF, 0xFB, 0xF7, +0xF4, 0xF4, 0xF6, 0xF8, 0xFB, 0xFD, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, +0xF9, 0xFD, 0x7D, 0x7C, 0x7F, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x79, 0x76, +0x71, 0x6F, 0x6F, 0x71, 0x76, 0x78, 0x78, 0x78, 0x7B, 0x7D, 0x7A, 0x77, 0x76, 0x76, 0x78, 0x79, +0x78, 0x79, 0x7C, 0xFD, 0xF4, 0xF1, 0xF2, 0xF5, 0xF9, 0xFB, 0x7F, 0x79, 0x76, 0x76, 0x78, 0x77, +0x77, 0x7B, 0xFF, 0xFA, 0xF6, 0xF6, 0xF7, 0xF6, 0xF6, 0xF7, 0xF9, 0xFA, 0xF9, 0xF6, 0xF6, 0xF9, +0xFB, 0xFE, 0x7F, 0x7E, 0x7C, 0x79, 0x7A, 0xFE, 0xF5, 0xEF, 0xEE, 0xEF, 0xF1, 0xF3, 0xF4, 0xFB, +0x79, 0x73, 0x72, 0x6E, 0x6B, 0x68, 0x68, 0x6C, 0x73, 0x7A, 0x7C, 0x7B, 0x7B, 0x7D, 0x7D, 0xFD, +0xF6, 0xF0, 0xEE, 0xEF, 0xF6, 0xFB, 0xFF, 0x7D, 0x7F, 0x7D, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0xFF, 0xFD, 0xFF, 0x7E, 0x7A, 0x75, 0x74, 0x71, 0x6F, 0x6F, 0x70, 0x77, 0x7A, 0x78, 0x75, +0x72, 0x75, 0x73, 0x6F, 0x6F, 0x70, 0x75, 0x77, 0x76, 0x78, 0x75, 0x78, 0x7B, 0x7B, 0x7F, 0x7B, +0x7E, 0x7F, 0x7E, 0x7E, 0x77, 0x79, 0x73, 0x71, 0x71, 0x6B, 0x6F, 0x60, 0x5B, 0x6F, 0x72, 0x69, +0x71, 0x72, 0x7E, 0xFC, 0xF7, 0xEE, 0xF4, 0xFB, 0x7E, 0x7E, 0xFC, 0xF9, 0xFD, 0x7F, 0xFC, 0x72, +0x78, 0x64, 0x53, 0x71, 0xDF, 0xF0, 0xEB, 0xE9, 0xF0, 0x7C, 0x7B, 0xEA, 0xF6, 0x7E, 0x79, 0x6C, +0x79, 0x5F, 0x5B, 0xEC, 0xE2, 0xEF, 0xED, 0xF1, 0xF7, 0xFE, 0x7C, 0xFE, 0x75, 0x6E, 0x75, 0x79, +0x7A, 0x72, 0x6E, 0x75, 0x7A, 0x7B, 0x77, 0x77, 0xFE, 0xF8, 0xF6, 0xF5, 0xEB, 0xE9, 0xEC, 0xE8, +0xEE, 0xEC, 0xED, 0x77, 0xFD, 0x61, 0x51, 0x66, 0xE7, 0xDC, 0xD8, 0xD3, 0xD3, 0x6C, 0x52, 0x63, +0x6F, 0x73, 0x7F, 0xFB, 0xF4, 0x79, 0x7B, 0xF1, 0xED, 0xEC, 0xFA, 0x76, 0x7A, 0x74, 0x6B, 0x6B, +0x75, 0x7C, 0x7C, 0x79, 0xFE, 0xF6, 0xFE, 0x7A, 0x71, 0x75, 0xFF, 0x70, 0x6D, 0x6E, 0x69, 0x66, +0x5E, 0x62, 0xFA, 0xEA, 0xE5, 0xE0, 0xE1, 0xE5, 0xEE, 0xF1, 0xE5, 0xE4, 0xEA, 0xE8, 0xE7, 0xE7, +0xE3, 0xE7, 0xE8, 0xE8, 0xEF, 0xF7, 0x78, 0x6E, 0x6D, 0x60, 0x5A, 0x57, 0x54, 0x53, 0x51, 0x50, +0x52, 0x54, 0x57, 0x59, 0x5D, 0x67, 0x70, 0x7B, 0xF5, 0xE5, 0xDA, 0xD5, 0xD2, 0xCD, 0xC4, 0xBE, +0xBB, 0xB7, 0xB5, 0xBB, 0xCB, 0xDE, 0xE9, 0x56, 0x3F, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, 0x3F, 0x4E, +0x5D, 0x69, 0xF2, 0xDD, 0xD9, 0xE2, 0xF3, 0xF4, 0x72, 0x5C, 0x53, 0x4E, 0x4D, 0x4E, 0x4E, 0x4F, +0x58, 0x7E, 0xDA, 0xCB, 0xBF, 0xBA, 0xB7, 0xB4, 0xB0, 0xAE, 0xB2, 0xBE, 0xD7, 0x70, 0x4E, 0x3B, +0x32, 0x30, 0x33, 0x35, 0x35, 0x3A, 0x49, 0x5F, 0x7E, 0xEF, 0xE1, 0xD2, 0xD1, 0xE6, 0xEF, 0xF7, +0x5F, 0x4F, 0x48, 0x48, 0x4B, 0x48, 0x4B, 0x55, 0x72, 0xE1, 0xD2, 0xC2, 0xBA, 0xB6, 0xB3, 0xB0, +0xAD, 0xAE, 0xBA, 0xD0, 0x64, 0x4C, 0x3C, 0x30, 0x2E, 0x2F, 0x33, 0x35, 0x3A, 0x47, 0x6C, 0xE6, +0xEB, 0xD0, 0xC6, 0xCC, 0xD6, 0xE3, 0xEF, 0x69, 0x4E, 0x4B, 0x4B, 0x47, 0x46, 0x48, 0x4F, 0x61, +0xFE, 0xD1, 0xBE, 0xB8, 0xB5, 0xB2, 0xAF, 0xAD, 0xAE, 0xBA, 0xCD, 0x5F, 0x47, 0x3B, 0x2F, 0x2D, +0x2E, 0x30, 0x35, 0x3B, 0x47, 0x6C, 0xF4, 0xE2, 0xCB, 0xC7, 0xCD, 0xD7, 0xDD, 0xE3, 0x6E, 0x4E, +0x4A, 0x4B, 0x48, 0x47, 0x4A, 0x5B, 0xE4, 0xD3, 0xC0, 0xB7, 0xB3, 0xB0, 0xAF, 0xAC, 0xAC, 0xB3, +0xC4, 0x7D, 0x4C, 0x3E, 0x30, 0x2C, 0x2E, 0x31, 0x35, 0x3A, 0x45, 0x62, 0xFA, 0xEB, 0xCE, 0xCA, +0xD2, 0xDA, 0xE7, 0xE9, 0x6D, 0x4C, 0x49, 0x49, 0x47, 0x48, 0x4C, 0x68, 0xD7, 0xCA, 0xBC, 0xB5, +0xB2, 0xB0, 0xAE, 0xAC, 0xAE, 0xB9, 0xCE, 0x5D, 0x45, 0x39, 0x2F, 0x2D, 0x2E, 0x31, 0x36, 0x3B, +0x47, 0x5C, 0x6E, 0xE4, 0xD3, 0xD3, 0xD4, 0xDA, 0xDE, 0xEB, 0x5B, 0x4D, 0x4A, 0x47, 0x48, 0x49, +0x54, 0xEB, 0xCE, 0xBE, 0xB8, 0xB7, 0xB3, 0xB3, 0xB5, 0xB3, 0xBB, 0xC9, 0xC8, 0xED, 0x47, 0x42, +0x3A, 0x36, 0x37, 0x34, 0x39, 0x3E, 0x3F, 0x47, 0x4E, 0x65, 0xDE, 0xEC, 0xDC, 0xCE, 0xD9, 0xEB, +0x5F, 0x54, 0x51, 0x47, 0x46, 0x4C, 0x58, 0xFC, 0xD8, 0xC4, 0xBB, 0xBA, 0xB8, 0xB5, 0xB2, 0xAF, +0xB0, 0xB6, 0xBD, 0xCC, 0x66, 0x47, 0x3B, 0x34, 0x32, 0x32, 0x34, 0x38, 0x3B, 0x3F, 0x4B, 0x58, +0x69, 0xE9, 0xD9, 0xD4, 0xDB, 0x77, 0x5C, 0x59, 0x4F, 0x4A, 0x4B, 0x51, 0x69, 0xE0, 0xCE, 0xC2, +0xBD, 0xBC, 0xBA, 0xB8, 0xB7, 0xB4, 0xB2, 0xB7, 0xC3, 0xCE, 0xD4, 0x67, 0x44, 0x3D, 0x3C, 0x3B, +0x38, 0x38, 0x3B, 0x3F, 0x42, 0x46, 0x4E, 0x5F, 0x6A, 0x6B, 0xFD, 0xF7, 0x70, 0x5C, 0x54, 0x58, +0x58, 0x53, 0x5B, 0x73, 0xE5, 0xD2, 0xCA, 0xC6, 0xC2, 0xBF, 0xBE, 0xBE, 0xBD, 0xBB, 0xBC, 0xC3, +0xCA, 0xD0, 0xE2, 0x5F, 0x4E, 0x4A, 0x44, 0x3E, 0x3D, 0x3D, 0x3F, 0x42, 0x44, 0x4B, 0x55, 0x57, +0x5F, 0x69, 0x68, 0x63, 0x58, 0x56, 0x5B, 0x56, 0x57, 0x66, 0x79, 0xE8, 0xD9, 0xCF, 0xCB, 0xCB, +0xC8, 0xC4, 0xC5, 0xC6, 0xC9, 0xC9, 0xC6, 0xCD, 0xD4, 0xD8, 0xE2, 0xF1, 0x66, 0x5C, 0x57, 0x4C, +0x49, 0x49, 0x48, 0x49, 0x49, 0x4B, 0x51, 0x51, 0x4F, 0x53, 0x56, 0x58, 0x58, 0x54, 0x58, 0x5F, +0x5E, 0x5B, 0x63, 0xF2, 0xE5, 0xE5, 0xD7, 0xCF, 0xD2, 0xD6, 0xD1, 0xCF, 0xD6, 0xD6, 0xD2, 0xCF, +0xCE, 0xD0, 0xD8, 0xDB, 0xDB, 0xE5, 0x6D, 0x67, 0x65, 0x5C, 0x58, 0x54, 0x59, 0x5D, 0x57, 0x57, +0x5B, 0x5B, 0x59, 0x56, 0x57, 0x5A, 0x56, 0x52, 0x5A, 0x5C, 0x5D, 0x7D, 0xF1, 0xF3, 0xE7, 0xE3, +0xDF, 0xDB, 0xDA, 0xE7, 0xEC, 0xDE, 0xE5, 0xE9, 0xE6, 0xE4, 0xD6, 0xDF, 0xF8, 0xDE, 0xE9, 0x7C, +0xEE, 0xFB, 0x7A, 0x6B, 0x65, 0xFF, 0x79, 0x69, 0x6B, 0x63, 0x65, 0x62, 0x56, 0x5A, 0x60, 0x55, +0x58, 0x62, 0x5E, 0x64, 0x79, 0x7C, 0x78, 0xED, 0xE1, 0xEC, 0xF0, 0xE4, 0xF0, 0x6E, 0x7C, 0xED, +0xDD, 0xDB, 0xFE, 0x73, 0xED, 0xF0, 0xFF, 0xF9, 0xDE, 0xDC, 0x76, 0x6E, 0xFB, 0x7B, 0xFB, 0x6F, +0x6F, 0xEF, 0x7B, 0x6E, 0xF8, 0xE9, 0x7E, 0x5B, 0x5F, 0xF3, 0xFD, 0x67, 0x74, 0xEA, 0xEF, 0x77, +0x6D, 0x7C, 0xE8, 0xE2, 0xEE, 0xFB, 0xE6, 0xED, 0x66, 0x6C, 0x7B, 0x7C, 0xF4, 0xEF, 0xE2, 0xE6, +0x72, 0x70, 0xF0, 0xEE, 0x6E, 0x6B, 0xFB, 0xF5, 0xF6, 0x71, 0x6A, 0x6C, 0x65, 0x67, 0x5F, 0x5D, +0x6B, 0x62, 0x65, 0xFD, 0xED, 0xE9, 0xF2, 0xED, 0xE3, 0xE7, 0xE4, 0xE8, 0xED, 0xEF, 0x66, 0x5E, +0x79, 0x7E, 0x78, 0xF5, 0xFA, 0x79, 0x7A, 0xF5, 0xE7, 0xE2, 0xE4, 0xF2, 0xFF, 0x73, 0x66, 0x6B, +0x70, 0xFD, 0xEF, 0x6F, 0x67, 0x5F, 0x5C, 0x6B, 0x6E, 0x78, 0x77, 0x6D, 0xF1, 0xF4, 0xF8, 0xE5, +0xE9, 0xEB, 0xEC, 0xEF, 0xEF, 0xF0, 0xE7, 0xED, 0x6B, 0x6F, 0xF0, 0xFF, 0x6A, 0x6F, 0x7E, 0x6F, +0x69, 0xED, 0xDF, 0xFF, 0x7C, 0xEB, 0xF3, 0xF8, 0x7E, 0x7A, 0xFB, 0x6E, 0x5E, 0x60, 0x70, 0x7A, +0xFC, 0xF4, 0xFF, 0xEF, 0xF5, 0x72, 0xF1, 0xEC, 0xEA, 0xE1, 0xE9, 0xED, 0xF2, 0xFC, 0xE7, 0xF0, +0x68, 0x76, 0xEF, 0xF4, 0xF9, 0x77, 0x79, 0xFB, 0xFC, 0xF6, 0xEE, 0xE9, 0xF2, 0x6D, 0x70, 0x6F, +0x6F, 0xFE, 0x6A, 0x69, 0x7F, 0x6F, 0x6F, 0x79, 0x78, 0x77, 0x6E, 0xFE, 0xEE, 0xF0, 0xEF, 0x7E, +0xF4, 0xE9, 0xF8, 0xFD, 0x7C, 0x77, 0x7D, 0x78, 0x7D, 0xFE, 0x79, 0x72, 0x6E, 0x72, 0x7B, 0x73, +0x6B, 0x74, 0x76, 0x6C, 0x72, 0x70, 0x75, 0x6D, 0x5A, 0x5C, 0x6A, 0x77, 0xFE, 0x71, 0x7A, 0xF2, +0xE9, 0xE7, 0xEA, 0xDE, 0xE6, 0xF5, 0xEB, 0xF5, 0xEE, 0xEA, 0xF3, 0xEE, 0xF4, 0xEE, 0xF5, 0x73, +0xF4, 0xF6, 0x73, 0x7C, 0xEC, 0xE9, 0x72, 0x67, 0x6C, 0x70, 0x6E, 0x69, 0x6F, 0x68, 0x5D, 0x64, +0x71, 0x75, 0x6B, 0x6D, 0xF9, 0x79, 0x6F, 0xF4, 0xEA, 0xF5, 0x79, 0x7B, 0x7D, 0xFA, 0xF3, 0xF7, +0xF4, 0xF4, 0xF9, 0x7F, 0x77, 0x7F, 0xF5, 0xFD, 0x71, 0x71, 0x7B, 0x78, 0x7A, 0x73, 0x68, 0x71, +0x7A, 0x6B, 0x6C, 0x6E, 0x69, 0x6E, 0x71, 0x6C, 0x69, 0x6C, 0x7A, 0x7D, 0xF6, 0xEB, 0xF4, 0xF2, +0xF4, 0x78, 0xF8, 0xF1, 0xF6, 0xFE, 0x71, 0x75, 0x7C, 0x7B, 0x7D, 0x7E, 0xFB, 0x7E, 0x77, 0x76, +0xFF, 0xF7, 0x79, 0x70, 0x6E, 0x6C, 0x71, 0x6F, 0x6C, 0x6A, 0x70, 0x6E, 0x5F, 0x65, 0x6C, 0x66, +0x6D, 0x7A, 0xF1, 0x78, 0x6B, 0xED, 0xFB, 0x6C, 0x7C, 0x74, 0xF1, 0xEC, 0x76, 0xF9, 0xF8, 0x75, +0x71, 0x7A, 0xEC, 0xFA, 0x6C, 0x76, 0x7C, 0x7F, 0x6E, 0x6A, 0x76, 0x6C, 0x76, 0xF2, 0x7C, 0x76, +0x66, 0x62, 0x7D, 0xF9, 0x78, 0x69, 0x6A, 0xF8, 0x78, 0x6D, 0xFC, 0xF8, 0xF3, 0xF7, 0x7D, 0xEF, +0xF1, 0x7C, 0xF1, 0xE9, 0xEB, 0xEE, 0xF3, 0xFD, 0x73, 0x7D, 0xFA, 0x74, 0x78, 0x7A, 0x6E, 0x70, +0x76, 0x73, 0x6F, 0x6D, 0x6C, 0x68, 0x6D, 0x7D, 0x6E, 0x64, 0x6D, 0xFC, 0xFA, 0x71, 0x6F, 0xFF, +0x70, 0x70, 0xF0, 0xEE, 0xEF, 0xEB, 0xEC, 0xEC, 0xED, 0xF0, 0xEE, 0xE9, 0xEB, 0xF8, 0xFB, 0xED, +0xE9, 0xF7, 0xFF, 0xED, 0xEE, 0xEF, 0xF3, 0x6E, 0x70, 0xF3, 0xFF, 0x6F, 0x6F, 0x6F, 0x79, 0x7C, +0x79, 0x7E, 0x77, 0x6E, 0x6E, 0x7B, 0x7C, 0x6B, 0x72, 0xF6, 0xFF, 0x7D, 0x7D, 0x72, 0x78, 0xFB, +0xFD, 0xFB, 0xFA, 0x7D, 0x7A, 0x6D, 0x68, 0x74, 0x75, 0xF1, 0xE7, 0x7B, 0x76, 0x6B, 0x66, 0xFD, +0x73, 0x68, 0x6B, 0x73, 0x7C, 0x62, 0x64, 0x70, 0x64, 0x6D, 0x79, 0x70, 0x70, 0x74, 0xF8, 0x7C, +0x7C, 0xF8, 0x6B, 0x70, 0xF9, 0x7D, 0xF1, 0xF0, 0xFF, 0x7F, 0xF8, 0xED, 0xF2, 0xFC, 0xFF, 0x76, +0x7B, 0x7C, 0xFE, 0xFE, 0x6C, 0x7C, 0xED, 0x79, 0x77, 0x71, 0x69, 0x76, 0x7A, 0x76, 0x7A, 0x6F, +0x6E, 0x6E, 0x73, 0xFF, 0x78, 0x76, 0x7F, 0x7A, 0x6F, 0x78, 0xFE, 0x77, 0xFB, 0xEE, 0xEE, 0xF1, +0x7A, 0xFB, 0xEE, 0x75, 0x70, 0xFE, 0x7D, 0x72, 0x6D, 0x6F, 0x7B, 0xFB, 0xF9, 0x7C, 0x7E, 0x7A, +0x70, 0x76, 0x7B, 0xF7, 0xF5, 0x70, 0x74, 0xFF, 0x78, 0xFA, 0xFC, 0x79, 0x78, 0x6D, 0x7A, 0xFA, +0x77, 0xFC, 0xF4, 0xF1, 0xF1, 0xF7, 0xEB, 0xED, 0xFB, 0xF7, 0xEF, 0xF2, 0x78, 0x79, 0xF0, 0xF3, +0xFC, 0xFC, 0x7E, 0x77, 0xFF, 0xFC, 0x78, 0xF6, 0xF9, 0x6F, 0x7A, 0x78, 0x6F, 0xFF, 0xF9, 0x7E, +0x76, 0x72, 0x76, 0x78, 0x79, 0xFD, 0xFA, 0x7A, 0x7E, 0xF1, 0xFB, 0x7A, 0xF2, 0xEF, 0xFF, 0x74, +0x75, 0x7E, 0xFF, 0xF6, 0xE9, 0xF4, 0x71, 0x74, 0x74, 0x7C, 0xF8, 0x79, 0x75, 0x74, 0x73, 0xF9, +0xFE, 0xFF, 0xFA, 0x6A, 0x6C, 0xFE, 0x70, 0x72, 0x7C, 0x7D, 0x70, 0x67, 0x6F, 0x76, 0x7B, 0xF0, +0x7E, 0x6E, 0x6E, 0x76, 0xF1, 0xF2, 0x7A, 0x72, 0x7B, 0xFD, 0x79, 0x77, 0x6E, 0x6A, 0x6D, 0x6E, +0x74, 0x72, 0x77, 0xF5, 0x7C, 0x6D, 0x6C, 0x6D, 0x70, 0x76, 0xFD, 0xFC, 0xFF, 0xFE, 0xFE, 0xFA, +0x7D, 0x77, 0x74, 0x6F, 0xFB, 0xFA, 0x71, 0xFC, 0xF8, 0xFE, 0xEB, 0xE5, 0xEE, 0x7F, 0xF6, 0xED, +0xFA, 0x78, 0xF6, 0xF1, 0xF8, 0xF6, 0x79, 0x70, 0x7C, 0x75, 0x78, 0xF6, 0xFA, 0xFC, 0xFB, 0x7B, +0x7D, 0xF9, 0xF7, 0xF7, 0x7E, 0x6B, 0x68, 0xFA, 0xE6, 0xEE, 0x7B, 0x7B, 0x79, 0x7E, 0xFB, 0xF2, +0xEA, 0xEE, 0xF1, 0xF6, 0x79, 0xFB, 0xF0, 0xFB, 0xFF, 0xF0, 0xEE, 0xF4, 0xEF, 0xFB, 0x6F, 0x6C, +0x72, 0xFF, 0x71, 0x6C, 0x6A, 0x6D, 0xF4, 0xFB, 0x7C, 0xF3, 0xFA, 0xFC, 0x6F, 0x73, 0xFB, 0x72, +0x7D, 0x78, 0x76, 0xEF, 0xF3, 0x7C, 0x71, 0xFA, 0xF2, 0xFB, 0xEF, 0xF0, 0xEA, 0xFD, 0x6B, 0xED, +0xF2, 0x77, 0x6E, 0x6D, 0xFD, 0x64, 0xF3, 0xDF, 0x5C, 0x61, 0xED, 0xF2, 0x7E, 0x66, 0x73, 0x6E, +0x66, 0xFF, 0x6F, 0x72, 0x70, 0x66, 0xF3, 0xF7, 0x6F, 0x72, 0x75, 0xED, 0xEF, 0xF4, 0xED, 0xEF, +0xEF, 0x6E, 0x6F, 0xF7, 0x72, 0x7E, 0x78, 0x6F, 0xF9, 0x77, 0xFC, 0xF4, 0x6C, 0x66, 0x6A, 0x76, +0x65, 0x5C, 0x6D, 0xFF, 0xF8, 0xEA, 0xE2, 0xEF, 0x65, 0x70, 0xEB, 0xE8, 0xE2, 0xDF, 0xDA, 0xD9, +0xE3, 0xF0, 0xFA, 0xE6, 0xDD, 0xDF, 0xDF, 0xE0, 0xE4, 0xFC, 0x63, 0x60, 0x64, 0x63, 0x66, 0x78, +0x65, 0x57, 0x60, 0x67, 0x64, 0x67, 0x5F, 0x6E, 0xF3, 0x7F, 0x75, 0xFE, 0xEA, 0xF4, 0xF8, 0xE0, +0xE0, 0xE4, 0xE3, 0xE7, 0xEA, 0xFB, 0x6F, 0x6E, 0x75, 0x72, 0x68, 0x6E, 0x77, 0x74, 0x6D, 0x73, +0xF9, 0x74, 0xF2, 0xE2, 0xEF, 0xDE, 0xDD, 0x79, 0xFD, 0xF4, 0x6F, 0x6A, 0x6E, 0xFE, 0x7A, 0x68, +0x60, 0x63, 0x6B, 0x66, 0x67, 0x76, 0xFE, 0x78, 0x65, 0x63, 0x7A, 0xFF, 0x72, 0x72, 0x74, 0x7D, +0x7C, 0x6B, 0x72, 0xEF, 0xF6, 0x73, 0x74, 0x7C, 0x74, 0x68, 0x68, 0x73, 0xFA, 0xF6, 0x6F, 0x67, +0x6F, 0x6D, 0x6A, 0x69, 0x68, 0x74, 0x6D, 0x64, 0x6F, 0x75, 0x77, 0xFA, 0x7F, 0xF5, 0xEF, 0x78, +0x77, 0x7D, 0x7A, 0xFE, 0x77, 0x73, 0xF8, 0xF4, 0xFE, 0x6F, 0x71, 0xF7, 0x74, 0x79, 0xEF, 0x7B, +0xF9, 0xFA, 0x68, 0x71, 0x7F, 0x76, 0x73, 0x71, 0x7D, 0x7D, 0x65, 0x5D, 0x69, 0x6E, 0x5F, 0x67, +0x6F, 0x6D, 0xFF, 0x7F, 0x6E, 0x6F, 0x73, 0x77, 0xF2, 0xDE, 0xD4, 0xD0, 0xD0, 0xCF, 0xCE, 0xD0, +0xD2, 0xD6, 0xDA, 0xDB, 0xE7, 0x6D, 0x5B, 0x52, 0x4C, 0x47, 0x44, 0x43, 0x44, 0x47, 0x49, 0x4B, +0x4E, 0x52, 0x56, 0x5A, 0x5D, 0x64, 0x75, 0xE6, 0xCF, 0xC5, 0xBF, 0xBD, 0xBB, 0xB7, 0xB5, 0xB1, +0xAF, 0xB5, 0xC1, 0xDF, 0x51, 0x44, 0x3A, 0x33, 0x33, 0x37, 0x3D, 0x44, 0x48, 0x4D, 0x51, 0x54, +0x53, 0x4D, 0x49, 0x44, 0x43, 0x45, 0x46, 0x4C, 0x54, 0x65, 0xE4, 0xCF, 0xC4, 0xBB, 0xB4, 0xAF, +0xAD, 0xAC, 0xAA, 0xAB, 0xB5, 0xD1, 0x49, 0x3B, 0x35, 0x2F, 0x2D, 0x32, 0x3D, 0x4E, 0x57, 0x51, +0x4F, 0x50, 0x4C, 0x42, 0x3D, 0x3F, 0x46, 0x4A, 0x4F, 0x5E, 0xEC, 0xD9, 0xDA, 0xD2, 0xC8, 0xBE, +0xB7, 0xB0, 0xAD, 0xAB, 0xA9, 0xA8, 0xAD, 0xC4, 0x48, 0x36, 0x31, 0x2E, 0x2D, 0x30, 0x3E, 0x67, +0xE2, 0x63, 0x47, 0x43, 0x42, 0x39, 0x36, 0x3B, 0x46, 0x6B, 0xE1, 0xDB, 0xCC, 0xC8, 0xCC, 0xD7, +0xDD, 0xC6, 0xBA, 0xB2, 0xAC, 0xAA, 0xA7, 0xA7, 0xB0, 0x69, 0x32, 0x2D, 0x2D, 0x2C, 0x2D, 0x39, +0xF1, 0xC2, 0xCA, 0x5E, 0x3D, 0x38, 0x34, 0x2E, 0x2F, 0x3E, 0x69, 0xCC, 0xC3, 0xBD, 0xBD, 0xC2, +0xCD, 0xEC, 0xF4, 0xCD, 0xC0, 0xB7, 0xAC, 0xA7, 0xA4, 0xA4, 0xB7, 0x3A, 0x2A, 0x29, 0x2A, 0x2B, +0x30, 0x56, 0xBA, 0xB6, 0xCD, 0x4A, 0x33, 0x2C, 0x2C, 0x2B, 0x34, 0x65, 0xC3, 0xBB, 0xBB, 0xBC, +0xC1, 0xDA, 0x7F, 0x6A, 0x75, 0xD1, 0xC2, 0xB8, 0xAC, 0xA6, 0xA5, 0xA4, 0xB0, 0x35, 0x23, 0x25, +0x29, 0x2F, 0x38, 0x73, 0xB3, 0xAF, 0xC8, 0x3E, 0x2E, 0x29, 0x26, 0x2C, 0x3D, 0xDF, 0xB8, 0xB5, +0xBB, 0xC5, 0xE7, 0x5A, 0x53, 0x68, 0xD9, 0xC8, 0xBA, 0xB3, 0xAD, 0xA8, 0xA7, 0xA6, 0xAF, 0x34, +0x1F, 0x24, 0x2E, 0x3B, 0x48, 0xDA, 0xB3, 0xB0, 0xD6, 0x33, 0x29, 0x29, 0x29, 0x2F, 0x5B, 0xC3, +0xB9, 0xB8, 0xC1, 0xDB, 0x53, 0x46, 0x4E, 0xEE, 0xCB, 0xC5, 0xBF, 0xBA, 0xB6, 0xAE, 0xAA, 0xA8, +0xAA, 0xDB, 0x26, 0x20, 0x2B, 0x3E, 0x5E, 0xEE, 0xC1, 0xB6, 0xC1, 0x3F, 0x2A, 0x29, 0x2A, 0x2F, +0x4F, 0xCA, 0xC0, 0xBE, 0xC5, 0xDC, 0x51, 0x44, 0x4B, 0x7D, 0xCB, 0xC5, 0xC5, 0xC2, 0xBF, 0xBD, +0xB1, 0xA9, 0xA8, 0xAA, 0xCB, 0x28, 0x20, 0x2C, 0x44, 0x7E, 0xDE, 0xC8, 0xBB, 0xC6, 0x3F, 0x2B, +0x29, 0x2E, 0x35, 0x4C, 0xCB, 0xBF, 0xC3, 0xCA, 0xE6, 0x4E, 0x43, 0x44, 0x6A, 0xC8, 0xC3, 0xC3, +0xC8, 0xC8, 0xBE, 0xB5, 0xAB, 0xA7, 0xA8, 0xBC, 0x2D, 0x1F, 0x29, 0x42, 0xD7, 0xD0, 0xCD, 0xBF, +0xC5, 0x4C, 0x2E, 0x2B, 0x2F, 0x36, 0x4A, 0xD7, 0xBE, 0xBD, 0xD5, 0x74, 0x50, 0x42, 0x45, 0x53, +0xD1, 0xBE, 0xBE, 0xC5, 0xD2, 0xCD, 0xBC, 0xAE, 0xA7, 0xA7, 0xB5, 0x36, 0x21, 0x28, 0x41, 0xD1, +0xC9, 0xD4, 0xCB, 0xCB, 0x51, 0x31, 0x2B, 0x2F, 0x39, 0x47, 0xE9, 0xC5, 0xC0, 0xCD, 0xED, 0x50, +0x3F, 0x3F, 0x52, 0xCD, 0xBB, 0xBC, 0xC6, 0xDE, 0xE7, 0xCB, 0xB5, 0xA8, 0xA4, 0xA9, 0xCC, 0x28, +0x20, 0x2E, 0x6F, 0xC2, 0xCF, 0xF7, 0xDA, 0xEB, 0x3F, 0x2E, 0x2D, 0x34, 0x3E, 0x5D, 0xCD, 0xBF, +0xC7, 0x73, 0x53, 0x43, 0x3C, 0x49, 0xDD, 0xBC, 0xB7, 0xC2, 0xE4, 0x62, 0xEC, 0xBD, 0xAA, 0xA3, +0xA4, 0xB3, 0x32, 0x1F, 0x26, 0x42, 0xC3, 0xC0, 0xF2, 0x68, 0x73, 0x4D, 0x37, 0x2D, 0x2F, 0x39, +0x47, 0xDD, 0xC2, 0xBE, 0xD2, 0x4A, 0x3E, 0x3B, 0x42, 0xEB, 0xBE, 0xB5, 0xB9, 0xD5, 0x54, 0x54, +0xCB, 0xAD, 0xA3, 0xA2, 0xAC, 0x4D, 0x23, 0x21, 0x34, 0xCF, 0xBA, 0xD0, 0x5E, 0x73, 0x5D, 0x43, +0x34, 0x30, 0x38, 0x3C, 0x46, 0xCE, 0xB9, 0xBE, 0x5F, 0x3E, 0x3B, 0x3E, 0x62, 0xC0, 0xB5, 0xB6, +0xC9, 0x54, 0x48, 0xE3, 0xB1, 0xA4, 0xA0, 0xA6, 0xC3, 0x2B, 0x1E, 0x29, 0x5D, 0xB9, 0xBD, 0x72, +0x50, 0x5B, 0x50, 0x3C, 0x30, 0x30, 0x36, 0x3F, 0x7C, 0xC0, 0xBA, 0xD0, 0x45, 0x3A, 0x38, 0x46, +0xCB, 0xB7, 0xB5, 0xC4, 0x5A, 0x48, 0x62, 0xBA, 0xA8, 0xA1, 0xA3, 0xB0, 0x3C, 0x20, 0x20, 0x39, +0xBD, 0xB1, 0xC7, 0x4F, 0x4A, 0x4E, 0x48, 0x35, 0x2E, 0x31, 0x39, 0x56, 0xC0, 0xB8, 0xC2, 0x4D, +0x39, 0x37, 0x3E, 0xE2, 0xBC, 0xB6, 0xBB, 0xDC, 0x4B, 0x4A, 0xD3, 0xAE, 0xA3, 0xA0, 0xA8, 0xD5, +0x29, 0x1F, 0x2B, 0xE3, 0xB3, 0xBA, 0x65, 0x47, 0x4C, 0x4F, 0x3D, 0x2F, 0x2D, 0x30, 0x41, 0xCB, +0xB7, 0xBA, 0x76, 0x3D, 0x38, 0x39, 0x51, 0xC5, 0xB6, 0xB6, 0xCC, 0x50, 0x46, 0x7E, 0xB4, 0xA6, +0xA1, 0xA4, 0xB8, 0x35, 0x20, 0x25, 0x48, 0xB8, 0xB5, 0xDB, 0x47, 0x47, 0x52, 0x4A, 0x34, 0x2D, +0x2E, 0x39, 0xEC, 0xBA, 0xB6, 0xCF, 0x3F, 0x38, 0x37, 0x41, 0xD0, 0xB8, 0xB4, 0xBF, 0x6A, 0x4A, +0x5B, 0xBC, 0xA8, 0xA1, 0xA2, 0xAF, 0x3E, 0x22, 0x24, 0x3E, 0xBA, 0xB3, 0xD4, 0x45, 0x41, 0x4F, +0x52, 0x37, 0x2D, 0x2D, 0x36, 0x65, 0xBB, 0xB6, 0xC9, 0x46, 0x38, 0x35, 0x3D, 0xDC, 0xB7, 0xB0, +0xBA, 0xF0, 0x48, 0x4E, 0xC1, 0xAA, 0xA2, 0xA1, 0xAB, 0x5E, 0x27, 0x21, 0x32, 0xC7, 0xB4, 0xC8, +0x48, 0x3E, 0x4B, 0x58, 0x3D, 0x2E, 0x2C, 0x2F, 0x48, 0xBF, 0xB5, 0xBF, 0x4C, 0x36, 0x34, 0x3A, +0x67, 0xBC, 0xB2, 0xB7, 0xD6, 0x4C, 0x4A, 0xCE, 0xAD, 0xA3, 0xA0, 0xA7, 0xD8, 0x29, 0x20, 0x2F, +0xD2, 0xB5, 0xC4, 0x4C, 0x40, 0x4B, 0x64, 0x44, 0x2F, 0x2C, 0x2D, 0x3F, 0xC4, 0xB4, 0xB9, 0x5F, +0x39, 0x36, 0x39, 0x5D, 0xBE, 0xB3, 0xB4, 0xC8, 0x59, 0x4B, 0xDC, 0xAF, 0xA3, 0x9F, 0xA5, 0xC5, +0x2C, 0x21, 0x2C, 0xFB, 0xB9, 0xC1, 0x53, 0x42, 0x4A, 0x5F, 0x49, 0x31, 0x2C, 0x2C, 0x3A, 0xCF, +0xB6, 0xBA, 0xF7, 0x3E, 0x39, 0x3A, 0x4C, 0xCA, 0xB7, 0xB4, 0xBF, 0x79, 0x4D, 0xE5, 0xB1, 0xA4, +0x9F, 0xA4, 0xC6, 0x2B, 0x20, 0x2C, 0xEC, 0xB7, 0xC1, 0x57, 0x43, 0x49, 0x5C, 0x47, 0x31, 0x2C, +0x2C, 0x39, 0xD3, 0xB7, 0xBA, 0xDC, 0x46, 0x3C, 0x39, 0x47, 0xCE, 0xB9, 0xB5, 0xBD, 0xDE, 0x5E, +0xD3, 0xB0, 0xA4, 0xA0, 0xA6, 0xCF, 0x2A, 0x21, 0x2D, 0xF6, 0xBB, 0xC8, 0x55, 0x44, 0x48, 0x51, +0x3F, 0x2F, 0x2C, 0x2D, 0x3B, 0xD8, 0xBC, 0xBF, 0xE7, 0x4E, 0x45, 0x3C, 0x44, 0xEB, 0xBE, 0xB5, +0xBA, 0xCA, 0xE3, 0xC9, 0xAF, 0xA5, 0xA0, 0xA7, 0xE6, 0x28, 0x22, 0x2E, 0xEA, 0xBD, 0xC8, 0x5D, +0x46, 0x4A, 0x4D, 0x3B, 0x2F, 0x2D, 0x2F, 0x3F, 0xD0, 0xBE, 0xC3, 0xE6, 0x56, 0x4B, 0x43, 0x4C, +0xFA, 0xC8, 0xBB, 0xBB, 0xC3, 0xC8, 0xBD, 0xAE, 0xA7, 0xA3, 0xAA, 0x6C, 0x2A, 0x25, 0x30, 0x5A, +0xCD, 0xD3, 0x5F, 0x4D, 0x50, 0x4C, 0x3B, 0x2F, 0x2D, 0x2F, 0x3D, 0xE6, 0xCC, 0xD3, 0xDA, 0xDB, +0x79, 0x55, 0x56, 0x68, 0xE0, 0xCA, 0xC2, 0xC0, 0xBC, 0xB1, 0xAB, 0xA6, 0xA5, 0xAE, 0x53, 0x2C, +0x29, 0x30, 0x41, 0x59, 0x62, 0x53, 0x57, 0x7F, 0x5D, 0x40, 0x35, 0x2E, 0x2F, 0x3D, 0x58, 0x78, +0xE5, 0xCD, 0xC8, 0xCF, 0xDA, 0xEC, 0x7B, 0xE4, 0xD1, 0xCA, 0xC4, 0xBA, 0xB0, 0xAC, 0xAA, 0xAB, +0xBA, 0x4F, 0x39, 0x39, 0x3D, 0x3F, 0x42, 0x3D, 0x3C, 0x45, 0x51, 0x52, 0x4C, 0x42, 0x3B, 0x3E, +0x4A, 0x4C, 0x4D, 0x57, 0x69, 0xEE, 0xDE, 0xE4, 0xFD, 0xED, 0xDC, 0xD3, 0xCD, 0xCA, 0xC3, 0xBD, +0xB9, 0xB6, 0xB8, 0xC3, 0xCE, 0xC8, 0xC1, 0xC5, 0xCE, 0xF9, 0x4A, 0x3F, 0x3F, 0x41, 0x3F, 0x3D, +0x39, 0x38, 0x3B, 0x3C, 0x3A, 0x3C, 0x43, 0x4C, 0x52, 0x58, 0x5B, 0x59, 0x65, 0xDC, 0xCB, 0xC3, +0xBD, 0xB8, 0xB6, 0xB2, 0xAF, 0xB2, 0xB6, 0xB2, 0xB0, 0xB6, 0xBF, 0xD7, 0x4F, 0x40, 0x3F, 0x3D, +0x3A, 0x35, 0x2F, 0x2D, 0x2F, 0x32, 0x33, 0x34, 0x39, 0x3E, 0x46, 0x51, 0x59, 0x5C, 0x6F, 0xD8, +0xC6, 0xBD, 0xB8, 0xB4, 0xB2, 0xAF, 0xAC, 0xAD, 0xAF, 0xAE, 0xAE, 0xB2, 0xBC, 0xCF, 0x55, 0x42, +0x3E, 0x3B, 0x36, 0x31, 0x2D, 0x2A, 0x2B, 0x2F, 0x32, 0x33, 0x36, 0x3B, 0x40, 0x4A, 0x57, 0x69, +0xEE, 0xD6, 0xC8, 0xBF, 0xB9, 0xB3, 0xB1, 0xAF, 0xAC, 0xAB, 0xAE, 0xAF, 0xAF, 0xB1, 0xB9, 0xC6, +0x75, 0x46, 0x3D, 0x3A, 0x36, 0x30, 0x2D, 0x2B, 0x2A, 0x2D, 0x31, 0x34, 0x36, 0x39, 0x3E, 0x46, +0x56, 0x77, 0xE3, 0xD4, 0xCA, 0xC3, 0xBD, 0xB6, 0xB1, 0xAF, 0xAC, 0xAB, 0xAC, 0xAF, 0xAF, 0xB0, +0xB5, 0xBE, 0xDA, 0x4E, 0x3E, 0x3A, 0x36, 0x31, 0x2D, 0x2C, 0x2B, 0x2C, 0x2F, 0x32, 0x34, 0x38, +0x3D, 0x43, 0x4D, 0x66, 0xE7, 0xD6, 0xCB, 0xC5, 0xC0, 0xBA, 0xB3, 0xAF, 0xAD, 0xAB, 0xAC, 0xAE, +0xAF, 0xAF, 0xB3, 0xBB, 0xCD, 0x5A, 0x40, 0x3A, 0x36, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2F, 0x31, +0x32, 0x38, 0x3D, 0x41, 0x4B, 0x5C, 0xF8, 0xD8, 0xCA, 0xC3, 0xBF, 0xBA, 0xB4, 0xB0, 0xAD, 0xAB, +0xAB, 0xAE, 0xAF, 0xB0, 0xB3, 0xBA, 0xC9, 0x68, 0x46, 0x3C, 0x37, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, +0x2F, 0x30, 0x31, 0x36, 0x3C, 0x3F, 0x49, 0x58, 0x70, 0xDD, 0xCA, 0xC2, 0xBE, 0xB9, 0xB3, 0xB0, +0xAD, 0xAA, 0xAB, 0xAE, 0xAF, 0xAF, 0xB4, 0xBC, 0xCB, 0x61, 0x46, 0x3D, 0x36, 0x30, 0x2E, 0x2C, +0x2B, 0x2D, 0x2F, 0x2F, 0x31, 0x37, 0x3B, 0x3F, 0x4B, 0x5C, 0xFF, 0xD8, 0xC8, 0xC1, 0xBC, 0xB6, +0xB2, 0xAF, 0xAC, 0xAA, 0xAB, 0xAD, 0xAE, 0xAF, 0xB5, 0xBD, 0xCF, 0x5C, 0x45, 0x3C, 0x35, 0x2F, +0x2D, 0x2C, 0x2C, 0x2D, 0x2F, 0x2F, 0x32, 0x37, 0x3B, 0x3F, 0x4B, 0x5F, 0xEE, 0xD4, 0xC8, 0xC1, +0xBC, 0xB5, 0xB0, 0xAE, 0xAB, 0xAA, 0xAB, 0xAD, 0xAF, 0xB1, 0xB7, 0xC0, 0xD9, 0x53, 0x42, 0x3B, +0x34, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x30, 0x33, 0x37, 0x3C, 0x43, 0x4D, 0x5E, 0xEC, 0xD0, +0xC7, 0xC0, 0xBB, 0xB6, 0xB0, 0xAE, 0xAB, 0xAA, 0xAC, 0xAE, 0xAF, 0xB3, 0xB9, 0xC5, 0xE2, 0x4E, +0x3F, 0x39, 0x32, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x2F, 0x33, 0x39, 0x3D, 0x44, 0x4F, 0x65, +0xE3, 0xCE, 0xC5, 0xBF, 0xBA, 0xB4, 0xAF, 0xAD, 0xAA, 0xAA, 0xAC, 0xAE, 0xB0, 0xB5, 0xBB, 0xC8, +0xF8, 0x4C, 0x3E, 0x38, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2E, 0x2F, 0x31, 0x35, 0x39, 0x3E, 0x4A, +0x5C, 0xF9, 0xD8, 0xCB, 0xC2, 0xBC, 0xB7, 0xB2, 0xAE, 0xAB, 0xA9, 0xAA, 0xAC, 0xAE, 0xB2, 0xB8, +0xBE, 0xCE, 0x72, 0x48, 0x3B, 0x34, 0x2F, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x36, 0x3A, +0x3E, 0x4A, 0x5F, 0xEA, 0xD0, 0xC9, 0xC1, 0xBB, 0xB5, 0xB0, 0xAE, 0xAB, 0xA9, 0xAB, 0xAC, 0xAE, +0xB4, 0xBB, 0xC4, 0xD6, 0x60, 0x45, 0x39, 0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, +0x35, 0x3A, 0x43, 0x51, 0x6A, 0xDF, 0xCB, 0xC3, 0xBD, 0xB8, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, +0xAC, 0xAF, 0xB7, 0xBD, 0xCC, 0xF1, 0x51, 0x3F, 0x36, 0x2F, 0x2D, 0x2B, 0x2A, 0x2C, 0x2D, 0x2E, +0x2F, 0x33, 0x37, 0x3B, 0x45, 0x58, 0x77, 0xD5, 0xC8, 0xC0, 0xBB, 0xB6, 0xB1, 0xAE, 0xAB, 0xA9, +0xAA, 0xAB, 0xAC, 0xB1, 0xB9, 0xC0, 0xD3, 0x6A, 0x4A, 0x3C, 0x33, 0x2E, 0x2D, 0x2B, 0x2B, 0x2C, +0x2D, 0x2E, 0x31, 0x34, 0x38, 0x3F, 0x4C, 0x5D, 0xEA, 0xCE, 0xC6, 0xBE, 0xB8, 0xB4, 0xAF, 0xAD, +0xAB, 0xAA, 0xAA, 0xAB, 0xAD, 0xB2, 0xB9, 0xC3, 0xD8, 0x61, 0x47, 0x3A, 0x32, 0x2E, 0x2C, 0x2B, +0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x38, 0x3F, 0x4D, 0x62, 0xDD, 0xCC, 0xC3, 0xBC, 0xB7, 0xB2, +0xAE, 0xAC, 0xAA, 0xAA, 0xAA, 0xAB, 0xAE, 0xB3, 0xBA, 0xC6, 0xE1, 0x55, 0x41, 0x37, 0x30, 0x2D, +0x2B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x39, 0x40, 0x4D, 0x6A, 0xD8, 0xC9, 0xC1, 0xBC, +0xB7, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, 0xAC, 0xAF, 0xB7, 0xBB, 0xC6, 0x79, 0x55, 0x44, 0x37, +0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2D, 0x2F, 0x33, 0x35, 0x39, 0x42, 0x51, 0x6C, 0xDA, 0xCA, +0xC4, 0xBE, 0xBA, 0xB6, 0xB0, 0xAD, 0xAC, 0xAC, 0xAC, 0xAD, 0xAF, 0xB4, 0xB9, 0xC0, 0xD0, 0x65, +0x47, 0x3A, 0x32, 0x2F, 0x2C, 0x2B, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x36, 0x3A, 0x3F, 0x4A, 0x5E, +0xDC, 0xCC, 0xC4, 0xBE, 0xBA, 0xB6, 0xB2, 0xAF, 0xAE, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB8, 0xBE, +0xCA, 0xE6, 0x4F, 0x3F, 0x38, 0x31, 0x2E, 0x2C, 0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x35, 0x3A, 0x3F, +0x4B, 0x64, 0xDD, 0xCB, 0xC3, 0xBD, 0xBA, 0xB7, 0xB4, 0xB1, 0xAF, 0xAE, 0xAE, 0xB0, 0xB3, 0xB5, +0xB9, 0xBE, 0xC6, 0xD3, 0x74, 0x4E, 0x40, 0x3A, 0x35, 0x32, 0x30, 0x2F, 0x2F, 0x30, 0x33, 0x36, +0x3A, 0x3F, 0x48, 0x52, 0x6C, 0xDF, 0xCE, 0xC7, 0xC1, 0xBE, 0xBB, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, +0xB7, 0xB9, 0xBB, 0xBE, 0xC4, 0xCA, 0xD9, 0x6C, 0x50, 0x45, 0x3D, 0x3A, 0x37, 0x35, 0x35, 0x35, +0x36, 0x37, 0x39, 0x3C, 0x3F, 0x46, 0x4F, 0x5E, 0xF1, 0xD9, 0xCF, 0xCC, 0xC9, 0xC5, 0xC1, 0xBE, +0xBC, 0xBC, 0xBC, 0xBD, 0xBF, 0xC2, 0xC4, 0xC7, 0xCC, 0xD5, 0xE8, 0x64, 0x52, 0x4A, 0x45, 0x41, +0x3F, 0x3E, 0x3D, 0x3D, 0x3E, 0x41, 0x45, 0x49, 0x4D, 0x53, 0x5C, 0x71, 0xE9, 0xDD, 0xD6, 0xD1, +0xCE, 0xCB, 0xC9, 0xC8, 0xC8, 0xC7, 0xC7, 0xC8, 0xC9, 0xCC, 0xCF, 0xD4, 0xDA, 0xE4, 0xF7, 0x69, +0x5B, 0x53, 0x4F, 0x4E, 0x4D, 0x4D, 0x4D, 0x4E, 0x51, 0x58, 0x5F, 0x68, 0x6F, 0x77, 0xFC, 0xEE, +0xE8, 0xE5, 0xE1, 0xDD, 0xDE, 0xDE, 0xDE, 0xE2, 0xE6, 0xE6, 0xEB, 0xF0, 0xED, 0xEA, 0xEC, 0xEE, +0xF8, 0x6A, 0x5C, 0x57, 0x55, 0x56, 0x58, 0x59, 0x58, 0x58, 0x5B, 0x5E, 0x63, 0x71, 0xF7, 0xEE, +0xE9, 0xE3, 0xE4, 0xE8, 0xE7, 0xEA, 0xEE, 0xEE, 0xF2, 0xFB, 0xFF, 0x7B, 0x74, 0x6E, 0x6B, 0x65, +0x60, 0x65, 0x67, 0x61, 0x60, 0x61, 0x5E, 0x5E, 0x62, 0x69, 0x70, 0x7F, 0xF6, 0xF2, 0xEC, 0xE7, +0xE6, 0xE3, 0xDF, 0xDE, 0xDE, 0xDD, 0xDE, 0xE0, 0xE5, 0xEC, 0xF6, 0x7F, 0x78, 0x75, 0x70, 0x6B, +0x64, 0x5E, 0x5A, 0x58, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x61, 0x67, 0x6C, 0x75, 0xF8, 0xEC, +0xE6, 0xE0, 0xDD, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE2, 0xE4, 0xE6, 0xE9, 0xEE, 0xF9, 0x7D, 0x75, +0x6E, 0x6A, 0x65, 0x61, 0x5E, 0x5C, 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x63, 0x66, 0x6C, 0x76, 0xFA, +0xEE, 0xE9, 0xE4, 0xE1, 0xDF, 0xDD, 0xDE, 0xDF, 0xE2, 0xE6, 0xEA, 0xEE, 0xF4, 0xFA, 0x7E, 0x7A, +0x75, 0x72, 0x74, 0x74, 0x71, 0x70, 0x6D, 0x6A, 0x6A, 0x6B, 0x6D, 0x70, 0x74, 0x78, 0x7A, 0x7D, +0xFA, 0xF0, 0xEA, 0xE5, 0xE3, 0xE2, 0xE0, 0xDF, 0xE1, 0xE3, 0xE4, 0xE8, 0xEB, 0xEE, 0xF4, 0xFB, +0x7E, 0x75, 0x6D, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x65, 0x64, 0x63, 0x64, 0x66, 0x69, 0x6D, 0x72, +0x77, 0x7B, 0xFE, 0xF7, 0xF0, 0xEB, 0xE8, 0xE7, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xEA, 0xED, +0xF3, 0xFC, 0x79, 0x72, 0x6F, 0x6C, 0x6B, 0x6B, 0x69, 0x66, 0x64, 0x63, 0x62, 0x63, 0x67, 0x6C, +0x73, 0x7C, 0xFE, 0xFD, 0xFA, 0xF4, 0xEE, 0xEA, 0xE5, 0xE1, 0xE1, 0xE2, 0xE5, 0xE9, 0xED, 0xEF, +0xF1, 0xF2, 0xF4, 0xF8, 0xFF, 0x76, 0x6E, 0x6A, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x61, +0x63, 0x67, 0x6B, 0x72, 0x7E, 0xFA, 0xF5, 0xF1, 0xEE, 0xED, 0xEC, 0xE9, 0xE8, 0xE7, 0xE7, 0xE9, +0xEC, 0xF0, 0xF9, 0x7D, 0x77, 0x73, 0x70, 0x6F, 0x6E, 0x6C, 0x69, 0x67, 0x65, 0x66, 0x66, 0x68, +0x69, 0x69, 0x6A, 0x6C, 0x6E, 0x75, 0x7F, 0xF8, 0xF1, 0xED, 0xEB, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, +0xEA, 0xE9, 0xEA, 0xEC, 0xEF, 0xF4, 0xFB, 0x7D, 0x77, 0x73, 0x71, 0x6F, 0x6D, 0x6B, 0x69, 0x67, +0x66, 0x67, 0x68, 0x69, 0x6B, 0x6D, 0x6F, 0x74, 0x79, 0x7F, 0xF9, 0xF3, 0xEF, 0xEE, 0xEE, 0xEE, +0xEE, 0xED, 0xED, 0xED, 0xEE, 0xEC, 0xEC, 0xF1, 0xF3, 0xF6, 0xFD, 0xFF, 0x7D, 0x78, 0x78, 0x76, +0x70, 0x6F, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0xFF, 0xFB, 0xF8, 0xF8, +0xFA, 0xFB, 0xFE, 0x7E, 0x7D, 0x7A, 0x79, 0x7A, 0x76, 0x76, 0x76, 0x72, 0x70, 0x6F, 0x6D, 0x6E, +0x6D, 0x6B, 0x6E, 0x65, 0x66, 0x57, 0x41, 0x59, 0xC7, 0x62, 0x57, 0xCD, 0x64, 0x6B, 0xCC, 0x6D, +0xF6, 0xD1, 0x69, 0x6E, 0xDA, 0x7D, 0x61, 0xEE, 0xF1, 0xFD, 0xFF, 0x6E, 0xE7, 0x74, 0x66, 0xE9, +0x6A, 0xFC, 0xF2, 0x64, 0xEE, 0x6F, 0x6B, 0x7B, 0x69, 0xF2, 0x68, 0x74, 0xEC, 0x5F, 0xED, 0xFC, +0x5F, 0xDE, 0x72, 0x65, 0xDC, 0x51, 0x4C, 0xE8, 0x5F, 0xEF, 0xD7, 0x4E, 0xF3, 0xF9, 0x52, 0xC3, +0xE2, 0x56, 0xC9, 0x5B, 0x59, 0xE4, 0x50, 0x53, 0x47, 0x66, 0xF9, 0x47, 0xC9, 0xCB, 0x59, 0xD4, +0x55, 0x58, 0xD3, 0x5C, 0xF9, 0xCE, 0xD7, 0x6D, 0x61, 0xDB, 0xE4, 0xE8, 0x70, 0x79, 0xCD, 0x6B, +0x5D, 0xEC, 0x66, 0xDC, 0x6C, 0x5F, 0xD3, 0xF9, 0xFB, 0x66, 0x55, 0xDE, 0xFB, 0x64, 0xD7, 0xDA, +0xF1, 0xF1, 0xF1, 0xE5, 0xDB, 0xF4, 0x75, 0xDF, 0xE7, 0xFD, 0x79, 0xEC, 0xD9, 0xF0, 0x6E, 0xF5, +0xE4, 0xE5, 0x64, 0x74, 0xDF, 0x7D, 0x68, 0x75, 0xF0, 0xFD, 0x7B, 0xFC, 0x7B, 0xDE, 0xEF, 0x64, +0xDF, 0xE8, 0xFF, 0xE9, 0xFF, 0xE2, 0xE1, 0x76, 0xF6, 0xEF, 0xEC, 0xF9, 0x6D, 0x7C, 0x73, 0x6D, +0x69, 0x67, 0x76, 0x75, 0x73, 0x64, 0x66, 0xFD, 0x60, 0x5F, 0x77, 0x67, 0x70, 0x74, 0x60, 0x78, +0x7A, 0x5C, 0x67, 0x79, 0x6C, 0x77, 0x63, 0x63, 0xEF, 0x6C, 0x66, 0x73, 0x6D, 0xF8, 0x72, 0x74, +0xE6, 0xFB, 0x7B, 0xF3, 0xF6, 0xF1, 0xFE, 0x7B, 0xF5, 0xF1, 0x6D, 0x63, 0x75, 0x6E, 0x60, 0x64, +0x67, 0x67, 0x68, 0x67, 0x67, 0x6C, 0x64, 0x5B, 0x65, 0x6E, 0x69, 0x72, 0x76, 0x74, 0xFE, 0xFD, +0xFF, 0xF6, 0xF3, 0x7C, 0x7A, 0xFC, 0xFE, 0xFB, 0x7E, 0x75, 0xF5, 0xEE, 0xFC, 0xF7, 0xF3, 0xFF, +0xFE, 0x74, 0x6B, 0x6F, 0x6D, 0x6A, 0x6C, 0x6A, 0x7A, 0xF9, 0x71, 0x7C, 0xF5, 0x7C, 0x7B, 0x7F, +0xFE, 0x72, 0x6E, 0xFF, 0x6F, 0x66, 0x6B, 0x6A, 0x6E, 0x76, 0x71, 0x7C, 0x7A, 0x6E, 0x6C, 0x69, +0x6C, 0x6D, 0x63, 0x65, 0x6A, 0x66, 0x63, 0x65, 0x6C, 0x68, 0x64, 0x69, 0x6A, 0x6E, 0x79, 0x7B, +0x78, 0x6D, 0x6E, 0x79, 0x77, 0xFA, 0xED, 0xEF, 0xEF, 0xEC, 0xE8, 0xEF, 0xFB, 0xF6, 0xEF, 0xEE, +0xF7, 0xF9, 0xF3, 0xF7, 0xF1, 0xF3, 0xFD, 0xFD, 0x7A, 0x7B, 0xFE, 0x79, 0x7C, 0x7B, 0x6E, 0x72, +0x7A, 0x72, 0x71, 0x79, 0x79, 0x6F, 0x6F, 0x78, 0x74, 0x72, 0x7B, 0x72, 0x78, 0xF6, 0xF7, 0xF9, +0x78, 0x79, 0xEE, 0xF5, 0x74, 0x76, 0x7A, 0xFE, 0x7E, 0x75, 0x7A, 0x7E, 0x74, 0x70, 0x7D, 0xF8, +0xF8, 0x7D, 0x77, 0xF8, 0xF0, 0x7F, 0x7E, 0xF2, 0xED, 0xF0, 0xF4, 0xEB, 0xE9, 0xFE, 0x74, 0xEF, +0xE1, 0xE0, 0xDC, 0xD9, 0xD7, 0xD3, 0xD7, 0xDD, 0xD9, 0xD9, 0xDF, 0xE6, 0xEB, 0xF2, 0x78, 0x65, +0x61, 0x65, 0x5F, 0x5A, 0x5B, 0x5B, 0x5A, 0x5C, 0x5B, 0x5D, 0x5E, 0x5C, 0x5B, 0x5B, 0x5B, 0x5C, +0x5E, 0x6B, 0xEA, 0xD9, 0xD2, 0xD1, 0xCD, 0xC8, 0xC6, 0xC5, 0xC5, 0xC3, 0xC3, 0xC6, 0xCA, 0xD2, +0xE8, 0x67, 0x51, 0x49, 0x42, 0x3D, 0x3D, 0x3E, 0x3F, 0x41, 0x44, 0x49, 0x4E, 0x50, 0x55, 0x5A, +0x5F, 0x6F, 0xEF, 0xDA, 0xCD, 0xCA, 0xC8, 0xC4, 0xBF, 0xBD, 0xBB, 0xB9, 0xB7, 0xB6, 0xBA, 0xC2, +0xCC, 0xE2, 0x56, 0x43, 0x3B, 0x39, 0x37, 0x36, 0x37, 0x3B, 0x3E, 0x42, 0x47, 0x4B, 0x51, 0x5A, +0x5B, 0x5E, 0x67, 0x7A, 0xED, 0xE8, 0xDB, 0xCF, 0xCB, 0xC5, 0xBD, 0xB9, 0xB6, 0xB2, 0xB0, 0xB4, +0xB9, 0xBF, 0xCD, 0xFC, 0x49, 0x3B, 0x37, 0x33, 0x31, 0x32, 0x33, 0x38, 0x3E, 0x45, 0x4F, 0x5F, +0x74, 0xF0, 0xEF, 0xF1, 0xF4, 0xFF, 0x77, 0x72, 0xFB, 0xE4, 0xD9, 0xCE, 0xC3, 0xBA, 0xB6, 0xB2, +0xB0, 0xB2, 0xB6, 0xBB, 0xC8, 0xE4, 0x51, 0x3E, 0x38, 0x33, 0x2F, 0x2F, 0x31, 0x35, 0x3A, 0x3E, +0x49, 0x5D, 0xFE, 0xE4, 0xDD, 0xD9, 0xD9, 0xE1, 0xEB, 0xEE, 0xEE, 0xE7, 0xDD, 0xD2, 0xC7, 0xBD, +0xB9, 0xB5, 0xB2, 0xB5, 0xB8, 0xBB, 0xC6, 0xDA, 0x5F, 0x45, 0x3D, 0x37, 0x33, 0x31, 0x31, 0x35, +0x39, 0x3D, 0x45, 0x53, 0x6F, 0xE3, 0xD9, 0xD0, 0xCF, 0xD2, 0xD5, 0xD9, 0xD9, 0xD8, 0xD4, 0xCE, +0xC8, 0xC0, 0xBD, 0xB9, 0xB8, 0xBB, 0xBD, 0xC1, 0xCD, 0xDF, 0x5F, 0x4A, 0x41, 0x3B, 0x37, 0x36, +0x35, 0x36, 0x3A, 0x3D, 0x44, 0x4E, 0x5F, 0xEC, 0xDB, 0xD6, 0xD2, 0xD4, 0xD6, 0xDA, 0xDD, 0xDB, +0xD8, 0xD2, 0xCD, 0xC9, 0xC3, 0xBF, 0xBE, 0xBF, 0xC3, 0xC4, 0xCA, 0xD6, 0xED, 0x5E, 0x50, 0x48, +0x3F, 0x3C, 0x3B, 0x3A, 0x3A, 0x3D, 0x40, 0x4A, 0x55, 0x6A, 0xE6, 0xDC, 0xD8, 0xD6, 0xD8, 0xD8, +0xDB, 0xDE, 0xDF, 0xE2, 0xDE, 0xDC, 0xD9, 0xD0, 0xCB, 0xC8, 0xC8, 0xCC, 0xCD, 0xCD, 0xD1, 0xDB, +0xF2, 0x67, 0x5B, 0x51, 0x49, 0x44, 0x42, 0x41, 0x42, 0x44, 0x49, 0x4E, 0x55, 0x5C, 0x6A, 0x7E, +0xF3, 0xED, 0xED, 0xEF, 0xEC, 0xED, 0xF4, 0xF7, 0xF0, 0xEB, 0xE4, 0xDF, 0xDA, 0xD2, 0xCD, 0xCC, +0xCC, 0xCF, 0xCF, 0xCE, 0xD3, 0xDB, 0xE7, 0x7C, 0x69, 0x5E, 0x54, 0x4F, 0x4E, 0x4D, 0x4E, 0x4F, +0x52, 0x58, 0x5B, 0x5E, 0x63, 0x67, 0x6B, 0x6B, 0x6A, 0x6B, 0x6C, 0x6E, 0x6F, 0x73, 0x7D, 0xF3, +0xEA, 0xE1, 0xDC, 0xD8, 0xD3, 0xD1, 0xCF, 0xCE, 0xD1, 0xD2, 0xD2, 0xD6, 0xDB, 0xE2, 0xEF, 0xFD, +0x73, 0x66, 0x5F, 0x5C, 0x5A, 0x59, 0x58, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x5A, 0x5C, 0x5D, +0x61, 0x65, 0x6A, 0x74, 0x7E, 0xF4, 0xEA, 0xE2, 0xDD, 0xDA, 0xD7, 0xD5, 0xD2, 0xD1, 0xD0, 0xD1, +0xD3, 0xD3, 0xD4, 0xD7, 0xDB, 0xE0, 0xE8, 0xEF, 0x7B, 0x69, 0x5F, 0x5B, 0x57, 0x53, 0x50, 0x4F, +0x4F, 0x4F, 0x4F, 0x50, 0x52, 0x56, 0x59, 0x5C, 0x60, 0x68, 0x6E, 0x7A, 0xFB, 0xF1, 0xEB, 0xE7, +0xE2, 0xDE, 0xDC, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD3, 0xD5, 0xD5, 0xD8, 0xDC, 0xE4, 0xF2, 0x78, +0x6A, 0x5E, 0x59, 0x55, 0x52, 0x50, 0x4F, 0x4F, 0x50, 0x52, 0x55, 0x58, 0x5A, 0x5D, 0x61, 0x64, +0x69, 0x6E, 0x74, 0xFF, 0xF6, 0xEE, 0xE9, 0xE4, 0xDF, 0xDC, 0xD8, 0xD5, 0xD2, 0xD0, 0xD1, 0xD1, +0xD2, 0xD6, 0xD7, 0xDA, 0xDF, 0xE8, 0xF8, 0x71, 0x69, 0x60, 0x5C, 0x58, 0x56, 0x54, 0x53, 0x53, +0x53, 0x55, 0x56, 0x58, 0x5A, 0x5C, 0x5F, 0x63, 0x69, 0x71, 0xFF, 0xEF, 0xEA, 0xE6, 0xE1, 0xDF, +0xDE, 0xDB, 0xDA, 0xDA, 0xD7, 0xD4, 0xD1, 0xD1, 0xD2, 0xD4, 0xD7, 0xD8, 0xDB, 0xE1, 0xED, 0x78, +0x69, 0x61, 0x5A, 0x53, 0x50, 0x4F, 0x4E, 0x4F, 0x4F, 0x51, 0x55, 0x59, 0x5D, 0x60, 0x65, 0x6C, +0x6F, 0x76, 0x7E, 0xFC, 0xF5, 0xF2, 0xF2, 0xED, 0xE7, 0xE1, 0xDD, 0xD9, 0xD4, 0xCE, 0xCB, 0xCA, +0xC8, 0xCA, 0xCF, 0xD0, 0xD7, 0xE6, 0x7C, 0x5E, 0x53, 0x4F, 0x4C, 0x4A, 0x4A, 0x4A, 0x4C, 0x4E, +0x4F, 0x51, 0x57, 0x5D, 0x62, 0x66, 0x69, 0x6D, 0x6D, 0x67, 0x63, 0x65, 0x6B, 0x70, 0x75, 0xFE, +0xEA, 0xDC, 0xD3, 0xCE, 0xC9, 0xC2, 0xBE, 0xBC, 0xBC, 0xC1, 0xC8, 0xCB, 0xDC, 0x69, 0x50, 0x46, +0x42, 0x3F, 0x3D, 0x3D, 0x3F, 0x43, 0x4B, 0x4F, 0x55, 0x61, 0x6F, 0xFC, 0xF0, 0xFA, 0xFD, 0x7B, +0x63, 0x5A, 0x54, 0x52, 0x54, 0x58, 0x62, 0x7D, 0xDE, 0xCC, 0xC4, 0xBC, 0xB6, 0xB1, 0xAE, 0xB2, +0xBA, 0xC1, 0xDA, 0x5A, 0x45, 0x38, 0x33, 0x32, 0x33, 0x36, 0x3A, 0x3E, 0x4B, 0x66, 0xEA, 0xD6, +0xCE, 0xCF, 0xD3, 0xE0, 0x6E, 0x5C, 0x51, 0x4D, 0x4B, 0x4A, 0x4F, 0x5B, 0x7A, 0xD6, 0xC6, 0xBA, +0xB1, 0xAE, 0xAA, 0xAA, 0xAF, 0xBA, 0xD1, 0x4E, 0x3D, 0x31, 0x2B, 0x2B, 0x2C, 0x30, 0x38, 0x3E, +0x4E, 0xEA, 0xCD, 0xC7, 0xC8, 0xCB, 0xCE, 0xDD, 0x64, 0x4F, 0x48, 0x48, 0x47, 0x46, 0x4D, 0x62, +0xDD, 0xCA, 0xBD, 0xB1, 0xAC, 0xA9, 0xA7, 0xAA, 0xB2, 0xC4, 0x51, 0x3A, 0x2F, 0x29, 0x28, 0x2A, +0x2E, 0x39, 0x45, 0x5A, 0xDB, 0xC8, 0xC2, 0xC5, 0xCD, 0xD5, 0xE8, 0x5B, 0x4C, 0x46, 0x47, 0x4C, +0x4E, 0x59, 0xF3, 0xD3, 0xC6, 0xBE, 0xB5, 0xAD, 0xAA, 0xA6, 0xA8, 0xB2, 0xC5, 0x54, 0x38, 0x2F, +0x28, 0x26, 0x2A, 0x2F, 0x3A, 0x4B, 0x73, 0xCF, 0xC5, 0xC4, 0xC9, 0xD9, 0xF8, 0x5F, 0x4C, 0x47, +0x47, 0x48, 0x4F, 0x5A, 0x74, 0xD9, 0xCE, 0xC7, 0xBF, 0xBA, 0xB0, 0xAC, 0xAA, 0xA9, 0xB0, 0xC5, +0x5C, 0x3B, 0x30, 0x2B, 0x27, 0x29, 0x2E, 0x39, 0x49, 0x6C, 0xD2, 0xC7, 0xC5, 0xCA, 0xDA, 0x7A, +0x5E, 0x4D, 0x48, 0x49, 0x4B, 0x52, 0x5E, 0x70, 0xDC, 0xCE, 0xC9, 0xC4, 0xBE, 0xB5, 0xAE, 0xAC, +0xAA, 0xAD, 0xBB, 0xE1, 0x43, 0x35, 0x2E, 0x29, 0x28, 0x2B, 0x32, 0x3D, 0x4E, 0x7E, 0xD2, 0xC9, +0xC7, 0xCC, 0xDF, 0xFE, 0x61, 0x4F, 0x4C, 0x4B, 0x4C, 0x54, 0x5D, 0x72, 0xDA, 0xCE, 0xC7, 0xC0, +0xB9, 0xB0, 0xAD, 0xAA, 0xAA, 0xB1, 0xC5, 0x5D, 0x3D, 0x33, 0x2C, 0x29, 0x29, 0x2D, 0x35, 0x3F, +0x4F, 0x78, 0xD7, 0xCA, 0xC7, 0xCD, 0xD9, 0xE3, 0x71, 0x5C, 0x54, 0x4D, 0x4E, 0x55, 0x5A, 0x6E, +0xE3, 0xD3, 0xC8, 0xBE, 0xB6, 0xAF, 0xAC, 0xAA, 0xAC, 0xB7, 0xCE, 0x53, 0x3D, 0x34, 0x2D, 0x2A, +0x2A, 0x2E, 0x35, 0x3E, 0x4A, 0x5C, 0xE5, 0xCD, 0xC8, 0xCB, 0xCE, 0xD5, 0xE2, 0xF7, 0x66, 0x57, +0x54, 0x56, 0x5B, 0x6E, 0xE7, 0xD5, 0xC9, 0xBE, 0xB6, 0xB1, 0xAE, 0xAE, 0xB4, 0xBE, 0xD3, 0x5C, +0x46, 0x3C, 0x34, 0x30, 0x2F, 0x32, 0x38, 0x3E, 0x45, 0x4E, 0x69, 0xDC, 0xCF, 0xCD, 0xCF, 0xD3, +0xD9, 0xDF, 0xEF, 0x6F, 0x68, 0x67, 0x6F, 0xF7, 0xE7, 0xDC, 0xD2, 0xC8, 0xC1, 0xBE, 0xBC, 0xBD, +0xC3, 0xCB, 0xD5, 0xEA, 0x6A, 0x58, 0x4D, 0x47, 0x43, 0x43, 0x44, 0x47, 0x4A, 0x4D, 0x52, 0x5D, +0x6D, 0x78, 0x77, 0x78, 0x76, 0x73, 0x75, 0x72, 0x72, 0x78, 0x7E, 0xF6, 0xEB, 0xE3, 0xDC, 0xD6, +0xD2, 0xCF, 0xCE, 0xCE, 0xCD, 0xCF, 0xD2, 0xD4, 0xD7, 0xDA, 0xDD, 0xE3, 0xEF, 0x7A, 0x6C, 0x65, +0x5F, 0x5B, 0x57, 0x53, 0x4F, 0x4E, 0x4D, 0x4C, 0x4A, 0x4A, 0x4A, 0x4B, 0x4D, 0x4F, 0x53, 0x59, +0x5F, 0x6C, 0xFE, 0xEC, 0xE3, 0xDE, 0xDC, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, +0xD8, 0xDA, 0xDC, 0xDE, 0xE3, 0xEC, 0xFB, 0x6F, 0x63, 0x5B, 0x55, 0x4F, 0x4D, 0x4C, 0x4B, 0x4C, +0x4C, 0x4D, 0x4F, 0x53, 0x58, 0x5E, 0x67, 0x73, 0xFB, 0xEE, 0xE8, 0xE3, 0xDF, 0xDC, 0xDA, 0xD9, +0xD8, 0xD8, 0xD8, 0xD9, 0xDB, 0xDD, 0xDF, 0xE1, 0xE5, 0xE9, 0xEE, 0xF6, 0x7C, 0x6E, 0x66, 0x5F, +0x5C, 0x5A, 0x58, 0x56, 0x56, 0x57, 0x58, 0x5A, 0x5D, 0x60, 0x66, 0x6D, 0x74, 0x7C, 0xFB, 0xF4, +0xEE, 0xEA, 0xE7, 0xE5, 0xE4, 0xE4, 0xE4, 0xE7, 0xEA, 0xEC, 0xED, 0xED, 0xEC, 0xED, 0xEC, 0xED, +0xEE, 0xF1, 0xF9, 0x7F, 0x79, 0x75, 0x70, 0x6D, 0x6C, 0x6C, 0x6E, 0x73, 0x79, 0xFE, 0xF9, 0xF3, +0xEE, 0xEB, 0xE9, 0xE8, 0xE6, 0xE5, 0xE6, 0xE8, 0xEA, 0xED, 0xF1, 0xF8, 0xFD, 0x7E, 0x7E, 0xFE, +0xFC, 0xF9, 0xF5, 0xF5, 0xF6, 0xFB, 0x7C, 0x77, 0x71, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6B, 0x6E, +0x70, 0x75, 0x7A, 0xFE, 0xF6, 0xF1, 0xEE, 0xEC, 0xEB, 0xEB, 0xEC, 0xEE, 0xF1, 0xF5, 0xFB, 0x7D, +0x7B, 0x7A, 0x7C, 0xFE, 0xFA, 0xF4, 0xF1, 0xF0, 0xF0, 0xF3, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, 0x7F, +0x7F, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0xFD, 0xFC, 0xFA, 0xF5, 0xF4, 0xF1, 0xEF, 0xEF, 0xEF, 0xF0, +0xF4, 0xF8, 0xFD, 0x7D, 0x78, 0x77, 0x78, 0x7A, 0x7C, 0x7C, 0x7E, 0x7C, 0x7A, 0x79, 0x76, 0x77, +0x78, 0x77, 0x7B, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0x7E, 0xFE, 0xFB, +0xFA, 0xF9, 0xFA, 0xFB, 0xFE, 0x7F, 0x7C, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7C, 0x7D, 0x7E, 0x7B, +0x77, 0x74, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x76, 0x76, 0x75, 0x76, +0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x77, 0x74, 0x72, 0x70, 0x6F, 0x6E, 0x6E, 0x6E, 0x70, 0x74, +0x78, 0x7B, 0x7D, 0x7D, 0x7C, 0x7C, 0x7A, 0x76, 0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x72, 0x72, +0x74, 0x76, 0x78, 0x7B, 0x7F, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF7, 0xFC, 0xFF, 0x7C, 0x79, 0x78, +0x77, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xFA, 0xFC, 0xFE, 0x7D, 0x7A, 0x76, +0x74, 0x74, 0x73, 0x75, 0x76, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xFF, 0xFB, 0xF9, 0xF8, 0xF9, 0xFD, +0x7E, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x7C, 0x7F, 0xFB, 0xF6, 0xF5, 0xF2, 0xF2, 0xF3, +0xF4, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFA, +0xF7, 0xF6, 0xF8, 0xFC, 0x7F, 0x7C, 0x79, 0x72, 0x6F, 0x6E, 0x6E, 0x6E, 0x6F, 0x73, 0x77, 0x77, +0x7B, 0x7D, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x77, 0x75, 0x71, 0x6F, 0x6E, 0x6D, 0x6E, 0x6F, 0x70, +0x73, 0x74, 0x77, 0x79, 0x7C, 0x7D, 0x7D, 0x7D, 0x7B, 0x7A, 0x79, 0x76, 0x73, 0x70, 0x6F, 0x71, +0x73, 0x78, 0x7B, 0x7F, 0xFB, 0xF8, 0xF5, 0xF3, 0xF5, 0xF6, 0xF6, 0xF8, 0xF9, 0xFC, 0xFE, 0xFF, +0x7F, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xF7, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF7, 0xF9, +0xFA, 0xFC, 0xFF, 0xFF, 0x7F, 0x7F, 0xFE, 0xFD, 0xFE, 0xFD, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7C, +0x7A, 0x79, 0x77, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7C, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0x7E, 0x7C, 0x7E, 0x7F, 0x7E, 0x7E, 0xFF, 0xFD, 0xFC, 0xFB, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, +0xFE, 0x7D, 0x78, 0x75, 0x72, 0x70, 0x70, 0x73, 0x75, 0x76, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x78, +0x77, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7D, 0x7F, 0xFC, 0xF8, 0xF6, +0xF4, 0xF2, 0xF3, 0xF7, 0xF9, 0xFB, 0x7E, 0x78, 0x75, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, +0x75, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x76, 0x79, 0x7B, +0x7C, 0x7E, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF6, 0xF7, 0xF9, 0xFC, 0xFE, 0x7C, 0x79, 0x77, 0x76, +0x75, 0x74, 0x74, 0x75, 0x74, 0x76, 0x77, 0x78, 0x79, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x78, 0x78, +0x77, 0x76, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7C, 0xFF, 0xFD, 0xFA, 0xF8, 0xF6, 0xF7, 0xF8, 0xF7, +0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFD, 0xFC, 0xFD, 0xFE, +0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, 0x7C, +0x7C, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x71, 0x70, 0x6F, 0x6F, 0x6E, +0x6D, 0x6C, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6E, 0x6F, 0x70, 0x70, 0x72, 0x75, 0x78, 0x7B, +0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, +0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFB, +0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0x7F, 0xFC, 0xFA, 0xFB, 0xFA, 0xFA, 0xF9, +0xFA, 0xFC, 0xFC, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFD, 0xFA, 0xFA, 0xF9, 0xF8, +0xFA, 0xF8, 0xFA, 0xFA, 0xFB, 0xFE, 0xFB, 0xFF, 0xFD, 0xFD, 0xFF, 0xFB, 0xFF, 0xFA, 0xFC, 0x7F, +0xFC, 0x70, 0x6A, 0x64, 0x61, 0x67, 0x6C, 0x73, 0x61, 0x60, 0x5A, 0x47, 0x53, 0xDF, 0x7D, 0x6F, +0x71, 0x69, 0x7F, 0x72, 0x70, 0x68, 0x5A, 0x5B, 0x59, 0x55, 0x5A, 0x5D, 0x4E, 0x46, 0x51, 0x77, +0xF6, 0xEC, 0xE8, 0xE6, 0xE5, 0xE4, 0xE1, 0xE5, 0xFD, 0x60, 0x65, 0xE6, 0xDB, 0xDD, 0xE1, 0xE4, +0xE2, 0xDC, 0xD4, 0xCF, 0xCF, 0xCF, 0xD1, 0xD2, 0xCF, 0xCD, 0xCC, 0xCD, 0xD0, 0xD4, 0xD7, 0xD5, +0xCE, 0xCD, 0xD3, 0xD9, 0xDB, 0xDA, 0xD9, 0xDC, 0xE2, 0xE5, 0xF1, 0xEE, 0xD7, 0xD2, 0xD9, 0xDC, +0xDD, 0xD9, 0xDC, 0xE7, 0xDF, 0xD9, 0xDD, 0x74, 0x62, 0xFC, 0xE9, 0xF2, 0x6C, 0x5D, 0x5D, 0x61, +0x6B, 0x6C, 0x5C, 0x5D, 0x70, 0x64, 0x5B, 0x6D, 0x78, 0x61, 0x57, 0x58, 0x65, 0x62, 0x53, 0x51, +0x69, 0xF5, 0x59, 0x53, 0x69, 0x68, 0x54, 0x4F, 0x67, 0xFA, 0x5B, 0x58, 0x5D, 0x60, 0x5D, 0x4E, +0x53, 0x61, 0x5A, 0x5F, 0x63, 0x61, 0x5E, 0x4C, 0x4C, 0x5A, 0x6B, 0xF7, 0x58, 0x47, 0x51, 0x6D, +0x68, 0x5A, 0x55, 0x53, 0x4A, 0x4E, 0xEE, 0xE1, 0x56, 0x46, 0x4D, 0x74, 0x70, 0x59, 0x53, 0x4C, +0x4E, 0x62, 0xF2, 0xF3, 0x5A, 0x4A, 0x4F, 0x6D, 0x6B, 0x57, 0x63, 0xED, 0x79, 0x69, 0x62, 0x5D, +0x6C, 0x67, 0x5E, 0xF5, 0xEA, 0x69, 0x63, 0x76, 0xFA, 0x6A, 0x59, 0x5D, 0xFB, 0xF6, 0x72, 0xFB, +0x71, 0x5D, 0x65, 0x7D, 0xFC, 0x79, 0xFB, 0xE9, 0xE2, 0xDD, 0xE3, 0xF9, 0xFA, 0xF3, 0xEA, 0xEC, +0x7D, 0xF1, 0xE5, 0xF2, 0x78, 0x6D, 0x6D, 0xED, 0xE4, 0xE5, 0xE4, 0xF6, 0x7A, 0xF8, 0xE5, 0xDC, +0xEA, 0xDF, 0xCF, 0xD3, 0xE7, 0x6C, 0x78, 0xCF, 0xC9, 0xD5, 0x7E, 0x64, 0x7E, 0xD7, 0xCF, 0xD7, +0xE0, 0xE8, 0xDC, 0xCB, 0xC5, 0xCC, 0xE6, 0x73, 0xE9, 0xD2, 0xC9, 0xCA, 0xD3, 0xED, 0x68, 0xF3, +0xD9, 0xDA, 0xDC, 0xDA, 0xD7, 0xDB, 0xE1, 0xE1, 0xEA, 0x69, 0x59, 0x60, 0xEE, 0xE0, 0xDC, 0xDF, +0xE5, 0xDD, 0xE1, 0xED, 0xED, 0xF4, 0xF6, 0xF2, 0xEE, 0xED, 0xFC, 0x6F, 0x64, 0x5C, 0x5C, 0x61, +0x76, 0xEA, 0xE1, 0xEB, 0x73, 0x66, 0x60, 0x69, 0xFB, 0x7E, 0x70, 0x76, 0xFF, 0x78, 0x73, 0xEB, +0xE2, 0x6F, 0x5C, 0x69, 0xE9, 0xDB, 0xDE, 0x73, 0x5E, 0x6D, 0xED, 0xEB, 0xF4, 0xFF, 0x77, 0xFD, +0xE7, 0xE2, 0xFB, 0x66, 0x69, 0xFE, 0xFA, 0x6B, 0x63, 0x69, 0x74, 0x74, 0x66, 0x63, 0x6F, 0xFB, +0xFD, 0x73, 0x71, 0x7B, 0xF4, 0xE8, 0xE2, 0xE8, 0xF2, 0xEB, 0xDE, 0xDC, 0xDE, 0xE2, 0xE7, 0xE5, +0xDF, 0xDF, 0xE8, 0xFC, 0x6D, 0x6A, 0x66, 0x5C, 0x53, 0x51, 0x56, 0x5B, 0x59, 0x56, 0x56, 0x5A, +0x5E, 0x5A, 0x53, 0x53, 0x59, 0x5D, 0x5F, 0x64, 0x74, 0xE9, 0xD6, 0xCB, 0xCB, 0xD3, 0xDC, 0xD4, +0xC8, 0xC1, 0xBF, 0xBE, 0xBE, 0xC5, 0xCE, 0xDC, 0xEA, 0x68, 0x4B, 0x3E, 0x3B, 0x3B, 0x3D, 0x3E, +0x41, 0x45, 0x47, 0x48, 0x4A, 0x4C, 0x4A, 0x47, 0x49, 0x4F, 0x5E, 0x6D, 0xF5, 0xDB, 0xCC, 0xC5, +0xC1, 0xBF, 0xBE, 0xBC, 0xBA, 0xB7, 0xB2, 0xAF, 0xAE, 0xB7, 0xDA, 0x43, 0x38, 0x35, 0x32, 0x31, +0x33, 0x3A, 0x46, 0x54, 0x5D, 0x56, 0x4A, 0x44, 0x43, 0x46, 0x44, 0x3F, 0x40, 0x4B, 0x61, 0x7B, +0xFD, 0xE7, 0xD4, 0xCA, 0xC5, 0xBF, 0xBB, 0xB6, 0xB1, 0xAF, 0xAD, 0xAC, 0xAC, 0xB4, 0xD8, 0x3C, +0x2D, 0x2B, 0x2D, 0x2F, 0x37, 0x41, 0x54, 0x76, 0xFF, 0x68, 0x54, 0x46, 0x40, 0x44, 0x49, 0x4A, +0x49, 0x4C, 0x5C, 0xFB, 0xE9, 0xE5, 0xDB, 0xCE, 0xC8, 0xC3, 0xBE, 0xBA, 0xB6, 0xB1, 0xAE, 0xAB, +0xA9, 0xAB, 0xBD, 0x3F, 0x2A, 0x26, 0x2A, 0x31, 0x3A, 0x43, 0x58, 0xE9, 0xDB, 0xE8, 0x5E, 0x46, +0x3C, 0x3D, 0x48, 0x55, 0x56, 0x55, 0x61, 0xF3, 0xE8, 0xE6, 0xDC, 0xCF, 0xC9, 0xC0, 0xB9, 0xB4, +0xB3, 0xB3, 0xAF, 0xAA, 0xA8, 0xAF, 0x75, 0x2C, 0x22, 0x24, 0x2D, 0x3F, 0x56, 0x72, 0xE0, 0xCF, +0xD4, 0x59, 0x3F, 0x38, 0x38, 0x3E, 0x4C, 0x68, 0xE8, 0xE3, 0xEA, 0x7E, 0x67, 0x64, 0x79, 0xDC, +0xCB, 0xBF, 0xB7, 0xB1, 0xAF, 0xAE, 0xAC, 0xAA, 0xB1, 0x56, 0x29, 0x1F, 0x20, 0x2B, 0x45, 0xD1, +0xC4, 0xC7, 0xCB, 0xD8, 0x4B, 0x33, 0x2E, 0x34, 0x42, 0x6D, 0xCD, 0xC5, 0xC8, 0xD1, 0xE0, 0x69, +0x52, 0x52, 0x6D, 0xD4, 0xC6, 0xBB, 0xB1, 0xAC, 0xAB, 0xAA, 0xA8, 0xAE, 0x68, 0x28, 0x1D, 0x1E, +0x2B, 0x53, 0xBC, 0xB6, 0xBD, 0xCA, 0xE1, 0x4E, 0x33, 0x2A, 0x2C, 0x3B, 0x7D, 0xBF, 0xBB, 0xC1, +0xD5, 0xED, 0x6A, 0x4F, 0x4C, 0x58, 0x7E, 0xD6, 0xC7, 0xBB, 0xB2, 0xAD, 0xA9, 0xA6, 0xA9, 0xC3, +0x2D, 0x1D, 0x1B, 0x23, 0x41, 0xBC, 0xAF, 0xB5, 0xC2, 0xDE, 0x4F, 0x3B, 0x2D, 0x27, 0x2D, 0x49, +0xC3, 0xB5, 0xB9, 0xCB, 0x64, 0x54, 0x56, 0x51, 0x58, 0x75, 0xE3, 0xD1, 0xCA, 0xC1, 0xB6, 0xAB, +0xA6, 0xA3, 0xA6, 0xC0, 0x2B, 0x1C, 0x1A, 0x24, 0x4D, 0xB0, 0xAA, 0xB0, 0xC3, 0xF0, 0x46, 0x38, +0x2D, 0x28, 0x2B, 0x4C, 0xBC, 0xB2, 0xB6, 0xD1, 0x4B, 0x46, 0x4F, 0x58, 0x61, 0xEE, 0xE1, 0xDB, +0xCF, 0xCB, 0xBD, 0xAE, 0xA7, 0xA3, 0xA2, 0xB6, 0x2C, 0x1B, 0x19, 0x21, 0x52, 0xAB, 0xA5, 0xAE, +0xC9, 0x4F, 0x3B, 0x37, 0x32, 0x2A, 0x2A, 0x3D, 0xC9, 0xB2, 0xB1, 0xCA, 0x44, 0x3D, 0x49, 0x5F, +0xDD, 0xD8, 0x77, 0x6E, 0xED, 0xDB, 0xC7, 0xB7, 0xAB, 0xA5, 0xA3, 0xA6, 0xC8, 0x26, 0x1A, 0x1A, +0x27, 0xC5, 0xA4, 0xA3, 0xAF, 0xE9, 0x3B, 0x33, 0x34, 0x31, 0x2D, 0x31, 0x57, 0xBF, 0xB3, 0xBA, +0x78, 0x41, 0x3E, 0x4E, 0xDC, 0xCE, 0xD4, 0x78, 0x5B, 0x67, 0xDC, 0xC4, 0xB7, 0xAC, 0xA6, 0xA5, +0xA5, 0xBA, 0x2C, 0x1B, 0x19, 0x23, 0xD8, 0xA3, 0x9F, 0xAB, 0xDA, 0x34, 0x2D, 0x30, 0x33, 0x33, +0x37, 0x54, 0xC1, 0xB7, 0xBD, 0x6E, 0x41, 0x3D, 0x4A, 0xD8, 0xCA, 0xD0, 0xEB, 0x56, 0x54, 0x74, +0xCE, 0xBD, 0xAF, 0xA8, 0xA6, 0xA5, 0xAE, 0x3B, 0x1E, 0x19, 0x1E, 0x43, 0xA8, 0x9E, 0xA6, 0xC8, +0x33, 0x29, 0x2C, 0x32, 0x39, 0x3D, 0x4E, 0xCD, 0xBE, 0xC2, 0xFF, 0x40, 0x3D, 0x48, 0xE0, 0xC4, +0xCB, 0xEA, 0x4F, 0x48, 0x59, 0xD7, 0xBE, 0xB5, 0xAD, 0xA9, 0xA9, 0xA7, 0xB3, 0x34, 0x1D, 0x19, +0x20, 0xEE, 0xA2, 0x9D, 0xA8, 0x60, 0x2A, 0x26, 0x2D, 0x3B, 0x4A, 0x4E, 0x64, 0xCE, 0xC6, 0xCF, +0x57, 0x42, 0x47, 0x67, 0xCB, 0xC3, 0xD4, 0x5C, 0x48, 0x47, 0x63, 0xCA, 0xBA, 0xB2, 0xAE, 0xAC, +0xAC, 0xAB, 0xB3, 0x3D, 0x1F, 0x1B, 0x20, 0x51, 0xA5, 0x9E, 0xA8, 0x6C, 0x2A, 0x24, 0x2B, 0x3E, +0x5E, 0x6C, 0x66, 0xFA, 0xE0, 0xE4, 0x60, 0x4B, 0x4E, 0x71, 0xD2, 0xC8, 0xD8, 0x5A, 0x4A, 0x49, +0x6E, 0xC6, 0xB9, 0xB3, 0xB1, 0xAF, 0xAE, 0xAC, 0xAF, 0x48, 0x21, 0x1B, 0x1F, 0x4C, 0xA5, 0x9D, +0xA7, 0x64, 0x28, 0x23, 0x2C, 0x4A, 0xD6, 0xD9, 0x61, 0x59, 0x6C, 0xEF, 0xF8, 0x5B, 0x5B, 0xEE, +0xD5, 0xCD, 0xDB, 0x5C, 0x4D, 0x4C, 0x6E, 0xC8, 0xBB, 0xB8, 0xB8, 0xB6, 0xB3, 0xAD, 0xA8, 0xBC, +0x2D, 0x1D, 0x1B, 0x2B, 0xB7, 0x9F, 0xA1, 0xB9, 0x33, 0x23, 0x28, 0x3A, 0xEB, 0xCF, 0x77, 0x50, +0x56, 0x6E, 0xE2, 0x73, 0x55, 0x5D, 0xE6, 0xCF, 0xD9, 0x5B, 0x4B, 0x47, 0x59, 0xD2, 0xC3, 0xBD, +0xBD, 0xBC, 0xB6, 0xAE, 0xA9, 0xAB, 0x68, 0x24, 0x1B, 0x1E, 0x3C, 0xAA, 0x9E, 0xA6, 0xDE, 0x2A, +0x23, 0x2C, 0x47, 0xD1, 0xCE, 0x72, 0x55, 0x58, 0x6A, 0x78, 0x5D, 0x5B, 0xF9, 0xDA, 0xD3, 0xDE, +0x5A, 0x49, 0x4A, 0x5F, 0xD1, 0xC0, 0xBD, 0xBC, 0xB9, 0xB3, 0xAD, 0xA9, 0xB1, 0x3C, 0x1F, 0x1C, +0x24, 0xE1, 0xA4, 0x9F, 0xAD, 0x44, 0x26, 0x25, 0x32, 0x6E, 0xC3, 0xCD, 0x64, 0x4F, 0x4F, 0x62, +0x70, 0x5C, 0x68, 0xE1, 0xD4, 0xD3, 0xF6, 0x4E, 0x45, 0x4B, 0x78, 0xCA, 0xBE, 0xBC, 0xBC, 0xB8, +0xB3, 0xAC, 0xA9, 0xBC, 0x2F, 0x1E, 0x1C, 0x2A, 0xBC, 0xA0, 0xA1, 0xB7, 0x35, 0x24, 0x28, 0x3B, +0xD8, 0xC4, 0xDC, 0x53, 0x4B, 0x4F, 0x67, 0x6D, 0x65, 0xEA, 0xDB, 0xD5, 0xDA, 0x5E, 0x4B, 0x48, +0x53, 0xDB, 0xC4, 0xBD, 0xBD, 0xBB, 0xB5, 0xAE, 0xA8, 0xAB, 0x75, 0x25, 0x1B, 0x1E, 0x3D, 0xAA, +0x9E, 0xA6, 0xDC, 0x2B, 0x25, 0x2E, 0x4E, 0xCC, 0xCC, 0x66, 0x4B, 0x4C, 0x5A, 0x74, 0x6C, 0x6D, +0xDF, 0xD6, 0xD6, 0xED, 0x4D, 0x43, 0x46, 0x59, 0xD0, 0xBF, 0xBC, 0xBB, 0xB8, 0xB3, 0xAD, 0xA9, +0xB3, 0x38, 0x1E, 0x1B, 0x24, 0xCF, 0xA2, 0x9F, 0xAF, 0x3E, 0x26, 0x27, 0x36, 0x6A, 0xCD, 0xE6, +0x4F, 0x4D, 0x55, 0x6E, 0xEF, 0x63, 0x7B, 0xDA, 0xDB, 0xDF, 0x5F, 0x49, 0x47, 0x4F, 0xE8, 0xC5, +0xBD, 0xBC, 0xBB, 0xB6, 0xAF, 0xAA, 0xAA, 0xCD, 0x29, 0x1C, 0x1D, 0x34, 0xAE, 0x9F, 0xA4, 0xC7, +0x2E, 0x25, 0x2C, 0x41, 0xDB, 0xD2, 0x75, 0x5B, 0x59, 0x60, 0x6E, 0x5B, 0x5C, 0xDF, 0xD0, 0xD8, +0x74, 0x4B, 0x43, 0x4B, 0x6E, 0xCC, 0xBF, 0xBD, 0xBE, 0xBC, 0xB5, 0xAD, 0xA8, 0xAD, 0x4B, 0x22, +0x1C, 0x22, 0x65, 0xA6, 0x9F, 0xAC, 0x4C, 0x2A, 0x28, 0x33, 0x50, 0xDE, 0xF2, 0x65, 0x7C, 0xF8, +0x79, 0x5A, 0x4B, 0x5E, 0xD7, 0xCF, 0xD6, 0x5F, 0x45, 0x43, 0x4C, 0xFB, 0xC9, 0xBF, 0xBD, 0xBC, +0xB8, 0xB2, 0xAD, 0xAA, 0xB7, 0x38, 0x20, 0x1D, 0x29, 0xC6, 0xA5, 0xA4, 0xB8, 0x3C, 0x2A, 0x2C, +0x39, 0x53, 0x7F, 0x6F, 0x79, 0xE8, 0xF9, 0x61, 0x4D, 0x4B, 0xFF, 0xD0, 0xD3, 0xEC, 0x4F, 0x45, +0x49, 0x58, 0xDF, 0xC7, 0xBF, 0xBD, 0xBB, 0xB5, 0xAF, 0xA9, 0xAA, 0xCA, 0x2C, 0x1D, 0x1E, 0x36, +0xB1, 0xA2, 0xA8, 0xCE, 0x33, 0x2B, 0x30, 0x3E, 0x4F, 0x5A, 0x6D, 0xD8, 0xD2, 0xF5, 0x4F, 0x46, +0x54, 0xD4, 0xCA, 0xD7, 0x65, 0x48, 0x43, 0x4C, 0x61, 0xD7, 0xC4, 0xBF, 0xBD, 0xB7, 0xB1, 0xAD, +0xAA, 0xB0, 0x48, 0x23, 0x1D, 0x24, 0x5D, 0xAA, 0xA4, 0xB0, 0x56, 0x30, 0x2E, 0x34, 0x3E, 0x47, +0x52, 0xE3, 0xC9, 0xCE, 0x65, 0x45, 0x43, 0x6A, 0xCE, 0xCD, 0xDE, 0x58, 0x49, 0x49, 0x4F, 0x6D, +0xD1, 0xC0, 0xBB, 0xB6, 0xAF, 0xAE, 0xAA, 0xAB, 0xCF, 0x2B, 0x1D, 0x1E, 0x36, 0xB2, 0xA4, 0xA9, +0xC7, 0x3B, 0x2F, 0x31, 0x37, 0x3D, 0x46, 0x6E, 0xC7, 0xC5, 0xE5, 0x4C, 0x41, 0x50, 0xD5, 0xCB, +0xDF, 0x58, 0x4C, 0x49, 0x4E, 0x62, 0xE4, 0xC8, 0xBD, 0xB9, 0xB4, 0xAF, 0xAD, 0xA9, 0xB2, 0x41, +0x22, 0x1D, 0x26, 0xEB, 0xAA, 0xA6, 0xB3, 0x5D, 0x38, 0x32, 0x32, 0x34, 0x39, 0x4D, 0xCC, 0xBD, +0xC7, 0x60, 0x44, 0x47, 0x6D, 0xDC, 0xE2, 0xEF, 0x63, 0x58, 0x50, 0x4D, 0x5A, 0xDB, 0xC3, 0xBA, +0xB3, 0xAF, 0xAD, 0xAC, 0xAE, 0xD3, 0x2D, 0x1F, 0x20, 0x38, 0xB9, 0xA9, 0xAD, 0xC4, 0x4C, 0x39, +0x33, 0x30, 0x32, 0x3C, 0xFA, 0xBE, 0xBE, 0xD5, 0x51, 0x46, 0x4F, 0x6F, 0x7B, 0x65, 0x68, 0x76, +0x60, 0x54, 0x52, 0x61, 0xCF, 0xBF, 0xB7, 0xAE, 0xAC, 0xAB, 0xAB, 0xBC, 0x39, 0x22, 0x1E, 0x2B, +0xE7, 0xAF, 0xAC, 0xB6, 0xD1, 0x4E, 0x3A, 0x2F, 0x2D, 0x31, 0x45, 0xCC, 0xBC, 0xC2, 0xDA, 0x58, +0x4D, 0x55, 0x52, 0x52, 0x68, 0xED, 0xF4, 0x66, 0x55, 0x59, 0xEF, 0xCE, 0xBF, 0xB5, 0xAD, 0xAB, +0xAB, 0xAE, 0xCC, 0x31, 0x22, 0x22, 0x2F, 0xE8, 0xB6, 0xB1, 0xB8, 0xC4, 0x73, 0x3D, 0x2F, 0x2B, +0x2F, 0x3F, 0xDD, 0xC0, 0xBF, 0xC7, 0xD8, 0x73, 0x55, 0x46, 0x44, 0x53, 0x7B, 0xEE, 0xED, 0xF2, +0xED, 0xDC, 0xCF, 0xC1, 0xB3, 0xAC, 0xA9, 0xA9, 0xB2, 0x58, 0x2C, 0x24, 0x28, 0x36, 0x5C, 0xC7, +0xBA, 0xB6, 0xB7, 0xCA, 0x49, 0x34, 0x2D, 0x2E, 0x37, 0x49, 0xE0, 0xC4, 0xBD, 0xBE, 0xC7, 0xEA, +0x4C, 0x42, 0x44, 0x49, 0x50, 0x69, 0xDD, 0xD0, 0xCB, 0xC6, 0xBD, 0xB3, 0xAD, 0xAB, 0xAB, 0xBA, +0x49, 0x2F, 0x2B, 0x2D, 0x32, 0x3A, 0x4B, 0xD6, 0xBC, 0xB6, 0xBD, 0xD7, 0x51, 0x3D, 0x36, 0x34, +0x37, 0x3E, 0x52, 0xDE, 0xC8, 0xC3, 0xC7, 0xCE, 0xDE, 0x72, 0x56, 0x4F, 0x53, 0x5D, 0xFF, 0xDA, +0xC9, 0xBD, 0xB7, 0xB4, 0xB2, 0xB6, 0xC6, 0x62, 0x47, 0x3F, 0x3D, 0x3B, 0x3B, 0x40, 0x4E, 0x6F, +0xEC, 0x7B, 0x67, 0x5E, 0x5B, 0x59, 0x55, 0x5A, 0x65, 0x5E, 0x5A, 0x5F, 0x61, 0x5E, 0x63, 0x65, +0x61, 0x6D, 0xF5, 0xFA, 0x7A, 0x77, 0x77, 0xFF, 0xEB, 0xDC, 0xD5, 0xCE, 0xCA, 0xC8, 0xC8, 0xCD, +0xD9, 0xEC, 0x76, 0x70, 0xFD, 0xED, 0xEA, 0xEE, 0x7D, 0x66, 0x59, 0x53, 0x50, 0x4F, 0x50, 0x54, +0x56, 0x58, 0x59, 0x5A, 0x5A, 0x5C, 0x5F, 0x6B, 0xF6, 0xE5, 0xE1, 0xE7, 0xEF, 0xF5, 0xF2, 0xEA, +0xDF, 0xD8, 0xCE, 0xC8, 0xC4, 0xC5, 0xCB, 0xD4, 0xDF, 0xE9, 0xE7, 0xE1, 0xDD, 0xDB, 0xDE, 0xEE, +0x68, 0x57, 0x4F, 0x4D, 0x4D, 0x4E, 0x4F, 0x4F, 0x52, 0x54, 0x53, 0x51, 0x53, 0x57, 0x5E, 0x6F, +0xFA, 0xEF, 0xEF, 0xF3, 0xF1, 0xF1, 0xEE, 0xE6, 0xDE, 0xD6, 0xCF, 0xCD, 0xCE, 0xD3, 0xDA, 0xDC, +0xDF, 0xDF, 0xD9, 0xD5, 0xD4, 0xD7, 0xE0, 0xFE, 0x6B, 0x5F, 0x5A, 0x58, 0x56, 0x54, 0x54, 0x53, +0x53, 0x50, 0x4E, 0x4F, 0x52, 0x56, 0x5C, 0x64, 0x67, 0x66, 0x69, 0x6C, 0x6D, 0x74, 0xFA, 0xEC, +0xDF, 0xD7, 0xD6, 0xDD, 0xE6, 0xF3, 0x7B, 0xF7, 0xE8, 0xDC, 0xD3, 0xD0, 0xD2, 0xD9, 0xE1, 0xE7, +0xEB, 0xF6, 0x7B, 0x74, 0x6F, 0x6B, 0x66, 0x5E, 0x59, 0x55, 0x53, 0x52, 0x56, 0x59, 0x5C, 0x61, +0x5F, 0x64, 0x65, 0x62, 0x6F, 0x7B, 0xFC, 0xE4, 0xDC, 0xD9, 0xE2, 0x7E, 0xFF, 0xFE, 0xFF, 0xEE, +0xDF, 0xD8, 0xD6, 0xD7, 0xDB, 0xDD, 0xDD, 0xE8, 0xE7, 0xE3, 0xEA, 0xE7, 0xF9, 0x72, 0x7C, 0x5F, +0x56, 0x58, 0x58, 0x56, 0x57, 0x57, 0x53, 0x54, 0x4A, 0x42, 0x4F, 0x67, 0x6A, 0xE0, 0xD4, 0xD8, +0xD7, 0xDD, 0xFD, 0xFE, 0xE4, 0x7B, 0xFF, 0xD9, 0xDF, 0xDE, 0xD7, 0xDA, 0xCF, 0xCF, 0xD3, 0xCD, +0xD3, 0xDF, 0xDD, 0xDE, 0xF3, 0x6D, 0x5F, 0x55, 0x54, 0x55, 0x51, 0x51, 0x50, 0x4F, 0x51, 0x53, +0x57, 0x59, 0x60, 0x73, 0xFB, 0xE7, 0xE1, 0xEA, 0xF4, 0x7D, 0x6D, 0x6F, 0x7F, 0x78, 0xF5, 0xE7, +0xEA, 0xE0, 0xDE, 0xD9, 0xCD, 0xCB, 0xC5, 0xC2, 0xC5, 0xCB, 0xDB, 0xDD, 0xEC, 0x53, 0x4C, 0x45, +0x42, 0x49, 0x48, 0x49, 0x4D, 0x51, 0x5A, 0x55, 0x55, 0x5D, 0x64, 0xF4, 0xED, 0xF5, 0xEB, 0xF2, +0x7A, 0x6D, 0x60, 0x5E, 0x6E, 0xF3, 0xF7, 0xE9, 0xDF, 0xDD, 0xD4, 0xCD, 0xC8, 0xC1, 0xBC, 0xB8, +0xB5, 0xB8, 0xC7, 0xF5, 0x52, 0x3E, 0x38, 0x37, 0x36, 0x3D, 0x4B, 0x59, 0xFD, 0xDF, 0xE3, 0xFE, +0x5C, 0x54, 0x52, 0x4E, 0x50, 0x55, 0x5D, 0xFF, 0xF2, 0xF1, 0xE9, 0xFB, 0xFD, 0x74, 0x5E, 0x62, +0x7A, 0xE3, 0xD2, 0xCA, 0xC0, 0xB9, 0xB1, 0xAD, 0xAE, 0xBC, 0x68, 0x3E, 0x31, 0x2D, 0x2E, 0x30, +0x3B, 0x5B, 0xD4, 0xC7, 0xC9, 0xD6, 0x65, 0x4A, 0x46, 0x3E, 0x3D, 0x47, 0x51, 0x7F, 0xD5, 0xD0, +0xCE, 0xD2, 0xE2, 0x6E, 0x57, 0x55, 0x61, 0xEA, 0xCD, 0xBE, 0xB7, 0xB2, 0xAD, 0xAB, 0xB0, 0xCE, +0x40, 0x2F, 0x2B, 0x2D, 0x2F, 0x38, 0x59, 0xCA, 0xBD, 0xBE, 0xCF, 0x70, 0x45, 0x39, 0x3A, 0x3B, +0x3F, 0x5D, 0xD9, 0xCB, 0xC4, 0xC5, 0xCF, 0xEA, 0x62, 0x52, 0x50, 0x5C, 0x7E, 0xD1, 0xBE, 0xB5, +0xAF, 0xAE, 0xAB, 0xAC, 0xC2, 0x44, 0x2F, 0x2A, 0x2D, 0x32, 0x38, 0x55, 0xC6, 0xBA, 0xBC, 0xCF, +0x5B, 0x40, 0x36, 0x34, 0x38, 0x40, 0x66, 0xCD, 0xC4, 0xC2, 0xC6, 0xD1, 0xFE, 0x52, 0x4C, 0x4F, +0x5C, 0xEF, 0xCF, 0xC1, 0xB7, 0xAF, 0xAD, 0xAB, 0xAD, 0xC9, 0x3C, 0x2D, 0x29, 0x2D, 0x35, 0x3D, +0xF1, 0xBD, 0xB8, 0xBF, 0xE1, 0x4C, 0x3C, 0x32, 0x31, 0x39, 0x47, 0xF7, 0xCB, 0xC4, 0xC2, 0xC7, +0xD9, 0x6F, 0x54, 0x4D, 0x4F, 0x5D, 0xEF, 0xCF, 0xC1, 0xB8, 0xAF, 0xAD, 0xAB, 0xAC, 0xC9, 0x3A, +0x2C, 0x29, 0x2D, 0x37, 0x44, 0xD8, 0xB9, 0xB7, 0xC4, 0x6C, 0x44, 0x38, 0x31, 0x30, 0x39, 0x4E, +0xDF, 0xCA, 0xC5, 0xC6, 0xCD, 0xEF, 0x5E, 0x5A, 0x53, 0x55, 0x64, 0xE8, 0xCD, 0xC4, 0xBB, 0xB0, +0xAC, 0xAA, 0xAC, 0xD0, 0x36, 0x2C, 0x2B, 0x2E, 0x39, 0x4A, 0xCB, 0xB6, 0xB7, 0xC8, 0x5D, 0x43, +0x39, 0x31, 0x32, 0x3D, 0x58, 0xD9, 0xCD, 0xCA, 0xC9, 0xD6, 0x73, 0x62, 0x63, 0x62, 0x68, 0x72, +0xE9, 0xCE, 0xC6, 0xBB, 0xAF, 0xAD, 0xAB, 0xAE, 0xD7, 0x38, 0x2D, 0x2C, 0x2F, 0x3B, 0x4F, 0xCA, +0xB6, 0xB8, 0xCB, 0x5D, 0x41, 0x39, 0x32, 0x33, 0x3E, 0x59, 0xDC, 0xCF, 0xCD, 0xCB, 0xD8, 0x63, +0x53, 0x5A, 0x5E, 0x61, 0x6F, 0xEA, 0xCF, 0xC6, 0xBC, 0xB0, 0xAD, 0xAB, 0xAE, 0xEE, 0x32, 0x2C, +0x2C, 0x30, 0x3B, 0x50, 0xC9, 0xB6, 0xB9, 0xCF, 0x5D, 0x47, 0x3A, 0x32, 0x33, 0x3F, 0x63, 0xDB, +0xD5, 0xCC, 0xC8, 0xD7, 0x66, 0x56, 0x58, 0x5C, 0x5A, 0x5B, 0x7E, 0xCE, 0xC4, 0xBB, 0xB0, 0xAD, +0xAB, 0xAF, 0x7B, 0x2F, 0x2C, 0x2E, 0x31, 0x39, 0x52, 0xC6, 0xB6, 0xBA, 0xD1, 0x5C, 0x4E, 0x3E, +0x32, 0x33, 0x3F, 0x64, 0xEA, 0xFD, 0xCE, 0xC2, 0xD0, 0x6C, 0x57, 0x5D, 0x64, 0x56, 0x53, 0x6C, +0xCE, 0xC4, 0xBD, 0xB1, 0xAD, 0xAA, 0xAE, 0x6F, 0x31, 0x2F, 0x31, 0x31, 0x37, 0x4F, 0xC5, 0xB6, +0xBA, 0xD2, 0xFC, 0x60, 0x45, 0x36, 0x35, 0x41, 0x56, 0xF8, 0xF2, 0xE4, 0xC6, 0xC8, 0x7C, 0x5A, +0x6A, 0x6A, 0x57, 0x52, 0x5B, 0xDA, 0xC6, 0xC0, 0xB6, 0xAE, 0xAA, 0xAC, 0xDD, 0x33, 0x30, 0x35, +0x31, 0x30, 0x42, 0xCE, 0xBA, 0xBA, 0xCC, 0xD9, 0xD9, 0x53, 0x3A, 0x35, 0x3E, 0x4D, 0x52, 0x60, +0xD6, 0xC5, 0xD2, 0x71, 0xE7, 0x7C, 0x55, 0x53, 0x51, 0x5B, 0xEE, 0xDC, 0xD3, 0xBE, 0xB2, 0xB0, +0xAD, 0xAE, 0x67, 0x31, 0x38, 0x39, 0x2F, 0x32, 0x49, 0xD5, 0xBE, 0xBF, 0xCF, 0xCD, 0xCA, 0x5C, +0x3D, 0x3C, 0x41, 0x41, 0x47, 0x5D, 0xE1, 0xC9, 0xC7, 0xD4, 0xDD, 0xFC, 0x51, 0x4C, 0x4C, 0x4C, +0x5F, 0xE2, 0xDC, 0xCA, 0xBF, 0xBD, 0xB9, 0xB5, 0xAF, 0xBA, 0x43, 0x35, 0x44, 0x3E, 0x2F, 0x36, +0x53, 0xD4, 0xC8, 0xCC, 0xD1, 0xC3, 0xC5, 0x5E, 0x41, 0x45, 0x49, 0x42, 0x44, 0x55, 0xE9, 0xD0, +0xD1, 0xDA, 0xD6, 0xD7, 0xFD, 0x5A, 0x58, 0x5B, 0x5A, 0x5B, 0x5F, 0x6C, 0x7A, 0xE1, 0xD3, 0xD2, +0xCC, 0xC8, 0xC4, 0xBF, 0xBD, 0xBA, 0xC2, 0x49, 0x3C, 0x4C, 0x41, 0x35, 0x3B, 0x52, 0xF3, 0xD6, +0xD1, 0xCE, 0xC3, 0xC6, 0x7A, 0x53, 0x57, 0x4E, 0x44, 0x46, 0x4F, 0x64, 0xE8, 0xDF, 0xDD, 0xD4, +0xD6, 0xEC, 0x56, 0x49, 0x54, 0x5E, 0x4F, 0x57, 0xFA, 0xE1, 0xDC, 0xE0, 0xE3, 0xD6, 0xD0, 0xDC, +0xD9, 0xC9, 0xC2, 0xBD, 0xC5, 0x58, 0x50, 0xE6, 0x4B, 0x37, 0x3F, 0x4F, 0x4D, 0x52, 0x6D, 0xDD, +0xC8, 0xC8, 0xDC, 0xDC, 0xD1, 0x72, 0x4A, 0x4A, 0x4E, 0x4B, 0x4E, 0x57, 0x6A, 0xDF, 0xD7, 0xDB, +0xD5, 0xCF, 0xDA, 0xF4, 0x74, 0x67, 0x5E, 0x5E, 0x5E, 0x66, 0xF9, 0xED, 0xEC, 0xE8, 0xE4, 0xE8, +0xF4, 0xF7, 0x60, 0x52, 0x6D, 0xF3, 0x5B, 0x66, 0xE7, 0xE1, 0xE0, 0xDF, 0xDF, 0xD8, 0xD1, 0xEA, +0x6B, 0xD9, 0xD1, 0xE5, 0xE6, 0xCC, 0xC4, 0xE7, 0x52, 0xEA, 0xE4, 0x4C, 0x48, 0x59, 0x5D, 0x59, +0x5D, 0x60, 0xF7, 0xDF, 0x79, 0x6A, 0xDF, 0xDC, 0xFE, 0xF8, 0xE2, 0xF0, 0x6F, 0x6B, 0x61, 0x5F, +0x62, 0x5D, 0x5E, 0x6C, 0x76, 0x70, 0xF7, 0xE5, 0xE6, 0xE7, 0xE5, 0xEA, 0xF4, 0x7D, 0x6C, 0x66, +0x68, 0x66, 0x66, 0x73, 0xF8, 0xF3, 0xF4, 0xF6, 0xFB, 0x7E, 0x7A, 0x7E, 0xF6, 0xEF, 0xED, 0xE9, +0xE9, 0xEF, 0xFB, 0x78, 0x6E, 0x69, 0x64, 0x63, 0x68, 0x6E, 0x74, 0x7B, 0xFA, 0xF6, 0xF3, 0xFF, +0x6B, 0x69, 0x69, 0x60, 0x5F, 0x65, 0x6C, 0x73, 0x7C, 0xF3, 0xEB, 0xE9, 0xEA, 0xE8, 0xE6, 0xE6, +0xE7, 0xE4, 0xDE, 0xDD, 0xE2, 0xE2, 0xE1, 0xE9, 0xF8, 0x77, 0x6B, 0x62, 0x5D, 0x5B, 0x5A, 0x59, +0x5A, 0x5B, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x62, 0x67, 0x6D, 0x78, 0xFA, 0xF2, 0xEE, 0xEF, 0xF3, +0xF7, 0xF8, 0xFA, 0xFE, 0xFA, 0xF3, 0xF1, 0xEF, 0xEA, 0xE7, 0xE5, 0xE6, 0xE9, 0xEF, 0xFB, 0x79, +0x70, 0x6C, 0x6A, 0x6C, 0x6F, 0x77, 0x7C, 0xFD, 0xFB, 0x7F, 0x73, 0x6C, 0x69, 0x69, 0x6C, 0x73, +0xFA, 0xED, 0xE9, 0xE5, 0xE1, 0xE4, 0xE8, 0xE8, 0xE7, 0xE7, 0xE5, 0xE2, 0xE0, 0xDD, 0xDC, 0xE1, +0xE3, 0xE2, 0xEC, 0x7C, 0x6C, 0x63, 0x5D, 0x5B, 0x59, 0x58, 0x5A, 0x5B, 0x5B, 0x5C, 0x5F, 0x60, +0x5F, 0x60, 0x65, 0x6A, 0x75, 0xF8, 0xEC, 0xE7, 0xE6, 0xE7, 0xEA, 0xF0, 0xF8, 0xF9, 0xF4, 0xED, +0xE9, 0xE5, 0xE3, 0xE3, 0xE6, 0xEB, 0xF6, 0x76, 0x6C, 0x67, 0x62, 0x5F, 0x61, 0x64, 0x69, 0x6F, +0x73, 0x73, 0x75, 0x75, 0x70, 0x6E, 0x6F, 0x6E, 0x6E, 0x75, 0xFE, 0xF3, 0xEC, 0xE9, 0xE9, 0xE9, +0xED, 0xFA, 0x7A, 0x74, 0x71, 0x72, 0x73, 0x74, 0x7A, 0xFF, 0xFF, 0x7B, 0x72, 0x6E, 0x6D, 0x6C, +0x6C, 0x6E, 0x73, 0x7C, 0xFC, 0xF7, 0xF0, 0xEB, 0xE6, 0xE0, 0xDD, 0xDB, 0xDB, 0xDB, 0xDC, 0xDF, +0xE2, 0xE3, 0xE8, 0xF2, 0x7D, 0x6C, 0x61, 0x5D, 0x5A, 0x58, 0x59, 0x5C, 0x5E, 0x61, 0x66, 0x69, +0x6A, 0x6B, 0x6C, 0x6B, 0x6C, 0x75, 0xFE, 0xF7, 0xEE, 0xEA, 0xE8, 0xE6, 0xE9, 0xEC, 0xEB, 0xEB, +0xEE, 0xF0, 0xF2, 0xF6, 0xF9, 0xFD, 0x7F, 0xFF, 0x7C, 0x74, 0x6D, 0x69, 0x66, 0x64, 0x64, 0x68, +0x6B, 0x6D, 0x75, 0x7D, 0xFC, 0xF8, 0xFA, 0xFC, 0xFA, 0xF7, 0xF5, 0xF0, 0xEB, 0xE6, 0xE4, 0xE5, +0xE9, 0xED, 0xF2, 0xFC, 0x7A, 0x74, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6E, +0x6D, 0x6E, 0x70, 0x71, 0x74, 0x79, 0x7B, 0x7E, 0xFB, 0xF6, 0xF8, 0xF9, 0xF6, 0xF5, 0xF8, 0xFA, +0xF7, 0xF0, 0xEE, 0xF0, 0xF7, 0xFC, 0x7D, 0x73, 0x6C, 0x6B, 0x6B, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, +0x6C, 0x6D, 0x6D, 0x6E, 0x71, 0x71, 0x71, 0x72, 0x77, 0x7D, 0xFC, 0xF7, 0xF3, 0xED, 0xEB, 0xEB, +0xEE, 0xF4, 0xF9, 0xFE, 0x79, 0x77, 0x7B, 0x7F, 0x7F, 0xFF, 0xFF, 0x7B, 0x77, 0x76, 0x77, 0x79, +0x79, 0x7A, 0x7C, 0xFF, 0xFC, 0xFC, 0xFA, 0xF8, 0xF9, 0xF9, 0xFA, 0xFD, 0xFE, 0xFD, 0xFA, 0xF8, +0xF5, 0xF2, 0xF1, 0xF2, 0xF4, 0xF8, 0xFE, 0x7C, 0x79, 0x77, 0x77, 0x7A, 0x7E, 0x7F, 0x7C, 0x79, +0x78, 0x75, 0x73, 0x72, 0x71, 0x73, 0x75, 0x76, 0x78, 0x7D, 0xFD, 0xFB, 0xFC, 0xFF, 0x7D, 0x79, +0x76, 0x76, 0x77, 0x7C, 0xFB, 0xF5, 0xF3, 0xF3, 0xF3, 0xF7, 0x7D, 0x74, 0x6F, 0x6D, 0x6B, 0x6C, +0x6E, 0x73, 0x77, 0x77, 0x77, 0x7A, 0x7A, 0x76, 0x73, 0x72, 0x6F, 0x6D, 0x6B, 0x6C, 0x6F, 0x76, +0x7A, 0x7D, 0xFE, 0xFC, 0x7E, 0x7A, 0x75, 0x71, 0x6E, 0x6D, 0x6E, 0x71, 0x77, 0x7D, 0xFE, 0xFC, +0xFC, 0xFE, 0xFF, 0x7D, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFC, 0xF9, 0xF7, 0xF6, 0xF8, 0xFA, 0xFC, +0xFF, 0x7E, 0x7F, 0xFF, 0xFD, 0xFB, 0xF7, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFD, 0x7D, 0x7A, 0x7A, +0x7D, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFD, 0xFD, +0xFB, 0xF8, 0xF7, 0xF9, 0xFD, 0x7C, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x75, 0x75, 0x75, 0x75, +0x75, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7F, 0xFD, 0xFB, 0xFF, 0x7A, 0x79, 0x7D, 0xFE, 0xFD, +0xFD, 0xFC, 0xFD, 0xFA, 0xF5, 0xF2, 0xF3, 0xF6, 0xF8, 0xF9, 0xFC, 0xFF, 0xFD, 0xF8, 0xF5, 0xF5, +0xF6, 0xFA, 0xFC, 0xFD, 0x7F, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x77, 0x7B, 0x7E, 0x7E, 0x7E, 0x7F, +0x7E, 0x7C, 0x79, 0x76, 0x76, 0x78, 0x79, 0x78, 0x7B, 0x7E, 0xFF, 0x7F, 0x7C, 0x7A, 0x78, 0x75, +0x73, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7B, 0x7B, 0x79, 0x79, 0x78, 0x77, 0x78, 0x74, 0x71, 0x72, +0x73, 0x76, 0x77, 0x77, 0x79, 0x79, 0x77, 0x76, 0x75, 0x76, 0x78, 0x7B, 0x7F, 0xFC, 0xFB, 0xFB, +0xFA, 0xFB, 0xFE, 0x7C, 0x79, 0x79, 0x78, 0x78, 0x7B, 0xFF, 0xFD, 0xFD, 0xFC, 0xFC, 0xFE, 0x7E, +0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7B, 0x77, 0x78, 0x7A, +0x7A, 0x7A, 0x7C, 0x7E, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, +0x79, 0x79, 0x7B, 0x7E, 0x7E, 0x7F, 0xFD, 0xFC, 0xFD, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, +0xFF, 0x7E, 0x7D, 0x7F, 0xFF, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFE, 0x7E, 0x7F, 0x7E, 0x7B, +0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x77, 0x7A, +0x7C, 0x7D, 0x7E, 0x7E, 0x7C, 0x79, 0x76, 0x77, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, +0x7D, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7B, 0x7C, +0x7C, 0x7C, 0x7D, 0xFF, 0xFC, 0xFB, 0xFB, 0xFC, 0xFF, 0x7C, 0x79, 0x77, 0x74, 0x75, 0x77, 0x7A, +0x7D, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7B, 0x7A, 0x7B, 0x7D, 0x7E, 0xFE, 0xFD, +0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x78, 0x76, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7C, +0x7A, 0x79, 0x78, 0x78, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7B, 0x7A, +0x7B, 0x7C, 0x7D, 0xFE, 0xFC, 0xFA, 0xF9, 0xFA, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFA, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xFB, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x79, 0x7B, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, +0x7E, 0x7C, 0x7B, 0x79, 0x7A, 0x7C, 0x7C, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7E, 0x7C, 0x7B, 0x79, +0x77, 0x76, 0x76, 0x78, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7B, +0x7D, 0x79, 0x79, 0x7E, 0x79, 0x78, 0x79, 0x78, 0x7A, 0x78, 0x7D, 0x7D, 0x7C, 0xFF, 0x7D, 0x7F, +0x7E, 0x7B, 0x7A, 0x76, 0x79, 0x76, 0x78, 0x7B, 0x79, 0xFF, 0x7D, 0xFB, 0xFD, 0x7D, 0xF9, 0x7B, +0xFF, 0x79, 0x75, 0xFF, 0x6E, 0x7F, 0x71, 0x73, 0x79, 0x51, 0x60, 0xE2, 0x6F, 0x7D, 0xF7, 0xF5, +0x77, 0x72, 0xE4, 0x50, 0x4C, 0xDE, 0xFB, 0x66, 0xE5, 0xF6, 0x6F, 0x6C, 0xE7, 0xDC, 0x6E, 0xFD, +0xE6, 0x7E, 0xE9, 0x77, 0x62, 0xE3, 0xE9, 0x6C, 0x71, 0xEA, 0xDE, 0x75, 0x7E, 0xE8, 0x75, 0xF8, +0x7A, 0xFC, 0xF2, 0x65, 0xF8, 0xEE, 0xF9, 0xF4, 0x73, 0xE4, 0xF9, 0x6E, 0xE5, 0x75, 0x67, 0x5A, +0x50, 0x57, 0x5A, 0x7D, 0x6C, 0x64, 0xDA, 0xED, 0x64, 0xEA, 0xE9, 0xF5, 0x7E, 0x6F, 0xFC, 0xF2, +0x66, 0x63, 0xF7, 0x7D, 0x78, 0xF6, 0xF8, 0xE1, 0xE2, 0xF9, 0xEB, 0xE4, 0xED, 0xFE, 0xFA, 0xF6, +0xF1, 0xF2, 0x6F, 0xFE, 0xE8, 0xFF, 0x7F, 0xEA, 0xE8, 0xED, 0xEE, 0xEA, 0xEB, 0xED, 0xF8, 0xEF, +0xE8, 0x7F, 0xF5, 0xE6, 0xF7, 0xF2, 0xF3, 0xF2, 0xDF, 0xEB, 0xF5, 0xE3, 0xEC, 0xF2, 0xEF, 0xFC, +0xED, 0xEF, 0xFD, 0xED, 0xF0, 0x7C, 0x77, 0xFE, 0xF1, 0x77, 0x79, 0xEF, 0xF6, 0xF8, 0xFB, 0x72, +0x75, 0x79, 0x78, 0x70, 0x6E, 0x7C, 0x7D, 0x74, 0x79, 0x77, 0x6E, 0x71, 0x7D, 0x6F, 0x6B, 0x7D, +0xFE, 0x76, 0x7A, 0x7D, 0x7F, 0x75, 0x6C, 0x7B, 0xF7, 0x7A, 0x7B, 0x7E, 0x74, 0x79, 0x75, 0x70, +0x7C, 0x79, 0xFD, 0xF6, 0x6E, 0x6E, 0x7B, 0x6B, 0x67, 0x6D, 0x6E, 0x6A, 0x67, 0x6A, 0x6D, 0x6F, +0x6B, 0x67, 0x6D, 0x6C, 0x65, 0x63, 0x5E, 0x65, 0x6A, 0x5F, 0x68, 0x6C, 0x60, 0x6C, 0x7D, 0x6D, +0x6E, 0x7D, 0x7C, 0xFF, 0xEE, 0xEB, 0xEC, 0xE3, 0xDE, 0xE1, 0xE4, 0xE0, 0xE8, 0xF8, 0xEE, 0xFA, +0x6D, 0x69, 0x5C, 0x58, 0x59, 0x53, 0x50, 0x4E, 0x4D, 0x4E, 0x4F, 0x4F, 0x53, 0x51, 0x51, 0x54, +0x55, 0x56, 0x5A, 0x5E, 0x69, 0xF7, 0xE2, 0xD8, 0xCF, 0xCE, 0xCD, 0xCC, 0xCE, 0xCE, 0xCA, 0xC7, +0xC2, 0xBF, 0xBE, 0xBD, 0xC2, 0xD5, 0xF1, 0x62, 0x4B, 0x3F, 0x3D, 0x3D, 0x3E, 0x40, 0x42, 0x4A, +0x51, 0x51, 0x51, 0x55, 0x56, 0x4F, 0x4D, 0x4E, 0x50, 0x52, 0x55, 0x5C, 0x69, 0xFA, 0xE4, 0xD9, +0xCD, 0xC9, 0xC5, 0xC1, 0xBF, 0xBB, 0xBB, 0xBD, 0xB9, 0xB7, 0xB5, 0xB7, 0xC8, 0xDD, 0x61, 0x43, +0x3C, 0x38, 0x38, 0x3D, 0x40, 0x46, 0x4E, 0x5A, 0x60, 0x5D, 0x5B, 0x5B, 0x5A, 0x58, 0x56, 0x58, +0x5C, 0x5E, 0x5E, 0x64, 0x6B, 0x6D, 0xF9, 0xED, 0xE5, 0xDC, 0xD9, 0xD2, 0xCC, 0xC5, 0xBF, 0xBF, +0xBA, 0xB7, 0xB6, 0xB1, 0xB7, 0xCB, 0xFA, 0x49, 0x3A, 0x35, 0x31, 0x33, 0x3A, 0x42, 0x4C, 0x5C, +0xFD, 0xE1, 0xEE, 0x68, 0x66, 0x5C, 0x51, 0x4F, 0x4D, 0x55, 0x5F, 0x5D, 0x64, 0x71, 0xFA, 0xED, +0xEF, 0xEB, 0xDE, 0xD3, 0xCC, 0xC3, 0xBE, 0xBD, 0xB9, 0xB8, 0xB5, 0xAF, 0xB7, 0xCC, 0x60, 0x3F, +0x39, 0x34, 0x2F, 0x31, 0x3A, 0x47, 0x56, 0x6F, 0xE3, 0xDA, 0xD5, 0xEC, 0x56, 0x50, 0x4E, 0x4B, +0x4B, 0x4C, 0x57, 0x7B, 0xE7, 0xE0, 0xDC, 0xD5, 0xD6, 0xDE, 0xEC, 0xEF, 0xDE, 0xD7, 0xCC, 0xC1, +0xBD, 0xB8, 0xB5, 0xB4, 0xB0, 0xB6, 0xCB, 0x58, 0x3E, 0x38, 0x34, 0x2F, 0x2F, 0x38, 0x45, 0x59, +0x7D, 0xDD, 0xD1, 0xCE, 0xDD, 0x63, 0x53, 0x4E, 0x4C, 0x4A, 0x4B, 0x53, 0x69, 0xE7, 0xDB, 0xD5, +0xD0, 0xCE, 0xD3, 0xDC, 0xE4, 0xEA, 0xE8, 0xE2, 0xD5, 0xC8, 0xC0, 0xBB, 0xB8, 0xB5, 0xB2, 0xB9, +0xD1, 0x54, 0x40, 0x3A, 0x34, 0x2F, 0x2F, 0x36, 0x3F, 0x4C, 0x5B, 0x7E, 0xDE, 0xD4, 0xDB, 0xFF, +0x62, 0x58, 0x55, 0x53, 0x4F, 0x52, 0x5D, 0x6F, 0xF0, 0xE4, 0xDE, 0xDA, 0xD8, 0xDC, 0xE1, 0xE5, +0xDF, 0xDC, 0xD6, 0xCC, 0xC6, 0xC1, 0xBE, 0xBB, 0xB8, 0xBC, 0xCE, 0x67, 0x4B, 0x44, 0x3E, 0x38, +0x35, 0x37, 0x3D, 0x45, 0x4B, 0x53, 0x61, 0xFA, 0xE4, 0xEC, 0x7F, 0x79, 0x78, 0x79, 0x70, 0x68, +0x68, 0x70, 0x7B, 0x7D, 0x7D, 0xF9, 0xEE, 0xEA, 0xE8, 0xE6, 0xE1, 0xDB, 0xD6, 0xCF, 0xCB, 0xC8, +0xC5, 0xC1, 0xBE, 0xBF, 0xC7, 0xD5, 0xF9, 0x5F, 0x55, 0x4A, 0x42, 0x3E, 0x3E, 0x41, 0x45, 0x48, +0x4C, 0x56, 0x5F, 0x6F, 0xF8, 0xEF, 0xE7, 0xE4, 0xE6, 0xE2, 0xEA, 0xF5, 0xFD, 0x75, 0x75, 0x79, +0x75, 0x76, 0x7E, 0xFA, 0xF1, 0xE9, 0xE0, 0xDA, 0xD3, 0xCF, 0xCC, 0xCA, 0xC7, 0xC4, 0xC5, 0xCC, +0xD3, 0xDF, 0xFF, 0x69, 0x58, 0x4C, 0x47, 0x43, 0x42, 0x42, 0x43, 0x46, 0x4C, 0x55, 0x59, 0x62, +0x77, 0xFD, 0xEE, 0xEC, 0xF3, 0xEC, 0xF2, 0x76, 0x76, 0x6F, 0x6E, 0x79, 0x79, 0x7F, 0xF3, 0xED, +0xE4, 0xDD, 0xDB, 0xD7, 0xD3, 0xD0, 0xCE, 0xCC, 0xCB, 0xCA, 0xCC, 0xD1, 0xD6, 0xDD, 0xEA, 0x7E, +0x62, 0x56, 0x4F, 0x4C, 0x49, 0x48, 0x49, 0x4C, 0x50, 0x56, 0x58, 0x5C, 0x67, 0x6F, 0x6C, 0x6E, +0x6D, 0x6A, 0x6F, 0x6D, 0x6B, 0x6E, 0x6D, 0x76, 0xFA, 0xF9, 0xF1, 0xEB, 0xE7, 0xE1, 0xDE, 0xDD, +0xDB, 0xD8, 0xD7, 0xD4, 0xD2, 0xD0, 0xCF, 0xD4, 0xD8, 0xDA, 0xDF, 0xEA, 0xF8, 0x6D, 0x60, 0x5C, +0x58, 0x56, 0x56, 0x56, 0x57, 0x59, 0x5B, 0x5B, 0x5A, 0x5C, 0x5F, 0x5F, 0x5F, 0x63, 0x66, 0x6B, +0x72, 0x77, 0x7E, 0xF7, 0xF0, 0xEC, 0xE9, 0xE9, 0xE8, 0xE8, 0xE8, 0xE8, 0xEA, 0xE7, 0xE6, 0xE5, +0xE3, 0xE1, 0xDD, 0xDA, 0xD9, 0xD8, 0xDD, 0xDF, 0xDD, 0xE0, 0xE7, 0xEE, 0xFE, 0x74, 0x6C, 0x62, +0x5C, 0x59, 0x56, 0x54, 0x52, 0x51, 0x51, 0x52, 0x55, 0x58, 0x59, 0x5D, 0x62, 0x68, 0x70, 0x75, +0x7D, 0xF9, 0xF8, 0xF4, 0xF5, 0xF9, 0xF5, 0xF3, 0xF3, 0xF2, 0xF2, 0xEF, 0xED, 0xEB, 0xEA, 0xE6, +0xE3, 0xE0, 0xDC, 0xDA, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA, 0xDC, 0xDF, 0xE8, 0xF6, 0x7F, 0x6E, 0x60, +0x5B, 0x58, 0x56, 0x54, 0x53, 0x52, 0x53, 0x59, 0x5C, 0x5E, 0x63, 0x68, 0x6F, 0x7B, 0x7C, 0xFF, +0xFC, 0xFC, 0xFB, 0xFC, 0xFD, 0xF8, 0xF7, 0xF6, 0xF4, 0xF5, 0xF3, 0xF0, 0xEF, 0xED, 0xEB, 0xE8, +0xE4, 0xE0, 0xDD, 0xDA, 0xD9, 0xDA, 0xDC, 0xDC, 0xDC, 0xE0, 0xE9, 0xF8, 0x76, 0x6B, 0x61, 0x5C, +0x5A, 0x5A, 0x5A, 0x5B, 0x5C, 0x5E, 0x62, 0x67, 0x6B, 0x6D, 0x6F, 0x72, 0x75, 0x76, 0x76, 0x75, +0x74, 0x79, 0x7E, 0x7B, 0x78, 0x7D, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF5, 0xF2, 0xEF, 0xEC, 0xE9, +0xE4, 0xDF, 0xDE, 0xDE, 0xE0, 0xE7, 0xEA, 0xEC, 0xF2, 0xFE, 0x76, 0x6F, 0x6F, 0x6D, 0x6A, 0x6A, +0x6B, 0x6C, 0x6C, 0x69, 0x67, 0x67, 0x66, 0x65, 0x64, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6B, 0x6E, +0x71, 0x76, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF4, 0xF0, 0xEE, 0xEC, 0xEA, 0xE9, 0xE8, 0xE9, +0xEB, 0xEB, 0xEC, 0xED, 0xEE, 0xED, 0xEB, 0xE9, 0xEA, 0xE9, 0xE9, 0xEA, 0xEC, 0xF0, 0xF6, 0xFD, +0x78, 0x71, 0x6D, 0x69, 0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, +0x69, 0x6B, 0x6D, 0x73, 0x7A, 0xFE, 0xF7, 0xF3, 0xEF, 0xEE, 0xEE, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, +0xE5, 0xE3, 0xE1, 0xE1, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xEF, 0xF8, 0x7E, 0x75, 0x6F, 0x6B, 0x69, +0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, +0x70, 0x6F, 0x6F, 0x6F, 0x72, 0x75, 0x79, 0xFF, 0xFB, 0xF6, 0xF2, 0xEF, 0xEE, 0xED, 0xEE, 0xF0, +0xF3, 0xF6, 0xF8, 0xFC, 0xFF, 0x7D, 0x79, 0x76, 0x72, 0x6E, 0x6D, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, +0x6E, 0x71, 0x76, 0x7B, 0xFF, 0xFE, 0xFD, 0xFC, 0xFD, 0x7F, 0x7B, 0x78, 0x75, 0x74, 0x75, 0x77, +0x7A, 0x7E, 0xFC, 0xF9, 0xF6, 0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xF8, 0xF7, 0xF6, 0xF5, 0xF5, +0xF6, 0xF8, 0xFA, 0xFC, 0x7F, 0x7B, 0x79, 0x78, 0x77, 0x77, 0x79, 0x7D, 0xFD, 0xF9, 0xF4, 0xF2, +0xF1, 0xF1, 0xF3, 0xF5, 0xFA, 0xFE, 0x7F, 0xFF, 0xFD, 0xFC, 0xFB, 0xF7, 0xF5, 0xF4, 0xF4, 0xF6, +0xF8, 0xFB, 0xFD, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7B, 0x79, 0x77, +0x76, 0x75, 0x74, 0x74, 0x75, 0x78, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0x7E, 0x7C, 0x7B, 0x79, +0x79, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xF9, 0xFB, 0xFD, 0x7F, 0x7B, 0x78, 0x76, 0x75, +0x74, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x7A, 0x7C, +0x7E, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x78, 0x77, 0x77, 0x76, 0x79, 0x7B, 0x7E, 0xFF, +0xFE, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7C, 0x7B, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x74, 0x74, +0x74, 0x74, 0x75, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFC, 0xF8, 0xF7, 0xF6, 0xF7, 0xF7, 0xF7, 0xF9, +0xFC, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7F, 0xFF, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, +0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xFA, 0xFD, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7D, 0x7E, 0xFE, +0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF9, 0xF9, 0xFA, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x79, 0x77, 0x75, +0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x72, 0x71, 0x72, 0x71, 0x72, 0x73, 0x72, +0x72, 0x71, 0x71, 0x71, 0x72, 0x74, 0x74, 0x76, 0x77, 0x77, 0x77, 0x78, 0x77, 0x78, 0x78, 0x78, +0x7A, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7C, 0x7E, 0xFF, 0xFD, +0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7D, +0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xFA, 0xF9, 0xF7, 0xF5, 0xF4, 0xF3, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, +0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, +0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7A, 0x7D, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x74, 0x74, 0x75, 0x74, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73, 0x74, +0x72, 0x70, 0x70, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x72, 0x73, 0x73, 0x76, +0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7F, 0x7D, 0x7C, 0x7B, 0x7B, 0x7C, +0x7B, 0x7B, 0x7A, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0xFF, 0x7D, 0x7E, 0x7C, 0x7C, 0x7B, 0x78, +0x7C, 0x7A, 0x7C, 0x7D, 0x7B, 0x7E, 0x7C, 0x7F, 0x7D, 0x7A, 0x7E, 0x78, 0x7B, 0x6F, 0x68, 0x5C, +0x4C, 0x58, 0xDD, 0xE1, 0xEB, 0xE1, 0xE9, 0xEF, 0xF8, 0xE9, 0xE1, 0xED, 0xF9, 0xFC, 0xF2, 0xED, +0x7D, 0x76, 0xFB, 0xF9, 0x7C, 0x70, 0x6F, 0x78, 0x79, 0x6D, 0x6D, 0x76, 0x7D, 0xFE, 0x7A, 0x79, +0xFC, 0xFD, 0xFD, 0xFA, 0xFB, 0xFA, 0xFC, 0xFF, 0xFC, 0xFC, 0xFE, 0xFD, 0xFE, 0xFB, 0xFB, 0xFE, +0xFE, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x78, 0x7D, 0x7D, 0xFF, 0xFA, 0xFF, 0xF9, 0xF9, 0xFA, 0xF7, +0x7F, 0xF9, 0x7A, 0x7A, 0x6F, 0x51, 0x52, 0x6E, 0x71, 0xF1, 0xD8, 0xD3, 0xDB, 0xEF, 0xE2, 0xDB, +0xED, 0xF6, 0xF3, 0xEF, 0xF4, 0x6A, 0x74, 0x73, 0x57, 0x5E, 0x77, 0x6E, 0xFD, 0xF4, 0xFC, 0x7D, +0x73, 0xE9, 0xDE, 0xE2, 0xDE, 0xE3, 0xE5, 0xE8, 0xFA, 0xF7, 0xFA, 0x6F, 0x6C, 0x6A, 0x6B, 0x6A, +0x66, 0x6B, 0x75, 0x70, 0x74, 0xFA, 0xFB, 0xFD, 0xF8, 0xF3, 0xF2, 0xFB, 0xF5, 0xED, 0xEF, 0xEB, +0xE5, 0xDF, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD4, 0xD8, 0xE0, 0xEE, 0x76, 0x5D, 0x53, 0x4D, 0x49, +0x46, 0x43, 0x42, 0x43, 0x43, 0x45, 0x48, 0x4B, 0x4F, 0x57, 0x60, 0x6D, 0xF7, 0xE3, 0xDB, 0xD4, +0xCF, 0xCB, 0xC8, 0xC4, 0xBE, 0xBC, 0xB9, 0xB4, 0xB6, 0xBC, 0xC1, 0xC3, 0xD5, 0x4F, 0x4B, 0x43, +0x36, 0x33, 0x34, 0x32, 0x31, 0x36, 0x3B, 0x3F, 0x48, 0x60, 0xDF, 0xD2, 0xC9, 0xC1, 0xC3, 0xC6, +0xC7, 0xCF, 0xE3, 0x67, 0x56, 0x47, 0x3E, 0x3F, 0x3C, 0x3B, 0x43, 0x48, 0x4F, 0xFA, 0xD5, 0xC5, +0xBD, 0xB7, 0xB1, 0xAE, 0xAC, 0xAE, 0xB1, 0xB5, 0xC0, 0xD7, 0x5D, 0x40, 0x38, 0x31, 0x2E, 0x2D, +0x2C, 0x2E, 0x32, 0x37, 0x3F, 0x4F, 0xF8, 0xD0, 0xC4, 0xBC, 0xBB, 0xBB, 0xBB, 0xBE, 0xC7, 0xD0, +0xF1, 0x56, 0x48, 0x40, 0x3D, 0x3B, 0x3D, 0x42, 0x49, 0x63, 0xDA, 0xCB, 0xBC, 0xB6, 0xB0, 0xAE, +0xAF, 0xAF, 0xB4, 0xBC, 0xC6, 0xFE, 0x4C, 0x3E, 0x34, 0x30, 0x2E, 0x2D, 0x2E, 0x30, 0x35, 0x3C, +0x46, 0x62, 0xDE, 0xCA, 0xBE, 0xBD, 0xBB, 0xBA, 0xBD, 0xC3, 0xCB, 0xDC, 0x6B, 0x59, 0x51, 0x52, +0x60, 0xFF, 0xD5, 0xC4, 0xBE, 0xBC, 0xBA, 0xB9, 0xBB, 0xC3, 0xC8, 0xD6, 0x5A, 0x4C, 0x42, 0x39, +0x36, 0x35, 0x32, 0x34, 0x36, 0x39, 0x41, 0x47, 0x58, 0xE0, 0xDA, 0xC9, 0xC1, 0xC4, 0xC0, 0xC0, +0xC6, 0xCA, 0xD1, 0xDC, 0xF3, 0x6E, 0xFC, 0xE8, 0xDB, 0xCB, 0xC2, 0xBE, 0xBD, 0xBE, 0xBD, 0xC0, +0xCD, 0xCE, 0xEC, 0x4E, 0x4C, 0x40, 0x38, 0x39, 0x37, 0x35, 0x38, 0x38, 0x3B, 0x43, 0x49, 0x54, +0xEA, 0xDB, 0xCE, 0xC5, 0xC5, 0xC3, 0xC1, 0xC7, 0xCA, 0xCF, 0xDB, 0xE9, 0xFD, 0xF7, 0xE9, 0xDD, +0xCE, 0xC6, 0xC1, 0xBF, 0xC0, 0xBF, 0xC3, 0xCF, 0xD0, 0xE6, 0x51, 0x4E, 0x43, 0x3A, 0x3B, 0x38, +0x35, 0x38, 0x38, 0x3A, 0x3F, 0x44, 0x4E, 0x5F, 0xEF, 0xD7, 0xCD, 0xC8, 0xC6, 0xC4, 0xC6, 0xC9, +0xCC, 0xD4, 0xDD, 0xE6, 0xE1, 0xDA, 0xD7, 0xCA, 0xC3, 0xC4, 0xC4, 0xC1, 0xC3, 0xCC, 0xCF, 0xD8, +0x60, 0x54, 0x4E, 0x3F, 0x3D, 0x3D, 0x39, 0x3A, 0x3C, 0x3B, 0x3D, 0x47, 0x48, 0x51, 0x79, 0xFA, +0xDD, 0xCD, 0xCF, 0xCC, 0xC8, 0xCD, 0xCE, 0xCE, 0xD7, 0xDC, 0xDC, 0xD7, 0xD4, 0xCC, 0xC3, 0xC1, +0xBF, 0xBF, 0xC2, 0xC1, 0xCE, 0xDB, 0xDD, 0x54, 0x4C, 0x49, 0x3C, 0x3B, 0x3B, 0x38, 0x3A, 0x3B, +0x3C, 0x3E, 0x48, 0x4C, 0x55, 0xF3, 0xEC, 0xDB, 0xCD, 0xD1, 0xCD, 0xCB, 0xD2, 0xD1, 0xD6, 0xDD, +0xE1, 0xE2, 0xD7, 0xD3, 0xCA, 0xC0, 0xBE, 0xBE, 0xBF, 0xBE, 0xC1, 0xCF, 0xD0, 0xED, 0x4E, 0x4D, +0x41, 0x3A, 0x3A, 0x37, 0x35, 0x38, 0x3A, 0x3A, 0x3F, 0x49, 0x4A, 0x62, 0xE7, 0xEA, 0xCE, 0xCB, +0xCF, 0xC8, 0xCB, 0xD1, 0xCF, 0xD7, 0xE2, 0xE5, 0xE5, 0xDF, 0xD5, 0xCC, 0xC5, 0xBE, 0xBE, 0xC0, +0xBC, 0xC0, 0xCD, 0xC8, 0xDC, 0x58, 0x5B, 0x47, 0x3C, 0x3D, 0x39, 0x36, 0x39, 0x3A, 0x39, 0x3E, +0x47, 0x49, 0x59, 0xEA, 0xEC, 0xD0, 0xC9, 0xCD, 0xC7, 0xC8, 0xCE, 0xCD, 0xD2, 0xDC, 0xDF, 0xDF, +0xDD, 0xD6, 0xCB, 0xC6, 0xBF, 0xBF, 0xC4, 0xBD, 0xC4, 0xD1, 0xC9, 0xEF, 0x55, 0x5D, 0x43, 0x3D, +0x3E, 0x38, 0x37, 0x3A, 0x3A, 0x3A, 0x3E, 0x45, 0x48, 0x56, 0x74, 0xF8, 0xD8, 0xCF, 0xD0, 0xCB, +0xCB, 0xCE, 0xCE, 0xD2, 0xD9, 0xDC, 0xDC, 0xD7, 0xD3, 0xCA, 0xC4, 0xC0, 0xBF, 0xC2, 0xBE, 0xC3, +0xCF, 0xCB, 0xE5, 0x58, 0x5C, 0x45, 0x3D, 0x3E, 0x39, 0x37, 0x39, 0x3A, 0x3A, 0x3D, 0x45, 0x46, +0x52, 0x79, 0x73, 0xD7, 0xCD, 0xD1, 0xC8, 0xC8, 0xCD, 0xCA, 0xCF, 0xD5, 0xD7, 0xDC, 0xDA, 0xD4, +0xCD, 0xC7, 0xC1, 0xC0, 0xC5, 0xBF, 0xC2, 0xD1, 0xCA, 0xDA, 0x5A, 0x68, 0x4C, 0x3E, 0x42, 0x3B, +0x38, 0x3B, 0x3A, 0x3A, 0x3D, 0x42, 0x44, 0x4B, 0x62, 0x66, 0xF1, 0xD0, 0xD6, 0xCD, 0xC8, 0xCE, +0xCA, 0xCB, 0xD1, 0xCF, 0xD2, 0xD2, 0xCE, 0xC9, 0xC5, 0xC1, 0xBF, 0xC5, 0xC1, 0xC0, 0xD3, 0xCE, +0xD6, 0x57, 0x5F, 0x4E, 0x3E, 0x41, 0x3D, 0x39, 0x3B, 0x3B, 0x3A, 0x3D, 0x42, 0x44, 0x4C, 0x5A, +0x5E, 0xEC, 0xDD, 0xDC, 0xCE, 0xD0, 0xD1, 0xCD, 0xD4, 0xD4, 0xD4, 0xDA, 0xD3, 0xCE, 0xCB, 0xC4, +0xBF, 0xBE, 0xC2, 0xBE, 0xBF, 0xCD, 0xCB, 0xD5, 0x5B, 0x5F, 0x4D, 0x3E, 0x3F, 0x3B, 0x37, 0x39, +0x3A, 0x39, 0x3C, 0x3F, 0x42, 0x4B, 0x59, 0x61, 0xEA, 0xDA, 0xD6, 0xCD, 0xCD, 0xCE, 0xCD, 0xCF, +0xD3, 0xD6, 0xDA, 0xD7, 0xD2, 0xCE, 0xC7, 0xC2, 0xBF, 0xC0, 0xC1, 0xBE, 0xC8, 0xCE, 0xCB, 0x79, +0x5A, 0x5C, 0x41, 0x3F, 0x3E, 0x38, 0x39, 0x3A, 0x39, 0x3A, 0x3E, 0x42, 0x45, 0x51, 0x62, 0x65, +0xDD, 0xD5, 0xD7, 0xCA, 0xCC, 0xCE, 0xCA, 0xCE, 0xD0, 0xCF, 0xCF, 0xCD, 0xC9, 0xC4, 0xBF, 0xBD, +0xBE, 0xBF, 0xBD, 0xC5, 0xCE, 0xCB, 0xF8, 0x58, 0x5B, 0x43, 0x3E, 0x3E, 0x39, 0x38, 0x3A, 0x39, +0x3A, 0x3E, 0x44, 0x45, 0x51, 0x6E, 0x69, 0xDC, 0xCF, 0xD7, 0xCA, 0xCB, 0xD0, 0xCC, 0xD1, 0xD5, +0xD5, 0xD5, 0xCF, 0xCB, 0xC5, 0xBF, 0xBC, 0xBD, 0xBF, 0xBB, 0xC3, 0xCC, 0xC8, 0xEF, 0x5B, 0x5D, +0x41, 0x3D, 0x3D, 0x37, 0x37, 0x38, 0x37, 0x38, 0x3B, 0x41, 0x43, 0x4E, 0x6B, 0x67, 0xDC, 0xCE, +0xD4, 0xC9, 0xC8, 0xCE, 0xCA, 0xCE, 0xD5, 0xD4, 0xD5, 0xD3, 0xCE, 0xC7, 0xC3, 0xBE, 0xBE, 0xC3, +0xBD, 0xC2, 0xD0, 0xC9, 0xDE, 0x57, 0x61, 0x47, 0x3D, 0x3F, 0x39, 0x36, 0x38, 0x38, 0x38, 0x3A, +0x41, 0x40, 0x48, 0x6A, 0x5C, 0xF7, 0xCD, 0xDB, 0xCD, 0xC6, 0xD1, 0xCC, 0xCC, 0xD6, 0xD5, 0xD3, +0xCF, 0xCE, 0xC6, 0xC0, 0xBF, 0xBE, 0xBF, 0xBE, 0xC0, 0xCC, 0xCB, 0xDB, 0x5D, 0x5B, 0x49, 0x3E, +0x3E, 0x39, 0x37, 0x38, 0x38, 0x38, 0x3B, 0x40, 0x42, 0x4A, 0x63, 0x66, 0xE5, 0xCE, 0xD0, 0xCA, +0xC7, 0xCA, 0xCA, 0xCC, 0xCE, 0xD1, 0xCF, 0xCC, 0xCC, 0xC4, 0xBF, 0xBF, 0xBE, 0xC0, 0xBE, 0xC2, +0xCE, 0xCC, 0xE2, 0x58, 0x59, 0x47, 0x3D, 0x3D, 0x39, 0x37, 0x39, 0x39, 0x39, 0x3C, 0x40, 0x44, +0x4D, 0x5D, 0x6F, 0xE0, 0xD4, 0xCF, 0xCC, 0xCB, 0xCB, 0xCD, 0xCF, 0xCF, 0xD4, 0xD1, 0xCC, 0xCA, +0xC4, 0xBF, 0xBD, 0xBF, 0xBF, 0xBE, 0xC7, 0xCF, 0xCE, 0x79, 0x52, 0x51, 0x41, 0x3C, 0x3B, 0x38, +0x36, 0x38, 0x39, 0x38, 0x3D, 0x44, 0x44, 0x55, 0x70, 0x76, 0xD5, 0xCF, 0xCF, 0xC9, 0xCB, 0xCB, +0xCD, 0xD1, 0xD1, 0xD9, 0xD2, 0xCD, 0xCD, 0xC4, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xC9, 0xCF, 0xD0, +0x6A, 0x53, 0x4F, 0x3F, 0x3C, 0x3B, 0x38, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x56, 0x75, +0xE7, 0xD7, 0xCD, 0xCB, 0xCA, 0xC9, 0xCA, 0xCD, 0xCE, 0xCF, 0xD3, 0xCE, 0xCA, 0xC7, 0xC0, 0xBE, +0xBE, 0xBF, 0xBF, 0xC1, 0xCD, 0xD2, 0xDB, 0x5C, 0x4F, 0x4A, 0x3E, 0x3C, 0x3B, 0x39, 0x38, 0x3A, +0x3A, 0x3C, 0x43, 0x46, 0x4E, 0x71, 0x7A, 0xDD, 0xCE, 0xD0, 0xCB, 0xCA, 0xCD, 0xCC, 0xD1, 0xD2, +0xD5, 0xD7, 0xCC, 0xCC, 0xC7, 0xBE, 0xBF, 0xBF, 0xBE, 0xC0, 0xC6, 0xCD, 0xD5, 0xEE, 0x54, 0x4D, +0x45, 0x3C, 0x3B, 0x39, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x59, 0x71, 0xE8, 0xD4, 0xCE, +0xCC, 0xC9, 0xCB, 0xCB, 0xCE, 0xD2, 0xD4, 0xD7, 0xD2, 0xCD, 0xCB, 0xC4, 0xBF, 0xBF, 0xC0, 0xC0, +0xC0, 0xC9, 0xD1, 0xD8, 0x73, 0x52, 0x4B, 0x42, 0x3C, 0x3A, 0x39, 0x38, 0x38, 0x39, 0x3C, 0x3F, +0x41, 0x4E, 0x5D, 0x63, 0xDF, 0xD3, 0xD1, 0xCD, 0xCB, 0xCC, 0xD1, 0xD1, 0xD3, 0xDE, 0xDA, 0xD1, +0xCF, 0xCC, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, 0xD2, 0xE3, 0x63, 0x4F, 0x4A, 0x42, 0x3C, +0x3B, 0x3A, 0x39, 0x3A, 0x3B, 0x3F, 0x42, 0x47, 0x5A, 0x62, 0x7C, 0xD5, 0xD2, 0xCF, 0xCC, 0xCD, +0xCE, 0xD5, 0xD6, 0xD9, 0xE0, 0xD9, 0xD2, 0xCE, 0xCB, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, +0xD4, 0xE2, 0x67, 0x4F, 0x4B, 0x43, 0x3D, 0x3C, 0x3B, 0x3B, 0x3B, 0x3C, 0x42, 0x43, 0x49, 0x60, +0x6B, 0xF5, 0xD4, 0xD2, 0xD0, 0xD2, 0xD2, 0xD4, 0xDF, 0xDD, 0xDF, 0xEA, 0xDC, 0xD5, 0xD0, 0xCB, +0xC4, 0xC0, 0xC2, 0xBF, 0xC0, 0xC7, 0xC9, 0xD0, 0xDD, 0x7A, 0x57, 0x52, 0x48, 0x3F, 0x3F, 0x3D, +0x3C, 0x3C, 0x3D, 0x42, 0x44, 0x49, 0x5B, 0x64, 0x7C, 0xDE, 0xDB, 0xDB, 0xDC, 0xDA, 0xDF, 0xEE, +0xE9, 0xE6, 0xE8, 0xE3, 0xDB, 0xD0, 0xCD, 0xCC, 0xC5, 0xC3, 0xC5, 0xC2, 0xC3, 0xC8, 0xCD, 0xD1, +0xDE, 0x6F, 0x5B, 0x50, 0x4A, 0x44, 0x40, 0x3F, 0x3E, 0x3E, 0x42, 0x43, 0x47, 0x4F, 0x58, 0x5F, +0x69, 0xF6, 0xED, 0xF7, 0xEB, 0xE8, 0xEA, 0xEC, 0xE8, 0xE0, 0xE0, 0xDD, 0xD7, 0xD0, 0xCE, 0xCC, +0xC8, 0xC7, 0xC6, 0xC4, 0xC8, 0xC9, 0xCB, 0xD2, 0xDA, 0xEF, 0x71, 0x5B, 0x4F, 0x4E, 0x49, 0x45, +0x46, 0x45, 0x47, 0x47, 0x4A, 0x4E, 0x4E, 0x54, 0x5A, 0x5D, 0x62, 0x65, 0x70, 0x6C, 0x69, 0xFA, +0x7A, 0x7A, 0xE6, 0xE2, 0xDF, 0xDA, 0xD5, 0xCF, 0xD1, 0xD1, 0xCB, 0xCE, 0xD4, 0xCE, 0xD1, 0xD9, +0xDB, 0xE0, 0xE1, 0xEE, 0x6A, 0x74, 0x6C, 0x5A, 0x5B, 0x5A, 0x56, 0x56, 0x53, 0x56, 0x57, 0x53, +0x57, 0x5B, 0x59, 0x59, 0x5D, 0x65, 0x60, 0x61, 0x6F, 0x73, 0xF7, 0xEF, 0xEA, 0xDD, 0xDF, 0xDC, +0xD5, 0xD8, 0xDC, 0xDC, 0xDA, 0xDF, 0xE5, 0xE1, 0xEB, 0xED, 0xED, 0xFC, 0xFF, 0x70, 0x6C, 0x6C, +0x66, 0x5F, 0x5F, 0x62, 0x5F, 0x60, 0x60, 0x5A, 0x5F, 0x64, 0x5C, 0x64, 0x6E, 0x5F, 0x5E, 0x69, +0x6B, 0x7B, 0xF0, 0xFA, 0xE9, 0xE4, 0xE8, 0xDF, 0xE6, 0xEB, 0xE1, 0xE2, 0xE6, 0xE3, 0xE8, 0xED, +0xE5, 0xFC, 0x71, 0xE9, 0xFE, 0x7A, 0xEC, 0x73, 0x7E, 0x77, 0x64, 0xFD, 0x74, 0x66, 0x7B, 0x6C, +0x6B, 0x72, 0x6A, 0x79, 0x73, 0x71, 0xF4, 0x79, 0xFC, 0xEF, 0xF9, 0xEB, 0xF1, 0xF0, 0xE2, 0xE3, +0xE0, 0xE2, 0xE3, 0xEB, 0xFC, 0xEA, 0xF8, 0x6F, 0x70, 0x69, 0x77, 0x6C, 0x6D, 0xEF, 0x6B, 0x67, +0x6D, 0x65, 0x76, 0x75, 0x6F, 0x7E, 0x69, 0x67, 0x6F, 0x68, 0x6F, 0x73, 0x68, 0x69, 0x68, 0x69, +0x75, 0xFA, 0xEE, 0xF2, 0xEA, 0xDE, 0xE2, 0xE7, 0xE5, 0xEB, 0xF3, 0xED, 0xE8, 0xF7, 0x7F, 0xFA, +0x74, 0x6A, 0x68, 0x65, 0x66, 0x68, 0x64, 0x65, 0x68, 0x64, 0x6D, 0x77, 0x72, 0x70, 0x69, 0x77, +0x78, 0x64, 0x6B, 0x68, 0x60, 0x66, 0x67, 0x67, 0x61, 0x6D, 0xEB, 0xE8, 0xEC, 0xEB, 0xEA, 0xF7, +0xF5, 0xE2, 0xE5, 0xF6, 0xF8, 0xF0, 0x7E, 0x77, 0xFA, 0x76, 0x77, 0x7D, 0x6E, 0x74, 0x74, 0x72, +0x72, 0x6D, 0x75, 0x74, 0x74, 0x75, 0x76, 0xEF, 0xEE, 0xEF, 0xEA, 0xFA, 0x7F, 0xF2, 0xF6, 0xF7, +0xEF, 0xEA, 0xE4, 0xE5, 0xE7, 0xE3, 0xE9, 0xEC, 0xE8, 0xEB, 0xF0, 0xF8, 0xFC, 0x7F, 0x73, 0x73, +0x70, 0x72, 0x75, 0x69, 0x67, 0x6A, 0x6C, 0x6D, 0x6C, 0x70, 0x6D, 0x6D, 0x78, 0x72, 0x6F, 0x6E, +0x6C, 0x6F, 0x77, 0xF7, 0xEF, 0xF1, 0xF6, 0xF4, 0xF1, 0xFC, 0xF8, 0xEE, 0xF0, 0xEE, 0xEF, 0xEF, +0xEC, 0xEE, 0xF3, 0xF4, 0x76, 0x69, 0x77, 0xFA, 0x70, 0x75, 0x7E, 0x6E, 0x6D, 0x6E, 0x6E, 0x6E, +0x6D, 0x70, 0x74, 0x79, 0xFE, 0x7D, 0x78, 0x7C, 0x7A, 0x75, 0x78, 0x75, 0x70, 0x7C, 0xFC, 0xFB, +0xF4, 0xF3, 0xED, 0xEC, 0xF6, 0xF1, 0xEF, 0xF6, 0xF0, 0xFB, 0x7A, 0x7C, 0x74, 0x79, 0x74, 0x6C, +0x6C, 0x63, 0x67, 0x6C, 0x62, 0x66, 0x67, 0x68, 0x6C, 0x6A, 0x7D, 0x78, 0x6B, 0x7B, 0x71, 0x75, +0xFB, 0x75, 0x76, 0x7E, 0xEE, 0xED, 0xFA, 0xE8, 0xEE, 0x7F, 0xE4, 0xE9, 0xED, 0xE1, 0xEC, 0xEE, +0xE6, 0xF6, 0xFE, 0xF7, 0xFF, 0x7B, 0x72, 0x7C, 0x7F, 0x6B, 0x6C, 0x66, 0x67, 0x71, 0x66, 0x72, +0xFF, 0x69, 0x7B, 0xF7, 0xFF, 0xF3, 0xF6, 0xF3, 0xF2, 0xEE, 0xED, 0xFF, 0xF6, 0xED, 0xFB, 0xF2, +0xE9, 0xF0, 0xEC, 0xE6, 0xF4, 0xF2, 0xF5, 0x7C, 0xED, 0x7E, 0x6B, 0x7B, 0x77, 0xFE, 0x7A, 0x69, +0x68, 0x60, 0x65, 0x66, 0x61, 0x71, 0x74, 0x74, 0xFC, 0x7E, 0xFA, 0xFF, 0x7E, 0xF9, 0xFB, 0xEE, +0xED, 0xEF, 0xEF, 0xF4, 0xEC, 0xEC, 0xF2, 0xF0, 0xEF, 0xED, 0xF4, 0xF6, 0xEF, 0xFD, 0xF8, 0xF1, +0x77, 0x74, 0x7A, 0x70, 0x6F, 0x79, 0x76, 0x6A, 0x68, 0x6C, 0x6C, 0x69, 0x65, 0x66, 0x6E, 0x73, +0x6C, 0x6D, 0x7A, 0x79, 0x7A, 0xFE, 0x73, 0x72, 0x7A, 0x7E, 0xF3, 0xEF, 0xEE, 0xF1, 0xF6, 0xEC, +0xEF, 0xFA, 0xEE, 0xF5, 0xFE, 0xF2, 0xF0, 0xF7, 0xFA, 0xF9, 0xFB, 0xFB, 0x7A, 0x6B, 0x6B, 0x72, +0x6C, 0x6A, 0x76, 0x74, 0x6E, 0x72, 0x6C, 0x6B, 0x6F, 0x6B, 0x6E, 0x71, 0x6D, 0x75, 0x76, 0x70, +0x78, 0x7C, 0xFA, 0xF2, 0xF7, 0xF1, 0xED, 0xF3, 0xF4, 0xF6, 0xFA, 0xF0, 0xEF, 0xFD, 0x7B, 0xFF, +0x78, 0x6C, 0x70, 0x72, 0x6E, 0x73, 0x6D, 0x6D, 0x6D, 0x65, 0x65, 0x69, 0x6F, 0x70, 0x6B, 0x6E, +0x71, 0x6E, 0x6E, 0x6F, 0x7A, 0x7D, 0x7E, 0xEF, 0xF4, 0x7D, 0xFB, 0xF3, 0xEC, 0xEB, 0xF0, 0xEF, +0xEE, 0xEE, 0xF3, 0xF0, 0xED, 0xFF, 0xFF, 0xF3, 0x7E, 0xFB, 0xFF, 0x73, 0x7E, 0x7A, 0x76, 0x6F, +0x6C, 0x7A, 0x74, 0x6F, 0xFF, 0x7B, 0x79, 0xF7, 0xF5, 0xFB, 0xF6, 0xF3, 0x7E, 0x7D, 0xFA, 0xFD, +0xF6, 0xF5, 0x7D, 0x7B, 0x7A, 0xFF, 0xFB, 0x7D, 0x75, 0x76, 0xF3, 0xF3, 0x78, 0xFE, 0x76, 0x6B, +0x7B, 0xFB, 0x75, 0x69, 0x6C, 0xF6, 0xF6, 0x7B, 0x6F, 0x69, 0x6E, 0x72, 0x70, 0x74, 0x78, 0xFF, +0x7F, 0xFD, 0xF5, 0xF8, 0xF5, 0xF9, 0x75, 0x74, 0x7D, 0xF7, 0xFB, 0x70, 0x7E, 0xE9, 0xEF, 0xF7, +0xE6, 0xED, 0x74, 0x7A, 0xF7, 0x7D, 0x71, 0x77, 0xFE, 0xF6, 0xFC, 0x6B, 0x6B, 0x72, 0x69, 0x6D, +0x7B, 0x7C, 0xFD, 0x6F, 0x6B, 0xFC, 0x7F, 0x73, 0xF9, 0xF5, 0x70, 0x6E, 0xFD, 0xFF, 0x7C, 0xFB, +0x70, 0x76, 0xEF, 0x7D, 0x75, 0xFB, 0xF6, 0xEF, 0xF6, 0x7C, 0x79, 0x76, 0xFE, 0x7D, 0x73, 0xFD, +0xFE, 0x76, 0x6E, 0x66, 0x6B, 0x75, 0x6D, 0x7D, 0xF2, 0x6D, 0x75, 0xED, 0x7A, 0x6D, 0x7E, 0xF9, +0xFE, 0x6E, 0x78, 0xF4, 0x6E, 0x73, 0xF8, 0x74, 0xFF, 0xFE, 0x77, 0xF6, 0x7C, 0x71, 0x7F, 0x7E, +0x7E, 0x79, 0x78, 0x7C, 0x6E, 0x6F, 0x70, 0x6D, 0xFD, 0xFA, 0x6C, 0x6B, 0x71, 0x70, 0x7B, 0x7A, +0x7C, 0xFD, 0x6D, 0x75, 0xED, 0xF8, 0xFC, 0xF7, 0xFB, 0xEE, 0xEF, 0x79, 0xFF, 0xED, 0xF8, 0x7A, +0xF1, 0xED, 0xF7, 0xFC, 0xF8, 0xF1, 0xF8, 0x79, 0x7D, 0xF6, 0x78, 0x6E, 0xFD, 0xFB, 0x72, 0x6E, +0x6C, 0x74, 0xFE, 0xFF, 0xF7, 0xFE, 0x6D, 0x75, 0x79, 0x6F, 0x7C, 0x7D, 0x76, 0x78, 0x7A, 0x7F, +0x75, 0x7D, 0xF7, 0xF8, 0xEF, 0x7B, 0x7A, 0xF3, 0xFF, 0xEF, 0xF8, 0xFE, 0xF6, 0x6E, 0xF4, 0xED, +0x6F, 0x7C, 0x74, 0x75, 0xF2, 0x7C, 0x75, 0xF9, 0xEE, 0xFF, 0x70, 0x7C, 0x7F, 0xFD, 0xFD, 0xFA, +0x79, 0x6C, 0x7C, 0x7F, 0xFD, 0xF3, 0x78, 0xFE, 0xF7, 0xFC, 0xED, 0xF1, 0xFD, 0xFE, 0x7D, 0xF4, +0xED, 0xF4, 0xFA, 0xFD, 0x70, 0x73, 0xF6, 0xFF, 0x7D, 0xF7, 0x79, 0x72, 0x78, 0x7D, 0x77, 0x6E, +0x71, 0x6C, 0x6A, 0x7D, 0x74, 0x71, 0x7D, 0x6E, 0x79, 0xF8, 0x70, 0x7C, 0xFE, 0x6D, 0x6F, 0x6E, +0x6D, 0x7D, 0xFD, 0xFB, 0xFA, 0x7C, 0xFD, 0xFA, 0xF7, 0xF4, 0xFD, 0x7B, 0x76, 0x7D, 0xF3, 0xF5, +0xFD, 0xF5, 0xED, 0x7A, 0x6D, 0xF5, 0x7C, 0x76, 0xEF, 0x77, 0x6E, 0xFF, 0x74, 0x79, 0xFD, 0x76, +0x7A, 0x7E, 0x7B, 0x7D, 0x78, 0x73, 0x7A, 0xFB, 0xFB, 0x7E, 0xFB, 0xF2, 0xF8, 0xF9, 0xFB, 0xFE, +0xF5, 0xF6, 0xF9, 0x7E, 0x73, 0xF7, 0xFA, 0x74, 0xFC, 0x7B, 0x70, 0xFF, 0xFC, 0x7E, 0x7C, 0xFE, +0xFF, 0x7C, 0xFC, 0x7E, 0x79, 0xFF, 0x7C, 0x79, 0x79, 0x79, 0x7A, 0x79, 0x7A, 0x7C, 0x7A, 0x75, +0x72, 0x7C, 0xFC, 0xFE, 0xFE, 0xFC, 0xF9, 0xFE, 0xFE, 0xFA, 0x7C, 0xFD, 0xFC, 0x77, 0x7B, 0x7A, +0x73, 0x78, 0x7A, 0x78, 0x7B, 0x77, 0x6E, 0x70, 0x7B, 0x7A, 0x72, 0x74, 0x76, 0x75, 0x77, 0x75, +0x70, 0x6F, 0x6F, 0x6F, 0x74, 0x77, 0x72, 0x6F, 0x70, 0x79, 0x79, 0x6F, 0x7E, 0xFA, 0x72, 0x79, +0x79, 0x78, 0xFE, 0x78, 0xFF, 0xFE, 0x76, 0xFF, 0xFF, 0x7D, 0xFF, 0x7E, 0x7B, 0x78, 0x7C, 0x75, +0x75, 0xFF, 0xFF, 0xF8, 0xF6, 0xFD, 0xF5, 0xF4, 0xF6, 0xFC, 0x7C, 0x7C, 0x7B, 0xFC, 0xFD, 0xFD, +0xFD, 0x77, 0x7A, 0x7F, 0x7E, 0xFC, 0xFA, 0xF7, 0xFF, 0xFE, 0xF1, 0xFD, 0xFD, 0xF0, 0xF9, 0xF8, +0xEE, 0xEF, 0xF8, 0x7E, 0x79, 0x77, 0x6C, 0x66, 0x6A, 0x68, 0x67, 0x71, 0x74, 0x77, 0x7E, 0x7B, +0xFD, 0xFD, 0x7F, 0xFF, 0x79, 0xFE, 0xFE, 0x75, 0x78, 0x7A, 0x74, 0x70, 0x76, 0x77, 0x75, 0x7C, +0x7C, 0x79, 0x78, 0x77, 0x78, 0x7C, 0x7E, 0x77, 0x74, 0x79, 0x77, 0x78, 0x78, 0x77, 0x7B, 0x78, +0x77, 0x77, 0x7A, 0xFE, 0x7D, 0xFE, 0xF6, 0xFB, 0xFC, 0xF8, 0xF6, 0xFA, 0xFD, 0xFB, 0xFC, 0x7D, +0x7B, 0xFB, 0xF5, 0xFC, 0xFF, 0xFD, 0xFE, 0xFF, 0x7F, 0xFC, 0xF8, 0xFF, 0x7F, 0xF7, 0xF9, 0xFA, +0xF9, 0xFB, 0xFA, 0xFA, 0xFA, 0xF8, 0xF8, 0xFD, 0x7E, 0xF8, 0xF7, 0xEF, 0xE0, 0xE1, 0xF7, 0x6E, +0x69, 0x65, 0x5C, 0x5B, 0x61, 0x69, 0x6E, 0x76, 0xF8, 0xEF, 0xF2, 0xEB, 0xE3, 0xDE, 0xE2, 0xFA, +0x66, 0x5B, 0x5F, 0x6E, 0x6E, 0xFB, 0xED, 0xED, 0xEC, 0xF8, 0x7E, 0x7B, 0x6E, 0x67, 0x60, 0x65, +0x6E, 0x6F, 0x78, 0xFB, 0x7E, 0x7D, 0xFA, 0xF9, 0xF7, 0xF5, 0xF7, 0xEE, 0xEB, 0xF3, 0xFA, 0x7A, +0x6D, 0x69, 0x6A, 0x69, 0x64, 0x69, 0x6E, 0x6F, 0x78, 0xFB, 0xFB, 0x7C, 0xF8, 0xF1, 0xFB, 0xF4, +0xF9, 0x7D, 0xF8, 0x7D, 0xFD, 0xF3, 0x7C, 0xFD, 0xF4, 0x7A, 0x6F, 0x79, 0xFF, 0x75, 0x78, 0xFA, +0xFB, 0xFE, 0xFB, 0xF9, 0xFE, 0xFF, 0xFF, 0xFC, 0xF5, 0xFD, 0x79, 0xFF, 0xF9, 0xFA, 0xFF, 0xFF, +0x7B, 0x74, 0x75, 0x6F, 0x71, 0x7D, 0x74, 0x75, 0x79, 0x71, 0x77, 0x7E, 0x7E, 0x7C, 0x74, 0x71, +0x77, 0x7A, 0x7F, 0xFB, 0x72, 0x69, 0x74, 0x74, 0x6A, 0x74, 0x7E, 0x79, 0x76, 0x74, 0x7F, 0x7C, +0x76, 0xF8, 0xF8, 0x7E, 0x7D, 0x7E, 0xFE, 0x77, 0x7B, 0xF8, 0x7B, 0xFF, 0xF3, 0xFC, 0xFF, 0xFE, +0xFD, 0xF5, 0xF6, 0xF3, 0xF2, 0xFA, 0xF8, 0xF3, 0xFB, 0x7E, 0xFA, 0xFA, 0x7E, 0xFE, 0xFC, 0x7C, +0x78, 0x7D, 0xFB, 0xF3, 0xFD, 0x74, 0xF7, 0xF5, 0x76, 0xF9, 0xF8, 0xFF, 0xF5, 0x76, 0x7B, 0xFA, +0x77, 0xFD, 0x7C, 0x77, 0x7D, 0x6F, 0x7D, 0xF7, 0xFC, 0xFD, 0x7B, 0xF5, 0xF8, 0x7A, 0xF4, 0xFB, +0x77, 0x7B, 0x76, 0x74, 0x7D, 0x7E, 0x72, 0x71, 0x70, 0x70, 0x77, 0x70, 0x7B, 0xFD, 0x6F, 0x72, +0x7D, 0x7A, 0x71, 0x79, 0xF8, 0x77, 0x6F, 0x74, 0x7A, 0x78, 0x7C, 0xF6, 0x7C, 0xFB, 0x7D, 0x6C, +0xEF, 0xFC, 0x6D, 0xF1, 0xF5, 0x7D, 0x79, 0xFA, 0xF5, 0x75, 0xF4, 0x7C, 0xFC, 0xE6, 0x68, 0x78, +0xE4, 0x6E, 0x77, 0xF2, 0x7E, 0x70, 0x69, 0xF9, 0xF7, 0x6C, 0x74, 0xF3, 0xEE, 0x79, 0x7E, 0xFB, +0x7A, 0xF6, 0x6C, 0x6B, 0xED, 0x77, 0x6A, 0x70, 0x6F, 0xFC, 0x7E, 0x79, 0xF2, 0xEE, 0xF8, 0x7D, +0xEF, 0xEB, 0x7E, 0x72, 0x7D, 0x74, 0x6B, 0xFA, 0xE5, 0xE7, 0xE4, 0xEB, 0xF8, 0xEC, 0xEA, 0xF3, +0xFB, 0xFA, 0xEF, 0xF6, 0x7C, 0xFF, 0x7B, 0x72, 0x78, 0x7C, 0x6F, 0x6E, 0xFF, 0xFF, 0x75, 0x74, +0x74, 0x76, 0x6C, 0x6A, 0x7F, 0x78, 0x6D, 0x74, 0x6E, 0x76, 0x7B, 0x69, 0x6B, 0x79, 0x72, 0x6A, +0x6D, 0x77, 0xFD, 0xFC, 0x6F, 0x7C, 0xEE, 0x76, 0x69, 0x74, 0xFB, 0x74, 0x6A, 0x7D, 0xF0, 0xFF, +0x6B, 0x71, 0xEF, 0x7D, 0x74, 0xF8, 0x75, 0x74, 0x77, 0x6C, 0x6E, 0x71, 0x73, 0x72, 0x70, 0xF4, +0xF0, 0x79, 0x7B, 0xFB, 0xF3, 0xF4, 0x78, 0x79, 0xF7, 0xFC, 0x6E, 0x70, 0xF8, 0xF8, 0x79, 0x6D, +0x70, 0xFB, 0x6E, 0x64, 0x6B, 0x72, 0x6F, 0x65, 0x71, 0xFC, 0x71, 0x76, 0x6E, 0x71, 0xF9, 0xFF, +0xFD, 0x73, 0x7A, 0xFF, 0x66, 0x70, 0xFE, 0x79, 0xFD, 0x7D, 0xF1, 0xF6, 0x76, 0x79, 0x6D, 0x79, +0xFF, 0x72, 0x7F, 0xF8, 0xF0, 0xFF, 0x71, 0xEC, 0xE9, 0x7C, 0x7C, 0xF1, 0xF7, 0xF7, 0xF5, 0xFA, +0xF1, 0x7C, 0x70, 0x7D, 0xFB, 0xF4, 0x7C, 0x7D, 0xF6, 0xFD, 0xEF, 0xF6, 0xEE, 0xE1, 0xEE, 0xF4, +0xF3, 0xEE, 0xF4, 0x78, 0xEC, 0xF7, 0x72, 0x74, 0x6E, 0xF5, 0x6A, 0x7B, 0xDF, 0x69, 0x7F, 0xE7, +0x6F, 0x7C, 0x68, 0xF4, 0xEE, 0x5C, 0x72, 0x6B, 0x6D, 0xEC, 0x60, 0x7E, 0xEB, 0x66, 0x6D, 0x6A, +0x7A, 0xFF, 0x6A, 0x6E, 0x74, 0xED, 0x79, 0x6B, 0xED, 0xFA, 0xFC, 0x70, 0x65, 0xF6, 0x75, 0x67, +0x78, 0x78, 0xF4, 0xFF, 0x5F, 0xF9, 0xE3, 0x6D, 0xF1, 0x7A, 0x70, 0xDB, 0x6A, 0xF9, 0xDC, 0x66, +0xDB, 0xF8, 0x65, 0xD6, 0x6A, 0xF2, 0xE6, 0x5E, 0xE1, 0x76, 0x6F, 0xF5, 0x65, 0xEF, 0x5F, 0x66, +0x6F, 0x5A, 0xFB, 0x5E, 0x65, 0x7E, 0x60, 0xF2, 0x5D, 0x72, 0xE8, 0x5A, 0xEA, 0x6E, 0x62, 0xE4, +0x5E, 0x6F, 0x74, 0x67, 0xEA, 0x64, 0x77, 0xF3, 0x69, 0xF1, 0x6B, 0x6E, 0xEB, 0x74, 0x74, 0x74, +0xF6, 0xF5, 0x66, 0xF5, 0xF7, 0x6C, 0xE9, 0x70, 0x6F, 0xE4, 0x6E, 0xF0, 0xF4, 0x63, 0xE1, 0xFE, +0x6D, 0xE4, 0x6D, 0xF2, 0xEF, 0x6C, 0xE8, 0x7B, 0xFC, 0xED, 0x74, 0xEB, 0xFE, 0xFC, 0xEF, 0x6D, +0xEC, 0xFB, 0x71, 0xEB, 0x77, 0xF3, 0xF8, 0x6F, 0xE9, 0xFE, 0xFC, 0xEE, 0x6F, 0xEB, 0xED, 0x7A, +0xEE, 0xF4, 0xF3, 0xF8, 0xF1, 0xEE, 0x79, 0xF4, 0xF3, 0xFC, 0xF1, 0x7C, 0xF4, 0xF9, 0x76, 0xE8, +0xF8, 0x75, 0xE3, 0x7B, 0x6E, 0xE0, 0x75, 0x72, 0xE3, 0x6C, 0xF8, 0xE7, 0x6D, 0xEA, 0xF4, 0x75, +0xEA, 0x71, 0xFA, 0xED, 0x6A, 0xF2, 0xFB, 0x70, 0xEB, 0x6F, 0x71, 0xEE, 0x6C, 0xF6, 0xF2, 0x68, +0xF3, 0xF8, 0x6D, 0x7A, 0xFC, 0x75, 0x6D, 0xF3, 0x6E, 0x6E, 0xEE, 0x61, 0x7C, 0xFE, 0x60, 0xF2, +0x6D, 0x78, 0x7C, 0x63, 0xEB, 0x64, 0x71, 0xED, 0x5C, 0xEB, 0x6F, 0x69, 0xEA, 0x5D, 0xE7, 0xF8, +0x5E, 0xE6, 0x6F, 0xFA, 0x79, 0x72, 0xE8, 0x5E, 0xE9, 0xFB, 0x5F, 0xDE, 0x61, 0xFA, 0xE3, 0x5A, +0xE3, 0x79, 0x62, 0xDF, 0x64, 0x76, 0xE4, 0x63, 0xFE, 0xE9, 0x64, 0xF8, 0xE6, 0x5F, 0xF2, 0xE8, +0x62, 0xE7, 0xFB, 0x6A, 0xF0, 0x77, 0xF9, 0x77, 0xE9, 0x78, 0x59, 0xE3, 0x71, 0x6C, 0xDF, 0x5F, +0xEF, 0xE9, 0x5F, 0xFA, 0x76, 0xF9, 0x7D, 0x67, 0xEE, 0x7B, 0x6F, 0x7E, 0x6B, 0x6D, 0xF7, 0x6E, +0x6B, 0xF0, 0x63, 0xF0, 0x75, 0x57, 0xD4, 0x59, 0x57, 0xCD, 0x4F, 0xEE, 0xDE, 0x4B, 0xCF, 0x68, +0x5B, 0xD4, 0x50, 0xE0, 0xEF, 0x54, 0xD5, 0x57, 0x6A, 0xD3, 0x54, 0x79, 0xDF, 0x5E, 0xFC, 0xE6, +0x5F, 0x71, 0xE0, 0x64, 0x76, 0xFC, 0x5D, 0xEA, 0xF8, 0x58, 0x79, 0xDB, 0x68, 0x59, 0xDF, 0x76, +0x64, 0xDA, 0x63, 0x5A, 0xD9, 0xE0, 0x51, 0xF3, 0xD3, 0x4D, 0xDE, 0xCF, 0x3F, 0xDA, 0xC2, 0x41, +0x6A, 0xC3, 0x50, 0x55, 0xC6, 0x5A, 0x4B, 0xC2, 0x7A, 0x46, 0xCA, 0xDF, 0x4C, 0xD8, 0xDE, 0x4F, +0xE2, 0xD2, 0x4D, 0x6B, 0xCD, 0x5C, 0x56, 0xD8, 0xEB, 0x54, 0xEF, 0xDE, 0x4F, 0x78, 0xD7, 0x54, +0x5B, 0xDA, 0xFA, 0x56, 0xF6, 0xE9, 0x58, 0xF1, 0xE5, 0x59, 0x6D, 0xE8, 0x7B, 0x64, 0x7E, 0xE2, +0x60, 0x6D, 0xDC, 0x63, 0x67, 0xDC, 0x6F, 0x62, 0xE2, 0x7B, 0x60, 0xEC, 0xF3, 0x67, 0x77, 0xF1, +0x7C, 0x75, 0xF0, 0x79, 0x6F, 0xED, 0x76, 0x6B, 0xF3, 0xFF, 0x74, 0xF4, 0xF8, 0x6B, 0x6C, 0xE6, +0xE7, 0x61, 0x79, 0xDD, 0x6F, 0x77, 0xDE, 0x6D, 0x6E, 0xE4, 0x7E, 0xF9, 0xE8, 0x6D, 0x6F, 0xDE, +0xEF, 0x5C, 0xEF, 0xDB, 0x64, 0x6B, 0xDF, 0xF9, 0x6C, 0xF4, 0xF5, 0x72, 0xF5, 0xF7, 0x66, 0x7D, +0xE9, 0x7D, 0x70, 0x79, 0xF6, 0x7B, 0x6C, 0xF3, 0xF2, 0x6A, 0x76, 0xED, 0x79, 0x6B, 0xF2, 0xF1, +0x6B, 0x78, 0xEF, 0x73, 0x74, 0xED, 0x73, 0x6A, 0xEB, 0xF2, 0x64, 0x6F, 0xE2, 0xF8, 0x5E, 0xF3, +0xE8, 0x64, 0x74, 0xEF, 0x7B, 0x77, 0x74, 0x78, 0x6D, 0xF8, 0xEA, 0x63, 0x68, 0xEC, 0xEF, 0x6E, +0x63, 0xEE, 0xFA, 0x5F, 0xE5, 0xEB, 0x58, 0x73, 0xD1, 0xF3, 0x4D, 0xF2, 0xCD, 0x5D, 0x54, 0xDF, +0xDD, 0x61, 0x5B, 0xD9, 0xDF, 0x50, 0xF0, 0xD3, 0x5F, 0x5D, 0xE4, 0xDF, 0x6E, 0x5B, 0xED, 0xD8, +0x68, 0x56, 0xEA, 0xD3, 0x70, 0x52, 0xF0, 0xD3, 0x74, 0x57, 0xF5, 0xD8, 0x6A, 0x58, 0xE4, 0xE2, +0x5C, 0x7A, 0xD8, 0x77, 0x5A, 0xE8, 0xD9, 0x73, 0x5F, 0x7D, 0xE3, 0xEC, 0x73, 0x72, 0x6E, 0xF6, +0xDF, 0xF7, 0x62, 0x6B, 0xE5, 0xDD, 0x6B, 0x58, 0xF7, 0xDB, 0x73, 0x5E, 0x75, 0x7E, 0xF6, 0xFE, +0x66, 0x71, 0x7B, 0x7E, 0xEE, 0x6C, 0x6B, 0xEB, 0x76, 0x6C, 0xEA, 0x7A, 0x67, 0xE5, 0xE8, 0x5F, +0x75, 0xDE, 0xEE, 0x6F, 0x7A, 0xED, 0xE8, 0xF8, 0xFB, 0xF4, 0x78, 0xF1, 0xE4, 0x6E, 0x62, 0xEB, +0xEC, 0x65, 0x6D, 0x7E, 0x6B, 0x69, 0x6E, 0x72, 0x78, 0x68, 0x5E, 0x74, 0xE9, 0x6F, 0x5E, 0x72, +0xEB, 0x7A, 0x6F, 0xF1, 0x78, 0x75, 0xE5, 0xE6, 0xE2, 0xDD, 0xE0, 0xD6, 0xD1, 0xD5, 0xD1, 0xD3, +0xDE, 0xE0, 0xDD, 0xE9, 0x68, 0x57, 0x52, 0x50, 0x4B, 0x48, 0x48, 0x48, 0x48, 0x4B, 0x51, 0x56, +0x56, 0x5D, 0x68, 0x6A, 0x69, 0x7C, 0xE8, 0xED, 0xED, 0xDC, 0xD5, 0xCD, 0xCB, 0xCD, 0xC5, 0xBE, +0xBE, 0xBC, 0xBC, 0xBF, 0xC5, 0xD2, 0x72, 0x52, 0x48, 0x40, 0x3C, 0x39, 0x39, 0x3B, 0x3D, 0x40, +0x4A, 0x5A, 0x6C, 0x7E, 0xDF, 0xCF, 0xCE, 0xDB, 0x6F, 0x63, 0x6E, 0x60, 0x4D, 0x47, 0x4D, 0x5E, +0x7C, 0xFA, 0xE4, 0xCD, 0xC1, 0xBD, 0xBC, 0xBA, 0xB7, 0xB4, 0xB5, 0xBE, 0xD7, 0xEB, 0xF2, 0x4E, +0x3B, 0x36, 0x37, 0x39, 0x38, 0x39, 0x3D, 0x48, 0x58, 0xFE, 0xDA, 0xD6, 0xD8, 0xCF, 0xC8, 0xCD, +0xF3, 0x5A, 0x59, 0x58, 0x4E, 0x47, 0x48, 0x4F, 0x5F, 0xF2, 0xD9, 0xCE, 0xC6, 0xBF, 0xBB, 0xBA, +0xB9, 0xB7, 0xB5, 0xB7, 0xC0, 0xD9, 0x68, 0x57, 0x49, 0x3B, 0x35, 0x35, 0x38, 0x3A, 0x3B, 0x3F, +0x4B, 0x60, 0xE7, 0xD8, 0xD5, 0xD4, 0xCE, 0xCA, 0xCF, 0xF9, 0x59, 0x51, 0x4E, 0x4C, 0x48, 0x46, +0x49, 0x56, 0xFB, 0xD9, 0xD1, 0xC9, 0xBE, 0xB8, 0xB6, 0xB5, 0xB3, 0xB2, 0xB6, 0xC3, 0xE5, 0x60, +0x4E, 0x3F, 0x37, 0x32, 0x34, 0x37, 0x39, 0x3C, 0x41, 0x4E, 0x6F, 0xDA, 0xD2, 0xD4, 0xD1, 0xCA, +0xC9, 0xD7, 0x6F, 0x59, 0x4D, 0x47, 0x47, 0x48, 0x45, 0x46, 0x52, 0xEE, 0xD7, 0xD0, 0xC7, 0xBC, +0xB5, 0xB3, 0xB3, 0xB1, 0xB0, 0xB7, 0xCA, 0x68, 0x4F, 0x45, 0x3B, 0x32, 0x2E, 0x30, 0x35, 0x39, +0x3D, 0x44, 0x52, 0xEC, 0xD0, 0xCF, 0xD3, 0xD0, 0xCD, 0xCF, 0xE3, 0x63, 0x5B, 0x59, 0x52, 0x4D, +0x4C, 0x4F, 0x5A, 0x6D, 0xE5, 0xD2, 0xC8, 0xBE, 0xB9, 0xB5, 0xB3, 0xB1, 0xAF, 0xB1, 0xBD, 0xE3, +0x53, 0x4B, 0x40, 0x35, 0x2E, 0x2F, 0x34, 0x39, 0x3B, 0x3F, 0x4C, 0x75, 0xDA, 0xD6, 0xD2, 0xCE, +0xCE, 0xD0, 0xD9, 0xEF, 0x62, 0x56, 0x55, 0x55, 0x4F, 0x4E, 0x52, 0x61, 0xEF, 0xDB, 0xCC, 0xBF, +0xB9, 0xB5, 0xB3, 0xB0, 0xAE, 0xB4, 0xC8, 0x63, 0x4D, 0x45, 0x39, 0x2E, 0x2C, 0x2F, 0x35, 0x38, +0x3B, 0x43, 0x5A, 0xDD, 0xCE, 0xCD, 0xCC, 0xCB, 0xCD, 0xD2, 0xDE, 0x76, 0x5A, 0x52, 0x53, 0x51, +0x4E, 0x4F, 0x5C, 0x7C, 0xE2, 0xD2, 0xC5, 0xBB, 0xB5, 0xB2, 0xB0, 0xAE, 0xAE, 0xB6, 0xCF, 0x55, +0x48, 0x3F, 0x34, 0x2C, 0x2C, 0x2F, 0x36, 0x39, 0x3D, 0x4A, 0x7D, 0xCE, 0xCA, 0xCB, 0xCB, 0xCB, +0xCD, 0xD9, 0x76, 0x59, 0x4F, 0x4C, 0x4C, 0x4A, 0x4C, 0x54, 0x68, 0xEC, 0xD8, 0xCB, 0xBF, 0xB8, +0xB3, 0xB0, 0xAE, 0xAD, 0xAE, 0xBC, 0xF5, 0x4C, 0x43, 0x39, 0x2E, 0x2A, 0x2D, 0x32, 0x37, 0x3B, +0x44, 0x5F, 0xD5, 0xC8, 0xC7, 0xC9, 0xCB, 0xCE, 0xD3, 0xE9, 0x5A, 0x4D, 0x4D, 0x4D, 0x4B, 0x4B, +0x50, 0x63, 0xF6, 0xDE, 0xCE, 0xC5, 0xBD, 0xB7, 0xB2, 0xB0, 0xAF, 0xAD, 0xAF, 0xBF, 0x5E, 0x45, +0x40, 0x37, 0x2C, 0x29, 0x2D, 0x34, 0x38, 0x3C, 0x48, 0x77, 0xCD, 0xC6, 0xC7, 0xCB, 0xCB, 0xCF, +0xE9, 0x59, 0x4E, 0x4B, 0x47, 0x44, 0x47, 0x4D, 0x57, 0x69, 0xEB, 0xD7, 0xCA, 0xBF, 0xB9, 0xB3, +0xAF, 0xAE, 0xAD, 0xAC, 0xB5, 0xDE, 0x49, 0x43, 0x3B, 0x2D, 0x28, 0x2A, 0x30, 0x36, 0x3A, 0x44, +0x6A, 0xCD, 0xC2, 0xC2, 0xC6, 0xCA, 0xCC, 0xD8, 0x60, 0x4C, 0x48, 0x46, 0x44, 0x43, 0x49, 0x54, +0x68, 0xEC, 0xD8, 0xCB, 0xC2, 0xBC, 0xB8, 0xB2, 0xAF, 0xAE, 0xAE, 0xAE, 0xBA, 0x74, 0x45, 0x3F, +0x36, 0x2C, 0x29, 0x2C, 0x32, 0x37, 0x3E, 0x4E, 0xE3, 0xC7, 0xC2, 0xC5, 0xC6, 0xC8, 0xD2, 0x71, +0x52, 0x4D, 0x49, 0x42, 0x41, 0x47, 0x51, 0x60, 0x7B, 0xDE, 0xCE, 0xC6, 0xC0, 0xBE, 0xB9, 0xB2, +0xAF, 0xAF, 0xAE, 0xAE, 0xBC, 0x6B, 0x47, 0x3F, 0x34, 0x2C, 0x2A, 0x2D, 0x32, 0x39, 0x3F, 0x4F, +0xDF, 0xC5, 0xC4, 0xCD, 0xCA, 0xC7, 0xDB, 0x5A, 0x4E, 0x4D, 0x48, 0x42, 0x40, 0x45, 0x54, 0x6F, +0x74, 0xEC, 0xCD, 0xC4, 0xC4, 0xC1, 0xBB, 0xB3, 0xAF, 0xB0, 0xAE, 0xAE, 0xBC, 0x6F, 0x4A, 0x3F, +0x34, 0x2C, 0x2B, 0x2E, 0x34, 0x3B, 0x42, 0x56, 0xCF, 0xBF, 0xC2, 0xCB, 0xC6, 0xC6, 0xE6, 0x52, +0x4B, 0x47, 0x45, 0x3F, 0x3D, 0x45, 0x5E, 0x7A, 0x72, 0xDB, 0xC7, 0xC3, 0xC5, 0xC2, 0xBC, 0xB5, +0xB1, 0xB3, 0xB0, 0xAE, 0xB9, 0xF0, 0x4C, 0x43, 0x38, 0x2E, 0x2B, 0x2D, 0x34, 0x3A, 0x3E, 0x4F, +0xD3, 0xC1, 0xC4, 0xCD, 0xCC, 0xC8, 0xDE, 0x4D, 0x45, 0x47, 0x47, 0x41, 0x3D, 0x47, 0x6D, 0xF7, +0x79, 0xDA, 0xC9, 0xC6, 0xC8, 0xC9, 0xC0, 0xB8, 0xB4, 0xB5, 0xB0, 0xAC, 0xB1, 0xCF, 0x5A, 0x4E, +0x3E, 0x30, 0x2B, 0x2D, 0x33, 0x38, 0x3B, 0x48, 0xDC, 0xC4, 0xC5, 0xCA, 0xCB, 0xCB, 0xD9, 0x50, +0x46, 0x4B, 0x46, 0x3E, 0x3F, 0x48, 0x55, 0x76, 0x7E, 0xE3, 0xCA, 0xC9, 0xCE, 0xCB, 0xC6, 0xBE, +0xBA, 0xB8, 0xB4, 0xAE, 0xAE, 0xBD, 0xEA, 0x62, 0x48, 0x35, 0x2D, 0x2C, 0x30, 0x35, 0x37, 0x3F, +0x6F, 0xCB, 0xCA, 0xC9, 0xC7, 0xCE, 0xD9, 0x60, 0x46, 0x46, 0x48, 0x40, 0x40, 0x49, 0x52, 0x69, +0xED, 0xE1, 0xD1, 0xCC, 0xD0, 0xD2, 0xD0, 0xCD, 0xC2, 0xBD, 0xB9, 0xB2, 0xAE, 0xAF, 0xBA, 0xE0, +0x67, 0x4C, 0x34, 0x2D, 0x2E, 0x30, 0x34, 0x37, 0x41, 0xF4, 0xCD, 0xCC, 0xC7, 0xC5, 0xD0, 0xED, +0x64, 0x4D, 0x45, 0x47, 0x43, 0x44, 0x4F, 0x51, 0x69, 0xD9, 0xDD, 0xD1, 0xCB, 0xD1, 0xCF, 0xD2, +0xCD, 0xBF, 0xBC, 0xB8, 0xB0, 0xAD, 0xAE, 0xBC, 0xD9, 0x76, 0x48, 0x32, 0x2D, 0x2F, 0x30, 0x32, +0x38, 0x49, 0xE6, 0xD1, 0xCB, 0xC1, 0xC1, 0xD2, 0x7A, 0x6F, 0x51, 0x42, 0x43, 0x45, 0x4A, 0x4D, +0x4E, 0x72, 0xD7, 0xDB, 0xD8, 0xCE, 0xCF, 0xD7, 0xDD, 0xD3, 0xC6, 0xBF, 0xBB, 0xB3, 0xAD, 0xAE, +0xB8, 0xCD, 0xE2, 0x52, 0x35, 0x2E, 0x2F, 0x2F, 0x2F, 0x35, 0x43, 0x62, 0xE5, 0xCF, 0xC1, 0xC0, +0xD1, 0xE1, 0xDB, 0x5E, 0x46, 0x49, 0x4D, 0x4A, 0x49, 0x51, 0x6A, 0xEE, 0xEB, 0xDE, 0xD0, 0xD4, +0xDF, 0xDC, 0xD7, 0xCF, 0xC5, 0xBE, 0xB7, 0xB1, 0xAE, 0xAF, 0xBC, 0xD3, 0xE7, 0x48, 0x31, 0x2E, +0x2F, 0x2E, 0x2F, 0x36, 0x44, 0x5B, 0xF4, 0xCC, 0xBF, 0xC2, 0xD4, 0xD1, 0xCF, 0x59, 0x4B, 0x51, +0x4B, 0x46, 0x44, 0x4C, 0x56, 0x51, 0x66, 0xE5, 0xE6, 0xE0, 0xDF, 0xD6, 0xD1, 0xCD, 0xC0, 0xBB, +0xB7, 0xB0, 0xAD, 0xB0, 0xBD, 0xCE, 0xEF, 0x44, 0x31, 0x2F, 0x30, 0x2E, 0x2E, 0x39, 0x46, 0x56, +0xF0, 0xC7, 0xBD, 0xC2, 0xC9, 0xC8, 0xCC, 0x7A, 0x50, 0x57, 0x4F, 0x42, 0x42, 0x4A, 0x4C, 0x4C, +0x5D, 0xEF, 0xEE, 0xE3, 0xD6, 0xD1, 0xD2, 0xCC, 0xC0, 0xBC, 0xBA, 0xB3, 0xAE, 0xAF, 0xBA, 0xC9, +0xD6, 0x4F, 0x36, 0x30, 0x30, 0x2E, 0x2D, 0x34, 0x3E, 0x45, 0x5C, 0xCF, 0xC1, 0xC0, 0xC1, 0xC0, +0xC9, 0xD9, 0xF5, 0x54, 0x4A, 0x47, 0x40, 0x41, 0x42, 0x45, 0x4E, 0x53, 0x68, 0xE8, 0xE1, 0xD1, +0xCD, 0xCC, 0xC5, 0xBF, 0xBB, 0xB8, 0xB4, 0xAF, 0xB0, 0xBD, 0xCB, 0xD8, 0x4B, 0x36, 0x34, 0x33, +0x2E, 0x2E, 0x37, 0x3D, 0x44, 0x62, 0xCD, 0xC4, 0xC0, 0xBE, 0xBF, 0xC5, 0xCF, 0xEE, 0x66, 0x4F, +0x45, 0x43, 0x40, 0x41, 0x44, 0x47, 0x51, 0x5B, 0x71, 0xDD, 0xD8, 0xCE, 0xC8, 0xC6, 0xC1, 0xBD, +0xB9, 0xB7, 0xB2, 0xAF, 0xB9, 0xC3, 0xCC, 0x71, 0x40, 0x37, 0x36, 0x31, 0x2E, 0x33, 0x3A, 0x3D, +0x4A, 0xE6, 0xCF, 0xC7, 0xBE, 0xBF, 0xC2, 0xCA, 0xD3, 0xE6, 0x50, 0x4C, 0x4B, 0x3E, 0x3E, 0x43, +0x41, 0x47, 0x4D, 0x59, 0x75, 0xE4, 0xD0, 0xCC, 0xC9, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB3, 0xB3, +0xBB, 0xC3, 0xCD, 0x6A, 0x42, 0x3A, 0x38, 0x31, 0x30, 0x36, 0x39, 0x3C, 0x4B, 0x7A, 0xDB, 0xCB, +0xC1, 0xC3, 0xC5, 0xC5, 0xD5, 0xE5, 0x6B, 0x4E, 0x4C, 0x43, 0x40, 0x45, 0x42, 0x48, 0x50, 0x55, +0x6C, 0xE8, 0xD7, 0xCD, 0xCC, 0xC7, 0xC3, 0xC0, 0xBD, 0xBC, 0xB8, 0xB2, 0xB5, 0xBD, 0xC2, 0xD0, +0x5D, 0x45, 0x3C, 0x38, 0x32, 0x32, 0x37, 0x37, 0x3C, 0x4C, 0x5E, 0xEE, 0xCD, 0xC5, 0xC8, 0xC6, +0xC5, 0xD0, 0xE2, 0xF9, 0x5D, 0x4D, 0x47, 0x46, 0x42, 0x41, 0x47, 0x4B, 0x4E, 0x63, 0xEA, 0xE3, +0xD3, 0xC9, 0xCB, 0xC8, 0xC0, 0xBF, 0xBD, 0xBA, 0xB5, 0xB6, 0xBC, 0xC1, 0xCC, 0x7E, 0x4B, 0x3F, +0x3B, 0x35, 0x32, 0x37, 0x37, 0x3A, 0x45, 0x50, 0x6D, 0xD7, 0xC8, 0xC6, 0xC7, 0xC2, 0xCA, 0xD7, +0xDB, 0x6D, 0x59, 0x4F, 0x48, 0x48, 0x45, 0x46, 0x4D, 0x4F, 0x5E, 0xFF, 0xE6, 0xD7, 0xD4, 0xCF, +0xD1, 0xD5, 0xD0, 0xD3, 0xCD, 0xC6, 0xC1, 0xBA, 0xB8, 0xBB, 0xC2, 0xC4, 0xCD, 0x58, 0x4C, 0x48, +0x39, 0x36, 0x39, 0x36, 0x37, 0x3E, 0x44, 0x4B, 0x66, 0xDC, 0xD4, 0xCA, 0xC3, 0xC5, 0xC7, 0xCA, +0xCE, 0xDD, 0x6D, 0x5F, 0x4F, 0x46, 0x47, 0x46, 0x43, 0x49, 0x4E, 0x53, 0x65, 0xF1, 0xE4, 0xD9, +0xCF, 0xCE, 0xCD, 0xC6, 0xC3, 0xC0, 0xBA, 0xB7, 0xB7, 0xBD, 0xC4, 0xC5, 0xFD, 0x4A, 0x4C, 0x3B, +0x33, 0x37, 0x34, 0x32, 0x3A, 0x3F, 0x47, 0x5B, 0xDC, 0xCB, 0xC8, 0xBE, 0xBC, 0xC3, 0xC0, 0xC7, +0xDE, 0xEC, 0x5B, 0x49, 0x45, 0x3F, 0x3E, 0x3F, 0x40, 0x49, 0x4E, 0x5B, 0xEF, 0xDF, 0xD4, 0xCC, +0xCA, 0xC7, 0xC5, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB8, 0xC0, 0xCB, 0xCA, 0x68, 0x45, 0x4D, 0x3D, +0x35, 0x3C, 0x3A, 0x38, 0x41, 0x49, 0x4D, 0x69, 0xDB, 0xD3, 0xCD, 0xC5, 0xC6, 0xCC, 0xCB, 0xD0, +0xEB, 0x76, 0x5C, 0x4C, 0x48, 0x44, 0x41, 0x41, 0x44, 0x49, 0x4E, 0x5D, 0x7E, 0xE6, 0xD4, 0xCE, +0xCE, 0xCB, 0xCB, 0xCE, 0xCE, 0xCA, 0xC9, 0xC6, 0xBE, 0xBC, 0xC6, 0xCA, 0xC4, 0xE0, 0x58, 0x77, +0x4A, 0x3D, 0x45, 0x3D, 0x39, 0x3F, 0x41, 0x40, 0x4C, 0x61, 0x6D, 0xE7, 0xCE, 0xCC, 0xCC, 0xC9, +0xCA, 0xD1, 0xDB, 0xE2, 0x66, 0x54, 0x50, 0x48, 0x45, 0x47, 0x47, 0x4B, 0x51, 0x5A, 0x71, 0xEB, +0xDD, 0xD5, 0xD2, 0xCF, 0xCC, 0xCC, 0xCA, 0xC4, 0xC3, 0xBF, 0xB9, 0xBD, 0xCB, 0xC0, 0xC9, 0x56, +0x71, 0x5A, 0x3A, 0x3F, 0x3E, 0x34, 0x3A, 0x3E, 0x3C, 0x42, 0x54, 0x62, 0x73, 0xCF, 0xC8, 0xCC, +0xC3, 0xC3, 0xCD, 0xCF, 0xDD, 0x6D, 0x56, 0x4D, 0x48, 0x42, 0x42, 0x44, 0x45, 0x4D, 0x57, 0x61, +0xED, 0xDB, 0xD5, 0xCD, 0xCD, 0xCD, 0xCD, 0xD0, 0xCD, 0xD1, 0xCA, 0xC4, 0xC7, 0xBA, 0xC2, 0xD8, +0xBB, 0xD7, 0x53, 0xCC, 0x4E, 0x3E, 0x57, 0x3E, 0x3B, 0x43, 0x3F, 0x3E, 0x46, 0x52, 0x50, 0x60, +0xD6, 0xD9, 0xD4, 0xC6, 0xCA, 0xCF, 0xCB, 0xD5, 0xF4, 0xFB, 0x5D, 0x4E, 0x4C, 0x4B, 0x46, 0x45, +0x4F, 0x4E, 0x4D, 0x7E, 0x6F, 0x71, 0xD4, 0xE1, 0xDF, 0xCE, 0xD9, 0xD5, 0xCD, 0xCD, 0xC5, 0xBF, +0xB9, 0xBA, 0xC6, 0xBA, 0xBF, 0x6C, 0xCE, 0xFB, 0x3D, 0x4D, 0x40, 0x35, 0x3C, 0x3B, 0x38, 0x3E, +0x47, 0x4B, 0x52, 0xDF, 0xD8, 0xD6, 0xC3, 0xC6, 0xCB, 0xC5, 0xCD, 0xDD, 0xE4, 0x6B, 0x50, 0x4D, +0x49, 0x44, 0x45, 0x47, 0x48, 0x49, 0x50, 0x5D, 0x5C, 0xEE, 0xDD, 0xE7, 0xD1, 0xD5, 0xDC, 0xD0, +0xDA, 0xD8, 0xD1, 0xCD, 0xC6, 0xBF, 0xBA, 0xC1, 0xC4, 0xBA, 0xD3, 0xE1, 0xCC, 0x4D, 0x49, 0x4F, +0x3B, 0x3B, 0x3E, 0x3A, 0x3C, 0x42, 0x4A, 0x4C, 0x6D, 0xD9, 0xDC, 0xC9, 0xC4, 0xCA, 0xC6, 0xC8, +0xD0, 0xD8, 0xE5, 0x68, 0x58, 0x53, 0x4C, 0x4A, 0x4B, 0x4C, 0x4E, 0x56, 0x5F, 0x69, 0xEA, 0xE0, +0xE8, 0xD5, 0xDD, 0xE7, 0xD9, 0xFB, 0xF9, 0xF5, 0x64, 0x75, 0x6D, 0xF5, 0xE5, 0xD8, 0xC8, 0xC4, +0xBB, 0xBF, 0xC4, 0xB7, 0xCC, 0xD6, 0xC3, 0x56, 0x52, 0x5F, 0x3D, 0x3E, 0x3E, 0x39, 0x3A, 0x3D, +0x41, 0x41, 0x4F, 0x6B, 0x63, 0xD6, 0xCD, 0xD1, 0xC7, 0xC8, 0xCE, 0xCE, 0xD6, 0xE8, 0x71, 0x67, +0x55, 0x4F, 0x52, 0x4D, 0x4F, 0x56, 0x56, 0x5E, 0x6D, 0x7E, 0xF5, 0xDF, 0xE3, 0xEE, 0xDC, 0x7B, +0x73, 0xED, 0x5C, 0x6A, 0x69, 0x5B, 0x70, 0x6D, 0xEF, 0xE1, 0xCF, 0xC8, 0xC4, 0xB9, 0xC5, 0xC2, +0xB6, 0xDC, 0xCD, 0xC3, 0x49, 0x60, 0x57, 0x3A, 0x40, 0x3D, 0x38, 0x3A, 0x3E, 0x3F, 0x3E, 0x53, +0x58, 0x59, 0xD3, 0xD7, 0xD2, 0xC4, 0xC9, 0xCA, 0xC8, 0xCD, 0xD8, 0xDE, 0xEE, 0x5F, 0x5D, 0x59, +0x4F, 0x54, 0x56, 0x54, 0x5D, 0x69, 0x6D, 0xF2, 0xE1, 0xDF, 0xDB, 0xD8, 0xDD, 0xE8, 0xEB, 0x71, +0x5D, 0x66, 0x56, 0x52, 0x62, 0x52, 0x5C, 0x74, 0x63, 0xE2, 0xDD, 0xD4, 0xCA, 0xC9, 0xBF, 0xC0, +0xBB, 0xBB, 0xCC, 0xBB, 0xC8, 0x68, 0xC8, 0x58, 0x44, 0x5D, 0x3C, 0x3B, 0x40, 0x3A, 0x3B, 0x3F, +0x44, 0x43, 0x52, 0x7A, 0x62, 0xD4, 0xCB, 0xD1, 0xC3, 0xC4, 0xC8, 0xC5, 0xCA, 0xD0, 0xD9, 0xE1, +0x6C, 0x5C, 0x5B, 0x4E, 0x4D, 0x50, 0x4C, 0x50, 0x58, 0x58, 0x63, 0x79, 0xFE, 0xED, 0xE1, 0xE7, +0xEE, 0xE6, 0xFB, 0x6D, 0x7A, 0x61, 0x5D, 0x62, 0x59, 0x5B, 0x5E, 0x5C, 0x64, 0x69, 0x72, 0xFE, +0xF1, 0xE6, 0xE2, 0xDB, 0xD9, 0xD6, 0xD3, 0xD3, 0xD0, 0xD0, 0xCF, 0xCE, 0xCD, 0xCD, 0xDA, 0xDB, +0xDA, 0x64, 0x69, 0x63, 0x4C, 0x4F, 0x4D, 0x46, 0x4A, 0x4A, 0x48, 0x4D, 0x52, 0x52, 0x5C, 0x70, +0x71, 0xEB, 0xDC, 0xDE, 0xD7, 0xD4, 0xD8, 0xD5, 0xD7, 0xDD, 0xDF, 0xE7, 0xFD, 0x71, 0x69, 0x5D, +0x5A, 0x5A, 0x57, 0x56, 0x5B, 0x59, 0x5A, 0x69, 0x62, 0x6A, 0xF5, 0x73, 0xF1, 0xE7, 0xF4, 0xE6, +0xE6, 0xEE, 0xEA, 0xED, 0xF5, 0xF1, 0xED, 0xF0, 0xEA, 0xE4, 0xE7, 0xDF, 0xDE, 0xDF, 0xDC, 0xDE, +0xDF, 0xE1, 0xE8, 0xEE, 0xFD, 0x77, 0x6B, 0x64, 0x61, 0x5C, 0x5C, 0x5C, 0x5B, 0x5F, 0x61, 0x67, +0x6E, 0x78, 0xF8, 0xF1, 0xEA, 0xE5, 0xE4, 0xE2, 0xE1, 0xE5, 0xEA, 0xED, 0xFA, 0x77, 0x6E, 0x66, +0x62, 0x5D, 0x5C, 0x5A, 0x59, 0x59, 0x59, 0x5B, 0x5C, 0x5D, 0x64, 0x64, 0x6C, 0x77, 0x7C, 0xEE, +0xEB, 0xE0, 0xDB, 0xD7, 0xCF, 0xCF, 0xCA, 0xC8, 0xC5, 0xC4, 0xCD, 0xC7, 0xCB, 0xE8, 0xD3, 0xFD, +0x55, 0x67, 0x4B, 0x45, 0x48, 0x40, 0x3F, 0x42, 0x43, 0x43, 0x4A, 0x50, 0x50, 0x6C, 0xF5, 0xF2, +0xD4, 0xD2, 0xD1, 0xCB, 0xCC, 0xCE, 0xCE, 0xD0, 0xDA, 0xDC, 0xDF, 0xFD, 0x7D, 0x6F, 0x5E, 0x5F, +0x5D, 0x59, 0x5A, 0x5C, 0x5C, 0x5F, 0x68, 0x68, 0x6F, 0xFC, 0xFC, 0xEF, 0xE9, 0xEB, 0xE9, 0xE9, +0xED, 0xEF, 0xF2, 0xF8, 0xFE, 0xFE, 0x7C, 0x7C, 0x7E, 0x79, 0xFE, 0xFB, 0xFE, 0xF7, 0xF6, 0xF9, +0xF6, 0xF8, 0xFD, 0xFF, 0x7C, 0x73, 0x70, 0x6E, 0x6A, 0x6A, 0x69, 0x68, 0x6A, 0x6B, 0x6C, 0x6F, +0x74, 0x79, 0xFF, 0xFA, 0xF8, 0xF2, 0xF4, 0xF6, 0xF3, 0xFE, 0xFB, 0x74, 0x62, 0x69, 0x5F, 0x5A, +0x66, 0x5B, 0x5D, 0x70, 0x61, 0x78, 0xED, 0xF4, 0xDB, 0xD7, 0xD0, 0xCB, 0xC9, 0xC3, 0xCC, 0xC9, +0xC4, 0xDD, 0xD2, 0xD7, 0x59, 0x6E, 0x57, 0x45, 0x4B, 0x45, 0x3F, 0x43, 0x44, 0x43, 0x49, 0x51, +0x4F, 0x5E, 0xFB, 0x70, 0xDE, 0xD8, 0xDC, 0xD1, 0xD2, 0xD7, 0xD4, 0xD6, 0xDD, 0xDF, 0xDF, 0xF1, +0xF2, 0xF2, 0x6F, 0x73, 0x72, 0x69, 0x6D, 0x6F, 0x6D, 0x72, 0x7B, 0x79, 0x7E, 0xF8, 0xFD, 0xF9, +0xF6, 0xFD, 0xFA, 0xFA, 0xFD, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF8, 0xF3, 0xF2, 0xF4, 0xEF, 0xF1, +0xF4, 0xF2, 0xF6, 0xF9, 0xF8, 0xF9, 0xFD, 0xFD, 0xFC, 0x7F, 0x7E, 0x7D, 0x79, 0x76, 0x74, 0x71, +0x6F, 0x6E, 0x6C, 0x6C, 0x6D, 0x6B, 0x6C, 0x6D, 0x6C, 0x71, 0x71, 0x70, 0x7E, 0x79, 0x7C, 0xFA, +0x7B, 0xFD, 0xFC, 0x7A, 0xFE, 0x7C, 0x78, 0x7B, 0x76, 0x76, 0x78, 0x77, 0x77, 0x7C, 0x7E, 0xFF, +0xF2, 0xF3, 0xED, 0xE7, 0xE8, 0xE0, 0xDE, 0xDC, 0xD7, 0xD8, 0xD3, 0xD4, 0xDA, 0xD7, 0xDF, 0xEB, +0xED, 0x6A, 0x60, 0x5C, 0x52, 0x4F, 0x4D, 0x4B, 0x4A, 0x4B, 0x4B, 0x4D, 0x50, 0x54, 0x5B, 0x66, +0x6F, 0xF1, 0xE6, 0xDF, 0xDA, 0xD8, 0xD8, 0xD7, 0xD9, 0xDB, 0xDE, 0xE2, 0xEA, 0xF1, 0xFA, 0x78, +0x70, 0x6D, 0x69, 0x68, 0x66, 0x65, 0x65, 0x66, 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x70, 0x74, 0x79, +0xFB, 0xF5, 0xEF, 0xEB, 0xE9, 0xE6, 0xE3, 0xE2, 0xE1, 0xE0, 0xE0, 0xE0, 0xE1, 0xE3, 0xE3, 0xE6, +0xE9, 0xEB, 0xEF, 0xF7, 0x7F, 0x75, 0x6E, 0x6A, 0x66, 0x62, 0x61, 0x5F, 0x5F, 0x60, 0x5F, 0x62, +0x65, 0x66, 0x6C, 0x6E, 0x72, 0x7D, 0xFE, 0xF6, 0xEF, 0xED, 0xE9, 0xE7, 0xE4, 0xE3, 0xE0, 0xDF, +0xE1, 0xDF, 0xE1, 0xE3, 0xE3, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xED, 0xF5, 0xF6, 0xF9, 0x75, +0x76, 0x6E, 0x66, 0x65, 0x5E, 0x5B, 0x5A, 0x56, 0x55, 0x54, 0x53, 0x54, 0x55, 0x57, 0x59, 0x5D, +0x60, 0x66, 0x70, 0x79, 0xFA, 0xF0, 0xEE, 0xEC, 0xED, 0xED, 0xF0, 0xF5, 0xF8, 0xFF, 0xFD, 0x7E, +0x7D, 0xFE, 0x7E, 0xFD, 0xF8, 0xF6, 0xEF, 0xED, 0xEB, 0xE8, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDC, +0xDD, 0xDC, 0xDD, 0xE1, 0xE2, 0xE9, 0xF3, 0x7A, 0x65, 0x61, 0x5B, 0x56, 0x56, 0x51, 0x50, 0x52, +0x50, 0x55, 0x58, 0x59, 0x5F, 0x68, 0x70, 0xFC, 0xEE, 0xE9, 0xE4, 0xE1, 0xE4, 0xE4, 0xE7, 0xED, +0xEE, 0xF8, 0xFF, 0x7D, 0x76, 0x76, 0x7A, 0x7B, 0xFF, 0xF9, 0xF7, 0xF1, 0xED, 0xED, 0xEB, 0xE9, +0xEA, 0xEA, 0xEC, 0xED, 0xEE, 0xF0, 0xF1, 0xF2, 0xF2, 0xF3, 0xF0, 0xF1, 0xF3, 0xEF, 0xF3, 0xF5, +0xF4, 0xFB, 0xFC, 0xFC, 0x7C, 0x7A, 0x76, 0x70, 0x6F, 0x6F, 0x6C, 0x6C, 0x6C, 0x68, 0x6B, 0x6B, +0x68, 0x6D, 0x6B, 0x6B, 0x6F, 0x6E, 0x70, 0x77, 0x76, 0x7A, 0x7F, 0xFF, 0xFD, 0xF6, 0xF7, 0xF5, +0xEF, 0xF4, 0xF1, 0xEF, 0xF2, 0xEE, 0xF0, 0xF1, 0xEE, 0xF0, 0xF1, 0xF1, 0xF2, 0xF6, 0xF9, 0xFA, +0x7F, 0x7E, 0x7A, 0x76, 0x7A, 0x73, 0x72, 0x74, 0x6F, 0x73, 0x75, 0x73, 0x75, 0x74, 0x76, 0x73, +0x77, 0x7A, 0x76, 0x7E, 0x78, 0x76, 0x7E, 0x76, 0x7A, 0x79, 0x74, 0x7D, 0x77, 0x77, 0x79, 0x74, +0x76, 0x77, 0x7A, 0x79, 0x7C, 0xFF, 0x79, 0xFC, 0xFA, 0x7E, 0xF4, 0xF9, 0xFC, 0xF6, 0x7E, 0xFF, +0xFF, 0x7B, 0x7C, 0x77, 0x75, 0x76, 0x78, 0x76, 0x74, 0x7B, 0x74, 0x75, 0x7E, 0x74, 0x7B, 0x7C, +0x72, 0x7A, 0x77, 0x74, 0x7A, 0x75, 0x72, 0x73, 0x72, 0x6E, 0x6E, 0x70, 0x6D, 0x70, 0x71, 0x6E, +0x75, 0x73, 0x72, 0x79, 0x78, 0x7B, 0xFF, 0xFF, 0xFD, 0xFA, 0xFC, 0xFB, 0xF7, 0xFD, 0xFE, 0xFA, +0x7D, 0x7D, 0xFE, 0x79, 0x7B, 0x7C, 0x7B, 0x7E, 0x7E, 0xFD, 0xFA, 0xFA, 0xF7, 0xF8, 0xF9, 0xF9, +0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x7D, 0x7B, 0x77, 0x78, 0x74, 0x71, 0x74, 0x6F, 0x6F, 0x71, 0x6D, +0x6F, 0x71, 0x6F, 0x73, 0x74, 0x77, 0x7B, 0x7D, 0x7F, 0xFF, 0xFC, 0xFE, 0xFB, 0xF8, 0xFB, 0xF7, +0xF9, 0xFE, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7E, 0x7B, 0x7B, 0x7E, 0x7C, 0xFF, 0xFE, +0xFE, 0xFB, 0xFE, 0xFF, 0xFD, 0xFE, 0x7E, 0x7F, 0x7A, 0x78, 0x79, 0x75, 0x74, 0x75, 0x73, 0x75, +0x77, 0x77, 0x79, 0x7B, 0x7D, 0xFF, 0xFA, 0xF8, 0xF4, 0xF2, 0xF5, 0xF1, 0xF2, 0xF6, 0xF3, 0xF6, +0xFA, 0xFB, 0xFC, 0x7D, 0x7A, 0x7A, 0x74, 0x77, 0x78, 0x74, 0x7A, 0x77, 0x7A, 0xFF, 0x7F, 0xF9, +0xFB, 0xFB, 0xF9, 0xFF, 0x7F, 0x7C, 0x7A, 0x77, 0x72, 0x73, 0x6E, 0x6E, 0x6E, 0x6D, 0x70, 0x70, +0x75, 0x7D, 0x7B, 0xFE, 0xFD, 0xFF, 0xFC, 0xFF, 0x7E, 0xFF, 0x7E, 0x7A, 0x79, 0x76, 0x6F, 0x72, +0x72, 0x6F, 0x73, 0x6F, 0x6E, 0x74, 0x72, 0x74, 0x7C, 0x7C, 0xFF, 0xF9, 0xFA, 0xF9, 0xF5, 0xF7, +0xF7, 0xF5, 0xFA, 0xFA, 0xF7, 0xFA, 0xF9, 0xF8, 0xFC, 0xF9, 0xF8, 0xFA, 0xF6, 0xF9, 0xFC, 0xFA, +0xFD, 0xFE, 0xFD, 0xFF, 0x7E, 0x7E, 0x7D, 0x7A, 0x7C, 0x7B, 0x79, 0x7C, 0x7B, 0x7B, 0xFF, 0x7E, +0xFF, 0xFC, 0xFE, 0xFE, 0xFB, 0xFD, 0x7C, 0x7F, 0x7F, 0x76, 0x78, 0x78, 0x74, 0x78, 0x78, 0x78, +0x7B, 0x7A, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x78, 0x7A, 0x7B, 0x7A, 0x7C, 0x7F, 0x7D, 0xFF, 0xFC, +0xFD, 0xFA, 0xFB, 0xFD, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x7B, 0x7D, 0x7D, 0x7E, 0x7E, 0x7D, +0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, 0xFD, 0xFF, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x77, 0x78, +0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, +0xFE, 0xFF, 0xFF, 0x7E, 0x7B, 0x78, 0x77, 0x76, 0x74, 0x73, 0x73, 0x71, 0x72, 0x73, 0x73, 0x74, +0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x7A, 0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7A, +0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7A, 0x7A, 0x79, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, +0x74, 0x77, 0x79, 0x7A, 0x7D, 0x7F, 0xFE, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFF, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4C, 0x49, 0x53, 0x54, 0x4A, 0x00, +0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x53, 0x46, 0x54, 0x3E, 0x00, 0x00, 0x00, 0x46, 0x69, +0x6C, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x6F, +0x6C, 0x64, 0x57, 0x61, 0x76, 0x65, 0x2E, 0x20, 0x20, 0x47, 0x6F, 0x6C, 0x64, 0x57, 0x61, 0x76, +0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, +0x43, 0x68, 0x72, 0x69, 0x73, 0x20, 0x43, 0x72, 0x61, 0x69, 0x67, 0x00 + +}; + +static const uint8_t shaun_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x08, 0x06, 0x00, 0x00, 0x00, 0xF2, 0x0C, 0xE0, + 0x57, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, + 0xBD, 0xA7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x42, 0x8A, 0x00, + 0x00, 0x42, 0x8A, 0x01, 0x34, 0xA8, 0x6C, 0x25, 0x00, 0x00, 0x00, 0x09, 0x76, 0x70, 0x41, 0x67, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x00, 0x73, 0x4D, 0x3B, 0xD6, 0x00, 0x00, 0x1B, + 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0x9D, 0x79, 0x74, 0x14, 0x55, 0xBE, 0xC7, 0x3F, + 0x55, 0xDD, 0x49, 0x67, 0x5F, 0x3A, 0x7B, 0x42, 0x82, 0x61, 0x49, 0x02, 0x81, 0xB0, 0x29, 0x32, + 0x22, 0x3C, 0x16, 0x41, 0x45, 0x10, 0x15, 0x7D, 0x13, 0x65, 0xD0, 0x81, 0xE3, 0x7B, 0xCC, 0xD3, + 0x51, 0x04, 0xF5, 0xE1, 0xB8, 0xCE, 0xE6, 0x28, 0x22, 0x23, 0x33, 0x2C, 0x2A, 0x22, 0xEE, 0x02, + 0x22, 0x0C, 0x2A, 0x83, 0x28, 0x7B, 0x20, 0xC8, 0x92, 0x10, 0xD9, 0x97, 0x40, 0x08, 0x81, 0x90, + 0x3D, 0x64, 0x21, 0xE9, 0x4E, 0x3A, 0x5D, 0xF7, 0xFD, 0x71, 0xBB, 0x93, 0x0E, 0x10, 0xD2, 0x59, + 0x3A, 0x01, 0xCF, 0xFB, 0x9E, 0xD3, 0xE7, 0xA4, 0x6E, 0xA5, 0x6E, 0xDD, 0xFA, 0xFD, 0xEA, 0xFE, + 0xEE, 0xEF, 0xFE, 0xB6, 0x52, 0xB8, 0xFE, 0xA1, 0x03, 0x7A, 0x01, 0x43, 0x81, 0x9B, 0x80, 0x6A, + 0x60, 0x3F, 0xA0, 0x02, 0x8F, 0x00, 0xB7, 0x03, 0xA1, 0x80, 0x00, 0x72, 0x81, 0xAD, 0xC0, 0xC7, + 0xC0, 0x6E, 0xA0, 0xAE, 0xB3, 0x07, 0xFF, 0x4B, 0x43, 0x30, 0xF0, 0x67, 0x20, 0x1B, 0xB0, 0x20, + 0x89, 0xAE, 0x01, 0x95, 0x40, 0xB9, 0xED, 0xF8, 0x6A, 0xBF, 0x3C, 0xDB, 0x75, 0x81, 0xCD, 0xF4, + 0xAF, 0x03, 0x8C, 0x40, 0x2C, 0xD0, 0x13, 0x88, 0x00, 0x0C, 0x9D, 0xF9, 0xC0, 0x4A, 0x27, 0xDD, + 0xD7, 0x13, 0x88, 0x07, 0xFA, 0x03, 0x51, 0x36, 0x22, 0xE4, 0x03, 0x87, 0x80, 0x83, 0x48, 0x62, + 0x1B, 0x81, 0x85, 0x40, 0x72, 0x2B, 0xC7, 0xA9, 0x01, 0x5F, 0x00, 0x2F, 0x03, 0x35, 0xB6, 0xE3, + 0x0A, 0xDB, 0xDF, 0xDE, 0xC0, 0x48, 0x60, 0x22, 0x30, 0x08, 0xC9, 0x78, 0x3D, 0x92, 0xD1, 0x99, + 0xC0, 0x0F, 0xC0, 0x5A, 0xE0, 0x5C, 0x47, 0x13, 0xA6, 0xA3, 0x19, 0xA2, 0x07, 0x46, 0x00, 0x4F, + 0x22, 0x45, 0x4D, 0xD0, 0x65, 0x63, 0xB8, 0x84, 0x14, 0x47, 0xEF, 0x03, 0x09, 0xC0, 0x4B, 0x48, + 0xD1, 0x44, 0x40, 0x40, 0x00, 0x31, 0x31, 0x31, 0x54, 0x56, 0x56, 0x92, 0x93, 0x93, 0x83, 0xD5, + 0x6A, 0x25, 0x3A, 0x3A, 0x9A, 0x89, 0x13, 0x27, 0x32, 0x60, 0xC0, 0x00, 0xAC, 0x56, 0x2B, 0xBB, + 0x77, 0xEF, 0x66, 0xDD, 0xBA, 0x75, 0x14, 0x16, 0x16, 0xDA, 0xFB, 0xAB, 0x03, 0x4E, 0x23, 0x67, + 0x4D, 0x9D, 0x8D, 0xC0, 0xFB, 0x90, 0x22, 0xF0, 0x1E, 0xC0, 0xAB, 0x89, 0x71, 0x6A, 0xC0, 0x11, + 0xE0, 0x0D, 0xE0, 0x6B, 0xE4, 0xEC, 0xFC, 0xC5, 0xC1, 0x07, 0x78, 0x0D, 0x28, 0xA5, 0x69, 0x51, + 0x63, 0xFF, 0x99, 0x80, 0x2A, 0xFB, 0xF1, 0xC0, 0x81, 0x03, 0xC5, 0xA6, 0x4D, 0x9B, 0x44, 0x49, + 0x49, 0x89, 0xC8, 0xCA, 0xCA, 0x12, 0xAF, 0xBF, 0xFE, 0xBA, 0x78, 0xFC, 0xF1, 0xC7, 0x45, 0x5A, + 0x5A, 0x9A, 0xD0, 0x34, 0x4D, 0xD8, 0x51, 0x57, 0x57, 0x27, 0xB6, 0x6E, 0xDD, 0x2A, 0xFA, 0xF7, + 0xEF, 0xDF, 0x5C, 0xFF, 0x8D, 0x7E, 0x8A, 0xA2, 0x08, 0x55, 0x55, 0xAF, 0x76, 0xAE, 0x02, 0x78, + 0x0E, 0xF9, 0x22, 0x75, 0x08, 0x3A, 0x6A, 0x86, 0x78, 0x02, 0x7F, 0x05, 0x9E, 0x02, 0xDC, 0x00, + 0x14, 0x45, 0x21, 0x24, 0x24, 0x84, 0xE8, 0xE8, 0x68, 0xDC, 0xDD, 0xDD, 0xB9, 0x70, 0xE1, 0x02, + 0xB9, 0xB9, 0xB9, 0xD4, 0xD5, 0x35, 0x5E, 0x87, 0xBD, 0xBC, 0xBC, 0x58, 0xB1, 0x62, 0x05, 0x13, + 0x26, 0x4C, 0xA8, 0x6F, 0x13, 0x42, 0x20, 0x84, 0x40, 0x55, 0xD5, 0xAB, 0xDE, 0x6C, 0xD7, 0xAE, + 0x5D, 0x3C, 0xFC, 0xF0, 0xC3, 0xE4, 0xE4, 0xE4, 0x34, 0xFD, 0xE0, 0x8A, 0x42, 0x7C, 0x7C, 0x3C, + 0xF7, 0xDC, 0x73, 0x0F, 0xFD, 0xFA, 0xF5, 0xC3, 0xC3, 0xC3, 0x83, 0xEC, 0xEC, 0x6C, 0x36, 0x6C, + 0xD8, 0x40, 0x6A, 0x6A, 0x2A, 0x35, 0x35, 0x35, 0xF6, 0x7F, 0xAD, 0xB4, 0x8D, 0xFB, 0x73, 0xC0, + 0xDA, 0x41, 0xF4, 0x72, 0x39, 0x7E, 0x8F, 0x7C, 0xEB, 0x05, 0x20, 0xC2, 0xC2, 0xC2, 0xC4, 0x2B, + 0xAF, 0xBC, 0x22, 0x0E, 0x1E, 0x3C, 0x28, 0x2E, 0x5E, 0xBC, 0x28, 0x2A, 0x2A, 0x2A, 0x44, 0x56, + 0x56, 0x96, 0x58, 0xBC, 0x78, 0xB1, 0x48, 0x48, 0x48, 0x68, 0xF4, 0x96, 0xC6, 0xC4, 0xC4, 0x88, + 0x33, 0x67, 0xCE, 0x88, 0x96, 0xE2, 0xE3, 0x8F, 0x3F, 0x16, 0x77, 0xDE, 0x79, 0xA7, 0x78, 0xFE, + 0xF9, 0xE7, 0xC5, 0xBB, 0xEF, 0xBE, 0x2B, 0xDE, 0x7E, 0xFB, 0x6D, 0xF1, 0xE0, 0x83, 0x0F, 0x0A, + 0xA3, 0xD1, 0x28, 0xDC, 0xDC, 0xDC, 0xC4, 0xD4, 0xA9, 0x53, 0xC5, 0xE9, 0xD3, 0xA7, 0xAF, 0xB8, + 0xAE, 0xA2, 0xA2, 0x42, 0x2C, 0x58, 0xB0, 0x40, 0x04, 0x07, 0x07, 0x3B, 0x8E, 0xA3, 0x00, 0x58, + 0x0D, 0xFC, 0x0E, 0x08, 0xEF, 0x6C, 0x62, 0xB6, 0x15, 0x7D, 0x80, 0x33, 0xF6, 0x87, 0x8B, 0x8D, + 0x8D, 0x15, 0xEB, 0xD7, 0xAF, 0x6F, 0x24, 0x6A, 0x1C, 0x91, 0x91, 0x91, 0x21, 0x06, 0x0F, 0x1E, + 0x2C, 0x00, 0x61, 0x30, 0x18, 0xC4, 0xAF, 0x7F, 0xFD, 0x6B, 0x51, 0x51, 0x51, 0xD1, 0x62, 0x86, + 0x58, 0xAD, 0x56, 0x61, 0x36, 0x9B, 0x1B, 0xDD, 0xA7, 0xA6, 0xA6, 0x46, 0xEC, 0xD8, 0xB1, 0x43, + 0xAC, 0x5A, 0xB5, 0x4A, 0x94, 0x97, 0x97, 0x37, 0x79, 0xAD, 0xA6, 0x69, 0x62, 0xF1, 0xE2, 0xC5, + 0xC2, 0xC3, 0xC3, 0xE3, 0x72, 0x11, 0x66, 0x05, 0x76, 0x02, 0x43, 0x3A, 0x9B, 0xA8, 0x6D, 0xC1, + 0xDB, 0xF6, 0x07, 0xF2, 0xF5, 0xF5, 0x15, 0x2B, 0x56, 0xAC, 0x68, 0x96, 0x98, 0xC7, 0x8E, 0x1D, + 0x13, 0xF3, 0xE7, 0xCF, 0x17, 0x1B, 0x36, 0x6C, 0x10, 0xA5, 0xA5, 0xA5, 0x2D, 0x66, 0x46, 0x7B, + 0xA0, 0xB2, 0xB2, 0x52, 0x4C, 0x98, 0x30, 0xA1, 0xA9, 0x75, 0xE7, 0x00, 0x52, 0x31, 0x68, 0x77, + 0xB8, 0x7A, 0x0D, 0x89, 0x02, 0x36, 0xDA, 0x07, 0x3F, 0x79, 0xF2, 0x64, 0x3E, 0xFC, 0xF0, 0x43, + 0x0C, 0x86, 0x4E, 0x55, 0xF5, 0x9D, 0xC6, 0xC1, 0x83, 0x07, 0x59, 0xBB, 0x76, 0x2D, 0x16, 0x8B, + 0x85, 0x94, 0x94, 0x14, 0x52, 0x53, 0x53, 0xB1, 0x5A, 0xEB, 0x97, 0x91, 0xF7, 0x91, 0xDA, 0xE2, + 0x0D, 0xB5, 0xAE, 0x8C, 0x07, 0xCC, 0x80, 0xF0, 0xF4, 0xF4, 0x14, 0xEB, 0xD6, 0xAD, 0xEB, 0x94, + 0xB7, 0xBD, 0x3D, 0x50, 0x54, 0x54, 0x24, 0x92, 0x93, 0x93, 0x1D, 0x67, 0x49, 0x36, 0xD0, 0xBD, + 0xB3, 0x09, 0xDC, 0x12, 0x84, 0x00, 0xAB, 0xEC, 0x0F, 0x10, 0x1F, 0x1F, 0x2F, 0x72, 0x73, 0x73, + 0x3B, 0x9B, 0xAE, 0x6D, 0xC2, 0x96, 0x2D, 0x5B, 0x84, 0x8F, 0x8F, 0x8F, 0xA3, 0x6A, 0x7E, 0x47, + 0x7B, 0x13, 0x4D, 0x6D, 0x7B, 0x17, 0x57, 0x85, 0x37, 0x72, 0x53, 0x35, 0xC9, 0xDE, 0xD0, 0xAD, + 0x5B, 0x37, 0x8C, 0x46, 0xA3, 0x8B, 0x6E, 0xD7, 0x31, 0xF0, 0xF5, 0xF5, 0x45, 0xAF, 0xAF, 0xDF, + 0x92, 0xA8, 0x80, 0x47, 0x7B, 0xDF, 0xC3, 0x55, 0x0C, 0xF9, 0x4F, 0xE0, 0x37, 0xD8, 0xD6, 0xA8, + 0x84, 0x84, 0x04, 0x9E, 0x7E, 0xFA, 0x69, 0x3C, 0x3C, 0xDA, 0x7D, 0xFC, 0x1D, 0x8A, 0x5D, 0xBB, + 0x76, 0x51, 0x56, 0x56, 0x66, 0x3F, 0xAC, 0x42, 0xDA, 0xCC, 0xDA, 0x15, 0xAE, 0xD8, 0x81, 0x1A, + 0x81, 0xC7, 0xB1, 0x19, 0xE9, 0x12, 0x12, 0x12, 0xF8, 0xEC, 0xB3, 0xCF, 0xB8, 0xF9, 0xE6, 0x9B, + 0x5D, 0x44, 0xA6, 0x8E, 0x43, 0x5E, 0x5E, 0x23, 0xFA, 0x0B, 0x5C, 0xF7, 0x42, 0xB7, 0x2B, 0x46, + 0x21, 0x6D, 0x52, 0x42, 0xAF, 0xD7, 0x8B, 0x25, 0x4B, 0x96, 0x74, 0xB6, 0xE8, 0x6F, 0x37, 0xEC, + 0xDD, 0xBB, 0x57, 0x84, 0x86, 0x86, 0x3A, 0x2E, 0xEC, 0xB3, 0xDB, 0x9B, 0x78, 0xAE, 0xE0, 0x70, + 0x12, 0x72, 0x0D, 0xA1, 0x6B, 0xD7, 0xAE, 0x8C, 0x1D, 0x3B, 0xD6, 0x85, 0xBC, 0xEF, 0x58, 0x24, + 0x25, 0x25, 0x31, 0x64, 0x48, 0xA3, 0x3D, 0xE1, 0x2D, 0xB4, 0xB3, 0x94, 0x71, 0x05, 0x43, 0x22, + 0xED, 0x7F, 0x44, 0x47, 0x47, 0x13, 0x12, 0x12, 0xE2, 0x1A, 0xEA, 0x74, 0x02, 0x0C, 0x06, 0x03, + 0x89, 0x89, 0x89, 0x8E, 0x4D, 0x51, 0x48, 0x3B, 0x5D, 0xBB, 0xC1, 0x15, 0x0C, 0xA9, 0xEF, 0x53, + 0xA7, 0xD3, 0x35, 0x69, 0x00, 0xBC, 0x51, 0xE1, 0xEB, 0xEB, 0xEB, 0x78, 0x68, 0xE0, 0x06, 0x98, + 0x21, 0xF5, 0xCE, 0x88, 0xBC, 0xBC, 0x3C, 0x47, 0xAD, 0xE4, 0x17, 0x81, 0xD2, 0xD2, 0x52, 0xC7, + 0xC3, 0x6A, 0xDA, 0xD9, 0x57, 0xE2, 0x0A, 0x86, 0x1C, 0x46, 0xEE, 0xCE, 0xC9, 0xCA, 0xCA, 0x22, + 0x35, 0x35, 0xD5, 0x65, 0xC4, 0xE9, 0x68, 0x54, 0x55, 0x55, 0x91, 0x91, 0x91, 0xE1, 0xD8, 0x94, + 0x8D, 0x64, 0xCA, 0x75, 0x8D, 0x70, 0xE0, 0x67, 0x6C, 0x9A, 0xC8, 0xD0, 0xA1, 0x43, 0x45, 0x76, + 0x76, 0x76, 0x67, 0x2B, 0x48, 0xED, 0x82, 0x1F, 0x7E, 0xF8, 0x41, 0xF8, 0xF9, 0xF9, 0x39, 0x6A, + 0x59, 0x4F, 0x74, 0x36, 0xB1, 0x9D, 0xC5, 0x73, 0x48, 0xA3, 0x9B, 0x00, 0xC4, 0xC8, 0x91, 0x23, + 0xC5, 0x8F, 0x3F, 0xFE, 0x28, 0xCC, 0x66, 0xB3, 0xCB, 0x88, 0x65, 0xB5, 0x5A, 0x5D, 0xCA, 0x8C, + 0xAC, 0xAC, 0x2C, 0x31, 0x6C, 0xD8, 0x30, 0x47, 0x66, 0x64, 0x01, 0x71, 0x9D, 0x4D, 0x68, 0x67, + 0x61, 0x04, 0xD6, 0x39, 0x0C, 0x5E, 0xF8, 0xF8, 0xF8, 0x88, 0x05, 0x0B, 0x16, 0xB8, 0x84, 0x58, + 0x99, 0x99, 0x99, 0x62, 0xFA, 0xF4, 0xE9, 0x62, 0xD9, 0xB2, 0x65, 0xC2, 0x64, 0x32, 0x5D, 0x71, + 0x5E, 0xD3, 0x34, 0x71, 0xEE, 0xDC, 0x39, 0x91, 0x97, 0x97, 0xD7, 0xAA, 0xFE, 0x4F, 0x9E, 0x3C, + 0x29, 0x46, 0x8C, 0x18, 0x71, 0xB9, 0x09, 0xFE, 0xF5, 0xCE, 0x26, 0xB2, 0xB3, 0x08, 0x46, 0x5A, + 0x79, 0x1B, 0x31, 0x04, 0x10, 0x49, 0x49, 0x49, 0x22, 0x27, 0x27, 0xA7, 0x5D, 0x99, 0x61, 0xB5, + 0x5A, 0xC5, 0x8C, 0x19, 0x33, 0x04, 0x20, 0xBC, 0xBC, 0xBC, 0xC4, 0xA3, 0x8F, 0x3E, 0x2A, 0x36, + 0x6F, 0xDE, 0x2C, 0xCE, 0x9F, 0x3F, 0x2F, 0x0A, 0x0B, 0x0B, 0xC5, 0xE1, 0xC3, 0x87, 0xC5, 0xDC, + 0xB9, 0x73, 0x45, 0x42, 0x42, 0x82, 0x18, 0x33, 0x66, 0x8C, 0x28, 0x28, 0x28, 0x68, 0xF1, 0x3D, + 0x96, 0x2E, 0x5D, 0x7A, 0x39, 0x33, 0x34, 0x60, 0x3B, 0xF0, 0xDF, 0x40, 0x37, 0x64, 0x38, 0xD1, + 0x75, 0x87, 0x28, 0xA4, 0xEF, 0x79, 0x2F, 0x36, 0x93, 0x3B, 0x57, 0x09, 0x26, 0x98, 0x35, 0x6B, + 0x56, 0xBB, 0x8A, 0xAE, 0x6D, 0xDB, 0xB6, 0x89, 0xD0, 0xD0, 0x50, 0xE1, 0xED, 0x69, 0x10, 0xE1, + 0xC1, 0x01, 0x02, 0x10, 0x9E, 0x5E, 0x5E, 0xA2, 0x5B, 0xB7, 0xEE, 0xA2, 0x57, 0xAF, 0x5E, 0x22, + 0x38, 0x24, 0x44, 0x28, 0x8A, 0x22, 0x00, 0xE1, 0xE6, 0xE6, 0x26, 0x3E, 0xFA, 0xE8, 0xA3, 0x16, + 0xDF, 0x63, 0xCD, 0x9A, 0x35, 0x42, 0xAF, 0xD7, 0x5F, 0xCD, 0x51, 0x55, 0x87, 0x14, 0x5D, 0x0B, + 0x80, 0x5B, 0x01, 0xF7, 0xB6, 0x12, 0xB1, 0x3D, 0x38, 0x1B, 0x0A, 0x4C, 0x07, 0xE6, 0x21, 0x0D, + 0x8A, 0x5D, 0x70, 0xD0, 0xCD, 0x75, 0x3A, 0x1D, 0xE1, 0xE1, 0xE1, 0x24, 0x25, 0x25, 0x61, 0x36, + 0x9B, 0x49, 0x4D, 0x4D, 0xC5, 0x64, 0x32, 0xD1, 0xB7, 0x6F, 0x5F, 0x7C, 0x7C, 0x7C, 0x00, 0x19, + 0xB4, 0x50, 0x50, 0x50, 0x40, 0x59, 0x59, 0x19, 0xBE, 0xBE, 0xBE, 0x28, 0x8A, 0x73, 0x7E, 0xB3, + 0xEC, 0xEC, 0x6C, 0x9E, 0x7E, 0xFA, 0x69, 0x8E, 0x1D, 0x3B, 0xC6, 0x8C, 0x87, 0xC7, 0x31, 0x77, + 0xC6, 0x14, 0x02, 0xFD, 0x7C, 0xA8, 0xAA, 0x36, 0x51, 0x5A, 0x5A, 0x42, 0x65, 0x45, 0x39, 0x81, + 0x3E, 0x06, 0xEE, 0xFC, 0x55, 0x7F, 0x86, 0x0D, 0x48, 0x20, 0xFD, 0xE8, 0x69, 0xB2, 0xB3, 0xCF, + 0x72, 0xC7, 0x1D, 0x77, 0xB4, 0xC8, 0xF2, 0xBC, 0x7E, 0xFD, 0x7A, 0x36, 0x6C, 0xD8, 0x80, 0x9F, + 0x9F, 0x1F, 0x3A, 0x9D, 0x0E, 0x8B, 0xA5, 0x5E, 0xD3, 0x55, 0x91, 0xC1, 0x78, 0x83, 0x81, 0xFB, + 0x81, 0xDE, 0x40, 0x11, 0xD2, 0xE8, 0xA8, 0xB5, 0x03, 0x6D, 0x5B, 0x04, 0x37, 0xA4, 0x68, 0x4A, + 0x45, 0xBE, 0x29, 0x8D, 0x66, 0x42, 0x97, 0x2E, 0x5D, 0xC4, 0x23, 0x8F, 0x3C, 0x22, 0x3E, 0xF9, + 0xE4, 0x13, 0x71, 0xEC, 0xD8, 0x31, 0x51, 0x55, 0x55, 0x25, 0x5E, 0x7A, 0xE9, 0x25, 0x01, 0x08, + 0x9D, 0x4E, 0x27, 0x06, 0x0E, 0x1A, 0x24, 0x66, 0xCF, 0x9E, 0x2D, 0xE6, 0xCF, 0x9F, 0x2F, 0x66, + 0xCE, 0x9C, 0x29, 0xFA, 0xF4, 0xE9, 0x23, 0x7A, 0xF7, 0xEE, 0x2D, 0xD6, 0xAC, 0x59, 0xE3, 0xD4, + 0x02, 0x9D, 0x99, 0x99, 0x29, 0xC6, 0x8D, 0x1B, 0x27, 0x95, 0x86, 0x9B, 0x13, 0x45, 0xEE, 0x86, + 0x25, 0x42, 0x64, 0xAC, 0x16, 0x5A, 0xFA, 0x2A, 0x51, 0xB6, 0xED, 0x63, 0x71, 0xFA, 0x9B, 0x05, + 0xE2, 0xF8, 0xD7, 0xF3, 0xC5, 0x85, 0x0D, 0xEF, 0x0B, 0xCB, 0xDE, 0x15, 0xA2, 0x74, 0xFB, 0x27, + 0x62, 0xFC, 0xB0, 0x41, 0x02, 0x10, 0x77, 0xDF, 0x7D, 0xB7, 0x38, 0x7A, 0xF4, 0x68, 0xA3, 0xFE, + 0x34, 0x4D, 0x13, 0xFB, 0xF7, 0xEF, 0x17, 0x6F, 0xBD, 0xF5, 0x96, 0xD8, 0xBD, 0x7B, 0xB7, 0xB0, + 0x58, 0x2C, 0xC2, 0x62, 0xB1, 0x88, 0x6D, 0xDB, 0xB6, 0x89, 0xB8, 0xB8, 0x38, 0xE1, 0xEE, 0xEE, + 0x2E, 0xDE, 0x7B, 0xEF, 0x3D, 0xB1, 0x69, 0xD3, 0x26, 0xF1, 0xDC, 0x73, 0xCF, 0x89, 0x7E, 0xFD, + 0xFA, 0x09, 0x77, 0x77, 0xF7, 0xAB, 0xCD, 0x9A, 0x12, 0xE0, 0x03, 0x64, 0x10, 0x60, 0x87, 0xC5, + 0xBD, 0x45, 0x20, 0x67, 0x44, 0x99, 0xE3, 0x60, 0x74, 0x3A, 0x9D, 0x48, 0x4A, 0x4A, 0x12, 0x6F, + 0xBE, 0xF9, 0xA6, 0x38, 0x76, 0xEC, 0x98, 0xB0, 0x58, 0x2C, 0xF5, 0x0F, 0x6C, 0x32, 0x99, 0xC4, + 0xA4, 0x49, 0x93, 0x04, 0x20, 0xBA, 0x84, 0x1A, 0x85, 0xA7, 0xC1, 0xAD, 0xD1, 0x83, 0x78, 0xB8, + 0xBB, 0x09, 0x9D, 0xAA, 0x8A, 0xA0, 0xA0, 0x20, 0xF1, 0xDA, 0x6B, 0xAF, 0x89, 0xB3, 0x67, 0xCF, + 0x5E, 0x35, 0x10, 0xA2, 0xA2, 0xA2, 0x42, 0xAC, 0x5C, 0xB9, 0x52, 0x0C, 0x18, 0x30, 0x40, 0x00, + 0xE2, 0x96, 0xDE, 0xDD, 0xC5, 0xC1, 0x95, 0x6F, 0x0B, 0xB1, 0xFF, 0x6B, 0x21, 0xD2, 0xBE, 0x92, + 0xBF, 0xF4, 0x55, 0x42, 0xEC, 0x5F, 0x25, 0xDB, 0xD2, 0x57, 0xC9, 0xB6, 0xFD, 0x5F, 0x8B, 0xC3, + 0x5F, 0xFD, 0x5D, 0x0C, 0x4E, 0xEC, 0x21, 0x00, 0xD1, 0xA3, 0x47, 0x0F, 0xF1, 0x87, 0x3F, 0xFC, + 0x41, 0xAC, 0x5A, 0xB5, 0x4A, 0xAC, 0x5C, 0xB9, 0x52, 0xCC, 0x9A, 0x35, 0x4B, 0xC4, 0xC4, 0xC4, + 0x08, 0x40, 0x84, 0x87, 0x87, 0x8B, 0xFB, 0xEE, 0xBB, 0x4F, 0x4C, 0x9C, 0x38, 0xB1, 0xDE, 0x98, + 0x38, 0x79, 0xF2, 0xE4, 0xFA, 0x60, 0x0B, 0x4D, 0xD3, 0x44, 0x7E, 0x7E, 0xBE, 0x58, 0xBE, 0x7C, + 0xB9, 0x18, 0x3F, 0x7E, 0xBC, 0xF0, 0xF5, 0xF5, 0xBD, 0x1A, 0x63, 0xCE, 0x21, 0x8D, 0x8F, 0xC1, + 0x2D, 0x21, 0x6C, 0x4B, 0x39, 0xA8, 0x20, 0x83, 0x9E, 0x5F, 0x07, 0x86, 0x39, 0x5E, 0x1F, 0x17, + 0x17, 0xC7, 0xF4, 0xE9, 0xD3, 0x49, 0x4E, 0x4E, 0x26, 0x32, 0x32, 0xF2, 0x8A, 0x0B, 0x77, 0xEC, + 0xD8, 0xC1, 0x84, 0x09, 0x13, 0xF0, 0xD4, 0x2B, 0x2C, 0xFF, 0xDB, 0x33, 0x58, 0xEA, 0xEA, 0x48, + 0x3B, 0x7A, 0x9A, 0xD2, 0x8A, 0x4B, 0x04, 0x07, 0xF8, 0x31, 0xA8, 0x57, 0x37, 0x52, 0x7F, 0x3E, + 0xCE, 0x3F, 0x96, 0xAF, 0xA7, 0xEC, 0x52, 0x35, 0x71, 0xF1, 0xF1, 0xDC, 0x39, 0x76, 0x2C, 0x03, + 0x07, 0x0E, 0x24, 0x28, 0x28, 0x88, 0xAA, 0xAA, 0x2A, 0x4E, 0x9C, 0x38, 0xC1, 0x96, 0x2D, 0x5B, + 0xD8, 0xB3, 0x67, 0x0F, 0x96, 0xDA, 0x5A, 0xEE, 0xBA, 0xAD, 0x3F, 0x73, 0x9F, 0x99, 0x42, 0xAF, + 0x6E, 0xD1, 0xA0, 0x39, 0x21, 0x21, 0x54, 0x95, 0x13, 0x67, 0xCE, 0xF3, 0xA7, 0x25, 0xAB, 0xF8, + 0x76, 0x7B, 0x1A, 0x55, 0xE6, 0x1A, 0xDB, 0x23, 0x08, 0x00, 0x02, 0x7C, 0xBD, 0x49, 0xEA, 0x19, + 0xC3, 0xD1, 0xAC, 0xF3, 0x14, 0x97, 0x55, 0xA2, 0x28, 0x0A, 0xE1, 0xE1, 0xE1, 0x24, 0x27, 0x27, + 0x33, 0x7B, 0xF6, 0x6C, 0xC2, 0xC2, 0xC2, 0xAE, 0xE8, 0xB2, 0xBA, 0xBA, 0x9A, 0xD4, 0xD4, 0x54, + 0x96, 0x2E, 0x5D, 0xCA, 0xF7, 0xDF, 0x7F, 0x4F, 0x65, 0x65, 0xA5, 0xE3, 0x69, 0x2B, 0xB0, 0x03, + 0xF8, 0x13, 0x90, 0x82, 0x13, 0x62, 0xAC, 0x25, 0x0C, 0x71, 0x03, 0x26, 0x03, 0x7F, 0x41, 0xAE, + 0x13, 0x80, 0xB4, 0xED, 0x4C, 0x99, 0x32, 0x85, 0x99, 0x33, 0x67, 0xD2, 0xA3, 0x47, 0x8F, 0xAB, + 0x5E, 0x28, 0x84, 0x60, 0xC6, 0x8C, 0x19, 0x2C, 0x58, 0xB0, 0x80, 0xA9, 0xF7, 0x8E, 0x64, 0xC9, + 0x2B, 0xBF, 0xB3, 0x79, 0xDE, 0x84, 0xA4, 0x85, 0x22, 0x87, 0x52, 0x67, 0xA9, 0x63, 0xEB, 0xDE, + 0x43, 0xFC, 0x73, 0xE5, 0xF7, 0x6C, 0x4F, 0x3F, 0x42, 0x65, 0xB5, 0x59, 0x0E, 0x52, 0x51, 0x11, + 0x42, 0x3E, 0x8B, 0x5E, 0xA7, 0x92, 0xD8, 0x2D, 0x9A, 0x69, 0x13, 0x47, 0x32, 0xE5, 0x9E, 0xFF, + 0x20, 0xD0, 0xDF, 0xD7, 0x39, 0x66, 0x38, 0x30, 0xA5, 0xDA, 0x64, 0x66, 0xD7, 0x81, 0x13, 0x6C, + 0xD9, 0x77, 0x98, 0xAC, 0xDC, 0x02, 0x54, 0x45, 0xA1, 0x67, 0x4C, 0x04, 0x63, 0x6E, 0x4D, 0x62, + 0x50, 0xAF, 0x6E, 0x7C, 0xBA, 0x6E, 0x3B, 0x4F, 0xCE, 0x59, 0x4A, 0x78, 0x44, 0x24, 0x5F, 0x7E, + 0xF9, 0x25, 0x43, 0x87, 0x0E, 0x45, 0xA7, 0xBB, 0xF6, 0x72, 0x6B, 0x36, 0x9B, 0xD9, 0xB6, 0x6D, + 0x1B, 0x0B, 0x17, 0x2E, 0x64, 0xD3, 0xA6, 0x4D, 0x8E, 0x81, 0x76, 0x20, 0xE3, 0xBA, 0xDE, 0x04, + 0x96, 0xD0, 0xCC, 0xCE, 0xDE, 0x59, 0x86, 0xF8, 0x02, 0xFF, 0x0B, 0x3C, 0x83, 0x0C, 0x09, 0x05, + 0x20, 0x31, 0x31, 0x91, 0x3F, 0xFE, 0xF1, 0x8F, 0xDC, 0x7B, 0xEF, 0xBD, 0xB8, 0xBB, 0x37, 0xAD, + 0x60, 0x9C, 0x39, 0x73, 0x86, 0x31, 0x63, 0xC7, 0x92, 0x9B, 0x73, 0x96, 0x7F, 0xCD, 0x7B, 0x9E, + 0xBB, 0x6E, 0x1F, 0x08, 0xD6, 0x26, 0x88, 0xA8, 0x53, 0xA9, 0xAA, 0x32, 0xF1, 0xF3, 0xF1, 0x33, + 0xEC, 0x3C, 0x70, 0x82, 0xE3, 0xD9, 0xB9, 0x54, 0x5C, 0xAA, 0xC6, 0xD3, 0xC3, 0x40, 0x4C, 0x78, + 0x30, 0x83, 0x13, 0xBB, 0x33, 0xA4, 0x6F, 0x1C, 0xE1, 0x21, 0x81, 0x36, 0xE1, 0x20, 0x9C, 0x67, + 0x86, 0xE3, 0x53, 0xAB, 0x2A, 0x08, 0xD0, 0xEA, 0xAC, 0xA0, 0x80, 0xAA, 0xD3, 0xD5, 0x4F, 0x96, + 0xBC, 0xA2, 0x52, 0xEE, 0x7A, 0xF2, 0xAF, 0x1C, 0x3D, 0x9B, 0xC7, 0x8A, 0xE5, 0xCB, 0x99, 0x34, + 0x69, 0x92, 0xD3, 0x5D, 0x57, 0x56, 0x56, 0xB2, 0x62, 0xC5, 0x0A, 0xE6, 0xCD, 0x9B, 0xC7, 0x89, + 0x13, 0x27, 0x1C, 0x4F, 0xD5, 0x00, 0xCB, 0x80, 0x57, 0x81, 0xE2, 0xB6, 0x30, 0x24, 0x10, 0x29, + 0xA2, 0xFE, 0x0B, 0x9B, 0xF6, 0xA4, 0xD7, 0xEB, 0x79, 0xE0, 0x81, 0x07, 0xF8, 0xF3, 0x9F, 0xFF, + 0x4C, 0x7C, 0x7C, 0x7C, 0xB3, 0x1D, 0x2C, 0x59, 0xB2, 0x84, 0xE9, 0xD3, 0xA7, 0x33, 0x6C, 0x40, + 0x02, 0xDF, 0xBE, 0xF3, 0x02, 0x01, 0xBE, 0xDE, 0xD7, 0x26, 0xA4, 0x9D, 0x60, 0x80, 0xB0, 0x6A, + 0x68, 0x9A, 0x86, 0xAA, 0x28, 0x28, 0x3A, 0x1D, 0x28, 0x8A, 0x9C, 0x11, 0xAD, 0x61, 0x84, 0xB3, + 0x50, 0x14, 0x5E, 0x5A, 0xB4, 0x9C, 0xBF, 0x2D, 0x5B, 0x43, 0x72, 0x72, 0x32, 0x9F, 0x7E, 0xFA, + 0x29, 0x6E, 0x6E, 0x6E, 0x2D, 0xEA, 0x22, 0x33, 0x33, 0x93, 0xD7, 0x5F, 0x7F, 0x9D, 0x15, 0x2B, + 0x56, 0x38, 0xCE, 0x16, 0x0D, 0x19, 0x01, 0x39, 0x13, 0x99, 0xCB, 0x72, 0x05, 0x9A, 0x33, 0x2E, + 0x86, 0x00, 0xFF, 0x40, 0xAA, 0xB5, 0x7A, 0x90, 0x22, 0xEA, 0x85, 0x17, 0x5E, 0x60, 0xC9, 0x92, + 0x25, 0x4E, 0x31, 0xC3, 0x6C, 0x36, 0xB3, 0x6E, 0xDD, 0x3A, 0x00, 0x26, 0x0C, 0xBF, 0x99, 0x00, + 0x7F, 0x9F, 0xE6, 0x89, 0x29, 0x90, 0x33, 0xC8, 0xAA, 0xA1, 0x00, 0x3A, 0x55, 0x95, 0xAA, 0xB0, + 0xA6, 0x81, 0xD5, 0xEA, 0x5A, 0x66, 0x00, 0xA8, 0x0A, 0x13, 0x86, 0x0F, 0x22, 0xC0, 0xD7, 0x8B, + 0x94, 0x94, 0x14, 0x32, 0x33, 0x33, 0x5B, 0xDC, 0x45, 0xCF, 0x9E, 0x3D, 0x59, 0xBC, 0x78, 0x31, + 0x73, 0xE6, 0xCC, 0x71, 0xF4, 0x09, 0xA9, 0xC0, 0x43, 0xC8, 0x7D, 0x4B, 0xC4, 0x55, 0x6F, 0x7D, + 0x8D, 0x3E, 0x8D, 0x34, 0xEC, 0x2D, 0x54, 0x80, 0x90, 0x90, 0x10, 0xDE, 0x79, 0xE7, 0x1D, 0x5E, + 0x7D, 0xF5, 0x55, 0xFC, 0xFD, 0xFD, 0x9D, 0x1A, 0xD8, 0xF1, 0xE3, 0xC7, 0xF9, 0x69, 0xF7, 0x6E, + 0x42, 0x02, 0xFD, 0x18, 0x3B, 0xA4, 0x9F, 0x7D, 0xFD, 0xBC, 0xBE, 0xA1, 0x69, 0xF4, 0xED, 0x11, + 0xC3, 0x2D, 0x89, 0x3D, 0xB8, 0x70, 0xE1, 0x02, 0x5B, 0xB7, 0x6E, 0x6D, 0x55, 0x37, 0x5E, 0x5E, + 0x5E, 0x3C, 0xF5, 0xD4, 0x53, 0x7C, 0xF0, 0xC1, 0x07, 0xC4, 0xC6, 0xC6, 0x3A, 0x9E, 0xBA, 0x1F, + 0x98, 0x03, 0x5C, 0x41, 0xC4, 0xA6, 0x18, 0xE2, 0x89, 0x4C, 0x1D, 0x98, 0x8C, 0x4D, 0xAC, 0x45, + 0x45, 0x45, 0xB1, 0x68, 0xD1, 0x22, 0xA6, 0x4D, 0x9B, 0xD6, 0xA2, 0xE9, 0xBB, 0x7D, 0xFB, 0x76, + 0x8A, 0x8B, 0x8A, 0xB8, 0xB5, 0x4F, 0x4F, 0xE2, 0xBB, 0x46, 0xB6, 0x6C, 0x01, 0xEE, 0x2C, 0x08, + 0xF0, 0xF6, 0xF6, 0x64, 0xDC, 0xD0, 0x01, 0x00, 0x6C, 0xD8, 0xB0, 0x01, 0xB3, 0xD9, 0xDC, 0xAA, + 0xAE, 0x54, 0x55, 0x65, 0xE2, 0xC4, 0x89, 0x2C, 0x5D, 0xBA, 0xF4, 0x72, 0xA5, 0xE7, 0x11, 0xE4, + 0xBA, 0xDC, 0xC8, 0xC1, 0x75, 0x35, 0x86, 0x28, 0xC0, 0xFF, 0x20, 0xC5, 0x94, 0x0A, 0x92, 0x19, + 0xEF, 0xBE, 0xFB, 0x2E, 0x0F, 0x3D, 0xF4, 0x90, 0xD3, 0xBB, 0x68, 0x90, 0xE2, 0x6A, 0xD3, 0xA6, + 0x4D, 0x00, 0x8C, 0x19, 0x92, 0x84, 0x87, 0xE7, 0x8D, 0x11, 0x42, 0x0A, 0x80, 0x80, 0x11, 0x83, + 0x12, 0x09, 0xF2, 0xF7, 0x21, 0x2D, 0x2D, 0x9D, 0xAC, 0xAC, 0xAC, 0x36, 0x75, 0x37, 0x6A, 0xD4, + 0x28, 0x16, 0x2D, 0x5A, 0x44, 0x54, 0x54, 0x94, 0xBD, 0x49, 0x87, 0xCC, 0x0A, 0xB8, 0xDF, 0xF1, + 0xFF, 0xAE, 0xC6, 0x90, 0x31, 0xC8, 0x0D, 0x8D, 0x01, 0xC0, 0x68, 0x34, 0x32, 0x6F, 0xDE, 0xBC, + 0x46, 0xF9, 0x19, 0xCE, 0x22, 0x3B, 0x3B, 0x9B, 0xF4, 0xFD, 0xFB, 0x09, 0xF2, 0xF7, 0x61, 0xF8, + 0x80, 0x5E, 0x37, 0x86, 0xB8, 0xB2, 0x43, 0x68, 0xC4, 0xC5, 0x44, 0x30, 0x20, 0x3E, 0x96, 0xFC, + 0xFC, 0x3C, 0x76, 0xED, 0xDA, 0xD5, 0xE6, 0x2E, 0xC7, 0x8E, 0x1D, 0xCB, 0x1B, 0x6F, 0xBC, 0xE1, + 0xE8, 0x06, 0xF6, 0x43, 0x66, 0x89, 0xDD, 0x64, 0x6F, 0xB8, 0x9C, 0x21, 0x91, 0x48, 0x51, 0x15, + 0x0A, 0xD2, 0xA9, 0xFF, 0xF2, 0xCB, 0x2F, 0xF3, 0xD0, 0x43, 0x0F, 0xB5, 0x6A, 0x00, 0xE9, 0xE9, + 0xE9, 0xE4, 0x5D, 0xC8, 0xA3, 0x4F, 0xF7, 0x18, 0x7A, 0x44, 0x87, 0x3B, 0xBF, 0x18, 0xAB, 0x2A, + 0xA8, 0xAA, 0x4C, 0xCC, 0x01, 0xD0, 0xA9, 0x52, 0xBB, 0x6A, 0x2D, 0x54, 0x05, 0x54, 0x15, 0xAB, + 0xA6, 0x61, 0xD5, 0xB4, 0xFA, 0xFE, 0xAF, 0x09, 0x01, 0x5E, 0x5E, 0x9E, 0x0C, 0x1F, 0xD8, 0x1B, + 0x80, 0x9D, 0x3B, 0x77, 0xA2, 0xB5, 0x83, 0xB8, 0x4D, 0x4E, 0x4E, 0x66, 0xFA, 0xF4, 0xE9, 0x8E, + 0x4D, 0xFD, 0x90, 0x41, 0xDB, 0x2A, 0x34, 0x96, 0x5F, 0x0A, 0x32, 0x21, 0xE5, 0x36, 0x7B, 0xC3, + 0x23, 0x8F, 0x3C, 0xC2, 0xF4, 0xE9, 0xD3, 0x5B, 0x1D, 0xA8, 0x20, 0xDD, 0xB7, 0x82, 0xDB, 0xFA, + 0xC5, 0xE3, 0xE3, 0xED, 0x09, 0x5A, 0x33, 0x0C, 0x51, 0x14, 0xAC, 0x9A, 0x46, 0xFA, 0xA1, 0x93, + 0xFC, 0x7B, 0xE7, 0x7E, 0x4E, 0x9D, 0xCB, 0xC7, 0xDB, 0xD3, 0xC0, 0x6D, 0x49, 0xF1, 0x8C, 0xBB, + 0x7D, 0x20, 0xA1, 0x41, 0x01, 0x2D, 0x5F, 0x83, 0x14, 0x85, 0x53, 0x39, 0x79, 0xFC, 0x6B, 0xCB, + 0x5E, 0xD2, 0x8F, 0x67, 0x61, 0xB5, 0x6A, 0x24, 0x76, 0x8F, 0xE6, 0xFE, 0x11, 0xB7, 0xD0, 0x37, + 0xEE, 0xA6, 0x6B, 0xAB, 0x99, 0x8A, 0xC2, 0xAD, 0x7D, 0x7B, 0xE2, 0xAE, 0xD7, 0x91, 0x91, 0x91, + 0x41, 0x49, 0x49, 0x49, 0x9B, 0xA3, 0x68, 0xDC, 0xDC, 0xDC, 0x78, 0xE6, 0x99, 0x67, 0x48, 0x49, + 0x49, 0x61, 0xEF, 0xDE, 0xBD, 0xF6, 0xE6, 0xC9, 0xC0, 0x72, 0x60, 0xBF, 0x23, 0x43, 0xFA, 0x03, + 0x53, 0xED, 0x07, 0x7D, 0xFA, 0xF4, 0xE1, 0xC5, 0x17, 0x5F, 0xC4, 0xCB, 0xCB, 0xCB, 0xE9, 0x9B, + 0x39, 0xA2, 0xAC, 0xAC, 0x8C, 0xFD, 0xFB, 0xF7, 0xA3, 0x53, 0x15, 0x86, 0xF4, 0xED, 0x09, 0x8A, + 0x4A, 0x73, 0x91, 0xFB, 0xB5, 0x96, 0x3A, 0x16, 0xAE, 0xFC, 0x9E, 0x39, 0x1F, 0x7F, 0x43, 0xE1, + 0xC5, 0xF2, 0xFA, 0xF6, 0x65, 0xDF, 0x6C, 0x65, 0xD8, 0x80, 0x04, 0xDE, 0x79, 0x76, 0x2A, 0xFD, + 0x13, 0x62, 0x9D, 0x67, 0x8A, 0xA2, 0xF0, 0x7D, 0xEA, 0x7E, 0x9E, 0x7D, 0xE7, 0x53, 0x8E, 0x9D, + 0x69, 0x50, 0xFB, 0xBF, 0xDE, 0xBC, 0x9B, 0x0F, 0xD7, 0x6E, 0xE6, 0x2F, 0xFF, 0x93, 0xCC, 0xA3, + 0xE3, 0xFF, 0x03, 0xB5, 0xA9, 0xD9, 0xA7, 0x69, 0xF4, 0x8E, 0xED, 0x42, 0xD7, 0x88, 0x10, 0x4E, + 0x67, 0x65, 0x71, 0xF2, 0xE4, 0xC9, 0x76, 0x09, 0x6B, 0x8A, 0x8A, 0x8A, 0x62, 0xE6, 0xCC, 0x99, + 0x4C, 0x9D, 0x3A, 0xD5, 0xAE, 0x2C, 0x44, 0x00, 0x8F, 0x02, 0x19, 0xF6, 0x17, 0x44, 0x05, 0xA6, + 0x61, 0x33, 0x89, 0xB8, 0xBB, 0xBB, 0x33, 0x6B, 0xD6, 0xAC, 0x26, 0x4D, 0x21, 0xCE, 0xE0, 0xEC, + 0xD9, 0xB3, 0x64, 0x9E, 0x3A, 0x45, 0x44, 0x70, 0x20, 0xBD, 0xBB, 0x75, 0x01, 0xD1, 0x0C, 0x11, + 0x55, 0x95, 0x55, 0x9B, 0x7E, 0xE2, 0xD5, 0xF7, 0xBE, 0x6A, 0xC4, 0x0C, 0x2F, 0x2F, 0x2F, 0xFC, + 0xFC, 0xFD, 0xD9, 0x96, 0x7E, 0x94, 0x67, 0xDE, 0xFE, 0x88, 0x82, 0xE2, 0x8B, 0xCE, 0x89, 0x2F, + 0x55, 0xE5, 0xF0, 0xE9, 0x1C, 0x66, 0xBC, 0xFD, 0x71, 0x23, 0x66, 0x18, 0x0C, 0x06, 0xC2, 0xC2, + 0xC2, 0x28, 0x2C, 0xAB, 0xE2, 0xF9, 0x7F, 0x7C, 0xCE, 0x96, 0x7D, 0x87, 0x9B, 0x16, 0x5F, 0x42, + 0x10, 0x1E, 0xE4, 0x4F, 0xBF, 0xB8, 0x9B, 0xA8, 0xBA, 0x74, 0x89, 0xB4, 0xB4, 0xB4, 0x36, 0x33, + 0xC3, 0x8E, 0x71, 0xE3, 0xC6, 0x31, 0x7C, 0xF8, 0x70, 0xC7, 0xA6, 0x7B, 0x80, 0x04, 0xFB, 0x48, + 0x12, 0x80, 0xFB, 0xEC, 0x67, 0x46, 0x8C, 0x18, 0xC1, 0x03, 0x0F, 0x3C, 0xD0, 0xA6, 0x1B, 0x1E, + 0x3D, 0x7A, 0x94, 0xD2, 0x92, 0x12, 0xE2, 0xBB, 0x46, 0x12, 0x19, 0x62, 0xBC, 0xB6, 0xB8, 0x52, + 0x14, 0xCA, 0x2B, 0x2E, 0xF1, 0xFE, 0xEA, 0x8D, 0x54, 0x99, 0x1A, 0xD4, 0xCB, 0xBE, 0x7D, 0xFB, + 0xB2, 0x72, 0xE5, 0x4A, 0x36, 0x6F, 0xDE, 0xCC, 0x13, 0x4F, 0x3C, 0xC1, 0x4F, 0x87, 0x32, 0xF9, + 0x2E, 0x25, 0x4D, 0xAE, 0x09, 0xCD, 0x41, 0x08, 0xBE, 0x58, 0xBF, 0x83, 0xCC, 0x9C, 0x86, 0x78, + 0x5C, 0xA3, 0xD1, 0xC8, 0xFC, 0xF9, 0xF3, 0x49, 0x49, 0x49, 0xE1, 0xBD, 0xF7, 0xDE, 0x45, 0xE8, + 0xDD, 0xF9, 0x60, 0xCD, 0x26, 0x2C, 0xB5, 0x4D, 0x47, 0xF2, 0xE8, 0xDD, 0xDD, 0xE4, 0x0C, 0x07, + 0xF6, 0xEC, 0xD9, 0xE3, 0x98, 0xB0, 0xD3, 0x26, 0xF8, 0xF9, 0xF9, 0x31, 0x79, 0xF2, 0x64, 0xC7, + 0x68, 0xFA, 0x58, 0x60, 0xBC, 0x9D, 0x21, 0xE3, 0xB1, 0xCD, 0x0E, 0x83, 0xC1, 0xC0, 0xB4, 0x69, + 0xD3, 0x9C, 0xDE, 0xF8, 0x35, 0x85, 0x43, 0x87, 0x0E, 0x01, 0x90, 0xD8, 0x3D, 0x06, 0x2F, 0x8F, + 0x66, 0xD4, 0x5D, 0x45, 0xE1, 0x6C, 0x5E, 0x11, 0xC7, 0xCE, 0x9C, 0x6F, 0xD4, 0xFC, 0xE4, 0x93, + 0x4F, 0x32, 0x7E, 0xFC, 0x78, 0x06, 0x0C, 0x18, 0xC0, 0x8B, 0x2F, 0xBE, 0x48, 0x74, 0xD7, 0x9B, + 0x48, 0xFD, 0xF9, 0x78, 0xD3, 0x76, 0x30, 0x07, 0x98, 0xCC, 0x35, 0xEC, 0x3D, 0x72, 0xAA, 0x51, + 0xDB, 0x98, 0x31, 0x63, 0x78, 0xFC, 0xF1, 0xC7, 0x89, 0x8B, 0x8B, 0xE3, 0xB1, 0xC7, 0x1E, 0x63, + 0xC2, 0x84, 0x09, 0xA4, 0x1F, 0x3B, 0x4D, 0x71, 0x59, 0xE5, 0x35, 0x66, 0x9D, 0x42, 0xBF, 0xB8, + 0x9B, 0x70, 0xD7, 0xEB, 0x38, 0x7E, 0xFC, 0x38, 0xE5, 0xE5, 0xE5, 0xCD, 0xDE, 0xDB, 0x59, 0x8C, + 0x1A, 0x35, 0x8A, 0xEE, 0xDD, 0xEB, 0x73, 0x7E, 0x74, 0xC0, 0x44, 0x15, 0xB9, 0x5B, 0xBC, 0xDB, + 0xDE, 0xDA, 0xB7, 0x6F, 0x5F, 0x46, 0x8F, 0x1E, 0xDD, 0xA6, 0x1B, 0x59, 0x2C, 0x16, 0x8E, 0x1E, + 0x3D, 0x2A, 0xFB, 0xEB, 0x11, 0xD3, 0xBC, 0x46, 0xA3, 0x80, 0xB9, 0xD6, 0x42, 0xAD, 0xA5, 0xF1, + 0xDB, 0x27, 0x1C, 0xB4, 0x32, 0x21, 0x04, 0x08, 0x41, 0xB5, 0xB9, 0x06, 0xAD, 0x39, 0x6D, 0x4D, + 0x01, 0xAB, 0x55, 0xC3, 0x5C, 0xD3, 0xF8, 0xCD, 0xB7, 0x58, 0x2C, 0xF5, 0x9A, 0x92, 0xA6, 0x69, + 0xD4, 0xD6, 0xD6, 0x52, 0x6B, 0xA9, 0xA3, 0xCE, 0x6A, 0x6D, 0xDA, 0xAA, 0x27, 0x34, 0x62, 0x23, + 0x43, 0x09, 0x35, 0xFA, 0x93, 0x9D, 0x9D, 0x4D, 0x4A, 0x4A, 0x0A, 0x15, 0x15, 0x15, 0x8D, 0xC6, + 0xD6, 0x52, 0x54, 0x57, 0x57, 0x93, 0x9E, 0x9E, 0xCE, 0xFB, 0xEF, 0xBF, 0x7F, 0x79, 0xE0, 0x5D, + 0x92, 0x1E, 0x48, 0x44, 0x66, 0xCA, 0x02, 0x70, 0xF7, 0xDD, 0x77, 0x13, 0x1C, 0xDC, 0x22, 0x9F, + 0xCA, 0x15, 0xA8, 0xA8, 0xA8, 0xE0, 0xCC, 0x99, 0x33, 0x78, 0xB8, 0xEB, 0xE9, 0x19, 0x13, 0x4E, + 0xB3, 0x1B, 0x10, 0x21, 0x08, 0x0F, 0x0A, 0x20, 0xD4, 0xE8, 0x47, 0x45, 0x55, 0x83, 0x75, 0x7A, + 0xD1, 0xA2, 0x45, 0x44, 0x44, 0x44, 0x10, 0x15, 0x15, 0xC5, 0x87, 0x1F, 0x7E, 0xC8, 0xE9, 0xAC, + 0xD3, 0x3C, 0x3C, 0xA2, 0x9F, 0xB4, 0xCC, 0x5E, 0x6B, 0x61, 0x17, 0xE0, 0xE5, 0x61, 0xA0, 0x47, + 0x74, 0x38, 0xBB, 0x0E, 0x36, 0x58, 0x5C, 0x37, 0x6E, 0xDC, 0xC8, 0xDC, 0xB9, 0x73, 0x19, 0x33, + 0x66, 0x0C, 0x3B, 0x76, 0xEC, 0xE0, 0xBB, 0xEF, 0xD6, 0x31, 0xA0, 0x47, 0x24, 0x81, 0xBE, 0xDE, + 0x4D, 0x0F, 0x51, 0x40, 0xA8, 0xD1, 0x9F, 0xAE, 0x11, 0x21, 0xA4, 0x1E, 0x38, 0xC1, 0x6F, 0x7F, + 0xFB, 0x5B, 0x12, 0x12, 0x12, 0x18, 0x32, 0x64, 0x08, 0x83, 0x07, 0x0F, 0xA6, 0x7B, 0xF7, 0xEE, + 0x44, 0x45, 0x45, 0x11, 0x18, 0x18, 0x88, 0xC1, 0x60, 0x40, 0xA7, 0xD3, 0xD5, 0x6F, 0x9E, 0x35, + 0x4D, 0xC3, 0x62, 0xB1, 0x50, 0x5D, 0x5D, 0x4D, 0x71, 0x71, 0x31, 0xA7, 0x4F, 0x9F, 0x26, 0x2D, + 0x2D, 0x8D, 0x94, 0x94, 0x14, 0x32, 0x32, 0x32, 0x28, 0x2E, 0xBE, 0xC2, 0xE8, 0x9B, 0xAB, 0x47, + 0xAA, 0xB9, 0x46, 0x00, 0x6F, 0x6F, 0x6F, 0x46, 0x8C, 0x18, 0xD1, 0x26, 0x66, 0x00, 0x14, 0x14, + 0x14, 0x90, 0x97, 0x9F, 0x4F, 0x90, 0xBF, 0x2F, 0x51, 0xA1, 0xC6, 0xE6, 0x37, 0x84, 0x9A, 0xA0, + 0x4B, 0x58, 0x10, 0xE3, 0x6E, 0x1F, 0xC8, 0x3F, 0x97, 0xAF, 0xAF, 0x6F, 0x3E, 0x7C, 0xF8, 0x30, + 0x0F, 0x3F, 0xFC, 0x30, 0xEE, 0xEE, 0xEE, 0x94, 0x57, 0x54, 0x10, 0x66, 0xF4, 0x63, 0xC2, 0xF0, + 0x41, 0x4E, 0x8D, 0x41, 0x75, 0xD3, 0x31, 0x69, 0xF4, 0xAD, 0xAC, 0xD9, 0xBA, 0x87, 0x4B, 0x36, + 0xBF, 0x4A, 0x65, 0x65, 0x25, 0xAF, 0xBD, 0xF6, 0x1A, 0x73, 0xE6, 0xCC, 0xA1, 0xBA, 0xBA, 0x1A, + 0x10, 0x3C, 0x74, 0xC7, 0x6D, 0xF8, 0xF8, 0x78, 0x35, 0xCD, 0x60, 0x21, 0xF0, 0xF1, 0xF2, 0x20, + 0xBE, 0x6B, 0x24, 0xA9, 0x07, 0x4E, 0x50, 0x5E, 0x5E, 0xCE, 0x9E, 0x3D, 0x7B, 0xD8, 0xB3, 0x67, + 0x0F, 0x3A, 0x9D, 0x0E, 0x1F, 0x1F, 0x1F, 0x42, 0x42, 0x42, 0x88, 0x88, 0x88, 0x20, 0x28, 0x28, + 0x08, 0x5F, 0x5F, 0x5F, 0x0C, 0x06, 0x03, 0x9A, 0xA6, 0x51, 0x5D, 0x5D, 0x4D, 0x59, 0x59, 0x19, + 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x50, 0x52, 0x52, 0xD2, 0x94, 0x09, 0x46, 0x43, 0x66, 0xF6, + 0xBE, 0xAA, 0x47, 0x3A, 0xE8, 0x55, 0x80, 0x2E, 0x5D, 0xBA, 0x90, 0x90, 0x90, 0xD0, 0x6A, 0x46, + 0x98, 0xCD, 0x66, 0x32, 0x32, 0x32, 0x58, 0xB8, 0x70, 0x21, 0x45, 0x85, 0x45, 0x0C, 0x4C, 0x88, + 0x25, 0xC8, 0xDF, 0xD7, 0xA9, 0x0D, 0xA1, 0xAA, 0x53, 0x99, 0xF9, 0xC8, 0x3D, 0x1C, 0x3C, 0x79, + 0x96, 0x6D, 0xE9, 0x47, 0xEA, 0xDB, 0x4D, 0x26, 0x13, 0x26, 0x93, 0x09, 0x1F, 0x4F, 0x0F, 0x66, + 0x3F, 0x76, 0x1F, 0x37, 0xF7, 0xEE, 0xEE, 0x9C, 0xDA, 0x6B, 0xD5, 0xB8, 0xEB, 0xB6, 0xFE, 0x3C, + 0x9D, 0x7C, 0x37, 0xF3, 0x3E, 0x5F, 0x47, 0x8D, 0x6D, 0xE1, 0xB6, 0x5A, 0xAD, 0x54, 0x56, 0x56, + 0xA2, 0x53, 0x55, 0x7E, 0x33, 0x6E, 0x38, 0x53, 0xC6, 0x0D, 0x6B, 0x76, 0x7C, 0x8A, 0x4E, 0x27, + 0x35, 0xC5, 0xCB, 0x6F, 0x61, 0xB5, 0x52, 0x5E, 0x5E, 0x4E, 0x79, 0x79, 0x39, 0xA7, 0x4E, 0x9D, + 0xA2, 0x15, 0xA8, 0x46, 0x46, 0x79, 0xAE, 0x04, 0xD6, 0x00, 0xE7, 0xF5, 0xC8, 0x48, 0x09, 0x40, + 0x9A, 0x8C, 0x5B, 0x2A, 0xAE, 0xEA, 0xEA, 0xEA, 0x38, 0x7F, 0xFE, 0x3C, 0x5B, 0xB7, 0x6E, 0x65, + 0xCD, 0x9A, 0x35, 0xEC, 0xDA, 0xB5, 0xAB, 0x5E, 0x2E, 0x46, 0x04, 0x07, 0xE0, 0xED, 0x61, 0x70, + 0x6E, 0x87, 0xAE, 0x09, 0x6E, 0x8A, 0x0A, 0xE5, 0xE3, 0x3F, 0x3D, 0xC9, 0x3F, 0x97, 0xAF, 0x67, + 0xDD, 0xCE, 0x74, 0x8A, 0x4A, 0x2B, 0x70, 0x73, 0xD3, 0xD3, 0x3B, 0xB6, 0x0B, 0xBF, 0x7B, 0x70, + 0x0C, 0xF7, 0x8F, 0xBA, 0x15, 0x55, 0x55, 0x9C, 0x36, 0xC1, 0xB8, 0xBB, 0xB9, 0xF1, 0xF2, 0xE3, + 0x0F, 0xD2, 0xA3, 0x4B, 0x38, 0x1F, 0x7D, 0xB7, 0x8D, 0x53, 0xE7, 0xF2, 0xD1, 0x34, 0x8D, 0xE8, + 0xB0, 0x20, 0x92, 0xEF, 0x1C, 0xCA, 0xB4, 0x89, 0xA3, 0xF1, 0x6F, 0xCE, 0x37, 0x63, 0x43, 0xD7, + 0x88, 0x10, 0x74, 0x3A, 0x15, 0xAB, 0x54, 0x28, 0x34, 0xA4, 0x93, 0xC9, 0x1B, 0x59, 0xC0, 0xC6, + 0x59, 0x33, 0x42, 0x1D, 0x32, 0x0E, 0xE1, 0x14, 0x32, 0x38, 0xE4, 0x47, 0x64, 0xD8, 0x54, 0x99, + 0xFD, 0x1F, 0xF4, 0x38, 0xD8, 0xE5, 0x2D, 0x16, 0x0B, 0x07, 0x0F, 0x1E, 0x24, 0x2A, 0x2A, 0x0A, + 0x3F, 0x3F, 0x3F, 0x0C, 0x06, 0x03, 0xAA, 0xCD, 0x17, 0xA1, 0x69, 0x1A, 0x75, 0x75, 0x75, 0x98, + 0x4C, 0x26, 0x4A, 0x4B, 0x4B, 0xC9, 0xCE, 0xCE, 0xE6, 0xC0, 0x81, 0x03, 0xEC, 0xDE, 0xBD, 0x9B, + 0x7D, 0xFB, 0xF6, 0x71, 0xEE, 0xDC, 0xB9, 0x2B, 0xEA, 0x94, 0x44, 0x86, 0x04, 0xE2, 0xEE, 0xD6, + 0x82, 0x68, 0x7D, 0x4D, 0xD0, 0x35, 0x32, 0x84, 0xB7, 0x9E, 0x99, 0xC2, 0xAC, 0xC9, 0xE3, 0x29, + 0xBC, 0x58, 0x8E, 0xC1, 0xDD, 0x8D, 0xE8, 0xB0, 0x20, 0x7C, 0x7D, 0xBC, 0x6D, 0x8E, 0x29, 0xE7, + 0xBB, 0x43, 0x08, 0x3C, 0x0D, 0x6E, 0x4C, 0xBD, 0x6F, 0x34, 0x93, 0x46, 0x0F, 0x21, 0xBF, 0xF8, + 0x22, 0x56, 0x4D, 0x10, 0x16, 0xE4, 0x4F, 0xA0, 0xBF, 0xAF, 0xA4, 0xA2, 0x53, 0x8B, 0xB3, 0x5C, + 0xE3, 0x3C, 0xDD, 0xDD, 0xB9, 0x24, 0xD5, 0xF2, 0x3A, 0xE0, 0x0F, 0xC8, 0x52, 0x4E, 0x7D, 0x80, + 0x18, 0x64, 0x5C, 0x5A, 0x28, 0x32, 0x11, 0x54, 0x8F, 0xD4, 0x9A, 0xAA, 0x6D, 0xC4, 0x2E, 0x45, + 0xC6, 0x6F, 0x1D, 0x47, 0x56, 0x27, 0x3A, 0x8B, 0x2C, 0x6C, 0x73, 0xC5, 0xCD, 0xF5, 0x38, 0x64, + 0x92, 0x6E, 0xDC, 0xB8, 0x91, 0x3D, 0x7B, 0xF6, 0x10, 0x1A, 0x1A, 0x4A, 0x68, 0x68, 0x28, 0x46, + 0xA3, 0x11, 0x2F, 0x2F, 0x2F, 0x54, 0x55, 0xA5, 0xB6, 0xB6, 0x96, 0xCA, 0xCA, 0x4A, 0x8A, 0x8B, + 0x8B, 0x29, 0x2C, 0x2C, 0xA4, 0xA4, 0xA4, 0x04, 0x93, 0xC9, 0x74, 0x4D, 0x6D, 0x23, 0x24, 0xD0, + 0x5F, 0x6A, 0x58, 0x2D, 0x31, 0x77, 0x68, 0x02, 0x9D, 0xA2, 0x10, 0x15, 0x16, 0x44, 0x54, 0x78, + 0x70, 0x3D, 0x61, 0x5B, 0x6D, 0xB6, 0x17, 0x80, 0xD0, 0xF0, 0xF3, 0xF1, 0xC2, 0xCF, 0xD7, 0xBB, + 0xA1, 0xBF, 0x96, 0x68, 0x49, 0x02, 0x42, 0x02, 0xFD, 0xF0, 0xF5, 0xF6, 0xB0, 0x33, 0xC4, 0x1D, + 0x39, 0x4B, 0x76, 0xD8, 0x7E, 0x20, 0x67, 0x89, 0x3B, 0x52, 0xFC, 0xEB, 0x6C, 0xC7, 0x16, 0x1B, + 0xF3, 0x9C, 0xAE, 0x6C, 0xA7, 0x07, 0x7E, 0x02, 0x46, 0x83, 0xD4, 0x0A, 0xCA, 0xCA, 0xCA, 0x28, + 0x2B, 0x2B, 0xE3, 0xE4, 0xC9, 0x93, 0x2D, 0x7D, 0xF4, 0x3A, 0xE0, 0x02, 0xD2, 0xCB, 0xE8, 0x09, + 0x10, 0xE4, 0xEF, 0xD3, 0x7A, 0xA3, 0x60, 0x4B, 0x89, 0xE6, 0xCA, 0xFE, 0x84, 0x20, 0xD0, 0xD7, + 0x9B, 0x40, 0x3F, 0x1F, 0xF2, 0x8A, 0xCB, 0xEC, 0xAD, 0x51, 0x97, 0xFF, 0x17, 0xD2, 0x6F, 0xDE, + 0x26, 0xE8, 0x91, 0x36, 0xF9, 0x67, 0x80, 0xE1, 0xC8, 0xCD, 0xA1, 0x0F, 0xCE, 0xC9, 0xC4, 0x3A, + 0xE4, 0xB4, 0xCB, 0x46, 0xCA, 0xC1, 0x6D, 0xC0, 0x79, 0x64, 0x15, 0xB7, 0xAE, 0x00, 0x7E, 0xDE, + 0xED, 0x9A, 0xED, 0xD5, 0x89, 0x10, 0x78, 0x7B, 0x7A, 0x60, 0xF4, 0xF3, 0x71, 0x6C, 0x0C, 0x72, + 0xC5, 0x9D, 0xF4, 0x48, 0xB9, 0xF6, 0x7B, 0x64, 0x40, 0x57, 0x37, 0xE4, 0xBE, 0xA4, 0x2B, 0xD2, + 0x14, 0x1F, 0x8C, 0x9C, 0x86, 0x3A, 0xA4, 0x65, 0xB0, 0x0C, 0x29, 0x0F, 0xCF, 0x03, 0x27, 0x69, + 0x90, 0x87, 0x17, 0x91, 0x6F, 0x48, 0x4F, 0x1C, 0xEA, 0x61, 0x79, 0x7A, 0x18, 0x3A, 0xAF, 0x88, + 0x60, 0x7B, 0x42, 0x80, 0x9B, 0x5E, 0x87, 0xBF, 0x4F, 0x23, 0x43, 0x6B, 0xDB, 0x4C, 0x19, 0x4D, + 0xC0, 0xBE, 0xE2, 0xD6, 0x21, 0x6B, 0x1E, 0xE6, 0x03, 0x76, 0x4F, 0x8C, 0x62, 0x3B, 0xEF, 0xB8, + 0xCD, 0xAE, 0xE3, 0xDA, 0x26, 0x5B, 0x9D, 0xFD, 0xFF, 0x55, 0x45, 0xC1, 0x5D, 0xAF, 0xBB, 0xB1, + 0x9C, 0x52, 0xD7, 0x22, 0x94, 0x5E, 0x87, 0x6F, 0xE3, 0x19, 0xEF, 0x47, 0xC3, 0x8B, 0xDA, 0x7E, + 0xF7, 0xB9, 0xC6, 0x39, 0xC1, 0x2F, 0xB4, 0xD6, 0x60, 0x6B, 0xA0, 0x2A, 0x0A, 0x9E, 0x86, 0x46, + 0xB1, 0x67, 0x9E, 0xB8, 0x80, 0x21, 0xED, 0x9D, 0x63, 0x58, 0x3F, 0x1F, 0x84, 0x10, 0xD2, 0x3B, + 0xF7, 0x4B, 0x10, 0x59, 0x00, 0x8A, 0x82, 0xA1, 0xB1, 0x0A, 0x6F, 0xD7, 0xA4, 0xDA, 0x15, 0xED, + 0xCD, 0x90, 0x1A, 0xA0, 0x16, 0x40, 0x13, 0x82, 0x6A, 0x73, 0xED, 0x2F, 0x46, 0x64, 0x01, 0x97, + 0x07, 0x78, 0xDC, 0x30, 0x0C, 0x31, 0xD9, 0x0F, 0x2A, 0xAA, 0x4C, 0x6D, 0xE8, 0xEA, 0x3A, 0x83, + 0x10, 0xD2, 0x2A, 0xDC, 0x00, 0x0D, 0x17, 0xBC, 0x6E, 0xED, 0xCD, 0x10, 0x13, 0xB2, 0xCE, 0x09, + 0x00, 0x45, 0xA5, 0xE5, 0xAE, 0x8F, 0x32, 0xEC, 0x20, 0x08, 0x21, 0x30, 0x35, 0x36, 0xE7, 0x9B, + 0x70, 0x41, 0x35, 0x39, 0x57, 0x30, 0xA4, 0xBE, 0x70, 0xC0, 0x85, 0xE2, 0x8B, 0x88, 0x1B, 0x21, + 0x30, 0xCE, 0x09, 0x58, 0x35, 0x8D, 0x4B, 0xD5, 0x8D, 0x66, 0xFC, 0x0D, 0xC1, 0x90, 0x1A, 0x1C, + 0x82, 0x88, 0xCF, 0xE6, 0x15, 0x61, 0x32, 0xB7, 0x79, 0xF3, 0xDA, 0xF9, 0x50, 0xA0, 0xA6, 0xB6, + 0x8E, 0x92, 0xF2, 0x4B, 0x8E, 0xAD, 0xC5, 0xDC, 0x00, 0x22, 0x0B, 0xE4, 0x66, 0x11, 0x80, 0x9C, + 0xFC, 0x62, 0xF9, 0x10, 0x6D, 0x89, 0xA9, 0xBA, 0x2E, 0xA0, 0x70, 0xC9, 0x64, 0x96, 0xAE, 0xDE, + 0x06, 0xB4, 0x7B, 0xF1, 0x32, 0x70, 0x5D, 0x69, 0x8D, 0x5A, 0x80, 0xFC, 0x92, 0x32, 0x4E, 0x9D, + 0xCB, 0x77, 0x2E, 0x28, 0xE1, 0x7A, 0x86, 0xA2, 0x50, 0x50, 0x5A, 0x4E, 0x51, 0x43, 0x34, 0x8C, + 0x40, 0x5A, 0x2B, 0xDA, 0x1D, 0xAE, 0x60, 0xC8, 0x49, 0x64, 0x26, 0x2A, 0x55, 0xA6, 0x2B, 0x03, + 0x0D, 0x6E, 0x48, 0x28, 0x0A, 0xA7, 0xCE, 0xE5, 0x53, 0x7E, 0xA9, 0xDE, 0xBD, 0x5C, 0x89, 0xF4, + 0x69, 0xB4, 0x3B, 0x5C, 0xC1, 0x90, 0x73, 0xC8, 0xCF, 0x4E, 0x00, 0xB0, 0x65, 0xDF, 0x61, 0xAA, + 0xAB, 0xCD, 0x9D, 0xBF, 0x41, 0x54, 0x14, 0x19, 0x92, 0xDA, 0x9A, 0x28, 0x4C, 0x21, 0xD8, 0x77, + 0xE4, 0x14, 0x96, 0xBA, 0xFA, 0x35, 0x3C, 0x1F, 0x69, 0xC3, 0x6B, 0x77, 0xB8, 0x82, 0x21, 0x26, + 0xE4, 0x57, 0x6E, 0x00, 0x48, 0x3F, 0x96, 0xC5, 0xE1, 0x53, 0x39, 0xAD, 0x23, 0x84, 0x1D, 0x8A, + 0xD2, 0x40, 0xD0, 0x96, 0xAE, 0x47, 0x0A, 0xA0, 0xD3, 0x51, 0x71, 0xA9, 0x9A, 0x9D, 0xE9, 0x47, + 0x39, 0x9E, 0xD5, 0xC2, 0x4F, 0x82, 0x28, 0x0A, 0xE5, 0x95, 0x97, 0xD8, 0x91, 0x71, 0xDC, 0xB1, + 0xF5, 0x20, 0x36, 0x29, 0xD0, 0xDE, 0x70, 0xD5, 0x67, 0x18, 0x36, 0xDB, 0x06, 0x1C, 0x52, 0x52, + 0x5E, 0xC9, 0xAA, 0x4D, 0xBB, 0x19, 0xDC, 0xA7, 0xF5, 0x51, 0x90, 0xCB, 0x37, 0xEC, 0x64, 0xF7, + 0xA1, 0x4C, 0x46, 0xDF, 0xD2, 0x87, 0x61, 0x03, 0x7B, 0x39, 0x9F, 0xE8, 0xA9, 0x28, 0x54, 0x9B, + 0x6B, 0xF8, 0xF1, 0xA7, 0x03, 0x2C, 0x59, 0xB3, 0x91, 0xED, 0xFB, 0x8F, 0xD2, 0x3B, 0x36, 0x9A, + 0xB5, 0xF3, 0x9E, 0x27, 0x2A, 0x2C, 0xC8, 0xB9, 0x3D, 0x92, 0xAA, 0xB0, 0xF7, 0xC8, 0x69, 0x0E, + 0x64, 0x66, 0xDB, 0x5B, 0x84, 0xED, 0xF9, 0x5C, 0x62, 0xE7, 0x73, 0x55, 0x8D, 0x8E, 0x12, 0x64, + 0xAC, 0x70, 0x1F, 0x80, 0x0B, 0xC5, 0xA5, 0x8C, 0x1D, 0xD2, 0x8F, 0x90, 0xA0, 0x80, 0x96, 0x6D, + 0x14, 0x6D, 0x8B, 0xE9, 0xF4, 0xD7, 0xDF, 0xE7, 0xDB, 0x94, 0x34, 0xD6, 0x6E, 0xDF, 0xC7, 0xB6, + 0xB4, 0x23, 0x18, 0xFD, 0x7C, 0xE8, 0xD9, 0x35, 0xB2, 0xE9, 0x98, 0x5C, 0xDB, 0xB5, 0x85, 0x17, + 0xCB, 0xF9, 0xDF, 0x7F, 0x7C, 0xC6, 0x6B, 0xEF, 0x7F, 0xC5, 0xB1, 0xEC, 0x5C, 0x2C, 0x75, 0x56, + 0xAA, 0xCC, 0x35, 0xDC, 0x3F, 0x62, 0x30, 0x51, 0xE1, 0xCE, 0x31, 0xA4, 0xCE, 0x6A, 0xE5, 0x8D, + 0x65, 0xFF, 0x62, 0xEF, 0xE1, 0xFA, 0x25, 0xE3, 0x3C, 0x32, 0x13, 0xB9, 0xB8, 0xD9, 0x8B, 0x5B, + 0x01, 0x57, 0xD5, 0xDF, 0xAB, 0x45, 0x3A, 0xAA, 0xAA, 0x01, 0xB2, 0x2F, 0x14, 0xB1, 0x74, 0xED, + 0x16, 0xB4, 0x56, 0x84, 0x61, 0x6A, 0x9A, 0x46, 0x8D, 0x45, 0x7A, 0x40, 0xCD, 0x35, 0xB5, 0xA4, + 0x1E, 0x38, 0xC1, 0xB4, 0x3F, 0x2D, 0xE6, 0x93, 0xEF, 0xB6, 0x35, 0xBD, 0x2E, 0xD9, 0x66, 0xC6, + 0x4B, 0x0B, 0x97, 0xB3, 0x74, 0xED, 0x16, 0xCC, 0x0E, 0xA1, 0xA2, 0x31, 0xE1, 0xC1, 0x44, 0x85, + 0x19, 0x9B, 0x8F, 0xC4, 0x07, 0xD0, 0xA9, 0xEC, 0x3B, 0x72, 0x8A, 0x75, 0x3B, 0xD2, 0x1D, 0x5B, + 0xBF, 0x47, 0xFA, 0xD2, 0x5D, 0x02, 0x57, 0x16, 0x44, 0xDC, 0x82, 0x8C, 0xAA, 0x00, 0xE0, 0xCB, + 0xEF, 0x77, 0xB0, 0xEB, 0xE0, 0x49, 0xB9, 0x0E, 0x38, 0x0B, 0x21, 0x08, 0x33, 0x06, 0x70, 0xD7, + 0x6D, 0xFD, 0xEB, 0x9B, 0xBC, 0x3D, 0x0D, 0x18, 0xDC, 0xDD, 0x78, 0xE5, 0xDD, 0x15, 0xEC, 0xFC, + 0xF9, 0xC4, 0xD5, 0xD7, 0x26, 0x45, 0x61, 0xD5, 0xC6, 0x9F, 0xF8, 0xF4, 0xDF, 0xDB, 0x19, 0x79, + 0x73, 0x62, 0xFD, 0xF5, 0xC1, 0x01, 0xBE, 0x3C, 0x3F, 0xE5, 0x5E, 0x19, 0x6B, 0xEC, 0x44, 0xF4, + 0xA3, 0xD9, 0x5C, 0xC3, 0xA2, 0xAF, 0x7E, 0xA0, 0xE8, 0x62, 0x85, 0xBD, 0xB5, 0x14, 0x17, 0x7F, + 0xD8, 0xC5, 0x95, 0x65, 0x85, 0x2C, 0x48, 0xD1, 0x75, 0x2F, 0xE0, 0x51, 0x65, 0xAA, 0xA1, 0xE8, + 0x62, 0x05, 0xF7, 0x0C, 0x1D, 0x88, 0x87, 0xC1, 0xF9, 0xA2, 0x39, 0x8A, 0xAA, 0x92, 0xD4, 0xB3, + 0x2B, 0x25, 0x65, 0x95, 0x14, 0x94, 0x94, 0x73, 0xEF, 0xF0, 0x9B, 0x99, 0xFD, 0xD8, 0x44, 0xBE, + 0x4D, 0x49, 0x27, 0x33, 0x27, 0x8F, 0x7B, 0x87, 0x0D, 0xC2, 0xE0, 0xD8, 0x9F, 0xA2, 0x90, 0x5B, + 0x58, 0xC2, 0xEF, 0xDF, 0x5A, 0x86, 0x5E, 0xA7, 0x63, 0xD9, 0x1F, 0x9F, 0xE0, 0x81, 0x91, 0xB7, + 0x12, 0xDF, 0x35, 0x82, 0x19, 0x0F, 0x8F, 0x63, 0xDC, 0xED, 0x03, 0x9D, 0xDB, 0x16, 0xE9, 0x54, + 0x56, 0x6F, 0xDA, 0xCD, 0x9C, 0x8F, 0xBF, 0x71, 0xD4, 0xAE, 0xBE, 0x44, 0x7E, 0x15, 0xC1, 0x65, + 0xF6, 0x20, 0x57, 0xD7, 0x79, 0x3A, 0x87, 0x0C, 0x33, 0x1A, 0x0C, 0x70, 0xE6, 0x42, 0x21, 0x46, + 0x3F, 0x6F, 0x7E, 0x95, 0x14, 0xD7, 0x22, 0x2D, 0xD8, 0xD7, 0xDB, 0x8B, 0x3B, 0x6F, 0xEB, 0xCF, + 0x83, 0xA3, 0x87, 0x30, 0x69, 0xF4, 0x10, 0x92, 0xE2, 0x63, 0x11, 0x42, 0xE3, 0x93, 0x75, 0xDB, + 0xE9, 0xD3, 0x3D, 0x9A, 0xC4, 0x9E, 0x31, 0x0D, 0x6F, 0xBC, 0x4E, 0xE5, 0x8B, 0x7F, 0xA7, 0xF0, + 0xD9, 0xFA, 0x14, 0x5E, 0xFD, 0xAF, 0x87, 0xB8, 0x7F, 0xD4, 0xAD, 0x04, 0xFA, 0x7B, 0x73, 0x4B, + 0xDF, 0x38, 0x62, 0x22, 0x42, 0x9C, 0x13, 0x09, 0xAA, 0xCA, 0x89, 0xEC, 0x5C, 0x9E, 0x7A, 0x6B, + 0x19, 0xB9, 0x85, 0xF5, 0xB1, 0xB7, 0x39, 0xC0, 0xB3, 0x34, 0x91, 0x5F, 0xDE, 0x5E, 0x70, 0x35, + 0x43, 0x34, 0xE4, 0x46, 0x71, 0x14, 0x10, 0xAA, 0x69, 0x82, 0x03, 0x27, 0xCF, 0xD2, 0x3F, 0x3E, + 0x96, 0xEE, 0x31, 0x11, 0x2D, 0x5A, 0xE0, 0xDD, 0x74, 0x3A, 0x8C, 0x81, 0x7E, 0x78, 0xB8, 0xCB, + 0x0C, 0xE0, 0xB8, 0xAE, 0x91, 0x6C, 0xDE, 0x7B, 0x88, 0xFC, 0x92, 0x8B, 0xDC, 0x3F, 0xE2, 0x96, + 0xFA, 0x05, 0xBE, 0xB6, 0xD6, 0xC2, 0x5F, 0x96, 0x7E, 0x8D, 0x97, 0x87, 0x81, 0x37, 0x9F, 0xFE, + 0x0D, 0x3E, 0x9E, 0x86, 0x86, 0x88, 0x13, 0x67, 0xEE, 0xA7, 0x28, 0x94, 0x55, 0x56, 0xF1, 0xEC, + 0xDF, 0x3F, 0x61, 0x6B, 0x5A, 0x7D, 0x04, 0xA5, 0x15, 0xF9, 0x71, 0x81, 0xD5, 0x2E, 0xA6, 0x57, + 0x87, 0xD4, 0x2E, 0x3F, 0x8D, 0xAC, 0x04, 0x51, 0x09, 0x50, 0x50, 0x2A, 0x35, 0x9F, 0xA3, 0xA7, + 0x72, 0x5A, 0xB6, 0x9E, 0x40, 0x43, 0x05, 0x07, 0x21, 0x08, 0x31, 0xFA, 0xF3, 0xDB, 0x09, 0x23, + 0x38, 0x73, 0xA1, 0x88, 0xCA, 0x2A, 0x53, 0xFD, 0x5E, 0xA5, 0xFC, 0x52, 0x35, 0x39, 0xF9, 0xC5, + 0xFC, 0xE7, 0xD8, 0xDB, 0x08, 0x0B, 0x0E, 0x68, 0xB1, 0x56, 0x67, 0xAE, 0xAD, 0xE5, 0xAF, 0x4B, + 0x57, 0xB3, 0x7A, 0xF3, 0x1E, 0xC7, 0x33, 0xDF, 0x21, 0x4B, 0x2E, 0xB9, 0x1C, 0x1D, 0x55, 0xE5, + 0x78, 0x35, 0xF0, 0x1E, 0x36, 0xEB, 0xE8, 0xCF, 0x27, 0xB2, 0x99, 0x31, 0xF7, 0x23, 0x72, 0x72, + 0x0B, 0x5B, 0xBF, 0x61, 0x14, 0x82, 0x31, 0x43, 0xFA, 0xD1, 0x2D, 0x2A, 0x94, 0x3A, 0x87, 0x7C, + 0x91, 0x3A, 0xAB, 0x95, 0x40, 0x3F, 0x1F, 0xC6, 0xDE, 0x9A, 0xD4, 0x32, 0x5B, 0xAC, 0xA2, 0x60, + 0xAE, 0xB5, 0x30, 0xE7, 0xA3, 0xB5, 0x2C, 0xFC, 0x6A, 0x83, 0x74, 0x3F, 0x4B, 0x1C, 0x01, 0x5E, + 0xC1, 0x21, 0xDC, 0xD3, 0x95, 0xE8, 0xA8, 0x5A, 0x81, 0x1A, 0x90, 0x81, 0x0C, 0x13, 0xEA, 0x05, + 0x90, 0x95, 0x5B, 0xC8, 0xC9, 0xB3, 0x17, 0xB8, 0xBD, 0x7F, 0x82, 0x73, 0xE5, 0x36, 0x2E, 0x87, + 0x00, 0x7F, 0x1F, 0x4F, 0x06, 0x27, 0xF6, 0x20, 0xD4, 0xE8, 0x57, 0x2F, 0xB2, 0xF4, 0x3A, 0x1D, + 0x91, 0x21, 0x46, 0x6E, 0xE9, 0xDD, 0x1D, 0x37, 0x9D, 0x93, 0x8F, 0xA7, 0xAA, 0x54, 0x56, 0x9B, + 0xF9, 0xDB, 0xD2, 0xD5, 0xCC, 0xFD, 0xFC, 0xBB, 0xFA, 0xC0, 0x6C, 0x64, 0xE0, 0xDF, 0x13, 0xC8, + 0x60, 0xC2, 0x0E, 0x41, 0x47, 0x16, 0x6F, 0xAC, 0x46, 0x7E, 0x65, 0x73, 0x10, 0x32, 0x16, 0x96, + 0xCC, 0x73, 0xF9, 0x1C, 0x3A, 0x95, 0xC3, 0xA0, 0x84, 0x6E, 0x84, 0xB6, 0x54, 0xBC, 0x20, 0x23, + 0x41, 0x02, 0xFC, 0x7D, 0x1A, 0x6D, 0x10, 0xDD, 0xF4, 0x3A, 0xE2, 0x6E, 0x8A, 0x72, 0x9E, 0x19, + 0x3A, 0x95, 0xF3, 0xF9, 0xC5, 0xBC, 0xF0, 0xCF, 0xCF, 0x79, 0x77, 0xF5, 0x8F, 0xD4, 0x5A, 0xEA, + 0xA3, 0x3E, 0x8B, 0x90, 0x45, 0x62, 0xBE, 0xE9, 0x40, 0x1A, 0x75, 0x78, 0x35, 0xCD, 0x8B, 0x48, + 0xA6, 0x0C, 0xC4, 0x96, 0x42, 0x77, 0x26, 0xB7, 0x90, 0x9D, 0x3F, 0x1F, 0x27, 0x36, 0x3C, 0x84, + 0xD8, 0xE8, 0xF0, 0x6B, 0xEF, 0xBE, 0xAF, 0x86, 0xAB, 0xF1, 0xD0, 0x49, 0x93, 0x88, 0x26, 0x20, + 0x25, 0xED, 0x08, 0x4F, 0xCE, 0x59, 0xCA, 0xB7, 0xDB, 0xD3, 0xB0, 0x36, 0x6C, 0x16, 0x0B, 0x90, + 0xCC, 0x58, 0xD1, 0xC1, 0xF4, 0xE9, 0x94, 0xF2, 0xA6, 0x85, 0xC8, 0x4F, 0x6B, 0xF7, 0xC5, 0x16, + 0x72, 0x5A, 0x50, 0x5A, 0xCE, 0x86, 0x9F, 0x7E, 0xA6, 0xA6, 0xA6, 0x96, 0x5E, 0x37, 0x45, 0xC9, + 0x04, 0x1A, 0x57, 0xC1, 0x66, 0xA4, 0xCC, 0x2D, 0x28, 0xE1, 0xEF, 0x9F, 0x7F, 0xC7, 0xEC, 0x05, + 0x5F, 0x34, 0xCA, 0xD2, 0x45, 0x2A, 0x21, 0x4F, 0x22, 0xF3, 0x35, 0x3A, 0x3C, 0x20, 0xA0, 0xB3, + 0xEA, 0xCD, 0x16, 0x21, 0x2D, 0xC2, 0x5D, 0x90, 0x5F, 0x8D, 0x56, 0x4D, 0xE6, 0x5A, 0x76, 0x64, + 0x1C, 0x27, 0xF5, 0xE7, 0xE3, 0xF8, 0x79, 0x79, 0x10, 0x13, 0x1E, 0x8C, 0xA1, 0xB9, 0x64, 0xD1, + 0x96, 0x40, 0x95, 0x96, 0xE2, 0xC2, 0xD2, 0x32, 0xBE, 0xF8, 0xF7, 0x0E, 0x9E, 0x7D, 0xE7, 0x13, + 0x56, 0x6D, 0xFC, 0xC9, 0x1E, 0xCD, 0x0E, 0x92, 0xF8, 0xDB, 0x91, 0xC5, 0x13, 0x5A, 0x57, 0xFE, + 0xA7, 0x1D, 0xD0, 0xD9, 0x5E, 0x8A, 0x40, 0xA4, 0x68, 0xF8, 0x3D, 0x0E, 0xDF, 0x3E, 0xF7, 0x34, + 0xB8, 0x33, 0x6C, 0x40, 0x2F, 0xA6, 0x8C, 0x1B, 0xCE, 0xE8, 0xC1, 0x7D, 0x09, 0x0F, 0x09, 0x40, + 0x51, 0x75, 0x36, 0x95, 0xD7, 0xC9, 0x1C, 0x11, 0x45, 0xB1, 0x79, 0x2A, 0x15, 0x6A, 0x6B, 0x6A, + 0x38, 0x95, 0x93, 0xCF, 0xBA, 0x9D, 0xE9, 0x7C, 0xB5, 0xF1, 0x27, 0x0E, 0x9C, 0x3C, 0x7B, 0x79, + 0x48, 0x4F, 0x39, 0xF0, 0x21, 0xF2, 0x23, 0x98, 0x2E, 0x71, 0xCD, 0x3A, 0x8B, 0xCE, 0x66, 0x08, + 0x48, 0x17, 0xC0, 0x9D, 0xC0, 0x8B, 0xC8, 0x62, 0xC4, 0xF5, 0xB3, 0xD6, 0x4D, 0xAF, 0x23, 0xBE, + 0x6B, 0x24, 0x23, 0x6F, 0xEE, 0xC3, 0xA8, 0x5B, 0x12, 0xE9, 0xD3, 0x3D, 0x86, 0x88, 0xE0, 0x40, + 0xBC, 0x3C, 0xDC, 0x1B, 0xAA, 0xCB, 0x35, 0x82, 0x00, 0x4D, 0x50, 0x6B, 0xB1, 0x50, 0x56, 0x51, + 0xC5, 0x99, 0x0B, 0x85, 0xEC, 0x3B, 0x7A, 0x9A, 0x2D, 0xFB, 0x0E, 0xB3, 0xFB, 0x50, 0x26, 0xF9, + 0x25, 0x65, 0x97, 0xE7, 0xB3, 0xD4, 0x21, 0x3F, 0xA5, 0x3A, 0x17, 0xF9, 0x01, 0xCC, 0x4E, 0x0F, + 0x9D, 0xBD, 0x1E, 0x18, 0x62, 0x47, 0x28, 0xB2, 0xB4, 0xC7, 0x34, 0xA4, 0x7A, 0xDC, 0x68, 0x6C, + 0xEE, 0x6E, 0x7A, 0x42, 0x8D, 0xFE, 0x74, 0x8B, 0x0C, 0x25, 0x36, 0x2A, 0x8C, 0x2E, 0xA1, 0x46, + 0x82, 0xFC, 0x7D, 0xF0, 0xF2, 0x34, 0xA0, 0x2A, 0x2A, 0xE6, 0x5A, 0x0B, 0x15, 0x97, 0xAA, 0xB9, + 0x50, 0x7C, 0x91, 0x9C, 0xFC, 0x62, 0xCE, 0xE4, 0x16, 0x72, 0xBE, 0xB0, 0x84, 0x8A, 0xAA, 0xAB, + 0x26, 0x15, 0xD5, 0x21, 0x93, 0x2C, 0x97, 0x02, 0x5F, 0x21, 0x8D, 0x86, 0xFF, 0x8F, 0xAB, 0x40, + 0x41, 0xA6, 0x44, 0xBC, 0x88, 0xDC, 0xB7, 0xD4, 0xD0, 0x82, 0xEF, 0xA2, 0x3B, 0xF1, 0x2B, 0x03, + 0x7E, 0x40, 0x32, 0x3D, 0xB4, 0xB3, 0x1F, 0xB6, 0x29, 0x02, 0x5C, 0xAF, 0x08, 0x45, 0xD6, 0x06, + 0xBE, 0x0B, 0xF8, 0x15, 0x72, 0xEF, 0xE2, 0x6C, 0x32, 0x91, 0x1D, 0x16, 0xA4, 0x23, 0xE9, 0x38, + 0x32, 0xA1, 0x68, 0x13, 0x72, 0x66, 0x54, 0x75, 0xF6, 0xC3, 0x35, 0x85, 0xEB, 0x99, 0x21, 0x76, + 0xE8, 0x90, 0x16, 0xE3, 0x3E, 0x48, 0xAB, 0x71, 0x5F, 0xA0, 0x07, 0x92, 0x61, 0x01, 0x34, 0xE4, + 0xF5, 0xD5, 0x22, 0x09, 0x5D, 0x8C, 0xF4, 0xEA, 0x1D, 0x45, 0xA6, 0x1C, 0x67, 0x20, 0x23, 0x44, + 0x2A, 0x5B, 0x76, 0xDB, 0xCE, 0xC1, 0xFF, 0x01, 0xCE, 0x34, 0xF5, 0xEC, 0x2D, 0xA9, 0x9C, 0xA8, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, 0x31, + 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0xED, 0x4F, 0xCC, + 0x0D, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x6D, 0x6F, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, + 0x31, 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0x9C, 0x12, + 0x74, 0xB1, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, + 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, + 0x42, 0x60, 0x82}; \ No newline at end of file diff --git a/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino b/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino new file mode 100755 index 000000000..b2a67e77d --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino @@ -0,0 +1,252 @@ + + +/** + * This example will send the Email in plain text version + * with rfc822 message attachment which the rfc822 message + * also contains its attachement. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +/* This is for attachment data */ +#include "image.h" + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + Serial.println("Connect to NTP server and set the device time\r\nPlease wait...\r\n"); + float timeZone = 3;//GMT+3 + float daylightOffset = 0; + + /* Set the device time */ + MailClient.Time.setClock(timeZone, daylightOffset); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending Email with rfc822 attachment"; + message.addRecipient("Someone", "####@#####_dot_com"); + + message.text.content = "This is simple plain text message with rfc822 attachment"; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + SMTP_Message rfc822; + rfc822.messageID = "1234@local.machine.example"; + rfc822.from.name = "rob"; + rfc822.from.email = "rob@example.com"; + rfc822.sender.name = "steve"; + rfc822.sender.email = "steve@example.com"; + String dt = MailClient.Time.getDateTimeString(); + rfc822.date = dt.c_str(); + rfc822.subject = "Test rfc822 message"; + rfc822.comment = "This is comment"; + rfc822.addRecipient("joe", "joe@example.com"); + rfc822.response.reply_to = "rob@example.com"; + rfc822.text.charSet = "utf-8"; + rfc822.text.content = "This is rfc822 text message"; + rfc822.text.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + rfc822.html.charSet = "utf-8"; + rfc822.html.content = "This is rfc822 html message"; + rfc822.html.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* The attachment data item */ + SMTP_Attachment att; + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size, + * and transfer encoding + */ + att.descr.filename = "firebase_logo.png"; + att.descr.mime = "image/png"; + att.blob.data = firebase_png; + att.blob.size = sizeof(firebase_png); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add the attachment to the rfc822 message */ + rfc822.addAttachment(att); + + /* Prepare other attachment data */ + uint8_t *a = new uint8_t[512]; + int j = 0; + + for (int i = 0; i < 512; i++) + { + a[i] = j; + j++; + if (j > 255) + j = 0; + } + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + message.resetAttachItem(att); //Clear the attach item data to reuse + att.descr.filename = "test.dat"; + att.descr.mime = "application/octet-stream"; + att.blob.data = a; + att.blob.size = 512; + + /* Add this attachment to the message */ + message.addAttachment(att); + + /* Add rfc822 message in the message */ + message.addRMessage(rfc822); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/image.h b/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/image.h new file mode 100755 index 000000000..5ddd6829b --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_RFC822_Attachment/image.h @@ -0,0 +1,1851 @@ +#include + +static const uint8_t firebase_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, + 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, + 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, + 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, + 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, + 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, + 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, + 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, + 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, + 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, + 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, + 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, + 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, + 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, + 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, + 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, + 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, + 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, + 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, + 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, + 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, + 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, + 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, + 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, + 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, + 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, + 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, + 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, + 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, + 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, + 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, + 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, + 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, + 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, + 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, + 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, + 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, + 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, + 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, + 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, + 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, + 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, + 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, + 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, + 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, + 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, + 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, + 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, + 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, + 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, + 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, + 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, + 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, + 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, + 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, + 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, + 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, + 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, + 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, + 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, + 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, + 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, + 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, + 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, + 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, + 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, + 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, + 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, + 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, + 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, + 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, + 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, + 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, + 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, + 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, + 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, + 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, + 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, + 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, + 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, + 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, + 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, + 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, + 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, + 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, + 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, + 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, + 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, + 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, + 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, + 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, + 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, + 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, + 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, + 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, + 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, + 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, + 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, + 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, + 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, + 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, + 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, + 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, + 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, + 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, + 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, + 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, + 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, + 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, + 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, + 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, + 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, + 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, + 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, + 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, + 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, + 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, + 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, + 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, + 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, + 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, + 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, + 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, + 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, + 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, + 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, + 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, + 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, + 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, + 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, + 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, + 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, + 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, + 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, + 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, + 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, + 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, + 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, + 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, + 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, + 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, + 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, + 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, + 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, + 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, + 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, + 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, + 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, + 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, + 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, + 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, + 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, + 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, + 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, + 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, + 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, + 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, + 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, + 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, + 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, + 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, + 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, + 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, + 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, + 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, + 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, + 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, + 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, + 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, + 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, + 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, + 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, + 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, + 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, + 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, + 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, + 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, + 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, + 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, + 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, + 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, + 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, + 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, + 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, + 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, + 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, + 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, + 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, + 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, + 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, + 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, + 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, + 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, + 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, + 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, + 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, + 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, + 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, + 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, + 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, + 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, + 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, + 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, + 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, + 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, + 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, + 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, + 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, + 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, + 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, + 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, + 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, + 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, + 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, + 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, + 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, + 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, + 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, + 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, + 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, + 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, + 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, + 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, + 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, + 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, + 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, + 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, + 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, + 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, + 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, + 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, + 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, + 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, + 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, + 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, + 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, + 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, + 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, + 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, + 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, + 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, + 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, + 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, + 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, + 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, + 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, + 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, + 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, + 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, + 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, + 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, + 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, + 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, + 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, + 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, + 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, + 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, + 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, + 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, + 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, + 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, + 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, + 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, + 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, + 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, + 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, + 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, + 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, + 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, + 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, + 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, + 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, + 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, + 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, + 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, + 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, + 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, + 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, + 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, + 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, + 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, + 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, + 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, + 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, + 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, + 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, + 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, + 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, + 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, + 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, + 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, + 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, + 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, + 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, + 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, + 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, + 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, + 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, + 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, + 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, + 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, + 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, + 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, + 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, + 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, + 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, + 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, + 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, + 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, + 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, + 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, + 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, + 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, + 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, + 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, + 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, + 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, + 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, + 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, + 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, + 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, + 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, + 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, + 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, + 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, + 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, + 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, + 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, + 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, + 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, + 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, + 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, + 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, + 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, + 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, + 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, + 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, + 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, + 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, + 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, + 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, + 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, + 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, + 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, + 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, + 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, + 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, + 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, + 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, + 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, + 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, + 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, + 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, + 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, + 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, + 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, + 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, + 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, + 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, + 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, + 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, + 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, + 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, + 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, + 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, + 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, + 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, + 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, + 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, + 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, + 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, + 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, + 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, + 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, + 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, + 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, + 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, + 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, + 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, + 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, + 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, + 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, + 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, + 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, + 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, + 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, + 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, + 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, + 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, + 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, + 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, + 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, + 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, + 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, + 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, + 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, + 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, + 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, + 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, + 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, + 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, + 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, + 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, + 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, + 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, + 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, + 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, + 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, + 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, + 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, + 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, + 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, + 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, + 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, + 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, + 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, + 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, + 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, + 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, + 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, + 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, + 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, + 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, + 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, + 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, + 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, + 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, + 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, + 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, + 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, + 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, + 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, + 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, + 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, + 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, + 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, + 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, + 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, + 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, + 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, + 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, + 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, + 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, + 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, + 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, + 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, + 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, + 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, + 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, + 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, + 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, + 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, + 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, + 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, + 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, + 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, + 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, + 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, + 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, + 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, + 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, + 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, + 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, + 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, + 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, + 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, + 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, + 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, + 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, + 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, + 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, + 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, + 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, + 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, + 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, + 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, + 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, + 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, + 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, + 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, + 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, + 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, + 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, + 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, + 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, + 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, + 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, + 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, + 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, + 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, + 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, + 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, + 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, + 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, + 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, + 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, + 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, + 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, + 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, + 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, + 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, + 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, + 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, + 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, + 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, + 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, + 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, + 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, + 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, + 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, + 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, + 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, + 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, + 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, + 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, + 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, + 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, + 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, + 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, + 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, + 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, + 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, + 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, + 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, + 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, + 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, + 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, + 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, + 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, + 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, + 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, + 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, + 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, + 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, + 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, + 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, + 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, + 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, + 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, + 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, + 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, + 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, + 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, + 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, + 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, + 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, + 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, + 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, + 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, + 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, + 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, + 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, + 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, + 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, + 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, + 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, + 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, + 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, + 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, + 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, + 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, + 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, + 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, + 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, + 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, + 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, + 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, + 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, + 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, + 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, + 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, + 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, + 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, + 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, + 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, + 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, + 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, + 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, + 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, + 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, + 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, + 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, + 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, + 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, + 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, + 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, + 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, + 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, + 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, + 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, + 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, + 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, + 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, + 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, + 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, + 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, + 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, + 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, + 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, + 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, + 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, + 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, + 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, + 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, + 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, + 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, + 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, + 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, + 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, + 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, + 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, + 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, + 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, + 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, + 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, + 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, + 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, + 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, + 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, + 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, + 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, + 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, + 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, + 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, + 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, + 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, + 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, + 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, + 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, + 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, + 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, + 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, + 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, + 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, + 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, + 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, + 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, + 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, + 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, + 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, + 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, + 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, + 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, + 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, + 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, + 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, + 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, + 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, + 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, + 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, + 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, + 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, + 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, + 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, + 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, + 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, + 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, + 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, + 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, + 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, + 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, + 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, + 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, + 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, + 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, + 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, + 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, + 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, + 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, + 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, + 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, + 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, + 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, + 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, + 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, + 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, + 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, + 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, + 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, + 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, + 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, + 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, + 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, + 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, + 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, + 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, + 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, + 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, + 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, + 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, + 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, + 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, + 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, + 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, + 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, + 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, + 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, + 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, + 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, + 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, + 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, + 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, + 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, + 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, + 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, + 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, + 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, + 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, + 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, + 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, + 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, + 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, + 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, + 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, + 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, + 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, + 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, + 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, + 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, + 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, + 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, + 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, + 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, + 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, + 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, + 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, + 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, + 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, + 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, + 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, + 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, + 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, + 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, + 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, + 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, + 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, + 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, + 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, + 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, + 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, + 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, + 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, + 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, + 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, + 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, + 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, + 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, + 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, + 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, + 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, + 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, + 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, + 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, + 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, + 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, + 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, + 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, + 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, + 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, + 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, + 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, + 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, + 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, + 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, + 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, + 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, + 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, + 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, + 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, + 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, + 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, + 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, + 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, + 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, + 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, + 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, + 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, + 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, + 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, + 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, + 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, + 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, + 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, + 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, + 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, + 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, + 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, + 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, + 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, + 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, + 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, + 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, + 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, + 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, + 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, + 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, + 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, + 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, + 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, + 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, + 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, + 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, + 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, + 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, + 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, + 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, + 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, + 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, + 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, + 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, + 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, + 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, + 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, + 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, + 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, + 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, + 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, + 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, + 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, + 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, + 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, + 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, + 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, + 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, + 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, + 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, + 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, + 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, + 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, + 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, + 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, + 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, + 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, + 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, + 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, + 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, + 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, + 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, + 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, + 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, + 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, + 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, + 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, + 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, + 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, + 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, + 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, + 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, + 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, + 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, + 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, + 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, + 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, + 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, + 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, + 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, + 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, + 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, + 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, + 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, + 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, + 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, + 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, + 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, + 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, + 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, + 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, + 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, + 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, + 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, + 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, + 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, + 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, + 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, + 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, + 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, + 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, + 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, + 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, + 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, + 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, + 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, + 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, + 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, + 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, + 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, + 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, + 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, + 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, + 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, + 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, + 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, + 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, + 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, + 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, + 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, + 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, + 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, + 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, + 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, + 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, + 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, + 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, + 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, + 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, + 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, + 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, + 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, + 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, + 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, + 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, + 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, + 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, + 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, + 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, + 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, + 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, + 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, + 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, + 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, + 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, + 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, + 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, + 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, + 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, + 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, + 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, + 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, + 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, + 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, + 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, + 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, + 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, + 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, + 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, + 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, + 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, + 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, + 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, + 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, + 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, + 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, + 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, + 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, + 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, + 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, + 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, + 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, + 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, + 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, + 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, + 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, + 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, + 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, + 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, + 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, + 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, + 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, + 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, + 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, + 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, + 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, + 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, + 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, + 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, + 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, + 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, + 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, + 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, + 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, + 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, + 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, + 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, + 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, + 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, + 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, + 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, + 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, + 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, + 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, + 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, + 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, + 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, + 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, + 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, + 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, + 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, + 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, + 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, + 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, + 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, + 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, + 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, + 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, + 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, + 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, + 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, + 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, + 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, + 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, + 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, + 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, + 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, + 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, + 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, + 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, + 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, + 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, + 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, + 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, + 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, + 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, + 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, + 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, + 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, + 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, + 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, + 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, + 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, + 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, + 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, + 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, + 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, + 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, + 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, + 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, + 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, + 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, + 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, + 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, + 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, + 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, + 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, + 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, + 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, + 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, + 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, + 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, + 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, + 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, + 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, + 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, + 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, + 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, + 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, + 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, + 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, + 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, + 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, + 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, + 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, + 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, + 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, + 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, + 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, + 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, + 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, + 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, + 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, + 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, + 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, + 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, + 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, + 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, + 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, + 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, + 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, + 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, + 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, + 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, + 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, + 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, + 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, + 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, + 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, + 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, + 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, + 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, + 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, + 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, + 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, + 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, + 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, + 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, + 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, + 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, + 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, + 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, + 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, + 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, + 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, + 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, + 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, + 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, + 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, + 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, + 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, + 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, + 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, + 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, + 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, + 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, + 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, + 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, + 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, + 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, + 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, + 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, + 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, + 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, + 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, + 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, + 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, + 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, + 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, + 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, + 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, + 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, + 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, + 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, + 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, + 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, + 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, + 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, + 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, + 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, + 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, + 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, + 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, + 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, + 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, + 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, + 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, + 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, + 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, + 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, + 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, + 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, + 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, + 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; + +static const uint8_t tree_gif[] PROGMEM = { + + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, + 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, + 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, + 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, + 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, + 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, + 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, + 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, + 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, + 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, + 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, + 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, + 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, + 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, + 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, + 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, + 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, + 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, + 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, + 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, + 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, + 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, + 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, + 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, + 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, + 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, + 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, + 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, + 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, + 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, + 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, + 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, + 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, + 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, + 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, + 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, + 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, + 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, + 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, + 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, + 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, + 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, + 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, + 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, + 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, + 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, + 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, + 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, + 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, + 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, + 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, + 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, + 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, + 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, + 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, + 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, + 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, + 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, + 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, + 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, + 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, + 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, + 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, + 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, + 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, + 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, + 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, + 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, + 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, + 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, + 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, + 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, + 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, + 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, + 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, + 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, + 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, + 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, + 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, + 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, + 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, + 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, + 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, + 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, + 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, + 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, + 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, + 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, + 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, + 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, + 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, + 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, + 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, + 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, + 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, + 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, + 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, + 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, + 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, + 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, + 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, + 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, + 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, + 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, + 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, + 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, + 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, + 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, + 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, + 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, + 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, + 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, + 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, + 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, + 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, + 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, + 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, + 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, + 0x00, 0x3B + +}; + +static const uint8_t bird_gif[] PROGMEM = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, + 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, + 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, + 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, + 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, + 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, + 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, + 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, + 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, + 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, + 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, + 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, + 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, + 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, + 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, + 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, + 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, + 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, + 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, + 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, + 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, + 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, + 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, + 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, + 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, + 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, + 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, + 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, + 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, + 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, + 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, + 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, + 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, + 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, + 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, + 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, + 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, + 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, + 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, + 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, + 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, + 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, + 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, + 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, + 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, + 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, + 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, + 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, + 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, + 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, + 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, + 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, + 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, + 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, + 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, + 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, + 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, + 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, + 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, + 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, + 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, + 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, + 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, + 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, + 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, + 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, + 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, + 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, + 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, + 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, + 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, + 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, + 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, + 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, + 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, + 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, + 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, + 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, + 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, + 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, + 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, + 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, + 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, + 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, + 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, + 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, + 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, + 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, + 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, + 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, + 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, + 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, + 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, + 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, + 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, + 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, + 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, + 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, + 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, + 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, + 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, + 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, + 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, + 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, + 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, + 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, + 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, + 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, + 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, + 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, + 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, + 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, + 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, + 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, + 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, + 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, + 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, + 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, + 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, + 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, + 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, + 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, + 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, + 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, + 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, + 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, + 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, + 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, + 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, + 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, + 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, + 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, + 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, + 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, + 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, + 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, + 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, + 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, + 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, + 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, + 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, + 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, + 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, + 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, + 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, + 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, + 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, + 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, + 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, + 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, + 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, + 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, + 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, + 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, + 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, + 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, + 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, + 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, + 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, + 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, + 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, + 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, + 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, + 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, + 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, + 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, + 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, + 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, + 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, + 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, + 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, + 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, + 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, + 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, + 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, + 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, + 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, + 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, + 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, + 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, + 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, + 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, + 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, + 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, + 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, + 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, + 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, + 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, + 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, + 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, + 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, + 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, + 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, + 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, + 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, + 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, + 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, + 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, + 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, + 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, + 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, + 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, + 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, + 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, + 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, + 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, + 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, + 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, + 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, + 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, + 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, + 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, + 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, + 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, + 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, + 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, + 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, + 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, + 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, + 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, + 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, + 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, + 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x3B}; diff --git a/lib/lib_div/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino b/lib/lib_div/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino new file mode 100755 index 000000000..df52cccab --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino @@ -0,0 +1,245 @@ + + +/** + * This example will send multiple messages which + * the session was keep open during sending. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "First Email with session reusage"; + message.addRecipient("Admin1", "####@#####_dot_com"); + message.addRecipient("Admin2", "####@#####_dot_com"); + message.addCc("####@#####_dot_com"); + message.addBcc("####@#####_dot_com"); + + message.html.content = "

This is the first message.

"; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = "utf-8"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + /** The option to add soft line break to to the message for + * the long text message > 78 characters (rfc 3676) + * Some Servers may not compliant with the standard. + */ + message.text.flowed = true; + + message.text.content = "This is the first message"; + message.text.charSet = "us-ascii"; + + message.html.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + Serial.println(); + Serial.println("Sending first Email..."); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /** Start sending the first Email and keep open the session + * The third parameter is for close the session. + */ + if (!MailClient.sendMail(&smtp, &message, false)) + Serial.println("Error sending Email, " + smtp.errorReason()); + + + /* To clear all message data */ + //message.clear(); + + /** Clear primary recipients, Cc recipients, Bcc recipients, custom headers + * attachments and inline images + */ + message.clearRecipients(); + message.clearCc(); + message.clearBcc(); + //message.clearAttachments(); + //message.clearInlineimages(); + + message.subject = "Second Email with session reusage"; + + message.addRecipient("Admin3", "####@#####_dot_com"); + message.addRecipient("Admin4", "####@#####_dot_com"); + message.addCc("####@#####_dot_com"); + message.addBcc("####@#####_dot_com"); + + message.html.content = "

This is the second message.

"; + message.html.charSet = "us-ascii"; + + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + message.text.content = "This is the second message"; + message.text.charSet = "UTF-8"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + Serial.println(); + Serial.println("Sending second Email..."); + + /* Start sending the second mail and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Text/Send_Text.ino b/lib/lib_div/lib_mail/examples/Send_Text/Send_Text.ino new file mode 100755 index 000000000..f824e498d --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Text/Send_Text.ino @@ -0,0 +1,185 @@ + + +/** + * This example will send the Email in plain text version. + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The sign in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending plain text Email"; + message.addRecipient("Someone", "####@#####_dot_com"); + + message.text.content = "This is simple plain text message"; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino b/lib/lib_div/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino new file mode 100755 index 000000000..384bf7592 --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino @@ -0,0 +1,197 @@ + + +/** + * This example will send the Email in plain text version + * with the quoted text and long line text. + * + * + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com + * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * and use the app password as password with your yahoo mail account to login. + * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en +*/ +#define SMTP_HOST "################" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 +*/ +#define SMTP_PORT 25 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* The SMTP Session object used for Email sending */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = SMTP_HOST; + session.server.port = SMTP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + session.login.user_domain = "mydomain.net"; + + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = "ESP Mail"; + message.sender.email = AUTHOR_EMAIL; + message.subject = "Test sending flowed plain text Email"; + message.addRecipient("Someone", "####@#####_dot_com"); + + /** The option to add soft line break to to the message for + * the long text message > 78 characters (rfc 3676) + * Some Servers may not compliant with the standard. + */ + message.text.flowed = true; + + /** if the option message.text.flowed is true, + * the following plain text message will be wrapped. + */ + message.text.content = "The text below is the long quoted text which breaks into several lines.\r\n\r\n>> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n\r\nThis is the normal short text.\r\n\r\nAnother long text, abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz."; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = "us-ascii"; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader("Message-ID: "); + + /* Connect to server with the session config */ + if (!smtp.connect(&session)) + return; + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + Serial.printf("Message sent success: %d\n", status.completedCount()); + Serial.printf("Message sent failled: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + localtime_r(&result.timesstamp, &dt); + + Serial.printf("Message No: %d\n", i + 1); + Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); + Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); + Serial.printf("Recipient: %s\n", result.recipients); + Serial.printf("Subject: %s\n", result.subject); + } + Serial.println("----------------\n"); + } +} diff --git a/lib/lib_div/lib_mail/examples/Set_Flags/Set_Flags.ino b/lib/lib_div/lib_mail/examples/Set_Flags/Set_Flags.ino new file mode 100755 index 000000000..e256bd4bc --- /dev/null +++ b/lib/lib_div/lib_mail/examples/Set_Flags/Set_Flags.ino @@ -0,0 +1,363 @@ +/** + * This example will set the argument to the flags and read the message. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2020 mobizt + * +*/ + +/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * +*/ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. +*/ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif +#include + +#define WIFI_SSID "################" +#define WIFI_PASSWORD "################" + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "################" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 +*/ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "################" +#define AUTHOR_PASSWORD "################" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(IMAPSession &imap); + +/* Print all messages from the message list */ +void printMessages(IMAPSession &imap); + +/* Print all rfc822 messages included in the message */ +void printRFC822Messages(IMAP_MSG_Item &msg); + +/* Print all attachments info from the message */ +void printAttacements(IMAP_MSG_Item &msg); + +/* The IMAP Session object used for Email reading */ +IMAPSession imap; + + +void setup() +{ + + Serial.begin(115200); + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * none debug or 0 + * basic debug or 1 + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the session config data */ + ESP_Mail_Session session; + + /* Set the session config */ + session.server.host_name = IMAP_HOST; + session.server.port = IMAP_PORT; + session.login.email = AUTHOR_EMAIL; + session.login.password = AUTHOR_PASSWORD; + + + /* Setup the configuration for searching or fetching operation and its result */ + IMAP_Config config; + + /* Message UID to fetch or read e.g. 100 */ + config.fetch.uid = "100"; + + /* Set seen flag */ + //config.fetch.set_seen = true; + + /* Search criteria */ + config.search.criteria = ""; + + /* Also search the unseen message */ + config.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + config.storage.saved_path = "/email_data"; + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + config.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download heades, text and html messaeges, + * attachments and inline images respectively. + */ + config.download.header = true; + config.download.text = true; + config.download.html = true; + config.download.attachment = true; + config.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option config.limit.msg_size. + * The whole message can be download through config.download.text + * or config.download.html which not depends on these enable options. + */ + config.enable.html = true; + config.enable.text = true; + + /* Set to enable the sort the result by message UID in the ascending order */ + config.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + config.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + config.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + config.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + config.limit.attachment_size = 1024 * 1024 * 5; + + + + /* Connect to server with the session and config */ + if (!imap.connect(&session, &config)) + return; + + /* {Optional] */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder("INBOX")) + return; + + /* {Optional] */ + printSelectedMailboxInfo(imap); + + /** Set \Seen and \Answered to flags for message with UID 100 + * The seesion will keep open. + */ + if (MailClient.setFlag(&imap, 100, "\\Seen \\Answered", false)) + Serial.println("Setting FLAG success"); + else + Serial.println("Error, setting FLAG"); + + /* Add \Seen and \Answered to flags for message with UID 100 */ + //MailClient.addFlag(imap, 100, "\\Seen \\Answered", false); + + /* Remove \Seen and \Answered from flags for message with UID 100 */ + //MailClient.removeFlag(imap, 100, "\\Seen \\Answered", false); + + /* Read or search the Email and close the session */ + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ + +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + printMessages(imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + Serial.printf("Free Heap: %d", ESP.getFreeHeap()); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + /* Show the mailbox info */ + Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); +} + +void printRFC822Messages(IMAP_MSG_Item &msg) +{ + Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + for (size_t j = 0; j < msg.rfc822.size(); j++) + { + IMAP_MSG_Item rfc822 = msg.rfc822[j]; + Serial.printf("%d. \n", j + 1); + Serial.printf("Messsage ID: %s\n", rfc822.messageID); + Serial.printf("From: %s\n", rfc822.from); + Serial.printf("Sender: %s\n", rfc822.sender); + Serial.printf("To: %s\n", rfc822.to); + Serial.printf("CC: %s\n", rfc822.cc); + Serial.printf("Subject: %s\n", rfc822.subject); + Serial.printf("Date: %s\n", rfc822.date); + Serial.printf("Reply-To: %s\n", rfc822.reply_to); + Serial.printf("Return-Path: %s\n", rfc822.return_path); + Serial.printf("Comment: %s\n", rfc822.comment); + Serial.printf("Keyword: %s\n", rfc822.keyword); + Serial.printf("Text Message: %s\n", rfc822.text.content); + Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", rfc822.html.content); + Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); + + if (rfc822.attachments.size() > 0) + printAttacements(rfc822); + } +} + +void printAttacements(IMAP_MSG_Item &msg) +{ + Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); + for (size_t j = 0; j < msg.attachments.size(); j++) + { + IMAP_Attach_Item att = msg.attachments[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); + } + Serial.println(); +} + +void printMessages(IMAPSession &imap) +{ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + for (size_t i = 0; i < msgList.msgItems.size(); i++) + { + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgList.msgItems[i]; + + Serial.println("################################"); + Serial.printf("Messsage Number: %s\n", msg.msgNo); + Serial.printf("Messsage UID: %s\n", msg.UID); + Serial.printf("Messsage ID: %s\n", msg.ID); + Serial.printf("Accept Language: %s\n", msg.acceptLang); + Serial.printf("Content Language: %s\n", msg.contentLang); + Serial.printf("From: %s\n", msg.from); + Serial.printf("From Charset: %s\n", msg.fromCharset); + Serial.printf("To: %s\n", msg.to); + Serial.printf("To Charset: %s\n", msg.toCharset); + Serial.printf("CC: %s\n", msg.cc); + Serial.printf("CC Charset: %s\n", msg.ccCharset); + Serial.printf("Date: %s\n", msg.date); + Serial.printf("Subject: %s\n", msg.subject); + Serial.printf("Subject Charset: %s\n", msg.subjectCharset); + + /* If the result contains the message info (Fetch mode) */ + if (!imap.headerOnly()) + { + Serial.printf("Text Message: %s\n", msg.text.content); + Serial.printf("Text Message Charset: %s\n", msg.text.charSet); + Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + Serial.printf("HTML Message: %s\n", msg.html.content); + Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); + Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.attachments.size() > 0) + printAttacements(msg); + + if (msg.rfc822.size() > 0) + printRFC822Messages(msg); + } + + Serial.println(); + } +} diff --git a/lib/lib_div/lib_mail/keywords.txt b/lib/lib_div/lib_mail/keywords.txt new file mode 100755 index 000000000..61a64fdb7 --- /dev/null +++ b/lib/lib_div/lib_mail/keywords.txt @@ -0,0 +1,126 @@ +###################################### +# Syntax Coloring Map ESP Mail Client +###################################### + +####################################### +# Classes and Structured Type (KEYWORD1) +####################################### + +MailClient KEYWORD1 +IMAPSession KEYWORD1 +SMTPSession KEYWORD1 +SMTP_Message KEYWORD1 +IMAP_Config KEYWORD1 +FoldersCollection KEYWORD1 +imapStatusCallback KEYWORD1 +IMAP_MSG_List KEYWORD1 +SelectedFolderInfo KEYWORD1 +ESP_Mail_Session KEYWORD1 +smtpStatusCallback KEYWORD1 +SMTP_Attachment KEYWORD1 +SMTP_Result KEYWORD1 +IMAP_MSG_Item KEYWORD1 +Content_Transfer_Encoding KEYWORD1 +MessageList KEYWORD1 + +############################################### +# Methods and Functions (KEYWORD2) +############################################### + +sendMail KEYWORD2 +readMail KEYWORD2 +setFlag KEYWORD2 +addFlag KEYWORD2 +removeFlag KEYWORD2 +sdBegin KEYWORD2 +connect KEYWORD2 +closeSession KEYWORD2 +debug KEYWORD2 +getFolders KEYWORD2 +selectFolder KEYWORD2 +openFolder KEYWORD2 +closeFolder KEYWORD2 +callback KEYWORD2 +headerOnly KEYWORD2 +data KEYWORD2 +selectedFolder KEYWORD2 +errorReason KEYWORD2 +empty KEYWORD2 +resetAttachItem KEYWORD2 +clear KEYWORD2 +clearInlineimages KEYWORD2 +clearAttachments KEYWORD2 +clearRFC822Messages KEYWORD2 +clearRecipients KEYWORD2 +clearCc KEYWORD2 +clearBcc KEYWORD2 +clearHeader KEYWORD2 +addAttachment KEYWORD2 +addParallelAttachment KEYWORD2 +addInlineImage KEYWORD2 +addMessage KEYWORD2 +addRecipient KEYWORD2 +addCc KEYWORD2 +addBcc KEYWORD2 +addHeader KEYWORD2 +info KEYWORD2 +successs KEYWORD2 +completedCount KEYWORD2 +failedCount KEYWORD2 +getItem KEYWORD2 +size KEYWORD2 +flagCount KEYWORD2 +msgCount KEYWORD2 +nextUID KEYWORD2 +searchCount KEYWORD2 +availableMessages KEYWORD2 +flag KEYWORD2 +setClock KEYWORD2 +getUnixTime KEYWORD2 +getTimestamp KEYWORD2 +getYear KEYWORD2 +getMonth KEYWORD2 +getDay KEYWORD2 +getDayOfWeek KEYWORD2 +getDayOfWeekString KEYWORD2 +getHour KEYWORD2 +getMin KEYWORD2 +getSecond KEYWORD2 +getNumberOfDayThisYear KEYWORD2 +getTotalDays KEYWORD2 +dayofWeek KEYWORD2 +getCurrentSecond KEYWORD2 +getCurrentTimestamp KEYWORD2 +getTimeFromSec KEYWORD2 +getDateTimeString KEYWORD2 +copyMessages KEYWORD2 +deleteMessages KEYWORD2 +createFolder KEYWORD2 +deleteFolder KEYWORD2 + + +####################################### +# Struct (LITERAL1) +####################################### + +esp_mail_email_info_t LITERAL1 +esp_mail_plain_body_t LITERAL1 +esp_mail_html_body_t LITERAL1 +esp_mail_smtp_msg_response_t LITERAL1 +esp_mail_smtp_enable_option_t LITERAL1 +esp_mail_email_info_t LITERAL1 +esp_mail_folder_info_item_t LITERAL1 +esp_mail_sesson_sever_config_t LITERAL1 +esp_mail_sesson_login_config_t LITERAL1 +esp_mail_sesson_secure_config_t LITERAL1 +esp_mail_sesson_cert_config_t LITERAL1 +esp_mail_imap_fetch_config_t LITERAL1 +esp_mail_imap_search_config_t LITERAL1 +esp_mail_imap_limit_config_t LITERAL1 +esp_mail_imap_enable_config_t LITERAL1 +esp_mail_imap_download_config_t LITERAL1 +esp_mail_imap_storage_config_t LITERAL1 + +esp_mail_file_storage_type_none LITERAL1 +esp_mail_file_storage_type_flash LITERAL1 +esp_mail_file_storage_type_sd LITERAL1 \ No newline at end of file diff --git a/lib/lib_div/lib_mail/library.json b/lib/lib_div/lib_mail/library.json new file mode 100755 index 000000000..e98d8e1ea --- /dev/null +++ b/lib/lib_div/lib_mail/library.json @@ -0,0 +1,16 @@ +{ + "name": "ESP Mail Client", + "version": "1.0.13", + "keywords": "communication, email, imap, smtp, esp32, esp8266, arduino", + "description": "Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices. This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails.", + "repository": { + "type": "git", + "url": "https://github.com/mobizt/ESP-Mail-Client.git" + }, + "authors": [{ + "name": "Mobizt", + "email": "suwatchai@outlook.com" + }], + "frameworks": "arduino", + "platforms": "espressif32, espressif8266" +} diff --git a/lib/lib_div/lib_mail/library.properties b/lib/lib_div/lib_mail/library.properties new file mode 100755 index 000000000..2512fe923 --- /dev/null +++ b/lib/lib_div/lib_mail/library.properties @@ -0,0 +1,9 @@ +name=ESP Mail Client +version=1.0.13 +author=Mobizt +maintainer=Mobizt +sentence=Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices. +paragraph=This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails. +category=Communication +url=https://github.com/mobizt/ESP-Mail-Client +architectures=esp32,esp8266 diff --git a/lib/lib_div/lib_mail/media/images/esp-mail-client.png b/lib/lib_div/lib_mail/media/images/esp-mail-client.png new file mode 100755 index 0000000000000000000000000000000000000000..5088656b01265b1f5575fdece9dc7c8dca684361 GIT binary patch literal 13006 zcmc(GXE>a}yT0C5*;N)1tlpLoEkVe#dhe^ZXi=hf!YWxrNrH$LStYvFmgqz$N}`wO zC2DjD;_UDL{eP}=KAjJ9z1RD`^UO0d&&)jcbI(k?o{lON#XSlz6Pp_cvYkKf8kz;oMGB9JiM9|z>OU-?w#CA&CC}MkJj%$3IC@P zdk`MpLkD#@%qYnEAeVHOp?9jEMju2^PfU#ehB`nr3o(wcH+@Ykd%@Hqb^&)FkEl^D z(B}XN1x!Tt#kJX@Ga>wHq(#yBocyS)qno4AEvxr)OLNwTf1ZrVUmk95W-NWU%kkYB z`Ji&=s0JkZM0BI}gaQenX9GcDK#gd!30OL9oDmO~cwkKM9MZo!Bb4Y*nQ- z@FA|T{H!SDDflh`{Yz*vk@*zChmP38DHF$)Xdvnt9Ie*YqScm3Xd%hd+(xL+UQ^-o zA0en345PfuET7Q%JPDO|pjba6vrEijh!awb>T^k?XM2;OCm|!n8xrisPIxP!WA zDZ11GPM<6G_7~=?8F*qH8eeqy$5&+)SbKR*hQMk34fqtDaDDwn>`g2=!8yH!As3z2 z&gzod+0t(Vq`C3{&oef~IoT7S+gH1pj*3Em@Zz{F4hay+O% z>YQCU@Ah<&l+y`sEE6&wU!BKSxtITgsZoKT9CSIH#1n$Fm1aT7&$=EXms(jR>R!@_ z@X7?l$sDi7kHTMJR>*&GAbAQ&7Ue8TR{k+0mcdxBiE%nJvh=Qi@GdB9g5e8AglA%FC04pqG8 zo7nMEE+kJ3ddIso8ESAX)ks947+W9HbatQJa;JJ~7k>9kz24j59GObNiBN?2n$SM! zB8Xi-e=wCuOu(s6$IoLlP@s_@Zo`m)?jpp`A2TBZy3vf*J(KQE)Z{ zBy?j&na~foQ1z3+x{SCX*Y{4N&{jX(FdrOsQG)?-ciJo-1?zHHA=U+LJrV_QqPul%mpT4q<$#uMsRMkQp}p%*RFws>iVXYFsuGoV zL;qF53Tx-p`-nz@1*C#KO91S?k z;26PyJqLnp;h5S!fr<5=Ya|z$~-Bio;X!){drLny(iA zuKHkW`{;s;p4)w2VXmpARVFImumuE=F(iN4FQ$*ufogeOLJV3Y3?G1B4+^2EGwt)* ze=`OUkA2@T&Ak$vXiJ=oCnUBs9xt?8~ zuWmCbFUK6HO~(hz_alzv)pK2D>mDx`c<#bcNn|GROy|bYdf^7CAKInOa^&nha`-c}^gxm) zHgROiH@<4+YZ{Cd6)~le8x$Gp+vDetwv!G>w6U9@TjN3+>!qf-0H!7h(!9Hn))s}L z!=|<=V{|=PK;MU(JLmCi`z1OASHIwQtfj~DK?)pfoCxAI*>*at8r7+{SS^w4{RRB9 zBn``dj5WMHmF*8J+Q-|)ER?O{o0)m*ezvFXKtCoF%GRZy$05vWKwW}(?6s1yenezb zF_DViW|73LSe}M&=DWSLga8KbV$qoZ(H0~hX%kW>BTRMDjbOr$-R(*qTboQLBn0L} zJbp;e*)U66-U>4&TG&)FTP=%hoxA0Gm8~6H^3<~1XVVg09=7H%pdM;5&D5tzB;=s? zdqBwF>+?AzxP$~yY60j(gD#r|eb|6_MMHy#O zl%Xuz#-~EG2=;+Vx#-)bq{<5M-XRKHUA3$?CKj>9q7Au>ELA@t2B9-i!=DLB7=-+y;9zsKFhm)WD{Kf? zfO0g>ln1Wt?s*GI^OvBSj{xBn$5qhGOfh$k%V{zYlypq7FimgM48S^=gH2pm{PqZeJSNIQ{NMvUB&@YsFo=U&_3eh|NdUt!G@!gMalZ6$!J~q=<5Mzpi;BjhgUyN{=p=8!IaZ*>q zq^6FH(i(m?42->UuSHq>3i?3W|54Y3kF9>Yi^9Z&g}FYgl%=cLgCk|&6y;RwvWZ_@ zBFrE!>9GFX5ZQBNtHsXk<9oTH&k&w}U2g$(s z%{V21k^{+m9~~Dp`nlYv*d?uSi%HhAqcaRvo$k!Y93zsW?dLG?NR<|%Vo+CzC=7t^ zw1+uzYotD@Zc0x+;03lZ>NTw2P<{D^HRbCTG%~?lY`wv?$An=zX6}$JS+ZwaGmRe> zkZOw4&>0JNzM2dtom~c<*J7si5a}8eCfPM}oBHQ2_UV&P5>j;5PKp#KA)yoYipyTQ z*J2iCC96lIScb0`_T6Ph8kp3)@qf`?{;B9%x|R@N*}A!T0XmghKYAZic9LxI>*|yM zed<(7$F36a-V2#L1a0Zj8CW>kNyj2sdstV=56ND5N6VzEDuT+-o~GVf9xmGTQXH4D z%$L4HM&$-!?(>nkv+!1E@DRD-x4cB?O7Rp?slIvZ_0Yngx=xMCp+=?joi2H9Gahn{1h;mE;CZX1W9O6APo6_lU-?iB9ebDRxje zGi1E>&vU|bt^3OI8K<51ng_ z#vdBw(^s4D>=aWzj$fVV24C^Lr*SnEn?rFWu#3aRDA2Pb%ki*sQQL5iX=W0RqBJ31 z1g5Gg>$8si_qW0iELyP^*)9tW&-^sAdiSf2ESBjtSR2taCqKf;6G9 zYh;ub>Z0tgk7A^LSHyTe=o|x|6O*3XSI3ZU(HD#`;cXh<3WWG2)jr%SVfupV3xZHzKN;wzmS>L z9z9p$;TJ5w%cW}{&f>#`9<0{>8kl}BZ2726w2mQN7EGJVtmkh?>O}0nkpJm#m(-$n zqa(*xl6uGLSDsmNiO@e?{)mn0dZc99i{}a{k}DtG{@tn+FsTFI>u@Dtop+(qJr-{074xA%OlPznc;4EUOm{`23spv}dogM2? zUf*U^Z+hC&N0q@yon~1j82*{|$!)C6AQ>eIX{8&3b&ta-ZBGXT0jz>h+obGF=Cfyyo1;mKniJU?+!f4j;g0f4zlUe!mZC`fUyIYn12nP ze3_S$IyhZQ=!S=G5N}Bi>X|5sIb3JajK9d#I`bIFkirm7xK^U#puEkl_!HOU)FN%O zRyV|nGoQjb{h{~B+PTQsiDDSvfzB06iQTT_;YUzIKDL_zK=v$&dfX3_-$~mf1gjx= z-;VPetb!wn7qOefLKP_1Z{NNjRS3`gq;Asngct##+0{W3U*anz$Yz|$`#bec{)z@v zL#&ek4^$)@#66MD6Ph=j0^fREkjyfHRN~frkP_R z6yER9gb{fk@xuFApyA_Ufkix)lE-U=o6i#lp1U*8W-wNW%2lPGb_quQFkALG&1Vd@$pp^1kv1 zNd&#eLop)V0B#F2we^yRMc@i)Gl>8(#7knfJ*~+U7Au3!@sLE>VYS1|7sr>K>u-_f zHh6Ahw!xo%eA0iBVgHwC&E#8u$va@vx`|y7Yj-ap6Tz8l4QXP>!9)9}14voK>oJLX z1Deevsrofn>LM^SO~vyvN`^fDs2TpXrQ{v`RgSEycI$mklMO&iu%VEn?W-7KO0i;X zu1RjCk)8BI_+F1+hbTGWYDi>CwP7%~Qa_>WZpOfir7hW-5kMhL+UG+uTJ3ZW8adfPVt~~bPH3v zqMzyIZ_!@NGy74DqKFadZW&2Msr7W}q9z;UFY@%)`@p$1pXL;oG-Z-w7C$)mx(p+S zuG4CG>QZ${y7h7U1IPL!wgA$`N|AlUJMir07Cqa2{T3ksk!&Tuq*cj2tTWeKHosDy zHA3S7VrO5Lh2&?KvE17``Q8aR3ZX0No3XzJoN@3$H1hjnsggmq^kTWl){!bmMHAF) zbml_L(f4b)2lkJ-q;$30(+d*uILn_3kz6!2Pm#}Yrz;Nd)AyEq{C&ThO zdIqR8uEKX~{emZ-FW?<>dbt}t3V-J1n`dc7Hx`Rv2Hod-X7ENPcXFpwKSnemrAcsF z{C5C&*2Aai&A%78SnWgpmprLVju6~nH@pn$p&oQ34c1ly)GN<$vT@sbKj|j@?)V*2 zT_Sp zc#fCCe`49Tu@BoWnrq{yCqTy_o=EK!z+n!oE{s0QG>&n}W%H5V#)vJHnVF>np&N4k zS9-Zj1n+@WcE(pHp@(?xj_v(x4QU@8ROkt?wYGtcuibuP2Hmuqu7ct#tGOS?FRUIM z#An5zO4&xEPuJztvJH5I%4w0rdg1iOYT8`^=jcsi)-T4pWyI?DkMV9#4@EDckgjFc0mH&UR-N z$!5zAm@soQ*;|yAp%^;*z#VQ%5*aTUr;k3+$5XD|nB7Fgtp&0z_ltH4mJ_6dDwby7 zl3hDs3b((;sPwm9CF)vJQ+yAOdQPY&+?1~BzfpAiO7`csoBRIx68@*0gl`l*Zl@W% z+Wc=&FWJE?1+@pyu#gvyGa|`64p{>UA$Hp_WU~%ibreP_m=&L=_1zDlF=kd0aka9@ zkTdHm@{H`CZlK$&%F3+shN6b86I*coqePd>t>kNu7e`4?%Sfs&=b)Tk9q0tpe&BGQ ztz(0jrB{;K=%aGl1Vu-Cgl(rKdYDQuRR;EOIh36KayZ(G&*GT>LHjO)LIL}5T%NtY zs-rHVkiUSAXu8(!_<)#WDWi;_=Bdh)#V7Y2W{p2qo5>~wt)D^z+~T})zZ&^GN+B)G zo=p%DPp5@WcBruKV_vVQ)H)9myp3iA-G2W(FQ}0_Vy`LSDyorUqa%@=GS3zGv?-k5 z4T)g7FkXx!#m@o!eA=Vu<3eepBzM?jvcs_l@~5$5Aau{D{R$8GWp%8|!v$-61~vy1(A%!_y+;4jyi%N-<4-Bf1Ld@O|-eBWV&)PPX3$jg)X8!>gel zj61roCc*OOEEPcsY;UO_eri1v5yfxvDLii__p8Kj#&%}QSj^S=kMC$7WP@9si@1g3hl|{NT5xoyKX8bO z;C%a=J>wx4+9uo{OIOd%QVpAIjFk}(NT;iq4l_jinQ%`Fi$qymjiXm62!u_zb{Rg= zMy4ttNE4n@UTbm8dvi{FWaMtlT~zi!P3t}!6d}bSYe<3xS&d+b)NdcKAlIH?_YvcX zKOzgvoP`3s(!`&<4N8T)LUe{VhE5S*n$X-h}+ zsp++o+pdA5HtX2*q__ZO+76*{;aene*%o-zc9?>B8wQDp{r*s~=IP?`r(QUzZk^P- zri{wcdTfZ&V`fmrTabT7MTzI?kDE4(7B87Q(tJu=VwemIZV5}4{1G_v+I_m}UxQ+- zz>?8?xA}wa*J}DpigbGv-1=K^6iw~;wKm^;LhSQSxzoz6^>HVEH!JA#Ez|TN3h;9$ z(_Z1QkE*}kQ~G$_lcwz&qMMBD$m%7Zo&-TnN{ZhQ^E1S3I<8AsR|&Zox^90Gtcxw~ z3cwL7C)|n;8v_Ql=%*7y7V{Q+gf(EP1XX=0!N#jOazToGP;AlT z<*Vat$&H$gZvk{8(~(p^V|F$&cHwFa?h`2zbWIVn4@8BsycgtJiP`te&ii(gGyq^6 z_l6E+%@)r@zS+yk3FIL`Bz0uN26MLDg>>h;6CB8XMIkr?Dx&m0)oYq`PDQJ+cJ=f6 zyDOVU$P4VcuPy^<`zh$$8EZ61_iux4!_Xdc-=DbLn;=ZA1C>v)fLOl~NVX<2XsJH= z7XlX23kK}rDC=t-eLjxh^3eKk!f$b8pZJrxBFRBd_U~_YW)q%?GZJh0K>{f(W?!bS zQY&Rk>rc}!kFjw8{u<{F0l-pS`&V}LKKHjzQ2`Fg*%4WXE=#d2k_6S>!yJGNQM)$Y z7>ZD!(;$a1^gWF|&rWF=ohsiyv!1zbzAvjHV_whv9b{xtDkAm_G=O4rL5XZ^YnHP1W%;#F)RCE7J>=pMcG%MDz}+>216nR>Vj&@#R6iF^6PGhilhvn>_d6nnGA_A= z+8@Ud3ju1n`yd^z9tS^A;gl&BHa&t+e>=OVpYFR{4sy_05XoaRyFl@Hz|d-zQDzKF z)a)xD<@EX7w2^_MrPgf0m)hd1&NV*{8UKPK{dGiU>G1qecYq_W{ZzKF5UAW1^KotB zN97fL8TT^|lM9~@GtHp3p8nEGc*Wa%Pa>fV3ztklI=vE=!jYP~!|!Lujqt_?-1DxS z6H$i3<${34VMjD|8Zxiho4n?Q#b zY|c`<$Lv81h(-Dt!~`MYYbA@OnagT+qXU&gOIQE^+u+{bx+!%vb9>m?7M!IRN_(x# z5h9gu-jks{*SyQ|#Z-+18@;1Hov4C8>}ada0cfjEI~mNukytOi3x3+6W#T(Kso|d+ z4EO|oA5~YJKZoU`xsgrh6akqvvCkt^JU>F;3y}EpAo72_f{SyG(%!Z{o=9ApRHv|% zd9^biyxT*#k2(cgn4XjIazTs`wP_4$zk3Ka3LKFIz{y-&R@vwsnCF@PAHKxi3jz0& z$f-LrEUBQa3Bm#7v-(z=Rd`BwFyU?U? zlcgGn<-U13EkO$^AK+V-XbN`_7nFv2+B_~Djz6CDwCgT-IesYUF#~DN$J@+$M^cA% zu32c5OqArkUkeoSz8=!HGDlpBaLODz_|v`_%%=0#b_tPnvAfVdh#xIawdJsW6;Jcw zfUeu%Ju;S6w>ia-5A-ET)%jU=|7I+1vR|cn_1znoX(@k4TeoAOS;+Rx?O{2$uJ?7B zs#SB$((J>8mR0T;Uh+87ruU3k6I~68MY#%*$c4be3ilq3#r9o;_h9g&K;DT;z?3@C zvz|xkvw;|F6&&k&=$gL+EG|ASQV{O7z&kWQOm83)CWK8eg zuVb$~<+qppe-H=(?&@{FGvWpW5#8?3Zu71VHct-liVE>y?#wG7OBh@2fycO+svpl^ zbqarMH`06uQ+#NrpUb9q$V;v_Nara@?R^~s!HFt<$h@`pWE17+G5RMv9Kmn0vUTw% zaf9JA$b{c|Ijc6LH{nvf1_((s$-k zVb7alyr_PV1X}_H=|?o*S-)5jn=keh_q zlKGTMsF5hynk%@RkaqM*H|H<>Q`DiZm`bejOh8!K=I*XCjGvzqfe%S0)&xk-wp|VP z!JT{6WTwQtKJl1Xx9s+8u7EStSj|`V!(d)qNJl)dazWE~=|qY}C%dWp$+2q}9j58w!!bTvLyzHvv$fwn{xC2!m0(K#R(`ey z#w0+H>2%8{#{FB=-U0jGgl~|N4WYj0NQe<7sN#O+aT1S-dQ&8S!mGcAk1(I2Ax1bD z`x@rDW>brZooiC;hwWdmc7YjUo=cu*L5x^I6_mjn;%GVrUUN2Yw?JqGwzAaYA)=0- zOj(IYh^s1B)$iARe_Euc8|^_2^~BgT?=Fr87dDH5PKt3Nn7#gLp<#fjc>M4z(7_mI zY?2^%mm%;TuuFq^gdnfmGoL*hQ{E`t5;Tz0KW$_1905E-*%ncrR8-jq0-vHp-!&>5 z`v3OLk$zwD1;T_orGY!9lZsDs+fDq%Ndv^&?Jd2pV$)I9mKAh^z{!I!Q(V%y2B`nF?C6L3>pG@MadN1|1o zlKuE}>qpL?(pi{?#wmU++yy;++qu{^Lp3w{ZRuru6n3wnK}LwT*$uy@X*+{u%FO5K ztaoLc!qGCd$M~p-{GLQX=-bVs5@(84+T@Uzln3F@?#vx1XoVt40%rw2vq-n{x1LNd z_{}v)Pqs6vj6s>sBP0ORSo#FKL-L*zue@xchFkdX9<~!Hrew*h#4H`Gm zB2kjQQcz#Mn>*dA^hxqs@$dS$NGw#s!9l&QIvGdi%c?qlP1t(3dGpwnuGc_O_2loZ z8OnX4tKrKb7PdRW(v#gfu=~%HJV=|Yzlo-m?bR$YRwrdPZE)3TV4SZ(!L~6sppcP` z+2C41>FAzOC|pj3PsBwF6&g!iLwx_@dcD(`x@m*pU_1YG{hBxGy)u2TLDmkJ1{v>+ zthLw#w$fteup#{D?$5|__yY6cOOWM42%jlnFJ0Qye;X3nXzjZxi0@C7!XbJUC`|(g zLRqi0h|G^4yNrA0h5S=Khq76NLDn>G485#1Wyw_@omtJX3rvR%EG@ae4)2DuE(D)x zRw0Y(_(kNe{m$KuMJ;^46)~38k&I8g+i$wMzjPUyS$N>|$4pCxS4TkSrpyJ>UdnQR z^ifU6i)Q@8yP8{S6KASc83Q7r7d~`Q32rL~iXn?AhQhj9^e85{#_B;hn+^g-uF15T zWdEj!Du&H7{q#3W%=ezX`TYrJzVi{5>VV9iPSj<94cGm*bqrdb$Ranb;>T)g`@Zka zCfjEMKjfZF`Z6V!y4Vws|5`D5oYE?THq90tT>g4F{RX~^Kc8`ZZ&lRe?p&)%33h`F@uTJy>rM2pz>QBF z4PR*_%%Lo`U0MCBRrP>(M+tq%F_q#5cHpiBiKTvG!xbn%+bYZL_Zrr8>F%<**e-&U z;Bx226Bu;a(%xjsTQ2KW{nt0UJMf%yN0ulY{F*38N~iUwI4XbnfZO!F*JW;?(O3jo zgda%7aVZdEdd5e7FZ0Kck8~L8;hf+PmP4Wrn!P<_4@ExydVA(gWvbl8xwKhATt~zE zYdF3Kz>WV_9-uxMd^TZ8togo)bU*vuXP4k`>>#BfeUA9Yt6Nx&+~wsSsEac;nEmXr z=dSA;5h(rTYWm?@DZ~pFtip=*2eO=ZQJ3<1d!a7TFuBz6p%l>#L4?=!3iU5CadctS z%){69_Kt^_{uX+kKYe??peL=mulM8$GuX7k?|W(cFM1!{?wU13?QP4W5w+e?dcO`C zEOnp{6y+H0%PeS^16IG>J`Q@Y`0`A*`l=+9fC9IC3HY`oN(C+bW4R{#5#alg2hR07 z>v^0DM`q^vJ&_*295Ei2p7`%sjy{1g`4f|Wj;wPBUZlnNZ<4U$xe0+jc1AtQ(y0du zi8DvxIH`u0D6&JER{BX#C57+3Pe7tHZXl&X6*-y0iwMS#{xXg6QRZTPuSCYB$HCq~ z@j&awyFU5uvr^m&bHf+r-SL$s%#4Wl_QU~r^TQwWXs4Y|%Y|sZy2T^^Z#jwASFh8x zwW*2K=Q64fjV#W)pUivCSR55!wY|~-USG<>pSb0BIK@+t?d6e8c$@!_B0XrC5oBe} zwc&%>4NZ62E6E17OXuAo6{^X4z)%Uxk<=?zSSAXL3>F^&_ymHTGEsa3MOu!W}ZZO;N>l zOx{t6By_=@JgdH%=oK(qb)Ss)^RIgm1V_Xb1^joq19_MO%f`{^2NHTx6g&tiAX)XC zQfh_^EPwnB&P>6ivO>Woyp*p`mmggw4{YyA1O<#PDv4CAHE@!X$6K~ ztf)euFxHW9k0c}6R29B0Svq6In**kU3N+eQJXG2tYv+BuyH+PAp7`3CL!q^sAai1x zwVAnBP~WAC0DHa0V@}qyoo<;$ayZ9+Ntq(f7G*Y7sA^8e>9dT{0g2by+cD6E{z|(3 zomEmw5z7e08}8DrPd(I2Pu|47UF50|U*gcX83HWyj{5q;CcL(G=3bdqlhqdm*EAZRSP5Ck~M&>(RaShLySaWu5OOp&KORb(|)>oYj9VlzF7PPAHgg zp|rJloO1u!-NFd}7=J(q|Oecbi+Bi`@^}Ed6j3QQhG>Q_MtIG;{gm zAbYOP!vC)_&K=#ROk_|FEb%}?{c0jEqB&_o2Q_{Q49;x z;wf|1)ngJ#hM{lDZEx*Aw$*#u>1{Qea&(k^k+9~m{qCdbR~KjPCONEEON6dYbm%fa zceB|sIu!oV$;Q?qSCmwRDSE%Ni~XkQ@cA>Om1MC=)_GeH0c5f=vzB0jf?!XcJAdu= zt?>O}W;?J`dCxk-XjXql`_$<#IRHgh^|({A@5yfsNrA-8Sc7iQ-%AGjG3tSf~JvQ-$1#TX(4Vw(aK$L8%I*-E+`hHDrBX3 zRETvaN_phR1yIp%)twqQGl+03)SfFC)7hP)fsuAf_K(mWzJDSbbdYCAf}CfJ5SnMC zz7E`*7pPcjm1+090C&e|+$$N!a|5Q#QjAa;7@wTT`I&&Lgil0r8F;&a7MSsY35+)N zQVFrmWtQfxP{^9^FFpwCO%MX%zjN*{~%Xw z?&)ul3j}Qjag$B+Z@j-m-^5zi=1gj{ZUM4t`L8M#aH<5 zf7XutKK^n(27~IW`3~>V54H6!uib43n{>9@L|n7ZuH?z%pu>UmHdTz&V5(xl-NW5r zh}Yg)Buff_ok&Y1%;cMqX`TLoRJZ-IR6`TBkDZn(b@frsd*is}t)C5jN6k%lKaWE9 zelBbTa$=JAVg$U&xSi4$ldJ++{f{brm)qbpF}K&;o!cDX1ZE-UKWw&l5jR-TY4yzI zsE!|B@{4Z?@7NtZQ)6DY3T=mf4V3z_ZPyW9<$?chjNl4t>3e-mpvAjVr>EbYriTmo ukg0sJ-sHqEAoBlrKjXiP+qi+Z3KaEP8Giy($8mR1@YI!c;8lvY$o~TEkX&;B literal 0 HcmV?d00001 diff --git a/lib/lib_div/lib_mail/media/images/esp-mail-client.svg b/lib/lib_div/lib_mail/media/images/esp-mail-client.svg new file mode 100755 index 000000000..b1aa41bc2 --- /dev/null +++ b/lib/lib_div/lib_mail/media/images/esp-mail-client.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp b/lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp new file mode 100755 index 000000000..0cfdd4aa1 --- /dev/null +++ b/lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp @@ -0,0 +1,8203 @@ +/** + * Mail Client Arduino Library for Espressif's ESP32 and ESP8266 + * + * Version: 1.0.13 + * Released: January 11, 2021 + * + * Updates: + * - Fix the IMAP search termination checking https://github.com/mobizt/ESP-Mail-Client/issues/15. + * - Fix the IMAP startTLS consequence commands + * + * + * This library allows Espressif's ESP32 and ESP8266 devices to send and read Email + * through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESP_Mail_Client_CPP +#define ESP_Mail_Client_CPP + +#include "ESP_Mail_Client.h" + +#if defined(ESP32) +extern "C" +{ +#include +#include +} +#endif + +bool ESP_Mail_Client::sendIMAPCommand(IMAPSession *imap, int msgIndex, int cmdCase) +{ + + std::string cmd; + if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) + appendP(cmd, esp_mail_str_142, true); + else + appendP(cmd, esp_mail_str_143, true); + + char *tmp = intStr(imap->_msgNum[msgIndex]); + cmd += tmp; + delS(tmp); + appendP(cmd, esp_mail_str_147, false); + if (!imap->_config->fetch.set_seen) + { + appendP(cmd, esp_mail_str_152, false); + appendP(cmd, esp_mail_str_214, false); + } + appendP(cmd, esp_mail_str_218, false); + + switch (cmdCase) + { + case 1: + + appendP(cmd, esp_mail_str_269, false); + break; + + case 2: + + if (cPart(imap)->partNumFetchStr.length() > 0) + cmd += cPart(imap)->partNumFetchStr; + else + appendP(cmd, esp_mail_str_215, false); + appendP(cmd, esp_mail_str_156, false); + break; + + case 3: + + cmd += cPart(imap)->partNumFetchStr; + appendP(cmd, esp_mail_str_156, false); + break; + + default: + break; + } + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + return true; +} + +bool ESP_Mail_Client::readMail(IMAPSession *imap, bool closeSession) +{ + + imap->checkUID(); + imap->checkPath(); + + if (!imap->_tcpConnected) + imap->_mailboxOpened = false; + + std::string buf; + std::string command; + std::string _uid; + appendP(command, esp_mail_str_27, true); + char *tmp = nullptr; + size_t readCount = 0; + imap->_multipart_levels.clear(); + + if (!reconnect(imap)) + return false; + + int cmem = ESP.getFreeHeap(); + + if (cmem < ESP_MAIL_MIN_MEM) + { + if (imap->_debug) + { + esp_mail_debug(""); + errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY); + } + goto out; + } + + //new session + if (!imap->_tcpConnected) + { + //authenticate new + if (!imapAuth(imap)) + { + closeTCP(imap); + return false; + } + } + else + { + //reuse session + for (size_t i = 0; i < imap->_headers.size(); i++) + imap->_headers[i].part_headers.clear(); + imap->_headers.clear(); + + if (strlen(imap->_config->fetch.uid) > 0) + imap->_headerOnly = false; + else + imap->_headerOnly = true; + } + imap->_rfc822_part_count = 0; + imap->_mbif._availableItems = 0; + imap->_msgNum.clear(); + imap->_uidSearch = false; + imap->_mbif._searchCount = 0; + + if (imap->_currentFolder.length() == 0) + return handleIMAPError(imap, IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED, false); + + if (!imap->_mailboxOpened || (imap->_config->fetch.set_seen && !imap->_headerOnly && imap->_readOnlyMode)) + { + if (!imap->openFolder(imap->_currentFolder.c_str(), imap->_readOnlyMode && !imap->_config->fetch.set_seen)) + return handleIMAPError(imap, IMAP_STATUS_OPEN_MAILBOX_FAILED, false); + } + + if (imap->_headerOnly) + { + if (strlen(imap->_config->search.criteria) > 0) + { + + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_66, false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_232); + + if (strposP(imap->_config->search.criteria, esp_mail_str_137, 0) != -1) + { + imap->_uidSearch = true; + appendP(command, esp_mail_str_138, false); + } + + appendP(command, esp_mail_str_139, false); + + for (size_t i = 0; i < strlen(imap->_config->search.criteria); i++) + { + if (imap->_config->search.criteria[i] != ' ' && imap->_config->search.criteria[i] != '\r' && imap->_config->search.criteria[i] != '\n' && imap->_config->search.criteria[i] != '$') + buf.append(1, imap->_config->search.criteria[i]); + + if (imap->_config->search.criteria[i] == ' ') + { + tmp = strP(esp_mail_str_140); + char *tmp2 = strP(esp_mail_str_224); + + if ((imap->_uidSearch && strcmp(buf.c_str(), tmp) == 0) || (imap->_unseen && buf.find(tmp2) != std::string::npos)) + buf.clear(); + delS(tmp); + delS(tmp2); + + tmp = strP(esp_mail_str_141); + if (strcmp(buf.c_str(), tmp) != 0 && buf.length() > 0) + { + appendP(command, esp_mail_str_131, false); + command += buf; + } + delS(tmp); + buf.clear(); + } + } + + tmp = strP(esp_mail_str_223); + if (imap->_unseen && strpos(imap->_config->search.criteria, tmp, 0) == -1) + appendP(command, esp_mail_str_223, false); + delS(tmp); + + if (buf.length() > 0) + { + appendP(command, esp_mail_str_131, false); + command += buf; + } + + if (imapSend(imap, command.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + std::string().swap(command); + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_search; + + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) + return false; + + if (imap->_readCallback) + { + std::string s; + appendP(s, esp_mail_str_34, true); + appendP(s, esp_mail_str_68, false); + char *tmp = intStr(imap->_config->limit.search); + s += tmp; + delS(tmp); + imapCB(imap, s.c_str(), false); + + if (imap->_msgNum.size() > 0) + { + + appendP(s, esp_mail_str_69, true); + tmp = intStr(imap->_mbif._searchCount); + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_70, false); + imapCB(imap, s.c_str(), false); + + appendP(s, esp_mail_str_71, true); + tmp = intStr(imap->_msgNum.size()); + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_70, false); + imapCB(imap, s.c_str(), false); + } + else + imapCBP(imap, esp_mail_str_72, false); + } + } + else + { + imap->_mbif._availableItems++; + imap->_msgNum.push_back(imap->_mbif._nextUID - 1); + imap->_headerOnly = false; + char *tmp = intStr(imap->_mbif._nextUID - 1); + _uid = tmp; + delS(tmp); + imap->_config->fetch.uid = _uid.c_str(); + + if (imap->_readCallback) + imapCBP(imap, esp_mail_str_73, false); + } + } + else + { + imap->_mbif._availableItems++; + imap->_msgNum.push_back(atoi(imap->_config->fetch.uid)); + } + + for (size_t i = 0; i < imap->_msgNum.size(); i++) + { + + imap->_cMsgIdx = i; + imap->_totalRead++; + + if (ESP.getFreeHeap() - (imap->_config->limit.msg_size * (i + 1)) < ESP_MAIL_MIN_MEM) + { + if (imap->_debug) + errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY); + goto out; + } + + if (imap->_readCallback) + { + readCount++; + + std::string s; + appendP(s, esp_mail_str_74, true); + char *tmp = intStr(imap->_totalRead); + s += tmp; + delS(tmp); + + if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) + appendP(s, esp_mail_str_75, false); + else + appendP(s, esp_mail_str_76, false); + + tmp = intStr(imap->_msgNum[i]); + s += tmp; + delS(tmp); + imapCB(imap, "", false); + imapCB(imap, s.c_str(), false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_233); + + std::string cmd; + if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) + appendP(cmd, esp_mail_str_142, true); + else + appendP(cmd, esp_mail_str_143, true); + + if (imap->_debug) + debugInfoP(esp_mail_str_77); + + char *tmp = intStr(imap->_msgNum[i]); + cmd += tmp; + delS(tmp); + + appendP(cmd, esp_mail_str_147, false); + if (!imap->_config->fetch.set_seen) + { + appendP(cmd, esp_mail_str_152, false); + appendP(cmd, esp_mail_str_214, false); + } + appendP(cmd, esp_mail_str_218, false); + + appendP(cmd, esp_mail_str_144, false); + appendP(cmd, esp_mail_str_156, false); + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_header; + + int err = IMAP_STATUS_BAD_COMMAND; + if (imap->_headerOnly) + err = IMAP_STATUS_IMAP_RESPONSE_FAILED; + + if (!handleIMAPResponse(imap, err, closeSession)) + return false; + + if (!imap->_headerOnly) + { + imap->_cPartIdx = 0; + + //multipart + if (cHeader(imap)->multipart) + { + struct esp_mail_imap_multipart_level_t mlevel; + mlevel.level = 1; + mlevel.fetch_rfc822_header = false; + mlevel.append_body_text = false; + imap->_multipart_levels.push_back(mlevel); + + if (!fetchMultipartBodyHeader(imap, i)) + return false; + } + else + { + //singlepart + if (imap->_debug) + { + std::string s; + appendP(s, esp_mail_str_81, true); + s += '1'; + esp_mail_debug(s.c_str()); + } + + cHeader(imap)->partNumStr.clear(); + if (!sendIMAPCommand(imap, i, 1)) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_mime; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) + return false; + } + + if (imap->_config->download.text || imap->_config->download.html || imap->_config->download.attachment || imap->_config->download.inlineImg) + { + if (!_sdOk && imap->_storageType == esp_mail_file_storage_type_sd) + { + _sdOk = sdTest(); + if (_sdOk) + if (!SD.exists(imap->_config->storage.saved_path)) + createDirs(imap->_config->storage.saved_path); + } + else if (!_flashOk && imap->_storageType == esp_mail_file_storage_type_flash) +#if defined(ESP32) + _flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + _flashOk = FLASH_FS.begin(); +#endif + } + + if (cHeader(imap)->part_headers.size() > 0) + { + if (cHeader(imap)->attachment_count > 0 && imap->_readCallback) + { + std::string s; + appendP(s, esp_mail_str_34, true); + appendP(s, esp_mail_str_78, false); + char *tmp = intStr(cHeader(imap)->attachment_count); + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_79, false); + imapCB(imap, s.c_str(), false); + + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + if (!cPart(imap)->rfc822_part && cPart(imap)->attach_type != esp_mail_att_type_none) + imapCB(imap, cPart(imap)->filename.c_str(), false); + } + } + + std::string s1, s2; + int _idx1 = 0; + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + if (cPart(imap)->rfc822_part) + { + s1 = cPart(imap)->partNumStr; + _idx1 = cPart(imap)->rfc822_msg_Idx; + } + else if (s1.length() > 0) + { + if (multipartMember(s1, cPart(imap)->partNumStr)) + { + cPart(imap)->message_sub_type = esp_mail_imap_message_sub_type_rfc822; + cPart(imap)->rfc822_msg_Idx = _idx1; + } + } + + if (cPart(imap)->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel) + s2 = cPart(imap)->partNumStr; + else if (s2.length() > 0) + { + if (multipartMember(s2, cPart(imap)->partNumStr)) + { + cPart(imap)->attach_type = esp_mail_att_type_attachment; + if (cPart(imap)->filename.length() == 0) + { + if (cPart(imap)->name.length() > 0) + cPart(imap)->filename = cPart(imap)->name; + else + { + char *tmp = getUID(); + cPart(imap)->filename = tmp; + appendP(cPart(imap)->filename, esp_mail_str_40, false); + delS(tmp); + } + } + } + } + } + + int acnt = 0; + int ccnt = 0; + + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + + if (cPart(imap)->rfc822_part || cPart(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_none) + continue; + + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + + if (cPart(imap)->attach_type == esp_mail_att_type_none || cPart(imap)->msg_type == esp_mail_msg_type_html || cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + { + + bool ret = ((imap->_config->enable.rfc822 || imap->_config->download.rfc822) && rfc822_body_subtype) || (!rfc822_body_subtype && ((imap->_config->enable.text && (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)) || (imap->_config->enable.html && cPart(imap)->msg_type == esp_mail_msg_type_html) || (cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))); + if (!ret) + continue; + + if ((imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))) + { + + if (ccnt == 0) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_57, false); + } + + if (imap->_debug) + { + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + debugInfoP(esp_mail_str_59); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + debugInfoP(esp_mail_str_60); + } + } + else + { + if (ccnt == 0) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_307, false); + } + + if (imap->_debug) + { + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + debugInfoP(esp_mail_str_308); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + debugInfoP(esp_mail_str_309); + } + } + + ccnt++; + + if (!sendIMAPCommand(imap, i, 2)) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_text; + if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) + return false; + } + else if (cPart(imap)->attach_type != esp_mail_att_type_none && (_sdOk || _flashOk)) + { + + if (imap->_config->download.attachment || imap->_config->download.inlineImg) + { + if (acnt == 0) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_80, false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_55); + + acnt++; + if (cPart(imap)->octetLen <= (int)imap->_config->limit.attachment_size) + { + + if (_sdOk || _flashOk) + { + + if ((int)j < (int)cHeader(imap)->part_headers.size() - 1) + if (cHeader(imap)->part_headers[j + 1].octetLen > (int)imap->_config->limit.attachment_size) + cHeader(imap)->downloaded_bytes += cHeader(imap)->part_headers[j + 1].octetLen; + + if (!sendIMAPCommand(imap, i, 3)) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_attachment; + if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) + return false; + delay(0); + } + } + else + { + if ((int)j == (int)cHeader(imap)->part_headers.size() - 1) + cHeader(imap)->downloaded_bytes += cPart(imap)->octetLen; + } + } + } + } + } + + if (imap->_config->download.header && !imap->_headerSaved) + { + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_124, false); + } + saveHeader(imap); + } + + if (closeSession) + { + if (imap->_storageType == esp_mail_file_storage_type_sd) + { + if (_sdOk) + SD.end(); + _sdOk = false; + } + else if (imap->_storageType == esp_mail_file_storage_type_flash) + { + if (_flashOk) +#if defined(ESP32) + SPIFFS.end(); +#elif defined(ESP8266) + FLASH_FS.end(); +#endif + + _flashOk = false; + } + } + + imap->_cMsgIdx++; + } + + if (imap->_debug) + { + std::string s; + appendP(s, esp_mail_str_261, true); + appendP(s, esp_mail_str_84, false); + char *tmp = intStr(ESP.getFreeHeap()); + s += tmp; + delS(tmp); + esp_mail_debug(s.c_str()); + } + } + +out: + + if (readCount < imap->_msgNum.size()) + { + imap->_mbif._availableItems = readCount; + imap->_msgNum.erase(imap->_msgNum.begin() + readCount, imap->_msgNum.end()); + } + + if (closeSession) + { + if (!imap->closeSession()) + return false; + } + else + { + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_87, false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_88); + } + + if (imap->_readCallback) + imapCB(imap, "", true); + + return true; +} +bool ESP_Mail_Client::getMultipartFechCmd(IMAPSession *imap, int msgIdx, std::string &partText) +{ + if (imap->_multipart_levels.size() == 0) + return false; + + int cLevel = imap->_multipart_levels.size() - 1; + + cHeader(imap)->partNumStr.clear(); + + if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) + appendP(partText, esp_mail_str_142, true); + else + appendP(partText, esp_mail_str_143, true); + + char *tmp = intStr(imap->_msgNum[msgIdx]); + partText += tmp; + delS(tmp); + + appendP(partText, esp_mail_str_147, false); + if (!imap->_config->fetch.set_seen) + { + appendP(partText, esp_mail_str_152, false); + appendP(partText, esp_mail_str_214, false); + } + appendP(partText, esp_mail_str_218, false); + + for (size_t i = 0; i < imap->_multipart_levels.size(); i++) + { + if (i > 0) + { + appendP(partText, esp_mail_str_152, false); + appendP(cHeader(imap)->partNumStr, esp_mail_str_152, false); + } + + tmp = intStr(imap->_multipart_levels[i].level); + partText += tmp; + cHeader(imap)->partNumStr += tmp; + delS(tmp); + } + + if (imap->_multipart_levels[cLevel].fetch_rfc822_header) + { + appendP(partText, esp_mail_str_51, false); + imap->_multipart_levels[cLevel].append_body_text = true; + } + else + appendP(partText, esp_mail_str_148, false); + + imap->_multipart_levels[cLevel].fetch_rfc822_header = false; + + return true; +} + +bool ESP_Mail_Client::multipartMember(const std::string &part, const std::string &check) +{ + if (part.length() > check.length()) + return false; + + for (size_t i = 0; i < part.length(); i++) + if (part[i] != check[i]) + return false; + + return true; +} + +bool ESP_Mail_Client::fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx) +{ + bool ret = true; + + if (!connected(imap)) + { + closeTCP(imap); + return false; + } + int cLevel = 0; + + do + { + + esp_mail_message_part_info_t *_cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; + bool rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + + std::string cmd; + + if (!getMultipartFechCmd(imap, msgIdx, cmd)) + return true; + + if (imap->_debug) + { + std::string s; + if (imap->_multipart_levels.size() > 1) + appendP(s, esp_mail_str_86, true); + else + appendP(s, esp_mail_str_81, true); + s += cHeader(imap)->partNumStr; + esp_mail_debug(s.c_str()); + } + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_mime; + + ret = handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, false); + + _cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; + rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + cLevel = imap->_multipart_levels.size() - 1; + + if (ret) + { + + if (_cpart->multipart) + { + if (_cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_alternative || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_related || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_mixed) + { + struct esp_mail_imap_multipart_level_t mlevel; + mlevel.level = 1; + mlevel.fetch_rfc822_header = false; + mlevel.append_body_text = false; + imap->_multipart_levels.push_back(mlevel); + fetchMultipartBodyHeader(imap, msgIdx); + } + else + imap->_multipart_levels[cLevel].level++; + } + else + { + if (rfc822_body_subtype) + { + //to get additional rfc822 message header + imap->_multipart_levels[cLevel].fetch_rfc822_header = true; + fetchMultipartBodyHeader(imap, msgIdx); + } + else + { + if (imap->_multipart_levels[cLevel].append_body_text) + { + //single part rfc822 message body, append TEXT to the body fetch command + appendP(_cpart->partNumFetchStr, esp_mail_str_152, false); + appendP(_cpart->partNumFetchStr, esp_mail_str_215, false); + imap->_multipart_levels[cLevel].append_body_text = false; + } + imap->_multipart_levels[cLevel].level++; + } + } + } + + } while (ret); + + imap->_multipart_levels.pop_back(); + + if (imap->_multipart_levels.size() > 0) + { + cLevel = imap->_multipart_levels.size() - 1; + imap->_multipart_levels[cLevel].level++; + } + + return true; +} + +bool ESP_Mail_Client::connected(IMAPSession *imap) +{ + if (!imap->_secure) + { + if (!imap->httpClient._stream()) + return false; + return imap->httpClient._stream()->_ns_connected(); + } + else + { + if (!imap->httpClient.stream()) + return false; + return imap->httpClient.stream()->connected(); + } +} + +bool ESP_Mail_Client::imapAuth(IMAPSession *imap) +{ + + bool ssl = false; + std::string buf; +#if defined(ESP32) + imap->httpClient.setDebugCallback(NULL); +#elif defined(ESP8266) + +#endif + + if (imap->_config != nullptr) + { + if (strlen(imap->_config->fetch.uid) > 0) + imap->_headerOnly = false; + else + imap->_headerOnly = true; + } + + imap->_totalRead = 0; + imap->_secure = true; + bool secureMode = true; + +#if defined(ESP32) + if (imap->_debug) + imap->httpClient.setDebugCallback(esp_mail_debug); +#elif defined(ESP8266) + imap->httpClient.txBufDivider = 16; //minimum, tx buffer size for ssl data and request command data + imap->httpClient.rxBufDivider = 1; + if (imap->_config != nullptr) + { + if (!imap->_headerOnly && !imap->_config->enable.html && !imap->_config->enable.text && !imap->_config->download.attachment && !imap->_config->download.inlineImg && !imap->_config->download.html && !imap->_config->download.text) + imap->httpClient.rxBufDivider = 16; // minimum rx buffer size for only message header + } +#endif + + if (imap->_sesson_cfg->server.port == esp_mail_imap_port_143) + { + imap->_secure = false; + secureMode = false; + } + else + secureMode = !imap->_sesson_cfg->secure.startTLS; + + setSecure(imap->httpClient, imap->_sesson_cfg, imap->_caCert); + + if (imap->_readCallback) + imapCBP(imap, esp_mail_str_50, false); + + if (imap->_debug) + { + std::string s; + appendP(s, esp_mail_str_314, true); + s += ESP_MAIL_VERSION; + esp_mail_debug(s.c_str()); + + debugInfoP(esp_mail_str_225); + appendP(s, esp_mail_str_261, true); + appendP(s, esp_mail_str_211, false); + s += imap->_sesson_cfg->server.host_name; + esp_mail_debug(s.c_str()); + char *tmp = intStr(imap->_sesson_cfg->server.port); + appendP(s, esp_mail_str_261, true); + appendP(s, esp_mail_str_201, false); + s += tmp; + delS(tmp); + esp_mail_debug(s.c_str()); + } + + imap->httpClient.begin(imap->_sesson_cfg->server.host_name, imap->_sesson_cfg->server.port); + + if (!imap->httpClient.connect(secureMode)) + return handleIMAPError(imap, IMAP_STATUS_SERVER_CONNECT_FAILED, false); + + imap->_tcpConnected = true; + WiFiClient *stream = imap->httpClient.stream(); +#if defined(ESP32) + stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC); +#elif defined(ESP8266) + stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000); +#endif + imap->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000; + + if (imap->_readCallback) + imapCBP(imap, esp_mail_str_54, false); + + if (imap->_debug) + debugInfoP(esp_mail_str_228); + +init: + + if (!imap->checkCapability()) + return false; + + //start TLS when needed or the server issue + if ((imap->_auth_capability.start_tls || imap->_sesson_cfg->secure.startTLS) && !ssl) + { + std::string s; + if (imap->_readCallback) + { + appendP(s, esp_mail_str_34, true); + appendP(s, esp_mail_str_209, false); + esp_mail_debug(s.c_str()); + } + + if (imap->_debug) + { + appendP(s, esp_mail_str_196, true); + esp_mail_debug(s.c_str()); + } + + imapSendP(imap, esp_mail_str_311, false); + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_starttls; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (imap->_debug) + { + debugInfoP(esp_mail_str_310); + } + + //connect in secure mode + //do ssl handshaking + if (!imap->httpClient._stream()->_ns_connect_ssl()) + return handleIMAPError(imap, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP, false); + + //set the secure mode + imap->_sesson_cfg->secure.startTLS = false; + ssl = true; + imap->_secure = true; + + //check the capabilitiy again + goto init; + } + + imap->clearMessageData(); + imap->_mailboxOpened = false; + + bool creds = strlen(imap->_sesson_cfg->login.email) > 0 && strlen(imap->_sesson_cfg->login.password) > 0; + bool xoauth_auth = strlen(imap->_sesson_cfg->login.accessToken) > 0 && imap->_auth_capability.xoauth2; + bool login_auth = creds; + bool plain_auth = imap->_auth_capability.plain && creds; + + bool supported_auth = xoauth_auth || login_auth || plain_auth; + + if (!supported_auth) + return handleIMAPError(imap, IMAP_STATUS_NO_SUPPORTED_AUTH, false); + + //rfc4959 + if (supported_auth) + { + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_56, false); + } + } + + if (xoauth_auth) + { + if (!imap->_auth_capability.xoauth2) + return handleIMAPError(imap, IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); + + if (imap->_debug) + debugInfoP(esp_mail_str_291); + + std::string cmd; + appendP(cmd, esp_mail_str_292, true); + cmd += getEncodedToken(imap); + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_auth; + if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, false)) + return false; + } + else if (login_auth) + { + + if (imap->_debug) + debugInfoP(esp_mail_str_229); + + std::string cmd; + + appendP(cmd, esp_mail_str_130, true); + cmd += imap->_sesson_cfg->login.email; + appendP(cmd, esp_mail_str_131, false); + cmd += imap->_sesson_cfg->login.password; + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login; + if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true)) + return false; + } + else if (plain_auth) + { + if (imap->_debug) + debugInfoP(esp_mail_str_290); + + const char *usr = imap->_sesson_cfg->login.email; + const char *psw = imap->_sesson_cfg->login.password; + int len = strlen(usr) + strlen(psw) + 2; + uint8_t *tmp = new uint8_t[len]; + memset(tmp, 0, len); + int p = 1; + memcpy(tmp + p, usr, strlen(usr)); + p += strlen(usr) + 1; + memcpy(tmp + p, psw, strlen(psw)); + p += strlen(psw); + + std::string s; + appendP(s, esp_mail_str_41, true); + s += encodeBase64Str(tmp, p); + delete[] tmp; + + if (imapSend(imap, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login; + if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true)) + return false; + } + + return true; +} + +std::string ESP_Mail_Client::getEncodedToken(IMAPSession *imap) +{ + std::string raw; + appendP(raw, esp_mail_str_285, true); + raw += imap->_sesson_cfg->login.email; + appendP(raw, esp_mail_str_286, false); + raw += imap->_sesson_cfg->login.accessToken; + appendP(raw, esp_mail_str_287, false); + std::string s = encodeBase64Str((const unsigned char *)raw.c_str(), raw.length()); + return s; +} + +bool ESP_Mail_Client::imapLogout(IMAPSession *imap) +{ + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_85, false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_234); + + if (imapSendP(imap, esp_mail_str_146, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_logout; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (imap->_readCallback) + { + imapCB(imap, "", false); + imapCBP(imap, esp_mail_str_187, false); + } + + if (imap->_debug) + debugInfoP(esp_mail_str_235); + + return true; +} + +void ESP_Mail_Client::errorStatusCB(IMAPSession *imap, int error) +{ + imap->_imapStatus.statusCode = error; + std::string s; + if (imap->_readCallback) + { + appendP(s, esp_mail_str_53, true); + s += imap->errorReason().c_str(); + imapCB(imap, s.c_str(), false); + } + + if (imap->_debug) + { + appendP(s, esp_mail_str_185, true); + s += imap->errorReason().c_str(); + esp_mail_debug(s.c_str()); + } +} + +size_t ESP_Mail_Client::imapSendP(IMAPSession *imap, PGM_P v, bool newline) +{ + if (!reconnect(imap)) + { + closeTCP(imap); + return 0; + } + + if (!connected(imap)) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!imap->_tcpConnected) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + char *tmp = strP(v); + size_t len = 0; + + if (newline) + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(tmp); + if (!imap->_secure) + len = imap->httpClient._ns_println(tmp); + else + len = imap->httpClient.stream()->println(tmp); + } + else + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(tmp, false); + if (!imap->_secure) + len = imap->httpClient._ns_print(tmp); + else + len = imap->httpClient.stream()->print(tmp); + } + + if (len != strlen(tmp) && len != strlen(tmp) + 2) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + delS(tmp); + + return len; +} + +size_t ESP_Mail_Client::imapSend(IMAPSession *imap, const char *data, bool newline) +{ + if (!reconnect(imap)) + { + closeTCP(imap); + return 0; + } + + if (!connected(imap)) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!imap->_tcpConnected) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + size_t len = 0; + + if (newline) + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(data); + if (!imap->_secure) + len = imap->httpClient._ns_println(data); + else + len = imap->httpClient.stream()->println(data); + } + else + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(data, false); + if (!imap->_secure) + len = imap->httpClient._ns_print(data); + else + len = imap->httpClient.stream()->print(data); + } + + if (len != strlen(data) && len != strlen(data) + 2) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + return len; +} + +size_t ESP_Mail_Client::imapSend(IMAPSession *imap, int data, bool newline) +{ + if (!reconnect(imap)) + { + closeTCP(imap); + return 0; + } + + if (!connected(imap)) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!imap->_tcpConnected) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + char *tmp = intStr(data); + size_t len = 0; + + if (newline) + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(tmp); + if (!imap->_secure) + len = imap->httpClient._ns_println(tmp); + else + len = imap->httpClient.stream()->println(tmp); + } + else + { + if (imap->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(tmp, false); + if (!imap->_secure) + len = imap->httpClient._ns_print(tmp); + else + len = imap->httpClient.stream()->print(tmp); + } + + if (len != strlen(tmp) && len != strlen(tmp) + 2) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + delS(tmp); + + return len; +} + +bool ESP_Mail_Client::setFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) +{ + return _setFlag(imap, msgUID, flag, 0, closeSession); +} + +bool ESP_Mail_Client::addFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) +{ + return _setFlag(imap, msgUID, flag, 1, closeSession); +} + +bool ESP_Mail_Client::removeFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) +{ + return _setFlag(imap, msgUID, flag, 2, closeSession); +} + +bool ESP_Mail_Client::_setFlag(IMAPSession *imap, int msgUID, const char *flag, uint8_t action, bool closeSession) +{ + if (!reconnect(imap)) + return false; + + if (!imap->_tcpConnected) + { + imap->_mailboxOpened = false; + return false; + } + + if (imap->_currentFolder.length() == 0) + { + if (imap->_readCallback) + debugInfoP(esp_mail_str_153); + + if (imap->_debug) + { + std::string e; + appendP(e, esp_mail_str_185, true); + appendP(e, esp_mail_str_151, false); + esp_mail_debug(e.c_str()); + } + } + else + { + if (imap->_readOnlyMode || !imap->_mailboxOpened) + { + if (!imap->selectFolder(imap->_currentFolder.c_str(), false)) + return false; + } + } + + if (imap->_readCallback) + { + imapCB(imap, "", false); + if (action == 0) + debugInfoP(esp_mail_str_157); + else if (action == 1) + debugInfoP(esp_mail_str_155); + else + debugInfoP(esp_mail_str_154); + } + + if (imap->_debug) + { + if (action == 0) + debugInfoP(esp_mail_str_253); + else if (action == 1) + debugInfoP(esp_mail_str_254); + else + debugInfoP(esp_mail_str_255); + } + + std::string cmd; + appendP(cmd, esp_mail_str_249, true); + char *tmp = intStr(msgUID); + cmd += tmp; + delS(tmp); + if (action == 0) + appendP(cmd, esp_mail_str_250, false); + else if (action == 1) + appendP(cmd, esp_mail_str_251, false); + else + appendP(cmd, esp_mail_str_252, false); + cmd += flag; + appendP(cmd, esp_mail_str_192, false); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_store; + + if (!handleIMAPResponse(imap, IMAP_STATUS_PARSE_FLAG_FAILED, false)) + return false; + + if (closeSession) + imap->closeSession(); + + return true; +} + +void ESP_Mail_Client::createDirs(std::string dirs) +{ + std::string dir = ""; + int count = 0; + for (size_t i = 0; i < dirs.length(); i++) + { + dir.append(1, dirs[i]); + count++; + if (dirs[i] == '/') + { + if (dir.length() > 0) + SD.mkdir(dir.substr(0, dir.length() - 1).c_str()); + count = 0; + } + } + if (count > 0) + SD.mkdir(dir.c_str()); + std::string().swap(dir); +} + +bool ESP_Mail_Client::sdTest() +{ + + if (_sdConfigSet) + sdBegin(_sck, _miso, _mosi, _ss); + else + sdBegin(); + + file = SD.open(esp_mail_str_204, FILE_WRITE); + if (!file) + return false; + + if (!file.write(32)) + return false; + file.close(); + + file = SD.open(esp_mail_str_204); + if (!file) + return false; + + while (file.available()) + { + if (file.read() != 32) + return false; + } + file.close(); + + SD.remove(esp_mail_str_204); + + return true; +} + +std::string ESP_Mail_Client::getEncodedToken(SMTPSession *smtp) +{ + std::string raw; + appendP(raw, esp_mail_str_285, true); + raw += smtp->_sesson_cfg->login.email; + appendP(raw, esp_mail_str_286, false); + raw += smtp->_sesson_cfg->login.accessToken; + appendP(raw, esp_mail_str_287, false); + return encodeBase64Str((const unsigned char *)raw.c_str(), raw.length()); +} + +bool ESP_Mail_Client::smtpAuth(SMTPSession *smtp) +{ + + if (!reconnect(smtp)) + return false; + + bool ssl = false; + smtp->_secure = true; + bool secureMode = true; + + std::string s; + +#if defined(ESP32) + smtp->httpClient.setDebugCallback(NULL); +#elif defined(ESP8266) + smtp->httpClient.rxBufDivider = 16; // minimum rx buffer for smtp status response + smtp->httpClient.txBufDivider = 8; // medium tx buffer for faster attachment/inline data transfer +#endif + + if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_25) + { + smtp->_secure = false; + secureMode = false; + } + else + { + if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_587) + smtp->_sesson_cfg->secure.startTLS = true; + + secureMode = !smtp->_sesson_cfg->secure.startTLS; + + //to prevent to send the connection upgrade command when some server promotes + //the starttls capability even the current connection was already secured. + if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_465) + ssl = true; + } + + setSecure(smtp->httpClient, smtp->_sesson_cfg, smtp->_caCert); + + //Server connection attempt: no status code + if (smtp->_sendCallback) + smtpCBP(smtp, esp_mail_str_120); + + if (smtp->_debug) + { + appendP(s, esp_mail_str_314, true); + s += ESP_MAIL_VERSION; + esp_mail_debug(s.c_str()); + + debugInfoP(esp_mail_str_236); + appendP(s, esp_mail_str_261, true); + appendP(s, esp_mail_str_211, false); + s += smtp->_sesson_cfg->server.host_name; + esp_mail_debug(s.c_str()); + char *tmp = intStr(smtp->_sesson_cfg->server.port); + appendP(s, esp_mail_str_261, true); + appendP(s, esp_mail_str_201, false); + s += tmp; + delS(tmp); + esp_mail_debug(s.c_str()); + } +#if defined(ESP32) + if (smtp->_debug) + smtp->httpClient.setDebugCallback(esp_mail_debug); +#endif + + smtp->httpClient.begin(smtp->_sesson_cfg->server.host_name, smtp->_sesson_cfg->server.port); + + if (!smtp->httpClient.connect(secureMode)) + return handleSMTPError(smtp, SMTP_STATUS_SERVER_CONNECT_FAILED); + + //server connected + smtp->_tcpConnected = true; + + if (smtp->_debug) + debugInfoP(esp_mail_str_238); + + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_121); + } + +#if defined(ESP32) + smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC); +#elif defined(ESP8266) + smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000); +#endif + smtp->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state; + + //expected status code 220 for ready to service + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_220, SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED)) + return false; + +init: + + //Sending greeting hello response + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_122); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_239); + + appendP(s, esp_mail_str_6, true); + if (strlen(smtp->_sesson_cfg->login.user_domain) > 0) + s += smtp->_sesson_cfg->login.user_domain; + else + appendP(s, esp_mail_str_44, false); + + if (smtpSendP(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting; + + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, 0)) + { + appendP(s, esp_mail_str_5, true); + if (strlen(smtp->_sesson_cfg->login.user_domain) > 0) + s += smtp->_sesson_cfg->login.user_domain; + else + appendP(s, esp_mail_str_44, false); + + if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) + return false; + smtp->_send_capability.esmtp = false; + smtp->_auth_capability.login = true; + } + else + smtp->_send_capability.esmtp = true; + + //start TLS when needed + if ((smtp->_auth_capability.start_tls || smtp->_sesson_cfg->secure.startTLS) && !ssl) + { + //send starttls command + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_209); + } + + if (smtp->_debug) + { + appendP(s, esp_mail_str_196, true); + esp_mail_debug(s.c_str()); + } + + //expected status code 250 for complete the request + //some server returns 220 to restart to initial state + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls; + smtpSendP(smtp, esp_mail_str_311, false); + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) + return false; + + if (smtp->_debug) + { + debugInfoP(esp_mail_str_310); + } + + //connect using secure mode + //do ssl handshaking + if (!smtp->httpClient._stream()->_ns_connect_ssl()) + return handleSMTPError(smtp, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP); + + //set the secure mode + smtp->_sesson_cfg->secure.startTLS = false; + ssl = true; + smtp->_secure = true; + + //return to initial state if the response status is 220. + if (smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_220) + goto init; + } + + bool creds = strlen(smtp->_sesson_cfg->login.email) > 0 && strlen(smtp->_sesson_cfg->login.password) > 0; + bool xoauth_auth = strlen(smtp->_sesson_cfg->login.accessToken) > 0 && smtp->_auth_capability.xoauth2; + bool login_auth = smtp->_auth_capability.login && creds; + bool plain_auth = smtp->_auth_capability.plain && creds; + + if (xoauth_auth || login_auth || plain_auth) + { + if (smtp->_sendCallback) + { + smtpCB(smtp, "", false); + smtpCBP(smtp, esp_mail_str_56, false); + } + + //log in + if (xoauth_auth) + { + if (smtp->_debug) + debugInfoP(esp_mail_str_288); + + if (!smtp->_auth_capability.xoauth2) + return handleSMTPError(smtp, SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); + + if (smtpSendP(smtp, esp_mail_str_289, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (smtpSend(smtp, getEncodedToken(smtp).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_AUTHEN_FAILED)) + return false; + + return true; + } + else if (plain_auth) + { + + if (smtp->_debug) + debugInfoP(esp_mail_str_241); + + if (smtp->_debug) + { + appendP(s, esp_mail_str_261, true); + s += smtp->_sesson_cfg->login.email; + esp_mail_debug(s.c_str()); + + appendP(s, esp_mail_str_131, false); + for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++) + appendP(s, esp_mail_str_183, false); + esp_mail_debug(s.c_str()); + } + + //rfc4616 + const char *usr = smtp->_sesson_cfg->login.email; + const char *psw = smtp->_sesson_cfg->login.password; + int len = strlen(usr) + strlen(psw) + 2; + uint8_t *tmp = new uint8_t[len]; + memset(tmp, 0, len); + int p = 1; + memcpy(tmp + p, usr, strlen(usr)); + p += strlen(usr) + 1; + memcpy(tmp + p, psw, strlen(psw)); + p += strlen(psw); + + std::string s; + appendP(s, esp_mail_str_45, true); + appendP(s, esp_mail_str_131, false); + s += encodeBase64Str(tmp, p); + delete[] tmp; + + if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth_plain; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_USER_LOGIN_FAILED)) + return false; + + return true; + } + else if (login_auth) + { + if (smtp->_debug) + debugInfoP(esp_mail_str_240); + + if (smtpSendP(smtp, esp_mail_str_4, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_AUTHEN_FAILED)) + return false; + + if (smtp->_debug) + { + appendP(s, esp_mail_str_261, true); + s += smtp->_sesson_cfg->login.email; + esp_mail_debug(s.c_str()); + } + + if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.email, strlen(smtp->_sesson_cfg->login.email)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_user; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_USER_LOGIN_FAILED)) + return false; + + if (smtp->_debug) + { + appendP(s, esp_mail_str_261, true); + for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++) + appendP(s, esp_mail_str_183, false); + esp_mail_debug(s.c_str()); + } + + if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.password, strlen(smtp->_sesson_cfg->login.password)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_psw; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_PASSWORD_LOGIN_FAILED)) + return false; + + return true; + } + } + + return true; +} + +void ESP_Mail_Client::mimeFromFile(const char *name, std::string &mime) +{ + std::string ext = name; + size_t p = ext.find_last_of("."); + if (p != std::string::npos) + { + ext = ext.substr(p, ext.length() - p); + if (ext.length() > 0) + getMIME(ext.c_str(), mime); + } +} + +bool ESP_Mail_Client::connected(SMTPSession *smtp) +{ + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + { + if (!smtp->httpClient._stream()) + return false; + return smtp->httpClient._stream()->_ns_connected(); + } + else + { + if (!smtp->httpClient.stream()) + return false; + return smtp->httpClient.stream()->connected(); + } +} + +bool ESP_Mail_Client::setSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result) +{ + if (result) + smtp->_sentSuccessCount++; + else + smtp->_sentFailedCount++; + + if (smtp->_sendCallback) + { + esp_mail_smtp_send_status_t status; + status.completed = result; + status.timesstamp = time(nullptr); + status.subject = msg->subject; + status.recipients = msg->_rcp[0].email; + + smtp->sendingResult.add(status); + + smtp->_cbData._sentSuccess = smtp->_sentSuccessCount; + smtp->_cbData._sentFailed = smtp->_sentFailedCount; + } + + return result; +} + +bool ESP_Mail_Client::sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) +{ + + if (strlen(msg->html.content) > 0) + msg->type |= esp_mail_msg_type_html; + + if (strlen(msg->text.content) > 0) + msg->type |= esp_mail_msg_type_plain; + + for (size_t i = 0; i < msg->_rfc822.size(); i++) + { + if (strlen(msg->_rfc822[i].html.content) > 0) + msg->_rfc822[i].type |= esp_mail_msg_type_html; + + if (strlen(msg->_rfc822[i].text.content) > 0) + msg->_rfc822[i].type |= esp_mail_msg_type_plain; + } + + return _sendMail(smtp, msg, closeSession); +} + +void ESP_Mail_Client::getMIME(const char *ext, std::string &mime) +{ + mime = ""; + for (int i = 0; i < esp_mail_file_extension_maxType; i++) + { + if (strcmp_P(ext, mimeinfo[i].endsWith) == 0) + { + char *tmp = strP(mimeinfo[i].mimeType); + mime = tmp; + delS(tmp); + break; + } + } +} + +size_t ESP_Mail_Client::numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg) +{ + size_t count = 0; + for (size_t i = 0; i < msg->_att.size(); i++) + { + if (msg->_att[i]._int.att_type == type) + count++; + } + return count; +} + +bool ESP_Mail_Client::validEmail(const char *s) +{ + std::string str(s); + auto at = std::find(str.begin(), str.end(), '@'); + auto dot = std::find(at, str.end(), '.'); + return (at != str.end()) && (dot != str.end()); +} +bool ESP_Mail_Client::checkEmail(SMTPSession *smtp, SMTP_Message *msg) +{ + bool validRecipient = false; + + if (!validEmail(msg->sender.email)) + { + errorStatusCB(smtp, SMTP_STATUS_NO_VALID_SENDER_EXISTED); + return setSendingResult(smtp, msg, false); + } + + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + { + if (validEmail(msg->_rcp[i].email)) + validRecipient = true; + } + + if (!validRecipient) + { + errorStatusCB(smtp, SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED); + return setSendingResult(smtp, msg, false); + } + + return true; +} + +bool ESP_Mail_Client::_sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) +{ + + smtp->_smtpStatus.statusCode = 0; + smtp->_smtpStatus.respCode = 0; + smtp->_smtpStatus.text.clear(); + bool rfc822MSG = false; + + if (!checkEmail(smtp, msg)) + return false; + + smtp->_chunkedEnable = false; + smtp->_chunkCount = 0; + + //new session + if (!smtp->_tcpConnected) + { + if (!smtpAuth(smtp)) + { + closeTCP(smtp); + return setSendingResult(smtp, msg, false); + } + smtp->_sentSuccessCount = 0; + smtp->_sentFailedCount = 0; + smtp->sendingResult.clear(); + } + else + { + //reuse session + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + if (smtp->_sentSuccessCount || smtp->_sentFailedCount) + smtpCBP(smtp, esp_mail_str_267); + else + smtpCBP(smtp, esp_mail_str_208); + } + + if (smtp->_debug) + { + if (smtp->_sentSuccessCount || smtp->_sentFailedCount) + debugInfoP(esp_mail_str_268); + else + debugInfoP(esp_mail_str_207); + } + } + + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_125); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_242); + + std::string buf; + std::string buf2; + checkBinaryData(smtp, msg); + + if (msg->priority >= esp_mail_smtp_priority_high && msg->priority <= esp_mail_smtp_priority_low) + { + char *tmp = intStr(msg->priority); + appendP(buf2, esp_mail_str_17, true); + buf2 += tmp; + delS(tmp); + appendP(buf2, esp_mail_str_34, false); + + if (msg->priority == esp_mail_smtp_priority_high) + { + appendP(buf2, esp_mail_str_18, false); + appendP(buf2, esp_mail_str_21, false); + } + else if (msg->priority == esp_mail_smtp_priority_normal) + { + appendP(buf2, esp_mail_str_19, false); + appendP(buf2, esp_mail_str_22, false); + } + else if (msg->priority == esp_mail_smtp_priority_low) + { + appendP(buf2, esp_mail_str_20, false); + appendP(buf2, esp_mail_str_23, false); + } + } + + appendP(buf2, esp_mail_str_10, false); + + if (strlen(msg->sender.name) > 0) + buf2 += msg->sender.name; + + appendP(buf2, esp_mail_str_14, false); + buf2 += msg->sender.email; + appendP(buf2, esp_mail_str_15, false); + appendP(buf2, esp_mail_str_34, false); + + appendP(buf, esp_mail_str_8, true); + appendP(buf, esp_mail_str_14, false); + buf += msg->sender.email; + appendP(buf, esp_mail_str_15, false); + + if (smtp->_send_capability.binaryMIME && smtp->_send_capability.chunking && msg->enable.chunking && (msg->text._int.binary || msg->html._int.binary)) + appendP(buf, esp_mail_str_104, false); + + if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_sender; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_SENDER_FAILED)) + return setSendingResult(smtp, msg, false); + + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + { + if (i == 0) + { + appendP(buf2, esp_mail_str_11, false); + if (strlen(msg->_rcp[i].name) > 0) + buf2 += msg->_rcp[i].name; + + appendP(buf2, esp_mail_str_14, false); + buf2 += msg->_rcp[i].email; + appendP(buf2, esp_mail_str_15, false); + } + else + { + if (strlen(msg->_rcp[i].name) > 0) + { + appendP(buf2, esp_mail_str_263, false); + buf2 += msg->_rcp[i].name; + appendP(buf2, esp_mail_str_14, false); + } + else + appendP(buf2, esp_mail_str_13, false); + buf2 += msg->_rcp[i].email; + appendP(buf2, esp_mail_str_15, false); + } + + if (i == msg->_rcp.size() - 1) + appendP(buf2, esp_mail_str_34, false); + + buf.clear(); + //only address + appendP(buf, esp_mail_str_9, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->_rcp[i].email; + appendP(buf, esp_mail_str_15, false); + + //rfc3461, rfc3464 + if (smtp->_send_capability.dsn) + { + if (msg->response.notify != esp_mail_smtp_notify::esp_mail_smtp_notify_never) + { + appendP(buf, esp_mail_str_262, false); + int opcnt = 0; + if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_success) + { + if (opcnt > 0) + appendP(buf, esp_mail_str_263, false); + appendP(buf, esp_mail_str_264, false); + opcnt++; + } + if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_failure) + { + if (opcnt > 0) + appendP(buf, esp_mail_str_263, false); + appendP(buf, esp_mail_str_265, false); + opcnt++; + } + if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_delay) + { + if (opcnt > 0) + appendP(buf, esp_mail_str_263, false); + appendP(buf, esp_mail_str_266, false); + opcnt++; + } + } + } + + if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return setSendingResult(smtp, msg, false); + } + + for (uint8_t i = 0; i < msg->_cc.size(); i++) + { + if (i == 0) + { + appendP(buf2, esp_mail_str_12, false); + appendP(buf2, esp_mail_str_14, false); + buf2 += msg->_cc[i].email; + appendP(buf2, esp_mail_str_15, false); + } + else + { + appendP(buf2, esp_mail_str_13, false); + buf2 += msg->_cc[i].email; + appendP(buf2, esp_mail_str_15, false); + } + + if (i == msg->_cc.size() - 1) + appendP(buf2, esp_mail_str_34, false); + + buf.clear(); + + appendP(buf, esp_mail_str_9, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->_cc[i].email; + appendP(buf, esp_mail_str_15, false); + + if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return setSendingResult(smtp, msg, false); + } + + for (uint8_t i = 0; i < msg->_bcc.size(); i++) + { + appendP(buf, esp_mail_str_9, true); + appendP(buf, esp_mail_str_14, false); + buf += msg->_bcc[i].email; + appendP(buf, esp_mail_str_15, false); + if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return setSendingResult(smtp, msg, false); + } + + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_126); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_243); + + if (smtp->_send_capability.chunking && msg->enable.chunking) + { + smtp->_chunkedEnable = true; + if (!bdat(smtp, msg, buf2.length(), false)) + return false; + } + else + { + if (smtpSendP(smtp, esp_mail_str_16, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_354, SMTP_STATUS_SEND_BODY_FAILED)) + return setSendingResult(smtp, msg, false); + } + + if (smtpSend(smtp, buf2.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + std::string s; + appendP(s, esp_mail_str_24, true); + s += msg->subject; + appendP(s, esp_mail_str_34, false); + + if (msg->_hdr.size() > 0) + { + for (uint8_t k = 0; k < msg->_hdr.size(); k++) + { + s += msg->_hdr[k]; + appendP(s, esp_mail_str_34, false); + } + } + + if (strlen(msg->response.reply_to) > 0) + { + appendP(s, esp_mail_str_184, false); + appendP(s, esp_mail_str_14, false); + s += msg->response.reply_to; + appendP(s, esp_mail_str_15, false); + appendP(s, esp_mail_str_34, false); + } + + if (strlen(msg->response.return_path) > 0) + { + appendP(s, esp_mail_str_46, false); + appendP(s, esp_mail_str_14, false); + s += msg->response.return_path; + appendP(s, esp_mail_str_15, false); + appendP(s, esp_mail_str_34, false); + } + + appendP(s, esp_mail_str_3, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + return sendMSGData(smtp, msg, closeSession, rfc822MSG); +} + +bool ESP_Mail_Client::sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG) +{ + std::string s; + std::string mixed = getBoundary(15); + std::string alt = getBoundary(15); + + if (numAtt(smtp, esp_mail_att_type_attachment, msg) == 0 && msg->_parallel.size() == 0 && msg->_rfc822.size() == 0) + { + if (msg->type == (esp_mail_msg_type_plain | esp_mail_msg_type_html | esp_mail_msg_type_enriched) || numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + { + if (!sendMSG(smtp, msg, alt)) + return setSendingResult(smtp, msg, false); + } + else if (msg->type != esp_mail_msg_type_none) + { + if (!sendPartText(smtp, msg, msg->type, "")) + return setSendingResult(smtp, msg, false); + } + } + else + { + + appendP(s, esp_mail_str_1, true); + s += mixed; + appendP(s, esp_mail_str_35, false); + + appendP(s, esp_mail_str_33, false); + s += mixed; + appendP(s, esp_mail_str_34, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + if (!sendMSG(smtp, msg, alt)) + return setSendingResult(smtp, msg, false); + + if (!bdat(smtp, msg, 2, false)) + return false; + + if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_127); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_244); + + if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_attachment, msg) > 0) + esp_mail_debug(""); + + if (!sendAttachments(smtp, msg, mixed)) + return setSendingResult(smtp, msg, false); + + if (!sendParallelAttachments(smtp, msg, mixed)) + return setSendingResult(smtp, msg, false); + + if (!sendRFC822Msg(smtp, msg, mixed, closeSession, msg->_rfc822.size() > 0)) + return setSendingResult(smtp, msg, false); + + appendP(s, esp_mail_str_33, true); + s += mixed; + appendP(s, esp_mail_str_33, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + } + + if (!rfc822MSG) + { + + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_303); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_304); + + if (smtp->_chunkedEnable) + { + + if (!bdat(smtp, msg, 0, true)) + return false; + + smtp->_smtp_cmd = esp_mail_smtp_cmd_chunk_termination; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return false; + } + else + { + if (smtpSendP(smtp, esp_mail_str_37, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return setSendingResult(smtp, msg, false); + } + + setSendingResult(smtp, msg, true); + + if (closeSession) + if (!smtp->closeSession()) + return false; + } + + return true; +} + +bool ESP_Mail_Client::sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool closeSession, bool rfc822MSG) +{ + if (msg->_rfc822.size() == 0) + return true; + std::string buf; + for (uint8_t i = 0; i < msg->_rfc822.size(); i++) + { + buf.clear(); + getRFC822PartHeader(smtp, buf, boundary); + + getRFC822MsgEnvelope(smtp, &msg->_rfc822[i], buf); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!sendMSGData(smtp, &msg->_rfc822[i], closeSession, rfc822MSG)) + return false; + } + + return true; +} + +void ESP_Mail_Client::getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, std::string &buf) +{ + if (strlen(msg->date) > 0) + { + appendP(buf, esp_mail_str_99, false); + buf += msg->date; + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->from.email) > 0) + { + appendP(buf, esp_mail_str_10, false); + + if (strlen(msg->from.name) > 0) + buf += msg->from.name; + + appendP(buf, esp_mail_str_14, false); + buf += msg->from.email; + appendP(buf, esp_mail_str_15, false); + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->sender.email) > 0) + { + appendP(buf, esp_mail_str_150, false); + + if (strlen(msg->sender.name) > 0) + buf += msg->sender.name; + + appendP(buf, esp_mail_str_14, false); + buf += msg->sender.email; + appendP(buf, esp_mail_str_15, false); + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->response.reply_to) > 0) + { + appendP(buf, esp_mail_str_184, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->response.reply_to; + appendP(buf, esp_mail_str_15, false); + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->response.return_path) > 0) + { + appendP(buf, esp_mail_str_46, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->response.return_path; + appendP(buf, esp_mail_str_15, false); + appendP(buf, esp_mail_str_34, false); + } + + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + { + if (i == 0) + { + appendP(buf, esp_mail_str_11, false); + if (strlen(msg->_rcp[i].name) > 0) + buf += msg->_rcp[i].name; + + appendP(buf, esp_mail_str_14, false); + buf += msg->_rcp[i].email; + appendP(buf, esp_mail_str_15, false); + } + else + { + if (strlen(msg->_rcp[i].name) > 0) + { + appendP(buf, esp_mail_str_263, false); + buf += msg->_rcp[i].name; + appendP(buf, esp_mail_str_14, false); + } + else + appendP(buf, esp_mail_str_13, false); + buf += msg->_rcp[i].email; + appendP(buf, esp_mail_str_15, false); + } + + if (i == msg->_rcp.size() - 1) + appendP(buf, esp_mail_str_34, false); + } + + for (uint8_t i = 0; i < msg->_cc.size(); i++) + { + if (i == 0) + { + appendP(buf, esp_mail_str_12, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->_cc[i].email; + appendP(buf, esp_mail_str_15, false); + } + else + { + appendP(buf, esp_mail_str_13, false); + buf += msg->_cc[i].email; + appendP(buf, esp_mail_str_15, false); + } + + if (i == msg->_cc.size() - 1) + appendP(buf, esp_mail_str_34, false); + } + + for (uint8_t i = 0; i < msg->_bcc.size(); i++) + { + if (i == 0) + { + appendP(buf, esp_mail_str_149, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->_bcc[i].email; + appendP(buf, esp_mail_str_15, false); + } + else + { + appendP(buf, esp_mail_str_13, false); + buf += msg->_bcc[i].email; + appendP(buf, esp_mail_str_15, false); + } + + if (i == msg->_bcc.size() - 1) + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->subject) > 0) + { + appendP(buf, esp_mail_str_279, false); + buf += msg->subject; + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->keyword) > 0) + { + appendP(buf, esp_mail_str_145, false); + buf += msg->keyword; + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->comment) > 0) + { + appendP(buf, esp_mail_str_134, false); + buf += msg->comment; + appendP(buf, esp_mail_str_34, false); + } + + if (strlen(msg->messageID) > 0) + { + appendP(buf, esp_mail_str_274, false); + appendP(buf, esp_mail_str_14, false); + buf += msg->messageID; + appendP(buf, esp_mail_str_15, false); + appendP(buf, esp_mail_str_34, false); + } +} + +bool ESP_Mail_Client::bdat(SMTPSession *smtp, SMTP_Message *msg, int len, bool last) +{ + if (!smtp->_chunkedEnable || !msg->enable.chunking) + return true; + + smtp->_chunkCount++; + + std::string bdat; + appendP(bdat, esp_mail_str_106, true); + char *tmp = intStr(len); + bdat += tmp; + if (last) + appendP(bdat, esp_mail_str_173, false); + delS(tmp); + if (smtpSend(smtp, bdat.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + if (!smtp->_send_capability.pipelining) + { + smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; + if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return setSendingResult(smtp, msg, false); + smtp->_chunkCount = 0; + } + return true; +} + +void ESP_Mail_Client::checkBinaryData(SMTPSession *smtp, SMTP_Message *msg) +{ + if (msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type & esp_mail_msg_type_html) + { + if ((msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched) > 0) + { + if (strlen(msg->text.transfer_encoding) > 0) + { + if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0) + { + msg->text._int.binary = true; + } + } + } + + if ((msg->type & esp_mail_msg_type_html) > 0) + { + if (strlen(msg->html.transfer_encoding) > 0) + { + if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0) + { + msg->html._int.binary = true; + } + } + } + } + + for (size_t i = 0; i < msg->_att.size(); i++) + { + if (strcmpP(msg->_att[i].descr.transfer_encoding, 0, esp_mail_str_166)) + { + msg->_att[i]._int.binary = true; + } + } +} + +bool ESP_Mail_Client::sendBlob(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att) +{ + if (strcmpP(att->descr.transfer_encoding, 0, esp_mail_str_31) && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0) + { + if (!sendBase64(smtp, msg, (const unsigned char *)att->blob.data, att->blob.size, att->_int.flash_blob, att->descr.filename, smtp->_sendCallback != NULL)) + return false; + return true; + } + else + { + if (att->blob.size > 0) + { + size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; + size_t writeLen = 0; + uint8_t *buf = new uint8_t[chunkSize]; + int pg = 0, _pg = 0; + while (writeLen < att->blob.size) + { + if (writeLen > att->blob.size - chunkSize) + chunkSize = att->blob.size - writeLen; + + if (!bdat(smtp, msg, chunkSize, false)) + break; + memcpy_P(buf, att->blob.data, chunkSize); + if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + break; + + if (smtp->_sendCallback) + { + pg = (float)(100.0f * writeLen / att->blob.size); + if (pg != _pg) + uploadReport(att->descr.filename, pg); + _pg = pg; + } + writeLen += chunkSize; + } + delete[] buf; + if (smtp->_sendCallback && _pg < 100) + uploadReport(att->descr.filename, 100); + + return writeLen >= att->blob.size; + } + } + return false; +} + +bool ESP_Mail_Client::sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file) +{ + if (strcmpP(att->descr.transfer_encoding, 0, esp_mail_str_31) && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0) + { + if (!sendBase64Stream(smtp, msg, file, att->descr.filename, smtp->_sendCallback != NULL)) + return false; + return true; + } + else + { + if (file.size() > 0) + { + size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; + size_t writeLen = 0; + if (file.size() < chunkSize) + chunkSize = file.size(); + uint8_t *buf = new uint8_t[chunkSize]; + int pg = 0, _pg = 0; + while (writeLen < file.size() && file.available()) + { + if (writeLen > file.size() - chunkSize) + chunkSize = file.size() - writeLen; + size_t readLen = file.read(buf, chunkSize); + if (readLen != chunkSize) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + break; + } + + if (!bdat(smtp, msg, chunkSize, false)) + break; + + if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + break; + + if (smtp->_sendCallback) + { + pg = (float)(100.0f * writeLen / file.size()); + if (pg != _pg) + uploadReport(att->descr.filename, pg); + _pg = pg; + } + writeLen += chunkSize; + } + delete[] buf; + if (smtp->_sendCallback && _pg < 100) + uploadReport(att->descr.filename, 100); + return writeLen == file.size(); + } + return false; + } + return false; +} + +bool ESP_Mail_Client::sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary) +{ + if (msg->_parallel.size() == 0) + return true; + + std::string buf; + std::string parallel = getBoundary(15); + appendP(buf, esp_mail_str_33, true); + buf += boundary; + appendP(buf, esp_mail_str_34, false); + + appendP(buf, esp_mail_str_28, false); + buf += parallel; + appendP(buf, esp_mail_str_35, false); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + if (!sendAttachments(smtp, msg, parallel, true)) + return setSendingResult(smtp, msg, false); + + appendP(buf, esp_mail_str_33, true); + buf += parallel; + appendP(buf, esp_mail_str_33, false); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return setSendingResult(smtp, msg, false); + + return true; +} + +bool ESP_Mail_Client::sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool parallel) +{ + std::string s; + std::string buf; + int cnt = 0; + + SMTP_Attachment *att = nullptr; + + size_t sz = msg->_att.size(); + if (parallel) + sz = msg->_parallel.size(); + + for (size_t i = 0; i < sz; i++) + { + if (parallel) + att = &msg->_parallel[i]; + else + att = &msg->_att[i]; + + if (att->_int.att_type == esp_mail_att_type_attachment) + { + appendP(s, esp_mail_str_261, true); + s += att->descr.filename; + + if (smtp->_sendCallback) + { + if (cnt > 0) + smtpCB(smtp, ""); + smtpCB(smtp, att->descr.filename); + } + + if (smtp->_debug) + esp_mail_debug(s.c_str()); + + cnt++; + + if (att->file.storage_type == esp_mail_file_storage_type_none) + { + if (!att->blob.data) + continue; + + if (smtp->_sendCallback) + smtpCB(smtp, att->descr.filename); + + if (smtp->_debug) + esp_mail_debug(s.c_str()); + + buf.clear(); + getAttachHeader(buf, boundary, att); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!sendBlob(smtp, msg, att)) + return false; + + if (!bdat(smtp, msg, 2, false)) + return false; + + if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + else + { + + if (att->file.storage_type == esp_mail_file_storage_type_univ) { + + } else { + + if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) + _sdOk = sdTest(); + + if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash) +#if defined(ESP32) + _flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + _flashOk = FLASH_FS.begin(); +#endif + + if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)) + { + + if (smtp->_sendCallback) + debugInfoP(esp_mail_str_158); + + if (smtp->_debug) + { + std::string e; + appendP(e, esp_mail_str_185, true); + appendP(e, esp_mail_str_158, false); + esp_mail_debug(e.c_str()); + } + + continue; + } + } + + if (openFileRead(smtp, msg, att, file, s, buf, boundary, false)) + { + if (file) + { + + if (!sendFile(smtp, msg, att, file)) + return false; + + if (!bdat(smtp, msg, 2, false)) + return false; + + if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + } + } + } + } + return true; +} + +bool ESP_Mail_Client::openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file, std::string &s, std::string &buf, const std::string &boundary, bool inlined) +{ + bool file_existed = false; + std::string filepath; + + if (strlen(att->file.path) > 0) + { + if (att->file.path[0] != '/') + appendP(filepath, esp_mail_str_202, true); + filepath += att->file.path; + } + + if (att->file.storage_type == esp_mail_file_storage_type_sd) { + file_existed = SD.exists(filepath.c_str()); + } + else if (att->file.storage_type == esp_mail_file_storage_type_flash) { +#if defined(ESP32) + file_existed = SPIFFS.exists(filepath.c_str()); +#elif defined(ESP8266) + file_existed = FLASH_FS.exists(filepath.c_str()); +#endif +} else if (att->file.storage_type == esp_mail_file_storage_type_univ) { + file_existed = ufsp->exists(filepath.c_str()); +} + if (!file_existed) + { + + if (strlen(att->descr.filename) > 0) + { + filepath.clear(); + if (att->descr.filename[0] != '/') + appendP(filepath, esp_mail_str_202, true); + filepath += att->descr.filename; + } + + if (att->file.storage_type == esp_mail_file_storage_type_sd) { + file_existed = SD.exists(filepath.c_str()); + } + else if (att->file.storage_type == esp_mail_file_storage_type_flash) { +#if defined(ESP32) + file_existed = SPIFFS.exists(filepath.c_str()); +#elif defined(ESP8266) + file_existed = FLASH_FS.exists(filepath.c_str()); +#endif + } + else if (att->file.storage_type == esp_mail_file_storage_type_univ) { + file_existed = ufsp->exists(filepath.c_str()); + } + } + + if (!file_existed) + { + if (smtp->_sendCallback) + debugInfoP(esp_mail_str_158); + + if (smtp->_debug) + { + std::string e; + appendP(e, esp_mail_str_185, true); + appendP(e, esp_mail_str_158, false); + esp_mail_debug(e.c_str()); + } + } + + if (file_existed) + { + + buf.clear(); + if (inlined) + getInlineHeader(buf, boundary, att); + else + getAttachHeader(buf, boundary, att); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (att->file.storage_type == esp_mail_file_storage_type_sd) { + file = SD.open(filepath.c_str(), FILE_READ); + } + else if (att->file.storage_type == esp_mail_file_storage_type_flash) { +#if defined(ESP32) + file = SPIFFS.open(filepath.c_str(), FILE_READ); +#elif defined(ESP8266) + file = FLASH_FS.open(filepath.c_str(), "r"); +#endif + } + else if (att->file.storage_type == esp_mail_file_storage_type_univ) { + file = ufsp->open(filepath.c_str(), "r"); + } + return true; + } + + return false; +} + +bool ESP_Mail_Client::sendInline(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, byte type) +{ + size_t num = numAtt(smtp, esp_mail_att_type_inline, msg) > 0; + + if (num > 0) + { + if (smtp->_sendCallback) + { + smtpCB(smtp, ""); + smtpCBP(smtp, esp_mail_str_167); + } + + if (smtp->_debug) + debugInfoP(esp_mail_str_271); + } + + std::string s; + std::string buf; + std::string related = getBoundary(15); + int cnt = 0; + SMTP_Attachment *att = nullptr; + + appendP(s, esp_mail_str_33, true); + s += boundary; + appendP(s, esp_mail_str_34, false); + + appendP(s, esp_mail_str_298, false); + s += related; + appendP(s, esp_mail_str_35, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!sendPartText(smtp, msg, type, related.c_str())) + return false; + + if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + esp_mail_debug(""); + + if (num > 0) + { + + for (uint8_t i = 0; i < msg->_att.size(); i++) + { + att = &msg->_att[i]; + if (att->_int.att_type == esp_mail_att_type_inline) + { + appendP(s, esp_mail_str_261, true); + s += att->descr.filename; + + if (smtp->_sendCallback) + { + if (cnt > 0) + smtpCB(smtp, ""); + smtpCB(smtp, att->descr.filename); + } + + if (smtp->_debug) + esp_mail_debug(s.c_str()); + + cnt++; + + if (att->file.storage_type == esp_mail_file_storage_type_none) + { + if (!att->blob.data) + continue; + + if (smtp->_sendCallback) + smtpCB(smtp, att->descr.filename); + + if (smtp->_debug) + esp_mail_debug(s.c_str()); + + buf.clear(); + getInlineHeader(buf, related, att); + + if (!bdat(smtp, msg, buf.length(), false)) + return false; + + if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!sendBlob(smtp, msg, att)) + return false; + + if (!bdat(smtp, msg, 2, false)) + return false; + + if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + else + { + if (att->file.storage_type == esp_mail_file_storage_type_univ) { + } else { + if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) + _sdOk = sdTest(); + + if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash) +#if defined(ESP32) + _flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + _flashOk = FLASH_FS.begin(); +#endif + + if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)) + { + + if (smtp->_sendCallback) + debugInfoP(esp_mail_str_158); + + if (smtp->_debug) + { + std::string e; + appendP(e, esp_mail_str_185, true); + appendP(e, esp_mail_str_158, false); + esp_mail_debug(e.c_str()); + } + + continue; + } + } + + if (openFileRead(smtp, msg, att, file, s, buf, related, true)) + { + if (!file) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + return false; + } + + if (!sendFile(smtp, msg, att, file)) + return false; + + if (!bdat(smtp, msg, 2, false)) + return false; + + if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + } + } + } + } + + appendP(s, esp_mail_str_34, true); + appendP(s, esp_mail_str_33, false); + s += related; + appendP(s, esp_mail_str_33, false); + appendP(s, esp_mail_str_34, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + return true; +} + +void ESP_Mail_Client::errorStatusCB(SMTPSession *smtp, int error) +{ + smtp->_smtpStatus.statusCode = error; + std::string s; + + if (smtp->_sendCallback) + { + appendP(s, esp_mail_str_53, true); + s += smtp->errorReason().c_str(); + smtpCB(smtp, s.c_str(), false); + } + + if (smtp->_debug) + { + appendP(s, esp_mail_str_185, true); + s += smtp->errorReason().c_str(); + esp_mail_debug(s.c_str()); + } +} + +size_t ESP_Mail_Client::smtpSendP(SMTPSession *smtp, PGM_P v, bool newline) +{ + if (!reconnect(smtp)) + { + closeTCP(smtp); + return 0; + } + + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!smtp->_tcpConnected) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + char *tmp = strP(v); + size_t len = 0; + + if (newline) + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(tmp); + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_println(tmp); + else + len = smtp->httpClient.stream()->println(tmp); + } + else + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(tmp, false); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_print(tmp); + else + len = smtp->httpClient.stream()->print(tmp); + } + + if (len != strlen(tmp) && len != strlen(tmp) + 2) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + delS(tmp); + + return len; +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, const char *data, bool newline) +{ + if (!reconnect(smtp)) + { + closeTCP(smtp); + return 0; + } + + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!smtp->_tcpConnected) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + size_t len = 0; + + if (newline) + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(data); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_println(data); + else + len = smtp->httpClient.stream()->println(data); + } + else + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(data, false); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_print(data); + else + len = smtp->httpClient.stream()->print(data); + } + + if (len != strlen(data) && len != strlen(data) + 2) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + return len; +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, int data, bool newline) +{ + if (!reconnect(smtp)) + { + closeTCP(smtp); + return 0; + } + + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!smtp->_tcpConnected) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + char *tmp = intStr(data); + size_t len = 0; + + if (newline) + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug(tmp); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_println(tmp); + else + len = smtp->httpClient.stream()->println(tmp); + } + else + { + if (smtp->_debugLevel > esp_mail_debug_level_2) + esp_mail_debug_line(tmp, false); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._ns_print(tmp); + else + len = smtp->httpClient.stream()->print(tmp); + } + + if (len != strlen(tmp) && len != strlen(tmp) + 2) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + delS(tmp); + + return len; +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, uint8_t *data, size_t size) +{ + if (!reconnect(smtp)) + { + closeTCP(smtp); + return 0; + } + + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return 0; + } + + if (!smtp->_tcpConnected) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + return 0; + } + + size_t len = 0; + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + len = smtp->httpClient._stream()->write(data, size); + else + len = smtp->httpClient.stream()->write(data, size); + + if (len != size) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); + len = 0; + } + + return len; +} + +bool ESP_Mail_Client::handleSMTPError(SMTPSession *smtp, int err, bool ret) +{ + if (err < 0) + errorStatusCB(smtp, err); + + if (smtp->_tcpConnected) + closeTCP(smtp); + + return ret; +} + +void ESP_Mail_Client::debugInfoP(PGM_P info) +{ + char *tmp = strP(info); + esp_mail_debug(tmp); + delS(tmp); +} + +bool ESP_Mail_Client::sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss) +{ + _sck = sck; + _miso = miso; + _mosi = mosi; + _ss = ss; + _sdConfigSet = true; +#if defined(ESP32) + SPI.begin(_sck, _miso, _mosi, _ss); + return SD.begin(_ss, SPI); +#elif defined(ESP8266) + return SD.begin(_ss); +#endif +} + +bool ESP_Mail_Client::sdBegin(void) +{ + _sdConfigSet = false; +#if defined(ESP32) + return SD.begin(); +#elif defined(ESP8266) + return SD.begin(SD_CS_PIN); +#endif +} + +bool ESP_Mail_Client::sendPartText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, const char *boundary) +{ + std::string header; + + if (strlen(boundary) > 0) + { + appendP(header, esp_mail_str_33, false); + header += boundary; + appendP(header, esp_mail_str_34, false); + } + + if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) + { + if (strlen(msg->text.content_type) > 0) + { + appendP(header, esp_mail_str_25, false); + header += msg->text.content_type; + + if (strlen(msg->text.charSet) > 0) + { + appendP(header, esp_mail_str_97, false); + appendP(header, esp_mail_str_131, false); + appendP(header, esp_mail_str_168, false); + header += msg->text.charSet; + appendP(header, esp_mail_str_136, false); + } + + if (msg->text.flowed) + { + appendP(header, esp_mail_str_97, false); + appendP(header, esp_mail_str_131, false); + appendP(header, esp_mail_str_270, false); + + appendP(header, esp_mail_str_97, false); + appendP(header, esp_mail_str_131, false); + appendP(header, esp_mail_str_110, false); + } + + if (msg->text.embed.enable) + { + appendP(header, esp_mail_str_26, false); + appendP(header, esp_mail_str_164, false); + appendP(header, esp_mail_str_136, false); + char *tmp = getUID(); + msg->text._int.cid = tmp; + delS(tmp); + } + + appendP(header, esp_mail_str_34, false); + } + + if (strlen(msg->text.transfer_encoding) > 0) + { + appendP(header, esp_mail_str_272, false); + header += msg->text.transfer_encoding; + appendP(header, esp_mail_str_34, false); + } + } + else if (type == esp_mail_msg_type_html) + { + if (strlen(msg->text.content_type) > 0) + { + appendP(header, esp_mail_str_25, false); + header += msg->html.content_type; + + if (strlen(msg->html.charSet) > 0) + { + appendP(header, esp_mail_str_97, false); + appendP(header, esp_mail_str_131, false); + appendP(header, esp_mail_str_168, false); + header += msg->html.charSet; + appendP(header, esp_mail_str_136, false); + } + if (msg->html.embed.enable) + { + appendP(header, esp_mail_str_26, false); + appendP(header, esp_mail_str_159, false); + appendP(header, esp_mail_str_136, false); + char *tmp = getUID(); + msg->html._int.cid = tmp; + delS(tmp); + } + appendP(header, esp_mail_str_34, false); + } + + if (strlen(msg->html.transfer_encoding) > 0) + { + appendP(header, esp_mail_str_272, false); + header += msg->html.transfer_encoding; + appendP(header, esp_mail_str_34, false); + } + } + + if ((type == esp_mail_msg_type_html && msg->html.embed.enable) || ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable)) + { + + if ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable) + { + if (msg->text.embed.type == esp_mail_smtp_embed_message_type_attachment) + appendP(header, esp_mail_str_30, false); + else if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline) + appendP(header, esp_mail_str_299, false); + + if (strlen(msg->text.embed.filename) > 0) + header += msg->text.embed.filename; + else + appendP(header, esp_mail_str_164, false); + appendP(header, esp_mail_str_36, false); + + if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline) + { + appendP(header, esp_mail_str_300, false); + if (strlen(msg->text.embed.filename) > 0) + header += msg->text.embed.filename; + else + appendP(header, esp_mail_str_159, false); + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_301, false); + header += msg->text._int.cid; + appendP(header, esp_mail_str_15, false); + appendP(header, esp_mail_str_34, false); + } + } + else if (type == esp_mail_msg_type_html && msg->html.embed.enable) + { + if (msg->html.embed.type == esp_mail_smtp_embed_message_type_attachment) + appendP(header, esp_mail_str_30, false); + else if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline) + appendP(header, esp_mail_str_299, false); + + if (strlen(msg->html.embed.filename) > 0) + header += msg->html.embed.filename; + else + appendP(header, esp_mail_str_159, false); + appendP(header, esp_mail_str_36, false); + + if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline) + { + appendP(header, esp_mail_str_300, false); + if (strlen(msg->html.embed.filename) > 0) + header += msg->html.embed.filename; + else + appendP(header, esp_mail_str_159, false); + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_301, false); + header += msg->html._int.cid; + appendP(header, esp_mail_str_15, false); + appendP(header, esp_mail_str_34, false); + } + } + } + + appendP(header, esp_mail_str_34, false); + + encodingText(smtp, msg, type, header); + + appendP(header, esp_mail_str_34, false); + + if (strlen(boundary) > 0) + appendP(header, esp_mail_str_34, false); + + if (!bdat(smtp, msg, header.length(), false)) + return false; + + if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + return true; +} + +char *ESP_Mail_Client::getUID() +{ + char *tmp = new char[36]; + memset(tmp, 0, 36); + itoa(random(10000000, 20000000), tmp, 10); + return tmp; +} + +void ESP_Mail_Client::encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, std::string &content) +{ + if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) + { + std::string s = msg->text.content; + + if (msg->text.flowed) + formatFlowedText(s); + + if (strlen(msg->text.transfer_encoding) > 0) + { + if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) + content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); + else if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0) + { + char *out = newS(s.length() * 3 + 1); + encodeQP(s.c_str(), out); + content += out; + delS(out); + } + else + content += s; + } + else + content += s; + } + else if (type == esp_mail_message_type::esp_mail_msg_type_html) + { + char *tmp = nullptr; + std::string s = msg->html.content; + std::string fnd, rep; + SMTP_Attachment *att = nullptr; + for (uint8_t i = 0; i < msg->_att.size(); i++) + { + att = &msg->_att[i]; + if (att->_int.att_type == esp_mail_att_type_inline) + { + std::string filename(att->descr.filename); + + size_t found = filename.find_last_of("/\\"); + if (found != std::string::npos) + filename = filename.substr(found + 1); + + appendP(fnd, esp_mail_str_136, true); + fnd += filename; + appendP(fnd, esp_mail_str_136, false); + + appendP(rep, esp_mail_str_136, true); + appendP(rep, esp_mail_str_302, false); + rep += att->_int.cid; + appendP(rep, esp_mail_str_136, false); + + tmp = strReplace((char *)s.c_str(), (char *)fnd.c_str(), (char *)rep.c_str()); + s = tmp; + delS(tmp); + } + } + + if (strlen(msg->html.transfer_encoding) > 0) + { + if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) + content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); + else if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0) + { + char *out = newS(strlen(msg->html.content) * 3 + 1); + encodeQP(msg->html.content, out); + content += out; + delS(out); + } + else + content += s; + } + else + content += s; + std::string().swap(s); + } +} + +/* Safe string splitter to avoid strsep bugs*/ +void ESP_Mail_Client::splitTk(std::string &str, std::vector &tk, const char *delim) +{ + std::size_t current, previous = 0; + current = str.find(delim, previous); + std::string s; + while (current != std::string::npos) + { + s = str.substr(previous, current - previous); + tk.push_back(s); + previous = current + strlen(delim); + current = str.find(delim, previous); + } + s = str.substr(previous, current - previous); + tk.push_back(s); + std::string().swap(s); +} + +/** Add the soft line break to the long text line (rfc 3676) + * and add Format=flowed parameter in the plain text content-type header. + * We use the existing white space as a part of this soft line break + * and set delSp="no" parameter to the header. + * + * Some servers are not rfc 3676 compliant. + * This causes the text lines are wrapped instead of joined. + * + * Some mail clients trim the space before the line break + * which makes the soft line break cannot be seen. +*/ +void ESP_Mail_Client::formatFlowedText(std::string &content) +{ + int count = 0; + std::string qms; + int j = 0; + std::vector tokens = std::vector(); + char *stk = strP(esp_mail_str_34); + char *qm = strP(esp_mail_str_15); + splitTk(content, tokens, stk); + content.clear(); + for (size_t i = 0; i < tokens.size(); i++) + { + if (tokens[i].length() > 0) + { + j = 0; + qms.clear(); + while (tokens[i][j] == qm[0]) + { + qms += qm; + j++; + } + softBreak(tokens[i], qms.c_str()); + if (count > 0) + content += stk; + content += tokens[i]; + } + else if (count > 0) + content += stk; + count++; + } + + delS(stk); + delS(qm); + tokens.clear(); +} + +void ESP_Mail_Client::softBreak(std::string &content, const char *quoteMarks) +{ + size_t len = 0; + char *stk = strP(esp_mail_str_131); + std::vector tokens = std::vector(); + splitTk(content, tokens, stk); + content.clear(); + for (size_t i = 0; i < tokens.size(); i++) + { + if (tokens[i].length() > 0) + { + if (len + tokens[i].length() + 3 > FLOWED_TEXT_LEN) + { + /* insert soft crlf */ + content += stk; + appendP(content, esp_mail_str_34, false); + + /* insert quote marks */ + if (strlen(quoteMarks) > 0) + content += quoteMarks; + content += tokens[i]; + len = tokens[i].length(); + } + else + { + if (len > 0) + { + content += stk; + len += strlen(stk); + } + content += tokens[i]; + len += tokens[i].length(); + } + } + } + delS(stk); + tokens.clear(); +} + +bool ESP_Mail_Client::sendMSG(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary) +{ + std::string alt = getBoundary(15); + std::string s; + + if (numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + { + appendP(s, esp_mail_str_297, true); + s += alt; + appendP(s, esp_mail_str_35, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) + { + if (!sendInline(smtp, msg, alt, msg->type)) + return false; + } + else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) + { + if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str())) + return false; + if (!sendInline(smtp, msg, alt, esp_mail_msg_type_html)) + return false; + } + + appendP(s, esp_mail_str_33, true); + s += alt; + appendP(s, esp_mail_str_33, false); + appendP(s, esp_mail_str_34, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + else + { + if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) + { + if (!sendPartText(smtp, msg, msg->type, "")) + return false; + } + else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) + { + appendP(s, esp_mail_str_33, true); + s += boundary; + appendP(s, esp_mail_str_34, false); + appendP(s, esp_mail_str_297, false); + s += alt; + appendP(s, esp_mail_str_35, false); + + if (!bdat(smtp, msg, s.length(), false)) + return false; + + if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str())) + return false; + + if (!sendPartText(smtp, msg, esp_mail_msg_type_html, alt.c_str())) + return false; + } + } + return true; +} + +void ESP_Mail_Client::getInlineHeader(std::string &header, const std::string &boundary, SMTP_Attachment *inlineAttach) +{ + appendP(header, esp_mail_str_33, false); + header += boundary; + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_25, false); + + if (strlen(inlineAttach->descr.mime) == 0) + { + std::string mime; + mimeFromFile(inlineAttach->descr.filename, mime); + if (mime.length() > 0) + header += mime; + else + appendP(header, esp_mail_str_32, false); + } + else + header += inlineAttach->descr.mime; + + appendP(header, esp_mail_str_26, false); + + std::string filename = inlineAttach->descr.filename; + + size_t found = filename.find_last_of("/\\"); + + if (found != std::string::npos) + filename = filename.substr(found + 1); + + header += filename; + appendP(header, esp_mail_str_36, false); + + appendP(header, esp_mail_str_299, false); + header += filename; + appendP(header, esp_mail_str_36, false); + + appendP(header, esp_mail_str_300, false); + header += filename; + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_301, false); + + header += inlineAttach->_int.cid; + + appendP(header, esp_mail_str_15, false); + + appendP(header, esp_mail_str_34, false); + + if (strlen(inlineAttach->descr.transfer_encoding) > 0) + { + appendP(header, esp_mail_str_272, false); + header += inlineAttach->descr.transfer_encoding; + appendP(header, esp_mail_str_34, false); + } + appendP(header, esp_mail_str_34, false); + + std::string().swap(filename); +} + +void ESP_Mail_Client::getAttachHeader(std::string &header, const std::string &boundary, SMTP_Attachment *attach) +{ + appendP(header, esp_mail_str_33, false); + header += boundary; + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_25, false); + + if (strlen(attach->descr.mime) == 0) + { + std::string mime; + mimeFromFile(attach->descr.filename, mime); + if (mime.length() > 0) + header += mime; + else + appendP(header, esp_mail_str_32, false); + } + else + header += attach->descr.mime; + + appendP(header, esp_mail_str_26, false); + + std::string filename = attach->descr.filename; + + size_t found = filename.find_last_of("/\\"); + if (found != std::string::npos) + filename = filename.substr(found + 1); + + header += filename; + appendP(header, esp_mail_str_36, false); + + if (!attach->_int.parallel) + { + appendP(header, esp_mail_str_30, false); + header += filename; + appendP(header, esp_mail_str_36, false); + } + + if (strlen(attach->descr.transfer_encoding) > 0) + { + appendP(header, esp_mail_str_272, false); + header += attach->descr.transfer_encoding; + appendP(header, esp_mail_str_34, false); + } + + appendP(header, esp_mail_str_34, false); + + std::string().swap(filename); +} + +void ESP_Mail_Client::getRFC822PartHeader(SMTPSession *smtp, std::string &header, const std::string &boundary) +{ + appendP(header, esp_mail_str_33, false); + header += boundary; + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_25, false); + + appendP(header, esp_mail_str_123, false); + appendP(header, esp_mail_str_34, false); + + appendP(header, esp_mail_str_98, false); + + appendP(header, esp_mail_str_34, false); +} + +void ESP_Mail_Client::smtpCBP(SMTPSession *smtp, PGM_P info, bool success) +{ + std::string s; + appendP(s, info, true); + smtp->_cbData._info = s; + smtp->_cbData._success = success; + smtp->_sendCallback(smtp->_cbData); + std::string().swap(s); +} + +void ESP_Mail_Client::smtpCB(SMTPSession *smtp, const char *info, bool success) +{ + smtp->_cbData._info = info; + smtp->_cbData._success = success; + smtp->_sendCallback(smtp->_cbData); +} + +void ESP_Mail_Client::imapCBP(IMAPSession *imap, PGM_P info, bool success) +{ + char *tmp = strP(info); + imap->_cbData._info = tmp; + imap->_cbData._success = success; + imap->_readCallback(imap->_cbData); + delS(tmp); +} + +void ESP_Mail_Client::imapCB(IMAPSession *imap, const char *info, bool success) +{ + imap->_cbData._info = info; + imap->_cbData._success = success; + imap->_readCallback(imap->_cbData); +} + +void ESP_Mail_Client::strcat_c(char *str, char c) +{ + for (; *str; str++) + ; + *str++ = c; + *str++ = 0; +} +int ESP_Mail_Client::strpos(const char *haystack, const char *needle, int offset) +{ + size_t len = strlen(haystack); + size_t len2 = strlen(needle); + if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len || offset < 0) + return -1; + char *_haystack = newS(len - offset + 1); + _haystack[len - offset] = 0; + strncpy(_haystack, haystack + offset, len - offset); + char *p = stristr(_haystack, needle); + int r = -1; + if (p) + r = p - _haystack + offset; + delS(_haystack); + return r; +} + +char *ESP_Mail_Client::stristr(const char *str1, const char *str2) +{ + const char *p1 = str1; + const char *p2 = str2; + const char *r = *p2 == 0 ? str1 : 0; + + while (*p1 != 0 && *p2 != 0) + { + if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) + { + if (r == 0) + r = p1; + p2++; + } + else + { + p2 = str2; + if (r != 0) + p1 = r + 1; + + if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) + { + r = p1; + p2++; + } + else + r = 0; + } + + p1++; + } + + return *p2 == 0 ? (char *)r : 0; +} + +char *ESP_Mail_Client::rstrstr(const char *haystack, const char *needle) +{ + size_t needle_length = strlen(needle); + const char *haystack_end = haystack + strlen(haystack) - needle_length; + const char *p; + size_t i; + for (p = haystack_end; p >= haystack; --p) + { + for (i = 0; i < needle_length; ++i) + { + if (p[i] != needle[i]) + goto next; + } + return (char *)p; + next:; + } + return 0; +} + +int ESP_Mail_Client::rstrpos(const char *haystack, const char *needle, int offset) +{ + size_t len = strlen(haystack); + size_t len2 = strlen(needle); + if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len) + return -1; + char *_haystack = newS(len - offset + 1); + _haystack[len - offset] = 0; + strncpy(_haystack, haystack + offset, len - offset); + char *p = rstrstr(_haystack, needle); + int r = -1; + if (p) + r = p - _haystack + offset; + delS(_haystack); + return r; +} + +int ESP_Mail_Client::readLine(WiFiClient *stream, char *buf, int bufLen, bool crlf, int &count) +{ + int ret = -1; + char c = 0; + char _c = 0; + int idx = 0; + if (!stream) + return idx; + while (stream->available() && idx < bufLen) + { + ret = stream->read(); + if (ret > -1) + { + if (idx >= bufLen - 1) + return idx; + + c = (char)ret; + strcat_c(buf, c); + idx++; + count++; + if (_c == '\r' && c == '\n') + { + if (!crlf) + { + buf[idx - 2] = 0; + idx -= 2; + } + return idx; + } + _c = c; + } + if (!stream) + return idx; + } + return idx; +} + +#if defined(ESP32) +int ESP_Mail_Client::_readLine(ESP_Mail_WCS32 *stream, char *buf, int bufLen, bool crlf, int &count) +#elif defined(ESP8266) +int ESP_Mail_Client::_readLine(ESP_Mail::ESP_Mail_WCS *stream, char *buf, int bufLen, bool crlf, int &count) +#endif +{ + int ret = -1; + char c = 0; + char _c = 0; + int idx = 0; + if (!stream) + return idx; + while (stream->_ns_available() && idx < bufLen) + { + ret = stream->_ns_read(); + if (ret > -1) + { + if (idx >= bufLen - 1) + return idx; + + c = (char)ret; + strcat_c(buf, c); + idx++; + count++; + if (_c == '\r' && c == '\n') + { + if (!crlf) + { + buf[idx - 2] = 0; + idx -= 2; + } + return idx; + } + _c = c; + } + if (!stream) + return idx; + } + return idx; +} + +int ESP_Mail_Client::getMSGNUM(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, bool &endSearch, int &nump, const char *key, const char *pc) +{ + int ret = -1; + char c = 0; + int idx = 0; + int num = 0; + while (available(imap) > 0 && idx < bufLen) + { + delay(0); + if (!imap->_secure) + ret = imap->httpClient._stream()->read(); + else + ret = imap->httpClient.stream()->read(); + + if (ret > -1) + { + + if (idx >= bufLen - 1) + return idx; + + c = (char)ret; + + if (c == '\n') + c = ' '; + + strcat_c(buf, c); + idx++; + + if (chunkIdx == 0) + { + if (strcmp(buf, key) == 0) + { + chunkIdx++; + return 0; + } + + if (strposP(buf, esp_mail_imap_response_1, 0) > -1) + goto end_search; + } + else + { + if (c == ' ') + { + imap->_mbif._searchCount++; + if (imap->_config->enable.recent_sort) + { + imap->_msgNum.push_back(atoi(buf)); + if (imap->_msgNum.size() > imap->_config->limit.search) + imap->_msgNum.erase(imap->_msgNum.begin()); + } + else + { + if (imap->_msgNum.size() < imap->_config->limit.search) + imap->_msgNum.push_back(atoi(buf)); + } + + if (imap->_debug) + { + num = (float)(100.0f * imap->_mbif._searchCount / imap->_mbif._msgCount); + if (nump != num) + { + nump = num; + searchReport(num, pc); + } + } + + chunkIdx++; + return idx; + } + else if (c == '$') + { + if (imap->_config->enable.recent_sort) + std::sort(imap->_msgNum.begin(), imap->_msgNum.end(), compFunc); + + goto end_search; + } + } + } + } + + return idx; + +end_search: + + endSearch = true; + int read = available(imap); + + if (!imap->_secure) + idx = imap->httpClient._stream()->readBytes(buf + idx, read); + else + idx = imap->httpClient.stream()->readBytes(buf + idx, read); + + return idx; +} + +struct esp_mail_message_part_info_t *ESP_Mail_Client::cPart(IMAPSession *imap) +{ + return &cHeader(imap)->part_headers[imap->_cPartIdx]; +} + +struct esp_mail_message_header_t *ESP_Mail_Client::cHeader(IMAPSession *imap) +{ + return &imap->_headers[cIdx(imap)]; +} + +void ESP_Mail_Client::handleHeader(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, struct esp_mail_message_header_t &header, int &headerState, int &octetCount) +{ + + char *tmp = nullptr; + if (chunkIdx == 0) + { + if (strposP(buf, esp_mail_str_324, 0) != -1 && buf[0] == '*') + chunkIdx++; + + tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); + if (tmp) + { + octetCount = 2; + header.header_data_len = atoi(tmp); + delS(tmp); + } + } + else + { + if (octetCount > header.header_data_len + 2) + return; + + if (strcmpP(buf, 0, esp_mail_str_10)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_from; + tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1); + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + else if (strcmpP(buf, 0, esp_mail_str_11)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_to; + tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1); + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + else if (strcmpP(buf, 0, esp_mail_str_276)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_cc; + tmp = subStr(buf, esp_mail_str_276, NULL, 0, -1); + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + else if (strcmpP(buf, 0, esp_mail_str_279)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_subject; + tmp = subStr(buf, esp_mail_str_279, NULL, 0, -1); + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + else if (strcmpP(buf, 0, esp_mail_str_25)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type; + tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); + if (tmp) + { + setHeader(imap, buf, header, headerState); + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_172)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding; + tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1); + if (tmp) + { + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_190)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_accept_language; + tmp = subStr(buf, esp_mail_str_190, NULL, 0, -1); + if (tmp) + { + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_191)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_language; + tmp = subStr(buf, esp_mail_str_191, NULL, 0, -1); + if (tmp) + { + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_273)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_date; + tmp = subStr(buf, esp_mail_str_273, NULL, 0, -1); + if (tmp) + { + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_274)) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_msg_id; + tmp = subStr(buf, esp_mail_str_274, NULL, 0, -1); + if (tmp) + { + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + chunkIdx++; + } +} + +void ESP_Mail_Client::setHeader(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state) +{ + switch (state) + { + case esp_mail_imap_header_state::esp_mail_imap_state_from: + header.from += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_to: + header.to += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_cc: + header.cc += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_subject: + header.subject += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_content_type: + header.content_type += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding: + header.content_transfer_encoding += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_accept_language: + header.accept_language += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_content_language: + header.content_language += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_date: + header.date += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_msg_id: + header.message_id += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_char_set: + header.char_set += buf; + break; + case esp_mail_imap_header_state::esp_mail_imap_state_boundary: + header.boundary += buf; + break; + default: + break; + } +} + +void ESP_Mail_Client::handlePartHeader(IMAPSession *imap, char *buf, int &chunkIdx, struct esp_mail_message_part_info_t &part) +{ + char *tmp = nullptr; + if (chunkIdx == 0) + { + tmp = subStr(buf, esp_mail_imap_response_7, NULL, 0, -1); + if (tmp) + { + delS(tmp); + tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); + if (tmp) + { + chunkIdx++; + part.octetLen = atoi(tmp); + delS(tmp); + } + } + } + else + { + if (strcmpP(buf, 0, esp_mail_str_25)) + { + tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); + bool con_type = false; + if (tmp) + { + con_type = true; + part.content_type = tmp; + delS(tmp); + int p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; + part.multipart = true; + //inline or embedded images + if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; + //multiple text formats e.g. plain, html, enriched + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; + //medias + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; + //rfc822 encapsulated + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; + //others can be attachments + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1) + part.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; + } + + p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; + if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1) + part.message_sub_type = esp_mail_imap_message_sub_type_rfc822; + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1) + part.message_sub_type = esp_mail_imap_message_sub_type_partial; + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1) + part.message_sub_type = esp_mail_imap_message_sub_type_external_body; + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1) + part.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; + } + + p1 = strpos(part.content_type.c_str(), esp_mail_imap_descrete_media_type_t::text, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_descrete_media_type_t::text) + 1; + if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::plain, p1) != -1) + part.msg_type = esp_mail_msg_type_plain; + else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::enriched, p1) != -1) + part.msg_type = esp_mail_msg_type_enriched; + else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::html, p1) != -1) + part.msg_type = esp_mail_msg_type_html; + else + part.msg_type = esp_mail_msg_type_plain; + } + } + + if (con_type) + { + if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched) + { + tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0); + if (tmp) + { + part.charset = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); + if (tmp) + { + part.charset = tmp; + delS(tmp); + } + } + + if (strposP(buf, esp_mail_str_275, 0) > -1 || strposP(buf, esp_mail_str_270, 0) > -1) + part.plain_flowed = true; + if (strposP(buf, esp_mail_str_259, 0) > -1 || strposP(buf, esp_mail_str_257, 0) > -1) + part.plain_delsp = true; + } + + if (part.charset.length() == 0) + { + tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0); + if (tmp) + { + part.charset = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); + if (tmp) + { + part.charset = tmp; + delS(tmp); + } + } + } + + tmp = subStr(buf, esp_mail_str_170, esp_mail_str_136, 0); + if (tmp) + { + part.name = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_171, NULL, 0, -1); + if (tmp) + { + part.name = tmp; + delS(tmp); + } + } + } + } + else if (strcmpP(buf, 0, esp_mail_str_172)) + { + tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1); + if (tmp) + { + part.content_transfer_encoding = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_174)) + { + tmp = subStr(buf, esp_mail_str_174, NULL, 0, -1); + if (tmp) + { + part.descr = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_175)) + { + tmp = subStr(buf, esp_mail_str_175, esp_mail_str_97, 0); + if (tmp) + { + //don't count altenative part text and html as embedded contents + if (cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) + { + part.content_disposition = tmp; + if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::attachment) == 0) + part.attach_type = esp_mail_att_type_attachment; + else if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::inline_) == 0) + part.attach_type = esp_mail_att_type_inline; + } + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_150)) + { + tmp = subStr(buf, esp_mail_str_150, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.sender = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_10)) + { + tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.from = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_11)) + { + tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.to = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_12)) + { + tmp = subStr(buf, esp_mail_str_12, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.cc = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_184)) + { + tmp = subStr(buf, esp_mail_str_184, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.reply_to = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_134)) + { + tmp = subStr(buf, esp_mail_str_134, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.comment = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_24)) + { + tmp = subStr(buf, esp_mail_str_24, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.subject = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_189)) + { + tmp = subStr(buf, esp_mail_str_189, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.messageID = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_46)) + { + tmp = subStr(buf, esp_mail_str_46, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.return_path = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_99)) + { + tmp = subStr(buf, esp_mail_str_99, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.date = tmp; + delS(tmp); + } + } + else if (strcmpP(buf, 0, esp_mail_str_145)) + { + tmp = subStr(buf, esp_mail_str_145, NULL, 0, -1); + if (tmp) + { + part.rfc822_header.keyword = tmp; + delS(tmp); + } + } + + if (part.content_disposition.length() > 0) + { + tmp = subStr(buf, esp_mail_str_176, esp_mail_str_136, 0); + if (tmp) + { + part.filename = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_177, NULL, 0, -1); + if (tmp) + { + part.filename = tmp; + delS(tmp); + } + } + + tmp = subStr(buf, esp_mail_str_178, esp_mail_str_97, 0); + if (tmp) + { + part.attach_data_size = atoi(tmp); + delS(tmp); + cHeader(imap)->total_attach_data_size += part.attach_data_size; + part.sizeProp = true; + } + else + { + tmp = subStr(buf, esp_mail_str_178, NULL, 0, -1); + if (tmp) + { + part.attach_data_size = atoi(tmp); + delS(tmp); + cHeader(imap)->total_attach_data_size += part.attach_data_size; + part.sizeProp = true; + } + } + + tmp = subStr(buf, esp_mail_str_179, esp_mail_str_136, 0); + if (tmp) + { + part.creation_date = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_180, NULL, 0, -1); + if (tmp) + { + part.creation_date = tmp; + delS(tmp); + } + } + + tmp = subStr(buf, esp_mail_str_181, esp_mail_str_136, 0); + if (tmp) + { + part.modification_date = tmp; + delS(tmp); + } + else + { + tmp = subStr(buf, esp_mail_str_182, NULL, 0, -1); + if (tmp) + { + part.modification_date = tmp; + delS(tmp); + } + } + } + + chunkIdx++; + } +} + +char *ESP_Mail_Client::subStr(const char *buf, PGM_P beginH, PGM_P endH, int beginPos, int endPos) +{ + + char *tmp = nullptr; + int p1 = strposP(buf, beginH, beginPos); + if (p1 != -1) + { + int p2 = -1; + if (endPos == 0) + p2 = strposP(buf, endH, p1 + strlen_P(beginH)); + + if (p2 == -1) + p2 = strlen(buf); + + int len = p2 - p1 - strlen_P(beginH); + tmp = newS(len + 1); + memcpy(tmp, &buf[p1 + strlen_P(beginH)], len); + return tmp; + } + + return nullptr; +} + +void ESP_Mail_Client::handleAuth(SMTPSession *smtp, char *buf) +{ + if (strposP(buf, esp_mail_smtp_response_1, 0) > -1) + { + if (strposP(buf, esp_mail_smtp_response_2, 0) > -1) + smtp->_auth_capability.login = true; + if (strposP(buf, esp_mail_smtp_response_3, 0) > -1) + smtp->_auth_capability.plain = true; + if (strposP(buf, esp_mail_smtp_response_4, 0) > -1) + smtp->_auth_capability.xoauth2 = true; + if (strposP(buf, esp_mail_smtp_response_11, 0) > -1) + smtp->_auth_capability.cram_md5 = true; + if (strposP(buf, esp_mail_smtp_response_12, 0) > -1) + smtp->_auth_capability.digest_md5 = true; + } + else if (strposP(buf, esp_mail_smtp_response_5, 0) > -1) + smtp->_auth_capability.start_tls = true; + else if (strposP(buf, esp_mail_smtp_response_6, 0) > -1) + smtp->_send_capability._8bitMIME = true; + else if (strposP(buf, esp_mail_smtp_response_7, 0) > -1) + smtp->_send_capability.binaryMIME = true; + else if (strposP(buf, esp_mail_smtp_response_8, 0) > -1) + smtp->_send_capability.chunking = true; + else if (strposP(buf, esp_mail_smtp_response_9, 0) > -1) + smtp->_send_capability.utf8 = true; + else if (strposP(buf, esp_mail_smtp_response_10, 0) > -1) + smtp->_send_capability.pipelining = true; + else if (strposP(buf, esp_mail_smtp_response_13, 0) > -1) + smtp->_send_capability.dsn = true; +} + +int ESP_Mail_Client::available(SMTPSession *smtp) +{ + int sz = 0; + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + { + if (smtp->httpClient._stream()) + sz = smtp->httpClient._stream()->_ns_available(); + } + else + { + if (smtp->httpClient.stream()) + sz = smtp->httpClient.stream()->available(); + } + + return sz; +} + +bool ESP_Mail_Client::handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_status_code respCode, int errCode) +{ + if (!reconnect(smtp)) + return false; + + bool ret = false; + char *response = nullptr; + int readLen = 0; + long dataTime = millis(); + int chunkBufSize = 0; + std::string s, r; + int chunkIndex = 0; + int count = 0; + bool completedResponse = false; + smtp->_smtpStatus.statusCode = 0; + smtp->_smtpStatus.respCode = 0; + smtp->_smtpStatus.text.clear(); + uint8_t minResLen = 5; + struct esp_mail_smtp_response_status_t status; + + chunkBufSize = available(smtp); + + while (smtp->_tcpConnected && chunkBufSize <= 0) + { + if (!reconnect(smtp, dataTime)) + return false; + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return false; + } + chunkBufSize = available(smtp); + delay(0); + } + + dataTime = millis(); + + if (chunkBufSize > 1) + { + while (!completedResponse) + { + delay(0); + + if (!reconnect(smtp, dataTime)) + return false; + + if (!connected(smtp)) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return false; + } + + chunkBufSize = available(smtp); + + if (chunkBufSize <= 0) + break; + + if (chunkBufSize > 0) + { + chunkBufSize = 512; + response = newS(chunkBufSize + 1); + + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + readLen = _readLine(smtp->httpClient._stream(), response, chunkBufSize, false, count); + else + readLen = readLine(smtp->httpClient.stream(), response, chunkBufSize, false, count); + + if (readLen) + { + if (smtp->_smtp_cmd != esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state) + { + //sometimes server sent multiple lines response + //sometimes rx buffer may not ready for a while + if (strlen(response) < minResLen) + { + r += response; + chunkBufSize = 0; + while (chunkBufSize == 0) + { + delay(0); + if (!reconnect(smtp, dataTime)) + return false; + chunkBufSize = available(smtp); + } + } + else + { + if (r.length() > 0) + { + r += response; + memset(response, 0, chunkBufSize); + strcpy(response, r.c_str()); + } + + if (smtp->_debugLevel > esp_mail_debug_level_1) + esp_mail_debug((const char *)response); + } + + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_greeting) + handleAuth(smtp, response); + } + + getResponseStatus(response, respCode, 0, status); + + //get the status code again for unexpected return code + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls || status.respCode == 0) + getResponseStatus(response, esp_mail_smtp_status_code_0, 0, status); + + ret = respCode == status.respCode; + smtp->_smtpStatus = status; + + if (status.respCode > 0 && (status.respCode < 400 || status.respCode == respCode)) + ret = true; + + if (smtp->_debug && strlen(response) >= minResLen) + { + appendP(s, esp_mail_str_260, true); + if (smtp->_smtpStatus.respCode != esp_mail_smtp_status_code_334) + s += response; + else + { + //base64 response + size_t olen; + char *decoded = (char *)decodeBase64((const unsigned char *)status.text.c_str(), status.text.length(), &olen); + if (decoded && olen > 0) + { + olen += s.length(); + s += decoded; + s[olen] = 0; + delete[] decoded; + } + } + esp_mail_debug(s.c_str()); + r.clear(); + } + + completedResponse = smtp->_smtpStatus.respCode > 0 && status.text.length() > minResLen; + + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_auth && smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_334) + { + if (authFailed(response, readLen, chunkIndex, 4)) + { + smtp->_smtpStatus.statusCode = -1; + ret = false; + } + } + + chunkIndex++; + + if (smtp->_chunkedEnable && smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_chunk_termination) + completedResponse = smtp->_chunkCount == chunkIndex; + } + delS(response); + } + } + + if (!ret) + handleSMTPError(smtp, errCode, false); + } + + return ret; +} + +void ESP_Mail_Client::getResponseStatus(const char *buf, esp_mail_smtp_status_code respCode, int beginPos, struct esp_mail_smtp_response_status_t &status) +{ + std::string s; + char *tmp = nullptr; + int p1 = 0; + if (respCode > esp_mail_smtp_status_code_0) + { + tmp = intStr((int)respCode); + s = tmp; + appendP(s, esp_mail_str_131, false); + delS(tmp); + p1 = strpos(buf, (const char *)s.c_str(), beginPos); + } + + if (p1 != -1) + { + int ofs = s.length() - 2; + if (ofs < 0) + ofs = 1; + + int p2 = strposP(buf, esp_mail_str_131, p1 + ofs); + + if (p2 < 4 && p2 > -1) + { + tmp = newS(p2 + 1); + memcpy(tmp, &buf[p1], p2); + status.respCode = atoi(tmp); + delS(tmp); + + p1 = p2 + 1; + p2 = strlen(buf); + if (p2 > p1) + { + tmp = newS(p2 + 1); + memcpy(tmp, &buf[p1], p2 - p1); + status.text = tmp; + delS(tmp); + } + } + } +} + +void ESP_Mail_Client::closeTCP(SMTPSession *smtp) +{ + + if (smtp->_tcpConnected) + { + if (smtp->httpClient.stream()) + { + if (connected(smtp)) + { + if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) + smtp->httpClient._stream()->stop(); + else + smtp->httpClient.stream()->stop(); + } + } + _lastReconnectMillis = millis(); + } + smtp->_tcpConnected = false; +} + +void ESP_Mail_Client::closeTCP(IMAPSession *imap) +{ + + if (imap->_tcpConnected) + { + if (imap->httpClient.stream()) + { + if (connected(imap)) + { + if (!imap->_secure) + imap->httpClient._stream()->stop(); + else + imap->httpClient.stream()->stop(); + } + } + _lastReconnectMillis = millis(); + } + imap->_tcpConnected = false; +} + +#if defined(ESP32) +void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient32 &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert) +#elif defined(ESP8266) +void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert) +#endif +{ + +#if defined(ESP32) + if (httpClient._certType == -1) + { + if (strlen(session->certificate.cert_file) == 0) + { + if (caCert != nullptr) + httpClient.setCACert(caCert.get()); + else + httpClient.setCACert(nullptr); + } + else + { + httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type); + } + } +#elif defined(ESP8266) + + if (httpClient._certType == -1) + { + +#ifndef USING_AXTLS + if (!MailClient._clockReady && (strlen(session->certificate.cert_file) > 0 || caCert != nullptr)) + { + MailClient.setClock(MailClient._gmtOffset); + httpClient._clockReady = MailClient._clockReady; + } +#endif + if (strlen(session->certificate.cert_file) == 0) + { + if (caCert != nullptr) + httpClient.setCACert(caCert.get()); + else + httpClient.setCACert(nullptr); + } + else + { + httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type, MailClient._sdPin); + } + } +#endif +} + +bool ESP_Mail_Client::reconnect(SMTPSession *smtp, unsigned long dataTime) +{ + + bool status = WiFi.status() == WL_CONNECTED; + + if (dataTime > 0) + { + if (millis() - dataTime > smtp->httpClient.tcpTimeout) + { + closeTCP(smtp); + errorStatusCB(smtp, MAIL_CLIENT_ERROR_READ_TIMEOUT); + return false; + } + } + + if (!status) + { + if (smtp->_tcpConnected) + closeTCP(smtp); + + errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); + + if (millis() - _lastReconnectMillis > _reconnectTimeout && !smtp->_tcpConnected) + { +#if defined(ESP32) + esp_wifi_connect(); +#elif defined(ESP8266) + WiFi.reconnect(); +#endif + _lastReconnectMillis = millis(); + } + + status = WiFi.status() == WL_CONNECTED; + } + + return status; +} + +bool ESP_Mail_Client::reconnect(IMAPSession *imap, unsigned long dataTime, bool downloadRequest) +{ + + bool status = WiFi.status() == WL_CONNECTED; + + if (dataTime > 0) + { + if (millis() - dataTime > imap->httpClient.tcpTimeout) + { + + closeTCP(imap); + + if (imap->_headers.size() > 0) + { + if (downloadRequest) + { + errorStatusCB(imap, IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT); + if (cHeader(imap)->part_headers.size() > 0) + cPart(imap)->download_error = imap->errorReason().c_str(); + } + else + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_READ_TIMEOUT); + cHeader(imap)->error_msg = imap->errorReason().c_str(); + } + } + return false; + } + } + + if (!status) + { + + if (imap->_tcpConnected) + closeTCP(imap); + + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + + if (imap->_headers.size() > 0) + { + if (downloadRequest) + cPart(imap)->download_error = imap->errorReason().c_str(); + else + cHeader(imap)->error_msg = imap->errorReason().c_str(); + } + + if (millis() - _lastReconnectMillis > _reconnectTimeout && !imap->_tcpConnected) + { +#if defined(ESP32) + esp_wifi_connect(); +#elif defined(ESP8266) + WiFi.reconnect(); +#endif + _lastReconnectMillis = millis(); + } + + status = WiFi.status() == WL_CONNECTED; + } + + return status; +} + +void ESP_Mail_Client::delS(char *p) +{ + if (p != nullptr) + delete[] p; +} + +char *ESP_Mail_Client::newS(size_t len) +{ + char *p = new char[len]; + memset(p, 0, len); + return p; +} + +char *ESP_Mail_Client::newS(char *p, size_t len) +{ + delS(p); + p = newS(len); + return p; +} + +char *ESP_Mail_Client::newS(char *p, size_t len, char *d) +{ + delS(p); + p = newS(len); + strcpy(p, d); + return p; +} + +bool ESP_Mail_Client::strcmpP(const char *buf, int ofs, PGM_P beginH) +{ + char *tmp = nullptr; + if (ofs < 0) + { + int p = strposP(buf, beginH, 0); + if (p == -1) + return false; + ofs = p; + } + tmp = strP(beginH); + char *tmp2 = newS(strlen_P(beginH) + 1); + memcpy(tmp2, &buf[ofs], strlen_P(beginH)); + tmp2[strlen_P(beginH)] = 0; + bool ret = (strcasecmp(tmp, tmp2) == 0); + delS(tmp); + delS(tmp2); + return ret; +} + +int ESP_Mail_Client::strposP(const char *buf, PGM_P beginH, int ofs) +{ + char *tmp = strP(beginH); + int p = strpos(buf, tmp, ofs); + delS(tmp); + return p; +} + +char *ESP_Mail_Client::strP(PGM_P pgm) +{ + size_t len = strlen_P(pgm) + 1; + char *buf = newS(len); + strcpy_P(buf, pgm); + buf[len - 1] = 0; + return buf; +} + +void ESP_Mail_Client::appendP(std::string &buf, PGM_P p, bool empty) +{ + if (empty) + buf.clear(); + char *b = strP(p); + buf += b; + delS(b); +} + +char *ESP_Mail_Client::intStr(int value) +{ + char *buf = newS(36); + memset(buf, 0, 36); + itoa(value, buf, 10); + return buf; +} + +int ESP_Mail_Client::available(IMAPSession *imap) +{ + int sz = 0; + if (!imap->_secure) + { + if (imap->httpClient._stream()) + sz = imap->httpClient._stream()->_ns_available(); + } + else + { + if (imap->httpClient.stream()) + sz = imap->httpClient.stream()->available(); + } + return sz; +} + +bool ESP_Mail_Client::handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession) +{ + + if (!reconnect(imap)) + return false; + + esp_mail_imap_response_status imapResp = esp_mail_imap_response_status::esp_mail_imap_resp_unknown; + char *response = nullptr; + int readLen = 0; + long dataTime = millis(); + int chunkBufSize = available(imap); + int chunkIdx = 0; + std::string s; + bool completedResponse = false; + bool endSearch = false; + struct esp_mail_message_header_t header; + struct esp_mail_message_part_info_t part; + + std::string filePath = ""; + bool downloadRequest = false; + int reportState = 0; + int octetCount = 0; + int octetLength = 0; + int oCount = 0; + bool tmo = false; + int headerState = 0; + int scnt = 0; + int dcnt = -1; + char *skey = nullptr; + char *spc = nullptr; + char *lastBuf = nullptr; + char *tmp = nullptr; + bool crLF = imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text && strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31); + + while (imap->_tcpConnected && chunkBufSize <= 0) + { + if (!reconnect(imap, dataTime)) + return false; + if (!connected(imap)) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return false; + } + chunkBufSize = available(imap); + delay(0); + } + + dataTime = millis(); + + if (chunkBufSize > 1) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_examine) + { + imap->_mbif.clear(); + imap->_mbif._msgCount = 0; + imap->_nextUID = ""; + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_search) + { + imap->_mbif._searchCount = 0; + imap->_msgNum.clear(); + } + + chunkBufSize = 512; + response = newS(chunkBufSize + 1); + + if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) + { + skey = strP(esp_mail_imap_response_6); + spc = strP(esp_mail_str_92); + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + lastBuf = newS(BASE64_CHUNKED_LEN + 1); + + while (!completedResponse) + { + delay(0); + if (!reconnect(imap, dataTime) || !connected(imap)) + { + if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) + { + delS(skey); + delS(spc); + } + + if (!connected(imap)) + { + errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); + return false; + } + return false; + } + chunkBufSize = available(imap); + + if (chunkBufSize > 0) + { + chunkBufSize = 512; + + if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) + { + readLen = getMSGNUM(imap, response, chunkBufSize, chunkIdx, endSearch, scnt, skey, spc); + imap->_mbif._availableItems = imap->_msgNum.size(); + } + else + { + if (!imap->_secure) + readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, crLF, octetCount); + else + readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, crLF, octetCount); + } + + if (readLen) + { + + if (imap->_debugLevel > esp_mail_debug_level_1) + { + if (imap->_imap_cmd != esp_mail_imap_cmd_search && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_text && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_attachment && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_inline) + esp_mail_debug((const char *)response); + } + + if (imap->_imap_cmd != esp_mail_imap_cmd_search || (imap->_imap_cmd == esp_mail_imap_cmd_search && endSearch)) + imapResp = imapResponseStatus(imap, response); + + if (imapResp != esp_mail_imap_response_status::esp_mail_imap_resp_unknown) + { + if (imap->_debugLevel > esp_mail_debug_level_1) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + esp_mail_debug((const char *)response); + } + + //some IMAP servers advertise CAPABILITY in their responses + //try to read the next available response + memset(response, 0, chunkBufSize); + if (!imap->_secure) + readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, true, octetCount); + else + readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, true, octetCount); + if (readLen) + { + completedResponse = false; + imapResp = imapResponseStatus(imap, response); + if (imapResp > esp_mail_imap_response_status::esp_mail_imap_resp_unknown) + completedResponse = true; + } + else + completedResponse = true; + } + else + { + if (imap->_imap_cmd == esp_mail_imap_cmd_auth) + { + if (authFailed(response, readLen, chunkIdx, 2)) + completedResponse = true; + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_capability) + handleCapability(imap, response, chunkIdx); + else if (imap->_imap_cmd == esp_mail_imap_cmd_list) + handleFolders(imap, response); + else if (imap->_imap_cmd == esp_mail_imap_cmd_select || imap->_imap_cmd == esp_mail_imap_cmd_examine) + handleExamine(imap, response); + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) + { + char *tmp = intStr(cMSG(imap)); + header.message_uid = tmp; + delS(tmp); + + tmp = intStr(imap->_totalRead); + header.message_no = tmp; + delS(tmp); + + int _st = headerState; + handleHeader(imap, response, readLen, chunkIdx, header, headerState, octetCount); + if (_st == headerState && headerState > 0 && octetCount <= header.header_data_len) + setHeader(imap, response, header, headerState); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) + handlePartHeader(imap, response, chunkIdx, part); + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) + decodeText(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetLength, octetCount, dcnt); + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + { + + if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) + { + //multi-line chunked base64 string attachment handle + if (octetCount < octetLength && readLen < BASE64_CHUNKED_LEN) + { + if (strlen(lastBuf) > 0) + { + tmp = newS(readLen + strlen(lastBuf) + 2); + strcpy(tmp, lastBuf); + strcat(tmp, response); + readLen = strlen(tmp); + tmo = handleAttachment(imap, tmp, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); + delS(tmp); + memset(lastBuf, 0, BASE64_CHUNKED_LEN + 1); + if (!tmo) + break; + } + else if (readLen < BASE64_CHUNKED_LEN + 1) + strcpy(lastBuf, response); + } + else + { + tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); + if (!tmo) + break; + } + } + else + tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); + } + dataTime = millis(); + } + } + memset(response, 0, chunkBufSize); + } + } + delS(response); + if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) + { + if (imap->_debug && scnt > 0 && scnt < 100) + searchReport(100, spc); + delS(skey); + delS(spc); + } + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment) + delS(lastBuf); + } + + if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header && header.header_data_len == 0) || imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no) + { + if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no) + imap->_imapStatus.statusCode = IMAP_STATUS_IMAP_RESPONSE_FAILED; + else + imap->_imapStatus.statusCode = IMAP_STATUS_NO_MESSAGE; + + if (imap->_readCallback) + { + std::string s; + appendP(s, esp_mail_str_53, true); + s += imap->errorReason().c_str(); + imapCB(imap, s.c_str(), false); + } + + if (imap->_debug) + { + std::string s; + appendP(s, esp_mail_str_185, true); + s += imap->errorReason().c_str(); + esp_mail_debug_line(s.c_str(), true); + } + + return false; + } + + if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_ok) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) + { + char *buf = newS(header.content_type.length() + 1); + strcpy(buf, header.content_type.c_str()); + header.content_type.clear(); + + tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); + if (tmp) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type; + setHeader(imap, tmp, header, headerState); + delS(tmp); + + int p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; + header.multipart = true; + //inline or embedded images + if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; + //multiple text formats e.g. plain, html, enriched + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; + //medias + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; + //rfc822 encapsulated + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; + //others can be attachments + else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1) + header.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; + } + + p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; + if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1) + { + header.rfc822_part = true; + header.message_sub_type = esp_mail_imap_message_sub_type_rfc822; + } + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1) + header.message_sub_type = esp_mail_imap_message_sub_type_partial; + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1) + header.message_sub_type = esp_mail_imap_message_sub_type_external_body; + else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1) + header.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; + } + + tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); + if (tmp) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_char_set; + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + + if (header.multipart) + { + if (strcmpP(buf, 0, esp_mail_str_277)) + { + tmp = subStr(buf, esp_mail_str_277, esp_mail_str_136, 0); + if (tmp) + { + headerState = esp_mail_imap_header_state::esp_mail_imap_state_boundary; + setHeader(imap, tmp, header, headerState); + delS(tmp); + } + } + } + } + + delS(buf); + + decodeHeader(header.from, header.from_charset); + decodeHeader(header.to, header.to_charset); + decodeHeader(header.cc, header.cc_charset); + decodeHeader(header.subject, header.subject_charset); + + imap->_headers.push_back(header); + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) + { + //expect the octet length in the response for the existent part + if (part.octetLen > 0) + { + + part.partNumStr = cHeader(imap)->partNumStr; + part.partNumFetchStr = cHeader(imap)->partNumStr; + if (cHeader(imap)->part_headers.size() > 0) + { + + esp_mail_message_part_info_t *_part = &cHeader(imap)->part_headers[cHeader(imap)->part_headers.size() - 1]; + bool rfc822_body_subtype = _part->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + + if (rfc822_body_subtype) + { + if (!_part->rfc822_part) + { + //additional rfc822 message header, store it to the rfc822 part header + _part->rfc822_part = true; + _part->rfc822_header = part.rfc822_header; + imap->_rfc822_part_count++; + _part->rfc822_msg_Idx = imap->_rfc822_part_count; + } + } + } + + cHeader(imap)->part_headers.push_back(part); + cHeader(imap)->message_data_count = cHeader(imap)->part_headers.size(); + + if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched || part.msg_type == esp_mail_msg_type_html || part.attach_type == esp_mail_att_type_none || (part.attach_type == esp_mail_att_type_attachment && imap->_config->download.attachment) || (part.attach_type == esp_mail_att_type_inline && imap->_config->download.inlineImg)) + { + if (part.message_sub_type != esp_mail_imap_message_sub_type_rfc822) + { + if (part.attach_type != esp_mail_att_type_none && cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) + cHeader(imap)->attachment_count++; + } + } + } + else + { + //nonexistent part + //return false to exit the loop without closing the connection + if (closeSession) + imap->closeSession(); + return false; + } + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + { + if (cPart(imap)->file_open_write) + file.close(); + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) + cPart(imap)->text[cPart(imap)->textLen] = 0; + } + else + { + //some server responses NO and should exit (false) from MIME feching loop without + //closing the session + if (imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime) + return handleIMAPError(imap, errCode, false); + + if (closeSession) + imap->closeSession(); + return false; + } + + return true; +} + +void ESP_Mail_Client::saveHeader(IMAPSession *imap) +{ + + std::string headerFilePath; + prepareFilePath(imap, headerFilePath, true); + if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk) + _sdOk = sdTest(); + else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk) +#if defined(ESP32) + _flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + _flashOk = FLASH_FS.begin(); +#endif + + if (_sdOk || _flashOk) + { + if (file) + file.close(); + + if (imap->_storageType == esp_mail_file_storage_type_sd) + file = SD.open(headerFilePath.c_str(), FILE_WRITE); + else if (imap->_storageType == esp_mail_file_storage_type_flash) +#if defined(ESP32) + file = SPIFFS.open(headerFilePath.c_str(), FILE_WRITE); +#elif defined(ESP8266) + file = FLASH_FS.open(headerFilePath.c_str(), "w"); +#endif + + if (file) + { + std::string s; + appendP(s, esp_mail_str_99, true); + file.print(s.c_str()); + file.println(cHeader(imap)->date.c_str()); + + appendP(s, esp_mail_str_100, true); + file.print(s.c_str()); + if (imap->_uidSearch) + file.println(cMSG(imap)); + else + file.println(); + + appendP(s, esp_mail_str_101, true); + file.print(s.c_str()); + file.println(cMSG(imap)); + + appendP(s, esp_mail_str_102, true); + file.print(s.c_str()); + file.println(cHeader(imap)->accept_language.c_str()); + + appendP(s, esp_mail_str_103, true); + file.print(s.c_str()); + file.println(cHeader(imap)->content_language.c_str()); + + appendP(s, esp_mail_str_10, true); + file.print(s.c_str()); + file.println(cHeader(imap)->from.c_str()); + + appendP(s, esp_mail_str_105, true); + file.print(s.c_str()); + file.println(cHeader(imap)->from_charset.c_str()); + + appendP(s, esp_mail_str_11, true); + file.print(s.c_str()); + file.println(cHeader(imap)->to.c_str()); + + appendP(s, esp_mail_str_107, true); + file.print(s.c_str()); + file.println(cHeader(imap)->to_charset.c_str()); + + appendP(s, esp_mail_str_108, true); + file.print(s.c_str()); + file.println(cHeader(imap)->cc.c_str()); + + appendP(s, esp_mail_str_109, true); + file.print(s.c_str()); + file.println(cHeader(imap)->cc_charset.c_str()); + + appendP(s, esp_mail_str_24, true); + file.print(s.c_str()); + file.println(cHeader(imap)->subject.c_str()); + + appendP(s, esp_mail_str_111, true); + file.print(s.c_str()); + file.println(cHeader(imap)->subject_charset.c_str()); + + appendP(s, esp_mail_str_112, true); + file.print(s.c_str()); + file.println(cPart(imap)->charset.c_str()); + + if (cHeader(imap)->attachment_count > 0) + { + + appendP(s, esp_mail_str_113, true); + file.print(s.c_str()); + file.println(cHeader(imap)->attachment_count); + + for (int j = 0; j < cHeader(imap)->attachment_count; j++) + { + if (imap->_headers[cIdx(imap)].part_headers[j].attach_type == esp_mail_att_type_none || imap->_headers[cIdx(imap)].part_headers[j].rfc822_part) + continue; + struct esp_mail_attacment_info_t att; + att.filename = imap->_headers[cIdx(imap)].part_headers[j].filename.c_str(); + att.mime = imap->_headers[cIdx(imap)].part_headers[j].content_type.c_str(); + att.name = imap->_headers[cIdx(imap)].part_headers[j].name.c_str(); + att.size = imap->_headers[cIdx(imap)].part_headers[j].attach_data_size; + att.creationDate = imap->_headers[cIdx(imap)].part_headers[j].creation_date.c_str(); + att.type = imap->_headers[cIdx(imap)].part_headers[j].attach_type; + + appendP(s, esp_mail_str_114, true); + file.print(s.c_str()); + file.println(j + 1); + + appendP(s, esp_mail_str_115, true); + file.print(s.c_str()); + file.println(att.filename); + + appendP(s, esp_mail_str_116, true); + file.print(s.c_str()); + file.println(att.name); + + appendP(s, esp_mail_str_117, true); + file.print(s.c_str()); + file.println(att.size); + + appendP(s, esp_mail_str_118, true); + file.print(s.c_str()); + file.println(att.mime); + + appendP(s, esp_mail_str_119, true); + file.print(s.c_str()); + file.println(att.creationDate); + } + } + + file.close(); + } + imap->_headerSaved = true; + } +} + +esp_mail_imap_response_status ESP_Mail_Client::imapResponseStatus(IMAPSession *imap, char *response) +{ + imap->_imapStatus.text.clear(); + if (strposP(response, esp_mail_imap_response_1, 0) > -1) + return esp_mail_imap_response_status::esp_mail_imap_resp_ok; + else if (strposP(response, esp_mail_imap_response_2, 0) > -1) + { + imap->_imapStatus.text = response; + imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_2)); + return esp_mail_imap_response_status::esp_mail_imap_resp_no; + } + else if (strposP(response, esp_mail_imap_response_3, 0) > -1) + { + imap->_imapStatus.text = response; + imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_3)); + return esp_mail_imap_response_status::esp_mail_imap_resp_bad; + } + return esp_mail_imap_response_status::esp_mail_imap_resp_unknown; +} + +void ESP_Mail_Client::decodeHeader(std::string &headerField, std::string &headerEnc) +{ + + size_t p1 = 0, p2 = 0; + + while (headerField[p1] == ' ' && p1 < headerField.length() - 1) + p1++; + + if (headerField[p1] == '=' && headerField[p1 + 1] == '?') + { + p2 = headerField.find("?", p1 + 2); + if (p2 != std::string::npos) + headerEnc = headerField.substr(p1 + 2, p2 - p1 - 2); + } + + int bufSize = 512; + char *buf = newS(bufSize); + + RFC2047Decoder.rfc2047Decode(buf, headerField.c_str(), bufSize); + + if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_iso8859_1) + { + int len = strlen(buf); + int olen = (len + 1) * 2; + unsigned char *out = (unsigned char *)newS(olen); + decodeLatin1_UTF8(out, &olen, (unsigned char *)buf, &len); + delS(buf); + buf = (char *)out; + } + else if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_tis620) + { + size_t len2 = strlen(buf); + char *tmp = newS((len2 + 1) * 3); + decodeTIS620_UTF8(tmp, buf, len2); + delS(buf); + buf = tmp; + } + + headerField = buf; + delS(buf); +} + +esp_mail_char_decoding_scheme ESP_Mail_Client::getEncodingFromCharset(const char *enc) +{ + esp_mail_char_decoding_scheme scheme = esp_mail_char_decoding_scheme_default; + + if (strposP(enc, esp_mail_str_237, 0) > -1 || strposP(enc, esp_mail_str_231, 0) > -1 || strposP(enc, esp_mail_str_226, 0) > -1) + scheme = esp_mail_char_decoding_scheme_tis620; + else if (strposP(enc, esp_mail_str_227, 0) > -1) + scheme = esp_mail_char_decoding_scheme_iso8859_1; + + return scheme; +} + +bool ESP_Mail_Client::handleAttachment(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetCount, int &octetLength, int &oCount, int &reportState, int &downloadCount) +{ + if (chunkIdx == 0) + { + char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); + if (tmp) + { + octetCount = 2; //CRLF counted from first line + octetLength = atoi(tmp); + delS(tmp); + chunkIdx++; + cHeader(imap)->total_download_size += octetLength; + } + return true; + } + + if (octetLength == 0) + return true; + + chunkIdx++; + + delay(0); + + if (!cPart(imap)->file_open_write) + { + + cPart(imap)->file_open_write = true; + + if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk) + _sdOk = sdTest(); + else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk) +#if defined(ESP32) + _flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + _flashOk = FLASH_FS.begin(); +#endif + + if (_sdOk || _flashOk) + { + + downloadRequest = true; + + filePath.clear(); + filePath += imap->_config->storage.saved_path; + appendP(filePath, esp_mail_str_202, false); + + char *tmp = intStr(cMSG(imap)); + filePath += tmp; + delS(tmp); + + if (imap->_storageType == esp_mail_file_storage_type_sd) + if (!SD.exists(filePath.c_str())) + createDirs(filePath); + + appendP(filePath, esp_mail_str_202, false); + + filePath += cPart(imap)->filename; + + if (imap->_storageType == esp_mail_file_storage_type_sd) + file = SD.open(filePath.c_str(), FILE_WRITE); + else if (imap->_storageType == esp_mail_file_storage_type_flash) +#if defined(ESP32) + file = SPIFFS.open(filePath.c_str(), FILE_WRITE); +#elif defined(ESP8266) + file = FLASH_FS.open(filePath.c_str(), "w"); +#endif + } + } + + if (_sdOk || _flashOk) + { + int nOctet = oCount + bufLen + 2; + if (nOctet > octetLength) + { + if (imap->_readCallback) + downloadReport(imap, 100); + + if (oCount < octetLength) + { + int dLen = nOctet - 2 - octetLength; + bufLen -= dLen; + buf[bufLen] = 0; + } + else + return true; + } + + oCount += bufLen + 2; + + if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) + { + + size_t olen = 0; + unsigned char *decoded = decodeBase64((const unsigned char *)buf, bufLen, &olen); + + if (decoded) + { + + if (!cPart(imap)->sizeProp) + { + cPart(imap)->attach_data_size += olen; + cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; + } + + file.write((const uint8_t *)decoded, olen); + delay(0); + delete[] decoded; + + if (imap->_config->enable.download_status) + { + int p = 0; + if (cHeader(imap)->total_download_size > 0) + p = 100 * octetCount / cHeader(imap)->total_download_size; + + if ((p != downloadCount) && (p <= 100)) + { + downloadCount = p; + if (imap->_readCallback && reportState != -1) + downloadReport(imap, p); + reportState = -1; + } + else + reportState = 0; + } + } + + if (!reconnect(imap)) + return false; + } + else + { + //binary content + if (!cPart(imap)->sizeProp) + { + cPart(imap)->attach_data_size += bufLen; + cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; + } + + file.write((const uint8_t *)buf, bufLen); + delay(0); + + if (imap->_config->enable.download_status) + { + int p = 0; + if (cHeader(imap)->total_download_size > 0) + p = 100 * octetCount / cHeader(imap)->total_download_size; + + if ((p != downloadCount) && (p <= 100)) + { + downloadCount = p; + if (imap->_readCallback && reportState != -1) + downloadReport(imap, p); + reportState = -1; + } + else + reportState = 0; + } + + if (!reconnect(imap)) + return false; + } + } + return true; +} + +void ESP_Mail_Client::downloadReport(IMAPSession *imap, int progress) +{ + if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) + { + std::string s; + char *tmp = intStr(progress); + appendP(s, esp_mail_str_90, true); + appendP(s, esp_mail_str_131, false); + s += cPart(imap)->filename; + appendP(s, esp_mail_str_91, false); + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_92, false); + appendP(s, esp_mail_str_34, false); + esp_mail_debug_line(s.c_str(), false); + std::string().swap(s); + } +} + +void ESP_Mail_Client::fetchReport(IMAPSession *imap, int progress, bool download) +{ + if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) + { + std::string s; + char *tmp = intStr(progress); + if (download) + appendP(s, esp_mail_str_90, true); + else + appendP(s, esp_mail_str_83, true); + appendP(s, esp_mail_str_131, false); + if (cPart(imap)->filename.length() > 0) + { + s += cPart(imap)->filename; + appendP(s, esp_mail_str_91, false); + } + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_92, false); + appendP(s, esp_mail_str_34, false); + esp_mail_debug_line(s.c_str(), false); + std::string().swap(s); + } +} + +void ESP_Mail_Client::searchReport(int progress, const char *percent) +{ + if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) + { + char *tmp = intStr(progress); + std::string s; + appendP(s, esp_mail_str_261, true); + s += tmp; + s += percent; + appendP(s, esp_mail_str_34, false); + esp_mail_debug_line(s.c_str(), false); + delS(tmp); + } +} + +void ESP_Mail_Client::uploadReport(const char *filename, int progress) +{ + if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) + { + std::string s; + char *tmp = intStr(progress); + appendP(s, esp_mail_str_160, true); + s += filename; + appendP(s, esp_mail_str_91, false); + s += tmp; + delS(tmp); + appendP(s, esp_mail_str_92, false); + appendP(s, esp_mail_str_34, false); + esp_mail_debug_line(s.c_str(), false); + std::string().swap(s); + } +} + +int ESP_Mail_Client::cMSG(IMAPSession *imap) +{ + return imap->_msgNum[cIdx(imap)]; +} + +int ESP_Mail_Client::cIdx(IMAPSession *imap) +{ + return imap->_cMsgIdx; +} + +void ESP_Mail_Client::decodeTIS620_UTF8(char *out, const char *in, size_t len) +{ + //output is the 3-byte value UTF-8 + int j = 0; + for (size_t i = 0; i < len; i++) + { + if (in[i] < 0x80) + out[j++] = in[i]; + else if ((in[i] >= 0xa0 && in[i] < 0xdb) || (in[i] > 0xde && in[i] < 0xfc)) + { + int unicode = 0x0e00 + in[i] - 0xa0; + out[j++] = 0xe0 | ((unicode >> 12) & 0xf); + out[j++] = 0x80 | ((unicode >> 6) & 0x3f); + out[j++] = 0x80 | (unicode & 0x3f); + } + } +} + +int ESP_Mail_Client::decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen) +{ + unsigned char *outstart = out; + const unsigned char *base = in; + const unsigned char *processed = in; + unsigned char *outend = out + *outlen; + const unsigned char *inend; + unsigned int c; + int bits; + + inend = in + (*inlen); + while ((in < inend) && (out - outstart + 5 < *outlen)) + { + c = *in++; + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) + { + *out++ = c; + bits = -6; + } + else + { + *out++ = ((c >> 6) & 0x1F) | 0xC0; + bits = 0; + } + + for (; bits >= 0; bits -= 6) + { + if (out >= outend) + break; + *out++ = ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char *)in; + } + *outlen = out - outstart; + *inlen = processed - base; + return (0); +} + +void ESP_Mail_Client::decodeText(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetLength, int &octetCount, int &readCount) +{ + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + if (chunkIdx == 0) + { + char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); + if (tmp) + { + octetCount = 2; + octetLength = atoi(tmp); + delS(tmp); + chunkIdx++; + cPart(imap)->octetLen = octetLength; + + if ((rfc822_body_subtype && imap->_config->download.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))) + prepareFilePath(imap, filePath, false); + + if (filePath.length() == 0) + { + if (!rfc822_body_subtype) + appendP(filePath, esp_mail_str_67, false); + else + { + appendP(filePath, esp_mail_str_82, false); + appendP(filePath, esp_mail_str_131, false); + appendP(filePath, esp_mail_str_67, false); + } + } + cPart(imap)->filename = filePath; + + return; + } + else + { + if (imap->_debug) + { + char *tmp = strP(esp_mail_str_280); + esp_mail_debug_line(tmp, false); + delS(tmp); + } + } + } + + delay(0); + + if (octetLength == 0) + return; + + if (imap->_config->download.rfc822 || imap->_config->download.html || imap->_config->download.text || (rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text)))) + { + if (imap->_readCallback && octetCount > octetLength + 2 && readCount < 100) + fetchReport(imap, 100, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))); + + if (octetCount <= octetLength + 2) + { + size_t olen = 0; + char *decoded = nullptr; + bool newC = true; + if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) + { + decoded = (char *)decodeBase64((const unsigned char *)buf, bufLen, &olen); + } + else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_278)) + { + decoded = newS(bufLen + 10); + decodeQP(buf, decoded); + olen = strlen(decoded); + } + else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_29)) + { + decoded = decode7Bit(buf); + olen = strlen(decoded); + } + else + { + //8bit and binary + newC = false; + decoded = buf; + olen = bufLen; + } + + if (decoded) + { + + if ((rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text)))) + { + + if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_iso8859_1) + { + int ilen = olen; + int olen2 = (ilen + 1) * 2; + unsigned char *tmp = (unsigned char *)newS(olen2); + decodeLatin1_UTF8(tmp, &olen2, (unsigned char *)decoded, &ilen); + delS(decoded); + olen = olen2; + decoded = (char *)tmp; + } + else if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_tis620) + { + char *out = newS((olen + 1) * 3); + delS(decoded); + decodeTIS620_UTF8(out, decoded, olen); + olen = strlen(out); + decoded = out; + } + + int p = 0; + + if (octetLength > 0) + p = 100 * octetCount / octetLength; + + if ((p != readCount) && (p <= 100)) + { + readCount = p; + if (imap->_readCallback) + fetchReport(imap, p, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))); + } + + if (cPart(imap)->text.length() < imap->_config->limit.msg_size) + { + + if (cPart(imap)->text.length() + olen < imap->_config->limit.msg_size) + { + cPart(imap)->textLen += olen; + cPart(imap)->text.append(decoded, olen); + } + else + { + int d = imap->_config->limit.msg_size - cPart(imap)->text.length(); + cPart(imap)->textLen += d; + if (d > 0) + cPart(imap)->text.append(decoded, d); + } + } + } + + if (filePath.length() > 0) + { + if (!cPart(imap)->file_open_write) + { + cPart(imap)->file_open_write = true; + + if (_sdOk || _flashOk) + { + downloadRequest = true; + + if (imap->_storageType == esp_mail_file_storage_type_sd) + file = SD.open(filePath.c_str(), FILE_WRITE); + else if (imap->_storageType == esp_mail_file_storage_type_flash) +#if defined(ESP32) + file = SPIFFS.open(filePath.c_str(), FILE_WRITE); +#elif defined(ESP8266) + file = FLASH_FS.open(filePath.c_str(), "w"); +#endif + } + } + + if (_sdOk || _flashOk) + file.write((const uint8_t *)decoded, olen); + } + + if (newC) + delS(decoded); + } + } + } +} +void ESP_Mail_Client::prepareFilePath(IMAPSession *imap, std::string &filePath, bool header) +{ + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + std::string fpath = imap->_config->storage.saved_path; + appendP(fpath, esp_mail_str_202, false); + char *tmp = intStr(cMSG(imap)); + fpath += tmp; + delS(tmp); + + if (imap->_storageType == esp_mail_file_storage_type_sd) + if (!SD.exists(fpath.c_str())) + createDirs(fpath); + + if (header) + { + appendP(fpath, esp_mail_str_203, false); + } + else + { + if (!rfc822_body_subtype) + { + appendP(fpath, esp_mail_str_161, false); + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + appendP(fpath, esp_mail_str_95, false); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + appendP(fpath, esp_mail_str_94, false); + } + else + { + appendP(fpath, esp_mail_str_163, false); + + if (cPart(imap)->rfc822_msg_Idx > 0) + { + char *tmp = intStr(cPart(imap)->rfc822_msg_Idx); + fpath += tmp; + delS(tmp); + } + + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + appendP(fpath, esp_mail_str_95, false); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + appendP(fpath, esp_mail_str_94, false); + else + //possible rfc822 encapsulated message which cannot fetch its header + appendP(fpath, esp_mail_str_40, false); + } + } + + filePath = fpath; +} + +char *ESP_Mail_Client::strReplace(char *orig, char *rep, char *with) +{ + char *result = nullptr; + char *ins = nullptr; + char *tmp = nullptr; + int len_rep; + int len_with; + int len_front; + int count; + + len_with = strlen(with); + len_rep = strlen(rep); + + ins = orig; + for (count = 0; (tmp = strstr(ins, rep)); ++count) + ins = tmp + len_rep; + + tmp = result = newS(strlen(orig) + (len_with - len_rep) * count + 1); + while (count--) + { + ins = strstr(orig, rep); + len_front = ins - orig; + tmp = strncpy(tmp, orig, len_front) + len_front; + tmp = strcpy(tmp, with) + len_with; + orig += len_front + len_rep; + } + strcpy(tmp, orig); + return result; +} + +int ESP_Mail_Client::decodeChar(const char *s) +{ + assert(s); + assert(*s == '='); + return 16 * hexval(*(s + 1)) + hexval(*(s + 2)); +} + +void ESP_Mail_Client::decodeQP(const char *buf, char *out) +{ + char *tmp = strP(esp_mail_str_295); + while (*buf) + { + if (*buf != '=') + strcat_c(out, *buf++); + else if (*(buf + 1) == '\r' && *(buf + 2) == '\n') + buf += 3; + else if (*(buf + 1) == '\n') + buf += 2; + else if (!strchr(tmp, *(buf + 1))) + strcat_c(out, *buf++); + else if (!strchr(tmp, *(buf + 2))) + strcat_c(out, *buf++); + else + { + strcat_c(out, decodeChar(buf)); + buf += 3; + } + } + delS(tmp); +} + +std::string ESP_Mail_Client::getBoundary(size_t len) +{ + char *tmp = strP(boundary_table); + char *buf = newS(len); + if (len) + { + --len; + buf[0] = tmp[0]; + buf[1] = tmp[1]; + for (size_t n = 2; n < len; n++) + { + int key = rand() % (int)(strlen(tmp) - 1); + buf[n] = tmp[key]; + } + buf[len] = '\0'; + } + std::string s = buf; + delS(buf); + delS(tmp); + return s; +} + +char *ESP_Mail_Client::decode7Bit(char *buf) +{ + char *out = strReplaceP(buf, imap_7bit_key1, imap_7bit_val1); + char *tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key2, imap_7bit_val2); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key3, imap_7bit_val3); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key4, imap_7bit_val4); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key5, imap_7bit_val5); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key6, imap_7bit_val6); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key7, imap_7bit_val7); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key8, imap_7bit_val8); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key9, imap_7bit_val9); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key10, imap_7bit_val10); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key11, imap_7bit_val11); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key12, imap_7bit_val12); + + delS(tmp); + tmp = newS(strlen(out) + 10); + strcpy(tmp, out); + delS(out); + out = strReplaceP(tmp, imap_7bit_key13, imap_7bit_val13); + delS(tmp); + return out; +} + +char *ESP_Mail_Client::strReplaceP(char *buf, PGM_P name, PGM_P value) +{ + char *n = strP(name); + char *v = strP(value); + char *out = strReplace(buf, n, v); + delS(n); + delS(v); + return out; +} + +void ESP_Mail_Client::handleCapability(IMAPSession *imap, char *buf, int &chunkIdx) +{ + if (chunkIdx == 0) + { + if (strposP(buf, esp_mail_imap_response_10, 0) > -1) + { + if (strposP(buf, esp_mail_imap_response_11, 0) > -1) + imap->_auth_capability.login = true; + if (strposP(buf, esp_mail_imap_response_12, 0) > -1) + imap->_auth_capability.plain = true; + if (strposP(buf, esp_mail_imap_response_13, 0) > -1) + imap->_auth_capability.xoauth2 = true; + if (strposP(buf, esp_mail_imap_response_14, 0) > -1) + imap->_auth_capability.start_tls = true; + if (strposP(buf, esp_mail_imap_response_15, 0) > -1) + imap->_auth_capability.cram_md5 = true; + if (strposP(buf, esp_mail_imap_response_16, 0) > -1) + imap->_auth_capability.digest_md5 = true; + } + } +} + +bool ESP_Mail_Client::authFailed(char *buf, int bufLen, int &chunkIdx, int ofs) +{ + bool ret = false; + if (chunkIdx == 0) + { + size_t olen; + unsigned char *decoded = decodeBase64((const unsigned char *)(buf + ofs), bufLen - ofs, &olen); + if (decoded) + { + ret = strposP((char *)decoded, esp_mail_str_294, 0) > -1; + delete[] decoded; + } + chunkIdx++; + } + return ret; +} + +void ESP_Mail_Client::handleFolders(IMAPSession *imap, char *buf) +{ + struct esp_mail_folder_info_t fd; + char *tmp = nullptr; + int p1 = strposP(buf, esp_mail_imap_response_4, 0); + int p2 = 0; + if (p1 != -1) + { + p1 = strposP(buf, esp_mail_str_198, 0); + if (p1 != -1) + { + p2 = strposP(buf, esp_mail_str_192, p1 + 1); + if (p2 != -1) + { + tmp = newS(p2 - p1); + strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); + if (tmp[p2 - p1 - 2] == '\r') + tmp[p2 - p1 - 2] = 0; + fd.attributes = tmp; + delS(tmp); + } + } + + p1 = strposP(buf, esp_mail_str_136, 0); + if (p1 != -1) + { + p2 = strposP(buf, esp_mail_str_136, p1 + 1); + if (p2 != -1) + { + tmp = newS(p2 - p1); + strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); + if (tmp[p2 - p1 - 2] == '\r') + tmp[p2 - p1 - 2] = 0; + fd.delimiter = tmp; + delS(tmp); + } + } + + p1 = strposP(buf, esp_mail_str_131, p2); + if (p1 != -1) + { + p2 = strlen(buf); + tmp = newS(p2 - p1); + if (buf[p1 + 1] == '"') + p1++; + strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); + if (tmp[p2 - p1 - 2] == '\r') + tmp[p2 - p1 - 2] = 0; + if (tmp[strlen(tmp) - 1] == '"') + tmp[strlen(tmp) - 1] = 0; + fd.name = tmp; + delS(tmp); + } + imap->_folders.add(fd); + } +} + +void ESP_Mail_Client::handleExamine(IMAPSession *imap, char *buf) +{ + char *tmp = nullptr; + int p1, p2; + + if (imap->_mbif._msgCount == 0) + { + p1 = strposP(buf, esp_mail_str_199, 0); + if (p1 != -1) + { + tmp = newS(p1); + strncpy(tmp, buf + 2, p1 - 1); + imap->_mbif._msgCount = atoi(tmp); + delS(tmp); + return; + } + } + + if (imap->_mbif._flags.size() == 0) + { + p1 = strposP(buf, esp_mail_imap_response_5, 0); + if (p1 != -1) + { + p1 = strposP(buf, esp_mail_str_198, 0); + if (p1 != -1) + { + p2 = strposP(buf, esp_mail_str_192, p1 + 1); + if (p2 != -1) + { + tmp = newS(p2 - p1); + strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); + char *stk = strP(esp_mail_str_131); + char *end_token; + char *token = strtok_r(tmp, stk, &end_token); + while (token != NULL) + { + imap->_mbif.addFlag(token); + token = strtok_r(NULL, stk, &end_token); + } + if (token) + delS(token); + delS(tmp); + delS(stk); + } + } + return; + } + } + + if (imap->_nextUID.length() == 0) + { + p1 = strposP(buf, esp_mail_str_200, 0); + if (p1 != -1) + { + p2 = strposP(buf, esp_mail_str_156, p1 + strlen_P(esp_mail_str_200)); + if (p2 != -1) + { + tmp = newS(p2 - p1 - strlen_P(esp_mail_str_200) + 1); + strncpy(tmp, buf + p1 + strlen_P(esp_mail_str_200), p2 - p1 - strlen_P(esp_mail_str_200)); + imap->_nextUID = tmp; + imap->_mbif._nextUID = atoi(tmp); + delS(tmp); + } + return; + } + } +} + +bool ESP_Mail_Client::handleIMAPError(IMAPSession *imap, int err, bool ret) +{ + if (err < 0) + { + errorStatusCB(imap, err); + + if (imap->_headers.size() > 0) + { + if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) && (imap->_config->download.attachment || imap->_config->download.inlineImg)) + { + if (cHeader(imap)->part_headers.size() > 0) + cPart(imap)->download_error = imap->errorReason().c_str(); + } + else + cHeader(imap)->error_msg = imap->errorReason().c_str(); + + cHeader(imap)->error = true; + } + } + + if (imap->_tcpConnected) + closeTCP(imap); + + imap->_cbData.empty(); + + return ret; +} + +unsigned char *ESP_Mail_Client::decodeBase64(const unsigned char *src, size_t len, size_t *out_len) +{ + + unsigned char *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + size_t extra_pad; + + unsigned char *dtable = new unsigned char[256]; + + memset(dtable, 0x80, 256); + + for (i = 0; i < sizeof(b64_index_table) - 1; i++) + dtable[b64_index_table[i]] = (unsigned char)i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) + { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0) + goto exit; + extra_pad = (4 - count % 4) % 4; + + olen = (count + extra_pad) / 4 * 3; + pos = out = (unsigned char *)malloc(olen); + if (out == NULL) + goto exit; + + count = 0; + for (i = 0; i < len + extra_pad; i++) + { + unsigned char val; + + if (i >= len) + val = '='; + else + val = src[i]; + tmp = dtable[val]; + if (tmp == 0x80) + continue; + + if (val == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) + { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) + { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else + { + free(out); + goto exit; + } + break; + } + } + } + + *out_len = pos - out; + delete[] dtable; + return out; +exit: + delete[] dtable; + return nullptr; +} + +std::string ESP_Mail_Client::encodeBase64Str(const unsigned char *src, size_t len) +{ + return encodeBase64Str((uint8_t *)src, len); +} + +std::string ESP_Mail_Client::encodeBase64Str(uint8_t *src, size_t len) +{ + std::string outStr; + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen = 4 * ((len + 2) / 3); + if (olen < len) + return outStr; + + outStr.resize(olen); + out = (unsigned char *)&outStr[0]; + + end = src + len; + in = src; + pos = out; + + while (end - in >= 3) + { + *pos++ = b64_index_table[in[0] >> 2]; + *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = b64_index_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = b64_index_table[in[2] & 0x3f]; + in += 3; + } + + if (end - in) + { + *pos++ = b64_index_table[in[0] >> 2]; + if (end - in == 1) + { + *pos++ = b64_index_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } + else + { + *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = b64_index_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + } + + return outStr; +} + +void ESP_Mail_Client::encodeQP(const char *buf, char *out) +{ + int n = 0, p = 0, pos = 0; + assert(buf); + for (n = 0; *buf; buf++) + { + if (n >= 73 && *buf != 10 && *buf != 13) + { + p = sprintf(out + pos, "=\r\n"); + pos += p; + n = 0; + } + + if (*buf == 10 || *buf == 13) + { + strcat_c(out, *buf); + pos++; + n = 0; + } + else if (*buf < 32 || *buf == 61 || *buf > 126) + { + p = sprintf(out + pos, "=%02X", (unsigned char)*buf); + n += p; + pos += p; + } + else if (*buf != 32 || (*(buf + 1) != 10 && *(buf + 1) != 13)) + { + strcat_c(out, *buf); + n++; + pos++; + } + else + { + p = sprintf(out + pos, "=20"); + n += p; + pos += p; + } + } +} + +bool ESP_Mail_Client::sendBase64(SMTPSession *smtp, SMTP_Message *msg, const unsigned char *data, size_t len, bool flashMem, const char *filename, bool report) +{ + bool ret = false; + const unsigned char *end, *in; + + size_t olen = 4 * ((len + 2) / 3); + + if (olen < len) + return false; + + end = data + len; + in = data; + + size_t chunkSize = 936; + size_t byteAdded = 0; + size_t byteSent = 0; + + int dByte = 0; + unsigned char *buf = new unsigned char[chunkSize]; + memset(buf, 0, chunkSize); + + unsigned char *tmp = new unsigned char[3]; + int bcnt = 0; + int pg = 0, _pg = 0; + + if (report) + uploadReport(filename, bcnt); + + while (end - in >= 3) + { + + memset(tmp, 0, 3); + if (flashMem) + memcpy_P(tmp, in, 3); + else + memcpy(tmp, in, 3); + bcnt += 3; + + buf[byteAdded++] = b64_index_table[tmp[0] >> 2]; + buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)]; + buf[byteAdded++] = b64_index_table[((tmp[1] & 0x0f) << 2) | (tmp[2] >> 6)]; + buf[byteAdded++] = b64_index_table[tmp[2] & 0x3f]; + dByte += 4; + if (dByte == BASE64_CHUNKED_LEN) + { + if (byteAdded + 1 < chunkSize) + { + buf[byteAdded++] = 0x0d; + buf[byteAdded++] = 0x0a; + } + dByte = 0; + } + if (byteAdded >= chunkSize - 4) + { + byteSent += byteAdded; + + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + memset(buf, 0, chunkSize); + byteAdded = 0; + } + in += 3; + + if (report) + { + pg = (float)(100.0f * bcnt / len); + if (pg != _pg) + uploadReport(filename, pg); + _pg = pg; + } + } + + if (byteAdded > 0) + { + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + } + + if (end - in) + { + memset(buf, 0, chunkSize); + byteAdded = 0; + memset(tmp, 0, 3); + if (flashMem) + { + if (end - in == 1) + memcpy_P(tmp, in, 1); + else + memcpy_P(tmp, in, 2); + } + else + { + if (end - in == 1) + memcpy(tmp, in, 1); + else + memcpy(tmp, in, 2); + } + + buf[byteAdded++] = b64_index_table[tmp[0] >> 2]; + if (end - in == 1) + { + buf[byteAdded++] = b64_index_table[(tmp[0] & 0x03) << 4]; + buf[byteAdded++] = '='; + } + else + { + buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)]; + buf[byteAdded++] = b64_index_table[(tmp[1] & 0x0f) << 2]; + } + buf[byteAdded++] = '='; + + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + memset(buf, 0, chunkSize); + } + + if (report && _pg < 100) + uploadReport(filename, 100); + + ret = true; +ex: + if (report) + esp_mail_debug(""); + delete[] tmp; + delete[] buf; + return ret; +} + +bool ESP_Mail_Client::sendBase64Stream(SMTPSession *smtp, SMTP_Message *msg, File file, const char *filename, bool report) +{ + bool ret = false; + + if (!file) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + return false; + } + + size_t chunkSize = 936; + size_t byteAdded = 0; + size_t byteSent = 0; + + unsigned char *buf = new unsigned char[chunkSize]; + memset(buf, 0, chunkSize); + + size_t len = file.size(); + size_t fbufIndex = 0; + unsigned char *fbuf = new unsigned char[3]; + + int dByte = 0; + + int bcnt = 0; + int pg = 0, _pg = 0; + + if (report) + uploadReport(filename, bcnt); + + while (file.available()) + { + memset(fbuf, 0, 3); + if (len - fbufIndex >= 3) + { + bcnt += 3; + size_t readLen = file.read(fbuf, 3); + if (readLen != 3) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + break; + } + + buf[byteAdded++] = b64_index_table[fbuf[0] >> 2]; + buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; + buf[byteAdded++] = b64_index_table[((fbuf[1] & 0x0f) << 2) | (fbuf[2] >> 6)]; + buf[byteAdded++] = b64_index_table[fbuf[2] & 0x3f]; + dByte += 4; + if (dByte == BASE64_CHUNKED_LEN) + { + if (byteAdded + 1 < chunkSize) + { + buf[byteAdded++] = 0x0d; + buf[byteAdded++] = 0x0a; + } + dByte = 0; + } + if (byteAdded >= chunkSize - 4) + { + byteSent += byteAdded; + + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + + memset(buf, 0, chunkSize); + byteAdded = 0; + } + fbufIndex += 3; + + if (report) + { + pg = (float)(100.0f * bcnt / len); + if (pg != _pg) + uploadReport(filename, pg); + _pg = pg; + } + } + else + { + if (len - fbufIndex == 1) + { + fbuf[0] = file.read(); + if (fbuf[0] < 0) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + break; + } + } + else if (len - fbufIndex == 2) + { + fbuf[0] = file.read(); + if (fbuf[0] < 0) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + break; + } + fbuf[1] = file.read(); + if (fbuf[1] < 0) + { + errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); + break; + } + } + break; + } + } + + file.close(); + if (byteAdded > 0) + { + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + } + + if (len - fbufIndex > 0) + { + memset(buf, 0, chunkSize); + byteAdded = 0; + buf[byteAdded++] = b64_index_table[fbuf[0] >> 2]; + if (len - fbufIndex == 1) + { + buf[byteAdded++] = b64_index_table[(fbuf[0] & 0x03) << 4]; + buf[byteAdded++] = '='; + } + else + { + buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; + buf[byteAdded++] = b64_index_table[(fbuf[1] & 0x0f) << 2]; + } + buf[byteAdded++] = '='; + + if (!bdat(smtp, msg, byteAdded, false)) + goto ex; + + if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + goto ex; + } + ret = true; + + if (report && _pg < 100) + uploadReport(filename, 100); + +ex: + delete[] buf; + delete[] fbuf; + file.close(); + return ret; +} + +IMAPSession::IMAPSession() {} +IMAPSession::~IMAPSession() +{ + empty(); + _caCert.reset(); + _caCert = nullptr; +} + +bool IMAPSession::closeSession() +{ + if (!_tcpConnected) + return false; +#if defined(ESP32) + /** + * The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure + * The client disposed without memory released after the server close + * the connection due to LOGOUT command, which caused the memory leaks. + */ + if (!MailClient.imapLogout(this)) + return false; +#endif + return MailClient.handleIMAPError(this, 0, true); +} + +bool IMAPSession::connect(ESP_Mail_Session *sesssion, IMAP_Config *config) +{ + + if (_tcpConnected) + MailClient.closeTCP(this); + + _sesson_cfg = sesssion; + _config = config; + _caCert = nullptr; + + if (strlen(_sesson_cfg->certificate.cert_data) > 0) + _caCert = std::shared_ptr(_sesson_cfg->certificate.cert_data); + + if (strlen(_sesson_cfg->certificate.cert_file) > 0) + { + if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk) + MailClient._sdOk = MailClient.sdTest(); + if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk) +#if defined(ESP32) + MailClient._flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + MailClient._flashOk = FLASH_FS.begin(); +#endif + } + + return MailClient.imapAuth(this); +} + +void IMAPSession::debug(int level) +{ + if (level > esp_mail_debug_level_0) + { + if (level > esp_mail_debug_level_3) + level = esp_mail_debug_level_1; + _debugLevel = level; + _debug = true; + } + else + { + _debugLevel = esp_mail_debug_level_0; + _debug = false; + } +} + +String IMAPSession::errorReason() +{ + std::string ret; + + if (_imapStatus.text.length() > 0) + return _imapStatus.text.c_str(); + + switch (_imapStatus.statusCode) + { + case IMAP_STATUS_SERVER_CONNECT_FAILED: + MailClient.appendP(ret, esp_mail_str_38, true); + break; + case MAIL_CLIENT_ERROR_CONNECTION_LOST: + MailClient.appendP(ret, esp_mail_str_221, true); + break; + case MAIL_CLIENT_ERROR_READ_TIMEOUT: + MailClient.appendP(ret, esp_mail_str_258, true); + break; + case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED: + MailClient.appendP(ret, esp_mail_str_305, true); + break; + case IMAP_STATUS_NO_MESSAGE: + MailClient.appendP(ret, esp_mail_str_306, true); + break; + case IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT: + MailClient.appendP(ret, esp_mail_str_93, true); + break; + case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP: + MailClient.appendP(ret, esp_mail_str_132, true); + break; + case IMAP_STATUS_CLOSE_MAILBOX_FAILED: + MailClient.appendP(ret, esp_mail_str_188, true); + break; + case IMAP_STATUS_OPEN_MAILBOX_FAILED: + MailClient.appendP(ret, esp_mail_str_281, true); + break; + case IMAP_STATUS_LIST_MAILBOXS_FAILED: + MailClient.appendP(ret, esp_mail_str_62, true); + break; + case IMAP_STATUS_NO_SUPPORTED_AUTH: + MailClient.appendP(ret, esp_mail_str_42, true); + break; + case IMAP_STATUS_CHECK_CAPABILITIES_FAILED: + MailClient.appendP(ret, esp_mail_str_63, true); + break; + case MAIL_CLIENT_ERROR_OUT_OF_MEMORY: + MailClient.appendP(ret, esp_mail_str_186, true); + break; + case IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED: + MailClient.appendP(ret, esp_mail_str_153, true); + break; + + default: + break; + } + return ret.c_str(); +} + +bool IMAPSession::selectFolder(const char *folderName, bool readOnly) +{ + if (_tcpConnected) + { + if (!openFolder(folderName, readOnly)) + return false; + } + else + { + _currentFolder = folderName; + } + return true; +} + +bool IMAPSession::openFolder(const char *folderName, bool readOnly) +{ + if (!_tcpConnected) + return false; + if (readOnly) + return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_examine, true); + else + return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_select, true); +} + +bool IMAPSession::getFolders(FoldersCollection &folders) +{ + if (!_tcpConnected) + return false; + return getMailboxes(folders); +} + +bool IMAPSession::closeFolder(const char *folderName) +{ + if (!_tcpConnected) + return false; + return closeMailbox(); +} + +void IMAPSession::checkUID() +{ + if (MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_140) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_212) || + MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_213) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_214) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_215) || + MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_216) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_217) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_218) || + MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_219) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_220)) + _config->fetch.uid = "*"; +} + +void IMAPSession::checkPath() +{ + std::string path = _config->storage.saved_path; + if (path[0] != '/') + { + path = "/"; + path += _config->storage.saved_path; + path = path.c_str(); + } +} + +bool IMAPSession::headerOnly() +{ + return _headerOnly; +} + +esp_mail_imap_msg_list_t IMAPSession::data() +{ + esp_mail_imap_msg_list_t ret; + + for (size_t i = 0; i < _headers.size(); i++) + { + if (ESP.getFreeHeap() < ESP_MAIL_MIN_MEM) + continue; + + esp_mail_imap_msg_item_t itm; + + itm.UID = _headers[i].message_uid.c_str(); + itm.ID = _headers[i].message_id.c_str(); + itm.msgNo = _headers[i].message_no.c_str(); + itm.from = _headers[i].from.c_str(); + itm.fromCharset = _headers[i].from_charset.c_str(); + itm.to = _headers[i].to.c_str(); + itm.toCharset = _headers[i].to_charset.c_str(); + itm.cc = _headers[i].cc.c_str(); + itm.ccCharset = _headers[i].cc_charset.c_str(); + itm.subject = _headers[i].subject.c_str(); + itm.subjectCharset = _headers[i].subject_charset.c_str(); + itm.date = _headers[i].date.c_str(); + itm.fetchError = _headers[i].error_msg.c_str(); + + getMessages(i, itm); + + getRFC822Messages(i, itm); + + ret.msgItems.push_back(itm); + } + + return ret; +} + +SelectedFolderInfo IMAPSession::selectedFolder() +{ + return _mbif; +} + +void IMAPSession::callback(imapStatusCallback imapCallback) +{ + _readCallback = std::move(imapCallback); +} + +void IMAPSession::getMessages(uint16_t messageIndex, esp_mail_imap_msg_item_t &msg) +{ + msg.text.content = ""; + msg.text.charSet = ""; + msg.text.content_type = ""; + msg.text.transfer_encoding = ""; + msg.html.content = ""; + msg.html.charSet = ""; + msg.html.content_type = ""; + msg.html.transfer_encoding = ""; + + if (messageIndex < _headers.size()) + { + int sz = _headers[messageIndex].part_headers.size(); + if (sz > 0) + { + for (int i = 0; i < sz; i++) + { + if (!_headers[messageIndex].part_headers[i].rfc822_part && _headers[messageIndex].part_headers[i].message_sub_type != esp_mail_imap_message_sub_type_rfc822) + { + if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) + { + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) + { + msg.text.content = _headers[messageIndex].part_headers[i].text.c_str(); + msg.text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + msg.text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + msg.text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) + { + msg.html.content = _headers[messageIndex].part_headers[i].text.c_str(); + msg.html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + msg.html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + msg.html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + } + else + { + struct esp_mail_attacment_info_t att; + att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); + att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); + att.name = _headers[messageIndex].part_headers[i].name.c_str(); + att.size = _headers[messageIndex].part_headers[i].attach_data_size; + att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); + att.type = _headers[messageIndex].part_headers[i].attach_type; + msg.attachments.push_back(att); + } + } + } + } + } +} + +void IMAPSession::getRFC822Messages(uint16_t messageIndex, esp_mail_imap_msg_item_t &msg) +{ + if (messageIndex < _headers.size()) + { + int sz = _headers[messageIndex].part_headers.size(); + int partIdx = 0; + int cIdx = 0; + IMAP_MSG_Item *_rfc822 = nullptr; + if (sz > 0) + { + for (int i = 0; i < sz; i++) + { + if (_headers[messageIndex].part_headers[i].message_sub_type == esp_mail_imap_message_sub_type_rfc822) + { + if (_headers[messageIndex].part_headers[i].rfc822_part) + { + if (partIdx > 0) + msg.rfc822.push_back(*_rfc822); + cIdx = i; + partIdx++; + _rfc822 = new IMAP_MSG_Item(); + + _rfc822->from = _headers[messageIndex].part_headers[i].rfc822_header.from.c_str(); + _rfc822->sender = _headers[messageIndex].part_headers[i].rfc822_header.sender.c_str(); + _rfc822->to = _headers[messageIndex].part_headers[i].rfc822_header.to.c_str(); + _rfc822->cc = _headers[messageIndex].part_headers[i].rfc822_header.cc.c_str(); + _rfc822->bcc = _headers[messageIndex].part_headers[i].rfc822_header.bcc.c_str(); + _rfc822->return_path = _headers[messageIndex].part_headers[i].rfc822_header.return_path.c_str(); + _rfc822->reply_to = _headers[messageIndex].part_headers[i].rfc822_header.reply_to.c_str(); + _rfc822->subject = _headers[messageIndex].part_headers[i].rfc822_header.subject.c_str(); + _rfc822->comment = _headers[messageIndex].part_headers[i].rfc822_header.comment.c_str(); + _rfc822->keyword = _headers[messageIndex].part_headers[i].rfc822_header.keyword.c_str(); + _rfc822->date = _headers[messageIndex].part_headers[i].rfc822_header.date.c_str(); + _rfc822->messageID = _headers[messageIndex].part_headers[i].rfc822_header.messageID.c_str(); + _rfc822->text.charSet = ""; + _rfc822->text.content_type = ""; + _rfc822->text.transfer_encoding = ""; + _rfc822->html.charSet = ""; + _rfc822->html.content_type = ""; + _rfc822->html.transfer_encoding = ""; + } + else + { + if (MailClient.multipartMember(_headers[messageIndex].part_headers[cIdx].partNumStr, _headers[messageIndex].part_headers[i].partNumStr)) + { + if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) + { + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) + { + _rfc822->text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + _rfc822->text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + _rfc822->text.content = _headers[messageIndex].part_headers[i].text.c_str(); + _rfc822->text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) + { + _rfc822->html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + _rfc822->html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + _rfc822->html.content = _headers[messageIndex].part_headers[i].text.c_str(); + _rfc822->html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + } + else + { + struct esp_mail_attacment_info_t att; + att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); + att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); + att.name = _headers[messageIndex].part_headers[i].name.c_str(); + att.size = _headers[messageIndex].part_headers[i].attach_data_size; + att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); + att.type = _headers[messageIndex].part_headers[i].attach_type; + _rfc822->attachments.push_back(att); + } + } + } + } + } + + if ((int)msg.rfc822.size() < partIdx && _rfc822 != nullptr) + msg.rfc822.push_back(*_rfc822); + } + } +} + +bool IMAPSession::closeMailbox() +{ + + if (!MailClient.reconnect(this)) + return false; + + std::string s; + + if (_readCallback) + { + MailClient.appendP(s, esp_mail_str_210, true); + s += _currentFolder; + MailClient.appendP(s, esp_mail_str_96, false); + MailClient.imapCB(this, "", false); + MailClient.imapCB(this, s.c_str(), false); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_197); + + if (MailClient.imapSendP(this, esp_mail_str_195, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + _imap_cmd = esp_mail_imap_cmd_close; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CLOSE_MAILBOX_FAILED, false)) + return false; + + _currentFolder.clear(); + _mailboxOpened = false; + + return true; +} + +bool IMAPSession::openMailbox(const char *folder, esp_mail_imap_auth_mode mode, bool waitResponse) +{ + + if (!MailClient.reconnect(this)) + return false; + + if (_currentFolder.length() > 0) + { + if (strcmp(_currentFolder.c_str(), folder) != 0) + { + if (!closeMailbox()) + return false; + } + } + + _currentFolder = folder; + std::string s; + if (_readCallback) + { + MailClient.appendP(s, esp_mail_str_61, true); + s += _currentFolder; + MailClient.appendP(s, esp_mail_str_96, false); + MailClient.imapCB(this, "", false); + MailClient.imapCB(this, s.c_str(), false); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_248); + + if (mode == esp_mail_imap_mode_examine) + { + MailClient.appendP(s, esp_mail_str_135, true); + _imap_cmd = esp_mail_imap_cmd_examine; + } + else if (mode == esp_mail_imap_mode_select) + { + MailClient.appendP(s, esp_mail_str_247, true); + _imap_cmd = esp_mail_imap_cmd_select; + } + s += _currentFolder; + MailClient.appendP(s, esp_mail_str_136, false); + if (MailClient.imapSend(this, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + if (waitResponse) + { + + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_OPEN_MAILBOX_FAILED, false)) + return false; + } + + if (mode == esp_mail_imap_mode_examine) + _readOnlyMode = true; + else if (mode == esp_mail_imap_mode_select) + _readOnlyMode = false; + + _mailboxOpened = true; + + return true; +} + +bool IMAPSession::getMailboxes(FoldersCollection &folders) +{ + _folders.clear(); + + if (_readCallback) + { + MailClient.imapCB(this, "", false); + MailClient.imapCBP(this, esp_mail_str_58, false); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_230); + + if (MailClient.imapSendP(this, esp_mail_str_133, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_list; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + folders = _folders; + return true; +} + +bool IMAPSession::checkCapability() +{ + if (_readCallback) + { + MailClient.imapCB(this, "", false); + MailClient.imapCBP(this, esp_mail_str_64, false); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_65); + + if (MailClient.imapSendP(this, esp_mail_str_2, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_capability; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CHECK_CAPABILITIES_FAILED, false)) + return false; + + return true; +} + +bool IMAPSession::createFolder(const char *folderName) +{ + if (_debug) + { + MailClient.imapCB(this, "", false); + MailClient.debugInfoP(esp_mail_str_320); + } + + std::string cmd; + MailClient.appendP(cmd, esp_mail_str_322, true); + cmd += folderName; + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_create; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::deleteFolder(const char *folderName) +{ + if (_debug) + { + MailClient.imapCB(this, "", false); + MailClient.debugInfoP(esp_mail_str_321); + } + + std::string cmd; + MailClient.appendP(cmd, esp_mail_str_323, true); + cmd += folderName; + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_delete; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::deleteMessages(MessageList *toDelete, bool expunge) +{ + if (toDelete->_list.size() > 0) + { + + if (!selectFolder(_currentFolder.c_str(), false)) + return false; + + if (_debug) + { + MailClient.imapCB(this, "", false); + MailClient.debugInfoP(esp_mail_str_316); + } + + std::string cmd; + char *tmp = nullptr; + MailClient.appendP(cmd, esp_mail_str_249, true); + for (size_t i = 0; i < toDelete->_list.size(); i++) + { + if (i > 0) + MailClient.appendP(cmd, esp_mail_str_263, false); + tmp = MailClient.intStr(toDelete->_list[i]); + cmd += tmp; + MailClient.delS(tmp); + } + MailClient.appendP(cmd, esp_mail_str_315, false); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (expunge) + { + if (MailClient.imapSendP(this, esp_mail_str_317, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_expunge; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + } + } + + return true; +} + +bool IMAPSession::copyMessages(MessageList *toCopy, const char *dest) +{ + if (toCopy->_list.size() > 0) + { + + if (!selectFolder(_currentFolder.c_str(), false)) + return false; + + if (_debug) + { + MailClient.imapCB(this, "", false); + std::string s; + MailClient.appendP(s, esp_mail_str_318, true); + s += dest; + esp_mail_debug(s.c_str()); + } + + std::string cmd; + char *tmp = nullptr; + MailClient.appendP(cmd, esp_mail_str_319, true); + for (size_t i = 0; i < toCopy->_list.size(); i++) + { + if (i > 0) + MailClient.appendP(cmd, esp_mail_str_263, false); + tmp = MailClient.intStr(toCopy->_list[i]); + cmd += tmp; + MailClient.delS(tmp); + } + MailClient.appendP(cmd, esp_mail_str_131, false); + cmd += dest; + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + } + + return true; +} + +#if defined(ESP8266) +void ESP_Mail_Client::setClock(float offset) +{ + if (WiFi.status() != WL_CONNECTED) + WiFi.reconnect(); + + time_t now = time(nullptr); + + _clockReady = now > ESP_MAIL_CLIENT_VALID_TS; + + if (!_clockReady) + { + char *server1 = strP(esp_mail_str_283); + char *server2 = strP(esp_mail_str_296); + + configTime(offset * 3600, 0, server1, server2); + + now = time(nullptr); + uint8_t attempts = 0; + while (now < ESP_MAIL_CLIENT_VALID_TS) + { + now = time(nullptr); + attempts++; + if (attempts > 200 || now > ESP_MAIL_CLIENT_VALID_TS) + break; + delay(100); + } + + delS(server1); + delS(server2); + } + + _clockReady = now > ESP_MAIL_CLIENT_VALID_TS; +} +#endif + +void IMAPSession::empty() +{ + std::string().swap(_nextUID); + clearMessageData(); +} + +void IMAPSession::clearMessageData() +{ + for (size_t i = 0; i < _headers.size(); i++) + { + _headers[i].part_headers.clear(); + std::vector().swap(_headers[i].part_headers); + } + std::vector().swap(_headers); + std::vector().swap(_msgNum); + _folders.clear(); + _mbif._flags.clear(); + _mbif._searchCount = 0; +} + +SMTPSession::SMTPSession() +{ +} + +SMTPSession::~SMTPSession() +{ + closeSession(); + _caCert.reset(); + _caCert = nullptr; +} + +bool SMTPSession::connect(ESP_Mail_Session *config) +{ + if (_tcpConnected) + MailClient.closeTCP(this); + + _sesson_cfg = config; + _caCert = nullptr; + + if (strlen(_sesson_cfg->certificate.cert_data) > 0) + _caCert = std::shared_ptr(_sesson_cfg->certificate.cert_data); + + if (strlen(_sesson_cfg->certificate.cert_file) > 0) + { + if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk) + MailClient._sdOk = MailClient.sdTest(); + if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk) +#if defined(ESP32) + MailClient._flashOk = SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED); +#elif defined(ESP8266) + MailClient._flashOk = FLASH_FS.begin(); +#endif + } + return MailClient.smtpAuth(this); +} + +void SMTPSession::debug(int level) +{ + if (level > esp_mail_debug_level_0) + { + if (level > esp_mail_debug_level_3) + level = esp_mail_debug_level_1; + _debugLevel = level; + _debug = true; + } + else + { + _debugLevel = esp_mail_debug_level_0; + _debug = false; + } +} + +String SMTPSession::errorReason() +{ + std::string ret; + if (_smtpStatus.text.length() > 0) + { + MailClient.appendP(ret, esp_mail_str_312, true); + char *code = MailClient.intStr(_smtpStatus.respCode); + ret += code; + MailClient.delS(code); + MailClient.appendP(ret, esp_mail_str_313, false); + ret += _smtpStatus.text; + return ret.c_str(); + } + + switch (_smtpStatus.statusCode) + { + case SMTP_STATUS_SERVER_CONNECT_FAILED: + MailClient.appendP(ret, esp_mail_str_38, true); + break; + case SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED: + MailClient.appendP(ret, esp_mail_str_39, true); + break; + case SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED: + MailClient.appendP(ret, esp_mail_str_39, true); + break; + case SMTP_STATUS_AUTHEN_NOT_SUPPORT: + MailClient.appendP(ret, esp_mail_str_42, true); + break; + case SMTP_STATUS_AUTHEN_FAILED: + MailClient.appendP(ret, esp_mail_str_43, true); + break; + case SMTP_STATUS_USER_LOGIN_FAILED: + MailClient.appendP(ret, esp_mail_str_43, true); + break; + case SMTP_STATUS_PASSWORD_LOGIN_FAILED: + MailClient.appendP(ret, esp_mail_str_47, true); + break; + case SMTP_STATUS_SEND_HEADER_SENDER_FAILED: + MailClient.appendP(ret, esp_mail_str_48, true); + break; + case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED: + MailClient.appendP(ret, esp_mail_str_222, true); + break; + case SMTP_STATUS_SEND_BODY_FAILED: + MailClient.appendP(ret, esp_mail_str_49, true); + break; + case MAIL_CLIENT_ERROR_CONNECTION_LOST: + MailClient.appendP(ret, esp_mail_str_221, true); + break; + case MAIL_CLIENT_ERROR_READ_TIMEOUT: + MailClient.appendP(ret, esp_mail_str_258, true); + break; + case MAIL_CLIENT_ERROR_FILE_IO_ERROR: + MailClient.appendP(ret, esp_mail_str_282, true); + break; + case SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED: + MailClient.appendP(ret, esp_mail_str_293, true); + break; + case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED: + MailClient.appendP(ret, esp_mail_str_305, true); + break; + case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP: + MailClient.appendP(ret, esp_mail_str_132, true); + break; + case SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED: + MailClient.appendP(ret, esp_mail_str_206, true); + break; + case SMTP_STATUS_NO_VALID_SENDER_EXISTED: + MailClient.appendP(ret, esp_mail_str_205, true); + break; + case MAIL_CLIENT_ERROR_OUT_OF_MEMORY: + MailClient.appendP(ret, esp_mail_str_186, true); + break; + case SMTP_STATUS_NO_SUPPORTED_AUTH: + MailClient.appendP(ret, esp_mail_str_42, true); + break; + + default: + break; + } + return ret.c_str(); +} + +bool SMTPSession::closeSession() +{ + if (!_tcpConnected) + return false; + + if (_sendCallback) + { + _cbData._sentSuccess = _sentSuccessCount; + _cbData._sentFailed = _sentFailedCount; + MailClient.smtpCB(this, ""); + MailClient.smtpCBP(this, esp_mail_str_128); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_245); + + bool ret = true; + +/* Sign out */ +#if defined(ESP32) + /** + * The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure + * The client disposed without memory released after the server close + * the connection due to QUIT command, which caused the memory leaks. + */ + MailClient.smtpSendP(this, esp_mail_str_7, true); + _smtp_cmd = esp_mail_smtp_cmd_logout; + ret = MailClient.handleSMTPResponse(this, esp_mail_smtp_status_code_221, SMTP_STATUS_SEND_BODY_FAILED); +#endif + + if (ret) + { + + if (_sendCallback) + { + MailClient.smtpCB(this, ""); + MailClient.smtpCBP(this, esp_mail_str_129, false); + } + + if (_debug) + MailClient.debugInfoP(esp_mail_str_246); + + if (_sendCallback) + MailClient.smtpCB(this, "", true); + } + + return MailClient.handleSMTPError(this, 0, ret); +} + +void SMTPSession::callback(smtpStatusCallback smtpCallback) +{ + _sendCallback = std::move(smtpCallback); +} + +IMAP_Status::IMAP_Status() +{ +} +IMAP_Status::~IMAP_Status() +{ + empty(); +} + +const char *IMAP_Status::info() +{ + return _info.c_str(); +} + +bool IMAP_Status::success() +{ + return _success; +} + +void IMAP_Status::empty() +{ + std::string().swap(_info); +} + +SMTP_Status::SMTP_Status() +{ +} + +SMTP_Status::~SMTP_Status() +{ + empty(); +} + +const char *SMTP_Status::info() +{ + return _info.c_str(); +} + +bool SMTP_Status::success() +{ + return _success; +} + +size_t SMTP_Status::completedCount() +{ + return _sentSuccess; +} + +size_t SMTP_Status::failedCount() +{ + return _sentFailed; +} + +void SMTP_Status::empty() +{ + std::string().swap(_info); +} + +ESP_Mail_Client MailClient = ESP_Mail_Client(); + +#endif /* ESP_Mail_Client_CPP */ diff --git a/lib/lib_div/lib_mail/src/ESP_Mail_Client.h b/lib/lib_div/lib_mail/src/ESP_Mail_Client.h new file mode 100755 index 000000000..8ae7163bf --- /dev/null +++ b/lib/lib_div/lib_mail/src/ESP_Mail_Client.h @@ -0,0 +1,2582 @@ +/** + * Mail Client Arduino Library for Espressif's ESP32 and ESP8266 + * + * Version: 1.0.13 + * Released: January 11, 2021 + * + * Updates: + * - Fix the IMAP search termination checking https://github.com/mobizt/ESP-Mail-Client/issues/15. + * - Fix the IMAP startTLS consequence commands + * + * + * This library allows Espressif's ESP32 and ESP8266 devices to send and read Email + * through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESP_Mail_Client_H +#define ESP_Mail_Client_H + +#define ESP_MAIL_VERSION "1.0.8" + +#include +#include "extras/RFC2047.h" +#include "extras/ESPTimeHelper.h" + +#if defined(ESP32) +#include +#include +#include +#include +#include +#include +#include "wcs/esp32/ESP_Mail_HTTPClient32.h" +#include "extras/ESPTimeHelper.h" +#elif defined(ESP8266) +#include +#include +#include +#define FS_NO_GLOBALS +#include +//#include +#include "wcs/esp8266/ESP_Mail_HTTPClient.h" +#endif + +#include "extras/MIMEInfo.h" + +#include +#include +#include + +#define FORMAT_SPIFFS_IF_FAILED true +#if defined(ESP8266) +#define SD_CS_PIN 15 +#endif + +#define SMTP_STATUS_SERVER_CONNECT_FAILED -100 +#define SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED -101 +#define SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED -102 +#define SMTP_STATUS_AUTHEN_NOT_SUPPORT -103 +#define SMTP_STATUS_AUTHEN_FAILED -104 +#define SMTP_STATUS_USER_LOGIN_FAILED -105 +#define SMTP_STATUS_PASSWORD_LOGIN_FAILED -106 +#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED -107 +#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED -108 +#define SMTP_STATUS_SEND_BODY_FAILED -109 +#define SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -110 +#define SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED -111 +#define SMTP_STATUS_NO_VALID_SENDER_EXISTED -112 +#define SMTP_STATUS_NO_SUPPORTED_AUTH -113 + +#define IMAP_STATUS_SERVER_CONNECT_FAILED -200 +#define IMAP_STATUS_IMAP_RESPONSE_FAILED -201 +#define IMAP_STATUS_LOGIN_FAILED -202 +#define IMAP_STATUS_BAD_COMMAND -203 +#define IMAP_STATUS_PARSE_FLAG_FAILED -204 +#define IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -205 +#define IMAP_STATUS_NO_MESSAGE -206 +#define IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT -207 +#define IMAP_STATUS_CLOSE_MAILBOX_FAILED -208 +#define IMAP_STATUS_OPEN_MAILBOX_FAILED -209 +#define IMAP_STATUS_LIST_MAILBOXS_FAILED -210 +#define IMAP_STATUS_CHECK_CAPABILITIES_FAILED -211 +#define IMAP_STATUS_NO_SUPPORTED_AUTH -212 +#define IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED -213 + +#define MAIL_CLIENT_ERROR_CONNECTION_LOST -28 +#define MAIL_CLIENT_ERROR_READ_TIMEOUT -29 +#define MAIL_CLIENT_ERROR_FILE_IO_ERROR -30 +#define MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED -31 +#define MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP -32 +#define MAIL_CLIENT_ERROR_OUT_OF_MEMORY -33 + +#define MAX_EMAIL_SEARCH_LIMIT 1000 +#define BASE64_CHUNKED_LEN 76 +#define FLOWED_TEXT_LEN 78 +#define ESP_MAIL_WIFI_RECONNECT_TIMEOUT 10000 +#define ESP_MAIL_PROGRESS_REPORT_STEP 20 +#define ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED 0 +#define ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE 256 +#define ESP_MAIL_CLIENT_VALID_TS 1577836800 + +#if defined(ESP32) +#define ESP_MAIL_MIN_MEM 70000 +#elif defined(ESP8266) +#define ESP_MAIL_MIN_MEM 4000 +#endif + +extern FS *ufsp; + +class IMAPSession; +class SMTPSession; +class SMTP_Status; +class DownloadProgress; +class MessageData; + +enum esp_mail_smtp_status_code +{ + esp_mail_smtp_status_code_0, //default + + /* Positive Completion */ + esp_mail_smtp_status_code_211 = 221, // System status, or system help reply + esp_mail_smtp_status_code_214 = 214, //Help message(A response to the HELP command) + esp_mail_smtp_status_code_220 = 220, // Service ready + esp_mail_smtp_status_code_221 = 221, // Service closing transmission channel [RFC 2034] + esp_mail_smtp_status_code_235 = 235, //2.7.0 Authentication succeeded[RFC 4954] + esp_mail_smtp_status_code_250 = 250, //Requested mail action okay, completed + esp_mail_smtp_status_code_251 = 251, //User not local; will forward + esp_mail_smtp_status_code_252 = 252, //Cannot verify the user, but it will try to deliver the message anyway + + /* Positive Intermediate */ + esp_mail_smtp_status_code_334 = 334, //(Server challenge - the text part contains the Base64 - encoded challenge)[RFC 4954] + esp_mail_smtp_status_code_354 = 354, //Start mail input + + /* Transient Negative Completion */ + /* "Transient Negative" means the error condition is temporary, and the action may be requested again.*/ + esp_mail_smtp_status_code_421 = 421, //Service is unavailable because the server is shutting down. + esp_mail_smtp_status_code_432 = 432, //4.7.12 A password transition is needed [RFC 4954] + esp_mail_smtp_status_code_450 = 450, //Requested mail action not taken: mailbox unavailable (e.g., mailbox busy or temporarily blocked for policy reasons) + esp_mail_smtp_status_code_451 = 451, //Requested action aborted : local error in processing + //e.g.IMAP server unavailable[RFC 4468] + esp_mail_smtp_status_code_452 = 452, //Requested action not taken : insufficient system storage + esp_mail_smtp_status_code_454 = 454, //4.7.0 Temporary authentication failure[RFC 4954] + esp_mail_smtp_status_code_455 = 455, //Server unable to accommodate parameters + + /* Permanent Negative Completion */ + esp_mail_smtp_status_code_500 = 500, //Syntax error, command unrecognized (This may include errors such as command line too long) + //e.g. Authentication Exchange line is too long [RFC 4954] + esp_mail_smtp_status_code_501 = 501, //Syntax error in parameters or arguments + //e.g. 5.5.2 Cannot Base64-decode Client responses [RFC 4954] + //5.7.0 Client initiated Authentication Exchange (only when the SASL mechanism specified that client does not begin the authentication exchange) [RFC 4954] + esp_mail_smtp_status_code_502 = 502, //Command not implemented + esp_mail_smtp_status_code_503 = 503, //Bad sequence of commands + esp_mail_smtp_status_code_504 = 504, //Command parameter is not implemented + //e.g. 5.5.4 Unrecognized authentication type [RFC 4954] + esp_mail_smtp_status_code_521 = 521, //Server does not accept mail [RFC 7504] + esp_mail_smtp_status_code_523 = 523, //Encryption Needed [RFC 5248] + esp_mail_smtp_status_code_530 = 530, //5.7.0 Authentication required [RFC 4954] + esp_mail_smtp_status_code_534 = 534, //5.7.9 Authentication mechanism is too weak [RFC 4954] + esp_mail_smtp_status_code_535 = 535, //5.7.8 Authentication credentials invalid [RFC 4954] + esp_mail_smtp_status_code_538 = 538, //5.7.11 Encryption required for requested authentication mechanism[RFC 4954] + esp_mail_smtp_status_code_550 = 550, //Requested action not taken: mailbox unavailable (e.g., mailbox not found, no access, or command rejected for policy reasons) + esp_mail_smtp_status_code_551 = 551, //User not local; please try + esp_mail_smtp_status_code_552 = 552, //Requested mail action aborted: exceeded storage allocation + esp_mail_smtp_status_code_553 = 553, //Requested action not taken: mailbox name not allowed + esp_mail_smtp_status_code_554 = 554, //Transaction has failed (Or, in the case of a connection-opening response, "No SMTP service here") + //e.g. 5.3.4 Message too big for system [RFC 4468] + esp_mail_smtp_status_code_556 = 556, //Domain does not accept mail[RFC 7504] +}; + +enum esp_mail_smtp_port +{ + esp_mail_smtp_port_25 = 25, //PLAIN/TLS with STARTTLS + esp_mail_smtp_port_465 = 465, //SSL + esp_mail_smtp_port_587 = 587 //TLS with STARTTLS +}; + +enum esp_mail_imap_port +{ + esp_mail_imap_port_143 = 143, //PLAIN/TLS with STARTTLS + esp_mail_imap_port_993 = 993, //SSL +}; + +enum esp_mail_smtp_notify +{ + esp_mail_smtp_notify_never = 0, + esp_mail_smtp_notify_success = 1, + esp_mail_smtp_notify_failure = 2, + esp_mail_smtp_notify_delay = 4 +}; + +enum esp_mail_attach_type +{ + esp_mail_att_type_none, + esp_mail_att_type_attachment, + esp_mail_att_type_inline +}; + +enum esp_mail_message_type +{ + esp_mail_msg_type_none = 0, + esp_mail_msg_type_plain = 1, + esp_mail_msg_type_html = 2, + esp_mail_msg_type_enriched = 1 +}; + +enum esp_mail_auth_type +{ + esp_mail_auth_type_psw, + esp_mail_auth_type_oath2, + esp_mail_auth_type_token +}; + +enum esp_mail_imap_auth_mode +{ + esp_mail_imap_mode_examine, + esp_mail_imap_mode_select +}; + +enum esp_mail_imap_response_status +{ + esp_mail_imap_resp_unknown, + esp_mail_imap_resp_ok, + esp_mail_imap_resp_no, + esp_mail_imap_resp_bad +}; + +enum esp_mail_imap_header_state +{ + esp_mail_imap_state_from = 1, + esp_mail_imap_state_to, + esp_mail_imap_state_cc, + esp_mail_imap_state_subject, + esp_mail_imap_state_content_type, + esp_mail_imap_state_content_transfer_encoding, + esp_mail_imap_state_accept_language, + esp_mail_imap_state_content_language, + esp_mail_imap_state_date, + esp_mail_imap_state_msg_id, + esp_mail_imap_state_char_set, + esp_mail_imap_state_boundary +}; + +enum esp_mail_imap_command +{ + esp_mail_imap_cmd_capability, + esp_mail_imap_cmd_starttls, + esp_mail_imap_cmd_login, + esp_mail_imap_cmd_plain, + esp_mail_imap_cmd_auth, + esp_mail_imap_cmd_list, + esp_mail_imap_cmd_select, + esp_mail_imap_cmd_examine, + esp_mail_imap_cmd_close, + esp_mail_imap_cmd_status, + esp_mail_imap_cmd_search, + esp_mail_imap_cmd_fetch_body_header, + esp_mail_imap_cmd_fetch_body_mime, + esp_mail_imap_cmd_fetch_body_text, + esp_mail_imap_cmd_fetch_body_attachment, + esp_mail_imap_cmd_fetch_body_inline, + esp_mail_imap_cmd_logout, + esp_mail_imap_cmd_store, + esp_mail_imap_cmd_expunge, + esp_mail_imap_cmd_create, + esp_mail_imap_cmd_delete +}; + +enum esp_mail_imap_mime_fetch_type +{ + esp_mail_imap_mime_fetch_type_part, + esp_mail_imap_mime_fetch_type_sub_part1, + esp_mail_imap_mime_fetch_type_sub_part2 +}; + +enum esp_mail_smtp_command +{ + esp_mail_smtp_cmd_initial_state, + esp_mail_smtp_cmd_greeting, + esp_mail_smtp_cmd_start_tls, + esp_mail_smtp_cmd_login_user, + esp_mail_smtp_cmd_auth_plain, + esp_mail_smtp_cmd_auth, + esp_mail_smtp_cmd_login_psw, + esp_mail_smtp_cmd_send_header_sender, + esp_mail_smtp_cmd_send_header_recipient, + esp_mail_smtp_cmd_send_body, + esp_mail_smtp_cmd_chunk_termination, + esp_mail_smtp_cmd_logout +}; + +enum esp_mail_imap_header_type +{ + esp_mail_imap_header_from, + esp_mail_imap_header_to, + esp_mail_imap_header_cc, + esp_mail_imap_header_subject, + esp_mail_imap_header_date, + esp_mail_imap_header_msg_id, + esp_mail_imap_header_cont_lang, + esp_mail_imap_header_accept_lang +}; + +enum esp_mail_char_decoding_scheme +{ + esp_mail_char_decoding_scheme_default, + esp_mail_char_decoding_scheme_iso8859_1, + esp_mail_char_decoding_scheme_tis620 +}; + +enum esp_mail_smtp_priority +{ + esp_mail_smtp_priority_high = 1, + esp_mail_smtp_priority_normal = 3, + esp_mail_smtp_priority_low = 5, +}; + +enum esp_mail_smtp_embed_message_type +{ + esp_mail_smtp_embed_message_type_attachment = 0, + esp_mail_smtp_embed_message_type_inline +}; + +enum esp_mail_debug_level +{ + esp_mail_debug_level_0 = 0, + esp_mail_debug_level_1, + esp_mail_debug_level_2 = 222, + esp_mail_debug_level_3 = 333 +}; + +enum esp_mail_imap_multipart_sub_type +{ + esp_mail_imap_multipart_sub_type_none = 0, + esp_mail_imap_multipart_sub_type_mixed, + esp_mail_imap_multipart_sub_type_alternative, + esp_mail_imap_multipart_sub_type_parallel, + esp_mail_imap_multipart_sub_type_digest, + esp_mail_imap_multipart_sub_type_related, + esp_mail_imap_multipart_sub_type_report, +}; + +enum esp_mail_imap_message_sub_type +{ + esp_mail_imap_message_sub_type_none = 0, + esp_mail_imap_message_sub_type_rfc822, + esp_mail_imap_message_sub_type_delivery_status, + esp_mail_imap_message_sub_type_partial, + esp_mail_imap_message_sub_type_external_body, +}; + +/* descrete media types (rfc 2046) */ +struct esp_mail_imap_descrete_media_type_t +{ + /** textual information with subtypes + * "plain" + * "enriched" (rfc 1896 revised from richtext in rfc 1341) + * + * unrecognized subtypes and charset should be interpreted as application/octet-stream + * + * parameters: + * "charset" (rfc 2045) default is us-ascii + * for character set includes 8-bit characters + * and such characters are used in the body, Content-Transfer-Encoding + * header field and a corresponding encoding on the data are required + * + * ISO-8859-X where "X" is to be replaced, as + * necessary, for the parts of ISO-8859 [ISO-8859]. + */ + static constexpr const char *text = "text"; + + /** image data with subtypes (rfc 2048) + * "jpeg" + * "gif" + * + * unrecognized subtypes should be interpreted as application/octet-stream + */ + static constexpr const char *image = "image"; + + /** audio data with initial subtype + * "baic" -- for single channel audio encoded using 8bit ISDN mu-law [PCM] + * at a sample rate of 8000 Hz. + * + * Unrecognized subtypes of "audio" should at a miniumum be treated as + * "application/octet-stream" + */ + static constexpr const char *audio = "audio"; + + /** video data with initial subtype + * "mpeg" + * + * Unrecognized subtypes of "video" should at a minumum be treated as + * "application/octet-stream" + */ + static constexpr const char *video = "video"; + + /** some other kind of data, typically either + * uninterpreted binary data or information to be + * processed by an application with subtypes + * + * "octet-stream" -- uninterpreted binary data + * "PostScript" -- for the transport of PostScript material + * + * Other expected uses include spreadsheets, data for mail-based + * scheduling systems, and languages for "active" (computational) + * messaging, and word processing formats that are not directly readable. + * + * The octet-stream subtype parameters: + * TYPE, PADDING, NAME + */ + static constexpr const char *application = "application"; +}; + +/** composite media types (rfc 2046) + * + * As stated in the definition of the Content-Transfer-Encoding field + * [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is + * permitted for entities of type "multipart". The "multipart" boundary + * delimiters and header fields are always represented as 7bit US-ASCII + * in any case (though the header fields may encode non-US-ASCII header + * text as per RFC 2047) and data within the body parts can be encoded + * on a part-by-part basis, with Content-Transfer-Encoding fields for + * each appropriate body part. +*/ +struct esp_mail_imap_composite_media_type_t +{ + /** data consisting of multiple entities of independent data types + * The Content-Type field for multipart entities requires one parameter, + * "boundary". + * The boundary delimiter line is then defined as a line + * consisting entirely of two hyphen characters ("-", decimal value 45) + * followed by the boundary parameter value from the Content-Type header + * field, optional linear whitespace, and a terminating CRLF. + * + * NOTE: The CRLF preceding the boundary delimiter line is conceptually + * attached to the boundary so that it is possible to have a part that + * does not end with a CRLF (line break). Body parts that must be + * considered to end with line breaks, therefore, must have two CRLFs + * preceding the boundary delimiter line, the first of which is part of + * the preceding body part, and the second of which is part of the + * encapsulation boundary. + * + * Boundary delimiters must not appear within the encapsulated material, + * and must be no longer than 70 characters, not counting the two + * leading hyphens. + * + * The boundary delimiter line following the last body part is a + * distinguished delimiter that indicates that no further body parts + * will follow. Such a delimiter line is identical to the previous + * delimiter lines, with the addition of two more hyphens after the + * boundary parameter value. + * + * See rfc2049 Appendix A for a Complex Multipart Example + */ + static constexpr const char *multipart = "multipart"; + + /* an encapsulated message */ + static constexpr const char *message = "message"; +}; + +struct esp_mail_imap_media_text_sub_type_t +{ + static constexpr const char *plain = "plain"; + static constexpr const char *enriched = "enriched"; + static constexpr const char *html = "html"; +}; + +/* multipart sub types */ +struct esp_mail_imap_multipart_sub_type_t +{ + /* a generic mixed set of parts */ + static constexpr const char *mixed = "mixed"; + + /* the same data in multiple formats */ + static constexpr const char *alternative = "alternative"; + + /* parts intended to be viewed simultaneously */ + static constexpr const char *parallel = "parallel"; + + /* multipart entities in which each part has a default type of "message/rfc822" */ + static constexpr const char *digest = "digest"; + + /* for compound objects consisting of several inter-related body parts (rfc 2387) */ + static constexpr const char *related = "related"; + + /* rfc 3462 */ + static constexpr const char *report = "report"; +}; + +/* message body sub types */ +struct esp_mail_imap_message_sub_type_t +{ + /* body contains an encapsulated message, with the syntax of an RFC 822 message. */ + static constexpr const char *rfc822 = "rfc822"; + + /* to allow large objects to be delivered as several separate pieces of mail */ + static constexpr const char *Partial = "Partial"; + + /* the actual body data are not included, but merely referenced */ + static constexpr const char *External_Body = "External-Body"; + + static constexpr const char *delivery_status = "delivery-status"; +}; + +/** content disposition rfc 2183 + * + * Parameters: + * "filename", "creation-date","modification-date", + * "read-date", * "size" +*/ +struct esp_mail_imap_content_disposition_type_t +{ + /** if it is intended to be displayed automatically + * upon display of the message. + */ + static constexpr const char *inline_ = "inline"; + + /** to indicate that they are separate from the main body + * of the mail message, and that their display should not + * be automatic, but contingent upon some further action of the user. + */ + static constexpr const char *attachment = "attachment"; +}; + +struct esp_mail_internal_use_t +{ + bool binary = false; + std::string cid = ""; +}; + +struct esp_mail_content_transfer_encoding_t +{ + /* The default 7-bit transfer encoding for US-ACII characters*/ + static constexpr const char *enc_7bit = "7bit"; + + /* The quoted printable transfer encoding for non-US-ASCII characters*/ + static constexpr const char *enc_qp = "quoted-printable"; + + /* The base64 encoded transfer encoding */ + static constexpr const char *enc_base64 = "base64"; + + /* The 8-bit transfer encoding for extended-US-ASCII characters*/ + static constexpr const char *enc_8bit = "8bit"; + + /* The binary transfer encoding for extended-US-ASCII characters with no line length limit*/ + static constexpr const char *enc_binary = "binary"; +}; + +struct esp_mail_smtp_response_status_t +{ + int respCode = 0; + int statusCode = 0; + std::string text = ""; +}; + +struct esp_mail_imap_response_status_t +{ + int statusCode = 0; + std::string text = ""; +}; + +/* The option to embed this message content as a file */ +struct esp_mail_smtp_embed_message_body_t +{ + /* Enable to send this message body as file */ + bool enable = false; + + /* The name of embedded file */ + const char *filename = ""; + + /** The embedded type + * esp_mail_smtp_embed_message_type_attachment or 0 + * esp_mail_smtp_embed_message_type_inline or 1 + */ + esp_mail_smtp_embed_message_type type = esp_mail_smtp_embed_message_type_attachment; +}; + +/* The PLAIN text body details of the message */ +struct esp_mail_plain_body_t +{ + /* The option to embed this message content as a file */ + esp_mail_smtp_embed_message_body_t embed; + + /* The PLAIN text content of the message */ + const char *content = ""; + + /* The charset of the PLAIN text content of the message */ + const char *charSet = "UTF-8"; + + /* The content type of message */ + const char *content_type = "text/plain"; + + /* The option to encode the content for data transfer */ + const char *transfer_encoding = "7bit"; + + /* The option to send the PLAIN text with wrapping */ + bool flowed = false; + + /* The internal usage data */ + esp_mail_internal_use_t _int; +}; + +struct esp_mail_html_body_t +{ + /* The option to embedded the content as a file */ + esp_mail_smtp_embed_message_body_t embed; + + /* The HTML content of the message */ + const char *content = ""; + + /* The charset of the HTML content of the message */ + const char *charSet = "UTF-8"; + + /* The content type of message */ + const char *content_type = "text/html"; + + /* The option to encode the content for data transfer */ + const char *transfer_encoding = "7bit"; + + /* The internal usage data */ + esp_mail_internal_use_t _int; +}; + +struct esp_mail_link_internal_t +{ + std::string cid = ""; +}; + +struct esp_mail_email_info_t +{ + /* The name of Email author*/ + const char *name = ""; + + /* The Email address */ + const char *email = ""; +}; +struct esp_mail_smtp_msg_response_t +{ + /* The author Email address to reply */ + const char *reply_to = ""; + + /* The sender Email address to return the message */ + const char *return_path = ""; + + /** The Delivery Status Notifications e.g. esp_mail_smtp_notify_never, + * esp_mail_smtp_notify_success, + * esp_mail_smtp_notify_failure, and + * esp_mail_smtp_notify_delay + */ + int notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; +}; + +struct esp_mail_smtp_enable_option_t +{ + /* Enable chunk data sending for large message */ + bool chunking = false; +}; + +struct esp_mail_attach_blob_t +{ + /* BLOB data (flash or ram) */ + const uint8_t *data = nullptr; + + /* BLOB data size in byte */ + size_t size = 0; +}; + +struct esp_mail_attach_file_t +{ + const char *path = ""; + /** The file storage type e.g. esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + esp_mail_file_storage_type storage_type = esp_mail_file_storage_type_none; +}; + +struct esp_mail_attach_descr_t +{ + /* The name of attachment */ + const char *name = ""; + + /* The attachment file name */ + const char *filename = ""; + + /* The MIME type of attachment */ + const char *mime = ""; + + /* The transfer encoding of attachnent e.g. base64 */ + const char *transfer_encoding = "base64"; + + /* The cntent encoding of attachnent e.g. base64 */ + const char *content_encoding = ""; +}; + +struct esp_mail_attach_internal_t +{ + esp_mail_attach_type att_type = esp_mail_att_type_attachment; + int index = 0; + int msg_uid = 0; + bool flash_blob = false; + bool binary = false; + bool parallel = false; + std::string cid = ""; +}; + +struct esp_mail_attachment_t +{ + /* The attachment description */ + struct esp_mail_attach_descr_t descr; + + /* The BLOB data config */ + struct esp_mail_attach_blob_t blob; + + /* The file data config */ + struct esp_mail_attach_file_t file; + + /* reserved for internal usage */ + esp_mail_attach_internal_t _int; +}; + +struct esp_mail_smtp_recipient_t +{ + /* The recipient's name */ + const char *name = ""; + + /* The recipient's Email address */ + const char *email = ""; +}; + +struct esp_mail_smtp_recipient_address_t +{ + /* The recipient's Email address */ + const char *email = ""; +}; + +struct esp_mail_smtp_send_status_t +{ + /* The status of the message */ + bool completed = false; + + /* The primary recipient mailbox of the message */ + const char *recipients = ""; + + /* The topic of the message */ + const char *subject = ""; + + /* The timestamp of the message */ + time_t timesstamp = 0; +}; + +struct esp_mail_attacment_info_t +{ + const char *filename = ""; + const char *name = ""; + const char *creationDate = ""; + const char *mime = ""; + esp_mail_attach_type type = esp_mail_att_type_none; + size_t size; +}; + +struct esp_mail_auth_capability_t +{ + bool plain = false; + bool xoauth2 = false; + bool cram_md5 = false; + bool digest_md5 = false; + bool login = false; + bool start_tls = false; +}; + +struct esp_mail_smtp_capability_t +{ + bool esmtp = false; + bool binaryMIME = false; + bool _8bitMIME = false; + bool chunking = false; + bool utf8 = false; + bool pipelining = false; + bool dsn = false; +}; + +struct esp_mail_imap_rfc822_msg_header_item_t +{ + std::string sender = ""; + std::string from; + std::string subject = ""; + std::string messageID = ""; + std::string keyword = ""; + std::string comment = ""; + std::string date = ""; + std::string return_path = ""; + std::string reply_to; + std::string to = ""; + std::string cc = ""; + std::string bcc = ""; +}; + +struct esp_mail_message_part_info_t +{ + int octetLen = 0; + int attach_data_size = 0; + int textLen = 0; + bool sizeProp = false; + int nestedLevel = 0; + std::string partNumStr = ""; + std::string partNumFetchStr = ""; + std::string text = ""; + std::string filename = ""; + std::string type = ""; + std::string save_path = ""; + std::string name = ""; + std::string content_disposition = ""; + std::string content_type = ""; + std::string descr = ""; + std::string content_transfer_encoding = ""; + std::string creation_date = ""; + std::string modification_date = ""; + std::string charset = ""; + std::string download_error = ""; + esp_mail_attach_type attach_type = esp_mail_att_type_none; + esp_mail_message_type msg_type = esp_mail_msg_type_none; + bool file_open_write = false; + bool multipart = false; + esp_mail_imap_multipart_sub_type multipart_sub_type = esp_mail_imap_multipart_sub_type_none; + esp_mail_imap_message_sub_type message_sub_type = esp_mail_imap_message_sub_type_none; + bool rfc822_part = false; + int rfc822_msg_Idx = 0; + struct esp_mail_imap_rfc822_msg_header_item_t rfc822_header; + bool error = false; + bool plain_flowed = false; + bool plain_delsp = false; +}; + +struct esp_mail_message_header_t +{ + int header_data_len = 0; + std::string from = ""; + std::string to = ""; + std::string cc = ""; + std::string subject = ""; + std::string content_type = ""; + std::string content_transfer_encoding = ""; + std::string date = ""; + std::string message_id = ""; + std::string message_uid = ""; + std::string message_no = ""; + std::string boundary = ""; + std::string accept_language = ""; + std::string content_language = ""; + std::string char_set = ""; + bool multipart = false; + bool rfc822_part = false; + int rfc822Idx = 0; + std::string partNumStr = ""; + + esp_mail_imap_multipart_sub_type multipart_sub_type = esp_mail_imap_multipart_sub_type_none; + esp_mail_imap_message_sub_type message_sub_type = esp_mail_imap_message_sub_type_none; + std::string from_charset = ""; + std::string to_charset = ""; + std::string cc_charset = ""; + std::string subject_charset = ""; + std::string msgID = ""; + std::string error_msg = ""; + bool error = false; + std::vector part_headers = std::vector(); + int attachment_count = 0; + int total_download_size = 0; + int downloaded_size = 0; + int total_attach_data_size = 0; + int downloaded_bytes = 0; + int message_data_count = 0; +}; + +/* Internal use */ +struct esp_mail_folder_info_t +{ + std::string name = ""; + std::string attributes = ""; + std::string delimiter = ""; +}; + +struct esp_mail_folder_info_item_t +{ + /* The name of folder */ + const char *name = ""; + + /* The attributes of folder */ + const char *attributes = ""; + + /* The delimeter of folder */ + const char *delimiter = ""; +}; + +struct esp_mail_sesson_cert_config_t +{ + /* The certificate data (base64 data) */ + const char *cert_data = ""; + + /* The certificate file (DER format) */ + const char *cert_file = ""; + + /* The storage type */ + esp_mail_file_storage_type cert_file_storage_type; +}; + +struct esp_mail_sesson_sever_config_t +{ + /* The hostName of the server */ + const char *host_name = ""; + /* The port on the server to connect to */ + uint16_t port = 0; +}; + +/* The log in credentials */ +struct esp_mail_sesson_login_config_t +{ + /* The user Email address to log in */ + const char *email = ""; + + /* The user password to log in */ + const char *password = ""; + + /* The OAuth2.0 access token to log in */ + const char *accessToken = ""; + + /* The user domain or ip of client */ + const char *user_domain = ""; +}; + +struct esp_mail_sesson_secure_config_t +{ + /* The option to send the command to start the TLS connection */ + bool startTLS = false; +}; + +struct esp_mail_session_config_t +{ + /* The server config */ + struct esp_mail_sesson_sever_config_t server; + + /* The log in config */ + struct esp_mail_sesson_login_config_t login; + + /* The secure config */ + struct esp_mail_sesson_secure_config_t secure; + + /* The certificate config */ + struct esp_mail_sesson_cert_config_t certificate; +}; + +struct esp_mail_imap_download_config_t +{ + /* To download the PLAIN text content of the message */ + bool text = false; + + /* To download the HTML content of the message */ + bool html = false; + + /* To download the attachments of the message */ + bool attachment = false; + + /* To download the inline image of the message */ + bool inlineImg = false; + + /* To download the rfc822 mesages in the message */ + bool rfc822 = false; + + /* To download the message header */ + bool header = false; +}; + +struct esp_mail_imap_enable_config_t +{ + /* To store the PLAIN text of the message in the IMAPSession */ + bool text = false; + + /* To store the HTML of the message in the IMAPSession */ + bool html = false; + + /* To store the rfc822 messages in the IMAPSession */ + bool rfc822 = false; + + /* To enable the download status via the serial port */ + bool download_status = false; + + /* To sort the message UID of the search result in descending order */ + bool recent_sort = false; +}; + +struct esp_mail_imap_limit_config_t +{ + /* The maximum messages from the search result */ + size_t search = 10; + + /** The maximum size of the memory buffer to store the message content. + * This is only limit for data to be stored in the IMAPSession. + */ + size_t msg_size = 1024; + + /* The maximum size of each attachment to download */ + size_t attachment_size = 1024 * 1024 * 5; +}; + +struct esp_mail_imap_storage_config_t +{ + /* The path to save the downloaded file */ + const char *saved_path = "/"; + + /** The type of file storages e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + esp_mail_file_storage_type type = esp_mail_file_storage_type_flash; +}; + +struct esp_mail_imap_search_config_t +{ + /* The search criteria */ + const char *criteria = ""; + + /* The option to search the unseen message */ + bool unseen_msg = false; +}; + +struct esp_mail_imap_fetch_config_t +{ + /* The UID of message to fetch */ + const char *uid = ""; + + /* Set the message flag as seen */ + bool set_seen = false; +}; + +struct esp_mail_imap_read_config_t +{ + /* The config for fetching */ + struct esp_mail_imap_fetch_config_t fetch; + + /* The config for search */ + struct esp_mail_imap_search_config_t search; + + /* The config about the limits */ + struct esp_mail_imap_limit_config_t limit; + + /* The config to enable the features */ + struct esp_mail_imap_enable_config_t enable; + + /* The config about downloads */ + struct esp_mail_imap_download_config_t download; + + /* The config about the storage and path to save the downloaded file */ + struct esp_mail_imap_storage_config_t storage; +}; + +/* Mail and MIME Header Fields */ +struct esp_mail_imap_msg_item_t +{ + /* The message number */ + const char *msgNo = ""; + + /* The message UID */ + const char *UID = ""; + + /* The message identifier (RFC 4021) */ + const char *ID = ""; + + /* The language(s) for auto-responses (RFC 4021) */ + const char *acceptLang = ""; + + /* The language of message content (RFC 4021) */ + const char *contentLang = ""; + + /* The mailbox of message author (RFC 4021) */ + const char *from = ""; + + /* The charset of the mailbox of message author */ + const char *fromCharset = ""; + + /* The primary recipient mailbox (RFC 4021) */ + const char *to = ""; + + /* The charset of the primary recipient mailbox */ + const char *toCharset = ""; + + /* The Carbon-copy recipient mailboxes (RFC 4021) */ + const char *cc = ""; + + /* The charset of the Carbon-copy recipient mailbox header */ + const char *ccCharset = ""; + + /* The message date and time (RFC 4021) */ + const char *date = ""; + + /* The topic of message (RFC 4021) */ + const char *subject = ""; + + /* The topic of message charset */ + const char *subjectCharset = ""; + + /* The PLAIN text content of the message */ + esp_mail_plain_body_t text; + + /* The HTML content of the message */ + esp_mail_html_body_t html; + + /* rfc822 related */ + + /* The sender Email */ + const char *sender; + + /* The message identifier */ + const char *messageID = ""; + + /* The keywords or phrases, separated by commas */ + const char *keyword = ""; + + /* The comment about message */ + const char *comment = ""; + + /* The return recipient of the message */ + const char *return_path = ""; + + /* The Email address to reply */ + const char *reply_to; + + /* The Blind carbon-copy recipients */ + const char *bcc = ""; + + /* The error description from fetching the message */ + const char *fetchError = ""; + + /* The info about the attachments in the message */ + std::vector attachments = std::vector(); + + /* The info about the rfc822 messages included in the message */ + std::vector rfc822 = std::vector(); +}; + +struct esp_mail_imap_msg_list_t +{ + /* The info of a message */ + std::vector msgItems = std::vector(); +}; + +struct esp_mail_smtp_msg_type_t +{ + bool rfc822 = false; + int rfc822Idx = 0; +}; +struct esp_mail_imap_multipart_level_t +{ + uint8_t level = 0; + bool fetch_rfc822_header = false; + bool append_body_text = false; +}; + +/** The content transfer encoding + * enc_7bit or "7bit" + * enc_qp or "quoted-printable" + * enc_base64 or "base64" + * enc_binary or "binary" + * enc_8bit or "8bit" +*/ +typedef struct esp_mail_content_transfer_encoding_t Content_Transfer_Encoding; + +/* The result from sending the Email */ +typedef struct esp_mail_smtp_send_status_t SMTP_Result; + +/* The attachment item details for a message which returned from fetching the Email */ +typedef struct esp_mail_attacment_info_t IMAP_Attach_Item; + +/* The attachment details for sending the Email */ +typedef struct esp_mail_attachment_t SMTP_Attachment; + +/* The info of the selected or open mailbox folder e.g. name, attributes and delimiter */ +typedef struct esp_mail_folder_info_item_t FolderInfo; + +/* The session configuations */ +typedef struct esp_mail_session_config_t ESP_Mail_Session; + +/** The IMAP operation configuations */ +typedef struct esp_mail_imap_read_config_t IMAP_Config; + +/* The message item data of the IMAP_MSG_List which contains header, body and attachments info for eacch message*/ +typedef struct esp_mail_imap_msg_item_t IMAP_MSG_Item; + +/* The list that contains the message items from searching or fetching the Email */ +typedef struct esp_mail_imap_msg_list_t IMAP_MSG_List; + +static const char esp_mail_str_1[] PROGMEM = "Content-Type: multipart/mixed; boundary=\""; +static const char esp_mail_str_2[] PROGMEM = "$ CAPABILITY"; +static const char esp_mail_str_3[] PROGMEM = "Mime-Version: 1.0\r\n"; +static const char esp_mail_str_4[] PROGMEM = "AUTH LOGIN"; +static const char esp_mail_str_5[] PROGMEM = "HELO "; +static const char esp_mail_str_6[] PROGMEM = "EHLO "; +static const char esp_mail_str_7[] PROGMEM = "QUIT"; +static const char esp_mail_str_8[] PROGMEM = "MAIL FROM:"; +static const char esp_mail_str_9[] PROGMEM = "RCPT TO:"; +static const char esp_mail_str_10[] PROGMEM = "From: "; +static const char esp_mail_str_11[] PROGMEM = "To: "; +static const char esp_mail_str_12[] PROGMEM = "Cc: "; +static const char esp_mail_str_13[] PROGMEM = ",<"; +static const char esp_mail_str_14[] PROGMEM = "<"; +static const char esp_mail_str_15[] PROGMEM = ">"; +static const char esp_mail_str_16[] PROGMEM = "DATA"; +static const char esp_mail_str_17[] PROGMEM = "X-Priority: "; +static const char esp_mail_str_18[] PROGMEM = "X-MSMail-Priority: High\r\n"; +static const char esp_mail_str_19[] PROGMEM = "X-MSMail-Priority: Normal\r\n"; +static const char esp_mail_str_20[] PROGMEM = "X-MSMail-Priority: Low\r\n"; +static const char esp_mail_str_21[] PROGMEM = "Importance: High\r\n"; +static const char esp_mail_str_22[] PROGMEM = "Importance: Normal\r\n"; +static const char esp_mail_str_23[] PROGMEM = "Importance: Low\r\n"; +static const char esp_mail_str_24[] PROGMEM = "Subject: "; +static const char esp_mail_str_25[] PROGMEM = "Content-Type: "; +static const char esp_mail_str_26[] PROGMEM = "; Name=\""; +static const char esp_mail_str_27[] PROGMEM = "$"; +static const char esp_mail_str_28[] PROGMEM = "Content-Type: multipart/parallel; boundary=\""; +static const char esp_mail_str_29[] PROGMEM = "7bit"; +static const char esp_mail_str_30[] PROGMEM = "Content-Disposition: attachment; filename=\""; +static const char esp_mail_str_31[] PROGMEM = "base64"; +static const char esp_mail_str_32[] PROGMEM = "application/octet-stream"; +static const char esp_mail_str_33[] PROGMEM = "--"; +static const char esp_mail_str_34[] PROGMEM = "\r\n"; +static const char esp_mail_str_35[] PROGMEM = "\"\r\n\r\n"; +static const char esp_mail_str_36[] PROGMEM = "\"\r\n"; +static const char esp_mail_str_37[] PROGMEM = "\r\n.\r\n"; +static const char esp_mail_str_38[] PROGMEM = "unable to connect to server"; +static const char esp_mail_str_39[] PROGMEM = "SMTP server greeting failed"; +static const char esp_mail_str_40[] PROGMEM = ".dat"; +static const char esp_mail_str_41[] PROGMEM = "$ AUTHENTICATE PLAIN "; +static const char esp_mail_str_42[] PROGMEM = "the provided SASL authentication mechanism is not support"; +static const char esp_mail_str_43[] PROGMEM = "authentication failed"; +static const char esp_mail_str_44[] PROGMEM = "mydomain.com"; +static const char esp_mail_str_45[] PROGMEM = "AUTH PLAIN"; +static const char esp_mail_str_46[] PROGMEM = "Return-Path: "; +static const char esp_mail_str_47[] PROGMEM = "login password is not valid"; +static const char esp_mail_str_48[] PROGMEM = "send header failed"; +static const char esp_mail_str_49[] PROGMEM = "send body failed"; +static const char esp_mail_str_50[] PROGMEM = "Connecting to IMAP server..."; +static const char esp_mail_str_51[] PROGMEM = ".HEADER.FIELDS (SUBJECT FROM SENDER RETURN-PATH TO REPLY-TO DATE CC Message-ID COMMENT KEYWORD content-type Content-transfer-encoding)]"; +static const char esp_mail_str_52[] PROGMEM = "failed"; +static const char esp_mail_str_53[] PROGMEM = "Error, "; +static const char esp_mail_str_54[] PROGMEM = "IMAP server connected"; +static const char esp_mail_str_55[] PROGMEM = "> C: download attachment"; +static const char esp_mail_str_56[] PROGMEM = "Logging in..."; +static const char esp_mail_str_57[] PROGMEM = "Downloading messages..."; +static const char esp_mail_str_58[] PROGMEM = "Reading the list of mailboxes..."; +static const char esp_mail_str_59[] PROGMEM = "> C: download plain TEXT message"; +static const char esp_mail_str_60[] PROGMEM = "> C: download HTML message"; +static const char esp_mail_str_61[] PROGMEM = "Selecting the "; +static const char esp_mail_str_62[] PROGMEM = "fail to list the mailboxes"; +static const char esp_mail_str_63[] PROGMEM = "fail to check the capabilities"; +static const char esp_mail_str_64[] PROGMEM = "Check the capability..."; +static const char esp_mail_str_65[] PROGMEM = "> C: check the capability"; +static const char esp_mail_str_66[] PROGMEM = "Searching messages..."; +static const char esp_mail_str_67[] PROGMEM = "message"; +static const char esp_mail_str_68[] PROGMEM = "Search limit:"; +static const char esp_mail_str_69[] PROGMEM = "Found "; +static const char esp_mail_str_70[] PROGMEM = " messages"; +static const char esp_mail_str_71[] PROGMEM = "Show "; +static const char esp_mail_str_72[] PROGMEM = "No message found for search criteria"; +static const char esp_mail_str_73[] PROGMEM = "Search criteria does not set, fetch the recent message"; +static const char esp_mail_str_74[] PROGMEM = "Fetching message "; +static const char esp_mail_str_75[] PROGMEM = ", UID: "; +static const char esp_mail_str_76[] PROGMEM = ", Number: "; +static const char esp_mail_str_77[] PROGMEM = "> C: fetch message header"; +static const char esp_mail_str_78[] PROGMEM = "Attachments ("; +static const char esp_mail_str_79[] PROGMEM = ")"; +static const char esp_mail_str_80[] PROGMEM = "Downloading attachments..."; +static const char esp_mail_str_81[] PROGMEM = "> C: fetch body part header, "; +static const char esp_mail_str_82[] PROGMEM = "rfc822"; +static const char esp_mail_str_83[] PROGMEM = "reading"; +static const char esp_mail_str_84[] PROGMEM = "Free Heap: "; +static const char esp_mail_str_85[] PROGMEM = "Logging out..."; +static const char esp_mail_str_86[] PROGMEM = "> C: fetch body sub part header, "; +static const char esp_mail_str_87[] PROGMEM = "Finished reading Email"; +static const char esp_mail_str_88[] PROGMEM = "> C: finished reading Email"; +static const char esp_mail_str_89[] PROGMEM = "SD card mount failed"; +static const char esp_mail_str_90[] PROGMEM = "download"; +static const char esp_mail_str_91[] PROGMEM = ", "; +static const char esp_mail_str_92[] PROGMEM = "%"; +static const char esp_mail_str_93[] PROGMEM = "connection timeout"; +static const char esp_mail_str_94[] PROGMEM = ".html"; +static const char esp_mail_str_95[] PROGMEM = ".txt"; +static const char esp_mail_str_96[] PROGMEM = " folder..."; +static const char esp_mail_str_97[] PROGMEM = ";"; +static const char esp_mail_str_98[] PROGMEM = "Content-Disposition: attachment\r\n"; +static const char esp_mail_str_99[] PROGMEM = "Date: "; +static const char esp_mail_str_100[] PROGMEM = "Messsage UID: "; +static const char esp_mail_str_101[] PROGMEM = "Messsage ID: "; +static const char esp_mail_str_102[] PROGMEM = "Accept Language: "; +static const char esp_mail_str_103[] PROGMEM = "Content Language: "; +static const char esp_mail_str_104[] PROGMEM = " BODY=BINARYMIME"; +static const char esp_mail_str_105[] PROGMEM = "From Charset: "; +static const char esp_mail_str_106[] PROGMEM = "BDAT "; +static const char esp_mail_str_107[] PROGMEM = "To Charset: "; +static const char esp_mail_str_108[] PROGMEM = "CC: "; +static const char esp_mail_str_109[] PROGMEM = "CC Charset: "; +static const char esp_mail_str_110[] PROGMEM = "delsp=\"no\""; +static const char esp_mail_str_111[] PROGMEM = "Subject Charset: "; +static const char esp_mail_str_112[] PROGMEM = "Message Charset: "; +static const char esp_mail_str_113[] PROGMEM = "Attachment: "; +static const char esp_mail_str_114[] PROGMEM = "File Index: "; +static const char esp_mail_str_115[] PROGMEM = "Filename: "; +static const char esp_mail_str_116[] PROGMEM = "Name: "; +static const char esp_mail_str_117[] PROGMEM = "Size: "; +static const char esp_mail_str_118[] PROGMEM = "Type: "; +static const char esp_mail_str_119[] PROGMEM = "Creation Date: "; +static const char esp_mail_str_120[] PROGMEM = "Connecting to SMTP server..."; +static const char esp_mail_str_121[] PROGMEM = "SMTP server connected, wait for greeting..."; +static const char esp_mail_str_122[] PROGMEM = "Sending greeting response..."; +static const char esp_mail_str_123[] PROGMEM = "message/rfc822"; +static const char esp_mail_str_124[] PROGMEM = "Saving message header to file..."; +static const char esp_mail_str_125[] PROGMEM = "Sending message header..."; +static const char esp_mail_str_126[] PROGMEM = "Sending message body..."; +static const char esp_mail_str_127[] PROGMEM = "Sending attachments..."; +static const char esp_mail_str_128[] PROGMEM = "Closing the session..."; +static const char esp_mail_str_129[] PROGMEM = "Message sent successfully"; +static const char esp_mail_str_130[] PROGMEM = "$ LOGIN "; +static const char esp_mail_str_131[] PROGMEM = " "; +static const char esp_mail_str_132[] PROGMEM = "fail to set up the SSL/TLS structure"; +static const char esp_mail_str_133[] PROGMEM = "$ LIST \"\" *"; +static const char esp_mail_str_134[] PROGMEM = "Comment: "; +static const char esp_mail_str_135[] PROGMEM = "$ EXAMINE \""; +static const char esp_mail_str_136[] PROGMEM = "\""; +static const char esp_mail_str_137[] PROGMEM = "UID "; +static const char esp_mail_str_138[] PROGMEM = " UID"; +static const char esp_mail_str_139[] PROGMEM = " SEARCH"; +static const char esp_mail_str_140[] PROGMEM = "UID"; +static const char esp_mail_str_141[] PROGMEM = "SEARCH"; +static const char esp_mail_str_142[] PROGMEM = "$ UID FETCH "; +static const char esp_mail_str_143[] PROGMEM = "$ FETCH "; +static const char esp_mail_str_144[] PROGMEM = "HEADER.FIELDS (SUBJECT FROM TO DATE CC Message-ID Accept-Language content-type Content-transfer-encoding Content-Language)"; +static const char esp_mail_str_145[] PROGMEM = "Keyword: "; +static const char esp_mail_str_146[] PROGMEM = "$ LOGOUT"; +static const char esp_mail_str_147[] PROGMEM = " BODY"; +static const char esp_mail_str_148[] PROGMEM = ".MIME]"; +static const char esp_mail_str_149[] PROGMEM = "Bcc: "; +static const char esp_mail_str_150[] PROGMEM = "Sender: "; +static const char esp_mail_str_151[] PROGMEM = "no mailbox opened"; +static const char esp_mail_str_152[] PROGMEM = "."; +static const char esp_mail_str_153[] PROGMEM = "No mailbox opened"; +static const char esp_mail_str_154[] PROGMEM = "Remove FLAG"; +static const char esp_mail_str_155[] PROGMEM = "Add FLAG"; +static const char esp_mail_str_156[] PROGMEM = "]"; +static const char esp_mail_str_157[] PROGMEM = "Set FLAG"; +static const char esp_mail_str_158[] PROGMEM = "file does not exist or can't access"; +static const char esp_mail_str_159[] PROGMEM = "msg.html"; +static const char esp_mail_str_160[] PROGMEM = "upload "; +static const char esp_mail_str_161[] PROGMEM = "/msg"; +static const char esp_mail_str_163[] PROGMEM = "/rfc822_msg"; +static const char esp_mail_str_164[] PROGMEM = "msg.txt"; +static const char esp_mail_str_165[] PROGMEM = "Content-Length: "; +static const char esp_mail_str_166[] PROGMEM = "binary"; +static const char esp_mail_str_167[] PROGMEM = "Sending inline data..."; +static const char esp_mail_str_168[] PROGMEM = "charset=\""; +static const char esp_mail_str_169[] PROGMEM = "charset="; +static const char esp_mail_str_170[] PROGMEM = "name=\""; +static const char esp_mail_str_171[] PROGMEM = "name="; +static const char esp_mail_str_172[] PROGMEM = "content-transfer-encoding: "; +static const char esp_mail_str_173[] PROGMEM = " LAST"; +static const char esp_mail_str_174[] PROGMEM = "content-description: "; +static const char esp_mail_str_175[] PROGMEM = "content-disposition: "; +static const char esp_mail_str_176[] PROGMEM = "filename=\""; +static const char esp_mail_str_177[] PROGMEM = "filename="; +static const char esp_mail_str_178[] PROGMEM = "size="; +static const char esp_mail_str_179[] PROGMEM = "creation-date=\""; +static const char esp_mail_str_180[] PROGMEM = "creation-date="; +static const char esp_mail_str_181[] PROGMEM = "modification-date=\""; +static const char esp_mail_str_182[] PROGMEM = "modification-date="; +static const char esp_mail_str_183[] PROGMEM = "*"; +static const char esp_mail_str_184[] PROGMEM = "Reply-To: "; +static const char esp_mail_str_185[] PROGMEM = "> E: "; +static const char esp_mail_str_186[] PROGMEM = "out of memory"; +static const char esp_mail_str_187[] PROGMEM = "Message fetch cmpleted"; +static const char esp_mail_str_188[] PROGMEM = "fail to close the mailbox"; +static const char esp_mail_str_189[] PROGMEM = "message-id: "; +static const char esp_mail_str_190[] PROGMEM = "accept-language: "; +static const char esp_mail_str_191[] PROGMEM = "content-language: "; +static const char esp_mail_str_192[] PROGMEM = ")"; +static const char esp_mail_str_193[] PROGMEM = "{"; +static const char esp_mail_str_194[] PROGMEM = "}"; +static const char esp_mail_str_195[] PROGMEM = "$ CLOSE\r\n"; +static const char esp_mail_str_196[] PROGMEM = "> C: send STARTTLS command"; +static const char esp_mail_str_197[] PROGMEM = "> C: close the mailbox folder"; +static const char esp_mail_str_198[] PROGMEM = "("; +static const char esp_mail_str_199[] PROGMEM = " EXISTS"; +static const char esp_mail_str_200[] PROGMEM = " [UIDNEXT "; +static const char esp_mail_str_201[] PROGMEM = "port > "; +static const char esp_mail_str_202[] PROGMEM = "/"; +static const char esp_mail_str_203[] PROGMEM = "/header.txt"; +static const char esp_mail_str_204[] PROGMEM = "/esp.32"; +static const char esp_mail_str_205[] PROGMEM = "sender Email address is not valid"; +static const char esp_mail_str_206[] PROGMEM = "some of the recipient Email address is not valid"; +static const char esp_mail_str_207[] PROGMEM = "> C: send Email"; +static const char esp_mail_str_208[] PROGMEM = "Sending Email..."; +static const char esp_mail_str_209[] PROGMEM = "Send command, STARTTLS"; +static const char esp_mail_str_210[] PROGMEM = "Closing the "; +static const char esp_mail_str_211[] PROGMEM = "host > "; +static const char esp_mail_str_212[] PROGMEM = "FLAGS"; +static const char esp_mail_str_213[] PROGMEM = "BODY"; +static const char esp_mail_str_214[] PROGMEM = "PEEK"; +static const char esp_mail_str_215[] PROGMEM = "TEXT"; +static const char esp_mail_str_216[] PROGMEM = "HEADER"; +static const char esp_mail_str_217[] PROGMEM = "FIELDS"; +static const char esp_mail_str_218[] PROGMEM = "["; +static const char esp_mail_str_219[] PROGMEM = "]"; +static const char esp_mail_str_220[] PROGMEM = "MIME"; +static const char esp_mail_str_221[] PROGMEM = "connection lost"; +static const char esp_mail_str_222[] PROGMEM = "set recipient failed"; +static const char esp_mail_str_223[] PROGMEM = " NEW"; +static const char esp_mail_str_224[] PROGMEM = "ALL"; +static const char esp_mail_str_225[] PROGMEM = "> C: connect to IMAP server"; +static const char esp_mail_str_226[] PROGMEM = "windows-874"; +static const char esp_mail_str_227[] PROGMEM = "iso-8859-1"; +static const char esp_mail_str_228[] PROGMEM = "> C: server connected"; +static const char esp_mail_str_229[] PROGMEM = "> C: send imap command, LOGIN"; +static const char esp_mail_str_230[] PROGMEM = "> C: send imap command, LIST"; +static const char esp_mail_str_231[] PROGMEM = "iso-8859-11"; +static const char esp_mail_str_232[] PROGMEM = "> C: search messages"; +static const char esp_mail_str_233[] PROGMEM = "> C: send imap command, FETCH"; +static const char esp_mail_str_234[] PROGMEM = "> C: send imap command, LOGOUT"; +static const char esp_mail_str_235[] PROGMEM = "> C: message fetch completed"; +static const char esp_mail_str_236[] PROGMEM = "> C: connect to SMTP server"; +static const char esp_mail_str_237[] PROGMEM = "tis-620"; +static const char esp_mail_str_238[] PROGMEM = "> C: smtp server connected"; +static const char esp_mail_str_239[] PROGMEM = "> C: send smtp command, HELO"; +static const char esp_mail_str_240[] PROGMEM = "> C: send smtp command, AUTH LOGIN"; +static const char esp_mail_str_241[] PROGMEM = "> C: send smtp command, AUTH PLAIN"; +static const char esp_mail_str_242[] PROGMEM = "> C: send message header"; +static const char esp_mail_str_243[] PROGMEM = "> C: send message body"; +static const char esp_mail_str_244[] PROGMEM = "> C: send attachments"; +static const char esp_mail_str_245[] PROGMEM = "> C: terminate the SMTP session"; +static const char esp_mail_str_246[] PROGMEM = "> C: Message sent successfully"; +static const char esp_mail_str_247[] PROGMEM = "$ SELECT \""; +static const char esp_mail_str_248[] PROGMEM = "> C: open the mailbox folder"; +static const char esp_mail_str_249[] PROGMEM = "$ UID STORE "; +static const char esp_mail_str_250[] PROGMEM = " FLAGS ("; +static const char esp_mail_str_251[] PROGMEM = " +FLAGS ("; +static const char esp_mail_str_252[] PROGMEM = " -FLAGS ("; +static const char esp_mail_str_253[] PROGMEM = "> C: set FLAG"; +static const char esp_mail_str_254[] PROGMEM = "> C: add FLAG"; +static const char esp_mail_str_255[] PROGMEM = "> C: remove FLAG"; +static const char esp_mail_str_256[] PROGMEM = "could not parse flag"; +static const char esp_mail_str_257[] PROGMEM = "delsp=\"yes\""; +static const char esp_mail_str_258[] PROGMEM = "session timed out"; +static const char esp_mail_str_259[] PROGMEM = "delsp=yes"; +static const char esp_mail_str_260[] PROGMEM = "< S: "; +static const char esp_mail_str_261[] PROGMEM = "> C: "; +static const char esp_mail_str_262[] PROGMEM = " NOTIFY="; +static const char esp_mail_str_263[] PROGMEM = ","; +static const char esp_mail_str_264[] PROGMEM = "SUCCESS"; +static const char esp_mail_str_265[] PROGMEM = "FAILURE"; +static const char esp_mail_str_266[] PROGMEM = "DELAY"; +static const char esp_mail_str_267[] PROGMEM = "Sending next Email..."; +static const char esp_mail_str_268[] PROGMEM = "> C: send next Email"; +static const char esp_mail_str_269[] PROGMEM = "header.fields (content-type Content-transfer-encoding)]"; +static const char esp_mail_str_270[] PROGMEM = "format=\"flowed\""; +static const char esp_mail_str_271[] PROGMEM = "> C: send inline data"; +static const char esp_mail_str_272[] PROGMEM = "Content-transfer-encoding: "; +static const char esp_mail_str_273[] PROGMEM = "Date: "; +static const char esp_mail_str_274[] PROGMEM = "Message-ID:"; +static const char esp_mail_str_275[] PROGMEM = "format=flowed"; +static const char esp_mail_str_276[] PROGMEM = "CC: "; +static const char esp_mail_str_277[] PROGMEM = "boundary=\""; +static const char esp_mail_str_278[] PROGMEM = "quoted-printable"; +static const char esp_mail_str_279[] PROGMEM = "Subject:"; +static const char esp_mail_str_280[] PROGMEM = "> C: no content"; +static const char esp_mail_str_281[] PROGMEM = "fail to open the mailbox"; +static const char esp_mail_str_282[] PROGMEM = "file I/O error"; +static const char esp_mail_str_283[] PROGMEM = "time.nist.gov"; +static const char esp_mail_str_284[] PROGMEM = "log in was disabled for this server"; +static const char esp_mail_str_285[] PROGMEM = "user="; +static const char esp_mail_str_286[] PROGMEM = "\1auth=Bearer "; +static const char esp_mail_str_287[] PROGMEM = "\1\1"; +static const char esp_mail_str_288[] PROGMEM = "> C: send smtp command, AUTH XOAUTH2"; +static const char esp_mail_str_289[] PROGMEM = "AUTH XOAUTH2 "; +static const char esp_mail_str_290[] PROGMEM = "> C: send imap command, AUTHENTICATE PLAIN"; +static const char esp_mail_str_291[] PROGMEM = "> C: send imap command, AUTH XOAUTH2"; +static const char esp_mail_str_292[] PROGMEM = "$ AUTHENTICATE XOAUTH2 "; +static const char esp_mail_str_293[] PROGMEM = "OAuth2.0 log in was disabled for this server"; +static const char esp_mail_str_294[] PROGMEM = "{\"status\":"; +static const char esp_mail_str_295[] PROGMEM = "0123456789ABCDEF"; +static const char esp_mail_str_296[] PROGMEM = "pool.ntp.org"; +static const char esp_mail_str_297[] PROGMEM = "Content-Type: multipart/alternative; boundary=\""; +static const char esp_mail_str_298[] PROGMEM = "Content-Type: multipart/related; boundary=\""; +static const char esp_mail_str_299[] PROGMEM = "Content-Disposition: inline; filename=\""; +static const char esp_mail_str_300[] PROGMEM = "Content-Location: "; +static const char esp_mail_str_301[] PROGMEM = "Content-ID: <"; +static const char esp_mail_str_302[] PROGMEM = "cid:"; +static const char esp_mail_str_303[] PROGMEM = "Finishing the message sending..."; +static const char esp_mail_str_304[] PROGMEM = "> C: Finish the message sending"; +static const char esp_mail_str_305[] PROGMEM = "connection failed"; +static const char esp_mail_str_306[] PROGMEM = "some of the requested messages no longer exist"; +static const char esp_mail_str_307[] PROGMEM = "Reading messages..."; +static const char esp_mail_str_308[] PROGMEM = "> C: reading plain TEXT message"; +static const char esp_mail_str_309[] PROGMEM = "> C: reading HTML message"; +static const char esp_mail_str_310[] PROGMEM = "> C: performing the SSL handshaking"; +static const char esp_mail_str_311[] PROGMEM = "STARTTLS\r\n"; +static const char esp_mail_str_312[] PROGMEM = "code: "; +static const char esp_mail_str_313[] PROGMEM = ", text: "; +static const char esp_mail_str_314[] PROGMEM = "> C: ESP Mail Client v"; +static const char esp_mail_str_315[] PROGMEM = " +FLAGS.SILENT (\\Deleted)"; +static const char esp_mail_str_316[] PROGMEM = "> C: delete message(s)"; +static const char esp_mail_str_317[] PROGMEM = "$ EXPUNGE"; +static const char esp_mail_str_318[] PROGMEM = "> C: copy message(s) to "; +static const char esp_mail_str_319[] PROGMEM = "$ UID COPY "; +static const char esp_mail_str_320[] PROGMEM = "> C: create folder"; +static const char esp_mail_str_321[] PROGMEM = "> C: delete folder"; +static const char esp_mail_str_322[] PROGMEM = "$ CREATE "; +static const char esp_mail_str_323[] PROGMEM = "$ DELETE "; +static const char esp_mail_str_324[] PROGMEM = "HEADER.FIELDS"; + +static const char esp_mail_smtp_response_1[] PROGMEM = "AUTH "; +static const char esp_mail_smtp_response_2[] PROGMEM = " LOGIN"; +static const char esp_mail_smtp_response_3[] PROGMEM = " PLAIN"; +static const char esp_mail_smtp_response_4[] PROGMEM = " XOAUTH2"; +static const char esp_mail_smtp_response_5[] PROGMEM = "STARTTLS"; +static const char esp_mail_smtp_response_6[] PROGMEM = "8BITMIME"; +static const char esp_mail_smtp_response_7[] PROGMEM = "BINARYMIME"; +static const char esp_mail_smtp_response_8[] PROGMEM = "CHUNKING"; +static const char esp_mail_smtp_response_9[] PROGMEM = "SMTPUTF8"; +static const char esp_mail_smtp_response_10[] PROGMEM = "PIPELINING"; +static const char esp_mail_smtp_response_11[] PROGMEM = " CRAM-MD5"; +static const char esp_mail_smtp_response_12[] PROGMEM = " DIGEST-MD5"; +static const char esp_mail_smtp_response_13[] PROGMEM = "DSN"; +//Tagged +static const char esp_mail_imap_response_1[] PROGMEM = "$ OK "; +static const char esp_mail_imap_response_2[] PROGMEM = "$ NO "; +static const char esp_mail_imap_response_3[] PROGMEM = "$ BAD "; +//Untagged +static const char esp_mail_imap_response_4[] PROGMEM = "* LIST "; +static const char esp_mail_imap_response_5[] PROGMEM = "* FLAGS "; +static const char esp_mail_imap_response_6[] PROGMEM = "* SEARCH "; +static const char esp_mail_imap_response_7[] PROGMEM = " FETCH "; +static const char esp_mail_imap_response_8[] PROGMEM = " NIL "; +static const char esp_mail_imap_response_9[] PROGMEM = " UID "; +static const char esp_mail_imap_response_10[] PROGMEM = "* CAPABILITY "; +static const char esp_mail_imap_response_11[] PROGMEM = "LOGINDISABLED"; +static const char esp_mail_imap_response_12[] PROGMEM = "AUTH=PLAIN"; +static const char esp_mail_imap_response_13[] PROGMEM = "AUTH=XOAUTH2"; +static const char esp_mail_imap_response_14[] PROGMEM = "STARTTLS"; +static const char esp_mail_imap_response_15[] PROGMEM = "CRAM-MD5"; +static const char esp_mail_imap_response_16[] PROGMEM = "DIGEST-MD5"; + +static const char imap_7bit_key1[] PROGMEM = "=20"; +static const char imap_7bit_val1[] PROGMEM = " "; +static const char imap_7bit_key2[] PROGMEM = "=2C"; +static const char imap_7bit_val2[] PROGMEM = ","; +static const char imap_7bit_key3[] PROGMEM = "=E2=80=99"; +static const char imap_7bit_val3[] PROGMEM = "'"; +static const char imap_7bit_key4[] PROGMEM = "=0A"; +static const char imap_7bit_val4[] PROGMEM = "\r\n"; +static const char imap_7bit_key5[] PROGMEM = "=0D"; +static const char imap_7bit_val5[] PROGMEM = "\r\n"; +static const char imap_7bit_key6[] PROGMEM = "=A0"; +static const char imap_7bit_val6[] PROGMEM = " "; +static const char imap_7bit_key7[] PROGMEM = "=B9"; +static const char imap_7bit_val7[] PROGMEM = "$sup1"; +static const char imap_7bit_key8[] PROGMEM = "=C2=A0"; +static const char imap_7bit_val8[] PROGMEM = " "; +static const char imap_7bit_key9[] PROGMEM = "=\r\n"; +static const char imap_7bit_val9[] PROGMEM = ""; +static const char imap_7bit_key10[] PROGMEM = "=E2=80=A6"; +static const char imap_7bit_val10[] PROGMEM = "…"; +static const char imap_7bit_key11[] PROGMEM = "=E2=80=A2"; +static const char imap_7bit_val11[] PROGMEM = "•"; +static const char imap_7bit_key12[] PROGMEM = "=E2=80=93"; +static const char imap_7bit_val12[] PROGMEM = "–"; +static const char imap_7bit_key13[] PROGMEM = "=E2=80=94"; +static const char imap_7bit_val13[] PROGMEM = "—"; + +static const unsigned char b64_index_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char boundary_table[] PROGMEM = "=_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +__attribute__((used)) static bool +compFunc(uint32_t i, uint32_t j) +{ + return (i > j); +} + +class MessageList +{ +public: + friend class IMAPSession; + MessageList(){}; + ~MessageList() { clear(); }; + void add(int uid) + { + if (uid > 0) + _list.push_back(uid); + } + + void clear() + { + _list.clear(); + } + +private: + std::vector _list = std::vector(); +}; + +/* The class that provides the info of selected or opened mailbox folder */ +class SelectedFolderInfo +{ +public: + friend class ESP_Mail_Client; + friend class IMAPSession; + SelectedFolderInfo(){}; + ~SelectedFolderInfo() { clear(); }; + + /* Get the flags count for this mailbox */ + size_t flagCount() { return _flags.size(); }; + + /* Get the numbers of messages in this mailbox */ + size_t msgCount() { return _msgCount; }; + + /* Get the predict next message UID */ + size_t nextUID() { return _nextUID; }; + + /* Get the numbers of messages from search result based on the search criteria */ + size_t searchCount() { return _searchCount; }; + + /* Get the numbers of messages to be stored in the ressult */ + size_t availableMessages() { return _availableItems; }; + + /* Get the flag argument at the specified index */ + String flag(size_t index) + { + if (index < _flags.size()) + return _flags[index].c_str(); + return ""; + } + +private: + void addFlag(const char *flag) + { + _flags.push_back(flag); + }; + void clear() + { + for (size_t i = 0; i < _flags.size(); i++) + std::string().swap(_flags[i]); + _flags.clear(); + } + size_t _msgCount = 0; + size_t _nextUID = 0; + size_t _searchCount = 0; + size_t _availableItems = 0; + std::vector _flags = std::vector(); +}; + +/* The class that provides the list of FolderInfo e.g. name, attributes and delimiter */ +class FoldersCollection +{ +public: + friend class ESP_Mail_Client; + friend class IMAPSession; + FoldersCollection(){}; + ~FoldersCollection() { clear(); }; + size_t size() { return _folders.size(); }; + + esp_mail_folder_info_item_t info(size_t index) + { + esp_mail_folder_info_item_t fd; + if (index < _folders.size()) + { + fd.name = _folders[index].name.c_str(); + fd.attributes = _folders[index].attributes.c_str(); + fd.delimiter = _folders[index].delimiter.c_str(); + } + return fd; + } + +private: + void add(esp_mail_folder_info_t &fd) { _folders.push_back(fd); }; + void clear() + { + for (size_t i = 0; i < _folders.size(); i++) + { + if (_folders[i].name.length() > 0) + std::string().swap(_folders[i].name); + if (_folders[i].attributes.length() > 0) + std::string().swap(_folders[i].attributes); + if (_folders[i].delimiter.length() > 0) + std::string().swap(_folders[i].delimiter); + } + _folders.clear(); + } + std::vector _folders = std::vector(); +}; + +/* The class that provides the status of message feching and searching */ +class IMAP_Status +{ +public: + IMAP_Status(); + ~IMAP_Status(); + const char *info(); + bool success(); + void empty(); + friend class IMAPSession; + + std::string _info = ""; + bool _success = false; +}; + +/* The SMTP message class */ +class SMTP_Message +{ +public: + SMTP_Message(){}; + ~SMTP_Message() { clear(); }; + + void resetAttachItem(SMTP_Attachment &att) + { + att.blob.size = 0; + att.blob.data = nullptr; + att.file.path = ""; + att.file.storage_type = esp_mail_file_storage_type_none; + att.descr.name = ""; + att.descr.filename = ""; + att.descr.transfer_encoding = ""; + att.descr.content_encoding = ""; + att.descr.mime = ""; + att._int.att_type = esp_mail_att_type_none; + att._int.index = 0; + att._int.msg_uid = 0; + att._int.flash_blob = false; + att._int.binary = false; + att._int.parallel = false; + att._int.cid = ""; + } + + void clear() + { + sender.name = ""; + sender.email = ""; + subject = ""; + text.charSet = ""; + text.content = ""; + text.content_type = ""; + text.embed.enable = false; + html.charSet = ""; + html.content = ""; + html.content_type = ""; + html.embed.enable = false; + response.reply_to = ""; + response.notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; + priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + for (size_t i = 0; i < _rcp.size(); i++) + { + _rcp[i].name = ""; + _rcp[i].email = ""; + } + + for (size_t i = 0; i < _cc.size(); i++) + _cc[i].email = ""; + + for (size_t i = 0; i < _bcc.size(); i++) + _bcc[i].email = ""; + + for (size_t i = 0; i < _hdr.size(); i++) + _hdr[i] = ""; + + for (size_t i = 0; i < _att.size(); i++) + { + _att[i].descr.filename = ""; + _att[i].blob.data = nullptr; + _att[i].descr.mime = ""; + _att[i].descr.name = ""; + _att[i].blob.size = 0; + _att[i].descr.transfer_encoding = ""; + _att[i].file.path = ""; + _att[i].file.storage_type = esp_mail_file_storage_type_none; + } + + for (size_t i = 0; i < _parallel.size(); i++) + { + _parallel[i].descr.filename = ""; + _parallel[i].blob.data = nullptr; + _parallel[i].descr.mime = ""; + _parallel[i].descr.name = ""; + _parallel[i].blob.size = 0; + _parallel[i].descr.transfer_encoding = ""; + _parallel[i].file.path = ""; + _parallel[i].file.storage_type = esp_mail_file_storage_type_none; + } + _rcp.clear(); + _cc.clear(); + _bcc.clear(); + _hdr.clear(); + _att.clear(); + _parallel.clear(); + } + + /** Clear all the inline images + */ + void clearInlineimages() + { + for (size_t i = _att.size() - 1; i >= 0; i--) + { + if (_att[i]._int.att_type == esp_mail_att_type_inline) + _att.erase(_att.begin() + i); + } + }; + + /* Clear all the attachments */ + void clearAttachments() + { + for (size_t i = _att.size() - 1; i >= 0; i--) + { + if (_att[i]._int.att_type == esp_mail_att_type_attachment) + _att.erase(_att.begin() + i); + } + + for (size_t i = _parallel.size() - 1; i >= 0; i--) + _parallel.erase(_parallel.begin() + i); + }; + + /** Clear all rfc822 message attachment + */ + void clearRFC822Messages() + { + for (size_t i = _rfc822.size() - 1; i >= 0; i--) + { + _rfc822[i].clear(); + _rfc822.erase(_rfc822.begin() + i); + } + }; + + /** Clear the primary recipient mailboxes + */ + void clearRecipients() { _rcp.clear(); }; + + /** Clear the Carbon-copy recipient mailboxes + */ + void clearCc() { _cc.clear(); }; + + /** Clear the Blind-carbon-copy recipient mailboxes + */ + void clearBcc() { _bcc.clear(); }; + + /** Clear the custom message headers + */ + void clearHeader() { _hdr.clear(); }; + + /** Add attachment to the message + * + * @param att The SMTP_Attachment data item + */ + void addAttachment(SMTP_Attachment &att) + { + att._int.att_type = esp_mail_att_type_attachment; + att._int.parallel = false; + att._int.flash_blob = true; + _att.push_back(att); + }; + + /** Add parallel attachment to the message + * + * @param att The SMTP_Attachment data item + */ + void addParallelAttachment(SMTP_Attachment &att) + { + att._int.att_type = esp_mail_att_type_attachment; + att._int.parallel = true; + att._int.flash_blob = true; + _parallel.push_back(att); + }; + + /** Add inline image to the message + * + * @param att The SMTP_Attachment data item + */ + void addInlineImage(SMTP_Attachment &att) + { + att._int.flash_blob = true; + att._int.parallel = false; + att._int.att_type = esp_mail_att_type_inline; + char *tmp = new char[36]; + memset(tmp, 0, 36); + itoa(random(10000000, 20000000), tmp, 10); + att._int.cid = tmp; + delete[] tmp; + _att.push_back(att); + }; + + /** Add rfc822 message to the message + * + * @param msg The RFC822_Message class object + */ + void addMessage(SMTP_Message &msg) + { + _rfc822.push_back(msg); + } + + /** Add the primary recipient mailbox to the message + * + * @param name The name of primary recipient + * @param email The Email address of primary recipient + */ + void addRecipient(const char *name, const char *email) + { + struct esp_mail_smtp_recipient_t rcp; + rcp.name = name; + rcp.email = email; + _rcp.push_back(rcp); + }; + + /** Add Carbon-copy recipient mailbox + * + * @param email The Email address of the secondary recipient + */ + void addCc(const char *email) + { + struct esp_mail_smtp_recipient_address_t cc; + cc.email = email; + _cc.push_back(cc); + }; + + /** Add Blind-carbon-copy recipient mailbox + * + * @param email The Email address of the tertiary recipient + */ + void addBcc(const char *email) + { + struct esp_mail_smtp_recipient_address_t bcc; + bcc.email = email; + _bcc.push_back(bcc); + }; + + /** Add the custom header to the message + * + * @param hdr The header name and value + */ + void addHeader(const char *hdr) { _hdr.push_back(hdr); }; + + /* The message author config */ + esp_mail_email_info_t sender; + + /* The topic of message */ + const char *subject = ""; + + /* The message type */ + byte type = esp_mail_msg_type_none; + + /* The PLAIN text message */ + esp_mail_plain_body_t text; + + /* The HTML text message */ + esp_mail_html_body_t html; + + /* The response config */ + esp_mail_smtp_msg_response_t response; + + /* The priority of the message */ + esp_mail_smtp_priority priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /* The enable options */ + esp_mail_smtp_enable_option_t enable; + + /* The message from config */ + esp_mail_email_info_t from; + + /* The message identifier */ + const char *messageID = ""; + + /* The keywords or phrases, separated by commas */ + const char *keyword = ""; + + /* The comment about message */ + const char *comment = ""; + + /* The date of message */ + const char *date = ""; + + /* The return recipient of the message */ + const char *return_path = ""; + +private: + friend class ESP_Mail_Client; + std::vector _rcp = std::vector(); + std::vector _cc = std::vector(); + std::vector _bcc = std::vector(); + std::vector _hdr = std::vector(); + std::vector _att = std::vector(); + std::vector _parallel = std::vector(); + std::vector _rfc822 = std::vector(); +}; + +class SMTP_Status +{ +public: + friend class SMTPSession; + friend class ESP_Mail_Client; + + SMTP_Status(); + ~SMTP_Status(); + const char *info(); + bool success(); + void empty(); + size_t completedCount(); + size_t failedCount(); + +private: + std::string _info = ""; + bool _success = false; + size_t _sentSuccess = 0; + size_t _sentFailed = 0; +}; + +typedef void (*imapStatusCallback)(IMAP_Status); +typedef void (*smtpStatusCallback)(SMTP_Status); + +class ESP_Mail_Client +{ + +public: + /** Sending Email through the SMTP server + * + * @param smtp The pointer to SMTP session object which holds the data and the TCP client. + * @param msg The pointer to SMTP_Message class which contains the header, body, and attachments. + * @param closeSession The option to Close the SMTP session after sent. + * @return The boolean value indicates the success of operation. + */ + bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); + + /** Reading Email through IMAP server. + * + * @param imap The pointer to IMAP sesssion object which holds the data and the TCP client. + + * @param closeSession The option to close the IMAP session after fetching or searching the Email. + * @return The boolean value indicates the success of operation. + */ + bool readMail(IMAPSession *imap, bool closeSession = true); + + /** Set the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the TCP client. + * @param msgUID The UID of the message. + * @param flags The flag list to set. + * @param closeSession The option to close the IMAP session after set flag. + * @return The boolean value indicates the success of operation. + */ + bool setFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); + + /** Add the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the TCP client. + * @param msgUID The UID of the message. + * @param flags The flag list to set. + * @param closeSession The option to close the IMAP session after add flag. + * @return The boolean value indicates the success of operation. + */ + bool addFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); + + /** Remove the argument from the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the TCP client. + * @param msgUID The UID of the message that flags to be removed. + * @param flags The flag list to remove. + * @param closeSession The option to close the IMAP session after remove flag. + * @return The boolean value indicates the success of operation. + */ + bool removeFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); + + /** Initialize the SD card with the SPI port. + * + * @param sck The SPI Clock pin (ESP32 only). + * @param miso The SPI MISO pin (ESSP32 only). + * @param mosi The SPI MOSI pin (ESP32 only). + * @param ss The SPI Chip/Slave Select pin (ESP32 and ESP8266). + * @return The boolean value indicates the success of operation. + */ + bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); + + /** Initialize the SD card with the default SPI port. + * + * @return The boolean value which indicates the success of operation. + */ + bool sdBegin(void); + + ESPTimeHelper Time; + +private: + friend class SMTPSession; + friend class IMAPSession; +#if defined(ESP8266) + void + setClock(float offset); +#endif + + RFC2047_Decoder RFC2047Decoder; + File file; + + bool _sdOk = false; + bool _flashOk = false; + bool _sdConfigSet = false; + uint8_t _sck, _miso, _mosi, _ss; + +#if defined(ESP8266) + bool _clockReady = false; + uint8_t _sdPin = SD_CS_PIN; + float _gmtOffset = 0.0; +#endif + + unsigned long _lastReconnectMillis = 0; + uint16_t _reconnectTimeout = ESP_MAIL_WIFI_RECONNECT_TIMEOUT; + + bool _sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); + bool reconnect(SMTPSession *smtp, unsigned long dataTime = 0); + bool reconnect(IMAPSession *imap, unsigned long dataTime = 0, bool downloadRequestuest = false); + void closeTCP(SMTPSession *smtp); + void closeTCP(IMAPSession *imap); + void getMIME(const char *ext, std::string &mime); + void mimeFromFile(const char *name, std::string &mime); +#if defined(ESP32) + void setSecure(ESP_Mail_HTTPClient32 &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert); +#elif defined(ESP8266) + void setSecure(ESP_Mail_HTTPClient &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert); +#endif + void delS(char *p); + char *newS(size_t len); + char *newS(char *p, size_t len); + char *newS(char *p, size_t len, char *d); + bool strcmpP(const char *buf, int ofs, PGM_P beginH); + int strposP(const char *buf, PGM_P beginH, int ofs); + char *strP(PGM_P pgm); + void appendP(std::string &buf, PGM_P p, bool empty); + char *intStr(int value); + void errorStatusCB(SMTPSession *smtp, int error); + size_t smtpSendP(SMTPSession *smtp, PGM_P v, bool newline = false); + size_t smtpSend(SMTPSession *smtp, const char *data, bool newline = false); + size_t smtpSend(SMTPSession *smtp, int data, bool newline = false); + size_t smtpSend(SMTPSession *smtp, uint8_t *data, size_t size); + bool getMultipartFechCmd(IMAPSession *imap, int msgIdx, std::string &partText); + bool multipartMember(const std::string &part, const std::string &check); + bool fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx); + bool connected(IMAPSession *imap); + bool imapAuth(IMAPSession *imap); + bool sendIMAPCommand(IMAPSession *imap, int msgIndex, int cmdCase); + bool handleSMTPError(SMTPSession *smtp, int err, bool ret = false); + void errorStatusCB(IMAPSession *imap, int error); + size_t imapSendP(IMAPSession *imap, PGM_P v, bool newline = false); + size_t imapSend(IMAPSession *imap, const char *data, bool nwline = false); + size_t imapSend(IMAPSession *imap, int data, bool newline = false); + std::string getBoundary(size_t len); + std::string getEncodedToken(IMAPSession *imap); + bool imapLogout(IMAPSession *imap); + bool sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary); + bool sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool parallel = false); + + bool sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG); + bool sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool closeSession, bool rfc822MSG); + void getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, std::string &buf); + bool bdat(SMTPSession *smtp, SMTP_Message *msg, int len, bool last); + void checkBinaryData(SMTPSession *smtp, SMTP_Message *msg); + bool sendBlob(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att); + bool sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file); + bool openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file, std::string &s, std::string &buf, const std::string &boundary, bool inlined); + bool sendInline(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, byte type); + void debugInfoP(PGM_P info); + size_t numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg); + bool validEmail(const char *s); + bool checkEmail(SMTPSession *smtp, SMTP_Message *msg); + bool sendPartText(SMTPSession *smtp, SMTP_Message *msg, byte type, const char *boundary); + char *getUID(); + void encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, std::string &content); + void splitTk(std::string &str, std::vector &tk, const char *delim); + void formatFlowedText(std::string &content); + void softBreak(std::string &content, const char *quoteMarks); + bool sendMSG(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary); + void getAttachHeader(std::string &header, const std::string &boundary, SMTP_Attachment *attach); + void getRFC822PartHeader(SMTPSession *smtp, std::string &header, const std::string &boundary); + void getInlineHeader(std::string &header, const std::string &boundary, SMTP_Attachment *inlineAttach); + unsigned char *decodeBase64(const unsigned char *src, size_t len, size_t *out_len); + std::string encodeBase64Str(const unsigned char *src, size_t len); + std::string encodeBase64Str(uint8_t *src, size_t len); + void encodeQP(const char *buf, char *out); + bool sendBase64(SMTPSession *smtp, SMTP_Message *msg, const unsigned char *data, size_t len, bool flashMem, const char *filename, bool report); + bool sendBase64Stream(SMTPSession *smtp, SMTP_Message *msg, File file, const char *filename, bool report); + void smtpCBP(SMTPSession *smtp, PGM_P info, bool success = false); + void smtpCB(SMTPSession *smtp, const char *info, bool success = false); + void imapCBP(IMAPSession *imap, PGM_P info, bool success); + void imapCB(IMAPSession *imap, const char *info, bool success); + int readLine(WiFiClient *stream, char *buf, int bufLen, bool crlf, int &count); +#if defined(ESP32) + int _readLine(ESP_Mail_WCS32 *stream, char *buf, int bufLen, bool crlf, int &count); +#elif defined(ESP8266) + int _readLine(ESP_Mail::ESP_Mail_WCS *stream, char *buf, int bufLen, bool crlf, int &count); +#endif + int getMSGNUM(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, bool &endSearch, int &nump, const char *key, const char *pc); + void handleHeader(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, struct esp_mail_message_header_t &header, int &headerState, int &octetCount); + void setHeader(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state); + void handlePartHeader(IMAPSession *imap, char *buf, int &chunkIdx, struct esp_mail_message_part_info_t &part); + char *subStr(const char *buf, PGM_P beginH, PGM_P endH, int beginPos, int endPos = 0); + struct esp_mail_message_part_info_t *cPart(IMAPSession *imap); + struct esp_mail_message_header_t *cHeader(IMAPSession *imap); + void strcat_c(char *str, char c); + int strpos(const char *haystack, const char *needle, int offset); + char *stristr(const char *str1, const char *str2); + char *rstrstr(const char *haystack, const char *needle); + int rstrpos(const char *haystack, const char *needle, int offset); + void getResponseStatus(const char *buf, esp_mail_smtp_status_code respCode, int beginPos, struct esp_mail_smtp_response_status_t &status); + void handleAuth(SMTPSession *smtp, char *buf); + std::string getEncodedToken(SMTPSession *smtp); + bool connected(SMTPSession *smtp); + bool setSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result); + bool smtpAuth(SMTPSession *smtp); + int available(SMTPSession *smtp); + bool handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_status_code respCode, int errCode); + int available(IMAPSession *imap); + bool handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession); + void downloadReport(IMAPSession *imap, int progress); + void fetchReport(IMAPSession *imap, int progress, bool html); + void searchReport(int progress, const char *percent); + void uploadReport(const char *filename, int progress); + int cMSG(IMAPSession *imap); + int cIdx(IMAPSession *imap); + esp_mail_imap_response_status imapResponseStatus(IMAPSession *imap, char *response); + void saveHeader(IMAPSession *imap); + esp_mail_char_decoding_scheme getEncodingFromCharset(const char *enc); + void decodeHeader(std::string &headerField, std::string &headerEnc); + bool handleAttachment(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetCount, int &octetLength, int &oCount, int &reportState, int &downloadCount); + int decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen); + void decodeTIS620_UTF8(char *out, const char *in, size_t len); + void decodeText(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetLength, int &readDataLen, int &readCount); + void prepareFilePath(IMAPSession *imap, std::string &filePath, bool header); + int decodeChar(const char *s); + void decodeQP(const char *buf, char *out); + char *decode7Bit(char *buf); + char *strReplace(char *orig, char *rep, char *with); + char *strReplaceP(char *buf, PGM_P key, PGM_P value); + bool authFailed(char *buf, int bufLen, int &chunkIdx, int ofs); + void handleFolders(IMAPSession *imap, char *buf); + void handleCapability(IMAPSession *imap, char *buf, int &chunkIdx); + void handleExamine(IMAPSession *imap, char *buf); + bool handleIMAPError(IMAPSession *imap, int err, bool ret); + bool _setFlag(IMAPSession *imap, int msgUID, const char *flags, uint8_t action, bool closeSession); + void createDirs(std::string dirs); + bool sdTest(); +}; + +class IMAPSession +{ +public: + IMAPSession(); + ~IMAPSession(); + + /** Begin the IMAP server connection. + * + * @param session The pointer to ESP_Mail_Session structured data that keeps the server and log in details. + * @param config The pointer to IMAP_Config structured data that keeps the operation options. + * @return The boolean value which indicates the success of operation. + */ + bool connect(ESP_Mail_Session *session, IMAP_Config *config); + + /** Close the IMAP session. + * + * @return The boolean value which indicates the success of operation. + */ + bool closeSession(); + + /** Set to enable the debug. + * + * @param level The level to enable the debug message + * level = 0, no debug + * level = 1, basic debug + * level = 2, full debug 1 + * level = 333, full debug 2 + */ + void debug(int level); + + /** Get the list of all the mailbox folders since the TCP session was opened and user was authenticated. + * + * @param folders The FoldersCollection class that contains the collection of the + * FolderInfo structured data. + * @return The boolean value which indicates the success of operation. + */ + bool getFolders(FoldersCollection &folders); + + /** Select or open the mailbox folder to search or fetch the message inside. + * + * @param folderName The known mailbox folder name. The default name is INBOX. + * @param readOnly The option to open the mailbox for read only. Set this option to false when you wish + * to modify the Flags using the setFlag, addFlag and removeFlag functions. + * @return The boolean value which indicates the success of operation. + */ + bool selectFolder(const char *folderName, bool readOnly = true); + + /** Open the mailbox folder to read or search the mesages. + * + * @param folderName The name of known mailbox folder to be opened. + * @param readOnly The option to open the mailbox for reading only. Set this option to false when you wish + * to modify the flags using the setFlag, addFlag and removeFlag functions. + * @return The boolean value which indicates the success of operation. + */ + bool openFolder(const char *folderName, bool readOnly = true); + + /** Close the mailbox folder that was opened. + * + * @param folderName The known mailbox folder name. + * @return The boolean value which indicates the success of operation. + */ + bool closeFolder(const char *folderName); + + /** Create folder. + * + * @param folderName The name of folder to create. + * @return The boolean value which indicates the success of operation. + */ + bool createFolder(const char *folderName); + + /** Delete folder. + * + * @param folderName The name of folder to delete. + * @return The boolean value which indicates the success of operation. + */ + bool deleteFolder(const char *folderName); + + /** Copy the messages to the defined mailbox folder. + * + * @param toCopy The pointer to the MessageListList class that contains the list of messages to copy. + * @param dest The destination folder that the messages to copy to. + * @return The boolean value which indicates the success of operation. + */ + bool copyMessages(MessageList *toCopy, const char* dest); + + /** Delete the messages in the opened mailbox folder. + * + * @param toDelete The pointer to the MessageListList class that contains the list of messages to delete. + * @param expunge The boolean option to expunge all messages. + * @return The boolean value which indicates the success of operation. + */ + bool deleteMessages(MessageList *toDelete, bool expunge = false); + + /** Assign the callback function that returns the operating status when fetching or reading the Email. + * + * @param imapCallback The function that accepts the imapStatusCallback as parameter. + */ + void callback(imapStatusCallback imapCallback); + + /** Determine if no message body contained in the search result and only the message header is available. + */ + bool headerOnly(); + + /** Get the message list from search or fetch the Emails + * + * @return The IMAP_MSG_List structured data which contains text and html contents, + * attachments, inline images, embedded rfc822 messages details for each message. + */ + IMAP_MSG_List data(); + + /** Get the details of the selected or opned mailbox folder + * + * @return The SelectedFolderInfo class which contains the info about flags, total messages, next UID, + * search count and the available messages count. + */ + SelectedFolderInfo selectedFolder(); + + /** Get the error details when readingg the Emails + * + * @return The string of error details. + */ + String errorReason(); + + /** Clear all the cache data stored in the IMAP session object. + */ + void empty(); + + friend class ESP_Mail_Client; + friend class foldderList; + +private: + void clearMessageData(); + void checkUID(); + void checkPath(); + void getMessages(uint16_t messageIndex, esp_mail_imap_msg_item_t &msg); + void getRFC822Messages(uint16_t messageIndex, esp_mail_imap_msg_item_t &msg); + bool closeMailbox(); + bool openMailbox(const char *folder, esp_mail_imap_auth_mode mode, bool waitResponse); + bool getMailboxes(FoldersCollection &flders); + bool checkCapability(); + + bool _tcpConnected = false; + esp_mail_imap_response_status_t _imapStatus; + int _cMsgIdx = 0; + int _cPartIdx = 0; + int _totalRead = 0; + std::vector _headers = std::vector(); + + esp_mail_imap_command _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login; + //std::string _partNumStr = ""; + std::vector _multipart_levels = std::vector(); + int _rfc822_part_count = 0; + esp_mail_file_storage_type _storageType = esp_mail_file_storage_type::esp_mail_file_storage_type_flash; + bool _unseen = false; + bool _readOnlyMode = true; + struct esp_mail_auth_capability_t _auth_capability; + ESP_Mail_Session *_sesson_cfg; + std::string _currentFolder = ""; + bool _mailboxOpened = false; + std::string _nextUID = ""; + + esp_mail_imap_read_config_t *_config = nullptr; + + bool _headerOnly = true; + bool _uidSearch = false; + bool _headerSaved = false; + bool _debug = false; + int _debugLevel = 0; + bool _secure = false; + imapStatusCallback _readCallback = NULL; + + std::vector _msgNum = std::vector(); + FoldersCollection _folders; + SelectedFolderInfo _mbif; + + int _certType = -1; + std::shared_ptr _caCert = nullptr; + +#if defined(ESP32) + ESP_Mail_HTTPClient32 httpClient; +#elif defined(ESP8266) + ESP_Mail_HTTPClient httpClient; +#endif + + IMAP_Status _cbData; +}; + +class SendingResult +{ +private: + std::vector _result = std::vector(); + void add(esp_mail_smtp_send_status_t r) + { + esp_mail_smtp_send_status_t _r = r; + _result.push_back(_r); + } + void clear() + { + for (size_t i = 0; i < _result.size(); i++) + { + _result[i].recipients = ""; + _result[i].subject = ""; + _result[i].timesstamp = 0; + _result[i].completed = false; + } + _result.clear(); + } + +public: + friend class SMTPSession; + friend class ESP_Mail_Client; + SendingResult(){}; + ~SendingResult() { clear(); }; + SMTP_Result getItem(size_t index) + { + esp_mail_smtp_send_status_t r; + if (index < _result.size()) + return _result[index]; + return r; + } + size_t size() { return _result.size(); }; +}; + +class SMTPSession +{ +public: + SMTPSession(); + ~SMTPSession(); + + /** Begin the SMTP server connection. + * + * @param session The pointer to ESP_Mail_Session structured data that keeps the server and log in details. + * @return The boolean value indicates the success of operation. + */ + bool connect(ESP_Mail_Session *session); + + /** Close the SMTP session. + * + */ + bool closeSession(); + + /** Set to enable the debug. + * + * @param level The level to enable the debug message + * level = 0, no debug + * level = 1, basic debug + * level = 2, full debug 1 + * level = 333, full debug 2 + */ + void debug(int level); + + /** Get the error details when sending the Email + * + * @return The string of error details. + */ + String errorReason(); + + /** Set the Email sending status callback function. + * + * @param smtpCallback The callback function that accept the smtpStatusCallback param. + */ + void callback(smtpStatusCallback smtpCallback); + + SendingResult sendingResult; + + friend class ESP_Mail_Client; + +private: + bool _tcpConnected = false; + esp_mail_smtp_response_status_t _smtpStatus; + int _sentSuccessCount = 0; + int _sentFailedCount = 0; + bool _chunkedEnable = false; + int _chunkCount = 0; + + esp_mail_smtp_command _smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting; + struct esp_mail_auth_capability_t _auth_capability; + struct esp_mail_smtp_capability_t _send_capability; + ESP_Mail_Session *_sesson_cfg; + + bool _debug = false; + int _debugLevel = 0; + bool _secure = false; + smtpStatusCallback _sendCallback = NULL; + + SMTP_Status _cbData; + esp_mail_smtp_msg_type_t _msgType; + + int _certType = -1; + std::shared_ptr _caCert = nullptr; + +#if defined(ESP32) + ESP_Mail_HTTPClient32 httpClient; +#elif defined(ESP8266) + ESP_Mail_HTTPClient httpClient; +#endif +}; + +static void __attribute__((used)) esp_mail_debug(const char *msg) +{ + delay(0); + Serial.println(msg); +} + +static void __attribute__((used)) esp_mail_debug_line(const char *msg, bool newline) +{ + delay(0); + if (newline) + Serial.println(msg); + else + Serial.print(msg); +} + +extern ESP_Mail_Client MailClient; + +#endif //ESP_Mail_Client_H diff --git a/lib/lib_div/lib_mail/src/README.md b/lib/lib_div/lib_mail/src/README.md new file mode 100755 index 000000000..874193eac --- /dev/null +++ b/lib/lib_div/lib_mail/src/README.md @@ -0,0 +1,1949 @@ +# ESP Mail Client Arduino Library for ESP32 and ESP8266 + + +The detail and usage of the available functions in the latest version (1.0.13) are showed below. + + +## Global functions + + +#### Sending Email through the SMTP server. + +param **`smtp`** The pointer to SMTP session object which holds the data and the TCP client. + +param **`msg`** The pointer to SMTP_Message class which contains the header, body, and attachments. + +param **`closeSession`** The option to Close the SMTP session after sent. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); +``` + + + + + +#### Reading Email through IMAP server. + +param **`imap`** The pointer to IMAP sesssion object which holds the data and the TCP client. + +param **`closeSession`** The option to close the IMAP session after fetching or searching the Email. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool readMail(IMAPSession *imap, bool closeSession = true); +``` + + + + + +#### Set the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message. + +param **`flags`** The flag list to set. + +param **`closeSession`** The option to close the IMAP session after set flag. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool setFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); +``` + + + + + +#### Add the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message. + +param **`flags`** The flag list to set. + +param **`closeSession`** The option to close the IMAP session after add flag. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool addFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); +``` + + + + + + +#### Remove the argument from the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message that flags to be removed. + +param **`flags`** The flag list to remove. + +param **`closeSession`** The option to close the IMAP session after remove flag. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool removeFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); +``` + + + + + + +#### Initialize the SD card with the SPI port. + +param **`sck`** The SPI Clock pin (ESP32 only). + +param **`miso`** The SPI MISO pin (ESSP32 only). + +param **`mosi`** The SPI MOSI pin (ESP32 only). + +param **`ss`** The SPI Chip/Slave Select pin (ESP32 and ESP8266). + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); +``` + + + + + + +#### Initialize the SD card with the default SPI port. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool sdBegin(void); +``` + + + + + + +## IMAPSession class functions + + +The following functions are available from the IMAP Session class. + +This class used for controlling IMAP transports and retrieving the data from the IMAP server. + + + + + +#### Begin the IMAP server connection. + +param **`session`** The pointer to ESP_Mail_Session structured data that keeps the server and log in details. + +param **`config`** The pointer to IMAP_Config structured data that keeps the operation options. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool connect(ESP_Mail_Session *session, IMAP_Config *config); +``` + + +#### Close the IMAP session. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool closeSession(); +``` + + + + + + +#### Set to enable the debug. + +param **`level`** The level to enable the debug message + +level = 0, no debug + +level = 1, basic debug + +level = 2, full debug 1 + +level = 333, full debug 2 + +```C++ +void debug(int level); +``` + + + + + +#### Get the list of all the mailbox folders since the TCP session was opened and user was authenticated. + +param **`folders`** The FoldersCollection class that contains the collection of the +FolderInfo structured data. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool getFolders(FoldersCollection &folders); +``` + + + + + +#### Select or open the mailbox folder to search or fetch the message inside. + +param **`folderName`** The known mailbox folder name. The default name is INBOX. + +param **`readOnly`** The option to open the mailbox for read only. Set this option to false when you wish +to modify the Flags using the setFlag, addFlag and removeFlag functions. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool selectFolder(const char *folderName, bool readOnly = true); +``` + + + + + +#### Open the mailbox folder to read or search the mesages. + +param **`folderName`** The name of known mailbox folder to be opened. + +param **`readOnly`** The option to open the mailbox for reading only. Set this option to false when you wish +to modify the flags using the setFlag, addFlag and removeFlag functions. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool openFolder(const char *folderName, bool readOnly = true); +``` + + + + + +#### Close the mailbox folder that was opened. + +param **`folderName`** The mailbox folder name. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool closeFolder(const char *folderName); +``` + + + + + + +#### Create folder. + +param **`folderName`** The name of folder to create. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool createFolder(const char *folderName); +``` + + + + + + +#### Delete folder. + +param **`folderName`** The name of folder to delete.. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool deleteFolder(const char *folderName); +``` + + + + + + +#### Copy the messages to the defined mailbox folder. + +param **`toCopy`** The pointer to the MessageList class that contains the list of messages to copy. + +param **`dest`** The destination folder that the messages to copy to. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool copyMessages(MessageList *toCopy, const char *dest); +``` + + + + + +#### Delete the messages in the opened mailbox folder. + +param **`toDelete`** The pointer to the MessageList class that contains the list of messages to delete. + +param **`expunge`** The boolean option to expunge all messages. + +return **`boolean`** The boolean value which indicates the success of operation. + +```C++ +bool deleteMessages(MessageList *toDelete, bool expunge = false); +``` + + + + + + + +#### Assign the callback function that returns the operating status when fetching or reading the Email. + +param **`imapCallback`** The function that accepts the imapStatusCallback as parameter. + +```C++ +void callback(imapStatusCallback imapCallback); +``` + + + + + +#### Determine if no message body contained in the search result and only the message header is available. + +```C++ +bool headerOnly(); +``` + + + + + +#### Get the message list from search or fetch the Emails + +return **`The IMAP_MSG_List structured`** data which contains the text and html contents, +attachments, inline images, embedded rfc822 messages details for each message. + +```C++ +IMAP_MSG_List data(); +``` + + + + + +#### Get the details of the selected or opned mailbox folder + +return **`The SelectedFolderInfo class`** instance which contains the info about flags, total messages, next UID, +earch count and the available messages count. + +```C++ +SelectedFolderInfo selectedFolder(); +``` + + + + + +#### Get the error details when readingg the Emails + +return **`String`** The string of error details. + +```C++ +String errorReason(); +``` + + + + + +#### Clear all the cache data stored in the IMAP session object. + +```C++ +void empty(); +``` + + + + + +## IMAPSession class functions + + +The following functions are available from the SMTP Session class. + +This class is similar to the IMAP session class, used for controlling SMTP transports +and retrieving the data from the SMTP server. + + + + + + +#### Begin the SMTP server connection. + +param **`session`** The pointer to ESP_Mail_Session structured data that keeps the server and log in details. + +return **`boolean`** The boolean value indicates the success of operation. + +```C++ +bool connect(ESP_Mail_Session *session); +``` + + + + + +### Close the SMTP session. + +```C++ +bool closeSession(); +``` + + + + + +#### Set to enable the debug. + +param **`level`** The level to enable the debug message + +level = 0, no debug + +level = 1, basic debug + +level = 2, full debug 1 + +level = 333, full debug 2 + +```C++ +void debug(int level); +``` + + + + + +#### Get the error details when sending the Email + +return **`String`** The string of error details. + +```C++ +String errorReason(); +``` + + + + + +#### Set the Email sending status callback function. + +param **`smtpCallback`** The callback function that accept the smtpStatusCallback param. + +```C++ +void callback(smtpStatusCallback smtpCallback); +``` + + + + + +## SMTP_Message class functions + + +The following functions are available from the SMTP Message class. + +This class is used for storing the message data including headers, body and attachments +which will be processed with the SMTP session class. + + + + +#### To reset the SMTP_Attachment item data + +param **`att`** The SMTP_Attachment class that stores the info about attachment + +This function was used for clear the internal data of attachment item to be ready for reuse. + +```C++ +void resetAttachItem(SMTP_Attachment &att); +``` + + + +#### To clear all data in SMTP_Message class included headers, bodies and attachments + +```C++ +void clear(); +``` + + + + +#### To clear all the inline images in SMTP_Message class. + +```C++ +void clearInlineimages(); +``` + + + + + +#### To clear all the attachments. + +```C++ +void clearAttachments(); +``` + + + + + +#### To clear all rfc822 message attachment. + +```C++ +void clearRFC822Messages(); +``` + + + + + +#### To clear the primary recipient mailboxes. + +```C++ +void clearRecipients(); +``` + + + + + +#### To clear the Carbon-copy recipient mailboxes. + +```C++ +void clearCc(); +``` + + + + + +#### To clear the Blind-carbon-copy recipient mailboxes. + +```C++ +void clearBcc(); +``` + + +#### To clear the custom message headers. + +```C++ +void clearHeader(); +``` + + + + +#### To add attachment to the message. + +param **`att`** The SMTP_Attachment data item + +```C++ +void addAttachment(SMTP_Attachment &att); +``` + + + + + +#### To add parallel attachment to the message. + +param **`att`** The SMTP_Attachment data item + +```C++ +void addParallelAttachment(SMTP_Attachment &att); +``` + + + + + +#### To add inline image to the message. + +param **`att`** The SMTP_Attachment data item + +```C++ +void addInlineImage(SMTP_Attachment &att); +``` + + + + + +#### To add rfc822 message to the message. + +param **`msg`** The RFC822_Message class object + +```C++ +void addMessage(SMTP_Message &msg); +``` + + + + + +#### To add the primary recipient mailbox to the message. + +param **`name`** The name of primary recipient + +param **`email`** The Email address of primary recipient + +```C++ +void addRecipient(const char *name, const char *email); +``` + + + + + +#### To add Carbon-copy recipient mailbox. + +param **`email`** The Email address of secondary recipient + +```C++ +void addCc(const char *email); +``` + + + + + +#### To add Blind-carbon-copy recipient mailbox. + +param **`email`** The Email address of the tertiary recipient + +```C++ +void addBcc(const char *email); +``` + + + + + +#### To add the custom header to the message. + +param **`hdr`** The header name and value + +```C++ +void addHeader(const char *hdr); +``` + + + + +##### [properties] The message author config + +This property has the sub properties + +###### [const char*] name - The sender name. + +###### [const char*] email - The sender Email address. + +```C++ +esp_mail_email_info_t sender; +``` + + +##### [properties] The topic of message + +```C++ +const char *subject; +``` + + +##### [properties] The message type + +```C++ +byte type; +``` + + +##### [properties] The PLAIN text message + +This property has the sub properties + +###### [esp_mail_smtp_embed_message_body_t] embed - The option to embed this message content as a file. + +###### [const char*] content - The PLAIN text content of the message. + +###### [const char*] charSet - The character transcoding of the PLAIN text content of the message. + +###### [const char*] content_type - The content type of message. + +###### [const char*] transfer_encoding - The option to encode the content for data transfer. + +###### [boolean] flowed - The option to send the PLAIN text with wrapping. + +```C++ +esp_mail_plain_body_t text; +``` + + +##### [properties] The HTML text message + +This propery has the sub properties + +###### [const char*] content - The HTML content of the message. + +###### [const char*] charSet - The character transcoding of the HTML content of the message. + +###### [const char*] content_type - The content type of message. + +###### [const char*] transfer_encoding - The option to encode the content for data transfer. + +```C++ +esp_mail_html_body_t html; +``` + + +##### [properties] The response config + +This propery has the sub properties + +###### [const char*] reply_to - The author Email address to reply. + +###### [const char*] return_path - The sender Email address to return the message. + +###### [int] notify - The Delivery Status Notifications enumeration e.g. + +esp_mail_smtp_notify_never = 0, + +esp_mail_smtp_notify_success = 1, + +esp_mail_smtp_notify_failure = 2, and + +esp_mail_smtp_notify_delay = 4 + +```C++ +esp_mail_smtp_msg_response_t response; +``` + + +##### [properties] The priority of the message + +This property has the enumeration values + +esp_mail_smtp_priority_high = 1, + +esp_mail_smtp_priority_normal = 3, + +esp_mail_smtp_priority_low = 5 + +```C++ +esp_mail_smtp_priority priority; +``` + + +##### [properties] The enable options + +This propery has the sub property + +###### [boolean] chunking - enable chunk data sending for large message. + +```C++ +esp_mail_smtp_enable_option_t enable; +``` + + +##### [properties] The message from config + +This property has the sub properties + +###### [const char*] name - The messsage author name. + +###### [const char*] email - The message author Email address. + +```C++ +esp_mail_email_info_t from; +``` + + +##### [properties] The message identifier + +```C++ +const char *messageID; +``` + +##### [properties] The keywords or phrases, separated by commas + +```C++ +const char *keyword; +``` + + +##### [properties] The comment about message + +```C++ +const char *comment; +``` + + +##### [properties] The date of message + +```C++ +const char *date; +``` + + +##### [properties] The return recipient of the message + +```C++ +const char *return_path; +``` + + + + + + +## IMAP_Status class functions + + +The following functions are available from the IMAP Status class. + +This class is used as the callback parameter for retrieving the status while reading the Email. + + + + +#### Provide the information of each process in the reading operation. + +return **`string`** The info for each process + +```C++ +const char *info(); +``` + + + + +#### Provide the status of completion. + +return **`boolean`** The bool value indicates that all reading processes are finished + +```C++ +bool success(); +``` + + + + + +#### To clear all data store in this class. + +```C++ +void empty(); +``` + + + + + + +## SMTP_Status class functions + + +The following functions are available from the SMTP Status class. + +This class is used as the callback parameter for retrieving the status while sending the Email. + + + + +#### Provide the information of each process in the sending operation. + +return **`string`** The info for each process + +```C++ +const char *info(); +``` + + + + +#### Provide the status of completion. + +return **`boolean`** The bool value indicates that all sending processes are finished + +```C++ +bool success(); +``` + + + + + +#### To clear all data store in this class. + +```C++ +void empty(); +``` + + + + +#### Provide the number of complete sending message. + +return **`number`** The number of message that was sent + +```C++ +size_t completedCount(); +``` + + + + + +#### Provide the number of failed sending message. + +return **`number`** The number of message that was not sent + +```C++ +size_t failedCount(); +``` + + + + +## SendingResult class functions + + +The following functions are available from the SendingResult class. + +This class is used for retrieving the info about the result of sending the messages. + + + + +#### Provide the information of a message sending status. + +param **`index`** The index number of a message sending status + +return **`SMTP_Result`** The SMTP_Result type data that provides these properties + +##### [bool] completed - The status of the message + +#### [const char *] recipients - The primary recipient mailbox of the message + +#### [const char *] subject - The topic of the message + +#### [time_t] timesstamp - The timestamp of the message + +```C++ +SMTP_Result getItem(size_t index); +``` + + + + + +#### Provide the amount of the result data. + +return **`number`** The number of result item + +```C++ +size_t size(); +``` + + + + +## FoldersCollection class functions + + +The following functions are available from the FoldersCollection class. + +This class is used for retrieving the info about the mailbox folders which available to read or serach +in the user Email mailbox. + + + + +#### Provide the information of a folder in a folder collection. + +param **`index`** The index number of folders + +return **`esp_mail_folder_info_item_t`** The esp_mail_folder_info_item_t structured data that provides these properties + +#### [const char *] name - The name of folder + +#### [const char *] attributes - The attributes of folder + +#### [const char *] delimiter - The delimeter of folder + +```C++ +esp_mail_folder_info_item_t info(size_t index); +``` + + + + + +#### Provide the number of folders in the collection. + +return **`number`** The number of folder in the collection + +```C++ +size_t size(); +``` + + + + + + +## SelectedFolderInfo class functions + + +The following functions are available from the SelectedFolderInfo class. + +This class is used for retrieving the info about the sselected or opened mailbox folder. + + + + +#### Provide the numbers of flags in the user Email mailbox. + +return **`number`** The numbers of flags + +```C++ +size_t flagCount(); +``` + + + + + +#### Provide the numbers of messages in this mailbox. + +return **`number`** The numbers of messages in the selected mailbox folder + +```C++ +size_t msgCount(); +``` + + + + + +#### Provide the predicted next message UID in the sselected folder. + +return **`number`** The number represents the next message UID number + +```C++ +size_t nextUID(); +``` + + + + + +#### Provide the numbers of messages from search result based on the search criteria. + +return **`number`** The total number of messsages from search + +```C++ +size_t searchCount(); +``` + + + + + +#### Provide the numbers of messages to be stored in the ressult. + +return **`number`** The number of messsage stored from search + +```C++ +size_t availableMessages(); +``` + + + + + +#### Provide the flag argument at the specified index. + +return **`index`** The index of flag in the flags list + +return **`String`** The argument of selected flag + +```C++ +String flag(size_t index); +``` + + + + +## ESP_Mail_Session type data + + +The following properties are available from the ESP_Mail_Session data type. + +This data type is used for storing the session info about the server and login credentials. + + +#### [Properties] The server config + +This property has the sub properties + +##### [const char *] host_name - The hostName of the server. + +##### [uint16_t] port - The port on the server to connect to. + +```C++ +esp_mail_sesson_sever_config_t server; +``` + + +#### [Properties] The log in config + +This property has the sub properties + +##### [const char *] email - The user Email address to log in. + +##### [consst char *] password - The user password to log in. + +##### [consst char *] accessToken - The OAuth2.0 access token to log in. + +##### [consst char *] user_domain - The user domain or ip of client. + +```C++ +esp_mail_sesson_login_config_t login; +``` + + +#### [Properties] The secure config + +This property has the sub properties + +##### [bool] startTLS - The option to send the command to start the TLS connection. + +```C++ +esp_mail_sesson_secure_config_t secure; +``` + + + +#### [Properties] The certificate config + +##### [const char *] cert_data - The certificate data (base64 data). + +##### [consst char *] cert_file - The certificate file (DER format). + +##### [esp_mail_file_storage_type] cert_file_storage_type - The storage type. + +```C++ +esp_mail_sesson_cert_config_t certificate; +``` + + + + +## IMAP_Config type data + + +The following properties are available from the IMAP_Config data type. + +This data type is used for storing the IMAP transport and operating options to +control and store the operation result e.g. the messahe contents from search and fetch. + + + + +#### [Properties] The config for fetching + +This property has the sub property + +##### [const char *] uid - The UID of message to fetch. + +```C++ +esp_mail_imap_fetch_config_t fetch; +``` + + +#### [Properties] The config for search + +This property has the sub properties + +##### [const char *] criteria - The search criteria. + +##### [boolean] unseen_msg - The option to search the unseen message. + +```C++ +esp_mail_imap_search_config_t search; +``` + + +#### [Properties] The config about the limits + +This property has the sub properties + +##### [size_t] search - The maximum messages from the search result. + +##### [size_t] msg_size - The maximum size of the memory buffer to store the message content. + +This is only limit for data to be stored in the IMAPSession. + +##### [size_t] attachment_size - The maximum size of each attachment to download. + +```C++ +esp_mail_imap_limit_config_t limit; +``` + + + +#### [Properties] The config to enable the features + +This property has the sub properties + +##### [boolean] text - To store the PLAIN text of the message in the IMAPSession. + +##### [boolean] html - To store the HTML of the message in the IMAPSession. + +##### [boolean] rfc822 - To store the rfc822 messages in the IMAPSession. + +##### [boolean] download_status - To enable the download status via the serial port. + +##### [boolean] recent_sort - To sort the message UID of the search result in descending order. + +```C++ +esp_mail_imap_enable_config_t enable; +``` + + + +#### [Properties] The config about downloads + +This property has the sub properties + +##### [boolean] text - To download the PLAIN text content of the message. + +##### [boolean] html - To download the HTML content of the message. + +##### [boolean] attachment - To download the attachments of the message. + +##### [boolean] inlineImg - To download the inline image of the message. + +##### [boolean] rfc822 - To download the rfc822 mesages in the message. + +##### [boolean] header - To download the message header. + +```C++ +esp_mail_imap_download_config_t download; +``` + + + +#### [Properties] The config about the storage and path to save the downloaded file. + +This property has the sub properties + +##### [const char*] saved_path - The path to save the downloaded file. + +##### [esp_mail_file_storage_type] type - The type of file storages enumeration e.g. + +esp_mail_file_storage_type_none = 0, + +esp_mail_file_storage_type_flash = 1, and + +esp_mail_file_storage_type_sd = 2 + +```C++ +esp_mail_imap_storage_config_t storage; +``` + + + + + +## esp_mail_smtp_embed_message_body_t structured data + + +The following properties are available from the IMAP_Config data type. + +This data type is used for storing the IMAP transport and operating options to +control and store the operation result e.g. the messahe contents from search and fetch. + + + + +##### [Properties] Enable to send this message body as file + +```C++ +bool enable; +``` + + +##### [Properties] The name of embedded file + +```C++ +const char* enable; +``` + + +##### [Properties] The embedded type enumeration + +esp_mail_smtp_embed_message_type_attachment = 0 + +sp_mail_smtp_embed_message_type_inline = 1 + +```C++ +esp_mail_smtp_embed_message_type type; +``` + + + + + + +## IMAP_MSG_Item type data + + +The following properties are available from the IMAP_MSG_Item data type. + +This data type is used for message item info and its contents from search and fetch. + + + + +#### [Properties] The message number + +```C++ +const char *msgNo; +``` + + +#### [Properties] The message UID + +```C++ +const char *UID; +``` + + +#### [Properties] The message identifier + +```C++ +const char *ID; +``` + + + +#### [Properties] The language(s) for auto-responses + +```C++ +const char *acceptLang; +``` + + + +#### [Properties] The language of message content + +```C++ +const char *contentLang; +``` + + + +#### [Properties] The mailbox of message author + +```C++ +const char *from; +``` + + +#### [Properties] The charset of the mailbox of message author + +```C++ +const char *fromCharset; +``` + + +#### [Properties] The primary recipient mailbox + +```C++ +const char *to; +``` + + +#### [Properties] The charset of the primary recipient mailbox + +```C++ +const char *toCharset; +``` + + +#### [Properties] The Carbon-copy recipient mailboxes + +```C++ +const char *cc; +``` + + +#### [Properties] The charset of the Carbon-copy recipient mailbox header + +```C++ +const char *ccCharset; +``` + +#### [Properties] The message date and time + +```C++ +const char *date; +``` + +#### [Properties] The topic of message + +```C++ +const char *subject; +``` + +#### [Properties] The topic of message charset + +```C++ +const char *subjectCharset; +``` + +#### [Properties] The PLAIN text content of the message + +```C++ +esp_mail_plain_body_t text; +``` + +#### [Properties] The HTML content of the message + +```C++ +esp_mail_html_body_t html; +``` + +#### [Properties] The sender Email + +```C++ +const char *sender; +``` + +#### [Properties] The message identifier + +```C++ +const char *messageID; +``` + +#### [Properties] The keywords or phrases, separated by commas + +```C++ +const char *keyword; +``` + +#### [Properties] The comment about message + +```C++ +const char *comment; +``` + + +#### [Properties] The return recipient of the message + +```C++ +const char *return_path; +``` + + +#### [Properties] The Email address to reply + +```C++ +const char *reply_to; +``` + + +#### [Properties] The Blind carbon-copy recipients + +```C++ +const char *bcc; +``` + + +#### [Properties] The error description from fetching the message + +```C++ +const char *fetchError; +``` + + +#### [Properties] The info about the attachments in the message + +```C++ +std::vector attachments; +``` + +#### [Properties] The info about the rfc822 messages included in the message + +```C++ +std::vector rfc822; +``` + + + + + + +## Search Criteria + +Search crieria is used for searching the mailbox for messages that match +the given searching criteria. + +Searching criteria consist of one or more search keys. When multiple keys are +specified, the result is the intersection (AND function) of all the messages +that match those keys. + +Example: + + **`DELETED FROM "SMITH" SINCE 1-Feb-1994`** refers +to all deleted messages from Smith that were placed in the mailbox since +February 1, 1994. + +A search key can also be a parenthesized list of one or more search keys +(e.g., for use with the OR and NOT keys). + +**`SINCE 10-Feb-2019`** will search all messages that received since 10 Feb 2019 + +**`UID SEARCH ALL`** will seach all message which will return the message UID +that can be use later for fetch one or more messages. + + +The following keywords can be used for the search criteria. + + +**ALL** - All messages in the mailbox; the default initial key for ANDing. + +**ANSWERED** - Messages with the \Answered flag set. + +**BCC** - Messages that contain the specified string in the envelope structure's BCC field. + +**BEFORE** - Messages whose internal date (disregarding time and timezone) is earlier than the specified date. + +**BODY** - Messages that contain the specified string in the body of the message. + +**CC** - Messages that contain the specified string in the envelope structure's CC field. + +**DELETED** - Messages with the \Deleted flag set. + +**DRAFT** - Messages with the \Draft flag set. + +**FLAGGED** - Messages with the \Flagged flag set. + +**FROM** - Messages that contain the specified string in the envelope structure's FROM field. + +**HEADER** - Messages that have a header with the specified field-name (as defined in [RFC-2822]) + +and that contains the specified string in the text of the header (what comes after the colon). + +If the string to search is zero-length, this matches all messages that have a header line with + +the specified field-name regardless of the contents. + +**KEYWORD** - Messages with the specified keyword flag set. + +**LARGER** - Messages with an (RFC-2822) size larger than the specified number of octets. + +**NEW** - Messages that have the \Recent flag set but not the \Seen flag. + +This is functionally equivalent to **"(RECENT UNSEEN)"**. + +**NOT** - Messages that do not match the specified search key. + +**OLD** - Messages that do not have the \Recent flag set. This is functionally equivalent to + +**"NOT RECENT"** (as opposed to **"NOT NEW"**). + +**ON** - Messages whose internal date (disregarding time and timezone) is within the specified date. + +**OR** - Messages that match either search key. + +**RECENT** - Messages that have the \Recent flag set. + +**SEEN** - Messages that have the \Seen flag set. + +**SENTBEFORE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is earlier than the specified date. + +**SENTON** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within the specified date. + +**SENTSINCE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within or later than the specified date. + +**SINCE** - Messages whose internal date (disregarding time and timezone) is within or later than the specified date. + +**SMALLER** - Messages with an (RFC-2822) size smaller than the specified number of octets. + +**SUBJECT** - Messages that contain the specified string in the envelope structure's SUBJECT field. + +**TEXT** - Messages that contain the specified string in the header or body of the message. + +**TO** - Messages that contain the specified string in the envelope structure's TO field. + +**UID** - Messages with unique identifiers corresponding to the specified unique identifier set. + +Sequence set ranges are permitted. + +**UNANSWERED** - Messages that do not have the \Answered flag set. + +**UNDELETED** - Messages that do not have the \Deleted flag set. + +**UNDRAFT** - Messages that do not have the \Draft flag set. + +**UNFLAGGED** - Messages that do not have the \Flagged flag set. + +**UNKEYWORD** - Messages that do not have the specified keyword flag set. + +**UNSEEN** - Messages that do not have the \Seen flag set. + + + + + + + + + +## MailClient.Time functions + + +The helper function to set and get the system time. + + + + + +#### Set the system time from the NTP server + +param **`gmtOffset`** The GMT time offset in hour. + +param **`daylightOffset`** The Daylight time offset in hour. + +return **`boolean`** The status indicates the success of operation. + +This requires internet connection + +```C++ +bool setClock(float gmtOffset, float daylightOffset); +``` + + + + + + +#### Provide the Unix time + +return **`uint32_t`** The value of current Unix time. + +```C++ +uint32_t getUnixTime(); +``` + + + + + + +#### Provide the timestamp from the year, month, date, hour, minute, and second provided + +param **`year`** The year. + +param **`mon`** The months from 1 to 12. + +param **`date`** The dates. + +param **`hour`** The hours. + +param **`mins`** The minutes. + +param **`sec`** The seconds. + +return **`time_t`** The value of timestamp. + +```C++ +time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); +``` + + + + + + +#### Provide the current year. + +return **`int`** The value of current year. + +```C++ +int getYear(); +``` + + + + + + +#### Provide the current month. + +return **`int`** The value of current month. + +```C++ +int getMonth(); +``` + + + + + +#### Provide the current date. + +return **`int`** The value of current date. + +```C++ +int getDay(); +``` + + + + + + +#### Provide the current day of week. + +return **`int`** The value of day of week. + +1 for sunday and 7 for saturday + +```C++ +int getDayOfWeek(); +``` + + + + + +#### Provide the current day of week in String. + +return **`String`** The value of day of week. + +Returns sunday, monday, tuesday, wednesday, thurseday, friday and saturday. + +```C++ +String getDayOfWeekString(); +``` + + + + + + +#### Provide the current hour. + +return **`int`** The value of current hour (0 to 23). + +```C++ +int getHour(); +``` + + + + + + +#### Provide the current minute. + +return **`int`** The value of current minute (0 to 59). + +```C++ +int getMin(); +``` + + + + + + +#### Provide the current second. + +return **`int`** The value of current second (0 to 59). + +```C++ +int getSecond(); +``` + + + + + + + +#### Provide the total days of current year. + +return **`int`** The value of total days of current year. + +```C++ +int getNumberOfDayThisYear(); +``` + + + + + + +#### Provide the total days of from January 1, 1970 to specific date. + +param **`year`** The years from 1970. + +param **`mon`** The months from 1 to 12. + +param **`date`** The dates. + +return **`int`** The value of total days. + +```C++ +int getTotalDays(int year, int month, int day); +``` + + + + + +#### Provide the day of week from specific date. + +param **`year`** The years. + +param **`month`** The months from 1 to 12. + +param **`day`** The dates. + +return **`int`** The value of day of week. + +1 for sunday and 7 for saturday + +```C++ +int dayofWeek(int year, int month, int day); +``` + + + + + + +#### Provide the second of current hour. + +return **`int`** The value of current second. + +```C++ +int getCurrentSecond(); +``` + + + + + +#### Provide the current timestamp. + +return **`uint64_t`** The value of current timestamp. + +```C++ +uint64_t getCurrentTimestamp(); +``` + + + + + + +#### Provide the date and time from second counted from January 1, 1970. + +param **`sec`** The seconds from January 1, 1970 00.00. + +return **`tm`** The tm structured data. + +The returned structured data tm has the members e.g. + +tm_year (from 1900), tm_mon (from 0 to 11), tm_mday, tm_hour, tm_min and tm_sec. + +```C++ +struct tm getTimeFromSec(int secCount); +``` + + + + + + +#### Provide the current date time string that valid for Email + +return **`String`** The current date time string. + +```C++ +String getDateTimeString(); +``` + + + + + + + +## License + +The MIT License (MIT) + +Copyright (c) 2021 K. Suwatchai (Mobizt) + + +Permission is hereby granted, free of charge, to any person returning a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.cpp b/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.cpp new file mode 100755 index 000000000..5e2c01d50 --- /dev/null +++ b/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.cpp @@ -0,0 +1,279 @@ +/* + * ESP32 Internet Time Helper Arduino Library v 1.0.1 + * + * The MIT License (MIT) + * Copyright (c) 2019 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESPTimeHelper_CPP +#define ESPTimeHelper_CPP + +#include "ESPTimeHelper.h" + +ESPTimeHelper::ESPTimeHelper() +{ +} +uint32_t ESPTimeHelper::getUnixTime() +{ + uint32_t utime = (msec_time_diff + millis()) / 1000; + return utime; +} + +time_t ESPTimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec) +{ + struct tm timeinfo; + timeinfo.tm_year = year - 1900; + timeinfo.tm_mon = mon - 1; + timeinfo.tm_mday = date; + timeinfo.tm_hour = hour; + timeinfo.tm_min = mins; + timeinfo.tm_sec = sec; + time_t ts = mktime(&timeinfo); + return ts; +} + +bool ESPTimeHelper::setClock(float gmtOffset, float daylightOffset) +{ + TZ = gmtOffset; + DST_MN = daylightOffset; + configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov"); + + now = time(nullptr); + uint8_t attempts = 0; + while (now < 1577836800) + { + now = time(nullptr); + attempts++; + if (attempts > 200 || now > 1577836800) + break; + delay(100); + } + + uint64_t tmp = now; + tmp = tmp * 1000; + msec_time_diff = tmp - millis(); + +#if defined(ESP32) + getLocalTime(&timeinfo); +#elif defined(ESP8266) + gmtime_r(&now, &timeinfo); +#endif + + clockReady = now > 8 * 3600 * 2; + return clockReady; +} + +int ESPTimeHelper::getYear() +{ + setSysTime(); + return timeinfo.tm_year + 1900; +} +int ESPTimeHelper::getMonth() +{ + setSysTime(); + return timeinfo.tm_mon + 1; +} +int ESPTimeHelper::getDay() +{ + setSysTime(); + return timeinfo.tm_mday; +} + +int ESPTimeHelper::getDayOfWeek() +{ + setSysTime(); + return timeinfo.tm_wday; +} +String ESPTimeHelper::getDayOfWeekString() +{ + setSysTime(); + return dow[timeinfo.tm_wday]; +} + +int ESPTimeHelper::getHour() +{ + setSysTime(); + return timeinfo.tm_hour; +} + +int ESPTimeHelper::getMin() +{ + setSysTime(); + return timeinfo.tm_min; +} +int ESPTimeHelper::getSec() +{ + setSysTime(); + return timeinfo.tm_sec; +} +int ESPTimeHelper::getNumberOfDayThisYear() +{ + setSysTime(); + return timeinfo.tm_yday + 1; +} + +int ESPTimeHelper::totalDays(int y, int m, int d) +{ + static char daytab[2][13] = + { + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + int daystotal = d; + for (int year = 1; year <= y; year++) + { + int max_month = (year < y ? 12 : m - 1); + int leap = (year % 4 == 0); + if (year % 100 == 0 && year % 400 != 0) + leap = 0; + for (int month = 1; month <= max_month; month++) + { + daystotal += daytab[leap][month]; + } + } + return daystotal; +} +int ESPTimeHelper::getTotalDays(int year, int month, int day) +{ + return totalDays(year, month, day) - totalDays(1970, 1, 1); +} + +int ESPTimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */ +{ + static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + year -= month < 3; + return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; +} + +int ESPTimeHelper::getCurrentSecond() +{ + return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec; +} +uint64_t ESPTimeHelper::getCurrentTimestamp() +{ + return now; +} +struct tm ESPTimeHelper::getTimeFromSec(int seconds) +{ + struct tm timeinfo; + int _yrs = seconds / (365 * 24 * 3600); + seconds = seconds - _yrs * (365 * 24 * 3600); + timeinfo.tm_year = _yrs - 1900; + int _months = seconds / (30 * 24 * 3600); + seconds = seconds - _months * (30 * 24 * 3600); + timeinfo.tm_mon = _months - 1; + int _days = seconds / (24 * 3600); + seconds = seconds - _days * (24 * 3600); + timeinfo.tm_mday = _days; + int _hr = seconds / 3600; + seconds = seconds - _hr * 3600; + timeinfo.tm_hour = _hr; + int _min = seconds / 60; + seconds = seconds - _min * 60; + timeinfo.tm_min = _min; + timeinfo.tm_sec = seconds; + return timeinfo; +} + +char *ESPTimeHelper::intStr(int value) +{ + char *buf = new char[36]; + memset(buf, 0, 36); + itoa(value, buf, 10); + return buf; +} + +String ESPTimeHelper::getDateTimeString() +{ + setSysTime(); + std::string s; + + s = sdow[timeinfo.tm_wday]; + + s += ", "; + char *tmp = intStr(timeinfo.tm_mday); + s += tmp; + delete[] tmp; + + s += " "; + s += months[timeinfo.tm_mon]; + + s += " "; + tmp = intStr(timeinfo.tm_year + 1900); + s += tmp; + delete[] tmp; + + s += " "; + if (timeinfo.tm_hour < 10) + s += "0"; + tmp = intStr(timeinfo.tm_hour); + s += tmp; + delete[] tmp; + + s += ":"; + if (timeinfo.tm_min < 10) + s += "0"; + tmp = intStr(timeinfo.tm_min); + s += tmp; + delete[] tmp; + + s += ":"; + if (timeinfo.tm_sec < 10) + s += "0"; + tmp = intStr(timeinfo.tm_sec); + s += tmp; + delete[] tmp; + + int p = 1; + if (TZ < 0) + p = -1; + int tz = TZ; + float dif = (p * (TZ - tz)) * 60.0; + if (TZ < 0) + s += " -"; + else + s += " +"; + + if (tz < 10) + s += "0"; + tmp = intStr(tz); + s += tmp; + delete[] tmp; + + if (dif < 10) + s += "0"; + tmp = intStr((int)dif); + s += tmp; + delete[] tmp; + + return s.c_str(); +} + +void ESPTimeHelper::setSysTime() +{ +#if defined(ESP32) + getLocalTime(&timeinfo); +#elif defined(ESP8266) + now = time(nullptr); + localtime_r(&now, &timeinfo); +#endif +} + +#endif //ESPTimeHelper_CPP \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.h b/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.h new file mode 100755 index 000000000..8ae9c336a --- /dev/null +++ b/lib/lib_div/lib_mail/src/extras/ESPTimeHelper.h @@ -0,0 +1,191 @@ +/* + * ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.1 + * + * The MIT License (MIT) + * Copyright (c) 2020 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESPTimeHelper_H +#define ESPTimeHelper_H + +#include +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + +class ESPTimeHelper +{ +public: + ESPTimeHelper(); + + /** Set the system time from the NTP server + * + * @param gmtOffset The GMT time offset in hour. + * @param daylightOffset The Daylight time offset in hour. + * @return boolean The status indicates the success of operation. + * + * @note This requires internet connection + */ + bool setClock(float gmtOffset, float daylightOffset); + + /** Provide the Unix time + * + * @return uint32_t The value of current Unix time. + */ + uint32_t getUnixTime(); + + /** Provide the timestamp from the year, month, date, hour, minute, + * and second provided. + * + * @param year The year. + * @param mon The month from 1 to 12. + * @param date The dates. + * @param hour The hours. + * @param mins The minutes. + * @param sec The seconds. + * @return time_t The value of timestamp. + */ + time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); + + /** Provide the current year. + * + * @return int The value of current year. + */ + int getYear(); + + /** Provide the current month. + * + * @return int The value of current month. + */ + int getMonth(); + + /** Provide the current date. + * + * @return int The value of current date. + */ + int getDay(); + + /** Provide the current day of week. + * + * @return int The value of current day of week. + * + * @note 1 for sunday and 7 for saturday. + */ + int getDayOfWeek(); + + /** Provide the current day of week in String. + * + * @return String The value of day of week. + */ + String getDayOfWeekString(); + + /** Provide the current hour. + * + * @return int The value of current hour (0 to 23). + */ + int getHour(); + + /** Provide the current minute. + * + * @return int The value of current minute. + */ + int getMin(); + + /** Provide the current second. + * + * @return int The value of current second. + */ + int getSec(); + + /** Provide the total days of current year. + * + * @return int The value of total days of current year. + */ + int getNumberOfDayThisYear(); + + /** Provide the total days of from January 1, 1970 to specific date. + * + * @param year The year from 1970. + * @param mon The month from 1 to 12. + * @param day The dates. + * @return int The value of total days. + */ + int getTotalDays(int year, int month, int day); + + /** Provide the day of week from specific date. + * + * @param year The year from 1970. + * @param mon The month from 1 to 12. + * @param day The dates. + * @return int the value of day of week. + * @note 1 for sunday and 7 for saturday + */ + int dayofWeek(int year, int month, int day); + + /** Provide the second of current hour. + * + * @return int The value of current second. + */ + int getCurrentSecond(); + + /** Provide the current timestamp. + * + * @return uint64_t The value of current timestamp. + */ + uint64_t getCurrentTimestamp(); + + /** Provide the date and time from second counted from January 1, 1970. + * + * @param sec The seconds from January 1, 1970 00.00. + * @return tm The tm structured data. + * + * @note The returned structured data tm has the members e.g. + * tm_year (from 1900), tm_mon (from 0 to 11), tm_mday, tm_hour, + * tm_min and tm_sec. + */ + struct tm getTimeFromSec(int seconds); + + /** Provide the current date time string that valid for Email. + * + * @return String The current date time string. + */ + String getDateTimeString(); + + time_t now; + uint64_t msec_time_diff = 0; + struct tm timeinfo; + float TZ = 0.0; + uint8_t DST_MN = 0; + bool clockReady = false; + +private: + int totalDays(int y, int m, int d); + char *intStr(int value); + void setSysTime(); + const char *dow[7] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"}; + const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + const char *sdow[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +}; + +#endif //ESPTimeHelper_H diff --git a/lib/lib_div/lib_mail/src/extras/ESP_Mail_Client_FS.h b/lib/lib_div/lib_mail/src/extras/ESP_Mail_Client_FS.h new file mode 100755 index 000000000..3834201d7 --- /dev/null +++ b/lib/lib_div/lib_mail/src/extras/ESP_Mail_Client_FS.h @@ -0,0 +1,8 @@ + +/* + +To use LittleFS file system instead of SPIFFS, uncomment the following line + +*/ + +//#define USE_LITTLEFS diff --git a/lib/lib_div/lib_mail/src/extras/MIMEInfo.h b/lib/lib_div/lib_mail/src/extras/MIMEInfo.h new file mode 100755 index 000000000..0c432a88d --- /dev/null +++ b/lib/lib_div/lib_mail/src/extras/MIMEInfo.h @@ -0,0 +1,65 @@ +#ifndef MIMEInfo_H +#define MIMEInfo_H +#include + +enum esp_mail_file_extension +{ + esp_mail_file_extension_html, + esp_mail_file_extension_htm, + esp_mail_file_extension_css, + esp_mail_file_extension_txt, + esp_mail_file_extension_js, + esp_mail_file_extension_json, + esp_mail_file_extension_png, + esp_mail_file_extension_gif, + esp_mail_file_extension_jpg, + esp_mail_file_extension_ico, + esp_mail_file_extension_svg, + esp_mail_file_extension_ttf, + esp_mail_file_extension_otf, + esp_mail_file_extension_woff, + esp_mail_file_extension_woff2, + esp_mail_file_extension_eot, + esp_mail_file_extension_sfnt, + esp_mail_file_extension_xml, + esp_mail_file_extension_pdf, + esp_mail_file_extension_zip, + esp_mail_file_extension_gz, + esp_mail_file_extension_appcache, + esp_mail_file_extension_none, + esp_mail_file_extension_maxType +}; + +struct esp_mail_mime_prop_t +{ + char endsWith[10]; + char mimeType[50]; +}; + +const struct esp_mail_mime_prop_t mimeinfo[esp_mail_file_extension_maxType] PROGMEM = + { + {".html", "text/html"}, + {".htm", "text/html"}, + {".css", "text/css"}, + {".txt", "text/plain"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".png", "image/png"}, + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".ico", "image/x-icon"}, + {".svg", "image/svg+xml"}, + {".ttf", "application/x-font-ttf"}, + {".otf", "application/x-font-opentype"}, + {".woff", "application/font-woff"}, + {".woff2", "application/font-woff2"}, + {".eot", "application/vnd.ms-fontobject"}, + {".sfnt", "application/font-sfnt"}, + {".xml", "text/xml"}, + {".pdf", "application/pdf"}, + {".zip", "application/zip"}, + {".gz", "application/x-gzip"}, + {".appcache", "text/cache-manifest"}, + {"", "application/octet-stream"}}; + +#endif diff --git a/lib/libesp32/ESP32-Mail-Client/src/RFC2047.cpp b/lib/lib_div/lib_mail/src/extras/RFC2047.cpp similarity index 86% rename from lib/libesp32/ESP32-Mail-Client/src/RFC2047.cpp rename to lib/lib_div/lib_mail/src/extras/RFC2047.cpp index 993c132e3..8f5dc31e3 100755 --- a/lib/libesp32/ESP32-Mail-Client/src/RFC2047.cpp +++ b/lib/lib_div/lib_mail/src/extras/RFC2047.cpp @@ -1,14 +1,13 @@ #ifndef RFC2047_CPP #define RFC2047_CPP -#ifdef ESP32 - #include "RFC2047.h" -RFC2047::RFC2047(){} +RFC2047_Decoder::RFC2047_Decoder() {} +RFC2047_Decoder::~RFC2047_Decoder() {} - -void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){ +void RFC2047_Decoder::rfc2047Decode(char *d, const char *s, size_t dlen) +{ const char *p, *q; size_t n; @@ -52,11 +51,11 @@ void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){ d += n; } *d = 0; - } -void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){ - +void RFC2047_Decoder::rfc2047DecodeWord(char *d, const char *s, size_t dlen) +{ + char *p = safe_strdup (s); char *pp = p; char *pd = d; @@ -154,8 +153,7 @@ void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){ return; } - -void *RFC2047::safe_calloc (size_t nmemb, size_t size) +void *RFC2047_Decoder::safe_calloc(size_t nmemb, size_t size) { void *p; @@ -169,7 +167,7 @@ void *RFC2047::safe_calloc (size_t nmemb, size_t size) return p; } -void *RFC2047::safe_malloc (unsigned int siz) +void *RFC2047_Decoder::safe_malloc(unsigned int siz) { void *p; @@ -183,7 +181,7 @@ void *RFC2047::safe_malloc (unsigned int siz) return (p); } -void RFC2047::safe_realloc (void **p, size_t siz) +void RFC2047_Decoder::safe_realloc(void **p, size_t siz) { void *r; @@ -213,7 +211,7 @@ void RFC2047::safe_realloc (void **p, size_t siz) *p = r; } -void RFC2047::safe_free (void *ptr) +void RFC2047_Decoder::safe_free(void *ptr) { void **p = (void **)ptr; if (*p) @@ -223,7 +221,7 @@ void RFC2047::safe_free (void *ptr) } } -char *RFC2047::safe_strdup (const char *s) +char *RFC2047_Decoder::safe_strdup(const char *s) { char *p; size_t l; @@ -235,6 +233,5 @@ char *RFC2047::safe_strdup (const char *s) return (p); } -#endif //ESP32 #endif //RFC2047_CPP \ No newline at end of file diff --git a/lib/libesp32/ESP32-Mail-Client/src/RFC2047.h b/lib/lib_div/lib_mail/src/extras/RFC2047.h similarity index 93% rename from lib/libesp32/ESP32-Mail-Client/src/RFC2047.h rename to lib/lib_div/lib_mail/src/extras/RFC2047.h index aeee0e12c..1753a2119 100755 --- a/lib/libesp32/ESP32-Mail-Client/src/RFC2047.h +++ b/lib/lib_div/lib_mail/src/extras/RFC2047.h @@ -2,7 +2,6 @@ #ifndef RFC2047_H #define RFC2047_H -#ifdef ESP32 #include @@ -47,11 +46,12 @@ __attribute__((used)) static int Index_64[128] = { #define hexval(c) Index_hex[(unsigned int)(c)] #define base64val(c) Index_64[(unsigned int)(c)] -class RFC2047{ +class RFC2047_Decoder{ public: - RFC2047(); - void rfc2047Decode(char *d, const char *s, size_t dlen); + RFC2047_Decoder(); + ~RFC2047_Decoder(); + void rfc2047Decode(char *d, const char *s, size_t dlen); private: @@ -65,6 +65,5 @@ class RFC2047{ }; -#endif //ESP32 #endif //RFC2047_H \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp new file mode 100755 index 000000000..d4354dd4c --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp @@ -0,0 +1,247 @@ +/* + * Customized version of ESP32 HTTPClient Library. + * + * v 1.1.1 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * HTTPClient Arduino library for ESP32 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the HTTPClient for Arduino. + * Port to ESP32 by Evandro Luis Copercini (2017), + * changed fingerprints to CA verification. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * +*/ + +#ifndef ESP_Mail_HTTPClient32_CPP +#define ESP_Mail_HTTPClient32_CPP + +#ifdef ESP32 + +#include "ESP_Mail_HTTPClient32.h" + +ESP_Mail_HTTPClient32::ESP_Mail_HTTPClient32() +{ + transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(nullptr)); + _wcs = transportTraits->create(); +} + +ESP_Mail_HTTPClient32::~ESP_Mail_HTTPClient32() +{ + if (_wcs) + { + _wcs->stop(); + _wcs.reset(nullptr); + _wcs.release(); + } + std::string().swap(_host); + std::string().swap(_caCertFile); + _cacert.reset(new char); + _cacert = nullptr; + transportTraits.reset(nullptr); +} + +bool ESP_Mail_HTTPClient32::begin(const char *host, uint16_t port) +{ + _host = host; + _port = port; + return true; +} + +bool ESP_Mail_HTTPClient32::connected() +{ + if (_wcs) + { + if (_secured) + return _wcs->connected(); + else + return _wcs->_ns_connected(); + } + return false; +} + +bool ESP_Mail_HTTPClient32::send(const char *header) +{ + if (!connected()) + return false; + if (_secured) + return (_wcs->write(header, strlen(header)) == strlen(header)); + else + return (_wcs->_ns_write(header, strlen(header)) == strlen(header)); +} + +int ESP_Mail_HTTPClient32::send(const char *header, const char *payload) +{ + size_t size = strlen(payload); + if (strlen(header) > 0) + { + if (!connect(_secured)) + { + return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED; + } + + if (!send(header)) + { + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED; + } + } + + if (size > 0) + { + if (_secured) + { + if (_wcs->write(&payload[0], size) != size) + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; + } + else + { + if (_wcs->_ns_write(&payload[0], size) != size) + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; + } + } + + return 0; +} + +WiFiClient *ESP_Mail_HTTPClient32::stream(void) +{ + if (connected()) + return _wcs.get(); + return nullptr; +} +ESP_Mail_WCS32 *ESP_Mail_HTTPClient32::_stream(void) +{ + if (connected()) + return _wcs.get(); + return nullptr; +} + +size_t ESP_Mail_HTTPClient32::_ns_print(const char *buf) +{ + size_t size = strlen(buf); + return _wcs->_ns_write(&buf[0], size); +} + +size_t ESP_Mail_HTTPClient32::_ns_println(const char *buf) +{ + size_t size = strlen(buf); + size_t wr = _wcs->_ns_write((const char *)&buf[0], size); + std::string s = "\r\n"; + wr += _wcs->_ns_write(s.c_str(), s.length()); + return wr; +} + +bool ESP_Mail_HTTPClient32::connect(void) +{ + return connect(false); +} + +bool ESP_Mail_HTTPClient32::connect(bool secured) +{ + _secured = secured; + + if (connected()) + { + if (_secured) + { + while (_wcs->available() > 0) + _wcs->read(); + } + else + { + while (_wcs->_ns_available() > 0) + _wcs->_ns_read(); + } + return true; + } + + if (!transportTraits) + return false; + + transportTraits->verify(*_wcs, _host.c_str(), !secured, _debugCallback); + if (!_wcs->connect(_host.c_str(), _port)) + return false; + return connected(); +} + +void ESP_Mail_HTTPClient32::setDebugCallback(DebugMsgCallback cb) +{ + _debugCallback = std::move(cb); +} + +void ESP_Mail_HTTPClient32::setCACert(const char *caCert) +{ + if (caCert) + { + transportTraits.reset(nullptr); + transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(caCert)); + _certType = 1; + } + else + _certType = 0; +} + +void ESP_Mail_HTTPClient32::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType) +{ + + if (strlen(caCertFile) > 0) + { + bool t = false; + _certType = 2; + + if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_flash) + t = SPIFFS.begin(true); + else if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_sd) + t = SD.begin(); + if (!t) + return; + + File f; + if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_flash) + { + if (SPIFFS.exists(caCertFile)) + f = SPIFFS.open(caCertFile, FILE_READ); + } + else if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_sd) + { + if (SD.exists(caCertFile)) + f = SD.open(caCertFile, FILE_READ); + } + + if (f) + { + size_t len = f.size(); + _cacert.reset(new char); + _cacert = nullptr; + _cacert = std::unique_ptr(new char[len]); + + if (f.available()) + f.readBytes(_cacert.get(), len); + + f.close(); + + transportTraits.reset(nullptr); + transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(_cacert.get())); + } + } +} + +#endif //ESP32 + +#endif //ESP_Mail_HTTPClient32_CPP diff --git a/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h new file mode 100755 index 000000000..e9ff9bf96 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h @@ -0,0 +1,179 @@ +/* + * Customized version of ESP32 HTTPClient Library. + * + * v 1.1.1 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * HTTPClient Arduino library for ESP32 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the HTTPClient for Arduino. + * Port to ESP32 by Evandro Luis Copercini (2017), + * changed fingerprints to CA verification. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * +*/ + +#ifndef ESP_Mail_HTTPClient32_H +#define ESP_Mail_HTTPClient32_H + +#ifdef ESP32 + +#include +#include +#include +#include +#include +#include "ESP_Mail_WCS32.h" + +#if __has_include() || __has_include() +#error WiFi UART bridge was not supported. +#endif + +#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1) +#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2) +#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) +#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30 + +enum esp_mail_file_storage_type +{ + esp_mail_file_storage_type_none, + esp_mail_file_storage_type_flash, + esp_mail_file_storage_type_sd, + esp_mail_file_storage_type_univ +}; + +class ESP_Mail_TransportTraits +{ +public: + virtual ~ESP_Mail_TransportTraits() {} + + virtual std::unique_ptr create() + { + return std::unique_ptr(new ESP_Mail_WCS32()); + } + + virtual bool + verify(ESP_Mail_WCS32 &client, const char *host, bool starttls, DebugMsgCallback cb) + { + return true; + } +}; + +class ESP_Mail_TLSTraits : public ESP_Mail_TransportTraits +{ +public: + ESP_Mail_TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {} + + std::unique_ptr create() override + { + return std::unique_ptr(new ESP_Mail_WCS32()); + } + + bool verify(ESP_Mail_WCS32 &client, const char *host, bool starttls, DebugMsgCallback cb) override + { + ESP_Mail_WCS32 &wcs = static_cast(client); + wcs.setCACert(_cacert); + wcs.setCertificate(_clicert); + wcs.setPrivateKey(_clikey); + wcs.setSTARTTLS(starttls); + wcs.setDebugCB(cb); + return true; + } + +protected: + const char *_cacert; + const char *_clicert; + const char *_clikey; +}; + +typedef std::unique_ptr ESP_Mail_TransportTraitsPtr; + +class ESP_Mail_HTTPClient32 +{ +public: + ESP_Mail_HTTPClient32(); + ~ESP_Mail_HTTPClient32(); + + /** + * Initialization of new http connection. + * \param host - Host name without protocols. + * \param port - Server's port. + * \return True as default. + * If no certificate string provided, use (const char*)NULL to CAcert param + */ + bool begin(const char *host, uint16_t port); + + /** + * Check the http connection status. + * \return True if connected. + */ + bool connected(); + + /** + * Establish http connection if header provided and send it, send payload if provided. + * \param header - The header string (constant chars array). + * \param payload - The payload string (constant chars array), optional. + * \return http status code, Return zero if new http connection and header and/or payload sent + * with no error or no header and payload provided. If obly payload provided, no new http connection was established. + */ + int send(const char *header, const char *payload); + + /** + * Send extra header without making new http connection (if send has been called) + * \param header - The header string (constant chars array). + * \return True if header sending success. + * Need to call send with header first. + */ + bool send(const char *header); + + /** + * Get the WiFi client pointer. + * \return WiFi client pointer. + */ + WiFiClient *stream(void); + + ESP_Mail_WCS32 *_stream(void); + size_t _ns_print(const char *buf); + size_t _ns_println(const char *buf); + + int tcpTimeout = 40000; + bool connect(void); + bool connect(bool secured); + void setCACert(const char *caCert); + void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType); + void setDebugCallback(DebugMsgCallback cb); + bool _secured = true; + + int _certType = -1; + std::string _caCertFile = ""; + esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none; + +protected: + DebugMsgCallback _debugCallback = NULL; + ESP_Mail_TransportTraitsPtr transportTraits; + std::unique_ptr _wcs; + std::unique_ptr _cacert; + + std::string _host = ""; + uint16_t _port = 0; +}; + +#endif //ESP32 + +#endif //ESP_Mail_HTTPClient32_H diff --git a/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp new file mode 100755 index 000000000..683a6a65c --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp @@ -0,0 +1,553 @@ +/* + *Customized WiFiClientSecure.cpp version 1.0.3 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + WiFiClientSecure.cpp - Client Secure class for ESP32 + Copyright (c) 2016 Hristo Gochkov All right reserved. + Additions Copyright (C) 2017 Evandro Luis Copercini. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ESP_Mail_WCS32_CPP +#define ESP_Mail_WCS32_CPP + +#ifdef ESP32 + +#include "ESP_Mail_WCS32.h" +#include +#include +#include + +#undef connect +#undef write +#undef read + +ESP_Mail_WCS32::ESP_Mail_WCS32() +{ + _connected = false; + + sslclient = new esp_mail_ssl_ctx32; + ssl_init(sslclient); + sslclient->socket = -1; + sslclient->handshake_timeout = 120000; + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; + _pskIdent = NULL; + _psKey = NULL; + next = NULL; +} + +ESP_Mail_WCS32::ESP_Mail_WCS32(int sock) +{ + _connected = false; + _timeout = 0; + + sslclient = new esp_mail_ssl_ctx32; + ssl_init(sslclient); + sslclient->socket = sock; + sslclient->handshake_timeout = 120000; + + if (sock >= 0) + { + _connected = true; + } + + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; + _pskIdent = NULL; + _psKey = NULL; + next = NULL; +} + +ESP_Mail_WCS32::ESP_Mail_WCS32(bool secured) +{ + _connected = false; + sslclient = new esp_mail_ssl_ctx32; + ssl_init(sslclient); + sslclient->socket = -1; + sslclient->handshake_timeout = 120000; + _secured = secured; + _CA_cert = NULL; + _cert = NULL; + _private_key = NULL; + _pskIdent = NULL; + _psKey = NULL; + next = NULL; +} + +ESP_Mail_WCS32::~ESP_Mail_WCS32() +{ + stop(); + delete sslclient; +} + +ESP_Mail_WCS32 &ESP_Mail_WCS32::operator=(const ESP_Mail_WCS32 &other) +{ + stop(); + sslclient->socket = other.sslclient->socket; + _connected = other._connected; + return *this; +} + +void ESP_Mail_WCS32::stop() +{ + if (sslclient->socket >= 0) + { + close(sslclient->socket); + sslclient->socket = -1; + _connected = false; + _peek = -1; + } + stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key); +} + +int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port) +{ + if (_pskIdent && _psKey) + return connect(ip, port, _pskIdent, _psKey); + return connect(ip, port, _CA_cert, _cert, _private_key); +} + +int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, int32_t timeout) +{ + _timeout = timeout; + return connect(ip, port); +} + +int ESP_Mail_WCS32::connect(const char *host, uint16_t port) +{ + if (_pskIdent && _psKey) + return connect(host, port, _pskIdent, _psKey); + return connect(host, port, _CA_cert, _cert, _private_key); +} + +int ESP_Mail_WCS32::connect(const char *host, uint16_t port, int32_t timeout) +{ + _timeout = timeout; + return connect(host, port); +} + +int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) +{ + return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key); +} + +int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) +{ + _host = host; + _port = port; + _withCert = true; + + if (_timeout > 0) + { + sslclient->handshake_timeout = _timeout; + } + + int ret = start_socket(sslclient, host, port, _timeout); + _lastError = ret; + if (ret < 0) + { + log_e("start_ssl_client: %d", ret); + stop(); + return 0; + } + + if (_secured) + { + ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL); + _lastError = ret; + if (ret < 0) + { + log_e("start_ssl_client: %d", ret); + stop(); + return 0; + } + } + + _connected = true; + return 1; +} + +int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) +{ + return connect(ip.toString().c_str(), port, _pskIdent, _psKey); +} + +int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) +{ + _host = host; + _port = port; + _withCert = true; + + log_v("start_ssl_client with PSK"); + if (_timeout > 0) + { + sslclient->handshake_timeout = _timeout; + } + int ret = start_socket(sslclient, host, port, _timeout); + _lastError = ret; + if (ret < 0) + { + log_e("start_ssl_client: %d", ret); + stop(); + return 0; + } + + if (_secured) + { + ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey); + _lastError = ret; + if (ret < 0) + { + log_e("start_ssl_client: %d", ret); + stop(); + return 0; + } + } + _connected = true; + return 1; +} + +int ESP_Mail_WCS32::peek() +{ + if (_peek >= 0) + { + return _peek; + } + _peek = timedRead(); + return _peek; +} + +size_t ESP_Mail_WCS32::write(uint8_t data) +{ + return write(&data, 1); +} + +int ESP_Mail_WCS32::read() +{ + uint8_t data = -1; + int res = read(&data, 1); + if (res < 0) + { + return res; + } + return data; +} + +size_t ESP_Mail_WCS32::write(const uint8_t *buf, size_t size) +{ + if (!_connected) + { + return 0; + } + int res = send_ssl_data(sslclient, buf, size); + if (res < 0) + { + stop(); + res = 0; + } + return res; +} + +int ESP_Mail_WCS32::read(uint8_t *buf, size_t size) +{ + int peeked = 0; + int avail = available(); + if ((!buf && size) || avail <= 0) + { + return -1; + } + if (!size) + { + return 0; + } + if (_peek >= 0) + { + buf[0] = _peek; + _peek = -1; + size--; + avail--; + if (!size || !avail) + { + return 1; + } + buf++; + peeked = 1; + } + + int res = get_ssl_receive(sslclient, buf, size); + if (res < 0) + { + stop(); + return peeked ? peeked : res; + } + return res + peeked; +} + +int ESP_Mail_WCS32::available() +{ + int peeked = (_peek >= 0); + if (!_connected) + { + return peeked; + } + int res = data_to_read(sslclient); + if (res < 0) + { + stop(); + return peeked ? peeked : res; + } + return res + peeked; +} + +uint8_t ESP_Mail_WCS32::connected() +{ + uint8_t dummy = 0; + read(&dummy, 0); + + return _connected; +} + +void ESP_Mail_WCS32::setCACert(const char *rootCA) +{ + _CA_cert = rootCA; +} + +void ESP_Mail_WCS32::setCertificate(const char *client_ca) +{ + _cert = client_ca; +} + +void ESP_Mail_WCS32::setPrivateKey(const char *private_key) +{ + _private_key = private_key; +} + +void ESP_Mail_WCS32::setPreSharedKey(const char *pskIdent, const char *psKey) +{ + _pskIdent = pskIdent; + _psKey = psKey; +} + +bool ESP_Mail_WCS32::verify(const char *fp, const char *domain_name) +{ + if (!sslclient) + return false; + + return verify_ssl_fingerprint(sslclient, fp, domain_name); +} + +char *ESP_Mail_WCS32::_streamLoad(Stream &stream, size_t size) +{ + static char *dest = nullptr; + if (dest) + { + free(dest); + } + dest = (char *)malloc(size); + if (!dest) + { + return nullptr; + } + if (size != stream.readBytes(dest, size)) + { + free(dest); + dest = nullptr; + } + return dest; +} + +bool ESP_Mail_WCS32::loadCACert(Stream &stream, size_t size) +{ + char *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { + setCACert(dest); + ret = true; + } + return ret; +} + +bool ESP_Mail_WCS32::loadCertificate(Stream &stream, size_t size) +{ + char *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { + setCertificate(dest); + ret = true; + } + return ret; +} + +bool ESP_Mail_WCS32::loadPrivateKey(Stream &stream, size_t size) +{ + char *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { + setPrivateKey(dest); + ret = true; + } + return ret; +} + +int ESP_Mail_WCS32::lastError(char *buf, const size_t size) +{ + if (!_lastError) + { + return 0; + } + char error_buf[100]; + mbedtls_strerror(_lastError, error_buf, 100); + snprintf(buf, size, "%s", error_buf); + return _lastError; +} + +void ESP_Mail_WCS32::setHandshakeTimeout(unsigned long handshake_timeout) +{ + sslclient->handshake_timeout = handshake_timeout * 1000; +} + +void ESP_Mail_WCS32::setSTARTTLS(bool enable) +{ + _secured = !enable; +} + +void ESP_Mail_WCS32::setDebugCB(DebugMsgCallback cb) +{ + sslclient->_debugCallback = std::move(cb); +} + +int ESP_Mail_WCS32::_ns_available() +{ + if (sslclient->socket < 0) + return false; + + if (_rxBuf.length() == 0) + { + int bufLen = 1024; + char *tmp = new char[bufLen]; + memset(tmp, 0, bufLen); + int ret = _ns_lwip_read(sslclient, tmp, bufLen); + if (ret > 0) + _rxBuf += tmp; + delete[] tmp; + } + + int result = _rxBuf.length(); + + if (!result) + { + optimistic_yield(100); + } + return result; +} +size_t ESP_Mail_WCS32::_ns_write(const char *buf, size_t size) +{ + if (sslclient->socket < 0 || !size) + return 0; + return _ns_lwip_write(sslclient, buf, size); +} + +size_t ESP_Mail_WCS32::_ns_read(char *buf, size_t size) +{ + if (_rxBuf.length() == 0) + return _ns_lwip_read(sslclient, buf, size); + else + { + size_t sz = size; + if (sz > _rxBuf.length()) + sz = _rxBuf.length(); + strncpy(buf, _rxBuf.c_str(), sz); + _rxBuf.erase(0, sz); + return sz; + } +} + +int ESP_Mail_WCS32::_ns_read() +{ + int c = -1; + if (_rxBuf.length() == 0) + { + char *buf = new char[2]; + memset(buf, 0, 2); + int ret = _ns_lwip_read(sslclient, buf, 1); + if (ret > 0) + c = buf[0]; + delete[] buf; + } + else + { + c = _rxBuf.c_str()[0]; + _rxBuf.erase(0, 1); + } + + return c; +} + +uint8_t ESP_Mail_WCS32::_ns_connected() +{ + return sslclient->socket >= 0; +} + +bool ESP_Mail_WCS32::_ns_connect_ssl() +{ + int ret = 0; + if (_withKey) + ret = start_ssl_client(sslclient, _host.c_str(), _port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL); + else if (_withCert) + ret = start_ssl_client(sslclient, _host.c_str(), _port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey); + + _lastError = ret; + if (ret < 0) + { + log_e("start_ssl_client: %d", ret); + stop(); + return 0; + } + + return 1; +} + +#endif //ESP32 + +#endif //WiFiClientSecureESP32_CPP \ No newline at end of file diff --git a/lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h similarity index 71% rename from lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h rename to lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h index 2a940c391..ce04846c7 100755 --- a/lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.h +++ b/lib/lib_div/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h @@ -1,9 +1,9 @@ /* - *Customized WiFiClientSecure.h to support STARTTLS protocol, version 1.0.1 + *Customized WiFiClientSecure.h version 1.0.3 * * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -25,7 +25,7 @@ */ /* - WiFiClientSecureESP32.h - Base class that provides Client SSL to ESP32 + WiFiClientSecure.h - Base class that provides Client SSL to ESP32 Copyright (c) 2011 Adrian McEwen. All right reserved. Additions Copyright (C) 2017 Evandro Luis Copercini. @@ -44,39 +44,40 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef WiFiClientSecureESP32_H -#define WiFiClientSecureESP32_H +#ifndef ESP_Mail_WCS32_H +#define ESP_Mail_WCS32_H #ifdef ESP32 #include "Arduino.h" #include "IPAddress.h" #include -#include "ssl_client32.h" +#include "esp_mail_ssl_client32.h" -typedef void (*DebugMsgCallback)(const char* msg); +typedef void (*DebugMsgCallback)(const char *msg); -class WiFiClientSecureESP32 : public WiFiClient +class ESP_Mail_WCS32 : public WiFiClient { protected: - sslclient_context32 *sslclient; - + esp_mail_ssl_ctx32 *sslclient; + int _lastError = 0; - int _peek = -1; + int _peek = -1; int _timeout = 0; const char *_CA_cert; const char *_cert; const char *_private_key; const char *_pskIdent; // identity for PSK cipher suites - const char *_psKey; // key in hex for PSK cipher suites + const char *_psKey; // key in hex for PSK cipher suites DebugMsgCallback _debugCallback = NULL; public: - WiFiClientSecureESP32 *next; - WiFiClientSecureESP32(); - WiFiClientSecureESP32(int socket); - WiFiClientSecureESP32(bool starttls); - ~WiFiClientSecureESP32(); + friend class ESP_Mail_HTTPClient32; + ESP_Mail_WCS32 *next; + ESP_Mail_WCS32(); + ESP_Mail_WCS32(int socket); + ESP_Mail_WCS32(bool secured); + ~ESP_Mail_WCS32(); int connect(IPAddress ip, uint16_t port); int connect(IPAddress ip, uint16_t port, int32_t timeout); int connect(const char *host, uint16_t port); @@ -85,7 +86,7 @@ public: int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey); int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey); - int peek(); + int peek(); size_t write(uint8_t data); size_t write(const uint8_t *buf, size_t size); int available(); @@ -98,20 +99,26 @@ public: void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex void setCACert(const char *rootCA); void setCertificate(const char *client_ca); - void setPrivateKey (const char *private_key); - bool loadCACert(Stream& stream, size_t size); - bool loadCertificate(Stream& stream, size_t size); - bool loadPrivateKey(Stream& stream, size_t size); - bool verify(const char* fingerprint, const char* domain_name); + void setPrivateKey(const char *private_key); + bool loadCACert(Stream &stream, size_t size); + bool loadCertificate(Stream &stream, size_t size); + bool loadPrivateKey(Stream &stream, size_t size); + bool verify(const char *fingerprint, const char *domain_name); void setHandshakeTimeout(unsigned long handshake_timeout); - void setSTARTTLS(bool starttls); + void setSTARTTLS(bool enable); void setDebugCB(DebugMsgCallback cb); + int _ns_available(); + size_t _ns_write(const char *buf, size_t size); + size_t _ns_read(char *buf, size_t size); + int _ns_read(); + uint8_t _ns_connected(); + bool _ns_connect_ssl(); operator bool() { return connected(); } - WiFiClientSecureESP32 &operator=(const WiFiClientSecureESP32 &other); + ESP_Mail_WCS32 &operator=(const ESP_Mail_WCS32 &other); bool operator==(const bool value) { return bool() == value; @@ -120,8 +127,8 @@ public: { return bool() != value; } - bool operator==(const WiFiClientSecureESP32 &); - bool operator!=(const WiFiClientSecureESP32 &rhs) + bool operator==(const ESP_Mail_WCS32 &); + bool operator!=(const ESP_Mail_WCS32 &rhs) { return !this->operator==(rhs); }; @@ -132,7 +139,13 @@ public: } private: - char *_streamLoad(Stream& stream, size_t size); + char *_streamLoad(Stream &stream, size_t size); + bool _secured = true; + bool _withCert = false; + bool _withKey = false; + std::string _host = ""; + std::string _rxBuf = ""; + int _port; //friend class WiFiServer; using Print::write; @@ -140,6 +153,4 @@ private: #endif //ESP32 -#endif //WiFiClientSecureESP32_H - - +#endif //ESP_Mail_WCS32_H diff --git a/lib/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp b/lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp similarity index 75% rename from lib/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp rename to lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp index 06e3f11b1..2fb192e78 100755 --- a/lib/libesp32/ESP32-Mail-Client/src/ssl_client32.cpp +++ b/lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp @@ -1,8 +1,8 @@ /* - *Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.3 + *Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.5 * * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) + * Copyright (c) 2021 K. Suwatchai (Mobizt) * * * Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -31,8 +31,8 @@ * Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License. */ -#ifndef SSL_CLIENT32_CPP -#define SSL_CLIENT32_CPP +#ifndef ESP_MAIL_SSL_CLIENT32_CPP +#define ESP_MAIL_SSL_CLIENT32_CPP #ifdef ESP32 @@ -46,10 +46,10 @@ #include #include #include -#include "ssl_client32.h" -#include "WiFi.h" +#include "esp_mail_ssl_client32.h" +#include -const char *pers32 = "esp32-tls"; +const char *_esp_mail_pers32 = "esp32-tls"; static int handle_error(int err) { @@ -66,7 +66,7 @@ static int handle_error(int err) return err; } -void ssl_init(sslclient_context32 *ssl_client) +void ssl_init(esp_mail_ssl_ctx32 *ssl_client) { mbedtls_ssl_init(&ssl_client->ssl_ctx); mbedtls_ssl_config_init(&ssl_client->ssl_conf); @@ -74,14 +74,12 @@ void ssl_init(sslclient_context32 *ssl_client) mbedtls_net_init(&ssl_client->server_fd); } -int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey) +int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout) { - char buf[512]; - int ret, flags; int enable = 1; if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_2, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_2); log_v("Free internal heap before TLS %u", ESP.getFreeHeap()); @@ -92,7 +90,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t if (ssl_client->socket < 0) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_3, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_3); log_e("ERROR opening socket"); return ssl_client->socket; } @@ -101,7 +99,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t if (!WiFiGenericClass::hostByName(host, srv)) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_4, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_4); return -1; } @@ -112,7 +110,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t serv_addr.sin_port = htons(port); if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_5, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_5); if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { @@ -124,48 +122,40 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); - - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_6, ssl_client); } else { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_7, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_7); log_e("Connect to Server failed!"); return -1; } fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK); - if (ssl_client->starttls && (port == 25 || port == 587 || port == 143)) - { + return ssl_client->socket; +} - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_8, ssl_client); - - if ((ret = starttlsHandshake(ssl_client, port)) != 0) - { - log_e("STARTTLS failed!"); - return -1; - } - } +int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey) +{ + char buf[512]; + int ret, flags; if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_9, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_9); log_v("Seeding the random number generator"); mbedtls_entropy_init(&ssl_client->entropy_ctx); ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func, - &ssl_client->entropy_ctx, (const unsigned char *)pers32, strlen(pers32)); + &ssl_client->entropy_ctx, (const unsigned char *)_esp_mail_pers32, strlen(_esp_mail_pers32)); if (ret < 0) { if (ssl_client->_debugCallback) { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -176,7 +166,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t } if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_10, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_10); log_v("Setting up the SSL/TLS structure..."); @@ -189,7 +179,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -204,7 +194,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t if (rootCABuff != NULL) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_11, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_11); log_v("Loading CA cert"); mbedtls_x509_crt_init(&ssl_client->ca_cert); mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); @@ -217,7 +207,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -229,13 +219,13 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t else if (pskIdent != NULL && psKey != NULL) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_12, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_12); log_v("Setting up PSK"); // convert PSK from hex to binary if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2 * MBEDTLS_PSK_MAX_LEN) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_13, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_13); log_e("pre-shared key not valid hex or too long"); return -1; } @@ -266,7 +256,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t } // set mbedtls config if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_14, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_14); ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len, (const unsigned char *)pskIdent, strlen(pskIdent)); if (ret != 0) @@ -275,7 +265,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -299,7 +289,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t mbedtls_pk_init(&ssl_client->client_key); if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_15, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_15); log_v("Loading CRT cert"); @@ -310,7 +300,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -320,7 +310,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t } if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_16, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_16); log_v("Loading private key"); ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0); @@ -334,7 +324,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t } if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_17, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_17); log_v("Setting hostname for TLS session..."); @@ -345,7 +335,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -362,7 +352,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -375,7 +365,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL); if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_18, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_18); log_v("Performing the SSL/TLS handshake..."); unsigned long handshake_start_time = millis(); @@ -387,7 +377,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t { char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -415,7 +405,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t } if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_19, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_19); log_v("Verifying peer X.509 certificate..."); @@ -424,7 +414,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t bzero(buf, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_20, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_20); log_e("Failed to verify peer certificate! verification info: %s", buf); stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue. return handle_error(ret); @@ -432,7 +422,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t else { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_21, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_21); log_v("Certificate verified."); } @@ -456,10 +446,10 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t return ssl_client->socket; } -void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key) +void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_22, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_22); log_v("Cleaning SSL connection."); if (ssl_client->socket >= 0) @@ -474,7 +464,7 @@ void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, co mbedtls_entropy_free(&ssl_client->entropy_ctx); } -int data_to_read(sslclient_context32 *ssl_client) +int data_to_read(esp_mail_ssl_ctx32 *ssl_client) { int ret, res; ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0); @@ -488,7 +478,7 @@ int data_to_read(sslclient_context32 *ssl_client) char *buf = new char[512]; char *error_buf = new char[100]; memset(buf, 0, 512); - strcpy_P(buf, ESP32_SSL_CLIENT_STR_1); + strcpy_P(buf, esp_ssl_client_str_1); mbedtls_strerror(ret, error_buf, 100); strcat(buf, error_buf); ssl_client->_debugCallback(buf); @@ -501,7 +491,7 @@ int data_to_read(sslclient_context32 *ssl_client) return res; } -int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len) +int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, uint16_t len) { log_v("Writing HTTP request..."); //for low level debug @@ -520,7 +510,7 @@ int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t return ret; } -int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length) +int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length) { //log_d( "Reading HTTP response..."); //for low level debug @@ -584,7 +574,7 @@ static bool matchName(const std::string &name, const std::string &domainName) } // Verifies certificate provided by the peer to match specified SHA256 fingerprint -bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, const char *domain_name) +bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name) { // Convert hex string to byte array uint8_t fingerprint_local[32]; @@ -599,7 +589,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con if (pos > len - 2) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_23, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_23); log_d("pos:%d len:%d fingerprint too short", pos, len); return false; } @@ -607,7 +597,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low)) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_24, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_24); log_d("pos:%d len:%d invalid hex sequence: %c%c", pos, len, fp[pos], fp[pos + 1]); return false; } @@ -621,7 +611,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con if (!crt) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_25, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_25); log_d("could not fetch peer certificate"); return false; } @@ -638,7 +628,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con if (memcmp(fingerprint_local, fingerprint_remote, 32)) { if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_26, ssl_client); + ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_26); log_d("fingerprint doesn't match"); return false; } @@ -651,7 +641,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con } // Checks if peer certificate has specified domain in CN or SANs -bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name) +bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name) { log_d("domain name: '%s'", (domain_name) ? domain_name : "(null)"); std::string domain_name_str(domain_name); @@ -698,15 +688,13 @@ bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name) return false; } -int starttlsHandshake(sslclient_context32 *ssl_client, int port) +int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen) { + return lwip_write(ssl_client->socket, buf, bufLen); +} - int ret = 0; - size_t msgLen = 100; - size_t bufLen = 512; - char *buf = new char[bufLen]; - char *hMsg = new char[msgLen]; - +int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen) +{ fd_set readset; fd_set writeset; fd_set errset; @@ -723,127 +711,21 @@ int starttlsHandshake(sslclient_context32 *ssl_client, int port) tv.tv_sec = 1; tv.tv_usec = 0; - - ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv); - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_27, ssl_client); - - goto starttls_exit; - } - - ret = read(ssl_client->socket, buf, bufLen); + int ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv); if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_28, ssl_client); - goto starttls_exit; - } - else - { - if (ssl_client->_debugCallback) - ssl_client->_debugCallback(buf); - } + return ret; - if (port == 587 || port == 25) - { - - memset(hMsg, 0, msgLen); - strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_29); - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_30, ssl_client); - ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg)); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_31, ssl_client); - goto starttls_exit; - } - - ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_32, ssl_client); - goto starttls_exit; - } - - memset(buf, 0, bufLen); - ret = lwip_read(ssl_client->socket, buf, bufLen); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_33, ssl_client); - goto starttls_exit; - } - else - { - if (ssl_client->_debugCallback) - ssl_client->_debugCallback(buf); - } - } - - memset(hMsg, 0, msgLen); - strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_34); - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_35, ssl_client); - ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg)); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_36, ssl_client); - goto starttls_exit; - } - - ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_37, ssl_client); - goto starttls_exit; - } - - memset(buf, 0, bufLen); - ret = lwip_read(ssl_client->socket, buf, bufLen); - - if (ret < 0) - { - if (ssl_client->_debugCallback) - ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_38, ssl_client); - goto starttls_exit; - } - else - { - if (ssl_client->_debugCallback) - ssl_client->_debugCallback(buf); - } - - delete[] buf; - delete[] hMsg; - - return 0; - -starttls_exit: - - delete[] buf; - delete[] hMsg; - - return -1; + return read(ssl_client->socket, buf, bufLen); } -void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client) +void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info) { size_t dbgInfoLen = strlen_P(info) + 1; char *dbgInfo = new char[dbgInfoLen]; memset(dbgInfo, 0, dbgInfoLen); strcpy_P(dbgInfo, info); + ssl_client->_debugCallback(dbgInfo); delete[] dbgInfo; } diff --git a/lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h b/lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h new file mode 100755 index 000000000..768d9697d --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h @@ -0,0 +1,105 @@ +/* + *Customized ssl_client.h to support STARTTLS protocol, version 1.0.5 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* Provide SSL/TLS functions to ESP32 with Arduino IDE + * by Evandro Copercini - 2017 - Apache 2.0 License + */ + +#ifndef ESP_MAIL_SSL_CLIENT32_H +#define ESP_MAIL_SSL_CLIENT32_H + +#ifdef ESP32 + +#include +#include +#include +#include +#include +#include +#include + +static const char esp_ssl_client_str_1[] PROGMEM = "! E: "; +static const char esp_ssl_client_str_2[] PROGMEM = "> C: starting socket"; +static const char esp_ssl_client_str_3[] PROGMEM = "! E: opening socket"; +static const char esp_ssl_client_str_4[] PROGMEM = "! E: could not get ip from host"; +static const char esp_ssl_client_str_5[] PROGMEM = "> C: connecting to Server"; +static const char esp_ssl_client_str_6[] PROGMEM = "> C: server connected"; +static const char esp_ssl_client_str_7[] PROGMEM = "! E: connect to Server failed!"; +static const char esp_ssl_client_str_8[] PROGMEM = "< S: "; +static const char esp_ssl_client_str_9[] PROGMEM = "> C: seeding the random number generator"; +static const char esp_ssl_client_str_10[] PROGMEM = "> C: setting up the SSL/TLS structure"; +static const char esp_ssl_client_str_11[] PROGMEM = "> C: loading CA cert"; +static const char esp_ssl_client_str_12[] PROGMEM = "> C: setting up PSK"; +static const char esp_ssl_client_str_13[] PROGMEM = "! E: pre-shared key not valid hex or too long"; +static const char esp_ssl_client_str_14[] PROGMEM = "> C: set mbedtls config"; +static const char esp_ssl_client_str_15[] PROGMEM = "> C: loading CRT cert"; +static const char esp_ssl_client_str_16[] PROGMEM = "> C: loading private key"; +static const char esp_ssl_client_str_17[] PROGMEM = "> C: setting hostname for TLS session"; +static const char esp_ssl_client_str_18[] PROGMEM = "> C: performing the SSL handshaking"; +static const char esp_ssl_client_str_19[] PROGMEM = "> C: verifying peer X.509 certificate"; +static const char esp_ssl_client_str_20[] PROGMEM = "! E: failed to verify peer certificate!"; +static const char esp_ssl_client_str_21[] PROGMEM = "> C: certificate verified"; +static const char esp_ssl_client_str_22[] PROGMEM = "> C: cleaning SSL connection"; +static const char esp_ssl_client_str_23[] PROGMEM = "!E: fingerprint too short"; +static const char esp_ssl_client_str_24[] PROGMEM = "!E: invalid hex sequence"; +static const char esp_ssl_client_str_25[] PROGMEM = "!E: could not fetch peer certificate"; +static const char esp_ssl_client_str_26[] PROGMEM = "!E: fingerprint doesn't match"; + +typedef void (*DebugMsgCallback)(const char *msg); + +typedef struct esp_mail_ssl_ctx32 +{ + int socket; + mbedtls_ssl_context ssl_ctx; + mbedtls_ssl_config ssl_conf; + mbedtls_net_context server_fd; + + mbedtls_ctr_drbg_context drbg_ctx; + mbedtls_entropy_context entropy_ctx; + + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context client_key; + DebugMsgCallback _debugCallback; + + unsigned long handshake_timeout; +} esp_mail_ssl_ctx32; + +void ssl_init(esp_mail_ssl_ctx32 *ssl_client); +int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout); +int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey); +void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key); +int data_to_read(esp_mail_ssl_ctx32 *ssl_client); +int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, uint16_t len); +int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length); +bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name); +bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name); +int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen); +int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen); +void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info); + +#endif //ESP32 + +#endif //SSL_CLIENT32_H diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp new file mode 100755 index 000000000..9c44c94ce --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp @@ -0,0 +1,1108 @@ +/* + Copy of BearSSLHelpers.cpp + + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef ESP_Mail_BearSSLHelpers_CPP +#define ESP_Mail_BearSSLHelpers_CPP + +#ifdef ESP8266 + +#include "ESP_Mail_BearSSLHelpers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef ARDUINO_SIGNING +#define ARDUINO_SIGNING 0 +#endif + +namespace ESP_Mail_brssl +{ + // Code here is pulled from brssl sources, with the copyright and license + // shown below. I've rewritten things using C++ semantics and removed + // custom VEC_* calls (std::vector to the rescue) and adjusted things to + // allow for long-running operation (i.e. some memory issues when DERs + // passed into the decoders). Bugs are most likely my fault. + + // Original (c) message follows: + /* + Copyright (c) 2016 Thomas Pornin + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + + class private_key + { + public: + int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ + union + { + br_rsa_private_key rsa; + br_ec_private_key ec; + } key; + }; + + class public_key + { + public: + int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ + union + { + br_rsa_public_key rsa; + br_ec_public_key ec; + } key; + }; + + class pem_object + { + public: + char *name; + unsigned char *data; + size_t data_len; + }; + + // Forward definitions + void free_ta_contents(br_x509_trust_anchor *ta); + void free_public_key(public_key *pk); + void free_private_key(private_key *sk); + bool looks_like_DER(const unsigned char *buf, size_t len); + pem_object *decode_pem(const void *src, size_t len, size_t *num); + void free_pem_object_contents(pem_object *po); + + // Used as callback multiple places to append a string to a vector + static void byte_vector_append(void *ctx, const void *buff, size_t len) + { + std::vector *vec = static_cast *>(ctx); + vec->reserve(vec->size() + len); // Allocate extra space all at once + for (size_t i = 0; i < len; i++) + { + vec->push_back(((uint8_t *)buff)[i]); + } + } + + static bool certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta, const br_x509_certificate *xc) + { + std::unique_ptr dc(new br_x509_decoder_context); // auto-delete on exit + std::vector vdn; + br_x509_pkey *pk; + + // Clear everything in the Trust Anchor + memset(ta, 0, sizeof(*ta)); + + br_x509_decoder_init(dc.get(), byte_vector_append, (void *)&vdn, 0, 0); + br_x509_decoder_push(dc.get(), xc->data, xc->data_len); + pk = br_x509_decoder_get_pkey(dc.get()); + if (pk == nullptr) + { + return false; // No key present, something broken in the cert! + } + + // Copy the raw certificate data + ta->dn.data = (uint8_t *)malloc(vdn.size()); + if (!ta->dn.data) + { + return false; // OOM, but nothing yet allocated + } + memcpy(ta->dn.data, &vdn[0], vdn.size()); + ta->dn.len = vdn.size(); + ta->flags = 0; + if (br_x509_decoder_isCA(dc.get())) + { + ta->flags |= BR_X509_TA_CA; + } + + // Extract the public key + switch (pk->key_type) + { + case BR_KEYTYPE_RSA: + ta->pkey.key_type = BR_KEYTYPE_RSA; + ta->pkey.key.rsa.n = (uint8_t *)malloc(pk->key.rsa.nlen); + ta->pkey.key.rsa.e = (uint8_t *)malloc(pk->key.rsa.elen); + if ((ta->pkey.key.rsa.n == nullptr) || (ta->pkey.key.rsa.e == nullptr)) + { + free_ta_contents(ta); // OOM, so clean up + return false; + } + memcpy(ta->pkey.key.rsa.n, pk->key.rsa.n, pk->key.rsa.nlen); + ta->pkey.key.rsa.nlen = pk->key.rsa.nlen; + memcpy(ta->pkey.key.rsa.e, pk->key.rsa.e, pk->key.rsa.elen); + ta->pkey.key.rsa.elen = pk->key.rsa.elen; + return true; + case BR_KEYTYPE_EC: + ta->pkey.key_type = BR_KEYTYPE_EC; + ta->pkey.key.ec.curve = pk->key.ec.curve; + ta->pkey.key.ec.q = (uint8_t *)malloc(pk->key.ec.qlen); + if (ta->pkey.key.ec.q == nullptr) + { + free_ta_contents(ta); // OOM, so clean up + return false; + } + memcpy(ta->pkey.key.ec.q, pk->key.ec.q, pk->key.ec.qlen); + ta->pkey.key.ec.qlen = pk->key.ec.qlen; + return true; + default: + free_ta_contents(ta); // Unknown key type + return false; + } + + // Should never get here, if so there was an unknown error + return false; + } + + br_x509_trust_anchor *certificate_to_trust_anchor(const br_x509_certificate *xc) + { + br_x509_trust_anchor *ta = (br_x509_trust_anchor *)malloc(sizeof(br_x509_trust_anchor)); + if (!ta) + { + return nullptr; + } + + if (!certificate_to_trust_anchor_inner(ta, xc)) + { + free(ta); + return nullptr; + } + return ta; + } + + void free_ta_contents(br_x509_trust_anchor *ta) + { + if (ta) + { + free(ta->dn.data); + if (ta->pkey.key_type == BR_KEYTYPE_RSA) + { + free(ta->pkey.key.rsa.n); + free(ta->pkey.key.rsa.e); + } + else if (ta->pkey.key_type == BR_KEYTYPE_EC) + { + free(ta->pkey.key.ec.q); + } + memset(ta, 0, sizeof(*ta)); + } + } + + // Checks if a bitstream looks like a valid DER(binary) encoding. + // Basically tries to verify the length of all included segments + // matches the length of the input buffer. Does not actually + // validate any contents. + bool looks_like_DER(const unsigned char *buff, size_t len) + { + if (len < 2) + { + return false; + } + if (pgm_read_byte(buff++) != 0x30) + { + return false; + } + int fb = pgm_read_byte(buff++); + len -= 2; + if (fb < 0x80) + { + return (size_t)fb == len; + } + else if (fb == 0x80) + { + return false; + } + else + { + fb -= 0x80; + if (len < (size_t)fb + 2) + { + return false; + } + len -= (size_t)fb; + size_t dlen = 0; + while (fb-- > 0) + { + if (dlen > (len >> 8)) + { + return false; + } + dlen = (dlen << 8) + (size_t)pgm_read_byte(buff++); + } + return dlen == len; + } + } + + void free_pem_object_contents(pem_object *po) + { + if (po) + { + free(po->name); + free(po->data); + po->name = nullptr; + po->data = nullptr; + } + } + + // Converts a PEM (~=base64) source into a set of DER-encoded binary blobs. + // Each blob is named by the ---- BEGIN xxx ---- field, and multiple + // blobs may be returned. + pem_object *decode_pem(const void *src, size_t len, size_t *num) + { + std::vector pem_list; + std::unique_ptr pc(new br_pem_decoder_context); // auto-delete on exit + if (!pc.get()) + { + return nullptr; + } + pem_object po, *pos; + const unsigned char *buff; + std::vector bv; + + *num = 0; + br_pem_decoder_init(pc.get()); + buff = (const unsigned char *)src; + po.name = nullptr; + po.data = nullptr; + po.data_len = 0; + bool inobj = false; + bool extra_nl = true; + + while (len > 0) + { + size_t tlen; + + tlen = br_pem_decoder_push(pc.get(), buff, len); + buff += tlen; + len -= tlen; + switch (br_pem_decoder_event(pc.get())) + { + case BR_PEM_BEGIN_OBJ: + po.name = strdup(br_pem_decoder_name(pc.get())); + br_pem_decoder_setdest(pc.get(), byte_vector_append, &bv); + inobj = true; + break; + + case BR_PEM_END_OBJ: + if (inobj) + { + // Stick data into the vector + po.data = (uint8_t *)malloc(bv.size()); + if (po.data) + { + memcpy(po.data, &bv[0], bv.size()); + po.data_len = bv.size(); + pem_list.push_back(po); + } + // Clean up state for next blob processing + bv.clear(); + po.name = nullptr; + po.data = nullptr; + po.data_len = 0; + inobj = false; + } + break; + + case BR_PEM_ERROR: + free(po.name); + for (size_t i = 0; i < pem_list.size(); i++) + { + free_pem_object_contents(&pem_list[i]); + } + return nullptr; + + default: + // Do nothing here, the parser is still working on things + break; + } + + if (len == 0 && extra_nl) + { + extra_nl = false; + buff = (const unsigned char *)"\n"; + len = 1; + } + } + + if (inobj) + { + free(po.name); + for (size_t i = 0; i < pem_list.size(); i++) + { + free_pem_object_contents(&pem_list[i]); + } + return nullptr; + } + + pos = (pem_object *)malloc((1 + pem_list.size()) * sizeof(*pos)); + if (pos) + { + *num = pem_list.size(); + pem_list.push_back(po); // Null-terminate list + memcpy(pos, &pem_list[0], pem_list.size() * sizeof(*pos)); + } + return pos; + } + + // Parse out DER or PEM encoded certificates from a binary buffer, + // potentially stored in PROGMEM. + br_x509_certificate *read_certificates(const char *buff, size_t len, size_t *num) + { + std::vector cert_list; + pem_object *pos; + size_t u, num_pos; + br_x509_certificate *xcs; + br_x509_certificate dummy; + + *num = 0; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + xcs = (br_x509_certificate *)malloc(2 * sizeof(*xcs)); + if (!xcs) + { + return nullptr; + } + xcs[0].data = (uint8_t *)malloc(len); + if (!xcs[0].data) + { + free(xcs); + return nullptr; + } + memcpy_P(xcs[0].data, buff, len); + xcs[0].data_len = len; + xcs[1].data = nullptr; + xcs[1].data_len = 0; + *num = 1; + return xcs; + } + + pos = decode_pem(buff, len, &num_pos); + if (!pos) + { + return nullptr; + } + for (u = 0; u < num_pos; u++) + { + if (!strcmp_P(pos[u].name, PSTR("CERTIFICATE")) || !strcmp_P(pos[u].name, PSTR("X509 CERTIFICATE"))) + { + br_x509_certificate xc; + xc.data = pos[u].data; + xc.data_len = pos[u].data_len; + pos[u].data = nullptr; // Don't free the data we moved to the xc vector! + cert_list.push_back(xc); + } + } + for (u = 0; u < num_pos; u++) + { + free_pem_object_contents(&pos[u]); + } + free(pos); + + if (cert_list.size() == 0) + { + return nullptr; + } + *num = cert_list.size(); + dummy.data = nullptr; + dummy.data_len = 0; + cert_list.push_back(dummy); + xcs = (br_x509_certificate *)malloc(cert_list.size() * sizeof(*xcs)); + if (!xcs) + { + for (size_t i = 0; i < cert_list.size(); i++) + { + free(cert_list[i].data); // Clean up any captured data blobs + } + return nullptr; + } + memcpy(xcs, &cert_list[0], cert_list.size() * sizeof(br_x509_certificate)); + // XCS now has [].data pointing to the previously allocated blobs, so don't + // want to free anything in cert_list[]. + return xcs; + } + + void free_certificates(br_x509_certificate *certs, size_t num) + { + if (certs) + { + for (size_t u = 0; u < num; u++) + { + free(certs[u].data); + } + free(certs); + } + } + + static public_key *decode_public_key(const unsigned char *buff, size_t len) + { + std::unique_ptr dc(new br_pkey_decoder_context); // auto-delete on exit + if (!dc.get()) + { + return nullptr; + } + + public_key *pk = nullptr; + + br_pkey_decoder_init(dc.get()); + br_pkey_decoder_push(dc.get(), buff, len); + int err = br_pkey_decoder_last_error(dc.get()); + if (err != 0) + { + return nullptr; + } + + const br_rsa_public_key *rk = nullptr; + const br_ec_public_key *ek = nullptr; + switch (br_pkey_decoder_key_type(dc.get())) + { + case BR_KEYTYPE_RSA: + rk = br_pkey_decoder_get_rsa(dc.get()); + pk = (public_key *)malloc(sizeof *pk); + if (!pk) + { + return nullptr; + } + pk->key_type = BR_KEYTYPE_RSA; + pk->key.rsa.n = (uint8_t *)malloc(rk->nlen); + pk->key.rsa.e = (uint8_t *)malloc(rk->elen); + if (!pk->key.rsa.n || !pk->key.rsa.e) + { + free(pk->key.rsa.n); + free(pk->key.rsa.e); + free(pk); + return nullptr; + } + memcpy(pk->key.rsa.n, rk->n, rk->nlen); + pk->key.rsa.nlen = rk->nlen; + memcpy(pk->key.rsa.e, rk->e, rk->elen); + pk->key.rsa.elen = rk->elen; + return pk; + + case BR_KEYTYPE_EC: + ek = br_pkey_decoder_get_ec(dc.get()); + pk = (public_key *)malloc(sizeof *pk); + if (!pk) + { + return nullptr; + } + pk->key_type = BR_KEYTYPE_EC; + pk->key.ec.q = (uint8_t *)malloc(ek->qlen); + if (!pk->key.ec.q) + { + free(pk); + return nullptr; + } + memcpy(pk->key.ec.q, ek->q, ek->qlen); + pk->key.ec.qlen = ek->qlen; + return pk; + + default: + return nullptr; + } + } + + void free_public_key(public_key *pk) + { + if (pk) + { + if (pk->key_type == BR_KEYTYPE_RSA) + { + free(pk->key.rsa.n); + free(pk->key.rsa.e); + } + else if (pk->key_type == BR_KEYTYPE_EC) + { + free(pk->key.ec.q); + } + free(pk); + } + } + + static private_key *decode_private_key(const unsigned char *buff, size_t len) + { + std::unique_ptr dc(new br_skey_decoder_context); // auto-delete on exit + if (!dc.get()) + { + return nullptr; + } + + private_key *sk = nullptr; + + br_skey_decoder_init(dc.get()); + br_skey_decoder_push(dc.get(), buff, len); + int err = br_skey_decoder_last_error(dc.get()); + if (err != 0) + { + return nullptr; + } + + const br_rsa_private_key *rk = nullptr; + const br_ec_private_key *ek = nullptr; + switch (br_skey_decoder_key_type(dc.get())) + { + case BR_KEYTYPE_RSA: + rk = br_skey_decoder_get_rsa(dc.get()); + sk = (private_key *)malloc(sizeof *sk); + if (!sk) + { + return nullptr; + } + sk->key_type = BR_KEYTYPE_RSA; + sk->key.rsa.p = (uint8_t *)malloc(rk->plen); + sk->key.rsa.q = (uint8_t *)malloc(rk->qlen); + sk->key.rsa.dp = (uint8_t *)malloc(rk->dplen); + sk->key.rsa.dq = (uint8_t *)malloc(rk->dqlen); + sk->key.rsa.iq = (uint8_t *)malloc(rk->iqlen); + if (!sk->key.rsa.p || !sk->key.rsa.q || !sk->key.rsa.dp || !sk->key.rsa.dq || !sk->key.rsa.iq) + { + free_private_key(sk); + return nullptr; + } + sk->key.rsa.n_bitlen = rk->n_bitlen; + memcpy(sk->key.rsa.p, rk->p, rk->plen); + sk->key.rsa.plen = rk->plen; + memcpy(sk->key.rsa.q, rk->q, rk->qlen); + sk->key.rsa.qlen = rk->qlen; + memcpy(sk->key.rsa.dp, rk->dp, rk->dplen); + sk->key.rsa.dplen = rk->dplen; + memcpy(sk->key.rsa.dq, rk->dq, rk->dqlen); + sk->key.rsa.dqlen = rk->dqlen; + memcpy(sk->key.rsa.iq, rk->iq, rk->iqlen); + sk->key.rsa.iqlen = rk->iqlen; + return sk; + + case BR_KEYTYPE_EC: + ek = br_skey_decoder_get_ec(dc.get()); + sk = (private_key *)malloc(sizeof *sk); + sk->key_type = BR_KEYTYPE_EC; + sk->key.ec.curve = ek->curve; + sk->key.ec.x = (uint8_t *)malloc(ek->xlen); + if (!sk->key.ec.x) + { + free_private_key(sk); + return nullptr; + } + memcpy(sk->key.ec.x, ek->x, ek->xlen); + sk->key.ec.xlen = ek->xlen; + return sk; + + default: + return nullptr; + } + } + + void free_private_key(private_key *sk) + { + if (sk) + { + switch (sk->key_type) + { + case BR_KEYTYPE_RSA: + free(sk->key.rsa.p); + free(sk->key.rsa.q); + free(sk->key.rsa.dp); + free(sk->key.rsa.dq); + free(sk->key.rsa.iq); + break; + case BR_KEYTYPE_EC: + free(sk->key.ec.x); + break; + default: + // Could be an uninitted key, no sub elements to free + break; + } + free(sk); + } + } + + void free_pem_object(pem_object *pos) + { + if (pos != nullptr) + { + for (size_t u = 0; pos[u].name; u++) + { + free_pem_object_contents(&pos[u]); + } + free(pos); + } + } + + private_key *read_private_key(const char *buff, size_t len) + { + private_key *sk = nullptr; + pem_object *pos = nullptr; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + sk = decode_private_key((const unsigned char *)buff, len); + return sk; + } + + size_t num; + pos = decode_pem(buff, len, &num); + if (pos == nullptr) + { + return nullptr; // PEM decode error + } + for (size_t u = 0; pos[u].name; u++) + { + const char *name = pos[u].name; + if (!strcmp_P(name, PSTR("RSA PRIVATE KEY")) || !strcmp_P(name, PSTR("EC PRIVATE KEY")) || !strcmp_P(name, PSTR("PRIVATE KEY"))) + { + sk = decode_private_key(pos[u].data, pos[u].data_len); + free_pem_object(pos); + return sk; + } + } + // If we hit here, no match + free_pem_object(pos); + return nullptr; + } + + public_key *read_public_key(const char *buff, size_t len) + { + public_key *pk = nullptr; + pem_object *pos = nullptr; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + pk = decode_public_key((const unsigned char *)buff, len); + return pk; + } + size_t num; + pos = decode_pem(buff, len, &num); + if (pos == nullptr) + { + return nullptr; // PEM decode error + } + for (size_t u = 0; pos[u].name; u++) + { + const char *name = pos[u].name; + if (!strcmp_P(name, PSTR("RSA PUBLIC KEY")) || !strcmp_P(name, PSTR("EC PUBLIC KEY")) || !strcmp_P(name, PSTR("PUBLIC KEY"))) + { + pk = decode_public_key(pos[u].data, pos[u].data_len); + free_pem_object(pos); + return pk; + } + } + + // We hit here == no key found + free_pem_object(pos); + return pk; + } + +}; // namespace ESP_Mail_brssl + +namespace ESP_Mail +{ + + // ----- Public Key ----- + + PublicKey::PublicKey() + { + _key = nullptr; + } + + PublicKey::PublicKey(const char *pemKey) + { + _key = nullptr; + parse(pemKey); + } + + PublicKey::PublicKey(const uint8_t *derKey, size_t derLen) + { + _key = nullptr; + parse(derKey, derLen); + } + + PublicKey::~PublicKey() + { + if (_key) + { + ESP_Mail_brssl::free_public_key(_key); + } + } + + bool PublicKey::parse(const char *pemKey) + { + return parse((const uint8_t *)pemKey, strlen_P(pemKey)); + } + + bool PublicKey::parse(const uint8_t *derKey, size_t derLen) + { + if (_key) + { + ESP_Mail_brssl::free_public_key(_key); + _key = nullptr; + } + _key = ESP_Mail_brssl::read_public_key((const char *)derKey, derLen); + return _key ? true : false; + } + + bool PublicKey::isRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return false; + } + return true; + } + + bool PublicKey::isEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return false; + } + return true; + } + + const br_rsa_public_key *PublicKey::getRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return nullptr; + } + return &_key->key.rsa; + } + + const br_ec_public_key *PublicKey::getEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return nullptr; + } + return &_key->key.ec; + } + + // ----- Private Key ----- + + PrivateKey::PrivateKey() + { + _key = nullptr; + } + + PrivateKey::PrivateKey(const char *pemKey) + { + _key = nullptr; + parse(pemKey); + } + + PrivateKey::PrivateKey(const uint8_t *derKey, size_t derLen) + { + _key = nullptr; + parse(derKey, derLen); + } + + PrivateKey::~PrivateKey() + { + if (_key) + { + ESP_Mail_brssl::free_private_key(_key); + } + } + + bool PrivateKey::parse(const char *pemKey) + { + return parse((const uint8_t *)pemKey, strlen_P(pemKey)); + } + + bool PrivateKey::parse(const uint8_t *derKey, size_t derLen) + { + if (_key) + { + ESP_Mail_brssl::free_private_key(_key); + _key = nullptr; + } + _key = ESP_Mail_brssl::read_private_key((const char *)derKey, derLen); + return _key ? true : false; + } + + bool PrivateKey::isRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return false; + } + return true; + } + + bool PrivateKey::isEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return false; + } + return true; + } + + const br_rsa_private_key *PrivateKey::getRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return nullptr; + } + return &_key->key.rsa; + } + + const br_ec_private_key *PrivateKey::getEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return nullptr; + } + return &_key->key.ec; + } + + // ----- Certificate Lists ----- + + ESP_Mail_X509List::ESP_Mail_X509List() + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + } + + ESP_Mail_X509List::ESP_Mail_X509List(const char *pemCert) + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + append(pemCert); + } + + ESP_Mail_X509List::ESP_Mail_X509List(const uint8_t *derCert, size_t derLen) + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + append(derCert, derLen); + } + + ESP_Mail_X509List::~ESP_Mail_X509List() + { + ESP_Mail_brssl::free_certificates(_cert, _count); // also frees cert + for (size_t i = 0; i < _count; i++) + { + ESP_Mail_brssl::free_ta_contents(&_ta[i]); + } + free(_ta); + } + + bool ESP_Mail_X509List::append(const char *pemCert) + { + return append((const uint8_t *)pemCert, strlen_P(pemCert)); + } + + bool ESP_Mail_X509List::append(const uint8_t *derCert, size_t derLen) + { + size_t numCerts; + br_x509_certificate *newCerts = ESP_Mail_brssl::read_certificates((const char *)derCert, derLen, &numCerts); + if (!newCerts) + { + return false; + } + + // Add in the certificates + br_x509_certificate *saveCert = _cert; + _cert = (br_x509_certificate *)realloc(_cert, (numCerts + _count) * sizeof(br_x509_certificate)); + if (!_cert) + { + free(newCerts); + _cert = saveCert; + return false; + } + memcpy(&_cert[_count], newCerts, numCerts * sizeof(br_x509_certificate)); + free(newCerts); + + // Build TAs for each certificate + br_x509_trust_anchor *saveTa = _ta; + _ta = (br_x509_trust_anchor *)realloc(_ta, (numCerts + _count) * sizeof(br_x509_trust_anchor)); + if (!_ta) + { + _ta = saveTa; + return false; + } + for (size_t i = 0; i < numCerts; i++) + { + br_x509_trust_anchor *newTa = ESP_Mail_brssl::certificate_to_trust_anchor(&_cert[_count + i]); + if (newTa) + { + _ta[_count + i] = *newTa; + free(newTa); + } + else + { + return false; // OOM + } + } + _count += numCerts; + + return true; + } + + // SHA256 hash for updater + void HashSHA256::begin() + { + br_sha256_init(&_cc); + memset(_sha256, 0, sizeof(_sha256)); + } + + void HashSHA256::add(const void *data, uint32_t len) + { + br_sha256_update(&_cc, data, len); + } + + void HashSHA256::end() + { + br_sha256_out(&_cc, _sha256); + } + + int HashSHA256::len() + { + return sizeof(_sha256); + } + + const void *HashSHA256::hash() + { + return (const void *)_sha256; + } + + const unsigned char *HashSHA256::oid() + { + return BR_HASH_OID_SHA256; + } + + // SHA256 verifier + uint32_t SigningVerifier::length() + { + if (!_pubKey) + { + return 0; + } + else if (_pubKey->isRSA()) + { + return _pubKey->getRSA()->nlen; + } + else if (_pubKey->isEC()) + { + return _pubKey->getEC()->qlen; + } + else + { + return 0; + } + } + /* + +// We need to use the 2nd stack to do a verification, so do the thunk +// directly inside the class function for ease of use. +extern "C" bool SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { + if (_pubKey->isRSA()) { + bool ret; + unsigned char vrf[hash->len()]; + br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default(); + ret = vrfy((const unsigned char *)signature, signatureLen, hash->oid(), sizeof(vrf), _pubKey->getRSA(), vrf); + if (!ret || memcmp(vrf, hash->hash(), sizeof(vrf)) ) { + return false; + } else { + return true; + } + } else { + br_ecdsa_vrfy vrfy = br_ecdsa_vrfy_raw_get_default(); + // The EC verifier actually does the compare, unlike the RSA one + return vrfy(br_ec_get_default(), hash->hash(), hash->len(), _pubKey->getEC(), (const unsigned char *)signature, signatureLen); + } +}; + + + +#if !CORE_MOCK +make_stack_thunk(SigningVerifier_verify); +extern "C" bool thunk_SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen); +#endif + +bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { + if (!_pubKey || !hash || !signature || signatureLen != length()) return false; +#if !CORE_MOCK + return thunk_SigningVerifier_verify(_pubKey, hash, signature, signatureLen); +#else + return SigningVerifier_verify(_pubKey, hash, signature, signatureLen); +#endif +} + + + +#if !CORE_MOCK + +// Second stack thunked helpers +make_stack_thunk(br_ssl_engine_recvapp_ack); +make_stack_thunk(br_ssl_engine_recvapp_buf); +make_stack_thunk(br_ssl_engine_recvrec_ack); +make_stack_thunk(br_ssl_engine_recvrec_buf); +make_stack_thunk(br_ssl_engine_sendapp_ack); +make_stack_thunk(br_ssl_engine_sendapp_buf); +make_stack_thunk(br_ssl_engine_sendrec_ack); +make_stack_thunk(br_ssl_engine_sendrec_buf); + +#endif +*/ + +}; // namespace ESP_Mail + +#if ARDUINO_SIGNING +namespace +{ + static ESP_Mail::PublicKey signingPubKey(signing_pubkey); + static ESP_Mail::HashSHA256 __signingHash; + static ESP_Mail::SigningVerifier __signingVerifier(&signingPubKey); +}; // namespace + +namespace esp8266 +{ + UpdaterHashClass &updaterSigningHash = __signingHash; + UpdaterVerifyClass &updaterSigningVerifier = __signingVerifier; +}; // namespace esp8266 +#endif + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_BearSSLHelpers_CPP */ \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h new file mode 100755 index 000000000..4ee319736 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h @@ -0,0 +1,200 @@ +/* + Copy of BearSSLHelpers.h + + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ESP_Mail_BearSSLHelpers_H +#define ESP_Mail_BearSSLHelpers_H + +#ifdef ESP8266 + +#include +#include + +// Internal opaque structures, not needed by user applications +namespace ESP_Mail_brssl +{ + class public_key; + class private_key; +}; // namespace ESP_Mail_brssl + +namespace ESP_Mail +{ + + // Holds either a single public RSA or EC key for use when BearSSL wants a pubkey. + // Copies all associated data so no need to keep input PEM/DER keys. + // All inputs can be either in RAM or PROGMEM. + class PublicKey + { + public: + PublicKey(); + PublicKey(const char *pemKey); + PublicKey(const uint8_t *derKey, size_t derLen); + ~PublicKey(); + + bool parse(const char *pemKey); + bool parse(const uint8_t *derKey, size_t derLen); + + // Accessors for internal use, not needed by apps + bool isRSA() const; + bool isEC() const; + const br_rsa_public_key *getRSA() const; + const br_ec_public_key *getEC() const; + + // Disable the copy constructor, we're pointer based + PublicKey(const PublicKey &that) = delete; + + private: + ESP_Mail_brssl::public_key *_key; + }; + + // Holds either a single private RSA or EC key for use when BearSSL wants a secretkey. + // Copies all associated data so no need to keep input PEM/DER keys. + // All inputs can be either in RAM or PROGMEM. + class PrivateKey + { + public: + PrivateKey(); + PrivateKey(const char *pemKey); + PrivateKey(const uint8_t *derKey, size_t derLen); + ~PrivateKey(); + + bool parse(const char *pemKey); + bool parse(const uint8_t *derKey, size_t derLen); + + // Accessors for internal use, not needed by apps + bool isRSA() const; + bool isEC() const; + const br_rsa_private_key *getRSA() const; + const br_ec_private_key *getEC() const; + + // Disable the copy constructor, we're pointer based + PrivateKey(const PrivateKey &that) = delete; + + private: + ESP_Mail_brssl::private_key *_key; + }; + + // Holds one or more X.509 certificates and associated trust anchors for + // use whenever BearSSL needs a cert or TA. May want to have multiple + // certs for things like a series of trusted CAs (but check the CertStore class + // for a more memory efficient way). + // Copies all associated data so no need to keep input PEM/DER certs. + // All inputs can be either in RAM or PROGMEM. + class ESP_Mail_X509List + { + public: + ESP_Mail_X509List(); + ESP_Mail_X509List(const char *pemCert); + ESP_Mail_X509List(const uint8_t *derCert, size_t derLen); + ~ESP_Mail_X509List(); + + bool append(const char *pemCert); + bool append(const uint8_t *derCert, size_t derLen); + + // Accessors + size_t getCount() const + { + return _count; + } + const br_x509_certificate *getX509Certs() const + { + return _cert; + } + const br_x509_trust_anchor *getTrustAnchors() const + { + return _ta; + } + + // Disable the copy constructor, we're pointer based + ESP_Mail_X509List(const ESP_Mail_X509List &that) = delete; + + private: + size_t _count; + br_x509_certificate *_cert; + br_x509_trust_anchor *_ta; + }; + + // Opaque object which wraps the BearSSL SSL session to make repeated connections + // significantly faster. Completely optional. + class ESP_Mail_WCS; + + class Session + { + friend class ESP_Mail_WCS; + + public: + Session() { memset(&_session, 0, sizeof(_session)); } + + private: + br_ssl_session_parameters *getSession() { return &_session; } + // The actual BearSSL ession information + br_ssl_session_parameters _session; + }; + + // Updater SHA256 hash and signature verification + class HashSHA256 : public UpdaterHashClass + { + public: + virtual void begin() override; + virtual void add(const void *data, uint32_t len) override; + virtual void end() override; + virtual int len() override; + virtual const void *hash() override; + virtual const unsigned char *oid() override; + + private: + br_sha256_context _cc; + unsigned char _sha256[32]; + }; + + class SigningVerifier : public UpdaterVerifyClass + { + public: + virtual uint32_t length() override; + virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) override; + + public: + SigningVerifier(PublicKey *pubKey) { _pubKey = pubKey; } + + private: + PublicKey *_pubKey; + }; + /* +// Stack thunked versions of calls +extern "C" { +extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len); +extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len); +extern unsigned char *thunk_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len); +extern void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len); +extern unsigned char *thunk_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len); +extern void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); +extern unsigned char *thunk_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len); +extern void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len); +}; +*/ + +}; // namespace ESP_Mail + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_BearSSLHelpers_H */ diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp new file mode 100755 index 000000000..f8efb1155 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp @@ -0,0 +1,238 @@ +/* + Copy of CertStoreBearSSL.cpp - Library for Arduino ESP8266 + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef ESP_Mail_CertStoreBearSSL_CPP +#define ESP_Mail_CertStoreBearSSL_CPP + +#ifdef ESP8266 + +#include "ESP_Mail_CertStoreBearSSL.h" +#include + + +#ifdef DEBUG_ESP_SSL +#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__) +#else +#define DEBUG_BSSL(...) +#endif + +namespace ESP_Mail { + +extern "C" { + // Callback for the x509 decoder + static void dn_append(void *ctx, const void *buf, size_t len) { + br_sha256_context *sha1 = (br_sha256_context*)ctx; + br_sha256_update(sha1, buf, len); + } +} + + +ESP_Mail_CertStore::~ESP_Mail_CertStore() { + free(_indexName); + free(_dataName); +} + +ESP_Mail_CertStore::ESP_Mail_CertInfo ESP_Mail_CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) { + ESP_Mail_CertStore::ESP_Mail_CertInfo ci; + + // Clear the CertInfo + memset(&ci, 0, sizeof(ci)); + + // Process it using SHA256, same as the hashed_dn + br_x509_decoder_context *ctx = new br_x509_decoder_context; + br_sha256_context *sha256 = new br_sha256_context; + if (!ctx || !sha256) { + DEBUG_BSSL("CertStore::_preprocessCert: OOM\n"); + return ci; + } + + br_sha256_init(sha256); + br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr); + br_x509_decoder_push(ctx, (const void*)raw, length); + + // Copy result to structure + br_sha256_out(sha256, &ci.sha256); + ci.length = length; + ci.offset = offset; + + // Clean up allocated memory + delete sha256; + delete ctx; + + // Return result + return ci; +} + +// The certs.ar file is a UNIX ar format file, concatenating all the +// individual certificates into a single blob in a space-efficient way. +int ESP_Mail_CertStore::initCertStore(FS &fs, const char *indexFileName, const char *dataFileName) { + int count = 0; + uint32_t offset = 0; + + _fs = &fs; + + // In case initCertStore called multiple times, don't leak old filenames + free(_indexName); + free(_dataName); + + // No strdup_P, so manually do it + _indexName = (char *)malloc(strlen_P(indexFileName) + 1); + _dataName = (char *)malloc(strlen_P(dataFileName) + 1); + if (!_indexName || !_dataName) { + free(_indexName); + free(_dataName); + return 0; + } + memcpy_P(_indexName, indexFileName, strlen_P(indexFileName) + 1); + memcpy_P(_dataName, dataFileName, strlen_P(dataFileName) + 1); + + File index = _fs->open(_indexName, "w"); + if (!index) { + return 0; + } + + File data = _fs->open(_dataName, "r"); + if (!data) { + index.close(); + return 0; + } + + uint8_t magic[8]; + if (data.read(magic, sizeof(magic)) != sizeof(magic) || + memcmp(magic, "!\n", sizeof(magic)) ) { + data.close(); + index.close(); + return 0; + } + offset += sizeof(magic); + + while (true) { + uint8_t fileHeader[60]; + // 0..15 = filename in ASCII + // 48...57 = length in decimal ASCII + uint32_t length; + if (data.read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) { + break; + } + offset += sizeof(fileHeader); + fileHeader[58] = 0; + if (1 != sscanf((char *)(fileHeader + 48), "%d", &length) || !length) { + break; + } + + void *raw = malloc(length); + if (!raw) { + break; + } + if (data.read((uint8_t *)raw, length) != length) { + free(raw); + break; + } + + // If the filename starts with "//" then this is a rename file, skip it + if (fileHeader[0] != '/' || fileHeader[1] != '/') { + ESP_Mail_CertStore::ESP_Mail_CertInfo ci = _preprocessCert(length, offset, raw); + if (index.write((uint8_t *)&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) { + free(raw); + break; + } + count++; + } + + offset += length; + free(raw); + if (offset & 1) { + uint8_t x; + data.read(&x, 1); + offset++; + } + } + data.close(); + index.close(); + return count; +} + +void ESP_Mail_CertStore::installCertStore(br_x509_minimal_context *ctx) { + br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA); +} + +const br_x509_trust_anchor *ESP_Mail_CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) { + ESP_Mail_CertStore *cs = static_cast(ctx); + ESP_Mail_CertStore::ESP_Mail_CertInfo ci; + + if (!cs || len != sizeof(ci.sha256) || !cs->_indexName || !cs->_dataName || !cs->_fs) { + return nullptr; + } + + File index = cs->_fs->open(cs->_indexName, "r"); + if (!index) { + return nullptr; + } + + while (index.read((uint8_t *)&ci, sizeof(ci)) == sizeof(ci)) { + if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) { + index.close(); + uint8_t *der = (uint8_t*)malloc(ci.length); + if (!der) { + return nullptr; + } + File data = cs->_fs->open(cs->_dataName, "r"); + if (!data) { + free(der); + return nullptr; + } + if (!data.seek(ci.offset, SeekSet)) { + data.close(); + free(der); + return nullptr; + } + if (data.read((uint8_t *)der, ci.length) != ci.length) { + free(der); + return nullptr; + } + data.close(); + cs->_x509 = new ESP_Mail_X509List(der, ci.length); + free(der); + if (!cs->_x509) { + DEBUG_BSSL("CertStore::findHashedTA: OOM\n"); + return nullptr; + } + + br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors(); + memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256)); + ta->dn.len = sizeof(ci.sha256); + + return ta; + } + } + index.close(); + return nullptr; +} + +void ESP_Mail_CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) { + ESP_Mail_CertStore *cs = static_cast(ctx); + (void) ta; // Unused + delete cs->_x509; + cs->_x509 = nullptr; +} + +} + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_CertStoreBearSSL_CPP */ \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h new file mode 100755 index 000000000..fd9f8c537 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h @@ -0,0 +1,72 @@ +/* + Copy of CertStoreBearSSL.h - Library for Arduino ESP8266 + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ESP_Mail_CertStoreBearSSL_H +#define ESP_Mail_CertStoreBearSSL_H + +#ifdef ESP8266 + +#include +#include "ESP_Mail_BearSSLHelpers.h" +#include +#include + +// Base class for the certificate stores, which allow use +// of a large set of certificates stored on FS or SD card to +// be dynamically used when validating a X509 certificate + +namespace ESP_Mail { + +class ESP_Mail_CertStore { + public: + ESP_Mail_CertStore() { }; + ~ESP_Mail_CertStore(); + + // Set the file interface instances, do preprocessing + int initCertStore(FS &fs, const char *indexFileName, const char *dataFileName); + + // Installs the cert store into the X509 decoder (normally via static function callbacks) + void installCertStore(br_x509_minimal_context *ctx); + + protected: + FS *_fs = nullptr; + char *_indexName = nullptr; + char *_dataName = nullptr; + ESP_Mail_X509List *_x509 = nullptr; + + // These need to be static as they are callbacks from BearSSL C code + static const br_x509_trust_anchor *findHashedTA(void *ctx, void *hashed_dn, size_t len); + static void freeHashedTA(void *ctx, const br_x509_trust_anchor *ta); + + // The binary format of the index file + class ESP_Mail_CertInfo { + public: + uint8_t sha256[32]; + uint32_t offset; + uint32_t length; + }; + static ESP_Mail_CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw); + +}; + +}; + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_CertStoreBearSSL_H */ diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp new file mode 100755 index 000000000..02d50e04a --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp @@ -0,0 +1,277 @@ +/* + * HTTP Client for ESP8266 wrapper v1.0.1 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESP_Mail_HTTPClient_CPP +#define ESP_Mail_HTTPClient_CPP + +#ifdef ESP8266 + +#include "ESP_Mail_HTTPClient.h" + +ESP_Mail_HTTPClient::ESP_Mail_HTTPClient() +{ +} + +ESP_Mail_HTTPClient::~ESP_Mail_HTTPClient() +{ + if (_wcs) + { + _wcs->stop(); + _wcs.reset(nullptr); + _wcs.release(); + } + + std::string().swap(_host); + std::string().swap(_caCertFile); + _cacert.reset(new char); + _cacert = nullptr; +} + +bool ESP_Mail_HTTPClient::begin(const char *host, uint16_t port) +{ + if (strcmp(_host.c_str(), host) != 0) + mflnChecked = false; + + _host = host; + _port = port; + + //probe for fragmentation support at the specified size + if (!mflnChecked) + { + fragmentable = _wcs->probeMaxFragmentLength(_host.c_str(), _port, chunkSize); + if (fragmentable) + { + _bsslRxSize = chunkSize; + _bsslTxSize = chunkSize; + _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); + } + mflnChecked = true; + } + + if (!fragmentable) + _wcs->setBufferSizes(maxRXBufSize / rxBufDivider, maxTXBufSize / txBufDivider); + + return true; +} + +bool ESP_Mail_HTTPClient::connected() +{ + if (_wcs) + { + if (_secured) + return _wcs->connected(); + else + return _wcs->_ns_connected(); + } + + return false; +} + +bool ESP_Mail_HTTPClient::send(const char *header) +{ + if (!connected()) + return false; + if (_secured) + return (_wcs->write((uint8_t *)header, strlen(header)) == strlen(header)); + else + return (_wcs->_ns_write((uint8_t *)header, strlen(header)) == strlen(header)); +} + +int ESP_Mail_HTTPClient::send(const char *header, const char *payload) +{ + size_t size = strlen(payload); + if (strlen(header) > 0) + { + if (!connect(_secured)) + { + return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED; + } + + if (!send(header)) + { + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED; + } + } + + if (size > 0) + { + if (_secured) + { + if (_wcs->write((uint8_t *)&payload[0], size) != size) + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; + } + else + { + if (_wcs->_ns_write((uint8_t *)&payload[0], size) != size) + return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; + } + } + + return 0; +} + +WiFiClient *ESP_Mail_HTTPClient::stream(void) +{ + if (connected()) + return _wcs.get(); + return nullptr; +} + +ESP_Mail::ESP_Mail_WCS *ESP_Mail_HTTPClient::_stream(void) +{ + if (connected()) + return _wcs.get(); + return nullptr; +} + +size_t ESP_Mail_HTTPClient::_ns_print(const char *buf) +{ + size_t size = strlen(buf); + return _wcs->_ns_write((uint8_t *)&buf[0], size); +} + +size_t ESP_Mail_HTTPClient::_ns_println(const char *buf) +{ + size_t size = strlen(buf); + size_t wr = _wcs->_ns_write((uint8_t *)&buf[0], size); + std::string s = "\r\n"; + wr += _wcs->_ns_write((uint8_t *)s.c_str(), s.length()); + return wr; +} + +bool ESP_Mail_HTTPClient::connect(bool secured) +{ + _secured = secured; + + if (connected()) + { + if (_secured) + { + while (_wcs->available() > 0) + _wcs->read(); + } + else + { + while (_wcs->_ns_available() > 0) + _wcs->_ns_read(); + } + return true; + } + + _wcs->setStartTLS(!_secured); + if (!_wcs->connect(_host.c_str(), _port)) + return false; + + return connected(); +} + +void ESP_Mail_HTTPClient::setCACert(const char *caCert) +{ + +#ifndef USING_AXTLS + _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); +#endif + + if (caCert) + { +#ifndef USING_AXTLS + _wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(caCert)); +#else + _wcs->setCACert_P(caCert, strlen_P(caCert)); +#endif + _certType = 1; + } + else + { +#ifndef USING_AXTLS + _wcs->setInsecure(); +#endif + _certType = 0; + } + + _wcs->setNoDelay(true); +} + +void ESP_Mail_HTTPClient::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin) +{ + +#ifndef USING_AXTLS + _sdPin = sdPin; + _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); + + if (_clockReady && strlen(caCertFile) > 0) + { + + if (storageType == 0) + { + bool t = FLASH_FS.begin(); + if (t) + { + fs::File f; + if (FLASH_FS.exists(caCertFile)) + { + f = FLASH_FS.open(caCertFile, "r"); + size_t len = f.size(); + uint8_t *der = new uint8_t[len]; + + if (f.available()) + f.read(der, len); + + f.close(); + _wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len)); + delete[] der; + } + } + } + else + { + bool t = SD.begin(_sdPin); + if (t) + { + File f; + if (SD.exists(caCertFile)) + { + f = SD.open(caCertFile, FILE_READ); + size_t len = f.size(); + uint8_t *der = new uint8_t[len]; + if (f.available()) + f.read(der, len); + + f.close(); + _wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len)); + delete[] der; + } + } + } + _certType = 2; + } +#endif + + _wcs->setNoDelay(true); +} + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_HTTPClient_CPP */ \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h new file mode 100755 index 000000000..ba032d212 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h @@ -0,0 +1,151 @@ +/* + * HTTP Client for ESP8266 wrapper v1.0.1 + * + * The MIT License (MIT) + * Copyright (c) 2021 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ESP_Mail_HTTPClient_H +#define ESP_Mail_HTTPClient_H + +#ifdef ESP8266 + +//ARDUINO_ESP8266_GIT_VER +//2.6.2 0xbc204a9b +//2.6.1 0x482516e3 +//2.6.0 0x643ec203 +//2.5.2 0x8b899c12 +//2.5.1 0xac02aff5 +//2.5.0 0x951aeffa +//2.5.0-beta3 0x21db8fc9 +//2.5.0-beta2 0x0fd86a07 +//2.5.0-beta1 0x9c1e03a1 +//2.4.2 0xbb28d4a3 +//2.4.1 0x614f7c32 +//2.4.0 0x4ceabea9 +//2.4.0-rc2 0x0c897c37 +//2.4.0-rc1 0xf6d232f1 + +#include +#include +#include + +#ifndef ARDUINO_ESP8266_GIT_VER +#error Your ESP8266 Arduino Core SDK is outdated, please update. From Arduino IDE go to Boards Manager and search 'esp8266' then select the latest version. +#endif + +#include + +#if ARDUINO_ESP8266_GIT_VER != 0xf6d232f1 && ARDUINO_ESP8266_GIT_VER != 0x0c897c37 && ARDUINO_ESP8266_GIT_VER != 0x4ceabea9 && ARDUINO_ESP8266_GIT_VER != 0x614f7c32 && ARDUINO_ESP8266_GIT_VER != 0xbb28d4a3 +#include "ESP_Mail_WCS.h" +#include "ESP_Mail_BearSSLHelpers.h" +#define ESP_MAIL_SSL_CLIENT ESP_Mail::ESP_Mail_WCS +#else +#error Please update the ESP8266 Arduino Core SDK to latest version. +#endif + +#define FS_NO_GLOBALS +#include +#include +#include "extras/ESP_Mail_Client_FS.h" + +#ifdef USE_LITTLEFS +#include +#define FLASH_FS LittleFS +#else +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#define FLASH_FS SPIFFS +#endif + +#if __has_include() || __has_include() +#error WiFi UART bridge was not supported. +#endif + +#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1) +#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2) +#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) +#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30 + +enum esp_mail_file_storage_type +{ + esp_mail_file_storage_type_none, + esp_mail_file_storage_type_flash, + esp_mail_file_storage_type_sd, + esp_mail_file_storage_type_univ +}; + +class ESP_Mail_HTTPClient +{ + +public: + ESP_Mail_HTTPClient(); + ~ESP_Mail_HTTPClient(); + + bool begin(const char *host, uint16_t port); + + bool connected(void); + + int send(const char *header, const char *payload); + + bool send(const char *header); + + WiFiClient *stream(void); + + ESP_Mail::ESP_Mail_WCS *_stream(void); + + size_t _ns_print(const char *buf); + + size_t _ns_println(const char *buf); + + void setCACert(const char *caCert); + void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin); + bool connect(bool secured); + + int _certType = -1; + std::string _caCertFile = ""; + esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none; + uint16_t tcpTimeout = 40000; + + uint8_t _sdPin = 15; + bool _clockReady = false; + uint16_t _bsslRxSize = 1024; + uint16_t _bsslTxSize = 1024; + bool fragmentable = false; + int chunkSize = 1024; + int maxRXBufSize = 16384; //SSL full supported 16 kB + int maxTXBufSize = 16384; + bool mflnChecked = false; + int rxBufDivider = maxRXBufSize / chunkSize; + int txBufDivider = maxRXBufSize / chunkSize; + ; + +private: + std::unique_ptr _wcs = std::unique_ptr(new ESP_MAIL_SSL_CLIENT()); + std::unique_ptr _cacert; + std::string _host = ""; + uint16_t _port = 0; + bool _secured = true; +}; + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_HTTPClient_H */ diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp new file mode 100755 index 000000000..081c18f7b --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp @@ -0,0 +1,2119 @@ +/* + Customized version of WiFiClientSecure.cpp + + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ESP_Mail_WCS_CPP +#define ESP_Mail_WCS_CPP + +#ifdef ESP8266 + +#define LWIP_INTERNAL + +#include +#include +#include + +extern "C" +{ +#include +#include +} +#include +#include +#include +#include +#include "ESP_Mail_WCS.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !CORE_MOCK + +// The BearSSL thunks in use for now +#define br_ssl_engine_recvapp_ack thunk_br_ssl_engine_recvapp_ack +#define br_ssl_engine_recvapp_buf thunk_br_ssl_engine_recvapp_buf +#define br_ssl_engine_recvrec_ack thunk_br_ssl_engine_recvrec_ack +#define br_ssl_engine_recvrec_buf thunk_br_ssl_engine_recvrec_buf +#define br_ssl_engine_sendapp_ack thunk_br_ssl_engine_sendapp_ack +#define br_ssl_engine_sendapp_buf thunk_br_ssl_engine_sendapp_buf +#define br_ssl_engine_sendrec_ack thunk_br_ssl_engine_sendrec_ack +#define br_ssl_engine_sendrec_buf thunk_br_ssl_engine_sendrec_buf + +#endif + +#ifdef DEBUG_ESP_SSL +#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR("BSSL:" fmt), ##__VA_ARGS__) +#else +#define DEBUG_BSSL(...) +#endif + +namespace ESP_Mail +{ + + void ESP_Mail_WCS::_clear() + { + // TLS handshake may take more than the 5 second default timeout + _timeout = 15000; + + _sc = nullptr; + _sc_svr = nullptr; + _eng = nullptr; + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + _iobuf_in = nullptr; + _iobuf_out = nullptr; + _now = 0; // You can override or ensure time() is correct w/configTime + _ta = nullptr; + setBufferSizes(16384, 512); // Minimum safe + _handshake_done = false; + _recvapp_buf = nullptr; + _recvapp_len = 0; + _oom_err = false; + _session = nullptr; + _cipher_list = nullptr; + _cipher_cnt = 0; + } + + void ESP_Mail_WCS::_clearAuthenticationSettings() + { + _use_insecure = false; + _use_fingerprint = false; + _use_self_signed = false; + _knownkey = nullptr; + _sk = nullptr; + _ta = nullptr; + _axtls_ta = nullptr; + _axtls_chain = nullptr; + _axtls_sk = nullptr; + } + + ESP_Mail_WCS::ESP_Mail_WCS() : WiFiClient() + { + _clear(); + _clearAuthenticationSettings(); + _certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived + stack_thunk_add_ref(); + } + + ESP_Mail_WCS::ESP_Mail_WCS(const ESP_Mail_WCS &rhs) : WiFiClient(rhs) + { + *this = rhs; + stack_thunk_add_ref(); + } + + ESP_Mail_WCS::~ESP_Mail_WCS() + { + if (_client) + { + _client->unref(); + _client = nullptr; + } + _cipher_list = nullptr; // std::shared will free if last reference + _freeSSL(); + stack_thunk_del_ref(); + // Clean up any dangling axtls compat structures, if needed + _axtls_ta = nullptr; + _axtls_chain = nullptr; + _axtls_sk = nullptr; + } + + ESP_Mail_WCS::ESP_Mail_WCS(ClientContext *client, + const ESP_Mail_X509List *chain, const PrivateKey *sk, + int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta) + { + _clear(); + _clearAuthenticationSettings(); + stack_thunk_add_ref(); + _iobuf_in_size = iobuf_in_size; + _iobuf_out_size = iobuf_out_size; + _client = client; + _client->ref(); + if (!_connectSSLServerRSA(chain, sk, client_CA_ta)) + { + _client->unref(); + _client = nullptr; + _clear(); + } + } + + ESP_Mail_WCS::ESP_Mail_WCS(ClientContext *client, + const ESP_Mail_X509List *chain, + unsigned cert_issuer_key_type, const PrivateKey *sk, + int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta) + { + _clear(); + _clearAuthenticationSettings(); + stack_thunk_add_ref(); + _iobuf_in_size = iobuf_in_size; + _iobuf_out_size = iobuf_out_size; + _client = client; + _client->ref(); + if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, client_CA_ta)) + { + _client->unref(); + _client = nullptr; + _clear(); + } + } + + void ESP_Mail_WCS::setClientRSACert(const ESP_Mail_X509List *chain, const PrivateKey *sk) + { + _chain = chain; + _sk = sk; + } + + void ESP_Mail_WCS::setClientECCert(const ESP_Mail_X509List *chain, + const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) + { + _chain = chain; + _sk = sk; + _allowed_usages = allowed_usages; + _cert_issuer_key_type = cert_issuer_key_type; + } + + void ESP_Mail_WCS::setBufferSizes(int recv, int xmit) + { + // Following constants taken from bearssl/src/ssl/ssl_engine.c (not exported unfortunately) + const int MAX_OUT_OVERHEAD = 85; + const int MAX_IN_OVERHEAD = 325; + + // The data buffers must be between 512B and 16KB + recv = std::max(512, std::min(16384, recv)); + xmit = std::max(512, std::min(16384, xmit)); + + // Add in overhead for SSL protocol + recv += MAX_IN_OVERHEAD; + xmit += MAX_OUT_OVERHEAD; + _iobuf_in_size = recv; + _iobuf_out_size = xmit; + } + + bool ESP_Mail_WCS::stop(unsigned int maxWaitMs) + { + bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush() + // Only if we've already connected, store session params and clear the connection options + if (_handshake_done) + { + if (_session) + { + br_ssl_engine_get_session_parameters(_eng, _session->getSession()); + } + } + _freeSSL(); + return ret; + } + + bool ESP_Mail_WCS::flush(unsigned int maxWaitMs) + { + (void)_run_until(BR_SSL_SENDAPP); + return WiFiClient::flush(maxWaitMs); + } + + int ESP_Mail_WCS::connect(IPAddress ip, uint16_t port) + { + if (!WiFiClient::connect(ip, port)) + { + return 0; + } + return _connectSSL(nullptr); + } + + int ESP_Mail_WCS::connect(const char *name, uint16_t port) + { + IPAddress remote_addr; + if (!WiFi.hostByName(name, remote_addr)) + { + DEBUG_BSSL("connect: Name loopup failure\n"); + return 0; + } + if (!WiFiClient::connect(remote_addr, port)) + { + DEBUG_BSSL("connect: Unable to connect TCP socket\n"); + return 0; + } + _host_name = name; + if (!_secured) + return true; + return _connectSSL(name); + } + + int ESP_Mail_WCS::connect(const String &host, uint16_t port) + { + return connect(host.c_str(), port); + } + + void ESP_Mail_WCS::_freeSSL() + { + // These are smart pointers and will free if refcnt==0 + _sc = nullptr; + _sc_svr = nullptr; + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + _iobuf_in = nullptr; + _iobuf_out = nullptr; + // Reset non-allocated ptrs (pointing to bits potentially free'd above) + _recvapp_buf = nullptr; + _recvapp_len = 0; + // This connection is toast + _handshake_done = false; + _timeout = 15000; + } + + bool ESP_Mail_WCS::_clientConnected() + { + return (_client && _client->state() == ESTABLISHED); + } + + uint8_t ESP_Mail_WCS::connected() + { + if (available() || (_clientConnected() && _handshake_done && (br_ssl_engine_current_state(_eng) != BR_SSL_CLOSED))) + { + return true; + } + return false; + } + + size_t ESP_Mail_WCS::_write(const uint8_t *buf, size_t size, bool pmem) + { + size_t sent_bytes = 0; + + if (!connected() || !size || !_handshake_done) + { + return 0; + } + + do + { + // Ensure we yield if we need multiple fragments to avoid WDT + if (sent_bytes) + { + optimistic_yield(1000); + } + + // Get BearSSL to a state where we can send + if (_run_until(BR_SSL_SENDAPP) < 0) + { + break; + } + + if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) + { + size_t sendapp_len; + unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len); + int to_send = size > sendapp_len ? sendapp_len : size; + if (pmem) + { + memcpy_P(sendapp_buf, buf, to_send); + } + else + { + memcpy(sendapp_buf, buf, to_send); + } + br_ssl_engine_sendapp_ack(_eng, to_send); + br_ssl_engine_flush(_eng, 0); + flush(); + buf += to_send; + sent_bytes += to_send; + size -= to_send; + } + else + { + break; + } + } while (size); + + return sent_bytes; + } + + size_t ESP_Mail_WCS::write(const uint8_t *buf, size_t size) + { + return _write(buf, size, false); + } + + size_t ESP_Mail_WCS::write_P(PGM_P buf, size_t size) + { + return _write((const uint8_t *)buf, size, true); + } + + // We have to manually read and send individual chunks. + size_t ESP_Mail_WCS::write(Stream &stream) + { + size_t totalSent = 0; + size_t countRead; + size_t countSent; + + if (!connected() || !_handshake_done) + { + DEBUG_BSSL("write: Connect/handshake not completed yet\n"); + return 0; + } + + do + { + uint8_t temp[256]; // Temporary chunk size same as ClientContext + countSent = 0; + countRead = stream.readBytes(temp, sizeof(temp)); + if (countRead) + { + countSent = _write((const uint8_t *)temp, countRead, true); + totalSent += countSent; + } + yield(); // Feed the WDT + } while ((countSent == countRead) && (countSent > 0)); + return totalSent; + } + + int ESP_Mail_WCS::read(uint8_t *buf, size_t size) + { + if (!ctx_present() || !_handshake_done) + { + return -1; + } + + int avail = available(); + bool conn = connected(); + if (!avail && conn) + { + return 0; // We're still connected, but nothing to read + } + if (!avail && !conn) + { + DEBUG_BSSL("read: Not connected, none left available\n"); + return -1; + } + + if (avail) + { + // Take data from the recvapp buffer + int to_copy = _recvapp_len < size ? _recvapp_len : size; + memcpy(buf, _recvapp_buf, to_copy); + br_ssl_engine_recvapp_ack(_eng, to_copy); + _recvapp_buf = nullptr; + _recvapp_len = 0; + return to_copy; + } + + if (!conn) + { + DEBUG_BSSL("read: Not connected\n"); + return -1; + } + return 0; // If we're connected, no error but no read. + } + + int ESP_Mail_WCS::read() + { + uint8_t c; + if (1 == read(&c, 1)) + { + return c; + } + DEBUG_BSSL("read: failed\n"); + return -1; + } + + int ESP_Mail_WCS::available() + { + if (_recvapp_buf) + { + return _recvapp_len; // Anything from last call? + } + _recvapp_buf = nullptr; + _recvapp_len = 0; + if (!ctx_present() || _run_until(BR_SSL_RECVAPP, false) < 0) + { + return 0; + } + int st = br_ssl_engine_current_state(_eng); + if (st == BR_SSL_CLOSED) + { + return 0; // Nothing leftover, SSL is closed + } + if (st & BR_SSL_RECVAPP) + { + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + return _recvapp_len; + } + + return 0; + } + + int ESP_Mail_WCS::peek() + { + if (!ctx_present() || !available()) + { + DEBUG_BSSL("peek: Not connected, none left available\n"); + return -1; + } + if (_recvapp_buf && _recvapp_len) + { + return _recvapp_buf[0]; + } + DEBUG_BSSL("peek: No data left\n"); + return -1; + } + + size_t ESP_Mail_WCS::peekBytes(uint8_t *buffer, size_t length) + { + size_t to_copy = 0; + if (!ctx_present()) + { + DEBUG_BSSL("peekBytes: Not connected\n"); + return 0; + } + + _startMillis = millis(); + while ((available() < (int)length) && ((millis() - _startMillis) < 5000)) + { + yield(); + } + + to_copy = _recvapp_len < length ? _recvapp_len : length; + memcpy(buffer, _recvapp_buf, to_copy); + return to_copy; + } + + /* --- Copied almost verbatim from BEARSSL SSL_IO.C --- + Run the engine, until the specified target state is achieved, or + an error occurs. The target state is SENDAPP, RECVAPP, or the + combination of both (the combination matches either). When a match is + achieved, this function returns 0. On error, it returns -1. +*/ + int ESP_Mail_WCS::_run_until(unsigned target, bool blocking) + { + if (!ctx_present()) + { + DEBUG_BSSL("_run_until: Not connected\n"); + return -1; + } + + esp8266::polledTimeout::oneShotMs loopTimeout(_timeout); + + for (int no_work = 0; blocking || no_work < 2;) + { + optimistic_yield(100); + + if (loopTimeout) + { + DEBUG_BSSL("_run_until: Timeout\n"); + return -1; + } + + int state; + state = br_ssl_engine_current_state(_eng); + if (state & BR_SSL_CLOSED) + { + return -1; + } + + if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) + { + return (state & target) ? 0 : -1; + } + + /* + If there is some record data to send, do it. This takes + precedence over everything else. + */ + if (state & BR_SSL_SENDREC) + { + unsigned char *buf; + size_t len; + int wlen; + size_t availForWrite; + + buf = br_ssl_engine_sendrec_buf(_eng, &len); + availForWrite = WiFiClient::availableForWrite(); + + if (!blocking && len > availForWrite) + { + /* + writes on WiFiClient will block if len > availableForWrite() + this is needed to prevent available() calls from blocking + on dropped connections + */ + len = availForWrite; + } + wlen = WiFiClient::write(buf, len); + if (wlen <= 0) + { + /* + If we received a close_notify and we + still send something, then we have our + own response close_notify to send, and + the peer is allowed by RFC 5246 not to + wait for it. + */ + return -1; + } + if (wlen > 0) + { + br_ssl_engine_sendrec_ack(_eng, wlen); + } + no_work = 0; + continue; + } + + /* + If we reached our target, then we are finished. + */ + if (state & target) + { + return 0; + } + + /* + If some application data must be read, and we did not + exit, then this means that we are trying to write data, + and that's not possible until the application data is + read. This may happen if using a shared in/out buffer, + and the underlying protocol is not strictly half-duplex. + This is unrecoverable here, so we report an error. + */ + if (state & BR_SSL_RECVAPP) + { + DEBUG_BSSL("_run_until: Fatal protocol state\n"); + return -1; + } + + /* + If we reached that point, then either we are trying + to read data and there is some, or the engine is stuck + until a new record is obtained. + */ + if (state & BR_SSL_RECVREC) + { + if (WiFiClient::available()) + { + unsigned char *buf; + size_t len; + int rlen; + + buf = br_ssl_engine_recvrec_buf(_eng, &len); + rlen = WiFiClient::read(buf, len); + if (rlen < 0) + { + return -1; + } + if (rlen > 0) + { + br_ssl_engine_recvrec_ack(_eng, rlen); + } + no_work = 0; + continue; + } + } + + /* + We can reach that point if the target RECVAPP, and + the state contains SENDAPP only. This may happen with + a shared in/out buffer. In that case, we must flush + the buffered data to "make room" for a new incoming + record. + */ + br_ssl_engine_flush(_eng, 0); + + no_work++; // We didn't actually advance here + } + // We only get here if we ran through the loop without getting anything done + return -1; + } + + bool ESP_Mail_WCS::_wait_for_handshake() + { + _handshake_done = false; + while (!_handshake_done && _clientConnected()) + { + int ret = _run_until(BR_SSL_SENDAPP); + if (ret < 0) + { + DEBUG_BSSL("_wait_for_handshake: failed\n"); + break; + } + if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) + { + _handshake_done = true; + } + optimistic_yield(1000); + } + return _handshake_done; + } + + static uint8_t htoi(unsigned char c) + { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; + else + return 255; + } + + // Set a fingerprint by parsing an ASCII string + bool ESP_Mail_WCS::setFingerprint(const char *fpStr) + { + int idx = 0; + uint8_t c, d; + uint8_t fp[20]; + + while (idx < 20) + { + c = pgm_read_byte(fpStr++); + if (!c) + break; // String ended, done processing + d = pgm_read_byte(fpStr++); + if (!d) + { + DEBUG_BSSL("setFingerprint: FP too short\n"); + return false; // Only half of the last hex digit, error + } + c = htoi(c); + d = htoi(d); + if ((c > 15) || (d > 15)) + { + DEBUG_BSSL("setFingerprint: Invalid char\n"); + return false; // Error in one of the hex characters + } + fp[idx++] = (c << 4) | d; + + // Skip 0 or more spaces or colons + while (pgm_read_byte(fpStr) && (pgm_read_byte(fpStr) == ' ' || pgm_read_byte(fpStr) == ':')) + { + fpStr++; + } + } + if ((idx != 20) || pgm_read_byte(fpStr)) + { + DEBUG_BSSL("setFingerprint: Garbage at end of fp\n"); + return false; // Garbage at EOL or we didn't have enough hex digits + } + return setFingerprint(fp); + } + + extern "C" + { + + // BearSSL doesn't define a true insecure decoder, so we make one ourselves + // from the simple parser. It generates the issuer and subject hashes and + // the SHA1 fingerprint, only one (or none!) of which will be used to + // "verify" the certificate. + + // Private x509 decoder state + struct br_x509_insecure_context + { + const br_x509_class *vtable; + bool done_cert; + const uint8_t *match_fingerprint; + br_sha1_context sha1_cert; + bool allow_self_signed; + br_sha256_context sha256_subject; + br_sha256_context sha256_issuer; + br_x509_decoder_context ctx; + }; + + // Callback for the x509_minimal subject DN + static void insecure_subject_dn_append(void *ctx, const void *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + br_sha256_update(&xc->sha256_subject, buf, len); + } + + // Callback for the x509_minimal issuer DN + static void insecure_issuer_dn_append(void *ctx, const void *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + br_sha256_update(&xc->sha256_issuer, buf, len); + } + + // Callback on the first byte of any certificate + static void insecure_start_chain(const br_x509_class **ctx, const char *server_name) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + br_x509_decoder_init(&xc->ctx, insecure_subject_dn_append, xc, insecure_issuer_dn_append, xc); + xc->done_cert = false; + br_sha1_init(&xc->sha1_cert); + br_sha256_init(&xc->sha256_subject); + br_sha256_init(&xc->sha256_issuer); + (void)server_name; + } + + // Callback for each certificate present in the chain (but only operates + // on the first one by design). + static void insecure_start_cert(const br_x509_class **ctx, uint32_t length) + { + (void)ctx; + (void)length; + } + + // Callback for each byte stream in the chain. Only process first cert. + static void insecure_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + // Don't process anything but the first certificate in the chain + if (!xc->done_cert) + { + br_sha1_update(&xc->sha1_cert, buf, len); + br_x509_decoder_push(&xc->ctx, (const void *)buf, len); +#ifdef DEBUG_ESP_SSL + DEBUG_BSSL("CERT: "); + for (size_t i = 0; i < len; i++) + { + DEBUG_ESP_PORT.printf_P(PSTR("%02x "), buf[i] & 0xff); + } + DEBUG_ESP_PORT.printf_P(PSTR("\n")); +#endif + } + } + + // Callback on individual cert end. + static void insecure_end_cert(const br_x509_class **ctx) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + xc->done_cert = true; + } + + // Callback when complete chain has been parsed. + // Return 0 on validation success, !0 on validation error + static unsigned insecure_end_chain(const br_x509_class **ctx) + { + const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; + if (!xc->done_cert) + { + DEBUG_BSSL("insecure_end_chain: No cert seen\n"); + return 1; // error + } + + // Handle SHA1 fingerprint matching + char res[20]; + br_sha1_out(&xc->sha1_cert, res); + if (xc->match_fingerprint && memcmp(res, xc->match_fingerprint, sizeof(res))) + { +#ifdef DEBUG_ESP_SSL + DEBUG_BSSL("insecure_end_chain: Received cert FP doesn't match\n"); + char buff[3 * sizeof(res) + 1]; // 3 chars per byte XX_, and null + buff[0] = 0; + for (size_t i = 0; i < sizeof(res); i++) + { + char hex[4]; // XX_\0 + snprintf(hex, sizeof(hex), "%02x ", xc->match_fingerprint[i] & 0xff); + strlcat(buff, hex, sizeof(buff)); + } + DEBUG_BSSL("insecure_end_chain: expected %s\n", buff); + buff[0] = 0; + for (size_t i = 0; i < sizeof(res); i++) + { + char hex[4]; // XX_\0 + snprintf(hex, sizeof(hex), "%02x ", res[i] & 0xff); + strlcat(buff, hex, sizeof(buff)); + } + DEBUG_BSSL("insecure_end_chain: received %s\n", buff); +#endif + return BR_ERR_X509_NOT_TRUSTED; + } + + // Handle self-signer certificate acceptance + char res_issuer[32]; + char res_subject[32]; + br_sha256_out(&xc->sha256_issuer, res_issuer); + br_sha256_out(&xc->sha256_subject, res_subject); + if (xc->allow_self_signed && memcmp(res_subject, res_issuer, sizeof(res_issuer))) + { + DEBUG_BSSL("insecure_end_chain: Didn't get self-signed cert\n"); + return BR_ERR_X509_NOT_TRUSTED; + } + + // Default (no validation at all) or no errors in prior checks = success. + return 0; + } + + // Return the public key from the validator (set by x509_minimal) + static const br_x509_pkey *insecure_get_pkey(const br_x509_class *const *ctx, unsigned *usages) + { + const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; + if (usages != NULL) + { + *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; // I said we were insecure! + } + return &xc->ctx.pkey; + } + + // Set up the x509 insecure data structures for BearSSL core to use. + void esp_mail_br_x509_insecure_init(br_x509_insecure_context *ctx, int _use_fingerprint, const uint8_t _fingerprint[20], int _allow_self_signed) + { + static const br_x509_class br_x509_insecure_vtable PROGMEM = { + sizeof(br_x509_insecure_context), + insecure_start_chain, + insecure_start_cert, + insecure_append, + insecure_end_cert, + insecure_end_chain, + insecure_get_pkey}; + + memset(ctx, 0, sizeof *ctx); + ctx->vtable = &br_x509_insecure_vtable; + ctx->done_cert = false; + ctx->match_fingerprint = _use_fingerprint ? _fingerprint : nullptr; + ctx->allow_self_signed = _allow_self_signed ? 1 : 0; + } + + + // Some constants uses to init the server/client contexts + // Note that suites_P needs to be copied to RAM before use w/BearSSL! + // List copied verbatim from BearSSL/ssl_client_full.c + /* + * The "full" profile supports all implemented cipher suites. + * + * Rationale for suite order, from most important to least + * important rule: + * + * -- Don't use 3DES if AES or ChaCha20 is available. + * -- Try to have Forward Secrecy (ECDHE suite) if possible. + * -- When not using Forward Secrecy, ECDH key exchange is + * better than RSA key exchange (slightly more expensive on the + * client, but much cheaper on the server, and it implies smaller + * messages). + * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code). + * -- GCM is better than CCM and CBC. CCM is better than CBC. + * -- CCM is preferable over CCM_8 (with CCM_8, forgeries may succeed + * with probability 2^(-64)). + * -- AES-128 is preferred over AES-256 (AES-128 is already + * strong enough, and AES-256 is 40% more expensive). + */ + static const uint16_t suites_P[] PROGMEM = { +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_RSA_WITH_AES_256_CCM_8, +#endif + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#endif + }; +#ifndef BEARSSL_SSL_BASIC + // Server w/EC has one set, not possible with basic SSL config + static const uint16_t suites_server_ec_P[] PROGMEM = { + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}; +#endif + + static const uint16_t suites_server_rsa_P[] PROGMEM = { +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_RSA_WITH_AES_256_CCM_8, +#endif + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#endif + }; + + // For apps which want to use less secure but faster ciphers, only + static const uint16_t faster_suites_P[] PROGMEM = { + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_CBC_SHA}; + + // Install hashes into the SSL engine + static void br_ssl_client_install_hashes(br_ssl_engine_context *eng) + { + br_ssl_engine_set_hash(eng, br_md5_ID, &br_md5_vtable); + br_ssl_engine_set_hash(eng, br_sha1_ID, &br_sha1_vtable); + br_ssl_engine_set_hash(eng, br_sha224_ID, &br_sha224_vtable); + br_ssl_engine_set_hash(eng, br_sha256_ID, &br_sha256_vtable); + br_ssl_engine_set_hash(eng, br_sha384_ID, &br_sha384_vtable); + br_ssl_engine_set_hash(eng, br_sha512_ID, &br_sha512_vtable); + } + + static void br_x509_minimal_install_hashes(br_x509_minimal_context *x509) + { + br_x509_minimal_set_hash(x509, br_md5_ID, &br_md5_vtable); + br_x509_minimal_set_hash(x509, br_sha1_ID, &br_sha1_vtable); + br_x509_minimal_set_hash(x509, br_sha224_ID, &br_sha224_vtable); + br_x509_minimal_set_hash(x509, br_sha256_ID, &br_sha256_vtable); + br_x509_minimal_set_hash(x509, br_sha384_ID, &br_sha384_vtable); + br_x509_minimal_set_hash(x509, br_sha512_ID, &br_sha512_vtable); + } + + // Default initializion for our SSL clients + static void br_ssl_client_base_init(br_ssl_client_context *cc, const uint16_t *cipher_list, int cipher_cnt) + { + uint16_t suites[cipher_cnt]; + memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0])); + br_ssl_client_zero(cc); + br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); // forbid SSL renegociation, as we free the Private Key after handshake + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); + br_ssl_client_set_default_rsapub(cc); + br_ssl_engine_set_default_rsavrfy(&cc->eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_ecdsa(&cc->eng); +#endif + br_ssl_client_install_hashes(&cc->eng); + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + br_ssl_engine_set_default_aes_cbc(&cc->eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +#endif + } + + // Default initializion for our SSL clients + static void br_ssl_server_base_init(br_ssl_server_context *cc, const uint16_t *cipher_list, int cipher_cnt) + { + uint16_t suites[cipher_cnt]; + memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0])); + br_ssl_server_zero(cc); + br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); // forbid SSL renegociation, as we free the Private Key after handshake + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_ec(&cc->eng); +#endif + + br_ssl_client_install_hashes(&cc->eng); + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + br_ssl_engine_set_default_aes_cbc(&cc->eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +#endif + } + } + + // Set custom list of ciphers + bool ESP_Mail_WCS::setCiphers(const uint16_t *cipherAry, int cipherCount) + { + _cipher_list = nullptr; + _cipher_list = std::shared_ptr(new uint16_t[cipherCount], std::default_delete()); + if (!_cipher_list.get()) + { + DEBUG_BSSL("setCiphers: list empty\n"); + return false; + } + memcpy_P(_cipher_list.get(), cipherAry, cipherCount * sizeof(uint16_t)); + _cipher_cnt = cipherCount; + return true; + } + + bool ESP_Mail_WCS::setCiphersLessSecure() + { + return setCiphers(faster_suites_P, sizeof(faster_suites_P) / sizeof(faster_suites_P[0])); + } + + bool ESP_Mail_WCS::setCiphers(std::vector list) + { + return setCiphers(&list[0], list.size()); + } + + // Installs the appropriate X509 cert validation method for a client connection + bool ESP_Mail_WCS::_installClientX509Validator() + { + if (_use_insecure || _use_fingerprint || _use_self_signed) + { + // Use common insecure x509 authenticator + _x509_insecure = std::make_shared(); + if (!_x509_insecure) + { + DEBUG_BSSL("_installClientX509Validator: OOM for _x509_insecure\n"); + return false; + } + esp_mail_br_x509_insecure_init(_x509_insecure.get(), _use_fingerprint, _fingerprint, _use_self_signed); + br_ssl_engine_set_x509(_eng, &_x509_insecure->vtable); + } + else if (_knownkey) + { + // Simple, pre-known public key authenticator, ignores cert completely. + _x509_knownkey = std::make_shared(); + if (!_x509_knownkey) + { + DEBUG_BSSL("_installClientX509Validator: OOM for _x509_knownkey\n"); + return false; + } + if (_knownkey->isRSA()) + { + br_x509_knownkey_init_rsa(_x509_knownkey.get(), _knownkey->getRSA(), _knownkey_usages); + } + else if (_knownkey->isEC()) + { +#ifndef BEARSSL_SSL_BASIC + br_x509_knownkey_init_ec(_x509_knownkey.get(), _knownkey->getEC(), _knownkey_usages); +#else + (void)_knownkey; + (void)_knownkey_usages; + DEBUG_BSSL("_installClientX509Validator: Attempting to use EC keys in minimal cipher mode (no EC)\n"); + return false; +#endif + } + br_ssl_engine_set_x509(_eng, &_x509_knownkey->vtable); + } + else + { + // X509 minimal validator. Checks dates, cert chain for trusted CA, etc. + _x509_minimal = std::make_shared(); + if (!_x509_minimal) + { + DEBUG_BSSL("_installClientX509Validator: OOM for _x509_minimal\n"); + return false; + } + br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta ? _ta->getTrustAnchors() : nullptr, _ta ? _ta->getCount() : 0); + br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng)); +#ifndef BEARSSL_SSL_BASIC + br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng)); +#endif + br_x509_minimal_install_hashes(_x509_minimal.get()); + if (_now) + { + // Magic constants convert to x509 times + br_x509_minimal_set_time(_x509_minimal.get(), ((uint32_t)_now) / 86400 + 719528, ((uint32_t)_now) % 86400); + } + if (_certStore) + { + _certStore->installCertStore(_x509_minimal.get()); + } + br_ssl_engine_set_x509(_eng, &_x509_minimal->vtable); + } + return true; + } + + // Called by connect() to do the actual SSL setup and handshake. + // Returns if the SSL handshake succeeded. + bool ESP_Mail_WCS::_connectSSL(const char *hostName) + { + DEBUG_BSSL("_connectSSL: start connection\n"); + _freeSSL(); + _oom_err = false; + +#ifdef DEBUG_ESP_SSL + // BearSSL will reject all connections unless an authentication option is set, warn in DEBUG builds + if (!_use_insecure && !_use_fingerprint && !_use_self_signed && !_knownkey && !_certStore && !_ta) + { + DEBUG_BSSL("Connection *will* fail, no authentication method is setup\n"); + } +#endif + + _sc = std::make_shared(); + _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr + _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); + _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); + + if (!_sc || !_iobuf_in || !_iobuf_out) + { + _freeSSL(); // Frees _sc, _iobuf* + _oom_err = true; + DEBUG_BSSL("_connectSSL: OOM error\n"); + return false; + } + + // If no cipher list yet set, use defaults + if (_cipher_list.get() == nullptr) + { + br_ssl_client_base_init(_sc.get(), suites_P, sizeof(suites_P) / sizeof(suites_P[0])); + } + else + { + br_ssl_client_base_init(_sc.get(), _cipher_list.get(), _cipher_cnt); + } + // Only failure possible in the installation is OOM + if (!_installClientX509Validator()) + { + _freeSSL(); + _oom_err = true; + DEBUG_BSSL("_connectSSL: Can't install x509 validator\n"); + return false; + } + br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); + + // Apply any client certificates, if supplied. + if (_sk && _sk->isRSA()) + { + br_ssl_client_set_single_rsa(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, + _sk->getRSA(), br_rsa_pkcs1_sign_get_default()); + } + else if (_sk && _sk->isEC()) + { +#ifndef BEARSSL_SSL_BASIC + br_ssl_client_set_single_ec(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, + _sk->getEC(), _allowed_usages, + _cert_issuer_key_type, br_ec_get_default(), br_ecdsa_sign_asn1_get_default()); +#else + _freeSSL(); + DEBUG_BSSL("_connectSSL: Attempting to use EC cert in minimal cipher mode (no EC)\n"); + return false; +#endif + } + + // Restore session from the storage spot, if present + if (_session) + { + br_ssl_engine_set_session_parameters(_eng, _session->getSession()); + } + + if (!br_ssl_client_reset(_sc.get(), hostName, _session ? 1 : 0)) + { + _freeSSL(); + DEBUG_BSSL("_connectSSL: Can't reset client\n"); + return false; + } + + auto ret = _wait_for_handshake(); +#ifdef DEBUG_ESP_SSL + if (!ret) + { + char err[256]; + getLastSSLError(err, sizeof(err)); + DEBUG_BSSL("Couldn't connect. Error = '%s'\n", err); + } + else + { + DEBUG_BSSL("Connected!\n"); + } +#endif + + // Session is already validated here, there is no need to keep following + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + + // reduce timeout after successful handshake to fail fast if server stop accepting our data for whathever reason + if (ret) + _timeout = 5000; + + return ret; + } + + // Slightly different X509 setup for servers who want to validate client + // certificates, so factor it out as it's used in RSA and EC servers. + bool ESP_Mail_WCS::_installServerX509Validator(const ESP_Mail_X509List *client_CA_ta) + { + if (client_CA_ta) + { + _ta = client_CA_ta; + // X509 minimal validator. Checks dates, cert chain for trusted CA, etc. + _x509_minimal = std::make_shared(); + if (!_x509_minimal) + { + _freeSSL(); + _oom_err = true; + DEBUG_BSSL("_installServerX509Validator: OOM for _x509_minimal\n"); + return false; + } + br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta->getTrustAnchors(), _ta->getCount()); + br_ssl_engine_set_default_rsavrfy(_eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_ecdsa(_eng); +#endif + br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng)); +#ifndef BEARSSL_SSL_BASIC + br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng)); +#endif + br_x509_minimal_install_hashes(_x509_minimal.get()); + if (_now) + { + // Magic constants convert to x509 times + br_x509_minimal_set_time(_x509_minimal.get(), ((uint32_t)_now) / 86400 + 719528, ((uint32_t)_now) % 86400); + } + br_ssl_engine_set_x509(_eng, &_x509_minimal->vtable); + br_ssl_server_set_trust_anchor_names_alt(_sc_svr.get(), _ta->getTrustAnchors(), _ta->getCount()); + } + return true; + } + + // Called by WiFiServerBearSSL when an RSA cert/key is specified. + bool ESP_Mail_WCS::_connectSSLServerRSA(const ESP_Mail_X509List *chain, + const PrivateKey *sk, + const ESP_Mail_X509List *client_CA_ta) + { + _freeSSL(); + _oom_err = false; + _sc_svr = std::make_shared(); + _eng = &_sc_svr->eng; // Allocation/deallocation taken care of by the _sc shared_ptr + _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); + _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); + + if (!_sc_svr || !_iobuf_in || !_iobuf_out) + { + _freeSSL(); + _oom_err = true; + DEBUG_BSSL("_connectSSLServerRSA: OOM error\n"); + return false; + } + + br_ssl_server_base_init(_sc_svr.get(), suites_server_rsa_P, sizeof(suites_server_rsa_P) / sizeof(suites_server_rsa_P[0])); + br_ssl_server_set_single_rsa(_sc_svr.get(), chain ? chain->getX509Certs() : nullptr, chain ? chain->getCount() : 0, + sk ? sk->getRSA() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + br_rsa_private_get_default(), br_rsa_pkcs1_sign_get_default()); + br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); + if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) + { + DEBUG_BSSL("_connectSSLServerRSA: Can't install serverX509check\n"); + return false; + } + if (!br_ssl_server_reset(_sc_svr.get())) + { + _freeSSL(); + DEBUG_BSSL("_connectSSLServerRSA: Can't reset server ctx\n"); + return false; + } + + return _wait_for_handshake(); + } + + // Called by WiFiServerBearSSL when an elliptic curve cert/key is specified. + bool ESP_Mail_WCS::_connectSSLServerEC(const ESP_Mail_X509List *chain, + unsigned cert_issuer_key_type, const PrivateKey *sk, + const ESP_Mail_X509List *client_CA_ta) + { +#ifndef BEARSSL_SSL_BASIC + _freeSSL(); + _oom_err = false; + _sc_svr = std::make_shared(); + _eng = &_sc_svr->eng; // Allocation/deallocation taken care of by the _sc shared_ptr + _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); + _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); + + if (!_sc_svr || !_iobuf_in || !_iobuf_out) + { + _freeSSL(); + _oom_err = true; + DEBUG_BSSL("_connectSSLServerEC: OOM error\n"); + return false; + } + + br_ssl_server_base_init(_sc_svr.get(), suites_server_ec_P, sizeof(suites_server_ec_P) / sizeof(suites_server_ec_P[0])); + br_ssl_server_set_single_ec(_sc_svr.get(), chain ? chain->getX509Certs() : nullptr, chain ? chain->getCount() : 0, + sk ? sk->getEC() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, + cert_issuer_key_type, br_ssl_engine_get_ec(_eng), br_ecdsa_i15_sign_asn1); + br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); + if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) + { + DEBUG_BSSL("_connectSSLServerEC: Can't install serverX509check\n"); + return false; + } + if (!br_ssl_server_reset(_sc_svr.get())) + { + _freeSSL(); + DEBUG_BSSL("_connectSSLServerEC: Can't reset server ctx\n"); + return false; + } + + return _wait_for_handshake(); +#else + (void)chain; + (void)cert_issuer_key_type; + (void)sk; + (void)client_CA_ta; + DEBUG_BSSL("_connectSSLServerEC: Attempting to use EC cert in minimal cipher mode (no EC)\n"); + return false; +#endif + } + + // Returns an error ID and possibly a string (if dest != null) of the last + // BearSSL reported error. + int ESP_Mail_WCS::getLastSSLError(char *dest, size_t len) + { + int err = 0; + const char *t = PSTR("OK"); + if (_sc || _sc_svr) + { + err = br_ssl_engine_last_error(_eng); + } + if (_oom_err) + { + err = -1000; + } + switch (err) + { + case -1000: + t = PSTR("Unable to allocate memory for SSL structures and buffers."); + break; + case BR_ERR_BAD_PARAM: + t = PSTR("Caller-provided parameter is incorrect."); + break; + case BR_ERR_BAD_STATE: + t = PSTR("Operation requested by the caller cannot be applied with the current context state (e.g. reading data while outgoing data is waiting to be sent)."); + break; + case BR_ERR_UNSUPPORTED_VERSION: + t = PSTR("Incoming protocol or record version is unsupported."); + break; + case BR_ERR_BAD_VERSION: + t = PSTR("Incoming record version does not match the expected version."); + break; + case BR_ERR_BAD_LENGTH: + t = PSTR("Incoming record length is invalid."); + break; + case BR_ERR_TOO_LARGE: + t = PSTR("Incoming record is too large to be processed, or buffer is too small for the handshake message to send."); + break; + case BR_ERR_BAD_MAC: + t = PSTR("Decryption found an invalid padding, or the record MAC is not correct."); + break; + case BR_ERR_NO_RANDOM: + t = PSTR("No initial entropy was provided, and none can be obtained from the OS."); + break; + case BR_ERR_UNKNOWN_TYPE: + t = PSTR("Incoming record type is unknown."); + break; + case BR_ERR_UNEXPECTED: + t = PSTR("Incoming record or message has wrong type with regards to the current engine state."); + break; + case BR_ERR_BAD_CCS: + t = PSTR("ChangeCipherSpec message from the peer has invalid contents."); + break; + case BR_ERR_BAD_ALERT: + t = PSTR("Alert message from the peer has invalid contents (odd length)."); + break; + case BR_ERR_BAD_HANDSHAKE: + t = PSTR("Incoming handshake message decoding failed."); + break; + case BR_ERR_OVERSIZED_ID: + t = PSTR("ServerHello contains a session ID which is larger than 32 bytes."); + break; + case BR_ERR_BAD_CIPHER_SUITE: + t = PSTR("Server wants to use a cipher suite that we did not claim to support. This is also reported if we tried to advertise a cipher suite that we do not support."); + break; + case BR_ERR_BAD_COMPRESSION: + t = PSTR("Server wants to use a compression that we did not claim to support."); + break; + case BR_ERR_BAD_FRAGLEN: + t = PSTR("Server's max fragment length does not match client's."); + break; + case BR_ERR_BAD_SECRENEG: + t = PSTR("Secure renegotiation failed."); + break; + case BR_ERR_EXTRA_EXTENSION: + t = PSTR("Server sent an extension type that we did not announce, or used the same extension type several times in a single ServerHello."); + break; + case BR_ERR_BAD_SNI: + t = PSTR("Invalid Server Name Indication contents (when used by the server, this extension shall be empty)."); + break; + case BR_ERR_BAD_HELLO_DONE: + t = PSTR("Invalid ServerHelloDone from the server (length is not 0)."); + break; + case BR_ERR_LIMIT_EXCEEDED: + t = PSTR("Internal limit exceeded (e.g. server's public key is too large)."); + break; + case BR_ERR_BAD_FINISHED: + t = PSTR("Finished message from peer does not match the expected value."); + break; + case BR_ERR_RESUME_MISMATCH: + t = PSTR("Session resumption attempt with distinct version or cipher suite."); + break; + case BR_ERR_INVALID_ALGORITHM: + t = PSTR("Unsupported or invalid algorithm (ECDHE curve, signature algorithm, hash function)."); + break; + case BR_ERR_BAD_SIGNATURE: + t = PSTR("Invalid signature in ServerKeyExchange or CertificateVerify message."); + break; + case BR_ERR_WRONG_KEY_USAGE: + t = PSTR("Peer's public key does not have the proper type or is not allowed for the requested operation."); + break; + case BR_ERR_NO_CLIENT_AUTH: + t = PSTR("Client did not send a certificate upon request, or the client certificate could not be validated."); + break; + case BR_ERR_IO: + t = PSTR("I/O error or premature close on transport stream."); + break; + case BR_ERR_X509_INVALID_VALUE: + t = PSTR("Invalid value in an ASN.1 structure."); + break; + case BR_ERR_X509_TRUNCATED: + t = PSTR("Truncated certificate or other ASN.1 object."); + break; + case BR_ERR_X509_EMPTY_CHAIN: + t = PSTR("Empty certificate chain (no certificate at all)."); + break; + case BR_ERR_X509_INNER_TRUNC: + t = PSTR("Decoding error: inner element extends beyond outer element size."); + break; + case BR_ERR_X509_BAD_TAG_CLASS: + t = PSTR("Decoding error: unsupported tag class (application or private)."); + break; + case BR_ERR_X509_BAD_TAG_VALUE: + t = PSTR("Decoding error: unsupported tag value."); + break; + case BR_ERR_X509_INDEFINITE_LENGTH: + t = PSTR("Decoding error: indefinite length."); + break; + case BR_ERR_X509_EXTRA_ELEMENT: + t = PSTR("Decoding error: extraneous element."); + break; + case BR_ERR_X509_UNEXPECTED: + t = PSTR("Decoding error: unexpected element."); + break; + case BR_ERR_X509_NOT_CONSTRUCTED: + t = PSTR("Decoding error: expected constructed element, but is primitive."); + break; + case BR_ERR_X509_NOT_PRIMITIVE: + t = PSTR("Decoding error: expected primitive element, but is constructed."); + break; + case BR_ERR_X509_PARTIAL_BYTE: + t = PSTR("Decoding error: BIT STRING length is not multiple of 8."); + break; + case BR_ERR_X509_BAD_BOOLEAN: + t = PSTR("Decoding error: BOOLEAN value has invalid length."); + break; + case BR_ERR_X509_OVERFLOW: + t = PSTR("Decoding error: value is off-limits."); + break; + case BR_ERR_X509_BAD_DN: + t = PSTR("Invalid distinguished name."); + break; + case BR_ERR_X509_BAD_TIME: + t = PSTR("Invalid date/time representation."); + break; + case BR_ERR_X509_UNSUPPORTED: + t = PSTR("Certificate contains unsupported features that cannot be ignored."); + break; + case BR_ERR_X509_LIMIT_EXCEEDED: + t = PSTR("Key or signature size exceeds internal limits."); + break; + case BR_ERR_X509_WRONG_KEY_TYPE: + t = PSTR("Key type does not match that which was expected."); + break; + case BR_ERR_X509_BAD_SIGNATURE: + t = PSTR("Signature is invalid."); + break; + case BR_ERR_X509_TIME_UNKNOWN: + t = PSTR("Validation time is unknown."); + break; + case BR_ERR_X509_EXPIRED: + t = PSTR("Certificate is expired or not yet valid."); + break; + case BR_ERR_X509_DN_MISMATCH: + t = PSTR("Issuer/Subject DN mismatch in the chain."); + break; + case BR_ERR_X509_BAD_SERVER_NAME: + t = PSTR("Expected server name was not found in the chain."); + break; + case BR_ERR_X509_CRITICAL_EXTENSION: + t = PSTR("Unknown critical extension in certificate."); + break; + case BR_ERR_X509_NOT_CA: + t = PSTR("Not a CA, or path length constraint violation."); + break; + case BR_ERR_X509_FORBIDDEN_KEY_USAGE: + t = PSTR("Key Usage extension prohibits intended usage."); + break; + case BR_ERR_X509_WEAK_PUBLIC_KEY: + t = PSTR("Public key found in certificate is too small."); + break; + case BR_ERR_X509_NOT_TRUSTED: + t = PSTR("Chain could not be linked to a trust anchor."); + break; + default: + t = PSTR("Unknown error code."); + break; + } + if (dest) + { + strncpy_P(dest, t, len); + dest[len - 1] = 0; + } + return err; + } + + bool ESP_Mail_WCS::probeMaxFragmentLength(const char *name, uint16_t port, uint16_t len) + { + IPAddress remote_addr; + if (!WiFi.hostByName(name, remote_addr)) + { + DEBUG_BSSL("probeMaxFragmentLength: Can't resolve host\n"); + return false; + } + return ESP_Mail_WCS::probeMaxFragmentLength(remote_addr, port, len); + } + + bool ESP_Mail_WCS::probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len) + { + return ESP_Mail_WCS::probeMaxFragmentLength(host.c_str(), port, len); + } + + // Helper function which aborts a TLS handshake by sending TLS + // ClientAbort and ClientClose messages. + static bool _SendAbort(WiFiClient &probe, bool supportsLen) + { + // If we're still connected, send the appropriate notice that + // we're aborting the handshake per RFCs. + static const uint8_t clientAbort_P[] PROGMEM = { + 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, + 1, 90 /* warning: user_cancelled */ + }; + static const uint8_t clientClose_P[] PROGMEM = { + 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, + 1, 0 /* warning: close_notify */ + }; + if (probe.connected()) + { + uint8_t msg[sizeof(clientAbort_P)]; + memcpy_P(msg, clientAbort_P, sizeof(clientAbort_P)); + probe.write(msg, sizeof(clientAbort_P)); + memcpy_P(msg, clientClose_P, sizeof(clientClose_P)); + probe.write(msg, sizeof(clientClose_P)); + } + return supportsLen; + } + + // Checks for support of Maximum Frame Length Negotiation at the given + // blocksize. Note that, per spec, only 512, 1024, 2048, and 4096 are + // supported. Many servers today do not support this negotiation. + + // TODO - Allow for fragmentation...but not very critical as the ServerHello + // we use comes to < 80 bytes which has no reason to ever be fragmented. + // TODO - Check the type of returned extensions and that the MFL is the exact + // same one we sent. Not critical as only horribly broken servers would + // return changed or add their own extensions. + bool ESP_Mail_WCS::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len) + { + // Hardcoded TLS 1.2 packets used throughout + static const uint8_t clientHelloHead_P[] PROGMEM = { + 0x16, 0x03, 0x03, 0x00, 0, // TLS header, change last 2 bytes to len + 0x01, 0x00, 0x00, 0, // Last 3 bytes == length + 0x03, 0x03, // Proto version TLS 1.2 + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Random (gmtime + rand[28]) + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x00, // Session ID + }; + // Followed by our cipher-suite, generated on-the-fly + // 0x00, 0x02, // cipher suite len + // 0xc0, 0x13, // BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + static const uint8_t clientHelloTail_P[] PROGMEM = { + 0x01, 0x00, // No compression + 0x00, 26 + 14 + 6 + 5, // Extension length + 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x03, 0x03, 0x05, 0x03, + 0x06, 0x03, 0x02, 0x03, 0x04, 0x01, 0x03, 0x01, 0x05, 0x01, 0x06, + 0x01, 0x02, 0x01, // Supported signature algorithms + 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, + 0x00, 0x1d, // Supported groups + 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, // Supported EC formats + 0x00, 0x01, // Max Frag Len + 0x00, 0x01, // len of MaxFragLen + }; + // Followed by a 1-byte MFLN size requesst + // 0x04 // 2^12 = 4K + uint8_t mfl; + + switch (len) + { + case 512: + mfl = 1; + break; + case 1024: + mfl = 2; + break; + case 2048: + mfl = 3; + break; + case 4096: + mfl = 4; + break; + default: + return false; // Invalid size + } + int ttlLen = sizeof(clientHelloHead_P) + (2 + sizeof(suites_P)) + (sizeof(clientHelloTail_P) + 1); + uint8_t *clientHello = new uint8_t[ttlLen]; + if (!clientHello) + { + DEBUG_BSSL("probeMaxFragmentLength: OOM\n"); + return false; + } + memcpy_P(clientHello, clientHelloHead_P, sizeof(clientHelloHead_P)); + clientHello[sizeof(clientHelloHead_P) + 0] = sizeof(suites_P) >> 8; // MSB byte len + clientHello[sizeof(clientHelloHead_P) + 1] = sizeof(suites_P) & 0xff; // LSB byte len + for (size_t i = 0; i < sizeof(suites_P) / sizeof(suites_P[0]); i++) + { + uint16_t flip = pgm_read_word(&suites_P[i]); + // Swap to network byte order + flip = ((flip >> 8) & 0xff) | ((flip & 0xff) << 8); + memcpy(clientHello + sizeof(clientHelloHead_P) + 2 + 2 * i, &flip, 2); + } + memcpy_P(clientHello + sizeof(clientHelloHead_P) + 2 + sizeof(suites_P), clientHelloTail_P, sizeof(clientHelloTail_P)); + clientHello[sizeof(clientHelloHead_P) + 2 + sizeof(suites_P) + sizeof(clientHelloTail_P)] = mfl; + + // Fix up TLS fragment length + clientHello[3] = (ttlLen - 5) >> 8; + clientHello[4] = (ttlLen - 5) & 0xff; + // Fix up ClientHello message length + clientHello[7] = (ttlLen - 5 - 4) >> 8; + clientHello[8] = (ttlLen - 5 - 4) & 0xff; + + WiFiClient probe; + probe.connect(ip, port); + if (!probe.connected()) + { + delete[] clientHello; + DEBUG_BSSL("probeMaxFragmentLength: Can't connect\n"); + return false; + } + + int ret = probe.write(clientHello, ttlLen); + delete[] clientHello; // We're done w/the hello message + if (!probe.connected() || (ret != ttlLen)) + { + DEBUG_BSSL("probeMaxFragmentLength: Protocol error\n"); + return false; + } + + bool supportsLen = false; + uint8_t fragResp[5]; + int fragLen; + uint8_t hand[4]; + int handLen; + uint8_t protoVer[2]; + uint8_t rand[32]; + uint8_t sessionLen; + uint8_t cipher[2]; + uint8_t comp; + uint8_t extBytes[2]; + uint16_t extLen; + + ret = probe.readBytes(fragResp, 5); + if (!probe.connected() || (ret != 5) || (fragResp[0] != 0x16) || (fragResp[1] != 0x03) || (fragResp[2] != 0x03)) + { + // Short read, not a HANDSHAKE or not TLS 1.2, so it's not supported + return _SendAbort(probe, supportsLen); + } + fragLen = (fragResp[3] << 8) | fragResp[4]; + if (fragLen < 4 + 2 + 32 + 1 + 2 + 1) + { + // Too short to have an extension + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(hand, 4); + fragLen -= ret; + if ((ret != 4) || (hand[0] != 2)) + { + // Short read or not server_hello + return _SendAbort(probe, supportsLen); + } + handLen = (hand[1] << 16) | (hand[2] << 8) | hand[3]; + if (handLen != fragLen) + { + // Got some weird mismatch, this is invalid + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(protoVer, 2); + handLen -= ret; + if ((ret != 2) || (protoVer[0] != 0x03) || (protoVer[1] != 0x03)) + { + // Short read or not tls 1.2, so can't do MFLN + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(rand, 32); + handLen -= ret; + if (ret != 32) + { + // short read of random data + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(&sessionLen, 1); + handLen -= ret; + if ((ret != 1) || (sessionLen > 32)) + { + // short read of session len or invalid size + return _SendAbort(probe, supportsLen); + } + if (sessionLen) + { + ret = probe.readBytes(rand, sessionLen); + handLen -= ret; + if (ret != sessionLen) + { + // short session id read + return _SendAbort(probe, supportsLen); + } + } + + ret = probe.readBytes(cipher, 2); + handLen -= ret; + if (ret != 2) + { + // Short read...we don't check the cipher here + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(&comp, 1); + handLen -= ret; + if ((ret != 1) || comp != 0) + { + // short read or invalid compression + return _SendAbort(probe, supportsLen); + } + + ret = probe.readBytes(extBytes, 2); + handLen -= ret; + extLen = extBytes[1] | (extBytes[0] << 8); + if ((extLen == 0) || (ret != 2)) + { + return _SendAbort(probe, supportsLen); + } + + while (handLen > 0) + { + // Parse each extension and look for MFLN + uint8_t typeBytes[2]; + ret = probe.readBytes(typeBytes, 2); + handLen -= 2; + if ((ret != 2) || (handLen <= 0)) + { + return _SendAbort(probe, supportsLen); + } + uint8_t lenBytes[2]; + ret = probe.readBytes(lenBytes, 2); + handLen -= 2; + uint16_t extLen = lenBytes[1] | (lenBytes[0] << 8); + if ((ret != 2) || (handLen <= 0) || (extLen > 32) || (extLen > handLen)) + { + return _SendAbort(probe, supportsLen); + } + if ((typeBytes[0] == 0x00) && (typeBytes[1] == 0x01)) + { // MFLN extension! + // If present and 1-byte in length, it's supported + return _SendAbort(probe, extLen == 1 ? true : false); + } + // Skip the extension, move to next one + uint8_t junk[32]; + ret = probe.readBytes(junk, extLen); + handLen -= extLen; + if (ret != extLen) + { + return _SendAbort(probe, supportsLen); + } + } + return _SendAbort(probe, supportsLen); + } + + // AXTLS compatibility interfaces + bool ESP_Mail_WCS::setCACert(const uint8_t *pk, size_t size) + { + _axtls_ta = nullptr; + _axtls_ta = std::shared_ptr(new ESP_Mail_X509List(pk, size)); + _ta = _axtls_ta.get(); + return _ta ? true : false; + } + + bool ESP_Mail_WCS::setCertificate(const uint8_t *pk, size_t size) + { + _axtls_chain = nullptr; + _axtls_chain = std::shared_ptr(new ESP_Mail_X509List(pk, size)); + _chain = _axtls_chain.get(); + return _chain ? true : false; + } + + bool ESP_Mail_WCS::setPrivateKey(const uint8_t *pk, size_t size) + { + _axtls_sk = nullptr; + _axtls_sk = std::shared_ptr(new PrivateKey(pk, size)); + _sk = _axtls_sk.get(); + return _sk ? true : false; + } + + uint8_t *ESP_Mail_WCS::_streamLoad(Stream &stream, size_t size) + { + uint8_t *dest = (uint8_t *)malloc(size); + if (!dest) + { + return nullptr; + } + if (size != stream.readBytes(dest, size)) + { + free(dest); + return nullptr; + } + return dest; + } + + bool ESP_Mail_WCS::loadCACert(Stream &stream, size_t size) + { + uint8_t *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ret = setCACert(dest, size); +#pragma GCC diagnostic pop + } + free(dest); + return ret; + } + + bool ESP_Mail_WCS::loadCertificate(Stream &stream, size_t size) + { + uint8_t *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ret = setCertificate(dest, size); +#pragma GCC diagnostic pop + } + free(dest); + return ret; + } + + bool ESP_Mail_WCS::loadPrivateKey(Stream &stream, size_t size) + { + uint8_t *dest = _streamLoad(stream, size); + bool ret = false; + if (dest) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ret = setPrivateKey(dest, size); +#pragma GCC diagnostic pop + } + free(dest); + return ret; + } + + void ESP_Mail_WCS::setStartTLS(bool enable) + { + _secured = !enable; + } + + size_t ESP_Mail_WCS::_ns_write(uint8_t b) + { + return write(&b, 1); + } + + size_t ESP_Mail_WCS::_ns_write(const uint8_t *buf, size_t size) + { + if (!_client || !size) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write(buf, size); + } + + size_t ESP_Mail_WCS::_ns_write(Stream &stream, size_t unused) + { + (void)unused; + return WiFiClient::write(stream); + } + + size_t ESP_Mail_WCS::_ns_write(Stream &stream) + { + if (!_client || !stream.available()) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write(stream); + } + + size_t ESP_Mail_WCS::_ns_write_P(PGM_P buf, size_t size) + { + if (!_client || !size) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write_P(buf, size); + } + + int ESP_Mail_WCS::_ns_available() + { + if (!_client) + return false; + + int result = _client->getSize(); + + if (!result) + { + optimistic_yield(100); + } + return result; + } + + int ESP_Mail_WCS::_ns_read() + { + if (!_ns_available()) + return -1; + + return _client->read(); + } + + int ESP_Mail_WCS::_ns_read(uint8_t *buf, size_t size) + { + return (int)_client->read(reinterpret_cast(buf), size); + } + + int ESP_Mail_WCS::_ns_peek() + { + if (!_ns_available()) + return -1; + + return _client->peek(); + } + + size_t ESP_Mail_WCS::_ns_peekBytes(uint8_t *buffer, size_t length) + { + size_t count = 0; + + if (!_client) + { + return 0; + } + + _startMillis = millis(); + while ((_ns_available() < (int)length) && ((millis() - _startMillis) < _timeout)) + { + yield(); + } + + if (_ns_available() < (int)length) + { + count = _ns_available(); + } + else + { + count = length; + } + + return _client->peekBytes((char *)buffer, count); + } + + uint8_t ESP_Mail_WCS::_ns_connected() + { + if (!_client || _client->state() == CLOSED) + return 0; + + return _client->state() == ESTABLISHED || _ns_available(); + } + + bool ESP_Mail_WCS::_ns_connect_ssl() + { + return _connectSSL(_host_name.c_str()); + } +}; // namespace ESP_Mail + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_WCS_CPP */ \ No newline at end of file diff --git a/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h new file mode 100755 index 000000000..276129a32 --- /dev/null +++ b/lib/lib_div/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h @@ -0,0 +1,306 @@ +/* + Customized version of WiFiClientSecure.h + + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ESP_Mail_WCS_H +#define ESP_Mail_WCS_H + +#ifdef ESP8266 + +#include +#include +#include +#include "ESP_Mail_BearSSLHelpers.h" +#include "ESP_Mail_CertStoreBearSSL.h" + + +namespace ESP_Mail { + +//#define DEBUG_ESP_SSL +//#define DEBUG_ESP_PORT Serial + + struct br_x509_insecure_context; + + class ESP_Mail_WCS : public WiFiClient + { + public: + ESP_Mail_WCS(); + ESP_Mail_WCS(const ESP_Mail_WCS &rhs); + ~ESP_Mail_WCS() override; + + ESP_Mail_WCS& operator=(const ESP_Mail_WCS&) = default; // The shared-ptrs handle themselves automatically + + int connect(IPAddress ip, uint16_t port) override; + int connect(const String& host, uint16_t port) override; + int connect(const char* name, uint16_t port) override; + + uint8_t connected() override; + size_t write(const uint8_t *buf, size_t size) override; + size_t write_P(PGM_P buf, size_t size) override; + size_t write(const char *buf) { + return write((const uint8_t*)buf, strlen(buf)); + } + size_t write_P(const char *buf) { + return write_P((PGM_P)buf, strlen_P(buf)); + } + size_t write(Stream& stream); // Note this is not virtual + int read(uint8_t *buf, size_t size) override; + int available() override; + int read() override; + int peek() override; + size_t peekBytes(uint8_t *buffer, size_t length) override; + bool flush(unsigned int maxWaitMs); + bool stop(unsigned int maxWaitMs); + void flush() override { (void)flush(0); } + void stop() override { (void)stop(0); } + + // Allow sessions to be saved/restored automatically to a memory area + void setSession(Session *session) { _session = session; } + + // Don't validate the chain, just accept whatever is given. VERY INSECURE! + void setInsecure() { + _clearAuthenticationSettings(); + _use_insecure = true; + } + // Assume a given public key, don't validate or use cert info at all + void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) { + _clearAuthenticationSettings(); + _knownkey = pk; + _knownkey_usages = usages; + } + // Only check SHA1 fingerprint of certificate + bool setFingerprint(const uint8_t fingerprint[20]) { + _clearAuthenticationSettings(); + _use_fingerprint = true; + memcpy_P(_fingerprint, fingerprint, 20); + return true; + } + bool setFingerprint(const char *fpStr); + // Accept any certificate that's self-signed + void allowSelfSignedCerts() { + _clearAuthenticationSettings(); + _use_self_signed = true; + } + // Install certificates of trusted CAs or specific site + void setTrustAnchors(const ESP_Mail_X509List *ta) { + _clearAuthenticationSettings(); + _ta = ta; + } + // In cases when NTP is not used, app must set a time manually to check cert validity + void setX509Time(time_t now) { + _now = now; + } + // Install a client certificate for this connection, in case the server requires it (i.e. MQTT) + void setClientRSACert(const ESP_Mail_X509List *cert, const PrivateKey *sk); + void setClientECCert(const ESP_Mail_X509List *cert, const PrivateKey *sk, + unsigned allowed_usages, unsigned cert_issuer_key_type); + + // Sets the requested buffer size for transmit and receive + void setBufferSizes(int recv, int xmit); + + // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection) + int getMFLNStatus() { + return connected() && br_ssl_engine_get_mfln_negotiated(_eng); + } + + // Return an error code and possibly a text string in a passed-in buffer with last SSL failure + int getLastSSLError(char *dest = NULL, size_t len = 0); + + // Attach a preconfigured certificate store + void setCertStore(ESP_Mail_CertStore *certStore) { + _certStore = certStore; + } + + // Select specific ciphers (i.e. optimize for speed over security) + // These may be in PROGMEM or RAM, either will run properly + bool setCiphers(const uint16_t *cipherAry, int cipherCount); + bool setCiphers(std::vector list); + bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC + + // Check for Maximum Fragment Length support for given len before connection (possibly insecure) + static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len); + static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len); + static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len); + + void setStartTLS(bool enable); + size_t _ns_write(uint8_t b); + size_t _ns_write(const uint8_t *buf, size_t size); + size_t _ns_write(Stream &stream, size_t unused); + size_t _ns_write(Stream &stream); + size_t _ns_write_P(PGM_P buf, size_t size); + int _ns_available(); + int _ns_read(); + int _ns_read(uint8_t *buf, size_t size); + int _ns_peek(); + size_t _ns_peekBytes(uint8_t *buffer, size_t length); + uint8_t _ns_connected(); + bool _ns_connect_ssl(); + + //////////////////////////////////////////////////// + // AxTLS API deprecated warnings to help upgrading + + bool setCACert(const uint8_t* pk, size_t size) ; + bool setCertificate(const uint8_t* pk, size_t size) ; + bool setPrivateKey(const uint8_t* pk, size_t size) ; + + bool loadCACert(Stream& stream, size_t size) ; + bool loadCertificate(Stream& stream, size_t size) ; + bool loadPrivateKey(Stream& stream, size_t size) ; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + bool setCACert_P(PGM_VOID_P pk, size_t size) { + return setCACert((const uint8_t *)pk, size); + } + + bool setCertificate_P(PGM_VOID_P pk, size_t size) { + return setCertificate((const uint8_t *)pk, size); + } + + bool setPrivateKey_P(PGM_VOID_P pk, size_t size) { + return setPrivateKey((const uint8_t *)pk, size); + } + +#pragma GCC diagnostic pop + + template + bool loadCertificate(TFile& file) { + return loadCertificate(file, file.size()); + } + + template + bool loadPrivateKey(TFile& file) { + return loadPrivateKey(file, file.size()); + } + + template + bool loadCACert(TFile& file) { + return loadCACert(file, file.size()); + } + + bool verify(const char* fingerprint, const char* domain_name) { + (void)fingerprint; + (void)domain_name; + return connected(); + } + + bool verifyCertChain(const char* domain_name) { + (void)domain_name; + return connected(); + } + + // AxTLS API deprecated section end + ///////////////////////////////////// + + protected: + bool _connectSSL(const char *hostName); // Do initial SSL handshake + + private: + void _clear(); + void _clearAuthenticationSettings(); + // Only one of the following two should ever be != nullptr! + std::shared_ptr _sc; + std::shared_ptr _sc_svr; + inline bool ctx_present() { + return (_sc != nullptr) || (_sc_svr != nullptr); + } + br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts + std::shared_ptr _x509_minimal; + std::shared_ptr _x509_insecure; + std::shared_ptr _x509_knownkey; + std::shared_ptr _iobuf_in; + std::shared_ptr _iobuf_out; + time_t _now; + const ESP_Mail_X509List *_ta; + ESP_Mail_CertStore *_certStore; + int _iobuf_in_size; + int _iobuf_out_size; + bool _handshake_done; + bool _oom_err; + + bool _secured; + std::string _host_name; + + // AXTLS compatibility shim elements: + // AXTLS managed memory for certs and keys, while BearSSL assumes + // the app manages these. Use this local storage for holding the + // BearSSL created objects in a shared form. + std::shared_ptr _axtls_ta; + std::shared_ptr _axtls_chain; + std::shared_ptr _axtls_sk; + + // Optional storage space pointer for session parameters + // Will be used on connect and updated on close + Session *_session; + + bool _use_insecure; + bool _use_fingerprint; + uint8_t _fingerprint[20]; + bool _use_self_signed; + const PublicKey *_knownkey; + unsigned _knownkey_usages; + + // Custom cipher list pointer or NULL if default + std::shared_ptr _cipher_list; + uint8_t _cipher_cnt; + + unsigned char *_recvapp_buf; + size_t _recvapp_len; + + bool _clientConnected(); // Is the underlying socket alive? + void _freeSSL(); + int _run_until(unsigned target, bool blocking = true); + size_t _write(const uint8_t *buf, size_t size, bool pmem); + bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting + + // Optional client certificate + const ESP_Mail_X509List *_chain; + const PrivateKey *_sk; + unsigned _allowed_usages; + unsigned _cert_issuer_key_type; + + // Methods for handling server.available() call which returns a client connection. + friend class WiFiServerSecure; // Server needs to access these constructors + ESP_Mail_WCS(ClientContext *client, const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type, + const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta); + ESP_Mail_WCS(ClientContext* client, const ESP_Mail_X509List *chain, const PrivateKey *sk, + int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta); + + // RSA keyed server + bool _connectSSLServerRSA(const ESP_Mail_X509List *chain, const PrivateKey *sk, const ESP_Mail_X509List *client_CA_ta); + // EC keyed server + bool _connectSSLServerEC(const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk, + const ESP_Mail_X509List *client_CA_ta); + + // X.509 validators differ from server to client + bool _installClientX509Validator(); // Set up X509 validator for a client conn. + bool _installServerX509Validator(const ESP_Mail_X509List *client_CA_ta); // Setup X509 client cert validation, if supplied + + uint8_t *_streamLoad(Stream& stream, size_t size); + }; +}; + +#endif /* ESP8266 */ + +#endif /* ESP_Mail_WCS_H */ diff --git a/lib/libesp32/ESP32-Mail-Client/README.md b/lib/libesp32/ESP32-Mail-Client/README.md deleted file mode 100755 index bd4cb6328..000000000 --- a/lib/libesp32/ESP32-Mail-Client/README.md +++ /dev/null @@ -1,2138 +0,0 @@ -# Mail Client Arduino Library for ESP32 v 2.1.4 - -This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download via SMTP and IMAP servers. - -The library was test and work well with ESP32s based module. - -Copyright (c) 2019 K. Suwatchai (Mobizt). - -![ESP32 Mail](/media/images/esp32-mail.png) - -## Tested Devices - -This following devices were tested and work well. - - * Sparkfun ESP32 Thing - * NodeMCU-32 - * WEMOS LOLIN32 - * TTGO T8 V1.8 - * M5Stack ESP32 - - - -## Features - -* Support Email sending with or without attachment via IMAP server. - -* Support SSL/TLS and STARTTLS protocols. - -* Working with SD card allows large file attachment supported or SPIFFS for small file size attachment. - -* Support Email reading via search and fetch modes (with or without attachment downloads). - -* Support large attachment download via SD card or SPIFFS for small file size attachment. - -* Message text and its header are able to download and save to SD card or SPIFFS. - -* Support Email message fetch and search via IMAP command as in RFC 3501 (depending on IMAP server implementation). - -* Support Ethernet. - -* Built-in Time function. - - - - -## Prerequisites - - -For library version 1.2.0 or newer, STARTTLS was supported and can be enable automatically when port 587 for SMTP was used or can set manually thrugh smtpData.setSTARTTLS(true) and for IMAP through imapData.setSTARTTLS(true). - - - -## Installing - - -Click on **Clone or download** dropdown at the top of repository, select **Download ZIP** and save file on your computer. - -From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP32-Mail-Client-master.zip** that previously downloaded. - -Go to menu **Files** -> **Examples** -> **ESP32-Mail-Client-master** and choose one from examples - - - -## Usages - - -__Declaration and Initialization__ - - - -**The first thing to do to use this library.** - -```C++ - - -//1. Include ESP32 Mail Client library (this library) - -#include "ESP32_MailClient.h" - - -//2. For sending Email, declare Email Sending data object in global scope. -SMTPData smtpData; - -//Or - -//For receiving Email, declare Email receiving data object in global scope. -IMAPData imapData; - - -//3 Setup SMTP server login credential in setup() - -smtpData.setLogin("smtp.gmail.com", 587, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD"); - -//Or - -//Setup IMAP server login credential in setup() - -imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD"); - - -//4 For SMTP, set some custom message header (optional) -smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)"); - -smtpData.addCustomMessageHeader("Message-ID: <10000.30000@gmail.com>"); - - -//5 To debug for SMTP - -smtpData.setDebug(true); - -//Or IMAP -imapData.setDebug(true); - - -//6. Send Email -MailClient.sendMail(smtpData)); - -//Or Receive Email - -MailClient.readdMail(imapData)); - - - - - -``` - -___ - - -__Send and Receive Email__ - - -**Compose Email** - -This library allows you to set sender, recipient, importance (priority), CC, BCC and attachment data (binary or from SD card file). - -To set sender, use `smtpData.setSender` e.g. `smtpData.setSender("Jarvis", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com")`. - -To set priority, use `smtpData.setPriority` e.g. `smtpData.setPriority("High")`. - -To set message subject, use `smtpData.setSubject` e.g. `smtpData.setSubject("ESP32 Send Mail Test")`. - -To set message text, use `smtpData.setMessage` e.g. `smtpData.setMessage("This is plain text message", false);`. - -To set sender, use `smtpData.addRecipient` e.g. `smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com")`. - -To add attachment, use `smtpData.addAttachData` e.g. `smtpData.addAttachData("test.png", "image/png", (uint8_t *)imageData, sizeof imageData);`. - - -When completed all required message data, sending Email `MailClient.sendMail(smtpData)`. - - - -**Get Email** - -To read or receive Email, mailbox folder should be assigned via `imapData.setFolder` e.g. `imapData.setFolder("INBOX")`. - -Then set search criteria to search specified mailbox folder via `imapData.setSearchCriteria` e.g. `imapData.setSearchCriteria("UID SEARCH ALL")`. - -Then set search limit to limut the memory and time usages `imapData.setSearchLimit`. - -From search criteria, UID of message will be available to fetch or read. - -Whit search, body message and attachment can be ignore to reduce the network data usage. - -Begin receive Email `MailClient.readMail(imapData)`. - -From above settings, you will get the following header information - -Messsage UID via `imapData.getUID`. - -Messsage ID via `imapData.getMessageID`. - -Accept Language via `imapData.getAcceptLanguage`. - -Content Language via `imapData.getContentLanguage`. - -Sender via `imapData.getFrom`. - -Sender Charset via `imapData.getFromCharset`. - -Recipient via `imapData.getTo`. - -Recipient Charset via `imapData.getToCharset`. - -CC via `imapData.getCC`. - -CC Charset via `imapData.getCCCharset`. - -Date via `imapData.getDate`. - -Subject via `imapData.getSubject`. - -Subject Charset via `imapData.getSubjectCharset`. - -In addition, by setting search criteria, the following infomation are available. - -Mailbox folder count via `imapData.getFolderCount`. - -Mailbox folder name via `imapData.getFolder`. - -Supported flags count via `imapData.getFlagCount`. - -Supported flags name via `imapData.getFlag`. - -Total message in folder via `imapData.totalMessages`. - -Total message from search result via `imapData.searchCount`. - -Available message from search result (limited by `imapData.setSearchLimit`) via `imapData.availableMessages`. - -When fetch specific message via `imapData.setFetchUID`, availability of attachment file can be determined via -`imapData.getAttachmentCount` for that message which will be automatically download by setting `imapData.setDownloadAttachment(true)` -prior to `MailClient.readMail`. - - - -See [full examples](https://github.com/mobizt/ESP32-Mail-Client/tree/master/examples) for all features usages. - - - - - -## All Supported Functions - - -**These are all functions available from the library and the descriptions.** - - -__Global functions__ - - -**Sending Email via SMTP server.** - -param *`smtpData`* - SMTP Data object to hold data and instances. - -return - *`Boolean`* type status indicates the success of operation. - -```C++ -bool sendMail(SMTPData &smtpData); -``` - - - - -**Reading Email via IMAP server.** - -param *`imapData`* - IMAP Data object to hold data and instances. - -return - *`Boolean`* type status indicates the success of operation. - -```C++ -bool readMail(IMAPData &imapData); -``` - - - - - -**Set the argument to the Flags for message.** - -param *`imapData`* - IMAP Data object to hold data and instances. - -param *`msgUID`* - The UID of message. - -param *`flags`* - The flag list. - -return - *`Boolean`* type status indicates the success of operation. - -```C++ -bool setFlag(IMAPData &imapData, int msgUID, const String &flags); -``` - - - - - -**Add the argument to the Flags for message.** - -param *`imapData`* - IMAP Data object to hold data and instances. - -param *`msgUID`* - The UID of message. - -param *`flags`* - The flag list. - -return - *`Boolean`* type status indicates the success of operation. - -```C++ -bool addFlag(IMAPData &imapData, int msgUID, const String &flags); -``` - - - - - - -**Remove the argument from the Flags for message.** - -param *`imapData`* - IMAP Data object to hold data and instances. - -param *`msgUID`* - The UID of message. - -param *`flags`* - The flag list. - -return - *`Boolean`* type status indicates the success of operation. - -```C++ -bool removeFlag(IMAPData &imapData, int msgUID, const String &flags); -``` - - - - - -**Get the Email sending error details.** - -return - *`Error details string (String object).`* - -```C++ -String smtpErrorReason(); -``` - - - - -**Get the Email reading error details.** - -return - *`Error details string (String object).`* - -```C++ -String imapErrorReason(); -``` - - - - - -**Init SD card with GPIO pins.** - -param *`sck`* -SPI Clock pin. - -param *`miso`* - SPI MISO pin. - -param *`m0si`* - SPI MOSI pin. - -param *`ss`* - SPI Chip/Slave Select pin. - -return *`Boolean`* type status indicates the success of operation. - - -```C++ -bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); -``` - - - - - - -**Init SD card with default GPIO pins.** - -return *`Boolean`* type status indicates the success of operation. - - -```C++ -bool sdBegin(void); -``` - - - - - - - -### IMAPData object call for receiving Email. - - -**Set the IMAP server login credentials.** - -param *`host`* - IMAP server e.g. imap.gmail.com. - -param *`port`* - IMAP port e.g. 993 for gmail. - -param *`loginEmail`* - The Email address of account. - -param *`loginPassword`* - The account password. - -param *`rootCA`* - Root CA certificate base64 string - -```C++ -void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword); - -void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA); - -``` - - - - - -**Set STARTTLS mode to enable STARTTLS protocol.** - -param *`starttls`* - bool flag that enables STARTTLS mode - -```C++ -void setSTARTTLS(bool starttls); -``` - - - - - - -**Set debug print to serial.** - -param *`debug`* - bool flag to enable debug - -```C++ -void setDebug(bool debug); -``` - - - - - - -**Set the mailbox folder to search or fetch.** - -param *`folderName`* - Known mailbox folder. Default value is INBOX - -```C++ -void setFolder(const String &folderName); -``` - - - -**Set the maximum message buffer size for text/html result from search or fetch the message.** - -param *`size`* - The message size in byte. - -```C++ -void setMessageBufferSize(size_t size); -``` - - - -**Set the maximum attachment file size to be downloaded.** - -param *`size`* - The attachement file size in byte. - -```C++ -void setAttachmentSizeLimit(size_t size); -``` - - - -**Set the search criteria used in selected mailbox search.** - -In case of message UID was set via setFetchUID function, search operation will not process, - -you need to clear message UID by calling imapData.setFetchUID("") to clear. - -param *`criteria`* - Search criteria String. - -If folder is not set, the INBOX folder will be used - -Example: - -*`SINCE 10-Feb-2019`* will search all messages that received since 10 Feb 2019 - -*`UID SEARCH ALL`* will seach all message which will return the message UID that can be use later for fetch one or more messages. - - -Search criteria can be consisted these keywords - - -*`ALL`* - All messages in the mailbox; the default initial key for ANDing. - -*`ANSWERED`* - Messages with the \Answered flag set. - -*`BCC`* - Messages that contain the specified string in the envelope structure's BCC field. - -*`BEFORE`* - Messages whose internal date (disregarding time and timezone) is earlier than the specified date. - -*`BODY`* - Messages that contain the specified string in the body of the message. - -*`CC`* - Messages that contain the specified string in the envelope structure's CC field. - -*`DELETED`* - Messages with the \Deleted flag set. - -*`DRAFT`* - Messages with the \Draft flag set. - -*`FLAGGED`* - Messages with the \Flagged flag set. - -*`FROM`* - Messages that contain the specified string in the envelope structure's FROM field. - -*`HEADER`* - Messages that have a header with the specified field-name (as defined in [RFC-2822]) - -and that contains the specified string in the text of the header (what comes after the colon). - -If the string to search is zero-length, this matches all messages that have a header line with - -the specified field-name regardless of the contents. - -*`KEYWORD`* - Messages with the specified keyword flag set. - -*`LARGER`* - Messages with an (RFC-2822) size larger than the specified number of octets. - -*`NEW`* - Messages that have the \Recent flag set but not the \Seen flag. - -This is functionally equivalent to `*"(RECENT UNSEEN)"*`. - -*`NOT`* - Messages that do not match the specified search key. - -*`OLD`* - Messages that do not have the \Recent flag set. This is functionally equivalent to - -*`"NOT RECENT"`* (as opposed to *`"NOT NEW"`*). - -*`ON`* - Messages whose internal date (disregarding time and timezone) is within the specified date. - -*`OR`* - Messages that match either search key. - -*`RECENT`* - Messages that have the \Recent flag set. - -*`SEEN`* - Messages that have the \Seen flag set. - -*`SENTBEFORE`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is earlier than the specified date. - -*`SENTON`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within the specified date. - -*`SENTSINCE`* - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within or later than the specified date. - -*`SINCE`* - Messages whose internal date (disregarding time and timezone) is within or later than the specified date. - -*`SMALLER`* - Messages with an (RFC-2822) size smaller than the specified number of octets. - -*`SUBJECT`* - Messages that contain the specified string in the envelope structure's SUBJECT field. - -*`TEXT`* - Messages that contain the specified string in the header or body of the message. - -*`TO`* - Messages that contain the specified string in the envelope structure's TO field. - -*`UID`* - Messages with unique identifiers corresponding to the specified unique identifier set. - -Sequence set ranges are permitted. - -*`UNANSWERED`* - Messages that do not have the \Answered flag set. - -*`UNDELETED`* - Messages that do not have the \Deleted flag set. - -*`UNDRAFT`* - Messages that do not have the \Draft flag set. - -*`UNFLAGGED`* - Messages that do not have the \Flagged flag set. - -*`UNKEYWORD`* - Messages that do not have the specified keyword flag set. - -*`UNSEEN`* - Messages that do not have the \Seen flag set. - -```C++ -void setSearchCriteria(const String &criteria); -``` - - - - - -**Set to search the unseen message.** - -param *`unseenSearch`* - Boolean flag to enable unseen message search. - -This function will be overridden (omitted) by setFetchUID as setSearchCriteria. - -```C++ -void setSearchUnseenMessage(bool unseenSearch); -``` - - - - - - -**Set the download folder.** - -param *`path`* - Path in SD card. - -All text/html message and attachemnts will be saved to message UID folder which created in defined path - -e.g. *`"/{DEFINED_PATH}/{MESSAGE_UID}/{ATTACHMENT_FILE...}"`*. - -```C++ -void setSaveFilePath(const String &path); -``` - - - - -**Specify message UID to fetch or read.** - -param *`fetchUID`* - The message UID. - -Specify the message UID to fetch (read) only specific message instead of search. - -```C++ -void setFetchUID(const String &fetchUID); -``` - - - - - -**Set storage type to save download attached file or messages.** - -param *`storageType`* - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS - -```C++ -void setFileStorageType(uint8_t storageType); -``` - - - - - - -**Enable/disable attachment download.** - -param *`download`* - Boolean flag to enable/disable attachment download. - -```C++ -void setDownloadAttachment(bool download); -``` - - - -**Enable/disable html message result.** - -param *`htmlFormat`* - Boolean flag to enable/disable html message result. - -The default value is false. - -```C++ -void setHTMLMessage(bool htmlFormat); -``` - - - - -**Enable/disable plain text message result.** - -param *`textFormat`* - Boolean flag to enable/disable plain text message result. - -The default value is true. - -```C++ -void setTextMessage(bool textFormat); -``` - - - - - -**Set the maximum message to search.** - -param *`limit`* - Any number from 0 to 65535. - -The default value is 20. - -```C++ -void setSearchLimit(uint16_t limit); -``` - - - -**Enable/disable recent sort result.** - -param *`recentSort`* - Boolean flag to enable/disable recent message sort result. - -The default value is true. - -```C++ -void setRecentSort(bool recentSort); -``` - - - -**Assign callback function that return status of message fetching or reading.** - -param *`readCallback`* - The function that accept readStatusCallback as parameter. - -```C++ -void setReadCallback(readStatusCallback readCallback); -``` - - - -**Enable/disable attachement download progress while fetching or receiving message.** - -param *`report`* - Boolean flag to enable/disable attachement download progress while fetching or receiving message. - -To get the download status, Callback function should be set via setReadCallback. - -```C++ -void setDownloadReport(bool report); -``` - - - -**Determine only message header is return when search.** - -```C++ -bool isHeaderOnly(); -``` - - - -**Get the sender name/Email for selected message from search result.** - -param *`messageIndex`* - The index of message. - -return *`Sender name/Email String.`* - -```C++ -String getFrom(uint16_t messageIndex); -``` - - - -**Get the sender name/Email charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`Sender name/Email charactor encoding which use for decoding.`* - -```C++ -String getFromCharset(uint16_t messageIndex); -``` - - - -**Get the recipient name/Email for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Recipient name/Email String.`* - -```C++ -String getTo(uint16_t messageIndex); -``` - - - - -**Get the recipient name/Email charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`Recipient name/Email charactor encoding which use in decoding to local language.`* - -```C++ -String getToCharset(uint16_t messageIndex); -``` - - - - -**Get the CC name/Email for selected message index of IMAPData result.** - -param *`messageIndex`* - The index of message. - -return *`CC name/Email String.`* - -```C++ -String getCC(uint16_t messageIndex); -``` - - - -**Get the CC name/Email charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`CC name/Email charactor encoding which use in decoding to local language.`* - -```C++ -String getCCCharset(uint16_t messageIndex); -``` - - - - -**Get the message subject for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Message subject name/Email String.`* - -```C++ -String getSubject(uint16_t messageIndex); -``` - - - - -**Get the message subject charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`Message subject charactor encoding which use in decoding to local language.`* - -```C++ -String getSubjectCharset(uint16_t messageIndex); -``` - - - -**Get the html message for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The html message String or empty String upon the setHTMLMessage was set.`* - -```C++ -String getHTMLMessage(uint16_t messageIndex); -``` - - - -**Get the plain text message for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The plain text message String or empty String upon the setTextMessage was set.`* - -```C++ -String getTextMessage(uint16_t messageIndex); -``` - - -**Get the html message charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`Html message charactor encoding which use in decoding to local language.`* - -```C++ -String getHTMLMessgaeCharset(uint16_t messageIndex); -``` - - - - -**Get the text message charactor encoding.** - -param *`messageIndex`* - The index of message. - -return *`The text message charactor encoding which use in decoding to local language.`* - -```C++ -String getTextMessgaeCharset(uint16_t messageIndex); -``` - - - - -**Get the date of received message for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The date String.`* - -```C++ -String getDate(uint16_t messageIndex); -``` - - - - -**Get the message UID for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`UID String that can be use in setFetchUID.`* - -```C++ -String getUID(uint16_t messageIndex); -``` - - - - -**Get the message number for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The message number which vary upon search criteria and sorting.`* - -```C++ -String getNumber(uint16_t messageIndex); -``` - - - - -**Get the message ID for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The message ID String.`* - -```C++ -String getMessageID(uint16_t messageIndex); -``` - - - - -**Get the accept language for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The accept language String.`* - -```C++ -String getAcceptLanguage(uint16_t messageIndex); -``` - - - -**Get the content language of text or html for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`The content language String.`* - -```C++ -String getContentLanguage(uint16_t messageIndex); -``` - - - - -**Determine fetch error status for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Fetch error status.`* - -```C++ -bool isFetchMessageFailed(uint16_t messageIndex); -``` - - - -**Get fetch error reason for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Fetch error reason String for selected message index.`* - -```C++ -String getFetchMessageFailedReason(uint16_t messageIndex); -``` - - - - -**Determine the attachment download error for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Fetch status.`* - -```C++ -bool isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex); -``` - - - - -**Get the attachment download error reason for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Download error reason String for selected message index.`* - -```C++ -String getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex); -``` - - - -**Determine the downloaded/saved text message error status for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Text message download status.`* - -```C++ -bool isDownloadMessageFailed(uint16_t messageIndex); -``` - - - - - -**Get the attachment or message downloadeds error reason for selected message index from search result.** - -param *`messageIndex`* - The index of message. - -return *`Downloaded error reason String for selected message index.`* - -```C++ -String getDownloadMessageFailedReason(uint16_t messageIndex); -``` - - - - -**Assign the download and decode flags for html message download.** - -param *`download`* - Boolean flag to enable/disable message download. - -return *`decoded`* - Boolean flag to enable/disable html message decoding (support utf8 and base64 encoding). - -```C++ -void saveHTMLMessage(bool download, bool decoded); -``` - - - - -**Assign the download and decode flags for plain text message download.** - -param *`download`* - Boolean flag to enable/disable message download. - -return *`decoded`* - Boolean flag to enable/disable plain text message decoding (support utf8 and base64 encoding). - -```C++ -void saveTextMessage(bool download, bool decoded); -``` - - - - -**Determine the mailbox folder count.** - -return *`Folder count number.`* - -```C++ -uint16_t getFolderCount(); -``` - - - - -**Get the mailbox folder name at selected index.** - -param *`folderIndex`* - Index of folder. - -return *`Folder name String.`* - -Use folder name from this function for fetch or search. - -```C++ -String getFolder(uint16_t folderIndex); -``` - - - -**Determin the number of supported flags count.** - -return *`Flag count number.`* - -```C++ -uint16_t getFlagCount(); -``` - - - - -**Get the flag name for selected index.** - -param *`folderIndex`* - Index of folder. - -return *`Flag name String.`* - -Use flags from this function for fetch or search. - -```C++ -String getFlag(uint16_t flagIndex); -``` - - - - -**Get the number of message in selected mailbox folder.** - -return *`Total message number.`* - -```C++ -size_t totalMessages(); -``` - - - - -**Get the number of message from search result.** - -return *`Search result number.`* - -```C++ -size_t searchCount(); -``` - - - - -**Get the number of message available from search result which less than search limit.** - -return *`Available message number.`* - -```C++ -size_t availableMessages(); -``` - - - - - -**Get the number of attachments for selected message index from search result.** - -param *`messageIndex`* - Index of message. - -return *`Number of attachments`* - -```C++ -size_t getAttachmentCount(uint16_t messageIndex); -``` - - - - - -**Get file name of attachment for selected attachment index and message index from search result.** - -param *`messageIndex`* - Index of message. - -param *`attachmentIndex`* - Index of attachment. - -return *`The attachment file name String at the selected index.`* - -```C++ -String getAttachmentFileName(size_t messageIndex, size_t attachmentIndex); -``` - - - - -**Get the name of attachment for selected attachment index and message index from search result.** - -param *`messageIndex`* - Index of message. - -param *`attachmentIndex`* - Index of attachment. - -return *`The attachment name String at the selected index.`* - -```C++ -String getAttachmentName(size_t messageIndex, size_t attachmentIndex); -``` - - - - -**Get attachment file size for selected attachment index and message index from search result.** - -param *`messageIndex`* - Index of message. - -param *`attachmentIndex`* - Index of attachment. - -return *`The attachment file size in byte at the selected index.`* - -```C++ -int getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex); -``` - - - - -**Get creation date of attachment for selected attachment index and message index from search result.** - -param *`messageIndex`* - Index of message. - -param *`attachmentIndex`* - Index of attachment. - -return *`The attachment creation date String at the selected index.`* - -```C++ -String getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex); -``` - - - - -**Get attachment file type for selected attachment index and message index from search result.** - -param *`messageIndex`* - Index of message. - -param *`attachmentIndex`* - Index of attachment. - -return *`File MIME String at the selected index`* e.g. image/jpeg. - -```C++ -String getAttachmentType(size_t messageIndex, size_t attachmentIndex); -``` - - - - -**Clear IMAPData object data.** - -```C++ -void empty(); -``` - - - - -### SMTPData object call for sending Email. - - -**Set SMTP server login credentials** - -param *`host`* - SMTP server e.g. smtp.gmail.com - -param *`port`* - SMTP port. - -param *`loginEmail`* - The account Email. - -param *`loginPassword`* - The account password. - -param *`rootCA`* - Root CA certificate base64 string - -```C++ -void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword); - -void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA); - -``` - - - - - -**Set STARTTLS mode to enable STARTTLS protocol.** - -param *`starttls`* - bool flag that enables STARTTLS mode - -```C++ -void setSTARTTLS(bool starttls); -``` - - - - - - -**Set debug print to serial.** - -param *`debug`* - bool flag to enable debug - -```C++ -void setDebug(bool debug); -``` - - - - - - -**Set Sender info** - -param *`fromName`* - Sender's name - -param *`senderEmail`* - Sender's Email. - -```C++ -void setSender(const String &fromName, const String &senderEmail); -``` - - - - - -**Get Sender's name** - -return *`Sender's name String.`* - -```C++ -String getFromName(); -``` - - - - - -**Get Sender's Email.** - -return *`Sender's Email String.`* - -```C++ -String getSenderEmail(); -``` - - - - -**Set Email priority or importance** - -param *`priority`* - Number from 1 to 5, 1 for highest, 3 for normal and 5 for lowest priority - -```C++ -void setPriority(int priority); -``` - - - - - -**Set Email priority or importance.** - -param *`priority`* - String (High, Normal or Low) - -```C++ -void setPriority(const String &priority); -``` - - - - -**Get Email priority** - -return *`Number`* represents Email priority (1 for highest, 3 for normal, 5 for low priority). - -```C++ -uint8_t getPriority(); -``` - - - - -**Add one or more recipient** - -param *`email`* - Recipient Email String of one recipient. - -To add multiple recipients, call addRecipient for each recipient. - -```C++ -void addRecipient(const String &email); -``` - - - - -**Remove recipient** - -param *`email`* - Recipient Email String. - -```C++ -void removeRecipient(const String &email); -``` - - - - -**Remove recipient** - -param *`index`* - Index of recipients in Email object that previously added. - -```C++ -void removeRecipient(uint8_t index); -``` - - - - -**Clear all recipients** -```C++ -void clearRecipient(); -``` - - - - -**Get one recipient** - -param *`index`* - Index of recipients. - -return *`Recipient Email`* String at the index. - -```C++ -String getRecipient(uint8_t index); -``` - - - - - -**Get number of recipients** - -return *`Number`* of recipients. - -```C++ -uint8_t recipientCount(); -``` - - - - -**Set the Email subject.** - -param *`subject`* - The subject. - -```C++ -void setSubject(const String &subject); -``` - - - - -**Get the Email subject.** - -return *`Subject String.`* - -```C++ -String getSubject(); -``` - - - - -**Set the Email message** - -param *`message`* - The message can be in normal text or html format. - -param *`htmlFormat`* - The html format flag, True for send the message as html format - -```C++ -void setMessage(const String &message, bool htmlFormat); -``` - - - - -**Get the message** - -return *`Message String.`* - -```C++ -String getMessage(); -``` - - - - -**Determine message is being send in html format.** - -return *`Boolean`* status. - -```C++ -bool htmlFormat(); -``` - - - - - -**Add Carbon Copy (CC) Email.** - -param *`email`* - The CC Email String. - -```C++ -void addCC(const String &email); -``` - - - - - -**Remove specified Carbon Copy (CC) Email** - -param *`email`* - The CC Email String to remove. - -```C++ -void removeCC(const String &email); -``` - - - - - -**Remove specified Carbon Copy (CC) Email** - -param *`index`* - The CC Email index to remove. - -```C++ -void removeCC(uint8_t index); -``` - - - - - -**Clear all Carbon Copy (CC) Emails** - -```C++ -void clearCC(); -``` - - - - - -**Get Carbon Copy (CC) Email at specified index.** - -param *`index`* - The CC Email index to get. -return *`The CC Email string`* at the index. - -```C++ -String getCC(uint8_t index); -``` - - - - - -**Get the number of Carbon Copy (CC) Email.** - -return *`Number`* of CC Emails. - -```C++ -uint8_t ccCount(); -``` - - - - - -**Add Blind Carbon Copy (BCC) Email** - -param *`email`* - The BCC Email String. - -```C++ -void addBCC(const String &email); -``` - - - - - -**Remove specified Blind Carbon Copy (BCC) Email** - -param *`email`* - The BCC Email String to remove. - -```C++ -void removeBCC(const String &email); -``` - - - - - -**Remove specified Blind Carbon Copy (BCC) Email** - -param *`index`* - The BCC Email index to remove. - -```C++ -void removeBCC(uint8_t index); -``` - - - - - - -**Clear all Blind Carbon Copy (BCC) Emails** - -```C++ -void clearBCC(); -``` - - - - - -**Get Blind Carbon Copy (BCC) Email at specified index.** - -param *`index`* - The BCC Email index to get. - -return *`The BCC Email string`* at the index. - -```C++ -String getBCC(uint8_t index); -``` - - - - - -**Get the number of Blind Carbon Copy (BCC) Email** - -return *`Number`* of BCC Emails. - -```C++ -uint8_t bccCount(); -``` - - - - - -**Add attchement data (binary) from internal memory (flash or ram).** - -param *`fileName`* - The file name String that recipient can be saved. - -param *`mimeType`* - The MIME type of file (image/jpeg, image/png, text/plain...). Can be empty String. - -param *`data`* - The byte array of data (uint8_t). - -param *`size`* - The data length in byte. - -```C++ -void addAttachData(const String &fileName, const String &mimeType, uint8_t *data, uint16_t size); -``` - - - - - -**Remove specified attachment data.** - -param *`fileName`* - The file name of the attachment data to remove. - -```C++ -void removeAttachData(const String &fileName); -``` - - - - - -**Remove specified attachment data.** - -param *`index`* - The index of the attachment data (count only data type attachment) to remove. - -```C++ -void removeAttachData(uint8_t index); -``` - - - - -**Get the number of attachment data.** - -return *`Number`* of attach data. - -```C++ -uint8_t attachDataCount(); -``` - - - -**Add attchement file from SD card** - -param *`fileName`* - The file name String that recipient can be saved. - -param *`mimeType`* - The MIME type of file (image/jpeg, image/png, text/plain...). Can be omitted. - -```C++ -void addAttachFile(const String &filePath, const String &mimeType = ""); -``` - - - - -**Remove specified attachment file from Email object.** - -param *`fileName`* - The file name of the attachment file to remove. - -```C++ -void removeAttachFile(const String &filePath); -``` - - - - -**Set storage type for all attach files.** - -param *`storageType`* - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS. - -```C++ -void setFileStorageType(uint8_t storageType); -``` - - - - - - -**Remove specified attachment file.** - -param *`index`* - The index of the attachment file (count only file type attachment) to remove. - -```C++ -void removeAttachFile(uint8_t index); -``` - - - - -**Clear all attachment data.** - -```C++ -void clearAttachData(); -``` - - - - -**Clear all attachment file.** - -```C++ -void clearAttachFile(); -``` - - - - -**Clear all attachments (both data and file type attachments).** - -```C++ -void clearAttachment(); -``` - - - - -**Get number of attachments (both data and file type attachments).** - -return *`Number`* of all attachemnts. - -```C++ -uint8_t attachFileCount(); -``` - - - - - -**Add one or more custom message header field.** - -param *`field`* - custom header String inform of FIELD: VALUE - -This header field will add to message header. - -```C++ -void addCustomMessageHeader(const String &field); -``` - - - - - - -**Remove one custom message header field that previously added..** - -param *`field`* - custom custom message header field String to remove. - -```C++ -void removeCustomMessageHeader(const String &field); -``` - - - - - -**Remove one custom message header field that previously added by its index.** - -param *`index`* - custom message header field index (number) to remove. - - -```C++ -void removeCustomMessageHeader(uint8_t index); -``` - - - - - -**Clear all ccustom message header field that previously added.** - -```C++ -void clearCustomMessageHeader(); -``` - - - - - - -**Get the number of custom message header field that previously added.** - -return *`Number`* of custom message header field. - -```C++ -uint8_t CustomMessageHeaderCount(); -``` - - - - - - -**Get custom message header field that previously added by index.** - -param *`index`* - The custom message header field index to get. - -return *`The custom message header field string at the index`*. - -```C++ -String getCustomMessageHeader(uint8_t index); -``` - - - - - -**Clear all data from Email object to free memory.** - -```C++ -void empty(); -``` - - - - - -**Set the Email sending status callback function to Email object.** - -param *`sendCallback`* - The callback function that accept the sendStatusCallback param. - -```C++ -void setSendCallback(sendStatusCallback sendCallback); -``` - - - - -__MailClient.Time functions__ - - -**Get the time from NTP server and set to device.** - -param *`gmtOffset`* - The GMT time offset in hour. - -param *`daylightOffset`* - The Daylight time offset in hour. - -return - *`Boolean`* type status indicates the success of operation. - -This requires internet connectivity. - -```C++ -bool setClock(float gmtOffset, float daylightOffset); -``` - - - - - - -**Get the Unix time.** - -return - *`uint32_t`* value of current Unix time. - -```C++ -uint32_t getUnixTime(); -``` - - - - - - -**Get timestamp from defined year, month, date, hour, minute, and second.** - -param *`year`* - Year. -param *`mon`* - Month (1 to 12). -param *`date`* - Date. -param *`hour`* - Hour. -param *`mins`* - Minute. -param *`sec`* - Second. - -return - *`time_t`* value of timestamp. - -```C++ -time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); -``` - - - - - - -**Get current year.** - -return - *`int`* value of current year. - -```C++ -int getYear(); -``` - - - - - - -**Get current month.** - -return - *`int`* value of current month. - -```C++ -int getMonth(); -``` - - - - - -**Get current date.** - -return - *`int`* value of current date. - -```C++ -int getDay(); -``` - - - - - - -**Get current day of week.** - -return - *`int`* value of day of week. - -1 for sunday and 7 for saturday - -```C++ -int getDayOfWeek(); -``` - - - - - -**Get current day of week in String.** - -return - *`String`* value of day of week. - -Returns sunday, monday, tuesday, wednesday, thurseday, friday and saturday. - -```C++ -String getDayOfWeekString(); -``` - - - - - - -**Get current hour.** - -return - *`int`* value of current hour (0 to 23). - -```C++ -int getHour(); -``` - - - - - - -**Get current minute.** - -return - *`int`* value of current minute (0 to 59). - -```C++ -int getMin(); -``` - - - - - - -**Get current second.** - -return - *`int`* value of current second (0 to 59). - -```C++ -int getSecond(); -``` - - - - - - - -**Get the total days of current year.** - -return - *`int`* value of total days of current year. - -```C++ -int getNumberOfDayThisYear(); -``` - - - - - - -**Get the total days of from January 1, 1970 to specific date.** - -param *`year`* - Year from 1970. -param *`mon`* - Month (1 to 12). -param *`date`* - Date. - -return - *`int`* value of total days. - -```C++ -int getTotalDays(int year, int month, int day); -``` - - - - - -**Get the day of week from specific date.** - -param *`year`* - Year. -param *`month`* - Month (1 to 12). -param *`day`* - Date. - -return - *`int`* value of day of week. - -1 for sunday and 7 for saturday - -```C++ -int dayofWeek(int year, int month, int day); -``` - - - - - - -**Get the second of current hour.** - -return - *`int`* value of current second. - -```C++ -int getCurrentSecond(); -``` - - - - - -**Get the current timestamp.** - -return - *`uint64_t`* value of current timestamp. - -```C++ -uint64_t getCurrentTimestamp(); -``` - - - - - - -**Get time (year, month, day, hour, minute, and second) from second counted from January 1, 1970.** - -param *`secCount`* - The seconds from January 1, 1970 00.00. -param *`yrs`* - The return year. -param *`months`* - The return month. -param *`days`* - The return day. -param *`hr`* - The return hour. -param *`min`* - The return minute. -param *`sec`* - The return second. - -```C++ -void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec); -``` - - - - - - -## License - -The MIT License (MIT) - -Copyright (c) 2019 K. Suwatchai (Mobizt) - - -Permission is hereby granted, free of charge, to any person returning a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - - diff --git a/lib/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino b/lib/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino deleted file mode 100755 index 4c3540898..000000000 --- a/lib/libesp32/ESP32-Mail-Client/examples/Receive_email/Receive_email.ino +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2019 mobizt - * -*/ - - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - -/* - =========================================================================================================================== - To prevent stack overrun in case of you want to download email attachments in IMAP readMail, - increase the stack size in app_main() in esp32 main.cpp will help by change the stack size from 8192 to any more value - as following - - xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE); - to - xTaskCreatePinnedToCore(loopTask, "loopTask", 16384, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE); - - For Arduino, file esp32's main.cpp is at C:\Users\USER_NAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\main.cpp - And for platformIO, that file is at C:\Users\USER_NAME\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp - =========================================================================================================================== - -*/ - -#include -#include "ESP32_MailClient.h" -#include "SD.h" - -#define WIFI_SSID "YOUR_WIFI_SSID" -#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" - - - -//The Email Reading data object contains config and data that received -IMAPData imapData; - -//Callback function to get the Email reading status -void readCallback(ReadStatus info); - -//List all files in SD card -void printDirectory(File &dir, int depth); - -void readEmail(); - -unsigned long lastTime = 0; - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - Serial.println(); - - MailClient.sdBegin(); - //MailClient.sdBegin(14,2,15,13); //SCK, MISO, MOSI,SS for TTGO T8 v1.7 or 1.8 - - File dir = SD.open("/"); - - printDirectory(dir, 0); - - Serial.println(); - - imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD"); - imapData.setFolder("INBOX"); - - //Clear fetch UID - //If fetch UID was set, no search is perform. - imapData.setFetchUID(""); - - //imapData.setSearchCriteria("UID SINCE 10-Feb-2019"); - //imapData.setSearchCriteria("UID 700:*"); - //imapData.setSearchCriteria("UID SEARCH NOT SEEN"); - //imapData.setSearchCriteria("UID SEARCH UNSEEN"); - imapData.setSearchCriteria("UID SEARCH ALL"); - - //To fetch or read one message UID = 320 - //imapData.setFechUID("320"); - - //Set SD folder to save download messages and attachments - imapData.setSaveFilePath("/email_data"); - - //Save attachament - imapData.setDownloadAttachment(true); - - //Set fetch/search result to return html message - imapData.setHTMLMessage(true); - - //Set fetch/search result to return text message - imapData.setTextMessage(true); - - //Set to save html message in SD card with decoded content. - imapData.saveHTMLMessage(true, true); - - //Set to save text message in SD card with decoded content. - imapData.saveTextMessage(true, true); - - //Set the maximum result when search criteria was set. - imapData.setSearchLimit(10); - - //Set the sort order of returning message upon most recent received email. - imapData.setRecentSort(true); - - //Set the return tex/html message size in byte. - imapData.setMessageBufferSize(200); - - //Set the maximum attachment size 5 MB (each file) - imapData.setAttachmentSizeLimit(1024 * 1024 * 5); - - //Set the Email receive callback function. - imapData.setReadCallback(readCallback); - - //Set to get attachment downloading progress status. - imapData.setDownloadReport(true); - - //Set the storage types to save download attachments or messages (SD is default) - //imapData.setFileStorageType(MailClientStorageType::SPIFFS) - imapData.setFileStorageType(MailClientStorageType::SD); - - MailClient.readMail(imapData); -} - -void readEmail() -{ - - Serial.println(); - Serial.println("Read Email..."); - - imapData.setFetchUID("10"); - imapData.setSearchCriteria(""); - MailClient.readMail(imapData); - - imapData.setFetchUID("11"); - imapData.setSearchCriteria(""); - MailClient.readMail(imapData); - - imapData.setFetchUID("12"); - imapData.setSearchCriteria(""); - MailClient.readMail(imapData); -} - -void loop() -{ - - if (millis() - lastTime > 1000 * 60 * 3) - { - - lastTime = millis(); - Serial.println(ESP.getFreeHeap()); - - readEmail(); - } -} - -//Callback function to get the Email reading status -void readCallback(ReadStatus msg) -{ - //Print the current status - Serial.println("INFO: " + msg.info()); - - if (msg.status() != "") - Serial.println("STATUS: " + msg.status()); - - //Show the result when reading finished - if (msg.success()) - { - - for (int i = 0; i < imapData.availableMessages(); i++) - { - Serial.println("================="); - - //Search result number which varied upon search crieria - Serial.println("Messsage Number: " + imapData.getNumber(i)); - - //UID only available when assigned UID keyword in setSearchCriteria - //e.g. imapData.setSearchCriteria("UID SEARCH ALL"); - Serial.println("Messsage UID: " + imapData.getUID(i)); - Serial.println("Messsage ID: " + imapData.getMessageID(i)); - Serial.println("Accept Language: " + imapData.getAcceptLanguage(i)); - Serial.println("Content Language: " + imapData.getContentLanguage(i)); - Serial.println("From: " + imapData.getFrom(i)); - Serial.println("From Charset: " + imapData.getFromCharset(i)); - Serial.println("To: " + imapData.getTo(i)); - Serial.println("To Charset: " + imapData.getToCharset(i)); - Serial.println("CC: " + imapData.getCC(i)); - Serial.println("CC Charset: " + imapData.getCCCharset(i)); - Serial.println("Date: " + imapData.getDate(i)); - Serial.println("Subject: " + imapData.getSubject(i)); - Serial.println("Subject Charset: " + imapData.getSubjectCharset(i)); - - //If setHeaderOnly to false; - if (!imapData.isHeaderOnly()) - { - Serial.println("Text Message: " + imapData.getTextMessage(i)); - Serial.println("Text Message Charset: " + imapData.getTextMessgaeCharset(i)); - Serial.println("HTML Message: " + imapData.getHTMLMessage(i)); - Serial.println("HTML Message Charset: " + imapData.getHTMLMessgaeCharset(i)); - if (imapData.isFetchMessageFailed(i)) - Serial.println("Fetch Error: " + imapData.getFetchMessageFailedReason(i)); - - if (imapData.isDownloadMessageFailed(i)) - Serial.println("Save Content Error: " + imapData.getDownloadMessageFailedReason(i)); - - if (imapData.getAttachmentCount(i) > 0) - { - - Serial.println("**************"); - Serial.println("Attachment: " + String(imapData.getAttachmentCount(i)) + " file(s)"); - - for (int j = 0; j < imapData.getAttachmentCount(i); j++) - { - Serial.println("File Index: " + String(j + 1)); - Serial.println("Filename: " + imapData.getAttachmentFileName(i, j)); - Serial.println("Name: " + imapData.getAttachmentName(i, j)); - Serial.println("Size: " + String(imapData.getAttachmentFileSize(i, j))); - Serial.println("Type: " + imapData.getAttachmentType(i, j)); - Serial.println("Creation Date: " + imapData.getAttachmentCreationDate(i, j)); - if (imapData.isDownloadAttachmentFailed(i, j)) - Serial.println("Download Attachment Error: " + imapData.getDownloadAttachmentFailedReason(i, j)); - } - } - } - - Serial.println(); - } - } -} - -//List all files in SD card -void printDirectory(File &dir, int depth) -{ - while (true) - { - File entry = dir.openNextFile(); - if (!entry) - break; - - for (uint8_t i = 0; i < depth; i++) - Serial.print("| "); - - std::string name = entry.name(); - if (entry.isDirectory()) - { - Serial.print("+----" + String(name.substr(name.find_last_of("/\\") + 1).c_str()) + "\r\n"); - printDirectory(entry, depth + 1); - } - else - { - Serial.print("+--" + String(name.substr(name.find_last_of("/\\") + 1).c_str())); - Serial.print("\t\t\t("); - Serial.print(entry.size(), DEC); - Serial.println(")"); - } - entry.close(); - } -} diff --git a/lib/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino b/lib/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino deleted file mode 100755 index 4d4a5b1aa..000000000 --- a/lib/libesp32/ESP32-Mail-Client/examples/Send_email/Send_email.ino +++ /dev/null @@ -1,180 +0,0 @@ - - -/* - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2019 mobizt - * -*/ - - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - - -#include -#include "ESP32_MailClient.h" -#include "SD.h" - -//For demo only -#include "image.h" - -#define WIFI_SSID "YOUR_WIFI_SSID" -#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" - - -//The Email Sending data object contains config and data to send -SMTPData smtpData; - -//Callback function to get the Email sending status -void sendCallback(SendStatus info); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - - Serial.println("Mounting SD Card..."); - - if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8 - { - - Serial.println("Preparing attach file..."); - - File file = SD.open("/text_file.txt", FILE_WRITE); - file.print("Hello World!\r\nHello World!"); - file.close(); - - file = SD.open("/binary_file.dat", FILE_WRITE); - - static uint8_t buf[512]; - - buf[0] = 'H'; - buf[1] = 'E'; - buf[2] = 'A'; - buf[3] = 'D'; - file.write(buf, 4); - - size_t i; - memset(buf, 0xff, 512); - for (i = 0; i < 2048; i++) - { - file.write(buf, 512); - } - - buf[0] = 'T'; - buf[1] = 'A'; - buf[2] = 'I'; - buf[3] = 'L'; - file.write(buf, 4); - - file.close(); - } - else - { - Serial.println("SD Card Monting Failed"); - } - - Serial.println(); - - - Serial.println("Sending email..."); - - //Set the Email host, port, account and password - smtpData.setLogin("outlook.office365.com", 587, "YOUR_EMAIL_ACCOUNT@outlook.com", "YOUR_EMAIL_PASSWORD"); - - //For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be - //enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function. - //smtpData.setSTARTTLS(true); - - //Set the sender name and Email - smtpData.setSender("ESP32", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com"); - - //Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest) - smtpData.setPriority("High"); - - //Set the subject - smtpData.setSubject("ESP32 SMTP Mail Sending Test"); - - //Set the message - normal text or html format - smtpData.setMessage("
Hello World! - From ESP32
", true); - - //Add recipients, can add more than one recipient - smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com"); - - - - //Add attachments, can add the file or binary data from flash memory, file in SD card - //Data from internal memory - smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData); - - //Add attach files from SD card - //Comment these two lines, if no SD card connected - //Two files that previousely created. - smtpData.addAttachFile("/binary_file.dat"); - smtpData.addAttachFile("/text_file.txt"); - - - //Add some custom header to message - //See https://tools.ietf.org/html/rfc822 - //These header fields can be read from raw or source of message when it received) - smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)"); - //Be careful when set Message-ID, it should be unique, otherwise message will not store - //smtpData.addCustomMessageHeader("Message-ID: "); - - //Set the storage types to read the attach files (SD is default) - //smtpData.setFileStorageType(MailClientStorageType::SPIFFS); - smtpData.setFileStorageType(MailClientStorageType::SD); - - - - smtpData.setSendCallback(sendCallback); - - //Start sending Email, can be set callback function to track the status - if (!MailClient.sendMail(smtpData)) - Serial.println("Error sending Email, " + MailClient.smtpErrorReason()); - - //Clear all data from Email object to free memory - smtpData.empty(); - -} - -void loop() -{ -} - -//Callback function to get the Email sending status -void sendCallback(SendStatus msg) -{ - //Print the current status - Serial.println(msg.info()); - - //Do something when complete - if (msg.success()) - { - Serial.println("----------------"); - } -} - diff --git a/lib/libesp32/ESP32-Mail-Client/examples/Send_email/image.h b/lib/libesp32/ESP32-Mail-Client/examples/Send_email/image.h deleted file mode 100755 index 4b8b3542d..000000000 --- a/lib/libesp32/ESP32-Mail-Client/examples/Send_email/image.h +++ /dev/null @@ -1,1074 +0,0 @@ -#include - -static const uint8_t dummyImageData[] PROGMEM = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, -0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, -0x70, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, -0x65, 0x00, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x49, 0x6D, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, -0x64, 0x79, 0x71, 0xC9, 0x65, 0x3C, 0x00, 0x00, 0x42, 0x9A, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, -0xEC, 0xDD, 0x7F, 0x90, 0x6C, 0xD9, 0x41, 0xD8, 0xF7, 0xD3, 0xF3, 0xE6, 0xFD, 0xD8, 0xDD, 0xA7, -0xDD, 0xD1, 0xB2, 0x20, 0x88, 0x70, 0x5E, 0x63, 0xB0, 0xB4, 0x20, 0xE1, 0x37, 0x26, 0x50, 0x05, -0x68, 0x57, 0xAF, 0x57, 0x3F, 0xA1, 0x70, 0x15, 0x4A, 0x59, 0x80, 0x88, 0xA9, 0xF8, 0x29, 0x02, -0x1B, 0x12, 0x5C, 0xBB, 0x40, 0x28, 0x48, 0x19, 0x67, 0xA5, 0x42, 0xC6, 0x8A, 0xA3, 0x64, 0xE5, -0x18, 0x63, 0x91, 0x22, 0x48, 0xB8, 0xCA, 0x95, 0xC4, 0x71, 0x2C, 0x1C, 0x40, 0x6F, 0x77, 0xE3, -0x18, 0xA5, 0xE2, 0x3F, 0x53, 0x05, 0x55, 0xB6, 0x14, 0x6C, 0x09, 0xF4, 0x0B, 0xAD, 0x24, 0x76, -0xB5, 0xDA, 0xDD, 0x37, 0x3F, 0x7B, 0xBA, 0xEF, 0x49, 0x9F, 0xDB, 0x7D, 0x7B, 0x6E, 0xFF, 0x98, -0x79, 0x3D, 0x33, 0xDD, 0x3D, 0x7D, 0xBB, 0x3F, 0x9F, 0xD2, 0xCC, 0x9B, 0xD7, 0x33, 0xD3, 0xD3, -0x73, 0x67, 0xDE, 0xD5, 0xF9, 0xEE, 0xE9, 0x73, 0x6E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0F, 0x35, 0x87, 0x00, -0x58, 0x35, 0xF1, 0xFF, 0xFC, 0xBE, 0x46, 0xEF, 0xCD, 0x17, 0x6A, 0x6F, 0x7E, 0xF2, 0x0F, 0x1D, -0x11, 0x00, 0x10, 0x20, 0x00, 0xD3, 0x8E, 0x8E, 0x9B, 0x9D, 0x3F, 0x1E, 0xED, 0xBC, 0x6C, 0x1E, -0xDE, 0x18, 0x8B, 0xB7, 0x3E, 0xDC, 0x79, 0xF9, 0xAD, 0xDA, 0x5B, 0x9E, 0xFA, 0x98, 0x23, 0x05, -0x00, 0x02, 0x04, 0xE0, 0x2C, 0xE1, 0x51, 0xEF, 0xFC, 0xF1, 0x91, 0x81, 0xF0, 0x18, 0x8C, 0x8F, -0xB2, 0x0F, 0x74, 0x22, 0xE4, 0x67, 0x1C, 0x35, 0x00, 0x10, 0x20, 0x00, 0xA7, 0x89, 0x8F, 0x14, -0x1D, 0xBF, 0xDF, 0x79, 0xD9, 0x08, 0xB1, 0x1D, 0x42, 0xF3, 0xAB, 0x9D, 0x97, 0x17, 0x43, 0x68, -0x37, 0x43, 0xC8, 0x3A, 0x2F, 0x17, 0xEE, 0xEA, 0xBC, 0x5C, 0x09, 0xE1, 0xF2, 0xFD, 0x21, 0xAC, -0xDF, 0x53, 0x7C, 0xDA, 0x87, 0x3B, 0x11, 0xF2, 0x4E, 0x47, 0x0F, 0x00, 0x04, 0x08, 0xC0, 0x49, -0x03, 0xE4, 0x0F, 0x42, 0x9A, 0xF9, 0xD8, 0x7F, 0x2E, 0x84, 0xDD, 0x2F, 0x87, 0x3C, 0x42, 0xC6, -0xCF, 0x7C, 0x74, 0x02, 0xE4, 0x6A, 0x08, 0x57, 0xAF, 0x75, 0xCE, 0x8A, 0x17, 0xD2, 0xDF, 0xFE, -0xE3, 0x4E, 0x84, 0xFC, 0xB6, 0x23, 0x08, 0x00, 0x02, 0x04, 0x60, 0xD2, 0xF8, 0xB8, 0xD9, 0xF9, -0xE3, 0x43, 0x61, 0xFB, 0xF3, 0xDD, 0x99, 0x8F, 0xFC, 0xC6, 0x78, 0x87, 0x33, 0x62, 0x27, 0x3E, -0x5E, 0xF6, 0xE7, 0xD3, 0xCC, 0xC8, 0x0B, 0x9D, 0x0F, 0xFE, 0xA6, 0xDA, 0x5B, 0x9E, 0x7E, 0xC1, -0x91, 0x04, 0x80, 0xE9, 0x5A, 0x73, 0x08, 0x80, 0x25, 0xF5, 0x78, 0xD8, 0xFB, 0xF2, 0xE4, 0xF1, -0x91, 0x7F, 0x4C, 0x3B, 0xE4, 0xC1, 0x12, 0x5B, 0x1B, 0x9D, 0xBF, 0x3D, 0xE6, 0x10, 0x02, 0xC0, -0xF4, 0x99, 0x01, 0x01, 0x96, 0x4E, 0xBE, 0xF0, 0x3C, 0x6B, 0x7E, 0x3A, 0xBC, 0xF8, 0x47, 0x93, -0xC7, 0xC7, 0xE1, 0x67, 0x87, 0x70, 0xD7, 0x2B, 0x42, 0xB8, 0xF2, 0x8A, 0x34, 0xFB, 0x61, 0x16, -0x04, 0x00, 0xA6, 0xCC, 0x0C, 0x08, 0xB0, 0x8C, 0xEA, 0x61, 0xEF, 0xB9, 0xD3, 0xC5, 0x47, 0x92, -0x3E, 0x37, 0xB6, 0xCD, 0x82, 0x00, 0x80, 0x00, 0x01, 0x98, 0x48, 0x23, 0xB4, 0xB6, 0x4E, 0x17, -0x1F, 0xF9, 0x9B, 0xED, 0xEE, 0xA2, 0xF5, 0x10, 0x1E, 0x8F, 0x4F, 0xBF, 0xA5, 0xEE, 0x70, 0x02, -0x80, 0x00, 0x01, 0x38, 0xCE, 0xB5, 0xD0, 0xDA, 0x3D, 0x5D, 0x7C, 0x14, 0xD2, 0xCE, 0x59, 0x69, -0xAB, 0xDE, 0xB4, 0x96, 0x04, 0x00, 0x10, 0x20, 0x00, 0x47, 0x3A, 0xD8, 0xAA, 0x9F, 0x29, 0x3E, -0x0A, 0xDD, 0x59, 0x90, 0x9B, 0x66, 0x41, 0x00, 0x40, 0x80, 0x00, 0x1C, 0x2D, 0x6B, 0x6D, 0x9E, -0x39, 0x3E, 0x92, 0xB4, 0x83, 0x56, 0x3B, 0x9F, 0x49, 0xF9, 0x90, 0x83, 0x0A, 0x00, 0x02, 0x04, -0x60, 0x34, 0x29, 0x9E, 0x7E, 0xEB, 0x46, 0xC8, 0xF6, 0x36, 0xCE, 0x1C, 0x1F, 0x85, 0x9D, 0x2F, -0xA6, 0xD7, 0x8D, 0xF8, 0xF4, 0x5B, 0x1A, 0x8E, 0x2E, 0x00, 0x08, 0x10, 0x80, 0x61, 0x9B, 0x77, -0x5E, 0xFF, 0x71, 0x82, 0xC5, 0xE9, 0x69, 0x31, 0x7B, 0x7A, 0x09, 0xD1, 0x5A, 0x10, 0x00, 0x10, -0x20, 0x00, 0x23, 0xEA, 0x21, 0x66, 0xD3, 0x89, 0x8F, 0x42, 0x77, 0x2D, 0x48, 0x23, 0x3E, 0xFD, -0xE6, 0x86, 0xC3, 0x0B, 0x00, 0x02, 0x04, 0x60, 0x30, 0x40, 0xF2, 0x19, 0x8B, 0x29, 0xC5, 0x47, -0xFA, 0x9C, 0x74, 0x7F, 0xDD, 0x2B, 0xAA, 0x5B, 0x0B, 0x02, 0x00, 0x02, 0x04, 0xA0, 0xA4, 0xBD, -0x77, 0x63, 0xAA, 0xF1, 0x51, 0xE8, 0xCE, 0x82, 0xD4, 0xE3, 0xD3, 0x6F, 0xBE, 0xE9, 0x20, 0x03, -0x80, 0x00, 0x01, 0xE8, 0xCA, 0x0E, 0xEA, 0x53, 0x8F, 0x8F, 0xFC, 0x7E, 0x9B, 0xC5, 0x2C, 0x88, -0xB5, 0x20, 0x00, 0x20, 0x40, 0x00, 0x8A, 0x50, 0xD8, 0xAF, 0x4F, 0x3D, 0x3E, 0x0A, 0x69, 0x16, -0x24, 0xB6, 0xD3, 0x2C, 0xC8, 0xBB, 0x1D, 0x68, 0x00, 0x10, 0x20, 0xC0, 0x8A, 0x8B, 0x4F, 0xBF, -0x75, 0x33, 0xB4, 0x9B, 0xB3, 0x89, 0x8F, 0x3C, 0x6E, 0x9A, 0xDD, 0x2B, 0xA4, 0x87, 0xF0, 0x68, -0x27, 0x42, 0x36, 0x1C, 0x71, 0x00, 0x10, 0x20, 0xC0, 0x6A, 0xAB, 0x87, 0xF6, 0xDE, 0x6C, 0xE2, -0xA3, 0xB0, 0xF7, 0x5C, 0x9A, 0x05, 0x49, 0xF1, 0xF1, 0x98, 0xC3, 0x0D, 0x00, 0x02, 0x04, 0x58, -0x6D, 0x9B, 0xDD, 0x2B, 0x97, 0xCF, 0x28, 0x3E, 0xF2, 0x0F, 0x6B, 0x9B, 0x05, 0x01, 0x00, 0x01, -0x02, 0x90, 0xBB, 0x16, 0x62, 0x6B, 0x76, 0xF1, 0x51, 0x48, 0x6B, 0x41, 0xB2, 0x66, 0x8A, 0x8F, -0x27, 0x1C, 0x72, 0x00, 0x10, 0x20, 0xC0, 0xAA, 0x6A, 0xBE, 0x50, 0x9F, 0x79, 0x7C, 0xE4, 0x9F, -0x12, 0x8B, 0x6D, 0x79, 0x6F, 0xC6, 0xA7, 0xDF, 0x5C, 0x77, 0xE0, 0x01, 0x40, 0x80, 0x00, 0x2B, -0x29, 0x6B, 0xCC, 0x25, 0x3E, 0x92, 0xFD, 0xE7, 0xBB, 0x8B, 0xD2, 0x6D, 0xCB, 0x0B, 0x00, 0x02, -0x04, 0x58, 0x3D, 0xF1, 0xE9, 0xB7, 0xD4, 0x7B, 0x41, 0x30, 0xFB, 0xF8, 0x28, 0xEC, 0x3C, 0x93, -0x5E, 0xA7, 0x59, 0x90, 0x86, 0x9F, 0x00, 0x00, 0x08, 0x10, 0x60, 0xB5, 0xD4, 0x43, 0x6B, 0x77, -0x7E, 0xF1, 0x91, 0x34, 0x5F, 0x0C, 0xA1, 0xB5, 0x95, 0xDE, 0x32, 0x0B, 0x02, 0x00, 0x02, 0x04, -0x58, 0x31, 0x9B, 0x21, 0x3B, 0x98, 0x5F, 0x7C, 0x14, 0xBA, 0x6B, 0x41, 0x1A, 0x66, 0x41, 0x00, -0x40, 0x80, 0x00, 0xAB, 0xE5, 0x5A, 0x77, 0x0B, 0xDE, 0x39, 0xC6, 0x47, 0x72, 0xB0, 0x65, 0x16, -0x04, 0x00, 0x04, 0x08, 0xB0, 0x72, 0x5A, 0xDB, 0x9B, 0x73, 0x8F, 0x8F, 0xC2, 0xD6, 0xE7, 0xD3, -0xEB, 0x34, 0x0B, 0x72, 0xD3, 0x0F, 0x02, 0x00, 0x04, 0x08, 0xB0, 0x0A, 0x62, 0x56, 0x3F, 0x97, -0xF8, 0x48, 0xD2, 0xE2, 0xF7, 0xB4, 0x2B, 0x96, 0x59, 0x10, 0x00, 0x10, 0x20, 0xC0, 0x8A, 0x68, -0xEF, 0xD4, 0xCF, 0x25, 0x3E, 0x0A, 0x69, 0x2D, 0x48, 0x8C, 0xF5, 0xF8, 0xD4, 0x9B, 0x6E, 0xFA, -0x61, 0x00, 0x80, 0x00, 0x01, 0x96, 0x58, 0x7C, 0xFA, 0x2D, 0x8D, 0xD0, 0x6E, 0x9E, 0x5F, 0x7C, -0x24, 0xD9, 0x7E, 0x08, 0xFB, 0xCF, 0xA6, 0xB7, 0x9E, 0xE8, 0x44, 0xC8, 0x86, 0x9F, 0x0A, 0x00, -0x08, 0x10, 0x60, 0x79, 0xD5, 0x47, 0x77, 0xC0, 0x9A, 0x63, 0x7C, 0x14, 0x5F, 0x2B, 0x9F, 0x05, -0x69, 0xA7, 0xF8, 0x78, 0xCC, 0x8F, 0x04, 0x00, 0x04, 0x08, 0xB0, 0xCC, 0x01, 0x32, 0xB0, 0x03, -0xD6, 0x39, 0xC4, 0x47, 0xFE, 0x66, 0x3B, 0x84, 0xFD, 0xE7, 0xD2, 0x5B, 0x8F, 0x9A, 0x05, 0x01, -0x00, 0x01, 0x02, 0x2C, 0xAB, 0xAC, 0x75, 0x3D, 0x1F, 0xFC, 0x9F, 0x67, 0x7C, 0x14, 0xF6, 0x9E, -0x2D, 0x66, 0x41, 0x2C, 0x48, 0x07, 0x00, 0x01, 0x02, 0x2C, 0xA5, 0xFE, 0x02, 0xF4, 0x73, 0x8E, -0x8F, 0xFC, 0xE6, 0x4E, 0x08, 0xED, 0x3C, 0x93, 0xDE, 0x7A, 0x2C, 0x3E, 0xF5, 0xA6, 0xBA, 0x1F, -0x0E, 0x00, 0x08, 0x10, 0x60, 0xD9, 0x64, 0xCD, 0xCD, 0x85, 0x88, 0x8F, 0x42, 0xF3, 0xF9, 0xEE, -0xD6, 0xBC, 0x66, 0x41, 0x00, 0x40, 0x80, 0x00, 0xCB, 0x25, 0x3E, 0xFD, 0x96, 0x7A, 0x88, 0xAD, -0xC5, 0x89, 0x8F, 0x42, 0x5A, 0x90, 0x1E, 0xC2, 0x4D, 0xB3, 0x20, 0x00, 0x20, 0x40, 0x80, 0xE5, -0x4A, 0x90, 0x7A, 0x38, 0xD8, 0x5E, 0xAC, 0xF8, 0x48, 0xD2, 0x2C, 0x48, 0x6B, 0x2B, 0xBD, 0xF5, -0x21, 0x3F, 0x23, 0x00, 0x10, 0x20, 0xC0, 0xF2, 0x68, 0xF4, 0x9E, 0xEE, 0xB4, 0x38, 0xF1, 0x51, -0xE8, 0xCE, 0x82, 0x34, 0xE2, 0x53, 0x6F, 0x6C, 0xF8, 0x31, 0x01, 0x80, 0x00, 0x01, 0x96, 0xC3, -0xB5, 0x89, 0x03, 0x64, 0x9E, 0xF1, 0x91, 0xA4, 0x19, 0x90, 0xD6, 0xED, 0xF4, 0x96, 0xB5, 0x20, -0x00, 0x20, 0x40, 0x80, 0xA5, 0xD0, 0xDA, 0xAE, 0x2F, 0x64, 0x7C, 0x14, 0x5F, 0xF3, 0x70, 0x16, -0xE4, 0x6D, 0x7E, 0x58, 0x00, 0x20, 0x40, 0x80, 0xAA, 0xCB, 0x5A, 0x9B, 0x0B, 0x1B, 0x1F, 0xC9, -0xC1, 0x56, 0x08, 0xFB, 0xCF, 0xA7, 0xB7, 0x9E, 0xF0, 0xC3, 0x02, 0x00, 0x01, 0x02, 0x54, 0x58, -0x7C, 0xFA, 0xCD, 0x1B, 0x21, 0xDB, 0xDB, 0x58, 0xD8, 0xF8, 0x28, 0x74, 0x67, 0x41, 0xEA, 0xF1, -0xA9, 0x37, 0xDE, 0xF4, 0x53, 0x03, 0x40, 0x80, 0x00, 0x54, 0xD7, 0x66, 0x68, 0xED, 0x2E, 0x76, -0x7C, 0x24, 0x69, 0x8D, 0x4A, 0x77, 0x16, 0xC4, 0x5A, 0x10, 0x00, 0x04, 0x88, 0x43, 0x00, 0x54, -0x58, 0x3D, 0xC4, 0x6C, 0xB1, 0xE3, 0xA3, 0x90, 0xAE, 0x8E, 0x1E, 0xDB, 0x69, 0x16, 0xE4, 0xDD, -0x7E, 0x6C, 0x00, 0x08, 0x10, 0x80, 0xAA, 0x06, 0x48, 0xF7, 0x5A, 0x1B, 0x8B, 0x1D, 0x1F, 0xF9, -0xFB, 0xDB, 0x21, 0xEC, 0x3D, 0x97, 0xDE, 0x7A, 0xB4, 0x13, 0x21, 0x1B, 0x7E, 0x74, 0x00, 0x08, -0x10, 0x80, 0xAA, 0x69, 0xEF, 0xDD, 0xA8, 0x44, 0x7C, 0x14, 0xF6, 0x9E, 0x4D, 0x21, 0x92, 0xE2, -0xE3, 0x31, 0x3F, 0x3C, 0x00, 0x04, 0x08, 0x40, 0xD5, 0x64, 0xCD, 0x8D, 0xCA, 0xC4, 0x47, 0xFE, -0xB1, 0xED, 0x6E, 0x84, 0x84, 0xF8, 0x68, 0x7C, 0xEA, 0x0D, 0x75, 0x3F, 0x40, 0x00, 0x04, 0x08, -0x40, 0xB5, 0x02, 0x64, 0xB3, 0x32, 0xF1, 0x51, 0xD8, 0xFD, 0x52, 0x11, 0x4E, 0x16, 0xA4, 0x03, -0xB0, 0x92, 0x6A, 0x0E, 0x01, 0x50, 0x45, 0xF1, 0xE9, 0x37, 0x6F, 0x86, 0x9D, 0x67, 0xFE, 0x20, -0xEC, 0x3F, 0x57, 0x9D, 0xF8, 0x28, 0xBE, 0xDE, 0xE5, 0xFB, 0x43, 0xB8, 0xE7, 0xCF, 0xA5, 0xB7, -0xBE, 0xA9, 0xF6, 0xD6, 0x7F, 0xF5, 0x99, 0xCA, 0x1D, 0xFB, 0x27, 0x1B, 0xF5, 0x90, 0xD6, 0xDF, -0x74, 0x7D, 0xA6, 0xF6, 0x7D, 0x1F, 0xFB, 0x8C, 0xDF, 0x48, 0x00, 0x26, 0xB5, 0xEE, 0x10, 0x00, -0x15, 0x55, 0x0F, 0xED, 0xBD, 0xEA, 0xC5, 0x47, 0x92, 0xB6, 0xE4, 0xBD, 0xEB, 0x15, 0x21, 0xAC, -0x5D, 0x4A, 0xB3, 0x20, 0xEF, 0xAC, 0x48, 0x74, 0x14, 0x6B, 0x57, 0xFE, 0x5A, 0x29, 0x3E, 0x8A, -0xF7, 0xA5, 0x00, 0xF9, 0xAD, 0xCE, 0xCB, 0x07, 0x3A, 0x31, 0xF2, 0x82, 0x5F, 0x4D, 0x00, 0x8E, -0xE3, 0x29, 0x58, 0x40, 0x55, 0x6D, 0x86, 0xD6, 0x4E, 0xF5, 0xE2, 0xA3, 0xB0, 0xFD, 0xF9, 0xF4, -0xFA, 0x66, 0x7C, 0xEA, 0x0D, 0x8D, 0x0A, 0xC4, 0xC7, 0xDB, 0x3A, 0x7F, 0x7C, 0x3A, 0x74, 0x9F, -0x36, 0x56, 0x1F, 0x1B, 0x83, 0xDD, 0xF7, 0x7D, 0xBA, 0xF7, 0xB1, 0x00, 0x20, 0x40, 0x80, 0xA5, -0x73, 0x2D, 0x5F, 0xD4, 0x5D, 0xC5, 0xF8, 0x48, 0x0E, 0xB6, 0x42, 0x6F, 0x0B, 0xE1, 0x85, 0x5E, -0x0B, 0xD2, 0x09, 0x8A, 0x9B, 0x9D, 0x3F, 0x3E, 0xD2, 0x79, 0xD9, 0xE8, 0x2F, 0xA2, 0xBF, 0xFD, -0xA9, 0xC1, 0x97, 0xEE, 0xEE, 0x5E, 0xA1, 0xFB, 0x31, 0xF1, 0x23, 0xF1, 0xD6, 0x8D, 0x9B, 0x7E, -0x3D, 0x01, 0x38, 0x8A, 0x35, 0x20, 0x40, 0x25, 0xC5, 0xDF, 0xFD, 0xAE, 0xDF, 0x0F, 0x5B, 0x9F, -0x6D, 0x54, 0x32, 0x3E, 0x0A, 0x17, 0xAF, 0x86, 0xF0, 0xB2, 0x6F, 0x4E, 0x6F, 0x3D, 0x52, 0x7B, -0xEB, 0xBF, 0xFA, 0xD8, 0x02, 0xC6, 0x47, 0xBD, 0xF3, 0xC7, 0x1F, 0xE4, 0x61, 0x91, 0x16, 0xCF, -0x1F, 0x86, 0xC6, 0x98, 0xFF, 0x37, 0xB9, 0x10, 0xC2, 0x95, 0x07, 0x3A, 0x2F, 0x5F, 0x9F, 0xFE, -0x96, 0x9E, 0x86, 0xF5, 0x97, 0x6A, 0xDF, 0xFF, 0x7F, 0x7F, 0xC6, 0x6F, 0x2A, 0x00, 0xC3, 0xCC, -0x80, 0x00, 0x15, 0x2D, 0x90, 0xAC, 0xDA, 0xF1, 0x91, 0x1C, 0xCE, 0x82, 0x3C, 0xB1, 0xA0, 0x47, -0xF9, 0x89, 0x3C, 0x3E, 0xB6, 0x3F, 0xD7, 0xDD, 0xBD, 0xEB, 0xB8, 0x19, 0xA7, 0xD8, 0xEA, 0x7E, -0x4C, 0xFA, 0xD8, 0xF4, 0x39, 0x21, 0x7C, 0xC8, 0x2F, 0x29, 0x00, 0x02, 0x04, 0x58, 0x8E, 0xF6, -0x78, 0xFA, 0xCD, 0x1B, 0x21, 0x3B, 0xA8, 0x76, 0x7C, 0x14, 0xB6, 0xF2, 0xB5, 0x20, 0x9B, 0xF1, -0xA9, 0x37, 0xDC, 0x5C, 0xA8, 0x63, 0xFC, 0x64, 0x23, 0x05, 0xDE, 0xDB, 0xC2, 0xCE, 0x17, 0xBA, -0x8B, 0xE6, 0x27, 0xFD, 0x7E, 0x9B, 0xCF, 0x17, 0x11, 0xD2, 0x88, 0xB7, 0x6E, 0x34, 0xFC, 0xB6, -0x02, 0x20, 0x40, 0x80, 0x65, 0xB0, 0x19, 0xDA, 0xBB, 0xD5, 0x8F, 0x8F, 0x24, 0x6B, 0x16, 0x03, -0xFC, 0x45, 0x5B, 0x0B, 0xF2, 0x78, 0x3E, 0x3B, 0x93, 0x5F, 0x38, 0xF1, 0x84, 0xDF, 0x6F, 0x8A, -0x90, 0x0A, 0xAC, 0x6F, 0x01, 0x40, 0x80, 0x00, 0x9C, 0x20, 0x40, 0x9A, 0xD5, 0x8F, 0x8F, 0xC2, -0xEE, 0x97, 0xD3, 0xEB, 0x7A, 0x7C, 0xF2, 0x91, 0xC7, 0x16, 0xE1, 0xE0, 0xF6, 0x66, 0x3F, 0x1A, -0xF9, 0x53, 0xAA, 0x4E, 0xFB, 0xFD, 0x76, 0x3F, 0xD7, 0x2C, 0x08, 0x00, 0x02, 0x04, 0x58, 0x0A, -0xD7, 0xEE, 0x3C, 0x03, 0x52, 0x91, 0xF8, 0x48, 0xD2, 0x2C, 0x48, 0x77, 0xC0, 0xFE, 0x78, 0x27, -0x42, 0x36, 0x16, 0xE0, 0xF8, 0x76, 0x67, 0x3F, 0x0E, 0xB6, 0x4E, 0xFF, 0xFD, 0xB6, 0xB6, 0xCC, -0x82, 0x00, 0x20, 0x40, 0x80, 0x25, 0xD1, 0xDA, 0xDA, 0x5C, 0x9A, 0xF8, 0x28, 0x3E, 0xBF, 0xBB, -0xC3, 0x54, 0x71, 0xB1, 0xBF, 0x73, 0xD3, 0xBB, 0x8E, 0x47, 0x23, 0x6C, 0x7D, 0xEE, 0xEC, 0xDF, -0xEF, 0xE1, 0x5A, 0x10, 0xD7, 0x06, 0x01, 0x40, 0x80, 0x00, 0x15, 0x16, 0x63, 0x7D, 0xA9, 0xE2, -0x23, 0xFF, 0xA3, 0x1D, 0xC2, 0xFE, 0x73, 0xE9, 0xAD, 0x47, 0xCF, 0x79, 0x16, 0xE4, 0x89, 0x7C, -0x4D, 0x4A, 0xD6, 0x3C, 0xFB, 0xF7, 0x9B, 0xEE, 0xA3, 0xF9, 0x7C, 0xF7, 0x3E, 0x01, 0x40, 0x80, -0x00, 0x95, 0xD5, 0xDA, 0xA9, 0x2F, 0x55, 0x7C, 0x14, 0xD2, 0x2C, 0x48, 0xD6, 0x4C, 0xF1, 0x71, -0x2E, 0x4F, 0x5B, 0xEA, 0x5D, 0x74, 0xB0, 0x7E, 0xF4, 0xDA, 0x8F, 0x53, 0x7C, 0xBF, 0xDD, 0xFB, -0xAA, 0xC7, 0x5B, 0xAF, 0xBF, 0xE9, 0x17, 0x17, 0x00, 0x01, 0x02, 0x54, 0x4E, 0x7C, 0xFA, 0xCD, -0x8D, 0xF1, 0xFF, 0x75, 0xBE, 0xE2, 0xF1, 0x91, 0xDF, 0xD4, 0x2E, 0x16, 0xA4, 0x3F, 0x16, 0x9F, -0x7C, 0xA4, 0x7E, 0x0E, 0x87, 0xF7, 0xF1, 0xA3, 0x67, 0x3F, 0x4E, 0xF9, 0xFD, 0xE6, 0xBB, 0x7C, -0x7D, 0x25, 0x04, 0x6B, 0x41, 0x00, 0x10, 0x20, 0x40, 0x45, 0x6D, 0x8C, 0x0E, 0x90, 0x97, 0x20, -0x3E, 0x0A, 0xCD, 0x7E, 0x00, 0xCC, 0x75, 0xC0, 0x7E, 0xFC, 0xEC, 0xC7, 0x19, 0x8F, 0x6F, 0xF7, -0x22, 0x86, 0x66, 0x41, 0x00, 0x10, 0x20, 0x40, 0x25, 0x6D, 0x86, 0xD6, 0xEE, 0x72, 0xC6, 0x47, -0xA1, 0x3B, 0x0B, 0x72, 0x33, 0x3E, 0xF9, 0xC8, 0xE6, 0x9C, 0xE2, 0xA3, 0xFB, 0xB4, 0xAF, 0x14, -0x0A, 0xB3, 0x88, 0xBB, 0x74, 0x9F, 0xDD, 0xEB, 0x89, 0x3C, 0xD1, 0x89, 0x90, 0x0D, 0xBF, 0xC2, -0x00, 0x02, 0x04, 0xA0, 0x3A, 0xB2, 0xD6, 0xF5, 0xFC, 0xA9, 0x4A, 0xCB, 0x1A, 0x1F, 0xC9, 0xE1, -0x85, 0xFC, 0xE6, 0xB5, 0x78, 0xFB, 0xB1, 0x34, 0x43, 0x31, 0x7A, 0xD1, 0xC1, 0x29, 0x1E, 0xDF, -0x05, 0xD9, 0xE5, 0x0B, 0x00, 0x01, 0x02, 0x70, 0x32, 0xFD, 0x05, 0xE8, 0x4B, 0x1A, 0x1F, 0x85, -0xEE, 0x2C, 0x48, 0x23, 0x3E, 0xF9, 0x48, 0x63, 0x96, 0x87, 0xB3, 0x37, 0xFB, 0xF1, 0x68, 0x2F, -0x10, 0x66, 0x13, 0x1F, 0xF9, 0x6D, 0xED, 0x62, 0x16, 0xE4, 0x51, 0xB3, 0x20, 0x00, 0x02, 0x04, -0xA0, 0x3A, 0xB2, 0xFD, 0xCD, 0xA5, 0x8F, 0x8F, 0xE4, 0xE0, 0xF6, 0xBC, 0x2E, 0xE4, 0xF7, 0x58, -0x3E, 0x33, 0x31, 0x30, 0xFB, 0x31, 0xA3, 0xE3, 0x6B, 0x16, 0x04, 0x00, 0x01, 0x02, 0x54, 0x49, -0x7C, 0xEA, 0x4D, 0xF5, 0xC1, 0xFF, 0x4A, 0xBF, 0xA4, 0xF1, 0x51, 0x3C, 0xCE, 0xED, 0x2F, 0xA4, -0xD7, 0x69, 0x16, 0x64, 0x26, 0x17, 0xF2, 0x1B, 0x3F, 0xFB, 0x31, 0xC3, 0xB8, 0x33, 0x0B, 0x02, -0x80, 0x00, 0x01, 0x2A, 0xA6, 0x1E, 0x0E, 0xB6, 0x56, 0x23, 0x3E, 0x92, 0xF6, 0x6E, 0xC8, 0xB7, -0xC5, 0x9D, 0xDD, 0x5A, 0x90, 0xC7, 0xF3, 0xEB, 0x8E, 0xF4, 0x77, 0xBE, 0x9A, 0xC3, 0xCC, 0x52, -0x77, 0xA1, 0xFB, 0xB9, 0x5D, 0xEB, 0x04, 0x00, 0x01, 0x02, 0x70, 0x12, 0x8D, 0xA3, 0xAF, 0xD0, -0xBD, 0x64, 0xF1, 0x51, 0x1E, 0xB0, 0xA7, 0x0B, 0xF9, 0x3D, 0xF9, 0xC8, 0xCD, 0x69, 0x1E, 0xC8, -0xF8, 0x64, 0xA3, 0x1E, 0xD2, 0x53, 0xA1, 0xE6, 0x19, 0x1F, 0x83, 0xDF, 0xD3, 0x63, 0xF1, 0xD6, -0xEB, 0xEB, 0x7E, 0xA5, 0x01, 0x04, 0x08, 0xC0, 0x22, 0xBB, 0xEF, 0xC4, 0x01, 0x52, 0xE5, 0xF8, -0x48, 0xF2, 0x0B, 0xF9, 0xE5, 0xB3, 0x20, 0x8F, 0x77, 0x22, 0x64, 0x9A, 0x4F, 0x5B, 0x7A, 0xFC, -0xF0, 0xBE, 0xE7, 0xBC, 0xA6, 0x66, 0xFF, 0x7C, 0xAE, 0x75, 0x02, 0x80, 0x00, 0x01, 0x38, 0x99, -0xD6, 0xD6, 0xC9, 0xAE, 0x8B, 0x51, 0xF5, 0xF8, 0x28, 0xEC, 0x7C, 0x21, 0xBF, 0x90, 0x5F, 0x98, -0xD2, 0xE2, 0xED, 0xDE, 0xEC, 0xC7, 0xCD, 0xEE, 0x4C, 0xC4, 0xBC, 0x17, 0xF4, 0xF7, 0x74, 0x67, -0x41, 0x6E, 0x9A, 0x05, 0x01, 0x58, 0x3D, 0xEB, 0x0E, 0x01, 0x50, 0x19, 0x59, 0x6B, 0xF2, 0x00, -0x59, 0x96, 0xF8, 0xC8, 0x3F, 0xA6, 0xB7, 0x78, 0xFB, 0xAE, 0xAF, 0x7F, 0x34, 0x3E, 0xF9, 0xC8, -0x07, 0x6A, 0xDF, 0xF7, 0xFB, 0x2F, 0x9C, 0xF1, 0x81, 0x3E, 0x9E, 0x5F, 0xCC, 0x71, 0xFF, 0x2B, -0xE7, 0x13, 0x1F, 0x49, 0x9A, 0x05, 0xB9, 0xF2, 0xB5, 0x21, 0x5C, 0xB8, 0x92, 0x66, 0x41, 0xDE, -0xE9, 0x97, 0x7B, 0xCC, 0x21, 0xFE, 0xC4, 0x8F, 0xA6, 0x19, 0xAF, 0xB4, 0x01, 0x41, 0x39, 0xD2, -0xFE, 0xB0, 0xF3, 0xF2, 0xB1, 0xDA, 0xB7, 0xFD, 0xCF, 0x2F, 0x38, 0x42, 0x40, 0x55, 0xD5, 0x1C, -0x02, 0xA0, 0x12, 0x83, 0xB1, 0xA7, 0xDE, 0xB4, 0x11, 0xF6, 0xBE, 0xFC, 0xD5, 0xC3, 0x35, 0x0B, -0x2B, 0x12, 0x1F, 0xFD, 0xB3, 0xF5, 0x85, 0x10, 0x36, 0xBE, 0x2D, 0xFD, 0xF9, 0x9E, 0x4E, 0x80, -0xBC, 0xFB, 0xD4, 0x8F, 0xF2, 0xC9, 0x46, 0x8A, 0xB8, 0x3F, 0x08, 0x2F, 0x7D, 0xB2, 0xD8, 0xE6, -0x77, 0xFE, 0xF1, 0x51, 0xB8, 0x78, 0x4F, 0x08, 0x2F, 0xFB, 0x96, 0xF4, 0xD6, 0x23, 0xB5, 0xEF, -0xFF, 0x7F, 0x3E, 0xE6, 0xB7, 0x7C, 0x20, 0x3C, 0xD2, 0xC6, 0x03, 0x37, 0x8F, 0x0C, 0xD2, 0xDA, -0x85, 0x0F, 0x77, 0xDE, 0xFA, 0x19, 0x21, 0x02, 0x54, 0x91, 0xA7, 0x60, 0x01, 0x55, 0xB1, 0x99, -0xFF, 0x57, 0xFB, 0x55, 0x8C, 0x8F, 0x62, 0xD0, 0xD9, 0x8D, 0xAF, 0x47, 0x7B, 0x4F, 0xA1, 0x3A, -0xAD, 0x27, 0x4A, 0xD7, 0x18, 0x39, 0xBF, 0xF8, 0x48, 0xC7, 0x2C, 0xED, 0x68, 0x36, 0x9F, 0x6B, -0x9D, 0x54, 0x29, 0x3E, 0x52, 0x20, 0x7E, 0x7A, 0x20, 0x3E, 0xE2, 0x41, 0x08, 0xD9, 0xCE, 0xE1, -0x56, 0xC9, 0x29, 0x46, 0xBB, 0xEF, 0xFF, 0x74, 0xEF, 0xE3, 0x01, 0x04, 0x08, 0xC0, 0x0C, 0xDC, -0xF9, 0x1A, 0x20, 0xCB, 0x1A, 0x1F, 0x85, 0xF4, 0x34, 0xAC, 0x6C, 0xFF, 0xD4, 0x5B, 0xD8, 0xC6, -0x5B, 0x37, 0x1A, 0x9D, 0xAF, 0xDD, 0x98, 0x68, 0x16, 0x69, 0xD6, 0xF1, 0x51, 0xE8, 0x3E, 0x96, -0x46, 0xBC, 0xF5, 0x70, 0x43, 0x7C, 0xE4, 0x31, 0xF1, 0xFB, 0x9D, 0x97, 0x8D, 0x3C, 0x3A, 0x9A, -0xCF, 0x74, 0x8E, 0xCF, 0xBF, 0xEF, 0xBC, 0x7C, 0xAA, 0xF3, 0xB3, 0xFF, 0xEC, 0xE1, 0xDB, 0xCD, -0x2F, 0x77, 0xA3, 0x24, 0x7D, 0x5C, 0xE7, 0xE3, 0x45, 0x08, 0x20, 0x40, 0x00, 0x66, 0x15, 0x20, -0xC7, 0xFD, 0x57, 0xFB, 0x65, 0x8F, 0x8F, 0xE2, 0xEB, 0x15, 0x8B, 0xB7, 0x4F, 0x37, 0x0B, 0xF2, -0x78, 0x7E, 0x0C, 0x4F, 0x33, 0xFB, 0x31, 0x8B, 0xF8, 0x48, 0xCC, 0x82, 0x8C, 0xC6, 0xC7, 0xC1, -0x73, 0xDD, 0xD0, 0x68, 0xBD, 0x18, 0x46, 0xA2, 0x3B, 0x85, 0x47, 0xEB, 0xF9, 0x4E, 0x90, 0x7C, -0xBA, 0xFB, 0xFE, 0x6E, 0x84, 0x3C, 0xE1, 0xF4, 0x00, 0x08, 0x10, 0x80, 0x69, 0x6B, 0xEF, 0xDD, -0x58, 0xF9, 0xF8, 0x48, 0x0E, 0xB7, 0xB0, 0x3D, 0xD1, 0xA0, 0x33, 0x9F, 0xFD, 0x48, 0xD7, 0x51, -0x39, 0xCD, 0xEC, 0xC7, 0xAC, 0xE2, 0xA3, 0x50, 0x5C, 0xF1, 0x7D, 0x45, 0x67, 0x41, 0x06, 0xE2, -0x23, 0xCD, 0x7A, 0x1C, 0x3C, 0x3B, 0xC1, 0x27, 0xB5, 0xBB, 0x33, 0x24, 0x29, 0x56, 0xD2, 0xB1, -0xFB, 0xC4, 0x8F, 0xBE, 0xCD, 0x49, 0x02, 0x10, 0x20, 0x00, 0xD3, 0xD4, 0xBD, 0x7A, 0xF6, 0x6A, -0xC7, 0x47, 0x61, 0xEB, 0x73, 0xE9, 0xA6, 0xB7, 0xC5, 0x5B, 0x8D, 0x93, 0x0C, 0xD8, 0x9F, 0x08, -0xCD, 0xE7, 0x4F, 0x3E, 0xFB, 0x31, 0xEB, 0xF8, 0xC8, 0xE3, 0x72, 0xE6, 0x57, 0x7C, 0xAF, 0x4E, -0x7C, 0x74, 0x67, 0x35, 0x26, 0x97, 0x62, 0xA5, 0x7D, 0x3B, 0xBD, 0xF5, 0x83, 0x4E, 0x12, 0x80, -0x00, 0x01, 0x98, 0x6A, 0x80, 0xEC, 0x6F, 0x8A, 0x8F, 0xDE, 0x5F, 0x4F, 0xF8, 0xB4, 0xA5, 0x78, -0xEB, 0xC6, 0xCD, 0x90, 0x16, 0xF1, 0x9F, 0x74, 0xF6, 0x63, 0x1E, 0xF1, 0x51, 0xE8, 0x3E, 0xB6, -0xCD, 0x78, 0xEB, 0xE1, 0x9B, 0xE2, 0xE3, 0x84, 0xD2, 0x9A, 0x90, 0x34, 0xBB, 0x05, 0x20, 0x40, -0x00, 0xA6, 0x34, 0x50, 0x7B, 0xEA, 0x4D, 0x9B, 0xA1, 0x7D, 0xB0, 0xBA, 0xF1, 0x11, 0x07, 0xBF, -0x74, 0xFE, 0xD7, 0xCE, 0x80, 0xBD, 0xF3, 0x67, 0x23, 0x9B, 0x6C, 0x16, 0xE4, 0xF1, 0x7C, 0xF6, -0xE3, 0x24, 0x57, 0x91, 0x9F, 0x67, 0x7C, 0xE4, 0x81, 0x79, 0x78, 0xC5, 0x77, 0xF1, 0x71, 0xD2, -0x3B, 0xEB, 0xFC, 0xDB, 0x68, 0xBF, 0x54, 0x77, 0xA6, 0x00, 0x04, 0x08, 0xC0, 0xF4, 0xD4, 0xF3, -0xA7, 0xE9, 0xAC, 0x6A, 0x7C, 0x24, 0xB5, 0xEE, 0xDD, 0xF5, 0xEF, 0xB1, 0xB9, 0xD5, 0x79, 0xC9, -0x07, 0xAD, 0x1F, 0x3A, 0xF6, 0x5E, 0xBA, 0xB3, 0x1F, 0xF5, 0x13, 0xCD, 0x7E, 0xCC, 0x3B, 0x3E, -0x0A, 0xDD, 0xC7, 0x58, 0x5F, 0xF6, 0x59, 0x90, 0xA9, 0xC6, 0x47, 0x71, 0x9C, 0xB3, 0xFD, 0xCE, -0xFD, 0xBE, 0xA3, 0xE1, 0x54, 0x01, 0x08, 0x10, 0x80, 0xE9, 0xD8, 0xEC, 0x07, 0xC8, 0x2A, 0xC6, -0xC7, 0xF0, 0xDD, 0x15, 0x6F, 0xA7, 0xC5, 0xDB, 0x31, 0xD4, 0xB3, 0x8F, 0x36, 0x8E, 0x1B, 0xB0, -0x3F, 0x1E, 0xF6, 0x9F, 0x9D, 0x7C, 0xF6, 0xE3, 0xBC, 0xE2, 0x23, 0x49, 0x8F, 0x71, 0xEF, 0xD9, -0xEE, 0x63, 0x16, 0x1F, 0x27, 0x3B, 0xCE, 0xD9, 0x76, 0x37, 0xD4, 0x01, 0x04, 0x08, 0xC0, 0x54, -0x5C, 0xCB, 0x77, 0xFD, 0x59, 0xC5, 0x35, 0x1F, 0xC5, 0x2D, 0x71, 0xB4, 0x4D, 0x62, 0x67, 0xC0, -0x1E, 0xF7, 0x9F, 0x4F, 0x6F, 0x8F, 0x1D, 0xB0, 0x67, 0xB7, 0x6E, 0xBC, 0xBB, 0x73, 0xDC, 0xEA, -0x61, 0xE7, 0x4B, 0x73, 0x78, 0xDC, 0x53, 0x3A, 0xE6, 0x69, 0x16, 0xA4, 0xF3, 0x98, 0xE3, 0xAD, -0x87, 0xDF, 0x2D, 0x3E, 0x4E, 0x70, 0x9C, 0xB3, 0x03, 0x01, 0x02, 0x08, 0x10, 0x80, 0xA9, 0x69, -0xBE, 0x50, 0x5F, 0xC9, 0xF8, 0xA8, 0x8D, 0xC6, 0x47, 0x2C, 0xBE, 0x44, 0xF1, 0xD2, 0x1B, 0xB0, -0xB7, 0x3F, 0xDA, 0x78, 0x6C, 0x28, 0x3E, 0xD2, 0xAE, 0x61, 0x8F, 0xE6, 0x33, 0x0A, 0x77, 0xBA, -0x80, 0xE3, 0xA2, 0xC4, 0x47, 0xFE, 0xE9, 0xED, 0x62, 0x16, 0xE4, 0xD1, 0x4E, 0x84, 0x6C, 0x88, -0x8F, 0x09, 0x8F, 0x73, 0xF7, 0xC2, 0x84, 0x37, 0x9C, 0x2C, 0x00, 0x01, 0x02, 0x30, 0x95, 0xD1, -0x5B, 0xBB, 0xB1, 0x52, 0xF1, 0xD1, 0x8B, 0x8B, 0x38, 0x66, 0x03, 0xAC, 0xEE, 0xAB, 0x5A, 0xE7, -0x7D, 0xBD, 0x97, 0x56, 0x67, 0xE0, 0xB9, 0x9B, 0x22, 0x23, 0x3C, 0xDE, 0xFE, 0xBD, 0xC6, 0x46, -0xE9, 0x83, 0x1F, 0xEB, 0x1C, 0xB7, 0x8D, 0xB8, 0xF7, 0xEC, 0x8C, 0x1F, 0xF7, 0x34, 0x8F, 0x79, -0xEF, 0xB1, 0xEC, 0xFE, 0x59, 0xFA, 0x99, 0xA7, 0xEF, 0xE5, 0x31, 0xF1, 0x71, 0x82, 0xE3, 0xDC, -0xBE, 0xBD, 0xE1, 0x64, 0x01, 0x08, 0x10, 0x80, 0xB3, 0x0E, 0xB5, 0x9E, 0x7A, 0xE3, 0x46, 0xEF, -0xE9, 0x25, 0xAB, 0x11, 0x1F, 0xC7, 0x7D, 0x44, 0x3E, 0x03, 0x52, 0xEB, 0x7F, 0xA9, 0xD8, 0x8B, -0x94, 0x6C, 0xE7, 0xD9, 0x81, 0x01, 0x7B, 0xFB, 0xA3, 0x37, 0x36, 0x62, 0x9A, 0xFD, 0xD8, 0xED, -0xCE, 0x7E, 0xC4, 0x52, 0xD4, 0x2C, 0x7C, 0x7C, 0x74, 0x83, 0x73, 0x69, 0x66, 0x41, 0xE6, 0x16, -0x1F, 0xF9, 0xBB, 0xB2, 0x4D, 0x67, 0x0C, 0x40, 0x80, 0x00, 0x9C, 0xDD, 0xE6, 0xC0, 0x0E, 0x58, -0xCB, 0x1E, 0x1F, 0xC3, 0xEB, 0xCF, 0xE3, 0x60, 0x7C, 0x14, 0x33, 0x23, 0x87, 0x4F, 0xC3, 0x4A, -0x05, 0xD2, 0x89, 0x8C, 0x4E, 0x6C, 0x74, 0xDE, 0x7C, 0xB4, 0xF5, 0xBB, 0x8D, 0x6E, 0x88, 0xA4, -0x20, 0xB9, 0xD3, 0xEC, 0xC7, 0x22, 0xC6, 0x47, 0x21, 0xCD, 0x82, 0x74, 0x2F, 0x3E, 0x59, 0xD9, -0x59, 0x90, 0xB9, 0xC6, 0x47, 0xFE, 0xEE, 0x83, 0xB4, 0x13, 0x96, 0x08, 0x01, 0x04, 0x08, 0xC0, -0xD9, 0x03, 0x64, 0xD2, 0xEB, 0x57, 0x2C, 0xC7, 0xCC, 0xC7, 0x9D, 0xE2, 0xA3, 0xF8, 0xB2, 0xB1, -0xF3, 0x6A, 0x60, 0x16, 0xA4, 0x9D, 0x0F, 0xD8, 0x3F, 0x12, 0x62, 0xED, 0xD1, 0xB4, 0x43, 0x56, -0xCC, 0x17, 0xEE, 0x8F, 0xDE, 0xE7, 0xC2, 0xC7, 0x47, 0x7E, 0x5B, 0xE7, 0xB1, 0xEF, 0x7C, 0x31, -0xBD, 0xF5, 0x78, 0xBC, 0xF5, 0x70, 0x5D, 0x7C, 0x4C, 0x70, 0x9C, 0xB3, 0xBD, 0xF4, 0xBA, 0xEE, -0x94, 0x01, 0x08, 0x10, 0x80, 0xB3, 0xB9, 0x36, 0xD9, 0x0C, 0xC8, 0x12, 0xC4, 0xC7, 0xD8, 0xA7, -0x48, 0x75, 0xC2, 0x63, 0x4C, 0x7C, 0xA4, 0x57, 0x31, 0x94, 0x66, 0x43, 0xD2, 0x2C, 0xC8, 0xCE, -0x97, 0x42, 0xFB, 0xC5, 0xD8, 0x88, 0xCD, 0xE6, 0x46, 0xDC, 0xFB, 0xEA, 0x40, 0xC0, 0x0C, 0xDC, -0x7D, 0xB6, 0xE0, 0xF1, 0x51, 0xD8, 0xEF, 0x5F, 0x3C, 0xB1, 0x52, 0xDB, 0xF2, 0x9E, 0x4B, 0x7C, -0xE4, 0x1F, 0x76, 0xD0, 0x0D, 0x76, 0x00, 0x01, 0x02, 0x70, 0x06, 0xAD, 0xAD, 0x09, 0x06, 0x54, -0xCB, 0xB3, 0xE6, 0x63, 0x64, 0xF6, 0x23, 0xC4, 0x81, 0x2F, 0x55, 0x9E, 0xF9, 0x08, 0xA5, 0x97, -0x7C, 0x16, 0x64, 0xFB, 0xF9, 0x90, 0x6D, 0x35, 0x43, 0xEB, 0xCB, 0x5F, 0xEC, 0x7D, 0x66, 0x6D, -0xF4, 0x4B, 0xC5, 0x8A, 0xC4, 0x47, 0xA1, 0x3B, 0x0B, 0x72, 0xB3, 0x2A, 0xB3, 0x20, 0xE7, 0x16, -0x1F, 0x79, 0x58, 0xE6, 0x33, 0x20, 0xD7, 0x9D, 0x34, 0x00, 0x01, 0x02, 0x70, 0xB6, 0x41, 0x6A, -0x7D, 0x25, 0xE2, 0x23, 0xDD, 0x5C, 0x1B, 0xBD, 0x2D, 0xF6, 0x6E, 0x8C, 0xF1, 0x30, 0x3E, 0x0E, -0xD7, 0x81, 0xD4, 0xBA, 0x8B, 0xD2, 0x7B, 0x1F, 0x9B, 0xBD, 0xD4, 0x09, 0x93, 0x17, 0x3F, 0x17, -0xB2, 0xE7, 0x9E, 0x0F, 0xB1, 0x15, 0x06, 0x67, 0x3E, 0x4A, 0xB3, 0x26, 0x95, 0x89, 0x8F, 0xA4, -0x42, 0xB3, 0x20, 0xE7, 0x1A, 0x1F, 0xFD, 0x08, 0xD9, 0xAD, 0x3B, 0x69, 0x00, 0x02, 0x04, 0xE0, -0x2C, 0x5A, 0x3B, 0xF5, 0xA5, 0x8F, 0x8F, 0xE1, 0xBB, 0x8E, 0x43, 0x33, 0x21, 0xF1, 0xF0, 0x69, -0x57, 0xFD, 0xA7, 0x62, 0xC5, 0xDA, 0xC0, 0xDB, 0xB1, 0xD5, 0x79, 0xD9, 0xE9, 0xBC, 0xDD, 0xDC, -0xEA, 0x1E, 0xB6, 0xAF, 0xC4, 0x7E, 0xA4, 0x1C, 0x5E, 0x3C, 0x64, 0x1A, 0x87, 0x6E, 0x8E, 0xF1, -0x51, 0xD8, 0xFE, 0xD3, 0xF4, 0x7A, 0xA1, 0x67, 0x41, 0x16, 0x22, 0x3E, 0xF2, 0x4F, 0x6B, 0x79, -0x0A, 0x16, 0x20, 0x40, 0x00, 0x4E, 0x3D, 0x04, 0x7B, 0xEA, 0x8D, 0x8D, 0xDE, 0x7F, 0xFD, 0x5E, -0xEE, 0xF8, 0xB8, 0xC3, 0xEC, 0x47, 0x71, 0xC3, 0xE1, 0x4C, 0x46, 0x6D, 0xE0, 0x82, 0x84, 0xF9, -0xD3, 0xAF, 0x5E, 0x1C, 0xBC, 0xFF, 0xB8, 0xDF, 0x7D, 0x29, 0x1E, 0xF7, 0xD8, 0xB5, 0x20, 0x55, -0x88, 0x8F, 0xA4, 0xD9, 0x19, 0xCC, 0x1F, 0xE4, 0x61, 0xF5, 0x21, 0xF1, 0x71, 0x07, 0xD9, 0x7E, -0xDA, 0x09, 0xAB, 0xEE, 0xEC, 0x01, 0x08, 0x10, 0x80, 0xD3, 0xD9, 0x18, 0x1F, 0x20, 0x4B, 0x78, -0x9D, 0x8F, 0x63, 0x66, 0x3F, 0x8A, 0x99, 0x8F, 0x10, 0x4B, 0x97, 0xF3, 0x28, 0xDF, 0x65, 0x3A, -0x44, 0xCD, 0xD1, 0xAF, 0xD1, 0x4E, 0x51, 0x92, 0xC5, 0xC3, 0x59, 0x90, 0xB2, 0xDA, 0x49, 0x0F, -0xC3, 0x39, 0xC5, 0x47, 0x61, 0x37, 0x5F, 0x0B, 0xD2, 0x88, 0xB7, 0x1E, 0x6E, 0x88, 0x8F, 0xE3, -0x02, 0xC4, 0x4E, 0x58, 0x80, 0x00, 0x01, 0x38, 0x8B, 0xCD, 0xD0, 0xDA, 0x5D, 0xFA, 0xF8, 0x38, -0x6A, 0xF6, 0xA3, 0xBF, 0x08, 0x3D, 0x94, 0x9F, 0x86, 0x55, 0x8A, 0x89, 0x22, 0x4A, 0xB6, 0x8F, -0xD8, 0xCE, 0x77, 0x2F, 0xA6, 0xFF, 0x20, 0x5E, 0xFE, 0xD0, 0xC3, 0x59, 0x90, 0x2A, 0xC5, 0x47, -0x92, 0x66, 0x40, 0xD2, 0x4B, 0x8C, 0x0B, 0xB3, 0x16, 0x64, 0xE1, 0xE2, 0x23, 0xBF, 0x8B, 0x7C, -0x27, 0xAC, 0x86, 0x53, 0x07, 0x20, 0x40, 0x00, 0x4E, 0x23, 0x6B, 0x5D, 0xCF, 0xAF, 0x07, 0xB1, -0xCC, 0xF1, 0x11, 0x8F, 0x9A, 0xFD, 0xE8, 0xBE, 0x23, 0x96, 0xAF, 0x60, 0x1E, 0x6B, 0x83, 0xBB, -0x5F, 0xA5, 0x3F, 0x8E, 0x98, 0xFD, 0x28, 0xEE, 0xB4, 0xFD, 0xD5, 0x38, 0x1A, 0x2E, 0xE5, 0xF0, -0x89, 0x33, 0x38, 0x66, 0xD3, 0x8E, 0x8F, 0xC2, 0xEE, 0x33, 0xF9, 0xE0, 0x3A, 0x7E, 0xF4, 0xA1, -0x73, 0x1F, 0x60, 0x2F, 0x64, 0x7C, 0xE4, 0xFF, 0x66, 0xF2, 0x19, 0x90, 0x6B, 0x4E, 0x1E, 0x80, -0x00, 0x01, 0x38, 0x8D, 0x81, 0x05, 0xE8, 0x4B, 0x18, 0x1F, 0x45, 0x04, 0x0C, 0x07, 0xC9, 0x98, -0x40, 0x89, 0xB1, 0x36, 0x70, 0x7B, 0x7F, 0x46, 0x64, 0x3B, 0x1E, 0xFB, 0xB8, 0xD3, 0x7F, 0x10, -0xCF, 0xB6, 0x0F, 0x1F, 0xD1, 0xC9, 0x66, 0x41, 0x16, 0x28, 0x3E, 0xD2, 0x63, 0x49, 0x33, 0x20, -0xCD, 0x7C, 0xA0, 0x7F, 0xAE, 0xB3, 0x20, 0x0B, 0x1B, 0x1F, 0xFD, 0x08, 0xD9, 0xAF, 0x3B, 0x79, -0x00, 0x02, 0x04, 0xE0, 0x74, 0x03, 0xA9, 0xCD, 0xA5, 0x8E, 0x8F, 0x78, 0xE7, 0x9D, 0xAF, 0x62, -0xB9, 0x1C, 0x86, 0x17, 0x91, 0xEF, 0xA7, 0x41, 0x79, 0xBC, 0xE3, 0xE3, 0xCE, 0xB7, 0xE7, 0x3D, -0x6E, 0x16, 0xA4, 0x0A, 0xF1, 0x51, 0xD8, 0xC9, 0x77, 0xC4, 0x4A, 0xB3, 0x20, 0x37, 0xC5, 0xC7, -0x51, 0xDA, 0x0D, 0x27, 0x0F, 0x40, 0x80, 0x00, 0x9C, 0x74, 0x58, 0xF6, 0xD4, 0x1B, 0xEB, 0xDD, -0xA7, 0x5F, 0x2D, 0x69, 0x7C, 0x1C, 0x15, 0x24, 0x61, 0x30, 0x44, 0x06, 0xD7, 0x83, 0x0C, 0xC5, -0xC8, 0x76, 0x9C, 0xE8, 0x71, 0xA7, 0x6B, 0x82, 0x14, 0xB3, 0x20, 0xFD, 0x47, 0x38, 0x70, 0x55, -0xF5, 0x8A, 0xC4, 0x47, 0x5E, 0x53, 0xCD, 0xEE, 0xB5, 0x41, 0xCE, 0x61, 0x16, 0xA4, 0x1A, 0xF1, -0x91, 0xFA, 0x63, 0xDB, 0x4E, 0x58, 0x80, 0x00, 0x01, 0x38, 0x85, 0x7A, 0x68, 0x6D, 0x2D, 0x67, -0x7C, 0x94, 0x76, 0xB4, 0x1A, 0x78, 0xBB, 0xFC, 0xF7, 0x71, 0xB3, 0x1F, 0xE5, 0x19, 0x93, 0x34, -0xFB, 0xD1, 0x9E, 0xFC, 0x71, 0x17, 0xB3, 0x20, 0xF1, 0x8E, 0xB3, 0x20, 0x0B, 0x1C, 0x1F, 0x85, -0xEE, 0x8E, 0x58, 0xF5, 0x79, 0xCE, 0x82, 0x54, 0x26, 0x3E, 0xF2, 0x3D, 0x99, 0x0F, 0xBA, 0xFF, -0x7E, 0x00, 0x04, 0x08, 0xC0, 0x89, 0x46, 0x52, 0x8D, 0xD0, 0x6E, 0x2E, 0x5F, 0x7C, 0x84, 0xD1, -0xC1, 0x7F, 0xEC, 0x7D, 0xED, 0x71, 0xB3, 0x1C, 0x47, 0x4E, 0x50, 0xEC, 0xC4, 0x13, 0x3D, 0xEE, -0x7C, 0x16, 0xE4, 0xA5, 0xC1, 0xBB, 0x1F, 0x88, 0x9A, 0x58, 0x91, 0xF8, 0xC8, 0x6B, 0x6A, 0xBE, -0xB3, 0x20, 0x95, 0x8A, 0x8F, 0xFC, 0xCF, 0x3C, 0x40, 0x5C, 0x90, 0x10, 0x10, 0x20, 0x00, 0x27, -0x74, 0xDF, 0xD1, 0x17, 0x21, 0xAC, 0x70, 0x7C, 0x0C, 0xAF, 0xE3, 0xE8, 0x0D, 0xFC, 0x63, 0xA8, -0x0D, 0xCC, 0x7C, 0x94, 0x2F, 0x3A, 0x38, 0x32, 0x4B, 0x52, 0x9E, 0xFD, 0x38, 0xC1, 0xE3, 0x6E, -0xDF, 0x8E, 0xBD, 0x67, 0xB5, 0x95, 0x66, 0x41, 0x6A, 0x53, 0x1C, 0x14, 0xCF, 0x23, 0x3E, 0x0A, -0x69, 0x16, 0x24, 0xB6, 0x67, 0x3E, 0x0B, 0x52, 0xB9, 0xF8, 0xC8, 0x7F, 0xD0, 0xF9, 0xF3, 0xED, -0xEC, 0x84, 0x05, 0x08, 0x10, 0x80, 0x13, 0x69, 0x6D, 0x9D, 0xF2, 0xBF, 0xE0, 0x56, 0x2B, 0x3E, -0x62, 0x88, 0x63, 0x9F, 0x92, 0xD5, 0xBF, 0x79, 0x60, 0x1B, 0xDE, 0xCE, 0x4B, 0xD6, 0x79, 0xD9, -0x8A, 0xA7, 0x7B, 0xDC, 0x9D, 0xCF, 0xCD, 0xFA, 0xCF, 0x6A, 0xAB, 0x95, 0xBE, 0x5E, 0x1C, 0xFC, -0xDA, 0x8B, 0x1E, 0x1F, 0xF9, 0xF7, 0xD2, 0x89, 0xD3, 0xBD, 0x67, 0xD3, 0x5B, 0x4F, 0x74, 0x22, -0x64, 0x43, 0x7C, 0x0C, 0x1F, 0x9F, 0x7D, 0x33, 0x20, 0x80, 0x00, 0x01, 0x38, 0xD9, 0x60, 0xB9, -0x75, 0x8A, 0x01, 0x54, 0x85, 0x16, 0x9C, 0x1F, 0x16, 0x48, 0x77, 0xF6, 0x23, 0x0C, 0x46, 0x47, -0x7F, 0xD7, 0xAA, 0xE1, 0x87, 0xB9, 0x5B, 0x2E, 0x93, 0x93, 0x2B, 0x66, 0x41, 0x62, 0x2C, 0x05, -0x50, 0x6D, 0x06, 0x03, 0xE0, 0x79, 0x1C, 0xCF, 0xBD, 0x3F, 0x4B, 0xB3, 0x20, 0x29, 0x3E, 0x1E, -0x13, 0x1F, 0xC3, 0xB7, 0xB7, 0x04, 0x08, 0x20, 0x40, 0x00, 0x26, 0x1E, 0x53, 0x3D, 0xF5, 0x86, -0x8D, 0xD0, 0xDE, 0x3F, 0xE1, 0x7F, 0xD5, 0xAE, 0x46, 0x7C, 0x94, 0x2F, 0x34, 0x38, 0x6E, 0xDB, -0xDD, 0xC3, 0x1B, 0x6B, 0xA3, 0x3B, 0x54, 0x65, 0x45, 0x80, 0x9C, 0xE1, 0x71, 0x77, 0xEE, 0xA3, -0xFD, 0x52, 0x3C, 0x7C, 0x2C, 0xE3, 0xB6, 0xF7, 0x8D, 0xF3, 0x3A, 0x86, 0x67, 0xFD, 0xF9, 0xB5, -0x8B, 0x59, 0x90, 0x47, 0xA7, 0x39, 0x0B, 0x52, 0xF9, 0xF8, 0xC8, 0x7F, 0xCE, 0xFB, 0x1B, 0xF1, -0x13, 0xEF, 0xD8, 0x70, 0x36, 0x01, 0x04, 0x08, 0xC0, 0x64, 0x36, 0x43, 0x7B, 0x77, 0xB9, 0xE2, -0x23, 0x8E, 0xF9, 0xCB, 0xF0, 0x16, 0xBB, 0x21, 0x8C, 0xDD, 0xA9, 0x6A, 0x60, 0xF6, 0x23, 0x3B, -0xFB, 0x60, 0x36, 0xBB, 0x9D, 0xD6, 0x29, 0xC7, 0xC1, 0xF0, 0x38, 0x4D, 0x84, 0x9C, 0x67, 0x7C, -0x14, 0xA6, 0x3C, 0x0B, 0xB2, 0x14, 0xF1, 0x91, 0xBF, 0xBF, 0xD9, 0xFD, 0x77, 0x04, 0x20, 0x40, -0x00, 0x26, 0xD2, 0xBB, 0x06, 0xC8, 0x92, 0xC4, 0xC7, 0xC0, 0x67, 0xC6, 0x23, 0xB7, 0xDD, 0x1D, -0x89, 0x8E, 0x91, 0xD9, 0x8F, 0x6C, 0x6A, 0x03, 0xFE, 0xF6, 0x71, 0xDB, 0xF2, 0xCE, 0xFC, 0x18, -0x4E, 0x71, 0x80, 0x9E, 0x7E, 0x4F, 0xF2, 0x6D, 0x79, 0xE3, 0xA3, 0xF1, 0xA3, 0xAF, 0x3B, 0xD3, -0x7F, 0xF1, 0x5F, 0x9A, 0xF8, 0xC8, 0x7F, 0x5F, 0xF6, 0x05, 0x08, 0x20, 0x40, 0x00, 0x4E, 0x14, -0x20, 0x07, 0x93, 0x5C, 0x03, 0xA4, 0x22, 0xF1, 0x91, 0x3E, 0xAD, 0x36, 0xF4, 0xF9, 0xE5, 0xB5, -0x1F, 0xA5, 0x87, 0x76, 0xE4, 0xEC, 0xC7, 0x56, 0xD6, 0x8D, 0x90, 0x29, 0x0D, 0xF8, 0xD3, 0x85, -0x09, 0xD3, 0xD6, 0xBC, 0xA5, 0x06, 0x1A, 0x9D, 0x05, 0x59, 0xF4, 0xF8, 0x28, 0xA4, 0x59, 0x90, -0xAC, 0x99, 0xE2, 0xE3, 0x09, 0xF1, 0x51, 0x04, 0xC8, 0x5E, 0x7A, 0x6D, 0x27, 0x2C, 0x40, 0x80, -0x00, 0x4C, 0xA4, 0xBD, 0x77, 0x63, 0x69, 0xE2, 0xA3, 0xFF, 0xA5, 0xCB, 0x4F, 0xBB, 0x2A, 0x45, -0x48, 0xF9, 0x42, 0x83, 0xE5, 0x87, 0x59, 0x5E, 0xEA, 0xD1, 0xEE, 0xBC, 0xB1, 0x37, 0x8D, 0x01, -0xED, 0xE0, 0x7D, 0x14, 0x17, 0x27, 0x0C, 0x47, 0xCD, 0x82, 0xC4, 0x0A, 0xC4, 0x47, 0x71, 0x3F, -0x3B, 0x69, 0x5B, 0xDE, 0x70, 0x33, 0xFE, 0xDE, 0xEB, 0xEA, 0x2B, 0x1F, 0x1F, 0xF9, 0xC7, 0xA6, -0x9D, 0x06, 0xDA, 0x66, 0x40, 0x00, 0x01, 0x02, 0x30, 0x59, 0x80, 0x34, 0x37, 0x96, 0x26, 0x3E, -0xF2, 0xD9, 0x8F, 0x38, 0x72, 0x5B, 0x79, 0xED, 0xC7, 0xE1, 0xCE, 0x57, 0xB5, 0xD1, 0x87, 0x99, -0x6E, 0xD8, 0x9E, 0x7E, 0x7C, 0xE4, 0x01, 0x92, 0x66, 0x41, 0xF6, 0x87, 0x3E, 0xE2, 0xB8, 0x59, -0x90, 0x45, 0x8D, 0x8F, 0xF4, 0x47, 0xBA, 0x30, 0x61, 0xF7, 0xBA, 0x31, 0x27, 0xBA, 0x38, 0xE1, -0x52, 0xC6, 0x47, 0xFF, 0x07, 0xBC, 0x5B, 0x77, 0x32, 0x01, 0x04, 0x08, 0xC0, 0x44, 0x03, 0xA7, -0xE3, 0xAE, 0x61, 0x50, 0xBD, 0xAD, 0x76, 0x63, 0x2C, 0x87, 0x47, 0xB9, 0x3A, 0xC6, 0xAC, 0xF5, -0x18, 0x78, 0xC8, 0xB1, 0xFB, 0xB4, 0xAB, 0xBD, 0x29, 0x6C, 0xF7, 0x7B, 0x54, 0xEB, 0xBD, 0xD8, -0x5B, 0x93, 0x32, 0x6E, 0x16, 0xA4, 0x56, 0xFA, 0xD4, 0x45, 0x8E, 0x8F, 0xDE, 0x63, 0x8D, 0xBB, -0x5F, 0x4C, 0x7F, 0xBD, 0x99, 0xFD, 0xEE, 0x64, 0xB3, 0x20, 0x4B, 0x1D, 0x1F, 0xF9, 0xBF, 0xA3, -0xA6, 0x00, 0x01, 0x04, 0x08, 0xC0, 0x1D, 0xC7, 0x5A, 0x4F, 0xBD, 0x61, 0x33, 0x64, 0x07, 0xCB, -0x11, 0x1F, 0x71, 0xCC, 0x35, 0x36, 0x86, 0x77, 0xBE, 0x8A, 0x43, 0xB3, 0x1F, 0xE5, 0x05, 0x19, -0xE9, 0xCF, 0xED, 0xD9, 0xC5, 0x47, 0xFE, 0xDE, 0xFD, 0x62, 0xBD, 0xF2, 0x98, 0xB5, 0x20, 0x55, -0x8A, 0x8F, 0x62, 0x16, 0xE4, 0x60, 0x2B, 0xDD, 0x7C, 0xC7, 0xB5, 0x20, 0x4B, 0x1F, 0x1F, 0xF9, -0xE7, 0x36, 0x3B, 0xDF, 0xE7, 0x3B, 0x1A, 0xCE, 0x2A, 0x80, 0x00, 0x01, 0x38, 0xDE, 0xC6, 0xF8, -0x2D, 0x78, 0x2B, 0x78, 0x91, 0xC1, 0x81, 0x41, 0xFC, 0x11, 0xB3, 0x1F, 0x63, 0x3F, 0xB3, 0xF7, -0x8E, 0xD4, 0x61, 0x7B, 0xB3, 0xFF, 0x1E, 0xD2, 0x2C, 0xC8, 0xD1, 0x6B, 0x41, 0x2A, 0x12, 0x1F, -0xC5, 0x31, 0x4E, 0x3B, 0x62, 0xC5, 0xDA, 0xDB, 0xDA, 0xBF, 0xF3, 0x50, 0x63, 0xA5, 0xE3, 0x23, -0xE9, 0x96, 0x65, 0xDD, 0x29, 0x05, 0x10, 0x20, 0x00, 0xC7, 0x6B, 0x84, 0xD6, 0x6E, 0xF5, 0xE3, -0xA3, 0xBF, 0xF3, 0xD5, 0xF0, 0xCD, 0xC7, 0xCF, 0x7E, 0xE4, 0x8B, 0xD5, 0x8B, 0xA9, 0x88, 0xED, -0xF9, 0x7C, 0x0F, 0xF9, 0x2C, 0xC8, 0xEE, 0x40, 0x1B, 0xF5, 0x5F, 0x4D, 0x67, 0x68, 0x3D, 0xA7, -0xF8, 0x48, 0x7F, 0x36, 0xB7, 0xBB, 0xB3, 0x20, 0x71, 0xFC, 0x5A, 0x90, 0x95, 0x89, 0x8F, 0x3C, -0x40, 0x9A, 0x02, 0x04, 0x10, 0x20, 0x00, 0x13, 0xB8, 0x36, 0x78, 0x0D, 0x90, 0x6A, 0xCE, 0x7C, -0x0C, 0x3C, 0x8C, 0x09, 0x67, 0x3F, 0x06, 0x86, 0xFB, 0x69, 0xF6, 0xE3, 0x20, 0xCE, 0xED, 0x7B, -0xC8, 0x5E, 0x18, 0x9E, 0x05, 0xA9, 0xD8, 0xCC, 0x47, 0xE8, 0x3E, 0xF6, 0xBC, 0xDF, 0xBA, 0x3B, -0x62, 0x35, 0x0E, 0x7E, 0x7B, 0x70, 0x16, 0x64, 0xA5, 0xE2, 0x23, 0xBF, 0x9F, 0xFC, 0xA9, 0x8C, -0x37, 0x9C, 0x52, 0x00, 0x01, 0x02, 0x70, 0x9C, 0xE6, 0x0B, 0xF5, 0x65, 0x88, 0x8F, 0x93, 0xCF, -0x7E, 0x94, 0x66, 0x3E, 0xCE, 0x34, 0xFB, 0x71, 0xBA, 0xCF, 0x4B, 0xD7, 0x04, 0x49, 0xBB, 0x62, -0x95, 0x1A, 0x69, 0xF2, 0xEB, 0x82, 0x2C, 0x52, 0x7C, 0xA4, 0x97, 0xE6, 0x56, 0xC8, 0x9A, 0x69, -0x16, 0xA4, 0xF6, 0xF8, 0xCA, 0xC6, 0x47, 0xA1, 0xBD, 0x55, 0x77, 0x52, 0x01, 0x16, 0xCD, 0xBA, -0x43, 0x00, 0x2C, 0x94, 0x98, 0x35, 0x2A, 0x1F, 0x1F, 0xC3, 0xD7, 0xFA, 0x28, 0x7F, 0xC8, 0xF0, -0xEC, 0x47, 0x2F, 0x3E, 0x06, 0xBE, 0xFA, 0xA9, 0x67, 0x3F, 0xCE, 0xF6, 0x3D, 0xA4, 0xEB, 0x82, -0xAC, 0xDD, 0x53, 0x6A, 0xA7, 0xDA, 0x22, 0x0C, 0xD0, 0x4F, 0x16, 0x1F, 0xC5, 0xF1, 0xCD, 0xB6, -0xBE, 0x10, 0x6A, 0xF7, 0x3D, 0xD8, 0xD8, 0xFF, 0xDF, 0x1F, 0x6E, 0x5C, 0xFA, 0xD6, 0x6F, 0x7C, -0x61, 0x25, 0xE3, 0xA3, 0x5B, 0x96, 0x02, 0x04, 0x58, 0x38, 0x66, 0x40, 0x80, 0xC5, 0x69, 0x8F, -0xA7, 0xDE, 0xB0, 0xD1, 0x7D, 0xDE, 0x7A, 0x85, 0xE3, 0x63, 0xDC, 0xC0, 0x7D, 0xF8, 0xAA, 0xE7, -0xE5, 0xD9, 0x8F, 0xF2, 0x00, 0xBB, 0x78, 0xB9, 0x9D, 0x9D, 0xC3, 0xF7, 0xD0, 0x19, 0xB4, 0x77, -0xA2, 0xA7, 0x7D, 0x7B, 0xE8, 0x1E, 0x4F, 0x35, 0x0B, 0x72, 0xCE, 0xF1, 0x91, 0x75, 0x6E, 0x3B, -0xD8, 0x0D, 0xD9, 0xEE, 0xF3, 0x21, 0x5C, 0xB9, 0xF8, 0xA1, 0x95, 0x8D, 0x8F, 0xFC, 0x7E, 0xD3, -0x4E, 0x58, 0x3F, 0xE2, 0x82, 0x84, 0x80, 0x00, 0x01, 0x38, 0x62, 0x10, 0xB6, 0x39, 0xBA, 0x00, -0xBD, 0x62, 0xF1, 0x11, 0x8F, 0x5E, 0xFB, 0xD1, 0x7F, 0x8A, 0x50, 0x3F, 0x38, 0xE2, 0xE8, 0xB5, -0x40, 0xD2, 0xAE, 0x57, 0xED, 0xF9, 0x0F, 0x8A, 0x8B, 0x2B, 0xB5, 0xE7, 0x3B, 0x62, 0xB5, 0x8F, -0xB8, 0x2E, 0x48, 0x55, 0xE2, 0x23, 0xBD, 0x9D, 0x37, 0xDC, 0x76, 0xB8, 0xF4, 0x1F, 0x7E, 0x6D, -0x7D, 0x65, 0xE3, 0x23, 0x3D, 0xDE, 0xF6, 0x4E, 0x7A, 0xA3, 0xEE, 0xE4, 0x02, 0x08, 0x10, 0x80, -0xF1, 0x36, 0x7B, 0x3B, 0xF7, 0x54, 0x33, 0x3E, 0x8E, 0xF8, 0x90, 0xE1, 0xB5, 0x1F, 0xA1, 0xB4, -0xDC, 0x63, 0xE4, 0xEE, 0x76, 0xE2, 0x9C, 0xBF, 0x87, 0xC3, 0xF8, 0xC8, 0x75, 0x06, 0xEE, 0xC5, -0x2C, 0xC8, 0xC0, 0x5A, 0x90, 0x38, 0xC9, 0x57, 0x5A, 0x9C, 0xF8, 0xA8, 0xDD, 0x73, 0x6F, 0xB8, -0xFC, 0xED, 0xDF, 0x19, 0xC2, 0x85, 0xCE, 0xFF, 0xCD, 0xAD, 0x6A, 0x7C, 0xE4, 0x3F, 0xCF, 0x66, -0xF7, 0xDF, 0x15, 0x80, 0x00, 0x01, 0x18, 0xEB, 0x88, 0x6B, 0x80, 0x54, 0x20, 0x3E, 0xCA, 0x83, -0xF4, 0x81, 0x01, 0x7B, 0x6D, 0x60, 0xED, 0x47, 0x2C, 0x1E, 0x77, 0xF9, 0x62, 0x7F, 0xA7, 0x9E, -0xFD, 0x98, 0x72, 0x7C, 0xF4, 0xB4, 0x6F, 0x77, 0x67, 0x41, 0x06, 0xAE, 0x0B, 0x52, 0x9B, 0xFD, -0x63, 0x99, 0x6A, 0x7C, 0x5C, 0xFF, 0xDE, 0x50, 0x5B, 0xBF, 0xB8, 0xDA, 0xF1, 0x91, 0xBF, 0x99, -0xEF, 0x84, 0x75, 0xDD, 0xA9, 0x05, 0x10, 0x20, 0x00, 0xE3, 0xB4, 0xB6, 0x26, 0xDF, 0x32, 0x74, -0x91, 0x67, 0x3E, 0x6A, 0x83, 0x17, 0x33, 0x2F, 0x07, 0x4A, 0xB1, 0xE0, 0x7C, 0x64, 0xA7, 0xDB, -0x13, 0xCF, 0x7E, 0xCC, 0x26, 0x3E, 0x72, 0xA5, 0x59, 0x90, 0x50, 0xCC, 0xDE, 0x1C, 0x3B, 0x0B, -0x22, 0x3E, 0x16, 0x32, 0x3E, 0xFA, 0x45, 0xB9, 0x53, 0x77, 0x72, 0x01, 0x04, 0x08, 0xC0, 0xF8, -0x41, 0x59, 0x7D, 0xC2, 0x8F, 0x5B, 0xAC, 0xF8, 0x18, 0x5E, 0xA8, 0xDD, 0xFF, 0x7B, 0x6D, 0x60, -0xE6, 0x23, 0xF6, 0x9F, 0x7B, 0x55, 0x1B, 0xDD, 0x0D, 0x6B, 0xE7, 0x24, 0xB3, 0x1F, 0x33, 0x8C, -0x8F, 0x62, 0xCC, 0x9A, 0x66, 0x41, 0x0E, 0x4A, 0x03, 0xFD, 0x5E, 0x10, 0x88, 0x8F, 0x8A, 0xC5, -0x47, 0xF7, 0xA7, 0xE9, 0x29, 0x58, 0x80, 0x00, 0x01, 0x18, 0x3F, 0x4E, 0x9A, 0xE0, 0xBF, 0xD4, -0x56, 0x20, 0x3E, 0x46, 0x66, 0x0C, 0xCA, 0x0B, 0xCE, 0xC3, 0xE1, 0x62, 0xF4, 0xFE, 0x27, 0x66, -0xE1, 0x04, 0xB3, 0x1F, 0xB3, 0x8F, 0x8F, 0x5C, 0x96, 0xC6, 0xEF, 0x71, 0x20, 0xA4, 0x46, 0xBF, -0x57, 0xF1, 0xB1, 0xF8, 0xF1, 0x91, 0x7E, 0x96, 0x7B, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xC0, 0xC8, -0xF0, 0xE9, 0xC9, 0x47, 0x1A, 0xA1, 0xDD, 0xAC, 0x56, 0x7C, 0x1C, 0xF3, 0xA1, 0xFD, 0x6D, 0x77, -0x63, 0x77, 0xE6, 0xE3, 0x70, 0xF0, 0x5C, 0x1B, 0xBD, 0xCB, 0xDD, 0x38, 0xE1, 0xDD, 0xCF, 0x29, -0x3E, 0x8A, 0x71, 0xEB, 0x76, 0xDA, 0x9A, 0x77, 0xA8, 0x0F, 0xE2, 0xD0, 0xFD, 0x9C, 0xF9, 0x21, -0x89, 0x8F, 0x99, 0xC6, 0x47, 0x1E, 0xF6, 0x7B, 0xE9, 0xF5, 0x86, 0xB3, 0x0C, 0x20, 0x40, 0x00, -0x06, 0x6D, 0x1C, 0xBB, 0x03, 0xD6, 0x02, 0xC7, 0xC7, 0x51, 0x17, 0x1D, 0xEC, 0x0E, 0x9A, 0xCB, -0x37, 0xD6, 0x06, 0x67, 0x3F, 0xF2, 0x51, 0x7E, 0x98, 0x70, 0xF6, 0x63, 0xBE, 0xF1, 0xD1, 0x1F, -0xBB, 0xBE, 0x18, 0xFB, 0xD7, 0x2C, 0xE9, 0x3F, 0x04, 0x33, 0x1F, 0xD5, 0x89, 0x8F, 0xFC, 0x43, -0xF2, 0x85, 0xE8, 0x0D, 0xA7, 0x18, 0x40, 0x80, 0x00, 0x0C, 0xDA, 0x3C, 0x72, 0x07, 0xAC, 0x45, -0x8D, 0x8F, 0x38, 0xFE, 0xB6, 0xD8, 0x0B, 0x8D, 0xF2, 0x75, 0x3E, 0x46, 0xAE, 0xAB, 0x71, 0xA2, -0xD9, 0x8F, 0xF3, 0x89, 0x8F, 0xBC, 0x8F, 0xB6, 0xF3, 0x6B, 0xD9, 0xF5, 0x1F, 0x45, 0x39, 0xA8, -0xE2, 0x34, 0x8E, 0xAB, 0xF8, 0x98, 0xFD, 0xE3, 0xCD, 0xF2, 0x19, 0x90, 0x6B, 0x4E, 0x31, 0x80, -0x00, 0x01, 0x18, 0x18, 0x24, 0xB5, 0xAE, 0x77, 0xF7, 0x7E, 0xAD, 0x48, 0x7C, 0x0C, 0x7F, 0xC4, -0xC8, 0x8E, 0x57, 0x71, 0xE4, 0xB3, 0x47, 0x66, 0x3F, 0xD2, 0xB7, 0xBB, 0x1D, 0x67, 0xFC, 0x3D, -0x9C, 0x3E, 0x3E, 0xFA, 0x0F, 0xF3, 0xAB, 0xDD, 0x59, 0x90, 0x7C, 0xB6, 0x26, 0x4E, 0xE3, 0x21, -0x8A, 0x8F, 0xB9, 0xC5, 0x47, 0xFF, 0x87, 0x68, 0x27, 0x2C, 0x40, 0x80, 0x00, 0x0C, 0x6A, 0x6D, -0x6D, 0x54, 0x2A, 0x3E, 0x62, 0x18, 0xDD, 0x15, 0xAA, 0x3F, 0xD3, 0x11, 0x4B, 0x7F, 0x3F, 0x66, -0xF6, 0xA3, 0x02, 0xF1, 0x91, 0xB7, 0xE1, 0x7E, 0xE7, 0x7E, 0xF6, 0xE2, 0xE0, 0xA3, 0x3A, 0xF5, -0x2C, 0x88, 0xF8, 0x98, 0x7B, 0x7C, 0x74, 0x35, 0x9C, 0x64, 0x00, 0x01, 0x02, 0x30, 0x30, 0xA6, -0x3A, 0x68, 0x54, 0x26, 0x3E, 0x86, 0x1F, 0x62, 0x1C, 0xDC, 0x19, 0x6A, 0xDC, 0x43, 0x2F, 0x0F, -0xA8, 0x73, 0x69, 0xF6, 0x63, 0x2F, 0x2E, 0x7C, 0x7C, 0x14, 0x8F, 0x25, 0xAD, 0x05, 0x09, 0xE3, -0x62, 0xAA, 0x17, 0x11, 0x27, 0x5A, 0x44, 0x2F, 0x3E, 0xE6, 0xFF, 0x78, 0xB3, 0xED, 0xB4, 0x13, -0x56, 0xDD, 0x89, 0x06, 0x10, 0x20, 0x00, 0x21, 0xDF, 0x01, 0xAB, 0x9E, 0x8F, 0x2E, 0xAB, 0x12, -0x1F, 0x47, 0xCE, 0x7E, 0x0C, 0xAE, 0xD3, 0x2E, 0x66, 0x3F, 0x46, 0xBE, 0x9D, 0xF4, 0xF7, 0xED, -0xEA, 0xC4, 0x47, 0x3E, 0x7E, 0xDD, 0xEF, 0xBE, 0x14, 0xB7, 0x0C, 0xEE, 0x88, 0x25, 0x3E, 0x16, -0x3A, 0x3E, 0xF2, 0x1F, 0x60, 0xBE, 0x10, 0x5D, 0x80, 0x00, 0x02, 0x04, 0xA0, 0xA7, 0x1E, 0x0E, -0xB6, 0xAA, 0x11, 0x1F, 0xC3, 0x63, 0xCC, 0xFE, 0xE0, 0x39, 0x1E, 0x5E, 0xFB, 0xE3, 0xA8, 0xCB, -0x85, 0x14, 0xB7, 0xB7, 0xC2, 0x31, 0xB3, 0x1F, 0x8B, 0x17, 0x1F, 0x85, 0xD6, 0xF3, 0xF1, 0x70, -0x2B, 0xE1, 0x13, 0xCD, 0x82, 0x88, 0x8F, 0x73, 0x8D, 0x8F, 0xFC, 0xD3, 0xED, 0x84, 0x05, 0x08, -0x10, 0x80, 0xB2, 0x46, 0xBE, 0x05, 0x6F, 0x15, 0xE2, 0x63, 0xEC, 0xEC, 0x47, 0xEC, 0xEE, 0x7C, -0x35, 0x34, 0x0E, 0xED, 0xCF, 0x7E, 0x94, 0x9F, 0x7A, 0x95, 0xFE, 0xDC, 0xAA, 0x5E, 0x7C, 0xE4, -0xB7, 0xB4, 0xBA, 0xBB, 0x62, 0x85, 0x70, 0x92, 0x59, 0x10, 0xF1, 0x71, 0xEE, 0xF1, 0x91, 0xB4, -0xF3, 0x1F, 0x9C, 0x9D, 0xB0, 0x00, 0x01, 0x02, 0xD0, 0x73, 0x5F, 0x68, 0xEF, 0x2F, 0x7E, 0x7C, -0x0C, 0x8F, 0x33, 0xCB, 0xD7, 0xF9, 0xB8, 0xD3, 0xEC, 0x47, 0x21, 0xFD, 0x87, 0xE8, 0x83, 0x38, -0x83, 0xEF, 0x61, 0xB6, 0xF1, 0xD1, 0x1F, 0xC7, 0xBE, 0x74, 0x87, 0x59, 0x10, 0xF1, 0xB1, 0x78, -0xF1, 0x51, 0xC8, 0xF6, 0xEB, 0x4E, 0x35, 0x80, 0x00, 0x01, 0x48, 0x5A, 0x5B, 0x9B, 0x55, 0x89, -0x8F, 0x81, 0x41, 0x76, 0x71, 0x9D, 0x8F, 0x49, 0x66, 0x3F, 0x8A, 0x97, 0xED, 0xEA, 0xC6, 0x47, -0xFE, 0xDE, 0xD2, 0x2C, 0x48, 0xFF, 0xA3, 0xCB, 0xB3, 0x20, 0x51, 0x7C, 0x2C, 0x64, 0x7C, 0x74, -0x7F, 0x78, 0x9B, 0x4E, 0x36, 0x80, 0x00, 0x01, 0x48, 0xB2, 0xD3, 0x0E, 0x8C, 0xE6, 0x1C, 0x1F, -0xE5, 0x19, 0x8E, 0xF2, 0x75, 0x3E, 0xC6, 0xCD, 0x7E, 0xC4, 0x30, 0xB8, 0x3B, 0x56, 0x32, 0x76, -0xF6, 0xA3, 0x3A, 0xF1, 0x51, 0xC8, 0x67, 0x41, 0xDA, 0xC7, 0xEC, 0x88, 0x25, 0x3E, 0x16, 0x2F, -0x3E, 0xF2, 0x7F, 0x67, 0x3B, 0x1B, 0xF1, 0x13, 0x3F, 0xBC, 0xE1, 0x84, 0x03, 0x08, 0x10, 0x80, -0xF6, 0xDE, 0x29, 0x06, 0x45, 0x73, 0x8E, 0x8F, 0xFE, 0xE0, 0x3A, 0x0C, 0x2E, 0x38, 0x1F, 0x7A, -0xDE, 0x51, 0x7F, 0xF6, 0x63, 0x28, 0x44, 0xC6, 0xCF, 0x7E, 0x54, 0x2F, 0x3E, 0xF2, 0x8F, 0x6C, -0x75, 0x7E, 0x64, 0x5B, 0x83, 0xDF, 0xDE, 0x61, 0x84, 0xC5, 0xC1, 0x35, 0x2F, 0xE2, 0x63, 0x71, -0x1E, 0x6F, 0x96, 0x5F, 0xD2, 0xDE, 0x2C, 0x08, 0x20, 0x40, 0x80, 0xD5, 0x16, 0x9F, 0x7C, 0xA4, -0x11, 0xDA, 0xBB, 0x8B, 0x1F, 0x1F, 0xFD, 0x01, 0x73, 0x1C, 0xB9, 0xEA, 0x79, 0x2C, 0x6F, 0xC1, -0x3B, 0xBC, 0x1E, 0xA4, 0xF8, 0xC0, 0xB4, 0xEB, 0xD5, 0x41, 0xAC, 0x7C, 0x7C, 0xF4, 0x9B, 0xF1, -0x76, 0x77, 0x16, 0x64, 0x60, 0x2D, 0x48, 0xCD, 0xCC, 0xC7, 0xC2, 0xC6, 0x47, 0x7E, 0xB0, 0x0F, -0x04, 0x08, 0x20, 0x40, 0x00, 0x42, 0xDA, 0x82, 0x37, 0x1F, 0xC9, 0x2E, 0x70, 0x7C, 0x8C, 0x1B, -0x74, 0x8E, 0x59, 0xFB, 0x31, 0xF6, 0xB6, 0xE2, 0x4B, 0xEE, 0x2C, 0x4F, 0x7C, 0xE4, 0xB2, 0x14, -0x21, 0xE5, 0x7B, 0x89, 0x23, 0x4F, 0x3B, 0x2B, 0xAF, 0x81, 0x11, 0x1F, 0xE7, 0x1C, 0x1F, 0xF9, -0xCF, 0x6C, 0x2F, 0xBD, 0xB6, 0x13, 0x16, 0x20, 0x40, 0x00, 0x01, 0xD2, 0xBF, 0x06, 0xC8, 0x22, -0xC6, 0xC7, 0x98, 0xA7, 0x16, 0x75, 0xEF, 0xA5, 0x36, 0x30, 0xD3, 0x31, 0x30, 0xFB, 0x11, 0xC6, -0xCC, 0x7E, 0xB4, 0x97, 0x28, 0x3E, 0x7A, 0xDA, 0x5B, 0xC5, 0x5A, 0x90, 0x30, 0xB8, 0x06, 0xA6, -0x36, 0xF8, 0xFD, 0x8B, 0x8F, 0x05, 0x88, 0x8F, 0xFC, 0xCD, 0xF4, 0xC3, 0x6A, 0x9B, 0x01, 0x01, -0x04, 0x08, 0xB0, 0xE2, 0xDA, 0x7B, 0x37, 0x16, 0x36, 0x3E, 0x86, 0x07, 0x9D, 0xB5, 0xC3, 0xD0, -0x18, 0x37, 0xCB, 0x31, 0x7C, 0x6D, 0x8C, 0xFE, 0x97, 0xDD, 0x89, 0x4B, 0x17, 0x1F, 0xB9, 0x4E, -0x38, 0xB4, 0xBE, 0x9A, 0xF5, 0x1E, 0x57, 0x6D, 0xE0, 0x70, 0xF5, 0x8F, 0x53, 0x14, 0x1F, 0x0B, -0x11, 0x1F, 0xFD, 0x9F, 0xD9, 0x9E, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xEA, 0x01, 0xB2, 0x3F, 0xC1, -0x02, 0xF4, 0x73, 0x8A, 0x8F, 0xDE, 0x9A, 0x8F, 0xD1, 0x9D, 0x65, 0x6B, 0x47, 0xAC, 0xFD, 0xA8, -0x8D, 0xEE, 0x86, 0xB5, 0x5B, 0xCC, 0x7E, 0x2C, 0x59, 0x7C, 0xF4, 0x06, 0xE4, 0x69, 0x4B, 0xDE, -0xEC, 0x60, 0x68, 0x8C, 0x5E, 0x9A, 0x29, 0xCA, 0x17, 0xE4, 0x67, 0xE2, 0x63, 0x21, 0xE2, 0x23, -0x0F, 0x90, 0x7D, 0xBB, 0x60, 0x01, 0x02, 0x04, 0x58, 0x71, 0x59, 0x73, 0xB3, 0x2A, 0xF1, 0x31, -0xB0, 0xDB, 0xD3, 0xD0, 0xC7, 0xF6, 0xD7, 0xA7, 0x97, 0x27, 0x3B, 0xD2, 0xE4, 0xC0, 0x76, 0x5C, -0xDA, 0xF8, 0xE8, 0x37, 0xE4, 0x8B, 0x71, 0x20, 0x2C, 0xCA, 0xF1, 0xD1, 0x0F, 0xB2, 0x4C, 0x7C, -0x9C, 0x7B, 0x7C, 0xE4, 0xEF, 0x6A, 0x86, 0xF8, 0x89, 0x1F, 0x6E, 0x38, 0xF1, 0x00, 0x02, 0x04, -0x58, 0x49, 0xF1, 0xC9, 0x47, 0x36, 0x7B, 0x5B, 0x83, 0x2E, 0x56, 0x7C, 0x1C, 0x35, 0xE8, 0x2C, -0x6F, 0xBB, 0x5B, 0x9E, 0x01, 0x29, 0x66, 0x3F, 0x86, 0xBF, 0xEC, 0x6E, 0x9C, 0xCA, 0xE0, 0x75, -0x91, 0xE3, 0x23, 0x6F, 0xC8, 0xED, 0xEE, 0xD6, 0xBC, 0xFD, 0x19, 0x8E, 0x70, 0x78, 0x21, 0xC6, -0xF2, 0x8B, 0xF8, 0x38, 0xE7, 0xF8, 0xC8, 0x7F, 0x58, 0xFB, 0xE9, 0x75, 0xDD, 0xD9, 0x07, 0x10, -0x20, 0xC0, 0xAA, 0xDA, 0x38, 0x7A, 0x0B, 0xDE, 0xF3, 0x8F, 0x8F, 0x91, 0xD9, 0x8F, 0x72, 0x78, -0x0C, 0x7C, 0x42, 0x6D, 0x70, 0xF6, 0x23, 0x1F, 0xE8, 0x75, 0x5E, 0x76, 0xB2, 0xA5, 0x8F, 0x8F, -0xE2, 0xA6, 0xD6, 0x73, 0xF1, 0xF0, 0x1A, 0x28, 0x9D, 0xD0, 0x28, 0x66, 0x3C, 0x06, 0xE2, 0x23, -0x13, 0x1F, 0xE7, 0x1A, 0x1F, 0xF9, 0xEF, 0xE5, 0x9E, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xD2, 0x1A, -0xA1, 0xB5, 0xBB, 0x78, 0xF1, 0x11, 0xC7, 0xDF, 0xE5, 0xC0, 0x16, 0xBB, 0xF1, 0xF0, 0xA2, 0x83, -0x61, 0xDC, 0x0E, 0xBB, 0xBB, 0xD9, 0x99, 0xBF, 0x8D, 0xAA, 0xC4, 0x47, 0x3E, 0xAE, 0xDD, 0xEF, -0xBE, 0x94, 0x9F, 0x76, 0x55, 0x04, 0x47, 0x7F, 0xE6, 0x23, 0x8A, 0x8F, 0x73, 0x8D, 0x8F, 0xFC, -0xC3, 0xF2, 0x05, 0x49, 0x37, 0x9C, 0x7A, 0x00, 0x01, 0x02, 0xAC, 0xAA, 0x6B, 0xA3, 0xD7, 0x00, -0x59, 0x8C, 0xA7, 0x5D, 0x1D, 0x35, 0xFB, 0x31, 0x6E, 0x07, 0xAC, 0xD1, 0xD9, 0x8F, 0x38, 0x74, -0xDD, 0x8F, 0xE5, 0x8E, 0x8F, 0xE2, 0xED, 0xF6, 0x0B, 0x45, 0x98, 0xD5, 0x3A, 0xD1, 0xD1, 0x9B, -0xF9, 0x28, 0x3D, 0x15, 0xAB, 0x76, 0xB7, 0xF8, 0x58, 0x88, 0xFB, 0x6D, 0x6F, 0xD5, 0x9D, 0x7A, -0x00, 0x01, 0x02, 0xAC, 0xA6, 0xE6, 0x0B, 0xF5, 0x85, 0x8B, 0x8F, 0xF4, 0x47, 0x6D, 0xF4, 0x6E, -0x63, 0x18, 0x5C, 0xE3, 0x71, 0xF4, 0xEC, 0x47, 0xE7, 0xD5, 0x56, 0x3C, 0xE3, 0x43, 0xA9, 0x5E, -0x7C, 0xA4, 0x83, 0x96, 0x9E, 0xDD, 0x93, 0x9E, 0x51, 0x57, 0xC4, 0x47, 0x2C, 0x3D, 0xED, 0x2A, -0xA4, 0xF8, 0xD8, 0x14, 0x1F, 0x0B, 0x71, 0xBF, 0xB1, 0x25, 0x40, 0x00, 0x01, 0x02, 0xAC, 0xA8, -0x98, 0x35, 0x16, 0x2A, 0x3E, 0x86, 0xFF, 0x3A, 0x66, 0xED, 0xC7, 0xB8, 0x4F, 0x8D, 0xE5, 0x0B, -0x80, 0xA4, 0x09, 0x9D, 0xBD, 0x78, 0x86, 0x87, 0x52, 0xCD, 0xF8, 0x28, 0x8E, 0x4F, 0xBE, 0x23, -0x56, 0x7A, 0xDA, 0x55, 0xBB, 0x37, 0x0B, 0xD2, 0x5B, 0xF3, 0x71, 0x45, 0x7C, 0x2C, 0xCE, 0xFD, -0xC6, 0x03, 0x3B, 0x61, 0x01, 0x02, 0x04, 0x58, 0xC1, 0xF6, 0x78, 0xF2, 0x91, 0x8D, 0xC3, 0x1D, -0xB0, 0x16, 0x24, 0x3E, 0x8E, 0x99, 0xFD, 0x88, 0x43, 0xC1, 0x51, 0xEC, 0xF2, 0x34, 0xF4, 0x81, -0xBD, 0x6D, 0x77, 0x57, 0x33, 0x3E, 0x92, 0x7C, 0x16, 0x64, 0xEB, 0x70, 0xF6, 0x43, 0x7C, 0x2C, -0xE0, 0xFD, 0xB6, 0x77, 0xD2, 0x6B, 0xD7, 0x03, 0x01, 0x04, 0x08, 0xB0, 0x72, 0x36, 0xBB, 0x3B, -0x60, 0x2D, 0xD6, 0x56, 0xBB, 0x47, 0xCD, 0x7E, 0x1C, 0x37, 0x03, 0x72, 0x38, 0xFA, 0x0E, 0xA7, -0x9E, 0xFD, 0x58, 0x86, 0xF8, 0x28, 0xC2, 0x2C, 0x35, 0x46, 0xB1, 0xE0, 0xFC, 0xCA, 0x5F, 0x12, -0x1F, 0x0B, 0x77, 0xBF, 0xDD, 0xF0, 0x77, 0x45, 0x74, 0x40, 0x80, 0x00, 0xAB, 0x18, 0x20, 0xFB, -0x8B, 0x13, 0x1F, 0x13, 0xCC, 0x7E, 0x94, 0x07, 0xD9, 0x87, 0x57, 0xFC, 0x2E, 0xAD, 0x1D, 0xD9, -0x12, 0x1F, 0xF9, 0x9F, 0xAD, 0x74, 0x59, 0x94, 0x97, 0x85, 0xBB, 0xBE, 0x43, 0x7C, 0x2C, 0xE4, -0xFD, 0xC6, 0xFC, 0xD2, 0xF5, 0xD7, 0x9D, 0x82, 0x00, 0x01, 0x02, 0xAC, 0x98, 0x78, 0xCC, 0x35, -0x40, 0xE6, 0x1C, 0x1F, 0xC3, 0x37, 0x4F, 0x32, 0xFB, 0x11, 0x87, 0xC2, 0x21, 0x8D, 0xE9, 0xF6, -0xE3, 0x29, 0x1E, 0xCA, 0x92, 0xC5, 0x47, 0xE7, 0x65, 0x6D, 0xE3, 0xDE, 0x70, 0xF5, 0x75, 0xE2, -0x63, 0xA1, 0xEF, 0xB7, 0x7D, 0xBB, 0xEE, 0x1C, 0x04, 0x08, 0x10, 0x60, 0xB5, 0xB4, 0xB6, 0xCE, -0x70, 0x2D, 0x82, 0xE9, 0x5F, 0xE1, 0xFC, 0xE4, 0xB3, 0x1F, 0xA5, 0x4A, 0x39, 0xE5, 0xDA, 0x8F, -0x65, 0x8D, 0x8F, 0x7B, 0xDF, 0xDA, 0x89, 0x8F, 0x4B, 0xE2, 0x63, 0xA1, 0xEF, 0x37, 0xB6, 0x3D, -0x05, 0x0B, 0x10, 0x20, 0xC0, 0x8A, 0x89, 0x59, 0x7D, 0x21, 0xE2, 0x63, 0xF8, 0x5D, 0x77, 0x9A, -0xFD, 0xE8, 0x8D, 0xB4, 0x07, 0xEE, 0x29, 0xCD, 0x7E, 0x1C, 0xC4, 0x13, 0x3E, 0x14, 0xF1, 0x21, -0x3E, 0xCE, 0xF1, 0x7E, 0xBB, 0x3B, 0x61, 0x89, 0x10, 0x40, 0x80, 0x00, 0x2B, 0xA4, 0xB5, 0x73, -0x8A, 0x00, 0x99, 0x4D, 0x7C, 0x4C, 0x3C, 0xFB, 0x91, 0x95, 0xB6, 0xDC, 0x3D, 0xC3, 0xEC, 0x87, -0xF8, 0x10, 0x1F, 0xE7, 0x7E, 0xBF, 0xED, 0xBD, 0xF4, 0xBA, 0x1E, 0x00, 0x04, 0x08, 0xB0, 0x0A, -0xE2, 0x93, 0x8D, 0xC6, 0xE1, 0x16, 0xBC, 0xE7, 0x1C, 0x1F, 0x71, 0xC2, 0xD9, 0x8F, 0x52, 0x78, -0x0C, 0xDC, 0x5B, 0x33, 0x9E, 0x68, 0xF6, 0x43, 0x7C, 0x88, 0x8F, 0xF3, 0xBF, 0xDF, 0x50, 0x2C, -0x44, 0x37, 0x03, 0x02, 0x08, 0x10, 0x60, 0x65, 0x6C, 0x9C, 0x2C, 0x40, 0x66, 0x14, 0x1F, 0xBD, -0xB1, 0xF5, 0x48, 0x90, 0x0C, 0xDD, 0x58, 0xCC, 0x7C, 0xC4, 0xE1, 0x87, 0x73, 0xC2, 0x9D, 0xAF, -0xC4, 0x87, 0xF8, 0x58, 0x88, 0xF8, 0x48, 0xB2, 0x7C, 0x06, 0xC4, 0x4E, 0x58, 0x80, 0x00, 0x01, -0x56, 0xC6, 0x66, 0x68, 0x4D, 0xBA, 0x03, 0xD6, 0x0C, 0xE3, 0x23, 0x1E, 0x7F, 0xD5, 0xF3, 0xC3, -0xAB, 0x9C, 0xC7, 0xF1, 0xEB, 0x41, 0xF6, 0x7A, 0x57, 0x3E, 0x17, 0x1F, 0xE2, 0xA3, 0x4A, 0xF1, -0x51, 0x68, 0xEF, 0xB8, 0x18, 0x21, 0x20, 0x40, 0x80, 0x15, 0x91, 0xB5, 0xAE, 0x87, 0x38, 0xC9, -0xC8, 0x7D, 0x86, 0xF1, 0x71, 0x54, 0x90, 0x0C, 0xAD, 0xFD, 0xE8, 0x2E, 0x38, 0xAF, 0x8D, 0x3E, -0x92, 0x74, 0xC3, 0x4E, 0x9C, 0xF0, 0xA1, 0x88, 0x0F, 0xF1, 0xB1, 0x60, 0xF1, 0xD1, 0x2D, 0x90, -0x86, 0x93, 0x11, 0x20, 0x40, 0x80, 0xD5, 0xD0, 0xDA, 0x9A, 0xE0, 0xBF, 0xBC, 0xCE, 0x76, 0xE6, -0xA3, 0x3F, 0xE3, 0x31, 0xB0, 0xAE, 0xA3, 0x36, 0x30, 0xD3, 0x11, 0x4B, 0x33, 0x1F, 0x23, 0x77, -0x3B, 0xE1, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0x8B, 0x19, 0x1F, 0x31, 0x7F, 0x1A, 0x56, 0xFC, 0xC4, -0x0F, 0xD7, 0x9D, 0x90, 0x00, 0x01, 0x02, 0x2C, 0xBF, 0xEC, 0xA0, 0x71, 0x6E, 0xF1, 0x31, 0xAC, -0x76, 0x18, 0x22, 0xC3, 0x33, 0x1F, 0xA1, 0xDC, 0x1F, 0xE5, 0x77, 0x66, 0x61, 0xA2, 0xD9, 0x0F, -0xF1, 0x21, 0x3E, 0x16, 0x36, 0x3E, 0x92, 0xEE, 0x85, 0x40, 0x05, 0x08, 0x20, 0x40, 0x80, 0xE5, -0x16, 0x9F, 0x6C, 0xD4, 0x8F, 0x7F, 0xFA, 0xD5, 0x8C, 0xE3, 0x23, 0x0E, 0x7D, 0x95, 0xFE, 0xDF, -0x6B, 0x03, 0x33, 0x1F, 0x87, 0xB3, 0x23, 0xB5, 0xD1, 0xDD, 0xB0, 0x76, 0xEF, 0x3C, 0xFB, 0x21, -0x3E, 0xC4, 0xC7, 0x42, 0xC7, 0x47, 0xBF, 0xA4, 0x43, 0xC3, 0x59, 0x09, 0x10, 0x20, 0xC0, 0xB2, -0xAB, 0x87, 0xD6, 0xD6, 0xC2, 0xC4, 0xC7, 0xC8, 0xD3, 0xB0, 0xCA, 0x0B, 0xCE, 0x43, 0x69, 0x21, -0x7A, 0xF9, 0x3E, 0xEE, 0x30, 0xFB, 0x21, 0x3E, 0xC4, 0xC7, 0xE2, 0xC7, 0x47, 0x47, 0x7B, 0x3B, -0xBD, 0xBE, 0xE6, 0x94, 0x04, 0x08, 0x10, 0x60, 0xD9, 0x35, 0x42, 0xBB, 0x39, 0xFF, 0xF8, 0x38, -0x66, 0x4C, 0xD6, 0xDF, 0x76, 0xB7, 0x37, 0xF3, 0x71, 0xB8, 0xFB, 0x55, 0x6D, 0xF4, 0x21, 0xEE, -0xC6, 0x63, 0x1F, 0xAA, 0xF8, 0x10, 0x1F, 0x95, 0x88, 0x8F, 0x42, 0xB6, 0x5F, 0x77, 0x4A, 0x02, -0xE6, 0x6D, 0xDD, 0x21, 0x00, 0xE6, 0xEC, 0xBE, 0xD1, 0x6B, 0x80, 0xCC, 0x2F, 0x3E, 0x46, 0x66, -0x3F, 0x8A, 0xF0, 0x88, 0xA5, 0xAB, 0x9C, 0x87, 0xEE, 0xA0, 0xFC, 0xA4, 0xB3, 0x1F, 0xE2, 0x43, -0x7C, 0x54, 0x2A, 0x3E, 0xF2, 0x77, 0xB5, 0x1A, 0x4E, 0x49, 0xC0, 0xBC, 0x99, 0x01, 0x01, 0xE6, -0xAB, 0xB5, 0xB5, 0x79, 0x2E, 0xF1, 0x11, 0xC7, 0xDF, 0x16, 0x87, 0xDE, 0x55, 0x0C, 0xC0, 0xC7, -0x7E, 0xFC, 0xF6, 0xD1, 0xB3, 0x1F, 0x8B, 0x1C, 0x1F, 0x51, 0x7C, 0x88, 0x8F, 0xA3, 0x64, 0x3B, -0x69, 0x27, 0x2C, 0xD7, 0x03, 0x01, 0x04, 0x08, 0xB0, 0xC4, 0xB2, 0xD6, 0xE6, 0xDC, 0xE3, 0x63, -0xF8, 0xAB, 0x0D, 0x5F, 0xD5, 0x7C, 0x64, 0xF6, 0x63, 0xCC, 0xDA, 0x8F, 0xB4, 0xE8, 0x7C, 0x37, -0x56, 0x32, 0x3E, 0x6A, 0xC7, 0xC4, 0xC7, 0xC0, 0x6D, 0xE2, 0x63, 0xB5, 0xE2, 0x23, 0xFF, 0xF7, -0x98, 0xCF, 0x46, 0x6E, 0x3A, 0x31, 0x01, 0x02, 0x04, 0x58, 0x5E, 0xED, 0xBD, 0x8D, 0xB9, 0xC7, -0x47, 0x31, 0x0A, 0x1F, 0xBA, 0x2D, 0x8E, 0xB9, 0xDB, 0x63, 0x67, 0x3F, 0x2A, 0x16, 0x1F, 0xE1, -0xC8, 0xF8, 0x08, 0x03, 0x8B, 0xEC, 0x8B, 0xDD, 0xBE, 0x32, 0xF1, 0xB1, 0x5A, 0xF1, 0x91, 0x7F, -0xD8, 0x81, 0x00, 0x01, 0x04, 0x08, 0xB0, 0xBC, 0xE2, 0x93, 0x8D, 0x46, 0xF7, 0xDA, 0x03, 0xF3, -0x5F, 0x70, 0x3E, 0x3C, 0xF0, 0x2E, 0xDE, 0x38, 0x1C, 0x80, 0x0F, 0x87, 0x48, 0x39, 0x9A, 0x42, -0xF7, 0xC2, 0x83, 0x15, 0x8B, 0x8F, 0x91, 0x9B, 0xFA, 0xC7, 0xA0, 0x76, 0x78, 0x2C, 0x86, 0x9E, -0x76, 0x75, 0x41, 0x7C, 0xAC, 0x4E, 0x7C, 0xE4, 0xBF, 0xDB, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xB0, -0xD4, 0x05, 0x12, 0xEB, 0x21, 0x6B, 0xCD, 0x77, 0xD0, 0x39, 0x76, 0xF6, 0x23, 0xE6, 0x3B, 0x5F, -0x95, 0x2F, 0xED, 0x51, 0x1E, 0x88, 0x8F, 0x7C, 0xFE, 0x76, 0xF5, 0xE3, 0x23, 0xF6, 0xB7, 0x19, -0xAE, 0x1D, 0xBE, 0xAF, 0xF4, 0xB4, 0xAB, 0xAC, 0x17, 0x1F, 0x2F, 0x13, 0x1F, 0xAB, 0x13, 0x1F, -0xFD, 0x4F, 0x69, 0x99, 0x01, 0x01, 0x04, 0x08, 0xB0, 0xB4, 0x8E, 0xB9, 0x06, 0xC8, 0xEC, 0x06, -0x9D, 0x83, 0xB3, 0x1F, 0xA5, 0x8B, 0x81, 0x8C, 0x59, 0xFB, 0x31, 0x32, 0x84, 0x4B, 0xBD, 0x34, -0x34, 0xFB, 0x51, 0x85, 0xF8, 0x18, 0xFF, 0x71, 0x83, 0xF1, 0x31, 0x3C, 0xF3, 0x21, 0x3E, 0x56, -0x30, 0x3E, 0x92, 0x6C, 0x5F, 0x80, 0x00, 0x02, 0x04, 0x58, 0x52, 0xED, 0xBD, 0x1B, 0x73, 0x1D, -0x74, 0x8E, 0xCC, 0x7E, 0xC4, 0xFE, 0x75, 0x3F, 0x06, 0x16, 0xA4, 0x97, 0x67, 0x3F, 0xCA, 0x41, -0x92, 0xFE, 0xDC, 0xAA, 0x66, 0x7C, 0x8C, 0x5D, 0x74, 0x5E, 0xBA, 0xBD, 0x7C, 0xBD, 0x93, 0x35, -0xF1, 0xB1, 0xBA, 0xF1, 0x91, 0x07, 0xC8, 0xDE, 0x86, 0x9D, 0xB0, 0x00, 0x01, 0x02, 0x2C, 0xA7, -0x6C, 0xFF, 0xE4, 0x83, 0x9C, 0x33, 0x0E, 0x3A, 0x63, 0x69, 0x0F, 0xDA, 0xB1, 0x3B, 0x5F, 0x1D, -0x37, 0x8C, 0x4B, 0xEB, 0x73, 0x0F, 0xE2, 0x72, 0xC4, 0x47, 0x2C, 0xCF, 0x7C, 0x1C, 0x06, 0x97, -0xF8, 0x58, 0xF1, 0xF8, 0xC8, 0x3F, 0xDD, 0x42, 0x74, 0x60, 0xBE, 0x5C, 0x88, 0x10, 0x98, 0x63, -0x80, 0x34, 0x4F, 0x36, 0xC8, 0x39, 0xEB, 0xA0, 0xB3, 0x56, 0x8C, 0xCD, 0x0E, 0xFF, 0xB3, 0xFF, -0x89, 0x66, 0x3F, 0xB6, 0x97, 0x34, 0x3E, 0x7A, 0x17, 0x59, 0x5C, 0x7B, 0x79, 0x27, 0x3E, 0xDE, -0x22, 0x3E, 0x56, 0x3A, 0x3E, 0xF2, 0x7F, 0x97, 0x7B, 0xE9, 0x75, 0xDD, 0x09, 0x0A, 0x98, 0x17, -0x33, 0x20, 0xC0, 0x7C, 0x86, 0x49, 0xB7, 0x6E, 0x6C, 0x86, 0x76, 0x73, 0x7E, 0x83, 0xCE, 0xFE, -0x0C, 0x47, 0x3C, 0xFA, 0xBA, 0x1F, 0xC3, 0xB7, 0x95, 0x3F, 0xBF, 0x34, 0xFB, 0x51, 0xF9, 0xF8, -0x18, 0xF8, 0x36, 0x4B, 0x33, 0x1F, 0xE2, 0x43, 0x7C, 0x08, 0x10, 0x40, 0x80, 0x00, 0x4B, 0x6C, -0xA3, 0xBB, 0x05, 0xEF, 0x9C, 0x06, 0x9D, 0xB5, 0xA1, 0x01, 0x5A, 0xEF, 0xBF, 0xFC, 0x0F, 0x07, -0x4A, 0x3E, 0xFB, 0x31, 0x3C, 0x9E, 0xCB, 0xD7, 0x7E, 0x64, 0x95, 0x8D, 0x8F, 0x30, 0x1C, 0x1F, -0xE3, 0x9E, 0x76, 0x25, 0x3E, 0xC4, 0x47, 0xFF, 0xAE, 0xDA, 0x69, 0x27, 0xAC, 0x1B, 0x01, 0x60, -0x4E, 0x3C, 0x05, 0x0B, 0x98, 0x97, 0x46, 0xEF, 0xAA, 0xCB, 0xB3, 0x1F, 0x74, 0x0E, 0xED, 0x76, -0x35, 0xFA, 0x94, 0xAB, 0xD2, 0x33, 0xB3, 0xC6, 0xCD, 0x88, 0xA4, 0x5D, 0xAF, 0x5A, 0xD5, 0x8D, -0x8F, 0x28, 0x3E, 0xC4, 0xC7, 0x49, 0x65, 0x7B, 0x75, 0xA7, 0x28, 0x40, 0x80, 0x00, 0xCB, 0xE6, -0xDA, 0x1D, 0x03, 0x64, 0x56, 0x03, 0xFE, 0x31, 0x6B, 0x3F, 0x46, 0x6E, 0x2B, 0xBF, 0x6F, 0x27, -0x2E, 0xC7, 0xD3, 0xAE, 0xC4, 0x87, 0xF8, 0x98, 0x38, 0x40, 0xF6, 0x05, 0x08, 0x30, 0x37, 0x9E, -0x82, 0x05, 0xCC, 0x47, 0xF3, 0x85, 0xFA, 0xCC, 0x07, 0x9D, 0xBD, 0xBD, 0x65, 0xE3, 0x40, 0x64, -0x1C, 0x0E, 0xCA, 0xC3, 0xB8, 0xD9, 0x8F, 0x30, 0x3A, 0xFB, 0x11, 0x5B, 0xCB, 0xB7, 0xDB, 0x55, -0x58, 0x5F, 0x0F, 0x57, 0x1B, 0xFF, 0x51, 0x2F, 0x3E, 0xBE, 0x2C, 0x3E, 0xC4, 0xC7, 0x70, 0x81, -0x84, 0xF8, 0x89, 0x1F, 0x6E, 0x38, 0x51, 0x01, 0x02, 0x04, 0x58, 0x1E, 0xB1, 0xBD, 0x39, 0xFB, -0x41, 0x67, 0xE9, 0x7E, 0x6A, 0xA5, 0x59, 0x80, 0x81, 0x40, 0x39, 0xBC, 0x2D, 0x0E, 0x8F, 0xE9, -0xD2, 0xED, 0xDB, 0x4B, 0x10, 0x1F, 0x61, 0x34, 0x3E, 0xD2, 0xCC, 0xC7, 0xDA, 0xD5, 0xAB, 0xDD, -0xF0, 0x68, 0x3D, 0x2F, 0x3E, 0xC4, 0xC7, 0xA0, 0xF6, 0x76, 0x7A, 0x5D, 0x77, 0xA2, 0x02, 0x04, -0x08, 0xB0, 0x1C, 0xED, 0x71, 0xEB, 0xC6, 0x46, 0x88, 0x07, 0x1B, 0x33, 0x1D, 0x74, 0xF6, 0xEE, -0x67, 0x78, 0x41, 0x79, 0x2C, 0x0D, 0xCC, 0x07, 0xA2, 0x23, 0x0E, 0x0E, 0xD8, 0xF3, 0xB7, 0x77, -0x3A, 0xAF, 0xDA, 0xD3, 0x78, 0x3C, 0x8B, 0x17, 0x1F, 0x17, 0xEE, 0xBF, 0xAF, 0x1B, 0x1F, 0xE9, -0xA9, 0x57, 0xE2, 0x43, 0x7C, 0x0C, 0xEB, 0x3E, 0x3D, 0x52, 0x80, 0x00, 0x02, 0x04, 0x58, 0x1A, -0x9B, 0xA1, 0xB5, 0x3B, 0xD7, 0xF8, 0x18, 0x79, 0x1A, 0xD6, 0xF0, 0xEC, 0xC7, 0xD0, 0xC2, 0xF3, -0x98, 0x75, 0xFE, 0xB2, 0x9D, 0x89, 0x0F, 0xF1, 0xB1, 0x7A, 0xF1, 0x91, 0x7F, 0x99, 0xFC, 0x62, -0x84, 0x76, 0xC2, 0x02, 0x04, 0x08, 0xB0, 0x44, 0x01, 0x32, 0xBC, 0x00, 0x7D, 0xD6, 0x8B, 0xBC, -0xCB, 0xDB, 0xEE, 0x0E, 0x47, 0x47, 0xAC, 0x0D, 0x3D, 0x94, 0xCE, 0x8D, 0xBB, 0x71, 0x0A, 0x63, -0x3D, 0xF1, 0x21, 0x3E, 0xAA, 0xFA, 0xB5, 0x3A, 0x5A, 0x2F, 0x6D, 0x38, 0x55, 0x01, 0x02, 0x04, -0x58, 0x16, 0x83, 0xD7, 0x00, 0x99, 0x41, 0x7C, 0x8C, 0xCC, 0x7E, 0x14, 0x6F, 0x97, 0x16, 0x65, -0x77, 0xD5, 0x06, 0x66, 0x3F, 0xF2, 0xF8, 0x48, 0x13, 0x1F, 0x3B, 0x71, 0x6A, 0x8F, 0x45, 0x7C, -0x88, 0x8F, 0xCA, 0xC5, 0x47, 0xFE, 0x25, 0x8F, 0x59, 0xA7, 0x05, 0x20, 0x40, 0x80, 0x4A, 0x69, -0xEF, 0xDD, 0x98, 0x59, 0x7C, 0xC4, 0xF1, 0xEF, 0x1A, 0xDE, 0x62, 0xB7, 0x18, 0xA0, 0x0F, 0x7E, -0x7C, 0xEF, 0x2F, 0x67, 0x9E, 0xFD, 0x10, 0x1F, 0xE2, 0xA3, 0xE2, 0xF1, 0x91, 0x7F, 0xD9, 0x83, -0x10, 0x3F, 0xFE, 0x43, 0x22, 0x04, 0x10, 0x20, 0xC0, 0x12, 0xC8, 0x9A, 0xF5, 0x99, 0xC4, 0xC7, -0xF0, 0xDF, 0xC6, 0xEC, 0x78, 0x35, 0x38, 0xFB, 0x51, 0x5E, 0xFB, 0x11, 0xBB, 0x7F, 0xB6, 0xC3, -0x19, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x58, 0x82, 0xF8, 0xC8, 0xFF, 0x9D, 0xEE, 0xA4, 0xD7, 0x75, -0x27, 0x2C, 0x40, 0x80, 0x00, 0xD5, 0xD7, 0xDA, 0xA9, 0xCF, 0x24, 0x3E, 0x62, 0x77, 0x3C, 0x3E, -0xFC, 0xEE, 0x18, 0x6A, 0x23, 0xE3, 0xDD, 0xC1, 0xD9, 0x8F, 0x78, 0xF8, 0x70, 0xB6, 0xCF, 0x32, -0xFB, 0x21, 0x3E, 0xC4, 0xC7, 0x92, 0xC4, 0x47, 0xFE, 0xE5, 0x53, 0x8D, 0x07, 0x33, 0x20, 0x80, -0x00, 0x01, 0xAA, 0x2D, 0xDE, 0xBA, 0xB1, 0x19, 0xB2, 0xFD, 0x99, 0x0D, 0xD0, 0x06, 0xB6, 0xD1, -0x2D, 0x47, 0x48, 0x69, 0xD7, 0xAB, 0xC1, 0x10, 0x29, 0xC5, 0x47, 0x1A, 0x6F, 0xED, 0xC5, 0xA9, -0x3D, 0x16, 0xF1, 0x21, 0x3E, 0x2A, 0x1B, 0x1F, 0x49, 0xB6, 0x97, 0x5E, 0x5F, 0x77, 0xD6, 0x02, -0x04, 0x08, 0x50, 0xF5, 0x04, 0xA9, 0x8F, 0xEC, 0x80, 0x35, 0x8D, 0x01, 0xDA, 0x31, 0xB3, 0x1F, -0xA5, 0x26, 0x19, 0x1C, 0xA8, 0x0F, 0xCF, 0x9E, 0x6C, 0x8B, 0x0F, 0xF1, 0x21, 0x3E, 0x06, 0x23, -0x64, 0xA7, 0xEE, 0x9C, 0x05, 0x08, 0x10, 0xA0, 0xEA, 0xC6, 0x5F, 0x03, 0x64, 0x0A, 0x03, 0xB4, -0xA3, 0x66, 0x3F, 0xC6, 0xAD, 0xFD, 0xC8, 0x9F, 0x76, 0x55, 0xBE, 0xAB, 0xB4, 0xF3, 0xD5, 0xA9, -0x66, 0x3F, 0xC4, 0x87, 0xF8, 0x58, 0xD2, 0xF8, 0xC8, 0x1F, 0x8E, 0x9D, 0xB0, 0x00, 0x01, 0x02, -0x54, 0x5D, 0xD6, 0xBA, 0xDE, 0x7B, 0x6E, 0xF9, 0xF4, 0x06, 0x68, 0x13, 0xCC, 0x7E, 0x1C, 0x6E, -0xC1, 0x5B, 0xEB, 0x6E, 0xB5, 0x3B, 0x7C, 0x51, 0xC2, 0x97, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0xA3, -0xFF, 0x5E, 0xF7, 0xD2, 0x4E, 0x58, 0x75, 0x27, 0x2E, 0x40, 0x80, 0x00, 0xD5, 0xD5, 0xDA, 0x3A, -0xC3, 0xC5, 0xCD, 0xE2, 0x9D, 0xC7, 0xB5, 0x47, 0xCD, 0x7E, 0x0C, 0xDD, 0xC7, 0xC0, 0x4D, 0xE9, -0xA2, 0xCF, 0x07, 0x71, 0x6A, 0x8F, 0x45, 0x7C, 0x88, 0x8F, 0xA5, 0x88, 0x8F, 0x5E, 0x80, 0x04, -0x3B, 0x61, 0x01, 0x02, 0x04, 0xA8, 0xB4, 0x98, 0x35, 0xA6, 0x3E, 0x40, 0x9B, 0x78, 0xF6, 0x63, -0x70, 0x31, 0x7A, 0xFF, 0xED, 0x6D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xF8, 0x87, 0x96, 0xEA, 0x3C, -0x34, 0x02, 0x80, 0x00, 0x01, 0x2A, 0xD9, 0x1E, 0xB7, 0x5E, 0x7F, 0xCA, 0x05, 0xE8, 0xF1, 0xD8, -0x77, 0x4D, 0x36, 0xFB, 0x31, 0xF4, 0xB4, 0xAB, 0xC2, 0x89, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x58, -0x91, 0xF8, 0x48, 0xBA, 0x33, 0x20, 0xD7, 0x9C, 0xBD, 0x00, 0x01, 0x02, 0x54, 0x55, 0x3D, 0xB4, -0xB6, 0xA6, 0x3B, 0x40, 0xBB, 0xD3, 0x75, 0x3F, 0xFA, 0x5B, 0xED, 0xD6, 0xC6, 0x6F, 0xCB, 0xBB, -0x2D, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0x3E, 0x42, 0xEC, 0x84, 0x05, 0xCC, 0xD6, 0xBA, 0x43, 0x00, -0xCC, 0xD0, 0x66, 0x68, 0x9F, 0x64, 0x06, 0x24, 0xDE, 0xF1, 0xDD, 0x47, 0x5D, 0xF5, 0xBC, 0xFF, -0x94, 0xAB, 0xD2, 0xCC, 0x47, 0xF9, 0xF6, 0x5C, 0x33, 0x9E, 0x60, 0xF6, 0x43, 0x7C, 0x88, 0x8F, -0x15, 0x8C, 0x8F, 0xAE, 0x86, 0x53, 0x17, 0x30, 0x4B, 0x66, 0x40, 0x80, 0x59, 0xBA, 0x36, 0xF9, -0x53, 0xB0, 0x4E, 0x31, 0x40, 0x1B, 0x59, 0xFB, 0x11, 0x47, 0x6F, 0x2B, 0xDF, 0xFD, 0x96, 0xF8, -0x10, 0x1F, 0xE2, 0xE3, 0x8E, 0xDA, 0xDB, 0x76, 0xC2, 0x02, 0x04, 0x08, 0x50, 0x51, 0xAD, 0xAD, -0x09, 0xAF, 0x29, 0x70, 0xE7, 0x99, 0x8F, 0x81, 0x2D, 0x74, 0xFB, 0xB3, 0x1F, 0xB5, 0xD2, 0x4C, -0x47, 0x1C, 0x78, 0xFF, 0xE1, 0x40, 0xBE, 0x77, 0x1F, 0xE9, 0x9A, 0x1F, 0xED, 0x29, 0x3C, 0x16, -0xF1, 0x21, 0x3E, 0x96, 0x39, 0x3E, 0xF2, 0x87, 0x9C, 0x2F, 0x44, 0x17, 0x20, 0x80, 0x00, 0x01, -0x2A, 0x28, 0x6B, 0x4D, 0x10, 0x20, 0x27, 0x1C, 0xA0, 0xD5, 0x0E, 0x43, 0x64, 0x78, 0xE6, 0xA3, -0xFC, 0xEC, 0xAB, 0x81, 0xBB, 0x4D, 0x6F, 0xEF, 0x4C, 0xF2, 0x75, 0xC4, 0x87, 0xF8, 0x58, 0xF1, -0xF8, 0x38, 0x0C, 0x10, 0x17, 0x24, 0x04, 0x04, 0x08, 0x50, 0x41, 0xED, 0xBD, 0x8D, 0x33, 0x0F, -0xD0, 0xE2, 0xD0, 0x47, 0xF6, 0xFF, 0x5E, 0x1B, 0x98, 0xF9, 0x38, 0x9C, 0xFD, 0x38, 0x1C, 0xD4, -0xF7, 0x3F, 0x67, 0xA2, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0xF7, 0xDF, 0xED, 0x76, 0x7A, -0x6D, 0x27, 0x2C, 0x40, 0x80, 0x00, 0xD5, 0x12, 0x6F, 0xBD, 0xBE, 0x71, 0xFC, 0xFA, 0x8F, 0xD3, -0xC5, 0xC7, 0xE0, 0xD3, 0xB0, 0x86, 0x16, 0x9C, 0x87, 0xA1, 0xA7, 0x5D, 0xA5, 0x3F, 0xB3, 0x30, -0xC1, 0xDA, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x80, 0x6C, 0xDF, 0x0C, 0x08, 0x20, 0x40, 0x80, -0xCA, 0x39, 0xE6, 0x1A, 0x20, 0x67, 0x18, 0xA0, 0xF5, 0xB7, 0xDD, 0x8D, 0xA3, 0xD1, 0x11, 0x6B, -0xA3, 0xE3, 0xE3, 0xDD, 0x78, 0x87, 0x2F, 0x27, 0x3E, 0xC4, 0x87, 0xF8, 0x18, 0xFD, 0x36, 0x5A, -0x02, 0x04, 0x10, 0x20, 0x40, 0x05, 0x03, 0xE4, 0x60, 0xEB, 0xCC, 0x03, 0xB4, 0xF1, 0xDB, 0xEE, -0xC6, 0xC1, 0xAB, 0x9C, 0x87, 0xEE, 0xC0, 0x7E, 0x60, 0xF6, 0x23, 0x49, 0xB3, 0x1F, 0xC7, 0xAE, -0xFD, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x8C, 0x95, 0xED, 0x6C, 0xC4, 0x8F, 0xFF, 0xD0, 0x86, 0xD3, -0x18, 0x20, 0x40, 0x80, 0xEA, 0x68, 0xEF, 0x5E, 0x3F, 0xD3, 0x00, 0x2D, 0x8E, 0xBF, 0x2D, 0x0E, -0xBD, 0xAB, 0x18, 0xC4, 0x87, 0x38, 0x66, 0x8C, 0x7C, 0xEC, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0xE2, -0xE3, 0xE8, 0x6F, 0x27, 0x5F, 0x34, 0x65, 0x16, 0x04, 0x10, 0x20, 0x40, 0x95, 0x02, 0xA4, 0x59, -0x3F, 0xEB, 0x00, 0x6D, 0x74, 0xF6, 0x23, 0x0E, 0x5C, 0x60, 0x70, 0x38, 0x3A, 0x26, 0x9F, 0xFD, -0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x1C, 0xFF, 0x2D, 0xED, 0x0B, 0x10, 0x40, 0x80, 0x00, 0x15, 0x93, -0x35, 0x37, 0x4F, 0x3D, 0x40, 0x8B, 0xDD, 0x31, 0xFB, 0xF0, 0x00, 0x38, 0x0E, 0xDD, 0x78, 0xEC, -0xEC, 0xC7, 0xF6, 0x51, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x3B, 0xFF, 0xFB, 0xDD, 0x4B, -0xAF, 0xED, 0x84, 0x05, 0x08, 0x10, 0xA0, 0x1A, 0xE2, 0xAD, 0xD7, 0x6F, 0x1E, 0x2E, 0x40, 0x3F, -0xDD, 0x00, 0xAD, 0xBC, 0x93, 0x55, 0x2C, 0x6D, 0x87, 0x15, 0x4B, 0xBB, 0x5E, 0x0D, 0x86, 0x48, -0xE9, 0x73, 0xD2, 0xB3, 0x47, 0x76, 0xA3, 0xF8, 0x10, 0x1F, 0xE2, 0xE3, 0xD4, 0xDF, 0x5A, 0x3B, -0xBD, 0x98, 0x01, 0x01, 0x04, 0x08, 0x50, 0x19, 0x1B, 0xA1, 0xBD, 0x7B, 0xBA, 0x01, 0xDA, 0xC8, -0xEC, 0x47, 0xEC, 0xEF, 0x7C, 0x55, 0xDE, 0x5D, 0x77, 0x60, 0x30, 0x3F, 0xFC, 0xF9, 0xDB, 0xE2, -0x43, 0x7C, 0x88, 0x8F, 0x33, 0xCB, 0x76, 0xEB, 0x4E, 0x65, 0x80, 0x00, 0x01, 0x2A, 0x22, 0x36, -0x42, 0x7B, 0xFF, 0xEC, 0xE3, 0xDE, 0x18, 0x07, 0x2F, 0x40, 0x38, 0x66, 0xED, 0x47, 0x7F, 0x28, -0x58, 0xDC, 0x96, 0xD6, 0x7E, 0xEC, 0x45, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x99, 0xBF, 0xCD, 0x7D, -0x01, 0x02, 0x08, 0x10, 0xA0, 0x32, 0xAE, 0x1D, 0x7F, 0x11, 0xC2, 0x63, 0xC6, 0x75, 0xB5, 0xA1, -0x41, 0xDE, 0xD0, 0xEC, 0x47, 0xFF, 0x2A, 0xE7, 0xC5, 0x80, 0xBE, 0x74, 0x11, 0xC2, 0xF1, 0xB3, -0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x53, 0xE9, 0xFC, 0x1B, 0x8E, 0x1F, 0x7F, 0x7B, 0xC3, 0xE9, -0x0C, 0x10, 0x20, 0xC0, 0xE2, 0x6B, 0xBE, 0x50, 0x3F, 0xDB, 0xD8, 0x37, 0x0E, 0x5D, 0xF7, 0x23, -0x0C, 0x0C, 0xEA, 0x8F, 0x1C, 0x0E, 0x1E, 0x84, 0xA1, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, -0xA9, 0x7F, 0x0F, 0xB2, 0x7C, 0x16, 0xB3, 0x1E, 0x00, 0x04, 0x08, 0xB0, 0xF8, 0x83, 0x97, 0x53, -0x2C, 0x5E, 0xED, 0xCF, 0x7E, 0xC4, 0x81, 0xDB, 0x26, 0x9A, 0xFD, 0x28, 0xDE, 0xDE, 0x16, 0x1F, -0xE2, 0x43, 0x7C, 0x4C, 0xED, 0xF7, 0xA0, 0x3B, 0x8B, 0x29, 0x40, 0x00, 0x01, 0x02, 0x2C, 0xF8, -0xD8, 0xE5, 0xD6, 0xC3, 0x1B, 0x21, 0x3B, 0x38, 0xD5, 0x15, 0x94, 0x63, 0x2C, 0x3F, 0xED, 0xAA, -0x34, 0xEE, 0x9B, 0x74, 0xF6, 0xE3, 0x20, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0xA6, 0xF5, 0x7B, 0x10, -0xD3, 0x3F, 0xAA, 0x70, 0xC3, 0x59, 0x0D, 0x10, 0x20, 0xC0, 0xA2, 0xDB, 0xEC, 0xEE, 0x80, 0x75, -0xC6, 0x41, 0xDE, 0xA9, 0x67, 0x3F, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x53, 0xFB, 0x3D, 0x68, 0x6F, -0xD5, 0x9D, 0xD2, 0x00, 0x01, 0x02, 0x54, 0x20, 0x40, 0x4E, 0xB8, 0x00, 0x7D, 0x68, 0xB7, 0xAB, -0x63, 0x67, 0x3F, 0xE2, 0xD0, 0xC7, 0x24, 0xFD, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x54, -0x7F, 0x0F, 0x62, 0x4B, 0x80, 0x00, 0x02, 0x04, 0x58, 0x78, 0x1B, 0x27, 0x9A, 0x01, 0x39, 0xE2, -0xB9, 0x55, 0x03, 0x57, 0x3D, 0x2F, 0xCF, 0x7E, 0x0C, 0xDD, 0x96, 0xDF, 0x70, 0x3B, 0x13, 0x1F, -0xE2, 0x43, 0x7C, 0xCC, 0xE2, 0xF7, 0x20, 0x1E, 0xA4, 0x9D, 0xB0, 0x5C, 0x90, 0x10, 0x10, 0x20, -0xC0, 0x02, 0x6B, 0xEF, 0x4D, 0xFE, 0x9C, 0xF1, 0xDE, 0xC0, 0xA7, 0xBF, 0x85, 0xEE, 0xD0, 0xEC, -0x47, 0xFF, 0x0A, 0xE7, 0xA5, 0xF7, 0x87, 0xE1, 0xAB, 0x9E, 0xA7, 0x5D, 0xAF, 0xDA, 0xE2, 0x43, -0x7C, 0x88, 0x8F, 0x99, 0xFC, 0x1E, 0xB4, 0x77, 0xD2, 0xEB, 0xBA, 0x13, 0x1B, 0x20, 0x40, 0x80, -0xC5, 0x95, 0x35, 0x27, 0x1B, 0xAC, 0x0C, 0x0F, 0x7C, 0x6A, 0xA5, 0xF0, 0x18, 0x5A, 0xFB, 0x31, -0x72, 0x5B, 0xF9, 0x7D, 0x3B, 0x99, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0x56, 0xBF, 0x07, 0xDD, 0x9D, -0xB0, 0xCC, 0x80, 0x00, 0x53, 0xB5, 0xEE, 0x10, 0x00, 0x53, 0xD5, 0xDA, 0xB9, 0x73, 0x80, 0x94, -0x06, 0x3E, 0xE5, 0xAB, 0x98, 0xC7, 0x70, 0x38, 0xC0, 0x0F, 0xE3, 0x66, 0x3F, 0xC2, 0xF0, 0xEC, -0x47, 0x27, 0x3E, 0xDA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x99, 0xFD, 0x1E, 0x74, 0x77, 0xC2, 0xBA, -0xEE, 0xC4, 0x06, 0x4C, 0x93, 0x19, 0x10, 0x60, 0x7A, 0x63, 0x9A, 0x5B, 0x0F, 0x6F, 0xDE, 0xF1, -0x0A, 0xE8, 0xE3, 0x06, 0x3E, 0xB5, 0xC3, 0xD0, 0x18, 0x9E, 0xF9, 0x28, 0x6E, 0x8B, 0xC3, 0xE3, -0xC3, 0x74, 0x3F, 0x3B, 0x53, 0x18, 0x30, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0x8E, 0xD7, 0xBE, 0x5D, -0x0F, 0x00, 0x02, 0x04, 0x58, 0x50, 0xF5, 0x63, 0x03, 0x64, 0x68, 0xE0, 0x13, 0x87, 0xDE, 0x88, -0xA5, 0x41, 0xFE, 0x40, 0x74, 0xC4, 0xC1, 0xDB, 0xF3, 0xD7, 0x29, 0x3E, 0xCE, 0x3A, 0xFB, 0x21, -0x3E, 0xC4, 0x87, 0xF8, 0x98, 0x84, 0xA7, 0x60, 0x01, 0x02, 0x04, 0x58, 0x58, 0x9B, 0xA1, 0xB5, -0x7B, 0xE2, 0xF8, 0x18, 0x59, 0x84, 0x3E, 0x3C, 0xFB, 0x51, 0x7E, 0xDA, 0x55, 0x7A, 0x23, 0x2D, -0xFB, 0x38, 0xEB, 0xEC, 0x87, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0x32, 0xD9, 0x9E, 0x9D, 0xB0, 0x00, -0x01, 0x02, 0x2C, 0xA8, 0xAC, 0x75, 0x3D, 0xC4, 0xF6, 0xC9, 0x07, 0x3E, 0xE5, 0x6D, 0x77, 0x87, -0xA3, 0x23, 0xD6, 0x4A, 0x77, 0xD3, 0xBB, 0x9F, 0xDD, 0x78, 0xB6, 0x71, 0xA3, 0xF8, 0x10, 0x1F, -0xE2, 0x63, 0x72, 0xED, 0xBD, 0xF4, 0x7A, 0xC3, 0x09, 0x0E, 0x10, 0x20, 0xC0, 0xE2, 0x69, 0x6D, -0x6D, 0x4C, 0x32, 0xF0, 0x39, 0xEA, 0xA2, 0x83, 0xB1, 0x7C, 0x6D, 0x8F, 0xD0, 0x0D, 0x80, 0xC3, -0xD9, 0x8F, 0xDE, 0x8D, 0x67, 0x9D, 0xFD, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x9C, 0xF0, 0xF3, 0xF3, -0x85, 0xE8, 0x0D, 0x27, 0x38, 0x40, 0x80, 0x00, 0x0B, 0x38, 0xD0, 0xC9, 0x1A, 0x27, 0x1E, 0xF8, -0x8C, 0xD9, 0x62, 0xB7, 0x18, 0xEC, 0x97, 0xEB, 0xA4, 0x7F, 0x57, 0x67, 0x99, 0xFD, 0x10, 0x1F, -0xE2, 0x43, 0x7C, 0x9C, 0x5C, 0x96, 0xCF, 0x80, 0x5C, 0x73, 0x82, 0x03, 0x04, 0x08, 0xB0, 0x58, -0xE3, 0x9C, 0x5B, 0x0F, 0x0F, 0x2E, 0x40, 0x3F, 0x6A, 0xB0, 0x3F, 0x10, 0x1E, 0xA5, 0x1B, 0x47, -0x66, 0x3F, 0x8A, 0x81, 0x7F, 0xE9, 0x86, 0xF4, 0xEC, 0xAE, 0xED, 0x53, 0x0E, 0xA8, 0xC4, 0x87, -0xF8, 0x10, 0x1F, 0xA7, 0xD7, 0x9E, 0x60, 0x7B, 0x6D, 0x00, 0x01, 0x02, 0xCC, 0x59, 0x3D, 0xB4, -0xB6, 0x4E, 0x36, 0xF0, 0x29, 0xAF, 0xFD, 0x08, 0x83, 0x03, 0xFE, 0xF2, 0xBE, 0xBB, 0xFD, 0xBB, -0x13, 0x1F, 0xE2, 0x43, 0x7C, 0x9C, 0xD3, 0xEF, 0x41, 0xBB, 0xE1, 0x14, 0x07, 0x08, 0x10, 0x60, -0xD1, 0x6C, 0x86, 0x76, 0xF3, 0xD8, 0x81, 0xCF, 0x71, 0x6B, 0x3F, 0xC2, 0xC8, 0xEC, 0x47, 0x1C, -0xDC, 0xFD, 0x2A, 0xCD, 0x7E, 0xEC, 0x9D, 0x62, 0x50, 0x25, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0xBB, -0xEE, 0x4E, 0x58, 0x75, 0xA7, 0x39, 0x40, 0x80, 0x00, 0x8B, 0xE4, 0x5A, 0x68, 0xEF, 0x9F, 0x68, -0x3C, 0x58, 0x5E, 0xFB, 0x51, 0xDE, 0xF9, 0x2A, 0x0E, 0x0F, 0xA0, 0xD2, 0x5F, 0xB7, 0xC5, 0x87, -0xF8, 0x10, 0x1F, 0xE7, 0xF6, 0x7B, 0x90, 0xE5, 0x0B, 0xD1, 0x05, 0x08, 0x20, 0x40, 0x80, 0x05, -0x72, 0xB0, 0xB5, 0x39, 0xD1, 0x10, 0xF0, 0xB8, 0xB5, 0x1F, 0x43, 0xD7, 0xFF, 0xE8, 0x7F, 0x60, -0xDA, 0xF9, 0xEA, 0xA4, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x29, 0xDE, 0xB7, 0x9D, 0xB0, -0x00, 0x01, 0x02, 0x2C, 0xDC, 0xE0, 0xA7, 0x35, 0xF9, 0x85, 0xCA, 0x86, 0x77, 0xBE, 0x2A, 0x6D, -0xC1, 0x3B, 0xF6, 0x02, 0x85, 0x2F, 0x89, 0x0F, 0xF1, 0x21, 0x3E, 0xCE, 0x2D, 0x3E, 0x92, 0xF6, -0x76, 0xFA, 0x37, 0x6E, 0x27, 0x2C, 0x40, 0x80, 0x00, 0x0B, 0xA4, 0xBD, 0xB7, 0x71, 0xC7, 0x61, -0xE0, 0xB1, 0xB3, 0x1F, 0x71, 0xF4, 0x63, 0x92, 0xF4, 0x1F, 0x5E, 0x0F, 0x4E, 0x30, 0xB8, 0x12, -0x1F, 0xE2, 0x43, 0x7C, 0xCC, 0xE8, 0xEB, 0xB4, 0xEB, 0x4E, 0x74, 0x80, 0x00, 0x01, 0x16, 0x63, -0xFC, 0x73, 0xEB, 0xE1, 0xC6, 0xC4, 0xEB, 0x3F, 0xC6, 0xCE, 0x7E, 0xC4, 0xEE, 0xE0, 0x7F, 0xE0, -0xB6, 0x70, 0xF2, 0xB5, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x19, 0x7E, 0xAD, 0x13, 0xCC, 0x72, -0x02, 0x08, 0x10, 0x60, 0xC6, 0x06, 0xAF, 0x01, 0x32, 0x6E, 0x28, 0x78, 0xE4, 0xEC, 0x47, 0x1C, -0x8A, 0x93, 0x92, 0x93, 0xCC, 0x7E, 0x88, 0x0F, 0xF1, 0x21, 0x3E, 0x66, 0x2B, 0xDB, 0xD9, 0x88, -0x1F, 0x7F, 0xFB, 0x86, 0xD3, 0x1D, 0x20, 0x40, 0x80, 0xC5, 0x08, 0x90, 0x83, 0xAD, 0x89, 0xC6, -0x86, 0xFD, 0xEB, 0x7E, 0xA4, 0xB1, 0x53, 0x16, 0x07, 0x03, 0x20, 0x84, 0xD3, 0xCD, 0x7E, 0x88, -0x0F, 0xF1, 0x21, 0x3E, 0xE6, 0x10, 0x20, 0xF9, 0x42, 0x74, 0xB3, 0x20, 0x80, 0x00, 0x01, 0x16, -0x40, 0x7B, 0xF7, 0xFA, 0x91, 0xC3, 0xC1, 0xF2, 0xAE, 0x56, 0xA5, 0xC0, 0xC8, 0x9F, 0x76, 0x35, -0x34, 0x66, 0x1C, 0xB8, 0xEE, 0x47, 0xDA, 0xF5, 0x6A, 0x92, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, -0xC7, 0x9C, 0xBE, 0xAE, 0x00, 0x01, 0x04, 0x08, 0xB0, 0x30, 0x01, 0xD2, 0xAC, 0x1F, 0xF9, 0xBE, -0x5A, 0x29, 0x3C, 0x42, 0xED, 0xF0, 0x69, 0x57, 0x31, 0x8C, 0xAE, 0x07, 0x29, 0x8F, 0x25, 0x77, -0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x0B, 0x13, 0x1F, 0xF9, 0xBF, 0xF3, 0xED, 0xF4, 0xDA, 0x4E, 0x58, -0xC0, 0x99, 0xAD, 0x3B, 0x04, 0xC0, 0x99, 0x65, 0xCD, 0xCD, 0xB1, 0x43, 0xC2, 0x58, 0x1E, 0x1E, -0xD6, 0xFA, 0xBB, 0x5D, 0xC5, 0xE1, 0xEB, 0x7C, 0xC4, 0x31, 0xB3, 0x1F, 0x6D, 0xF1, 0x21, 0x3E, -0xC4, 0xC7, 0xC2, 0xC4, 0x47, 0xFF, 0x31, 0xB4, 0xCD, 0x80, 0x00, 0x67, 0x66, 0x06, 0x04, 0x38, -0xDB, 0x78, 0xE4, 0xD6, 0xC3, 0xF5, 0x23, 0x77, 0xC0, 0xAA, 0x1D, 0x86, 0xC6, 0xF0, 0xCC, 0x47, -0xF1, 0xB4, 0xAC, 0x91, 0x31, 0xD5, 0x24, 0xB3, 0x1F, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x73, 0xFA, -0x8F, 0x0D, 0x7B, 0x02, 0x04, 0x10, 0x20, 0xC0, 0xB9, 0xEB, 0x04, 0xC8, 0xEE, 0xF8, 0x61, 0x61, -0x79, 0x06, 0xA4, 0x34, 0xF3, 0x71, 0xB8, 0x36, 0xA4, 0x76, 0x18, 0x06, 0xC5, 0xE7, 0xEC, 0xDE, -0x61, 0xF6, 0x43, 0x7C, 0x88, 0x0F, 0xF1, 0x71, 0x8E, 0x01, 0xB2, 0x6F, 0x17, 0x2C, 0x40, 0x80, -0x00, 0xE7, 0xAE, 0x11, 0xDA, 0xCD, 0xB1, 0xF1, 0x31, 0xB2, 0x08, 0x7D, 0x78, 0xF6, 0xA3, 0x3C, -0xB6, 0xCA, 0x77, 0xC5, 0x0A, 0xC7, 0xEF, 0x7C, 0x25, 0x3E, 0xC4, 0x87, 0xF8, 0x38, 0xE7, 0xC7, -0xD3, 0x0C, 0xF1, 0xE3, 0x6F, 0x6F, 0x38, 0xED, 0x01, 0x02, 0x04, 0x38, 0x4F, 0xD7, 0x8E, 0xBA, -0x06, 0xC8, 0xE0, 0x95, 0xCE, 0x0F, 0x83, 0x23, 0x96, 0x66, 0x3F, 0x06, 0xC6, 0x58, 0xBB, 0xF1, -0xE8, 0xB1, 0xA5, 0xF8, 0x10, 0x1F, 0xE2, 0xE3, 0xFC, 0x65, 0x7B, 0xE9, 0x75, 0xDD, 0x69, 0x0F, -0x10, 0x20, 0xC0, 0xF9, 0x69, 0xBE, 0x50, 0x1F, 0x19, 0x1A, 0xC6, 0xC3, 0xA7, 0x5D, 0x0D, 0x2C, -0x30, 0xEF, 0x7F, 0x40, 0x6D, 0x74, 0xFD, 0x47, 0x9A, 0xFD, 0x38, 0x6A, 0xED, 0x87, 0xF8, 0x10, -0x1F, 0xE2, 0x63, 0x11, 0x1E, 0x94, 0x00, 0x01, 0x04, 0x08, 0xB0, 0x00, 0xB2, 0xD6, 0xE6, 0x51, -0x03, 0xA8, 0xE1, 0x2D, 0x76, 0x8B, 0x20, 0x08, 0x71, 0xCC, 0x38, 0xEB, 0xA8, 0xD9, 0x0F, 0xF1, -0x21, 0x3E, 0xC4, 0xC7, 0x62, 0xC4, 0x47, 0xFE, 0x47, 0xBB, 0xF3, 0xD2, 0xBA, 0xE1, 0xC4, 0x07, -0x08, 0x10, 0xE0, 0x7C, 0x86, 0x24, 0xB7, 0x1E, 0xDE, 0xE8, 0x0C, 0x46, 0x36, 0x06, 0x86, 0x87, -0xBD, 0x8B, 0x0C, 0x0E, 0xAC, 0xF7, 0x88, 0x83, 0xE3, 0xC7, 0x89, 0x67, 0x3F, 0xC4, 0x87, 0xF8, -0x10, 0x1F, 0x8B, 0x13, 0x1F, 0xFD, 0x7F, 0xAF, 0x7B, 0x75, 0x67, 0x3F, 0x40, 0x80, 0x00, 0xE7, -0x65, 0x33, 0xB4, 0x76, 0x46, 0x07, 0x50, 0xBD, 0x0B, 0x0C, 0x8E, 0xDC, 0x7C, 0xD4, 0xEC, 0xC7, -0xD6, 0x98, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xE2, 0xC5, 0x47, 0x7E, 0x53, 0x4B, 0x80, -0x00, 0x02, 0x04, 0x38, 0x37, 0xF5, 0xB4, 0x00, 0x3D, 0x96, 0x06, 0x50, 0x83, 0x33, 0x21, 0xA1, -0xB4, 0xEF, 0xEE, 0xE1, 0x70, 0x66, 0xE0, 0xA2, 0x83, 0x69, 0xCB, 0xDD, 0xBD, 0x28, 0x3E, 0xC4, -0x87, 0xF8, 0xA8, 0x42, 0x7C, 0xE4, 0x37, 0x1F, 0xD8, 0x09, 0x0B, 0x10, 0x20, 0xC0, 0xB9, 0x8D, -0x4F, 0xEA, 0xA1, 0xB5, 0x5B, 0x1A, 0xFD, 0x87, 0xFE, 0xEC, 0x47, 0x1C, 0x09, 0x8E, 0xDA, 0xE8, -0x70, 0x26, 0xDD, 0xB0, 0x2D, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x4C, 0x7C, 0xE4, 0xFF, 0xD1, 0x60, -0x3B, 0xBD, 0x76, 0x3D, 0x10, 0x40, 0x80, 0x00, 0xE7, 0xA0, 0xBD, 0x77, 0x63, 0x60, 0xB7, 0xAB, -0xF2, 0xD8, 0x65, 0xCC, 0xDA, 0x8F, 0x81, 0xEB, 0x81, 0x24, 0x69, 0xED, 0xC7, 0x5E, 0x14, 0x1F, -0xE2, 0x43, 0x7C, 0x54, 0x25, 0x3E, 0xF2, 0x7F, 0xB7, 0xF9, 0xB6, 0xDB, 0xAE, 0x88, 0x0E, 0x08, -0x10, 0xE0, 0x1C, 0x64, 0xCD, 0xFA, 0x60, 0x1D, 0x0C, 0xCE, 0x7E, 0x1C, 0x6E, 0xC1, 0x5B, 0x1B, -0x7F, 0x81, 0xC2, 0x2D, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0xA5, 0xE2, 0x23, 0xFF, 0x90, 0x83, 0xF4, -0xFA, 0xBA, 0x13, 0x20, 0x20, 0x40, 0x80, 0xF9, 0x0F, 0x55, 0x0E, 0xB6, 0xEB, 0x03, 0x51, 0x51, -0x8C, 0x5F, 0xE2, 0x98, 0xB1, 0xD5, 0xF0, 0x3A, 0xF3, 0x34, 0x86, 0xD9, 0x8F, 0xE2, 0x43, 0x7C, -0x88, 0x8F, 0x2A, 0xC5, 0x47, 0xA1, 0x7D, 0xBB, 0xEE, 0x0C, 0x08, 0x08, 0x10, 0x60, 0xBE, 0x43, -0x95, 0x8F, 0x3E, 0xB4, 0x19, 0xB2, 0xFD, 0xA1, 0xC0, 0x98, 0x60, 0xF6, 0xA3, 0x78, 0x5A, 0xD6, -0xB6, 0xF8, 0x10, 0x1F, 0xE2, 0xA3, 0x92, 0xF1, 0x91, 0x7F, 0x78, 0xDB, 0x53, 0xB0, 0x00, 0x01, -0x02, 0xCC, 0x7D, 0x0C, 0x95, 0xEF, 0x80, 0x75, 0xEA, 0xD9, 0x8F, 0x83, 0x28, 0x3E, 0xC4, 0x87, -0xF8, 0xA8, 0x62, 0x7C, 0xE4, 0x9F, 0x92, 0xEF, 0x84, 0x25, 0x42, 0x00, 0x01, 0x02, 0xCC, 0xD5, -0xE6, 0xE1, 0x0E, 0x58, 0x27, 0x9D, 0xFD, 0xC8, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x55, 0x8D, 0x8F, -0xA4, 0x9D, 0xFF, 0xDB, 0xAF, 0x3B, 0x0D, 0x02, 0x02, 0x04, 0x98, 0x9F, 0xEC, 0xE0, 0x5A, 0xC8, -0xDA, 0xA7, 0x98, 0xFD, 0xE8, 0xFC, 0xAD, 0x29, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x6C, 0x7C, 0xE4, -0x9F, 0x7A, 0xD0, 0xFD, 0x8F, 0x10, 0x00, 0x02, 0x04, 0x98, 0x9B, 0x56, 0x79, 0x01, 0x7A, 0x6D, -0x30, 0x38, 0xCA, 0xA1, 0x50, 0xBA, 0x2D, 0x1F, 0xEF, 0xBC, 0x94, 0x89, 0x0F, 0xF1, 0x21, 0x3E, -0xAA, 0x1C, 0x1F, 0xF9, 0x7F, 0x80, 0xD8, 0x4B, 0x57, 0x44, 0xB7, 0x13, 0x16, 0x20, 0x40, 0x80, -0x79, 0x8E, 0x5F, 0xB2, 0xC6, 0xE8, 0x53, 0xAE, 0x86, 0xAE, 0xF3, 0x11, 0x86, 0xAE, 0x7A, 0xBE, -0x9B, 0x75, 0xAF, 0x7C, 0x2E, 0x3E, 0xC4, 0x87, 0xF8, 0xA8, 0x6E, 0x7C, 0xF4, 0x23, 0x64, 0xDF, -0xC5, 0x08, 0x01, 0x01, 0x02, 0xCC, 0x47, 0xF6, 0x7B, 0x0F, 0xD5, 0x43, 0xBB, 0x39, 0x76, 0xED, -0xC7, 0xC8, 0x6D, 0xFD, 0x4F, 0xEA, 0xDC, 0xB2, 0x13, 0xC5, 0x87, 0xF8, 0x10, 0x1F, 0xCB, 0x10, -0x1F, 0xDD, 0x7F, 0xD4, 0x0D, 0x67, 0x43, 0x40, 0x80, 0x00, 0xF3, 0x1A, 0xC3, 0xD4, 0x63, 0xEB, -0x76, 0x3F, 0x16, 0xC2, 0xB8, 0xD9, 0x8F, 0xD2, 0xAC, 0x48, 0xFE, 0x2A, 0x5D, 0xF1, 0xBC, 0x2D, -0x3E, 0xC4, 0x87, 0xF8, 0x58, 0x8E, 0xF8, 0x08, 0xF9, 0xD3, 0xB0, 0xE2, 0xC7, 0xDF, 0x5E, 0x77, -0x42, 0x04, 0x04, 0x08, 0x30, 0x8F, 0x61, 0xCC, 0x66, 0x9A, 0x01, 0x19, 0x9E, 0xF9, 0x28, 0x16, -0x9C, 0x0F, 0x8C, 0xBD, 0xD2, 0x5F, 0xD2, 0xB2, 0x8F, 0xA1, 0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, -0x47, 0xA8, 0xF6, 0xF1, 0xB7, 0x13, 0x16, 0x20, 0x40, 0x80, 0x39, 0xBA, 0x16, 0xDB, 0x07, 0x03, -0x33, 0x1F, 0xFD, 0xD9, 0x8F, 0x58, 0x2B, 0x05, 0x44, 0x6F, 0xD0, 0xB3, 0x3B, 0x38, 0xFB, 0x21, -0x3E, 0xC4, 0x87, 0xF8, 0x08, 0xD5, 0x3F, 0xFE, 0xDD, 0x9D, 0xB0, 0x1A, 0x4E, 0x87, 0x80, 0x00, -0x01, 0x66, 0xEF, 0x60, 0x6B, 0x33, 0x94, 0x9F, 0x72, 0x55, 0x9E, 0xFD, 0x08, 0xA5, 0xA7, 0x5D, -0xA5, 0x3F, 0x87, 0x66, 0x3F, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x61, 0x39, 0x8E, 0x7F, 0xDA, 0x09, -0x2B, 0x84, 0x6B, 0x4E, 0x88, 0x80, 0x00, 0x01, 0x66, 0x2F, 0x3B, 0xA8, 0x17, 0x63, 0x9B, 0x7E, -0x6B, 0x14, 0x31, 0xD1, 0x1B, 0x88, 0x1D, 0xEE, 0x7C, 0x75, 0x78, 0x21, 0x10, 0xF1, 0x21, 0x3E, -0xC4, 0x47, 0x58, 0xAE, 0xE3, 0x9F, 0xED, 0xD7, 0x9D, 0x10, 0x01, 0x01, 0x02, 0xCC, 0x5E, 0x7B, -0xBF, 0x1E, 0xCB, 0xD7, 0xF6, 0x08, 0xDD, 0x98, 0x18, 0x78, 0xDA, 0x55, 0x3E, 0x38, 0x09, 0xFD, -0xD9, 0x0F, 0xF1, 0x21, 0x3E, 0xC4, 0x47, 0x58, 0xBE, 0xE3, 0x1F, 0x5B, 0x0D, 0x27, 0x44, 0x40, -0x80, 0x00, 0xB3, 0x6D, 0x8F, 0xDF, 0x79, 0xB8, 0x11, 0xD3, 0x16, 0xBC, 0x61, 0x30, 0x1C, 0x42, -0xE9, 0x69, 0x57, 0xFD, 0xF1, 0xD8, 0x76, 0x1C, 0xB9, 0x3A, 0xBA, 0xF8, 0x10, 0x1F, 0xE2, 0x63, -0x89, 0x8E, 0x7F, 0xB6, 0x93, 0x76, 0xC2, 0x72, 0x3D, 0x10, 0x40, 0x80, 0x00, 0x33, 0x95, 0x5F, -0x03, 0x64, 0x70, 0xF6, 0x23, 0xE6, 0x33, 0x1F, 0x03, 0x63, 0xB1, 0xB4, 0xE8, 0x7C, 0x37, 0x8A, -0x0F, 0xF1, 0x21, 0x3E, 0x96, 0x35, 0x3E, 0xF2, 0x00, 0xC9, 0xFF, 0x63, 0xC4, 0xA6, 0xD3, 0x22, -0x20, 0x40, 0x80, 0x59, 0x8E, 0x6F, 0xEA, 0xF1, 0x60, 0xAB, 0x14, 0x0F, 0x61, 0xE4, 0xCA, 0xE7, -0xB9, 0x6D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0x52, 0xC7, 0x47, 0xFE, 0x25, 0x0F, 0x04, 0x08, 0x20, -0x40, 0x80, 0x19, 0x8F, 0x37, 0xDA, 0xBB, 0xD7, 0x43, 0x39, 0x3A, 0xCA, 0x17, 0x21, 0x2C, 0xB4, -0x3B, 0x7F, 0xDF, 0x8D, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x65, 0x3F, 0xFE, 0xED, 0xED, 0xF4, 0xDA, -0x4E, 0x58, 0x80, 0x00, 0x01, 0x66, 0xA8, 0xD5, 0xAC, 0x1F, 0xEE, 0x7C, 0x15, 0x07, 0xC6, 0x3F, -0xFD, 0xB8, 0xD8, 0x16, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xCC, 0xF1, 0xCF, 0xF6, 0xCD, 0x80, 0x00, -0x02, 0x04, 0x98, 0xE1, 0x50, 0x27, 0x6B, 0x6E, 0x1E, 0x5E, 0x00, 0xA4, 0x56, 0xDA, 0x82, 0xB7, -0xF7, 0xFE, 0xF4, 0x8C, 0x8C, 0xDD, 0x28, 0x3E, 0xC4, 0x87, 0xF8, 0x58, 0x95, 0xE3, 0x1F, 0x5B, -0x02, 0x04, 0x10, 0x20, 0xC0, 0x6C, 0xB4, 0xFE, 0xC5, 0xC3, 0xF5, 0xD0, 0xDE, 0x3F, 0x5C, 0x70, -0x1E, 0xC7, 0x8C, 0x83, 0xB6, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x2B, 0x75, 0xFC, 0xB3, 0xBD, 0x0D, -0x3B, 0x61, 0x01, 0x02, 0x04, 0x98, 0xD1, 0x70, 0x27, 0xD6, 0xE3, 0xC1, 0xCE, 0xC0, 0xF0, 0x27, -0x96, 0x87, 0x42, 0x69, 0x43, 0x9C, 0x66, 0x14, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xD2, 0xF1, 0xB7, -0x10, 0x1D, 0x10, 0x20, 0xC0, 0x0C, 0xC7, 0x3C, 0x8D, 0x98, 0x15, 0x5B, 0xF0, 0x76, 0x03, 0xA3, -0x56, 0x7E, 0xF7, 0xB6, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0xE5, 0x8E, 0x7F, 0xB6, 0x97, 0x5E, 0xD7, -0x9D, 0x20, 0x01, 0x01, 0x02, 0xCC, 0x62, 0xD8, 0x73, 0x2D, 0x5D, 0x03, 0x24, 0x14, 0x31, 0x11, -0x4A, 0x5B, 0xF1, 0xA6, 0x9B, 0xF7, 0xA3, 0xF8, 0x10, 0x1F, 0xE2, 0x63, 0xD5, 0x8E, 0xBF, 0x00, -0x01, 0x04, 0x08, 0x30, 0x33, 0xFB, 0x2F, 0xD4, 0x87, 0xAF, 0xED, 0xD1, 0x7F, 0x0A, 0xD6, 0xED, -0x4C, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0x8A, 0xC7, 0x3F, 0xA6, 0x7D, 0xB7, 0x5B, 0x37, 0x9C, 0x20, -0x01, 0x01, 0x02, 0x4C, 0x5F, 0x36, 0xBA, 0xDB, 0x4D, 0x2D, 0x8D, 0x89, 0xD2, 0x15, 0xCF, 0x0F, -0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x2B, 0x7B, 0xFC, 0xB3, 0xBD, 0xBA, 0x13, 0x24, 0x20, 0x40, 0x80, -0xA9, 0x6A, 0x7E, 0xE4, 0xA1, 0x8D, 0x4E, 0x80, 0x6C, 0xE4, 0x4F, 0xBF, 0x0A, 0x83, 0x8B, 0xCF, -0xB3, 0xDB, 0x41, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0xCA, 0xC7, 0x3F, 0xDB, 0x17, 0x20, 0x80, 0x00, -0x01, 0xA6, 0xAC, 0x16, 0x36, 0x63, 0x6B, 0xA7, 0x5F, 0x1A, 0xB5, 0x62, 0x4C, 0xB4, 0x1B, 0xBA, -0x57, 0x3E, 0x17, 0x1F, 0xE2, 0x43, 0x7C, 0xAC, 0xEE, 0xF1, 0x8F, 0x07, 0x21, 0x7E, 0xFC, 0xED, -0x0D, 0x27, 0x4A, 0x40, 0x80, 0x00, 0xD3, 0x54, 0x4F, 0x0B, 0xD0, 0x63, 0xAF, 0x46, 0x8A, 0x3F, -0xB3, 0xDB, 0x51, 0x7C, 0x88, 0x0F, 0xF1, 0xB1, 0xEA, 0xC7, 0xDF, 0x42, 0x74, 0x40, 0x80, 0x00, -0x33, 0x18, 0x9F, 0xD5, 0x63, 0x6B, 0xB7, 0x3B, 0x01, 0xD2, 0x1B, 0x18, 0xC5, 0xAD, 0xCE, 0x5B, -0x2D, 0xF1, 0x21, 0x3E, 0xC4, 0xC7, 0xCA, 0x1F, 0xFF, 0xAC, 0x29, 0x40, 0x00, 0x01, 0x02, 0x4C, -0x59, 0x7B, 0xAF, 0xBF, 0xCB, 0x4D, 0xAD, 0xB7, 0xDB, 0x55, 0x9A, 0xFD, 0x10, 0x1F, 0xE2, 0x43, -0x7C, 0x38, 0xFE, 0xF9, 0xC5, 0x08, 0xED, 0x84, 0x05, 0x08, 0x10, 0x60, 0xBA, 0x01, 0xD2, 0xAC, -0x97, 0xC7, 0x6C, 0xD9, 0x56, 0xE7, 0xCF, 0xAC, 0x37, 0x56, 0x12, 0x1F, 0xE2, 0x43, 0x7C, 0x38, -0xFE, 0xD9, 0xEE, 0x86, 0x13, 0x25, 0x30, 0x89, 0x75, 0x87, 0x00, 0x98, 0x48, 0x6B, 0xA7, 0x17, -0x20, 0xBD, 0xD9, 0x8F, 0xAD, 0xD8, 0x9F, 0xF9, 0x08, 0xE2, 0x43, 0x7C, 0x88, 0x0F, 0xC7, 0x3F, -0xB6, 0x37, 0x9D, 0x28, 0x81, 0x49, 0x98, 0x01, 0x01, 0xEE, 0xA8, 0xF9, 0xDB, 0x0F, 0x6D, 0x86, -0x6C, 0xBF, 0xD3, 0x1E, 0xB5, 0xFC, 0xEF, 0xF9, 0xEC, 0x47, 0xBB, 0x74, 0x15, 0x74, 0xF1, 0x21, -0x3E, 0xC4, 0x87, 0xE3, 0xDF, 0xDD, 0x09, 0x4B, 0x84, 0x00, 0x02, 0x04, 0x98, 0x8A, 0x7C, 0x07, -0xAC, 0x7C, 0x8C, 0x94, 0xC2, 0xE3, 0x76, 0x31, 0x58, 0xAA, 0x85, 0xDA, 0xC5, 0xF5, 0x70, 0xF5, -0xAD, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x95, 0x3F, 0xFE, 0xED, 0xED, 0xF4, 0xBD, 0xD4, 0x9D, 0x2E, -0x01, 0x01, 0x02, 0x4C, 0xC3, 0x66, 0x68, 0xEF, 0x75, 0xC7, 0x18, 0x2F, 0xC5, 0x7C, 0xED, 0x47, -0xFE, 0xD4, 0xAB, 0xF5, 0x4E, 0x7C, 0xA4, 0x99, 0x8F, 0x97, 0x8B, 0x0F, 0xF1, 0x21, 0x3E, 0x56, -0xFE, 0xF8, 0x77, 0x77, 0xC2, 0x32, 0x03, 0x02, 0xDC, 0x91, 0x35, 0x20, 0xC0, 0x1D, 0xD5, 0xB2, -0x83, 0x6B, 0x31, 0x3D, 0xE7, 0xAA, 0xF3, 0xBF, 0x6C, 0xBB, 0x3B, 0x64, 0x4A, 0x33, 0x1F, 0xF7, -0xBC, 0x59, 0x7C, 0x88, 0x0F, 0xF1, 0xE1, 0xF8, 0xF7, 0xBE, 0x97, 0x98, 0x07, 0xC8, 0x75, 0x67, -0x4C, 0x40, 0x80, 0x00, 0x67, 0xD7, 0xDA, 0xAE, 0xA7, 0xB5, 0xE7, 0x69, 0xF6, 0x23, 0x8D, 0x33, -0x52, 0x7C, 0xDC, 0xFD, 0x26, 0xF1, 0x21, 0x3E, 0xC4, 0x87, 0xE3, 0x3F, 0xF4, 0xBD, 0xB4, 0x8B, -0xCD, 0x2A, 0x00, 0x04, 0x08, 0x70, 0x06, 0xB5, 0xD0, 0x6E, 0x84, 0x56, 0xCC, 0x17, 0x9F, 0x87, -0x4B, 0x9D, 0xF8, 0x78, 0xE3, 0xEB, 0xC4, 0x87, 0xF8, 0x10, 0x1F, 0x8E, 0xFF, 0x98, 0xEF, 0xC5, -0x4E, 0x58, 0xC0, 0x9D, 0x59, 0x03, 0x02, 0x1C, 0xAB, 0xFD, 0x3B, 0xAF, 0xAB, 0xA7, 0xA7, 0x56, -0xB4, 0xBE, 0x22, 0x3E, 0xC4, 0x87, 0xF8, 0x70, 0xFC, 0xEF, 0xF0, 0xBD, 0x64, 0x7B, 0x21, 0x7E, -0xFC, 0xAF, 0xD4, 0x9D, 0x39, 0x01, 0x01, 0x02, 0x9C, 0x45, 0x3D, 0xBB, 0x7D, 0x3B, 0xC4, 0xAC, -0x13, 0x1F, 0x6F, 0x10, 0x1F, 0xE2, 0x43, 0x7C, 0x38, 0xFE, 0xC7, 0x7C, 0x2F, 0xED, 0xDD, 0xFC, -0x9C, 0xE1, 0xB4, 0x09, 0x08, 0x10, 0xE0, 0xD4, 0x0E, 0xF6, 0xB3, 0xCD, 0xD6, 0xED, 0x2C, 0xDC, -0xD5, 0x89, 0x8F, 0x35, 0xF1, 0x21, 0x3E, 0xC4, 0x87, 0xE3, 0x7F, 0xCC, 0xF7, 0x12, 0xDB, 0x07, -0x61, 0xFF, 0xF6, 0x41, 0xC3, 0x99, 0x13, 0x38, 0x8E, 0x35, 0x20, 0xC0, 0xB1, 0x6E, 0x7F, 0x39, -0xBB, 0xB6, 0x7E, 0xED, 0x7A, 0xB8, 0x78, 0xE5, 0x6A, 0x58, 0x13, 0x1F, 0xE2, 0x43, 0x7C, 0x88, -0x8F, 0x23, 0xEC, 0xBE, 0x90, 0x85, 0xBD, 0x17, 0xB7, 0x42, 0xBC, 0xBC, 0x77, 0xCD, 0x99, 0x13, -0x10, 0x20, 0xC0, 0xA9, 0xAD, 0x7D, 0xE3, 0xD7, 0xBD, 0x3A, 0x76, 0xCE, 0x14, 0xB7, 0xFF, 0xF4, -0xD9, 0xB0, 0xBE, 0xF6, 0x5C, 0xB8, 0xE7, 0x81, 0x0B, 0x61, 0xED, 0xD4, 0x67, 0x0E, 0xF1, 0x21, -0x3E, 0xC4, 0xC7, 0xB2, 0xC5, 0xC7, 0xFE, 0x56, 0x0C, 0xBB, 0x5F, 0xCD, 0x42, 0xD6, 0xEA, 0xBD, -0x3F, 0xDB, 0xDD, 0x70, 0xE6, 0x04, 0x8E, 0x1D, 0x5B, 0x38, 0x04, 0xC0, 0x71, 0xFE, 0xCD, 0xAD, -0x7B, 0xDF, 0x71, 0xB0, 0xBD, 0xFB, 0xFE, 0xB8, 0xF7, 0xEC, 0x56, 0x6B, 0x2F, 0x86, 0x17, 0xFF, -0xB4, 0x15, 0xB6, 0x9F, 0xCB, 0xF2, 0x8B, 0x11, 0x8A, 0x0F, 0xF1, 0x21, 0x3E, 0x56, 0x37, 0x3E, -0xD2, 0xF9, 0xE0, 0xF6, 0x17, 0xDB, 0x61, 0xFB, 0xD9, 0x76, 0x11, 0x1F, 0x2F, 0x74, 0x5E, 0xDE, -0xF3, 0xE4, 0x2F, 0xFC, 0x7F, 0x3F, 0xE4, 0xCC, 0x09, 0x1C, 0xA7, 0xE6, 0x10, 0x00, 0x93, 0xF8, -0xF8, 0x7B, 0x36, 0x5F, 0xF9, 0x75, 0xAF, 0x6A, 0xBF, 0xFF, 0xC2, 0xC5, 0xF8, 0x8E, 0xFC, 0xE4, -0xB1, 0x16, 0xC2, 0x95, 0x7B, 0xD7, 0xC2, 0x95, 0x8D, 0x49, 0xFE, 0x3B, 0x86, 0xF8, 0x10, 0x1F, -0xE2, 0x63, 0x59, 0xE2, 0x23, 0x6B, 0x85, 0xB0, 0xF3, 0x95, 0x76, 0x68, 0xEE, 0xC4, 0xF2, 0x6D, -0xFF, 0x70, 0x6D, 0x3D, 0xFC, 0xD2, 0xD7, 0xFC, 0xC8, 0xA7, 0x5E, 0x70, 0xB6, 0x04, 0x04, 0x08, -0x30, 0x55, 0x9F, 0xFC, 0x6F, 0xAF, 0x5F, 0x7F, 0xF9, 0x9F, 0x6B, 0x7F, 0xB0, 0x33, 0xD8, 0xF8, -0xEE, 0xF4, 0xF7, 0xB5, 0xF5, 0x5A, 0xB8, 0xAB, 0x13, 0x21, 0x97, 0xAE, 0xD6, 0xC4, 0x87, 0xF8, -0x10, 0x1F, 0x4B, 0x1C, 0x1F, 0x69, 0xD6, 0x33, 0x3D, 0xD5, 0x6A, 0xEF, 0xA5, 0xC3, 0xE9, 0xCF, -0xAC, 0x1D, 0x7E, 0x77, 0xED, 0x42, 0xF8, 0x9B, 0x9D, 0xF0, 0xF8, 0x8C, 0xB3, 0x23, 0x20, 0x40, -0x80, 0x99, 0xFA, 0xDC, 0x07, 0xFF, 0xE2, 0x0F, 0xDE, 0x73, 0x7F, 0xF6, 0xAB, 0xB5, 0xB5, 0xF0, -0x8D, 0xE9, 0xEF, 0xEB, 0x57, 0xBA, 0x21, 0x92, 0xFE, 0x14, 0x1F, 0xE2, 0x43, 0x7C, 0x2C, 0x57, -0x7C, 0x74, 0x17, 0x98, 0x0F, 0x3C, 0xF5, 0xF2, 0x0F, 0x3B, 0x2F, 0x3F, 0xD3, 0x09, 0x8F, 0x8F, -0x39, 0x1B, 0x02, 0x02, 0x04, 0x98, 0x9B, 0xFF, 0xE3, 0xCD, 0xDF, 0xB5, 0xFE, 0x9D, 0x3F, 0xBA, -0xF7, 0x5F, 0x5C, 0xBE, 0x1A, 0xDF, 0xDB, 0x09, 0x91, 0xAB, 0xE9, 0xB6, 0x8B, 0x77, 0xD7, 0xC2, -0xDD, 0xF7, 0xAF, 0x9D, 0x61, 0xA1, 0xBA, 0xF8, 0x30, 0xF8, 0x15, 0x1F, 0x8B, 0xF2, 0xBD, 0x0C, -0x2F, 0x30, 0xEF, 0x04, 0xC8, 0x9F, 0x76, 0xFE, 0xAD, 0xFF, 0xED, 0x4E, 0x78, 0x7C, 0xD8, 0x19, -0x10, 0x10, 0x20, 0xC0, 0xB9, 0xF9, 0xDC, 0x07, 0xFF, 0xE2, 0x03, 0x97, 0xEE, 0x8A, 0x7F, 0xEB, -0xE2, 0x5D, 0xF1, 0xC7, 0xBB, 0x21, 0x12, 0xF3, 0xD9, 0x90, 0xCB, 0xF7, 0xAE, 0xE5, 0x6B, 0x45, -0xC4, 0x87, 0xC1, 0xAF, 0xF8, 0xA8, 0x56, 0x7C, 0xA4, 0x05, 0xE6, 0x29, 0x3C, 0x0E, 0xF6, 0xFA, -0xDF, 0x57, 0x5A, 0xDB, 0xF1, 0xF7, 0x3B, 0x2F, 0x1F, 0xB0, 0xCE, 0x03, 0x10, 0x20, 0xC0, 0x22, -0x85, 0xC8, 0x83, 0x57, 0x5E, 0x96, 0xFD, 0xF2, 0xFA, 0xE5, 0xF8, 0xF6, 0xFC, 0x04, 0xD3, 0x89, -0x8F, 0x22, 0x44, 0xC4, 0x87, 0xC1, 0xAF, 0xF8, 0x58, 0x7C, 0x69, 0xA6, 0x63, 0x78, 0x81, 0x79, -0xC7, 0x87, 0x5F, 0xFC, 0x42, 0xFB, 0xE7, 0xFF, 0xFC, 0xCF, 0x7E, 0xFA, 0x39, 0x67, 0x39, 0x40, -0x80, 0x00, 0x0B, 0xE9, 0x8B, 0xBF, 0xF5, 0xDA, 0xB7, 0xAE, 0x5F, 0x8C, 0xEF, 0xBD, 0x70, 0x29, -0x7C, 0x67, 0xFA, 0x7B, 0x5A, 0xA8, 0x9E, 0x9E, 0x96, 0x95, 0x9E, 0x9E, 0x25, 0x3E, 0x0C, 0x7E, -0xC5, 0xC7, 0x02, 0x7E, 0x17, 0xF9, 0x02, 0xF3, 0xF6, 0xC0, 0x02, 0xF3, 0x8E, 0x8F, 0xED, 0xBD, -0x98, 0xFD, 0xC4, 0x2B, 0xFF, 0xFA, 0x9F, 0x7C, 0xCA, 0x59, 0x0D, 0x10, 0x20, 0xC0, 0xC2, 0xFB, -0x17, 0x6F, 0xFC, 0x8E, 0xF5, 0xEF, 0xFA, 0xB1, 0xE6, 0x8F, 0x5C, 0xBE, 0x27, 0xBE, 0xEF, 0xF8, -0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0xF3, 0x94, 0xA2, 0x23, 0xC5, 0x47, 0xB1, 0xC0, 0x3C, -0xB6, 0xC3, 0xBF, 0xAD, 0x75, 0x77, 0xB6, 0xFA, 0x98, 0x33, 0x19, 0x20, 0x40, 0x80, 0x2A, 0x86, -0xC8, 0x95, 0xEF, 0x7D, 0xD7, 0xFE, 0xE3, 0x6B, 0xEB, 0xE1, 0xA7, 0x8B, 0x85, 0xEA, 0x97, 0xAE, -0xAE, 0xE5, 0x21, 0x72, 0xC7, 0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x88, 0x8F, 0x99, 0x49, 0x4F, 0xB3, -0x4A, 0x4F, 0xB7, 0xB2, 0xC0, 0x1C, 0x10, 0x20, 0xC0, 0x52, 0xFA, 0xF7, 0x7F, 0xEF, 0xDB, 0xBF, -0xFE, 0xBE, 0xFF, 0x20, 0xFE, 0xF2, 0xC5, 0x2B, 0xF1, 0xC7, 0xF3, 0x93, 0x4F, 0xEF, 0x42, 0x86, -0x47, 0x2E, 0x54, 0x17, 0x1F, 0xE2, 0x43, 0x7C, 0xCC, 0xC4, 0xE0, 0x02, 0xF3, 0xFE, 0x15, 0xCC, -0x2D, 0x30, 0x07, 0x04, 0x08, 0xB0, 0x9C, 0xFE, 0xE4, 0x03, 0xDF, 0xFE, 0x9A, 0xAB, 0x5F, 0x97, -0x7D, 0x60, 0xFD, 0x52, 0x78, 0x53, 0x11, 0x22, 0x77, 0xDF, 0x7F, 0x61, 0xF0, 0x42, 0x86, 0xE2, -0x43, 0x7C, 0x88, 0x8F, 0xA9, 0x4B, 0x57, 0x30, 0x4F, 0xE1, 0xB1, 0xBF, 0x95, 0x95, 0xBF, 0x17, -0x0B, 0xCC, 0x01, 0x01, 0x02, 0xAC, 0x86, 0x2F, 0xFC, 0xC6, 0x6B, 0x7F, 0xE0, 0xF2, 0xD5, 0xF8, -0xFE, 0xB5, 0xF5, 0xF0, 0x60, 0xFA, 0x7B, 0x5A, 0xA8, 0x7E, 0xCF, 0x03, 0x6B, 0x61, 0xFD, 0x72, -0xD5, 0x06, 0x8E, 0xE2, 0x43, 0x7C, 0x2C, 0xF8, 0xA1, 0xCC, 0x8A, 0x75, 0x1E, 0xE5, 0x05, 0xE6, -0xD1, 0x02, 0x73, 0x40, 0x80, 0x00, 0xAB, 0x27, 0x2D, 0x54, 0xFF, 0xEE, 0x77, 0x36, 0xDF, 0x75, -0xE1, 0x62, 0x7C, 0xF7, 0xDA, 0x85, 0xF0, 0xF5, 0xB1, 0x33, 0xE8, 0xBC, 0x78, 0xA5, 0xBB, 0x63, -0xD6, 0x85, 0x4B, 0xD3, 0x3C, 0x3D, 0x89, 0x0F, 0xF1, 0xB1, 0x9A, 0xC7, 0xBF, 0x08, 0x8F, 0xD1, -0x05, 0xE6, 0x9F, 0xFC, 0x98, 0x33, 0x10, 0x20, 0x40, 0x80, 0x95, 0xF5, 0xB9, 0x7F, 0xF4, 0xDA, -0x07, 0x2E, 0x5D, 0x8D, 0xBF, 0xB0, 0x7E, 0x29, 0xFE, 0x64, 0xB1, 0x50, 0xFD, 0xF2, 0xD5, 0xB5, -0x3C, 0x44, 0xCE, 0x7E, 0x21, 0x43, 0xF1, 0x21, 0x3E, 0x56, 0xEF, 0xF8, 0x77, 0x17, 0x98, 0x8F, -0xBB, 0x82, 0xF9, 0x27, 0x3F, 0xEC, 0x8C, 0x03, 0x08, 0x10, 0x80, 0x9E, 0x7F, 0xF3, 0x5F, 0xBF, -0xF6, 0x95, 0xAF, 0x78, 0x30, 0x7B, 0xFF, 0x85, 0x8B, 0xE1, 0x1D, 0xF9, 0x09, 0xAA, 0xB7, 0x50, -0xFD, 0xCA, 0xA9, 0xAF, 0xA8, 0x2E, 0x3E, 0xC4, 0xC7, 0x6A, 0x1D, 0xFF, 0xE3, 0xAF, 0x60, 0xFE, -0x49, 0x0B, 0xCC, 0x01, 0x01, 0x02, 0x30, 0xCE, 0x67, 0x7F, 0xED, 0x35, 0xAF, 0xBB, 0xFB, 0xE5, -0xF9, 0xFA, 0x90, 0xEF, 0x4E, 0x7F, 0x4F, 0xEB, 0x43, 0xF2, 0x2B, 0xAA, 0x5F, 0x3D, 0xC9, 0x29, -0x4B, 0x7C, 0x88, 0x8F, 0xD5, 0x39, 0xFE, 0xA3, 0x0B, 0xCC, 0x73, 0xBD, 0x05, 0xE6, 0x7F, 0x62, -0x81, 0x39, 0x20, 0x40, 0x00, 0x26, 0x0A, 0x91, 0x7F, 0xF4, 0x9A, 0x1F, 0xBC, 0xE7, 0xFE, 0xF8, -0xAB, 0xC5, 0x85, 0x0C, 0xD3, 0xBA, 0x90, 0x7B, 0xEE, 0x9F, 0xE4, 0x42, 0x86, 0xE2, 0x43, 0x7C, -0xAC, 0xC6, 0xF1, 0x1F, 0xBF, 0xC0, 0xBC, 0xB8, 0x82, 0xF9, 0x1F, 0x5B, 0x60, 0x0E, 0x08, 0x10, -0x80, 0x93, 0xFA, 0x48, 0xE3, 0xFA, 0xFA, 0x77, 0xBF, 0xB3, 0xF5, 0x0B, 0x17, 0xAF, 0xC4, 0x5F, -0x2C, 0xD6, 0x87, 0xA4, 0x85, 0xEA, 0xF7, 0x3C, 0x70, 0xE1, 0x88, 0x0B, 0x19, 0x8A, 0x0F, 0xF1, -0xB1, 0x1A, 0xC7, 0xDF, 0x02, 0x73, 0x40, 0x80, 0x00, 0xCC, 0xD0, 0x67, 0x7F, 0xED, 0x35, 0x0F, -0x5C, 0xBC, 0x3B, 0xFC, 0xAD, 0xCB, 0xF7, 0xC4, 0xC7, 0x8A, 0xDB, 0xD2, 0xDA, 0x90, 0xF4, 0xD4, -0xAC, 0xC3, 0xF5, 0x21, 0xE2, 0x43, 0x7C, 0x2C, 0xFF, 0xF1, 0xB7, 0xC0, 0x1C, 0x10, 0x20, 0x00, -0xF3, 0x0D, 0x91, 0x07, 0xAF, 0xDC, 0x1B, 0x7F, 0x79, 0xFD, 0x72, 0x78, 0x7B, 0x7E, 0x12, 0x5B, -0x2B, 0x42, 0x64, 0x56, 0xA7, 0x33, 0xF1, 0x21, 0x3E, 0x16, 0x83, 0x05, 0xE6, 0x80, 0x00, 0x01, -0x38, 0x47, 0xCF, 0x7C, 0xF8, 0x35, 0x6F, 0x5D, 0xBF, 0x18, 0xDF, 0x7B, 0xE1, 0x52, 0xF8, 0xCE, -0x34, 0x70, 0x3C, 0xDD, 0x42, 0x75, 0xF1, 0x21, 0x3E, 0x16, 0xFF, 0xF8, 0x5B, 0x60, 0x0E, 0x08, -0x10, 0x80, 0x05, 0x91, 0xD6, 0x87, 0x7C, 0xCF, 0xBB, 0x0E, 0xDE, 0xB5, 0x7E, 0x29, 0xFE, 0x52, -0xB1, 0x50, 0x3D, 0xAD, 0x0F, 0x49, 0x21, 0x72, 0xE7, 0x85, 0xEA, 0xE2, 0x43, 0x7C, 0x2C, 0xF6, -0xF1, 0x3F, 0x6A, 0x81, 0x79, 0x27, 0x3C, 0x7E, 0xAA, 0x13, 0x1E, 0x7F, 0xE4, 0x0C, 0x00, 0x08, -0x10, 0x80, 0x73, 0xF2, 0xCF, 0x1F, 0x7A, 0xCD, 0x95, 0x87, 0x7E, 0x2A, 0x7B, 0x7C, 0x6D, 0x3D, -0xFC, 0x74, 0xF9, 0x42, 0x86, 0x29, 0x44, 0xC6, 0x2F, 0x54, 0x17, 0x1F, 0xE2, 0x63, 0xB1, 0x8F, -0xFF, 0xB8, 0x05, 0xE6, 0xED, 0x83, 0xF8, 0x33, 0xAF, 0xF8, 0x6B, 0x9F, 0xFA, 0x97, 0xFE, 0xC5, -0x03, 0x02, 0x04, 0x60, 0x41, 0xFC, 0xBB, 0xF7, 0x7D, 0xDB, 0x2B, 0xEE, 0x7B, 0x65, 0x7C, 0xEF, -0xC5, 0x2B, 0xE1, 0xC7, 0x8B, 0xDB, 0x52, 0x84, 0x9C, 0xEC, 0x42, 0x86, 0xE2, 0x43, 0x7C, 0x9C, -0x9F, 0xE1, 0x05, 0xE6, 0x1D, 0x2F, 0x74, 0xC2, 0xE3, 0xE7, 0xBF, 0xEE, 0xC7, 0x3E, 0xF5, 0x1B, -0xFE, 0x85, 0x03, 0x02, 0x04, 0x60, 0x41, 0xFD, 0xF1, 0x7F, 0xFF, 0x6D, 0xAF, 0xB9, 0xF7, 0x1B, -0xE2, 0x6F, 0x14, 0x17, 0x32, 0x4C, 0xF1, 0x51, 0x84, 0x88, 0xF8, 0x10, 0x1F, 0x8B, 0x78, 0xFC, -0x87, 0x17, 0x98, 0xC7, 0x2C, 0x6C, 0x75, 0x7E, 0x6F, 0xFF, 0xBB, 0x60, 0x81, 0x39, 0x20, 0x40, -0x00, 0xAA, 0xE3, 0xF3, 0xFF, 0xE3, 0xB7, 0xFE, 0xC0, 0x95, 0x97, 0x85, 0x74, 0x45, 0xF5, 0x07, -0xD3, 0xDF, 0xD3, 0x42, 0xF5, 0xBB, 0xEF, 0x5F, 0x0B, 0x97, 0xEE, 0xAE, 0x89, 0x0F, 0xF1, 0xB1, -0x10, 0x8E, 0x5A, 0x60, 0xDE, 0x79, 0x79, 0x4F, 0x27, 0x3C, 0x3E, 0xE3, 0x5F, 0x31, 0x20, 0x40, -0x00, 0x2A, 0xE6, 0x9F, 0x3F, 0xF4, 0x9A, 0xF5, 0xEF, 0xFD, 0x1B, 0xD9, 0xBB, 0xD6, 0x2F, 0x85, -0xF7, 0x97, 0x2F, 0x64, 0x98, 0x42, 0x24, 0x5D, 0x59, 0x5D, 0x7C, 0x88, 0x8F, 0x73, 0x79, 0x14, -0x47, 0x2C, 0x30, 0x6F, 0x6E, 0xC7, 0x9F, 0xFF, 0x86, 0xFF, 0xEC, 0x53, 0xFF, 0xAF, 0x7F, 0xB9, -0x80, 0x00, 0x01, 0xA8, 0xB8, 0xCF, 0xFE, 0xDA, 0xB7, 0x3E, 0x70, 0xF9, 0x6A, 0xF8, 0x85, 0xF5, -0xCB, 0xE1, 0x27, 0x0F, 0x17, 0xAA, 0xD7, 0xCE, 0xB0, 0x50, 0x5D, 0x7C, 0x88, 0x8F, 0xD3, 0x19, -0x5E, 0x60, 0xDE, 0xF1, 0x99, 0xD6, 0x5E, 0xFC, 0x09, 0x0B, 0xCC, 0x01, 0x01, 0x02, 0xB0, 0x9C, -0x21, 0xF2, 0xEA, 0xBB, 0x36, 0xC2, 0xBB, 0x2F, 0x5C, 0x0C, 0xEF, 0x48, 0x03, 0xD2, 0xE2, 0x42, -0x86, 0x27, 0x5B, 0xA8, 0x2E, 0x3E, 0xC4, 0xC7, 0xC9, 0x59, 0x60, 0x0E, 0x20, 0x40, 0x80, 0x95, -0x0E, 0x91, 0x07, 0x5F, 0x77, 0xF7, 0xCB, 0xF3, 0xF5, 0x21, 0xFD, 0x85, 0xEA, 0x77, 0xDF, 0x7F, -0x61, 0xCA, 0x17, 0x32, 0x14, 0x1F, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0x50, 0xF2, 0x85, -0xFF, 0xE9, 0xC1, 0xBF, 0x7A, 0xF9, 0x6A, 0x78, 0x5F, 0x71, 0x21, 0xC3, 0xB4, 0x50, 0xFD, 0xEA, -0x03, 0xD3, 0xB8, 0x90, 0xA1, 0xF8, 0x58, 0xF5, 0xF8, 0xB0, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x8C, -0xF5, 0xCF, 0xBE, 0xE7, 0xD5, 0xEB, 0xAF, 0xFB, 0xC9, 0xDA, 0x2F, 0x5C, 0xBC, 0x12, 0x7E, 0xB1, -0xBC, 0x50, 0xFD, 0x9E, 0x07, 0x2E, 0x9C, 0x71, 0x7D, 0x88, 0xF8, 0x58, 0xC5, 0xF8, 0xB0, 0xC0, -0x1C, 0x40, 0x80, 0x00, 0x4C, 0xE4, 0xB3, 0xFF, 0xF0, 0xC1, 0x07, 0x2E, 0xDF, 0x1B, 0xFE, 0x6E, -0xF9, 0x42, 0x86, 0xE9, 0x8A, 0xEA, 0x69, 0xC7, 0xAC, 0x93, 0xAF, 0x0F, 0x11, 0x1F, 0xAB, 0x18, -0x1F, 0xFB, 0x5B, 0x69, 0x9D, 0x47, 0xDB, 0x02, 0x73, 0x00, 0x01, 0x02, 0x70, 0xA2, 0x10, 0x79, -0xF5, 0x5D, 0x2F, 0x0F, 0x1F, 0xB8, 0x70, 0x31, 0x7C, 0x5F, 0x7E, 0xA2, 0x3C, 0xF1, 0x42, 0x75, -0xF1, 0xB1, 0x6A, 0xF1, 0x91, 0xD6, 0x79, 0x6C, 0x3D, 0x6B, 0x81, 0x39, 0x80, 0x00, 0x01, 0x38, -0x83, 0x67, 0x3E, 0xF4, 0xE0, 0x5B, 0x2F, 0x5E, 0x09, 0xEF, 0x2E, 0x16, 0xAA, 0xA7, 0xF5, 0x21, -0x69, 0xDB, 0xDE, 0xE3, 0x17, 0xAA, 0x8B, 0x8F, 0x55, 0x8A, 0x8F, 0x76, 0xB3, 0xBB, 0xB3, 0x95, -0x05, 0xE6, 0x00, 0x02, 0x04, 0x60, 0x2A, 0xD2, 0xFA, 0x90, 0x87, 0xFE, 0xF3, 0x5A, 0xBA, 0x90, -0xE1, 0x2F, 0x15, 0x0B, 0xD5, 0xD3, 0xFA, 0x90, 0x14, 0x22, 0xA3, 0x0B, 0xD5, 0xC5, 0xC7, 0xAA, -0xC4, 0x87, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x60, 0xA6, 0xD2, 0xFA, 0x90, 0xBB, 0x36, 0xC2, 0xCF, -0xAD, 0xAD, 0x87, 0x9F, 0x2E, 0x16, 0xAA, 0x5F, 0xBA, 0xBB, 0x96, 0x6F, 0xDD, 0xDB, 0x5D, 0xA8, -0x2E, 0x3E, 0x56, 0x21, 0x3E, 0x8A, 0x05, 0xE6, 0x7B, 0x2F, 0x0E, 0x5C, 0x48, 0xD0, 0x02, 0x73, -0x00, 0x01, 0x02, 0x30, 0x1B, 0x7F, 0xF4, 0x77, 0x1F, 0x7C, 0xC5, 0xFD, 0xD7, 0xF2, 0xF5, 0x21, -0xEF, 0x28, 0x6E, 0xBB, 0xF2, 0xB2, 0x5A, 0xB8, 0xEB, 0xE5, 0xB3, 0xBE, 0x90, 0xA1, 0xF8, 0x38, -0xEF, 0xF8, 0x18, 0xB7, 0xC0, 0xBC, 0x13, 0x22, 0x3F, 0xF5, 0xCA, 0xBF, 0xFE, 0xC7, 0x4F, 0xFA, -0x97, 0x01, 0x20, 0x40, 0x00, 0x66, 0x2A, 0x2D, 0x54, 0xBF, 0xFB, 0xE5, 0xE1, 0xC3, 0x6B, 0xEB, -0xB1, 0x7F, 0x21, 0xC3, 0x2B, 0xF7, 0xAD, 0xE5, 0x4F, 0xCD, 0x12, 0x1F, 0xCB, 0x15, 0x1F, 0xE3, -0x16, 0x98, 0x37, 0x77, 0xE2, 0x7F, 0xF5, 0x0D, 0xEF, 0xFC, 0xD4, 0x07, 0xFD, 0x4B, 0x00, 0x10, -0x20, 0x00, 0x73, 0xF5, 0xF9, 0x5F, 0x7F, 0xF5, 0x0F, 0xDC, 0x75, 0x5F, 0xF8, 0x60, 0xF9, 0x42, -0x86, 0x77, 0x7F, 0xCD, 0x5A, 0xFE, 0xF4, 0x2C, 0xF1, 0x51, 0xED, 0xF8, 0x18, 0xB7, 0xC0, 0xBC, -0xF3, 0xF2, 0xF7, 0xD7, 0xD6, 0xC3, 0xFB, 0x2D, 0x30, 0x07, 0x10, 0x20, 0x00, 0xE7, 0xE6, 0x7F, -0xFB, 0xAE, 0x6F, 0x59, 0x7F, 0xF8, 0x6F, 0x5E, 0x48, 0x0B, 0xD5, 0xDF, 0x5F, 0xBE, 0x90, 0x61, -0x7A, 0x5A, 0xD6, 0xF4, 0xAE, 0xA8, 0x2E, 0x3E, 0xE6, 0x15, 0x1F, 0xE3, 0x16, 0x98, 0x67, 0xED, -0xF0, 0x4F, 0xD6, 0x2E, 0x84, 0x5F, 0xB2, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x2C, 0x8C, 0xCF, 0xFE, -0xEA, 0xAB, 0x1E, 0xB8, 0xB2, 0x51, 0xFB, 0xB9, 0x4E, 0x88, 0xFC, 0x62, 0x71, 0x5B, 0xBA, 0x90, -0x61, 0x0A, 0x91, 0xB3, 0x5D, 0x51, 0x5D, 0x7C, 0xCC, 0x23, 0x3E, 0x2C, 0x30, 0x07, 0x10, 0x20, -0x00, 0x55, 0x0D, 0x91, 0x57, 0xDF, 0xF5, 0xF2, 0xDA, 0xBB, 0xCB, 0x0B, 0xD5, 0x53, 0x84, 0x4C, -0x7E, 0x21, 0x43, 0xF1, 0x31, 0xEF, 0xF8, 0xB0, 0xC0, 0x1C, 0x40, 0x80, 0x00, 0x54, 0xDE, 0x33, -0xBF, 0xF9, 0xEA, 0x81, 0x0B, 0x19, 0xA6, 0xF8, 0x28, 0x42, 0x44, 0x7C, 0x2C, 0x46, 0x7C, 0x58, -0x60, 0x0E, 0x20, 0x40, 0x00, 0x96, 0xCE, 0x17, 0x7E, 0xE3, 0xD5, 0x7F, 0xF5, 0xF2, 0xD5, 0xF0, -0xBE, 0xF2, 0x42, 0xF5, 0xAB, 0x5F, 0xBB, 0xC0, 0xEB, 0x43, 0x56, 0x20, 0x3E, 0x2C, 0x30, 0x07, -0x10, 0x20, 0x00, 0x4B, 0x2D, 0x2D, 0x54, 0x6F, 0xFC, 0xEC, 0x85, 0xC7, 0x6B, 0xB5, 0xF0, 0x58, -0x79, 0xA1, 0x7A, 0xDA, 0x31, 0xEB, 0xC2, 0xA5, 0x05, 0x3A, 0x15, 0x2F, 0x79, 0x7C, 0x58, 0x60, -0x0E, 0x20, 0x40, 0x00, 0x56, 0x4A, 0x5A, 0xA8, 0x7E, 0xF9, 0xDE, 0xDA, 0xAF, 0x5C, 0xBC, 0x12, -0x7E, 0xA2, 0xB8, 0x6D, 0x61, 0x16, 0xAA, 0x2F, 0x71, 0x7C, 0x1C, 0xB5, 0xC0, 0xBC, 0xF3, 0xF2, -0x9E, 0x4E, 0x78, 0x7C, 0xCC, 0x6F, 0x26, 0x80, 0x00, 0x01, 0x58, 0xF6, 0x10, 0x49, 0x0B, 0xD5, -0xD3, 0x15, 0xD5, 0xBF, 0x2F, 0x3F, 0x19, 0xF7, 0x2E, 0x64, 0x78, 0x6E, 0x0B, 0xD5, 0x97, 0x38, -0x3E, 0xC6, 0x2D, 0x30, 0x6F, 0xED, 0xC7, 0x9F, 0x7F, 0xC5, 0x7F, 0xFA, 0xA9, 0x7F, 0xE6, 0x37, -0x11, 0x40, 0x80, 0x00, 0xAC, 0x94, 0xB4, 0x50, 0xFD, 0xD2, 0xDD, 0xF9, 0xF5, 0x43, 0x5E, 0x9B, -0xFE, 0x9E, 0xD6, 0x87, 0xA4, 0xD9, 0x90, 0xCB, 0x57, 0xE7, 0x78, 0x7A, 0x5E, 0xD2, 0xF8, 0x18, -0xB7, 0xC0, 0xBC, 0x7D, 0x10, 0xFE, 0xCE, 0xD7, 0xFD, 0xD8, 0x27, 0xDF, 0xEF, 0x37, 0x0F, 0x40, -0x80, 0x00, 0xAC, 0xAC, 0x7F, 0xFA, 0x1D, 0xF5, 0xF5, 0xD7, 0x3F, 0x76, 0x39, 0x5D, 0xC8, 0xF0, -0x97, 0x8A, 0x85, 0xEA, 0x69, 0x5D, 0xC8, 0x3D, 0x5F, 0x33, 0x87, 0x85, 0xEA, 0x4B, 0x18, 0x1F, -0xC3, 0x0B, 0xCC, 0x93, 0xAC, 0x15, 0xFE, 0x8E, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x80, 0x92, 0xE2, -0x42, 0x86, 0x17, 0xD6, 0xC3, 0x4F, 0x97, 0x17, 0xAA, 0xDF, 0xF3, 0xB5, 0x17, 0x66, 0xB3, 0x3E, -0x64, 0xC9, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x29, 0x3C, 0xF3, 0x9B, 0xAF, 0xFA, -0xE6, 0xF5, 0xCB, 0xB5, 0xF7, 0x96, 0x2F, 0x64, 0x98, 0x16, 0xAA, 0xA7, 0x1D, 0xB3, 0xA6, 0xB6, -0x3E, 0x64, 0x89, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x14, 0x7C, 0xE9, 0xB7, 0x5E, -0xF5, 0x9D, 0x17, 0x2E, 0xD6, 0xFE, 0x87, 0xB5, 0xF5, 0xF0, 0x3D, 0xF9, 0x09, 0xBB, 0xB7, 0x50, -0xFD, 0xAE, 0x8D, 0x33, 0x56, 0xC8, 0x12, 0xC5, 0x87, 0x05, 0xE6, 0x00, 0x02, 0x04, 0x80, 0x29, -0xFB, 0xFC, 0xAF, 0xBF, 0xEA, 0x07, 0xEE, 0xBA, 0xAF, 0xF6, 0xC1, 0xF2, 0x85, 0x0C, 0x4F, 0xBD, -0x50, 0x7D, 0x49, 0xE2, 0xC3, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x0C, 0xA5, 0x85, 0xEA, 0x8F, -0xFC, 0x97, 0x97, 0x1F, 0xED, 0x44, 0xC8, 0xBB, 0xCB, 0xEB, 0x43, 0x52, 0x88, 0x4C, 0xBC, 0x50, -0x7D, 0x09, 0xE2, 0x63, 0xDC, 0x02, 0xF3, 0x4E, 0x8C, 0xFC, 0x37, 0x9D, 0x63, 0xF0, 0x3E, 0x0B, -0xCC, 0x01, 0x04, 0x08, 0x00, 0x53, 0x56, 0x2C, 0x54, 0x5F, 0xBF, 0x14, 0x7E, 0xB1, 0xB8, 0xED, -0xD2, 0xDD, 0xE9, 0x8A, 0xEA, 0x77, 0x58, 0xA8, 0x5E, 0xF1, 0xF8, 0x48, 0x4F, 0xB1, 0x4A, 0xE1, -0x51, 0x5E, 0x60, 0xDE, 0x6A, 0xC6, 0xFF, 0x75, 0xFD, 0x52, 0xED, 0x17, 0x2D, 0x30, 0x07, 0x10, -0x20, 0x00, 0xCC, 0x3E, 0x44, 0x5E, 0x7D, 0xCF, 0x03, 0xB5, 0x74, 0xFD, 0x90, 0xBF, 0x5C, 0xDC, -0x96, 0x2E, 0x62, 0x98, 0x66, 0x44, 0x46, 0x16, 0xAA, 0x57, 0x38, 0x3E, 0xC6, 0x2D, 0x30, 0xCF, -0xDA, 0xE1, 0x5F, 0xAF, 0x5D, 0x08, 0x7F, 0xDB, 0x02, 0x73, 0x00, 0x01, 0x02, 0xC0, 0x9C, 0x3D, -0xF3, 0x9B, 0xAF, 0x7A, 0xEB, 0xC5, 0x2B, 0xB5, 0xC7, 0xCB, 0x0B, 0xD5, 0x53, 0x84, 0xA4, 0x18, -0xA9, 0x7A, 0x7C, 0xA4, 0x05, 0xE6, 0x69, 0x5B, 0xDD, 0xD2, 0x3A, 0x0F, 0x0B, 0xCC, 0x01, 0x04, -0x08, 0x00, 0x8B, 0xE0, 0x4B, 0xFF, 0xF8, 0xD5, 0x7F, 0xA3, 0x7C, 0x21, 0xC3, 0xF4, 0x74, 0xAC, -0xBB, 0xEF, 0x5F, 0xCB, 0x9F, 0x9E, 0x55, 0xB5, 0xF8, 0x48, 0x0B, 0xCC, 0xB7, 0xBF, 0x92, 0xE5, -0xEB, 0x3D, 0x7A, 0xF2, 0x05, 0xE6, 0xFF, 0xF2, 0x57, 0x6E, 0x7F, 0xE0, 0x3F, 0xF9, 0xC4, 0x97, -0x5A, 0x7E, 0xDA, 0x00, 0x02, 0x04, 0x80, 0x05, 0x90, 0x2F, 0x54, 0xFF, 0xF9, 0xCB, 0x8F, 0xD7, -0x6A, 0xE1, 0xB1, 0xDA, 0x5A, 0x3C, 0x5C, 0xA8, 0xBE, 0x31, 0x87, 0x2B, 0xAA, 0x4F, 0x21, 0x3E, -0xD2, 0x85, 0x04, 0xB7, 0x9F, 0x6D, 0x5B, 0x60, 0x0E, 0x20, 0x40, 0x00, 0xA8, 0x92, 0xCF, 0xFC, -0x83, 0x6F, 0x79, 0xE0, 0xEE, 0xFB, 0xD7, 0xFE, 0xC1, 0xF0, 0x85, 0x0C, 0x53, 0x88, 0xCC, 0xE4, -0x8A, 0xEA, 0x67, 0x8C, 0x0F, 0x0B, 0xCC, 0x01, 0x04, 0x08, 0x00, 0xCB, 0x11, 0x22, 0xAF, 0xBE, -0xFA, 0xB5, 0x6B, 0xBF, 0x51, 0x5B, 0x0B, 0x0F, 0xE5, 0x27, 0xFC, 0xB5, 0xEE, 0x42, 0xF5, 0xF4, -0x32, 0xB5, 0x2B, 0xAA, 0x9F, 0x21, 0x3E, 0x2C, 0x30, 0x07, 0x10, 0x20, 0x00, 0x2C, 0xA1, 0x67, -0x7E, 0xF3, 0x2F, 0xBC, 0xF5, 0xD2, 0xDD, 0xF9, 0x8E, 0x59, 0xAF, 0x2D, 0x42, 0xE4, 0xEE, 0xFB, -0x2F, 0x9C, 0xEE, 0x42, 0x86, 0x53, 0x8A, 0x0F, 0x0B, 0xCC, 0x01, 0x04, 0x08, 0x00, 0x4B, 0xEC, -0x7F, 0xB9, 0xFE, 0x8D, 0xEB, 0x8D, 0x9F, 0xBD, 0xEB, 0x5D, 0x17, 0xEF, 0xAA, 0xBD, 0xAF, 0xF3, -0xD7, 0x8D, 0x74, 0x5B, 0xBA, 0xA2, 0xFA, 0xD5, 0x07, 0x66, 0xB9, 0x3E, 0x64, 0x34, 0x3E, 0x2C, -0x30, 0x07, 0x40, 0x80, 0x00, 0xAC, 0x90, 0xB4, 0x3E, 0xE4, 0xAE, 0x97, 0xD7, 0x7E, 0xEE, 0xC2, -0x7A, 0xED, 0xA7, 0xCB, 0x57, 0x54, 0x4F, 0x3B, 0x66, 0x5D, 0xB8, 0x34, 0xCD, 0xFF, 0x4B, 0x18, -0x8C, 0x0F, 0x0B, 0xCC, 0x01, 0x10, 0x20, 0x00, 0x2B, 0xEC, 0x99, 0xDF, 0xFC, 0x0B, 0xDF, 0xBC, -0x7E, 0xB9, 0xF6, 0xDE, 0xE1, 0x85, 0xEA, 0x57, 0xEE, 0xAD, 0x4D, 0x21, 0x44, 0xE2, 0x40, 0x78, -0xA4, 0xA7, 0x5A, 0x59, 0x60, 0x0E, 0x80, 0x00, 0x01, 0x20, 0x7C, 0xE5, 0x9F, 0xBE, 0xAA, 0xD1, -0x89, 0x84, 0x5F, 0x29, 0x2E, 0x64, 0x98, 0xA4, 0x00, 0x49, 0x0B, 0xD5, 0xD3, 0xCC, 0xC8, 0xC9, -0x77, 0xCD, 0x8A, 0xF9, 0x82, 0xF2, 0xE6, 0x4E, 0x0C, 0xCD, 0xDB, 0xD9, 0xC0, 0x8C, 0x47, 0x6C, -0x87, 0x7F, 0x5D, 0xB3, 0xC0, 0x1C, 0x40, 0x80, 0x38, 0x04, 0x00, 0xFC, 0xD9, 0x3F, 0x79, 0xD5, -0x5F, 0xB9, 0x70, 0x31, 0xBC, 0xBF, 0xF3, 0x66, 0xBD, 0x7C, 0x7B, 0x8A, 0x91, 0x22, 0x44, 0xD6, -0x3B, 0x6F, 0xA7, 0x05, 0xEC, 0xE5, 0x19, 0x92, 0xB4, 0x96, 0x23, 0x05, 0x47, 0xAB, 0xF3, 0x67, -0x5A, 0x50, 0x7E, 0xB0, 0x1B, 0xCB, 0xEB, 0x3B, 0x0A, 0x9F, 0xE9, 0xBC, 0xBC, 0xA7, 0x13, 0x1E, -0x1F, 0x76, 0xA4, 0x01, 0x10, 0x20, 0x00, 0xF4, 0xA5, 0x1D, 0xB3, 0xD6, 0x2F, 0xD7, 0x1E, 0xED, -0xC4, 0xC8, 0xF7, 0x9F, 0xE8, 0x13, 0xE3, 0xD8, 0xDD, 0xAE, 0x7E, 0x7B, 0xEF, 0xA5, 0xF8, 0xEB, -0xAF, 0xFC, 0x89, 0x4F, 0x3D, 0xE9, 0xC8, 0x02, 0x20, 0x40, 0x00, 0x38, 0x52, 0x5A, 0xAC, 0x7E, -0xF9, 0x65, 0xB5, 0x37, 0x5E, 0x58, 0xAF, 0x35, 0x6A, 0x6B, 0xA1, 0xB1, 0xB6, 0x1E, 0x1E, 0xBC, -0x53, 0x7C, 0xC4, 0x2C, 0xFC, 0xDB, 0xCE, 0x9B, 0x7F, 0xB8, 0x76, 0x21, 0xFC, 0x5F, 0x2F, 0x7D, -0xB1, 0xFD, 0xBB, 0xDF, 0xF4, 0xD8, 0x9F, 0x3C, 0xE7, 0x48, 0x02, 0x20, 0x40, 0x00, 0x38, 0xB1, -0xB4, 0x8D, 0xEF, 0x77, 0xFF, 0xF8, 0x95, 0x6F, 0x7E, 0xD9, 0x2B, 0xD6, 0xBE, 0x61, 0xF8, 0x7D, -0x9D, 0xD8, 0xF8, 0xE2, 0x37, 0x3D, 0xFA, 0xC7, 0xFF, 0xCE, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xC7, -0xFF, 0x2F, 0xC0, 0x00, 0x23, 0xF2, 0x4C, 0x01, 0x21, 0x26, 0xDF, 0x39, 0x00, 0x00, 0x00, 0x00, -0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; diff --git a/lib/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino b/lib/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino deleted file mode 100755 index e9ff771e4..000000000 --- a/lib/libesp32/ESP32-Mail-Client/examples/Set_flag/Set_flag.ino +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2019 mobizt - * -*/ - - -#include -#include "ESP32_MailClient.h" - -#define WIFI_SSID "YOUR_WIFI_SSID" -#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" - -//The Email Reading data object contains config and data that received -IMAPData imapData; - -void readEmail(); - -unsigned long lastTime = 0; - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - Serial.println(); - - Serial.println(); - - imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD"); - imapData.setFolder("INBOX"); - imapData.setDebug(true); - - //Set \Seen and \Answered to flags for message with UID 100 - MailClient.setFlag(imapData, 100, "\\Seen \\Answered"); - - //Add \Seen and \Answered to flags for message with UID 100 - //MailClient.addFlag(imapData, 100, "\\Seen \\Answered"); - - //Remove \Seen and \Answered from flags for message with UID 100 - //MailClient.removeFlag(imapData, 100, "\\Seen \\Answered"); -} - - - -void loop() -{ - -} - diff --git a/lib/libesp32/ESP32-Mail-Client/examples/Time/Time.ino b/lib/libesp32/ESP32-Mail-Client/examples/Time/Time.ino deleted file mode 100755 index 4726064d3..000000000 --- a/lib/libesp32/ESP32-Mail-Client/examples/Time/Time.ino +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2019 mobizt - * -*/ - - -#include -#include "ESP32_MailClient.h" - -#define WIFI_SSID "YOUR_WIFI_SSID" -#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD" - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - - Serial.println(); - - //Set Clock - //GMT offset (3 Hrs), Daylight offset (0 Hrs) - MailClient.Time.setClock(3, 0); - - Serial.println("Number of Days This Year (since January): " + String(MailClient.Time.getNumberOfDayThisYear())); - Serial.println("Day of Week Number: " + String(MailClient.Time.getDayOfWeek())); - Serial.println("Day of Week String: : " + String(MailClient.Time.getDayOfWeekString())); - Serial.println("Total seconds today: : " + String(MailClient.Time.getCurrentSecond())); - Serial.println(); -} - -void loop() -{ - - if (!MailClient.Time.clockReady) - return; - - //Print out current date and time - int d = MailClient.Time.getDay(); - int m = MailClient.Time.getMonth(); - int y = MailClient.Time.getYear(); - int hr = MailClient.Time.getHour(); - int min = MailClient.Time.getMin(); - int sec = MailClient.Time.getSec(); - Serial.print("Current Time (GMT+3): "); - Serial.print(d); - Serial.print("/"); - Serial.print(m); - Serial.print("/"); - Serial.print(y); - Serial.print(" "); - Serial.print(hr); - Serial.print(":"); - Serial.print(min); - Serial.print(":"); - Serial.println(sec); - - uint32_t todayFromMidnightTimestamp = MailClient.Time.getTimestamp(y, m, d, 0, 0, 0); - uint32_t currentTimestamp = MailClient.Time.getUnixTime(); - uint32_t totalSecondsFromMidnight = currentTimestamp - todayFromMidnightTimestamp; - - //Assumed we countdown until 15:00:00 everyday - uint8_t targetSec = 0; - uint8_t targetMin = 0; - uint8_t targetHr = 15; - uint32_t targetSecondsFromMidnight = targetHr * 60 * 60 + targetMin * 60 + targetSec; - - if (targetSecondsFromMidnight >= totalSecondsFromMidnight) - { - uint32_t diffSeconds = targetSecondsFromMidnight - totalSecondsFromMidnight; - int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec; - MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec); - Serial.print("Everyday countdown until 15:00:00 is "); - Serial.print(remainHr); - Serial.print(" Hr, "); - Serial.print(remainMin); - Serial.print(" Min and "); - Serial.print(remainSec); - Serial.println(" Sec to go."); - } - else - { - Serial.println("Everyday countdown until 15:00:00 was passed."); - } - - //Assumed we countdown until 18/12/2019 8:30:45 - uint32_t targetTimestamp = MailClient.Time.getTimestamp(2019, 12, 18, 8, 30, 45); - if (targetTimestamp >= currentTimestamp) - { - uint32_t diffSeconds = targetTimestamp - currentTimestamp; - int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec; - MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec); - Serial.print("One time countdown until 18/12/2019 8:30:45 is "); - Serial.print(remainYrs); - Serial.print(" Years, "); - Serial.print(remainMonths); - Serial.print(" Months, "); - Serial.print(remainDays); - Serial.print(" Days, "); - Serial.print(remainHr); - Serial.print(" Hr, "); - Serial.print(remainMin); - Serial.print(" Min and "); - Serial.print(remainSec); - Serial.println(" Sec to go."); - } - else - { - Serial.println("One time countdown until 18/12/2019 8:30:45 was finished."); - } - Serial.println(); - - delay(1000); -} - diff --git a/lib/libesp32/ESP32-Mail-Client/keywords.txt b/lib/libesp32/ESP32-Mail-Client/keywords.txt deleted file mode 100755 index 81b7ee9b2..000000000 --- a/lib/libesp32/ESP32-Mail-Client/keywords.txt +++ /dev/null @@ -1,166 +0,0 @@ -####################################### -# Syntax Coloring Map ESP32-Mail-Client -####################################### - -####################################### -# Classes (KEYWORD1) -####################################### - -IMAPData KEYWORD1 -SMTPData KEYWORD1 -attachmentData KEYWORD1 -SendStatus KEYWORD1 -messageBodyData KEYWORD1 -DownloadProgress KEYWORD1 -MessageData KEYWORD1 - -TIME KEYWORD1 - - -################################## -# Methods and Functions (KEYWORD2) -################################## - -sendMail KEYWORD2 -readMail KEYWORD2 -smtpErrorReason KEYWORD2 -imapErrorReason KEYWORD2 -sdBegin KEYWORD2 -setFlag KEYWORD2 -addFlag KEYWORD2 -removeFlag KEYWORD2 - - -setClock KEYWORD2 -getUnixTime KEYWORD2 -getTimestamp KEYWORD2 -getYear KEYWORD2 -getMonth KEYWORD2 -getDay KEYWORD2 -getDayOfWeek KEYWORD2 -getDayOfWeekString KEYWORD2 -getHour KEYWORD2 -getMin KEYWORD2 -getSec KEYWORD2 -getNumberOfDayThisYear KEYWORD2 -getTotalDays KEYWORD2 -dayofweek KEYWORD2 -getCurrentSecond KEYWORD2 -getCurrentTimestamp KEYWORD2 -getTimeFromSec KEYWORD2 - -######################################### -# Methods for IMAP Data object (KEYWORD2) -######################################### - -setLogin KEYWORD2 -setSTARTTLS KEYWORD2 -setDebug KEYWORD2 -setFolder KEYWORD2 -setMessageBufferSize KEYWORD2 -setAttachmentSizeLimit KEYWORD2 -setSearchCriteria KEYWORD2 -setSaveFilePath KEYWORD2 -setFechUID KEYWORD2 -setDownloadAttachment KEYWORD2 -setHTMLMessage KEYWORD2 -setTextMessage KEYWORD2 -setSearchLimit KEYWORD2 -setRecentSort KEYWORD2 -setReadCallback KEYWORD2 -setDownloadReport KEYWORD2 -isHeaderOnly KEYWORD2 -getFrom KEYWORD2 -getFromCharset KEYWORD2 -getTo KEYWORD2 -getToCharset KEYWORD2 -getCC KEYWORD2 -getCCCharset KEYWORD2 -getSubject KEYWORD2 -getSubjectCharset KEYWORD2 -getHTMLMessage KEYWORD2 -getTextMessage KEYWORD2 -getHTMLMessgaeCharset KEYWORD2 -getTextMessgaeCharset KEYWORD2 -getDate KEYWORD2 -getUID KEYWORD2 -getNumber KEYWORD2 -getMessageID KEYWORD2 -getAcceptLanguage KEYWORD2 -getContentLanguage KEYWORD2 -isFetchMessageFailed KEYWORD2 -getFetchMessageFailedReason KEYWORD2 -isDownloadAttachmentFailed KEYWORD2 -getDownloadAttachmentFailedReason KEYWORD2 -isDownloadMessageFailed KEYWORD2 -getDownloadMessageFailedReason KEYWORD2 -saveHTMLMessage KEYWORD2 -saveTextMessage KEYWORD2 -getFolderCount KEYWORD2 -getFolder KEYWORD2 -getFlagCount KEYWORD2 -getFlag KEYWORD2 -totalMessages KEYWORD2 -searchCount KEYWORD2 -availableMessages KEYWORD2 -getAttachmentCount KEYWORD2 -getAttachmentFileName KEYWORD2 -getAttachmentName KEYWORD2 -getAttachmentFileSize KEYWORD2 -getAttachmentCreationDate KEYWORD2 -getAttachmentType KEYWORD2 -empty KEYWORD2 -clearMessageData KEYWORD2 - -######################################### -# Methods for SMTP Data object (KEYWORD2) -######################################### - -setSender KEYWORD2 -getFromName KEYWORD2 -getSenderEmail KEYWORD2 -setPriority KEYWORD2 -getPriority KEYWORD2 -addRecipient KEYWORD2 -removeRecipient KEYWORD2 -clearRecipient KEYWORD2 -getRecipient KEYWORD2 -recipientCount KEYWORD2 -setSubject KEYWORD2 -getSubject KEYWORD2 -setMessage KEYWORD2 -getMessage KEYWORD2 -htmlFormat KEYWORD2 -addCC KEYWORD2 -removeCC KEYWORD2 -clearCC KEYWORD2 -getCC KEYWORD2 -ccCount KEYWORD2 -addBCC KEYWORD2 -removeBCC KEYWORD2 -clearBCC KEYWORD2 -getBCC KEYWORD2 -bccCount KEYWORD2 -addAttachData KEYWORD2 -removeAttachData KEYWORD2 -attachDataCount KEYWORD2 -addAttachFile KEYWORD2 -removeAttachFile KEYWORD2 -clearAttachData KEYWORD2 -clearAttachFile KEYWORD2 -clearAttachment KEYWORD2 -attachFileCount KEYWORD2 -setSendCallback KEYWORD2 - - -############################################################ -# Functions for ReadStatus and SendStatus classes (KEYWORD2) -############################################################ - -SendStatus KEYWORD2 -info KEYWORD2 -success KEYWORD2 -ReadStatus KEYWORD2 -status KEYWORD2 - -clockReady KEYWORD3 \ No newline at end of file diff --git a/lib/libesp32/ESP32-Mail-Client/library.json b/lib/libesp32/ESP32-Mail-Client/library.json deleted file mode 100644 index 7ad58f5ee..000000000 --- a/lib/libesp32/ESP32-Mail-Client/library.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "ESP32 Mail Client", - "keywords": "esp32, mail, communication", - "description": "Mail Client Arduino Library for ESP32", - "version": "2.1.4", - "frameworks": "arduino", - "platforms": "espressif32" -} diff --git a/lib/libesp32/ESP32-Mail-Client/library.properties b/lib/libesp32/ESP32-Mail-Client/library.properties deleted file mode 100755 index 03eab43ef..000000000 --- a/lib/libesp32/ESP32-Mail-Client/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ESP32 Mail Client -version=2.1.4 -author=Mobizt -maintainer=Mobizt -sentence=Mail Client Arduino Library for ESP32 -paragraph=This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers. -category=Communication -url=https://github.com/mobizt/ESP32-Mail-Client -architectures=esp32 diff --git a/lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg b/lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.jpg deleted file mode 100755 index d4c62c865885f8e303251a331d5340efb611bf1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10499 zcmeHtcT`i^zi%7|3)m14rN{_Uq>2zaGHL)p0uxCHogqkX5)zO;Iw}wZ29OpY3;_a! z5-A}jw2>-Z2%#4ZHH0EHbRP42@7}xKA8);T|G4X|x7K{mTIZa#zkBcRcYn^=pZ)#r zbB>3PzXGlp8yFb?PMrb(PMsWp<1xS^!08|UmcP%ZPvpllKmIM}&Ya;obN(DR_xW?@ z&vRe6e1V(i63_Yb7kMvUx_spd?-lL~SNX19;XAp%@^>ev{%(2t$8#qQukf7bIVt@w z%JE+S-gBpZKK1kIQ@ns5cu$??J$2j+5Iu47#I3*m{Wm#tmh0T9(?9-j{zMJA0yr^z z>IZHvt_x?*bNyZA)DNeBitQV!Y8)=cY}Z*xqdi(=G55}r2+2=Y9~mYy>RYF zF0Ow$^)Gw8S8wqtKY;ip^qt`sP%C+`9(s<~5w9=a% zALhDjIRvK7ig3fqia|HvRG( zYw`CcDk*P#XK`7hZ`9S2suwd5)E4Y`FroX)i$LIJMz*M3fsnQdTTpr}I9}s_nz?*w zu0F|sy0~iE&^-$=bEE{B7iC3mptc@-8z1WT2}K8Fx-F}e*k-pZ>P*+&J@Ua7>S$y4 zz`b#0^jJ{>IwonS&M-5OAl6N1oQ?E%Fruz8M*VWDddiUzf`uD#n@zj4;6MKv%0Ex# z|LqIr=~Qd9BCJzdITI=DAX7?bv{?-=sT9_$N8yip+;;%FiI!>x27%xsG+gjWEb zk@n(W+RNWe*nRV5xPg0*r}*PA1`FGo)-xPg|0D!@>QXquJw1B*t(jO0Ql41kwzjVi zMwNo?J}JYl<2Xw9q&=`@lN1*qRZH?~#es#B!`U|!pjj~oC&S5$E-&fpFI9DSPt4b3 zjRg>_&>WvtHpx-2(K0-u1MbkMS(Z^4jq@g=cXI{DeGcC-_L7h2=8x31)Z7@ff;!;* zL%W*6RfFnzn3U4#=)d5fm~L3tAu&ZGjxwPc)SCKC*sz4~wj%o)F;u0z!eGTLlL3Z2 z_D^#x%93ip9>vX8#=LJq4QEM*`WD2L4llp+1{M}`BrRwtAkbkT635%P8*#tYp)q|Z zx7SX$u!Y$a+_sp4;dmD1WNE(8oVHNRc9)tMRcx&?C3=}&J>ssv%nPFH(1moQno-!M zO0Qmt{N0BW&Iwfxqr{uTw^r*Q#e1KJ{8GGnk{NZruRi;WG{#+RDH@s264#mshxOVu zJ)<(XgjbYDbIS;^0uGW~Cg{h_rfB<%o%n#FH`fnz{VU0Ndz{+{?X>Q@o8WeGsdA@D zi^F@H!7lr~cpy$1dovpe@V<}Qr7Adi;+7Y&kvx*3A(@Fri ze=b#dP@$)b(ZFb!scqz_r!yB~s;tupK_2~S2XoTvp_A1P*x`i~7Q}4}bM0^oEYejJ z+wde82HH3Cp7yfK!g@>%wA~nAaehf@oFHo}ck=PwJOt7wF<0OJ3Ai_?V}7e$ycpZ& zi7kJxEYIK(^88deNywlqkEF#U5o(Qwbt(np3AFEnbA`E~EW*MuU;zRC{1f2bI@3x- zV>8IMIz7WZ#q@l#akg>~=N3_EEF+WOY;exBSfPdf=AAdxj7xD$@njhl z9YCSgxj(wO<)A7DbR}YA=lxUDFL)4TqKRcPUSy9N&Ks7lY!m*51Td z(THjC8jpT0OjNZIFN+N>*azX54QF|Q6WjR%fe&EN;ZN>*JMM>H#NL;Qjkz8J(pER5 zy_&G!^3PiXCJ> zPz)mD%q(Zyf7@V}zagD{7k6#EjWHNV*Gb}Q6Y{_Hq|4+N zv#T9rU}xwJuADyxI)%d@P)?A*ho9#juNL=)k&^Y)Z6?rY^LLcIW56_J&(R^jhZ#eJ zL&c8)b%DDn!pdE<%w<2V7W2W1ZFB-STY3L(m&?|$93t47SYXF;BSL7E=<)qHs6lZM zW*k=7cnlaAiB+ABGm5lJbn@tl__Ve`762{5wCAvRV61e!5wq`HE4%c?pz&z!tB%yi zZkd}~a6NQc0&rrILl(@^GNQN>x9Svnu? z<}qlua@m41*JLKN^60eI_0|G$aUPA3fIIzB%OPoVA4~e@&qo#8yUoNy4f%D{-o4s# zEQ_0Vr4BqDXs+oFMas(F7$@tG26)Cgit)rWyrK#|-|7Y$%1a49ajxHW`QUvf4kzT1 z(JA?A`U2R1GKjEPeH@h;T^sLlD4S<;yPL*t>SFV=3P9URm5VYhj!Q08=9TJb3|^!9 zgz20{r+>X$k~o2}b*W)kIelapa_4iK6n$#BxAAz6wNV8|nFTfQx)g7=@LD8vektiF zAFNgC}fBFhW2zE5l!Gf?~Y=E8#tQw1&` zU4QE;*YqB)i6kO|sL~AOmb*RP)(o$_y1vP!DwdgHcn*d+%&Y396i~RWUKvzIFaM?Q z6%_^r3#?*YOep2;TUn(|xPZWam zwOv?7Ei!gV{+6@J#{f@GeK)t4B;R$cBCHJx(~Zw@{fLq6Q2M&GQv)2sYaygP!q$hF zYa6Z#p17J)590Pu%n)7`tw*VCw>|R`sKuk$o1o@3U1EAJ8j?G+g)#H!RIoUZV#oBx zJcU_|OT|6*Q96*+QqST`vbS$Bop`)8LM$E_#}LFdHLne-2&+98yoKKJ?MS^V}K7*EPCK*&E&(RR9w`qa`!RdO2aZ^ zFaHDX%`pJu9AO=^J9{l?dx2A*yy?kQ7F9jSuV~?8{Rsg4VxNX<91WK^;I^H?-7kxu z6uZA?c%U{#5hDduVDg+DtxKx`=VQ-4dDHMGfEl{d>M{)TJ%yX^V5(p|{l`g6;)sZWgWy-sE7 zv>P@OK_YDuNvub%LOLdNtrMCYD#Hp*|o}DcB0iOTUs+S4H5((P!{=QG2YuvUU~3pcBd*v^cZln zG_Mb3ST8vq$Oyc5_cJ_kGo$i0duTP&bO+rP~>FnS)UYyGEGA(9=bsDy4R1lKdmHySW6 zH!<&;_Y-^(!kEZjOvh0fLtHvrN?%#uP;npzq=@trk?0odk#&8v61llFMsNv(sI0q| zWZds0txFeK%{@E6V_ZakRS>Pak}wM7TUNDg8KDR-E>6kGD;lOD7W-q&c{_myU4~^Y zsJC#pz!*>fTkUfEKt)+%bNjX6>Vob(Mzuv~qbrQmeOg-c&+|Q!yBb|brGh(Y9S3HUUi%ZK zkR3HWe0*lz5YV>wS(UmA;V@i6y>NguuayY4kXAxyicAg292v;E&5$DMH71#QE%%I- z)`lXp(zm6TdTD_nj8DJLT1a&`Vwwy?M|G{mB@@#fb0!ZKM<6ygafbtwfd?}1Y1cQ{ z=WBg-qBwiQqAx{1rVt)qf z<)asm;Zyk!nqYF^Ydjw#7d-{jIr$*%mc$%@>1mt2zba_W9 zcn+US2HD4g;j*}WiU=0AFZFe~&%y{pRTgRq*u+^5*;#^d`~HqQul1_ljypt=@Zpa& zm6(Eps^x~utN zLObsa!FqSR%0YW>|JUTrvkSHQPGOv`*0EON%ai|Ms#pe**hLEYDZNWS@Upl^Atvh_ z)Ut7;0l73@U^SYG#=2@8Pm1coA=JiTzphF<{H+=o#tkx7w(K zeP~0ARc{__H$Wqtu^l5PDw6)DuRB=IHU_$-uRm|=F`UA!M>k8#GVjhomKAcB!a2X%=tu+LQQ|NyUm?-E| zgAN7)PXfM$kuu=x5-D}w-$<{U;HnG)w(TCosM>b6uxh9n;~;a}&N=TR<*gIF96qnY z^2iZF?rSYWgjITZFxo|3E*d&uNI;ymXH?p*Cy4|%4U8MftsYY`vA82%HK{(0R*joP zOFmJZim^{Qn6V&HLoPob^28D=1D6ezbo|M4J97M^l(b)SpTJKd;qY!qn`v!%=gqvk zX*tM2>WYCfab6Pz0x@8Qe8bUMU#b+o(7l4YC^0d@QclR;Ha^sx3j(N>a zB9Ww3=aDs zsakMcOUmtw<;16Ln2?0@MxI0go-x*(5ha#zB*6C^4NWUt>uujB_ zqn>YeBk6)26jd<90uKcbk{Af!{jA594)b;--u4#JlRQc>Qu`Qi>62wgZk&WqgGZSR z$FRFQWBp=6C^B`Me|vt)ZQFI*@$E5y;wLsvS$}_t?on1ZUQ~MRvnUW|8;g+{>zS8b z=aVbTKy{=29{zqYk{VM7j!`a!nI^27`c#*uedE*W^?&l#DDY*VM@mY5)n@tQ?9f)K z^=x=dds$Rw=4)BGW~P%*?45!nyY+?D;r4aRN1inpJ7K%pRlA|l@>ty3CSjT|(K0J52?h|f$RNAh2 zo4`PO7+|8}2!B z;=}cky_jE)0pHpv;k&+g(nvAa&LyQW@(Gl4 z&Bi}}3ahCfp!qC>n)2+c9xd+R=6=?_Hp(4S8m3#Fgs%mX*s2 z@#(}MVK1v<-hd2MKZY`I*}@b%xI!Mefw3#7a43A1UtAEt#?H*x57@t7ek2Tct22Rv z*cXS#1rF-BEJO9RU}A?Q!F68l<-798a=-$Z;QDjZzJ--a^-^M;!2?AN?+@Wq1wgP)*)Gc!g_Ai z9{0X^BZ6IqlZlECr_tVd>$3hBZW`Z*4XKOkbrQPF8sY>F6(qrE5bFJNBb^P+8zO!b zxMpWp)ayMW#>tB5Z?QZSP>3J*RB5?V;hs~m^ys0pu2V2E}#@UjVwyU6LLCs zZzqgWJM#8q2ouU+<-A9!4dHWAvv3lu)V$us-e2lZ!2g+#9xxNubQ4==J<|&3h$vaU z%|Ve`lV&zgk4|``R=tyrSt-Z{*+&bRrlPzyW5LU_bg+F!wlVR2Wx(?R_}e($a1vsf_Kp}Th7?znzGPA|^@mr?^!tVnc{bT$xg*&l=zk}i)NIG6^tP&Eq{&>h5dtTR zMtVeRS5ATWF8KTQJqR?d^|qvQaFot6BHij}KsA2Xiy)whFwa{fPBu z-{%>7JEN*Du(Il!=GcHOeik~h4^bhR$>o=X#yy_)p!UpoT4RYM>V=P3rc~g=pz68% zIxMFI;!yPjXh?hmpLc=5|1xE@yapHUlS|vd`pZO551*toWB)-EjjK}%o3MT0*M?Iq z`vLW6i5lJQxu&&q5$+dv8vaf?lSlsh!!p;CJ@q!9{ttU>AYmkNX<5%fADgIzrdl~e7(Z43kJqDF{C~7PWB4AG4kSOX95F)o2bF?A- zN9S+NyHlG@4sY)HJ~##-3odt6Tb4py+5>G1X-b_}6=TLl&Pewh{qn+GYEz6O`}4C9 z3;2Dh=iYExGL22cu1n<&GbiWf5U!TvxUubWpk0OVwLr)GcDFx$X6~8JIztr}47xID z(p2H%~gT!GUwb7zGi|&*07|V%V>4S}3rPqVU_pJO<3KB6cxL*; z>QK&kXKl3M#v&LN^r;AI9T;)w`EWRg{k8YHBc?QZ5crp7stQC6bxG2xRcRY_lYRJLX9xe{3Sl7 zk%8$KFBR7V67;jI+6gpvB?Y3IH8dk38L z!Y=Dz)TDRiQ=)*oey(1f)rZb{KI54!?b?L)lbE8LF$-FP&O8OauvWAuY_2tqUCeZ7 za^@iS?svCGFVN#jsX5ng6Q9cJ)NQ6IG;teCQIogIE#&tPN-e|*D=V2a_Npq($zw~M z%#4mBCzrH(&vNbx>-i8phB933Mni^$Jg^w8s700w%KYI>$W2C{^~|jPBUCd?$haP} zNQS~eEaiGh-J;&ROXXHD95bnYCf1 zFo@}Jp5*xK>{0v;7M9&J>0G~0r3|N$5@~a?L@n|AC1$E?O}rViNpqBW2jZ_^^Fw(- zn^W-O*}x3*YEfY*9aops~e_1#+mAS>K!{pO3E~ zr>B*^3ngE-X6UANXkB6}W6_7*LYiysas2D6;@9fXXLPL%FLpbd5&yx?4pH}I z(uUi(3U(pudNE;pkxd{3x_xsa#=Ynh=89U?0oNK}mtX?!y?KkwLlk!&1ikt>>x93i2e7s&syOc?a!zh z)JDDfUv}%RMAM5CSu?_@jZCg7so=b?6C;xkC}x`fsQ$k|BfskY+jB)m$?SruKGZRw uL33#Z;hAe@!`3s{gz3LC7;vx8eqRmE4U_p#{VVfNrGF6kUkIE&9{C>~u~Gv7 diff --git a/lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png b/lib/libesp32/ESP32-Mail-Client/media/images/esp32-mail.png deleted file mode 100755 index 4592387824398a257aec8bf088ea83d41b04212f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12582 zcma)@Wl$V2w}uyAtSqjDh2pM7THK1eTXBctQXGnI(Zz~GaVy1ji#v_34R0owgn&(P1!&Hog^NXe7$qVs{#%tO+NbabrD-uUhB*~HL@e}vGHe9Mmx zVP-b@_V3j+K9EDSJ?r@MX-?)dVtwszqWltlR^r3c{bPXc()dYECLf>egs=yet0VUIl}7pu4#)xk0MbQ+!+;K0%nTnY`%kt9(~2n9(*Ikij&H7yF9VXSmW(i$1xcbd zqT@#rOQPb>Qpk|$qTA zEloPItW*yj5RKSIAEKFw7SSx2jw}Vx_;O8{#tZZ8 zdY}x6EquR`nj7_LbGkL6h4ll06wS^hHftxI1N(@bvFV*I#GD8Hhb~H@90s^5tPzbi zUyKV(op64d*e+X+%H02)G6Nybr_>gh;7;=MV-O3u*V1XlJ148A_ zlq|!yog7)oi+#Id5Hd+Vpw9xB!~pOi4)`Bj;OF(61+i` zjt}oxf*=i|Ou4Wj75WkYKBD2YK+kwcu!UDc5@J*e#kfku#6QZ=Nh-A5`BZc?d5MI~ zI_z%r9qYboJg@5g^e?PgA1nb>mjpCq-{%h$K?bNW=u7L3E!o6-3!!w?B*IsJa<$u> zM>Rtd<9QTE9zsM!yRVx65?H$g{jW#r8XKMJki4X zKR!M2Ntyq~my3zz@oqiz@{)+i1o!Rp)gKy&cso=oe%K$QXNhbv#@Y@ArbgLo7#K=X z;6{0gXt1*w7`6Fr7j9iT>Ir$fh+`y<(S#+VM2yJsTMP2-|Ew3udgs%&Fk7J#%nF?9 zJFda$O)NG-2XEah>MM43Ip2zNJ@k9s?I;d5RYygSGa_ZyjXnaeLhCc!v=K&GgWji8 zYFgqKL8`TtT&Zc(`8!5|bgG}6SDIaN_g9;JGRGP${MRo-7sNGq~^WtM%- z=ONeh@+{MW4w_tTqs}Si3zap$m$XOb9~u{MiU9|nznc7J?4DceTQN~E;2*<20zi@c zP40Z`17s;o(_S}|PdyuHPLs0=0^Bjb*cKUBQ8P6@6c@kp3J8--(+?}WZA33BqsktJ zJTl0#VeLKswfPN?^TwA5VXSshJls~hi~$#~fwrVz^@Kl3YGSL2AM&bba+gd^h;4SLo<4 z^&TIN;@ms-udT?GOoCw=AVG!#ND)rY(Q@>lYWF_nG;DWpe&WK`%UJRD40jWH3fd;D4K(r|A_dP`PhadI-FK$W2=c}mX^J#7h$!ZhPjS* z;16hMx8%=3+en+X73zXIUsjkunAB4_261h$sPmPh;?VT_@od5!XI;@kCW!hkiT zkYc@`N!lQYLh?7EoJ|qsaI{%14(9c)%l->3u}6JYb^wph&G-H&=F|Iy-{G*miOfg0iJNON4g;8rU-*J)9tMv~KWf2pMq1cM zBOXDYuXU~){t-kg!P1O@!Hfzz)`*mXF`hI3gq%Flqvo=vW8b=2PJ9@iq;~kFHUCw6s*FJpq38-y{5h}(u7I1SIjHKL42X>);u!mF?Ms^I7p|n+1 z4csxR-1qq$orPKs#-A~51bR%L@o*(LaR>F-OY2_U&mMR2&R8hV`{47DH$8}+^>$zF zj!rP)k^6g$L?@XcMSLSjh{BIT`5D4F#F_E{4oQ@MpXY41b`?Ih$C1aW-?CYUt;JOP zSMllH(JQK-VN1uDiQ6@zL9KXHQTc{mS3CEX_i0rIom_376BzA_a`Sq!luZ~)Q}EM` zOvk`woX_=mp+`wFf!mB~Rw@skEr_9Ro@=P zpy_oMBWbOvu&CSq<0C^9if$^tscw<=!AP6=+VxWh_Ii~Y4UX{R5>sU+_@;6|oeEuD zF;OmVO+JBL=y9s$-Y*WV`1yXE=C*72_yzgo_>48hM=>>d~M19#8lFc7)&8(GH~nE)}3v?}nxIbClzsn0MBU*bbupu(#t zdc$f89fzD|iXb6->mHL%O?Uvmi+Ok0?aR@=jSfkb-(}b>!H9_PeJ{h>sFXbCz~5+p zA$hgKwMR*5bEw+!&?Ceneo9$2L))M6q^5ow5^gv?-vMX5Y~(QW?)rTb^XBNis6&n& zmouwjH36Y4T>{?+4A0>kVhZLl{gTi%PM(Bj)sY_<=_R61Hbsz#mo;QbLe^2N4*xW)TBoJun zBNu^Y8HXf}c6nV;P1xZ_U_yVS4B5B)s{vBk33q^|LsT~%+zJ=n^ccUD3{ymfd?7yBpx{{3V1<{J3eh%-@ zK!!lJ$=pO9^@~~?*E0mujwl6UJzk5nkXkrl2MNw%h7jjRt(tL8;*H5<&6QTC%!^+x zAz&fEFzgwae=5(F&ml;t~h-BYrP4GE`(u&Bj@z=$5jP-nD@DBYIKqHvTxM~jRDBjsa3GWZ5 z!oK(q>^!PxvP*0n_l~x(NDaT45g3D1Or!msqw7=h)#^oM=0+Zc6~UY=8$_G+EBoca z;X<&G^-WQDRo2@j#rf)6q9d<#7qWiJu$zFxmI)Iv`+v6$JOd;ggQJI}nvUFnL@uAv zSpTwQ22p9L+8|fLQp%m0n?P1xvK{Z*_dyY$OaIVfw-i!}K#^UvF4fMMr!5QWa_#dl zT^*|j^w{}^jQlrQU0)p-@!u5LqU^Vy0 zE1)e6G+f^1E_V&1WRyl`!}}h{3KRhn-84oJ4lZl z(my%6SPjH>P0(wsCFo*2W=iePlrs!6Q9^O040Zd62744*mKv)f0e z&-Nk%G@ZEiNR0uJON_?EAs}wak1~H7p)#)6j0#n(fddY2dNrx|V@7vBoh$|F=VT){ zkdt%R|1x8H4-EtHXnY^(>Ciw|>*u6LT6eN{b@I{re82v>zbkCDS~5z`d-xhaC@b}z znnmboGtmWSUBFR zEhNg*3yE$Zz%<`=ev9_DIuH?Wpx!^agO>+om@%wI?`h@Rh+p-{aB`J{YKK|86k#a}&(O%{CCP-|`&-s1I1)9<4dSM?uw<_14T zs6M|3S6G(v--=%PdJvUv95zUdie!QTVvJYbO7M0=BK8OSB7N-!w6pgu6)Lp>iA>4T zRIcNXPxq%fZf+DNYyTu?5jth$kq9k0AZBFu$ErE^?4>a`#+m-~E$}!Q)-nd$dq#t5 zTvLcPi-YA~KAflY6ii%UQ^0#Jq}uCe-5aUN8#Wq!hp%k~4_#I(0~e9r)mAnpyKi)I z6Og@usYD%2o%p{xs8Q{HwKXsh$4=)X<9=oO$ca5|OaVuiZ z9|{dVb;6)0>l%q~55E)yXnU5}akRRRS+`Qxw1i5mTO^Uk`~r%ey#I0PTJU2NdDE}d z{g^`mb3nIxX0Gn+D^l25-w~2BJ0s0mjg{NmQXda80#`opi%Qq z@;K%56$wf9JekUYPPO<3vpPBi4EFL3qtOwCVNIT~>)MCZsZe5{`BsVo^=#$~=@-LK zapsn97y=Um#6CJC3QJ_^Ugvm-kKORJn~eH^r4$xoezk~^Z71qtJ7v9{*c`V3EffuY z8a@C>lz8-`DKPM39sSEt*g7cO9qp=fHoot?U#zR=wbZb<<_u-!BvFsCOS!}A;_Fh| zK;+AA$o@=Ell3!p?Xl*eqWh}baJuZ5r?34z{@88Mi7_@nM;2{XERumR6bYF}vrnFhb+FcOoFBP=ZB*~DCs(!ZXE z^Mv_Q-=9yovK!O|)E~^REF-11QG$#Yt_WannTr(dpgZCocb$Z;u-gI{c*D_dzQbku zN0e!U=bu%43u6qxM`Q?Qv>x%z#O|Nw+6{j3(}N z$6U|8F8dh~#JWjj%eoKY7jqqahdkWMv990V;rlMlcmw_@LZa3^REOS=VYuk=3d#D_ zf(kl7GRXHGp#aSwSBE*?Oe{Je=l2REOBpefn8D5(&%rB8jkPwP-&O~yi6iR|sm(O{ zCm00%Tz`NkUc=MuyzuY`kz%_$ktslSa49BX4}3K< z!YT{0#NG0v{!t;S;lR+VNe|Gl`UZurlfygSYyU_~#5PkU=iEU&_sGj%C;~tHV(W;! z14f|^Sfz$;hd9sVweRBb+aEZSB~^^EaAk;NUrbF&4Huei3}mCzUv_-vzihFV)5wVe z=&XulPZZ66JrX=RELn&mYX+h(tVavPK}V?@+q66vR$SQ(yFBww|CNg;%4unAw-ZdN zqCIDB39#)s&Kw!x440#nfrmVdlFo+5u%zO})A=0lauBdP3$JB9IPTcP-|gy+r07K_-uztP*09mVUQqMu=dDG3vX-Q-iJLG3K_GrP zv!V_MU_mvKI9e2?Zx?yM$mJWwN;|yzi{t!aLf6geX5mJ<7#g<-JX2Y}gdv5V!32`b zR_V?2}@>pL&s*hhX-se`FwF3 z&;H2vUy{!8VF!;jl=u4#(%^)NxF0+htsD;zMk-Ne5z2N$Y4JS*M8J9@skssQX6F^r z={gVJ{;la#6xtv{%>RZ7kraONy#NpA3spKuc}Dx`49!9qscxmKiPN;@-Q}=tuJXS4 z$1ZhaA`Uo*3=n;W;kVMycJyfs$sx%xT42cjC_Ev)s}hbQU2ij>MFYu#a0lPf1O*EK zh|MCnhe|MM73W7rAKtOvV}-Ud$3v7sDwlGiF!uW*g#_BZr0fKy06)8(XkA$tMq{5)*dz4m4jN*Bm)`_}3@KdTWd#@43uyje}`w}kk4C0TBl*k>=HHe@bI zmoHF?iMPiBq}XXlnCGV#CJS{O&bIpFWTLix6Y-(89K*?ca#W{{&a2!?>A9~8-)-C_ z?xYp#8`qto1z!E=KUbU|JGJTCc&x=N97o58&m=lKfzAQQ_~inZGt_~9?0L90w#9ty z7^dxr(Txg%bdXqG3T%|?m_9M`*@P*&A#iM)&>8M`FSnRbO2yuArt5B0-Rh}yWsCi4 zbLnqyjSE^1*sE7CBjwDvZfxBi=NLPFceQ7^?e8!>ZHPRe3<1e?nhr4+$Le|Gei;3X zNfZO3#OZ*6PfJ&q_z?S)Hkp>6{{_UOYS*8e2|G5Dp$9}gosk-R{Rp|0?e@vvSunHN zfoHu-(b#h3zUoXLdo9wXmaRJH#U~I!3DvAx*q%OKDJ6E%&rE;+kc5#aw_@yW%+#+s zhr;`d9#W@}799^e--_ybGZ@6*WPh2q<6f8O>PZ_8PFr7+bUX4pp;_b;pyiS)KPrI0sHbkgq7h~RjLm!K-SObU%&;EgC=JU7H^dV zr_Gi($`MVaAdkjhB!IEGCXe-U^gtTNibZveDL4P#a(6or>F`YBS1)zlBf4kvzZMV2 z;gQ`9gN52h(PxD0{RJt<`w)R;x5Ke9t5Ii@b~3G*lNUA@Kv_CBUr;y{J&23clA-k| zH;${NSqnn0n;OFY@?|sucHUDYrGa1eyw^@+QO&94F0AlZ2JbQkaQ@zdYVo=#F+CmI z&y-lXNe)!Y`n~YE%xi5~TFhwJo}MRlcb+paB@!nvwOOVyjVfNEZU3-1D%mxb=VqaN zm~bGAvT?E$hx)2*zoG-KB?NZ0+qy(Hk$W`Hp1Ls~t{~nZUug=W2J|1(6B+WzvF!Zw z|71Q<ov$xfy1IU7UhE5V)-6-3RY?Ayf-21XMy)i4}N|| z{b3!c{f_fhjn3=7%%{Je{QSt^TK#=wg>Bxa76-l;5|%S0K0J!sF)Iv8f~g}+6TnbO zVqty^kpVytRS2tT2@ASI>Y&g0sagVzXV0V#ypeadw;esTNj0hpCmhSpV950LZs14K8C^56Y>BM&rb>2wV1eY5+Cfc@)Oq+D2Z$#c zYl<6GA(?LJyV%q08)YIsB)~eiqJGeXU7L==lUbLoh3uE4^dS54RT#6EaR8T>rY4ux zeU{9W!#gP@XG-kmht{6EK^jUdQjQzZ;HQoa4vyvi%(hi`Gvx&rHOm}MrD6LCw_W%o zfOeCegiW{71Oig~5a|#RvhV3%92T~{4pXb*(C<9|d|mU}R++<)oHF?CmTA$>KiT*F zuC;FH`jF<2nV7?P|EHXWQn_6e0Q4V+sbk&#dfi&+Y{iA9{Xy5(SI4XDJi&Tcf!j>O z_up?!d8`D3pwP4m$z9bW_fQ3bZW}(^wWi&inY_RU`4LMs@0q#U=L);V5e#*eRw~T~ zMuYn3qcucQPhPO$;bN1QoG}b3oE}DFqDH5q=|_n()E0DXywU0b_SzxrEo080jnL^% zEO*yZWx)XT=$Ag*!kN+N)g@z@{kCh=-{qrY>XK^wh7>_Qgz#lbPCxdZ*an?e10vG* z`*vAVG)LO?X@OP*I_v5R-zA91+}i!VZ)FwreYYvU7QazG?+k~3hUXgWu6NnGte;{( zH>j-(7hCna^39k9ST`_sK2a*FdMHY}Z&`-A%SPV?Z1%Bn{j(~Fy;P(pmwzlS7CW0& z*cH6H!);jF79+EX1)xDJ@C-d%B-&waP;|3|b zRMGpLUO{*fs|E>_ns`oY2jX{VPih)S+7KM*>wey z<*f@cenxMUDp2@7zlo9;zf~N*6SrYn4OFA7o1Lg}aI}QbeMNtlKx3lWU_N*I{XS|9 zgD1V(_#xtgH@0 znxU-QV?IRJvv=usU$+?f>4PmASo8dn;HEodo9YEz*xhu?U;I#9lc_uUGO!PIcySsi zUVn`hiQ+xc?xl7I9^tRdT>47-ju?_>Fty9=izw6{MJ|T;)EKCJ92HuM+2d@95V=@n|LS`MNeC(2C+6aC$xWB6Q zTTZLCAasFkyJ=-LHLFWjVS{H;e!U0%Hr`muHt9cFsA13Kej*RFnP2R?j|?(*TK3F` zA5_(GiVJv1YUAbqq=iaoF~;b!ZC*yMU#|Pr;>W}tS!P}Ln#oq`zR&d4J2hiS$BxvD zmcrz0T*B8X4@q`-<2n4tq5uLesyOjWDrQI3VU;shl}yR@w|zmcrLX-C&*Wp%IsJt1 zPE4`&CA=_gvm)?gwhN26va@f;MVmOX)NDGQ<}2GWGDu~za+q1N966C$iiDxm;vY9R z>&=vNci-PESXk;_Sg)$oui^}Cch4R#>HPTEP2(1L*RZo~;YzBc*khBY#Vfw= zx!7t8A7mQrI-{GWE+G69j73LELFRSn2*=tu6~dhqK)4sV<2GRoG4ofo^&!<^S{H+Q#0M_{PcUl zagQJNph1>?t)ojNHGB{hjzE=)*HTc$cyYMmbR~$KoQd%pcUn;YvE)15mf4^lVD}3! zknCO+4pg$4xT!qx;CfFz(|C_j*a@8jzq!{zqP3bmLVF1U#c{Zib6rH@M&WgjJ(vxE}In-#w7g(SPZ8mMJ$a>R!*zMq^s1xS-=DW6z`s?BK7^ND(aF zvgq7lX3!>JAx6`^vM7`&Ur}Lj#6$@Z_}Xr}`B0TmTJ`>Z9J++)%HRc-&pkYo7_^<0 zonaRlBH<6xD{PIYH4UpJ_-8B7eL7v{Ai<){)-C&?6((MdRvJ zX=;)5+P@6J<>_xr3iZ)vJ*WQpD~x zQw$N_Q@=s9gWa3OxLx%0rR?k&7?tPTndN7U+pm}Mf?G+=ePizeg1&3&&@%<6()Ik{ z3}-+7;6genXvYmY@XYs}J3sD2aABqSRu~Mb=pZ4>U?Nczm4{c!E;hTEP(COX&tqfv zv7d8uo{Zhn?EMoH+^)>=GV{HyTQm(UVL8-rHrGWOx=Zbg1}2|;{usgTe5*>G_mzJ+ zc)bQ~WCI29TUz`+A&;5Ir^}DqQd5&#z-{+BPxC|-+juZxoXr4sr+kircR4?=0!t8j zP0w5xC8bvUkK*!P79b%v{o^;b5^DCVR{4+e8E$wb#(0 ziifufSR!c!DVFS9-xP7@PQV`~93#-+DR~{evC}ZDAny))Jdf|l+&EDPzHLn3Iz72h zwQ8Ksr&JtYe!YMqmErqdB7G_!R_r|3*U{>MKmowJe|=@`Boi!~kDX^wvT-Nji*CKB z`F-vhHZh!vW(oaRe12Q8tF(hRcD$TG?;=H2^uF zgkg?cdS(uoh!iQWv9FvxgknEklL2VsrPJScK9$pc6b(n90Y9_d36cD$`!tJK^Zz@X z)cm>0NqGGxg~hVS6=oS`rIn#0#BG2sgQ|I6Ex-CV4>@WmW^YGrqJkiI`z)K6|sToaF+;n_T=US#Q|(F3BNy=++94 zj+z9(C>wBDlM2BOVKeKw>yw% zor(P-8)Qb)FU9D0)SDn$dzH8tJXti0z&3N?86eXx4^h{)@;TWsi{<}DKcKIin9-P4 zvLID$t*RteY1|aM&18qdCITbjrzt7g{ zQ=%r@PRle!4X!rU3%ceRNHjz-j>4O8J6U}~c70ovuL5ST|8CW;?HF=VivrWECGA_E zYsc2C9PfsX3fPA8FpQ&sP2o$0UyrDh=-tS-gvgXt^;_k&Vy$#aHW6RMM@}!lQe0vQ z=lO$WUu_i@_V*BvM$-6u_N`$0tj_&h8f&El4{r25AcvA&2*jqPqD4gCJxb&xPqY0t z3*>Wh)O}VC=<1E$)?dHgP(f&FhMtwY!b=>XKWJC%RWvS|BC>SJm|NA-&S1OiD8;X_ z`ts*oVR|lhdEiHxCM{mkOe^f^e06DYfR%23ZvTrvZHE@2-fTZFz4r~8vkzb5fe5)<{sPelI zEpGcoXQ8bJGgtGIHdRYaI^g1aXH`eE!PFPos^UP=FC8j zj@OoVIjz(}GBlR{7k0{QLVpjxT&RRpY+5ms2s}Cr0dP&EFlJUzaJ(m%kZ?uRKWYaU~aL*t4y+o)}UotnY z;P)3N1iN->*ilV53 zUNz&E-A|Wo!VS|q7};ebS|E{AgMh>%IGwawr9gXh_z@@vtj6YliSq=d|>FEZ;!Kt%Pzy zu36mMqsEuGATyEbd@uWM|KE<9X+MRtRQ+j?epPJ3sbaS3h^(xhX+^SN!UA@f>etjD zV;#v%>}G5kpVOxg-N|{R(f$44y@__}?_p*rD3|D!^!b!@5c*QW{cnP|YA-DNwdnn= zEey-su~{TMYGQ{&gM+>~1qnT$4i%L=7)&2!u3C$csK>Lh#HTb7aCP<}vY_Azwqe>F z{OS1$$@Srz>?sz)6N3!JV2tC*d3dxB5r+(lHUDjhq%&AOI@B_}*m6d1aNNo|bAHbv z*J3$9dFteoC&b(MX`%x@p?V)+zrHFw3K49CzvXvcUrEeaQ_ayVr6%lW1{SCaACr4X zrB)1i-)wI1BUa^B(p1=#u206a`UfvApC7M=_FdKnV_q4tTY_he^*592^n&dzfaGVs zzLr^68~jh_S*8eB=37SFo*UuT8Q9bC;!{ahp~%|m;B27|A8V2oumBT~ZvnYYQq%8YbBDQ+Pw~0QWw~YQMKH*YczIoafr_s)CTpKPr%WlBKNyPGmLbE+ zLA_xR^;ZAGfkwl>8S5;`RaN#s@tQzkOdK8ioPGz~f~&RA&^#RQK5ORT%DoRi$O zVgQ$Z*olU?Nrr@h<|DQUTGU_^vRw9WAai9|$r0bj98~AEHVFb$-PDs$BgPI5u_^33 zLdL43NI>gvcW6{=#rGcx>~P+)_$ChaAte?AVlT6HvYtRVgvR!wfyRFi)D z`+MN*E`PYXyBJzGGmA}x5V#_l&Eb}4PAXzc>aoirDm1azu)1UO1q1GYnmy9J9`D{L zL*tQwN`Q}{9T%X?m`$ax4y(LME6kN>(+(>D$iKb=RALS(Nd_L$Ax-RBMO@wiN+d?U zPe8C7g+PRZ0N4etQ1|0gsq;+aW8!u^?|@Ucon)@U_gAhwfd; z&hW~VPW-&oRFs{<0)+qc*F&boKwA7ZO%JW~l zlwy%I)>ET@WZCuIAtqxnUIvuuP&90f zZB{cgHj$>0Rl`~6S3iNF$L$)85WZEfYX??Q&T-3N;hs6fH<7E@!V(A*yR3eV`VJkv zbdc~$`Qa&BS^2`{f8_kA&*8w{*#Bt$ap`c_!hm#T0@2)6FN**Cd2r8<|NI6p{J#o9 z=tMLWEM)jJxjpg!ZTnjaT!d;90eWQtsgs1G$N^+%7kJ`cI-@J2R>w+G#Yohx+3w~?8h^2`MQJU^deldl;+zeGK~_ DBwKMR diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp b/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp deleted file mode 100755 index 39df83f7e..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Customized version of ESP32 HTTPClient Library. - * Allow custom header and payload with STARTTLS support - * - * v 1.0.0 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * HTTPClient Arduino library for ESP32 - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the HTTPClient for Arduino. - * Port to ESP32 by Evandro Luis Copercini (2017), - * changed fingerprints to CA verification. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * -*/ - -#ifndef ESP32MailHTTPClient_CPP -#define ESP32MailHTTPClient_CPP - -#ifdef ESP32 - -#include "ESP32MailHTTPClient.h" - -class TransportTraits -{ -public: - virtual ~TransportTraits() {} - - virtual std::unique_ptr create() - { - return std::unique_ptr(new WiFiClient()); - } - - virtual bool - verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb) - { - return true; - } -}; - -class TLSTraits : public TransportTraits -{ -public: - TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {} - - std::unique_ptr create() override - { - return std::unique_ptr(new WiFiClientSecureESP32()); - } - - bool verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb) override - { - WiFiClientSecureESP32 &wcs = static_cast(client); - wcs.setCACert(_cacert); - wcs.setCertificate(_clicert); - wcs.setPrivateKey(_clikey); - wcs.setSTARTTLS(starttls); - wcs.setDebugCB(cb); - return true; - } - -protected: - const char *_cacert; - const char *_clicert; - const char *_clikey; -}; - -ESP32MailHTTPClient::ESP32MailHTTPClient() {} - -ESP32MailHTTPClient::~ESP32MailHTTPClient() -{ - if (_client) - _client->stop(); -} - -bool ESP32MailHTTPClient::begin(const char *host, uint16_t port, const char *uri, const char *CAcert) -{ - transportTraits.reset(nullptr); - - _host = host; - _port = port; - _uri = uri; - transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); - return true; -} - -bool ESP32MailHTTPClient::connected() -{ - if (_client) - return ((_client->available() > 0) || _client->connected()); - return false; -} - -bool ESP32MailHTTPClient::sendHeader(const char *header) -{ - if (!connected()) - return false; - return (_client->write(header, strlen(header)) == strlen(header)); -} - -int ESP32MailHTTPClient::sendRequest(const char *header, const char *payload) -{ - size_t size = strlen(payload); - if (strlen(header) > 0) - { - if (!connect()) - return HTTPC_ERROR_CONNECTION_REFUSED; - if (!sendHeader(header)) - return HTTPC_ERROR_SEND_HEADER_FAILED; - } - if (size > 0) - if (_client->write(&payload[0], size) != size) - return HTTPC_ERROR_SEND_PAYLOAD_FAILED; - - return 0; -} - -WiFiClient *ESP32MailHTTPClient::getStreamPtr(void) -{ - if (connected()) - return _client.get(); - return nullptr; -} - -bool ESP32MailHTTPClient::connect(void) -{ - if (connected()) - { - while (_client->available() > 0) - _client->read(); - return true; - } - - if (!transportTraits) - return false; - - _client = transportTraits->create(); - - if (!transportTraits->verify(*_client, _host.c_str(), false, _debugCallback)) - { - _client->stop(); - return false; - } - - if (!_client->connect(_host.c_str(), _port)) - return false; - - return connected(); -} - -bool ESP32MailHTTPClient::connect(bool starttls) -{ - if (connected()) - { - while (_client->available() > 0) - _client->read(); - return true; - } - - if (!transportTraits) - return false; - - _client = transportTraits->create(); - - if (!transportTraits->verify(*_client, _host.c_str(), starttls, _debugCallback)) - { - _client->stop(); - return false; - } - - if (!_client->connect(_host.c_str(), _port)) - return false; - - return connected(); -} - -void ESP32MailHTTPClient::setDebugCallback(DebugMsgCallback cb) -{ - _debugCallback = std::move(cb); -} - -#endif //ESP32 - -#endif //ESP32MailHTTPClient_CPP diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h b/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h deleted file mode 100755 index 5df2c8d2d..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32MailHTTPClient.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Customized version of ESP32 HTTPClient Library. - * Allow custom header and payload with STARTTLS support - * - * v 1.0.0 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * HTTPClient Arduino library for ESP32 - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the HTTPClient for Arduino. - * Port to ESP32 by Evandro Luis Copercini (2017), - * changed fingerprints to CA verification. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * -*/ - -#ifndef ESP32MailHTTPClient_H -#define ESP32MailHTTPClient_H - -#ifdef ESP32 - -#include -#include - -#include -#include "WiFiClientSecureESP32.h" - -class ESP32MailHTTPClient : public HTTPClient -{ -public: - ESP32MailHTTPClient(); - ~ESP32MailHTTPClient(); - - /** - * Initialization of new http connection. - * \param host - Host name without protocols. - * \param port - Server's port. - * \param uri - The URI of resource. - * \param CAcert - The Base64 encode root certificate string - * \return True as default. - * If no certificate string provided, use (const char*)NULL to CAcert param - */ - bool begin(const char *host, uint16_t port, const char *uri, const char *CAcert); - - /** - * Check the http connection status. - * \return True if connected. - */ - bool connected(); - - /** - * Establish http connection if header provided and send it, send payload if provided. - * \param header - The header string (constant chars array). - * \param payload - The payload string (constant chars array), optional. - * \return http status code, Return zero if new http connection and header and/or payload sent - * with no error or no header and payload provided. If obly payload provided, no new http connection was established. - */ - int sendRequest(const char *header, const char *payload); - - /** - * Send extra header without making new http connection (if sendRequest has been called) - * \param header - The header string (constant chars array). - * \return True if header sending success. - * Need to call sendRequest with header first. - */ - bool sendHeader(const char *header); - - /** - * Get the WiFi client pointer. - * \return WiFi client pointer. - */ - WiFiClient *getStreamPtr(void); - - uint16_t tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; - bool connect(void); - bool connect(bool starttls); - void setDebugCallback(DebugMsgCallback cb); - -protected: - TransportTraitsPtr transportTraits; - std::unique_ptr _client; - DebugMsgCallback _debugCallback = NULL; - - std::string _host = ""; - std::string _uri = ""; - uint16_t _port = 0; -}; - -#endif //ESP32 - -#endif //ESP32MailHTTPClient_H diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp b/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp deleted file mode 100755 index 8e37b566b..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ESP32 Internet Time Helper Arduino Library v 1.0.1 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP32TimeHelper_CPP -#define ESP32TimeHelper_CPP - -#ifdef ESP32 - -#include "ESP32TimeHelper.h" - -ESP32TimeHelper::ESP32TimeHelper() -{ -} -uint32_t ESP32TimeHelper::getUnixTime() -{ - uint32_t utime = (msec_time_diff + millis()) / 1000; - return utime; -} - -time_t ESP32TimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec) -{ - struct tm timeinfo; - timeinfo.tm_year = year - 1900; - timeinfo.tm_mon = mon - 1; - timeinfo.tm_mday = date; - timeinfo.tm_hour = hour; - timeinfo.tm_min = mins; - timeinfo.tm_sec = sec; - time_t ts = mktime(&timeinfo); - return ts; -} - -bool ESP32TimeHelper::setClock(float gmtOffset, float daylightOffset) -{ - TZ = gmtOffset; - DST_MN = daylightOffset; - configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov", NULL); - - now = time(nullptr); - int cnt = 0; - while (now < 8 * 3600 * 2 && cnt < 20) - { - delay(50); - now = time(nullptr); - cnt++; - } - - uint64_t tmp = now; - tmp = tmp * 1000; - msec_time_diff = tmp - millis(); - - getLocalTime(&timeinfo); - - clockReady = now > 8 * 3600 * 2; - return clockReady; -} - -int ESP32TimeHelper::getYear() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_year + 1900; -} -int ESP32TimeHelper::getMonth() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_mon + 1; -} -int ESP32TimeHelper::getDay() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_mday; -} - -int ESP32TimeHelper::getDayOfWeek() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_wday; -} -String ESP32TimeHelper::getDayOfWeekString() -{ - getLocalTime(&timeinfo); - return dow[timeinfo.tm_wday]; -} - -int ESP32TimeHelper::getHour() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_hour; -} - -int ESP32TimeHelper::getMin() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_min; -} -int ESP32TimeHelper::getSec() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_sec; -} -int ESP32TimeHelper::getNumberOfDayThisYear() -{ - getLocalTime(&timeinfo); - return timeinfo.tm_yday + 1; -} - -int ESP32TimeHelper::totalDays(int y, int m, int d) -{ - static char daytab[2][13] = - { - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; - int daystotal = d; - for (int year = 1; year <= y; year++) - { - int max_month = (year < y ? 12 : m - 1); - int leap = (year % 4 == 0); - if (year % 100 == 0 && year % 400 != 0) - leap = 0; - for (int month = 1; month <= max_month; month++) - { - daystotal += daytab[leap][month]; - } - } - return daystotal; -} -int ESP32TimeHelper::getTotalDays(int year, int month, int day) -{ - return totalDays(year, month, day) - totalDays(1970, 1, 1); -} - -int ESP32TimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */ -{ - static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - year -= month < 3; - return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; -} - -int ESP32TimeHelper::getCurrentSecond() -{ - return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec; -} -uint64_t ESP32TimeHelper::getCurrentTimestamp() -{ - return now; -} -void ESP32TimeHelper::getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec) -{ - int _yrs = secCount / (365 * 24 * 3600); - secCount = secCount - _yrs * (365 * 24 * 3600); - yrs = _yrs; - int _months = secCount / (30* 24 * 3600); - secCount = secCount - _months * (30 * 24 * 3600); - months = _months; - int _days = secCount / (24 * 3600); - secCount = secCount - _days * (24 * 3600); - days = _days; - int _hr = secCount / 3600; - secCount = secCount - _hr * 3600; - hr = _hr; - int _min = secCount / 60; - secCount = secCount - _min * 60; - min = _min; - sec = secCount; -} - -#endif //ESP32 - -#endif //ESP32TimeHelper_CPP \ No newline at end of file diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h b/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h deleted file mode 100755 index e4feff648..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32TimeHelper.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ESP32 Internet Time Helper Arduino Library v 1.0.1 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP32TimeHelper_H -#define ESP32TimeHelper_H - -#ifdef ESP32 - - -#include -#include -#include - -class ESP32TimeHelper -{ -public: - ESP32TimeHelper(); - bool clockReady = false; - bool setClock(float gmtOffset, float daylightOffset); - uint32_t getUnixTime(); - time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); - int getYear(); - int getMonth(); - int getDay(); - int getDayOfWeek(); - String getDayOfWeekString(); - int getHour(); - int getMin(); - int getSec(); - int getNumberOfDayThisYear(); - int getTotalDays(int year, int month, int day); - int dayofWeek(int year, int month, int day); - int getCurrentSecond(); - uint64_t getCurrentTimestamp(); - void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec); - -private: - time_t now; - uint64_t msec_time_diff = 0; - struct tm timeinfo; - float TZ = 0.0; - float DST_MN = 0.0; - - bool setClock(); - int totalDays(int y, int m, int d); - const char *dow[20] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"}; -}; - -#endif //ESP32 - -#endif //ESP32TimeHelper_H diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp b/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp deleted file mode 100755 index 395c43028..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.cpp +++ /dev/null @@ -1,4917 +0,0 @@ -/* - *Mail Client Arduino Library for ESP32, version 2.1.4 - * - * April 12, 2020 - * - * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers. - * - * The library supports all ESP32 MCU based modules. - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP32_MailClient_CPP -#define ESP32_MailClient_CPP - -#ifdef ESP32 - -#include "ESP32_MailClient.h" - -struct ESP32_MailClient::IMAP_COMMAND_TYPE -{ - static const uint8_t LOGIN = 0; - static const uint8_t LIST = 1; - static const uint8_t SELECT = 2; - static const uint8_t EXAMINE = 3; - static const uint8_t STATUS = 4; - static const uint8_t SEARCH = 5; - static const uint8_t FETCH_BODY_HEADER = 6; - static const uint8_t FETCH_BODY_MIME = 7; - static const uint8_t FETCH_BODY_TEXT = 8; - static const uint8_t FETCH_BODY_ATTACHMENT = 9; - static const uint8_t LOGOUT = 10; -}; - -struct ESP32_MailClient::IMAP_HEADER_TYPE -{ - static const uint8_t FROM = 1; - static const uint8_t TO = 2; - static const uint8_t CC = 3; - static const uint8_t SUBJECT = 4; - static const uint8_t DATE = 5; - static const uint8_t MSG_ID = 6; - static const uint8_t CONT_LANG = 7; - static const uint8_t ACCEPT_LANG = 8; -}; - - - -bool ESP32_MailClient::readMail(IMAPData &imapData) -{ - - std::string buf; - std::string command = "$"; - - size_t mailIndex = 0; - int messageDataIndex = 0; - int partID = 1; - int _partID = 1; - bool res = false; - bool _res = false; - bool starttls = imapData._starttls; - bool connected = false; - - int bufSize = 50; - - char *_val = new char[bufSize]; - char *_part = new char[bufSize]; - - unsigned long dataTime = 0; - - int count = 0; - - imapData._net->setDebugCallback(NULL); - - if (imapData._debug) - { - ESP32MailDebugInfo(ESP32_MAIL_STR_225); - ESP32MailDebug(imapData._host.c_str()); - ESP32MailDebug(String(imapData._port).c_str()); - } - - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_50; - imapData._cbData._status = ESP32_MAIL_STR_51; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - imapData._net->setDebugCallback(ESP32MailDebug); - - if (imapData._rootCA.size() > 0) - imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)imapData._rootCA.front()); - else - imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)NULL); - - while (!imapData._net->connected() && count < 10) - { - - count++; - - if (!imapData._net->connect(starttls)) - { - - _imapStatus = IMAP_STATUS_SERVER_CONNECT_FAILED; - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - } - else - { - break; - } - } - - if (!imapData._net->connect(starttls)) - { - goto out; - } - - connected = true; - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_54; - imapData._cbData._status = ESP32_MAIL_STR_55; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_228); - - //Don't expect handshake from some servers - dataTime = millis(); - - while (imapData._net->connected() && !imapData._net->getStreamPtr()->available() && millis() - 500 < dataTime) - delay(0); - - if (imapData._net->connected() && imapData._net->getStreamPtr()->available()) - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData.clearMessageData(); - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_56; - imapData._cbData._status = ESP32_MAIL_STR_57; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_229); - - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_130); - imapData._net->getStreamPtr()->print(imapData._loginEmail.c_str()); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_131); - imapData._net->getStreamPtr()->println(imapData._loginPassword.c_str()); - - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LOGIN)) - { - _imapStatus = IMAP_STATUS_LOGIN_FAILED; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._fetchUID.length() > 0) - imapData._headerOnly = false; - else - imapData._headerOnly = true; - - if (imapData._headerOnly) - { - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_58; - imapData._cbData._status = ESP32_MAIL_STR_59; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_230); - - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_133); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LIST)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - imapData._cbData.empty(); - } - - if (imapData._readCallback) - { - - imapData._cbData._info = ESP32_MAIL_STR_60; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - for (size_t i = 0; i < imapData._folders.size(); i++) - { - imapData._cbData._info = imapData._folders[i]; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - imapData._cbData._info = ESP32_MAIL_STR_61 + imapData._currentFolder + ESP32_MAIL_STR_97; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_231); - - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_135); - imapData._net->getStreamPtr()->print(imapData._currentFolder.c_str()); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_136); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::EXAMINE)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._headerOnly) - { - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_62 + imapData._nextUID; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - imapData._cbData._info = ESP32_MAIL_STR_63; - memset(_val, 0, bufSize); - itoa(imapData._totalMessage, _val, 10); - imapData._cbData._info += _val; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - imapData._cbData._info = ESP32_MAIL_STR_64; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - for (size_t i = 0; i < imapData._flag.size(); i++) - { - imapData._cbData._info = imapData._flag[i]; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - imapData._cbData._info = ESP32_MAIL_STR_65; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - imapData._cbData._info = ESP32_MAIL_STR_66; - imapData._cbData._status = ESP32_MAIL_STR_67; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - - imapData._msgNum.clear(); - imapData._uidSearch = false; - imapData._msgID.clear(); - imapData._contentLanguage.clear(); - imapData._acceptLanguage.clear(); - imapData._attachmentCount.clear(); - imapData._totalAttachFileSize.clear(); - imapData._downloadedByte.clear(); - imapData._error.clear(); - imapData._errorMsg.clear(); - imapData._searchCount = 0; - - if (imapData._headerOnly) - { - - if (imapData._searchCriteria != "") - { - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_232); - - if (imapData._searchCriteria.find(ESP32_MAIL_STR_137) != std::string::npos) - { - imapData._uidSearch = true; - command += ESP32_MAIL_STR_138; - } - command += ESP32_MAIL_STR_139; - - for (size_t i = 0; i < imapData._searchCriteria.length(); i++) - { - if (imapData._searchCriteria[i] != ' ' && imapData._searchCriteria[i] != '\r' && imapData._searchCriteria[i] != '\n' && imapData._searchCriteria[i] != '$') - buf.append(1, imapData._searchCriteria[i]); - - if (imapData._searchCriteria[i] == ' ') - { - if ((imapData._uidSearch && buf == ESP32_MAIL_STR_140) || (imapData._unseen && buf.find(ESP32_MAIL_STR_224) != std::string::npos)) - buf.clear(); - - if (buf != ESP32_MAIL_STR_141 && buf != "") - { - command += ESP32_MAIL_STR_131; - command += buf; - } - - buf.clear(); - } - } - - if (imapData._unseen && imapData._searchCriteria.find(ESP32_MAIL_STR_223) == std::string::npos) - command += ESP32_MAIL_STR_223; - - if (buf.length() > 0) - { - command += ESP32_MAIL_STR_131; - command += buf; - } - - imapData._net->getStreamPtr()->println(command.c_str()); - - std::string().swap(command); - - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::SEARCH, 1)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._readCallback) - { - - imapData._cbData._info = ESP32_MAIL_STR_68; - memset(_val, 0, bufSize); - itoa(imapData._emailNumMax, _val, 10); - imapData._cbData._info += _val; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - if (imapData._msgNum.size() > 0) - { - - imapData._cbData._info = ESP32_MAIL_STR_69; - memset(_val, 0, bufSize); - itoa(imapData._searchCount, _val, 10); - imapData._cbData._info += _val; - imapData._cbData._info += ESP32_MAIL_STR_70; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - imapData._cbData._info = ESP32_MAIL_STR_71; - memset(_val, 0, bufSize); - itoa(imapData._msgNum.size(), _val, 10); - imapData._cbData._info += _val; - imapData._cbData._info += ESP32_MAIL_STR_70; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - else - { - imapData._cbData._info = ESP32_MAIL_STR_72; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - } - else - { - - imapData._msgNum.push_back(imapData._totalMessage); - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_73; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - } - else - { - - imapData._msgNum.push_back(atoi(imapData._fetchUID.c_str())); - } - - for (int i = 0; i < imapData._messageDataInfo.size(); i++) - imapData._messageDataInfo[i].clear(); - - imapData._messageDataInfo.clear(); - - for (int i = 0; i < imapData._msgNum.size(); i++) - { - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_233); - - if (imapData._readCallback) - { - - imapData._cbData._info = ESP32_MAIL_STR_74; - memset(_val, 0, bufSize); - itoa(i + 1, _val, 10); - imapData._cbData._info += _val; - - imapData._cbData._status = ""; - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._cbData._info += ESP32_MAIL_STR_75; - else - imapData._cbData._info += ESP32_MAIL_STR_76; - - memset(_val, 0, bufSize); - itoa(imapData._msgNum[i], _val, 10); - imapData._cbData._info += _val; - imapData._cbData._status = ESP32_MAIL_STR_77; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - imapData._date.push_back(std::string()); - imapData._subject.push_back(std::string()); - imapData._subject_charset.push_back(std::string()); - imapData._from.push_back(std::string()); - imapData._from_charset.push_back(std::string()); - imapData._to.push_back(std::string()); - imapData._to_charset.push_back(std::string()); - imapData._cc.push_back(std::string()); - imapData._attachmentCount.push_back(0); - imapData._totalAttachFileSize.push_back(0); - imapData._downloadedByte.push_back(0); - imapData._messageDataCount.push_back(0); - imapData._error.push_back(false); - imapData._errorMsg.push_back(std::string()); - imapData._cc_charset.push_back(std::string()); - imapData._msgID.push_back(std::string()); - imapData._acceptLanguage.push_back(std::string()); - imapData._contentLanguage.push_back(std::string()); - - std::vector d = std::vector(); - - imapData._messageDataInfo.push_back(d); - - std::vector().swap(d); - - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143); - - imapData._net->getStreamPtr()->print(imapData._msgNum[i]); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_144); - - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_HEADER, 0, mailIndex)) - { - if (imapData._headerOnly) - _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED; - else - _imapStatus = IMAP_STATUS_BAD_COMMAND; - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (!imapData._headerOnly) - { - - messageDataIndex = 0; - partID = 1; - _partID = 1; - res = false; - _res = false; - - do - { - - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143); - - imapData._net->getStreamPtr()->print(imapData._msgNum[i]); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147); - imapData._net->getStreamPtr()->print(partID); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_148); - - memset(_part, 0, bufSize); - memset(_val, 0, bufSize); - itoa(partID, _val, 10); - strcpy(_part, _val); - res = waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_MIME, 0, mailIndex, messageDataIndex, _part); - if (res) - { - - if (imapData._messageDataInfo[mailIndex].size() < messageDataIndex + 1) - { - messageBodyData b; - imapData._messageDataInfo[mailIndex].push_back(b); - b.empty(); - imapData._messageDataCount[mailIndex] = imapData._messageDataInfo[mailIndex].size(); - } - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == "") - continue; - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType.find(ESP32_MAIL_STR_149) != std::string::npos) - { - do - { - - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143); - - imapData._net->getStreamPtr()->print(imapData._msgNum[i]); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147); - imapData._net->getStreamPtr()->print(partID); - imapData._net->getStreamPtr()->print("."); - imapData._net->getStreamPtr()->print(_partID); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_148); - - memset(_part, 0, bufSize); - memset(_val, 0, bufSize); - itoa(partID, _val, 10); - strcpy(_part, _val); - strcat(_part, "."); - memset(_val, 0, bufSize); - itoa(_partID, _val, 10); - strcat(_part, _val); - _res = waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_MIME, 0, mailIndex, messageDataIndex, _part); - - if (_res) - { - messageDataIndex++; - _partID++; - } - - } while (_res); - } - else - { - messageDataIndex++; - } - partID++; - } - - } while (res); - - if (imapData._saveHTMLMsg || imapData._saveTextMsg || imapData._downloadAttachment) - { - - if (!_sdOk) - { - if (imapData._storageType == MailClientStorageType::SD) - { - _sdOk = sdTest(); - if (_sdOk) - if (!imapData.fsp->exists(imapData._savePath.c_str())) - createDirs(imapData._savePath); - } - else if (imapData._storageType == MailClientStorageType::SPIFFS) - _sdOk = SPIFFS.begin(true); - } - } - - if (imapData._messageDataInfo[mailIndex].size() > 0) - { - if (imapData._attachmentCount[mailIndex] > 0 && imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_78; - memset(_val, 0, bufSize); - itoa(imapData._attachmentCount[mailIndex], _val, 10); - imapData._cbData._info += _val; - imapData._cbData._info += ESP32_MAIL_STR_79; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - for (int j = 0; j < imapData._messageDataInfo[mailIndex].size(); j++) - { - if (imapData._messageDataInfo[mailIndex][j]._disposition == ESP32_MAIL_STR_153) - { - imapData._cbData._info = imapData._messageDataInfo[mailIndex][j]._filename; - imapData._cbData._info += ESP32_MAIL_STR_83; - memset(_val, 0, bufSize); - itoa(imapData._messageDataInfo[mailIndex][j]._size, _val, 10); - imapData._cbData._info += _val; - imapData._cbData._info += ESP32_MAIL_STR_82; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - - if (imapData._downloadAttachment && _sdOk) - { - imapData._cbData._info = ESP32_MAIL_STR_80; - imapData._cbData._status = ESP32_MAIL_STR_81; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - } - - for (int j = 0; j < imapData._messageDataInfo[mailIndex].size(); j++) - { - - if (imapData._messageDataInfo[mailIndex][j]._disposition == "") - { - - if (!imapData._textFormat && imapData._messageDataInfo[mailIndex][j]._contentType != ESP32_MAIL_STR_154) - continue; - - if (!imapData._htmlFormat && imapData._messageDataInfo[mailIndex][j]._contentType != ESP32_MAIL_STR_155) - continue; - - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143); - - imapData._net->getStreamPtr()->print(imapData._msgNum[i]); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147); - imapData._net->getStreamPtr()->print(imapData._messageDataInfo[mailIndex][j]._part.c_str()); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_156); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_TEXT, imapData._message_buffer_size, mailIndex, j)) - { - _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - } - } - else if (imapData._messageDataInfo[mailIndex][j]._disposition == ESP32_MAIL_STR_153 && _sdOk) - { - - if (imapData._downloadAttachment) - { - if (imapData._messageDataInfo[mailIndex][j]._size <= imapData._attacement_max_size) - { - - if (_sdOk) - { - - if (j < imapData._messageDataInfo[mailIndex].size() - 1) - if (imapData._messageDataInfo[mailIndex][j + 1]._size > imapData._attacement_max_size) - imapData._downloadedByte[mailIndex] += imapData._messageDataInfo[mailIndex][j + 1]._size; - - if (imapData._uidSearch || imapData._fetchUID.length() > 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_142); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_143); - - imapData._net->getStreamPtr()->print(imapData._msgNum[i]); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_147); - imapData._net->getStreamPtr()->print(imapData._messageDataInfo[mailIndex][j]._part.c_str()); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_156); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT, imapData._message_buffer_size, mailIndex, j)) - { - _imapStatus = IMAP_STATUS_IMAP_RESPONSE_FAILED; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - } - - delay(0); - } - } - else - { - if (j == imapData._messageDataInfo[mailIndex].size() - 1) - imapData._downloadedByte[mailIndex] += imapData._messageDataInfo[mailIndex][j]._size; - } - } - } - } - } - - if (imapData._storageType == MailClientStorageType::SD) - { - if (_sdOk) - SD.end(); - } - else if (imapData._storageType == MailClientStorageType::SPIFFS) - { - if (_sdOk) - SPIFFS.end(); - } - - _sdOk = false; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_84; - memset(_val, 0, bufSize); - itoa(ESP.getFreeHeap(), _val, 10); - imapData._cbData._info += _val; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - mailIndex++; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_85; - imapData._cbData._status = ESP32_MAIL_STR_86; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_234); - - if (imapData._net->connected()) - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_146); - - if (!waitIMAPResponse(imapData, 0)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_98; - imapData._cbData._status = ESP32_MAIL_STR_96; - imapData._cbData._success = true; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_235); - - if (imapData._net->connected()) - { - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData._net->getStreamPtr()->stop(); - } - - imapData._cbData.empty(); - delete[] _val; - delete[] _part; - std::string().swap(command); - std::string().swap(buf); - - return true; - -out: - - if (connected) - { - if (imapData._net->connected()) - { - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - imapData._net->getStreamPtr()->stop(); - } - } - - imapData._cbData.empty(); - delete[] _val; - delete[] _part; - std::string().swap(command); - std::string().swap(buf); - - return false; -} - -bool ESP32_MailClient::setFlag(IMAPData &imapData, int msgUID, const String &flag) -{ - return _setFlag(imapData, msgUID, flag, 0); -} - -bool ESP32_MailClient::addFlag(IMAPData &imapData, int msgUID, const String &flag) -{ - return _setFlag(imapData, msgUID, flag, 1); -} - -bool ESP32_MailClient::removeFlag(IMAPData &imapData, int msgUID, const String &flag) -{ - return _setFlag(imapData, msgUID, flag, 2); -} - -bool ESP32_MailClient::_setFlag(IMAPData &imapData, int msgUID, const String &flag, uint8_t action) -{ - - std::string buf; - - bool starttls = imapData._starttls; - bool connected = false; - - int bufSize = 50; - - char *_val = new char[bufSize]; - char *_part = new char[bufSize]; - - unsigned long dataTime = 0; - - int count = 0; - - imapData._net->setDebugCallback(NULL); - - if (imapData._debug) - { - ESP32MailDebugInfo(ESP32_MAIL_STR_225); - ESP32MailDebug(imapData._host.c_str()); - ESP32MailDebug(String(imapData._port).c_str()); - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_50; - imapData._cbData._status = ESP32_MAIL_STR_51; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - imapData._net->setDebugCallback(ESP32MailDebug); - - if (imapData._rootCA.size() > 0) - imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)imapData._rootCA.front()); - else - imapData._net->begin(imapData._host.c_str(), imapData._port, ESP32_MAIL_STR_202, (const char *)NULL); - - while (!imapData._net->connected() && count < 10) - { - - count++; - - if (!imapData._net->connect(starttls)) - { - - _imapStatus = IMAP_STATUS_SERVER_CONNECT_FAILED; - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - } - else - { - break; - } - } - - if (!imapData._net->connect(starttls)) - { - goto out; - } - - connected = true; - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_54; - imapData._cbData._status = ESP32_MAIL_STR_55; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_228); - - //Don't expect handshake from some servers - dataTime = millis(); - - while (imapData._net->connected() && !imapData._net->getStreamPtr()->available() && millis() - 500 < dataTime) - delay(0); - - if (imapData._net->connected() && imapData._net->getStreamPtr()->available()) - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData.clearMessageData(); - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_56; - imapData._cbData._status = ESP32_MAIL_STR_57; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_229); - - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_130); - imapData._net->getStreamPtr()->print(imapData._loginEmail.c_str()); - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_131); - imapData._net->getStreamPtr()->println(imapData._loginPassword.c_str()); - - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LOGIN)) - { - _imapStatus = IMAP_STATUS_LOGIN_FAILED; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_58; - imapData._cbData._status = ESP32_MAIL_STR_59; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_230); - - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_133); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::LIST)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - imapData._cbData.empty(); - } - - if (imapData._readCallback) - { - - imapData._cbData._info = ESP32_MAIL_STR_60; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - - for (size_t i = 0; i < imapData._folders.size(); i++) - { - imapData._cbData._info = imapData._folders[i]; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - imapData._cbData._info = ESP32_MAIL_STR_61 + imapData._currentFolder + ESP32_MAIL_STR_97; - imapData._cbData._status = ""; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_248); - - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_247); - imapData._net->getStreamPtr()->print(imapData._currentFolder.c_str()); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_136); - if (!waitIMAPResponse(imapData, IMAP_COMMAND_TYPE::EXAMINE)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._debug) - { - if (action == 0) - ESP32MailDebugInfo(ESP32_MAIL_STR_253); - else if (action == 1) - ESP32MailDebugInfo(ESP32_MAIL_STR_254); - else - ESP32MailDebugInfo(ESP32_MAIL_STR_255); - } - - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_249); - imapData._net->getStreamPtr()->print(msgUID); - if (action == 0) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_250); - else if (action == 1) - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_251); - else - imapData._net->getStreamPtr()->print(ESP32_MAIL_STR_252); - imapData._net->getStreamPtr()->print(flag); - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_192); - - if (!getIMAPResponse(imapData)) - { - _imapStatus = IMAP_STATUS_PARSE_FLAG_FAILED; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_85; - imapData._cbData._status = ESP32_MAIL_STR_86; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_234); - - if (imapData._net->connected()) - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData._net->getStreamPtr()->println(ESP32_MAIL_STR_146); - - if (!waitIMAPResponse(imapData, 0)) - { - _imapStatus = IMAP_STATUS_BAD_COMMAND; - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_53 + imapErrorReasonStr(); - imapData._cbData._status = ESP32_MAIL_STR_52; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - if (imapData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(imapErrorReasonStr().c_str(), true); - } - goto out; - } - - if (imapData._readCallback) - { - imapData._cbData._info = ESP32_MAIL_STR_98; - imapData._cbData._status = ESP32_MAIL_STR_96; - imapData._cbData._success = true; - imapData._readCallback(imapData._cbData); - } - - if (imapData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_235); - - if (imapData._net->connected()) - { - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - - imapData._net->getStreamPtr()->stop(); - } - - imapData._cbData.empty(); - delete[] _val; - delete[] _part; - std::string().swap(buf); - - return true; - -out: - - if (connected) - { - if (imapData._net->connected()) - { - while (imapData._net->getStreamPtr()->available()) - imapData._net->getStreamPtr()->read(); - imapData._net->getStreamPtr()->stop(); - } - } - - imapData._cbData.empty(); - delete[] _val; - delete[] _part; - std::string().swap(buf); - return false; -} - - -bool ESP32_MailClient::smtpClientAvailable(SMTPData &smtpData, bool available) -{ - - if (!smtpData._net->getStreamPtr()) - return false; - - if (available) - return smtpData._net->getStreamPtr()->connected() && smtpData._net->getStreamPtr()->available(); - else - return smtpData._net->getStreamPtr()->connected() && !smtpData._net->getStreamPtr()->available(); -} - -bool ESP32_MailClient::imapClientAvailable(IMAPData &imapData, bool available) -{ - - if (!imapData._net->getStreamPtr()) - return false; - - if (available) - return imapData._net->getStreamPtr()->connected() && imapData._net->getStreamPtr()->available(); - else - return imapData._net->getStreamPtr()->connected() && !imapData._net->getStreamPtr()->available(); -} - -void ESP32_MailClient::createDirs(std::string dirs) -{ - std::string dir = ""; - int count = 0; - for (int i = 0; i < dirs.length(); i++) - { - dir.append(1, dirs[i]); - count++; - if (dirs[i] == '/') - { - if (dir.length() > 0) - SD.mkdir(dir.substr(0, dir.length() - 1).c_str()); - count = 0; - } - } - if (count > 0) - SD.mkdir(dir.c_str()); - std::string().swap(dir); -} - -bool ESP32_MailClient::sdTest() -{ - - if (_sdConfigSet) - sdBegin(_sck, _miso, _mosi, _ss); - else - sdBegin(); - - File file = SD.open(ESP32_MAIL_STR_204, FILE_WRITE); - if (!file) - return false; - - if (!file.write(32)) - return false; - file.close(); - - file = SD.open(ESP32_MAIL_STR_204); - if (!file) - return false; - - while (file.available()) - { - if (file.read() != 32) - return false; - } - file.close(); - - SD.remove(ESP32_MAIL_STR_204); - - return true; -} - -bool ESP32_MailClient::sendMail(SMTPData &smtpData) -{ - - _smtpStatus = 0; - std::string buf; - std::string buf2; - int bufSize = 50; - bool starttls = smtpData._starttls; - bool connected = false; - char *_val = new char[bufSize]; - int res = 0; - - smtpData._net->setDebugCallback(NULL); - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_120; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - { - ESP32MailDebugInfo(ESP32_MAIL_STR_236); - ESP32MailDebug(smtpData._host.c_str()); - ESP32MailDebug(String(smtpData._port).c_str()); - } - - - if (smtpData._debug) - smtpData._net->setDebugCallback(ESP32MailDebug); - - if (smtpData._rootCA.size() > 0) - smtpData._net->begin(smtpData._host.c_str(), smtpData._port, ESP32_MAIL_STR_202, (const char *)smtpData._rootCA.front()); - else - smtpData._net->begin(smtpData._host.c_str(), smtpData._port, ESP32_MAIL_STR_202, (const char *)NULL); - - if (smtpData._port == 587) - starttls = true; - - if (!smtpData._net->connect(starttls)) - { - _smtpStatus = SMTP_STATUS_SERVER_CONNECT_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_238); - - connected = true; - - if (!starttls) - { - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_121; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (waitSMTPResponse(smtpData) != 220) - { - _smtpStatus = SMTP_STATUS_SMTP_RESPONSE_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_122; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_239); - - smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_5); - - if (waitSMTPResponse(smtpData) != 250) - { - _smtpStatus = SMTP_STATUS_IDENTIFICATION_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_123; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_240); - - smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_4); - - if (waitSMTPResponse(smtpData) != 334) - { - _smtpStatus = SMTP_STATUS_AUTHEN_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_124; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_241); - - smtpData._net->getStreamPtr()->println(base64_encode_string((const unsigned char *)smtpData._loginEmail.c_str(), smtpData._loginEmail.length()).c_str()); - - if (waitSMTPResponse(smtpData) != 334) - { - _smtpStatus = SMTP_STATUS_USER_LOGIN_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - smtpData._net->getStreamPtr()->println(base64_encode_string((const unsigned char *)smtpData._loginPassword.c_str(), smtpData._loginPassword.length()).c_str()); - - if (waitSMTPResponse(smtpData) != 235) - { - _smtpStatus = SMTP_STATUS_PASSWORD_LOGIN_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_125; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_242); - - if (smtpData._priority > 0 && smtpData._priority <= 5) - { - memset(_val, 0, bufSize); - itoa(smtpData._priority, _val, 10); - - buf2 += ESP32_MAIL_STR_17; - buf2 += _val; - buf2 += ESP32_MAIL_STR_34; - - if (smtpData._priority == 1) - { - buf2 += ESP32_MAIL_STR_18; - buf2 += ESP32_MAIL_STR_21; - } - else if (smtpData._priority == 3) - { - buf2 += ESP32_MAIL_STR_19; - buf2 += ESP32_MAIL_STR_22; - } - else if (smtpData._priority == 5) - { - buf2 += ESP32_MAIL_STR_20; - buf2 += ESP32_MAIL_STR_23; - } - } - - buf2 += ESP32_MAIL_STR_10; - - if (smtpData._fromName.length() > 0) - buf2 += smtpData._fromName; - - buf2 += ESP32_MAIL_STR_14; - buf2 += smtpData._senderEmail; - buf2 += ESP32_MAIL_STR_15; - buf2 += ESP32_MAIL_STR_34; - - buf += ESP32_MAIL_STR_8; - buf += ESP32_MAIL_STR_14; - buf += smtpData._senderEmail; - buf += ESP32_MAIL_STR_15; - smtpData._net->getStreamPtr()->println(buf.c_str()); - - if (waitSMTPResponse(smtpData) != 250) - { - _smtpStatus = SMTP_STATUS_SEND_HEADER_SENDER_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - for (uint8_t i = 0; i < smtpData._recipient.size(); i++) - { - if (i == 0) - { - buf2 += ESP32_MAIL_STR_11; - buf2 += ESP32_MAIL_STR_14; - buf2 += smtpData._recipient[i]; - buf2 += ESP32_MAIL_STR_15; - } - else - { - buf2 += ESP32_MAIL_STR_13; - buf2 += smtpData._recipient[i]; - buf2 += ESP32_MAIL_STR_15; - } - - if (i == smtpData._recipient.size() - 1) - buf2 += ESP32_MAIL_STR_34; - - buf.clear(); - - buf += ESP32_MAIL_STR_9; - buf += ESP32_MAIL_STR_14; - buf += smtpData._recipient[i]; - buf += ESP32_MAIL_STR_15; - - smtpData._net->getStreamPtr()->println(buf.c_str()); - - if (waitSMTPResponse(smtpData) != 250) - { - _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - } - - for (uint8_t i = 0; i < smtpData._cc.size(); i++) - { - - if (i == 0) - { - buf2 += ESP32_MAIL_STR_12; - buf2 += ESP32_MAIL_STR_14; - buf2 += smtpData._cc[i]; - buf2 += ESP32_MAIL_STR_15; - } - else - { - buf2 += ESP32_MAIL_STR_13; - buf2 += smtpData._cc[i]; - buf2 += ESP32_MAIL_STR_15; - } - - if (i == smtpData.ccCount() - 1) - buf2 += ESP32_MAIL_STR_34; - - buf.clear(); - - buf += ESP32_MAIL_STR_9; - buf += ESP32_MAIL_STR_14; - buf += smtpData._cc[i]; - buf += ESP32_MAIL_STR_15; - smtpData._net->getStreamPtr()->println(buf.c_str()); - - if (waitSMTPResponse(smtpData) != 250) - { - _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - } - - for (uint8_t i = 0; i < smtpData._bcc.size(); i++) - { - buf.clear(); - buf += ESP32_MAIL_STR_9; - buf += ESP32_MAIL_STR_14; - buf += smtpData._bcc[i]; - buf += ESP32_MAIL_STR_15; - smtpData._net->getStreamPtr()->println(buf.c_str()); - - if (waitSMTPResponse(smtpData) != 250) - { - _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_126; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_243); - - smtpData._net->getStreamPtr()->println(ESP32_MAIL_STR_16); - - if (waitSMTPResponse(smtpData) != 354) - { - _smtpStatus = SMTP_STATUS_SEND_BODY_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - smtpData._net->getStreamPtr()->print(buf2.c_str()); - - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_24); - smtpData._net->getStreamPtr()->println(smtpData._subject.c_str()); - - if (smtpData._customMessageHeader.size() > 0) - for (uint8_t k = 0; k < smtpData._customMessageHeader.size(); k++) - smtpData._net->getStreamPtr()->println(smtpData._customMessageHeader[k].c_str()); - - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_3); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_1); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_2); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_35); - - buf.clear(); - - set_message_header(buf, smtpData._message, smtpData._htmlFormat); - - smtpData._net->getStreamPtr()->print(buf.c_str()); - - if (smtpData._attach._index > 0) - { - smtpData._cbData._info = ESP32_MAIL_STR_127; - smtpData._cbData._success = false; - if (smtpData._sendCallback) - smtpData._sendCallback(smtpData._cbData); - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_244); - } - - for (uint8_t i = 0; i < smtpData._attach._index; i++) - { - if (smtpData._attach._type[i] == 0) - { - - smtpData._cbData._info = smtpData._attach._filename[i]; - smtpData._cbData._success = false; - if (smtpData._sendCallback) - smtpData._sendCallback(smtpData._cbData); - if (smtpData._debug) - ESP32MailDebug(smtpData._attach._filename[i].c_str()); - - buf.clear(); - set_attachment_header(i, buf, smtpData._attach); - smtpData._net->getStreamPtr()->print(buf.c_str()); - send_base64_encode_mime_data(smtpData._net->getStreamPtr(), smtpData._attach._buf[i].front(), smtpData._attach._size[i]); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_34); - } - else - { - -/* - if (!_sdOk) - { - if (smtpData._storageType == MailClientStorageType::SD) - _sdOk = sdTest(); - else if (smtpData._storageType == MailClientStorageType::SPIFFS) - _sdOk = SPIFFS.begin(true); - } - - if (!_sdOk) - continue; -*/ - bool file_existed = false; -/* - if (smtpData._storageType == MailClientStorageType::SD) - file_existed = SD.exists(smtpData._attach._filename[i].c_str()); - else if (smtpData._storageType == MailClientStorageType::SPIFFS) - file_existed = SPIFFS.exists(smtpData._attach._filename[i].c_str()); - else if (smtpData._storageType == MailClientStorageType::FFat) - file_existed = FFat.exists(smtpData._attach._filename[i].c_str()); -*/ - - file_existed = smtpData.fsp->exists(smtpData._attach._filename[i].c_str()); - if (file_existed) - { - smtpData._cbData._info = smtpData._attach._filename[i]; - smtpData._cbData._success = false; - if (smtpData._sendCallback) - smtpData._sendCallback(smtpData._cbData); - - if (smtpData._debug) - ESP32MailDebug(smtpData._attach._filename[i].c_str()); - - buf.clear(); - set_attachment_header(i, buf, smtpData._attach); - smtpData._net->getStreamPtr()->print(buf.c_str()); - - File file; - /* - if (smtpData._storageType == MailClientStorageType::SD) - file = SD.open(smtpData._attach._filename[i].c_str(), FILE_READ); - else if (smtpData._storageType == MailClientStorageType::SPIFFS) - file = SPIFFS.open(smtpData._attach._filename[i].c_str(), FILE_READ); - else if (smtpData._storageType == MailClientStorageType::FFat) - file = FFat.open(smtpData._attach._filename[i].c_str(), FILE_READ); - */ - file = smtpData.fsp->open(smtpData._attach._filename[i].c_str(), FILE_READ); - - send_base64_encode_mime_file(smtpData._net->getStreamPtr(), file); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_34); - } - } - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_245); - - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_33); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_2); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_33); - smtpData._net->getStreamPtr()->print(ESP32_MAIL_STR_37); - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_128; - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - - res = waitSMTPResponse(smtpData); - - if (res != 250 && res != -1000) - { - _smtpStatus = SMTP_STATUS_SEND_BODY_FAILED; - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); - smtpData._cbData._success = false; - smtpData._sendCallback(smtpData._cbData); - } - if (smtpData._debug) - { - ESP32MailDebugError(); - ESP32MailDebugLine(smtpErrorReasonStr().c_str(), true); - } - goto failed; - } - - if (smtpData._sendCallback) - { - smtpData._cbData._info = ESP32_MAIL_STR_129; - smtpData._cbData._success = true; - smtpData._sendCallback(smtpData._cbData); - } - - if (smtpData._debug) - ESP32MailDebugInfo(ESP32_MAIL_STR_246); - - if (smtpData._net->connected()) - smtpData._net->getStreamPtr()->stop(); - - smtpData._cbData.empty(); - - std::string().swap(buf); - std::string().swap(buf2); - delete[] _val; - - return true; - -failed: - - if (connected) - { - if (smtpData._net->connected()) - smtpData._net->getStreamPtr()->stop(); - } - - smtpData._cbData.empty(); - std::string().swap(buf); - std::string().swap(buf2); - delete[] _val; - return false; -} - -String ESP32_MailClient::smtpErrorReason() -{ - return smtpErrorReasonStr().c_str(); -} - -std::string ESP32_MailClient::smtpErrorReasonStr() -{ - std::string res = ""; - switch (_smtpStatus) - { - case SMTP_STATUS_SERVER_CONNECT_FAILED: - res = ESP32_MAIL_STR_38; - break; - case SMTP_STATUS_SMTP_RESPONSE_FAILED: - res = ESP32_MAIL_STR_39; - break; - case SMTP_STATUS_IDENTIFICATION_FAILED: - res = ESP32_MAIL_STR_41; - break; - case SMTP_STATUS_AUTHEN_NOT_SUPPORT: - res = ESP32_MAIL_STR_42; - break; - case SMTP_STATUS_AUTHEN_FAILED: - res = ESP32_MAIL_STR_43; - break; - case SMTP_STATUS_USER_LOGIN_FAILED: - res = ESP32_MAIL_STR_44; - break; - case SMTP_STATUS_PASSWORD_LOGIN_FAILED: - res = ESP32_MAIL_STR_47; - break; - case SMTP_STATUS_SEND_HEADER_SENDER_FAILED: - res = ESP32_MAIL_STR_48; - break; - case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED: - res = ESP32_MAIL_STR_222; - break; - case SMTP_STATUS_SEND_BODY_FAILED: - res = ESP32_MAIL_STR_49; - break; - case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL: - res = ESP32_MAIL_STR_221; - break; - default: - res = ""; - } - return res; -} - -String ESP32_MailClient::imapErrorReason() -{ - std::string res = ""; - switch (_imapStatus) - { - case IMAP_STATUS_SERVER_CONNECT_FAILED: - res = ESP32_MAIL_STR_38; - break; - case IMAP_STATUS_IMAP_RESPONSE_FAILED: - res = ESP32_MAIL_STR_40; - break; - case IMAP_STATUS_LOGIN_FAILED: - res = ESP32_MAIL_STR_45; - break; - case IMAP_STATUS_BAD_COMMAND: - res = ESP32_MAIL_STR_46; - break; - case IMAP_STATUS_PARSE_FLAG_FAILED: - res = ESP32_MAIL_STR_256; - break; - case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL: - res = ESP32_MAIL_STR_221; - break; - default: - res = ""; - } - return res.c_str(); -} - -std::string ESP32_MailClient::imapErrorReasonStr() -{ - std::string res = ""; - - switch (_imapStatus) - { - case IMAP_STATUS_SERVER_CONNECT_FAILED: - res = ESP32_MAIL_STR_38; - break; - case IMAP_STATUS_IMAP_RESPONSE_FAILED: - res = ESP32_MAIL_STR_40; - break; - case IMAP_STATUS_LOGIN_FAILED: - res = ESP32_MAIL_STR_45; - break; - case IMAP_STATUS_BAD_COMMAND: - res = ESP32_MAIL_STR_46; - break; - case IMAP_STATUS_PARSE_FLAG_FAILED: - res = ESP32_MAIL_STR_256; - break; - case MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL: - res = ESP32_MAIL_STR_221; - break; - default: - res = ""; - } - return res; -} - -void ESP32_MailClient::ESP32MailDebugError() -{ - size_t dbgInfoLen = strlen_P(ESP32_MAIL_STR_227) + 1; - char *dbgInfo = new char[dbgInfoLen]; - memset(dbgInfo, 0, dbgInfoLen); - strcpy_P(dbgInfo, ESP32_MAIL_STR_227); - ESP32MailDebugLine(dbgInfo, false); - delete[] dbgInfo; -} - -void ESP32_MailClient::ESP32MailDebugInfo(PGM_P info) -{ - size_t dbgInfoLen = strlen_P(info) + 1; - char *dbgInfo = new char[dbgInfoLen]; - memset(dbgInfo, 0, dbgInfoLen); - strcpy_P(dbgInfo, info); - ESP32MailDebug(dbgInfo); - delete[] dbgInfo; -} - -bool ESP32_MailClient::sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss) -{ - _sck = sck; - _miso = miso; - _mosi = mosi; - _ss = ss; - _sdConfigSet = true; - - SPI.begin(_sck, _miso, _mosi, _ss); - return SD.begin(_ss, SPI); -} - -bool ESP32_MailClient::sdBegin(void) -{ - _sdConfigSet = false; - return SD.begin(); -} - -void ESP32_MailClient::set_message_header(string &header, string &message, bool htmlFormat) -{ - header += ESP32_MAIL_STR_33; - header += ESP32_MAIL_STR_2; - header += ESP32_MAIL_STR_34; - if (!htmlFormat) - header += ESP32_MAIL_STR_27; - else - header += ESP32_MAIL_STR_28; - - header += ESP32_MAIL_STR_29; - header += ESP32_MAIL_STR_34; - - header += message; - header += ESP32_MAIL_STR_34; - header += ESP32_MAIL_STR_34; -} - -void ESP32_MailClient::set_attachment_header(uint8_t index, std::string &header, attachmentData &attach) -{ - - header += ESP32_MAIL_STR_33; - header += ESP32_MAIL_STR_2; - header += ESP32_MAIL_STR_34; - - header += ESP32_MAIL_STR_25; - - if (attach._mime_type[index].length() == 0) - header += ESP32_MAIL_STR_32; - else - header += attach._mime_type[index]; - - header += ESP32_MAIL_STR_26; - - std::string filename(attach._filename[index]); - - size_t found = filename.find_last_of("/\\"); - - if (found != std::string::npos) - { - filename.clear(); - filename += attach._filename[index].substr(found + 1); - } - - header += filename; - header += ESP32_MAIL_STR_36; - - header += ESP32_MAIL_STR_30; - header += filename; - header += ESP32_MAIL_STR_36; - - header += ESP32_MAIL_STR_31; - header += ESP32_MAIL_STR_34; - - std::string().swap(filename); -} - -int ESP32_MailClient::waitSMTPResponse(SMTPData &smtpData) -{ - - long dataTime = millis(); - char c = '\0'; - std::string lineBuf = ""; - int lfCount = 0; - size_t p1 = 0; - int resCode = -1000; - - while (smtpClientAvailable(smtpData, false) && millis() - dataTime < smtpData._net->tcpTimeout) - delay(0); - - dataTime = millis(); - if (smtpClientAvailable(smtpData, true)) - { - while (smtpClientAvailable(smtpData, true)) - { - int r = smtpData._net->getStreamPtr()->read(); - - if (r < 0) - continue; - - c = (char)r; - - lineBuf.append(1, c); - if (c == '\n') - { - dataTime = millis(); - if (lfCount == 0) - { - p1 = lineBuf.find(" "); - if (p1 != std::string::npos) - resCode = atoi(lineBuf.substr(0, p1).c_str()); - } - if (smtpData._debug) - ESP32MailDebug(lineBuf.c_str()); - lineBuf.clear(); - lfCount++; - } - - if (millis() - dataTime > smtpData._net->tcpTimeout + 30000) - break; - } - } - std::string().swap(lineBuf); - return resCode; -} - -bool ESP32_MailClient::getIMAPResponse(IMAPData &imapData) -{ - long dataTime = millis(); - char c = '\0'; - bool success = false; - std::string str = ""; - while (imapClientAvailable(imapData, false) && millis() - dataTime < imapData._net->tcpTimeout) - delay(0); - - dataTime = millis(); - if (imapClientAvailable(imapData, true)) - { - while (imapClientAvailable(imapData, true)) - { - int r = imapData._net->getStreamPtr()->read(); - if (r < 0) - continue; - c = (char)r; - if (c == '\n') - { - if (imapData._debug) - ESP32MailDebug(str.c_str()); - str.clear(); - } - else - str += c; - - if (str.find(ESP32_MAIL_STR_132) != std::string::npos) - success = true; - } - } - - std::string().swap(str); - return success; -} - -bool ESP32_MailClient::waitIMAPResponse(IMAPData &imapData, uint8_t imapCommandType, int maxChar, int mailIndex, int messageDataIndex, std::string part) -{ - - long dataTime = millis(); - - char c = 0; - std::string lineBuf = ""; - std::string msgNumBuf = ""; - std::string filepath = ""; - std::string hpath = ""; - std::string tmp = ""; - std::string msgID = ""; - std::string from = ""; - std::string to = ""; - std::string subject = ""; - std::string date = ""; - std::string cc = ""; - std::string from_charset = ""; - std::string to_charset = ""; - std::string cc_charset = ""; - std::string subject_charset = ""; - std::string acceptLanguage = ""; - std::string contentLanguage = ""; - - int bufSize = 100; - char *dest = new char[bufSize]; - char *buf = new char[bufSize]; - - int readCount = 0; - int lfCount = 0; - int charCount = 0; - size_t p1 = 0; - size_t p2 = 0; - size_t p3 = 0; - size_t payloadLength = 0; - size_t outputLength; - - bool completeResp = false; - bool validResponse = false; - bool downloadReq = false; - size_t currentDownloadByte = 0; - - int max = imapData._emailNumMax; - if (!imapData._recentSort) - max = max - 1; - - uint8_t headerType = 0; - - File file; - int reportState = 0; - int downloadedByte = 0; - - if (imapCommandType == IMAP_COMMAND_TYPE::LIST) - std::vector() - .swap(imapData._folders); - - while (imapClientAvailable(imapData, false) && millis() - dataTime < imapData._net->tcpTimeout) - delay(0); - - dataTime = millis(); - if (imapClientAvailable(imapData, true)) - { - while (imapClientAvailable(imapData, true) || !completeResp) - { - - int r = imapData._net->getStreamPtr()->read(); - - if (r < 0) - continue; - - c = (char)r; - - if (payloadLength > 0 && !completeResp) - charCount++; - - if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount == 0) - { - delay(0); - if (c == ' ') - { - p3 = msgNumBuf.find(ESP32_MAIL_STR_257); - if (p3 != std::string::npos) - { - validResponse = false; - break; - } - - if (msgNumBuf != ESP32_MAIL_STR_183 && msgNumBuf != ESP32_MAIL_STR_141 && imapData._msgNum.size() <= max) - { - imapData._msgNum.push_back(atoi(msgNumBuf.c_str())); - - if (imapData._msgNum.size() > imapData._emailNumMax && imapData._recentSort) - imapData._msgNum.erase(imapData._msgNum.begin()); - imapData._searchCount++; - } - - msgNumBuf.clear(); - } - else if (c != '\r' && c != '\n') - { - msgNumBuf.append(1, c); - } - } - - if (c != '\r' && c != '\n' && imapCommandType != IMAP_COMMAND_TYPE::SEARCH) - lineBuf.append(1, c); - - if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT && lfCount > 0) - { - - if (payloadLength > 0 && charCount < payloadLength - 1) - { - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding != ESP32_MAIL_STR_160) - { - if (charCount < maxChar) - imapData._messageDataInfo[mailIndex][messageDataIndex]._text.append(1, c); - - if (imapData._saveHTMLMsg || imapData._saveTextMsg) - { - - if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true; - - if (_sdOk) - { - downloadReq = true; - - filepath.clear(); - - filepath = imapData._savePath; - filepath += ESP32_MAIL_STR_202; - - char *midx = new char[50]; - memset(midx, 0, 50); - itoa(imapData._msgNum[mailIndex], midx, 10); - - filepath += midx; - - delete[] midx; - - if (imapData._storageType == MailClientStorageType::SD) - if (!imapData.fsp->exists(filepath.c_str())) - createDirs(filepath); - - if (!imapData._headerSaved) - hpath = filepath + ESP32_MAIL_STR_203; - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155) - { - if (imapData._saveDecodedText) - filepath += ESP32_MAIL_STR_161; - else - filepath += ESP32_MAIL_STR_162; - } - else if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154) - { - if (imapData._saveDecodedHTML) - filepath += ESP32_MAIL_STR_163; - else - filepath += ESP32_MAIL_STR_164; - } - - if (imapData._storageType == MailClientStorageType::SD) - file = imapData.fsp->open(filepath.c_str(), FILE_WRITE); - else if (imapData._storageType == MailClientStorageType::SPIFFS) - file = SPIFFS.open(filepath.c_str(), FILE_WRITE); - } - else - { - - if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true; - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear(); - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89; - } - } - } - if (_sdOk) - file.write(c); - } - } - } - - if (millis() - dataTime > imapData._net->tcpTimeout + (30 * 1000) || (payloadLength > 0 && charCount == payloadLength && completeResp)) - { - - if (charCount < payloadLength || !completeResp) - clientReadAll(imapData._net->getStreamPtr()); - - break; - } - } - - if (c == '\n') - { - dataTime = millis(); - - if (lfCount == 0) - { - if (imapData._debug) - ESP32MailDebug(lineBuf.c_str()); - - if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT || - imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME || - imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER || - imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT) - { - - p1 = lineBuf.find(ESP32_MAIL_STR_165); - if (p1 != std::string::npos) - validResponse = true; - } - - p1 = lineBuf.find(ESP32_MAIL_STR_166); - if (p1 != std::string::npos) - validResponse = true; - } - - p1 = lineBuf.find(ESP32_MAIL_STR_211); - p2 = lineBuf.find(ESP32_MAIL_STR_158); - p3 = lineBuf.find(ESP32_MAIL_STR_159); - - if (p1 != std::string::npos || p2 != std::string::npos || p3 != std::string::npos) - { - - validResponse = true; - - if (p2 != std::string::npos || p3 != std::string::npos) - validResponse = false; - - if (payloadLength == 0) - { - if (imapCommandType == IMAP_COMMAND_TYPE::LOGIN || - imapCommandType == IMAP_COMMAND_TYPE::LIST || - imapCommandType == IMAP_COMMAND_TYPE::EXAMINE || - imapCommandType == IMAP_COMMAND_TYPE::SEARCH || - imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME || - imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER) - { - - //Cyrus server 3.0 does not comply to rfc3501 as it resonses the CAPABILITY after received LOGIN command with no CAPABILITY command requested. - if (lineBuf.find(ESP32_MAIL_STR_134) == std::string::npos && lineBuf.find(ESP32_MAIL_STR_145) == std::string::npos) - completeResp = true; - - //Some servers e.g. STRATO E-Mail-Server does not reply any error when fetching none existing MIME header part at defined index. - if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME) - validResponse = false; - } - } - else - { - - if ((payloadLength > 0 && charCount >= payloadLength) || imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME) - { - completeResp = true; - } - } - } - - if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount > 0) - { - completeResp = true; - validResponse = true; - } - - tmp = lineBuf; - std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower); - - if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_MIME && lfCount > 0) - { - - if (payloadLength > 0 && validResponse) - { - - if (imapData._messageDataInfo[mailIndex].size() < messageDataIndex + 1) - { - messageBodyData b; - imapData._messageDataInfo[mailIndex].push_back(b); - imapData._messageDataCount[mailIndex] = imapData._messageDataInfo[mailIndex].size(); - } - - p1 = tmp.find(ESP32_MAIL_STR_167); - if (p1 != std::string::npos) - { - - p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_167)); - if (p2 != std::string::npos) - { - - imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_167), p2 - p1 - strlen(ESP32_MAIL_STR_167)); - - p1 = tmp.find(ESP32_MAIL_STR_168, p2); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_168)); - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._charset = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_168), p2 - p1 - strlen(ESP32_MAIL_STR_168)); - } - else if (tmp.find(ESP32_MAIL_STR_169, p2) != std::string::npos) - { - p1 = tmp.find(ESP32_MAIL_STR_169, p2); - imapData._messageDataInfo[mailIndex][messageDataIndex]._charset = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_169)); - } - - p1 = tmp.find(ESP32_MAIL_STR_170, p2); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_170)); - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._name = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_170), p2 - p1 - strlen(ESP32_MAIL_STR_170)); - } - else if (tmp.find(ESP32_MAIL_STR_171, p2) != std::string::npos) - { - p1 = tmp.find(ESP32_MAIL_STR_171, p2); - imapData._messageDataInfo[mailIndex][messageDataIndex]._name = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_171)); - } - } - } - - p1 = tmp.find(ESP32_MAIL_STR_172); - if (p1 != std::string::npos) - { - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_172)); - - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_172), p2 - p1 - strlen(ESP32_MAIL_STR_172)); - else - imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_172)); - } - - p1 = tmp.find(ESP32_MAIL_STR_174); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_174)); - - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._descr = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_174), p2 - p1 - strlen(ESP32_MAIL_STR_174)); - else - imapData._messageDataInfo[mailIndex][messageDataIndex]._descr = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_174)); - } - - p1 = tmp.find(ESP32_MAIL_STR_175); - if (p1 != std::string::npos) - { - - p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_175)); - - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_175), p2 - p1 - strlen(ESP32_MAIL_STR_175)); - else - imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_175)); - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition == ESP32_MAIL_STR_153) - imapData._attachmentCount[mailIndex]++; - } - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._disposition != "") - { - - p1 = tmp.find(ESP32_MAIL_STR_176); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_176)); - - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._filename = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_176), p2 - p1 - strlen(ESP32_MAIL_STR_176)); - } - else if (tmp.find(ESP32_MAIL_STR_177) != std::string::npos) - { - - p1 = tmp.find(ESP32_MAIL_STR_177); - imapData._messageDataInfo[mailIndex][messageDataIndex]._filename = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_177)); - } - - p1 = tmp.find(ESP32_MAIL_STR_178); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(";", p1 + strlen(ESP32_MAIL_STR_178) + 1); - if (p2 != std::string::npos) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._size = atoi(lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_178), p2 - p1 - strlen(ESP32_MAIL_STR_178)).c_str()); - imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size; - } - else - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._size = atoi(lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_178)).c_str()); - imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size; - } - } - - p1 = tmp.find(ESP32_MAIL_STR_179); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_179)); - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._creation_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_179), p2 - p1 - strlen(ESP32_MAIL_STR_179)); - } - else if (tmp.find(ESP32_MAIL_STR_180) != std::string::npos) - { - p1 = tmp.find(ESP32_MAIL_STR_180); - imapData._messageDataInfo[mailIndex][messageDataIndex]._creation_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_180)); - } - - p1 = tmp.find(ESP32_MAIL_STR_181); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_136, p1 + strlen(ESP32_MAIL_STR_181)); - if (p2 != std::string::npos) - imapData._messageDataInfo[mailIndex][messageDataIndex]._modification_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_181), p2 - p1 - strlen(ESP32_MAIL_STR_181)); - } - else if (tmp.find(ESP32_MAIL_STR_182) != std::string::npos) - { - p1 = tmp.find(ESP32_MAIL_STR_182); - imapData._messageDataInfo[mailIndex][messageDataIndex]._modification_date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_182)); - } - } - - imapData._messageDataInfo[mailIndex][messageDataIndex]._part = part; - } - } - - if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount == 0) - { - - if (msgNumBuf.length() > 0 && msgNumBuf != ESP32_MAIL_STR_183 && msgNumBuf != ESP32_MAIL_STR_141 && imapData._msgNum.size() <= max) - { - imapData._msgNum.push_back(atoi(msgNumBuf.c_str())); - imapData._searchCount++; - - if (imapData._msgNum.size() > imapData._emailNumMax && imapData._recentSort) - imapData._msgNum.erase(imapData._msgNum.begin()); - } - - if (imapData._recentSort) - std::sort(imapData._msgNum.begin(), imapData._msgNum.end(), compFunc); - } - - if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER) - { - - uint8_t _headerType = 0; - - p1 = tmp.find(ESP32_MAIL_STR_184); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::FROM; - _headerType = IMAP_HEADER_TYPE::FROM; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + strlen(ESP32_MAIL_STR_184)); - if (p2 != std::string::npos) - from = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_184), p2 - p1 - strlen(ESP32_MAIL_STR_184)); - else - from = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_184)); - - if (from[0] == '=' && from[1] == '?') - { - p1 = from.find("?", 2); - - if (p1 != std::string::npos) - from_charset = from.substr(2, p1 - 2); - } - - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, from.c_str(), bufSize); - from = dest; - } - - p1 = tmp.find(ESP32_MAIL_STR_185); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::TO; - _headerType = IMAP_HEADER_TYPE::TO; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - to = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_185), p2 - p1 - strlen(ESP32_MAIL_STR_185)); - else - to = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_185)); - - if (to[0] == '=' && to[1] == '?') - { - p1 = to.find("?", 2); - - if (p1 != std::string::npos) - to_charset = to.substr(2, p1 - 2); - } - - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, to.c_str(), bufSize); - to = dest; - } - - p1 = tmp.find(ESP32_MAIL_STR_186); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::CC; - _headerType = IMAP_HEADER_TYPE::CC; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - cc = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_186), p2 - p1 - strlen(ESP32_MAIL_STR_186)); - else - cc = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_186)); - - if (cc[0] == '=' && cc[1] == '?') - { - p1 = cc.find("?", 2); - - if (p1 != std::string::npos) - cc_charset = cc.substr(2, p1 - 2); - } - - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, cc.c_str(), bufSize); - cc = dest; - } - - p1 = tmp.find(ESP32_MAIL_STR_187); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::SUBJECT; - _headerType = IMAP_HEADER_TYPE::SUBJECT; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - - memset(dest, 0, bufSize); - if (p2 != std::string::npos) - subject = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_187), p2 - p1 - strlen(ESP32_MAIL_STR_187)); - else - subject = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_187)); - - if (subject[0] == '=' && subject[1] == '?') - { - p1 = subject.find("?", 2); - if (p1 != std::string::npos) - subject_charset = subject.substr(2, p1 - 2); - } - - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, subject.c_str(), bufSize); - subject = dest; - } - p1 = tmp.find(ESP32_MAIL_STR_188); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::DATE; - _headerType = IMAP_HEADER_TYPE::DATE; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_188), p2 - p1 - strlen(ESP32_MAIL_STR_188)); - else - date = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_188)); - } - - p1 = tmp.find(ESP32_MAIL_STR_189); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::MSG_ID; - _headerType = IMAP_HEADER_TYPE::MSG_ID; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - msgID = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_189), p2 - p1 - strlen(ESP32_MAIL_STR_189)); - else - msgID = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_189)); - } - - p1 = tmp.find(ESP32_MAIL_STR_190); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::ACCEPT_LANG; - _headerType = IMAP_HEADER_TYPE::ACCEPT_LANG; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - acceptLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_190), p2 - p1 - strlen(ESP32_MAIL_STR_190)); - else - acceptLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_190)); - } - - p1 = tmp.find(ESP32_MAIL_STR_191); - if (p1 != std::string::npos) - { - headerType = IMAP_HEADER_TYPE::CONT_LANG; - _headerType = IMAP_HEADER_TYPE::CONT_LANG; - - p2 = lineBuf.find(ESP32_MAIL_STR_173, p1 + 1); - if (p2 != std::string::npos) - contentLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_191), p2 - p1 - strlen(ESP32_MAIL_STR_191)); - else - contentLanguage = lineBuf.substr(p1 + strlen(ESP32_MAIL_STR_191)); - } - - if (_headerType == 0 && charCount < payloadLength && payloadLength > 0) - { - if (headerType == IMAP_HEADER_TYPE::FROM) - { - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize); - from += dest; - } - else if (headerType == IMAP_HEADER_TYPE::TO) - { - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize); - to += dest; - } - else if (headerType == IMAP_HEADER_TYPE::CC) - { - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize); - cc += dest; - } - else if (headerType == IMAP_HEADER_TYPE::SUBJECT) - { - memset(dest, 0, bufSize); - RFC2047Decoder.rfc2047Decode(dest, lineBuf.c_str(), bufSize); - subject += dest; - } - } - } - - if (imapCommandType == IMAP_COMMAND_TYPE::LIST) - { - p1 = lineBuf.find(ESP32_MAIL_STR_195); - p2 = lineBuf.find(ESP32_MAIL_STR_196); - - if (p1 != std::string::npos && p2 == std::string::npos) - { - p2 = lineBuf.find_last_of(ESP32_MAIL_STR_136); - if (p2 != std::string::npos) - { - p1 = lineBuf.find_last_of(ESP32_MAIL_STR_136, p2 - 1); - if (p1 != std::string::npos) - imapData._folders.push_back(lineBuf.substr(p1 + 1, p2 - p1 - 1)); - } - } - } - - if (imapCommandType == IMAP_COMMAND_TYPE::SELECT || imapCommandType == IMAP_COMMAND_TYPE::EXAMINE) - { - - p1 = lineBuf.find(ESP32_MAIL_STR_197); - if (p1 != std::string::npos) - { - p1 = lineBuf.find(ESP32_MAIL_STR_198); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_192); - if (p2 != std::string::npos) - { - string _tmp; - - _tmp = lineBuf.substr(p1 + 1, p2 - p1 - 1).c_str(); - msgNumBuf.clear(); - - for (size_t i = 0; i < _tmp.length(); i++) - { - if (_tmp[i] != '\\' && _tmp[i] != ' ' && _tmp[i] != '\r' && _tmp[i] != '\n') - msgNumBuf.append(1, _tmp[i]); - - if (_tmp[i] == ' ') - { - imapData._flag.push_back(msgNumBuf); - msgNumBuf.clear(); - } - } - if (msgNumBuf.length() > 0) - { - imapData._flag.push_back(msgNumBuf); - } - - std::string().swap(_tmp); - } - } - } - - p2 = lineBuf.find(ESP32_MAIL_STR_199); - if (p2 != std::string::npos) - imapData._totalMessage = atoi(lineBuf.substr(2, p2 - 2).c_str()); - - p1 = lineBuf.find(ESP32_MAIL_STR_200); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_156, p1 + 10); - if (p2 != std::string::npos) - imapData._nextUID = lineBuf.substr(p1 + 10, p2 - p1 - 10); - } - } - - if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT && lfCount > 0 && (charCount < maxChar || imapData._saveHTMLMsg || imapData._saveTextMsg)) - { - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding == ESP32_MAIL_STR_160) - { - - unsigned char *decoded = base64_decode_char((const unsigned char *)lineBuf.c_str(), lineBuf.length(), &outputLength); - - if (decoded) - { - if (charCount < maxChar) - imapData._messageDataInfo[mailIndex][messageDataIndex]._text.append((char *)decoded, outputLength); - - if (imapData._saveHTMLMsg || imapData._saveTextMsg) - { - - if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite) - { - - imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true; - - if (_sdOk) - { - - downloadReq = true; - - filepath.clear(); - filepath += imapData._savePath; - filepath += ESP32_MAIL_STR_202; - - char *midx = new char[50]; - memset(midx, 0, 50); - itoa(imapData._msgNum[mailIndex], midx, 10); - - filepath += midx; - - delete[] midx; - - if (imapData._storageType == MailClientStorageType::SD) - if (!imapData.fsp->exists(filepath.c_str())) - createDirs(filepath); - - if (!imapData._headerSaved) - hpath = filepath + ESP32_MAIL_STR_203; - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155) - { - if (imapData._saveDecodedText) - filepath += ESP32_MAIL_STR_161; - else - filepath += ESP32_MAIL_STR_162; - } - else if (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154) - { - if (imapData._saveDecodedHTML) - filepath += ESP32_MAIL_STR_163; - else - filepath += ESP32_MAIL_STR_164; - } - - if (imapData._storageType == MailClientStorageType::SD) - file = imapData.fsp->open(filepath.c_str(), FILE_WRITE); - else if (imapData._storageType == MailClientStorageType::SPIFFS) - file = SPIFFS.open(filepath.c_str(), FILE_WRITE); - } - else - { - if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true; - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear(); - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89; - } - } - } - - if (_sdOk) - { - if ((imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_155 && imapData._saveDecodedText) || - (imapData._messageDataInfo[mailIndex][messageDataIndex]._contentType == ESP32_MAIL_STR_154 && imapData._saveDecodedHTML)) - file.write((const uint8_t *)decoded, outputLength); - else - file.write((const uint8_t *)lineBuf.c_str(), lineBuf.length()); - } - } - - delete[] decoded; - } - } - } - - if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT && lfCount > 0) - { - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._transfer_encoding == ESP32_MAIL_STR_160) - { - - if (!imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite) - { - - imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true; - - if (_sdOk) - { - - downloadReq = true; - - filepath.clear(); - filepath += imapData._savePath; - filepath += ESP32_MAIL_STR_202; - - char *midx = new char[50]; - memset(midx, 0, 50); - itoa(imapData._msgNum[mailIndex], midx, 10); - - filepath += midx; - - delete[] midx; - - if (imapData._storageType == MailClientStorageType::SD) - if (!imapData.fsp->exists(filepath.c_str())) - createDirs(filepath); - - filepath += ESP32_MAIL_STR_202; - - filepath += imapData._messageDataInfo[mailIndex][messageDataIndex]._filename; - - if (imapData._storageType == MailClientStorageType::SD) - file = imapData.fsp->open(filepath.c_str(), FILE_WRITE); - else if (imapData._storageType == MailClientStorageType::SPIFFS) - file = SPIFFS.open(filepath.c_str(), FILE_WRITE); - } - else - { - if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true; - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear(); - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_89; - } - } - } - - if (_sdOk) - { - - unsigned char *decoded = base64_decode_char((const unsigned char *)lineBuf.c_str(), lineBuf.length(), &outputLength); - - downloadedByte += outputLength; - - if (downloadedByte > imapData._messageDataInfo[mailIndex][messageDataIndex]._size) - continue; - - if (decoded) - { - file.write((const uint8_t *)decoded, outputLength); - - if (imapData._storageType == MailClientStorageType::SPIFFS) - delayMicroseconds(1); - else - yield(); - - if (imapData._downloadReport) - { - imapData._downloadedByte[mailIndex] += outputLength; - currentDownloadByte += outputLength; - - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._size == 0) - { - if (payloadLength > 36) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._size = base64DecodeSize(lineBuf, payloadLength - (payloadLength / 36)); - imapData._totalAttachFileSize[mailIndex] += imapData._messageDataInfo[mailIndex][messageDataIndex]._size; - } - } - - int p = 0; - - if (imapData._totalAttachFileSize[mailIndex] > 0) - p = 100 * imapData._downloadedByte[mailIndex] / imapData._totalAttachFileSize[mailIndex]; - - if ((p % 5 == 0) && (p <= 100)) - { - - if (imapData._readCallback && reportState != -1) - { - memset(buf, 0, bufSize); - itoa(p, buf, 10); - - std::string dl = ESP32_MAIL_STR_90 + imapData._messageDataInfo[mailIndex][messageDataIndex]._filename + ESP32_MAIL_STR_91 + buf + ESP32_MAIL_STR_92; - - if (imapData._readCallback) - { - imapData._cbData._info = dl; - imapData._cbData._status = dl; - imapData._cbData._success = false; - imapData._readCallback(imapData._cbData); - } - - std::string().swap(dl); - } - reportState = -1; - } - else - reportState = 0; - } - - delete[] decoded; - } - - if (millis() - dataTime > imapData._net->tcpTimeout + 1000 * 60 * 5) - break; - } - } - } - - if (lfCount == 0) - { - p1 = lineBuf.find_last_of(ESP32_MAIL_STR_193); - if (p1 != std::string::npos) - { - p2 = lineBuf.find(ESP32_MAIL_STR_194, p1 + 1); - if (p2 != std::string::npos) - payloadLength = atoi(lineBuf.substr(p1 + 1, p2 - p1 - 1).c_str()); - } - } - - lineBuf.clear(); - lfCount++; - std::string().swap(tmp); - } - - readCount++; - } - - if (imapData._error.size() > 0 && mailIndex > -1) - { - if (validResponse && !imapData._error[mailIndex]) - { - imapData._errorMsg[mailIndex].clear(); - imapData._errorMsg[mailIndex] = ""; - } - } - - if (millis() - dataTime > imapData._net->tcpTimeout) - { - - if (downloadReq) - { - if (imapData._messageDataCount[mailIndex] == messageDataIndex + 1) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._error = true; - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError.clear(); - imapData._messageDataInfo[mailIndex][messageDataIndex]._downloadError = ESP32_MAIL_STR_93; - } - } - else - { - - if (imapData._error.size() > 0 && mailIndex > -1) - { - imapData._error[mailIndex] = true; - imapData._errorMsg[mailIndex].clear(); - imapData._errorMsg[mailIndex] = ESP32_MAIL_STR_95; - } - } - } - } - - if (validResponse && (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT || imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_TEXT) && messageDataIndex != -1) - { - if (imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite) - file.close(); - } - - if (validResponse && imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_ATTACHMENT && imapData._messageDataInfo[mailIndex][messageDataIndex]._size != currentDownloadByte) - { - imapData._messageDataInfo[mailIndex][messageDataIndex]._size = currentDownloadByte; - } - - if (hpath != "") - { - - if (imapData._storageType == MailClientStorageType::SD) - file = imapData.fsp->open(hpath.c_str(), FILE_WRITE); - else if (imapData._storageType == MailClientStorageType::SPIFFS) - file = SPIFFS.open(hpath.c_str(), FILE_WRITE); - - file.print(ESP32_MAIL_STR_99); - file.println(imapData._date[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_100); - if (imapData._uidSearch) - file.println(imapData._msgNum[mailIndex]); - else - file.println(); - - file.print(ESP32_MAIL_STR_101); - file.println(imapData._msgNum[mailIndex]); - - file.print(ESP32_MAIL_STR_102); - file.println(imapData._acceptLanguage[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_103); - file.println(imapData._contentLanguage[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_104); - file.println(imapData._from[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_105); - file.println(imapData._from_charset[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_106); - file.println(imapData._to[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_107); - file.println(imapData._to_charset[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_108); - file.println(imapData._cc[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_109); - file.println(imapData._cc_charset[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_110); - file.println(imapData._subject[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_111); - file.println(imapData._subject_charset[mailIndex].c_str()); - - file.print(ESP32_MAIL_STR_112); - file.println(imapData._messageDataInfo[mailIndex][messageDataIndex]._charset.c_str()); - - if (imapData._attachmentCount[mailIndex] > 0) - { - - file.print(ESP32_MAIL_STR_113); - file.println(imapData._attachmentCount[mailIndex]); - - for (int j = 0; j < imapData._attachmentCount[mailIndex]; j++) - { - file.print(ESP32_MAIL_STR_114); - file.println(j + 1); - - file.print(ESP32_MAIL_STR_115); - file.println(imapData.getAttachmentFileName(mailIndex, j)); - - file.print(ESP32_MAIL_STR_116); - file.println(imapData.getAttachmentName(mailIndex, j)); - - file.print(ESP32_MAIL_STR_117); - file.println(imapData.getAttachmentFileSize(mailIndex, j)); - - file.print(ESP32_MAIL_STR_118); - file.println(imapData.getAttachmentType(mailIndex, j)); - - file.print(ESP32_MAIL_STR_119); - file.println(imapData.getAttachmentCreationDate(mailIndex, j)); - } - } - - file.close(); - imapData._headerSaved = true; - } - - if (imapCommandType == IMAP_COMMAND_TYPE::FETCH_BODY_HEADER) - { - if (from != "") - { - imapData._msgID[mailIndex] = msgID; - imapData._from[mailIndex] = from; - imapData._to[mailIndex] = to; - imapData._cc[mailIndex] = cc; - imapData._subject[mailIndex] = subject; - imapData._date[mailIndex] = date; - imapData._from_charset[mailIndex] = from_charset; - imapData._to_charset[mailIndex] = to_charset; - imapData._cc_charset[mailIndex] = cc_charset; - imapData._subject_charset[mailIndex] = subject_charset; - imapData._contentLanguage[mailIndex] = contentLanguage; - imapData._acceptLanguage[mailIndex] = acceptLanguage; - } - } - - delete[] buf; - delete[] dest; - - std::string().swap(lineBuf); - std::string().swap(msgNumBuf); - std::string().swap(filepath); - std::string().swap(hpath); - std::string().swap(tmp); - - std::string().swap(msgID); - std::string().swap(from); - std::string().swap(to); - std::string().swap(subject); - std::string().swap(date); - std::string().swap(cc); - std::string().swap(from_charset); - std::string().swap(to_charset); - std::string().swap(cc_charset); - std::string().swap(subject_charset); - std::string().swap(contentLanguage); - std::string().swap(acceptLanguage); - - return validResponse; -} - -void ESP32_MailClient::clientReadAll(WiFiClient *client) -{ - if (client) - { - if (client->available() > 0) - client->read(); - } -} - -double ESP32_MailClient::base64DecodeSize(std::string lastBase64String, int length) -{ - double result = 0; - int padding = 0; - if (lastBase64String != "") - { - - if (lastBase64String[lastBase64String.length() - 1] == '=' && lastBase64String[lastBase64String.length() - 2] == '=') - padding = 2; - else if (lastBase64String[lastBase64String.length() - 1] == '=') - padding = 1; - } - result = (ceil(length / 4) * 3) - padding; - return result; -} - -unsigned char *ESP32_MailClient::base64_decode_char(const unsigned char *src, size_t len, size_t *out_len) -{ - - unsigned char *out, *pos, block[4], tmp; - size_t i, count, olen; - int pad = 0; - size_t extra_pad; - - unsigned char *dtable = new unsigned char[256]; - - memset(dtable, 0x80, 256); - - for (i = 0; i < sizeof(base64_table) - 1; i++) - dtable[base64_table[i]] = (unsigned char)i; - dtable['='] = 0; - - count = 0; - for (i = 0; i < len; i++) - { - if (dtable[src[i]] != 0x80) - count++; - } - - if (count == 0) - goto exit; - extra_pad = (4 - count % 4) % 4; - - olen = (count + extra_pad) / 4 * 3; - pos = out = (unsigned char *)malloc(olen); - if (out == NULL) - goto exit; - - count = 0; - for (i = 0; i < len + extra_pad; i++) - { - unsigned char val; - - if (i >= len) - val = '='; - else - val = src[i]; - tmp = dtable[val]; - if (tmp == 0x80) - continue; - - if (val == '=') - pad++; - block[count] = tmp; - count++; - if (count == 4) - { - *pos++ = (block[0] << 2) | (block[1] >> 4); - *pos++ = (block[1] << 4) | (block[2] >> 2); - *pos++ = (block[2] << 6) | block[3]; - count = 0; - if (pad) - { - if (pad == 1) - pos--; - else if (pad == 2) - pos -= 2; - else - { - free(out); - goto exit; - } - break; - } - } - } - - *out_len = pos - out; - delete[] dtable; - return out; - -exit: - delete[] dtable; - return NULL; -} - -std::string ESP32_MailClient::base64_encode_string(const unsigned char *src, size_t len) -{ - unsigned char *out, *pos; - const unsigned char *end, *in; - - size_t olen; - - olen = 4 * ((len + 2) / 3); - - if (olen < len) - return std::string(); - - std::string outStr = ""; - outStr.resize(olen); - out = (unsigned char *)&outStr[0]; - - end = src + len; - in = src; - pos = out; - - while (end - in >= 3) - { - *pos++ = base64_table[in[0] >> 2]; - *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; - *pos++ = base64_table[in[2] & 0x3f]; - in += 3; - } - - if (end - in) - { - *pos++ = base64_table[in[0] >> 2]; - if (end - in == 1) - { - *pos++ = base64_table[(in[0] & 0x03) << 4]; - *pos++ = '='; - } - else - { - *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - *pos++ = base64_table[(in[1] & 0x0f) << 2]; - } - *pos++ = '='; - } - - return outStr; -} - -void ESP32_MailClient::send_base64_encode_mime_data(WiFiClient *client, const unsigned char *src, size_t len) -{ - - const unsigned char *end, *in; - - size_t olen; - - olen = 4 * ((len + 2) / 3); - - if (olen < len) - return; - - end = src + len; - in = src; - - size_t chunkSize = 936; - size_t byteAdd = 0; - size_t byteSent = 0; - - int dByte = 0; - unsigned char *buf = new unsigned char[chunkSize]; - memset(buf, 0, chunkSize); - - while (end - in >= 3) - { - buf[byteAdd++] = base64_table[in[0] >> 2]; - buf[byteAdd++] = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - buf[byteAdd++] = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; - buf[byteAdd++] = base64_table[in[2] & 0x3f]; - dByte += 4; - if (dByte == 76) - { - if(byteAdd + 1 < chunkSize) - { - buf[byteAdd++] = 0x0d; - buf[byteAdd++] = 0x0a; - } - dByte = 0; - } - if (byteAdd >= chunkSize - 4) - { - byteSent += byteAdd; - client->write(buf, byteAdd); - memset(buf, 0, chunkSize); - byteAdd = 0; - } - in += 3; - } - - if (byteAdd > 0) - client->write(buf, byteAdd); - - if (end - in) - { - memset(buf, 0, chunkSize); - byteAdd = 0; - - buf[byteAdd++] = base64_table[in[0] >> 2]; - if (end - in == 1) - { - buf[byteAdd++] = base64_table[(in[0] & 0x03) << 4]; - buf[byteAdd++] = '='; - } - else - { - buf[byteAdd++] = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - buf[byteAdd++] = base64_table[(in[1] & 0x0f) << 2]; - } - buf[byteAdd++] = '='; - - client->write(buf, byteAdd); - memset(buf, 0, chunkSize); - } - delete[] buf; -} - -void ESP32_MailClient::send_base64_encode_mime_file(WiFiClient *client, File file) -{ - - if (!file) - return; - - size_t chunkSize = 936; - size_t byteAdd = 0; - size_t byteSent = 0; - - unsigned char *buf = new unsigned char[chunkSize]; - memset(buf, 0, chunkSize); - - size_t len = file.size(); - size_t fbufIndex = 0; - unsigned char *fbuf = new unsigned char[3]; - - int dByte = 0; - - while (file.available()) - { - memset(fbuf, 0, 3); - if (len - fbufIndex >= 3) - { - file.read(fbuf, 3); - buf[byteAdd++] = base64_table[fbuf[0] >> 2]; - buf[byteAdd++] = base64_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; - buf[byteAdd++] = base64_table[((fbuf[1] & 0x0f) << 2) | (fbuf[2] >> 6)]; - buf[byteAdd++] = base64_table[fbuf[2] & 0x3f]; - dByte += 4; - if (dByte == 76) - { - if(byteAdd + 1 < chunkSize) - { - buf[byteAdd++] = 0x0d; - buf[byteAdd++] = 0x0a; - } - dByte = 0; - } - if (byteAdd >= chunkSize - 4) - { - byteSent += byteAdd; - client->write(buf, byteAdd); - memset(buf, 0, chunkSize); - byteAdd = 0; - } - fbufIndex += 3; - } - else - { - if (len - fbufIndex == 1) - { - fbuf[0] = file.read(); - } - else if (len - fbufIndex == 2) - { - fbuf[0] = file.read(); - fbuf[1] = file.read(); - } - break; - } - } - - file.close(); - if (byteAdd > 0) - client->write(buf, byteAdd); - - if (len - fbufIndex > 0) - { - memset(buf, 0, chunkSize); - byteAdd = 0; - buf[byteAdd++] = base64_table[fbuf[0] >> 2]; - if (len - fbufIndex == 1) - { - buf[byteAdd++] = base64_table[(fbuf[0] & 0x03) << 4]; - buf[byteAdd++] = '='; - } - else - { - buf[byteAdd++] = base64_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; - buf[byteAdd++] = base64_table[(fbuf[1] & 0x0f) << 2]; - } - buf[byteAdd++] = '='; - client->write(buf, byteAdd); - } - delete[] buf; - delete[] fbuf; -} - -IMAPData::IMAPData() {} -IMAPData::~IMAPData() -{ - empty(); - _net.reset(); - _net.release(); -} - -void IMAPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA) -{ - - _host.clear(); - _port = port; - _loginEmail.clear(); - _loginPassword.clear(); - - _host = host.c_str(); - _loginEmail = loginEmail.c_str(); - _loginPassword = loginPassword.c_str(); - - _rootCA.clear(); - if (strlen(rootCA) > 0) - _rootCA.push_back((char *)rootCA); -} - -void IMAPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword) -{ - _host.clear(); - _port = port; - _loginEmail.clear(); - _loginPassword.clear(); - - _host = host.c_str(); - _loginEmail = loginEmail.c_str(); - _loginPassword = loginPassword.c_str(); -} - -void IMAPData::setSTARTTLS(bool starttls) -{ - _starttls = starttls; -} - -void IMAPData::setDebug(bool debug) -{ - _debug = debug; -} - -void IMAPData::setFolder(const String &folderName) -{ - _currentFolder.clear(); - _currentFolder = folderName.c_str(); -} -void IMAPData::setMessageBufferSize(size_t size) -{ - _message_buffer_size = size; -} - -void IMAPData::setAttachmentSizeLimit(size_t size) -{ - _attacement_max_size = size; -} - -void IMAPData::setSearchCriteria(const String &criteria) -{ - _searchCriteria.clear(); - _searchCriteria = criteria.c_str(); -} - -void IMAPData::setSearchUnseenMessage(bool unseenSearch) -{ - _unseen = unseenSearch; -} - -void IMAPData::setSaveFilePath(const String &path) -{ - _savePath.clear(); - if (path.c_str()[0] != '/') - { - _savePath = "/"; - _savePath += path.c_str(); - } - else - _savePath = path.c_str(); -} - -void IMAPData::setFetchUID(const String &fetchUID) -{ - _fetchUID.clear(); - string tmp = fetchUID.c_str(); - std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper); - if (tmp.find(ESP32_MAIL_STR_140) != std::string::npos || tmp.find(ESP32_MAIL_STR_212) != std::string::npos || - tmp.find(ESP32_MAIL_STR_213) != std::string::npos || tmp.find(ESP32_MAIL_STR_214) != std::string::npos || tmp.find(ESP32_MAIL_STR_215) != std::string::npos || - tmp.find(ESP32_MAIL_STR_216) != std::string::npos || tmp.find(ESP32_MAIL_STR_217) != std::string::npos || tmp.find(ESP32_MAIL_STR_218) != std::string::npos || - tmp.find(ESP32_MAIL_STR_219) != std::string::npos || tmp.find(ESP32_MAIL_STR_220) != std::string::npos) - _fetchUID = ESP32_MAIL_STR_183; - else - _fetchUID = fetchUID.c_str(); - - std::string().swap(tmp); -} - -extern FS *ufsp; - -void IMAPData::setFileStorageType(uint8_t storageType) -{ - _storageType = storageType; - switch (storageType) { - case MailClientStorageType::SPIFFS: - fsp = &SPIFFS; - break; - case MailClientStorageType::SD: - fsp = &SD; - break; - case MailClientStorageType::FFat: - fsp = &FFat; - break; - case MailClientStorageType::Univ: - fsp = ufsp; - break; - } -} - -void IMAPData::setDownloadAttachment(bool download) -{ - _downloadAttachment = download; -} -void IMAPData::setRecentSort(bool recentSort) -{ - _recentSort = recentSort; -} - -void IMAPData::setHTMLMessage(bool htmlFormat) -{ - _htmlFormat = htmlFormat; -} -void IMAPData::setTextMessage(bool textFormat) -{ - _textFormat = textFormat; -} - -void IMAPData::setSearchLimit(uint16_t limit) -{ - if (limit <= MAX_EMAIL_SEARCH_LIMIT) - _emailNumMax = limit; -} - -bool IMAPData::isHeaderOnly() -{ - return _headerOnly; -} - -void IMAPData::saveHTMLMessage(bool download, bool decoded) -{ - _saveDecodedHTML = decoded; - _saveHTMLMsg = download; -} -void IMAPData::saveTextMessage(bool download, bool decoded) -{ - _saveDecodedText = decoded; - _saveTextMsg = download; -} - -void IMAPData::setReadCallback(readStatusCallback readCallback) -{ - _readCallback = std::move(readCallback); -} - -void IMAPData::setDownloadReport(bool report) -{ - _downloadReport = report; -} - -uint16_t IMAPData::getFolderCount() -{ - return _folders.size(); -} -String IMAPData::getFolder(uint16_t folderIndex) -{ - if (folderIndex < _folders.size()) - return _folders[folderIndex].c_str(); - return std::string().c_str(); -} - -uint16_t IMAPData::getFlagCount() -{ - return _flag.size(); -} -String IMAPData::getFlag(uint16_t flagIndex) -{ - if (flagIndex < _flag.size()) - return _flag[flagIndex].c_str(); - return std::string().c_str(); -} - -size_t IMAPData::totalMessages() -{ - return _totalMessage; -} - -size_t IMAPData::searchCount() -{ - return _searchCount; -} - -size_t IMAPData::availableMessages() -{ - return _msgNum.size(); -} - -size_t IMAPData::getAttachmentCount(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _attachmentCount[messageIndex]; - return 0; -} - -String IMAPData::getAttachmentFileName(size_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._filename.c_str(); - id++; - } - } - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getAttachmentName(size_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._name.c_str(); - id++; - } - } - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -int IMAPData::getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._size; - id++; - } - } - } - else - return 0; - } - else - return 0; - - return 0; -} - -String IMAPData::getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._creation_date.c_str(); - id++; - } - } - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getAttachmentType(size_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._contentType.c_str(); - id++; - } - } - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getFrom(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _from[messageIndex].c_str(); - return std::string().c_str(); -} - -String IMAPData::getFromCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _from_charset[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getTo(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _to[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getToCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _to_charset[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getCC(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _cc[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getCCCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _cc_charset[messageIndex].c_str(); - return std::string().c_str(); -} - -String IMAPData::getSubject(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _subject[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getSubjectCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _subject_charset[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getHTMLMessage(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return getMessage(messageIndex, true); - return std::string().c_str(); -} - -String IMAPData::getTextMessage(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return getMessage(messageIndex, false); - return std::string().c_str(); -} - -String IMAPData::getMessage(uint16_t messageIndex, bool htmlFormat) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_155 && !htmlFormat) - return _messageDataInfo[messageIndex][i]._text.c_str(); - else if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_154 && htmlFormat) - return _messageDataInfo[messageIndex][i]._text.c_str(); - } - return std::string().c_str(); - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getHTMLMessgaeCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_154) - return _messageDataInfo[messageIndex][i]._charset.c_str(); - } - return std::string().c_str(); - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getTextMessgaeCharset(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._contentType == ESP32_MAIL_STR_155) - return _messageDataInfo[messageIndex][i]._charset.c_str(); - } - return std::string().c_str(); - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -String IMAPData::getDate(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _date[messageIndex].c_str(); - return std::string().c_str(); -} - -String IMAPData::getUID(uint16_t messageIndex) -{ - char *buf = new char[50]; - memset(buf, 0, 50); - if (_uidSearch) - { - if (messageIndex < _msgNum.size()) - itoa(_msgNum[messageIndex], buf, 10); - } - - String v = buf; - delete[] buf; - return v; -} - -String IMAPData::getNumber(uint16_t messageIndex) -{ - char *buf = new char[50]; - memset(buf, 0, 50); - - if (messageIndex < _msgNum.size()) - { - if (!_uidSearch) - itoa(_msgNum[messageIndex], buf, 10); - else - itoa(_msgNum[messageIndex] + 1, buf, 10); - } - - String v = buf; - delete[] buf; - return v; -} - -String IMAPData::getMessageID(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _msgID[messageIndex].c_str(); - return std::string().c_str(); -} - -String IMAPData::getAcceptLanguage(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _acceptLanguage[messageIndex].c_str(); - return std::string().c_str(); -} -String IMAPData::getContentLanguage(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _contentLanguage[messageIndex].c_str(); - return std::string().c_str(); -} - -bool IMAPData::isFetchMessageFailed(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _error[messageIndex]; - return false; -} -String IMAPData::getFetchMessageFailedReason(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - return _errorMsg[messageIndex].c_str(); - return std::string().c_str(); -} - -bool IMAPData::isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._error; - id++; - } - } - } - else - return false; - } - else - return false; - - return false; -} - -String IMAPData::getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - int id = 0; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == ESP32_MAIL_STR_153) - { - if (attachmentIndex == id) - return _messageDataInfo[messageIndex][i]._downloadError.c_str(); - id++; - } - } - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - return std::string().c_str(); -} - -bool IMAPData::isDownloadMessageFailed(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - bool res = false; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == "") - { - res |= _messageDataInfo[messageIndex][i]._error; - } - } - - return res; - } - else - return false; - } - else - return false; - - return false; -} -String IMAPData::getDownloadMessageFailedReason(uint16_t messageIndex) -{ - if (messageIndex < _msgNum.size()) - { - int s = _messageDataInfo[messageIndex].size(); - string res = ""; - if (s > 0) - { - for (int i = 0; i < s; i++) - { - if (_messageDataInfo[messageIndex][i]._disposition == "") - { - if (_messageDataInfo[messageIndex][i]._downloadError != "") - res = _messageDataInfo[messageIndex][i]._downloadError; - } - } - - return res.c_str(); - } - else - return std::string().c_str(); - } - else - return std::string().c_str(); - - return std::string().c_str(); -} - -void IMAPData::empty() -{ - std::string().swap(_host); - std::string().swap(_loginEmail); - std::string().swap(_loginPassword); - std::string().swap(_currentFolder); - std::string().swap(_nextUID); - std::string().swap(_searchCriteria); - std::vector().swap(_date); - std::vector().swap(_subject); - std::vector().swap(_subject_charset); - std::vector().swap(_from); - std::vector().swap(_from_charset); - std::vector().swap(_to); - std::vector().swap(_to_charset); - std::vector().swap(_cc); - std::vector().swap(_cc_charset); - std::vector().swap(_msgNum); - std::vector().swap(_folders); - std::vector().swap(_flag); - std::vector().swap(_msgID); - std::vector().swap(_acceptLanguage); - std::vector().swap(_contentLanguage); - std::vector().swap(_attachmentCount); - std::vector().swap(_totalAttachFileSize); - std::vector().swap(_downloadedByte); - std::vector().swap(_error); - std::vector>().swap(_messageDataInfo); - std::vector().swap(_errorMsg); -} - -void IMAPData::clearMessageData() -{ - std::vector().swap(_date); - std::vector().swap(_subject); - std::vector().swap(_subject_charset); - std::vector().swap(_from); - std::vector().swap(_from_charset); - std::vector().swap(_to); - std::vector().swap(_to_charset); - std::vector().swap(_cc); - std::vector().swap(_cc_charset); - std::vector().swap(_msgNum); - std::vector().swap(_msgID); - std::vector().swap(_contentLanguage); - std::vector().swap(_acceptLanguage); - std::vector().swap(_folders); - std::vector().swap(_flag); - std::vector().swap(_attachmentCount); - std::vector>().swap(_messageDataInfo); - std::vector().swap(_totalAttachFileSize); - std::vector().swap(_downloadedByte); - std::vector().swap(_messageDataCount); - std::vector().swap(_errorMsg); - std::vector().swap(_error); - _searchCount = 0; -} - -messageBodyData::messageBodyData() -{ -} -messageBodyData::~messageBodyData() -{ - empty(); -} - -void messageBodyData::empty() -{ - std::string().swap(_text); - std::string().swap(_filename); - std::string().swap(_savePath); - std::string().swap(_name); - std::string().swap(_disposition); - std::string().swap(_contentType); - std::string().swap(_descr); - std::string().swap(_transfer_encoding); - std::string().swap(_creation_date); - std::string().swap(_modification_date); - std::string().swap(_charset); - std::string().swap(_part); - std::string().swap(_downloadError); -} - -attachmentData::attachmentData() {} -attachmentData::~attachmentData() -{ - - std::vector>().swap(_buf); - std::vector().swap(_filename); - std::vector().swap(_id); - std::vector().swap(_type); - std::vector().swap(_size); - std::vector().swap(_mime_type); -} - -void attachmentData::add(const String &fileName, const String &mimeType, uint8_t *data, size_t size) -{ - _filename.push_back(fileName.c_str()); - _mime_type.push_back(mimeType.c_str()); - - if (size > 0) - { - std::vector d = std::vector(); - d.push_back(data); - _buf.push_back(d); - _size.push_back(size); - _type.push_back(0); - } - else - { - _buf.push_back(std::vector()); - _size.push_back(0); - _type.push_back(1); - } - - _id.push_back(_index); - _index++; -} - -void attachmentData::remove(uint8_t index) -{ - _buf.erase(_buf.begin() + index); - _filename.erase(_filename.begin() + index); - _type.erase(_type.begin() + index); - _size.erase(_size.begin() + index); - _mime_type.erase(_mime_type.begin() + index); - _id.erase(_id.begin() + index); -} - -void attachmentData::free() -{ - std::vector>().swap(_buf); - std::vector().swap(_filename); - std::vector().swap(_id); - std::vector().swap(_type); - std::vector().swap(_size); - std::vector().swap(_mime_type); - _index = 0; -} - -String attachmentData::getFileName(uint8_t index) -{ - return _filename[index].c_str(); -} - -String attachmentData::getMimeType(uint8_t index) -{ - return _mime_type[index].c_str(); -} - -uint8_t *attachmentData::getData(uint8_t index) -{ - uint8_t *ptr = _buf[index].front(); - return ptr; -} - -uint16_t attachmentData::getSize(uint8_t index) -{ - return _size[index]; -} - -uint8_t attachmentData::getCount() -{ - return _index; -} - -uint8_t attachmentData::getType(uint8_t index) -{ - return _type[index]; -} - -SMTPData::SMTPData() {} - -SMTPData::~SMTPData() -{ - empty(); - _net.reset(); - _net.release(); -} - -void SMTPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA) -{ - - _host.clear(); - _port = port; - _loginEmail.clear(); - _loginPassword.clear(); - - _host = host.c_str(); - _loginEmail = loginEmail.c_str(); - _loginPassword = loginPassword.c_str(); - - _rootCA.clear(); - if (strlen(rootCA) > 0) - _rootCA.push_back((char *)rootCA); -} - -void SMTPData::setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword) -{ - - _host.clear(); - _port = port; - _loginEmail.clear(); - _loginPassword.clear(); - - _host = host.c_str(); - _loginEmail = loginEmail.c_str(); - _loginPassword = loginPassword.c_str(); - - _rootCA.clear(); -} - -void SMTPData::setSTARTTLS(bool starttls) -{ - _starttls = starttls; -} - -void SMTPData::setDebug(bool debug) -{ - _debug = debug; -} - -void SMTPData::setSender(const String &fromName, const String &senderEmail) -{ - - _fromName.clear(); - _senderEmail.clear(); - - _fromName += fromName.c_str(); - _senderEmail += senderEmail.c_str(); -} - -String SMTPData::getFromName() -{ - return _fromName.c_str(); -} - -String SMTPData::getSenderEmail() -{ - return _senderEmail.c_str(); -} - -void SMTPData::setPriority(int priority) -{ - _priority = priority; -} -void SMTPData::setPriority(const String &priority) -{ - if (priority == ESP32_MAIL_STR_205 || priority == ESP32_MAIL_STR_206) - _priority = 1; - else if (priority == ESP32_MAIL_STR_207 || priority == ESP32_MAIL_STR_208) - _priority = 3; - else if (priority == ESP32_MAIL_STR_209 || priority == ESP32_MAIL_STR_210) - _priority = 5; -} - -uint8_t SMTPData::getPriority() -{ - return _priority; -} - -void SMTPData::addRecipient(const String &email) -{ - _recipient.insert(_recipient.end(), email.c_str()); -} - -void SMTPData::removeRecipient(const String &email) -{ - for (uint8_t i = 0; i < _recipient.size(); i++) - if (_recipient[i].c_str() == email.c_str()) - _recipient.erase(_recipient.begin() + i); -} - -void SMTPData::removeRecipient(uint8_t index) -{ - _recipient.erase(_recipient.begin() + index); -} - -void SMTPData::clearRecipient() -{ - std::vector().swap(_recipient); -} - -uint8_t SMTPData::recipientCount() -{ - return _recipient.size(); -} - -String SMTPData::getRecipient(uint8_t index) -{ - if (index >= _recipient.size()) - return std::string().c_str(); - return _recipient[index].c_str(); -} - -void SMTPData::setSubject(const String &subject) -{ - _subject = subject.c_str(); -} - -String SMTPData::getSubject() -{ - return _subject.c_str(); -} - -void SMTPData::setMessage(const String &message, bool htmlFormat) -{ - _message.clear(); - _message += message.c_str(); - _htmlFormat = htmlFormat; -} - -void SMTPData::clrMessage(bool htmlFormat) -{ - _message.clear(); - _htmlFormat = htmlFormat; -} - -void SMTPData::addMessage(const String &message) -{ - _message += message.c_str(); -} - -String SMTPData::getMessage() -{ - return _message.c_str(); -} - -bool SMTPData::htmlFormat() -{ - return _htmlFormat; -} -void SMTPData::addCC(const String &email) -{ - _cc.push_back(email.c_str()); -} - -void SMTPData::removeCC(const String &email) -{ - for (uint8_t i = 0; i < _cc.size(); i++) - if (_cc[i].c_str() == email.c_str()) - _cc.erase(_cc.begin() + i); -} - -void SMTPData::removeCC(uint8_t index) -{ - _cc.erase(_cc.begin() + index); -} -void SMTPData::clearCC() -{ - std::vector().swap(_cc); -} - -uint8_t SMTPData::ccCount() -{ - return _cc.size(); -} - -String SMTPData::getCC(uint8_t index) -{ - if (index >= _cc.size()) - return std::string().c_str(); - return _cc[index].c_str(); -} - -void SMTPData::addBCC(const String &email) -{ - _bcc.push_back(email.c_str()); -} - -void SMTPData::removeBCC(const String &email) -{ - for (uint8_t i = 0; i < _bcc.size(); i++) - if (_bcc[i].c_str() == email.c_str()) - _bcc.erase(_bcc.begin() + i); -} - -void SMTPData::removeBCC(uint8_t index) -{ - _bcc.erase(_bcc.begin() + index); -} - -void SMTPData::clearBCC() -{ - std::vector().swap(_bcc); -} - -uint8_t SMTPData::bccCount() -{ - return _bcc.size(); -} - -String SMTPData::getBCC(uint8_t index) -{ - if (index >= _bcc.size()) - return std::string().c_str(); - return _bcc[index].c_str(); -} - -void SMTPData::addAttachData(const String &fileName, const String &mimeType, uint8_t *data, size_t size) -{ - _attach.add(fileName, mimeType, data, size); -} - -void SMTPData::removeAttachData(const String &fileName) -{ - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getFileName(i) == fileName && _attach.getType(i) == 0) - { - _attach.remove(i); - } -} - -void SMTPData::removeAttachData(uint8_t index) -{ - uint8_t id = 0; - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 0) - { - if (id == index) - { - _attach.remove(i); - break; - } - id++; - } -} - -uint8_t SMTPData::attachDataCount() -{ - uint8_t count = 0; - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 0) - count++; - - return count; -} - -void SMTPData::addAttachFile(const String &filePath, const String &mimeType) -{ - _attach.add(filePath, mimeType, NULL, 0); -} - -void SMTPData::removeAttachFile(const String &filePath) -{ - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getFileName(i) == filePath && _attach.getType(i) == 1) - { - _attach.remove(i); - } -} - -void SMTPData::removeAttachFile(uint8_t index) -{ - uint8_t id = 0; - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 1) - { - if (id == index) - { - _attach.remove(i); - break; - } - id++; - } -} - -void SMTPData::setFileStorageType(uint8_t storageType) -{ - _storageType = storageType; - switch (storageType) { - case MailClientStorageType::SPIFFS: - fsp = &SPIFFS; - break; - case MailClientStorageType::SD: - fsp = &SD; - break; - case MailClientStorageType::FFat: - fsp = &FFat; - break; - case MailClientStorageType::Univ: - fsp = ufsp; - break; - } -} - -void SMTPData::clearAttachData() -{ - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 0) - _attach.remove(i); -} - -void SMTPData::clearAttachFile() -{ - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 1) - _attach.remove(i); -} - -void SMTPData::clearAttachment() -{ - _attach.free(); -} - -uint8_t SMTPData::attachFileCount() -{ - uint8_t count = 0; - for (uint8_t i = 0; i < _attach.getCount(); i++) - if (_attach.getType(i) == 1) - count++; - - return count; -} - -void SMTPData::addCustomMessageHeader(const String &commmand) -{ - _customMessageHeader.insert(_customMessageHeader.end(), commmand.c_str()); -} - -void SMTPData::removeCustomMessageHeader(const String &commmand) -{ - for (uint8_t i = 0; i < _customMessageHeader.size(); i++) - if (_customMessageHeader[i].c_str() == commmand.c_str()) - _customMessageHeader.erase(_customMessageHeader.begin() + i); -} - -void SMTPData::removeCustomMessageHeader(uint8_t index) -{ - _customMessageHeader.erase(_customMessageHeader.begin() + index); -} - -void SMTPData::clearCustomMessageHeader() -{ - std::vector().swap(_customMessageHeader); -} - -uint8_t SMTPData::CustomMessageHeaderCount() -{ - return _customMessageHeader.size(); -} - -String SMTPData::getCustomMessageHeader(uint8_t index) -{ - if (index >= _customMessageHeader.size()) - return std::string().c_str(); - return _customMessageHeader[index].c_str(); -} - -void SMTPData::empty() -{ - std::string().swap(_host); - std::string().swap(_loginEmail); - std::string().swap(_loginPassword); - std::string().swap(_fromName); - std::string().swap(_senderEmail); - std::string().swap(_subject); - std::string().swap(_message); - clearRecipient(); - clearCustomMessageHeader(); - clearCC(); - clearBCC(); - clearAttachment(); -} - -void SMTPData::setSendCallback(sendStatusCallback sendCallback) -{ - _sendCallback = std::move(sendCallback); -} - -ReadStatus::ReadStatus() -{ -} -ReadStatus::~ReadStatus() -{ - empty(); -} - -String ReadStatus::status() -{ - return _status.c_str(); -} -String ReadStatus::info() -{ - return _info.c_str(); -} - -bool ReadStatus::success() -{ - return _success; -} -void ReadStatus::empty() -{ - std::string().swap(_info); - std::string().swap(_status); -} - -SendStatus::SendStatus() -{ -} - -SendStatus::~SendStatus() -{ - empty(); -} - -String SendStatus::info() -{ - return _info.c_str(); -} -bool SendStatus::success() -{ - return _success; -} -void SendStatus::empty() -{ - std::string().swap(_info); -} - -ESP32_MailClient MailClient = ESP32_MailClient(); - -#endif //ESP32 - -#endif //ESP32_MailClient_CPP diff --git a/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h b/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h deleted file mode 100755 index 0b1f4496c..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ESP32_MailClient.h +++ /dev/null @@ -1,1912 +0,0 @@ -/* - *Mail Client Arduino Library for ESP32, version 2.1.4 - * - * April 12, 2020 - * - * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers. - * - * The library supports all ESP32 MCU based modules. - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - - -#ifndef ESP32_MailClient_H -#define ESP32_MailClient_H - -#ifdef ESP32 - -#include -#include "WiFiClientSecureESP32.h" -#include -#include -#include -#include -#include -#include -#include -#include "RFC2047.h" -#include "ESP32MailHTTPClient.h" -#include "ESP32TimeHelper.h" -#include - -#define FORMAT_SPIFFS_IF_FAILED true - -static RFC2047 RFC2047Decoder; - -using namespace std; - -#define SMTP_STATUS_SERVER_CONNECT_FAILED 1 -#define SMTP_STATUS_SMTP_RESPONSE_FAILED 2 -#define SMTP_STATUS_IDENTIFICATION_FAILED 3 -#define SMTP_STATUS_AUTHEN_NOT_SUPPORT 4 -#define SMTP_STATUS_AUTHEN_FAILED 5 -#define SMTP_STATUS_USER_LOGIN_FAILED 6 -#define SMTP_STATUS_PASSWORD_LOGIN_FAILED 7 -#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED 8 -#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED 9 -#define SMTP_STATUS_SEND_BODY_FAILED 10 - -#define IMAP_STATUS_SERVER_CONNECT_FAILED 1 -#define IMAP_STATUS_IMAP_RESPONSE_FAILED 2 -#define IMAP_STATUS_LOGIN_FAILED 3 -#define IMAP_STATUS_BAD_COMMAND 4 -#define IMAP_STATUS_PARSE_FLAG_FAILED 5 - -#define MAIL_CLIENT_STATUS_WIFI_CONNECT_FAIL 100 - -#define MAX_EMAIL_SEARCH_LIMIT 1000 - -static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -class IMAPData; -class SMTPData; -class attachmentData; -class SendStatus; -class messageBodyData; -class DownloadProgress; -class MessageData; - -struct MailClientStorageType -{ - static const uint8_t SPIFFS = 0; - static const uint8_t SD = 1; - static const uint8_t FFat = 2; - static const uint8_t Univ = 3; -}; - -static const char ESP32_MAIL_STR_1[] PROGMEM = "Content-Type: multipart/mixed; boundary=\""; -static const char ESP32_MAIL_STR_2[] PROGMEM = "{BOUNDARY}"; -static const char ESP32_MAIL_STR_3[] PROGMEM = "Mime-Version: 1.0\r\n"; -static const char ESP32_MAIL_STR_4[] PROGMEM = "AUTH LOGIN"; -static const char ESP32_MAIL_STR_5[] PROGMEM = "HELO dude"; -static const char ESP32_MAIL_STR_6[] PROGMEM = "EHLO dude"; -static const char ESP32_MAIL_STR_7[] PROGMEM = "QUIT"; -static const char ESP32_MAIL_STR_8[] PROGMEM = "MAIL FROM:"; -static const char ESP32_MAIL_STR_9[] PROGMEM = "RCPT TO:"; -static const char ESP32_MAIL_STR_10[] PROGMEM = "From: "; -static const char ESP32_MAIL_STR_11[] PROGMEM = "To: "; -static const char ESP32_MAIL_STR_12[] PROGMEM = "Cc: "; -static const char ESP32_MAIL_STR_13[] PROGMEM = ",<"; -static const char ESP32_MAIL_STR_14[] PROGMEM = "<"; -static const char ESP32_MAIL_STR_15[] PROGMEM = ">"; -static const char ESP32_MAIL_STR_16[] PROGMEM = "DATA"; -static const char ESP32_MAIL_STR_17[] PROGMEM = "X-Priority: "; -static const char ESP32_MAIL_STR_18[] PROGMEM = "X-MSMail-Priority: High\r\n"; -static const char ESP32_MAIL_STR_19[] PROGMEM = "X-MSMail-Priority: Normal\r\n"; -static const char ESP32_MAIL_STR_20[] PROGMEM = "X-MSMail-Priority: Low\r\n"; -static const char ESP32_MAIL_STR_21[] PROGMEM = "Importance: High\r\n"; -static const char ESP32_MAIL_STR_22[] PROGMEM = "Importance: Normal\r\n"; -static const char ESP32_MAIL_STR_23[] PROGMEM = "Importance: Low\r\n"; -static const char ESP32_MAIL_STR_24[] PROGMEM = "Subject: "; -static const char ESP32_MAIL_STR_25[] PROGMEM = "Content-Type: "; -static const char ESP32_MAIL_STR_26[] PROGMEM = "; Name=\""; -static const char ESP32_MAIL_STR_27[] PROGMEM = "Content-type: text/plain; charset=us-ascii\r\n"; -static const char ESP32_MAIL_STR_28[] PROGMEM = "Content-type: text/html; charset=\"UTF-8\"\r\n"; -static const char ESP32_MAIL_STR_29[] PROGMEM = "Content-transfer-encoding: 7bit\r\n"; -static const char ESP32_MAIL_STR_30[] PROGMEM = "Content-Disposition: attachment; filename=\""; -static const char ESP32_MAIL_STR_31[] PROGMEM = "Content-transfer-encoding: base64\r\n"; -static const char ESP32_MAIL_STR_32[] PROGMEM = "application/octet-stream"; -static const char ESP32_MAIL_STR_33[] PROGMEM = "--"; -static const char ESP32_MAIL_STR_34[] PROGMEM = "\r\n"; -static const char ESP32_MAIL_STR_35[] PROGMEM = "\"\r\n\r\n"; -static const char ESP32_MAIL_STR_36[] PROGMEM = "\"\r\n"; -static const char ESP32_MAIL_STR_37[] PROGMEM = "\r\n.\r\n"; -static const char ESP32_MAIL_STR_38[] PROGMEM = "could not connect to server"; -static const char ESP32_MAIL_STR_39[] PROGMEM = "could not handle SMTP server response"; -static const char ESP32_MAIL_STR_40[] PROGMEM = "could not handle IMAP server response"; -static const char ESP32_MAIL_STR_41[] PROGMEM = "identification failed"; -static const char ESP32_MAIL_STR_42[] PROGMEM = "authentication is not support"; -static const char ESP32_MAIL_STR_43[] PROGMEM = "authentication failed"; -static const char ESP32_MAIL_STR_44[] PROGMEM = "login account is not valid"; -static const char ESP32_MAIL_STR_45[] PROGMEM = "could not sigin"; -static const char ESP32_MAIL_STR_46[] PROGMEM = "could not parse command"; -static const char ESP32_MAIL_STR_47[] PROGMEM = "login password is not valid"; -static const char ESP32_MAIL_STR_48[] PROGMEM = "send header failed"; -static const char ESP32_MAIL_STR_49[] PROGMEM = "send body failed"; -static const char ESP32_MAIL_STR_50[] PROGMEM = "Connecting to IMAP server..."; -static const char ESP32_MAIL_STR_51[] PROGMEM = "initialize"; -static const char ESP32_MAIL_STR_52[] PROGMEM = "failed"; -static const char ESP32_MAIL_STR_53[] PROGMEM = "Error, "; -static const char ESP32_MAIL_STR_54[] PROGMEM = "IMAP server connected"; -static const char ESP32_MAIL_STR_55[] PROGMEM = "server_connected"; -static const char ESP32_MAIL_STR_56[] PROGMEM = "Sign in..."; -static const char ESP32_MAIL_STR_57[] PROGMEM = "signin"; -static const char ESP32_MAIL_STR_58[] PROGMEM = "Lising folders..."; -static const char ESP32_MAIL_STR_59[] PROGMEM = "listing"; -static const char ESP32_MAIL_STR_60[] PROGMEM = ":::::::Message folders:::::::"; -static const char ESP32_MAIL_STR_61[] PROGMEM = "Reading "; -static const char ESP32_MAIL_STR_62[] PROGMEM = "Predicted next UID: "; -static const char ESP32_MAIL_STR_63[] PROGMEM = "Total Message: "; -static const char ESP32_MAIL_STR_64[] PROGMEM = "::::::::::::Flags::::::::::::"; -static const char ESP32_MAIL_STR_65[] PROGMEM = "::::::::::Messages:::::::::::"; -static const char ESP32_MAIL_STR_66[] PROGMEM = "Searching messages..."; -static const char ESP32_MAIL_STR_67[] PROGMEM = "searching"; -static const char ESP32_MAIL_STR_68[] PROGMEM = "Search limit:"; -static const char ESP32_MAIL_STR_69[] PROGMEM = "Found "; -static const char ESP32_MAIL_STR_70[] PROGMEM = " messages"; -static const char ESP32_MAIL_STR_71[] PROGMEM = "Show "; -static const char ESP32_MAIL_STR_72[] PROGMEM = "Could not found any Email for defined criteria"; -static const char ESP32_MAIL_STR_73[] PROGMEM = "Search criteria is not set, fetch the recent message"; -static const char ESP32_MAIL_STR_74[] PROGMEM = "Feching message "; -static const char ESP32_MAIL_STR_75[] PROGMEM = ", UID: "; -static const char ESP32_MAIL_STR_76[] PROGMEM = ", Number: "; -static const char ESP32_MAIL_STR_77[] PROGMEM = "fetching"; -static const char ESP32_MAIL_STR_78[] PROGMEM = "Attachment ("; -static const char ESP32_MAIL_STR_79[] PROGMEM = ")"; -static const char ESP32_MAIL_STR_80[] PROGMEM = "Downloading attachments..."; -static const char ESP32_MAIL_STR_81[] PROGMEM = "downloading"; -static const char ESP32_MAIL_STR_82[] PROGMEM = " bytes"; -static const char ESP32_MAIL_STR_83[] PROGMEM = " - "; -static const char ESP32_MAIL_STR_84[] PROGMEM = "Free Heap: "; -static const char ESP32_MAIL_STR_85[] PROGMEM = "Sign out..."; -static const char ESP32_MAIL_STR_86[] PROGMEM = "signout"; -static const char ESP32_MAIL_STR_87[] PROGMEM = "Finished"; -static const char ESP32_MAIL_STR_88[] PROGMEM = "finished"; -static const char ESP32_MAIL_STR_89[] PROGMEM = "SD card mount failed"; -static const char ESP32_MAIL_STR_90[] PROGMEM = "download "; -static const char ESP32_MAIL_STR_91[] PROGMEM = ", "; -static const char ESP32_MAIL_STR_92[] PROGMEM = "%"; -static const char ESP32_MAIL_STR_93[] PROGMEM = "connection timeout"; -static const char ESP32_MAIL_STR_94[] PROGMEM = "WiFi connection lost"; -static const char ESP32_MAIL_STR_95[] PROGMEM = "no server response"; -static const char ESP32_MAIL_STR_96[] PROGMEM = "finished"; -static const char ESP32_MAIL_STR_97[] PROGMEM = " folder..."; -static const char ESP32_MAIL_STR_98[] PROGMEM = "Finished"; -static const char ESP32_MAIL_STR_99[] PROGMEM = "Date: "; -static const char ESP32_MAIL_STR_100[] PROGMEM = "Messsage UID: "; -static const char ESP32_MAIL_STR_101[] PROGMEM = "Messsage ID: "; -static const char ESP32_MAIL_STR_102[] PROGMEM = "Accept Language: "; -static const char ESP32_MAIL_STR_103[] PROGMEM = "Content Language: "; -static const char ESP32_MAIL_STR_104[] PROGMEM = "From: "; -static const char ESP32_MAIL_STR_105[] PROGMEM = "From Charset: "; -static const char ESP32_MAIL_STR_106[] PROGMEM = "To: "; -static const char ESP32_MAIL_STR_107[] PROGMEM = "To Charset: "; -static const char ESP32_MAIL_STR_108[] PROGMEM = "CC: "; -static const char ESP32_MAIL_STR_109[] PROGMEM = "CC Charset: "; -static const char ESP32_MAIL_STR_110[] PROGMEM = "Subject: "; -static const char ESP32_MAIL_STR_111[] PROGMEM = "Subject Charset: "; -static const char ESP32_MAIL_STR_112[] PROGMEM = "Message Charset: "; -static const char ESP32_MAIL_STR_113[] PROGMEM = "Attachment: "; -static const char ESP32_MAIL_STR_114[] PROGMEM = "File Index: "; -static const char ESP32_MAIL_STR_115[] PROGMEM = "Filename: "; -static const char ESP32_MAIL_STR_116[] PROGMEM = "Name: "; -static const char ESP32_MAIL_STR_117[] PROGMEM = "Size: "; -static const char ESP32_MAIL_STR_118[] PROGMEM = "Type: "; -static const char ESP32_MAIL_STR_119[] PROGMEM = "Creation Date: "; -static const char ESP32_MAIL_STR_120[] PROGMEM = "Connecting to SMTP server..."; -static const char ESP32_MAIL_STR_121[] PROGMEM = "SMTP server connected, wait for response..."; -static const char ESP32_MAIL_STR_122[] PROGMEM = "Identification..."; -static const char ESP32_MAIL_STR_123[] PROGMEM = "Authentication..."; -static const char ESP32_MAIL_STR_124[] PROGMEM = "Sign in..."; -static const char ESP32_MAIL_STR_125[] PROGMEM = "Sending Email header..."; -static const char ESP32_MAIL_STR_126[] PROGMEM = "Sending Email body..."; -static const char ESP32_MAIL_STR_127[] PROGMEM = "Sending attachments..."; -static const char ESP32_MAIL_STR_128[] PROGMEM = "Finalize..."; -static const char ESP32_MAIL_STR_129[] PROGMEM = "Finished\r\nEmail sent successfully"; -static const char ESP32_MAIL_STR_130[] PROGMEM = "$ LOGIN "; -static const char ESP32_MAIL_STR_131[] PROGMEM = " "; -static const char ESP32_MAIL_STR_132[] PROGMEM = " OK "; -static const char ESP32_MAIL_STR_133[] PROGMEM = "$ LIST \"\" \"*\""; -static const char ESP32_MAIL_STR_134[] PROGMEM = "CAPABILITY"; -static const char ESP32_MAIL_STR_135[] PROGMEM = "$ EXAMINE \""; -static const char ESP32_MAIL_STR_136[] PROGMEM = "\""; -static const char ESP32_MAIL_STR_137[] PROGMEM = "UID "; -static const char ESP32_MAIL_STR_138[] PROGMEM = " UID"; -static const char ESP32_MAIL_STR_139[] PROGMEM = " SEARCH"; -static const char ESP32_MAIL_STR_140[] PROGMEM = "UID"; -static const char ESP32_MAIL_STR_141[] PROGMEM = "SEARCH"; -static const char ESP32_MAIL_STR_142[] PROGMEM = "$ UID FETCH "; -static const char ESP32_MAIL_STR_143[] PROGMEM = "$ FETCH "; -static const char ESP32_MAIL_STR_144[] PROGMEM = " BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO DATE Message-ID Accept-Language Content-Language)]"; -static const char ESP32_MAIL_STR_145[] PROGMEM = "IMAP"; -static const char ESP32_MAIL_STR_146[] PROGMEM = "$ LOGOUT"; -static const char ESP32_MAIL_STR_147[] PROGMEM = " BODY.PEEK["; -static const char ESP32_MAIL_STR_148[] PROGMEM = ".MIME]"; -static const char ESP32_MAIL_STR_149[] PROGMEM = "multipart/"; -static const char ESP32_MAIL_STR_150[] PROGMEM = "$ UID FETCH "; -static const char ESP32_MAIL_STR_151[] PROGMEM = " BODY.PEEK["; -static const char ESP32_MAIL_STR_152[] PROGMEM = "."; -static const char ESP32_MAIL_STR_153[] PROGMEM = "attachment"; -static const char ESP32_MAIL_STR_154[] PROGMEM = "text/html"; -static const char ESP32_MAIL_STR_155[] PROGMEM = "text/plain"; -static const char ESP32_MAIL_STR_156[] PROGMEM = "]"; -static const char ESP32_MAIL_STR_157[] PROGMEM = "* ESEARCH"; -static const char ESP32_MAIL_STR_158[] PROGMEM = "$ NO "; -static const char ESP32_MAIL_STR_159[] PROGMEM = "$ BAD "; -static const char ESP32_MAIL_STR_160[] PROGMEM = "base64"; -static const char ESP32_MAIL_STR_161[] PROGMEM = "/decoded_msg.txt"; -static const char ESP32_MAIL_STR_162[] PROGMEM = "/raw_msg.txt"; -static const char ESP32_MAIL_STR_163[] PROGMEM = "/decoded_msg.html"; -static const char ESP32_MAIL_STR_164[] PROGMEM = "/raw_msg.html"; -static const char ESP32_MAIL_STR_165[] PROGMEM = " FETCH "; -static const char ESP32_MAIL_STR_166[] PROGMEM = "* OK "; -static const char ESP32_MAIL_STR_167[] PROGMEM = "content-type: "; -static const char ESP32_MAIL_STR_168[] PROGMEM = "charset=\""; -static const char ESP32_MAIL_STR_169[] PROGMEM = "charset="; -static const char ESP32_MAIL_STR_170[] PROGMEM = "name=\""; -static const char ESP32_MAIL_STR_171[] PROGMEM = "name="; -static const char ESP32_MAIL_STR_172[] PROGMEM = "content-transfer-encoding: "; -static const char ESP32_MAIL_STR_173[] PROGMEM = "\r"; -static const char ESP32_MAIL_STR_174[] PROGMEM = "content-description: "; -static const char ESP32_MAIL_STR_175[] PROGMEM = "content-disposition: "; -static const char ESP32_MAIL_STR_176[] PROGMEM = "filename=\""; -static const char ESP32_MAIL_STR_177[] PROGMEM = "filename="; -static const char ESP32_MAIL_STR_178[] PROGMEM = "size="; -static const char ESP32_MAIL_STR_179[] PROGMEM = "creation-date=\""; -static const char ESP32_MAIL_STR_180[] PROGMEM = "creation-date="; -static const char ESP32_MAIL_STR_181[] PROGMEM = "modification-date=\""; -static const char ESP32_MAIL_STR_182[] PROGMEM = "modification-date="; -static const char ESP32_MAIL_STR_183[] PROGMEM = "*"; -static const char ESP32_MAIL_STR_184[] PROGMEM = "from: "; -static const char ESP32_MAIL_STR_185[] PROGMEM = "to: "; -static const char ESP32_MAIL_STR_186[] PROGMEM = "cc: "; -static const char ESP32_MAIL_STR_187[] PROGMEM = "subject: "; -static const char ESP32_MAIL_STR_188[] PROGMEM = "date: "; -static const char ESP32_MAIL_STR_189[] PROGMEM = "message-id: "; -static const char ESP32_MAIL_STR_190[] PROGMEM = "accept-language: "; -static const char ESP32_MAIL_STR_191[] PROGMEM = "content-language: "; -static const char ESP32_MAIL_STR_192[] PROGMEM = ")"; -static const char ESP32_MAIL_STR_193[] PROGMEM = "{"; -static const char ESP32_MAIL_STR_194[] PROGMEM = "}"; -static const char ESP32_MAIL_STR_195[] PROGMEM = " LIST "; -static const char ESP32_MAIL_STR_196[] PROGMEM = "\\Noselect"; -static const char ESP32_MAIL_STR_197[] PROGMEM = " FLAGS "; -static const char ESP32_MAIL_STR_198[] PROGMEM = "("; -static const char ESP32_MAIL_STR_199[] PROGMEM = " EXISTS"; -static const char ESP32_MAIL_STR_200[] PROGMEM = " [UIDNEXT "; -static const char ESP32_MAIL_STR_201[] PROGMEM = "]"; -static const char ESP32_MAIL_STR_202[] PROGMEM = "/"; -static const char ESP32_MAIL_STR_203[] PROGMEM = "/header.txt"; -static const char ESP32_MAIL_STR_204[] PROGMEM = "/esp.32"; -static const char ESP32_MAIL_STR_205[] PROGMEM = "high"; -static const char ESP32_MAIL_STR_206[] PROGMEM = "High"; -static const char ESP32_MAIL_STR_207[] PROGMEM = "normal"; -static const char ESP32_MAIL_STR_208[] PROGMEM = "Normal"; -static const char ESP32_MAIL_STR_209[] PROGMEM = "low"; -static const char ESP32_MAIL_STR_210[] PROGMEM = "Low"; -static const char ESP32_MAIL_STR_211[] PROGMEM = "$ OK "; -static const char ESP32_MAIL_STR_212[] PROGMEM = "FLAGS"; -static const char ESP32_MAIL_STR_213[] PROGMEM = "BODY"; -static const char ESP32_MAIL_STR_214[] PROGMEM = "PEEK"; -static const char ESP32_MAIL_STR_215[] PROGMEM = "TEXT"; -static const char ESP32_MAIL_STR_216[] PROGMEM = "HEADER"; -static const char ESP32_MAIL_STR_217[] PROGMEM = "FIELDS"; -static const char ESP32_MAIL_STR_218[] PROGMEM = "["; -static const char ESP32_MAIL_STR_219[] PROGMEM = "]"; -static const char ESP32_MAIL_STR_220[] PROGMEM = "MIME"; -static const char ESP32_MAIL_STR_221[] PROGMEM = "connection lost"; -static const char ESP32_MAIL_STR_222[] PROGMEM = "set recipient failed"; -static const char ESP32_MAIL_STR_223[] PROGMEM = " NEW"; -static const char ESP32_MAIL_STR_224[] PROGMEM = "ALL"; - -static const char ESP32_MAIL_STR_225[] PROGMEM = "INFO: connecting to IMAP server..."; -static const char ESP32_MAIL_STR_226[] PROGMEM = "ERROR: could not connect to internet"; -static const char ESP32_MAIL_STR_227[] PROGMEM = "ERROR: "; -static const char ESP32_MAIL_STR_228[] PROGMEM = "INFO: server connected"; -static const char ESP32_MAIL_STR_229[] PROGMEM = "INFO: send imap command LOGIN"; -static const char ESP32_MAIL_STR_230[] PROGMEM = "INFO: send imap command LIST"; -static const char ESP32_MAIL_STR_231[] PROGMEM = "INFO: send imap command EXAMINE"; -static const char ESP32_MAIL_STR_232[] PROGMEM = "INFO: search message"; -static const char ESP32_MAIL_STR_233[] PROGMEM = "INFO: fetch message"; -static const char ESP32_MAIL_STR_234[] PROGMEM = "INFO: send imap command LOGOUT"; -static const char ESP32_MAIL_STR_235[] PROGMEM = "INFO: message fetch completed"; -static const char ESP32_MAIL_STR_236[] PROGMEM = "INFO: connecting to SMTP server..."; -static const char ESP32_MAIL_STR_237[] PROGMEM = "ERROR: could not connect to internet"; -static const char ESP32_MAIL_STR_238[] PROGMEM = "INFO: smtp server connected"; -static const char ESP32_MAIL_STR_239[] PROGMEM = "INFO: send smtp HELO command"; -static const char ESP32_MAIL_STR_240[] PROGMEM = "INFO: send smtp AUTH LOGIN command"; -static const char ESP32_MAIL_STR_241[] PROGMEM = "INFO: log in with username and password"; -static const char ESP32_MAIL_STR_242[] PROGMEM = "INFO: send email header"; -static const char ESP32_MAIL_STR_243[] PROGMEM = "INFO: send email body"; -static const char ESP32_MAIL_STR_244[] PROGMEM = "INFO: send attachment..."; -static const char ESP32_MAIL_STR_245[] PROGMEM = "INFO: finalize..."; -static const char ESP32_MAIL_STR_246[] PROGMEM = "INFO: email sent successfully"; -static const char ESP32_MAIL_STR_247[] PROGMEM = "$ SELECT \""; -static const char ESP32_MAIL_STR_248[] PROGMEM = "INFO: send imap command SELECT"; -static const char ESP32_MAIL_STR_249[] PROGMEM = "$ UID STORE "; -static const char ESP32_MAIL_STR_250[] PROGMEM = " FLAGS ("; -static const char ESP32_MAIL_STR_251[] PROGMEM = " +FLAGS ("; -static const char ESP32_MAIL_STR_252[] PROGMEM = " -FLAGS ("; -static const char ESP32_MAIL_STR_253[] PROGMEM = "INFO: set FLAG"; -static const char ESP32_MAIL_STR_254[] PROGMEM = "INFO: add FLAG"; -static const char ESP32_MAIL_STR_255[] PROGMEM = "INFO: remove FLAG"; -static const char ESP32_MAIL_STR_256[] PROGMEM = "could not parse flag"; -static const char ESP32_MAIL_STR_257[] PROGMEM = "BAD"; - -__attribute__((used)) static bool compFunc(uint32_t i, uint32_t j) -{ - return (i > j); -} - -class ReadStatus -{ -public: - ReadStatus(); - ~ReadStatus(); - String status(); - String info(); - bool success(); - void empty(); - friend IMAPData; - - std::string _status = ""; - std::string _info = ""; - bool _success = false; -}; - -class SendStatus -{ -public: - SendStatus(); - ~SendStatus(); - String info(); - bool success(); - void empty(); - friend SMTPData; - - std::string _info = ""; - bool _success = false; -}; - -typedef void (*readStatusCallback)(ReadStatus); -typedef void (*sendStatusCallback)(SendStatus); - - - -class ESP32_MailClient -{ - -public: - /* - - Sending Email through SMTP server - - @param net - HTTPClientESP32 WiFi client. - - @return Boolean type status indicates the success of operation. - - */ - bool sendMail(SMTPData &smtpData); - - /* - - Reading Email through IMAP server. - - @param imapData - IMAP Data object to hold data and instances. - - @return Boolean type status indicates the success of operation. - - */ - bool readMail(IMAPData &imapData); - - /* - - Set the argument to the Flags for message. - - @param imapData - IMAP Data object to hold data and instances. - - @param msgUID - The UID of message. - - @param flags - The flag list. - - - @return Boolean type status indicates the success of operation. - - */ - bool setFlag(IMAPData &imapData, int msgUID, const String &flags); - - - - /* - - Add the argument to the Flags for message. - - @param imapData - IMAP Data object to hold data and instances. - - @param msgUID - The UID of message. - - @param flags - The flag list. - - - @return Boolean type status indicates the success of operation. - - */ - bool addFlag(IMAPData &imapData, int msgUID, const String &flags); - - /* - - Remove the argument from the Flags for message. - - @param imapData - IMAP Data object to hold data and instances. - - @param msgUID - The UID of message. - - @param flags - The flag list. - - - @return Boolean type status indicates the success of operation. - - */ - bool removeFlag(IMAPData &imapData, int msgUID, const String &flags); - - /* - - Get the Email sending error details. - - @return Error details string (String object). - - */ - String smtpErrorReason(); - - /* - - Get the Email reading error details. - - @return Error details string (String object). - - */ - String imapErrorReason(); - - /* - - Init SD card with GPIO pins. - - @param sck - SPI Clock pin. - @param miso - SPI MISO pin. - @param mosi - SPI MOSI pin. - @param ss - SPI Chip/Slave Select pin. - - @return Boolean type status indicates the success of operation. - - */ - bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); - - /* - - Init SD card with default GPIO pins. - - @return Boolean type status indicates the success of operation. - - */ - bool sdBegin(void); - - struct IMAP_COMMAND_TYPE; - struct IMAP_HEADER_TYPE; - - -ESP32TimeHelper Time; - -private: - int _smtpStatus = 0; - int _imapStatus = 0; - bool _sdOk = false; - bool _sdConfigSet = false; - uint8_t _sck, _miso, _mosi, _ss; - unsigned long _lastReconnectMillis = 0; - uint16_t _reconnectTimeout = 10000; - - - std::string smtpErrorReasonStr(); - std::string imapErrorReasonStr(); - void ESP32MailDebugError(); - void ESP32MailDebugInfo(PGM_P info); - void set_message_header(string &header, std::string &message, bool htmlFormat); - void set_attachment_header(uint8_t index, std::string &header, attachmentData &attach); - void clientReadAll(WiFiClient *client); - double base64DecodeSize(std::string lastBase64String, int length); - unsigned char *base64_decode_char(const unsigned char *src, size_t len, size_t *out_len); - std::string base64_encode_string(const unsigned char *src, size_t len); - void send_base64_encode_mime_data(WiFiClient *client, const unsigned char *src, size_t len); - void send_base64_encode_mime_file(WiFiClient *client, File file); - int waitSMTPResponse(SMTPData &smtpData); - bool waitIMAPResponse(IMAPData &imapData, uint8_t imapCommandType = 0, int maxChar = 0, int mailIndex = -1, int messageDataIndex = -1, std ::string part = ""); - bool _setFlag(IMAPData &imapData, int msgUID, const String &flags, uint8_t action); - bool getIMAPResponse(IMAPData &imapData); - void createDirs(std::string dirs); - bool smtpClientAvailable(SMTPData &smtpData, bool available); - bool imapClientAvailable(IMAPData &imapData, bool available); - bool sdTest(); -}; - -class messageBodyData -{ -public: - messageBodyData(); - ~messageBodyData(); - void empty(); - - friend ESP32_MailClient; - friend IMAPData; - -protected: - uint8_t _index = 0; - size_t _size = 0; - std::string _text = ""; - std::string _filename = ""; - std::string _savePath = ""; - std::string _name = ""; - std::string _disposition = ""; - std::string _contentType = ""; - std::string _descr = ""; - std::string _transfer_encoding = ""; - std::string _creation_date = ""; - std::string _modification_date = ""; - std::string _charset = ""; - std::string _part = ""; - std::string _downloadError = ""; - bool _sdFileOpenWrite = false; - bool _error = false; -}; - -class attachmentData -{ -public: - attachmentData(); - ~attachmentData(); - - friend ESP32_MailClient; - friend SMTPData; - -protected: - uint8_t _index = 0; - std::vector> _buf = std::vector>(); - std::vector _filename = std::vector(); - std::vector _id = std::vector(); - std::vector _type = std::vector(); - std::vector _size = std::vector(); - std::vector _mime_type = std::vector(); - - void add(const String &fileName, const String &mimeType, uint8_t *data, size_t size); - void remove(uint8_t index); - void free(); - String getFileName(uint8_t index); - String getMimeType(uint8_t index); - uint8_t *getData(uint8_t index); - uint16_t getSize(uint8_t index); - uint8_t getCount(); - uint8_t getType(uint8_t index); -}; - -class IMAPData -{ -public: - IMAPData(); - ~IMAPData(); - - /* - Set the IMAP server login credentials. - - @param host - IMAP server e.g. imap.gmail.com. - @param port - IMAP port e.g. 993 for gmail. - @param loginEmail - The Email address of account. - @param loginPassword - The account password. - @rootCA - Root CA certificate base64 string - - */ - void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA); - void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword); - - /* - - Set STARTTLS mode to enable STARTTLS protocol - - @param starttls - bool flag that enables STARTTLS mode - - */ - void setSTARTTLS(bool starttls); - - /* - - Set debug print to serial - - @param debug - bool flag to enable debug - - */ - void setDebug(bool debug); - - /* - - Set the mailbox folder to search or fetch. - - @param folderName - Known mailbox folder. Ddefault value is INBOX - - */ - void setFolder(const String &folderName); - - /* - - Set the maximum message buffer size for text/html result from search or fetch the message. - - @param size - The message size in byte. - - */ - void setMessageBufferSize(size_t size); - - /* - - Set the maximum attachment file size to be downloaded. - - @param size - The attachement file size in byte. - - */ - void setAttachmentSizeLimit(size_t size); - - /* - Set the search criteria used in selected mailbox search. - - In case of message UID was set through setFetchUID function, search operation will not process, - you need to clear message UID by calling imapData.setFetchUID("") to clear. - - @param criteria - Search criteria String. - - If folder is not set, the INBOX folder will be used - - Example: - - "SINCE 10-Feb-2019" will search all messages that received since 10 Feb 2019 - "UID SEARCH ALL" will seach all message which will return the message UID that can be use later for fetch one or more messages. - - - Search criteria can be consisted these keywords - - ALL - All messages in the mailbox; the default initial key for ANDing. - ANSWERED - Messages with the \Answered flag set. - BCC - Messages that contain the specified string in the envelope structure's BCC field. - BEFORE - Messages whose internal date (disregarding time and timezone) is earlier than the specified date. - BODY - Messages that contain the specified string in the body of the message. - CC - Messages that contain the specified string in the envelope structure's CC field. - DELETED - Messages with the \Deleted flag set. - DRAFT - Messages with the \Draft flag set. - FLAGGED - Messages with the \Flagged flag set. - FROM - Messages that contain the specified string in the envelope structure's FROM field. - HEADER - Messages that have a header with the specified field-name (as defined in [RFC-2822]) - and that contains the specified string in the text of the header (what comes after the colon). - - If the string to search is zero-length, this matches all messages that have a header line with - the specified field-name regardless of the contents. - - KEYWORD - Messages with the specified keyword flag set. - LARGER - Messages with an [RFC-2822] size larger than the specified number of octets. - NEW - Messages that have the \Recent flag set but not the \Seen flag. - This is functionally equivalent to "(RECENT UNSEEN)". - NOT - Messages that do not match the specified search key. - OLD - Messages that do not have the \Recent flag set. This is functionally equivalent to - "NOT RECENT" (as opposed to "NOT NEW"). - ON - Messages whose internal date (disregarding time and timezone) is within the specified date. - OR - Messages that match either search key. - RECENT - Messages that have the \Recent flag set. - SEEN - Messages that have the \Seen flag set. - SENTBEFORE - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is earlier than the specified date. - SENTON - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is within the specified date. - SENTSINCE - Messages whose [RFC-2822] Date: header (disregarding time and timezone) is within or later than the specified date. - SINCE - Messages whose internal date (disregarding time and timezone) is within or later than the specified date. - SMALLER - Messages with an [RFC-2822] size smaller than the specified number of octets. - SUBJECT - Messages that contain the specified string in the envelope structure's SUBJECT field. - TEXT - Messages that contain the specified string in the header or body of the message. - TO - Messages that contain the specified string in the envelope structure's TO field. - UID - Messages with unique identifiers corresponding to the specified unique identifier set. - Sequence set ranges are permitted. - UNANSWERED - Messages that do not have the \Answered flag set. - UNDELETED - Messages that do not have the \Deleted flag set. - UNDRAFT - Messages that do not have the \Draft flag set. - UNFLAGGED - Messages that do not have the \Flagged flag set. - UNKEYWORD - Messages that do not have the specified keyword flag set. - UNSEEN - Messages that do not have the \Seen flag set. - - */ - void setSearchCriteria(const String &criteria); - - /* - Set to search the unseen message. - - @param unseenSearch - Boolean flag to enable unseen message search. - - This function will be overridden (omitted) by setFetchUID as setSearchCriteria. - - */ - void setSearchUnseenMessage(bool unseenSearch); - - /* - Set the download folder. - - @param path - Path in SD card. - - All text/html message and attachemnts will be saved to message UID folder which created in defined path - e.g. "/{DEFINED_PATH}/{MESSAGE_UID}/{ATTACHMENT_FILE...}". - - */ - void setSaveFilePath(const String &path); - - /* - - Specify message UID to fetch or read. - - @param fetchUID - The message UID. - - Specify the message UID to fetch (read) only specific message instead of search. - - */ - void setFetchUID(const String &fetchUID); - - /* - - Set storage type to save download attached file or messages. - - @param storageType - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS - - */ - void setFileStorageType(uint8_t storageType); - - /* - - Enable/disable attachment download. - - @param download - Boolean flag to enable/disable attachment download. - - */ - void setDownloadAttachment(bool download); - - /* - - Enable/disable html message result. - - @param htmlFormat - Boolean flag to enable/disable html message result. - - The default value is false. - - */ - void setHTMLMessage(bool htmlFormat); - - /* - - Enable/disable plain text message result. - - @param textFormat - Boolean flag to enable/disable plain text message result. - - The default value is true. - - */ - void setTextMessage(bool textFormat); - - /* - - Set the maximum message to search. - - @param limit - Any number from 0 to 65535. - - The default value is 20. - - */ - void setSearchLimit(uint16_t limit); - - /* - - Enable/disable recent sort result. - - @param recentSort - Boolean flag to enable/disable recent message sort result. - - The default value is true. - - */ - void setRecentSort(bool recentSort); - - /* - - Assign callback function that return status of message fetching or reading. - - @param readCallback - The function that accept readStatusCallback as parameter. - - */ - void setReadCallback(readStatusCallback readCallback); - - /* - - Enable/disable attachement download progress while fetching or receiving message. - - @param report - Boolean flag to enable/disable attachement download progress while fetching or receiving message. - - To get the download status, Callback function should be set through setReadCallback. - - */ - void setDownloadReport(bool report); - - /* - - Determine only message header is return when search. - - */ - bool isHeaderOnly(); - - /* - - Get the sender name/Email for selected message from search result. - - @param messageIndex - The index of message. - - @return Sender name/Email String. - - */ - String getFrom(uint16_t messageIndex); - - /* - - Get the sender name/Email charactor encoding. - - @param messageIndex - The index of message. - - @return Sender name/Email charactor encoding which use for decoding. - - */ - String getFromCharset(uint16_t messageIndex); - - /* - - Get the recipient name/Email for selected message index from search result. - - @param messageIndex - The index of message. - - @return Recipient name/Email String. - - */ - String getTo(uint16_t messageIndex); - - /* - - Get the recipient name/Email charactor encoding. - - @param messageIndex - The index of message. - - @return Recipient name/Email charactor encoding which use in decoding to local language. - - */ - String getToCharset(uint16_t messageIndex); - - /* - - Get the CC name/Email for selected message index of IMAPData result. - - @param messageIndex - The index of message. - - @return CC name/Email String. - - */ - String getCC(uint16_t messageIndex); - - /* - - Get the CC name/Email charactor encoding. - - @param messageIndex - The index of message. - - @return CC name/Email charactor encoding which use in decoding to local language. - - */ - String getCCCharset(uint16_t messageIndex); - - /* - - Get the message subject for selected message index from search result. - - @param messageIndex - The index of message. - - @return Message subject name/Email String. - - */ - String getSubject(uint16_t messageIndex); - - /* - - Get the message subject charactor encoding. - - @param messageIndex - The index of message. - - @return Message subject charactor encoding which use in decoding to local language. - - */ - String getSubjectCharset(uint16_t messageIndex); - - /* - - Get the html message for selected message index from search result. - - @param messageIndex - The index of message. - - @return The html message String or empty String upon the setHTMLMessage was set. - - */ - String getHTMLMessage(uint16_t messageIndex); - - /* - - Get the plain text message for selected message index from search result. - - @param messageIndex - The index of message. - - @return The plain text message String or empty String upon the setTextMessage was set. - - */ - String getTextMessage(uint16_t messageIndex); - - /* - - Get the html message charactor encoding. - - @param messageIndex - The index of message. - - @return Html message charactor encoding which use in decoding to local language. - - */ - String getHTMLMessgaeCharset(uint16_t messageIndex); - - /* - - Get the text message charactor encoding. - - @param messageIndex - The index of message. - - @return The text message charactor encoding which use in decoding to local language. - - */ - String getTextMessgaeCharset(uint16_t messageIndex); - - /* - - Get the date of received message for selected message index from search result. - - @param messageIndex - The index of message. - - @return The date String. - - */ - String getDate(uint16_t messageIndex); - - /* - - Get the message UID for selected message index from search result. - - @param messageIndex - The index of message. - - @return UID String that can be use in setFetchUID. - - */ - String getUID(uint16_t messageIndex); - - /* - - Get the message number for selected message index from search result. - - @param messageIndex - The index of message. - - @return The message number which vary upon search criteria and sorting. - - */ - String getNumber(uint16_t messageIndex); - - /* - - Get the message ID for selected message index from search result. - - @param messageIndex - The index of message. - - @return The message ID String. - - */ - String getMessageID(uint16_t messageIndex); - - /* - - Get the accept language for selected message index from search result. - - @param messageIndex - The index of message. - - @return The accept language String. - - */ - String getAcceptLanguage(uint16_t messageIndex); - - /* - - Get the content language of text or html for selected message index from search result. - - @param messageIndex - The index of message. - - @return The content language String. - - */ - String getContentLanguage(uint16_t messageIndex); - - /* - - Determine fetch error status for selected message index from search result. - - @param messageIndex - The index of message. - - @return Fetch error status. - - */ - bool isFetchMessageFailed(uint16_t messageIndex); - - /* - Get fetch error reason for selected message index from search result. - - @param messageIndex - The index of message. - - @return Fetch error reason String for selected message index. - - */ - String getFetchMessageFailedReason(uint16_t messageIndex); - - /* - Determine the attachment download error for selected message index from search result. - - @param messageIndex - The index of message. - - @return Fetch status. - - */ - bool isDownloadAttachmentFailed(uint16_t messageIndex, size_t attachmentIndex); - - /* - - Get the attachment download error reason for selected message index from search result. - - @param messageIndex - The index of message. - - @return Download error reason String for selected message index. - - */ - String getDownloadAttachmentFailedReason(uint16_t messageIndex, size_t attachmentIndex); - - /* - - Determine the downloaded/saved text message error status for selected message index from search result. - - @param messageIndex - The index of message. - - @return Text message download status. - - */ - bool isDownloadMessageFailed(uint16_t messageIndex); - - /* - - Get the attachment or message downloadeds error reason for selected message index from search result. - - @param messageIndex - The index of message. - - @return Downloaded error reason String for selected message index. - - */ - String getDownloadMessageFailedReason(uint16_t messageIndex); - - /* - - Assign the download and decode flags for html message download. - - @param download - Boolean flag to enable/disable message download. - - @param decoded - Boolean flag to enable/disable html message decoding (support utf8 and base64 encoding). - - */ - void saveHTMLMessage(bool download, bool decoded); - - /* - - Assign the download and decode flags for plain text message download. - - @param download - Boolean flag to enable/disable message download. - - @param decoded - Boolean flag to enable/disable plain text message decoding (support utf8 and base64 encoding). - - */ - void saveTextMessage(bool download, bool decoded); - - /* - - Determine the mailbox folder count. - - @return Folder count number. - - */ - uint16_t getFolderCount(); - - /* - Get the mailbox folder name at selected index. - - @param folderIndex - Index of folder. - - @return Folder name String. - - Use folder name from this function for fetch or search. - - */ - String getFolder(uint16_t folderIndex); - - /* - - Determin the number of supported flags count. - - @return Flag count number. - - */ - uint16_t getFlagCount(); - - /* - Get the flag name for selected index. - - @param folderIndex - Index of folder. - - @return Flag name String. - - Use flags from this function for fetch or search. - - */ - String getFlag(uint16_t flagIndex); - - /* - - Get the number of message in selected mailbox folder. - - @return Total message number. - - */ - size_t totalMessages(); - - /* - - Get the number of message from search result. - - @return Search result number. - - */ - size_t searchCount(); - - /* - - Get the number of message available from search result which less than search limit. - - @return Available message number. - - */ - size_t availableMessages(); - - /* - - Get the number of attachments for selected message index from search result. - - @param messageIndex - Index of message. - - @return Number of attachments - - */ - size_t getAttachmentCount(uint16_t messageIndex); - - /* - - Get file name of attachment for selected attachment index and message index from search result. - - @param messageIndex - Index of message. - @param attachmentIndex - Index of attachment. - - @return The attachment file name String at the selected index. - - */ - String getAttachmentFileName(size_t messageIndex, size_t attachmentIndex); - - /* - - Get the name of attachment for selected attachment index and message index from search result. - - @param messageIndex - Index of message. - @param attachmentIndex - Index of attachment. - - @return The attachment name String at the selected index. - - */ - String getAttachmentName(size_t messageIndex, size_t attachmentIndex); - - /* - - Get attachment file size for selected attachment index and message index from search result. - - @param messageIndex - Index of message. - @param attachmentIndex - Index of attachment. - - @return The attachment file size in byte at the selected index. - - */ - int getAttachmentFileSize(size_t messageIndex, size_t attachmentIndex); - - /* - - Get creation date of attachment for selected attachment index and message index from search result. - - @param messageIndex - Index of message. - @param attachmentIndex - Index of attachment. - - @return The attachment creation date String at the selected index. - - */ - String getAttachmentCreationDate(size_t messageIndex, size_t attachmentIndex); - - /* - Get attachment file type for selected attachment index and message index from search result. - - @param messageIndex - Index of message. - @param attachmentIndex - Index of attachment. - - @return File MIME String at the selected index e.g. image/jpeg. - - */ - String getAttachmentType(size_t messageIndex, size_t attachmentIndex); - - /* - - Clear all IMAPData object data. - - */ - void empty(); - - /* - - Clear IMAPData object message data. - - */ - void clearMessageData(); - - friend ESP32_MailClient; - -private: - String getMessage(uint16_t messageIndex, bool htmlFormat); - - - size_t _totalMessage = 0; - std::string _host = ""; - uint16_t _port = 993; - uint8_t _storageType = 1; - FS *fsp = &SD; - bool _unseen = false; - std::string _loginEmail = ""; - std::string _loginPassword = ""; - std::string _currentFolder = "INBOX"; - std::string _nextUID = ""; - std::string _searchCriteria = "ALL*"; - std::string _fetchUID = ""; - std::string _savePath = ""; - - bool _downloadAttachment = false; - bool _recentSort = true; - bool _htmlFormat = false; - bool _textFormat = false; - bool _headerOnly = true; - bool _uidSearch = false; - bool _saveHTMLMsg = false; - bool _saveTextMsg = false; - bool _saveDecodedHTML = false; - bool _saveDecodedText = false; - bool _downloadReport = false; - bool _headerSaved = false; - - size_t _message_buffer_size = 200; - size_t _attacement_max_size = 1024 * 1024; - uint16_t _emailNumMax = 20; - int _searchCount; - bool _starttls = false; - bool _debug = false; - readStatusCallback _readCallback = NULL; - - std::vector _date = std::vector(); - std::vector _subject = std::vector(); - std::vector _subject_charset = std::vector(); - std::vector _from = std::vector(); - std::vector _from_charset = std::vector(); - std::vector _to = std::vector(); - std::vector _to_charset = std::vector(); - std::vector _cc = std::vector(); - std::vector _cc_charset = std::vector(); - std::vector _msgNum = std::vector(); - std::vector _msgID = std::vector(); - std::vector _contentLanguage = std::vector(); - std::vector _acceptLanguage = std::vector(); - - std::vector _folders = std::vector(); - std::vector _flag = std::vector(); - std::vector _attachmentCount = std::vector(); - std::vector> _messageDataInfo = std::vector>(); - std::vector _totalAttachFileSize = std::vector(); - std::vector _downloadedByte = std::vector(); - std::vector _messageDataCount = std::vector(); - std::vector _errorMsg = std::vector(); - std::vector _error = std::vector(); - std::vector _rootCA = std::vector(); - - - std::unique_ptr _net = std::unique_ptr(new ESP32MailHTTPClient()); - - ReadStatus _cbData; -}; - -class SMTPData -{ -public: - SMTPData(); - ~SMTPData(); - - /* - - Set SMTP server login credentials - - @param host - SMTP server e.g. smtp.gmail.com - @param port - SMTP port. - @param loginEmail - The account Email. - @param loginPassword - The account password. - @rootCA - Root CA certificate base64 string - - */ - void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword, const char *rootCA); - void setLogin(const String &host, uint16_t port, const String &loginEmail, const String &loginPassword); - - /* - - Set STARTTLS mode to enable STARTTLS protocol - - @param starttls - bool flag that enables STARTTLS mode - - */ - void setSTARTTLS(bool starttls); - - /* - - Set debug print to serial - - @param debug - bool flag to enable debug - - */ - void setDebug(bool debug); - /* - - Set Sender info - - @param fromName - Sender's name - @param senderEmail - Sender's Email. - - */ - void setSender(const String &fromName, const String &senderEmail); - - /* - - Get Sender's name - - @return Sender's name String. - - */ - String getFromName(); - - /* - - Get Sender's Email - - @return Sender's Email String. - - */ - String getSenderEmail(); - - /* - - Set Email priority or importance - - @param priority - Number from 1 to 5, 1 for highest, 3 for normal and 5 for lowest priority - - */ - void setPriority(int priority); - - /* - - Set Email priority or importance - - @param priority - String (High, Normal or Low) - - */ - void setPriority(const String &priority); - - /* - - Get Email priority - - @return number represents Email priority (1 for highest, 3 for normal, 5 for low priority). - - */ - uint8_t getPriority(); - - /* - - Add one or more recipient - - @param email - Recipient Email String of one recipient. - - To add multiple recipients, call addRecipient for each recipient. - - */ - void addRecipient(const String &email); - - /* - - Remove recipient - - @param email - Recipient Email String. - - */ - void removeRecipient(const String &email); - - /* - - Remove recipient - - @param index - Index of recipients in Email object that previously added. - - */ - void removeRecipient(uint8_t index); - - /* - Clear all recipients. - */ - void clearRecipient(); - - /* - - Get one recipient - - @param index - Index of recipients. - - @return Recipient Email String at the index. - - */ - String getRecipient(uint8_t index); - - /* - - Get number of recipients - - @return Number of recipients. - - */ - uint8_t recipientCount(); - - /* - - Set the Email subject - - @param subject - The subject. - - */ - void setSubject(const String &subject); - - /* - - Get the Email subject - - @return Subject String. - - */ - String getSubject(); - - /* - - Set the Email message - - @param message - The message can be in normal text or html format. - @param htmlFormat - The html format flag, True for send the message as html format - - */ - void setMessage(const String &message, bool htmlFormat); - - void clrMessage(bool htmlFormat); - - void addMessage(const String &message); - - - /* - - Get the message - - @return Message String. - - */ - String getMessage(); - - /* - - Determine message is being send in html format - - @return Boolean status. - - */ - bool htmlFormat(); - - /* - - Add Carbon Copy (CC) Email - - @param email - The CC Email String. - - */ - void addCC(const String &email); - - /* - - Remove specified Carbon Copy (CC) Email - - @param email - The CC Email String to remove. - - */ - void removeCC(const String &email); - - /* - - Remove specified Carbon Copy (CC) Email - - @param index - The CC Email index to remove. - - */ - void removeCC(uint8_t index); - - /* - - Clear all Carbon Copy (CC) Emails - - */ - void clearCC(); - - /* - - Get Carbon Copy (CC) Email at specified index - - @param index - The CC Email index to get. - @return The CC Email string at the index. - - */ - String getCC(uint8_t index); - - /* - - Get the number of Carbon Copy (CC) Email - - @return Number of CC Emails. - - */ - uint8_t ccCount(); - - /* - Add Blind Carbon Copy (BCC) Email - - @param email - The BCC Email String. - - */ - void addBCC(const String &email); - - /* - - Remove specified Blind Carbon Copy (BCC) Email - - @param email - The BCC Email String to remove. - - */ - void removeBCC(const String &email); - - /* - - Remove specified Blind Carbon Copy (BCC) Email - - @param index - The BCC Email index to remove. - - */ - void removeBCC(uint8_t index); - - /* - - Clear all Blind Carbon Copy (BCC) Emails - - */ - void clearBCC(); - - /* - - Get Blind Carbon Copy (BCC) Email at specified index - - @param index - The BCC Email index to get. - - @return The BCC Email string at the index. - - */ - String getBCC(uint8_t index); - - /* - - Get the number of Blind Carbon Copy (BCC) Email - - @return Number of BCC Emails. - - */ - uint8_t bccCount(); - - /* - - Add attchement data (binary) from internal memory (flash or ram) - - @param fileName - The file name String that recipient can be saved. - @param mimeType - The MIME type of file (image/jpeg, image/png, text/plain...). Can be empty String. - @param data - The byte array of data (uint8_t) - @param size - The data length in byte. - - */ - void addAttachData(const String &fileName, const String &mimeType, uint8_t *data, size_t size); - - /* - - Remove specified attachment data - - @param fileName - The file name of the attachment data to remove. - - */ - void removeAttachData(const String &fileName); - - /* - - Remove specified attachment data - - @param index - The index of the attachment data (count only data type attachment) to remove. - - */ - void removeAttachData(uint8_t index); - - /* - - Get the number of attachment data - - @return Number of attach data. - - */ - uint8_t attachDataCount(); - - /* - - Add attchement file from SD card - - @param fileName - The file name String that recipient can be saved. - @param mimeType - The MIME type of file (image/jpeg, image/png, text/plain...). Can be omitted. - - */ - void addAttachFile(const String &filePath, const String &mimeType = ""); - - /* - - Remove specified attachment file from Email object - - @param fileName - The file name of the attachment file to remove. - - */ - void removeAttachFile(const String &filePath); - - /* - - Remove specified attachment file - - @param index - The index of the attachment file (count only file type attachment) to remove. - - */ - void removeAttachFile(uint8_t index); - - /* - - Set storage type for all attach files. - - @param storageType - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS - - */ - void setFileStorageType(uint8_t storageType); - - /* - - Clear all attachment data - - */ - void clearAttachData(); - - /* - - Clear all attachment file. - - */ - void clearAttachFile(); - - /* - - Clear all attachments (both data and file type attachments). - - */ - void clearAttachment(); - - /* - - Get number of attachments (both data and file type attachments). - - @return Number of all attachemnts. - - */ - uint8_t attachFileCount(); - - /* - - Add one or more custom message header field. - - @param field - custom header String inform of FIELD: VALUE - - This header field will add to message header. - - - */ - void addCustomMessageHeader(const String &field); - - /* - - Remove one custom message header field that previously added. - - @param field - custom custom message header field String to remove. - - - */ - void removeCustomMessageHeader(const String &field); - - /* - - Remove one custom message header field that previously added by its index. - - @param index - custom message header field index (number) to remove. - - - */ - void removeCustomMessageHeader(uint8_t index); - - /* - - Clear all ccustom message header field that previously added. - - */ - void clearCustomMessageHeader(); - - /* - - Get the number of custom message header field that previously added. - - @return Number of custom message header field. - - */ - uint8_t CustomMessageHeaderCount(); - - /* - - Get custom message header field that previously added by index - - @param index - The custom message header field index to get. - - @return The custom message header field string at the index. - - */ - String getCustomMessageHeader(uint8_t index); - - - - /* - - Clear all data from Email object to free memory. - - */ - void empty(); - - /* - - Set the Email sending status callback function to Email object. - - @param sendCallback - The callback function that accept the sendStatusCallback param. - - */ - void setSendCallback(sendStatusCallback sendCallback); - - friend ESP32_MailClient; - friend attachmentData; - -protected: - int _priority = -1; - string _loginEmail = ""; - string _loginPassword = ""; - string _host = ""; - uint16_t _port = 0; - uint8_t _storageType = 1; - FS *fsp = &SD; - string _fromName = ""; - string _senderEmail = ""; - string _subject = ""; - string _message = ""; - bool _htmlFormat = false; - bool _starttls = false; - bool _debug = false; - sendStatusCallback _sendCallback = NULL; - - std::vector _recipient = std::vector(); - std::vector _customMessageHeader = std::vector(); - std::vector _cc = std::vector(); - std::vector _bcc = std::vector(); - attachmentData _attach; - SendStatus _cbData; - std::vector _rootCA = std::vector(); - std::unique_ptr _net = std::unique_ptr(new ESP32MailHTTPClient()); - -}; - - -static void __attribute__((used)) ESP32MailDebug(const char *msg) -{ - - Serial.print(FPSTR("[DEBUG] - ")); - Serial.println(msg); - -} - -static void __attribute__((used)) ESP32MailDebugLine(const char *msg, bool newline) -{ - if (!newline) - Serial.print(FPSTR("[DEBUG] - ")); - - if (newline) - Serial.println(msg); - else - Serial.print(msg); -} - - -extern ESP32_MailClient MailClient; - -#endif //ESP32 - -#endif //ESP32_MailClient_H diff --git a/lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp b/lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp deleted file mode 100755 index 26460a604..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/WiFiClientSecureESP32.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/* - *Customized WiFiClientSecure.cpp to support STARTTLS protocol, version 1.0.1 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - WiFiClientSecureESP32.cpp - Client Secure class for ESP32 - Copyright (c) 2016 Hristo Gochkov All right reserved. - Additions Copyright (C) 2017 Evandro Luis Copercini. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef WiFiClientSecureESP32_CPP -#define WiFiClientSecureESP32_CPP - -#ifdef ESP32 - -#include "WiFiClientSecureESP32.h" -#include -#include -#include - -#undef connect -#undef write -#undef read - - -WiFiClientSecureESP32::WiFiClientSecureESP32() -{ - _connected = false; - - sslclient = new sslclient_context32; - ssl_init(sslclient); - sslclient->socket = -1; - sslclient->handshake_timeout = 120000; - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - - -WiFiClientSecureESP32::WiFiClientSecureESP32(int sock) -{ - _connected = false; - _timeout = 0; - - sslclient = new sslclient_context32; - ssl_init(sslclient); - sslclient->socket = sock; - sslclient->handshake_timeout = 120000; - - if (sock >= 0) { - _connected = true; - } - - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - -WiFiClientSecureESP32::WiFiClientSecureESP32(bool starttls) -{ - _connected = false; - - sslclient = new sslclient_context32; - ssl_init(sslclient); - sslclient->socket = -1; - sslclient->handshake_timeout = 120000; - sslclient->starttls = true; - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - -WiFiClientSecureESP32::~WiFiClientSecureESP32() -{ - stop(); - delete sslclient; -} - -WiFiClientSecureESP32 &WiFiClientSecureESP32::operator=(const WiFiClientSecureESP32 &other) -{ - stop(); - sslclient->socket = other.sslclient->socket; - _connected = other._connected; - return *this; -} - -void WiFiClientSecureESP32::stop() -{ - if (sslclient->socket >= 0) { - close(sslclient->socket); - sslclient->socket = -1; - _connected = false; - _peek = -1; - } - stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key); -} - -int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port) -{ - if (_pskIdent && _psKey) - return connect(ip, port, _pskIdent, _psKey); - return connect(ip, port, _CA_cert, _cert, _private_key); -} - -int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, int32_t timeout){ - _timeout = timeout; - return connect(ip, port); -} - -int WiFiClientSecureESP32::connect(const char *host, uint16_t port) -{ - if (_pskIdent && _psKey) - return connect(host, port, _pskIdent, _psKey); - return connect(host, port, _CA_cert, _cert, _private_key); -} - -int WiFiClientSecureESP32::connect(const char *host, uint16_t port, int32_t timeout){ - _timeout = timeout; - return connect(host, port); -} - -int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) -{ - return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key); -} - -int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key) -{ - if(_timeout > 0){ - sslclient->handshake_timeout = _timeout; - } - int ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL); - _lastError = ret; - if (ret < 0) { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - _connected = true; - return 1; -} - -int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) { - return connect(ip.toString().c_str(), port,_pskIdent, _psKey); -} - -int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) { - log_v("start_ssl_client with PSK"); - if(_timeout > 0){ - sslclient->handshake_timeout = _timeout; - } - int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey); - _lastError = ret; - if (ret < 0) { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - _connected = true; - return 1; -} - -int WiFiClientSecureESP32::peek(){ - if(_peek >= 0){ - return _peek; - } - _peek = timedRead(); - return _peek; -} - -size_t WiFiClientSecureESP32::write(uint8_t data) -{ - return write(&data, 1); -} - -int WiFiClientSecureESP32::read() -{ - uint8_t data = -1; - int res = read(&data, 1); - if (res < 0) { - return res; - } - return data; -} - -size_t WiFiClientSecureESP32::write(const uint8_t *buf, size_t size) -{ - if (!_connected) { - return 0; - } - int res = send_ssl_data(sslclient, buf, size); - if (res < 0) { - stop(); - res = 0; - } - return res; -} - -int WiFiClientSecureESP32::read(uint8_t *buf, size_t size) -{ - int peeked = 0; - int avail = available(); - if ((!buf && size) || avail <= 0) { - return -1; - } - if(!size){ - return 0; - } - if(_peek >= 0){ - buf[0] = _peek; - _peek = -1; - size--; - avail--; - if(!size || !avail){ - return 1; - } - buf++; - peeked = 1; - } - - int res = get_ssl_receive(sslclient, buf, size); - if (res < 0) { - stop(); - return peeked?peeked:res; - } - return res + peeked; -} - -int WiFiClientSecureESP32::available() -{ - int peeked = (_peek >= 0); - if (!_connected) { - return peeked; - } - int res = data_to_read(sslclient); - if (res < 0) { - stop(); - return peeked?peeked:res; - } - return res+peeked; -} - -uint8_t WiFiClientSecureESP32::connected() -{ - uint8_t dummy = 0; - read(&dummy, 0); - - return _connected; -} - -void WiFiClientSecureESP32::setCACert (const char *rootCA) -{ - _CA_cert = rootCA; -} - -void WiFiClientSecureESP32::setCertificate (const char *client_ca) -{ - _cert = client_ca; -} - -void WiFiClientSecureESP32::setPrivateKey (const char *private_key) -{ - _private_key = private_key; -} - -void WiFiClientSecureESP32::setPreSharedKey(const char *pskIdent, const char *psKey) { - _pskIdent = pskIdent; - _psKey = psKey; -} - -bool WiFiClientSecureESP32::verify(const char* fp, const char* domain_name) -{ - if (!sslclient) - return false; - - return verify_ssl_fingerprint(sslclient, fp, domain_name); -} - -char *WiFiClientSecureESP32::_streamLoad(Stream& stream, size_t size) { - static char *dest = nullptr; - if(dest) { - free(dest); - } - dest = (char*)malloc(size); - if (!dest) { - return nullptr; - } - if (size != stream.readBytes(dest, size)) { - free(dest); - dest = nullptr; - } - return dest; -} - -bool WiFiClientSecureESP32::loadCACert(Stream& stream, size_t size) { - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) { - setCACert(dest); - ret = true; - } - return ret; -} - -bool WiFiClientSecureESP32::loadCertificate(Stream& stream, size_t size) { - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) { - setCertificate(dest); - ret = true; - } - return ret; -} - -bool WiFiClientSecureESP32::loadPrivateKey(Stream& stream, size_t size) { - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) { - setPrivateKey(dest); - ret = true; - } - return ret; -} - -int WiFiClientSecureESP32::lastError(char *buf, const size_t size) -{ - if (!_lastError) { - return 0; - } - char error_buf[100]; - mbedtls_strerror(_lastError, error_buf, 100); - snprintf(buf, size, "%s", error_buf); - return _lastError; -} - -void WiFiClientSecureESP32::setHandshakeTimeout(unsigned long handshake_timeout) -{ - sslclient->handshake_timeout = handshake_timeout * 1000; -} - -void WiFiClientSecureESP32::setSTARTTLS(bool starttls) -{ - sslclient->starttls = starttls; -} - -void WiFiClientSecureESP32::setDebugCB(DebugMsgCallback cb) -{ - sslclient->_debugCallback = std::move(cb); -} - -#endif //ESP32 - -#endif //WiFiClientSecureESP32_CPP \ No newline at end of file diff --git a/lib/libesp32/ESP32-Mail-Client/src/ssl_client32.h b/lib/libesp32/ESP32-Mail-Client/src/ssl_client32.h deleted file mode 100755 index 3e2d3b09a..000000000 --- a/lib/libesp32/ESP32-Mail-Client/src/ssl_client32.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - *Customized ssl_client.h to support STARTTLS protocol, version 1.0.3 - * - * The MIT License (MIT) - * Copyright (c) 2019 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* Provide SSL/TLS functions to ESP32 with Arduino IDE - * by Evandro Copercini - 2017 - Apache 2.0 License - */ - -#ifndef SSL_CLIENT32_H -#define SSL_CLIENT32_H - -#ifdef ESP32 - -#include "mbedtls/platform.h" -#include "mbedtls/net.h" -#include "mbedtls/debug.h" -#include "mbedtls/ssl.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/error.h" - -static const char ESP32_SSL_CLIENT_STR_1[] PROGMEM = "ERROR: "; -static const char ESP32_SSL_CLIENT_STR_2[] PROGMEM = "INFO: starting socket"; -static const char ESP32_SSL_CLIENT_STR_3[] PROGMEM = "ERROR: opening socket"; -static const char ESP32_SSL_CLIENT_STR_4[] PROGMEM = "ERROR: could not get ip from host"; -static const char ESP32_SSL_CLIENT_STR_5[] PROGMEM = "INFO: connecting to Server..."; -static const char ESP32_SSL_CLIENT_STR_6[] PROGMEM = "INFO: server connected"; -static const char ESP32_SSL_CLIENT_STR_7[] PROGMEM = "ERROR: connect to Server failed!"; -static const char ESP32_SSL_CLIENT_STR_8[] PROGMEM = "INFO: begin STARTTLS handshake"; -static const char ESP32_SSL_CLIENT_STR_9[] PROGMEM = "INFO: seeding the random number generator"; -static const char ESP32_SSL_CLIENT_STR_10[] PROGMEM = "INFO: setting up the SSL/TLS structure..."; -static const char ESP32_SSL_CLIENT_STR_11[] PROGMEM = "INFO: loading CA cert"; -static const char ESP32_SSL_CLIENT_STR_12[] PROGMEM = "INFO: setting up PSK"; -static const char ESP32_SSL_CLIENT_STR_13[] PROGMEM = "ERROR: pre-shared key not valid hex or too long"; -static const char ESP32_SSL_CLIENT_STR_14[] PROGMEM = "INFO: set mbedtls config"; -static const char ESP32_SSL_CLIENT_STR_15[] PROGMEM = "INFO: loading CRT cert"; -static const char ESP32_SSL_CLIENT_STR_16[] PROGMEM = "INFO: loading private key"; -static const char ESP32_SSL_CLIENT_STR_17[] PROGMEM = "INFO: setting hostname for TLS session..."; -static const char ESP32_SSL_CLIENT_STR_18[] PROGMEM = "INFO: performing the SSL/TLS handshake..."; -static const char ESP32_SSL_CLIENT_STR_19[] PROGMEM = "INFO: verifying peer X.509 certificate..."; -static const char ESP32_SSL_CLIENT_STR_20[] PROGMEM = "ERROR: failed to verify peer certificate!"; -static const char ESP32_SSL_CLIENT_STR_21[] PROGMEM = "INFO: certificate verified"; -static const char ESP32_SSL_CLIENT_STR_22[] PROGMEM = "INFO: cleaning SSL connection"; -static const char ESP32_SSL_CLIENT_STR_23[] PROGMEM = "ERROR: fingerprint too short"; -static const char ESP32_SSL_CLIENT_STR_24[] PROGMEM = "ERROR: invalid hex sequence"; -static const char ESP32_SSL_CLIENT_STR_25[] PROGMEM = "ERROR: could not fetch peer certificate"; -static const char ESP32_SSL_CLIENT_STR_26[] PROGMEM = "ERROR: fingerprint doesn't match"; -static const char ESP32_SSL_CLIENT_STR_27[] PROGMEM = "ERROR: waiting incoming data failed!"; -static const char ESP32_SSL_CLIENT_STR_28[] PROGMEM = "ERROR: reading incoming data failed!"; -static const char ESP32_SSL_CLIENT_STR_29[] PROGMEM = "EHLO DUDE\r\n"; -static const char ESP32_SSL_CLIENT_STR_30[] PROGMEM = "INFO: send SMTP command extended HELO"; -static const char ESP32_SSL_CLIENT_STR_31[] PROGMEM = "ERROR: send SMTP command failed!"; -static const char ESP32_SSL_CLIENT_STR_32[] PROGMEM = "ERROR: waiting incoming data failed!"; -static const char ESP32_SSL_CLIENT_STR_33[] PROGMEM = "ERROR: reading incoming data failed!"; -static const char ESP32_SSL_CLIENT_STR_34[] PROGMEM = "STARTTLS\r\n"; -static const char ESP32_SSL_CLIENT_STR_35[] PROGMEM = "INFO: send STARTTLS protocol command"; -static const char ESP32_SSL_CLIENT_STR_36[] PROGMEM = "ERROR: send STARTTLS protocol command failed!"; -static const char ESP32_SSL_CLIENT_STR_37[] PROGMEM = "ERROR: waiting incoming data failed!"; -static const char ESP32_SSL_CLIENT_STR_38[] PROGMEM = "ERROR: reading incoming data failed!"; - -typedef void (*DebugMsgCallback)(const char *msg); - -typedef struct sslclient_context32 { - int socket; - bool starttls; - mbedtls_ssl_context ssl_ctx; - mbedtls_ssl_config ssl_conf; - mbedtls_net_context server_fd; - - mbedtls_ctr_drbg_context drbg_ctx; - mbedtls_entropy_context entropy_ctx; - - mbedtls_x509_crt ca_cert; - mbedtls_x509_crt client_cert; - mbedtls_pk_context client_key; - DebugMsgCallback _debugCallback; - - unsigned long handshake_timeout; -} sslclient_context32; - - -void ssl_init(sslclient_context32 *ssl_client); -int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey); -void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key); -int data_to_read(sslclient_context32 *ssl_client); -int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len); -int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length); -bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char* fp, const char* domain_name); -bool verify_ssl_dn(sslclient_context32 *ssl_client, const char* domain_name); -int starttlsHandshake(sslclient_context32 *ssl_client, int port); -void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client); - -#endif //ESP32 - -#endif //SSL_CLIENT32_H diff --git a/tasmota/sendemail_ESP32.ino b/tasmota/sendemail_ESP32.ino new file mode 100644 index 000000000..eefabfbe7 --- /dev/null +++ b/tasmota/sendemail_ESP32.ino @@ -0,0 +1,325 @@ +#ifdef USE_ESP32MAIL + + +#include + +#ifndef SEND_MAIL32_MINRAM +#define SEND_MAIL32_MINRAM 30*1024 +#endif +#define xPSTR(a) a +#define MAX_ATTCHMENTS 8 +char *attachments[MAX_ATTCHMENTS]; +uint8_t num_attachments; +void script_send_email_body(void(*func)(char *)); +String html_content = ""; +SMTP_Message *email_mptr; + +//#define DEBUG_EMAIL_PORT + +uint16_t SendMail(char *buffer) { + char *params,*oparams = 0; + const char *mserv; + uint16_t port; + const char *user; + const char *pstr; + const char *passwd; + const char *from; + const char *to; + const char *subject; + const char *cmd; + uint16_t status = 0; + uint16_t blen; + char *endcmd; + SMTPSession smtp; + ESP_Mail_Session session; + SMTP_Message message; + email_mptr = &message; + + // return if not enough memory + uint32_t mem = ESP.getFreeHeap(); + //AddLog(LOG_LEVEL_INFO, PSTR("heap: %d"),mem); + if (mem < SEND_MAIL32_MINRAM) { + // return 4; + } + + while (*buffer==' ') buffer++; + + if (*buffer != '[') { + goto exit; + } + + buffer++; + + endcmd = strchr(buffer, ']'); + if (!endcmd) { + goto exit; + } + + // copy params + blen = (uint32_t)endcmd - (uint32_t)buffer; + oparams = (char*)calloc(blen+2, 1); + if (!oparams) return 4; + params = oparams; + strncpy(oparams, buffer, blen+2); + oparams[blen] = 0; + + cmd = endcmd + 1; + + + for (uint32_t cnt = 0; cnt < MAX_ATTCHMENTS; cnt++) { + attachments[cnt] = 0; + } + num_attachments = 0; + +#ifdef DEBUG_EMAIL_PORT + AddLog(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen); +#endif + + mserv = strtok(params, ":"); + if (!mserv) { + goto exit; + } + + // port + pstr = strtok(NULL, ":"); + if (!pstr) { + goto exit; + } + +#ifdef EMAIL_PORT + if (*pstr == '*') { + port = EMAIL_PORT; + } else { + port = atoi(pstr); + } +#else + port = atoi(pstr); +#endif + + user = strtok(NULL, ":"); + if (!user) { + goto exit; + } + + passwd = strtok(NULL, ":"); + if (!passwd) { + goto exit; + } + + from = strtok(NULL, ":"); + if (!from) { + goto exit; + } + + to = strtok(NULL, ":"); + if (!to) { + goto exit; + } + + subject = strtok(NULL, "]"); + if (!subject) { + goto exit; + } + +#ifdef EMAIL_USER + if (*user == '*') { + user = xPSTR(EMAIL_USER); + } +#endif + +#ifdef EMAIL_PASSWORD + if (*passwd == '*') { + passwd = xPSTR(EMAIL_PASSWORD); + } +#endif + +#ifdef EMAIL_SERVER + if (*mserv == '*') { + mserv = xPSTR(EMAIL_SERVER); + } +#endif + +#ifdef DEBUG_EMAIL_PORT + AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"), mserv, port, user, passwd); +#endif + +#ifdef EMAIL_FROM + if (*from == '*') { + from = xPSTR(EMAIL_FROM); + } +#endif + +#ifdef DEBUG_EMAIL_PORT + AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"), from, to, subject, cmd); +#endif + + + smtp.debug(true); + //smtp.debug(false); + + message.clearRecipients(); + message.clearCc(); + message.clearBcc(); + + //smtp.callback(smtpCallback); + + session.server.host_name = mserv; + session.server.port = port; + session.login.email = user; + session.login.password = passwd; + session.login.user_domain = "googlemail.com"; + + + message.enable.chunking = true; + char sname[32]; + strlcpy(sname, SettingsText(SET_FRIENDLYNAME1), sizeof(sname)); + message.sender.name = sname; + message.sender.email = from; + message.subject = subject; + message.addRecipient("user1", to); + message.html.charSet = "utf-8"; + message.text.charSet = "utf-8"; + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + //message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + message.response.notify = esp_mail_smtp_notify_failure; + message.html.charSet = "us-ascii"; + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + message.addHeader("Message-ID: "); + + #ifdef USE_SCRIPT + if (*cmd == '*' && *(cmd + 1) == 0) { + script_send_email_body(send_message_txt); + } else { + html_content += cmd; + message.html.content = html_content.c_str(); + } + #else + html_content += cmd; + message.html.content = html_content.c_str(); + #endif + + /* Connect to server with the session config */ + delay(0); + if (!smtp.connect(&session)) + goto exit; + + /* Start sending the Email and close the session */ + delay(0); + + if (!MailClient.sendMail(&smtp, &message, true)) { + Serial.println("Error sending Email, " + smtp.errorReason()); + } + +exit: + for (uint32_t cnt = 0; cnt < MAX_ATTCHMENTS; cnt++) { + if (attachments[cnt]) { + free(attachments[cnt]); + attachments[cnt] = 0; + } + } + html_content = ""; + if (oparams) free(oparams); + return status; +} + + +void send_message_txt(char *txt) { + if (*txt == '@') { + txt++; + attach_File(txt); + } else if (*txt == '&') { + txt++; + attach_Array(txt); + } else if (*txt == '$') { + txt++; +#if defined(ESP32) && defined(USE_WEBCAM) + if (num_attachments < MAX_ATTCHMENTS) { + attachments[num_attachments] = (char*)malloc(32); + uint32_t cnt; + uint8_t *buff; + uint32_t len, picmax; + picmax = WcGetPicstore(-1, 0); + cnt = *txt&7; + if (cnt < 1 || cnt > picmax) cnt = 1; + len = WcGetPicstore(cnt - 1, &buff); + if (len) { + sprintf(attachments[num_attachments], "img_%1d.jpg", cnt); + attach_Data(attachments[num_attachments], buff, len); + } + num_attachments++; + } +#endif + } else { + html_content += txt; + email_mptr->html.content = html_content.c_str(); + } +} + +void attach_File(char *path) { + SMTP_Attachment att; + if (num_attachments < MAX_ATTCHMENTS) { + attachments[num_attachments] = (char*)malloc(32); + strcpy(attachments[num_attachments], path); + + char *cp = attachments[num_attachments]; + att.file.path = cp; + if (*cp == '/') { + cp++; + } + att.descr.filename = cp; + att.descr.mime = "application/octet-stream"; //binary data + att.file.storage_type = esp_mail_file_storage_type_univ; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + email_mptr->addAttachment(att); + email_mptr->resetAttachItem(att); + num_attachments++; + } +} + +float *get_array_by_name(char *name, uint16_t *alen); +void flt2char(float num, char *nbuff); + +void attach_Array(char *aname) { + float *array = 0; + uint16_t alen; + String ttstr = ""; + array = get_array_by_name(aname, &alen); + if (array && alen) { + float *fp = array; + for (uint32_t cnt = 0; cnt < alen; cnt++) { + // export array as tab gelimited text + char nbuff[16]; + flt2char(*fp++, nbuff); + if (cnt < (alen - 1)) { + strcat(nbuff, "\t"); + } else { + strcat(nbuff, "\n"); + } + ttstr += nbuff; + } + + if (num_attachments < MAX_ATTCHMENTS) { + attachments[num_attachments] = (char*)malloc(ttstr.length() + 1 + 32); + strcpy(attachments[num_attachments] + 32, ttstr.c_str()); + sprintf(attachments[num_attachments], "%s.txt", aname); + attach_Data(attachments[num_attachments], (uint8_t*)attachments[num_attachments]+32, ttstr.length()); + num_attachments++; + } + } else { + //g_client->print(F("\r\n\r\narray not found!\r\n")); + } +} + +void attach_Data(char *name, uint8_t *buff, uint32_t len) { + SMTP_Attachment att; + att.descr.filename = name; + att.descr.mime = "application/octet-stream"; + att.blob.data = buff; + att.blob.size = len; + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + email_mptr->addAttachment(att); + email_mptr->resetAttachItem(att); +} + +#endif // USE_ESP32MAIL diff --git a/tasmota/sendemail.h b/tasmota/sendemail_ESP8266.h similarity index 76% rename from tasmota/sendemail.h rename to tasmota/sendemail_ESP8266.h index 5c75ae260..a56f6916f 100644 --- a/tasmota/sendemail.h +++ b/tasmota/sendemail_ESP8266.h @@ -3,17 +3,8 @@ //#define DEBUG_EMAIL_PORT -//#include -//#include #include -//#include - -#ifdef ESP8266 #include "WiFiClientSecureLightBearSSL.h" -#endif // ESP8266 -#ifdef ESP32 -#include -#endif // ESP32 class SendEmail { @@ -25,13 +16,8 @@ class SendEmail const int timeout; const bool ssl; const int auth_used; -#ifdef ESP8266 // use bear ssl BearSSL::WiFiClientSecure_light *client; -#endif // ESP8266 -#ifdef ESP32 - WiFiClient *client; -#endif // ESP32 String readClient(); void a3_to_a4(unsigned char * a4, unsigned char * a3); diff --git a/tasmota/sendemail.ino b/tasmota/sendemail_ESP8266.ino similarity index 55% rename from tasmota/sendemail.ino rename to tasmota/sendemail_ESP8266.ino index dd2539b4f..896b8e0e3 100644 --- a/tasmota/sendemail.ino +++ b/tasmota/sendemail_ESP8266.ino @@ -1,8 +1,6 @@ #ifdef USE_SENDMAIL -#ifndef USE_ESP32MAIL - -#include "sendemail.h" +#include "sendemail_ESP8266.h" // enable serial debugging //#define DEBUG_EMAIL_PORT @@ -179,19 +177,10 @@ exit: } - -#ifdef ESP8266 WiFiClient *g_client; SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) : host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new BearSSL::WiFiClientSecure_light(1024,1024)) { } -#endif // ESP8266 -#ifdef ESP32 -WiFiClient *g_client; -SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) : - host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure()) { -} -#endif // ESP32 String SendEmail::readClient() { delay(0); @@ -385,11 +374,14 @@ exit: return status; } +#ifdef USE_SCRIPT void xsend_message_txt(char *msg) { + #ifdef DEBUG_EMAIL_PORT AddLog_P(LOG_LEVEL_INFO, PSTR("%s"),msg); #endif -#if (defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)) || defined(USE_UFILESYS) + +#ifdef USE_UFILESYS if (*msg=='@') { msg++; attach_File(msg); @@ -415,43 +407,6 @@ void xsend_message_txt(char *msg) { #endif } -#if (defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)) || defined(USE_UFILESYS) -#ifdef ESP8266 -#include -#endif // ESP8266 -#ifdef ESP32 -#include -#endif // ESP32 -extern FS *ufsp; - -void attach_File(char *path) { - g_client->print(F("--frontier\r\n")); - g_client->print(F("Content-Type: text/plain\r\n")); - char buff[64]; - char *cp = path; - while (*cp=='/') cp++; - File file = ufsp->open(path, "r"); - if (file) { - sprintf_P(buff,PSTR("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n"), cp); - g_client->write(buff); - uint16_t flen = file.size(); - uint8_t fbuff[64]; - uint16_t blen = sizeof(fbuff); - while (flen>0) { - file.read(fbuff, blen); - flen -= blen; - g_client->write(fbuff, blen); - if (flenprint(F("\r\n\r\nfile not found!\r\n")); - } - g_client->print(F("\r\n--frontier\r\n")); -} - -#endif // defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) - float *get_array_by_name(char *name, uint16_t *alen); void flt2char(float num, char *nbuff); @@ -490,353 +445,41 @@ void attach_Array(char *aname) { } g_client->print(F("\r\n--frontier\r\n")); } - -#else - - -/* - * Created by K. Suwatchai (Mobizt) - * - * Email: k_suwatchai@hotmail.com - * - * Github: https://github.com/mobizt - * - * Copyright (c) 2019 mobizt - * -*/ - - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - -#include "ESP32_MailClient.h" -#include "SD.h" - -//For demo only -//#include "image.h" - -#ifndef SEND_MAIL32_MINRAM -#define SEND_MAIL32_MINRAM 30*1024 -#endif - -void script_send_email_body(void(*func)(char *)); - -#define xPSTR(a) a -//The Email Sending data object contains config and data to send -SMTPData smtpData; -#define MAX_ATTCHMENTS 8 -char *attachments[MAX_ATTCHMENTS]; -uint8_t num_attachments; - -//Callback function to get the Email sending status -//void sendCallback(SendStatus info); -//#define DEBUG_EMAIL_PORT - -uint16_t SendMail(char *buffer) { - char *params,*oparams; - const char *mserv; - uint16_t port; - const char *user; - const char *pstr; - const char *passwd; - const char *from; - const char *to; - const char *subject; - const char *cmd; - uint16_t status=1; - uint16_t blen; - char *endcmd; - - // return if not enough memory - uint32_t mem=ESP.getFreeHeap(); - //AddLog(LOG_LEVEL_INFO, PSTR("heap: %d"),mem); - if (mem +extern FS *ufsp; - //For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be - //enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function. - //smtpData.setSTARTTLS(true); - - //Set the sender name and Email - smtpData.setSender("ESP32",from); - - //Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest) - smtpData.setPriority("High"); - - //Set the subject - smtpData.setSubject(subject); - - #ifdef USE_SCRIPT - if (*cmd=='*' && *(cmd+1)==0) { - smtpData.clrMessage(true); - script_send_email_body(send_message_txt); - } else { - smtpData.setMessage(cmd, true); +void attach_File(char *path) { + g_client->print(F("--frontier\r\n")); + g_client->print(F("Content-Type: text/plain\r\n")); + char buff[64]; + char *cp = path; + while (*cp=='/') cp++; + File file = ufsp->open(path, "r"); + if (file) { + sprintf_P(buff,PSTR("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n"), cp); + g_client->write(buff); + uint16_t flen = file.size(); + uint8_t fbuff[64]; + uint16_t blen = sizeof(fbuff); + while (flen>0) { + file.read(fbuff, blen); + flen -= blen; + g_client->write(fbuff, blen); + if (flen"); - - //Set the storage types to read the attach files (SD is default) - //smtpData.setFileStorageType(MailClientStorageType::SPIFFS); - - -/* -#ifdef USE_SCRIPT_FATFS -#if USE_SCRIPT_FATFS<0 - smtpData.setFileStorageType(MailClientStorageType::FFat); -#else - smtpData.setFileStorageType(MailClientStorageType::SD); -#endif -#endif -*/ - -smtpData.setFileStorageType(MailClientStorageType::Univ); - - - //smtpData.setSendCallback(sendCallback); - - //Start sending Email, can be set callback function to track the status - if (!MailClient.sendMail(smtpData)) { - //Serial.println("Error sending Email, " + MailClient.smtpErrorReason()); - AddLog(LOG_LEVEL_INFO, PSTR("Error sending Email, %s"), MailClient.smtpErrorReason().c_str()); - + file.close(); } else { - status=0; + g_client->print(F("\r\n\r\nfile not found!\r\n")); } - //Clear all data from Email object to free memory - smtpData.empty(); - for (uint32_t cnt=0; cntprint(F("\r\n--frontier\r\n")); } -float *get_array_by_name(char *name, uint16_t *alen); -void flt2char(float num, char *nbuff); - -void attach_Array(char *aname) { - float *array = 0; - uint16_t alen; - String ttstr = ""; - array = get_array_by_name(aname, &alen); - if (array && alen) { - float *fp=array; - for (uint32_t cnt = 0; cntprint(F("\r\n\r\narray not found!\r\n")); - } -} - -void send_message_txt(char *txt) { - if (*txt=='@') { - txt++; - smtpData.addAttachFile(txt); - } else if (*txt=='&') { - txt++; - attach_Array(txt); - } else if (*txt=='$') { - txt++; -#if defined(ESP32) && defined(USE_WEBCAM) - uint32_t cnt; - uint8_t *buff; - uint32_t len,picmax; - picmax=WcGetPicstore(-1,0); - cnt=*txt&7; - if (cnt<1 || cnt>picmax) cnt=1; - len=WcGetPicstore(cnt-1,&buff); - if (len) { - char str[12]; - sprintf(str,"img_%1d.jpg",cnt+1); - smtpData.addAttachData(str, "image/jpg",buff,len); - } -#endif - } else { - smtpData.addMessage(txt); - } -} - -/* -//Callback function to get the Email sending status -void sendCallback(SendStatus msg) -{ - //Print the current status - Serial.println(msg.info()); - - //Do something when complete - if (msg.success()) - { - Serial.println("----------------"); - } -} -*/ -#endif +#endif // USE_UFILESYS #endif // USE_SENDMAIL