diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 5c9e6cbc..00000000 --- a/.clang-format +++ /dev/null @@ -1,89 +0,0 @@ ---- -Language: Cpp -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: false -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: true - AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeTernaryOperators: false -BreakConstructorInitializersBeforeComma: true -ColumnLimit: 0 -CommentPragmas: '^ (IWYU pragma:|NOLINT)' -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ForEachMacros: [] -IncludeCategories: - - Regex: '^"(stdafx|PrecompiledHeader)' - Priority: -2 - - Regex: '^".*Common' - Priority: -1 - - Regex: '^<' - Priority: 1 - - Regex: '^"' - Priority: 2 -IndentCaseLabels: true -IndentWidth: 4 -IndentWrappedFunctionNames: false -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 3 -NamespaceIndentation: All -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Right -ReflowComments: true -SortIncludes: false -SpaceAfterCStyleCast: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 4 -UseTab: Never -... diff --git a/.gitignore b/.gitignore index 35d06bef..2bebeb00 100644 --- a/.gitignore +++ b/.gitignore @@ -386,4 +386,9 @@ ASALocalRun/ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch -i18n_preview*.jpg +tmp/ + +# WebUI +data/ +!public/scripts/bin +public/src/**/*.js diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 080e70d0..e8463ca5 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,7 +2,9 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "platformio.platformio-ide" + "cschlosser.doxdocgen", + "platformio.platformio-ide", + "psioniq.psi-header" ], "unwantedRecommendations": [ "ms-vscode.cpptools-extension-pack" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..2ce29abe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,53 @@ +{ + "files.associations": { + ".env*": "dotenv", + "plyconfig.json": "jsonc", + "*.tcc": "cpp", + "fstream": "cpp", + "functional": "cpp", + "string": "cpp", + "typeinfo": "cpp", + "random": "cpp", + "*.html.tpl": "html", + "new": "cpp", + "atomic": "cpp", + "memory": "cpp", + "type_traits": "cpp", + "cmath": "cpp", + "limits": "cpp", + "utility": "cpp" + }, + "editor.tabSize": 4, + "editor.insertSpaces": true, + "editor.renderWhitespace": "all", + "psi-header.templates": [ + { + "language": "*", + "template": [ + "#########################################################################", + " File: <>", + " File Created: <>", + " Author: <>", + " Last Modified: <>", + " Modified By: <>", + " License: <>", + "#########################################################################", + " CHANGELOG:", + "#########################################################################" + ], + "changeLogCaption": " CHANGELOG:", + "changeLogHeaderLineCount": 3, + "changeLogEntryTemplate": [ + " <>\t<>\t" + ] + } + ], + "psi-header.changes-tracking": { + "isActive": true, + "modAuthor": "Modified By:", + "modDate": "Last Modified:", + "modDateFormat": "date", + "exclude": ["json"], + "autoHeader": "off" + }, +} \ No newline at end of file diff --git a/3rdparty/PersWiFiManager/.gitignore b/3rdparty/PersWiFiManager/.gitignore deleted file mode 100644 index 1065d7c4..00000000 --- a/3rdparty/PersWiFiManager/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -PersWiFiManager.ino -data/* -!data/wifi* \ No newline at end of file diff --git a/3rdparty/PersWiFiManager/LICENSE b/3rdparty/PersWiFiManager/LICENSE deleted file mode 100644 index 8878ca7c..00000000 --- a/3rdparty/PersWiFiManager/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Ryan Downing - -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/3rdparty/PersWiFiManager/PersWiFiManager.cpp b/3rdparty/PersWiFiManager/PersWiFiManager.cpp deleted file mode 100644 index 4df3ed53..00000000 --- a/3rdparty/PersWiFiManager/PersWiFiManager.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* PersWiFiManager - version 3.0.1 - https://r-downing.github.io/PersWiFiManager/ -*/ - -#include "PersWiFiManager.h" - -#ifdef WIFI_HTM_PROGMEM -const char wifi_htm[] PROGMEM = R"=====(ESP WiFi








Back |Home
)====="; -#endif - -PersWiFiManager::PersWiFiManager(ESP8266WebServer& s, DNSServer& d) { - _server = &s; - _dnsServer = &d; - _apPass = ""; -} //PersWiFiManager - -bool PersWiFiManager::attemptConnection(const String& ssid, const String& pass) { - //attempt to connect to wifi - WiFi.mode(WIFI_STA); - if (ssid.length()) { - if (pass.length()) WiFi.begin(ssid.c_str(), pass.c_str()); - else WiFi.begin(ssid.c_str()); - } else { - WiFi.begin(); - } - - //if in nonblock mode, skip this loop - _connectStartTime = millis();// + 1; - while (!_connectNonBlock && _connectStartTime) { - handleWiFi(); - delay(10); - } - - return (WiFi.status() == WL_CONNECTED); - -} //attemptConnection - -void PersWiFiManager::handleWiFi() { - if (!_connectStartTime) return; - - if (WiFi.status() == WL_CONNECTED) { - _connectStartTime = 0; - if (_connectHandler) _connectHandler(); - return; - } - - //if failed or not connected and time is up - if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) { - startApMode(); - _connectStartTime = 0; //reset connect start time - } - -} //handleWiFi - -void PersWiFiManager::startApMode(){ - //start AP mode - IPAddress apIP(192, 168, 1, 1); - WiFi.mode(WIFI_AP); - WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); - _apPass.length() ? WiFi.softAP(getApSsid().c_str(), _apPass.c_str()) : WiFi.softAP(getApSsid().c_str()); - if (_apHandler) _apHandler(); -}//startApMode - -void PersWiFiManager::setConnectNonBlock(bool b) { - _connectNonBlock = b; -} //setConnectNonBlock - -void PersWiFiManager::setupWiFiHandlers() { - IPAddress apIP(192, 168, 1, 1); - _dnsServer->setErrorReplyCode(DNSReplyCode::NoError); - _dnsServer->start((byte)53, "*", apIP); //used for captive portal in AP mode - - _server->on("/wifi/list", [&] () { - //scan for wifi networks - int n = WiFi.scanNetworks(); - - //build array of indices - int ix[n]; - for (int i = 0; i < n; i++) ix[i] = i; - - //sort by signal strength - for (int i = 0; i < n; i++) for (int j = 1; j < n - i; j++) if (WiFi.RSSI(ix[j]) > WiFi.RSSI(ix[j - 1])) std::swap(ix[j], ix[j - 1]); - //remove duplicates - for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) if (WiFi.SSID(ix[i]).equals(WiFi.SSID(ix[j])) && WiFi.encryptionType(ix[i]) == WiFi.encryptionType(ix[j])) ix[j] = -1; - - //build plain text string of wifi info - //format [signal%]:[encrypted 0 or 1]:SSID - String s = ""; - s.reserve(2050); - for (int i = 0; i < n && s.length() < 2000; i++) { //check s.length to limit memory usage - if (ix[i] != -1) { - s += String(i ? "\n" : "") + ((constrain(WiFi.RSSI(ix[i]), -100, -50) + 100) * 2) + "," - + ((WiFi.encryptionType(ix[i]) == ENC_TYPE_NONE) ? 0 : 1) + "," + WiFi.SSID(ix[i]); - } - } - - //send string to client - _server->send(200, "text/plain", s); - }); //_server->on /wifi/list - - _server->on("/wifi/wps", [&]() { - _server->send(200, "text/html", "attempting WPS"); - WiFi.mode(WIFI_STA); - WiFi.beginWPSConfig(); - delay(100); - if (WiFi.status() != WL_CONNECTED) { - attemptConnection("", ""); - } - }); //_server->on /wifi/wps - - _server->on("/wifi/connect", [&]() { - _server->send(200, "text/html", "connecting..."); - attemptConnection(_server->arg("n"), _server->arg("p")); - }); //_server->on /wifi/connect - - _server->on("/wifi/ap", [&](){ - _server->send(200, "text/html", "access point: "+getApSsid()); - startApMode(); - }); //_server->on /wifi/ap - - _server->on("/wifi/rst", [&]() { - _server->send(200, "text/html", "Rebooting..."); - delay(100); - ESP.restart(); - }); - -#ifdef WIFI_HTM_PROGMEM - _server->on("/wifi.htm", [&]() { - _server->send(200, "text/html", wifi_htm); - }); -#endif - -}//setupWiFiHandlers - -bool PersWiFiManager::begin(const String& ssid, const String& pass) { - setupWiFiHandlers(); - return attemptConnection(ssid, pass); //switched order of these two for return -} //begin - -String PersWiFiManager::getApSsid() { - return _apSsid.length() ? _apSsid : "ESP8266"; -} //getApSsid - -void PersWiFiManager::setApCredentials(const String& apSsid, const String& apPass) { - if (apSsid.length()) _apSsid = apSsid; - if (apPass.length() >= 8) _apPass = apPass; -} //setApCredentials - -void PersWiFiManager::onConnect(WiFiChangeHandlerFunction fn) { - _connectHandler = fn; -} - -void PersWiFiManager::onAp(WiFiChangeHandlerFunction fn) { - _apHandler = fn; -} - - diff --git a/3rdparty/PersWiFiManager/PersWiFiManager.h b/3rdparty/PersWiFiManager/PersWiFiManager.h deleted file mode 100644 index 80fcf03b..00000000 --- a/3rdparty/PersWiFiManager/PersWiFiManager.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef PERSWIFIMANAGER_H -#define PERSWIFIMANAGER_H - -#include -#include -#include - -#define WIFI_CONNECT_TIMEOUT 30 - -class PersWiFiManager { - - public: - - typedef std::function WiFiChangeHandlerFunction; - - PersWiFiManager(ESP8266WebServer& s, DNSServer& d); - - bool attemptConnection(const String& ssid = "", const String& pass = ""); - - void setupWiFiHandlers(); - - bool begin(const String& ssid = "", const String& pass = ""); - - String getApSsid(); - - void setApCredentials(const String& apSsid, const String& apPass = ""); - - void setConnectNonBlock(bool b); - - void handleWiFi(); - - void startApMode(); - - void onConnect(WiFiChangeHandlerFunction fn); - - void onAp(WiFiChangeHandlerFunction fn); - - private: - ESP8266WebServer * _server; - DNSServer * _dnsServer; - String _apSsid, _apPass; - - bool _connectNonBlock; - unsigned long _connectStartTime; - - WiFiChangeHandlerFunction _connectHandler; - WiFiChangeHandlerFunction _apHandler; - -};//class - -#endif - diff --git a/3rdparty/PersWiFiManager/README.md b/3rdparty/PersWiFiManager/README.md deleted file mode 100644 index 8b1115f9..00000000 --- a/3rdparty/PersWiFiManager/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# PersWiFiManager -Persistent WiFiManager Arduino library for ESP8266-based microcontrollers - -This Persistent WiFi Manager provides a WiFi Settings web interface for ESP8266-based microcontrollers. It can autoconnect to the last used network, and then if unsuccessful, switch to AP mode with a captive DNS server. This action is non-blocking; the program will proceed to the main loop after, regardless of WiFi connection status. In AP mode, any device (phone, computer, etc) can connect to this network to configure the wifi connection, or access the device as a webserver. - -This library and UI was inspired by tzapu's [WiFiManager library](https://github.com/tzapu/WiFiManager). The main difference is that it allows the program to continue functioning normally, even in AP mode. It is also more memory efficient, as it does not have to dynamically build the page, and can serve it from SPIFFS rather than PROGMEM. - -[Full Documentation](http://ryandowning.net/PersWiFiManager) \ No newline at end of file diff --git a/3rdparty/PersWiFiManager/data/wifi.htm b/3rdparty/PersWiFiManager/data/wifi.htm deleted file mode 100644 index 5d083729..00000000 --- a/3rdparty/PersWiFiManager/data/wifi.htm +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - ESP WiFi - - - - - -
- -

-
- -
- -
-
- -
-
-
- -
- -
- -
- Back | - Home -
- - - diff --git a/3rdparty/PersWiFiManager/data/wifi.min.htm b/3rdparty/PersWiFiManager/data/wifi.min.htm deleted file mode 100644 index 49a4a55b..00000000 --- a/3rdparty/PersWiFiManager/data/wifi.min.htm +++ /dev/null @@ -1 +0,0 @@ -ESP WiFi









Back | Home
\ No newline at end of file diff --git a/3rdparty/PersWiFiManager/data/wifi.min.htm.gz b/3rdparty/PersWiFiManager/data/wifi.min.htm.gz deleted file mode 100644 index c8b0d2fb..00000000 Binary files a/3rdparty/PersWiFiManager/data/wifi.min.htm.gz and /dev/null differ diff --git a/3rdparty/PersWiFiManager/examples/basic_rest_api/basic_rest_api.ino b/3rdparty/PersWiFiManager/examples/basic_rest_api/basic_rest_api.ino deleted file mode 100644 index b2f22dc8..00000000 --- a/3rdparty/PersWiFiManager/examples/basic_rest_api/basic_rest_api.ino +++ /dev/null @@ -1,154 +0,0 @@ -#define DEBUG_SERIAL //uncomment for Serial debugging statements - -#ifdef DEBUG_SERIAL -#define DEBUG_BEGIN Serial.begin(115200) -#define DEBUG_PRINT(x) Serial.println(x) -#else -#define DEBUG_PRINT(x) -#define DEBUG_BEGIN -#endif - -//includes -#include -#include -#include -#include -#include -#include -#include - -#define DEVICE_NAME "ESP8266 DEVICE" - -//const char *metaRefreshStr = "redirecting..."; -const char *metaRefreshStr = "redirecting..."; - -//server objects -ESP8266WebServer server(80); -DNSServer dnsServer; -PersWiFiManager persWM(server, dnsServer); - -////// Sample program data -int x; -String y; - - -//code from fsbrowser example, consolidated. -bool handleFileRead(String path) { - DEBUG_PRINT("handlefileread" + path); - if (path.endsWith("/")) path += "index.htm"; - String contentType; - if (path.endsWith(".htm") || path.endsWith(".html")) contentType = "text/html"; - else if (path.endsWith(".css")) contentType = "text/css"; - else if (path.endsWith(".js")) contentType = "application/javascript"; - else if (path.endsWith(".png")) contentType = "image/png"; - else if (path.endsWith(".gif")) contentType = "image/gif"; - else if (path.endsWith(".jpg")) contentType = "image/jpeg"; - else if (path.endsWith(".ico")) contentType = "image/x-icon"; - else if (path.endsWith(".xml")) contentType = "text/xml"; - else if (path.endsWith(".pdf")) contentType = "application/x-pdf"; - else if (path.endsWith(".zip")) contentType = "application/x-zip"; - else if (path.endsWith(".gz")) contentType = "application/x-gzip"; - else if (path.endsWith(".json")) contentType = "application/json"; - else contentType = "text/plain"; - - //split filepath and extension - String prefix = path, ext = ""; - int lastPeriod = path.lastIndexOf('.'); - if (lastPeriod >= 0) { - prefix = path.substring(0, lastPeriod); - ext = path.substring(lastPeriod); - } - - //look for smaller versions of file - //minified file, good (myscript.min.js) - if (SPIFFS.exists(prefix + ".min" + ext)) path = prefix + ".min" + ext; - //gzipped file, better (myscript.js.gz) - if (SPIFFS.exists(prefix + ext + ".gz")) path = prefix + ext + ".gz"; - //min and gzipped file, best (myscript.min.js.gz) - if (SPIFFS.exists(prefix + ".min" + ext + ".gz")) path = prefix + ".min" + ext + ".gz"; - - if (SPIFFS.exists(path)) { - DEBUG_PRINT("sending file " + path); - File file = SPIFFS.open(path, "r"); - if (server.hasArg("download")) - server.sendHeader("Content-Disposition", " attachment;"); - if (server.uri().indexOf("nocache") < 0) - server.sendHeader("Cache-Control", " max-age=172800"); - - //optional alt arg (encoded url), server sends redirect to file on the web - if (WiFi.status() == WL_CONNECTED && server.hasArg("alt")) { - server.sendHeader("Location", server.arg("alt"), true); - server.send ( 302, "text/plain", ""); - } else { - //server sends file - size_t sent = server.streamFile(file, contentType); - } - file.close(); - return true; - } //if SPIFFS.exists - return false; -} //bool handleFileRead - -void setup() { - DEBUG_BEGIN; //for terminal debugging - DEBUG_PRINT(); - - //allows serving of files from SPIFFS - SPIFFS.begin(); - persWM.begin(); - - //serve files from SPIFFS - server.onNotFound([]() { - if (!handleFileRead(server.uri())) { - server.sendHeader("Cache-Control", " max-age=172800"); - server.send(302, "text/html", metaRefreshStr); - } - }); //server.onNotFound - - //handles commands from webpage, sends live data in JSON format - server.on("/api", []() { - DEBUG_PRINT("server.on /api"); - if (server.hasArg("x")) { - x = server.arg("x").toInt(); - DEBUG_PRINT(String("x: ")+x); - } //if - if (server.hasArg("y")) { - y = server.arg("y"); - DEBUG_PRINT("y: "+y); - } //if - - //build json object of program data - StaticJsonBuffer<200> jsonBuffer; - JsonObject &json = jsonBuffer.createObject(); - json["x"] = x; - json["y"] = y; - - char jsonchar[200]; - json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece - server.send(200, "application/json", jsonchar); - - }); //server.on api - - - //SSDP makes device visible on windows network - server.on("/description.xml", HTTP_GET, []() { - SSDP.schema(server.client()); - }); - SSDP.setSchemaURL("description.xml"); - SSDP.setHTTPPort(80); - SSDP.setName(DEVICE_NAME); - SSDP.setURL("/"); - SSDP.begin(); - SSDP.setDeviceType("upnp:rootdevice"); - - server.begin(); - DEBUG_PRINT("setup complete."); -} //void setup - -void loop() { - dnsServer.processNextRequest(); - server.handleClient(); - - // do stuff with x and y - -} //void loop diff --git a/3rdparty/PersWiFiManager/examples/basic_rest_api/data/index.htm b/3rdparty/PersWiFiManager/examples/basic_rest_api/data/index.htm deleted file mode 100644 index c6f2be1f..00000000 --- a/3rdparty/PersWiFiManager/examples/basic_rest_api/data/index.htm +++ /dev/null @@ -1,52 +0,0 @@ -

Current Data

-x: - -
y: - - -
Last updated - seconds ago. - -
- -

Update Data

-
- x: - - -
-
- y: - - -
- -WiFi settings - - diff --git a/3rdparty/PersWiFiManager/examples/basic_rest_api/data/wifi.min.htm.gz b/3rdparty/PersWiFiManager/examples/basic_rest_api/data/wifi.min.htm.gz deleted file mode 100644 index c8b0d2fb..00000000 Binary files a/3rdparty/PersWiFiManager/examples/basic_rest_api/data/wifi.min.htm.gz and /dev/null differ diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/index.htm b/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/index.htm deleted file mode 100644 index c6f2be1f..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/index.htm +++ /dev/null @@ -1,52 +0,0 @@ -

Current Data

-x: - -
y: - - -
Last updated - seconds ago. - -
- -

Update Data

-
- x: - - -
-
- y: - - -
- -WiFi settings - - diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/wifi.min.htm.gz b/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/wifi.min.htm.gz deleted file mode 100644 index c8b0d2fb..00000000 Binary files a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/data/wifi.min.htm.gz and /dev/null differ diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/spiffs_rest_api.ino b/3rdparty/PersWiFiManager/examples/spiffs_rest_api/spiffs_rest_api.ino deleted file mode 100644 index 3f26aad9..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api/spiffs_rest_api.ino +++ /dev/null @@ -1,94 +0,0 @@ -#define DEBUG_SERIAL //uncomment for Serial debugging statements - -#ifdef DEBUG_SERIAL -#define DEBUG_BEGIN Serial.begin(115200) -#define DEBUG_PRINT(x) Serial.println(x) -#else -#define DEBUG_PRINT(x) -#define DEBUG_BEGIN -#endif - -//includes -#include -#include -#include -#include - -//extension of ESP8266WebServer with SPIFFS handlers built in -#include // https://github.com/r-downing/SPIFFSReadServer -// upload data folder to chip with Arduino ESP8266 filesystem uploader -// https://github.com/esp8266/arduino-esp8266fs-plugin - -#include -#include - -#define DEVICE_NAME "ESP8266 DEVICE" - - -//server objects -SPIFFSReadServer server(80); -DNSServer dnsServer; -PersWiFiManager persWM(server, dnsServer); - -////// Sample program data -int x; -String y; - -void setup() { - DEBUG_BEGIN; //for terminal debugging - DEBUG_PRINT(); - - //allows serving of files from SPIFFS - SPIFFS.begin(); - //sets network name for AP mode - persWM.setApCredentials(DEVICE_NAME); - //persWM.setApCredentials(DEVICE_NAME, "password"); optional password - persWM.begin(); - - //handles commands from webpage, sends live data in JSON format - server.on("/api", []() { - DEBUG_PRINT("server.on /api"); - if (server.hasArg("x")) { - x = server.arg("x").toInt(); - DEBUG_PRINT(String("x: ")+x); - } //if - if (server.hasArg("y")) { - y = server.arg("y"); - DEBUG_PRINT("y: "+y); - } //if - - //build json object of program data - StaticJsonBuffer<200> jsonBuffer; - JsonObject &json = jsonBuffer.createObject(); - json["x"] = x; - json["y"] = y; - - char jsonchar[200]; - json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece - server.send(200, "application/json", jsonchar); - - }); //server.on api - - - //SSDP makes device visible on windows network - server.on("/description.xml", HTTP_GET, []() { - SSDP.schema(server.client()); - }); - SSDP.setSchemaURL("description.xml"); - SSDP.setHTTPPort(80); - SSDP.setName(DEVICE_NAME); - SSDP.setURL("/"); - SSDP.begin(); - SSDP.setDeviceType("upnp:rootdevice"); - - server.begin(); - DEBUG_PRINT("setup complete."); -} //void setup - -void loop() { - dnsServer.processNextRequest(); - server.handleClient(); - - // do stuff with x and y - -} //void loop diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/index.htm b/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/index.htm deleted file mode 100644 index c6f2be1f..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/index.htm +++ /dev/null @@ -1,52 +0,0 @@ -

Current Data

-x: - -
y: - - -
Last updated - seconds ago. - -
- -

Update Data

-
- x: - - -
-
- y: - - -
- -WiFi settings - - diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.htm b/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.htm deleted file mode 100644 index 5d083729..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.htm +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - ESP WiFi - - - - - -
- -

-
- -
- -
-
- -
-
-
- -
- -
- -
- Back | - Home -
- - - diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm b/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm deleted file mode 100644 index 49a4a55b..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm +++ /dev/null @@ -1 +0,0 @@ -ESP WiFi









Back | Home
\ No newline at end of file diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm.gz b/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm.gz deleted file mode 100644 index c8b0d2fb..00000000 Binary files a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/data/wifi.min.htm.gz and /dev/null differ diff --git a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/spiffs_rest_api_nonblocking.ino b/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/spiffs_rest_api_nonblocking.ino deleted file mode 100644 index bab08e5d..00000000 --- a/3rdparty/PersWiFiManager/examples/spiffs_rest_api_nonblocking/spiffs_rest_api_nonblocking.ino +++ /dev/null @@ -1,111 +0,0 @@ -/* -SPIFFS-served REST API example for PersWiFiManager v3.0 -*/ - -#define DEBUG_SERIAL //uncomment for Serial debugging statements - -#ifdef DEBUG_SERIAL -#define DEBUG_BEGIN Serial.begin(115200) -#define DEBUG_PRINT(x) Serial.println(x) -#else -#define DEBUG_PRINT(x) -#define DEBUG_BEGIN -#endif - -//includes -#include -#include -#include - -#include // http://ryandowning.net/EasySSDP/ - -//extension of ESP8266WebServer with SPIFFS handlers built in -#include // http://ryandowning.net/SPIFFSReadServer/ -// upload data folder to chip with Arduino ESP8266 filesystem uploader -// https://github.com/esp8266/arduino-esp8266fs-plugin - -#include -#include - -#define DEVICE_NAME "ESP8266 DEVICE" - - -//server objects -SPIFFSReadServer server(80); -DNSServer dnsServer; -PersWiFiManager persWM(server, dnsServer); - -////// Sample program data -int x; -String y; - -void setup() { - DEBUG_BEGIN; //for terminal debugging - DEBUG_PRINT(); - - //optional code handlers to run everytime wifi is connected... - persWM.onConnect([]() { - DEBUG_PRINT("wifi connected"); - DEBUG_PRINT(WiFi.localIP()); - EasySSDP::begin(server); - }); - //...or AP mode is started - persWM.onAp([](){ - DEBUG_PRINT("AP MODE"); - DEBUG_PRINT(persWM.getApSsid()); - }); - - //allows serving of files from SPIFFS - SPIFFS.begin(); - //sets network name for AP mode - persWM.setApCredentials(DEVICE_NAME); - //persWM.setApCredentials(DEVICE_NAME, "password"); optional password - - //make connecting/disconnecting non-blocking - persWM.setConnectNonBlock(true); - - //in non-blocking mode, program will continue past this point without waiting - persWM.begin(); - - //handles commands from webpage, sends live data in JSON format - server.on("/api", []() { - DEBUG_PRINT("server.on /api"); - if (server.hasArg("x")) { - x = server.arg("x").toInt(); - DEBUG_PRINT(String("x: ") + x); - } //if - if (server.hasArg("y")) { - y = server.arg("y"); - DEBUG_PRINT("y: " + y); - } //if - - //build json object of program data - StaticJsonBuffer<200> jsonBuffer; - JsonObject &json = jsonBuffer.createObject(); - json["x"] = x; - json["y"] = y; - - char jsonchar[200]; - json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece - server.send(200, "application/json", jsonchar); - - }); //server.on api - - - server.begin(); - DEBUG_PRINT("setup complete."); -} //void setup - -void loop() { - //in non-blocking mode, handleWiFi must be called in the main loop - persWM.handleWiFi(); - - dnsServer.processNextRequest(); - server.handleClient(); - - //DEBUG_PRINT(millis()); - - // do stuff with x and y - -} //void loop - diff --git a/3rdparty/PersWiFiManager/keywords.txt b/3rdparty/PersWiFiManager/keywords.txt deleted file mode 100644 index 01e0d404..00000000 --- a/3rdparty/PersWiFiManager/keywords.txt +++ /dev/null @@ -1,28 +0,0 @@ -####################################### -# Syntax Coloring Map For PersWiFiManager Library -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -PersWiFiManager KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -attemptConnection KEYWORD2 -setupWiFiHandlers KEYWORD2 -begin KEYWORD2 -getApSsid KEYWORD2 -setApCredentials KEYWORD2 -handleWiFi KEYWORD2 -setConnectNonBlock KEYWORD2 -startApMode KEYWORD2 -onConnect KEYWORD2 -onAp KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### diff --git a/3rdparty/PersWiFiManager/library.properties b/3rdparty/PersWiFiManager/library.properties deleted file mode 100644 index 03ad2842..00000000 --- a/3rdparty/PersWiFiManager/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=PersWiFiManager -version=3.0.1 -author=Ryan Downing -maintainer=Ryan Downing -sentence=Persistent WiFi Manager -paragraph=A non-blocking, persistant wifi manager for ESP8266 that allows network changes at any time -category=Communication -url=http://ryandowning.net/PersWiFiManager/ -architectures=esp8266 diff --git a/3rdparty/WebSockets/LICENSE b/3rdparty/WebSockets/LICENSE deleted file mode 100644 index f166cc57..00000000 --- a/3rdparty/WebSockets/LICENSE +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! \ No newline at end of file diff --git a/3rdparty/WebSockets/README.md b/3rdparty/WebSockets/README.md deleted file mode 100644 index 63eef3e2..00000000 --- a/3rdparty/WebSockets/README.md +++ /dev/null @@ -1,98 +0,0 @@ -WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.org/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.org/Links2004/arduinoWebSockets) -=========================================== - -a WebSocket Server and Client for Arduino based on RFC6455. - - -##### Supported features of RFC6455 ##### - - text frame - - binary frame - - connection close - - ping - - pong - - continuation frame - -##### Limitations ##### - - max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define - - max output length has no limit (the hardware is the limit) - - Client send big frames with mask 0x00000000 (on AVR all frames) - - continuation frame reassembly need to be handled in the application code - - ##### Limitations for Async ##### - - Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround. - - wss / SSL is not possible. - -##### Supported Hardware ##### - - ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/) - - ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32) - - ESP31B - - Particle with STM32 ARM Cortex M3 - - ATmega328 with Ethernet Shield (ATmega branch) - - ATmega328 with enc28j60 (ATmega branch) - - ATmega2560 with Ethernet Shield (ATmega branch) - - ATmega2560 with enc28j60 (ATmega branch) - -###### Note: ###### - - version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch. - - Arduino for AVR not supports std namespace of c++. - -### wss / SSL ### - supported for: - - wss client on the ESP8266 - - wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets - by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a - sample Nginx server configuration file to enable this. - -### ESP Async TCP ### - -This libary can run in Async TCP mode on the ESP. - -The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define). - -[ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required. - - -### High Level Client API ### - - - `begin` : Initiate connection sequence to the websocket host. -``` -void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); -void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); - ``` - - `onEvent`: Callback to handle for websocket events - - ``` - void onEvent(WebSocketClientEvent cbEvent); - ``` - - - `WebSocketClientEvent`: Handler for websocket events - ``` - void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length) - ``` -Where `WStype_t type` is defined as: - ``` - typedef enum { - WStype_ERROR, - WStype_DISCONNECTED, - WStype_CONNECTED, - WStype_TEXT, - WStype_BIN, - WStype_FRAGMENT_TEXT_START, - WStype_FRAGMENT_BIN_START, - WStype_FRAGMENT, - WStype_FRAGMENT_FIN, - } WStype_t; - ``` - -### Issues ### -Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues - -[![Join the chat at https://gitter.im/Links2004/arduinoWebSockets](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Links2004/arduinoWebSockets?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -### License and credits ### - -The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE) - -[libb64](http://libb64.sourceforge.net/) written by Chris Venter. It is distributed under Public Domain see [LICENSE](https://github.com/Links2004/arduinoWebSockets/blob/master/src/libb64/LICENSE). diff --git a/3rdparty/WebSockets/examples/Nginx/esp8266.ssl.reverse.proxy.conf b/3rdparty/WebSockets/examples/Nginx/esp8266.ssl.reverse.proxy.conf deleted file mode 100644 index ec5aa89f..00000000 --- a/3rdparty/WebSockets/examples/Nginx/esp8266.ssl.reverse.proxy.conf +++ /dev/null @@ -1,83 +0,0 @@ -# ESP8266 nginx SSL reverse proxy configuration file (tested and working on nginx v1.10.0) - -# proxy cache location -proxy_cache_path /opt/etc/nginx/cache levels=1:2 keys_zone=ESP8266_cache:10m max_size=10g inactive=5m use_temp_path=off; - -# webserver proxy -server { - - # general server parameters - listen 50080; - server_name myDomain.net; - access_log /opt/var/log/nginx/myDomain.net.access.log; - - # SSL configuration - ssl on; - ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem; - ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem; - ssl_session_cache builtin:1000 shared:SSL:10m; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; - ssl_prefer_server_ciphers on; - - location / { - - # proxy caching configuration - proxy_cache ESP8266_cache; - proxy_cache_revalidate on; - proxy_cache_min_uses 1; - proxy_cache_use_stale off; - proxy_cache_lock on; - # proxy_cache_bypass $http_cache_control; - # include the sessionId cookie value as part of the cache key - keeps the cache per user - # proxy_cache_key $proxy_host$request_uri$cookie_sessionId; - - # header pass through configuration - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # ESP8266 custom headers which identify to the device that it's running through an SSL proxy - proxy_set_header X-SSL On; - proxy_set_header X-SSL-WebserverPort 50080; - proxy_set_header X-SSL-WebsocketPort 50081; - - # extra debug headers - add_header X-Proxy-Cache $upstream_cache_status; - add_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # actual proxying configuration - proxy_ssl_session_reuse on; - # target the IP address of the device with proxy_pass - proxy_pass http://192.168.0.20; - proxy_read_timeout 90; - } - } - -# websocket proxy -server { - - # general server parameters - listen 50081; - server_name myDomain.net; - access_log /opt/var/log/nginx/myDomain.net.wss.access.log; - - # SSL configuration - ssl on; - ssl_certificate /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/fullchain.pem; - ssl_certificate_key /usr/builtin/etc/certificate/lets-encrypt/myDomain.net/privkey.pem; - ssl_session_cache builtin:1000 shared:SSL:10m; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; - ssl_prefer_server_ciphers on; - - location / { - - # websocket upgrade tunnel configuration - proxy_pass http://192.168.0.20:81; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_read_timeout 86400; - } - } diff --git a/3rdparty/WebSockets/examples/avr/WebSocketClientAVR/WebSocketClientAVR.ino b/3rdparty/WebSockets/examples/avr/WebSocketClientAVR/WebSocketClientAVR.ino deleted file mode 100644 index 9d49d149..00000000 --- a/3rdparty/WebSockets/examples/avr/WebSocketClientAVR/WebSocketClientAVR.ino +++ /dev/null @@ -1,84 +0,0 @@ -/* - * WebSocketClientAVR.ino - * - * Created on: 10.12.2015 - * - */ - -#include - -#include -#include - -#include - - - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; - -// Set the static IP address to use if the DHCP fails to assign -IPAddress ip(192, 168, 0, 177); - -WebSocketsClient webSocket; - - - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - - switch(type) { - case WStype_DISCONNECTED: - Serial.println("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - { - Serial.print("[WSc] Connected to url: "); - Serial.println((char *)payload); - // send message to server when Connected - webSocket.sendTXT("Connected"); - } - break; - case WStype_TEXT: - Serial.print("[WSc] get text: "); - Serial.println((char *)payload); - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: - Serial.print("[WSc] get binary length: "); - Serial.println(length); - // hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - } - -} - -void setup() -{ - // Open serial communications and wait for port to open: - Serial.begin(115200); - while (!Serial) {} - - // start the Ethernet connection: - if (Ethernet.begin(mac) == 0) { - Serial.println("Failed to configure Ethernet using DHCP"); - // no point in carrying on, so do nothing forevermore: - // try to congifure using IP address instead of DHCP: - Ethernet.begin(mac, ip); - } - - webSocket.begin("192.168.0.123", 8011); - webSocket.onEvent(webSocketEvent); - -} - - -void loop() -{ - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp32/WebSocketClient/WebSocketClient.ino b/3rdparty/WebSockets/examples/esp32/WebSocketClient/WebSocketClient.ino deleted file mode 100644 index 5e5ead46..00000000 --- a/3rdparty/WebSockets/examples/esp32/WebSocketClient/WebSocketClient.ino +++ /dev/null @@ -1,110 +0,0 @@ -/* - * WebSocketClient.ino - * - * Created on: 24.05.2015 - * - */ - -#include - -#include -#include -#include - -#include - - -WiFiMulti WiFiMulti; -WebSocketsClient webSocket; - -#define USE_SERIAL Serial1 - -void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { - const uint8_t* src = (const uint8_t*) mem; - USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); - for(uint32_t i = 0; i < len; i++) { - if(i % cols == 0) { - USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); - } - USE_SERIAL.printf("%02X ", *src); - src++; - } - USE_SERIAL.printf("\n"); -} - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - - // send message to server when Connected - webSocket.sendTXT("Connected"); - break; - case WStype_TEXT: - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - case WStype_ERROR: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: - case WStype_FRAGMENT_FIN: - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - // server address, port and URL - webSocket.begin("192.168.0.123", 81, "/"); - - // event handler - webSocket.onEvent(webSocketEvent); - - // use HTTP Basic Authorization this is optional remove if not needed - webSocket.setAuthorization("user", "Password"); - - // try ever 5000 again if connection has failed - webSocket.setReconnectInterval(5000); - -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp32/WebSocketClientSSL/WebSocketClientSSL.ino b/3rdparty/WebSockets/examples/esp32/WebSocketClientSSL/WebSocketClientSSL.ino deleted file mode 100644 index 9d722427..00000000 --- a/3rdparty/WebSockets/examples/esp32/WebSocketClientSSL/WebSocketClientSSL.ino +++ /dev/null @@ -1,106 +0,0 @@ -/* - * WebSocketClientSSL.ino - * - * Created on: 10.12.2015 - * - * note SSL is only possible with the ESP8266 - * - */ - -#include - -#include -#include -#include - -#include - - -WiFiMulti WiFiMulti; -WebSocketsClient webSocket; - -#define USE_SERIAL Serial1 - -void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { - const uint8_t* src = (const uint8_t*) mem; - USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); - for(uint32_t i = 0; i < len; i++) { - if(i % cols == 0) { - USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); - } - USE_SERIAL.printf("%02X ", *src); - src++; - } - USE_SERIAL.printf("\n"); -} - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - { - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - - // send message to server when Connected - webSocket.sendTXT("Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - case WStype_ERROR: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: - case WStype_FRAGMENT_FIN: - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - webSocket.beginSSL("192.168.0.123", 81); - webSocket.onEvent(webSocketEvent); - -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp32/WebSocketServer/WebSocketServer.ino b/3rdparty/WebSockets/examples/esp32/WebSocketServer/WebSocketServer.ino deleted file mode 100644 index 3e0d4f5b..00000000 --- a/3rdparty/WebSockets/examples/esp32/WebSocketServer/WebSocketServer.ino +++ /dev/null @@ -1,104 +0,0 @@ -/* - * WebSocketServer.ino - * - * Created on: 22.05.2015 - * - */ - -#include - -#include -#include -#include - -#include - -WiFiMulti WiFiMulti; -WebSocketsServer webSocket = WebSocketsServer(81); - -#define USE_SERIAL Serial1 - -void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { - const uint8_t* src = (const uint8_t*) mem; - USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); - for(uint32_t i = 0; i < len; i++) { - if(i % cols == 0) { - USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); - } - USE_SERIAL.printf("%02X ", *src); - src++; - } - USE_SERIAL.printf("\n"); -} - -void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[%u] Disconnected!\n", num); - break; - case WStype_CONNECTED: - { - IPAddress ip = webSocket.remoteIP(num); - USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); - - // send message to client - webSocket.sendTXT(num, "Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); - - // send message to client - // webSocket.sendTXT(num, "message here"); - - // send data to all connected clients - // webSocket.broadcastTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); - hexdump(payload, length); - - // send message to client - // webSocket.sendBIN(num, payload, length); - break; - case WStype_ERROR: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: - case WStype_FRAGMENT_FIN: - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - webSocket.begin(); - webSocket.onEvent(webSocketEvent); -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketClient/WebSocketClient.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketClient/WebSocketClient.ino deleted file mode 100644 index 5ee489cd..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketClient/WebSocketClient.ino +++ /dev/null @@ -1,106 +0,0 @@ -/* - * WebSocketClient.ino - * - * Created on: 24.05.2015 - * - */ - -#include - -#include -#include - -#include - -#include - -ESP8266WiFiMulti WiFiMulti; -WebSocketsClient webSocket; - -#define USE_SERIAL Serial1 - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: { - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - - // send message to server when Connected - webSocket.sendTXT("Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - case WStype_PING: - // pong will be send automatically - USE_SERIAL.printf("[WSc] get ping\n"); - break; - case WStype_PONG: - // answer to a ping we send - USE_SERIAL.printf("[WSc] get pong\n"); - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - // server address, port and URL - webSocket.begin("192.168.0.123", 81, "/"); - - // event handler - webSocket.onEvent(webSocketEvent); - - // use HTTP Basic Authorization this is optional remove if not needed - webSocket.setAuthorization("user", "Password"); - - // try ever 5000 again if connection has failed - webSocket.setReconnectInterval(5000); - - // start heartbeat (optional) - // ping server every 15000 ms - // expect pong from server within 3000 ms - // consider connection disconnected if pong is not received 2 times - webSocket.enableHeartbeat(15000, 3000, 2); - -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketClientSSL/WebSocketClientSSL.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketClientSSL/WebSocketClientSSL.ino deleted file mode 100644 index d45060e9..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketClientSSL/WebSocketClientSSL.ino +++ /dev/null @@ -1,88 +0,0 @@ -/* - * WebSocketClientSSL.ino - * - * Created on: 10.12.2015 - * - * note SSL is only possible with the ESP8266 - * - */ - -#include - -#include -#include - -#include - -#include - -ESP8266WiFiMulti WiFiMulti; -WebSocketsClient webSocket; - - -#define USE_SERIAL Serial1 - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - { - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - - // send message to server when Connected - webSocket.sendTXT("Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - webSocket.beginSSL("192.168.0.123", 81); - webSocket.onEvent(webSocketEvent); - -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketClientSocketIO/WebSocketClientSocketIO.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketClientSocketIO/WebSocketClientSocketIO.ino deleted file mode 100644 index a952e5de..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketClientSocketIO/WebSocketClientSocketIO.ino +++ /dev/null @@ -1,125 +0,0 @@ -/* - * WebSocketClientSocketIO.ino - * - * Created on: 06.06.2016 - * - */ - -#include - -#include -#include - -#include - -#include -#include - -#include - -ESP8266WiFiMulti WiFiMulti; -SocketIOclient socketIO; - -#define USE_SERIAL Serial1 - -void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { - switch(type) { - case sIOtype_DISCONNECT: - USE_SERIAL.printf("[IOc] Disconnected!\n"); - break; - case sIOtype_CONNECT: - USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload); - break; - case sIOtype_EVENT: - USE_SERIAL.printf("[IOc] get event: %s\n", payload); - break; - case sIOtype_ACK: - USE_SERIAL.printf("[IOc] get ack: %u\n", length); - hexdump(payload, length); - break; - case sIOtype_ERROR: - USE_SERIAL.printf("[IOc] get error: %u\n", length); - hexdump(payload, length); - break; - case sIOtype_BINARY_EVENT: - USE_SERIAL.printf("[IOc] get binary: %u\n", length); - hexdump(payload, length); - break; - case sIOtype_BINARY_ACK: - USE_SERIAL.printf("[IOc] get binary ack: %u\n", length); - hexdump(payload, length); - break; - } -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - // disable AP - if(WiFi.getMode() & WIFI_AP) { - WiFi.softAPdisconnect(true); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - //WiFi.disconnect(); - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - String ip = WiFi.localIP().toString(); - USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str()); - - // server address, port and URL - socketIO.begin("10.11.100.100", 8880); - - // event handler - socketIO.onEvent(socketIOEvent); -} - -unsigned long messageTimestamp = 0; -void loop() { - socketIO.loop(); - - uint64_t now = millis(); - - if(now - messageTimestamp > 2000) { - messageTimestamp = now; - - // creat JSON message for Socket.IO (event) - DynamicJsonDocument doc(1024); - JsonArray array = doc.to(); - - // add evnet name - // Hint: socket.on('event_name', .... - array.add("event_name"); - - // add payload (parameters) for the event - JsonObject param1 = array.createNestedObject(); - param1["now"] = now; - - // JSON to String (serializion) - String output; - serializeJson(doc, output); - - // Send event - socketIO.sendEVENT(output); - - // Print JSON for debugging - USE_SERIAL.println(output); - } -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino deleted file mode 100644 index a0eb011f..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketClientStomp/WebSocketClientStomp.ino +++ /dev/null @@ -1,149 +0,0 @@ -/* - WebSocketClientStomp.ino - - Example for connecting and maintining a connection with a STOMP websocket connection. - In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html). - - Created on: 25.09.2017 - Author: Martin Becker , Contact: becker@informatik.uni-wuerzburg.de -*/ - -// PRE - -#define USE_SERIAL Serial - - -// LIBRARIES - -#include -#include - -#include -#include - - -// SETTINGS - -const char* wlan_ssid = "yourssid"; -const char* wlan_password = "somepassword"; - -const char* ws_host = "the.host.net"; -const int ws_port = 80; - -// URL for STOMP endpoint. -// For the default config of Spring's STOMP support, the default URL is "/socketentry/websocket". -const char* stompUrl = "/socketentry/websocket"; // don't forget the leading "/" !!! - - -// VARIABLES - -WebSocketsClient webSocket; - - -// FUNCTIONS - -/** - * STOMP messages need to be NULL-terminated (i.e., \0 or \u0000). - * However, when we send a String or a char[] array without specifying - * a length, the size of the message payload is derived by strlen() internally, - * thus dropping any NULL values appended to the "msg"-String. - * - * To solve this, we first convert the String to a NULL terminated char[] array - * via "c_str" and set the length of the payload to include the NULL value. - */ -void sendMessage(String & msg) { - webSocket.sendTXT(msg.c_str(), msg.length() + 1); -} - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - switch (type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - { - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - - String msg = "CONNECT\r\naccept-version:1.1,1.0\r\nheart-beat:10000,10000\r\n\r\n"; - sendMessage(msg); - } - break; - case WStype_TEXT: - { - // ##################### - // handle STOMP protocol - // ##################### - - String text = (char*) payload; - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - if (text.startsWith("CONNECTED")) { - - // subscribe to some channels - - String msg = "SUBSCRIBE\nid:sub-0\ndestination:/user/queue/messages\n\n"; - sendMessage(msg); - delay(1000); - - // and send a message - - msg = "SEND\ndestination:/app/message\n\n{\"user\":\"esp\",\"message\":\"Hello!\"}"; - sendMessage(msg); - delay(1000); - - } else { - - // do something with messages - - } - - break; - } - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - } - -} - -void setup() { - - // setup serial - - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - // USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - - - // connect to WiFi - - USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ..."); - WiFi.mode(WIFI_STA); - WiFi.begin(wlan_ssid, wlan_password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - USE_SERIAL.print("."); - } - USE_SERIAL.println(" success."); - USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP()); - - - // connect to websocket - webSocket.begin(ws_host, ws_port, stompUrl); - webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config - // webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny - webSocket.onEvent(webSocketEvent); -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketClientStompOverSockJs/WebSocketClientStompOverSockJs.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketClientStompOverSockJs/WebSocketClientStompOverSockJs.ino deleted file mode 100644 index cb0c45be..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketClientStompOverSockJs/WebSocketClientStompOverSockJs.ino +++ /dev/null @@ -1,150 +0,0 @@ -/* - WebSocketClientStompOverSockJs.ino - - Example for connecting and maintining a connection with a SockJS+STOMP websocket connection. - In this example, we connect to a Spring application (see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html). - - Created on: 18.07.2017 - Author: Martin Becker , Contact: becker@informatik.uni-wuerzburg.de -*/ - -// PRE - -#define USE_SERIAL Serial - - -// LIBRARIES - -#include -#include - -#include -#include - - -// SETTINGS - -const char* wlan_ssid = "yourssid"; -const char* wlan_password = "somepassword"; - -const char* ws_host = "the.host.net"; -const int ws_port = 80; - -// base URL for SockJS (websocket) connection -// The complete URL will look something like this(cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36): -// ws://://<3digits>//websocket -// For the default config of Spring's SockJS/STOMP support, the default base URL is "/socketentry/". -const char* ws_baseurl = "/socketentry/"; // don't forget leading and trailing "/" !!! - - -// VARIABLES - -WebSocketsClient webSocket; - - -// FUNCTIONS - -void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { - - switch (type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: - { - USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); - } - break; - case WStype_TEXT: - { - // ##################### - // handle SockJs+STOMP protocol - // ##################### - - String text = (char*) payload; - - USE_SERIAL.printf("[WSc] get text: %s\n", payload); - - if (payload[0] == 'h') { - - USE_SERIAL.println("Heartbeat!"); - - } else if (payload[0] == 'o') { - - // on open connection - char *msg = "[\"CONNECT\\naccept-version:1.1,1.0\\nheart-beat:10000,10000\\n\\n\\u0000\"]"; - webSocket.sendTXT(msg); - - } else if (text.startsWith("a[\"CONNECTED")) { - - // subscribe to some channels - - char *msg = "[\"SUBSCRIBE\\nid:sub-0\\ndestination:/user/queue/messages\\n\\n\\u0000\"]"; - webSocket.sendTXT(msg); - delay(1000); - - // and send a message - - msg = "[\"SEND\\ndestination:/app/message\\n\\n{\\\"user\\\":\\\"esp\\\",\\\"message\\\":\\\"Hello!\\\"}\\u0000\"]"; - webSocket.sendTXT(msg); - delay(1000); - } - - break; - } - case WStype_BIN: - USE_SERIAL.printf("[WSc] get binary length: %u\n", length); - hexdump(payload, length); - - // send data to server - // webSocket.sendBIN(payload, length); - break; - } - -} - -void setup() { - - // setup serial - - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - // USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - - - // connect to WiFi - - USE_SERIAL.print("Logging into WLAN: "); Serial.print(wlan_ssid); Serial.print(" ..."); - WiFi.mode(WIFI_STA); - WiFi.begin(wlan_ssid, wlan_password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - USE_SERIAL.print("."); - } - USE_SERIAL.println(" success."); - USE_SERIAL.print("IP: "); USE_SERIAL.println(WiFi.localIP()); - - - // ##################### - // create socket url according to SockJS protocol (cf. http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-36) - // ##################### - String socketUrl = ws_baseurl; - socketUrl += random(0, 999); - socketUrl += "/"; - socketUrl += random(0, 999999); // should be a random string, but this works (see ) - socketUrl += "/websocket"; - - // connect to websocket - webSocket.begin(ws_host, ws_port, socketUrl); - webSocket.setExtraHeaders(); // remove "Origin: file://" header because it breaks the connection with Spring's default websocket config - // webSocket.setExtraHeaders("foo: I am so funny\r\nbar: not"); // some headers, in case you feel funny - webSocket.onEvent(webSocketEvent); -} - -void loop() { - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketServer/WebSocketServer.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketServer/WebSocketServer.ino deleted file mode 100644 index 1ac3002d..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketServer/WebSocketServer.ino +++ /dev/null @@ -1,86 +0,0 @@ -/* - * WebSocketServer.ino - * - * Created on: 22.05.2015 - * - */ - -#include - -#include -#include -#include -#include - -ESP8266WiFiMulti WiFiMulti; - -WebSocketsServer webSocket = WebSocketsServer(81); - -#define USE_SERIAL Serial1 - -void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[%u] Disconnected!\n", num); - break; - case WStype_CONNECTED: - { - IPAddress ip = webSocket.remoteIP(num); - USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); - - // send message to client - webSocket.sendTXT(num, "Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); - - // send message to client - // webSocket.sendTXT(num, "message here"); - - // send data to all connected clients - // webSocket.broadcastTXT("message here"); - break; - case WStype_BIN: - USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); - hexdump(payload, length); - - // send message to client - // webSocket.sendBIN(num, payload, length); - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - webSocket.begin(); - webSocket.onEvent(webSocketEvent); -} - -void loop() { - webSocket.loop(); -} - diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketServerAllFunctionsDemo/WebSocketServerAllFunctionsDemo.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketServerAllFunctionsDemo/WebSocketServerAllFunctionsDemo.ino deleted file mode 100644 index 5fed1a95..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketServerAllFunctionsDemo/WebSocketServerAllFunctionsDemo.ino +++ /dev/null @@ -1,132 +0,0 @@ -/* - * WebSocketServerAllFunctionsDemo.ino - * - * Created on: 10.05.2018 - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#define LED_RED 15 -#define LED_GREEN 12 -#define LED_BLUE 13 - -#define USE_SERIAL Serial - -ESP8266WiFiMulti WiFiMulti; - -ESP8266WebServer server(80); -WebSocketsServer webSocket = WebSocketsServer(81); - -void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[%u] Disconnected!\n", num); - break; - case WStype_CONNECTED: { - IPAddress ip = webSocket.remoteIP(num); - USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); - - // send message to client - webSocket.sendTXT(num, "Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); - - if(payload[0] == '#') { - // we get RGB data - - // decode rgb data - uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); - - analogWrite(LED_RED, ((rgb >> 16) & 0xFF)); - analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF)); - analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF)); - } - - break; - } - -} - -void setup() { - //USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - pinMode(LED_RED, OUTPUT); - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_BLUE, OUTPUT); - - digitalWrite(LED_RED, 1); - digitalWrite(LED_GREEN, 1); - digitalWrite(LED_BLUE, 1); - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - // start webSocket server - webSocket.begin(); - webSocket.onEvent(webSocketEvent); - - if(MDNS.begin("esp8266")) { - USE_SERIAL.println("MDNS responder started"); - } - - // handle index - server.on("/", []() { - // send index.html - server.send(200, "text/html", "LED Control:

R:
G:
B:
"); - }); - - server.begin(); - - // Add service to MDNS - MDNS.addService("http", "tcp", 80); - MDNS.addService("ws", "tcp", 81); - - digitalWrite(LED_RED, 0); - digitalWrite(LED_GREEN, 0); - digitalWrite(LED_BLUE, 0); - -} - -unsigned long last_10sec = 0; -unsigned int counter = 0; - -void loop() { - unsigned long t = millis(); - webSocket.loop(); - server.handleClient(); - - if((t - last_10sec) > 10 * 1000) { - counter++; - bool ping = (counter % 2); - int i = webSocket.connectedClients(ping); - USE_SERIAL.printf("%d Connected websocket clients ping: %d\n", i, ping); - last_10sec = millis(); - } -} diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketServerFragmentation/WebSocketServerFragmentation.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketServerFragmentation/WebSocketServerFragmentation.ino deleted file mode 100644 index 84c9775d..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketServerFragmentation/WebSocketServerFragmentation.ino +++ /dev/null @@ -1,94 +0,0 @@ -/* - * WebSocketServer.ino - * - * Created on: 22.05.2015 - * - */ - -#include - -#include -#include -#include -#include - -ESP8266WiFiMulti WiFiMulti; - -WebSocketsServer webSocket = WebSocketsServer(81); - -#define USE_SERIAL Serial - -String fragmentBuffer = ""; - -void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[%u] Disconnected!\n", num); - break; - case WStype_CONNECTED: { - IPAddress ip = webSocket.remoteIP(num); - USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); - - // send message to client - webSocket.sendTXT(num, "Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); - break; - case WStype_BIN: - USE_SERIAL.printf("[%u] get binary length: %u\n", num, length); - hexdump(payload, length); - break; - - // Fragmentation / continuation opcode handling - // case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT_TEXT_START: - fragmentBuffer = (char*)payload; - USE_SERIAL.printf("[%u] get start start of Textfragment: %s\n", num, payload); - break; - case WStype_FRAGMENT: - fragmentBuffer += (char*)payload; - USE_SERIAL.printf("[%u] get Textfragment : %s\n", num, payload); - break; - case WStype_FRAGMENT_FIN: - fragmentBuffer += (char*)payload; - USE_SERIAL.printf("[%u] get end of Textfragment: %s\n", num, payload); - USE_SERIAL.printf("[%u] full frame: %s\n", num, fragmentBuffer.c_str()); - break; - } - -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - webSocket.begin(); - webSocket.onEvent(webSocketEvent); -} - -void loop() { - webSocket.loop(); -} - diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketServerHttpHeaderValidation/WebSocketServerHttpHeaderValidation.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketServerHttpHeaderValidation/WebSocketServerHttpHeaderValidation.ino deleted file mode 100644 index 8bc646c4..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketServerHttpHeaderValidation/WebSocketServerHttpHeaderValidation.ino +++ /dev/null @@ -1,86 +0,0 @@ -/* - * WebSocketServerHttpHeaderValidation.ino - * - * Created on: 08.06.2016 - * - */ - -#include - -#include -#include -#include -#include - -ESP8266WiFiMulti WiFiMulti; - -WebSocketsServer webSocket = WebSocketsServer(81); - -#define USE_SERIAL Serial1 - -const unsigned long int validSessionId = 12345; //some arbitrary value to act as a valid sessionId - -/* - * Returns a bool value as an indicator to describe whether a user is allowed to initiate a websocket upgrade - * based on the value of a cookie. This function expects the rawCookieHeaderValue to look like this "sessionId=|" - */ -bool isCookieValid(String rawCookieHeaderValue) { - - if (rawCookieHeaderValue.indexOf("sessionId") != -1) { - String sessionIdStr = rawCookieHeaderValue.substring(rawCookieHeaderValue.indexOf("sessionId=") + 10, rawCookieHeaderValue.indexOf("|")); - unsigned long int sessionId = strtoul(sessionIdStr.c_str(), NULL, 10); - return sessionId == validSessionId; - } - return false; -} - -/* - * The WebSocketServerHttpHeaderValFunc delegate passed to webSocket.onValidateHttpHeader - */ -bool validateHttpHeader(String headerName, String headerValue) { - - //assume a true response for any headers not handled by this validator - bool valid = true; - - if(headerName.equalsIgnoreCase("Cookie")) { - //if the header passed is the Cookie header, validate it according to the rules in 'isCookieValid' function - valid = isCookieValid(headerValue); - } - - return valid; -} - -void setup() { - // USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //Serial.setDebugOutput(true); - USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - //connecting clients must supply a valid session cookie at websocket upgrade handshake negotiation time - const char * headerkeys[] = { "Cookie" }; - size_t headerKeyCount = sizeof(headerkeys) / sizeof(char*); - webSocket.onValidateHttpHeader(validateHttpHeader, headerkeys, headerKeyCount); - webSocket.begin(); -} - -void loop() { - webSocket.loop(); -} - diff --git a/3rdparty/WebSockets/examples/esp8266/WebSocketServer_LEDcontrol/WebSocketServer_LEDcontrol.ino b/3rdparty/WebSockets/examples/esp8266/WebSocketServer_LEDcontrol/WebSocketServer_LEDcontrol.ino deleted file mode 100644 index 8f32e753..00000000 --- a/3rdparty/WebSockets/examples/esp8266/WebSocketServer_LEDcontrol/WebSocketServer_LEDcontrol.ino +++ /dev/null @@ -1,121 +0,0 @@ -/* - * WebSocketServer_LEDcontrol.ino - * - * Created on: 26.11.2015 - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#define LED_RED 15 -#define LED_GREEN 12 -#define LED_BLUE 13 - -#define USE_SERIAL Serial - - -ESP8266WiFiMulti WiFiMulti; - -ESP8266WebServer server(80); -WebSocketsServer webSocket = WebSocketsServer(81); - -void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - - switch(type) { - case WStype_DISCONNECTED: - USE_SERIAL.printf("[%u] Disconnected!\n", num); - break; - case WStype_CONNECTED: { - IPAddress ip = webSocket.remoteIP(num); - USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); - - // send message to client - webSocket.sendTXT(num, "Connected"); - } - break; - case WStype_TEXT: - USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); - - if(payload[0] == '#') { - // we get RGB data - - // decode rgb data - uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); - - analogWrite(LED_RED, ((rgb >> 16) & 0xFF)); - analogWrite(LED_GREEN, ((rgb >> 8) & 0xFF)); - analogWrite(LED_BLUE, ((rgb >> 0) & 0xFF)); - } - - break; - } - -} - -void setup() { - //USE_SERIAL.begin(921600); - USE_SERIAL.begin(115200); - - //USE_SERIAL.setDebugOutput(true); - - USE_SERIAL.println(); - USE_SERIAL.println(); - USE_SERIAL.println(); - - for(uint8_t t = 4; t > 0; t--) { - USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); - USE_SERIAL.flush(); - delay(1000); - } - - pinMode(LED_RED, OUTPUT); - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_BLUE, OUTPUT); - - digitalWrite(LED_RED, 1); - digitalWrite(LED_GREEN, 1); - digitalWrite(LED_BLUE, 1); - - WiFiMulti.addAP("SSID", "passpasspass"); - - while(WiFiMulti.run() != WL_CONNECTED) { - delay(100); - } - - // start webSocket server - webSocket.begin(); - webSocket.onEvent(webSocketEvent); - - if(MDNS.begin("esp8266")) { - USE_SERIAL.println("MDNS responder started"); - } - - // handle index - server.on("/", []() { - // send index.html - server.send(200, "text/html", "LED Control:

R:
G:
B:
"); - }); - - server.begin(); - - // Add service to MDNS - MDNS.addService("http", "tcp", 80); - MDNS.addService("ws", "tcp", 81); - - digitalWrite(LED_RED, 0); - digitalWrite(LED_GREEN, 0); - digitalWrite(LED_BLUE, 0); - -} - -void loop() { - webSocket.loop(); - server.handleClient(); -} diff --git a/3rdparty/WebSockets/examples/particle/ParticleWebSocketClient/application.cpp b/3rdparty/WebSockets/examples/particle/ParticleWebSocketClient/application.cpp deleted file mode 100644 index 461228f3..00000000 --- a/3rdparty/WebSockets/examples/particle/ParticleWebSocketClient/application.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* To compile using make CLI, create a folder under \firmware\user\applications and copy application.cpp there. -* Then, copy src files under particleWebSocket folder. -*/ - -#include "application.h" -#include "particleWebSocket/WebSocketsClient.h" - -WebSocketsClient webSocket; - -void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) -{ - switch (type) - { - case WStype_DISCONNECTED: - Serial.printlnf("[WSc] Disconnected!"); - break; - case WStype_CONNECTED: - Serial.printlnf("[WSc] Connected to URL: %s", payload); - webSocket.sendTXT("Connected\r\n"); - break; - case WStype_TEXT: - Serial.printlnf("[WSc] get text: %s", payload); - break; - case WStype_BIN: - Serial.printlnf("[WSc] get binary length: %u", length); - break; - } -} - -void setup() -{ - Serial.begin(9600); - - WiFi.setCredentials("[SSID]", "[PASSWORD]", WPA2, WLAN_CIPHER_AES_TKIP); - WiFi.connect(); - - webSocket.begin("192.168.1.153", 85, "/ClientService/?variable=Test1212"); - webSocket.onEvent(webSocketEvent); -} - -void loop() -{ - webSocket.sendTXT("Hello world!"); - delay(500); - webSocket.loop(); -} diff --git a/3rdparty/WebSockets/library.json b/3rdparty/WebSockets/library.json deleted file mode 100644 index efbc51be..00000000 --- a/3rdparty/WebSockets/library.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "WebSockets", - "description": "WebSocket Server and Client for Arduino based on RFC6455", - "keywords": "wifi, http, web, server, client, websocket", - "authors": [ - { - "name": "Markus Sattler", - "url": "https://github.com/Links2004", - "maintainer": true - } - ], - "repository": { - "type": "git", - "url": "https://github.com/Links2004/arduinoWebSockets.git" - }, - "version": "2.1.4", - "license": "LGPL-2.1", - "export": { - "exclude": [ - "tests" - ] - }, - "frameworks": "arduino", - "platforms": "atmelavr, espressif8266, espressif32" -} diff --git a/3rdparty/WebSockets/library.properties b/3rdparty/WebSockets/library.properties deleted file mode 100644 index 2fe174b9..00000000 --- a/3rdparty/WebSockets/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=WebSockets -version=2.1.4 -author=Markus Sattler -maintainer=Markus Sattler -sentence=WebSockets for Arduino (Server + Client) -paragraph=use 2.x.x for ESP and 1.3 for AVR -category=Communication -url=https://github.com/Links2004/arduinoWebSockets -architectures=* diff --git a/3rdparty/WebSockets/src/SocketIOclient.cpp b/3rdparty/WebSockets/src/SocketIOclient.cpp deleted file mode 100644 index e9467d45..00000000 --- a/3rdparty/WebSockets/src/SocketIOclient.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * SocketIOclient.cpp - * - * Created on: May 12, 2018 - * Author: links - */ - -#include "WebSockets.h" -#include "WebSocketsClient.h" -#include "SocketIOclient.h" - -SocketIOclient::SocketIOclient() { -} - -SocketIOclient::~SocketIOclient() { -} - -void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) { - WebSocketsClient::beginSocketIO(host, port, url, protocol); - WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); -} - -void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) { - WebSocketsClient::beginSocketIO(host, port, url, protocol); - WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); -} - -/** - * set callback function - * @param cbEvent SocketIOclientEvent - */ -void SocketIOclient::onEvent(SocketIOclientEvent cbEvent) { - _cbEvent = cbEvent; -} - -bool SocketIOclient::isConnected(void) { - return WebSocketsClient::isConnected(); -} - -/** - * send text data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) { - bool ret = false; - if(length == 0) { - length = strlen((const char *)payload); - } - if(clientIsConnected(&_client)) { - if(!headerToPayload) { - // webSocket Header - ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true); - // Engine.IO / Socket.IO Header - if(ret) { - uint8_t buf[3] = { eIOtype_MESSAGE, sIOtype_EVENT, 0x00 }; - ret = WebSocketsClient::write(&_client, buf, 2); - } - if(ret && payload && length > 0) { - ret = WebSocketsClient::write(&_client, payload, length); - } - return ret; - } else { - // TODO implement - } - - // return WebSocketsClient::sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload); - } - return false; -} - -bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) { - return sendEVENT((uint8_t *)payload, length); -} - -bool SocketIOclient::sendEVENT(char * payload, size_t length, bool headerToPayload) { - return sendEVENT((uint8_t *)payload, length, headerToPayload); -} - -bool SocketIOclient::sendEVENT(const char * payload, size_t length) { - return sendEVENT((uint8_t *)payload, length); -} - -bool SocketIOclient::sendEVENT(String & payload) { - return sendEVENT((uint8_t *)payload.c_str(), payload.length()); -} - -void SocketIOclient::loop(void) { - WebSocketsClient::loop(); - unsigned long t = millis(); - if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) { - _lastConnectionFail = t; - DEBUG_WEBSOCKETS("[wsIOc] send ping\n"); - WebSocketsClient::sendTXT(eIOtype_PING); - } -} - -void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t length) { - switch(type) { - case WStype_DISCONNECTED: - runIOCbEvent(sIOtype_DISCONNECT, NULL, 0); - DEBUG_WEBSOCKETS("[wsIOc] Disconnected!\n"); - break; - case WStype_CONNECTED: { - DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload); - // send message to server when Connected - // Engine.io upgrade confirmation message (required) - WebSocketsClient::sendTXT(eIOtype_UPGRADE); - runIOCbEvent(sIOtype_CONNECT, payload, length); - } break; - case WStype_TEXT: { - if(length < 1) { - break; - } - - engineIOmessageType_t eType = (engineIOmessageType_t)payload[0]; - switch(eType) { - case eIOtype_PING: - payload[0] = eIOtype_PONG; - DEBUG_WEBSOCKETS("[wsIOc] get ping send pong (%s)\n", payload); - WebSocketsClient::sendTXT(payload, length, false); - break; - case eIOtype_PONG: - DEBUG_WEBSOCKETS("[wsIOc] get pong\n"); - break; - case eIOtype_MESSAGE: { - if(length < 2) { - break; - } - socketIOmessageType_t ioType = (socketIOmessageType_t)payload[1]; - uint8_t * data = &payload[2]; - size_t lData = length - 2; - switch(ioType) { - case sIOtype_EVENT: - DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data); - break; - case sIOtype_CONNECT: - case sIOtype_DISCONNECT: - case sIOtype_ACK: - case sIOtype_ERROR: - case sIOtype_BINARY_EVENT: - case sIOtype_BINARY_ACK: - default: - DEBUG_WEBSOCKETS("[wsIOc] Socket.IO Message Type %c (%02X) is not implemented\n", ioType, ioType); - DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload); - break; - } - - runIOCbEvent(ioType, data, lData); - } break; - case eIOtype_OPEN: - case eIOtype_CLOSE: - case eIOtype_UPGRADE: - case eIOtype_NOOP: - default: - DEBUG_WEBSOCKETS("[wsIOc] Engine.IO Message Type %c (%02X) is not implemented\n", eType, eType); - DEBUG_WEBSOCKETS("[wsIOc] get text: %s\n", payload); - break; - } - } break; - - case WStype_BIN: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: - case WStype_FRAGMENT_FIN: - case WStype_PING: - case WStype_PONG: - break; - } -} diff --git a/3rdparty/WebSockets/src/SocketIOclient.h b/3rdparty/WebSockets/src/SocketIOclient.h deleted file mode 100644 index 64b8c87c..00000000 --- a/3rdparty/WebSockets/src/SocketIOclient.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * SocketIOclient.h - * - * Created on: May 12, 2018 - * Author: links - */ - -#ifndef SOCKETIOCLIENT_H_ -#define SOCKETIOCLIENT_H_ - -#include "WebSockets.h" - -#define EIO_HEARTBEAT_INTERVAL 20000 - -#define EIO_MAX_HEADER_SIZE (WEBSOCKETS_MAX_HEADER_SIZE + 1) -#define SIO_MAX_HEADER_SIZE (EIO_MAX_HEADER_SIZE + 1) - -typedef enum { - eIOtype_OPEN = '0', ///< Sent from the server when a new transport is opened (recheck) - eIOtype_CLOSE = '1', ///< Request the close of this transport but does not shutdown the connection itself. - eIOtype_PING = '2', ///< Sent by the client. Server should answer with a pong packet containing the same data - eIOtype_PONG = '3', ///< Sent by the server to respond to ping packets. - eIOtype_MESSAGE = '4', ///< actual message, client and server should call their callbacks with the data - eIOtype_UPGRADE = '5', ///< Before engine.io switches a transport, it tests, if server and client can communicate over this transport. If this test succeed, the client sends an upgrade packets which requests the server to flush its cache on the old transport and switch to the new transport. - eIOtype_NOOP = '6', ///< A noop packet. Used primarily to force a poll cycle when an incoming websocket connection is received. -} engineIOmessageType_t; - -typedef enum { - sIOtype_CONNECT = '0', - sIOtype_DISCONNECT = '1', - sIOtype_EVENT = '2', - sIOtype_ACK = '3', - sIOtype_ERROR = '4', - sIOtype_BINARY_EVENT = '5', - sIOtype_BINARY_ACK = '6', -} socketIOmessageType_t; - -class SocketIOclient : protected WebSocketsClient { - public: -#ifdef __AVR__ - typedef void (*SocketIOclientEvent)(socketIOmessageType_t type, uint8_t * payload, size_t length); -#else - typedef std::function SocketIOclientEvent; -#endif - - SocketIOclient(void); - virtual ~SocketIOclient(void); - - void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); - void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); - - bool isConnected(void); - - void onEvent(SocketIOclientEvent cbEvent); - - bool sendEVENT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool sendEVENT(const uint8_t * payload, size_t length = 0); - bool sendEVENT(char * payload, size_t length = 0, bool headerToPayload = false); - bool sendEVENT(const char * payload, size_t length = 0); - bool sendEVENT(String & payload); - - void loop(void); - - protected: - uint64_t _lastHeartbeat = 0; - SocketIOclientEvent _cbEvent; - virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { - if(_cbEvent) { - _cbEvent(type, payload, length); - } - } - - // Handeling events from websocket layer - virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { - handleCbEvent(type, payload, length); - } - void handleCbEvent(WStype_t type, uint8_t * payload, size_t length); -}; - -#endif /* SOCKETIOCLIENT_H_ */ diff --git a/3rdparty/WebSockets/src/WebSockets.cpp b/3rdparty/WebSockets/src/WebSockets.cpp deleted file mode 100644 index 3a90a402..00000000 --- a/3rdparty/WebSockets/src/WebSockets.cpp +++ /dev/null @@ -1,749 +0,0 @@ -/** - * @file WebSockets.cpp - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 - * - */ - -#include "WebSockets.h" - -#ifdef ESP8266 -#include -#endif - -extern "C" { -#ifdef CORE_HAS_LIBB64 -#include -#else -#include "libb64/cencode_inc.h" -#endif -} - -#ifdef ESP8266 -#include -#elif defined(ESP32) -#include -#else - -extern "C" { -#include "libsha1/libsha1.h" -} - -#endif - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param code uint16_t see RFC - * @param reason ptr to the disconnect reason message - * @param reasonLen length of the disconnect reason message - */ -void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] clientDisconnect code: %u\n", client->num, code); - if(client->status == WSC_CONNECTED && code) { - if(reason) { - sendFrame(client, WSop_close, (uint8_t *)reason, reasonLen); - } else { - uint8_t buffer[2]; - buffer[0] = ((code >> 8) & 0xFF); - buffer[1] = (code & 0xFF); - sendFrame(client, WSop_close, &buffer[0], 2); - } - } - clientDisconnect(client); -} - -/** - * - * @param buf uint8_t * ptr to the buffer for writing - * @param opcode WSopcode_t - * @param length size_t length of the payload - * @param mask bool add dummy mask to the frame (needed for web browser) - * @param maskkey uint8_t[4] key used for payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - */ -uint8_t WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) { - uint8_t headerSize; - // calculate header Size - if(length < 126) { - headerSize = 2; - } else if(length < 0xFFFF) { - headerSize = 4; - } else { - headerSize = 10; - } - - if(mask) { - headerSize += 4; - } - - // create header - - // byte 0 - *headerPtr = 0x00; - if(fin) { - *headerPtr |= bit(7); ///< set Fin - } - *headerPtr |= opcode; ///< set opcode - headerPtr++; - - // byte 1 - *headerPtr = 0x00; - if(mask) { - *headerPtr |= bit(7); ///< set mask - } - - if(length < 126) { - *headerPtr |= length; - headerPtr++; - } else if(length < 0xFFFF) { - *headerPtr |= 126; - headerPtr++; - *headerPtr = ((length >> 8) & 0xFF); - headerPtr++; - *headerPtr = (length & 0xFF); - headerPtr++; - } else { - // Normally we never get here (to less memory) - *headerPtr |= 127; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = ((length >> 24) & 0xFF); - headerPtr++; - *headerPtr = ((length >> 16) & 0xFF); - headerPtr++; - *headerPtr = ((length >> 8) & 0xFF); - headerPtr++; - *headerPtr = (length & 0xFF); - headerPtr++; - } - - if(mask) { - *headerPtr = maskKey[0]; - headerPtr++; - *headerPtr = maskKey[1]; - headerPtr++; - *headerPtr = maskKey[2]; - headerPtr++; - *headerPtr = maskKey[3]; - headerPtr++; - } - return headerSize; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param length size_t length of the payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - * @return true if ok - */ -bool WebSockets::sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length, bool fin) { - uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 }; - uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 }; - - uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin); - - if(write(client, &buffer[0], headerSize) != headerSize) { - return false; - } - - return true; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param payload uint8_t * ptr to the payload - * @param length size_t length of the payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - * @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!) - * @return true if ok - */ -bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin, bool headerToPayload) { - if(client->tcp && !client->tcp->connected()) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num); - return false; - } - - if(client->status != WSC_CONNECTED) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num); - return false; - } - - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send message frame -------\n", client->num); - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] fin: %u opCode: %u mask: %u length: %u headerToPayload: %u\n", client->num, fin, opcode, client->cIsClient, length, headerToPayload); - - if(opcode == WSop_text) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] text: %s\n", client->num, (payload + (headerToPayload ? 14 : 0))); - } - - uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 }; - uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 }; - - uint8_t headerSize; - uint8_t * headerPtr; - uint8_t * payloadPtr = payload; - bool useInternBuffer = false; - bool ret = true; - - // calculate header Size - if(length < 126) { - headerSize = 2; - } else if(length < 0xFFFF) { - headerSize = 4; - } else { - headerSize = 10; - } - - if(client->cIsClient) { - headerSize += 4; - } - -#ifdef WEBSOCKETS_USE_BIG_MEM - // only for ESP since AVR has less HEAP - // try to send data in one TCP package (only if some free Heap is there) - if(!headerToPayload && ((length > 0) && (length < 1400)) && (GET_FREE_HEAP > 6000)) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num); - uint8_t * dataPtr = (uint8_t *)malloc(length + WEBSOCKETS_MAX_HEADER_SIZE); - if(dataPtr) { - memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length); - headerToPayload = true; - useInternBuffer = true; - payloadPtr = dataPtr; - } - } -#endif - - // set Header Pointer - if(headerToPayload) { - // calculate offset in payload - headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize)); - } else { - headerPtr = &buffer[0]; - } - - if(client->cIsClient && useInternBuffer) { - // if we use a Intern Buffer we can modify the data - // by this fact its possible the do the masking - for(uint8_t x = 0; x < sizeof(maskKey); x++) { - maskKey[x] = random(0xFF); - } - } - - createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin); - - if(client->cIsClient && useInternBuffer) { - uint8_t * dataMaskPtr; - - if(headerToPayload) { - dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE); - } else { - dataMaskPtr = payloadPtr; - } - - for(size_t x = 0; x < length; x++) { - dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]); - } - } - -#ifndef NODEBUG_WEBSOCKETS - unsigned long start = micros(); -#endif - - if(headerToPayload) { - // header has be added to payload - // payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings - // offset in payload is calculatetd 14 - headerSize - if(write(client, &payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) { - ret = false; - } - } else { - // send header - if(write(client, &buffer[0], headerSize) != headerSize) { - ret = false; - } - - if(payloadPtr && length > 0) { - // send payload - if(write(client, &payloadPtr[0], length) != length) { - ret = false; - } - } - } - - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] sending Frame Done (%luus).\n", client->num, (micros() - start)); - -#ifdef WEBSOCKETS_USE_BIG_MEM - if(useInternBuffer && payloadPtr) { - free(payloadPtr); - } -#endif - - return ret; -} - -/** - * callen when HTTP header is done - * @param client WSclient_t * ptr to the client struct - */ -void WebSockets::headerDone(WSclient_t * client) { - client->status = WSC_CONNECTED; - client->cWsRXsize = 0; - DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done.\n", client->num); -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; - handleWebsocket(client); -#endif -} - -/** - * handle the WebSocket stream - * @param client WSclient_t * ptr to the client struct - */ -void WebSockets::handleWebsocket(WSclient_t * client) { - if(client->cWsRXsize == 0) { - handleWebsocketCb(client); - } -} - -/** - * wait for - * @param client - * @param size - */ -bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) { - if(!client->tcp || !client->tcp->connected()) { - return false; - } - - if(size > WEBSOCKETS_MAX_HEADER_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size); - return false; - } - - if(client->cWsRXsize >= size) { - return true; - } - - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d cWsRXsize: %d\n", client->num, size, client->cWsRXsize); - readCb(client, &client->cWsHeader[client->cWsRXsize], (size - client->cWsRXsize), std::bind([](WebSockets * server, size_t size, WSclient_t * client, bool ok) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor][readCb] size: %d ok: %d\n", client->num, size, ok); - if(ok) { - client->cWsRXsize = size; - server->handleWebsocketCb(client); - } else { - DEBUG_WEBSOCKETS("[WS][%d][readCb] failed.\n", client->num); - client->cWsRXsize = 0; - // timeout or error - server->clientDisconnect(client, 1002); - } - }, - this, size, std::placeholders::_1, std::placeholders::_2)); - return false; -} - -void WebSockets::handleWebsocketCb(WSclient_t * client) { - if(!client->tcp || !client->tcp->connected()) { - return; - } - - uint8_t * buffer = client->cWsHeader; - - WSMessageHeader_t * header = &client->cWsHeaderDecode; - uint8_t * payload = NULL; - - uint8_t headerLen = 2; - - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - - // split first 2 bytes in the data - header->fin = ((*buffer >> 7) & 0x01); - header->rsv1 = ((*buffer >> 6) & 0x01); - header->rsv2 = ((*buffer >> 5) & 0x01); - header->rsv3 = ((*buffer >> 4) & 0x01); - header->opCode = (WSopcode_t)(*buffer & 0x0F); - buffer++; - - header->mask = ((*buffer >> 7) & 0x01); - header->payloadLen = (WSopcode_t)(*buffer & 0x7F); - buffer++; - - if(header->payloadLen == 126) { - headerLen += 2; - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - header->payloadLen = buffer[0] << 8 | buffer[1]; - buffer += 2; - } else if(header->payloadLen == 127) { - headerLen += 8; - // read 64bit integer as length - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - - if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) { - // really too big! - header->payloadLen = 0xFFFFFFFF; - } else { - header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; - } - buffer += 8; - } - - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ------- read massage frame -------\n", client->num); - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] fin: %u rsv1: %u rsv2: %u rsv3 %u opCode: %u\n", client->num, header->fin, header->rsv1, header->rsv2, header->rsv3, header->opCode); - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen); - - if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen); - clientDisconnect(client, 1009); - return; - } - - if(header->mask) { - headerLen += 4; - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - header->maskKey = buffer; - buffer += 4; - } - - if(header->payloadLen > 0) { - // if text data we need one more - payload = (uint8_t *)malloc(header->payloadLen + 1); - - if(!payload) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen); - clientDisconnect(client, 1011); - return; - } - readCb(client, payload, header->payloadLen, std::bind(&WebSockets::handleWebsocketPayloadCb, this, std::placeholders::_1, std::placeholders::_2, payload)); - } else { - handleWebsocketPayloadCb(client, true, NULL); - } -} - -void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) { - WSMessageHeader_t * header = &client->cWsHeaderDecode; - if(ok) { - if(header->payloadLen > 0) { - payload[header->payloadLen] = 0x00; - - if(header->mask) { - //decode XOR - for(size_t i = 0; i < header->payloadLen; i++) { - payload[i] = (payload[i] ^ header->maskKey[i % 4]); - } - } - } - - switch(header->opCode) { - case WSop_text: - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload); - // no break here! - case WSop_binary: - case WSop_continuation: - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_ping: - // send pong back - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ping received (%s)\n", client->num, payload ? (const char *)payload : ""); - sendFrame(client, WSop_pong, payload, header->payloadLen); - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_pong: - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload ? (const char *)payload : ""); - client->pongReceived = true; - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_close: { -#ifndef NODEBUG_WEBSOCKETS - uint16_t reasonCode = 1000; - if(header->payloadLen >= 2) { - reasonCode = payload[0] << 8 | payload[1]; - } -#endif - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode); - if(header->payloadLen > 2) { - DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2)); - } else { - DEBUG_WEBSOCKETS("\n"); - } - clientDisconnect(client, 1000); - } break; - default: - clientDisconnect(client, 1002); - break; - } - - if(payload) { - free(payload); - } - - // reset input - client->cWsRXsize = 0; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - //register callback for next message - handleWebsocketWaitFor(client, 2); -#endif - - } else { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] missing data!\n", client->num); - free(payload); - clientDisconnect(client, 1002); - } -} - -/** - * generate the key for Sec-WebSocket-Accept - * @param clientKey String - * @return String Accept Key - */ -String WebSockets::acceptKey(String & clientKey) { - uint8_t sha1HashBin[20] = { 0 }; -#ifdef ESP8266 - sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]); -#elif defined(ESP32) - String data = clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - esp_sha(SHA1, (unsigned char *)data.c_str(), data.length(), &sha1HashBin[0]); -#else - clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, (const unsigned char *)clientKey.c_str(), clientKey.length()); - SHA1Final(&sha1HashBin[0], &ctx); -#endif - - String key = base64_encode(sha1HashBin, 20); - key.trim(); - - return key; -} - -/** - * base64_encode - * @param data uint8_t * - * @param length size_t - * @return base64 encoded String - */ -String WebSockets::base64_encode(uint8_t * data, size_t length) { - size_t size = ((length * 1.6f) + 1); - char * buffer = (char *)malloc(size); - if(buffer) { - base64_encodestate _state; - base64_init_encodestate(&_state); - int len = base64_encode_block((const char *)&data[0], length, &buffer[0], &_state); - len = base64_encode_blockend((buffer + len), &_state); - - String base64 = String(buffer); - free(buffer); - return base64; - } - return String("-FAIL-"); -} - -/** - * read x byte from tcp or get timeout - * @param client WSclient_t * - * @param out uint8_t * data buffer - * @param n size_t byte count - * @return true if ok - */ -bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - if(!client->tcp || !client->tcp->connected()) { - return false; - } - - client->tcp->readBytes(out, n, std::bind([](WSclient_t * client, bool ok, WSreadWaitCb cb) { - if(cb) { - cb(client, ok); - } - }, - client, std::placeholders::_1, cb)); - -#else - unsigned long t = millis(); - size_t len; - DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t); - while(n > 0) { - if(client->tcp == NULL) { - DEBUG_WEBSOCKETS("[readCb] tcp is null!\n"); - if(cb) { - cb(client, false); - } - return false; - } - - if(!client->tcp->connected()) { - DEBUG_WEBSOCKETS("[readCb] not connected!\n"); - if(cb) { - cb(client, false); - } - return false; - } - - if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) { - DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %lu\n", (millis() - t)); - if(cb) { - cb(client, false); - } - return false; - } - - if(!client->tcp->available()) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - continue; - } - - len = client->tcp->read((uint8_t *)out, n); - if(len) { - t = millis(); - out += len; - n -= len; - //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); - } else { - //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - if(cb) { - cb(client, true); - } -#endif - return true; -} - -/** - * write x byte to tcp or get timeout - * @param client WSclient_t * - * @param out uint8_t * data buffer - * @param n size_t byte count - * @return bytes send - */ -size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) { - if(out == NULL) - return 0; - if(client == NULL) - return 0; - unsigned long t = millis(); - size_t len = 0; - size_t total = 0; - DEBUG_WEBSOCKETS("[write] n: %zu t: %lu\n", n, t); - while(n > 0) { - if(client->tcp == NULL) { - DEBUG_WEBSOCKETS("[write] tcp is null!\n"); - break; - } - - if(!client->tcp->connected()) { - DEBUG_WEBSOCKETS("[write] not connected!\n"); - break; - } - - if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) { - DEBUG_WEBSOCKETS("[write] write TIMEOUT! %lu\n", (millis() - t)); - break; - } - - len = client->tcp->write((const uint8_t *)out, n); - if(len) { - t = millis(); - out += len; - n -= len; - total += len; - //DEBUG_WEBSOCKETS("write %d left %d!\n", len, n); - } else { - //DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return total; -} - -size_t WebSockets::write(WSclient_t * client, const char * out) { - if(client == NULL) - return 0; - if(out == NULL) - return 0; - return write(client, (uint8_t *)out, strlen(out)); -} - -/** - * enable ping/pong heartbeat process - * @param client WSclient_t * - * @param pingInterval uint32_t how often ping will be sent - * @param pongTimeout uint32_t millis after which pong should timout if not received - * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect - */ -void WebSockets::enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { - if(client == NULL) - return; - client->pingInterval = pingInterval; - client->pongTimeout = pongTimeout; - client->disconnectTimeoutCount = disconnectTimeoutCount; - client->pongReceived = false; -} - -/** - * handle ping/pong heartbeat timeout process - * @param client WSclient_t * - */ -void WebSockets::handleHBTimeout(WSclient_t * client) { - if(client->pingInterval) { // if heartbeat is enabled - uint32_t pi = millis() - client->lastPing; - - if(client->pongReceived) { - client->pongTimeoutCount = 0; - } else { - if(pi > client->pongTimeout) { // pong not received in time - client->pongTimeoutCount++; - client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run - - DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%d pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount); - - if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) { - DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount); - clientDisconnect(client); - } - } - } - } -} diff --git a/3rdparty/WebSockets/src/WebSockets.h b/3rdparty/WebSockets/src/WebSockets.h deleted file mode 100644 index a70768e7..00000000 --- a/3rdparty/WebSockets/src/WebSockets.h +++ /dev/null @@ -1,331 +0,0 @@ -/** - * @file WebSockets.h - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 WEBSOCKETS_H_ -#define WEBSOCKETS_H_ - -#ifdef STM32_DEVICE -#include -#define bit(b) (1UL << (b)) // Taken directly from Arduino.h -#else -#include -#include -#endif - -#ifdef ARDUINO_ARCH_AVR -#error Version 2.x.x currently does not support Arduino with AVR since there is no support for std namespace of c++. -#error Use Version 1.x.x. (ATmega branch) -#else -#include -#endif - -#ifndef NODEBUG_WEBSOCKETS -#ifdef DEBUG_ESP_PORT -#define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf(__VA_ARGS__) -#else -//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ ) -#endif -#endif - -#ifndef DEBUG_WEBSOCKETS -#define DEBUG_WEBSOCKETS(...) -#define NODEBUG_WEBSOCKETS -#endif - -#if defined(ESP8266) || defined(ESP32) - -#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024) -#define WEBSOCKETS_USE_BIG_MEM -#define GET_FREE_HEAP ESP.getFreeHeap() -// moves all Header strings to Flash (~300 Byte) -//#define WEBSOCKETS_SAVE_RAM - -#elif defined(STM32_DEVICE) - -#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024) -#define WEBSOCKETS_USE_BIG_MEM -#define GET_FREE_HEAP System.freeMemory() - -#else - -//atmega328p has only 2KB ram! -#define WEBSOCKETS_MAX_DATA_SIZE (1024) -// moves all Header strings to Flash -#define WEBSOCKETS_SAVE_RAM - -#endif - -#define WEBSOCKETS_TCP_TIMEOUT (2000) - -#define NETWORK_ESP8266_ASYNC (0) -#define NETWORK_ESP8266 (1) -#define NETWORK_W5100 (2) -#define NETWORK_ENC28J60 (3) -#define NETWORK_ESP32 (4) -#define NETWORK_ESP32_ETH (5) - -// max size of the WS Message Header -#define WEBSOCKETS_MAX_HEADER_SIZE (14) - -#if !defined(WEBSOCKETS_NETWORK_TYPE) -// select Network type based -#if defined(ESP8266) || defined(ESP31B) -#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266 -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 - -#elif defined(ESP32) -#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32 -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH -#else -#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 - -#endif -#endif - -// Includes and defined based on Network Type -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - -// Note: -// No SSL/WSS support for client in Async mode -// TLS lib need a sync interface! - -#if defined(ESP8266) -#include -#elif defined(ESP32) -#include -#include -#elif defined(ESP31B) -#include -#else -#error "network type ESP8266 ASYNC only possible on the ESP mcu!" -#endif - -#include -#include -#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer -#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - -#if !defined(ESP8266) && !defined(ESP31B) -#error "network type ESP8266 only possible on the ESP mcu!" -#endif - -#ifdef ESP8266 -#include -#else -#include -#endif -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100) - -#ifdef STM32_DEVICE -#define WEBSOCKETS_NETWORK_CLASS TCPClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS TCPServer -#else -#include -#include -#define WEBSOCKETS_NETWORK_CLASS EthernetClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer -#endif - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60) - -#include -#define WEBSOCKETS_NETWORK_CLASS UIPClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - -#include -#include -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32_ETH) - -#include -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#else -#error "no network type selected!" -#endif - -#ifdef WEBSOCKETS_NETWORK_SSL_CLASS -#define HAS_SSL -#endif - -// moves all Header strings to Flash (~300 Byte) -#ifdef WEBSOCKETS_SAVE_RAM -#define WEBSOCKETS_STRING(var) F(var) -#else -#define WEBSOCKETS_STRING(var) var -#endif - -typedef enum { - WSC_NOT_CONNECTED, - WSC_HEADER, - WSC_CONNECTED -} WSclientsStatus_t; - -typedef enum { - WStype_ERROR, - WStype_DISCONNECTED, - WStype_CONNECTED, - WStype_TEXT, - WStype_BIN, - WStype_FRAGMENT_TEXT_START, - WStype_FRAGMENT_BIN_START, - WStype_FRAGMENT, - WStype_FRAGMENT_FIN, - WStype_PING, - WStype_PONG, -} WStype_t; - -typedef enum { - WSop_continuation = 0x00, ///< %x0 denotes a continuation frame - WSop_text = 0x01, ///< %x1 denotes a text frame - WSop_binary = 0x02, ///< %x2 denotes a binary frame - ///< %x3-7 are reserved for further non-control frames - WSop_close = 0x08, ///< %x8 denotes a connection close - WSop_ping = 0x09, ///< %x9 denotes a ping - WSop_pong = 0x0A ///< %xA denotes a pong - ///< %xB-F are reserved for further control frames -} WSopcode_t; - -typedef struct { - bool fin; - bool rsv1; - bool rsv2; - bool rsv3; - - WSopcode_t opCode; - bool mask; - - size_t payloadLen; - - uint8_t * maskKey; -} WSMessageHeader_t; - -typedef struct { - uint8_t num; ///< connection number - - WSclientsStatus_t status; - - WEBSOCKETS_NETWORK_CLASS * tcp; - - bool isSocketIO; ///< client for socket.io server - -#if defined(HAS_SSL) - bool isSSL; ///< run in ssl mode - WEBSOCKETS_NETWORK_SSL_CLASS * ssl; -#endif - - String cUrl; ///< http url - uint16_t cCode; ///< http code - - bool cIsClient = false; ///< will be used for masking - bool cIsUpgrade; ///< Connection == Upgrade - bool cIsWebsocket; ///< Upgrade == websocket - - String cSessionId; ///< client Set-Cookie (session id) - String cKey; ///< client Sec-WebSocket-Key - String cAccept; ///< client Sec-WebSocket-Accept - String cProtocol; ///< client Sec-WebSocket-Protocol - String cExtensions; ///< client Sec-WebSocket-Extensions - uint16_t cVersion; ///< client Sec-WebSocket-Version - - uint8_t cWsRXsize; ///< State of the RX - uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer - WSMessageHeader_t cWsHeaderDecode; - - String base64Authorization; ///< Base64 encoded Auth request - String plainAuthorization; ///< Base64 encoded Auth request - - String extraHeaders; - - bool cHttpHeadersValid; ///< non-websocket http header validity indicator - size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count - - bool pongReceived; - uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active" - uint32_t lastPing; // millis when last pong has been received - uint32_t pongTimeout; // interval in millis after which pong is considered to timeout - uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect" - uint8_t pongTimeoutCount; // current pong timeout count - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - String cHttpLine; ///< HTTP header lines -#endif - -} WSclient_t; - -class WebSockets { - protected: -#ifdef __AVR__ - typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok); -#else - typedef std::function WSreadWaitCb; -#endif - - virtual void clientDisconnect(WSclient_t * client) = 0; - virtual bool clientIsConnected(WSclient_t * client) = 0; - - void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0); - - virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0; - - uint8_t createHeader(uint8_t * buf, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin); - bool sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length = 0, bool fin = true); - bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false); - - void headerDone(WSclient_t * client); - - void handleWebsocket(WSclient_t * client); - - bool handleWebsocketWaitFor(WSclient_t * client, size_t size); - void handleWebsocketCb(WSclient_t * client); - void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload); - - String acceptKey(String & clientKey); - String base64_encode(uint8_t * data, size_t length); - - bool readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb); - virtual size_t write(WSclient_t * client, uint8_t * out, size_t n); - size_t write(WSclient_t * client, const char * out); - - void enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); - void handleHBTimeout(WSclient_t * client); -}; - -#ifndef UNUSED -#define UNUSED(var) (void)(var) -#endif -#endif /* WEBSOCKETS_H_ */ diff --git a/3rdparty/WebSockets/src/WebSocketsClient.cpp b/3rdparty/WebSockets/src/WebSocketsClient.cpp deleted file mode 100644 index 82277ea7..00000000 --- a/3rdparty/WebSockets/src/WebSocketsClient.cpp +++ /dev/null @@ -1,854 +0,0 @@ -/** - * @file WebSocketsClient.cpp - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 - * - */ - -#include "WebSockets.h" -#include "WebSocketsClient.h" - -WebSocketsClient::WebSocketsClient() { - _cbEvent = NULL; - _client.num = 0; - _client.cIsClient = true; - _client.extraHeaders = WEBSOCKETS_STRING("Origin: file://"); -} - -WebSocketsClient::~WebSocketsClient() { - disconnect(); -} - -/** - * calles to init the Websockets server - */ -void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, const char * protocol) { - _host = host; - _port = port; -#if defined(HAS_SSL) - _fingerprint = ""; - _CA_cert = NULL; -#endif - - _client.num = 0; - _client.status = WSC_NOT_CONNECTED; - _client.tcp = NULL; -#if defined(HAS_SSL) - _client.isSSL = false; - _client.ssl = NULL; -#endif - _client.cUrl = url; - _client.cCode = 0; - _client.cIsUpgrade = false; - _client.cIsWebsocket = true; - _client.cKey = ""; - _client.cAccept = ""; - _client.cProtocol = protocol; - _client.cExtensions = ""; - _client.cVersion = 0; - _client.base64Authorization = ""; - _client.plainAuthorization = ""; - _client.isSocketIO = false; - - _client.lastPing = 0; - _client.pongReceived = false; - _client.pongTimeoutCount = 0; - -#ifdef ESP8266 - randomSeed(RANDOM_REG32); -#else - // todo find better seed - randomSeed(millis()); -#endif -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - asyncConnect(); -#endif - - _lastConnectionFail = 0; - _reconnectInterval = 500; -} - -void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) { - begin(host.c_str(), port, url.c_str(), protocol.c_str()); -} - -void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, const char * protocol) { - return begin(host.toString().c_str(), port, url, protocol); -} - -#if defined(HAS_SSL) -void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) { - begin(host, port, url, protocol); - _client.isSSL = true; - _fingerprint = fingerprint; - _CA_cert = NULL; -} - -void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) { - beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str()); -} - -void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { - begin(host, port, url, protocol); - _client.isSSL = true; - _fingerprint = ""; - _CA_cert = CA_cert; -} -#endif - -void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) { - begin(host, port, url, protocol); - _client.isSocketIO = true; -} - -void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) { - beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str()); -} - -#if defined(HAS_SSL) -void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const char * url, const char * protocol) { - begin(host, port, url, protocol); - _client.isSocketIO = true; - _client.isSSL = true; - _fingerprint = ""; -} - -void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) { - beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str()); -} - -void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { - begin(host, port, url, protocol); - _client.isSocketIO = true; - _client.isSSL = true; - _fingerprint = ""; - _CA_cert = CA_cert; -} -#endif - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * called in arduino loop - */ -void WebSocketsClient::loop(void) { - if(!clientIsConnected(&_client)) { - // do not flood the server - if((millis() - _lastConnectionFail) < _reconnectInterval) { - return; - } - -#if defined(HAS_SSL) - if(_client.isSSL) { - DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n"); - if(_client.ssl) { - delete _client.ssl; - _client.ssl = NULL; - _client.tcp = NULL; - } - _client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS(); - _client.tcp = _client.ssl; - if(_CA_cert) { - DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate"); -#if defined(ESP32) - _client.ssl->setCACert(_CA_cert); -#elif defined(ESP8266) - _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1); -#else -#error setCACert not implemented -#endif - } - } else { - DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n"); - if(_client.tcp) { - delete _client.tcp; - _client.tcp = NULL; - } - _client.tcp = new WEBSOCKETS_NETWORK_CLASS(); - } -#else - _client.tcp = new WEBSOCKETS_NETWORK_CLASS(); -#endif - - if(!_client.tcp) { - DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); - return; - } -#if defined(ESP32) - if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) { -#else - if(_client.tcp->connect(_host.c_str(), _port)) { -#endif - connectedCb(); - _lastConnectionFail = 0; - } else { - connectFailedCb(); - _lastConnectionFail = millis(); - } - } else { - handleClientData(); - - if(_client.status == WSC_CONNECTED) { - handleHBPing(); - handleHBTimeout(&_client); - } - } -} -#endif - -/** - * set callback function - * @param cbEvent WebSocketServerEvent - */ -void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) { - _cbEvent = cbEvent; -} - -/** - * send text data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) { - if(length == 0) { - length = strlen((const char *)payload); - } - if(clientIsConnected(&_client)) { - return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) { - return sendTXT((uint8_t *)payload, length); -} - -bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) { - return sendTXT((uint8_t *)payload, length, headerToPayload); -} - -bool WebSocketsClient::sendTXT(const char * payload, size_t length) { - return sendTXT((uint8_t *)payload, length); -} - -bool WebSocketsClient::sendTXT(String & payload) { - return sendTXT((uint8_t *)payload.c_str(), payload.length()); -} - -bool WebSocketsClient::sendTXT(char payload) { - uint8_t buf[WEBSOCKETS_MAX_HEADER_SIZE + 2] = { 0x00 }; - buf[WEBSOCKETS_MAX_HEADER_SIZE] = payload; - return sendTXT(buf, 1, true); -} - -/** - * send binary data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) { - if(clientIsConnected(&_client)) { - return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) { - return sendBIN((uint8_t *)payload, length); -} - -/** - * sends a WS ping to Server - * @param payload uint8_t * - * @param length size_t - * @return true if ping is send out - */ -bool WebSocketsClient::sendPing(uint8_t * payload, size_t length) { - if(clientIsConnected(&_client)) { - bool sent = sendFrame(&_client, WSop_ping, payload, length); - if(sent) - _client.lastPing = millis(); - return sent; - } - return false; -} - -bool WebSocketsClient::sendPing(String & payload) { - return sendPing((uint8_t *)payload.c_str(), payload.length()); -} - -/** - * disconnect one client - * @param num uint8_t client id - */ -void WebSocketsClient::disconnect(void) { - if(clientIsConnected(&_client)) { - WebSockets::clientDisconnect(&_client, 1000); - } -} - -/** - * set the Authorizatio for the http request - * @param user const char * - * @param password const char * - */ -void WebSocketsClient::setAuthorization(const char * user, const char * password) { - if(user && password) { - String auth = user; - auth += ":"; - auth += password; - _client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length()); - } -} - -/** - * set the Authorizatio for the http request - * @param auth const char * base64 - */ -void WebSocketsClient::setAuthorization(const char * auth) { - if(auth) { - //_client.base64Authorization = auth; - _client.plainAuthorization = auth; - } -} - -/** - * set extra headers for the http request; - * separate headers by "\r\n" - * @param extraHeaders const char * extraHeaders - */ -void WebSocketsClient::setExtraHeaders(const char * extraHeaders) { - _client.extraHeaders = extraHeaders; -} - -/** - * set the reconnect Interval - * how long to wait after a connection initiate failed - * @param time in ms - */ -void WebSocketsClient::setReconnectInterval(unsigned long time) { - _reconnectInterval = time; -} - -bool WebSocketsClient::isConnected(void) { - return (_client.status == WSC_CONNECTED); -} - -//################################################################################# -//################################################################################# -//################################################################################# - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param payload uint8_t * - * @param length size_t - */ -void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { - WStype_t type = WStype_ERROR; - - UNUSED(client); - - switch(opcode) { - case WSop_text: - type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START; - break; - case WSop_binary: - type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START; - break; - case WSop_continuation: - type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT; - break; - case WSop_ping: - type = WStype_PING; - break; - case WSop_pong: - type = WStype_PONG; - break; - case WSop_close: - default: - break; - } - - runCbEvent(type, payload, length); -} - -/** - * Disconnect an client - * @param client WSclient_t * ptr to the client struct - */ -void WebSocketsClient::clientDisconnect(WSclient_t * client) { - bool event = false; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - if(client->isSSL && client->ssl) { - if(client->ssl->connected()) { - client->ssl->flush(); - client->ssl->stop(); - } - event = true; - delete client->ssl; - client->ssl = NULL; - client->tcp = NULL; - } -#endif - - if(client->tcp) { - if(client->tcp->connected()) { -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - client->tcp->flush(); -#endif - client->tcp->stop(); - } - event = true; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->status = WSC_NOT_CONNECTED; -#else - delete client->tcp; -#endif - client->tcp = NULL; - } - - client->cCode = 0; - client->cKey = ""; - client->cAccept = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - client->cSessionId = ""; - - client->status = WSC_NOT_CONNECTED; - - DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n"); - if(event) { - runCbEvent(WStype_DISCONNECTED, NULL, 0); - } -} - -/** - * get client state - * @param client WSclient_t * ptr to the client struct - * @return true = conneted - */ -bool WebSocketsClient::clientIsConnected(WSclient_t * client) { - if(!client->tcp) { - return false; - } - - if(client->tcp->connected()) { - if(client->status != WSC_NOT_CONNECTED) { - return true; - } - } else { - // client lost - if(client->status != WSC_NOT_CONNECTED) { - DEBUG_WEBSOCKETS("[WS-Client] connection lost.\n"); - // do cleanup - clientDisconnect(client); - } - } - - if(client->tcp) { - // do cleanup - clientDisconnect(client); - } - - return false; -} -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * Handel incomming data from Client - */ -void WebSocketsClient::handleClientData(void) { - int len = _client.tcp->available(); - if(len > 0) { - switch(_client.status) { - case WSC_HEADER: { - String headerLine = _client.tcp->readStringUntil('\n'); - handleHeader(&_client, &headerLine); - } break; - case WSC_CONNECTED: - WebSockets::handleWebsocket(&_client); - break; - default: - WebSockets::clientDisconnect(&_client, 1002); - break; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - delay(0); -#endif -} -#endif - -/** - * send the WebSocket header to Server - * @param client WSclient_t * ptr to the client struct - */ -void WebSocketsClient::sendHeader(WSclient_t * client) { - static const char * NEW_LINE = "\r\n"; - - DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n"); - - uint8_t randomKey[16] = { 0 }; - - for(uint8_t i = 0; i < sizeof(randomKey); i++) { - randomKey[i] = random(0xFF); - } - - client->cKey = base64_encode(&randomKey[0], 16); - -#ifndef NODEBUG_WEBSOCKETS - unsigned long start = micros(); -#endif - - String handshake; - bool ws_header = true; - String url = client->cUrl; - - if(client->isSocketIO) { - if(client->cSessionId.length() == 0) { - url += WEBSOCKETS_STRING("&transport=polling"); - ws_header = false; - } else { - url += WEBSOCKETS_STRING("&transport=websocket&sid="); - url += client->cSessionId; - } - } - - handshake = WEBSOCKETS_STRING("GET "); - handshake += url + WEBSOCKETS_STRING( - " HTTP/1.1\r\n" - "Host: "); - handshake += _host + ":" + _port + NEW_LINE; - - if(ws_header) { - handshake += WEBSOCKETS_STRING( - "Connection: Upgrade\r\n" - "Upgrade: websocket\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Key: "); - handshake += client->cKey + NEW_LINE; - - if(client->cProtocol.length() > 0) { - handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: "); - handshake += client->cProtocol + NEW_LINE; - } - - if(client->cExtensions.length() > 0) { - handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: "); - handshake += client->cExtensions + NEW_LINE; - } - } else { - handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n"); - } - - // add extra headers; by default this includes "Origin: file://" - if(client->extraHeaders) { - handshake += client->extraHeaders + NEW_LINE; - } - - handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n"); - - if(client->base64Authorization.length() > 0) { - handshake += WEBSOCKETS_STRING("Authorization: Basic "); - handshake += client->base64Authorization + NEW_LINE; - } - - if(client->plainAuthorization.length() > 0) { - handshake += WEBSOCKETS_STRING("Authorization: "); - handshake += client->plainAuthorization + NEW_LINE; - } - - handshake += NEW_LINE; - - DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str()); - write(client, (uint8_t *)handshake.c_str(), handshake.length()); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine))); -#endif - - DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start)); -} - -/** - * handle the WebSocket header reading - * @param client WSclient_t * ptr to the client struct - */ -void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { - headerLine->trim(); // remove \r - - if(headerLine->length() > 0) { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str()); - - if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) { - // "HTTP/1.1 101 Switching Protocols" - client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt(); - } else if(headerLine->indexOf(':') >= 0) { - String headerName = headerLine->substring(0, headerLine->indexOf(':')); - String headerValue = headerLine->substring(headerLine->indexOf(':') + 1); - - // remove space in the beginning (RFC2616) - if(headerValue[0] == ' ') { - headerValue.remove(0, 1); - } - - if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) { - if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) { - client->cIsUpgrade = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) { - if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) { - client->cIsWebsocket = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) { - client->cAccept = headerValue; - client->cAccept.trim(); // see rfc6455 - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) { - client->cProtocol = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) { - client->cExtensions = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { - client->cVersion = headerValue.toInt(); - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) { - if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) { - client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";")); - } else { - client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1); - } - } - } else { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); - } - - (*headerLine) = ""; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine))); -#endif - } else { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n"); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n"); - - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cURL: %s\n", client->cUrl.c_str()); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cKey: %s\n", client->cKey.c_str()); - - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n"); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cCode: %d\n", client->cCode); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsUpgrade: %d\n", client->cIsUpgrade); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsWebsocket: %d\n", client->cIsWebsocket); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cAccept: %s\n", client->cAccept.c_str()); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str()); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str()); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion); - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str()); - - bool ok = (client->cIsUpgrade && client->cIsWebsocket); - - if(ok) { - switch(client->cCode) { - case 101: ///< Switching Protocols - - break; - case 200: - if(client->isSocketIO) { - break; - } - case 403: ///< Forbidden - // todo handle login - default: ///< Server dont unterstand requrst - ok = false; - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode); - clientDisconnect(client); - _lastConnectionFail = millis(); - break; - } - } - - if(ok) { - if(client->cAccept.length() == 0) { - ok = false; - } else { - // generate Sec-WebSocket-Accept key for check - String sKey = acceptKey(client->cKey); - if(sKey != client->cAccept) { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Sec-WebSocket-Accept is wrong\n"); - ok = false; - } - } - } - - if(ok) { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n"); - headerDone(client); - - runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length()); - } else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) { - if(_client.tcp->available()) { - // read not needed data - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available()); - while(_client.tcp->available() > 0) { - _client.tcp->read(); - } - } - sendHeader(client); - } else { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); - _lastConnectionFail = millis(); - if(clientIsConnected(client)) { - write(client, "This is a webSocket client!"); - } - clientDisconnect(client); - } - } -} - -void WebSocketsClient::connectedCb() { - DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { - DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num); - client->status = WSC_NOT_CONNECTED; - client->tcp = NULL; - - // reconnect - c->asyncConnect(); - - return true; - }, - this, std::placeholders::_1, &_client)); -#endif - - _client.status = WSC_HEADER; - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - // set Timeout for readBytesUntil and readStringUntil - _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); -#endif - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - _client.tcp->setNoDelay(true); -#endif - -#if defined(HAS_SSL) - if(_client.isSSL && _fingerprint.length()) { - if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) { - DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n"); - WebSockets::clientDisconnect(&_client, 1000); - return; - } - } else if(_client.isSSL && !_CA_cert) { -#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h) - _client.ssl->setInsecure(); -#endif - } -#endif - - // send Header to Server - sendHeader(&_client); -} - -void WebSocketsClient::connectFailedCb() { - DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Failed\n", _host.c_str(), _port); -} - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - -void WebSocketsClient::asyncConnect() { - DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n"); - - AsyncClient * tcpclient = new AsyncClient(); - - if(!tcpclient) { - DEBUG_WEBSOCKETS("[WS-Client] creating AsyncClient class failed!\n"); - return; - } - - tcpclient->onDisconnect([](void * obj, AsyncClient * c) { - c->free(); - delete c; - }); - - tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) { - ws->_client.tcp = new AsyncTCPbuffer(tcp); - if(!ws->_client.tcp) { - DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n"); - ws->connectFailedCb(); - return; - } - ws->connectedCb(); - }, - this, std::placeholders::_2)); - - tcpclient->onError(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) { - ws->connectFailedCb(); - - // reconnect - ws->asyncConnect(); - }, - this, std::placeholders::_2)); - - if(!tcpclient->connect(_host.c_str(), _port)) { - connectFailedCb(); - delete tcpclient; - } -} - -#endif - -/** - * send heartbeat ping to server in set intervals - */ -void WebSocketsClient::handleHBPing() { - if(_client.pingInterval == 0) - return; - uint32_t pi = millis() - _client.lastPing; - if(pi > _client.pingInterval) { - DEBUG_WEBSOCKETS("[WS-Client] sending HB ping\n"); - if(sendPing()) { - _client.lastPing = millis(); - _client.pongReceived = false; - } - } -} - -/** - * enable ping/pong heartbeat process - * @param pingInterval uint32_t how often ping will be sent - * @param pongTimeout uint32_t millis after which pong should timout if not received - * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect - */ -void WebSocketsClient::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { - WebSockets::enableHeartbeat(&_client, pingInterval, pongTimeout, disconnectTimeoutCount); -} - -/** - * disable ping/pong heartbeat process - */ -void WebSocketsClient::disableHeartbeat() { - _client.pingInterval = 0; -} diff --git a/3rdparty/WebSockets/src/WebSocketsClient.h b/3rdparty/WebSockets/src/WebSocketsClient.h deleted file mode 100644 index b6fe7387..00000000 --- a/3rdparty/WebSockets/src/WebSocketsClient.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * @file WebSocketsClient.h - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 WEBSOCKETSCLIENT_H_ -#define WEBSOCKETSCLIENT_H_ - -#include "WebSockets.h" - -class WebSocketsClient : protected WebSockets { - public: -#ifdef __AVR__ - typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length); -#else - typedef std::function WebSocketClientEvent; -#endif - - WebSocketsClient(void); - virtual ~WebSocketsClient(void); - - void begin(const char * host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); - void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); - void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); - -#if defined(HAS_SSL) - void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino"); - void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino"); - void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino"); -#endif - - void beginSocketIO(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); - void beginSocketIO(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); - -#if defined(HAS_SSL) - void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); - void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); - void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino"); -#endif - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void loop(void); -#else - // Async interface not need a loop call - void loop(void) __attribute__((deprecated)) {} -#endif - - void onEvent(WebSocketClientEvent cbEvent); - - bool sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(const uint8_t * payload, size_t length = 0); - bool sendTXT(char * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(const char * payload, size_t length = 0); - bool sendTXT(String & payload); - bool sendTXT(char payload); - - bool sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false); - bool sendBIN(const uint8_t * payload, size_t length); - - bool sendPing(uint8_t * payload = NULL, size_t length = 0); - bool sendPing(String & payload); - - void disconnect(void); - - void setAuthorization(const char * user, const char * password); - void setAuthorization(const char * auth); - - void setExtraHeaders(const char * extraHeaders = NULL); - - void setReconnectInterval(unsigned long time); - - void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); - void disableHeartbeat(); - - protected: - String _host; - uint16_t _port; - - bool isConnected(void); - -#if defined(HAS_SSL) - String _fingerprint; - const char * _CA_cert; -#endif - WSclient_t _client; - - WebSocketClientEvent _cbEvent; - - unsigned long _lastConnectionFail; - unsigned long _reconnectInterval; - - void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); - - void clientDisconnect(WSclient_t * client); - bool clientIsConnected(WSclient_t * client); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void handleClientData(void); -#endif - - void sendHeader(WSclient_t * client); - void handleHeader(WSclient_t * client, String * headerLine); - - void connectedCb(); - void connectFailedCb(); - - void handleHBPing(); // send ping in specified intervals - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - void asyncConnect(); -#endif - - /** - * called for sending a Event to the app - * @param type WStype_t - * @param payload uint8_t * - * @param length size_t - */ - virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { - if(_cbEvent) { - _cbEvent(type, payload, length); - } - } -}; - -#endif /* WEBSOCKETSCLIENT_H_ */ diff --git a/3rdparty/WebSockets/src/WebSocketsServer.cpp b/3rdparty/WebSockets/src/WebSocketsServer.cpp deleted file mode 100644 index 633e34c2..00000000 --- a/3rdparty/WebSockets/src/WebSocketsServer.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/** - * @file WebSocketsServer.cpp - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 - * - */ - -#include "WebSockets.h" -#include "WebSocketsServer.h" - -WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) { - _port = port; - _origin = origin; - _protocol = protocol; - _runnning = false; - - _server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _server->onClient([](void * s, AsyncClient * c) { - ((WebSocketsServer *)s)->newClient(new AsyncTCPbuffer(c)); - }, - this); -#endif - - _cbEvent = NULL; - - _httpHeaderValidationFunc = NULL; - _mandatoryHttpHeaders = NULL; - _mandatoryHttpHeaderCount = 0; - - memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX)); -} - -WebSocketsServer::~WebSocketsServer() { - // disconnect all clients - close(); - - if(_mandatoryHttpHeaders) - delete[] _mandatoryHttpHeaders; - - _mandatoryHttpHeaderCount = 0; -} - -/** - * called to initialize the Websocket server - */ -void WebSocketsServer::begin(void) { - WSclient_t * client; - - // init client storage - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - - client->num = i; - client->status = WSC_NOT_CONNECTED; - client->tcp = NULL; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - client->isSSL = false; - client->ssl = NULL; -#endif - client->cUrl = ""; - client->cCode = 0; - client->cKey = ""; - client->cProtocol = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - - client->base64Authorization = ""; - - client->cWsRXsize = 0; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; -#endif - } - -#ifdef ESP8266 - randomSeed(RANDOM_REG32); -#elif defined(ESP32) -#define DR_REG_RNG_BASE 0x3ff75144 - randomSeed(READ_PERI_REG(DR_REG_RNG_BASE)); -#else - // TODO find better seed - randomSeed(millis()); -#endif - - _runnning = true; - _server->begin(); - - DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); -} - -void WebSocketsServer::close(void) { - _runnning = false; - disconnect(); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - _server->close(); -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _server->end(); -#else - // TODO how to close server? -#endif -} - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * called in arduino loop - */ -void WebSocketsServer::loop(void) { - if(_runnning) { - handleNewClients(); - handleClientData(); - } -} -#endif - -/** - * set callback function - * @param cbEvent WebSocketServerEvent - */ -void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) { - _cbEvent = cbEvent; -} - -/* - * Sets the custom http header validator function - * @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function - * @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed - * @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array - */ -void WebSocketsServer::onValidateHttpHeader( - WebSocketServerHttpHeaderValFunc validationFunc, - const char * mandatoryHttpHeaders[], - size_t mandatoryHttpHeaderCount) { - _httpHeaderValidationFunc = validationFunc; - - if(_mandatoryHttpHeaders) - delete[] _mandatoryHttpHeaders; - - _mandatoryHttpHeaderCount = mandatoryHttpHeaderCount; - _mandatoryHttpHeaders = new String[_mandatoryHttpHeaderCount]; - - for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { - _mandatoryHttpHeaders[i] = mandatoryHttpHeaders[i]; - } -} - -/* - * send text data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - if(length == 0) { - length = strlen((const char *)payload); - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_text, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { - return sendTXT(num, (uint8_t *)payload, length); -} - -bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { - return sendTXT(num, (uint8_t *)payload, length, headerToPayload); -} - -bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) { - return sendTXT(num, (uint8_t *)payload, length); -} - -bool WebSocketsServer::sendTXT(uint8_t num, String & payload) { - return sendTXT(num, (uint8_t *)payload.c_str(), payload.length()); -} - -/** - * send text data to client all - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { - WSclient_t * client; - bool ret = true; - if(length == 0) { - length = strlen((const char *)payload); - } - - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_text, payload, length, true, headerToPayload)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) { - return broadcastTXT((uint8_t *)payload, length); -} - -bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) { - return broadcastTXT((uint8_t *)payload, length, headerToPayload); -} - -bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) { - return broadcastTXT((uint8_t *)payload, length); -} - -bool WebSocketsServer::broadcastTXT(String & payload) { - return broadcastTXT((uint8_t *)payload.c_str(), payload.length()); -} - -/** - * send binary data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_binary, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { - return sendBIN(num, (uint8_t *)payload, length); -} - -/** - * send binary data to client all - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { - WSclient_t * client; - bool ret = true; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_binary, payload, length, true, headerToPayload)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) { - return broadcastBIN((uint8_t *)payload, length); -} - -/** - * sends a WS ping to Client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @return true if ping is send out - */ -bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_ping, payload, length); - } - return false; -} - -bool WebSocketsServer::sendPing(uint8_t num, String & payload) { - return sendPing(num, (uint8_t *)payload.c_str(), payload.length()); -} - -/** - * sends a WS ping to all Client - * @param payload uint8_t * - * @param length size_t - * @return true if ping is send out - */ -bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) { - WSclient_t * client; - bool ret = true; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_ping, payload, length)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastPing(String & payload) { - return broadcastPing((uint8_t *)payload.c_str(), payload.length()); -} - -/** - * disconnect all clients - */ -void WebSocketsServer::disconnect(void) { - WSclient_t * client; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - WebSockets::clientDisconnect(client, 1000); - } - } -} - -/** - * disconnect one client - * @param num uint8_t client id - */ -void WebSocketsServer::disconnect(uint8_t num) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - WebSockets::clientDisconnect(client, 1000); - } -} - -/* - * set the Authorization for the http request - * @param user const char * - * @param password const char * - */ -void WebSocketsServer::setAuthorization(const char * user, const char * password) { - if(user && password) { - String auth = user; - auth += ":"; - auth += password; - _base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length()); - } -} - -/** - * set the Authorizatio for the http request - * @param auth const char * base64 - */ -void WebSocketsServer::setAuthorization(const char * auth) { - if(auth) { - _base64Authorization = auth; - } -} - -/** - * count the connected clients (optional ping them) - * @param ping bool ping the connected clients - */ -int WebSocketsServer::connectedClients(bool ping) { - WSclient_t * client; - int count = 0; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(client->status == WSC_CONNECTED) { - if(ping != true || sendPing(i)) { - count++; - } - } - } - return count; -} - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) -/** - * get an IP for a client - * @param num uint8_t client id - * @return IPAddress - */ -IPAddress WebSocketsServer::remoteIP(uint8_t num) { - if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return client->tcp->remoteIP(); - } - } - - return IPAddress(); -} -#endif - -//################################################################################# -//################################################################################# -//################################################################################# - -/** - * handle new client connection - * @param client - */ -bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { - WSclient_t * client; - // search free list entry for client - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - - // state is not connected or tcp connection is lost - if(!clientIsConnected(client)) { - client->tcp = TCPclient; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - client->isSSL = false; - client->tcp->setNoDelay(true); -#endif -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - // set Timeout for readBytesUntil and readStringUntil - client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); -#endif - client->status = WSC_HEADER; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress ip = client->tcp->remoteIP(); - DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]); -#else - DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num); -#endif - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { - DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num); - - AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp; - if(*sl == obj) { - client->status = WSC_NOT_CONNECTED; - *sl = NULL; - } - return true; - }, - this, std::placeholders::_1, client)); - - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); -#endif - - return true; - break; - } - } - return false; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param payload uint8_t * - * @param length size_t - */ -void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { - WStype_t type = WStype_ERROR; - - switch(opcode) { - case WSop_text: - type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START; - break; - case WSop_binary: - type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START; - break; - case WSop_continuation: - type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT; - break; - case WSop_ping: - type = WStype_PING; - break; - case WSop_pong: - type = WStype_PONG; - break; - case WSop_close: - default: - break; - } - - runCbEvent(client->num, type, payload, length); -} - -/** - * Disconnect an client - * @param client WSclient_t * ptr to the client struct - */ -void WebSocketsServer::clientDisconnect(WSclient_t * client) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - if(client->isSSL && client->ssl) { - if(client->ssl->connected()) { - client->ssl->flush(); - client->ssl->stop(); - } - delete client->ssl; - client->ssl = NULL; - client->tcp = NULL; - } -#endif - - if(client->tcp) { - if(client->tcp->connected()) { -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - client->tcp->flush(); -#endif - client->tcp->stop(); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->status = WSC_NOT_CONNECTED; -#else - delete client->tcp; -#endif - client->tcp = NULL; - } - - client->cUrl = ""; - client->cKey = ""; - client->cProtocol = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - - client->cWsRXsize = 0; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; -#endif - - client->status = WSC_NOT_CONNECTED; - - DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num); - - runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0); -} - -/** - * get client state - * @param client WSclient_t * ptr to the client struct - * @return true = connected - */ -bool WebSocketsServer::clientIsConnected(WSclient_t * client) { - if(!client->tcp) { - return false; - } - - if(client->tcp->connected()) { - if(client->status != WSC_NOT_CONNECTED) { - return true; - } - } else { - // client lost - if(client->status != WSC_NOT_CONNECTED) { - DEBUG_WEBSOCKETS("[WS-Server][%d] client connection lost.\n", client->num); - // do cleanup - clientDisconnect(client); - } - } - - if(client->tcp) { - // do cleanup - DEBUG_WEBSOCKETS("[WS-Server][%d] client list cleanup.\n", client->num); - clientDisconnect(client); - } - - return false; -} -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * Handle incoming Connection Request - */ -void WebSocketsServer::handleNewClients(void) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - while(_server->hasClient()) { -#endif - bool ok = false; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - // store new connection - WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#else - WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#endif - - if(!tcpClient) { - DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); - return; - } - - ok = newClient(tcpClient); - - if(!ok) { - // no free space to handle client -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress ip = tcpClient->remoteIP(); - DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); -#else - DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n"); -#endif - tcpClient->stop(); - } - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - delay(0); - } -#endif -} - -/** - * Handel incomming data from Client - */ -void WebSocketsServer::handleClientData(void) { - WSclient_t * client; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - int len = client->tcp->available(); - if(len > 0) { - //DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len); - switch(client->status) { - case WSC_HEADER: { - String headerLine = client->tcp->readStringUntil('\n'); - handleHeader(client, &headerLine); - } break; - case WSC_CONNECTED: - WebSockets::handleWebsocket(client); - break; - default: - WebSockets::clientDisconnect(client, 1002); - break; - } - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } -} -#endif - -/* - * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection - * @param headerName String ///< the name of the header being checked - */ -bool WebSocketsServer::hasMandatoryHeader(String headerName) { - for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { - if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName)) - return true; - } - return false; -} - -/** - * handles http header reading for WebSocket upgrade - * @param client WSclient_t * ///< pointer to the client struct - * @param headerLine String ///< the header being read / processed - */ -void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { - static const char * NEW_LINE = "\r\n"; - - headerLine->trim(); // remove \r - - if(headerLine->length() > 0) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str()); - - // websocket requests always start with GET see rfc6455 - if(headerLine->startsWith("GET ")) { - // cut URL out - client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4)); - - //reset non-websocket http header validation state for this client - client->cHttpHeadersValid = true; - client->cMandatoryHeadersCount = 0; - - } else if(headerLine->indexOf(':') >= 0) { - String headerName = headerLine->substring(0, headerLine->indexOf(':')); - String headerValue = headerLine->substring(headerLine->indexOf(':') + 1); - - // remove space in the beginning (RFC2616) - if(headerValue[0] == ' ') { - headerValue.remove(0, 1); - } - - if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) { - headerValue.toLowerCase(); - if(headerValue.indexOf(WEBSOCKETS_STRING("upgrade")) >= 0) { - client->cIsUpgrade = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) { - if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) { - client->cIsWebsocket = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { - client->cVersion = headerValue.toInt(); - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Key"))) { - client->cKey = headerValue; - client->cKey.trim(); // see rfc6455 - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) { - client->cProtocol = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) { - client->cExtensions = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Authorization"))) { - client->base64Authorization = headerValue; - } else { - client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue); - if(_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) { - client->cMandatoryHeadersCount++; - } - } - - } else { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); - } - - (*headerLine) = ""; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); -#endif - } else { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount); - - bool ok = (client->cIsUpgrade && client->cIsWebsocket); - - if(ok) { - if(client->cUrl.length() == 0) { - ok = false; - } - if(client->cKey.length() == 0) { - ok = false; - } - if(client->cVersion != 13) { - ok = false; - } - if(!client->cHttpHeadersValid) { - ok = false; - } - if(client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) { - ok = false; - } - } - - if(_base64Authorization.length() > 0) { - String auth = WEBSOCKETS_STRING("Basic "); - auth += _base64Authorization; - if(auth != client->base64Authorization) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num); - handleAuthorizationFailed(client); - return; - } - } - - if(ok) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num); - - // generate Sec-WebSocket-Accept key - String sKey = acceptKey(client->cKey); - - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - sKey: %s\n", client->num, sKey.c_str()); - - client->status = WSC_CONNECTED; - - String handshake = WEBSOCKETS_STRING( - "HTTP/1.1 101 Switching Protocols\r\n" - "Server: arduino-WebSocketsServer\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Accept: "); - handshake += sKey + NEW_LINE; - - if(_origin.length() > 0) { - handshake += WEBSOCKETS_STRING("Access-Control-Allow-Origin: "); - handshake += _origin + NEW_LINE; - } - - if(client->cProtocol.length() > 0) { - handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: "); - handshake += _protocol + NEW_LINE; - } - - // header end - handshake += NEW_LINE; - - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] handshake %s", client->num, (uint8_t *)handshake.c_str()); - - write(client, (uint8_t *)handshake.c_str(), handshake.length()); - - headerDone(client); - - // send ping - WebSockets::sendFrame(client, WSop_ping); - - runCbEvent(client->num, WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length()); - - } else { - handleNonWebsocketConnection(client); - } - } -} diff --git a/3rdparty/WebSockets/src/WebSocketsServer.h b/3rdparty/WebSockets/src/WebSocketsServer.h deleted file mode 100644 index 60144a12..00000000 --- a/3rdparty/WebSockets/src/WebSocketsServer.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @file WebSocketsServer.h - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 WEBSOCKETSSERVER_H_ -#define WEBSOCKETSSERVER_H_ - -#include "WebSockets.h" - -#ifndef WEBSOCKETS_SERVER_CLIENT_MAX -#define WEBSOCKETS_SERVER_CLIENT_MAX (5) -#endif - -class WebSocketsServer : protected WebSockets { - public: -#ifdef __AVR__ - typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); - typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue); -#else - typedef std::function WebSocketServerEvent; - typedef std::function WebSocketServerHttpHeaderValFunc; -#endif - - WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino"); - virtual ~WebSocketsServer(void); - - void begin(void); - void close(void); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void loop(void); -#else - // Async interface not need a loop call - void loop(void) __attribute__((deprecated)) {} -#endif - - void onEvent(WebSocketServerEvent cbEvent); - void onValidateHttpHeader( - WebSocketServerHttpHeaderValFunc validationFunc, - const char * mandatoryHttpHeaders[], - size_t mandatoryHttpHeaderCount); - - bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0); - bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(uint8_t num, const char * payload, size_t length = 0); - bool sendTXT(uint8_t num, String & payload); - - bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool broadcastTXT(const uint8_t * payload, size_t length = 0); - bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false); - bool broadcastTXT(const char * payload, size_t length = 0); - bool broadcastTXT(String & payload); - - bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false); - bool sendBIN(uint8_t num, const uint8_t * payload, size_t length); - - bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false); - bool broadcastBIN(const uint8_t * payload, size_t length); - - bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0); - bool sendPing(uint8_t num, String & payload); - - bool broadcastPing(uint8_t * payload = NULL, size_t length = 0); - bool broadcastPing(String & payload); - - void disconnect(void); - void disconnect(uint8_t num); - - void setAuthorization(const char * user, const char * password); - void setAuthorization(const char * auth); - - int connectedClients(bool ping = false); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress remoteIP(uint8_t num); -#endif - - protected: - uint16_t _port; - String _origin; - String _protocol; - String _base64Authorization; ///< Base64 encoded Auth request - String * _mandatoryHttpHeaders; - size_t _mandatoryHttpHeaderCount; - - WEBSOCKETS_NETWORK_SERVER_CLASS * _server; - - WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; - - WebSocketServerEvent _cbEvent; - WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc; - - bool _runnning; - - bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); - - void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); - - void clientDisconnect(WSclient_t * client); - bool clientIsConnected(WSclient_t * client); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void handleNewClients(void); - void handleClientData(void); -#endif - - void handleHeader(WSclient_t * client, String * headerLine); - - /** - * called if a non Websocket connection is coming in. - * Note: can be override - * @param client WSclient_t * ptr to the client struct - */ - virtual void handleNonWebsocketConnection(WSclient_t * client) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num); - client->tcp->write( - "HTTP/1.1 400 Bad Request\r\n" - "Server: arduino-WebSocket-Server\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 32\r\n" - "Connection: close\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n" - "This is a Websocket server only!"); - clientDisconnect(client); - } - - /** - * called if a non Authorization connection is coming in. - * Note: can be override - * @param client WSclient_t * ptr to the client struct - */ - virtual void handleAuthorizationFailed(WSclient_t * client) { - client->tcp->write( - "HTTP/1.1 401 Unauthorized\r\n" - "Server: arduino-WebSocket-Server\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 45\r\n" - "Connection: close\r\n" - "Sec-WebSocket-Version: 13\r\n" - "WWW-Authenticate: Basic realm=\"WebSocket Server\"" - "\r\n" - "This Websocket server requires Authorization!"); - clientDisconnect(client); - } - - /** - * called for sending a Event to the app - * @param num uint8_t - * @param type WStype_t - * @param payload uint8_t * - * @param length size_t - */ - virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - if(_cbEvent) { - _cbEvent(num, type, payload, length); - } - } - - /* - * Called at client socket connect handshake negotiation time for each http header that is not - * a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*) - * If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the - * socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected - * This mechanism can be used to enable custom authentication schemes e.g. test the value - * of a session cookie to determine if a user is logged on / authenticated - */ - virtual bool execHttpHeaderValidation(String headerName, String headerValue) { - if(_httpHeaderValidationFunc) { - //return the value of the custom http header validation function - return _httpHeaderValidationFunc(headerName, headerValue); - } - //no custom http header validation so just assume all is good - return true; - } - - private: - /* - * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection - * @param headerName String ///< the name of the header being checked - */ - bool hasMandatoryHeader(String headerName); -}; - -#endif /* WEBSOCKETSSERVER_H_ */ diff --git a/3rdparty/WebSockets/src/libb64/AUTHORS b/3rdparty/WebSockets/src/libb64/AUTHORS deleted file mode 100644 index af687375..00000000 --- a/3rdparty/WebSockets/src/libb64/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -libb64: Base64 Encoding/Decoding Routines -====================================== - -Authors: -------- - -Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com diff --git a/3rdparty/WebSockets/src/libb64/LICENSE b/3rdparty/WebSockets/src/libb64/LICENSE deleted file mode 100644 index a6b56069..00000000 --- a/3rdparty/WebSockets/src/libb64/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Copyright-Only Dedication (based on United States law) -or Public Domain Certification - -The person or persons who have associated work with this document (the -"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of -his knowledge, the work of authorship identified is in the public domain of the -country from which the work is published, or (b) hereby dedicates whatever -copyright the dedicators holds in the work of authorship identified below (the -"Work") to the public domain. A certifier, moreover, dedicates any copyright -interest he may have in the associated work, and for these purposes, is -described as a "dedicator" below. - -A certifier has taken reasonable steps to verify the copyright status of this -work. Certifier recognizes that his good faith efforts may not shield him from -liability if in fact the work certified is not in the public domain. - -Dedicator makes this dedication for the benefit of the public at large and to -the detriment of the Dedicator's heirs and successors. Dedicator intends this -dedication to be an overt act of relinquishment in perpetuity of all present -and future rights under copyright law, whether vested or contingent, in the -Work. Dedicator understands that such relinquishment of all rights includes -the relinquishment of all rights to enforce (by lawsuit or otherwise) those -copyrights in the Work. - -Dedicator recognizes that, once placed in the public domain, the Work may be -freely reproduced, distributed, transmitted, used, modified, built upon, or -otherwise exploited by anyone for any purpose, commercial or non-commercial, -and in any way, including by methods that have not yet been invented or -conceived. \ No newline at end of file diff --git a/3rdparty/WebSockets/src/libb64/cdecode.c b/3rdparty/WebSockets/src/libb64/cdecode.c deleted file mode 100644 index e135da24..00000000 --- a/3rdparty/WebSockets/src/libb64/cdecode.c +++ /dev/null @@ -1,98 +0,0 @@ -/* -cdecoder.c - c source to a base64 decoding algorithm implementation - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifdef ESP8266 -#include -#endif - -#if defined(ESP32) -#define CORE_HAS_LIBB64 -#endif - -#ifndef CORE_HAS_LIBB64 -#include "cdecode_inc.h" - -int base64_decode_value(char value_in) -{ - static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; - static const char decoding_size = sizeof(decoding); - value_in -= 43; - if (value_in < 0 || value_in > decoding_size) return -1; - return decoding[(int)value_in]; -} - -void base64_init_decodestate(base64_decodestate* state_in) -{ - state_in->step = step_a; - state_in->plainchar = 0; -} - -int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) -{ - const char* codechar = code_in; - char* plainchar = plaintext_out; - char fragment; - - *plainchar = state_in->plainchar; - - switch (state_in->step) - { - while (1) - { - case step_a: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_a; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = (char)base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar = (fragment & 0x03f) << 2; - case step_b: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_b; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = (char)base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x030) >> 4; - *plainchar = (fragment & 0x00f) << 4; - case step_c: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_c; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = (char)base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x03c) >> 2; - *plainchar = (fragment & 0x003) << 6; - case step_d: - do { - if (codechar == code_in+length_in) - { - state_in->step = step_d; - state_in->plainchar = *plainchar; - return plainchar - plaintext_out; - } - fragment = (char)base64_decode_value(*codechar++); - } while (fragment < 0); - *plainchar++ |= (fragment & 0x03f); - } - } - /* control should not reach here */ - return plainchar - plaintext_out; -} - -#endif diff --git a/3rdparty/WebSockets/src/libb64/cdecode_inc.h b/3rdparty/WebSockets/src/libb64/cdecode_inc.h deleted file mode 100644 index d0d7f489..00000000 --- a/3rdparty/WebSockets/src/libb64/cdecode_inc.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -cdecode.h - c header for a base64 decoding algorithm - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifndef BASE64_CDECODE_H -#define BASE64_CDECODE_H - -typedef enum -{ - step_a, step_b, step_c, step_d -} base64_decodestep; - -typedef struct -{ - base64_decodestep step; - char plainchar; -} base64_decodestate; - -void base64_init_decodestate(base64_decodestate* state_in); - -int base64_decode_value(char value_in); - -int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); - -#endif /* BASE64_CDECODE_H */ diff --git a/3rdparty/WebSockets/src/libb64/cencode.c b/3rdparty/WebSockets/src/libb64/cencode.c deleted file mode 100644 index afe1463c..00000000 --- a/3rdparty/WebSockets/src/libb64/cencode.c +++ /dev/null @@ -1,119 +0,0 @@ -/* -cencoder.c - c source to a base64 encoding algorithm implementation - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifdef ESP8266 -#include -#endif - -#if defined(ESP32) -#define CORE_HAS_LIBB64 -#endif - -#ifndef CORE_HAS_LIBB64 -#include "cencode_inc.h" - -const int CHARS_PER_LINE = 72; - -void base64_init_encodestate(base64_encodestate* state_in) -{ - state_in->step = step_A; - state_in->result = 0; - state_in->stepcount = 0; -} - -char base64_encode_value(char value_in) -{ - static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - if (value_in > 63) return '='; - return encoding[(int)value_in]; -} - -int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) -{ - const char* plainchar = plaintext_in; - const char* const plaintextend = plaintext_in + length_in; - char* codechar = code_out; - char result; - char fragment; - - result = state_in->result; - - switch (state_in->step) - { - while (1) - { - case step_A: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_A; - return codechar - code_out; - } - fragment = *plainchar++; - result = (fragment & 0x0fc) >> 2; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x003) << 4; - case step_B: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_B; - return codechar - code_out; - } - fragment = *plainchar++; - result |= (fragment & 0x0f0) >> 4; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x00f) << 2; - case step_C: - if (plainchar == plaintextend) - { - state_in->result = result; - state_in->step = step_C; - return codechar - code_out; - } - fragment = *plainchar++; - result |= (fragment & 0x0c0) >> 6; - *codechar++ = base64_encode_value(result); - result = (fragment & 0x03f) >> 0; - *codechar++ = base64_encode_value(result); - - ++(state_in->stepcount); - if (state_in->stepcount == CHARS_PER_LINE/4) - { - *codechar++ = '\n'; - state_in->stepcount = 0; - } - } - } - /* control should not reach here */ - return codechar - code_out; -} - -int base64_encode_blockend(char* code_out, base64_encodestate* state_in) -{ - char* codechar = code_out; - - switch (state_in->step) - { - case step_B: - *codechar++ = base64_encode_value(state_in->result); - *codechar++ = '='; - *codechar++ = '='; - break; - case step_C: - *codechar++ = base64_encode_value(state_in->result); - *codechar++ = '='; - break; - case step_A: - break; - } - *codechar++ = 0x00; - - return codechar - code_out; -} - -#endif diff --git a/3rdparty/WebSockets/src/libb64/cencode_inc.h b/3rdparty/WebSockets/src/libb64/cencode_inc.h deleted file mode 100644 index c1e3464a..00000000 --- a/3rdparty/WebSockets/src/libb64/cencode_inc.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -cencode.h - c header for a base64 encoding algorithm - -This is part of the libb64 project, and has been placed in the public domain. -For details, see http://sourceforge.net/projects/libb64 -*/ - -#ifndef BASE64_CENCODE_H -#define BASE64_CENCODE_H - -typedef enum -{ - step_A, step_B, step_C -} base64_encodestep; - -typedef struct -{ - base64_encodestep step; - char result; - int stepcount; -} base64_encodestate; - -void base64_init_encodestate(base64_encodestate* state_in); - -char base64_encode_value(char value_in); - -int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); - -int base64_encode_blockend(char* code_out, base64_encodestate* state_in); - -#endif /* BASE64_CENCODE_H */ diff --git a/3rdparty/WebSockets/src/libsha1/libsha1.c b/3rdparty/WebSockets/src/libsha1/libsha1.c deleted file mode 100644 index 48f4df5a..00000000 --- a/3rdparty/WebSockets/src/libsha1/libsha1.c +++ /dev/null @@ -1,202 +0,0 @@ -/* from valgrind tests */ - -/* ================ sha1.c ================ */ -/* -SHA-1 in C -By Steve Reid -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#if !defined(ESP8266) && !defined(ESP32) - -#define SHA1HANDSOFF - -#include -#include -#include - -#include "libsha1.h" - - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN -#define blk0(i) block->l[i] -#else -#error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) -{ - uint32_t a, b, c, d, e; - typedef union { - unsigned char c[64]; - uint32_t l[16]; - } CHAR64LONG16; -#ifdef SHA1HANDSOFF - CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ - CHAR64LONG16* block = (const CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len) -{ - uint32_t i, j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len>>29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ - unsigned i; - unsigned char finalcount[8]; - unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) - { - uint32_t t = context->count[i]; - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t; - } -#else - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } -#endif - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} -/* ================ end of sha1.c ================ */ - - -#endif diff --git a/3rdparty/WebSockets/src/libsha1/libsha1.h b/3rdparty/WebSockets/src/libsha1/libsha1.h deleted file mode 100644 index ee3718e1..00000000 --- a/3rdparty/WebSockets/src/libsha1/libsha1.h +++ /dev/null @@ -1,21 +0,0 @@ -/* ================ sha1.h ================ */ -/* -SHA-1 in C -By Steve Reid -100% Public Domain -*/ - -#if !defined(ESP8266) && !defined(ESP32) - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); - -#endif diff --git a/3rdparty/WebSockets/tests/webSocket.html b/3rdparty/WebSockets/tests/webSocket.html deleted file mode 100644 index 66a27089..00000000 --- a/3rdparty/WebSockets/tests/webSocket.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - -LED Control:
-
-R:
-G:
-B:
- - \ No newline at end of file diff --git a/3rdparty/WebSockets/tests/webSocketServer/index.js b/3rdparty/WebSockets/tests/webSocketServer/index.js deleted file mode 100644 index 389e1930..00000000 --- a/3rdparty/WebSockets/tests/webSocketServer/index.js +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env node -var WebSocketServer = require('websocket').server; -var http = require('http'); - -var server = http.createServer(function(request, response) { - console.log((new Date()) + ' Received request for ' + request.url); - response.writeHead(404); - response.end(); -}); -server.listen(8011, function() { - console.log((new Date()) + ' Server is listening on port 8011'); -}); - -wsServer = new WebSocketServer({ - httpServer: server, - // You should not use autoAcceptConnections for production - // applications, as it defeats all standard cross-origin protection - // facilities built into the protocol and the browser. You should - // *always* verify the connection's origin and decide whether or not - // to accept it. - autoAcceptConnections: false -}); - -function originIsAllowed(origin) { - // put logic here to detect whether the specified origin is allowed. - return true; -} - -wsServer.on('request', function(request) { - - if (!originIsAllowed(request.origin)) { - // Make sure we only accept requests from an allowed origin - request.reject(); - console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.'); - return; - } - - var connection = request.accept('arduino', request.origin); - console.log((new Date()) + ' Connection accepted.'); - - connection.on('message', function(message) { - if (message.type === 'utf8') { - console.log('Received Message: ' + message.utf8Data); - // connection.sendUTF(message.utf8Data); - } - else if (message.type === 'binary') { - console.log('Received Binary Message of ' + message.binaryData.length + ' bytes'); - //connection.sendBytes(message.binaryData); - } - }); - - connection.on('close', function(reasonCode, description) { - console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); - }); - - connection.sendUTF("Hallo Client!"); -}); diff --git a/3rdparty/WebSockets/tests/webSocketServer/package.json b/3rdparty/WebSockets/tests/webSocketServer/package.json deleted file mode 100644 index 9538323e..00000000 --- a/3rdparty/WebSockets/tests/webSocketServer/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "webSocketServer", - "version": "1.0.0", - "description": "WebSocketServer for testing", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/Links2004/arduinoWebSockets" - }, - "keywords": [ - "esp8266", - "websocket", - "arduino" - ], - "author": "Markus Sattler", - "license": "LGPLv2", - "bugs": { - "url": "https://github.com/Links2004/arduinoWebSockets/issues" - }, - "homepage": "https://github.com/Links2004/arduinoWebSockets", - "dependencies": { - "websocket": "^1.0.18" - } -} diff --git a/3rdparty/WebSockets/travis/common.sh b/3rdparty/WebSockets/travis/common.sh deleted file mode 100644 index be959faf..00000000 --- a/3rdparty/WebSockets/travis/common.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -function build_sketches() -{ - local arduino=$1 - local srcpath=$2 - local platform=$3 - local sketches=$(find $srcpath -name *.ino) - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - if [[ -f "$sketchdir/.$platform.skip" ]]; then - echo -e "\n\n ------------ Skipping $sketch ------------ \n\n"; - continue - fi - echo -e "\n\n ------------ Building $sketch ------------ \n\n"; - $arduino --verify $sketch; - local result=$? - if [ $result -ne 0 ]; then - echo "Build failed ($sketch) build verbose..." - $arduino --verify --verbose --preserve-temp-files $sketch - result=$? - fi - if [ $result -ne 0 ]; then - echo "Build failed ($1) $sketch" - return $result - fi - done -} - - -function get_core() -{ - echo Setup core for $1 - - cd $HOME/arduino_ide/hardware - - if [ "$1" = "esp8266" ] ; then - mkdir esp8266com - cd esp8266com - git clone https://github.com/esp8266/Arduino.git esp8266 - cd esp8266/tools - python get.py - fi - - if [ "$1" = "esp32" ] ; then - mkdir espressif - cd espressif - git clone https://github.com/espressif/arduino-esp32.git esp32 - cd esp32/tools - python get.py - fi - -} diff --git a/OLEDMenuConfig.h b/OLEDMenuConfig.h deleted file mode 100644 index ad5534cc..00000000 --- a/OLEDMenuConfig.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - See https://github.com/PSHarold/OLED-SSD1306-Menu - for original code, license and documentation -*/ -#ifndef OLED_MENU_CONFIG_H_ -#define OLED_MENU_CONFIG_H_ -// include your translations here -#include "OLEDMenuTranslations.h" -#define OLED_MENU_WIDTH 128 -#define OLED_MENU_HEIGHT 64 -#define OLED_MENU_MAX_SUBITEMS_NUM 16 // should be less than 256 -#define OLED_MENU_MAX_ITEMS_NUM 64 // should be less than 1024 -#define OLED_MENU_MAX_DEPTH 8 // maximum levels of submenus -#define OLED_MENU_REFRESH_INTERVAL_IN_MS 50 // not precise -#define OLED_MENU_SCREEN_SAVER_REFRESH_INTERVAL_IN_MS 5000 // not precise -#define OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS 600 // milliseconds before items start to scroll after being selected -#define OLED_MENU_SCREEN_SAVER_KICK_IN_SECONDS 180 // after "OLED_MENU_SCREEN_SAVE_KICK_IN_SECONDS" seconds, screen saver will show up until any key is pressed -#define OLED_MENU_OVER_DRAW 0 // if set to 0, the last menu item of a page will not be drawn at all if partially outside the screen, and you need to scroll down to see them -#define OLED_MENU_RESET_ALWAYS_SCROLL_ON_SELECTION 0 // if set 1, scrolling items will reset to original position on selection -#define OLED_MENU_WRAPPING_SPACE (OLED_MENU_WIDTH / 3) -#define REVERSE_ROTARY_ENCODER_FOR_OLED_MENU 0 // if set 1, rotary encoder will be reversed for menu navigation -#define REVERSE_ROTARY_ENCODER_FOR_OSD 0 // if set 1, rotary encoder will be reversed for OSD navigation -#define OSD_TIMEOUT 8000 // OSD will disappear after OSD_TIMEOUT milliseconds without inputs - -// do not edit these -#define OLED_MENU_STATUS_BAR_HEIGHT (OLED_MENU_HEIGHT / 4) // status bar uses 1/4 of the screen -#define OLED_MENU_USABLE_AREA_HEIGHT (OLED_MENU_HEIGHT - OLED_MENU_STATUS_BAR_HEIGHT) -#define OLED_MENU_SCROLL_LEAD_IN_FRAMES (OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS / OLED_MENU_REFRESH_INTERVAL_IN_MS) -#endif \ No newline at end of file diff --git a/OLEDMenuImplementation.cpp b/OLEDMenuImplementation.cpp deleted file mode 100644 index 72a9a7d6..00000000 --- a/OLEDMenuImplementation.cpp +++ /dev/null @@ -1,417 +0,0 @@ -#define OSD_TIMEOUT 8000 - -#include -#include "OLEDMenuImplementation.h" -#include "options.h" -#include "tv5725.h" -#include "slot.h" -#include "src/WebSockets.h" -#include "src/WebSocketsServer.h" -#include "fonts.h" -#include "OSDManager.h" - -typedef TV5725 GBS; -extern void applyPresets(uint8_t videoMode); -extern void setOutModeHdBypass(bool bypass); -extern void saveUserPrefs(); -extern float getOutputFrameRate(); -extern void loadDefaultUserOptions(); -extern uint8_t getVideoMode(); -extern runTimeOptions *rto; -extern userOptions *uopt; -extern const char *ap_ssid; -extern const char *ap_password; -extern const char *device_hostname_full; -extern WebSocketsServer webSocket; -extern OLEDMenuManager oledMenu; -extern OSDManager osdManager; -unsigned long oledMenuFreezeStartTime; -unsigned long oledMenuFreezeTimeoutInMS; - -bool resolutionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) -{ - if (!isFirstTime) { - if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { - manager->unfreeze(); - } - return false; - } - oledMenuFreezeTimeoutInMS = 1000; // freeze for 1s - oledMenuFreezeStartTime = millis(); - OLEDDisplay *display = manager->getDisplay(); - display->clear(); - display->setColor(OLEDDISPLAY_COLOR::WHITE); - display->setFont(ArialMT_Plain_16); - display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); - display->drawString(OLED_MENU_WIDTH / 2, 16, item->str); - display->drawXbm((OLED_MENU_WIDTH - TEXT_LOADED_WIDTH) / 2, OLED_MENU_HEIGHT / 2, IMAGE_ITEM(TEXT_LOADED)); - display->display(); - uint8_t videoMode = getVideoMode(); - PresetPreference preset = PresetPreference::Output1080P; - switch (item->tag) { - case MT_1280x960: - preset = PresetPreference::Output960P; - break; - case MT1280x1024: - preset = PresetPreference::Output1024P; - break; - case MT1280x720: - preset = PresetPreference::Output720P; - break; - case MT1920x1080: - preset = PresetPreference::Output1080P; - break; - case MT_480s576: - preset = PresetPreference::Output480P; - break; - case MT_DOWNSCALE: - preset = PresetPreference::OutputDownscale; - break; - case MT_BYPASS: - preset = PresetPreference::OutputCustomized; - break; - default: - break; - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) { - videoMode = rto->videoStandardInput; - } - if (item->tag != MT_BYPASS) { - uopt->presetPreference = preset; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - } else { - setOutModeHdBypass(false); - uopt->presetPreference = preset; - if (rto->videoStandardInput != 15) { - rto->autoBestHtotalEnabled = 0; - if (rto->applyPresetDoneStage == 11) { - rto->applyPresetDoneStage = 1; - } else { - rto->applyPresetDoneStage = 10; - } - } else { - rto->applyPresetDoneStage = 1; - } - } - saveUserPrefs(); - manager->freeze(); - return false; -} -bool presetSelectionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) -{ - if (!isFirstTime) { - if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { - manager->unfreeze(); - } - return false; - } - OLEDDisplay *display = manager->getDisplay(); - display->clear(); - display->setColor(OLEDDISPLAY_COLOR::WHITE); - display->setFont(ArialMT_Plain_16); - display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); - display->drawString(OLED_MENU_WIDTH / 2, 16, item->str); - display->drawXbm((OLED_MENU_WIDTH - TEXT_LOADED_WIDTH) / 2, OLED_MENU_HEIGHT / 2, IMAGE_ITEM(TEXT_LOADED)); - display->display(); - uopt->presetSlot = 'A' + item->tag; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~()!*:, - uopt->presetPreference = PresetPreference::OutputCustomized; - saveUserPrefs(); - if (rto->videoStandardInput == 14) { - // vga upscale path: let synwatcher handle it - rto->videoStandardInput = 15; - } else { - // normal path - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - manager->freeze(); - oledMenuFreezeTimeoutInMS = 2000; - oledMenuFreezeStartTime = millis(); - - return false; -} -bool presetsCreationMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool) -{ - SlotMetaArray slotsObject; - File slotsBinaryFileRead = SPIFFS.open(SLOTS_FILE, "r"); - manager->clearSubItems(item); - int curNumSlot = 0; - if (slotsBinaryFileRead) { - slotsBinaryFileRead.read((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileRead.close(); - for (int i; i < SLOTS_TOTAL; ++i) { - const SlotMeta &slot = slotsObject.slot[i]; - if (strcmp(EMPTY_SLOT_NAME, slot.name) == 0 || !strlen(slot.name)) { - continue; - } - curNumSlot++; - if (curNumSlot > OLED_MENU_MAX_SUBITEMS_NUM) { - break; - } - manager->registerItem(item, slot.slot, slot.name, presetSelectionMenuHandler); - } - } - - if (curNumSlot > OLED_MENU_MAX_SUBITEMS_NUM) { - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_TOO_MANY_PRESETS)); - } - - if (!item->numSubItem) { - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_NO_PRESETS)); - } - return true; -} -bool resetMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) -{ - if (!isFirstTime) { - // not precise - if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { - manager->unfreeze(); - ESP.reset(); - return false; - } - return false; - } - - OLEDDisplay *display = manager->getDisplay(); - display->clear(); - display->setColor(OLEDDISPLAY_COLOR::WHITE); - switch (item->tag) { - case MT_RESET_GBS: - display->drawXbm(CENTER_IMAGE(TEXT_RESETTING_GBS)); - break; - case MT_RESTORE_FACTORY: - display->drawXbm(CENTER_IMAGE(TEXT_RESTORING)); - break; - case MT_RESET_WIFI: - display->drawXbm(CENTER_IMAGE(TEXT_RESETTING_WIFI)); - break; - } - display->display(); - webSocket.close(); - delay(50); - switch (item->tag) { - case MT_RESET_WIFI: - WiFi.disconnect(); - break; - case MT_RESTORE_FACTORY: - loadDefaultUserOptions(); - saveUserPrefs(); - break; - } - manager->freeze(); - oledMenuFreezeStartTime = millis(); - oledMenuFreezeTimeoutInMS = 2000; // freeze for 2 seconds - return false; -} -bool currentSettingHandler(OLEDMenuManager *manager, OLEDMenuItem *, OLEDMenuNav nav, bool isFirstTime) -{ - static unsigned long lastUpdateTime = 0; - if (isFirstTime) { - lastUpdateTime = 0; - oledMenuFreezeStartTime = millis(); - oledMenuFreezeTimeoutInMS = 2000; // freeze for 2 seconds if no input - manager->freeze(); - } else if (nav != OLEDMenuNav::IDLE) { - manager->unfreeze(); - return false; - } - if (millis() - lastUpdateTime <= 200) { - return false; - } - OLEDDisplay &display = *manager->getDisplay(); - display.clear(); - display.setColor(OLEDDISPLAY_COLOR::WHITE); - display.setFont(ArialMT_Plain_16); - if (rto->sourceDisconnected || !rto->boardHasPower) { - if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { - manager->unfreeze(); - return false; - } - display.setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); - display.drawXbm(CENTER_IMAGE(TEXT_NO_INPUT)); - } else { - // TODO translations - boolean vsyncActive = 0; - boolean hsyncActive = 0; - float ofr = getOutputFrameRate(); - uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); - rto->presetID = GBS::GBS_PRESET_ID::read(); - - display.setFont(URW_Gothic_L_Book_20); - display.setTextAlignment(TEXT_ALIGN_LEFT); - - if (rto->presetID == 0x01 || rto->presetID == 0x11) { - display.drawString(0, 0, "1280x960"); - } else if (rto->presetID == 0x02 || rto->presetID == 0x12) { - display.drawString(0, 0, "1280x1024"); - } else if (rto->presetID == 0x03 || rto->presetID == 0x13) { - display.drawString(0, 0, "1280x720"); - } else if (rto->presetID == 0x05 || rto->presetID == 0x15) { - display.drawString(0, 0, "1920x1080"); - } else if (rto->presetID == 0x06 || rto->presetID == 0x16) { - display.drawString(0, 0, "Downscale"); - } else if (rto->presetID == 0x04) { - display.drawString(0, 0, "720x480"); - } else if (rto->presetID == 0x14) { - display.drawString(0, 0, "768x576"); - } else { - display.drawString(0, 0, "bypass"); - } - - display.drawString(0, 20, String(ofr, 5) + "Hz"); - - if (currentInput == 1) { - display.drawString(0, 41, "RGB"); - } else { - display.drawString(0, 41, "YpBpR"); - } - - if (currentInput == 1) { - vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); - if (vsyncActive) { - display.drawString(70, 41, "V"); - hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); - if (hsyncActive) { - display.drawString(53, 41, "H"); - } - } - } - } - display.display(); - lastUpdateTime = millis(); - - return false; -} -bool wifiMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool) -{ - static char ssid[64]; - static char ip[25]; - static char domain[25]; - WiFiMode_t wifiMode = WiFi.getMode(); - manager->clearSubItems(item); - if (wifiMode == WIFI_STA) { - sprintf(ssid, "SSID: %s", WiFi.SSID().c_str()); - manager->registerItem(item, 0, ssid); - if (WiFi.isConnected()) { - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_CONNECTED)); - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_URL)); - sprintf(ip, "http://%s", WiFi.localIP().toString().c_str()); - manager->registerItem(item, 0, ip); - sprintf(domain, "http://%s", device_hostname_full); - manager->registerItem(item, 0, domain); - } else { - // shouldn't happen? - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_DISCONNECTED)); - } - } else if (wifiMode == WIFI_AP) { - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_CONNECT_TO)); - sprintf(ssid, "SSID: %s (%s)", ap_ssid, ap_password); - manager->registerItem(item, 0, ssid); - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_URL)); - manager->registerItem(item, 0, "http://192.168.4.1"); - sprintf(domain, "http://%s", device_hostname_full); - manager->registerItem(item, 0, domain); - } else { - // shouldn't happen? - manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_DISCONNECTED)); - } - return true; -} -bool osdMenuHanlder(OLEDMenuManager *manager, OLEDMenuItem *, OLEDMenuNav nav, bool isFirstTime) -{ - static unsigned long start; - static long left; - char buf[30]; - auto display = manager->getDisplay(); - - if (isFirstTime) { - left = OSD_TIMEOUT; - start = millis(); - manager->freeze(); - osdManager.tick(OSDNav::ENTER); - } else { - display->clear(); - display->setColor(OLEDDISPLAY_COLOR::WHITE); - display->setFont(ArialMT_Plain_16); - display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); - display->drawStringf(OLED_MENU_WIDTH / 2, 16, buf, "OSD (%ds)", left / 1000 + 1); - display->display(); - if (REVERSE_ROTARY_ENCODER_FOR_OLED_MENU){ - // reverse nav back to normal - if(nav == OLEDMenuNav::DOWN) { - nav = OLEDMenuNav::UP; - } else if(nav == OLEDMenuNav::UP) { - nav = OLEDMenuNav::DOWN; - } - } - switch (nav) { - case OLEDMenuNav::ENTER: - osdManager.tick(OSDNav::ENTER); - start = millis(); - break; - case OLEDMenuNav::DOWN: - if(REVERSE_ROTARY_ENCODER_FOR_OSD) { - osdManager.tick(OSDNav::RIGHT); - } else { - osdManager.tick(OSDNav::LEFT); - } - start = millis(); - break; - case OLEDMenuNav::UP: - if(REVERSE_ROTARY_ENCODER_FOR_OSD) { - osdManager.tick(OSDNav::LEFT); - } else { - osdManager.tick(OSDNav::RIGHT); - } - start = millis(); - break; - default: - break; - } - left = OSD_TIMEOUT - (millis() - start); - if (left <= 0) { - manager->unfreeze(); - osdManager.menuOff(); - } - } - return true; -} -void initOLEDMenu() -{ - OLEDMenuItem *root = oledMenu.rootItem; - - // OSD Menu - oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_OSD), osdMenuHanlder); - - // Resolutions - OLEDMenuItem *resMenu = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_RESOLUTION)); - const char *resolutions[5] = {"1280x960", "1280x1024", "1280x720", "1920x1080", "480/576"}; - uint8_t tags[5] = {MT_1280x960, MT1280x1024, MT1280x720, MT1920x1080, MT_480s576}; - for (int i = 0; i < 5; ++i) { - oledMenu.registerItem(resMenu, tags[i], resolutions[i], resolutionMenuHandler); - } - // downscale and passthrough - oledMenu.registerItem(resMenu, MT_DOWNSCALE, IMAGE_ITEM(OM_DOWNSCALE), resolutionMenuHandler); - oledMenu.registerItem(resMenu, MT_BYPASS, IMAGE_ITEM(OM_PASSTHROUGH), resolutionMenuHandler); - - // Presets - oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_PRESET), presetsCreationMenuHandler); - - // WiFi - oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_WIFI), wifiMenuHandler); - - // Current Settings - oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_CURRENT), currentSettingHandler); - - // Reset (Misc.) - OLEDMenuItem *resetMenu = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_RESET_RESTORE)); - oledMenu.registerItem(resetMenu, MT_RESET_GBS, IMAGE_ITEM(OM_RESET_GBS), resetMenuHandler); - oledMenu.registerItem(resetMenu, MT_RESTORE_FACTORY, IMAGE_ITEM(OM_RESTORE_FACTORY), resetMenuHandler); - oledMenu.registerItem(resetMenu, MT_RESET_WIFI, IMAGE_ITEM(OM_RESET_WIFI), resetMenuHandler); -} diff --git a/OLEDMenuTranslations.h b/OLEDMenuTranslations.h deleted file mode 100644 index 3d636618..00000000 --- a/OLEDMenuTranslations.h +++ /dev/null @@ -1,594 +0,0 @@ -#ifndef OLED_MENU_TRANSLATIONS_H_ -#define OLED_MENU_TRANSLATIONS_H_ - -#define OM_STATUS_CUSTOM_WIDTH 59 -#define OM_STATUS_CUSTOM_HEIGHT 13 -const unsigned char OM_STATUS_CUSTOM [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x86,0x1,0x4,0xc0,0x30,0x0,0x0,0x0,0x86,0x1,0x0,0xc0,0x30,0x0,0x0,0x0, -0x86,0x71,0xf4,0xc0,0x30,0x8e,0x47,0x4,0x4a,0xc9,0x94,0x41,0x29,0x99,0x4c,0x4, -0x4a,0x81,0x14,0x41,0x29,0x91,0x48,0x4,0x4a,0xf1,0x14,0x41,0xa9,0x9f,0x48,0x4, -0x32,0x89,0x14,0x41,0x26,0x81,0x48,0x4,0x32,0xcd,0x14,0x41,0x26,0x91,0x48,0x6, -0x32,0xb9,0x14,0x41,0x26,0x8e,0x88,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_STATUS_BAR_BACK_WIDTH 39 -#define OM_STATUS_BAR_BACK_HEIGHT 13 -const unsigned char OM_STATUS_BAR_BACK [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x3,0x0,0x4,0x0, -0x20,0x6,0x0,0x4,0x0,0x20,0xc4,0xe1,0x24,0x0,0x20,0x22,0x93,0x15,0x4,0xe0, -0x7,0x12,0x1c,0x6,0x20,0xc4,0x1b,0x1c,0x6,0x20,0x24,0x12,0x14,0x4,0x20,0x34, -0x13,0x25,0x0,0xe0,0xe3,0xe2,0x64,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0, - -}; - -#define OM_SCREEN_SAVER_WIDTH 78 -#define OM_SCREEN_SAVER_HEIGHT 15 -const unsigned char OM_SCREEN_SAVER [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x30,0x0,0x0,0x84,0x0,0x0,0x42,0x0, -0x0,0x0,0x30,0x0,0x0,0x44,0x0,0x0,0x42,0xce,0x71,0x1c,0x38,0x3c,0x21,0x24, -0x38,0x21,0x42,0x22,0x93,0x24,0x48,0x64,0x12,0x34,0x64,0x12,0x3e,0x22,0x12,0x4, -0x48,0x44,0x12,0x3c,0x44,0x12,0x2,0xf2,0xe3,0x38,0xfc,0x44,0x12,0x2c,0x7e,0x12, -0x2,0x22,0x80,0x20,0x84,0x44,0xc,0x44,0x4,0xc,0x2,0x22,0x92,0x24,0x84,0x44, -0xc,0xc4,0x44,0xc,0x2,0xc2,0xf1,0x3c,0x2,0x45,0xc,0x84,0x39,0xc,0x0,0x0, -0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0, -0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_RESOLUTION_WIDTH 63 -#define OM_RESOLUTION_HEIGHT 13 -const unsigned char OM_RESOLUTION [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x7e,0x0,0x0,0x20,0x40,0x4,0x0,0x0,0xc2,0x0,0x0,0x20,0x40,0x0,0x0,0x0, -0x82,0x38,0x87,0x23,0xf1,0xe4,0x78,0x1c,0xc2,0x64,0x49,0x26,0x51,0x94,0xc9,0x24, -0x7e,0x44,0x41,0x24,0x51,0x14,0x89,0x4,0x22,0x7e,0x6e,0x24,0x51,0x1c,0x89,0x38, -0x42,0x4,0x48,0x24,0x51,0x14,0x89,0x20,0xc2,0x44,0x49,0x26,0x59,0x94,0x89,0x24, -0x82,0x38,0x8f,0x23,0xd6,0xe4,0x88,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_PASSTHROUGH_WIDTH 67 -#define OM_PASSTHROUGH_HEIGHT 15 -const unsigned char OM_PASSTHROUGH [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x3e,0x0,0x0,0x90,0x0,0x0,0x0,0x40,0x0,0x42,0x0,0x0,0x90,0x0, -0x0,0x0,0x40,0x0,0x42,0x1c,0xc7,0xb9,0xc7,0x39,0x11,0xcb,0x3,0x42,0x32,0x49, -0x92,0x4c,0x64,0x91,0x4c,0x6,0x3e,0x20,0x41,0x90,0x48,0x44,0x91,0x48,0x4,0x2, -0x3c,0x8e,0x93,0x48,0x46,0x51,0x48,0x4,0x2,0x22,0x8,0x92,0x48,0x44,0x91,0x48, -0x4,0x2,0x33,0x49,0x92,0x48,0x64,0x99,0x4c,0x4,0x2,0x2e,0xcf,0xb3,0x48,0x38, -0x16,0x4f,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x80,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_DOWNSCALE_WIDTH 65 -#define OM_DOWNSCALE_HEIGHT 13 -const unsigned char OM_DOWNSCALE [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x3e,0x0,0x0,0x0,0xe0,0x1,0x0,0x1,0x0,0x42,0x0,0x0,0x0,0x10, -0x3,0x0,0x1,0x0,0xc2,0xb8,0x48,0x1e,0x10,0xe2,0x38,0x71,0x0,0x82,0xe4,0x4c, -0x32,0x30,0x90,0x65,0xc9,0x0,0x82,0x44,0x4d,0x22,0xc0,0x11,0x40,0x89,0x0,0x82, -0x46,0x55,0xa2,0x7,0x1a,0x78,0xfd,0x0,0xc2,0x44,0x35,0x22,0x10,0x12,0x44,0x9, -0x0,0x42,0x64,0x32,0x22,0x10,0x12,0x67,0x89,0x0,0x3e,0x38,0x32,0x22,0xe0,0xe1, -0x5c,0x71,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_PRESET_WIDTH 41 -#define OM_PRESET_HEIGHT 13 -const unsigned char OM_PRESET [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0, -0x1,0x0,0x42,0x0,0x0,0x0,0x1,0x0,0x42,0xce,0x71,0xb8,0x73,0x0,0x42,0x22, -0x93,0x64,0x91,0x0,0x3e,0x22,0x12,0x44,0x11,0x0,0x2,0xf2,0xe3,0x7e,0xe1,0x0, -0x2,0x22,0x80,0x4,0x81,0x0,0x2,0x22,0x92,0x44,0x91,0x0,0x2,0xc2,0xf1,0x38, -0xf3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_RESET_RESTORE_WIDTH 77 -#define OM_RESET_RESTORE_HEIGHT 13 -const unsigned char OM_RESET_RESTORE [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0x20,0xf2,0x3,0x0,0x2,0x0,0x0,0xc2,0x0, -0x0,0x20,0x12,0x6,0x0,0x2,0x0,0x0,0x82,0x38,0x87,0x73,0x12,0xe4,0x38,0xe7, -0x38,0x7,0xc2,0x64,0x49,0x26,0x10,0x96,0x49,0x92,0x89,0xc,0x7e,0x44,0x41,0x24, -0xf1,0x13,0x9,0x12,0x89,0x8,0x22,0x7e,0xee,0x27,0x11,0xf9,0x71,0x1a,0xc9,0xf, -0x42,0x4,0x48,0x20,0x11,0x12,0x40,0x12,0x89,0x0,0xc2,0x44,0x49,0xa4,0x10,0x16, -0x49,0x92,0x89,0x8,0x82,0x38,0x8f,0xe3,0x10,0xe4,0x78,0xe6,0x8,0x7,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0, - -}; - -#define OM_RESET_GBS_WIDTH 60 -#define OM_RESET_GBS_HEIGHT 13 -const unsigned char OM_RESET_GBS [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x7e,0x0,0x0,0x20,0xc0,0xe3,0xc3,0x3,0xc2,0x0,0x0,0x20,0x20,0x24,0x26,0x6, -0x82,0x38,0x87,0x73,0x10,0x20,0x24,0x4,0xc2,0x64,0x49,0x26,0x10,0x20,0x62,0x0, -0x7e,0x44,0x41,0x24,0x10,0xef,0x87,0x3,0x22,0x7e,0xee,0x27,0x10,0x2c,0x4,0x4, -0x42,0x4,0x48,0x20,0x10,0x2c,0x24,0x4,0xc2,0x44,0x49,0x24,0x20,0x24,0x24,0x4, -0x82,0x38,0x8f,0x63,0xc0,0xe3,0xc3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_RESET_WIFI_WIDTH 126 -#define OM_RESET_WIFI_HEIGHT 13 -const unsigned char OM_RESET_WIFI [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x38,0x4,0x0,0x0,0x61,0x94,0x5f,0xc0,0x1,0x0,0x0,0x0,0x40,0x2,0x0,0x0, -0xc4,0x4,0x0,0x0,0x62,0x84,0x0,0x20,0x6,0x0,0x0,0x0,0x40,0x0,0x0,0x0, -0x82,0xe4,0x70,0x1c,0x52,0x96,0x40,0x10,0xc4,0xf1,0x3c,0x1c,0xee,0xe2,0x3c,0xe, -0x2,0x94,0xc9,0x4,0x52,0x92,0x40,0x10,0x20,0x93,0x65,0x32,0x59,0x92,0x65,0x12, -0x2,0x14,0x81,0x4,0xd2,0x92,0x4f,0x10,0x20,0x12,0x45,0x22,0x41,0x12,0x45,0x2, -0x2,0xfc,0xf1,0x4,0x94,0x92,0x40,0x10,0x30,0x12,0x45,0xbf,0x41,0x1a,0x45,0x1c, -0x82,0x14,0x88,0x4,0x8c,0x91,0x40,0x10,0x24,0x12,0x45,0x2,0x41,0x12,0x45,0x10, -0xc6,0x14,0xcd,0x4,0x8c,0x91,0x40,0x30,0x26,0x13,0x45,0x22,0x51,0x92,0x45,0x12, -0x38,0xe4,0xb8,0x4,0xc,0x91,0x40,0xc0,0xc1,0x11,0x45,0x1c,0xce,0xe2,0x44,0x1e, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_RESTORE_FACTORY_WIDTH 85 -#define OM_RESTORE_FACTORY_HEIGHT 15 -const unsigned char OM_RESTORE_FACTORY [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x40,0x0,0x0,0xc0,0xf,0x0,0x4,0x0, -0x0,0xc2,0x0,0x40,0x0,0x0,0x40,0x0,0x0,0x4,0x0,0x0,0x82,0x38,0xe7,0x38, -0xe7,0x40,0x80,0xe3,0x8e,0xf3,0x10,0xc2,0x64,0x49,0x64,0x91,0x41,0x40,0x96,0x45, -0x16,0x9,0x7e,0x44,0x41,0x44,0x11,0xc1,0x7,0x14,0x44,0x14,0x9,0x22,0x7e,0x4e, -0x46,0xf9,0x41,0x80,0x1f,0x64,0x14,0x9,0x42,0x4,0x48,0x44,0x11,0x40,0x40,0x14, -0x44,0x14,0x6,0xc2,0x44,0x49,0x64,0x11,0x41,0x60,0x16,0x45,0x16,0x6,0x82,0x38, -0xcf,0x38,0xe1,0x40,0xc0,0xe5,0x8c,0x13,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_CURRENT_WIDTH 80 -#define OM_CURRENT_HEIGHT 15 -const unsigned char OM_CURRENT [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x40,0xc0,0x3,0x10,0x0,0x20,0xc4,0x0, -0x0,0x0,0x40,0x20,0x6,0x10,0x0,0x20,0x82,0x44,0x77,0x8e,0xe7,0x10,0x44,0x3c, -0x4f,0x74,0x2,0x44,0x11,0x99,0x4c,0x10,0x48,0x14,0x59,0x24,0x2,0x44,0x11,0x91, -0x48,0x10,0x48,0x14,0x51,0x24,0x2,0x44,0x91,0x9f,0x48,0x10,0x4c,0x14,0x51,0x24, -0x82,0x44,0x11,0x81,0x48,0x10,0x44,0x14,0x51,0x24,0xc6,0x64,0x11,0x91,0x48,0x20, -0x46,0x16,0x59,0x26,0x38,0x58,0x11,0x8e,0xc8,0xc0,0x83,0x35,0x8f,0x65,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_WIFI_WIDTH 48 -#define OM_WIFI_HEIGHT 13 -const unsigned char OM_WIFI [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x61,0x94,0x5f,0x10, -0xc0,0x1,0x62,0x84,0x0,0x10,0x40,0x0,0x52,0x96,0x40,0x10,0xef,0x38,0x52,0x92, -0x40,0x10,0x59,0x64,0xd2,0x92,0x4f,0x10,0x51,0x44,0x94,0x92,0x40,0x10,0x51,0x46, -0x8c,0x91,0x40,0x10,0x51,0x44,0x8c,0x91,0x40,0x10,0x51,0x64,0xc,0x91,0x40,0x10, -0x51,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_NO_PRESETS_WIDTH 288 -#define TEXT_NO_PRESETS_HEIGHT 13 -const unsigned char TEXT_NO_PRESETS [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x0,0xf0,0x1,0x0,0x0,0x8,0x0, -0xf8,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x20,0x8c,0x80,0x0,0x82,0x4, -0x2,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x3c,0x0,0x4,0x86,0x0,0x10,0x2, -0x0,0x0,0x8,0x0,0x8,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x40,0x8c, -0x80,0x0,0x82,0x4,0x2,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x4,0x0,0x4, -0x8a,0x38,0x10,0x72,0xce,0xe1,0xdc,0x1,0x8,0x89,0xe3,0x38,0x1c,0x88,0x1c,0xe, -0xee,0xe1,0x40,0xca,0x9c,0x7,0x82,0x4,0xe7,0x80,0x73,0xe,0x77,0x1c,0x70,0x1e, -0xe,0x2e,0x77,0xe,0x8a,0x64,0x10,0x12,0x59,0x92,0x49,0x2,0x8,0x49,0x96,0x49, -0x32,0x88,0x24,0x19,0x24,0x93,0x41,0x4a,0xb2,0xc,0x82,0x4,0x92,0x41,0x16,0x99, -0x2c,0x32,0xc8,0x32,0x19,0x24,0x91,0x4,0x92,0x44,0xf0,0x11,0x51,0x10,0x49,0x0, -0xf8,0x48,0x4,0x9,0x22,0x88,0x4,0x11,0x24,0x12,0x41,0x5a,0xa2,0x8,0x82,0x4, -0x12,0x41,0x10,0x11,0x28,0x22,0x88,0x22,0x11,0x24,0x11,0x4,0x92,0x46,0x10,0x90, -0x9f,0xfb,0x89,0x3,0x8,0xe8,0xe7,0x71,0x3f,0x88,0xb8,0x1f,0x24,0xfa,0x81,0x52, -0xbf,0x8,0x82,0x4,0x1a,0x61,0x90,0x1f,0x2f,0x3f,0x8c,0xa2,0x1f,0x24,0xe1,0x4, -0xa2,0x44,0x10,0x10,0x1,0x12,0x8,0x2,0x8,0x48,0x10,0x41,0x2,0x88,0x20,0x1, -0x24,0x12,0x80,0x31,0x82,0x8,0xc2,0x4,0x12,0x41,0x10,0x81,0x28,0x2,0x88,0x22, -0x1,0x24,0x81,0x4,0xc2,0x64,0x10,0x10,0x51,0x12,0x49,0x2,0x8,0x48,0x9c,0x49, -0x22,0xc8,0x24,0x11,0x24,0x12,0x81,0x31,0xa2,0xc,0x46,0x4,0x92,0x41,0x14,0xd1, -0x2c,0x22,0xc8,0x22,0x11,0x24,0x91,0x4,0xc2,0x38,0x10,0x10,0xce,0xe3,0xd8,0x13, -0x8,0x88,0x73,0x79,0x1c,0xb0,0x3c,0xe,0x2c,0xe2,0x80,0x21,0x9c,0x7,0x3c,0x4, -0xe6,0x80,0x13,0x8e,0x6b,0x1c,0x70,0x22,0xe,0x24,0xf1,0x2c,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0, - -}; - -#define TEXT_TOO_MANY_PRESETS_WIDTH 230 -#define TEXT_TOO_MANY_PRESETS_HEIGHT 15 -const unsigned char TEXT_TOO_MANY_PRESETS [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x2,0x0,0x0,0x0,0x0, -0x0,0x80,0x30,0x2,0x2,0x41,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x42,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x31, -0x2,0x2,0x41,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x4,0x0,0x42,0xe2,0x38,0xe,0x7,0x22,0x87,0x3,0x29,0x73,0x1e,0x41, -0xc2,0x71,0xc0,0x71,0x1c,0xc7,0x71,0xe0,0x1d,0xc7,0x39,0xf0,0x38,0xe7,0x70,0xee, -0x0,0x42,0x92,0x65,0x92,0xc,0x22,0x49,0x6,0x29,0xc9,0x32,0x41,0x82,0xc8,0x20, -0xcb,0xb2,0x4c,0x92,0x20,0x93,0x4c,0x64,0x90,0x89,0x2c,0xc9,0x24,0x1,0x3e,0x12, -0x41,0x82,0x8,0x22,0x41,0x4,0x69,0x89,0x22,0x41,0x82,0x88,0x0,0xa,0x82,0x48, -0x10,0x20,0x93,0x48,0x44,0x10,0x89,0x28,0x88,0x24,0x0,0x2,0xfa,0x79,0xdc,0xf, -0x22,0xee,0x7,0x4a,0xfd,0x22,0x41,0x82,0x8c,0xc0,0xf,0xc3,0x8f,0xe3,0x20,0xd3, -0x48,0x7e,0x10,0xc9,0xcf,0xfd,0xc4,0x1,0x2,0x12,0x44,0x90,0x0,0x22,0x48,0x0, -0xc6,0x8,0x22,0x61,0x82,0x88,0x20,0xa,0x82,0x0,0x82,0x20,0x93,0x48,0x4,0x10, -0x89,0x0,0x9,0x4,0x1,0x2,0x12,0x67,0x92,0x8,0x32,0x49,0x4,0xc6,0x88,0x32, -0x23,0x82,0xc8,0x30,0x8b,0xa2,0x48,0x92,0x20,0x93,0x4c,0x44,0x90,0x89,0x28,0x89, -0x24,0x1,0x2,0xe2,0x5c,0x1e,0x7,0x2c,0x8f,0x3,0x86,0x70,0x1e,0x1e,0x82,0x71, -0xe0,0x72,0x1c,0xc7,0xf3,0x20,0x13,0x47,0x38,0xf0,0x8,0xe7,0x71,0xec,0x9,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0, - -}; - -#define TEXT_RESETTING_GBS_WIDTH 106 -#define TEXT_RESETTING_GBS_HEIGHT 55 -const unsigned char TEXT_RESETTING_GBS [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x1,0x0,0x0,0x0,0x80, -0x0,0x0,0x0,0xf0,0xc1,0x1f,0x7c,0x0,0x6,0x3,0x0,0x0,0xc0,0x18,0x0,0x0, -0x0,0x18,0xc3,0x30,0xc2,0x0,0x6,0x2,0x0,0x0,0xc0,0x18,0x0,0x0,0x0,0x4, -0xc6,0x20,0x83,0x0,0x6,0x82,0xc3,0x83,0xe3,0xbd,0xe8,0xe1,0x7,0x6,0xc4,0x20, -0x3,0x0,0x6,0x62,0x24,0x66,0xc4,0x98,0x18,0x31,0x7,0x6,0xc0,0x10,0x6,0x0, -0x6,0x23,0x2c,0x20,0xcc,0x98,0x18,0x13,0x6,0x2,0xc0,0x3f,0x3e,0x0,0xfe,0x21, -0xe8,0x20,0xc8,0x98,0x8,0x13,0x6,0x82,0xc7,0x30,0xf0,0x0,0xc6,0xe0,0xcf,0xe3, -0xcf,0x98,0x8,0x13,0x6,0x6,0xc4,0x60,0x80,0x1,0x86,0x21,0x0,0x26,0xc0,0x98, -0x8,0x13,0x6,0x6,0xc4,0x60,0x80,0x1,0x6,0x23,0x8,0x24,0xc8,0x98,0x8,0x13, -0x6,0x4,0xc4,0x60,0x81,0x1,0x6,0x63,0x24,0x66,0xc4,0x98,0x8,0x33,0x7,0x18, -0xc6,0x30,0x83,0x0,0x6,0x86,0xc3,0x83,0x83,0xb1,0x8,0xe3,0x7,0xf0,0xc1,0x1f, -0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0xe0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0xe0,0xf,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0, -0x0,0x0,0x0,0x60,0x10,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0, -0x0,0x60,0x30,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x60, -0x30,0xe1,0xe0,0xc3,0x83,0x3,0xc6,0x88,0x8f,0x1e,0x0,0x0,0x0,0x60,0x30,0x19, -0x31,0x22,0x66,0x4,0xc6,0xc8,0x88,0xc,0x0,0x0,0x0,0x60,0x18,0x9,0x13,0x26, -0x20,0xc,0xe4,0x4c,0x98,0xc,0x0,0x0,0x0,0xe0,0xf,0x9,0x82,0xe7,0x20,0x8, -0xa4,0x4,0x9e,0xc,0x0,0x0,0x0,0x60,0x0,0xf9,0xf3,0xc6,0xe3,0xf,0xac,0xc5, -0x9b,0xc,0x0,0x0,0x0,0x60,0x0,0x9,0x10,0x6,0x26,0x0,0xa8,0x45,0x98,0xc, -0x0,0x0,0x0,0x60,0x0,0x9,0x12,0x6,0x24,0x8,0x38,0x47,0x98,0xc,0x0,0x0, -0x0,0x60,0x0,0x19,0x31,0x27,0x66,0x4,0x18,0xc3,0x9c,0xc,0x0,0x0,0x0,0x60, -0x0,0xe1,0xe0,0xc5,0x83,0x3,0x18,0x83,0x97,0x18,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x31,0x3, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0, - -}; - -#define TEXT_RESETTING_WIFI_WIDTH 104 -#define TEXT_RESETTING_WIFI_HEIGHT 55 -const unsigned char TEXT_RESETTING_WIFI [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x1,0x0,0x0,0x0,0x80,0x0,0x0,0x0, -0x83,0x61,0xf1,0x4f,0x6,0x3,0x0,0x0,0xc0,0x18,0x0,0x0,0x0,0xc2,0x61,0x30, -0x0,0x6,0x2,0x0,0x0,0xc0,0x18,0x0,0x0,0x0,0xc2,0x21,0x30,0x0,0x6,0x82, -0xc3,0x83,0xe3,0xbd,0xe8,0xe1,0x7,0x46,0x21,0x31,0x40,0x6,0x62,0x24,0x66,0xc4, -0x98,0x18,0x31,0x7,0x66,0x33,0x31,0x40,0x6,0x23,0x2c,0x20,0xcc,0x98,0x18,0x13, -0x6,0x64,0x12,0x31,0x40,0xfe,0x21,0xe8,0x20,0xc8,0x98,0x8,0x13,0x6,0x24,0x12, -0xf1,0x47,0xc6,0xe0,0xcf,0xe3,0xcf,0x98,0x8,0x13,0x6,0x24,0x12,0x31,0x40,0x86, -0x21,0x0,0x26,0xc0,0x98,0x8,0x13,0x6,0x3c,0x1e,0x31,0x40,0x6,0x23,0x8,0x24, -0xc8,0x98,0x8,0x13,0x6,0x18,0xc,0x31,0x40,0x6,0x63,0x24,0x66,0xc4,0x98,0x8, -0x33,0x7,0x18,0xc,0x31,0x40,0x6,0x86,0xc3,0x83,0x83,0xb1,0x8,0xe3,0x7,0x18, -0xc,0x31,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0xe0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0, -0x87,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x30,0x88,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x30,0x98,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0xc,0x0,0x0,0x30,0x98,0x70,0xf0,0xe1,0xc1,0x1,0xc6,0xc8,0x47, -0x1e,0x0,0x0,0x30,0x98,0x8c,0x18,0x11,0x33,0x2,0xc6,0x68,0x44,0xc,0x0,0x0, -0x30,0x8c,0x84,0x9,0x13,0x10,0x6,0xe4,0x2c,0x4c,0xc,0x0,0x0,0xf0,0x87,0x4, -0xc1,0x73,0x10,0x4,0xa4,0x4,0x4f,0xc,0x0,0x0,0x30,0x80,0xfc,0x79,0xe3,0xf1, -0x7,0xac,0xe5,0x4d,0xc,0x0,0x0,0x30,0x80,0x4,0x8,0x3,0x13,0x0,0xa8,0x25, -0x4c,0xc,0x0,0x0,0x30,0x80,0x4,0x9,0x3,0x12,0x4,0x38,0x27,0x4c,0xc,0x0, -0x0,0x30,0x80,0x8c,0x98,0x13,0x33,0x2,0x18,0x63,0x4e,0xc,0x0,0x0,0x30,0x80, -0x70,0xf0,0xe2,0xc1,0x1,0x18,0xc3,0x4b,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x98,0x1,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_RESTORING_WIDTH 126 -#define TEXT_RESTORING_HEIGHT 55 -const unsigned char TEXT_RESTORING [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0xfe,0x1,0x0,0x0,0x0,0x0,0x0,0xf8,0x7,0x0,0x0,0x0,0x0,0x4,0x0,0x0, -0x6,0x0,0x0,0x30,0x0,0x0,0x0,0x18,0xc,0x0,0x80,0x1,0x0,0x0,0x0,0x0, -0x6,0x0,0x0,0x30,0x0,0x0,0x0,0x18,0x8,0x0,0x80,0x1,0x0,0x0,0x0,0x0, -0x6,0xf0,0xc1,0x79,0x1c,0x7e,0x18,0x18,0x8,0x7,0xcf,0xc3,0xe1,0x45,0x8f,0x1f, -0x6,0x18,0x31,0x32,0x23,0x46,0x8,0x18,0xc8,0x88,0x98,0x31,0x62,0xc4,0xc8,0x1c, -0x6,0x8,0x13,0x30,0x61,0xc6,0x8,0x18,0x4c,0x98,0x80,0x11,0x66,0xc4,0x58,0x18, -0xfe,0xc0,0x13,0x30,0x41,0x86,0xc,0xf8,0x47,0x90,0x83,0x11,0x64,0x44,0x58,0x18, -0x6,0x78,0x13,0x30,0x41,0x82,0x4,0x18,0xc3,0x1f,0x8f,0x11,0x24,0x44,0x58,0x18, -0x6,0x8,0x13,0x30,0x41,0x82,0x5,0x18,0x46,0x0,0x98,0x11,0x24,0x44,0x58,0x18, -0x6,0x8,0x13,0x30,0x61,0x2,0x7,0x18,0x4c,0x10,0x90,0x11,0x26,0x44,0x58,0x18, -0x6,0x98,0x33,0x36,0x23,0x2,0x3,0x18,0xcc,0x88,0x98,0x31,0x22,0x44,0xd8,0x1c, -0x6,0xf0,0xc2,0x63,0x1e,0x2,0x3,0x18,0x18,0x7,0xf,0xe3,0x21,0x44,0x98,0x1f, -0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18, -0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x8, -0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x7, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x80,0x3f,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0, -0x0,0x0,0x80,0x41,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0, -0x0,0x0,0x80,0xc1,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0, -0x0,0x0,0x80,0xc1,0x84,0x83,0xf,0xf,0xe,0x30,0x46,0x3e,0xf2,0x0,0x0,0x0, -0x0,0x0,0x80,0xc1,0x64,0xc4,0x88,0x98,0x11,0x30,0x46,0x23,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x61,0x24,0x4c,0x98,0x80,0x30,0x20,0x67,0x61,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x3f,0x24,0x8,0x9e,0x83,0x20,0x20,0x25,0x78,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x1,0xe4,0xcf,0x1b,0x8f,0x3f,0x60,0x2d,0x6f,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x1,0x24,0x40,0x18,0x98,0x0,0x40,0x2d,0x61,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x1,0x24,0x48,0x18,0x90,0x20,0xc0,0x39,0x61,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x1,0x64,0xc4,0x9c,0x98,0x11,0xc0,0x18,0x73,0x62,0x0,0x0,0x0, -0x0,0x0,0x80,0x1,0x84,0x83,0x17,0xf,0xe,0xc0,0x18,0x5e,0xc2,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xcc,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_WIFI_CONNECT_TO_WIDTH 355 -#define TEXT_WIFI_CONNECT_TO_HEIGHT 15 -const unsigned char TEXT_WIFI_CONNECT_TO [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0,0x4, -0x2,0x40,0x4,0x0,0x1c,0x90,0x0,0x0,0x2,0x0,0xe0,0xe1,0x11,0x1f,0x20,0x0, -0x0,0x0,0x0,0x0,0x0,0x9,0x4,0x0,0x7,0x0,0x0,0x0,0x10,0x0,0x0,0x9, -0x0,0x8,0x23,0x40,0x0,0x41,0x1,0xc4,0x0,0x0,0x0,0x0,0x4,0x2,0x40,0x4, -0x0,0x4,0x90,0x0,0x0,0x0,0x0,0x10,0x13,0x13,0x21,0x20,0x0,0x0,0x0,0x0, -0x0,0x0,0x1,0x4,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x10,0x23, -0x40,0x0,0x41,0x1,0x82,0x38,0x8f,0x87,0xe3,0xe,0xe7,0xe0,0x3c,0xe,0x8e,0x93, -0xb8,0x48,0xf2,0x58,0x10,0x12,0x12,0x61,0x10,0x8f,0xe3,0x38,0x91,0x38,0xe7,0x11, -0x3c,0x9c,0x73,0x9c,0x3,0xd1,0x91,0x87,0x85,0x7b,0x38,0x90,0x32,0xc7,0x3,0x41, -0x1,0x2,0x64,0x99,0x4c,0x96,0x5,0x92,0x41,0x64,0x19,0x44,0x96,0xe4,0x4c,0x92, -0x65,0x30,0x30,0x10,0x41,0x10,0x59,0x26,0x49,0x99,0x64,0x91,0x11,0x64,0x32,0xc9, -0x44,0x6,0x51,0x92,0x4c,0x6,0xc9,0x64,0x90,0x92,0x4c,0x6,0x41,0x1,0x2,0x44, -0x91,0x48,0x14,0x4,0x12,0x41,0x44,0x11,0x44,0x94,0x44,0x4d,0x12,0x45,0xc0,0xc1, -0x11,0x41,0x10,0x11,0x24,0x8,0x9a,0x44,0x11,0x11,0x44,0x22,0x89,0x44,0x4,0x51, -0x90,0x48,0x4,0x89,0x44,0x90,0x96,0x48,0x4,0x41,0x1,0x2,0x46,0x91,0xe8,0x1f, -0x4,0x1a,0x41,0xc4,0x1f,0x64,0x94,0x46,0x55,0x12,0x43,0x0,0x2,0x12,0x41,0x10, -0x91,0xc7,0x71,0xaa,0x46,0x19,0x31,0x44,0x3f,0x8d,0xe4,0x7,0x91,0x93,0x28,0x4, -0x89,0x7e,0xa0,0xd4,0x4f,0x4,0x41,0x1,0x82,0x44,0x91,0x48,0x10,0x4,0x12,0x41, -0x44,0x1,0x44,0x94,0x44,0x35,0x12,0x45,0x10,0x12,0x12,0x61,0x10,0x51,0x4,0x41, -0x6a,0x44,0x11,0x11,0x44,0x2,0x89,0x44,0x0,0x11,0x92,0x48,0x4,0x89,0x4,0x60, -0x8c,0x40,0x4,0x61,0x1,0xc6,0x64,0x91,0x48,0x14,0x5,0x92,0x41,0x44,0x11,0x44, -0x96,0x64,0x32,0x12,0x65,0x10,0x12,0x12,0x21,0x10,0x79,0x26,0x49,0x64,0x64,0x91, -0x11,0x64,0x22,0xc9,0x44,0x4,0x59,0x92,0x48,0x6,0x89,0x44,0x60,0x8c,0x48,0x6, -0x23,0x1,0x38,0x38,0x91,0x88,0xe3,0xc,0xe6,0xc0,0x44,0xe,0x84,0x93,0x38,0x32, -0x12,0x79,0xe0,0xe1,0x11,0x1f,0x10,0xcf,0xe5,0x79,0x64,0x38,0xe1,0x11,0x3c,0x1c, -0x71,0x84,0x3,0xd6,0x93,0x88,0x7,0x8b,0x38,0x60,0x8,0xc7,0x3,0x1e,0x1,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0, -0x0,0x0,0x0,0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0, -0x20,0x1,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0, -0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0, - -}; - -#define TEXT_WIFI_CONNECTED_WIDTH 99 -#define TEXT_WIFI_CONNECTED_HEIGHT 13 -const unsigned char TEXT_WIFI_CONNECTED [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x2,0x8,0x0,0x0,0x70, -0x0,0x0,0x0,0x0,0x8,0x0,0x2,0x62,0x2,0x8,0x0,0x0,0x88,0x1,0x0,0x0, -0x0,0x8,0x0,0x2,0x42,0xe7,0x5c,0xe4,0x8,0x4,0x39,0x1e,0x8f,0xc3,0x9d,0xc3, -0x3,0x6,0x92,0x49,0x24,0x1,0x4,0x64,0x32,0x59,0x26,0x4b,0x26,0x3,0x38,0x2, -0x49,0x24,0x0,0x4,0x44,0x22,0x51,0x24,0x48,0x24,0x2,0x40,0xe2,0x49,0xc4,0x1, -0x4,0x46,0x22,0xf1,0x37,0xe8,0x37,0x2,0x42,0x12,0x49,0x4,0x1,0x4,0x45,0x22, -0x51,0x20,0x48,0x20,0x2,0x42,0x9a,0x49,0x26,0x1,0x8c,0x65,0x22,0x51,0x24,0x4a, -0x24,0x3,0x3c,0x76,0x99,0xe5,0x9,0x70,0x38,0x22,0x91,0xc3,0x99,0xc3,0x3,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_WIFI_DISCONNECTED_WIDTH 113 -#define TEXT_WIFI_DISCONNECTED_HEIGHT 13 -const unsigned char TEXT_WIFI_DISCONNECTED [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x2, -0x8,0x0,0x0,0x7c,0x4,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x1,0x62,0x2,0x8, -0x0,0x0,0x84,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x1,0x42,0xe7,0x5c,0xe4, -0x8,0x84,0xe5,0x70,0x1c,0xcf,0xc3,0xe1,0xce,0xe1,0x1,0x6,0x92,0x49,0x24,0x1, -0x4,0x25,0xc9,0x32,0x59,0x26,0x93,0x25,0x93,0x1,0x38,0x2,0x49,0x24,0x0,0x4, -0x25,0x8,0x22,0x51,0x24,0x12,0x24,0x12,0x1,0x40,0xe2,0x49,0xc4,0x1,0x4,0xc5, -0xd,0x23,0x51,0xf4,0x1b,0xf4,0x1b,0x1,0x42,0x12,0x49,0x4,0x1,0x84,0x5,0x9, -0x22,0x51,0x24,0x10,0x24,0x10,0x1,0x42,0x9a,0x49,0x26,0x1,0x84,0x24,0x89,0x32, -0x51,0x24,0x12,0x25,0x92,0x1,0x3c,0x76,0x99,0xe5,0x9,0x7c,0xe4,0x71,0x1c,0x51, -0xc4,0xe1,0xcc,0xe1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0, - -}; - -#define TEXT_WIFI_URL_WIDTH 261 -#define TEXT_WIFI_URL_HEIGHT 15 -const unsigned char TEXT_WIFI_URL [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x47,0x4,0x0,0x1c,0x90,0x0,0x0, -0x2,0x0,0x10,0xe4,0x47,0x0,0x40,0x0,0x0,0x0,0x0,0x24,0x0,0x20,0x8c,0x0, -0x1,0x4,0x5,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x41,0x4,0x0,0x4,0x90,0x0, -0x0,0x0,0x0,0x10,0x24,0x4c,0x0,0x40,0x0,0x0,0x0,0x0,0x24,0x0,0x40,0x8c, -0x0,0x1,0x4,0x5,0x82,0x1c,0xe,0x38,0xf,0x7,0x9c,0xe3,0x3c,0xe,0x8e,0x93, -0xb8,0x48,0xf2,0x58,0x10,0x24,0x48,0x70,0xe0,0x1c,0x88,0x1c,0xe,0xee,0xe1,0x40, -0xca,0x1c,0xf,0x4,0x5,0x82,0x24,0x19,0x64,0x99,0xc,0x32,0x41,0x64,0x19,0x44, -0x96,0xe4,0x4c,0x92,0x65,0x10,0x24,0x4c,0x90,0x40,0x32,0x88,0x24,0x19,0x24,0x93, -0x41,0x4a,0x32,0x19,0x4,0x5,0x82,0x4,0x11,0x44,0x91,0x8,0x22,0x41,0x44,0x11, -0x44,0x94,0x44,0x4d,0x12,0x45,0x10,0xe4,0x47,0x10,0x40,0x22,0x88,0x4,0x11,0x24, -0x12,0x41,0x5a,0x22,0x11,0x4,0x5,0x82,0xb8,0x1f,0x46,0xd1,0xf,0x23,0x41,0xc4, -0x1f,0x64,0x94,0x46,0x55,0x12,0x43,0x10,0x24,0x42,0xe0,0x40,0x23,0x88,0xb8,0x1f, -0x24,0xfa,0x81,0x52,0x3f,0x11,0x4,0x5,0xc2,0x20,0x1,0x44,0x91,0x0,0x22,0x41, -0x44,0x1,0x44,0x94,0x44,0x35,0x12,0x45,0x10,0x26,0x44,0x80,0x40,0x22,0x88,0x20, -0x1,0x24,0x12,0x80,0x31,0x2,0x11,0x84,0x5,0x46,0x24,0x11,0x64,0x91,0x8,0x32, -0x41,0x44,0x11,0x44,0x96,0x64,0x32,0x12,0x65,0x30,0x22,0x4c,0x90,0x40,0x32,0xc8, -0x24,0x11,0x24,0x12,0x81,0x31,0x22,0x19,0x8c,0x4,0x3c,0x3c,0xe,0x38,0x11,0x7, -0x1c,0xc1,0x44,0xe,0x84,0x93,0x38,0x32,0x12,0x79,0xe0,0x21,0xc8,0xf7,0xc0,0x1c, -0xb0,0x3c,0xe,0x2c,0xe2,0x80,0x21,0x1c,0xf,0x78,0x4,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_LOADED_WIDTH 53 -#define TEXT_LOADED_HEIGHT 17 -const unsigned char TEXT_LOADED [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x6,0x0,0x18,0x6,0x0,0x0,0x0, -0x6,0x0,0x18,0x6,0x0,0x0,0x0,0x6,0x0,0x18,0x6,0x70,0xf0,0xe1,0x87,0x83, -0x1f,0x6,0x8c,0x18,0x31,0x67,0xc4,0x1c,0x6,0x84,0x9,0x13,0x26,0x4c,0x18,0x6, -0x4,0xc1,0x13,0x26,0x48,0x18,0x6,0x4,0x79,0x13,0xe6,0x4f,0x18,0x6,0x4,0x9, -0x13,0x26,0x40,0x18,0x6,0x84,0x9,0x13,0x26,0x48,0x18,0x6,0x8c,0x98,0x33,0x67, -0xc4,0x1c,0xfe,0x78,0xf0,0xe2,0x87,0x83,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define TEXT_NO_INPUT_WIDTH 61 -#define TEXT_NO_INPUT_HEIGHT 20 -const unsigned char TEXT_NO_INPUT [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x2,0x0,0xc,0x0,0x0,0x0,0x0, -0xe,0x2,0x0,0xc,0x0,0x0,0x0,0x6,0xe,0x2,0x0,0xc,0x0,0x0,0x0,0x6, -0x16,0x82,0x3,0x4c,0x8f,0xe,0x61,0xf,0x16,0x62,0x4,0xcc,0x88,0x11,0x61,0x6, -0x26,0x22,0xc,0xcc,0x98,0x31,0x61,0x6,0x6,0x22,0x8,0x4c,0x98,0x20,0x61,0x6, -0x46,0x22,0x8,0x4c,0x98,0x20,0x61,0x6,0x86,0x22,0x8,0x4c,0x98,0x20,0x61,0x6, -0x86,0x22,0xc,0x4c,0x98,0x31,0x63,0x6,0x6,0x63,0x4,0x4c,0x98,0x11,0x73,0x6, -0x6,0xc3,0x3,0x4c,0x98,0xf,0x7e,0xc,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, - -}; - -#define OM_OSD_WIDTH 92 -#define OM_OSD_HEIGHT 15 -const unsigned char OM_OSD [] PROGMEM = { -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0xf0,0xf0,0xf8,0x80, -0x61,0x0,0x0,0x0,0xc4,0x0,0x0,0x0,0x88,0x89,0x9,0x81,0x61,0x0,0x0,0x0, -0x82,0x3c,0x1c,0xf,0x4,0x9,0x9,0x83,0x61,0x1c,0x4f,0x4,0x2,0x65,0x32,0x19, -0x4,0x1a,0x8,0x82,0x52,0x32,0x59,0x4,0x2,0x45,0x22,0x11,0x4,0xe2,0x8,0x82, -0x52,0x22,0x51,0x4,0x82,0x45,0x3f,0x11,0x4,0x3,0x9,0x82,0x52,0x3f,0x51,0x4, -0x82,0x44,0x2,0x11,0x4,0x9,0x9,0x83,0x4c,0x2,0x51,0x4,0xc4,0x64,0x22,0x11, -0x88,0x9,0x9,0x81,0x4c,0x22,0x51,0x6,0x78,0x3c,0x1c,0x11,0xf0,0xf0,0xf8,0x80, -0x4c,0x1c,0x91,0x5,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, -0x0,0x0,0x0,0x0, - -}; -#endif \ No newline at end of file diff --git a/PersWiFiManager.cpp b/PersWiFiManager.cpp deleted file mode 100644 index fd7de767..00000000 --- a/PersWiFiManager.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* PersWiFiManager - version 3.0.1 - https://r-downing.github.io/PersWiFiManager/ - - modified for inclusion in gbs-control - see /3rdparty/PersWiFiManager/ for original code and license -*/ -#if defined(ESP8266) -#include "PersWiFiManager.h" - -// #define WIFI_HTM_PROGMEM -// #ifdef WIFI_HTM_PROGMEM -// static const char wifi_htm[] PROGMEM = R"=====( ESP WiFi

)====="; -// #endif - -extern const char *device_hostname_full; -extern const char *device_hostname_partial; - -PersWiFiManager::PersWiFiManager(AsyncWebServer &s, DNSServer &d) -{ - _server = &s; - _dnsServer = &d; - _apPass = ""; -} //PersWiFiManager - -bool PersWiFiManager::attemptConnection(const String &ssid, const String &pass) -{ - //attempt to connect to wifi - WiFi.mode(WIFI_STA); - WiFi.hostname(device_hostname_partial); // _full // before WiFi.begin(); - if (ssid.length()) { - if (pass.length()) - WiFi.begin(ssid.c_str(), pass.c_str()); - else - WiFi.begin(ssid.c_str()); - } else { - WiFi.begin(); - } - - //if in nonblock mode, skip this loop - _connectStartTime = millis(); // + 1; - while (!_connectNonBlock && _connectStartTime) { - handleWiFi(); - delay(10); - } - - return (WiFi.status() == WL_CONNECTED); - -} //attemptConnection - -void PersWiFiManager::handleWiFi() -{ - if (!_connectStartTime) - return; - - if (WiFi.status() == WL_CONNECTED) { - _connectStartTime = 0; - if (_connectHandler) - _connectHandler(); - return; - } - - //if failed or not connected and time is up - if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) { - startApMode(); - _connectStartTime = 0; //reset connect start time - } - -} //handleWiFi - -void PersWiFiManager::startApMode() -{ - //start AP mode - IPAddress apIP(192, 168, 4, 1); - WiFi.mode(WIFI_AP); - WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); - _apPass.length() ? WiFi.softAP(getApSsid().c_str(), _apPass.c_str(), 11) : WiFi.softAP(getApSsid().c_str()); - - _dnsServer->stop(); - // set which return code will be used for all other domains (e.g. sending - // ServerFailure instead of NonExistentDomain will reduce number of queries - // sent by clients) - // default is DNSReplyCode::NonExistentDomain - //_dnsServer->setErrorReplyCode(DNSReplyCode::ServerFailure); - // modify TTL associated with the domain name (in seconds) // default is 60 seconds - _dnsServer->setTTL(300); // (in seconds) as per example - //_dnsServer->start((byte)53, device_hostname_full, apIP); - _dnsServer->start(53, "*", apIP); - - if (_apHandler) - _apHandler(); -} //startApMode - -void PersWiFiManager::setConnectNonBlock(bool b) -{ - _connectNonBlock = b; -} //setConnectNonBlock - -void PersWiFiManager::setupWiFiHandlers() -{ - // note: removed DNS server setup here - - _server->on("/wifi/list", HTTP_GET, [](AsyncWebServerRequest *request) { - //scan for wifi networks - int n = WiFi.scanComplete(); - String s = ""; - if (n == -2) { - WiFi.scanNetworks(true); - } else if (n) { - //build array of indices - int ix[n]; - for (int i = 0; i < n; i++) - ix[i] = i; - - //sort by signal strength - for (int i = 0; i < n; i++) - for (int j = 1; j < n - i; j++) - if (WiFi.RSSI(ix[j]) > WiFi.RSSI(ix[j - 1])) - std::swap(ix[j], ix[j - 1]); - //remove duplicates - for (int i = 0; i < n; i++) - for (int j = i + 1; j < n; j++) - if (WiFi.SSID(ix[i]).equals(WiFi.SSID(ix[j])) && WiFi.encryptionType(ix[i]) == WiFi.encryptionType(ix[j])) - ix[j] = -1; - - s.reserve(2050); - //build plain text string of wifi info - //format [signal%]:[encrypted 0 or 1]:SSID - for (int i = 0; i < n && s.length() < 2000; i++) { //check s.length to limit memory usage - if (ix[i] != -1) { - s += String(i ? "\n" : "") + ((constrain(WiFi.RSSI(ix[i]), -100, -50) + 100) * 2) + "," + ((WiFi.encryptionType(ix[i]) == ENC_TYPE_NONE) ? 0 : 1) + "," + WiFi.SSID(ix[i]); - } - } - // don't cache found ssid's - WiFi.scanDelete(); - } - //send string to client - request->send(200, "text/plain", s); - }); //_server->on /wifi/list - - // #ifdef WIFI_HTM_PROGMEM - // _server->on("/wifi.htm", HTTP_GET, [](AsyncWebServerRequest* request) { - // request->send(200, "text/html", FPSTR(wifi_htm)); - // WiFi.scanNetworks(true); // early scan to have results ready on /wifi/list - // }); - // #endif - -} //setupWiFiHandlers - -bool PersWiFiManager::begin(const String &ssid, const String &pass) -{ - setupWiFiHandlers(); - return attemptConnection(ssid, pass); //switched order of these two for return -} //begin - -String PersWiFiManager::getApSsid() -{ - return _apSsid.length() ? _apSsid : "gbscontrol"; -} //getApSsid - -void PersWiFiManager::setApCredentials(const String &apSsid, const String &apPass) -{ - if (apSsid.length()) - _apSsid = apSsid; - if (apPass.length() >= 8) - _apPass = apPass; -} //setApCredentials - -void PersWiFiManager::onConnect(WiFiChangeHandlerFunction fn) -{ - _connectHandler = fn; -} - -void PersWiFiManager::onAp(WiFiChangeHandlerFunction fn) -{ - _apHandler = fn; -} -#endif diff --git a/PersWiFiManager.h b/PersWiFiManager.h deleted file mode 100644 index bd657abe..00000000 --- a/PersWiFiManager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* PersWiFiManager - version 3.0.1 - https://r-downing.github.io/PersWiFiManager/ - - modified for inclusion in gbs-control - see /3rdparty/PersWiFiManager/ for original code and license -*/ -#if defined(ESP8266) -#ifndef PERSWIFIMANAGER_H -#define PERSWIFIMANAGER_H - -#include -#include -#include -#include - -#define WIFI_CONNECT_TIMEOUT 45 - -class PersWiFiManager -{ - -public: - typedef std::function WiFiChangeHandlerFunction; - - PersWiFiManager(AsyncWebServer &s, DNSServer &d); - - bool attemptConnection(const String &ssid = "", const String &pass = ""); - - void setupWiFiHandlers(); - - bool begin(const String &ssid = "", const String &pass = ""); - - String getApSsid(); - - void setApCredentials(const String &apSsid, const String &apPass = ""); - - void setConnectNonBlock(bool b); - - void handleWiFi(); - - void startApMode(); - - void onConnect(WiFiChangeHandlerFunction fn); - - void onAp(WiFiChangeHandlerFunction fn); - -private: - AsyncWebServer *_server; - DNSServer *_dnsServer; - String _apSsid, _apPass; - - bool _connectNonBlock; - unsigned long _connectStartTime; - - WiFiChangeHandlerFunction _connectHandler; - WiFiChangeHandlerFunction _apHandler; - -}; //class - -#endif -#endif diff --git a/README.md b/README.md index 5a276115..9199653e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,20 @@ -# gbs-control +

-Documentation: https://ramapcsx2.github.io/gbs-control/ +![GBS-Control](./doc/img/logo.jpg) + +

+ +

+ +![Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fway5%2Fgbs-control%2Fpio%2Fconfigure.json&query=%24.version&logo=C%2B%2B&logoColor=white&style=flat&label=%20Version%3A&color=red) + +

+ +

GBS-Control

+ +GBS-Control is an alternative firmware for Tvia Trueview5725 based upscalers / video converter boards. +Its growing list of features includes: -Gbscontrol is an alternative firmware for Tvia Trueview5725 based upscalers / video converter boards. -Its growing list of features includes: - very low lag - sharp and defined upscaling, comparing well to other -expensive- units - no synchronization loss switching 240p/480i (output runs independent from input, sync to display never drops) @@ -19,11 +30,295 @@ Supported standards are NTSC / PAL, the EDTV and HD formats, as well as VGA from Sources can be connected via RGB/HV (VGA), RGBS (game consoles, SCART) or Component Video (YUV). Various variations are supported, such as the PlayStation 2's VGA modes that run over Component cables. -Gbscontrol is a continuation of previous work by dooklink, mybook4, Ian Stedman and others. +Gbscontrol is a continuation of previous work by dooklink, mybook4, Ian Stedman and others. -Bob from RetroRGB did an overview video on the project. This is a highly recommended watch! +Bob from RetroRGB did an overview video on the project. This is a highly recommended watch! https://www.youtube.com/watch?v=fmfR0XI5czI -Development threads: -https://shmups.system11.org/viewtopic.php?f=6&t=52172 -https://circuit-board.de/forum/index.php/Thread/15601-GBS-8220-Custom-Firmware-in-Arbeit/ +Development threads: +- [shmups.system11.org](https://shmups.system11.org/viewtopic.php?f=6&t=52172) +- [circuit-board.de/forum](https://circuit-board.de/forum/index.php/Thread/15601-GBS-8220-Custom-Firmware-in-Arbeit) + +

Table of Contents

+ +- [Toolkit](#toolkit) + - [Windows](#windows) + - [MacOS](#macos) + - [Linux](#linux) +- [Prepare](#prepare) +- [Build and Upload Firmware Image](#build-and-upload-firmware-image) + - [Using Platformio IDE (preferred)](#using-platformio-ide-preferred) + - [Using Arduino IDE](#using-arduino-ide) +- [Filesystem Image and UI Translations](#filesystem-image-and-ui-translations) + - [Platformio IDE (preferred)](#platformio-ide-preferred) + - [Arduino IDE](#arduino-ide) + - [HardwareUI](#hardwareui) + - [WebUI](#webui) + - [Uploading Filesystem image via Platformio IDE (recommended)](#uploading-filesystem-image-via-platformio-ide-recommended) + - [Uploading Filesystem image via Arduino IDE](#uploading-filesystem-image-via-arduino-ide) +- [OTA update](#ota-update) + - [Using Platformio IDE](#using-platformio-ide) + - [Using Arduino IDE](#using-arduino-ide-1) +- [Theory of operation](#theory-of-operation) + - [Slots vs Presets](#slots-vs-presets) + - [Vocabulary](#vocabulary) + - [How-to switch GBS-Control to upload mode?](#how-to-switch-gbs-control-to-upload-mode) +- [TODO:](#todo) +- [Additional information](#additional-information) +- [Old documentation](#old-documentation) + +## Toolkit + +#### Windows +- [NodeJS](https://nodejs.org) +- [Git](https://git-scm.com/download/win) +- [Python 3+](https://www.python.org/downloads) + +#### MacOS +```bash +brew install node git python@3 +``` + +#### Linux +```bash +your_package_manager install node git python +``` + +## Prepare + +Make sure the latest version of `node-js` installed on your computer. After installing `node-js`, run the following in your OS command prompt from the Project root duirctory: + +```bash +npm install -g typescript run-script-os + +npm install +``` + +## Build and Upload Firmware Image + + + +### Using Platformio IDE (preferred) + +>***Please note:***\ +If your objective is to make changes to the Project, please use VSCode + Platformio IDE. + +1. Clone the repository, open it with your VSCode and press Build/Upload. It's never been easier :) + +>***Please note:***\ +Platformio IDE enables upload speed limitation on ESP8266. Upload process at any higher upload speed may fail. + +### Using Arduino IDE + +1. Open "Preferences" in Arduino IDE. In "Additional Boards Manager URLs" put the following source links: + +``` +https://dl.espressif.com/dl/package_esp32_index.json +http://arduino.esp8266.com/stable/package_esp8266com_index.json +``` + +2. Save and close Preferences window. Go to the "Board Manager" and search for ESP8266. Make sure that the latest version of the framework installed. +3. Download/clone the following repositories into your Arduino libraries directory (see: "Preferences - Sketchbook location" + libraries). +For more intfrmation please refer to http://www.arduino.cc/en/Guide/Libraries + +```bash +git clone https://github.com/Links2004/arduinoWebSockets.git +git clone https://github.com/pavelmc/Si5351mcu.git +git clone https://github.com/ThingPulse/esp8266-oled-ssd1306.git +``` + +If you plan to be using ping-library (see: HAVE_PINGER_LIBRARY in options.h) in addition to the above clone/download the following sources: + +```bash +git clone https://github.com/bluemurder/esp8266-ping.git +``` + +4. In menu "Tools" select the board "LOLIN(WEMOS) D1 R2 & mini". Then change "Flash size" to `4MB (FS:1MB OTA:~1019KB), "CPU frequency" to 160MHz, "SSL Support` to `Basic SSL cyphers`. +5. Now remove src/main.cpp file. Arduino IDE will NOT compile your project if you omit this step. You can always restore main.cpp from main repository/active branch. +6. Build/Upload the Project. + +>***Please note:***\ +If you erase the whole chip or doing fresh install, you need to upload both, firmware and filesystem images. See how-to below. + +## Filesystem Image and UI Translations + +HardwareUI (OLED display) can be translated using [`translation.hdwui.json`](./translation.hdwui.json) file, WebUI using [`translation.webui.json`](./translation.webui.json) in the Project root directory. If you wish to add a new language, please use ISO 639-1 formatted locale tag names. + +### Platformio IDE (preferred) + +By changing value of `ui-lang` parameter in `configure.json` you're changing UI (both Web and Hardware) language. You also may change the UI fonts the same way (`ui-hdw-fonts`, `ui-web-font`). +HardwareUI font size may be specified for every translation block in [translation.hdwui.json](./translation.hdwui.json), the default size if `12`. If you add a font size which is not specified in [configure.json](./configure.json), translation generator will ask you to do that by throwing an error. + +- `ui-hdw-fonts` parameter should be formatted as: `FONT_SIZE@FONT_NAME[,FONT_SIZE@FONT_NAME[,...]]`. +- `ui-web-fonts` parameter must match with font-family name in CSS and the Font file name. + +To add a new font (Hardware and Web UI alike) drop it into [/public/assets/fonts](./public/assets/fonts/) directory, only `.ttf` fonts may be used for HardwareUI and only `.woff2` for WebUI. + +>***Please note:***\ +The default and fallback translation is always "en". + +### Arduino IDE + +If you're still using Arduino IDE you need to do a few extra steps to generate translated UI. Please follow steps below: + +#### HardwareUI + +1. Do the necessary changes in ```translation.hdw.json``` +2. Make sure you have installed the latest version of Python on your computer +3. Install ***pillow***: + + ```bash + python -m pip install pillow + ``` + +4. Generate translations + + >_The following commands executed from Project root directory._ + + 4.1. Hardare UI + + #### Linux / MacOS + ```bash + python scripts/generate_translations.py FONT_SIZE@FONT_NAME,FONT_SIZE@FONT_NAME LOCALE + ``` + #### Windows + ```bash + python scripts\generate_translations.py FONT_SIZE@FONT_NAME,FONT_SIZE@FONT_NAME LOCALE + ``` + +5. Now you're ready to build and upload the `firmware` image. + +#### WebUI + +The WebUI consists of two main parts: `public/src/index.ts` and `public/src/index.html.tpl`. Changin any one of them likewise `translation.webui.json`, require re-build the WebUI. + +1. Do the necessary changes in `translation.web.json` +2. Generate WebUI by running the following command: + +```bash +npm run build +``` + +3. Now you're ready to build and upload the `filesystem` image. + +### Uploading Filesystem image via Platformio IDE (recommended) + +You can use `Platform - Build Filesystem Image` command in PlatformIO tab to get the WebUI re-generated. +Either you may use the manual method described below. + +>***Please note:***\ +When you first time open the Project you may not find `Platform` section in PlatformIO tab. This happens because `/data` directory will be only available after you run `Build project`. Run `Build`, then press `Refresh Project Tasks` on top of PlatformIO tab, the required menu will be available once it reloads. + +### Uploading Filesystem image via Arduino IDE + +1. Download the latest release of (ESP8266LittleFS.jar](https://github.com/earlephilhower/arduino-esp8266littlefs-plugin/releases). +2. Extract archive into your Arduino tools directory, keep original directory names and its structure (see: "Preferences - Sketchbook location" + tools) +3. Restart Arduino IDE, open [gbs-control.ino](./gbs-control.ino) file. + >At this point `/data` directory must exist in the Project root. +4. From the Tools menu, select “ESP8266 LittleFS Data Upload“. The contents of `/data` directory will be converted into a binary image file and the upload process will begin. + +## OTA update + +>***A word of warning:***\ +Do not interrupt the network connection or upload process while updating via OTA. Your device may stop working properly. + +Make sure you've enabled OTA mode in Control panel of GBSС. + +### Using Platformio IDE + +1. Open [platformio.ini](./platformio.ini) and uncomment ```upload_protocol, upload_port``` options. Option ```upload_port``` should be equal to the IP address of your GBSС (ex.: upload_port = 192.168.4.1) +2. Now go to "Platformio - Build and Upload" the firmware. + +### Using Arduino IDE + +1. Open sketch (gbs-control.ino). Make sure you already completed the steps 1-5 from ["Build and Upload - Using Arduino IDE"](#build-n-upload-arduino) +2. Go to "Tools - Ports". At the very end of dropdown menu find and chouse your device. +3. Proceed with build/upload. + +For more details visit: https://github.com/JAndrassy/ArduinoOTA/blob/master/README.md + + +## Theory of operation + +### Slots vs Presets + +- Preset - is a collection of predefined runtime values (including output screen resolution, etc). + - Custom presets - a collection of predefined runtime values stored on GBSC filesystem. Custom presets are created and updated together with correspondng Slot. +- Slot - is a collection of Presets. +- Preferences - a collection of parameters which are used system-wide independently of Slots and Presets. So when Slot changes which causes Preset to change, Preferences will remain the same until user not to switch them manually. + +When you connecting a new device, GBS tries to identify the input video signal. There are 9 signal types (VIDEO_ID), which also used to identify Preset for current Slot while saving/loading preferences. +>Slots are managed by user while firmware takes care of Presets automatically, depending on input conditions. + +While managing Slots the following principles must be taken into account: + +1. General parameters of a SLOT are stored in slots.bin, where each of (SLOTS_TOTAL) Slots has structure: + + 1.1. Slot name\ + + 1.2. output resolution\ + ... etc. + + Each Slot has its own SLOT_ID which is one character long. The input video signal ID (VIDEO_ID) is not stored in Slots. + + > This allows to use multiple Presets with the same Slot, when current Preset depends on the input video signal ID. + +2. Preset file names are formatted as `input_video_format.SLOT_ID`, for example: + + - preset_ntsc.SLOT_ID + - preset_pal.SLOT_ID + - preset_ntsc_480p.SLOT_ID\ + ...etc. + +3. Current/Active SLOT_ID and other auxiliar pararmeters are stored in preferencev2.txt file. + +The following diagram represents the structure of system and user configurations: + +![gbs-control user configuration structure](./doc/img/slot-preset-prefs.png) + +### Vocabulary + +- Auto Gain - the functionality or circuit the purpose of which is to maintain a suitable signal amplitude at its output, despite variation of the signal amplitude at the input. +- Clipping - a form of distortion that limits a signal once it exceeds a threshold. Clipping may occur when a signal is recorded by a sensor that has constraints on the range of data it can measure, it can occur when a signal is digitized, or it can occur any other time an analog or digital signal is transformed, particularly in the presence of gain or overshoot and undershoot. [[?]](https://en.wikipedia.org/wiki/Clipping_%28signal_processing) +- FrameTime - the time a frame takes to be rendered and displayed. +- Deinterlacing - the process of converting interlaced video into a non-interlaced or progressive form. [[?]](https://en.wikipedia.org/wiki/Deinterlacing) + - Bob (a.k.a linear spatial) - vertical interpolation from the same frame, this method interpolates the missing pixels from the pixels located directly above and below them in the same frame. The Bob method avoids motion artifacts, but at the cost of considerable vertical detail. + - Line doubling (a.k.a linear temporal, weave, static mesh) - this method generates the missing pixels by copying the corresponding pixels from the previous frame (meshing two fields together to create a single frame). + - Motion adaptive - the method of dynamic weights (functions of measured pixel based motion), it combines the best aspects of both Bob and Weave by isolating the de-interlacing compensation to the pixel level. Spatial and temporal comparisons are performed to decide whether or not an individual pixel has motion. Areas of no motion are statically meshed (weave) and areas where motion is detected are treated with a proprietary filtering technique resulting in very high quality, progressive-scan images. +- Interlacing - a type of video scanning where each frame is made up of 2 images that divide it horizontally by alternating pixel lines (the even and the odd). [[?]](https://en.wikipedia.org/wiki/Interlaced_video) +- Peaking - it takes the high resolution RGB video signal and increases its signal amplitude (the higher peaking the sharper image with more details). +- Progressive scanning (a.k.a noninterlaced scanning) - a format of displaying, storing, or transmitting moving images in which all the lines of each frame are drawn in sequence. [[?]](https://en.wikipedia.org/wiki/Progressive_scan) +- RGBs (Red, Green, Blue and sync) - both the horizontal and vertical sync signals are combined into this one line. [[?]](https://www.retrorgb.com/sync.html) +- RGBHV (RGB Horizontal sync Vertical sync) - is essentially the same as RGBs, however the horizontal and vertical sync signals are sent down their own individual lines, totaling 5 channels. "VGA" uses RGBHV. +- RGsB (Sync on green) - the green cable also carries the horizontal and vertical sync signals, totaling only three cables. The only time you’ll run into RGsB in the classic gaming world is with the PlayStation 2 and it’s usually just better to use component video. +- Scanline - one row in a raster scanning pattern, such as a line of video on a CRT display. +- Step Response - system response to the step input. +- YUV - is the color model found in the PAL analogue color TV standard (excluding PAL-N). A color is described as a Y component (luma) and two chroma components U and V (colorspaces that are encoded using YCbCr). + +### How-to switch GBS-Control to upload mode? + +ESP8266 version of the factory built GBSC, boots into firmware upload mode by pressing the knob button while the device is off and connecting it to a computer with USB cable. + +## TODO: + +- [ ] Full height doesn't work (?) +- [ ] Invert Sync issue +- [ ] PassThrough doesn't work +- [ ] preferScalingRgbhv doesn't work (?) +- [x] device disconnects from WiFi when displaying Output status +- [x] disable ambigous preset paramters inside slots + - [ ] startup runtime parameters loading malfunction +- [ ] De-interlacer noise reduction ctl. +- [ ] color artifacts on high SDRAM refresh rates +- [x] fix OLEDMenu items list offset +- [x] feature request [#553] +- [x] creation/destruction OLEDMenuItem procedure + +## Additional information + +See [/doc/developer_guide.md](./doc/DEVELOPER_GUIDE.md). + +## Old documentation + +https://ramapcsx2.github.io/gbs-control \ No newline at end of file diff --git a/configure.json b/configure.json new file mode 100644 index 00000000..6da647f4 --- /dev/null +++ b/configure.json @@ -0,0 +1,26 @@ +{ + "d1_mini": { + "slots_total": 50, + "menu_width": 131, + "menu_height": 19, + "osd_timeout": 8000, + "use_new_oled_menu": 1, + "reverse_rotary_encoder_for_osd": 0, + "reverse_rotary_encoder_for_oled_menu": 0, + "oled_menu_items_per_screen": 4, + "oled_menu_max_items_num": 64, + "oled_menu_max_subitems_num": 16, + "oled_menu_max_depth": 8, + "oled_menu_refresh_interval_in_ms": 50, + "oled_menu_screen_saver_refresh_interval_in_ms": 5000, + "oled_menu_scroll_lead_in_time_in_ms": 600, + "oled_menu_screen_saver_kick_in_seconds": 180, + "oled_menu_over_draw": 0, + "oled_menu_reset_always_scroll_on_selection": 0, + "serial_buffer_max_len": 2048 + }, + "ui-lang": "en", + "ui-hdw-fonts": "12@FreeSans,16@FreeSans", + "ui-web-font": "Oswald Regular", + "version": "24.0625" +} \ No newline at end of file diff --git a/doc/DEVELOPER_NOTES.md b/doc/DEVELOPER_NOTES.md new file mode 100644 index 00000000..b9a3c2f3 --- /dev/null +++ b/doc/DEVELOPER_NOTES.md @@ -0,0 +1,133 @@ +# TV5725 REGISTERS + +![register map](./img/reg-map.jpg) + +## (S0_41) Display clock tuning register + +![display clock tuning](./img/display-clock-tuning-reg.jpg) + +## (S0_90_1) Osd horizontal zoom select + +![Osd horizontal zoom select](./img/osd-horizontal-zoom-select.jpg) + +## (S0_90_4) Osd vertical zoom select + +![Osd vertical zoom select](./img/osd-vertical-zoom-select.jpg) + +## (S0_91_0) Osd menu icons select + +![Osd vertical zoom select](./img/osd-menu-icons-select.jpg) + +## (S0_91_4) Osd icons modification select + +![Osd vertical zoom select](./img/osd-icons-modification-select.jpg) + +## (S1_00) Select 16bit data + +![Select 16bit data](./img/select-16bit-data.jpg) + +## (S1_01) Y data pipes control in YUV422to444 conversion + +![Y data pipes control in YUV422to444 conversion](./img/y-data-pipes-YUV422to444-conv.jpg) + +## (S1_02) Y data pipes control in YUV444to422 conversion + +![Y data pipes control in YUV444to422 conversion](./img/y-data-pipes-YUV444to422-conv.jpg) + +## (S1_62) Horizontal Stable Estimation Error Range Control + +![Horizontal Stable Estimation Error Range Control](./img/horizontal-stable-est-error-range.jpg) + +## (S2_00) Diagonal Bob Low pass Filter Coefficient Selection + +![diagonal bob coeff. selection](./img/diagonal-bob-lpf-coeff.jpg) + +## (S2_17) Y delay pipe control + +![Y delay pipe control](./img/y-delay-pipe-control.jpg) + +## (S2_17) UV delay pipe control + +![UV delay pipe control](./img/uv-delay-pipe-control.jpg) + +## (S2_3A) Delay pipe control for motion index feedback-bit + +![Delay pipe control for MI](./img/pipe-control-motion-index.jpg) + +## (S2_3C) Motion index delay control + +![Motion index delay control](./img/motion-index-delay-control.jpg) + +## (S3_00) External sync enable + +![External sync enable](./img/vds-sync-enable.jpg) + +## (S3_1F) Programmable repeat frame number + +![Programmable repeat frame number](./img/progm-repeat-frame-num.jpg) + +## (S3_24_4) Y compensation delay + +![Y compensation delay](./img/y-compensation-delay.jpg) + +## (S3_24_6) Compensation delay control + +![Compensation delay control](./img/compensation-delay-ctl.jpg) + +## (S3_2A) UV step response data select + +![UV step response data select](./img/uv-step-response-data-sel.jpg) + +U/V2 is 2 clocks delay of input U/V, UV3 is 3 clocks delay of input U/V, and so on. + +## (S3_32) SVM data generation select control + +![SVM data generation select control](./img/svm-data-generation-select-ctl.jpg) + +A1 is one pipe delay of a0, a2 is one pipe delay of a1, a3 is one pipe delay of a2, a4 is one pipe delay of a3, here a* is the input data y for generate SVM signal. + +## (S3_40) SVM delay be V2CLK control + +![SVM delay be V2CLK control](./img/svm-delay-be-v2clk-ctl.jpg) + +This field define the SVM delay from 1 to 4 V2CLKs + +## (S3_55) Menu mode control for global still index + +![Menu mode control for global still index](./img/menu-mode-control-4-glob-still-ind.jpg) + +This bit is the user defined menu mode for global still signal, when it is 1, the global still signal is 1, the following is the detail. + +## (S3_73) Blue extend range control bit + +![Blue extend range control bit](./img/blue-extend-range-ctl-bit.jpg) + +This field defines the range for blue extend. + +## (S3_80) Y compensation delay control + +![Y compensation delay control](./img/y-compensation-delay-ctl.jpg) + +To compensation the pipe of UV, program this field can delay Y from 1 to 4 clocks. + +## (S4_00) SDRAM Idle Period Control and IDLE Done Select + +![SDRAM Idle Period Control and IDLE Done Select](./img/sdram-idle-period-ctl-n-idle.jpg) + +## (S4_28) Enable playback request mode + +![Enable playback request mode](./img/enable-playback-request-mode.jpg) + +## (S4_4D_0) Read buffer page select from 1 to 16 + +![Read buffer page select from 1 to 16](./img/read-buffer-page-select-1-16.jpg) + +## (S4_4D_5) Enable read FIFO request mode + +![Enable read FIFO request mode](./img/en-read-fifo-request-mode.jpg) + +## (S5_16) CKO2 - PLLAD CKO2 output clock selection + +![PLLAD CKO2 output clock selection](./img/pllad-cko2.jpg) + + diff --git a/doc/img/blue-extend-range-ctl-bit.jpg b/doc/img/blue-extend-range-ctl-bit.jpg new file mode 100644 index 00000000..42ac2759 Binary files /dev/null and b/doc/img/blue-extend-range-ctl-bit.jpg differ diff --git a/doc/img/compensation-delay-ctl.jpg b/doc/img/compensation-delay-ctl.jpg new file mode 100644 index 00000000..e20f55c3 Binary files /dev/null and b/doc/img/compensation-delay-ctl.jpg differ diff --git a/doc/img/diagonal-bob-lpf-coeff.jpg b/doc/img/diagonal-bob-lpf-coeff.jpg new file mode 100644 index 00000000..764f6a1e Binary files /dev/null and b/doc/img/diagonal-bob-lpf-coeff.jpg differ diff --git a/doc/img/display-clock-tuning-reg.jpg b/doc/img/display-clock-tuning-reg.jpg new file mode 100644 index 00000000..a8ff4c60 Binary files /dev/null and b/doc/img/display-clock-tuning-reg.jpg differ diff --git a/doc/img/en-read-fifo-request-mode.jpg b/doc/img/en-read-fifo-request-mode.jpg new file mode 100644 index 00000000..6e1a1771 Binary files /dev/null and b/doc/img/en-read-fifo-request-mode.jpg differ diff --git a/doc/img/enable-playback-request-mode.jpg b/doc/img/enable-playback-request-mode.jpg new file mode 100644 index 00000000..3bbdd447 Binary files /dev/null and b/doc/img/enable-playback-request-mode.jpg differ diff --git a/doc/img/horizontal-stable-est-error-range.jpg b/doc/img/horizontal-stable-est-error-range.jpg new file mode 100644 index 00000000..343bbe0e Binary files /dev/null and b/doc/img/horizontal-stable-est-error-range.jpg differ diff --git a/doc/img/logo.jpg b/doc/img/logo.jpg new file mode 100644 index 00000000..19eb22bb Binary files /dev/null and b/doc/img/logo.jpg differ diff --git a/doc/img/menu-mode-control-4-glob-still-ind.jpg b/doc/img/menu-mode-control-4-glob-still-ind.jpg new file mode 100644 index 00000000..94360c41 Binary files /dev/null and b/doc/img/menu-mode-control-4-glob-still-ind.jpg differ diff --git a/doc/img/motion-index-delay-control.jpg b/doc/img/motion-index-delay-control.jpg new file mode 100644 index 00000000..208e2788 Binary files /dev/null and b/doc/img/motion-index-delay-control.jpg differ diff --git a/doc/img/osd-horizontal-zoom-select.jpg b/doc/img/osd-horizontal-zoom-select.jpg new file mode 100644 index 00000000..a5928a14 Binary files /dev/null and b/doc/img/osd-horizontal-zoom-select.jpg differ diff --git a/doc/img/osd-icons-modification-select.jpg b/doc/img/osd-icons-modification-select.jpg new file mode 100644 index 00000000..fc0b8861 Binary files /dev/null and b/doc/img/osd-icons-modification-select.jpg differ diff --git a/doc/img/osd-menu-icons-select.jpg b/doc/img/osd-menu-icons-select.jpg new file mode 100644 index 00000000..f3711303 Binary files /dev/null and b/doc/img/osd-menu-icons-select.jpg differ diff --git a/doc/img/osd-vertical-zoom-select.jpg b/doc/img/osd-vertical-zoom-select.jpg new file mode 100644 index 00000000..988b0a49 Binary files /dev/null and b/doc/img/osd-vertical-zoom-select.jpg differ diff --git a/doc/img/pipe-control-motion-index.jpg b/doc/img/pipe-control-motion-index.jpg new file mode 100644 index 00000000..8962a0f0 Binary files /dev/null and b/doc/img/pipe-control-motion-index.jpg differ diff --git a/doc/img/pllad-cko2.jpg b/doc/img/pllad-cko2.jpg new file mode 100644 index 00000000..dd5b7248 Binary files /dev/null and b/doc/img/pllad-cko2.jpg differ diff --git a/doc/img/progm-repeat-frame-num.jpg b/doc/img/progm-repeat-frame-num.jpg new file mode 100644 index 00000000..b73595b8 Binary files /dev/null and b/doc/img/progm-repeat-frame-num.jpg differ diff --git a/doc/img/read-buffer-page-select-1-16.jpg b/doc/img/read-buffer-page-select-1-16.jpg new file mode 100644 index 00000000..ba2b6260 Binary files /dev/null and b/doc/img/read-buffer-page-select-1-16.jpg differ diff --git a/doc/img/reg-map.jpg b/doc/img/reg-map.jpg new file mode 100644 index 00000000..cdc961b7 Binary files /dev/null and b/doc/img/reg-map.jpg differ diff --git a/doc/img/sdram-idle-period-ctl-n-idle.jpg b/doc/img/sdram-idle-period-ctl-n-idle.jpg new file mode 100644 index 00000000..f6bfdd3f Binary files /dev/null and b/doc/img/sdram-idle-period-ctl-n-idle.jpg differ diff --git a/doc/img/select-16bit-data.jpg b/doc/img/select-16bit-data.jpg new file mode 100644 index 00000000..ba255ea7 Binary files /dev/null and b/doc/img/select-16bit-data.jpg differ diff --git a/doc/img/slot-preset-prefs.drawio b/doc/img/slot-preset-prefs.drawio new file mode 100644 index 00000000..9094f7f6 --- /dev/null +++ b/doc/img/slot-preset-prefs.drawio @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/img/slot-preset-prefs.png b/doc/img/slot-preset-prefs.png new file mode 100644 index 00000000..f605d7f5 Binary files /dev/null and b/doc/img/slot-preset-prefs.png differ diff --git a/doc/img/svm-data-generation-select-ctl.jpg b/doc/img/svm-data-generation-select-ctl.jpg new file mode 100644 index 00000000..f9887762 Binary files /dev/null and b/doc/img/svm-data-generation-select-ctl.jpg differ diff --git a/doc/img/svm-delay-be-v2clk-ctl.jpg b/doc/img/svm-delay-be-v2clk-ctl.jpg new file mode 100644 index 00000000..d788d854 Binary files /dev/null and b/doc/img/svm-delay-be-v2clk-ctl.jpg differ diff --git a/doc/img/uv-delay-pipe-control.jpg b/doc/img/uv-delay-pipe-control.jpg new file mode 100644 index 00000000..943585f4 Binary files /dev/null and b/doc/img/uv-delay-pipe-control.jpg differ diff --git a/doc/img/uv-step-response-data-sel.jpg b/doc/img/uv-step-response-data-sel.jpg new file mode 100644 index 00000000..fa3c638b Binary files /dev/null and b/doc/img/uv-step-response-data-sel.jpg differ diff --git a/doc/img/vds-sync-enable.jpg b/doc/img/vds-sync-enable.jpg new file mode 100644 index 00000000..94ae0cb4 Binary files /dev/null and b/doc/img/vds-sync-enable.jpg differ diff --git a/doc/img/y-compensation-delay-ctl.jpg b/doc/img/y-compensation-delay-ctl.jpg new file mode 100644 index 00000000..597feb54 Binary files /dev/null and b/doc/img/y-compensation-delay-ctl.jpg differ diff --git a/doc/img/y-compensation-delay.jpg b/doc/img/y-compensation-delay.jpg new file mode 100644 index 00000000..a265b841 Binary files /dev/null and b/doc/img/y-compensation-delay.jpg differ diff --git a/doc/img/y-data-pipes-YUV422to444-conv.jpg b/doc/img/y-data-pipes-YUV422to444-conv.jpg new file mode 100644 index 00000000..2f8c2569 Binary files /dev/null and b/doc/img/y-data-pipes-YUV422to444-conv.jpg differ diff --git a/doc/img/y-data-pipes-YUV444to422-conv.jpg b/doc/img/y-data-pipes-YUV444to422-conv.jpg new file mode 100644 index 00000000..ed0afcfb Binary files /dev/null and b/doc/img/y-data-pipes-YUV444to422-conv.jpg differ diff --git a/doc/img/y-delay-pipe-control.jpg b/doc/img/y-delay-pipe-control.jpg new file mode 100644 index 00000000..df5a0a02 Binary files /dev/null and b/doc/img/y-delay-pipe-control.jpg differ diff --git a/doc/tv5725_datasheet.pdf b/doc/tv5725_datasheet.pdf new file mode 100644 index 00000000..aeffb3b5 Binary files /dev/null and b/doc/tv5725_datasheet.pdf differ diff --git a/doc/tv5725_programming_guide.pdf b/doc/tv5725_programming_guide.pdf new file mode 100644 index 00000000..5f166aae Binary files /dev/null and b/doc/tv5725_programming_guide.pdf differ diff --git a/doc/tv5725_registers_definition_v1.1.pdf b/doc/tv5725_registers_definition_v1.1.pdf new file mode 100644 index 00000000..a1bb3434 Binary files /dev/null and b/doc/tv5725_registers_definition_v1.1.pdf differ diff --git a/framesync.h b/framesync.h deleted file mode 100644 index 9e1939c5..00000000 --- a/framesync.h +++ /dev/null @@ -1,680 +0,0 @@ -#ifndef FRAMESYNC_H_ -#define FRAMESYNC_H_ - -// fast digitalRead() -#if defined(ESP8266) -#define digitalRead(x) ((GPIO_REG_READ(GPIO_IN_ADDRESS) >> x) & 1) -#ifndef DEBUG_IN_PIN -#define DEBUG_IN_PIN D6 -#endif -#else // Arduino -// fastest, but non portable (Uno pin 11 = PB3, Mega2560 pin 11 = PB5) -//#define digitalRead(x) bitRead(PINB, 3) -#include "fastpin.h" -#define digitalRead(x) fastRead() -// no define for DEBUG_IN_PIN -#endif - -#include - -// FS_DEBUG: full verbose debug over serial -// FS_DEBUG_LED: just blink LED (off = adjust phase, on = normal phase) -//#define FS_DEBUG -//#define FS_DEBUG_LED -// #define FRAMESYNC_DEBUG - -#ifdef FRAMESYNC_DEBUG -#define fsDebugPrintf(...) SerialM.printf(__VA_ARGS__) -#else -#define fsDebugPrintf(...) -#endif - -namespace MeasurePeriod { - volatile uint32_t stopTime, startTime; - volatile uint32_t armed; - - void _risingEdgeISR_prepare(); - void _risingEdgeISR_measure(); - - void start() { - startTime = 0; - stopTime = 0; - armed = 0; - attachInterrupt(DEBUG_IN_PIN, _risingEdgeISR_prepare, RISING); - } - - void ICACHE_RAM_ATTR _risingEdgeISR_prepare() - { - noInterrupts(); - //startTime = ESP.getCycleCount(); - __asm__ __volatile__("rsr %0,ccount" - : "=a"(startTime)); - detachInterrupt(DEBUG_IN_PIN); - armed = 1; - attachInterrupt(DEBUG_IN_PIN, _risingEdgeISR_measure, RISING); - interrupts(); - } - - void ICACHE_RAM_ATTR _risingEdgeISR_measure() - { - noInterrupts(); - //stopTime = ESP.getCycleCount(); - __asm__ __volatile__("rsr %0,ccount" - : "=a"(stopTime)); - detachInterrupt(DEBUG_IN_PIN); - interrupts(); - } -} - -void setExternalClockGenFrequencySmooth(uint32_t freq) { - uint32_t current = rto->freqExtClockGen; - - rto->freqExtClockGen = freq; - - constexpr uint32_t STEP_SIZE_HZ = 1000; - - if (current > rto->freqExtClockGen) { - if ((current - rto->freqExtClockGen) < 750000) { - while (current > (rto->freqExtClockGen + STEP_SIZE_HZ)) { - current -= STEP_SIZE_HZ; - Si.setFreq(0, current); - handleWiFi(0); - } - } - } else if (current < rto->freqExtClockGen) { - if ((rto->freqExtClockGen - current) < 750000) { - while ((current + STEP_SIZE_HZ) < rto->freqExtClockGen) { - current += STEP_SIZE_HZ; - Si.setFreq(0, current); - handleWiFi(0); - } - } - } - - Si.setFreq(0, rto->freqExtClockGen); -} - -template -class FrameSyncManager -{ -private: - typedef typename GBS::STATUS_VDS_VERT_COUNT VERT_COUNT; - typedef typename GBS::VDS_HSYNC_RST HSYNC_RST; - typedef typename GBS::VDS_VSYNC_RST VSYNC_RST; - typedef typename GBS::VDS_VS_ST VSST; - typedef typename GBS::template Tie VRST_SST; - - static const uint8_t debugInPin = Attrs::debugInPin; - static const int16_t syncCorrection = Attrs::syncCorrection; - static const int32_t syncTargetPhase = Attrs::syncTargetPhase; - - static bool syncLockReady; - static uint8_t delayLock; - static int16_t syncLastCorrection; - - /// Set to -1 if uninitialized. - /// Reset with syncLastCorrection. - static float maybeFreqExt_per_videoFps; - - // Sample vsync start and stop times from debug pin. - static bool vsyncOutputSample(uint32_t *start, uint32_t *stop) - { - yield(); - ESP.wdtDisable(); - MeasurePeriod::start(); - - // typical: 300000 at 80MHz, 600000 at 160MHz - for (uint32_t i = 0; i < 3000000; i++) { - if (MeasurePeriod::armed) { - MeasurePeriod::armed = 0; - delay(7); - WiFi.setSleepMode(WIFI_LIGHT_SLEEP); - } - if (MeasurePeriod::stopTime > 0) { - break; - } - } - *start = MeasurePeriod::startTime; - *stop = MeasurePeriod::stopTime; - ESP.wdtEnable(0); - WiFi.setSleepMode(WIFI_NONE_SLEEP); - - if ((*start >= *stop) || *stop == 0 || *start == 0) { - // ESP.getCycleCount() overflow oder no pulse, just fail this round - return false; - } - - return true; - } - - // Sample input and output vsync periods and their phase - // difference in microseconds - static bool vsyncPeriodAndPhase(int32_t *periodInput, int32_t *periodOutput, int32_t *phase) - { - fsDebugPrintf("vsyncPeriodAndPhase(), TEST_BUS_SEL=%d\n", GBS::TEST_BUS_SEL::read()); - - uint32_t inStart, inStop, outStart, outStop; - uint32_t inPeriod, outPeriod, diff; - - // calling code needs to ensure debug bus is ready to sample vperiod - - if (!vsyncInputSample(&inStart, &inStop)) { - return false; - } - - GBS::TEST_BUS_SEL::write(0x2); // 0x2 = VDS (t3t50t4) // measure VDS vblank (VB ST/SP) - inPeriod = (inStop - inStart); //>> 1; - if (!vsyncOutputSample(&outStart, &outStop)) { - return false; - } - outPeriod = (outStop - outStart); //>> 1; - - - diff = (outStart - inStart) % inPeriod; - if (periodInput) - *periodInput = inPeriod; - if (periodOutput) - *periodOutput = outPeriod; - if (phase) - *phase = (diff < inPeriod) ? diff : diff - inPeriod; - - return true; - } - - static bool sampleVsyncPeriods(uint32_t *input, uint32_t *output) - { - int32_t inPeriod, outPeriod; - - if (!vsyncPeriodAndPhase(&inPeriod, &outPeriod, NULL)) - return false; - - *input = inPeriod; - *output = outPeriod; - - return true; - } - - // Find appropriate htotal that makes output frame time slightly more than the input. - static bool findBestHTotal(uint32_t &bestHtotal) - { - uint16_t inHtotal = HSYNC_RST::read(); - uint32_t inPeriod, outPeriod; - - if (inHtotal == 0) { - return false; - } // safety - if (!sampleVsyncPeriods(&inPeriod, &outPeriod)) { - return false; - } - - if (inPeriod == 0 || outPeriod == 0) { - return false; - } // safety - - // allow ~4 negative (inPeriod is < outPeriod) clock cycles jitter - if ((inPeriod > outPeriod ? inPeriod - outPeriod : outPeriod - inPeriod) <= 4) { - /*if (inPeriod >= outPeriod) { - Serial.print("inPeriod >= out: "); - Serial.println(inPeriod - outPeriod); - } - else { - Serial.print("inPeriod < out: "); - Serial.println(outPeriod - inPeriod); - }*/ - bestHtotal = inHtotal; - } else { - // large htotal can push intermediates to 33 bits - bestHtotal = (uint64_t)(inHtotal * (uint64_t)inPeriod) / (uint64_t)outPeriod; - } - - // new 08.11.19: skip this step, IF period measurement should be stable enough to give repeatable results - //if (bestHtotal == (inHtotal + 1)) { bestHtotal -= 1; } // works well - //if (bestHtotal == (inHtotal - 1)) { bestHtotal += 1; } // check with SNES + vtotal = 1000 (1280x960) - -#ifdef FS_DEBUG - if (bestHtotal != inHtotal) { - Serial.print(F(" wants new htotal, oldbest: ")); - Serial.print(inHtotal); - Serial.print(F(" newbest: ")); - Serial.println(bestHtotal); - Serial.print(F(" inPeriod: ")); - Serial.print(inPeriod); - Serial.print(F(" outPeriod: ")); - Serial.println(outPeriod); - } -#endif - return true; - } - -public: - // sets syncLockReady = ready() = false, which in turn starts a new init() - // -> findBestHtotal() run in loop() - static void reset(uint8_t frameTimeLockMethod) - { -#ifdef FS_DEBUG - Serial.print("FS reset(), with correction: "); -#endif - if (syncLastCorrection != 0) { -#ifdef FS_DEBUG - Serial.println("Yes"); -#endif - uint16_t vtotal = 0, vsst = 0; - VRST_SST::read(vtotal, vsst); - uint16_t timeout = 0; - vtotal -= syncLastCorrection; - if (frameTimeLockMethod == 0) { // moves VS position - vsst -= syncLastCorrection; - } - - while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)) - ; - GBS::VDS_VS_ST::write(vsst); - timeout = 0; - while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 400)) - ; - GBS::VDS_VSYNC_RST::write(vtotal); - } -#ifdef FS_DEBUG - else { - Serial.println("No"); - } -#endif - fsDebugPrintf("FrameSyncManager::reset(%d)\n", frameTimeLockMethod); - - syncLockReady = false; - syncLastCorrection = 0; - delayLock = 0; - // Don't clear maybeFreqExt_per_videoFps. - // - // Clearing is unsafe, since many callers call reset(), don't - // call externalClockGenSyncInOutRate() -> initFrequency(), then - // expect runFrequency() to keep working. - // - // Not clearing is hopefully safe, since when loading an output - // resolution, externalClockGenResetClock() calls - // FrameSync::clearFrequency() and clears the variable, and - // later someone calls externalClockGenSyncInOutRate() -> - // FrameSync::initFrequency(). - } - - static void resetWithoutRecalculation() - { - syncLockReady = false; - delayLock = 0; - } - - static uint16_t init() - { - uint32_t bestHTotal = 0; - - // Adjust output horizontal sync timing so that the overall - // frame time is as close to the input as possible while still - // being less. Increasing the vertical frame size slightly - // should then push the output frame time to being larger than - // the input. - if (!findBestHTotal(bestHTotal)) { - return 0; - } - - syncLockReady = true; - delayLock = 0; - return (uint16_t)bestHTotal; - } - - static uint32_t getPulseTicks() - { - uint32_t inStart, inStop; - if (!vsyncInputSample(&inStart, &inStop)) { - return 0; - } - return inStop - inStart; - } - - static bool ready(void) - { - return syncLockReady; - } - - static int16_t getSyncLastCorrection() - { - return syncLastCorrection; - } - - static void cleanup() - { - fsDebugPrintf("FrameSyncManager::cleanup(), resetting video frequency\n"); - - syncLastCorrection = 0; // the important bit - syncLockReady = 0; - delayLock = 0; - - // Should we clear maybeFreqExt_per_videoFps? - // - // Clearing is hopefully safe. cleanup() appears to only be - // called when switching between 15 kHz and 31 kHz inputs, or - // when no video is present for an extended period of time and - // the output shuts off. (cleanup() is not called when switching - // between 240p and 480i.) When a new video signal is present, - // someone calls externalClockGenSyncInOutRate() -> - // FrameSync::initFrequency() to reinitialize the output frame - // sync. - // - // Not clearing is hopefully safe. See reset() for an - // explanation. - maybeFreqExt_per_videoFps = -1; - } - - // Sample vsync start and stop times from debug pin. - static bool vsyncInputSample(uint32_t *start, uint32_t *stop) - { - yield(); - ESP.wdtDisable(); - MeasurePeriod::start(); - - // typical: 300000 at 80MHz, 600000 at 160MHz - for (uint32_t i = 0; i < 3000000; i++) { - if (MeasurePeriod::armed) { - MeasurePeriod::armed = 0; - delay(7); - WiFi.setSleepMode(WIFI_LIGHT_SLEEP); - } - if (MeasurePeriod::stopTime > 0) { - break; - } - } - *start = MeasurePeriod::startTime; - *stop = MeasurePeriod::stopTime; - ESP.wdtEnable(0); - WiFi.setSleepMode(WIFI_NONE_SLEEP); - - if ((*start >= *stop) || *stop == 0 || *start == 0) { - // ESP.getCycleCount() overflow oder no pulse, just fail this round - return false; - } - - return true; - } - - // Perform vsync phase locking. This is accomplished by measuring - // the period and phase offset of the input and output vsync - // signals and adjusting the frame size (and thus the output vsync - // frequency) to bring the phase offset closer to the desired - // value. - static bool runVsync(uint8_t frameTimeLockMethod) - { - int32_t period; - int32_t phase; - int32_t target; - int16_t correction; - - if (!syncLockReady) - return false; - - if (delayLock < 2) { - delayLock++; - return true; - } - - if (!vsyncPeriodAndPhase(&period, NULL, &phase)) - return false; - - target = (syncTargetPhase * period) / 360; - - if (phase > target) - correction = 0; - else - correction = syncCorrection; - -#ifdef FS_DEBUG - Serial.printf("phase: %7d target: %7d", phase, target); - if (correction == syncLastCorrection) { - // terminate line if returning early - Serial.println(); - } -#endif -#ifdef FS_DEBUG_LED - if (correction == 0) { - digitalWrite(LED_BUILTIN, LOW); // LED ON - } else { - digitalWrite(LED_BUILTIN, HIGH); // LED OFF - } -#endif - - // return early? - if (correction == syncLastCorrection) { - return true; - } - - int16_t delta = correction - syncLastCorrection; - uint16_t vtotal = 0, vsst = 0; - uint16_t timeout = 0; - VRST_SST::read(vtotal, vsst); - vtotal += delta; - if (frameTimeLockMethod == 0) { // moves VS position - vsst += delta; - } - // else it is method 1: leaves VS position alone - - while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)) - ; - GBS::VDS_VS_ST::write(vsst); - timeout = 0; - while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 400)) - ; - GBS::VDS_VSYNC_RST::write(vtotal); - - syncLastCorrection = correction; - -#ifdef FS_DEBUG - Serial.printf(" vtotal: %4d\n", vtotal); -#endif - - return true; - } - - static void clearFrequency() { - maybeFreqExt_per_videoFps = -1; - } - - static void initFrequency(float outFramesPerS, uint32_t freqExtClockGen) { - /* - This value can be interpreted in multiple ways: - - - Each output frame is a fixed number of video clocks long, at a - given output resolution. - - At a given output resolution, the video clock rate should be - proportional to the input FPS. - */ - maybeFreqExt_per_videoFps = (float)freqExtClockGen / outFramesPerS; - } - - // Perform vsync phase locking. This is accomplished by measuring - // the period and phase offset of the input and output vsync - // signals, then adjusting the output video clock to bring the phase - // offset closer to the desired value. - static bool runFrequency() - { - if (maybeFreqExt_per_videoFps < 0) { - SerialM.printf( - "Error: trying to tune external clock frequency while clock frequency uninitialized!\n"); - return true; - } - - // Compare to externalClockGenSyncInOutRate(). - if (GBS::PAD_CKIN_ENZ::read() != 0) { - // Failed due to external factors (PAD_CKIN_ENZ=0 on - // startup), not bad input signal, don't return frame sync - // error. - fsDebugPrintf( - "Skipping FrameSyncManager::runFrequency(), GBS::PAD_CKIN_ENZ::read() != 0\n"); - return true; - } - - if (rto->outModeHdBypass) { - fsDebugPrintf( - "Skipping FrameSyncManager::runFrequency(), rto->outModeHdBypass\n"); - return true; - } - if (GBS::PLL648_CONTROL_01::read() != 0x75) { - SerialM.printf( - "Error: trying to tune external clock frequency while set to internal clock, PLL648_CONTROL_01=%d!\n", - GBS::PLL648_CONTROL_01::read()); - return true; - } - - if (!syncLockReady) { - fsDebugPrintf( - "Skipping FrameSyncManager::runFrequency(), !syncLockReady\n"); - return false; - } - - // ESP32 FPU only accelerates single-precision float add/mul, not divide, not double. - // https://esp32.com/viewtopic.php?p=82090#p82090 - - // ESP CPU cycles/s - const float esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; - - // ESP CPU cycles - int32_t periodInput; // int32_t periodOutput; - int32_t phase; - - // Frame/s - float fpsInput; - - // Measure input period until we get two consistent measurements. This - // substantially reduces the chance of incorrectly guessing FPS when - // input sync changes (but does not eliminate it, eg. when resetting a - // SNES). - bool success = false; - for (int attempt = 0; attempt < 2; attempt++) { - // Measure input period and output latency. - bool ret = vsyncPeriodAndPhase(&periodInput, nullptr, &phase); - // TODO make vsyncPeriodAndPhase() restore TEST_BUS_SEL, not the caller? - GBS::TEST_BUS_SEL::write(0x0); - if (!ret) { - SerialM.printf("runFrequency(): vsyncPeriodAndPhase failed, retrying...\n"); - continue; - } - - fpsInput = esp8266_clock_freq / (float)periodInput; - if (fpsInput < 47.0f || fpsInput > 86.0f) { - SerialM.printf( - "runFrequency(): fpsInput wrong: %f, retrying...\n", - fpsInput); - continue; - } - - // Measure input period again. vsyncPeriodAndPhase()/getPulseTicks() - // -> vsyncInputSample() depend on GBS::TEST_BUS_SEL = 0, but - // vsyncPeriodAndPhase() sets it to 2. - GBS::TEST_BUS_SEL::write(0x0); - uint32_t periodInput2 = getPulseTicks(); - if (periodInput2 == 0) { - SerialM.printf("runFrequency(): getPulseTicks failed, retrying...\n"); - continue; - } - float fpsInput2 = esp8266_clock_freq / (float)periodInput2; - if (fpsInput2 < 47.0f || fpsInput2 > 86.0f) { - SerialM.printf( - "runFrequency(): fpsInput2 wrong: %f, retrying...\n", - fpsInput2); - continue; - } - - // Check that the two FPS measurements are sufficiently close. - float diff = fabs(fpsInput2 - fpsInput); - float relDiff = diff / std::min(fpsInput, fpsInput2); - if (relDiff != relDiff || diff > 0.5f || relDiff > 0.00833f) { - SerialM.printf( - "FrameSyncManager::runFrequency() measured inconsistent FPS %f and %f, retrying...\n", - fpsInput, - fpsInput2); - continue; - } - - success = true; - break; - } - if (!success) { - SerialM.printf("FrameSyncManager::runFrequency() failed!\n"); - return false; - } - - // ESP CPU cycles - int32_t target = (syncTargetPhase * periodInput) / 360; - - // Latency error (distance behind target), in fractional frames. - // If latency increases, boost frequency, and vice versa. - const float latency_err_frames = - (float)(phase - target) // cycles - / esp8266_clock_freq // s - * fpsInput; // frames - - // 0.0038f is 2/525, the difference between SNES and Wii 240p. - // This number is somewhat arbitrary, but works well in - // practice. - float correction = 0.0038f * latency_err_frames; - - // Some LCD displays (eg. Dell U2312HM) lose sync when changing - // frequency by 0.1% (switching between 59.94 and 60 FPS). - // - // To ensure long-term FPS stability, clamp the maximum deviation from - // input FPS to 0.06%. This is sufficient as long as fpsInput does not - // vary drastically from frame to frame. - constexpr float MAX_CORRECTION = 0.0006f; - if (correction > MAX_CORRECTION) correction = MAX_CORRECTION; - if (correction < -MAX_CORRECTION) correction = -MAX_CORRECTION; - - const float rawFpsOutput = fpsInput * (1 + correction); - - // This has floating-point conversion round-trip rounding errors, which - // is suboptimal, but it's not a big deal. - const float prevFpsOutput = (float)rto->freqExtClockGen / maybeFreqExt_per_videoFps; - - // In case fpsInput is measured incorrectly, rawFpsOutput may be - // drastically different from the previous frame's output FPS. To limit - // the impact of incorrect input FPS measurements, clamp the maximum FPS - // deviation relative to the previous frame's *output* FPS. This - // provides short-term FPS stability. - constexpr float MAX_FPS_CHANGE = 0.0006f; - float fpsOutput = rawFpsOutput; - fpsOutput = std::min(fpsOutput, prevFpsOutput * (1 + MAX_FPS_CHANGE)); - fpsOutput = std::max(fpsOutput, prevFpsOutput * (1 - MAX_FPS_CHANGE)); - - if (fabs(rawFpsOutput - prevFpsOutput) >= 1.f) { - SerialM.printf( - "FPS excursion detected! Measured input FPS %f, previous output FPS %f", - fpsInput, prevFpsOutput); - } - - fsDebugPrintf( - "periodInput=%d, fpsInput=%f, latency_err_frames=%f from %f, " - "fpsOutput=%f := %f\n", - periodInput, fpsInput, latency_err_frames, (float)syncTargetPhase / 360.f, - prevFpsOutput, fpsOutput); - - const auto freqExtClockGen = (uint32_t)(maybeFreqExt_per_videoFps * fpsOutput); - - fsDebugPrintf( - "Setting clock frequency from %u to %u\n", - rto->freqExtClockGen, freqExtClockGen); - - setExternalClockGenFrequencySmooth(freqExtClockGen); - return true; - } -}; - -// grrrrrrrrr - -template -int16_t FrameSyncManager::syncLastCorrection; - -template -float FrameSyncManager::maybeFreqExt_per_videoFps; - -template -uint8_t FrameSyncManager::delayLock; - -template -bool FrameSyncManager::syncLockReady; -#endif diff --git a/gbs-control.ino b/gbs-control.ino index 2134cb2c..4f412c80 100644 --- a/gbs-control.ino +++ b/gbs-control.ino @@ -1,95 +1,46 @@ -#include "ntsc_240p.h" -#include "pal_240p.h" -#include "ntsc_720x480.h" -#include "pal_768x576.h" -#include "ntsc_1280x720.h" -#include "ntsc_1280x1024.h" -#include "ntsc_1920x1080.h" -#include "ntsc_downscale.h" -#include "pal_1280x720.h" -#include "pal_1280x1024.h" -#include "pal_1920x1080.h" -#include "pal_downscale.h" -#include "presetMdSection.h" -#include "presetDeinterlacerSection.h" -#include "presetHdBypassSection.h" -#include "ofw_RGBS.h" -#include "options.h" -#include "slot.h" - +//! This is autogenerated file +//! Please do not edit if you're using PlatformIO + +#define VERSION "24.0625" + +/* +########################################################################### +# File: main.cpp # +# File Created: Friday, 19th April 2024 3:13:38 pm # +# Author: Robert Neumann # +# Last Modified: Tuesday, 25th June 2024 12:48:15 pm # +# Modified By: Sergey Ko # +# # +# License: GPLv3 # +# GBS-Control # +# Copyright (C) 2024 # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program 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 General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +########################################################################### +*/ + +#include "src/options.h" +#include #include -#include "tv5725.h" -#include "osd.h" -#include "SSD1306Wire.h" -#include "images.h" - -#define HAVE_BUTTONS 0 -#define USE_NEW_OLED_MENU 1 - - -static inline void writeBytes(uint8_t slaveRegister, uint8_t *values, uint8_t numValues); -const uint8_t *loadPresetFromSPIFFS(byte forVideoMode); - -SSD1306Wire display(0x3c, D2, D1); //inits I2C address & pins for OLED -const int pin_clk = 14; //D5 = GPIO14 (input of one direction for encoder) -const int pin_data = 13; //D7 = GPIO13 (input of one direction for encoder) -const int pin_switch = 0; //D3 = GPIO0 pulled HIGH, else boot fail (middle push button for encoder) - - -#if USE_NEW_OLED_MENU -#include "OLEDMenuImplementation.h" -#include "OSDManager.h" -OLEDMenuManager oledMenu(&display); -OSDManager osdManager; -volatile OLEDMenuNav oledNav = OLEDMenuNav::IDLE; -volatile uint8_t rotaryIsrID = 0; -#else -String oled_menu[4] = {"Resolutions", "Presets", "Misc.", "Current Settings"}; -String oled_Resolutions[7] = {"1280x960", "1280x1024", "1280x720", "1920x1080", "480/576", "Downscale", "Pass-Through"}; -String oled_Presets[8] = {"1", "2", "3", "4", "5", "6", "7", "Back"}; -String oled_Misc[4] = {"Reset GBS", "Restore Factory", "-----Back"}; - -int oled_menuItem = 1; -int oled_subsetFrame = 0; -int oled_selectOption = 0; -int oled_page = 0; - -int oled_lastCount = 0; -volatile int oled_encoder_pos = 0; -volatile int oled_main_pointer = 0; // volatile vars change done with ISR -volatile int oled_pointer_count = 0; -volatile int oled_sub_pointer = 0; -#endif -#include -// ESPAsyncTCP and ESPAsyncWebServer libraries by me-no-dev -// download (green "Clone or download" button) and extract to Arduino libraries folder -// Windows: "Documents\Arduino\libraries" or full path: "C:\Users\rama\Documents\Arduino\libraries" -// https://github.com/me-no-dev/ESPAsyncTCP -// https://github.com/me-no-dev/ESPAsyncWebServer -#include -#include -#include "FS.h" -#include -#include -#include // mDNS library for finding gbscontrol.local on the local network -#include - -// PersWiFiManager library by Ryan Downing -// https://github.com/r-downing/PersWiFiManager -// included in project root folder to allow modifications within limitations of the Arduino framework -// See 3rdparty/PersWiFiManager for unmodified source and license -#include "PersWiFiManager.h" - -// WebSockets library by Markus Sattler -// https://github.com/Links2004/arduinoWebSockets -// included in src folder to allow header modifications within limitations of the Arduino framework -// See 3rdparty/WebSockets for unmodified source and license -#include "src/WebSockets.h" -#include "src/WebSocketsServer.h" - -// Optional: +#include "src/wserial.h" +#include "src/presets.h" +#include "src/images.h" +#include "src/wifiman.h" +#include "src/menu.h" +#include "src/wserver.h" +#include "src/prefs.h" // ESP8266-ping library to aid debugging WiFi issues, install via Arduino library manager -//#define HAVE_PINGER_LIBRARY #ifdef HAVE_PINGER_LIBRARY #include #include @@ -97,10717 +48,496 @@ unsigned long pingLastTime; Pinger pinger; // pinger global object to aid debugging WiFi issues #endif -typedef TV5725 GBS; - -static unsigned long lastVsyncLock = millis(); - -// Si5351mcu library by Pavel Milanes -// https://github.com/pavelmc/Si5351mcu -// included in project root folder to allow modifications within limitations of the Arduino framework -// See 3rdparty/Si5351mcu for unmodified source and license -#include "src/si5351mcu.h" -Si5351mcu Si; - -#define THIS_DEVICE_MASTER -#ifdef THIS_DEVICE_MASTER -const char *ap_ssid = "gbscontrol"; -const char *ap_password = "qqqqqqqq"; -// change device_hostname_full and device_hostname_partial to rename the device -// (allows 2 or more on the same network) -// new: only use _partial throughout, comply to standards -const char *device_hostname_full = "gbscontrol.local"; -const char *device_hostname_partial = "gbscontrol"; // for MDNS -// -static const char ap_info_string[] PROGMEM = - "(WiFi): AP mode (SSID: gbscontrol, pass 'qqqqqqqq'): Access 'gbscontrol.local' in your browser"; -static const char st_info_string[] PROGMEM = - "(WiFi): Access 'http://gbscontrol:80' or 'http://gbscontrol.local' (or device IP) in your browser"; +#if defined(ESP8266) + // serial mirror class for websocket logs + SerialMirror SerialM; #else -const char *ap_ssid = "gbsslave"; -const char *ap_password = "qqqqqqqq"; -const char *device_hostname_full = "gbsslave.local"; -const char *device_hostname_partial = "gbsslave"; // for MDNS -// -static const char ap_info_string[] PROGMEM = - "(WiFi): AP mode (SSID: gbsslave, pass 'qqqqqqqq'): Access 'gbsslave.local' in your browser"; -static const char st_info_string[] PROGMEM = - "(WiFi): Access 'http://gbsslave:80' or 'http://gbsslave.local' (or device IP) in your browser"; + #define SerialM Serial #endif -AsyncWebServer server(80); +Si5351mcu Si; +ESP8266WebServer server(80); DNSServer dnsServer; WebSocketsServer webSocket(81); -//AsyncWebSocket webSocket("/ws"); -PersWiFiManager persWM(server, dnsServer); - -#define DEBUG_IN_PIN D6 // marked "D12/MISO/D6" (Wemos D1) or D6 (Lolin NodeMCU) -// SCL = D1 (Lolin), D15 (Wemos D1) // ESP8266 Arduino default map: SCL -// SDA = D2 (Lolin), D14 (Wemos D1) // ESP8266 Arduino default map: SDA -#define LEDON \ - pinMode(LED_BUILTIN, OUTPUT); \ - digitalWrite(LED_BUILTIN, LOW) -#define LEDOFF \ - digitalWrite(LED_BUILTIN, HIGH); \ - pinMode(LED_BUILTIN, INPUT) - -// fast ESP8266 digitalRead (21 cycles vs 77), *should* work with all possible input pins -// but only "D7" and "D6" have been tested so far -#define digitalRead(x) ((GPIO_REG_READ(GPIO_IN_ADDRESS) >> x) & 1) +SSD1306Wire display(0x3c, D2, D1); // inits I2C address & pins for OLED + +runTimeOptions rto; +userOptions uopt; +adcOptions adco; +char serialCommand = '@'; // Serial / Web Server commands +char userCommand = '@'; // Serial / Web Server commands +unsigned long lastVsyncLock = 0; +unsigned long resetCountdown = 0; + +/** + * @brief Schedule the device reset + * + * @param millis + */ +void resetInMSec(unsigned long ms) { + if(ms != 0) + resetCountdown = ms + millis(); + if(resetCountdown == 0) + return; + if(millis() >= resetCountdown) { + server.stop(); + webSocket.close(); + LittleFS.end(); + _WSN(F("restarting...")); + delay(100); + ESP.reset(); + } +} + +/** + * @brief This function used to start communication with the board while setup() + * or restart communication after power loss + * (which is actually may never happen on production env.). + * + */ +inline bool powerLossBoardReinit() { + // software reset + utilsZeroAll(); + delay(10); + // put system in the default state + presetsResetParameters(); + prepareSyncProcessor(); -// feed the current measurement, get back the moving average -uint8_t getMovingAverage(uint8_t item) -{ - static const uint8_t sz = 16; - static uint8_t arr[sz] = {0}; - static uint8_t pos = 0; + // prefs data loaded, load current slot + if(!slotLoad(uopt.slotID)) + slotResetFlush(uopt.slotID); - arr[pos] = item; - if (pos < (sz - 1)) { - pos++; - } else { - pos = 0; + if(!utilsCheckBoardPower()) { + stopWire(); + _WSN(F("\n (!) Please check board power and cabling or restart\n")); + return false; } - uint16_t sum = 0; - for (uint8_t i = 0; i < sz; i++) { - sum += arr[i]; + if (uopt.enableCalibrationADC) { + // enabled by default + calibrateAdcOffset(); } - return sum >> 4; // for array size 16 + + return true; } -struct MenuAttrs +/** + * @brief + * + */ +void setup() { - static const int8_t shiftDelta = 4; - static const int8_t scaleDelta = 4; - static const int16_t vertShiftRange = 300; - static const int16_t horizShiftRange = 400; - static const int16_t vertScaleRange = 100; - static const int16_t horizScaleRange = 130; - static const int16_t barLength = 100; -}; -typedef MenuManager Menu; - -/// Video processing mode, loaded into register GBS_PRESET_ID by applyPresets() -/// and read to rto->presetID by doPostPresetLoadSteps(). Shown on web UI. -enum PresetID : uint8_t { - PresetHdBypass = 0x21, - PresetBypassRGBHV = 0x22, -}; -struct runTimeOptions rtos; -struct runTimeOptions *rto = &rtos; -struct userOptions uopts; -struct userOptions *uopt = &uopts; -struct adcOptions adcopts; -struct adcOptions *adco = &adcopts; - -String slotIndexMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~()!*:,"; - -char serialCommand; // Serial / Web Server commands -char userCommand; // Serial / Web Server commands -static uint8_t lastSegment = 0xFF; // GBS segment for direct access -//uint8_t globalDelay; // used for dev / debug + unsigned long initDelay = 0; + bool retryExtClockDetect = false; + // bool powerOrWireIssue = false; + lastVsyncLock = millis(); -#if defined(ESP8266) -// serial mirror class for websocket logs -class SerialMirror : public Stream -{ - size_t write(const uint8_t *data, size_t size) - { - if (ESP.getFreeHeap() > 20000) { - webSocket.broadcastTXT(data, size); - } else { - webSocket.disconnect(); - } - Serial.write(data, size); - return size; - } + pinMode(DEBUG_IN_PIN, INPUT); + pinMode(LED_BUILTIN, OUTPUT); + pinMode(PIN_CLK, INPUT_PULLUP); + pinMode(PIN_DATA, INPUT_PULLUP); + pinMode(PIN_SWITCH, INPUT_PULLUP); + LEDON; // enable the LED, lets users know the board is starting up - size_t write(const char *data, size_t size) - { - if (ESP.getFreeHeap() > 20000) { - webSocket.broadcastTXT(data, size); - } else { - webSocket.disconnect(); - } - Serial.write(data, size); - return size; - } + Serial.begin(115200); // Arduino IDE Serial Monitor requires the same 115200 bauds! + Serial.setTimeout(10); - size_t write(uint8_t data) - { - if (ESP.getFreeHeap() > 20000) { - webSocket.broadcastTXT(&data, 1); - } else { - webSocket.disconnect(); - } - Serial.write(data); - return 1; + // filesystem (web page, custom presets, etc) + if (!LittleFS.begin()) { + _DBGN(F("FS mount failed ((1M FS) selected?)")); + return; } - size_t write(char data) - { - if (ESP.getFreeHeap() > 20000) { - webSocket.broadcastTXT(&data, 1); - } else { - webSocket.disconnect(); - } - Serial.write(data); - return 1; - } + // inits OLED on I2C bus + if(!display.init()) + _DBGN(F("display init failed")); + display.flipScreenVertically(); // orientation fix for OLED - int available() - { - return 0; - } - int read() - { - return -1; - } - int peek() - { - return -1; - } - void flush() {} -}; + menuInit(); -SerialMirror SerialM; -#else -#define SerialM Serial -#endif + startWire(); -#include "framesync.h" +#if WEB_SERVER_ENABLE == 1 + wifiInit(); + serverWebSocketInit(); + serverInit(); -// -// Sync locking tunables/magic numbers -// -struct FrameSyncAttrs -{ - static const uint8_t debugInPin = DEBUG_IN_PIN; - static const uint32_t lockInterval = 100 * 16.70; // every 100 frames - static const int16_t syncCorrection = 2; // Sync correction in scanlines to apply when phase lags target - static const int32_t syncTargetPhase = 90; // Target vsync phase offset (output trails input) in degrees - // to debug: syncTargetPhase = 343 lockInterval = 15 * 16 -}; -typedef FrameSyncManager FrameSync; +#ifdef HAVE_PINGER_LIBRARY + pingLastTime = millis(); + // pinger library + pinger.OnReceive([](const PingerResponse &response) { + if (response.ReceivedResponse) { + _DBGF( + PSTR("Reply from %s: time=%lums\n"), + response.DestIPAddress.toString().c_str(), + response.ResponseTime); -void externalClockGenResetClock() -{ - if (!rto->extClockGenDetected) { - return; - } - fsDebugPrintf("externalClockGenResetClock()\n"); + pingLastTime = millis() - 900; // produce a fast stream of pings if connection is good + } else { + _DBGN(F("Request timed out.")); + } - uint8_t activeDisplayClock = GBS::PLL648_CONTROL_01::read(); + // Return true to continue the ping sequence. + // If current event returns false, the ping sequence is interrupted. + return true; + }); - if (activeDisplayClock == 0x25) - rto->freqExtClockGen = 40500000; - else if (activeDisplayClock == 0x45) - rto->freqExtClockGen = 54000000; - else if (activeDisplayClock == 0x55) - rto->freqExtClockGen = 64800000; - else if (activeDisplayClock == 0x65) - rto->freqExtClockGen = 81000000; - else if (activeDisplayClock == 0x85) - rto->freqExtClockGen = 108000000; - else if (activeDisplayClock == 0x95) - rto->freqExtClockGen = 129600000; - else if (activeDisplayClock == 0xa5) - rto->freqExtClockGen = 162000000; - else if (activeDisplayClock == 0x35) - rto->freqExtClockGen = 81000000; // clock unused - else if (activeDisplayClock == 0) - rto->freqExtClockGen = 81000000; // no preset loaded - else if (!rto->outModeHdBypass) { - SerialM.print(F("preset display clock: 0x")); - SerialM.println(activeDisplayClock, HEX); - } + pinger.OnEnd([](const PingerResponse &response) { + // detailed info not necessary + return true; + }); +#endif // HAVE_PINGER_LIBRARY +#else // WEB_SERVER_ENABLE + wifiDisable(); +#endif // WEB_SERVER_ENABLE - // problem: around 108MHz the library seems to double the clock - // maybe there are regs to check for this and resetPLL - if (rto->freqExtClockGen == 108000000) { - Si.setFreq(0, 87000000); - delay(1); // quick fix - } - // same thing it seems at 40500000 - if (rto->freqExtClockGen == 40500000) { - Si.setFreq(0, 48500000); - delay(1); // quick fix + // Splash screen delay + initDelay = millis(); + // upped from < 500 to < 1500, allows more time for wifi and GBS startup + while (millis() - initDelay < 1500) { + display.drawXbm(2, 2, gbsicon_width, gbsicon_height, gbsicon_bits); + display.display(); + optimistic_yield(500); } + display.clear(); - Si.setFreq(0, rto->freqExtClockGen); - GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) - FrameSync::clearFrequency(); - - SerialM.print(F("clock gen reset: ")); - SerialM.println(rto->freqExtClockGen); -} - -void externalClockGenSyncInOutRate() -{ - fsDebugPrintf("externalClockGenSyncInOutRate()\n"); + // load user preferences file + if(!prefsLoad()) + prefsLoadDefaults(); - if (!rto->extClockGenDetected) { - return; - } - if (GBS::PAD_CKIN_ENZ::read() != 0) { - return; - } - if (rto->outModeHdBypass) { - return; - } - if (GBS::PLL648_CONTROL_01::read() != 0x75) { - return; + GBS::PAD_CKIN_ENZ::write(1); // disable to prevent startup spike damage + if(utilsExternClockGenInit() == -1) { + retryExtClockDetect = true; + _DBGN(F("(!) unable to detect ext. clock, going to try later...")); } - float sfr = getSourceFieldRate(0); - if (sfr < 47.0f || sfr > 86.0f) { - SerialM.print(F("sync skipped sfr wrong: ")); - SerialM.println(sfr); - return; - } + // delay 2 of 2 + // initDelay = millis(); + // while (millis() - initDelay < 1000) { + // // wifiLoop(0); + // delay(10); + // } - float ofr = getOutputFrameRate(); - if (ofr < 47.0f || ofr > 86.0f) { - SerialM.print(F("sync skipped ofr wrong: ")); - SerialM.println(ofr); + // if (powerOrWireIssue == 0) { + // second init, in cases where i2c got stuck earlier but has recovered + // *if* ext clock gen is installed and *if* i2c got stuck, then clockgen must be already running + if (!rto.extClockGenDetected && retryExtClockDetect + && utilsExternClockGenInit() != 1) { + _WSN(F("\n (!) No external clock detected\n")); return; } - uint32_t old = rto->freqExtClockGen; - FrameSync::initFrequency(ofr, old); + if(!powerLossBoardReinit()) + return; - setExternalClockGenFrequencySmooth((sfr / ofr) * rto->freqExtClockGen); + // some debug tools leave garbage in the serial rx buffer + discardSerialRxData(); - int32_t diff = rto->freqExtClockGen - old; + _DBGF(PSTR("\n\n GBS-Control v.%s\n\n\nTV id: 0x%02X rev: 0x%02X\n"), + STRING(VERSION), + GBS::CHIP_ID_PRODUCT::read(), + GBS::CHIP_ID_REVISION::read() + ); + // system init is OK + rto.systemInitOK = true; - SerialM.print(F("source Hz: ")); - SerialM.print(sfr, 5); - SerialM.print(F(" new out: ")); - SerialM.print(getOutputFrameRate(), 5); - SerialM.print(F(" clock: ")); - SerialM.print(rto->freqExtClockGen); - SerialM.print(F(" (")); - SerialM.print(diff >= 0 ? "+" : ""); - SerialM.print(diff); - SerialM.println(F(")")); - delay(1); + LEDOFF; // LED behaviour: only light LED on active sync } -void externalClockGenDetectAndInitialize() -{ - const uint8_t xtal_cl = 0xD2; // 10pF, other choices are 8pF (0x92) and 6pF (0x52) NOTE: Per AN619, the low bytes should be written 0b010010 - // MHz: 27, 32.4, 40.5, 54, 64.8, 81, 108, 129.6, 162 - rto->freqExtClockGen = 81000000; - rto->extClockGenDetected = 0; +void loop() +{ + // stay in loop_wrapper if setup has not been completed + if(!rto.systemInitOK) return; - if (uopt->disableExternalClockGenerator) { - SerialM.println(F("ExternalClockGenerator disabled, skipping detection")); - return; - } + static unsigned long lastTimeSyncWatcher = millis(); + // 500 to start right away (after setup it will be 2790ms when we get here) + static unsigned long lastTimeSourceCheck = 500; + static unsigned long lastTimeInterruptClear = millis(); - uint8_t retVal = 0; - Wire.beginTransmission(SIADDR); - retVal = Wire.endTransmission(); + menuLoop(); + wifiLoop(); - if (retVal != 0) { - return; - } + // run FrameTimeLock if enabled + if (uopt.enableFrameTimeLock && !rto.sourceDisconnected + && rto.autoBestHtotalEnabled && rto.syncWatcherEnabled + && FrameSync::ready() && millis() - lastVsyncLock > FrameSyncAttrs::lockInterval + && rto.continousStableCounter > 20 && rto.noSyncCounter == 0) + { + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); - Wire.beginTransmission(SIADDR); - Wire.write(0); // Device Status - Wire.endTransmission(); - size_t bytes_read = Wire.requestFrom((uint8_t)SIADDR, (size_t)1, false); + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); + if (debug_backup != 0x0) { + GBS::TEST_BUS_SEL::write(0x0); + } + // unsigned long startTime = millis(); + _DBGF( + PSTR("running frame sync, clock gen enabled = %d\n"), + rto.extClockGenDetected + ); + bool success = rto.extClockGenDetected ? FrameSync::runFrequency() : FrameSync::runVsync(uopt.frameTimeLockMethod); + if (!success) { + if (rto.syncLockFailIgnore-- == 0) { + FrameSync::reset(uopt.frameTimeLockMethod); // in case run() failed because we lost sync signal + } + } else if (rto.syncLockFailIgnore > 0) { + rto.syncLockFailIgnore = 16; + } + // _WSN(millis() - startTime); - if (bytes_read == 1) { - retVal = Wire.read(); - if ((retVal & 0x80) == 0) { - // SYS_INIT indicates device is ready. - rto->extClockGenDetected = 1; - } else { - return; + if (debug_backup != 0x0) { + GBS::TEST_BUS_SEL::write(debug_backup); + } } - } else { - return; + lastVsyncLock = millis(); } - Si.init(25000000L); // many Si5351 boards come with 25MHz crystal; 27000000L for one with 27MHz - Wire.beginTransmission(SIADDR); - Wire.write(183); // XTAL_CL - Wire.write(xtal_cl); - Wire.endTransmission(); - Si.setPower(0, SIOUT_6mA); - Si.setFreq(0, rto->freqExtClockGen); - Si.disable(0); -} - -static inline void writeOneByte(uint8_t slaveRegister, uint8_t value) -{ - writeBytes(slaveRegister, &value, 1); -} - -static inline void writeBytes(uint8_t slaveRegister, uint8_t *values, uint8_t numValues) -{ - if (slaveRegister == 0xF0 && numValues == 1) { - lastSegment = *values; - } else - GBS::write(lastSegment, slaveRegister, values, numValues); -} - -void copyBank(uint8_t *bank, const uint8_t *programArray, uint16_t *index) -{ - for (uint8_t x = 0; x < 16; ++x) { - bank[x] = pgm_read_byte(programArray + *index); - (*index)++; + // syncWatcherEnabled is enabled by-default + if (rto.syncWatcherEnabled && rto.boardHasPower) { + if ((millis() - lastTimeInterruptClear) > 3000) { + GBS::INTERRUPT_CONTROL_00::write(0xfe); // reset except for SOGBAD + GBS::INTERRUPT_CONTROL_00::write(0x00); + lastTimeInterruptClear = millis(); + } } -} -boolean videoStandardInputIsPalNtscSd() -{ - if (rto->videoStandardInput == 1 || rto->videoStandardInput == 2) { - return true; + // TODO heavy load for serial and WS. to reimplement + if (rto.printInfos) { + printInfo(); } - return false; -} + // uint16_t testbus = GBS::TEST_BUS::read() & 0x0fff; + // if (testbus >= 0x0FFD){ + // _WSN(testbus,HEX); + // } + // if (rto.videoIsFrozen && (rto.continousStableCounter >= 2)) { + // unfreezeVideo(); + // } -void zeroAll() -{ - // turn processing units off first - writeOneByte(0xF0, 0); - writeOneByte(0x46, 0x00); // reset controls 1 - writeOneByte(0x47, 0x00); // reset controls 2 + // syncwatcher polls SP status. when necessary, initiates adjustments or preset changes + if (!rto.sourceDisconnected && rto.syncWatcherEnabled + && (millis() - lastTimeSyncWatcher) > 20) + { + runSyncWatcher(); + lastTimeSyncWatcher = millis(); - // zero out entire register space - for (int y = 0; y < 6; y++) { - writeOneByte(0xF0, (uint8_t)y); - for (int z = 0; z < 16; z++) { - uint8_t bank[16]; - for (int w = 0; w < 16; w++) { - bank[w] = 0; - // exceptions - //if (y == 5 && z == 0 && w == 2) { - // bank[w] = 0x51; // 5_02 - //} - //if (y == 5 && z == 5 && w == 6) { - // bank[w] = 0x01; // 5_56 - //} - //if (y == 5 && z == 5 && w == 7) { - // bank[w] = 0xC0; // 5_57 - //} + // auto adc gain + if (uopt.enableAutoGain && !rto.sourceDisconnected + && rto.videoStandardInput > 0 && rto.clampPositionIsSet + && rto.noSyncCounter == 0 && rto.continousStableCounter > 90 + && rto.boardHasPower) + { + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + uint8_t debugRegBackup = 0, debugPinBackup = 0; + debugPinBackup = GBS::PAD_BOUT_EN::read(); + debugRegBackup = GBS::TEST_BUS_SEL::read(); + GBS::PAD_BOUT_EN::write(0); // disable output to pin for test + GBS::DEC_TEST_SEL::write(1); // luma and G channel + GBS::TEST_BUS_SEL::write(0xb); // decimation + if (GBS::STATUS_INT_SOG_BAD::read() == 0) { + runAutoGain(); + } + GBS::TEST_BUS_SEL::write(debugRegBackup); + GBS::PAD_BOUT_EN::write(debugPinBackup); // debug output pin back on } - writeBytes(z * 16, bank, 16); } } -} -void loadHdBypassSection() -{ - uint16_t index = 0; - uint8_t bank[16]; - writeOneByte(0xF0, 1); - for (int j = 3; j <= 5; j++) { // start at 0x30 - copyBank(bank, presetHdBypassSection, &index); - writeBytes(j * 16, bank, 16); + // init frame sync + besthtotal routine + // autoBestHtotalEnabled is enabled by default + if (rto.autoBestHtotalEnabled && !FrameSync::ready() && rto.syncWatcherEnabled) { + if (rto.continousStableCounter >= 10 && rto.coastPositionIsSet && + ((millis() - lastVsyncLock) > 500)) { + if ((rto.continousStableCounter % 5) == 0) { // 5, 10, 15, .., 255 + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + runAutoBestHTotal(); + } + } + } } -} -void loadPresetDeinterlacerSection() -{ - uint16_t index = 0; - uint8_t bank[16]; - writeOneByte(0xF0, 2); - for (int j = 0; j <= 3; j++) { // start at 0x00 - copyBank(bank, presetDeinterlacerSection, &index); - writeBytes(j * 16, bank, 16); + // update clamp + coast positions after preset change // do it quickly + if (rto.videoStandardInput <= 14 && rto.videoStandardInput != 0 && + rto.syncWatcherEnabled && !rto.coastPositionIsSet) { + if (rto.continousStableCounter >= 7) { + if (getStatus16SpHsStable() && getVideoMode() == rto.videoStandardInput) { + updateCoastPosition(0); + if (rto.coastPositionIsSet && videoStandardInputIsPalNtscSd()) { + // TODO: verify for other csync formats + GBS::SP_DIS_SUB_COAST::write(0); // enable 5_3e 5 + GBS::SP_H_PROTECT::write(0); // no 5_3e 4 + } + } + } } -} -void loadPresetMdSection() -{ - uint16_t index = 0; - uint8_t bank[16]; - writeOneByte(0xF0, 1); - for (int j = 6; j <= 7; j++) { // start at 0x60 - copyBank(bank, presetMdSection, &index); - writeBytes(j * 16, bank, 16); + // don't exclude modes 13 / 14 / 15 (rgbhv bypass) + if (rto.videoStandardInput != 0 && rto.continousStableCounter >= 4 && + !rto.clampPositionIsSet && rto.syncWatcherEnabled) { + updateClampPosition(); + if (rto.clampPositionIsSet && GBS::SP_NO_CLAMP_REG::read() == 1) { + GBS::SP_NO_CLAMP_REG::write(0); + } } - bank[0] = pgm_read_byte(presetMdSection + index); - bank[1] = pgm_read_byte(presetMdSection + index + 1); - bank[2] = pgm_read_byte(presetMdSection + index + 2); - bank[3] = pgm_read_byte(presetMdSection + index + 3); - writeBytes(8 * 16, bank, 4); // MD section ends at 0x83, not 0x90 -} - -// programs all valid registers (the register map has holes in it, so it's not straight forward) -// 'index' keeps track of the current preset data location. -void writeProgramArrayNew(const uint8_t *programArray, boolean skipMDSection) -{ - uint16_t index = 0; - uint8_t bank[16]; - uint8_t y = 0; - //GBS::PAD_SYNC_OUT_ENZ::write(1); - //GBS::DAC_RGBS_PWDNZ::write(0); // no DAC - //GBS::SFTRST_MEM_FF_RSTZ::write(0); // stop mem fifos + // later stage post preset adjustments + if (rto.applyPresetDoneStage == 1 && + ((rto.continousStableCounter > 35 && rto.continousStableCounter < 45) || // this + !rto.syncWatcherEnabled)) // or that + { + if (rto.applyPresetDoneStage == 1) { + // 2nd chance + GBS::DAC_RGBS_PWDNZ::write(1); // 2nd chance + if (!uopt.wantOutputComponent) { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 2nd chance + } + if (!rto.syncWatcherEnabled) { + updateClampPosition(); + GBS::SP_NO_CLAMP_REG::write(0); // 5_57 0 + } - FrameSync::cleanup(); + if (rto.extClockGenDetected && rto.videoStandardInput != 14) { + // switch to ext clock + // if (!rto.outModeHdBypass) { + if (utilsNotPassThroughMode()) { + uint8_t pll648_value = GBS::PLL648_CONTROL_01::read(); + if (pll648_value != 0x35 && pll648_value != 0x75) { + // first store original in an option byte in 1_2D + // GBS::GBS_PRESET_DISPLAY_CLOCK::write(pll648_value); + rto.presetDisplayClock = pll648_value; + // enable and switch input + Si.enable(0); + delayMicroseconds(800); + GBS::PLL648_CONTROL_01::write(0x75); + } + } + // sync clocks now + externalClockGenSyncInOutRate(); + } + rto.applyPresetDoneStage = 0; + } + } else if (rto.applyPresetDoneStage == 1 && rto.continousStableCounter > 35) { + // 3rd chance + GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC // 3rd chance + if (!uopt.wantOutputComponent) { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 3rd chance + } - // should only be possible if previously was in RGBHV bypass, then hit a manual preset switch - if (rto->videoStandardInput == 15) { - rto->videoStandardInput = 0; + // sync clocks now + externalClockGenSyncInOutRate(); + rto.applyPresetDoneStage = 0; // timeout } - rto->outModeHdBypass = 0; // the default at this stage - if (GBS::ADC_INPUT_SEL::read() == 0) { - //if (rto->inputIsYpBpR == 0) SerialM.println("rto->inputIsYpBpR was 0, fixing to 1"); - rto->inputIsYpBpR = 1; // new: update the var here, allow manual preset loads - } else { - //if (rto->inputIsYpBpR == 1) SerialM.println("rto->inputIsYpBpR was 1, fixing to 0"); - rto->inputIsYpBpR = 0; + if (rto.applyPresetDoneStage == 10) { + rto.applyPresetDoneStage = 11; // set first, so we don't loop applying presets + // registers uninitialized, do post preset + setOutputHdBypassMode(false); } - uint8_t reset46 = GBS::RESET_CONTROL_0x46::read(); // for keeping these as they are now - uint8_t reset47 = GBS::RESET_CONTROL_0x47::read(); + // Input signal detection + if (rto.syncWatcherEnabled && rto.sourceDisconnected && rto.boardHasPower) { + if ((millis() - lastTimeSourceCheck) >= 500) { + if (utilsCheckBoardPower()) { + inputAndSyncDetect(); + } else { + // rto.boardHasPower = false; + // rto.continousStableCounter = 0; + // rto.syncWatcherEnabled = false; + } + lastTimeSourceCheck = millis(); - for (; y < 6; y++) { - writeOneByte(0xF0, (uint8_t)y); - switch (y) { - case 0: - for (int j = 0; j <= 1; j++) { // 2 times - for (int x = 0; x <= 15; x++) { - if (j == 0 && x == 4) { - // keep DAC off - if (rto->useHdmiSyncFix) { - bank[x] = pgm_read_byte(programArray + index) & ~(1 << 0); - } else { - bank[x] = pgm_read_byte(programArray + index); - } - } else if (j == 0 && x == 6) { - bank[x] = reset46; - } else if (j == 0 && x == 7) { - bank[x] = reset47; - } else if (j == 0 && x == 9) { - // keep sync output off - if (rto->useHdmiSyncFix) { - bank[x] = pgm_read_byte(programArray + index) | (1 << 2); - } else { - bank[x] = pgm_read_byte(programArray + index); - } - } else { - // use preset values - bank[x] = pgm_read_byte(programArray + index); - } + // vary SOG slicer level from 2 to 6 + uint8_t currentSOG = GBS::ADC_SOGCTRL::read(); + if (currentSOG >= 3) { + rto.currentLevelSOG = currentSOG - 1; + GBS::ADC_SOGCTRL::write(rto.currentLevelSOG); + } else { + rto.currentLevelSOG = 6; + GBS::ADC_SOGCTRL::write(rto.currentLevelSOG); + } + } + } - index++; - } - writeBytes(0x40 + (j * 16), bank, 16); - } - copyBank(bank, programArray, &index); - writeBytes(0x90, bank, 16); - break; - case 1: - for (int j = 0; j <= 2; j++) { // 3 times - copyBank(bank, programArray, &index); - if (j == 0) { - bank[0] = bank[0] & ~(1 << 5); // clear 1_00 5 - bank[1] = bank[1] | (1 << 0); // set 1_01 0 - bank[12] = bank[12] & 0x0f; // clear 1_0c upper bits - bank[13] = 0; // clear 1_0d - } - writeBytes(j * 16, bank, 16); - } - if (!skipMDSection) { - loadPresetMdSection(); - if (rto->syncTypeCsync) - GBS::MD_SEL_VGA60::write(0); // EDTV possible - else - GBS::MD_SEL_VGA60::write(1); // VGA 640x480 more likely + // has the GBS board lost power? + // check at 2 points, in case one doesn't register + // low values chosen to not do this check on small sync issues + if ((rto.noSyncCounter == 61 || rto.noSyncCounter == 62) && rto.boardHasPower) { + if (!utilsCheckBoardPower()) { + rto.noSyncCounter = 1; // some neutral "no sync" value + // rto.continousStableCounter = 0; + // rto.syncWatcherEnabled = false; + stopWire(); // sets pinmodes SDA, SCL to INPUT + _DBGN(F("(!) TWI has been stopped")); + } else { + rto.noSyncCounter = 63; // avoid checking twice + } + } - GBS::MD_HD1250P_CNTRL::write(rto->medResLineCount); // patch med res support - } - break; - case 2: - loadPresetDeinterlacerSection(); - break; - case 3: - for (int j = 0; j <= 7; j++) { // 8 times - copyBank(bank, programArray, &index); - //if (rto->useHdmiSyncFix) { - // if (j == 0) { - // bank[0] = bank[0] | (1 << 0); // 3_00 0 sync lock - // } - // if (j == 1) { - // bank[10] = bank[10] | (1 << 4); // 3_1a 4 frame lock - // } - //} - writeBytes(j * 16, bank, 16); - } - // blank out VDS PIP registers, otherwise they can end up uninitialized - for (int x = 0; x <= 15; x++) { - writeOneByte(0x80 + x, 0x00); - } - break; - case 4: - for (int j = 0; j <= 5; j++) { // 6 times - copyBank(bank, programArray, &index); - writeBytes(j * 16, bank, 16); - } - break; - case 5: - for (int j = 0; j <= 6; j++) { // 7 times - for (int x = 0; x <= 15; x++) { - bank[x] = pgm_read_byte(programArray + index); - if (index == 322) { // s5_02 bit 6+7 = input selector (only bit 6 is relevant) - if (rto->inputIsYpBpR) - bitClear(bank[x], 6); - else - bitSet(bank[x], 6); - } - if (index == 323) { // s5_03 set clamps according to input channel - if (rto->inputIsYpBpR) { - bitClear(bank[x], 2); // G bottom clamp - bitSet(bank[x], 1); // R mid clamp - bitSet(bank[x], 3); // B mid clamp - } else { - bitClear(bank[x], 2); // G bottom clamp - bitClear(bank[x], 1); // R bottom clamp - bitClear(bank[x], 3); // B bottom clamp - } - } - //if (index == 324) { // s5_04 reset(0) for ADC REF init - // bank[x] = 0x00; - //} - if (index == 352) { // s5_20 always force to 0x02 (only SP_SOG_P_ATO) - bank[x] = 0x02; - } - if (index == 375) { // s5_37 - if (videoStandardInputIsPalNtscSd()) { - bank[x] = 0x6b; - } else { - bank[x] = 0x02; - } - } - if (index == 382) { // s5_3e - bitSet(bank[x], 5); // SP_DIS_SUB_COAST = 1 - } - if (index == 407) { // s5_57 - bitSet(bank[x], 0); // SP_NO_CLAMP_REG = 1 - } - index++; - } - writeBytes(j * 16, bank, 16); - } - break; - } - } - - // scaling RGBHV mode - if (uopt->preferScalingRgbhv && rto->isValidForScalingRGBHV) { - GBS::GBS_OPTION_SCALING_RGBHV::write(1); - rto->videoStandardInput = 3; - } -} - -void activeFrameTimeLockInitialSteps() -{ - // skip if using external clock gen - if (rto->extClockGenDetected) { - SerialM.println(F("Active FrameTime Lock enabled, adjusting external clock gen frequency")); - return; - } - // skip when out mode = bypass - if (rto->presetID != PresetHdBypass && rto->presetID != PresetBypassRGBHV) { - SerialM.print(F("Active FrameTime Lock enabled, disable if display unstable or stays blank! Method: ")); - if (uopt->frameTimeLockMethod == 0) { - SerialM.println(F("0 (vtotal + VSST)")); - } - if (uopt->frameTimeLockMethod == 1) { - SerialM.println(F("1 (vtotal only)")); - } - if (GBS::VDS_VS_ST::read() == 0) { - // VS_ST needs to be at least 1, so method 1 can decrease it when needed (but currently only increases VS_ST) - // don't force this here, instead make sure to have all presets follow the rule (easier dev) - SerialM.println(F("Warning: Check VDS_VS_ST!")); - } - } -} - -void resetInterruptSogSwitchBit() -{ - GBS::INT_CONTROL_RST_SOGSWITCH::write(1); - GBS::INT_CONTROL_RST_SOGSWITCH::write(0); -} - -void resetInterruptSogBadBit() -{ - GBS::INT_CONTROL_RST_SOGBAD::write(1); - GBS::INT_CONTROL_RST_SOGBAD::write(0); -} - -void resetInterruptNoHsyncBadBit() -{ - GBS::INT_CONTROL_RST_NOHSYNC::write(1); - GBS::INT_CONTROL_RST_NOHSYNC::write(0); -} - -void setResetParameters() -{ - SerialM.println(""); - rto->videoStandardInput = 0; - rto->videoIsFrozen = false; - rto->applyPresetDoneStage = 0; - rto->presetVlineShift = 0; - rto->sourceDisconnected = true; - rto->outModeHdBypass = 0; - rto->clampPositionIsSet = 0; - rto->coastPositionIsSet = 0; - rto->phaseIsSet = 0; - rto->continousStableCounter = 0; - rto->noSyncCounter = 0; - rto->isInLowPowerMode = false; - rto->currentLevelSOG = 5; - rto->thisSourceMaxLevelSOG = 31; // 31 = auto sog has not (yet) run - rto->failRetryAttempts = 0; - rto->HPLLState = 0; - rto->motionAdaptiveDeinterlaceActive = false; - rto->scanlinesEnabled = false; - rto->syncTypeCsync = false; - rto->isValidForScalingRGBHV = false; - rto->medResLineCount = 0x33; // 51*8=408 - rto->osr = 0; - rto->useHdmiSyncFix = 0; - rto->notRecognizedCounter = 0; - - adco->r_gain = 0; - adco->g_gain = 0; - adco->b_gain = 0; - - // clear temp storage - GBS::ADC_UNUSED_64::write(0); - GBS::ADC_UNUSED_65::write(0); - GBS::ADC_UNUSED_66::write(0); - GBS::ADC_UNUSED_67::write(0); - GBS::GBS_PRESET_CUSTOM::write(0); - GBS::GBS_PRESET_ID::write(0); - GBS::GBS_OPTION_SCALING_RGBHV::write(0); - GBS::GBS_OPTION_PALFORCED60_ENABLED::write(0); - - // set minimum IF parameters - GBS::IF_VS_SEL::write(1); - GBS::IF_VS_FLIP::write(1); - GBS::IF_HSYNC_RST::write(0x3FF); - GBS::IF_VB_ST::write(0); - GBS::IF_VB_SP::write(2); - - // could stop ext clock gen output here? - FrameSync::cleanup(); - - GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD - GBS::DAC_RGBS_PWDNZ::write(0); // disable DAC - GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 1 // minor SOG clamp effect - GBS::ADC_TEST_04::write(0x02); // 5_04 - GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 - GBS::ADC_CLK_PA::write(0); // 5_00 0/1 PA_ADC input clock = PLLAD CLKO2 - GBS::ADC_SOGEN::write(1); - GBS::SP_SOG_MODE::write(1); - GBS::ADC_INPUT_SEL::write(1); // 1 = RGBS / RGBHV adc data input - GBS::ADC_POWDZ::write(1); // ADC on - setAndUpdateSogLevel(rto->currentLevelSOG); - GBS::RESET_CONTROL_0x46::write(0x00); // all units off - GBS::RESET_CONTROL_0x47::write(0x00); - GBS::GPIO_CONTROL_00::write(0x67); // most GPIO pins regular GPIO - GBS::GPIO_CONTROL_01::write(0x00); // all GPIO outputs disabled - GBS::DAC_RGBS_PWDNZ::write(0); // disable DAC (output) - GBS::PLL648_CONTROL_01::write(0x00); // VCLK(1/2/4) display clock // needs valid for debug bus - GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) - GBS::PAD_CKOUT_ENZ::write(1); // clock output disable - GBS::IF_SEL_ADC_SYNC::write(1); // ! 1_28 2 - GBS::PLLAD_VCORST::write(1); // reset = 1 - GBS::PLL_ADS::write(1); // When = 1, input clock is from ADC ( otherwise, from unconnected clock at pin 40 ) - GBS::PLL_CKIS::write(0); // PLL use OSC clock - GBS::PLL_MS::write(2); // fb memory clock can go lower power - GBS::PAD_CONTROL_00_0x48::write(0x2b); //disable digital inputs, enable debug out pin - GBS::PAD_CONTROL_01_0x49::write(0x1f); //pad control pull down/up transistors on - loadHdBypassSection(); // 1_30 to 1_55 - loadPresetMdSection(); // 1_60 to 1_83 - setAdcParametersGainAndOffset(); - GBS::SP_PRE_COAST::write(9); // was 0x07 // need pre / poast to allow all sources to detect - GBS::SP_POST_COAST::write(18); // was 0x10 // ps2 1080p 18 - GBS::SP_NO_COAST_REG::write(0); // can be 1 in some soft reset situations, will prevent sog vsync decoding << really? - GBS::SP_CS_CLP_ST::write(32); // define it to something at start - GBS::SP_CS_CLP_SP::write(48); - GBS::SP_SOG_SRC_SEL::write(0); // SOG source = ADC - GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) - GBS::SP_NO_CLAMP_REG::write(1); - GBS::PLLAD_ICP::write(0); // lowest charge pump current - GBS::PLLAD_FS::write(0); // low gain (have to deal with cold and warm startups) - GBS::PLLAD_5_16::write(0x1f); - GBS::PLLAD_MD::write(0x700); - resetPLL(); // cycles PLL648 - delay(2); - resetPLLAD(); // same for PLLAD - GBS::PLL_VCORST::write(1); // reset on - GBS::PLLAD_CONTROL_00_5x11::write(0x01); // reset on - resetDebugPort(); - - //GBS::RESET_CONTROL_0x47::write(0x16); - GBS::RESET_CONTROL_0x46::write(0x41); // new 23.07.19 - GBS::RESET_CONTROL_0x47::write(0x17); // new 23.07.19 (was 0x16) - GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts - GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status - GBS::INTERRUPT_CONTROL_00::write(0x00); - GBS::PAD_SYNC_OUT_ENZ::write(0); // sync output enabled, will be low (HC125 fix) - rto->clampPositionIsSet = 0; // some functions override these, so make sure - rto->coastPositionIsSet = 0; - rto->phaseIsSet = 0; - rto->continousStableCounter = 0; - serialCommand = '@'; - userCommand = '@'; -} - -void OutputComponentOrVGA() -{ - - // TODO replace with rto->isCustomPreset? - boolean isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); - if (uopt->wantOutputComponent) { - SerialM.println(F("Output Format: Component")); - GBS::VDS_SYNC_LEV::write(0x80); // 0.25Vpp sync (leave more room for Y) - GBS::VDS_CONVT_BYPS::write(1); // output YUV - GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD - } else { - GBS::VDS_SYNC_LEV::write(0); - GBS::VDS_CONVT_BYPS::write(0); // output RGB - GBS::OUT_SYNC_CNTRL::write(1); // H / V sync out enable - } - - if (!isCustomPreset) { - if (rto->inputIsYpBpR == true) { - applyYuvPatches(); - } else { - applyRGBPatches(); - } - } -} - -void applyComponentColorMixing() -{ - GBS::VDS_Y_GAIN::write(0x64); // 3_35 - GBS::VDS_UCOS_GAIN::write(0x19); // 3_36 - GBS::VDS_VCOS_GAIN::write(0x19); // 3_37 - GBS::VDS_Y_OFST::write(0xfe); // 3_3a - GBS::VDS_U_OFST::write(0x01); // 3_3b -} - -void toggleIfAutoOffset() -{ - if (GBS::IF_AUTO_OFST_EN::read() == 0) { - // and different ADC offsets - GBS::ADC_ROFCTRL::write(0x40); - GBS::ADC_GOFCTRL::write(0x42); - GBS::ADC_BOFCTRL::write(0x40); - // enable - GBS::IF_AUTO_OFST_EN::write(1); - GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame - } else { - if (adco->r_off != 0 && adco->g_off != 0 && adco->b_off != 0) { - GBS::ADC_ROFCTRL::write(adco->r_off); - GBS::ADC_GOFCTRL::write(adco->g_off); - GBS::ADC_BOFCTRL::write(adco->b_off); - } - // adco->r_off = 0: auto calibration on boot failed, leave at current values - GBS::IF_AUTO_OFST_EN::write(0); - GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame - } -} - -// blue only mode: t0t44t1 t0t44t4 -void applyYuvPatches() -{ - GBS::ADC_RYSEL_R::write(1); // midlevel clamp red - GBS::ADC_RYSEL_B::write(1); // midlevel clamp blue - GBS::ADC_RYSEL_G::write(0); // gnd clamp green - GBS::DEC_MATRIX_BYPS::write(1); // ADC - GBS::IF_MATRIX_BYPS::write(1); - - if (GBS::GBS_PRESET_CUSTOM::read() == 0) { - // colors - GBS::VDS_Y_GAIN::write(0x80); // 3_25 - GBS::VDS_UCOS_GAIN::write(0x1c); // 3_26 - GBS::VDS_VCOS_GAIN::write(0x29); // 3_27 - GBS::VDS_Y_OFST::write(0xFE); - GBS::VDS_U_OFST::write(0x03); - GBS::VDS_V_OFST::write(0x03); - if (rto->videoStandardInput >= 5 && rto->videoStandardInput <= 7) { - // todo: Rec. 709 (vs Rec. 601 used normally - // needs this on VDS and HDBypass - } - } - - // if using ADC auto offset for yuv input / rgb output - //GBS::ADC_AUTO_OFST_EN::write(1); - //GBS::VDS_U_OFST::write(0x36); //3_3b - //GBS::VDS_V_OFST::write(0x4d); //3_3c - - if (uopt->wantOutputComponent) { - applyComponentColorMixing(); - } -} - -// blue only mode: t0t44t1 t0t44t4 -void applyRGBPatches() -{ - GBS::ADC_RYSEL_R::write(0); // gnd clamp red - GBS::ADC_RYSEL_B::write(0); // gnd clamp blue - GBS::ADC_RYSEL_G::write(0); // gnd clamp green - GBS::DEC_MATRIX_BYPS::write(0); // 5_1f 2 = 1 for YUV / 0 for RGB << using DEC matrix - GBS::IF_MATRIX_BYPS::write(1); - - if (GBS::GBS_PRESET_CUSTOM::read() == 0) { - // colors - GBS::VDS_Y_GAIN::write(0x80); // 0x80 = 0 - GBS::VDS_UCOS_GAIN::write(0x1c); - GBS::VDS_VCOS_GAIN::write(0x29); // 0x27 when using IF matrix, 0x29 for DEC matrix - GBS::VDS_Y_OFST::write(0x00); // 0 - GBS::VDS_U_OFST::write(0x00); // 2 - GBS::VDS_V_OFST::write(0x00); // 2 - } - - if (uopt->wantOutputComponent) { - applyComponentColorMixing(); - } -} - -/// Write ADC gain registers, and save in adco->r_gain to properly transfer it -/// across loading presets or passthrough. -void setAdcGain(uint8_t gain) { - // gain is actually range, increasing it dims the image. - GBS::ADC_RGCTRL::write(gain); - GBS::ADC_GGCTRL::write(gain); - GBS::ADC_BGCTRL::write(gain); - - // Save gain for applying preset. (Gain affects passthrough presets, and - // loading a passthrough preset loads from adco but doesn't save to it.) - adco->r_gain = gain; - adco->g_gain = gain; - adco->b_gain = gain; -} - -void setAdcParametersGainAndOffset() -{ - GBS::ADC_ROFCTRL::write(0x40); - GBS::ADC_GOFCTRL::write(0x40); - GBS::ADC_BOFCTRL::write(0x40); - - // Do not call setAdcGain() and overwrite adco->r_gain. This function should - // only be called during startup, or during doPostPresetLoadSteps(), and if - // `uopt->enableAutoGain == 1` then doPostPresetLoadSteps() will revert - // these writes with `adco->r_gain`. - GBS::ADC_RGCTRL::write(0x7B); - GBS::ADC_GGCTRL::write(0x7B); - GBS::ADC_BGCTRL::write(0x7B); -} - -void updateHVSyncEdge() -{ - static uint8_t printHS = 0, printVS = 0; - uint16_t temp = 0; - - if (GBS::STATUS_INT_SOG_BAD::read() == 1) { - resetInterruptSogBadBit(); - return; - } - - uint8_t syncStatus = GBS::STATUS_16::read(); - if (rto->syncTypeCsync) { - // sog check, only check H - if ((syncStatus & 0x02) != 0x02) - return; - } else { - // HV check, check H + V - if ((syncStatus & 0x0a) != 0x0a) - return; - } - - if ((syncStatus & 0x02) != 0x02) // if !hs active - { - //SerialM.println("(SP) can't detect sync edge"); - } else { - if ((syncStatus & 0x01) == 0x00) { - if (printHS != 1) { - SerialM.println(F("(SP) HS active low")); - } - printHS = 1; - - temp = GBS::HD_HS_SP::read(); - if (GBS::HD_HS_ST::read() < temp) { // if out sync = ST < SP - GBS::HD_HS_SP::write(GBS::HD_HS_ST::read()); - GBS::HD_HS_ST::write(temp); - GBS::SP_HS2PLL_INV_REG::write(1); - //GBS::SP_SOG_P_INV::write(0); // 5_20 2 //could also use 5_20 1 "SP_SOG_P_ATO" - } - } else { - if (printHS != 2) { - SerialM.println(F("(SP) HS active high")); - } - printHS = 2; - - temp = GBS::HD_HS_SP::read(); - if (GBS::HD_HS_ST::read() > temp) { // if out sync = ST > SP - GBS::HD_HS_SP::write(GBS::HD_HS_ST::read()); - GBS::HD_HS_ST::write(temp); - GBS::SP_HS2PLL_INV_REG::write(0); - //GBS::SP_SOG_P_INV::write(1); // 5_20 2 //could also use 5_20 1 "SP_SOG_P_ATO" - } - } - - // VS check, but only necessary for separate sync (CS should have VS always active low) - if (rto->syncTypeCsync == false) { - if ((syncStatus & 0x08) != 0x08) // if !vs active - { - Serial.println(F("VS can't detect sync edge")); - } else { - if ((syncStatus & 0x04) == 0x00) { - if (printVS != 1) { - SerialM.println(F("(SP) VS active low")); - } - printVS = 1; - - temp = GBS::HD_VS_SP::read(); - if (GBS::HD_VS_ST::read() < temp) { // if out sync = ST < SP - GBS::HD_VS_SP::write(GBS::HD_VS_ST::read()); - GBS::HD_VS_ST::write(temp); - } - } else { - if (printVS != 2) { - SerialM.println(F("(SP) VS active high")); - } - printVS = 2; - - temp = GBS::HD_VS_SP::read(); - if (GBS::HD_VS_ST::read() > temp) { // if out sync = ST > SP - GBS::HD_VS_SP::write(GBS::HD_VS_ST::read()); - GBS::HD_VS_ST::write(temp); - } - } - } - } - } -} - -void prepareSyncProcessor() -{ - writeOneByte(0xF0, 5); - GBS::SP_SOG_P_ATO::write(0); // 5_20 disable sog auto polarity // hpw can be > ht, but auto is worse - GBS::SP_JITTER_SYNC::write(0); - // H active detect control - writeOneByte(0x21, 0x18); // SP_SYNC_TGL_THD H Sync toggle time threshold 0x20; lower than 5_33(not always); 0 to turn off (?) 0x18 for 53.69 system @ 33.33 - writeOneByte(0x22, 0x0F); // SP_L_DLT_REG Sync pulse width difference threshold (less than this = equal) - writeOneByte(0x23, 0x00); // UNDOCUMENTED range from 0x00 to at least 0x1d - writeOneByte(0x24, 0x40); // SP_T_DLT_REG H total width difference threshold rgbhv: b // range from 0x02 upwards - writeOneByte(0x25, 0x00); // SP_T_DLT_REG - writeOneByte(0x26, 0x04); // SP_SYNC_PD_THD H sync pulse width threshold // from 0(?) to 0x50 // in yuv 720p range only to 0x0a! - writeOneByte(0x27, 0x00); // SP_SYNC_PD_THD - writeOneByte(0x2a, 0x0F); // SP_PRD_EQ_THD How many legal lines as valid; scales with 5_33 (needs to be below) - // V active detect control - // these 4 only have effect with HV input; test: s5s2ds34 s5s2es24 s5s2fs16 s5s31s84 - writeOneByte(0x2d, 0x03); // SP_VSYNC_TGL_THD V sync toggle time threshold // at 5 starts to drop many 0_16 vsync events - writeOneByte(0x2e, 0x00); // SP_SYNC_WIDTH_DTHD V sync pulse width threshold - writeOneByte(0x2f, 0x02); // SP_V_PRD_EQ_THD How many continue legal v sync as valid // at 4 starts to drop 0_16 vsync events - writeOneByte(0x31, 0x2f); // SP_VT_DLT_REG V total difference threshold - // Timer value control - writeOneByte(0x33, 0x3a); // SP_H_TIMER_VAL H timer value for h detect (was 0x28) - writeOneByte(0x34, 0x06); // SP_V_TIMER_VAL V timer for V detect // 0_16 vsactive // was 0x05 - // Sync separation control - if (rto->videoStandardInput == 0) - GBS::SP_DLT_REG::write(0x70); // 5_35 130 too much for ps2 1080i, 0xb0 for 1080p - else if (rto->videoStandardInput <= 4) - GBS::SP_DLT_REG::write(0xC0); // old: extended to 0x150 later if mode = 1 or 2 - else if (rto->videoStandardInput <= 6) - GBS::SP_DLT_REG::write(0xA0); - else if (rto->videoStandardInput == 7) - GBS::SP_DLT_REG::write(0x70); - else - GBS::SP_DLT_REG::write(0x70); - - if (videoStandardInputIsPalNtscSd()) { - GBS::SP_H_PULSE_IGNOR::write(0x6b); - } else { - GBS::SP_H_PULSE_IGNOR::write(0x02); // test with MS / Genesis mode (wsog 2) vs ps2 1080p (0x13 vs 0x05) - } - // leave out pre / post coast here - // 5_3a attempted 2 for 1chip snes 239 mode intermittency, works fine except for MD in MS mode - // make sure this is stored in the presets as well, as it affects sync time - GBS::SP_H_TOTAL_EQ_THD::write(3); - - GBS::SP_SDCS_VSST_REG_H::write(0); - GBS::SP_SDCS_VSSP_REG_H::write(0); - GBS::SP_SDCS_VSST_REG_L::write(4); // 5_3f // was 12 - GBS::SP_SDCS_VSSP_REG_L::write(1); // 5_40 // was 11 - - GBS::SP_CS_HS_ST::write(0x10); // 5_45 - GBS::SP_CS_HS_SP::write(0x00); // 5_47 720p source needs ~20 range, may be necessary to adjust at runtime, based on source res - - writeOneByte(0x49, 0x00); // retime HS start for RGB+HV rgbhv: 20 - writeOneByte(0x4a, 0x00); // - writeOneByte(0x4b, 0x44); // retime HS stop rgbhv: 50 - writeOneByte(0x4c, 0x00); // - - writeOneByte(0x51, 0x02); // 0x00 rgbhv: 2 - writeOneByte(0x52, 0x00); // 0xc0 - writeOneByte(0x53, 0x00); // 0x05 rgbhv: 6 - writeOneByte(0x54, 0x00); // 0xc0 - - if (rto->videoStandardInput != 15 && (GBS::GBS_OPTION_SCALING_RGBHV::read() != 1)) { - GBS::SP_CLAMP_MANUAL::write(0); // 0 = automatic on/off possible - GBS::SP_CLP_SRC_SEL::write(0); // clamp source 1: pixel clock, 0: 27mhz // was 1 but the pixel clock isn't available at first - GBS::SP_NO_CLAMP_REG::write(1); // 5_57_0 unlock clamp - GBS::SP_SOG_MODE::write(1); - GBS::SP_H_CST_ST::write(0x10); // 5_4d - GBS::SP_H_CST_SP::write(0x100); // 5_4f - GBS::SP_DIS_SUB_COAST::write(0); // 5_3e 5 - GBS::SP_H_PROTECT::write(1); // SP_H_PROTECT on for detection - GBS::SP_HCST_AUTO_EN::write(0); - GBS::SP_NO_COAST_REG::write(0); - } - - GBS::SP_HS_REG::write(1); // 5_57 7 - GBS::SP_HS_PROC_INV_REG::write(0); // no SP sync inversion - GBS::SP_VS_PROC_INV_REG::write(0); // - - writeOneByte(0x58, 0x05); //rgbhv: 0 - writeOneByte(0x59, 0x00); //rgbhv: 0 - writeOneByte(0x5a, 0x01); //rgbhv: 0 // was 0x05 but 480p ps2 doesnt like it - writeOneByte(0x5b, 0x00); //rgbhv: 0 - writeOneByte(0x5c, 0x03); //rgbhv: 0 - writeOneByte(0x5d, 0x02); //rgbhv: 0 // range: 0 - 0x20 (how long should clamp stay off) -} - -// Sync detect resolution: 5bits; comparator voltage range 10mv~320mv. -// -> 10mV per step; if cables and source are to standard (level 6 = 60mV) -void setAndUpdateSogLevel(uint8_t level) -{ - rto->currentLevelSOG = level & 0x1f; - GBS::ADC_SOGCTRL::write(level); - setAndLatchPhaseSP(); - setAndLatchPhaseADC(); - latchPLLAD(); - GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status - GBS::INTERRUPT_CONTROL_00::write(0x00); - //Serial.print("sog: "); Serial.println(rto->currentLevelSOG); -} - -// in operation: t5t04t1 for 10% lower power on ADC -// also: s0s40s1c for 5% (lower memclock of 108mhz) -// for some reason: t0t45t2 t0t45t4 (enable SDAC, output max voltage) 5% lower done in presets -// t0t4ft4 clock out should be off -// s4s01s20 (was 30) faster latency // unstable at 108mhz -// both phase controls off saves some power 506ma > 493ma -// oversample ratio can save 10% at 1x -// t3t24t3 VDS_TAP6_BYPS on can save 2% - -// Generally, the ADC has to stay enabled to perform SOG separation and thus "see" a source. -// It is possible to run in low power mode. -// Function should not further nest, so it can be called in syncwatcher -void goLowPowerWithInputDetection() -{ - GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD - GBS::DAC_RGBS_PWDNZ::write(0); // direct disableDAC() - //zeroAll(); - setResetParameters(); // includes rto->videoStandardInput = 0 - prepareSyncProcessor(); - delay(100); - rto->isInLowPowerMode = true; - SerialM.println(F("Scanning inputs for sources ...")); - LEDOFF; -} - -boolean optimizePhaseSP() -{ - uint16_t pixelClock = GBS::PLLAD_MD::read(); - uint8_t badHt = 0, prevBadHt = 0, worstBadHt = 0, worstPhaseSP = 0, prevPrevBadHt = 0, goodHt = 0; - boolean runTest = 1; - - if (GBS::STATUS_SYNC_PROC_HTOTAL::read() < (pixelClock - 8)) { - return 0; - } - if (GBS::STATUS_SYNC_PROC_HTOTAL::read() > (pixelClock + 8)) { - return 0; - } - - if (rto->currentLevelSOG <= 2) { - // not very stable, use fixed values - rto->phaseSP = 16; - rto->phaseADC = 16; - if (rto->videoStandardInput > 0 && rto->videoStandardInput <= 4) { - if (rto->osr == 4) { - rto->phaseADC += 16; - rto->phaseADC &= 0x1f; - } - } - delay(8); // a bit longer, to match default run time - runTest = 0; // skip to end - } - - //unsigned long startTime = millis(); - - if (runTest) { - // 32 distinct phase settings, 3 average samples (missing 2 phase steps) > 34 - for (uint8_t u = 0; u < 34; u++) { - rto->phaseSP++; - rto->phaseSP &= 0x1f; - setAndLatchPhaseSP(); - badHt = 0; - delayMicroseconds(256); - for (uint8_t i = 0; i < 20; i++) { - if (GBS::STATUS_SYNC_PROC_HTOTAL::read() != pixelClock) { - badHt++; - delayMicroseconds(384); - } - } - // if average 3 samples has more badHt than seen yet, this phase step is worse - if ((badHt + prevBadHt + prevPrevBadHt) > worstBadHt) { - worstBadHt = (badHt + prevBadHt + prevPrevBadHt); - worstPhaseSP = (rto->phaseSP - 1) & 0x1f; // medium of 3 samples - } - - if (badHt == 0) { - // count good readings as well, to know whether the entire run is valid - goodHt++; - } - - prevPrevBadHt = prevBadHt; - prevBadHt = badHt; - //Serial.print(rto->phaseSP); Serial.print(" badHt: "); Serial.println(badHt); - } - - //Serial.println(goodHt); - - if (goodHt < 17) { - //Serial.println("pxClk unstable"); - return 0; - } - - // adjust global phase values according to test results - if (worstBadHt != 0) { - rto->phaseSP = (worstPhaseSP + 16) & 0x1f; - // assume color signals arrive at same time: phase adc = phase sp - // test in hdbypass mode shows this is more related to sog.. the assumptions seem fine at sog = 8 - rto->phaseADC = 16; //(rto->phaseSP) & 0x1f; - - // different OSR require different phase angles, also depending on bypass, etc - // shift ADC phase 180 degrees for the following - if (rto->videoStandardInput >= 5 && rto->videoStandardInput <= 7) { - if (rto->osr == 2) { - //Serial.println("shift adc phase"); - rto->phaseADC += 16; - rto->phaseADC &= 0x1f; - } - } else if (rto->videoStandardInput > 0 && rto->videoStandardInput <= 4) { - if (rto->osr == 4) { - //Serial.println("shift adc phase"); - rto->phaseADC += 16; - rto->phaseADC &= 0x1f; - } - } - } else { - // test was always good, so choose any reasonable value - rto->phaseSP = 16; - rto->phaseADC = 16; - if (rto->videoStandardInput > 0 && rto->videoStandardInput <= 4) { - if (rto->osr == 4) { - rto->phaseADC += 16; - rto->phaseADC &= 0x1f; - } - } - } - } - - //Serial.println(millis() - startTime); - //Serial.print("worstPhaseSP: "); Serial.println(worstPhaseSP); - - /*static uint8_t lastLevelSOG = 99; - if (lastLevelSOG != rto->currentLevelSOG) { - SerialM.print("Phase: "); SerialM.print(rto->phaseSP); - SerialM.print(" SOG: "); SerialM.print(rto->currentLevelSOG); - SerialM.println(); - } - lastLevelSOG = rto->currentLevelSOG;*/ - - setAndLatchPhaseSP(); - delay(1); - setAndLatchPhaseADC(); - - return 1; -} - -void optimizeSogLevel() -{ - if (rto->boardHasPower == false) // checkBoardPower is too invasive now - { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 13; - return; - } - if (rto->videoStandardInput == 15 || GBS::SP_SOG_MODE::read() != 1 || rto->syncTypeCsync == false) { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 13; - return; - } - - if (rto->inputIsYpBpR) { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 14; - } else { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 13; // similar to yuv, allow variations - } - setAndUpdateSogLevel(rto->currentLevelSOG); - - uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); - uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(0xa); - delay(1); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(0x0f); - delay(1); - } - - GBS::TEST_BUS_EN::write(1); - - delay(100); - while (1) { - uint16_t syncGoodCounter = 0; - unsigned long timeout = millis(); - while ((millis() - timeout) < 60) { - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { - syncGoodCounter++; - if (syncGoodCounter >= 60) { - break; - } - } else if (syncGoodCounter >= 4) { - syncGoodCounter -= 3; - } - } - - if (syncGoodCounter >= 60) { - syncGoodCounter = 0; - //if (getVideoMode() != 0) { - if (GBS::TEST_BUS_2F::read() > 0) { - delay(20); - for (int a = 0; a < 50; a++) { - syncGoodCounter++; - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 0 || GBS::TEST_BUS_2F::read() == 0) { - syncGoodCounter = 0; - break; - } - } - if (syncGoodCounter >= 49) { - //SerialM.print("OK @SOG "); SerialM.println(rto->currentLevelSOG); printInfo(); - break; // found, exit - } else { - //Serial.print(" inner test failed syncGoodCounter: "); Serial.println(syncGoodCounter); - } - } else { // getVideoMode() == 0 - //Serial.print("sog-- syncGoodCounter: "); Serial.println(syncGoodCounter); - } - } else { // syncGoodCounter < 40 - //Serial.print("outer test failed syncGoodCounter: "); Serial.println(syncGoodCounter); - } - - if (rto->currentLevelSOG >= 2) { - rto->currentLevelSOG -= 1; - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(8); // time for sog to settle - } else { - rto->currentLevelSOG = 13; // leave at default level - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(8); - break; // break and exit - } - } - - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG; - if (rto->thisSourceMaxLevelSOG == 0) { - rto->thisSourceMaxLevelSOG = 1; // fail safe - } - - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(debug_backup); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); - } -} - -// GBS boards have 2 potential sync sources: -// - RCA connectors -// - VGA input / 5 pin RGBS header / 8 pin VGA header (all 3 are shared electrically) -// This routine looks for sync on the currently active input. If it finds it, the input is returned. -// If it doesn't find sync, it switches the input and returns 0, so that an active input will be found eventually. -uint8_t detectAndSwitchToActiveInput() -{ // if any - uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); - unsigned long timeout = millis(); - while (millis() - timeout < 450) { - delay(10); - handleWiFi(0); - - boolean stable = getStatus16SpHsStable(); - if (stable) { - currentInput = GBS::ADC_INPUT_SEL::read(); - SerialM.print(F("Activity detected, input: ")); - if (currentInput == 1) - SerialM.println("RGB"); - else - SerialM.println(F("Component")); - - if (currentInput == 1) { // RGBS or RGBHV - boolean vsyncActive = 0; - rto->inputIsYpBpR = false; // declare for MD - rto->currentLevelSOG = 13; // test startup with MD and MS separately! - setAndUpdateSogLevel(rto->currentLevelSOG); - - unsigned long timeOutStart = millis(); - // vsync test - // 360ms good up to 5_34 SP_V_TIMER_VAL = 0x0b - while (!vsyncActive && ((millis() - timeOutStart) < 360)) { - vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); - handleWiFi(0); // wifi stack - delay(1); - } - - // if VSync is active, it's RGBHV or RGBHV with CSync on HS pin - if (vsyncActive) { - SerialM.println(F("VSync: present")); - GBS::MD_SEL_VGA60::write(1); // VGA 640x480 more likely than EDTV - boolean hsyncActive = 0; - - timeOutStart = millis(); - while (!hsyncActive && millis() - timeOutStart < 400) { - hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); - handleWiFi(0); // wifi stack - delay(1); - } - - if (hsyncActive) { - SerialM.print(F("HSync: present")); - // The HSync and SOG pins are setup to detect CSync, if present - // (SOG mode on, coasting setup, debug bus setup, etc) - // SP_H_PROTECT is needed for CSync with a VS source present as well - GBS::SP_H_PROTECT::write(1); - delay(120); - - short decodeSuccess = 0; - for (int i = 0; i < 3; i++) { - // no success if: no signal at all (returns 0.0f), no embedded VSync (returns ~18.5f) - // todo: this takes a while with no csync present - rto->syncTypeCsync = 1; // temporary for test - float sfr = getSourceFieldRate(1); - rto->syncTypeCsync = 0; // undo - if (sfr > 40.0f) - decodeSuccess++; // properly decoded vsync from 40 to xx Hz - } - - if (decodeSuccess >= 2) { - SerialM.println(F(" (with CSync)")); - GBS::SP_PRE_COAST::write(0x10); // increase from 9 to 16 (EGA 364) - delay(40); - rto->syncTypeCsync = true; - } else { - SerialM.println(); - rto->syncTypeCsync = false; - } - - // check for 25khz, all regular SOG modes first // update: only check for mode 8 - // MD reg for medium res starts at 0x2C and needs 16 loops to ramp to max of 0x3C (vt 360 .. 496) - // if source is HS+VS, can't detect via MD unit, need to set 5_11=0x92 and look at vt: counter - for (uint8_t i = 0; i < 16; i++) { - //printInfo(); - uint8_t innerVideoMode = getVideoMode(); - if (innerVideoMode == 8) { - setAndUpdateSogLevel(rto->currentLevelSOG); - rto->medResLineCount = GBS::MD_HD1250P_CNTRL::read(); - SerialM.println(F("med res")); - - return 1; - } - // update 25khz detection - GBS::MD_HD1250P_CNTRL::write(GBS::MD_HD1250P_CNTRL::read() + 1); - //Serial.println(GBS::MD_HD1250P_CNTRL::read(), HEX); - delay(30); - } - - rto->videoStandardInput = 15; - // exception: apply preset here, not later in syncwatcher - applyPresets(rto->videoStandardInput); - delay(100); - - return 3; - } else { - // need to continue looking - SerialM.println(F("but no HSync!")); - } - } - - if (!vsyncActive) { // then do RGBS check - rto->syncTypeCsync = true; - GBS::MD_SEL_VGA60::write(0); // EDTV60 more likely than VGA60 - uint16_t testCycle = 0; - timeOutStart = millis(); - while ((millis() - timeOutStart) < 6000) { - delay(2); - if (getVideoMode() > 0) { - if (getVideoMode() != 8) { // if it's mode 8, need to set stuff first - return 1; - } - } - testCycle++; - // post coast 18 can mislead occasionally (SNES 239 mode) - // but even then it still detects the video mode pretty well - if ((testCycle % 150) == 0) { - if (rto->currentLevelSOG == 1) { - rto->currentLevelSOG = 2; - } else { - rto->currentLevelSOG += 2; - } - if (rto->currentLevelSOG >= 15) { - rto->currentLevelSOG = 1; - } - setAndUpdateSogLevel(rto->currentLevelSOG); - } - - // new: check for 25khz, use regular scaling route for those - if (getVideoMode() == 8) { - rto->currentLevelSOG = rto->thisSourceMaxLevelSOG = 13; - setAndUpdateSogLevel(rto->currentLevelSOG); - rto->medResLineCount = GBS::MD_HD1250P_CNTRL::read(); - SerialM.println(F("med res")); - return 1; - } - - uint8_t currentMedResLineCount = GBS::MD_HD1250P_CNTRL::read(); - if (currentMedResLineCount < 0x3c) { - GBS::MD_HD1250P_CNTRL::write(currentMedResLineCount + 1); - } else { - GBS::MD_HD1250P_CNTRL::write(0x33); - } - //Serial.println(GBS::MD_HD1250P_CNTRL::read(), HEX); - } - - //rto->currentLevelSOG = rto->thisSourceMaxLevelSOG = 13; - //setAndUpdateSogLevel(rto->currentLevelSOG); - - return 1; //anyway, let later stage deal with it - } - - GBS::SP_SOG_MODE::write(1); - resetSyncProcessor(); - resetModeDetect(); // there was some signal but we lost it. MD is stuck anyway, so reset - delay(40); - } else if (currentInput == 0) { // YUV - uint16_t testCycle = 0; - rto->inputIsYpBpR = true; // declare for MD - GBS::MD_SEL_VGA60::write(0); // EDTV more likely than VGA 640x480 - - unsigned long timeOutStart = millis(); - while ((millis() - timeOutStart) < 6000) { - delay(2); - if (getVideoMode() > 0) { - return 2; - } - - testCycle++; - if ((testCycle % 180) == 0) { - if (rto->currentLevelSOG == 1) { - rto->currentLevelSOG = 2; - } else { - rto->currentLevelSOG += 2; - } - if (rto->currentLevelSOG >= 16) { - rto->currentLevelSOG = 1; - } - setAndUpdateSogLevel(rto->currentLevelSOG); - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG; - } - } - - rto->currentLevelSOG = rto->thisSourceMaxLevelSOG = 14; - setAndUpdateSogLevel(rto->currentLevelSOG); - - return 2; //anyway, let later stage deal with it - } - - SerialM.println(" lost.."); - rto->currentLevelSOG = 2; - setAndUpdateSogLevel(rto->currentLevelSOG); - } - - GBS::ADC_INPUT_SEL::write(!currentInput); // can only be 1 or 0 - delay(200); - - return 0; // don't do the check on the new input here, wait till next run - } - - return 0; -} - -uint8_t inputAndSyncDetect() -{ - uint8_t syncFound = detectAndSwitchToActiveInput(); - - if (syncFound == 0) { - if (!getSyncPresent()) { - if (rto->isInLowPowerMode == false) { - rto->sourceDisconnected = true; - rto->videoStandardInput = 0; - // reset to base settings, then go to low power - GBS::SP_SOG_MODE::write(1); - goLowPowerWithInputDetection(); - rto->isInLowPowerMode = true; - } - } - return 0; - } else if (syncFound == 1) { // input is RGBS - rto->inputIsYpBpR = 0; - rto->sourceDisconnected = false; - rto->isInLowPowerMode = false; - resetDebugPort(); - applyRGBPatches(); - LEDON; - return 1; - } else if (syncFound == 2) { - rto->inputIsYpBpR = 1; - rto->sourceDisconnected = false; - rto->isInLowPowerMode = false; - resetDebugPort(); - applyYuvPatches(); - LEDON; - return 2; - } else if (syncFound == 3) { // input is RGBHV - //already applied - rto->isInLowPowerMode = false; - rto->inputIsYpBpR = 0; - rto->sourceDisconnected = false; - rto->videoStandardInput = 15; - resetDebugPort(); - LEDON; - return 3; - } - - return 0; -} - -uint8_t getSingleByteFromPreset(const uint8_t *programArray, unsigned int offset) -{ - return pgm_read_byte(programArray + offset); -} - -static inline void readFromRegister(uint8_t reg, int bytesToRead, uint8_t *output) -{ - return GBS::read(lastSegment, reg, output, bytesToRead); -} - -void printReg(uint8_t seg, uint8_t reg) -{ - uint8_t readout; - readFromRegister(reg, 1, &readout); - // didn't think this HEX trick would work, but it does! (?) - SerialM.print("0x"); - SerialM.print(readout, HEX); - SerialM.print(", // s"); - SerialM.print(seg); - SerialM.print("_"); - SerialM.println(reg, HEX); - // old: - //SerialM.print(readout); SerialM.print(", // s"); SerialM.print(seg); SerialM.print("_"); SerialM.println(reg, HEX); -} - -// dumps the current chip configuration in a format that's ready to use as new preset :) -void dumpRegisters(byte segment) -{ - if (segment > 5) - return; - writeOneByte(0xF0, segment); - - switch (segment) { - case 0: - for (int x = 0x40; x <= 0x5F; x++) { - printReg(0, x); - } - for (int x = 0x90; x <= 0x9F; x++) { - printReg(0, x); - } - break; - case 1: - for (int x = 0x0; x <= 0x2F; x++) { - printReg(1, x); - } - break; - case 2: - for (int x = 0x0; x <= 0x3F; x++) { - printReg(2, x); - } - break; - case 3: - for (int x = 0x0; x <= 0x7F; x++) { - printReg(3, x); - } - break; - case 4: - for (int x = 0x0; x <= 0x5F; x++) { - printReg(4, x); - } - break; - case 5: - for (int x = 0x0; x <= 0x6F; x++) { - printReg(5, x); - } - break; - } -} - -void resetPLLAD() -{ - GBS::PLLAD_VCORST::write(1); - GBS::PLLAD_PDZ::write(1); // in case it was off - latchPLLAD(); - GBS::PLLAD_VCORST::write(0); - delay(1); - latchPLLAD(); - rto->clampPositionIsSet = 0; // test, but should be good - rto->continousStableCounter = 1; -} - -void latchPLLAD() -{ - GBS::PLLAD_LAT::write(0); - delayMicroseconds(128); - GBS::PLLAD_LAT::write(1); -} - -void resetPLL() -{ - GBS::PLL_VCORST::write(1); - delay(1); - GBS::PLL_VCORST::write(0); - delay(1); - rto->clampPositionIsSet = 0; // test, but should be good - rto->continousStableCounter = 1; -} - -void ResetSDRAM() -{ - //GBS::SDRAM_RESET_CONTROL::write(0x87); // enable "Software Control SDRAM Idle Period" and "SDRAM_START_INITIAL_CYCLE" - //GBS::SDRAM_RESET_SIGNAL::write(1); - //GBS::SDRAM_RESET_SIGNAL::write(0); - //GBS::SDRAM_START_INITIAL_CYCLE::write(0); - GBS::SDRAM_RESET_CONTROL::write(0x02); - GBS::SDRAM_RESET_SIGNAL::write(1); - GBS::SDRAM_RESET_SIGNAL::write(0); - GBS::SDRAM_RESET_CONTROL::write(0x82); -} - -// soft reset cycle -// This restarts all chip units, which is sometimes required when important config bits are changed. -void resetDigital() -{ - boolean keepBypassActive = 0; - if (GBS::SFTRST_HDBYPS_RSTZ::read() == 1) { // if HDBypass enabled - keepBypassActive = 1; - } - - //GBS::RESET_CONTROL_0x47::write(0x00); - GBS::RESET_CONTROL_0x47::write(0x17); // new, keep 0,1,2,4 on (DEC,MODE,SYNC,INT) //MODE okay? - - if (rto->outModeHdBypass) { // if currently in bypass - GBS::RESET_CONTROL_0x46::write(0x00); - GBS::RESET_CONTROL_0x47::write(0x1F); - return; // 0x46 stays all 0 - } - - GBS::RESET_CONTROL_0x46::write(0x41); // keep VDS (6) + IF (0) enabled, reset rest - if (keepBypassActive == 1) { // if HDBypass enabled - GBS::RESET_CONTROL_0x47::write(0x1F); - } - //else { - // GBS::RESET_CONTROL_0x47::write(0x17); - //} - GBS::RESET_CONTROL_0x46::write(0x7f); -} - -void resetSyncProcessor() -{ - GBS::SFTRST_SYNC_RSTZ::write(0); - delayMicroseconds(10); - GBS::SFTRST_SYNC_RSTZ::write(1); - //rto->clampPositionIsSet = false; // resetSyncProcessor is part of autosog - //rto->coastPositionIsSet = false; -} - -void resetModeDetect() -{ - GBS::SFTRST_MODE_RSTZ::write(0); - delay(1); // needed - GBS::SFTRST_MODE_RSTZ::write(1); - //rto->clampPositionIsSet = false; - //rto->coastPositionIsSet = false; -} - -void shiftHorizontal(uint16_t amountToShift, bool subtracting) -{ - uint16_t hrst = GBS::VDS_HSYNC_RST::read(); - uint16_t hbst = GBS::VDS_HB_ST::read(); - uint16_t hbsp = GBS::VDS_HB_SP::read(); - - // Perform the addition/subtraction - if (subtracting) { - if ((int16_t)hbst - amountToShift >= 0) { - hbst -= amountToShift; - } else { - hbst = hrst - (amountToShift - hbst); - } - if ((int16_t)hbsp - amountToShift >= 0) { - hbsp -= amountToShift; - } else { - hbsp = hrst - (amountToShift - hbsp); - } - } else { - if ((int16_t)hbst + amountToShift <= hrst) { - hbst += amountToShift; - // also extend hbst_d to maximum hrst-1 - if (hbst > GBS::VDS_DIS_HB_ST::read()) { - GBS::VDS_DIS_HB_ST::write(hbst); - } - } else { - hbst = 0 + (amountToShift - (hrst - hbst)); - } - if ((int16_t)hbsp + amountToShift <= hrst) { - hbsp += amountToShift; - } else { - hbsp = 0 + (amountToShift - (hrst - hbsp)); - } - } - - GBS::VDS_HB_ST::write(hbst); - GBS::VDS_HB_SP::write(hbsp); - //Serial.print("hbst: "); Serial.println(hbst); - //Serial.print("hbsp: "); Serial.println(hbsp); -} - -void shiftHorizontalLeft() -{ - shiftHorizontal(4, true); -} - -void shiftHorizontalRight() -{ - shiftHorizontal(4, false); -} - -// unused but may become useful -void shiftHorizontalLeftIF(uint8_t amount) -{ - uint16_t IF_HB_ST2 = GBS::IF_HB_ST2::read() + amount; - uint16_t IF_HB_SP2 = GBS::IF_HB_SP2::read() + amount; - uint16_t PLLAD_MD = GBS::PLLAD_MD::read(); - - if (rto->videoStandardInput <= 2) { - GBS::IF_HSYNC_RST::write(PLLAD_MD / 2); // input line length from pll div - } else if (rto->videoStandardInput <= 7) { - GBS::IF_HSYNC_RST::write(PLLAD_MD); - } - uint16_t IF_HSYNC_RST = GBS::IF_HSYNC_RST::read(); - - GBS::IF_LINE_SP::write(IF_HSYNC_RST + 1); - - // start - if (IF_HB_ST2 < IF_HSYNC_RST) { - GBS::IF_HB_ST2::write(IF_HB_ST2); - } else { - GBS::IF_HB_ST2::write(IF_HB_ST2 - IF_HSYNC_RST); - } - //SerialM.print("IF_HB_ST2: "); SerialM.println(GBS::IF_HB_ST2::read()); - - // stop - if (IF_HB_SP2 < IF_HSYNC_RST) { - GBS::IF_HB_SP2::write(IF_HB_SP2); - } else { - GBS::IF_HB_SP2::write((IF_HB_SP2 - IF_HSYNC_RST) + 1); - } - //SerialM.print("IF_HB_SP2: "); SerialM.println(GBS::IF_HB_SP2::read()); -} - -// unused but may become useful -void shiftHorizontalRightIF(uint8_t amount) -{ - int16_t IF_HB_ST2 = GBS::IF_HB_ST2::read() - amount; - int16_t IF_HB_SP2 = GBS::IF_HB_SP2::read() - amount; - uint16_t PLLAD_MD = GBS::PLLAD_MD::read(); - - if (rto->videoStandardInput <= 2) { - GBS::IF_HSYNC_RST::write(PLLAD_MD / 2); // input line length from pll div - } else if (rto->videoStandardInput <= 7) { - GBS::IF_HSYNC_RST::write(PLLAD_MD); - } - int16_t IF_HSYNC_RST = GBS::IF_HSYNC_RST::read(); - - GBS::IF_LINE_SP::write(IF_HSYNC_RST + 1); - - if (IF_HB_ST2 > 0) { - GBS::IF_HB_ST2::write(IF_HB_ST2); - } else { - GBS::IF_HB_ST2::write(IF_HSYNC_RST - 1); - } - //SerialM.print("IF_HB_ST2: "); SerialM.println(GBS::IF_HB_ST2::read()); - - if (IF_HB_SP2 > 0) { - GBS::IF_HB_SP2::write(IF_HB_SP2); - } else { - GBS::IF_HB_SP2::write(IF_HSYNC_RST - 1); - //GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() - 2); - } - //SerialM.print("IF_HB_SP2: "); SerialM.println(GBS::IF_HB_SP2::read()); -} - -void scaleHorizontal(uint16_t amountToScale, bool subtracting) -{ - uint16_t hscale = GBS::VDS_HSCALE::read(); - - // smooth out areas of interest - if (subtracting && (hscale == 513 || hscale == 512)) - amountToScale = 1; - if (!subtracting && (hscale == 511 || hscale == 512)) - amountToScale = 1; - - if (subtracting && (((int)hscale - amountToScale) <= 256)) { - hscale = 256; - GBS::VDS_HSCALE::write(hscale); - SerialM.println("limit"); - return; - } - - if (subtracting && (hscale - amountToScale > 255)) { - hscale -= amountToScale; - } else if (hscale + amountToScale < 1023) { - hscale += amountToScale; - } else if (hscale + amountToScale == 1023) { // exact max > bypass but apply VDS fetch changes - hscale = 1023; - GBS::VDS_HSCALE::write(hscale); - GBS::VDS_HSCALE_BYPS::write(1); - } else if (hscale + amountToScale > 1023) { // max + overshoot > bypass and no VDS fetch adjust - hscale = 1023; - GBS::VDS_HSCALE::write(hscale); - GBS::VDS_HSCALE_BYPS::write(1); - SerialM.println("limit"); - return; - } - - // will be scaling - GBS::VDS_HSCALE_BYPS::write(0); - - // move within VDS VB fetch area (within reason) - uint16_t htotal = GBS::VDS_HSYNC_RST::read(); - uint16_t toShift = 0; - if (hscale < 540) - toShift = 4; - else if (hscale < 640) - toShift = 3; - else - toShift = 2; - - if (subtracting) { - shiftHorizontal(toShift, true); - if ((GBS::VDS_HB_ST::read() + 5) < GBS::VDS_DIS_HB_ST::read()) { - GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 5); - } else if ((GBS::VDS_DIS_HB_ST::read() + 5) < htotal) { - GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() + 5); - GBS::VDS_HB_ST::write(GBS::VDS_DIS_HB_ST::read()); // dis_hbst = hbst - } - - // fix HB_ST > HB_SP conditions - if (GBS::VDS_HB_SP::read() < (GBS::VDS_HB_ST::read() + 16)) { // HB_SP < HB_ST - if ((GBS::VDS_HB_SP::read()) > (htotal / 2)) { // but HB_SP > some small value - GBS::VDS_HB_ST::write(GBS::VDS_HB_SP::read() - 16); - } - } - } - - // !subtracting check just for readability - if (!subtracting) { - shiftHorizontal(toShift, false); - if ((GBS::VDS_HB_ST::read() - 5) > 0) { - GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() - 5); - } - } - - // fix scaling < 512 glitch: factor even, htotal even: hbst / hbsp should be even, etc - if (hscale < 512) { - if (hscale % 2 == 0) { // hscale 512 / even - if (GBS::VDS_HB_ST::read() % 2 == 1) { - GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 1); - } - if (htotal % 2 == 1) { - if (GBS::VDS_HB_SP::read() % 2 == 0) { - GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); - } - } else { - if (GBS::VDS_HB_SP::read() % 2 == 1) { - GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); - } - } - } else { // hscale 499 / uneven - if (GBS::VDS_HB_ST::read() % 2 == 1) { - GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 1); - } - if (htotal % 2 == 0) { - if (GBS::VDS_HB_SP::read() % 2 == 1) { - GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); - } - } else { - if (GBS::VDS_HB_SP::read() % 2 == 0) { - GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); - } - } - } - // if scaling was < 512 and HB_ST moved, align with VDS_DIS_HB_ST - if (GBS::VDS_DIS_HB_ST::read() < GBS::VDS_HB_ST::read()) { - GBS::VDS_DIS_HB_ST::write(GBS::VDS_HB_ST::read()); - } - } - - //SerialM.print("HB_ST: "); SerialM.println(GBS::VDS_HB_ST::read()); - //SerialM.print("HB_SP: "); SerialM.println(GBS::VDS_HB_SP::read()); - SerialM.print("HScale: "); - SerialM.println(hscale); - GBS::VDS_HSCALE::write(hscale); -} - -// moves horizontal sync (VDS or HDB as needed) -void moveHS(uint16_t amountToAdd, bool subtracting) -{ - if (rto->outModeHdBypass) { - uint16_t SP_CS_HS_ST = GBS::SP_CS_HS_ST::read(); - uint16_t SP_CS_HS_SP = GBS::SP_CS_HS_SP::read(); - uint16_t htotal = GBS::HD_HSYNC_RST::read(); - - if (videoStandardInputIsPalNtscSd()) { - htotal -= 8; // account for the way hdbypass is setup in setOutModeHdBypass() - htotal *= 2; - } - - if (htotal == 0) - return; // safety - int16_t amount = subtracting ? (0 - amountToAdd) : amountToAdd; - - if (SP_CS_HS_ST + amount < 0) { - SP_CS_HS_ST = htotal + SP_CS_HS_ST; // yep, this works :p - } - if (SP_CS_HS_SP + amount < 0) { - SP_CS_HS_SP = htotal + SP_CS_HS_SP; - } - - GBS::SP_CS_HS_ST::write((SP_CS_HS_ST + amount) % htotal); - GBS::SP_CS_HS_SP::write((SP_CS_HS_SP + amount) % htotal); - - SerialM.print("HSST: "); - SerialM.print(GBS::SP_CS_HS_ST::read()); - SerialM.print(" HSSP: "); - SerialM.println(GBS::SP_CS_HS_SP::read()); - } else { - uint16_t VDS_HS_ST = GBS::VDS_HS_ST::read(); - uint16_t VDS_HS_SP = GBS::VDS_HS_SP::read(); - uint16_t htotal = GBS::VDS_HSYNC_RST::read(); - - if (htotal == 0) - return; // safety - int16_t amount = subtracting ? (0 - amountToAdd) : amountToAdd; - - if (VDS_HS_ST + amount < 0) { - VDS_HS_ST = htotal + VDS_HS_ST; // yep, this works :p - } - if (VDS_HS_SP + amount < 0) { - VDS_HS_SP = htotal + VDS_HS_SP; - } - - GBS::VDS_HS_ST::write((VDS_HS_ST + amount) % htotal); - GBS::VDS_HS_SP::write((VDS_HS_SP + amount) % htotal); - - //SerialM.print("HSST: "); SerialM.print(GBS::VDS_HS_ST::read()); - //SerialM.print(" HSSP: "); SerialM.println(GBS::VDS_HS_SP::read()); - } - printVideoTimings(); -} - -void moveVS(uint16_t amountToAdd, bool subtracting) -{ - uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); - if (vtotal == 0) - return; // safety - uint16_t VDS_DIS_VB_ST = GBS::VDS_DIS_VB_ST::read(); - uint16_t newVDS_VS_ST = GBS::VDS_VS_ST::read(); - uint16_t newVDS_VS_SP = GBS::VDS_VS_SP::read(); - - if (subtracting) { - if ((newVDS_VS_ST - amountToAdd) > VDS_DIS_VB_ST) { - newVDS_VS_ST -= amountToAdd; - newVDS_VS_SP -= amountToAdd; - } else - SerialM.println("limit"); - } else { - if ((newVDS_VS_SP + amountToAdd) < vtotal) { - newVDS_VS_ST += amountToAdd; - newVDS_VS_SP += amountToAdd; - } else - SerialM.println("limit"); - } - //SerialM.print("VSST: "); SerialM.print(newVDS_VS_ST); - //SerialM.print(" VSSP: "); SerialM.println(newVDS_VS_SP); - - GBS::VDS_VS_ST::write(newVDS_VS_ST); - GBS::VDS_VS_SP::write(newVDS_VS_SP); -} - -void invertHS() -{ - uint8_t high, low; - uint16_t newST, newSP; - - writeOneByte(0xf0, 3); - readFromRegister(0x0a, 1, &low); - readFromRegister(0x0b, 1, &high); - newST = ((((uint16_t)high) & 0x000f) << 8) | (uint16_t)low; - readFromRegister(0x0b, 1, &low); - readFromRegister(0x0c, 1, &high); - newSP = ((((uint16_t)high) & 0x00ff) << 4) | ((((uint16_t)low) & 0x00f0) >> 4); - - uint16_t temp = newST; - newST = newSP; - newSP = temp; - - writeOneByte(0x0a, (uint8_t)(newST & 0x00ff)); - writeOneByte(0x0b, ((uint8_t)(newSP & 0x000f) << 4) | ((uint8_t)((newST & 0x0f00) >> 8))); - writeOneByte(0x0c, (uint8_t)((newSP & 0x0ff0) >> 4)); -} - -void invertVS() -{ - uint8_t high, low; - uint16_t newST, newSP; - - writeOneByte(0xf0, 3); - readFromRegister(0x0d, 1, &low); - readFromRegister(0x0e, 1, &high); - newST = ((((uint16_t)high) & 0x000f) << 8) | (uint16_t)low; - readFromRegister(0x0e, 1, &low); - readFromRegister(0x0f, 1, &high); - newSP = ((((uint16_t)high) & 0x00ff) << 4) | ((((uint16_t)low) & 0x00f0) >> 4); - - uint16_t temp = newST; - newST = newSP; - newSP = temp; - - writeOneByte(0x0d, (uint8_t)(newST & 0x00ff)); - writeOneByte(0x0e, ((uint8_t)(newSP & 0x000f) << 4) | ((uint8_t)((newST & 0x0f00) >> 8))); - writeOneByte(0x0f, (uint8_t)((newSP & 0x0ff0) >> 4)); -} - -void scaleVertical(uint16_t amountToScale, bool subtracting) -{ - uint16_t vscale = GBS::VDS_VSCALE::read(); - - // least invasive "is vscaling enabled" check - if (vscale == 1023) { - GBS::VDS_VSCALE_BYPS::write(0); - } - - // smooth out areas of interest - if (subtracting && (vscale == 513 || vscale == 512)) - amountToScale = 1; - if (subtracting && (vscale == 684 || vscale == 683)) - amountToScale = 1; - if (!subtracting && (vscale == 511 || vscale == 512)) - amountToScale = 1; - if (!subtracting && (vscale == 682 || vscale == 683)) - amountToScale = 1; - - if (subtracting && (vscale - amountToScale > 128)) { - vscale -= amountToScale; - } else if (subtracting) { - vscale = 128; - } else if (vscale + amountToScale <= 1023) { - vscale += amountToScale; - } else if (vscale + amountToScale > 1023) { - vscale = 1023; - // don't enable vscale bypass here, since that disables ie line filter - } - - SerialM.print("VScale: "); - SerialM.println(vscale); - GBS::VDS_VSCALE::write(vscale); -} - -// modified to move VBSP, set VBST to VBSP-2 -void shiftVertical(uint16_t amountToAdd, bool subtracting) -{ - typedef GBS::Tie Regs; - uint16_t vrst = GBS::VDS_VSYNC_RST::read() - FrameSync::getSyncLastCorrection(); - uint16_t vbst = 0, vbsp = 0; - int16_t newVbst = 0, newVbsp = 0; - - Regs::read(vbst, vbsp); - newVbst = vbst; - newVbsp = vbsp; - - if (subtracting) { - //newVbst -= amountToAdd; - newVbsp -= amountToAdd; - } else { - //newVbst += amountToAdd; - newVbsp += amountToAdd; - } - - // handle the case where hbst or hbsp have been decremented below 0 - if (newVbst < 0) { - newVbst = vrst + newVbst; - } - if (newVbsp < 0) { - newVbsp = vrst + newVbsp; - } - - // handle the case where vbst or vbsp have been incremented above vrstValue - if (newVbst > (int16_t)vrst) { - newVbst = newVbst - vrst; - } - if (newVbsp > (int16_t)vrst) { - newVbsp = newVbsp - vrst; - } - - // mod: newVbsp needs to be at least newVbst+2 - if (newVbsp < (newVbst + 2)) { - newVbsp = newVbst + 2; - } - // mod: -= 2 - newVbst = newVbsp - 2; - - Regs::write(newVbst, newVbsp); - //SerialM.print("VSST: "); SerialM.print(newVbst); SerialM.print(" VSSP: "); SerialM.println(newVbsp); -} - -void shiftVerticalUp() -{ - shiftVertical(1, true); -} - -void shiftVerticalDown() -{ - shiftVertical(1, false); -} - -void shiftVerticalUpIF() -{ - // -4 to allow variance in source line count - uint8_t offset = rto->videoStandardInput == 2 ? 4 : 1; - uint16_t sourceLines = GBS::VPERIOD_IF::read() - offset; - // add an override for sourceLines, in case where the IF data is not available - if ((GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) && rto->videoStandardInput == 14) { - sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - } - int16_t stop = GBS::IF_VB_SP::read(); - int16_t start = GBS::IF_VB_ST::read(); - - if (stop < (sourceLines - 1) && start < (sourceLines - 1)) { - stop += 2; - start += 2; - } else { - start = 0; - stop = 2; - } - GBS::IF_VB_SP::write(stop); - GBS::IF_VB_ST::write(start); -} - -void shiftVerticalDownIF() -{ - uint8_t offset = rto->videoStandardInput == 2 ? 4 : 1; - uint16_t sourceLines = GBS::VPERIOD_IF::read() - offset; - // add an override for sourceLines, in case where the IF data is not available - if ((GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) && rto->videoStandardInput == 14) { - sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - } - - int16_t stop = GBS::IF_VB_SP::read(); - int16_t start = GBS::IF_VB_ST::read(); - - if (stop > 1 && start > 1) { - stop -= 2; - start -= 2; - } else { - start = sourceLines - 2; - stop = sourceLines; - } - GBS::IF_VB_SP::write(stop); - GBS::IF_VB_ST::write(start); -} - -void setHSyncStartPosition(uint16_t value) -{ - if (rto->outModeHdBypass) { - //GBS::HD_HS_ST::write(value); - GBS::SP_CS_HS_ST::write(value); - } else { - GBS::VDS_HS_ST::write(value); - } -} - -void setHSyncStopPosition(uint16_t value) -{ - if (rto->outModeHdBypass) { - //GBS::HD_HS_SP::write(value); - GBS::SP_CS_HS_SP::write(value); - } else { - GBS::VDS_HS_SP::write(value); - } -} - -void setMemoryHblankStartPosition(uint16_t value) -{ - GBS::VDS_HB_ST::write(value); - GBS::HD_HB_ST::write(value); -} - -void setMemoryHblankStopPosition(uint16_t value) -{ - GBS::VDS_HB_SP::write(value); - GBS::HD_HB_SP::write(value); -} - -void setDisplayHblankStartPosition(uint16_t value) -{ - GBS::VDS_DIS_HB_ST::write(value); -} - -void setDisplayHblankStopPosition(uint16_t value) -{ - GBS::VDS_DIS_HB_SP::write(value); -} - -void setVSyncStartPosition(uint16_t value) -{ - GBS::VDS_VS_ST::write(value); - GBS::HD_VS_ST::write(value); -} - -void setVSyncStopPosition(uint16_t value) -{ - GBS::VDS_VS_SP::write(value); - GBS::HD_VS_SP::write(value); -} - -void setMemoryVblankStartPosition(uint16_t value) -{ - GBS::VDS_VB_ST::write(value); - GBS::HD_VB_ST::write(value); -} - -void setMemoryVblankStopPosition(uint16_t value) -{ - GBS::VDS_VB_SP::write(value); - GBS::HD_VB_SP::write(value); -} - -void setDisplayVblankStartPosition(uint16_t value) -{ - GBS::VDS_DIS_VB_ST::write(value); -} - -void setDisplayVblankStopPosition(uint16_t value) -{ - GBS::VDS_DIS_VB_SP::write(value); -} - -uint16_t getCsVsStart() -{ - return (GBS::SP_SDCS_VSST_REG_H::read() << 8) + GBS::SP_SDCS_VSST_REG_L::read(); -} - -uint16_t getCsVsStop() -{ - return (GBS::SP_SDCS_VSSP_REG_H::read() << 8) + GBS::SP_SDCS_VSSP_REG_L::read(); -} - -void setCsVsStart(uint16_t start) -{ - GBS::SP_SDCS_VSST_REG_H::write(start >> 8); - GBS::SP_SDCS_VSST_REG_L::write(start & 0xff); -} - -void setCsVsStop(uint16_t stop) -{ - GBS::SP_SDCS_VSSP_REG_H::write(stop >> 8); - GBS::SP_SDCS_VSSP_REG_L::write(stop & 0xff); -} - -void printVideoTimings() -{ - if (rto->presetID < 0x20) { - SerialM.println(""); - SerialM.print(F("HT / scale : ")); - SerialM.print(GBS::VDS_HSYNC_RST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_HSCALE::read()); - SerialM.print(F("HS ST/SP : ")); - SerialM.print(GBS::VDS_HS_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_HS_SP::read()); - SerialM.print(F("HB ST/SP(d) : ")); - SerialM.print(GBS::VDS_DIS_HB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_DIS_HB_SP::read()); - SerialM.print(F("HB ST/SP : ")); - SerialM.print(GBS::VDS_HB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_HB_SP::read()); - SerialM.println(F("------")); - // vertical - SerialM.print(F("VT / scale : ")); - SerialM.print(GBS::VDS_VSYNC_RST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_VSCALE::read()); - SerialM.print(F("VS ST/SP : ")); - SerialM.print(GBS::VDS_VS_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_VS_SP::read()); - SerialM.print(F("VB ST/SP(d) : ")); - SerialM.print(GBS::VDS_DIS_VB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_DIS_VB_SP::read()); - SerialM.print(F("VB ST/SP : ")); - SerialM.print(GBS::VDS_VB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::VDS_VB_SP::read()); - // IF V offset - SerialM.print(F("IF VB ST/SP : ")); - SerialM.print(GBS::IF_VB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::IF_VB_SP::read()); - } else { - SerialM.println(""); - SerialM.print(F("HD_HSYNC_RST : ")); - SerialM.println(GBS::HD_HSYNC_RST::read()); - SerialM.print(F("HD_INI_ST : ")); - SerialM.println(GBS::HD_INI_ST::read()); - SerialM.print(F("HS ST/SP : ")); - SerialM.print(GBS::SP_CS_HS_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::SP_CS_HS_SP::read()); - SerialM.print(F("HB ST/SP : ")); - SerialM.print(GBS::HD_HB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::HD_HB_SP::read()); - SerialM.println(F("------")); - // vertical - SerialM.print(F("VS ST/SP : ")); - SerialM.print(GBS::HD_VS_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::HD_VS_SP::read()); - SerialM.print(F("VB ST/SP : ")); - SerialM.print(GBS::HD_VB_ST::read()); - SerialM.print(" "); - SerialM.println(GBS::HD_VB_SP::read()); - } - - SerialM.print(F("CsVT : ")); - SerialM.println(GBS::STATUS_SYNC_PROC_VTOTAL::read()); - SerialM.print(F("CsVS_ST/SP : ")); - SerialM.print(getCsVsStart()); - SerialM.print(F(" ")); - SerialM.println(getCsVsStop()); -} - -void set_htotal(uint16_t htotal) -{ - // ModeLine "1280x960" 108.00 1280 1376 1488 1800 960 961 964 1000 +HSync +VSync - // front porch: H2 - H1: 1376 - 1280 - // back porch : H4 - H3: 1800 - 1488 - // sync pulse : H3 - H2: 1488 - 1376 - - uint16_t h_blank_display_start_position = htotal - 1; - uint16_t h_blank_display_stop_position = htotal - ((htotal * 3) / 4); - uint16_t center_blank = ((h_blank_display_stop_position / 2) * 3) / 4; // a bit to the left - uint16_t h_sync_start_position = center_blank - (center_blank / 2); - uint16_t h_sync_stop_position = center_blank + (center_blank / 2); - uint16_t h_blank_memory_start_position = h_blank_display_start_position - 1; - uint16_t h_blank_memory_stop_position = h_blank_display_stop_position - (h_blank_display_stop_position / 50); - - GBS::VDS_HSYNC_RST::write(htotal); - GBS::VDS_HS_ST::write(h_sync_start_position); - GBS::VDS_HS_SP::write(h_sync_stop_position); - GBS::VDS_DIS_HB_ST::write(h_blank_display_start_position); - GBS::VDS_DIS_HB_SP::write(h_blank_display_stop_position); - GBS::VDS_HB_ST::write(h_blank_memory_start_position); - GBS::VDS_HB_SP::write(h_blank_memory_stop_position); -} - -void set_vtotal(uint16_t vtotal) -{ - uint16_t VDS_DIS_VB_ST = vtotal - 2; // just below vtotal - uint16_t VDS_DIS_VB_SP = (vtotal >> 6) + 8; // positive, above new sync stop position - uint16_t VDS_VB_ST = ((uint16_t)(vtotal * 0.016f)) & 0xfffe; // small fraction of vtotal - uint16_t VDS_VB_SP = VDS_VB_ST + 2; // always VB_ST + 2 - uint16_t v_sync_start_position = 1; - uint16_t v_sync_stop_position = 5; - // most low line count formats have negative sync! - // exception: 1024x768 (1344x806 total) has both sync neg. // also 1360x768 (1792x795 total) - if ((vtotal < 530) || (vtotal >= 803 && vtotal <= 809) || (vtotal >= 793 && vtotal <= 798)) { - uint16_t temp = v_sync_start_position; - v_sync_start_position = v_sync_stop_position; - v_sync_stop_position = temp; - } - - GBS::VDS_VSYNC_RST::write(vtotal); - GBS::VDS_VS_ST::write(v_sync_start_position); - GBS::VDS_VS_SP::write(v_sync_stop_position); - GBS::VDS_VB_ST::write(VDS_VB_ST); - GBS::VDS_VB_SP::write(VDS_VB_SP); - GBS::VDS_DIS_VB_ST::write(VDS_DIS_VB_ST); - GBS::VDS_DIS_VB_SP::write(VDS_DIS_VB_SP); - - // VDS_VSYN_SIZE1 + VDS_VSYN_SIZE2 to VDS_VSYNC_RST + 2 - GBS::VDS_VSYN_SIZE1::write(GBS::VDS_VSYNC_RST::read() + 2); - GBS::VDS_VSYN_SIZE2::write(GBS::VDS_VSYNC_RST::read() + 2); -} - -void resetDebugPort() -{ - GBS::PAD_BOUT_EN::write(1); // output to pad enabled - GBS::IF_TEST_EN::write(1); - GBS::IF_TEST_SEL::write(3); // IF vertical period signal - GBS::TEST_BUS_SEL::write(0xa); // test bus to SP - GBS::TEST_BUS_EN::write(1); - GBS::TEST_BUS_SP_SEL::write(0x0f); // SP test signal select (vsync in, after SOG separation) - GBS::MEM_FF_TOP_FF_SEL::write(1); // g0g13/14 shows FIFO stats (capture, rff, wff, etc) - // SP test bus enable bit is included in TEST_BUS_SP_SEL - GBS::VDS_TEST_EN::write(1); // VDS test enable -} - -void readEeprom() -{ - int addr = 0; - const uint8_t eepromAddr = 0x50; - Wire.beginTransmission(eepromAddr); - //if (addr >= 0x1000) { addr = 0; } - Wire.write(addr >> 8); // high addr byte, 4 bits + - Wire.write((uint8_t)addr); // low addr byte, 8 bits = 12 bits (0xfff max) - Wire.endTransmission(); - Wire.requestFrom(eepromAddr, (uint8_t)128); - uint8_t readData = 0; - uint8_t i = 0; - while (Wire.available()) { - Serial.print("addr 0x"); - Serial.print(i, HEX); - Serial.print(": 0x"); - readData = Wire.read(); - Serial.println(readData, HEX); - //addr++; - i++; - } -} - -void setIfHblankParameters() -{ - if (!rto->outModeHdBypass) { - uint16_t pll_divider = GBS::PLLAD_MD::read(); - - // if line doubling (PAL, NTSC), div 2 + a couple pixels - GBS::IF_HSYNC_RST::write(((pll_divider >> 1) + 13) & 0xfffe); // 1_0e - GBS::IF_LINE_SP::write(GBS::IF_HSYNC_RST::read() + 1); // 1_22 - if (rto->presetID == 0x05) { - // override for 1080p manually for now (pll_divider alone isn't correct :/) - GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() + 32); - GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() + 32); - } - if (rto->presetID == 0x15) { - GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() + 20); - GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() + 20); - } - - if (GBS::IF_LD_RAM_BYPS::read()) { - // no LD = EDTV or similar - GBS::IF_HB_SP2::write((uint16_t)((float)pll_divider * 0.06512f) & 0xfffe); // 1_1a // 0.06512f - // pll_divider / 2 - 3 is minimum IF_HB_ST2 - GBS::IF_HB_ST2::write((uint16_t)((float)pll_divider * 0.4912f) & 0xfffe); // 1_18 - } else { - // LD mode (PAL, NTSC) - GBS::IF_HB_SP2::write(4 + ((uint16_t)((float)pll_divider * 0.0224f) & 0xfffe)); // 1_1a - GBS::IF_HB_ST2::write((uint16_t)((float)pll_divider * 0.4550f) & 0xfffe); // 1_18 - - if (GBS::IF_HB_ST2::read() >= 0x420) { - // limit (fifo?) (0x420 = 1056) (might be 0x424 instead) - // limit doesn't apply to EDTV modes, where 1_18 typically = 0x4B0 - GBS::IF_HB_ST2::write(0x420); - } - - if (rto->presetID == 0x05 || rto->presetID == 0x15) { - // override 1_1a for 1080p manually for now (pll_divider alone isn't correct :/) - GBS::IF_HB_SP2::write(0x2A); - } - - // position move via 1_26 and reserve for deinterlacer: add IF RST pixels - // seems no extra pixels available at around PLLAD:84A or 2122px - //uint16_t currentRst = GBS::IF_HSYNC_RST::read(); - //GBS::IF_HSYNC_RST::write((currentRst + (currentRst / 15)) & 0xfffe); // 1_0e - //GBS::IF_LINE_SP::write(GBS::IF_HSYNC_RST::read() + 1); // 1_22 - } - } -} - -void fastGetBestHtotal() -{ - uint32_t inStart, inStop; - signed long inPeriod = 1; - double inHz = 1.0; - GBS::TEST_BUS_SEL::write(0xa); - if (FrameSync::vsyncInputSample(&inStart, &inStop)) { - inPeriod = (inStop - inStart) >> 1; - if (inPeriod > 1) { - inHz = (double)1000000 / (double)inPeriod; - } - SerialM.print("inPeriod: "); - SerialM.println(inPeriod); - SerialM.print("in hz: "); - SerialM.println(inHz); - } else { - SerialM.println("error"); - } - - uint16_t newVtotal = GBS::VDS_VSYNC_RST::read(); - double bestHtotal = 108000000 / ((double)newVtotal * inHz); // 107840000 - double bestHtotal50 = 108000000 / ((double)newVtotal * 50); - double bestHtotal60 = 108000000 / ((double)newVtotal * 60); - SerialM.print("newVtotal: "); - SerialM.println(newVtotal); - // display clock probably not exact 108mhz - SerialM.print("bestHtotal: "); - SerialM.println(bestHtotal); - SerialM.print("bestHtotal50: "); - SerialM.println(bestHtotal50); - SerialM.print("bestHtotal60: "); - SerialM.println(bestHtotal60); - if (bestHtotal > 800 && bestHtotal < 3200) { - //applyBestHTotal((uint16_t)bestHtotal); - //FrameSync::resetWithoutRecalculation(); // was single use of this function, function has changed since - } -} - -boolean runAutoBestHTotal() -{ - if (!FrameSync::ready() && rto->autoBestHtotalEnabled == true && rto->videoStandardInput > 0 && rto->videoStandardInput < 15) { - - //Serial.println("running"); - //unsigned long startTime = millis(); - - boolean stableNow = 1; - - for (uint8_t i = 0; i < 64; i++) { - if (!getStatus16SpHsStable()) { - stableNow = 0; - //Serial.println("prevented: !getStatus16SpHsStable"); - break; - } - } - - if (stableNow) { - if (GBS::STATUS_INT_SOG_BAD::read()) { - //Serial.println("prevented_2!"); - resetInterruptSogBadBit(); - delay(40); - stableNow = false; - } - resetInterruptSogBadBit(); - - if (stableNow && (getVideoMode() == rto->videoStandardInput)) { - uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); - uint8_t vdsBusSelBackup = GBS::VDS_TEST_BUS_SEL::read(); - uint8_t ifBusSelBackup = GBS::IF_TEST_SEL::read(); - - if (testBusSelBackup != 0) - GBS::TEST_BUS_SEL::write(0); // needs decimation + if - if (vdsBusSelBackup != 0) - GBS::VDS_TEST_BUS_SEL::write(0); // VDS test # 0 = VBlank - if (ifBusSelBackup != 3) - GBS::IF_TEST_SEL::write(3); // IF averaged frame time - - yield(); - uint16_t bestHTotal = FrameSync::init(); // critical task - yield(); - - GBS::TEST_BUS_SEL::write(testBusSelBackup); // always restore from backup (TB has changed) - if (vdsBusSelBackup != 0) - GBS::VDS_TEST_BUS_SEL::write(vdsBusSelBackup); - if (ifBusSelBackup != 3) - GBS::IF_TEST_SEL::write(ifBusSelBackup); - - if (GBS::STATUS_INT_SOG_BAD::read()) { - //Serial.println("prevented_5 INT_SOG_BAD!"); - stableNow = false; - } - for (uint8_t i = 0; i < 16; i++) { - if (!getStatus16SpHsStable()) { - stableNow = 0; - //Serial.println("prevented_5: !getStatus16SpHsStable"); - break; - } - } - resetInterruptSogBadBit(); - - if (bestHTotal > 4095) { - if (!rto->forceRetime) { - stableNow = false; - } else { - // roll with it - bestHTotal = 4095; - } - } - - if (stableNow) { - for (uint8_t i = 0; i < 24; i++) { - delay(1); - if (!getStatus16SpHsStable()) { - stableNow = false; - //Serial.println("prevented_3!"); - break; - } - } - } - - if (bestHTotal > 0 && stableNow) { - boolean success = applyBestHTotal(bestHTotal); - if (success) { - rto->syncLockFailIgnore = 16; - //Serial.print("ok, took: "); - //Serial.println(millis() - startTime); - return true; // success - } - } - } - } - - // reaching here can happen even if stableNow == 1 - if (!stableNow) { - FrameSync::reset(uopt->frameTimeLockMethod); - - if (rto->syncLockFailIgnore > 0) { - rto->syncLockFailIgnore--; - if (rto->syncLockFailIgnore == 0) { - GBS::DAC_RGBS_PWDNZ::write(1); // xth chance - if (!uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // xth chance - } - rto->autoBestHtotalEnabled = false; - } - } - Serial.print(F("bestHtotal retry (")); - Serial.print(rto->syncLockFailIgnore); - Serial.println(")"); - } - } else if (FrameSync::ready()) { - // FS ready but mode is 0 or 15 or autoBestHtotal is off - return true; - } - - if (rto->continousStableCounter != 0 && rto->continousStableCounter != 255) { - rto->continousStableCounter++; // stop repetitions - } - - return false; -} - -boolean applyBestHTotal(uint16_t bestHTotal) -{ - if (rto->outModeHdBypass) { - return true; // false? doesn't matter atm - } - - uint16_t orig_htotal = GBS::VDS_HSYNC_RST::read(); - int diffHTotal = bestHTotal - orig_htotal; - uint16_t diffHTotalUnsigned = abs(diffHTotal); - - if (((diffHTotalUnsigned == 0) || (rto->extClockGenDetected && diffHTotalUnsigned == 1)) && // all this - !rto->forceRetime) // and that - { - if (!uopt->enableFrameTimeLock) { // FTL can double throw this when it resets to adjust - SerialM.print(F("HTotal Adjust (skipped)")); - - if (!rto->extClockGenDetected) { - float sfr = getSourceFieldRate(0); - yield(); // wifi - float ofr = getOutputFrameRate(); - if (sfr < 1.0f) { - sfr = getSourceFieldRate(0); // retry - } - if (ofr < 1.0f) { - ofr = getOutputFrameRate(); // retry - } - SerialM.print(F(", source Hz: ")); - SerialM.print(sfr, 3); // prec. 3 - SerialM.print(F(", output Hz: ")); - SerialM.println(ofr, 3); // prec. 3 - } else { - SerialM.println(); - } - } - return true; // nothing to do - } - - if (GBS::GBS_OPTION_PALFORCED60_ENABLED::read() == 1) { - // source is 50Hz, preset has to stay at 60Hz: return - return true; - } - - boolean isLargeDiff = (diffHTotalUnsigned > (orig_htotal * 0.06f)) ? true : false; // typical diff: 1802 to 1794 (=8) - - if (isLargeDiff && (getVideoMode() == 8 || rto->videoStandardInput == 14)) { - // arcade stuff syncs down from 60 to 52 Hz.. - isLargeDiff = (diffHTotalUnsigned > (orig_htotal * 0.16f)) ? true : false; - } - - if (isLargeDiff) { - SerialM.println(F("ABHT: large diff")); - } - - // rto->forceRetime = true means the correction should be forced (command '.') - if (isLargeDiff && (rto->forceRetime == false)) { - if (rto->videoStandardInput != 14) { - rto->failRetryAttempts++; - if (rto->failRetryAttempts < 8) { - SerialM.println(F("retry")); - FrameSync::reset(uopt->frameTimeLockMethod); - delay(60); - } else { - SerialM.println(F("give up")); - rto->autoBestHtotalEnabled = false; - } - } - return false; // large diff, no forced - } - - // bestHTotal 0? could be an invald manual retime - if (bestHTotal == 0) { - Serial.println(F("bestHTotal 0")); - return false; - } - - if (rto->forceRetime == false) { - if (GBS::STATUS_INT_SOG_BAD::read() == 1) { - //Serial.println("prevented in apply"); - return false; - } - } - - rto->failRetryAttempts = 0; // else all okay!, reset to 0 - - // move blanking (display) - uint16_t h_blank_display_start_position = GBS::VDS_DIS_HB_ST::read(); - uint16_t h_blank_display_stop_position = GBS::VDS_DIS_HB_SP::read(); - uint16_t h_blank_memory_start_position = GBS::VDS_HB_ST::read(); - uint16_t h_blank_memory_stop_position = GBS::VDS_HB_SP::read(); - - // new 25.10.2019 - //uint16_t blankingAreaTotal = bestHTotal * 0.233f; - //h_blank_display_start_position += (diffHTotal / 2); - //h_blank_display_stop_position += (diffHTotal / 2); - //h_blank_memory_start_position = bestHTotal - (blankingAreaTotal * 0.212f); - //h_blank_memory_stop_position = blankingAreaTotal * 0.788f; - - // h_blank_memory_start_position usually is == h_blank_display_start_position - if (h_blank_memory_start_position == h_blank_display_start_position) { - h_blank_display_start_position += (diffHTotal / 2); - h_blank_display_stop_position += (diffHTotal / 2); - h_blank_memory_start_position = h_blank_display_start_position; // normal case - h_blank_memory_stop_position += (diffHTotal / 2); - } else { - h_blank_display_start_position += (diffHTotal / 2); - h_blank_display_stop_position += (diffHTotal / 2); - h_blank_memory_start_position += (diffHTotal / 2); // the exception (currently 1280x1024) - h_blank_memory_stop_position += (diffHTotal / 2); - } - - if (diffHTotal < 0) { - h_blank_display_start_position &= 0xfffe; - h_blank_display_stop_position &= 0xfffe; - h_blank_memory_start_position &= 0xfffe; - h_blank_memory_stop_position &= 0xfffe; - } else if (diffHTotal > 0) { - h_blank_display_start_position += 1; - h_blank_display_start_position &= 0xfffe; - h_blank_display_stop_position += 1; - h_blank_display_stop_position &= 0xfffe; - h_blank_memory_start_position += 1; - h_blank_memory_start_position &= 0xfffe; - h_blank_memory_stop_position += 1; - h_blank_memory_stop_position &= 0xfffe; - } - - // don't move HSync with small diffs - uint16_t h_sync_start_position = GBS::VDS_HS_ST::read(); - uint16_t h_sync_stop_position = GBS::VDS_HS_SP::read(); - - // fix over / underflows - if (h_blank_display_start_position > (bestHTotal - 8) || isLargeDiff) { - // typically happens when scaling Hz up (60 to 70) - //Serial.println("overflow h_blank_display_start_position"); - h_blank_display_start_position = bestHTotal * 0.936f; - } - if (h_blank_display_stop_position > bestHTotal || isLargeDiff) { - //Serial.println("overflow h_blank_display_stop_position"); - h_blank_display_stop_position = bestHTotal * 0.178f; - } - if ((h_blank_memory_start_position > bestHTotal) || (h_blank_memory_start_position > h_blank_display_start_position) || isLargeDiff) { - //Serial.println("overflow h_blank_memory_start_position"); - h_blank_memory_start_position = h_blank_display_start_position * 0.971f; - } - if (h_blank_memory_stop_position > bestHTotal || isLargeDiff) { - //Serial.println("overflow h_blank_memory_stop_position"); - h_blank_memory_stop_position = h_blank_display_stop_position * 0.64f; - } - - // check whether HS spills over HBSPD - if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync - if (h_sync_start_position >= h_blank_display_stop_position) { - h_sync_start_position = h_blank_display_stop_position * 0.8f; - h_sync_stop_position = 4; // good idea to move this close to 0 as well - } - } else { - if (h_sync_stop_position >= h_blank_display_stop_position) { - h_sync_stop_position = h_blank_display_stop_position * 0.8f; - h_sync_start_position = 4; // - } - } - - // just fix HS - if (isLargeDiff) { - if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync - h_sync_stop_position = 4; - // stop = at least start, then a bit outwards - h_sync_start_position = 16 + (h_blank_display_stop_position * 0.3f); - } else { - h_sync_start_position = 4; - h_sync_stop_position = 16 + (h_blank_display_stop_position * 0.3f); - } - } - - // finally, fix forced timings with large diff - // update: doesn't seem necessary anymore - //if (isLargeDiff) { - // h_blank_display_start_position = bestHTotal * 0.946f; - // h_blank_display_stop_position = bestHTotal * 0.22f; - // h_blank_memory_start_position = h_blank_display_start_position * 0.971f; - // h_blank_memory_stop_position = h_blank_display_stop_position * 0.64f; - - // if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync - // h_sync_stop_position = 0; - // // stop = at least start, then a bit outwards - // h_sync_start_position = 16 + (h_blank_display_stop_position * 0.4f); - // } - // else { - // h_sync_start_position = 0; - // h_sync_stop_position = 16 + (h_blank_display_stop_position * 0.4f); - // } - //} - - if (diffHTotal != 0) { // apply - // delay the change to field start, a bit more compatible - uint16_t timeout = 0; - while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)) - ; - while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 800)) - ; - - GBS::VDS_HSYNC_RST::write(bestHTotal); - GBS::VDS_DIS_HB_ST::write(h_blank_display_start_position); - GBS::VDS_DIS_HB_SP::write(h_blank_display_stop_position); - GBS::VDS_HB_ST::write(h_blank_memory_start_position); - GBS::VDS_HB_SP::write(h_blank_memory_stop_position); - GBS::VDS_HS_ST::write(h_sync_start_position); - GBS::VDS_HS_SP::write(h_sync_stop_position); - } - - boolean print = 1; - if (uopt->enableFrameTimeLock) { - if ((GBS::GBS_RUNTIME_FTL_ADJUSTED::read() == 1) && !rto->forceRetime) { - // FTL enabled and regular update, so don't print - print = 0; - } - GBS::GBS_RUNTIME_FTL_ADJUSTED::write(0); - } - - rto->forceRetime = false; - - if (print) { - SerialM.print(F("HTotal Adjust: ")); - if (diffHTotal >= 0) { - SerialM.print(" "); // formatting to align with negative value readouts - } - SerialM.print(diffHTotal); - - if (!rto->extClockGenDetected) { - float sfr = getSourceFieldRate(0); - delay(0); - float ofr = getOutputFrameRate(); - if (sfr < 1.0f) { - sfr = getSourceFieldRate(0); // retry - } - if (ofr < 1.0f) { - ofr = getOutputFrameRate(); // retry - } - SerialM.print(F(", source Hz: ")); - SerialM.print(sfr, 3); // prec. 3 - SerialM.print(F(", output Hz: ")); - SerialM.println(ofr, 3); // prec. 3 - } else { - SerialM.println(); - } - } - - return true; -} - -float getSourceFieldRate(boolean useSPBus) -{ - double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; - uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); - uint8_t spBusSelBackup = GBS::TEST_BUS_SP_SEL::read(); - uint8_t ifBusSelBackup = GBS::IF_TEST_SEL::read(); - uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); - - if (debugPinBackup != 1) - GBS::PAD_BOUT_EN::write(1); // enable output to pin for test - - if (ifBusSelBackup != 3) - GBS::IF_TEST_SEL::write(3); // IF averaged frame time - - if (useSPBus) { - if (rto->syncTypeCsync) { - //Serial.println("TestBus for csync"); - if (testBusSelBackup != 0xa) - GBS::TEST_BUS_SEL::write(0xa); - } else { - //Serial.println("TestBus for HV Sync"); - if (testBusSelBackup != 0x0) - GBS::TEST_BUS_SEL::write(0x0); // RGBHV: TB 0x20 has vsync - } - if (spBusSelBackup != 0x0f) - GBS::TEST_BUS_SP_SEL::write(0x0f); - } else { - if (testBusSelBackup != 0) - GBS::TEST_BUS_SEL::write(0); // needs decimation + if - } - - float retVal = 0; - - uint32_t fieldTimeTicks = FrameSync::getPulseTicks(); - if (fieldTimeTicks == 0) { - // try again - fieldTimeTicks = FrameSync::getPulseTicks(); - } - - if (fieldTimeTicks > 0) { - retVal = esp8266_clock_freq / (double)fieldTimeTicks; - if (retVal < 47.0f || retVal > 86.0f) { - // try again - fieldTimeTicks = FrameSync::getPulseTicks(); - if (fieldTimeTicks > 0) { - retVal = esp8266_clock_freq / (double)fieldTimeTicks; - } - } - } - - GBS::TEST_BUS_SEL::write(testBusSelBackup); - GBS::PAD_BOUT_EN::write(debugPinBackup); - if (spBusSelBackup != 0x0f) - GBS::TEST_BUS_SP_SEL::write(spBusSelBackup); - if (ifBusSelBackup != 3) - GBS::IF_TEST_SEL::write(ifBusSelBackup); - - return retVal; -} - -float getOutputFrameRate() -{ - double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; - uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); - uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); - - if (debugPinBackup != 1) - GBS::PAD_BOUT_EN::write(1); // enable output to pin for test - - if (testBusSelBackup != 2) - GBS::TEST_BUS_SEL::write(2); // 0x4d = 0x22 VDS test - - float retVal = 0; - - uint32_t fieldTimeTicks = FrameSync::getPulseTicks(); - if (fieldTimeTicks == 0) { - // try again - fieldTimeTicks = FrameSync::getPulseTicks(); - } - - if (fieldTimeTicks > 0) { - retVal = esp8266_clock_freq / (double)fieldTimeTicks; - if (retVal < 47.0f || retVal > 86.0f) { - // try again - fieldTimeTicks = FrameSync::getPulseTicks(); - if (fieldTimeTicks > 0) { - retVal = esp8266_clock_freq / (double)fieldTimeTicks; - } - } - } - - GBS::TEST_BUS_SEL::write(testBusSelBackup); - GBS::PAD_BOUT_EN::write(debugPinBackup); - - return retVal; -} - -// used for RGBHV to determine the ADPLL speed "level" / can jitter with SOG Sync -uint32_t getPllRate() -{ - uint32_t esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; - uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); - uint8_t spBusSelBackup = GBS::TEST_BUS_SP_SEL::read(); - uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); - - if (testBusSelBackup != 0xa) { - GBS::TEST_BUS_SEL::write(0xa); - } - if (rto->syncTypeCsync) { - if (spBusSelBackup != 0x6b) - GBS::TEST_BUS_SP_SEL::write(0x6b); - } else { - if (spBusSelBackup != 0x09) - GBS::TEST_BUS_SP_SEL::write(0x09); - } - GBS::PAD_BOUT_EN::write(1); // enable output to pin for test - yield(); // BOUT signal and wifi - delayMicroseconds(200); - uint32_t ticks = FrameSync::getPulseTicks(); - - // restore - GBS::PAD_BOUT_EN::write(debugPinBackup); - if (testBusSelBackup != 0xa) { - GBS::TEST_BUS_SEL::write(testBusSelBackup); - } - GBS::TEST_BUS_SP_SEL::write(spBusSelBackup); - - uint32_t retVal = 0; - if (ticks > 0) { - retVal = esp8266_clock_freq / ticks; - } - - return retVal; -} - -#define AUTO_GAIN_INIT 0x48 - -void doPostPresetLoadSteps() -{ - //unsigned long postLoadTimer = millis(); - - // adco->r_gain gets applied if uopt->enableAutoGain is set. - if (uopt->enableAutoGain) { - if (uopt->presetPreference == OutputCustomized) { - // Loaded custom preset, we want to keep newly loaded gain. Save - // gain written by loadPresetFromSPIFFS -> writeProgramArrayNew. - adco->r_gain = GBS::ADC_RGCTRL::read(); - adco->g_gain = GBS::ADC_GGCTRL::read(); - adco->b_gain = GBS::ADC_BGCTRL::read(); - } else { - // Loaded fixed preset. Keep adco->r_gain from before overwriting - // registers. - } - } - - //GBS::PAD_SYNC_OUT_ENZ::write(1); // no sync out - //GBS::DAC_RGBS_PWDNZ::write(0); // no DAC - //GBS::SFTRST_MEM_FF_RSTZ::write(0); // mem fifos keep in reset - - if (rto->videoStandardInput == 0) { - uint8_t videoMode = getVideoMode(); - SerialM.print(F("post preset: rto->videoStandardInput 0 > ")); - SerialM.println(videoMode); - if (videoMode > 0) { - rto->videoStandardInput = videoMode; - } - } - rto->presetID = GBS::GBS_PRESET_ID::read(); - rto->isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); - - GBS::ADC_UNUSED_64::write(0); - GBS::ADC_UNUSED_65::write(0); // clear temp storage - GBS::ADC_UNUSED_66::write(0); - GBS::ADC_UNUSED_67::write(0); // clear temp storage - GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) - - if (!rto->isCustomPreset) { - prepareSyncProcessor(); // todo: handle modes 14 and 15 better, now that they support scaling - } - if (rto->videoStandardInput == 14) { - // copy of code in bypassModeSwitch_RGBHV - if (rto->syncTypeCsync == false) { - GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: from hs // use ADC and turn it off = no SOG - GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG // having it 0 drags down the SOG (hsync) input; = 1: need to supress SOG decoding - GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) - GBS::SP_SOG_MODE::write(0); // 5_56 bit 0 // 0: normal, 1: SOG - GBS::SP_NO_COAST_REG::write(1); // vblank coasting off - GBS::SP_PRE_COAST::write(0); - GBS::SP_POST_COAST::write(0); - GBS::SP_H_PULSE_IGNOR::write(0xff); // cancel out SOG decoding - GBS::SP_SYNC_BYPS::write(0); // external H+V sync for decimator (+ sync out) | 1 to mirror in sync, 0 to output processed sync - GBS::SP_HS_POL_ATO::write(1); // 5_55 4 auto polarity for retiming - GBS::SP_VS_POL_ATO::write(1); // 5_55 6 - GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS - GBS::SP_H_PROTECT::write(0); // 5_3e 4 disable for H/V - rto->phaseADC = 16; - rto->phaseSP = 8; - } else { - // todo: SOG SRC can be ADC or HS input pin. HS requires TTL level, ADC can use lower levels - // HS seems to have issues at low PLL speeds - // maybe add detection whether ADC Sync is needed - GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: hs is sog source - GBS::SP_EXT_SYNC_SEL::write(1); // disconnect HV input - GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG - GBS::SP_SOG_MODE::write(1); // apparently needs to be off for HS input (on for ADC) - GBS::SP_NO_COAST_REG::write(0); // vblank coasting on - GBS::SP_PRE_COAST::write(4); // 5_38, > 4 can be seen with clamp invert on the lower lines - GBS::SP_POST_COAST::write(7); - GBS::SP_SYNC_BYPS::write(0); // use regular sync for decimator (and sync out) path - GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS - GBS::SP_H_PROTECT::write(1); // 5_3e 4 enable for SOG - rto->currentLevelSOG = 24; - rto->phaseADC = 16; - rto->phaseSP = 8; - } - } - - GBS::SP_H_PROTECT::write(0); - GBS::SP_COAST_INV_REG::write(0); // just in case - if (!rto->outModeHdBypass && GBS::GBS_OPTION_SCALING_RGBHV::read() == 0) { - // setOutModeHdBypass has it's own and needs to update later - updateSpDynamic(0); // remember: rto->videoStandardInput for RGB(C/HV) in scaling is 1, 2 or 3 here - } - - GBS::SP_NO_CLAMP_REG::write(1); // (keep) clamp disabled, to be enabled when position determined - GBS::OUT_SYNC_CNTRL::write(1); // prepare sync out to PAD - - // auto offset adc prep - GBS::ADC_AUTO_OFST_PRD::write(1); // by line (0 = by frame) - GBS::ADC_AUTO_OFST_DELAY::write(0); // sample delay 0 (1 to 4 pipes) - GBS::ADC_AUTO_OFST_STEP::write(0); // 0 = abs diff, then 1 to 3 steps - GBS::ADC_AUTO_OFST_TEST::write(1); - GBS::ADC_AUTO_OFST_RANGE_REG::write(0x00); // 5_0f U/V ranges = 0 (full range, 1 to 15) - - if (rto->inputIsYpBpR == true) { - applyYuvPatches(); - } else { - applyRGBPatches(); - } - - if (rto->outModeHdBypass) { - GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP - rto->autoBestHtotalEnabled = false; - } else { - rto->autoBestHtotalEnabled = true; - } - - rto->phaseADC = GBS::PA_ADC_S::read(); // we can't know which is right, get from preset - rto->phaseSP = 8; // get phase into global variables early: before latching - - if (rto->inputIsYpBpR) { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 14; - } else { - rto->thisSourceMaxLevelSOG = rto->currentLevelSOG = 13; // similar to yuv, allow variations - } - - setAndUpdateSogLevel(rto->currentLevelSOG); - - if (!rto->isCustomPreset) { - // Writes ADC_RGCTRL. If auto gain is enabled, ADC_RGCTRL will be - // overwritten further down at `uopt->enableAutoGain == 1`. - setAdcParametersGainAndOffset(); - } - - GBS::GPIO_CONTROL_00::write(0x67); // most GPIO pins regular GPIO - GBS::GPIO_CONTROL_01::write(0x00); // all GPIO outputs disabled - rto->clampPositionIsSet = 0; - rto->coastPositionIsSet = 0; - rto->phaseIsSet = 0; - rto->continousStableCounter = 0; - rto->noSyncCounter = 0; - rto->motionAdaptiveDeinterlaceActive = false; - rto->scanlinesEnabled = false; - rto->failRetryAttempts = 0; - rto->videoIsFrozen = true; // ensures unfreeze - rto->sourceDisconnected = false; // this must be true if we reached here (no syncwatcher operation) - rto->boardHasPower = true; //same - - if (rto->presetID == 0x06 || rto->presetID == 0x16) { - rto->isCustomPreset = 0; // override so it applies section 2 deinterlacer settings - } - - if (!rto->isCustomPreset) { - if (rto->videoStandardInput == 3 || rto->videoStandardInput == 4 || - rto->videoStandardInput == 8 || rto->videoStandardInput == 9) { - GBS::IF_LD_RAM_BYPS::write(1); // 1_0c 0 no LD, do this before setIfHblankParameters - } - - //setIfHblankParameters(); // 1_0e, 1_18, 1_1a - GBS::IF_INI_ST::write(0); // 16.08.19: don't calculate, use fixed to 0 - // the following sets a field offset that eliminates 240p content forced to 480i flicker - //GBS::IF_INI_ST::write(GBS::PLLAD_MD::read() * 0.4261f); // upper: * 0.4282f lower: 0.424f - - GBS::IF_HS_INT_LPF_BYPS::write(0); // 1_02 2 - // 0 allows int/lpf for smoother scrolling with non-ideal scaling, also reduces jailbars and even noise - // interpolation or lpf available, lpf looks better - GBS::IF_HS_SEL_LPF::write(1); // 1_02 1 - GBS::IF_HS_PSHIFT_BYPS::write(1); // 1_02 3 nonlinear scale phase shift bypass - // 1_28 1 1:hbin generated write reset 0:line generated write reset - GBS::IF_LD_WRST_SEL::write(1); // at 1 fixes output position regardless of 1_24 - //GBS::MADPT_Y_DELAY_UV_DELAY::write(0); // 2_17 default: 0 // don't overwrite - - GBS::SP_RT_HS_ST::write(0); // 5_49 // retiming hs ST, SP - GBS::SP_RT_HS_SP::write(GBS::PLLAD_MD::read() * 0.93f); - - GBS::VDS_PK_LB_CORE::write(0); // 3_44 0-3 // 1 for anti source jailbars - GBS::VDS_PK_LH_CORE::write(0); // 3_46 0-3 // 1 for anti source jailbars - if (rto->presetID == 0x05 || rto->presetID == 0x15) { - GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 // peaking HF - GBS::VDS_PK_LH_GAIN::write(0x0A); // 3_47 - } else { - GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 - GBS::VDS_PK_LH_GAIN::write(0x18); // 3_47 - } - GBS::VDS_PK_VL_HL_SEL::write(0); // 3_43 0 if 1 then 3_45 HF almost no effect (coring 0xf9) - GBS::VDS_PK_VL_HH_SEL::write(0); // 3_43 1 - - GBS::VDS_STEP_GAIN::write(1); // step response, max 15 (VDS_STEP_DLY_CNTRL set in presets) - - // DAC filters / keep in presets for now - //GBS::VDS_1ST_INT_BYPS::write(1); // disable RGB stage interpolator - //GBS::VDS_2ND_INT_BYPS::write(1); // disable YUV stage interpolator - - // most cases will use osr 2 - setOverSampleRatio(2, true); // prepare only = true - - // full height option - if (uopt->wantFullHeight) { - if (rto->videoStandardInput == 1 || rto->videoStandardInput == 3) { - //if (rto->presetID == 0x5) - //{ // out 1080p 60 - // GBS::VDS_DIS_VB_ST::write(GBS::VDS_VSYNC_RST::read() - 1); - // GBS::VDS_DIS_VB_SP::write(42); - // GBS::VDS_VB_SP::write(42 - 10); // is VDS_DIS_VB_SP - 10 = 32 // watch for vblank overflow (ps3) - // GBS::VDS_VSCALE::write(455); - // GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 4); - // GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 4); - // SerialM.println(F("full height")); - //} - } else if (rto->videoStandardInput == 2 || rto->videoStandardInput == 4) { - if (rto->presetID == 0x15) { // out 1080p 50 - GBS::VDS_VSCALE::write(455); - GBS::VDS_DIS_VB_ST::write(GBS::VDS_VSYNC_RST::read()); // full = 1125 of 1125 - GBS::VDS_DIS_VB_SP::write(42); - GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 22); - GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 22); - SerialM.println(F("full height")); - } - } - } - - if (rto->videoStandardInput == 1 || rto->videoStandardInput == 2) { - //GBS::PLLAD_ICP::write(5); // 5 rather than 6 to work well with CVBS sync as well as CSync - - GBS::ADC_FLTR::write(3); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - GBS::PLLAD_KS::write(2); // 5_16 - setOverSampleRatio(4, true); // prepare only = true - GBS::IF_SEL_WEN::write(0); // 1_02 0; 0 for SD, 1 for EDTV - if (rto->inputIsYpBpR) { // todo: check other videoStandardInput in component vs rgb - GBS::IF_HS_TAP11_BYPS::write(0); // 1_02 4 Tap11 LPF bypass in YUV444to422 - GBS::IF_HS_Y_PDELAY::write(2); // 1_02 5+6 delays - GBS::VDS_V_DELAY::write(0); // 3_24 2 - GBS::VDS_Y_DELAY::write(3); // 3_24 4/5 delays - } - - // downscale preset: source is SD - if (rto->presetID == 0x06 || rto->presetID == 0x16) { - setCsVsStart(2); // or 3, 0 - setCsVsStop(0); // fixes field position - GBS::IF_VS_SEL::write(1); // 1_00 5 // turn off VHS sync feature - GBS::IF_VS_FLIP::write(0); // 1_01 0 - GBS::IF_LD_RAM_BYPS::write(0); // 1_0c 0 - GBS::IF_HS_DEC_FACTOR::write(1); // 1_0b 4 - GBS::IF_LD_SEL_PROV::write(0); // 1_0b 7 - GBS::IF_HB_ST::write(2); // 1_10 deinterlace offset - GBS::MADPT_Y_VSCALE_BYPS::write(0); // 2_02 6 - GBS::MADPT_UV_VSCALE_BYPS::write(0); // 2_02 7 - GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 one line fifo for line phase adjust - GBS::MADPT_VSCALE_DEC_FACTOR::write(1); // 2_31 0..1 - GBS::MADPT_SEL_PHASE_INI::write(0); // 2_31 2 disable for SD (check 240p content) - if (rto->videoStandardInput == 1) { - GBS::IF_HB_ST2::write(0x490); // 1_18 - GBS::IF_HB_SP2::write(0x80); // 1_1a - GBS::IF_HB_SP::write(0x4A); // 1_12 deinterlace offset, green bar - GBS::IF_HBIN_SP::write(0xD0); // 1_26 - } else if (rto->videoStandardInput == 2) { - GBS::IF_HB_SP2::write(0x74); // 1_1a - GBS::IF_HB_SP::write(0x50); // 1_12 deinterlace offset, green bar - GBS::IF_HBIN_SP::write(0xD0); // 1_26 - } - } - } - if (rto->videoStandardInput == 3 || rto->videoStandardInput == 4 || - rto->videoStandardInput == 8 || rto->videoStandardInput == 9) { - // EDTV p-scan, need to either double adc data rate and halve vds scaling - // or disable line doubler (better) (50 / 60Hz shared) - - GBS::ADC_FLTR::write(3); // 5_03 4/5 - GBS::PLLAD_KS::write(1); // 5_16 - - if (rto->presetID != 0x06 && rto->presetID != 0x16) { - setCsVsStart(14); // pal // hm - setCsVsStop(11); // probably setting these for modes 8,9 - GBS::IF_HB_SP::write(0); // 1_12 deinterlace offset, fixes colors (downscale needs diff) - } - setOverSampleRatio(2, true); // with KS = 1 for modes 3, 4, 8 - GBS::IF_HS_DEC_FACTOR::write(0); // 1_0b 4+5 - GBS::IF_LD_SEL_PROV::write(1); // 1_0b 7 - GBS::IF_PRGRSV_CNTRL::write(1); // 1_00 6 - GBS::IF_SEL_WEN::write(1); // 1_02 0 - GBS::IF_HS_SEL_LPF::write(0); // 1_02 1 0 = use interpolator not lpf for EDTV - GBS::IF_HS_TAP11_BYPS::write(0); // 1_02 4 filter - GBS::IF_HS_Y_PDELAY::write(3); // 1_02 5+6 delays (ps2 test on one board clearly says 3, not 2) - GBS::VDS_V_DELAY::write(1); // 3_24 2 // new 24.07.2019 : 1, also set 2_17 to 1 - GBS::MADPT_Y_DELAY_UV_DELAY::write(1); // 2_17 : 1 - GBS::VDS_Y_DELAY::write(3); // 3_24 4/5 delays (ps2 test saying 3 for 1_02 goes with 3 here) - if (rto->videoStandardInput == 9) { - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() > 650) { - delay(20); - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() > 650) { - GBS::PLLAD_KS::write(0); // 5_16 - GBS::VDS_VSCALE_BYPS::write(1); // 3_00 5 no vscale - } - } - } - - // downscale preset: source is EDTV - if (rto->presetID == 0x06 || rto->presetID == 0x16) { - GBS::MADPT_Y_VSCALE_BYPS::write(0); // 2_02 6 - GBS::MADPT_UV_VSCALE_BYPS::write(0); // 2_02 7 - GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 one line fifo for line phase adjust - GBS::MADPT_VSCALE_DEC_FACTOR::write(1); // 2_31 0..1 - GBS::MADPT_SEL_PHASE_INI::write(1); // 2_31 2 enable - GBS::MADPT_SEL_PHASE_INI::write(0); // 2_31 2 disable - } - } - if (rto->videoStandardInput == 3 && rto->presetID != 0x06) { // ED YUV 60 - setCsVsStart(16); // ntsc - setCsVsStop(13); // - GBS::IF_HB_ST::write(30); // 1_10; magic number - GBS::IF_HBIN_ST::write(0x20); // 1_24 - GBS::IF_HBIN_SP::write(0x60); // 1_26 - if (rto->presetID == 0x5) { // out 1080p - GBS::IF_HB_SP2::write(0xB0); // 1_1a - GBS::IF_HB_ST2::write(0x4BC); // 1_18 - } else if (rto->presetID == 0x3) { // out 720p - GBS::VDS_VSCALE::write(683); // same as base preset - GBS::IF_HB_ST2::write(0x478); // 1_18 - GBS::IF_HB_SP2::write(0x84); // 1_1a - } else if (rto->presetID == 0x2) { // out x1024 - GBS::IF_HB_SP2::write(0x84); // 1_1a - GBS::IF_HB_ST2::write(0x478); // 1_18 - } else if (rto->presetID == 0x1) { // out x960 - GBS::IF_HB_SP2::write(0x84); // 1_1a - GBS::IF_HB_ST2::write(0x478); // 1_18 - } else if (rto->presetID == 0x4) { // out x480 - GBS::IF_HB_ST2::write(0x478); // 1_18 - GBS::IF_HB_SP2::write(0x90); // 1_1a - } - } else if (rto->videoStandardInput == 4 && rto->presetID != 0x16) { // ED YUV 50 - GBS::IF_HBIN_SP::write(0x40); // 1_26 was 0x80 test: ps2 videomodetester 576p mode - GBS::IF_HBIN_ST::write(0x20); // 1_24, odd but need to set this here (blue bar) - GBS::IF_HB_ST::write(0x30); // 1_10 - if (rto->presetID == 0x15) { // out 1080p - GBS::IF_HB_ST2::write(0x4C0); // 1_18 - GBS::IF_HB_SP2::write(0xC8); // 1_1a - } else if (rto->presetID == 0x13) { // out 720p - GBS::IF_HB_ST2::write(0x478); // 1_18 - GBS::IF_HB_SP2::write(0x88); // 1_1a - } else if (rto->presetID == 0x12) { // out x1024 - // VDS_VB_SP -= 12 used to shift pic up, but seems not necessary anymore - //GBS::VDS_VB_SP::write(GBS::VDS_VB_SP::read() - 12); - GBS::IF_HB_ST2::write(0x454); // 1_18 - GBS::IF_HB_SP2::write(0x88); // 1_1a - } else if (rto->presetID == 0x11) { // out x960 - GBS::IF_HB_ST2::write(0x454); // 1_18 - GBS::IF_HB_SP2::write(0x88); // 1_1a - } else if (rto->presetID == 0x14) { // out x576 - GBS::IF_HB_ST2::write(0x478); // 1_18 - GBS::IF_HB_SP2::write(0x90); // 1_1a - } - } else if (rto->videoStandardInput == 5) { // 720p - GBS::ADC_FLTR::write(1); // 5_03 - GBS::IF_PRGRSV_CNTRL::write(1); // progressive - GBS::IF_HS_DEC_FACTOR::write(0); - GBS::INPUT_FORMATTER_02::write(0x74); - GBS::VDS_Y_DELAY::write(3); - } else if (rto->videoStandardInput == 6 || rto->videoStandardInput == 7) { // 1080i/p - GBS::ADC_FLTR::write(1); // 5_03 - GBS::PLLAD_KS::write(0); // 5_16 - GBS::IF_PRGRSV_CNTRL::write(1); - GBS::IF_HS_DEC_FACTOR::write(0); - GBS::INPUT_FORMATTER_02::write(0x74); - GBS::VDS_Y_DELAY::write(3); - } else if (rto->videoStandardInput == 8) { // 25khz - // todo: this mode for HV sync - uint32_t pllRate = 0; - for (int i = 0; i < 8; i++) { - pllRate += getPllRate(); - } - pllRate /= 8; - SerialM.print(F("(H-PLL) rate: ")); - SerialM.println(pllRate); - if (pllRate > 200) { // is PLL even working? - if (pllRate < 1800) { // rate very low? - GBS::PLLAD_FS::write(0); // then low gain - } - } - GBS::PLLAD_ICP::write(6); // all 25khz submodes have more lines than NTSC - GBS::ADC_FLTR::write(1); // 5_03 - GBS::IF_HB_ST::write(30); // 1_10; magic number - //GBS::IF_HB_ST2::write(0x60); // 1_18 - //GBS::IF_HB_SP2::write(0x88); // 1_1a - GBS::IF_HBIN_SP::write(0x60); // 1_26 works for all output presets - if (rto->presetID == 0x1) { // out x960 - GBS::VDS_VSCALE::write(410); - } else if (rto->presetID == 0x2) { // out x1024 - GBS::VDS_VSCALE::write(402); - } else if (rto->presetID == 0x3) { // out 720p - GBS::VDS_VSCALE::write(546); - } else if (rto->presetID == 0x5) { // out 1080p - GBS::VDS_VSCALE::write(400); - } - } - } - - if (rto->presetID == 0x06 || rto->presetID == 0x16) { - rto->isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); // override back - } - - resetDebugPort(); - - boolean avoidAutoBest = 0; - if (rto->syncTypeCsync) { - if (GBS::TEST_BUS_2F::read() == 0) { - delay(4); - if (GBS::TEST_BUS_2F::read() == 0) { - optimizeSogLevel(); - avoidAutoBest = 1; - delay(4); - } - } - } - - latchPLLAD(); // besthtotal reliable with this (EDTV modes, possibly others) - - if (rto->isCustomPreset) { - // patch in segments not covered in custom preset files (currently seg 2) - if (rto->videoStandardInput == 3 || rto->videoStandardInput == 4 || rto->videoStandardInput == 8) { - GBS::MADPT_Y_DELAY_UV_DELAY::write(1); // 2_17 : 1 - } - - // get OSR - if (GBS::DEC1_BYPS::read() && GBS::DEC2_BYPS::read()) { - rto->osr = 1; - } else if (GBS::DEC1_BYPS::read() && !GBS::DEC2_BYPS::read()) { - rto->osr = 2; - } else { - rto->osr = 4; - } - - // always start with internal clock active first - if (GBS::PLL648_CONTROL_01::read() == 0x75 && GBS::GBS_PRESET_DISPLAY_CLOCK::read() != 0) { - GBS::PLL648_CONTROL_01::write(GBS::GBS_PRESET_DISPLAY_CLOCK::read()); - } else if (GBS::GBS_PRESET_DISPLAY_CLOCK::read() == 0) { - SerialM.println(F("no stored display clock to use!")); - } - } - - if (rto->presetIsPalForce60) { - if (GBS::GBS_OPTION_PALFORCED60_ENABLED::read() != 1) { - SerialM.println(F("pal forced 60hz: apply vshift")); - uint16_t vshift = 56; // default shift - if (rto->presetID == 0x5) { - GBS::IF_VB_SP::write(4); - } // out 1080p - else { - GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + vshift); - } - GBS::IF_VB_ST::write(GBS::IF_VB_SP::read() - 2); - GBS::GBS_OPTION_PALFORCED60_ENABLED::write(1); - } - } - - //freezeVideo(); - - GBS::ADC_TEST_04::write(0x02); // 5_04 - GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 - GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 - - // auto ADC gain - if (uopt->enableAutoGain == 1) { - if (adco->r_gain == 0) { - // SerialM.printf("ADC gain: reset %x := %x\n", GBS::ADC_RGCTRL::read(), AUTO_GAIN_INIT); - setAdcGain(AUTO_GAIN_INIT); - GBS::DEC_TEST_ENABLE::write(1); - } else { - // SerialM.printf("ADC gain: transferred %x := %x\n", GBS::ADC_RGCTRL::read(), adco->r_gain); - GBS::ADC_RGCTRL::write(adco->r_gain); - GBS::ADC_GGCTRL::write(adco->g_gain); - GBS::ADC_BGCTRL::write(adco->b_gain); - GBS::DEC_TEST_ENABLE::write(1); - } - } else { - GBS::DEC_TEST_ENABLE::write(0); // no need for decimation test to be enabled - } - - // ADC offset if measured - if (adco->r_off != 0 && adco->g_off != 0 && adco->b_off != 0) { - GBS::ADC_ROFCTRL::write(adco->r_off); - GBS::ADC_GOFCTRL::write(adco->g_off); - GBS::ADC_BOFCTRL::write(adco->b_off); - } - - SerialM.print(F("ADC offset: R:")); - SerialM.print(GBS::ADC_ROFCTRL::read(), HEX); - SerialM.print(" G:"); - SerialM.print(GBS::ADC_GOFCTRL::read(), HEX); - SerialM.print(" B:"); - SerialM.println(GBS::ADC_BOFCTRL::read(), HEX); - - GBS::IF_AUTO_OFST_U_RANGE::write(0); // 0 seems to be full range, else 1 to 15 - GBS::IF_AUTO_OFST_V_RANGE::write(0); // 0 seems to be full range, else 1 to 15 - GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame ; by line is easier to spot - GBS::IF_AUTO_OFST_EN::write(0); // not reliable yet - // to get it working with RGB: - // leave RGB to YUV at the ADC DEC stage (s5_1f 2 = 0) - // s5s07s42, 1_2a to 0, s5_06 + s5_08 to 0x40 - // 5_06 + 5_08 will be the target center value, 5_07 sets general offset - // s3s3as00 s3s3bs00 s3s3cs00 - - if (uopt->wantVdsLineFilter) { - GBS::VDS_D_RAM_BYPS::write(0); - } else { - GBS::VDS_D_RAM_BYPS::write(1); - } - - if (uopt->wantPeaking) { - GBS::VDS_PK_Y_H_BYPS::write(0); - } else { - GBS::VDS_PK_Y_H_BYPS::write(1); - } - - // unused now - GBS::VDS_TAP6_BYPS::write(0); - /*if (uopt->wantTap6) { GBS::VDS_TAP6_BYPS::write(0); } - else { - GBS::VDS_TAP6_BYPS::write(1); - if (!isCustomPreset) { - GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() + 1); - } - }*/ - - if (uopt->wantStepResponse) { - // step response requested, but exclude 1080p presets - if (rto->presetID != 0x05 && rto->presetID != 0x15) { - GBS::VDS_UV_STEP_BYPS::write(0); - } else { - GBS::VDS_UV_STEP_BYPS::write(1); - } - } else { - GBS::VDS_UV_STEP_BYPS::write(1); - } - - // transfer preset's display clock to ext. gen - externalClockGenResetClock(); - - //unfreezeVideo(); - Menu::init(); - FrameSync::cleanup(); - rto->syncLockFailIgnore = 16; - - // undo eventual rto->useHdmiSyncFix (not using this method atm) - GBS::VDS_SYNC_EN::write(0); - GBS::VDS_FLOCK_EN::write(0); - - if (!rto->outModeHdBypass && rto->autoBestHtotalEnabled && - GBS::GBS_OPTION_SCALING_RGBHV::read() == 0 && !avoidAutoBest && - (rto->videoStandardInput >= 1 && rto->videoStandardInput <= 4)) { - // autobesthtotal - updateCoastPosition(0); - delay(1); - resetInterruptNoHsyncBadBit(); - resetInterruptSogBadBit(); - delay(10); - // works reliably now on my test HDMI dongle - if (rto->useHdmiSyncFix && !uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out - } - delay(70); // minimum delay without random failures: TBD - - for (uint8_t i = 0; i < 4; i++) { - if (GBS::STATUS_INT_SOG_BAD::read() == 1) { - optimizeSogLevel(); - resetInterruptSogBadBit(); - delay(40); - } else if (getStatus16SpHsStable() && getStatus16SpHsStable()) { - delay(1); // wifi - if (getVideoMode() == rto->videoStandardInput) { - boolean ok = 0; - float sfr = getSourceFieldRate(0); - //Serial.println(sfr, 3); - if (rto->videoStandardInput == 1 || rto->videoStandardInput == 3) { - if (sfr > 58.6f && sfr < 61.4f) - ok = 1; - } else if (rto->videoStandardInput == 2 || rto->videoStandardInput == 4) { - if (sfr > 49.1f && sfr < 51.1f) - ok = 1; - } - if (ok) { // else leave it for later - runAutoBestHTotal(); - delay(1); // wifi - break; - } - } - } - delay(10); - } - } else { - // scaling rgbhv, HD modes, no autobesthtotal - delay(10); - // works reliably now on my test HDMI dongle - if (rto->useHdmiSyncFix && !uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out - } - delay(20); - updateCoastPosition(0); - updateClampPosition(); - } - - //SerialM.print("pp time: "); SerialM.println(millis() - postLoadTimer); - - // make sure - if (rto->useHdmiSyncFix && !uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out - } - - // late adjustments that require some delay time first - if (!rto->isCustomPreset) { - if (videoStandardInputIsPalNtscSd() && !rto->outModeHdBypass) { - // SNES has less total lines and a slight offset (only relevant in 60Hz) - if (GBS::VPERIOD_IF::read() == 523) { - GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 4); - GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 4); - } - } - } - - // new, might be useful (3_6D - 3_72) - GBS::VDS_EXT_HB_ST::write(GBS::VDS_DIS_HB_ST::read()); - GBS::VDS_EXT_HB_SP::write(GBS::VDS_DIS_HB_SP::read()); - GBS::VDS_EXT_VB_ST::write(GBS::VDS_DIS_VB_ST::read()); - GBS::VDS_EXT_VB_SP::write(GBS::VDS_DIS_VB_SP::read()); - // VDS_VSYN_SIZE1 + VDS_VSYN_SIZE2 to VDS_VSYNC_RST + 2 - GBS::VDS_VSYN_SIZE1::write(GBS::VDS_VSYNC_RST::read() + 2); - GBS::VDS_VSYN_SIZE2::write(GBS::VDS_VSYNC_RST::read() + 2); - GBS::VDS_FRAME_RST::write(4); // 3_19 - // VDS_FRAME_NO, VDS_FR_SELECT - GBS::VDS_FRAME_NO::write(1); // 3_1f 0-3 - GBS::VDS_FR_SELECT::write(1); // 3_1b, 3_1c, 3_1d, 3_1e - - // noise starts here! - resetDigital(); - - resetPLLAD(); // also turns on pllad - GBS::PLLAD_LEN::write(1); // 5_11 1 - - if (!rto->isCustomPreset) { - GBS::VDS_IN_DREG_BYPS::write(0); // 3_40 2 // 0 = input data triggered on falling clock edge, 1 = bypass - GBS::PLLAD_R::write(3); - GBS::PLLAD_S::write(3); - GBS::PLL_R::write(1); // PLL lock detector skew - GBS::PLL_S::write(2); - GBS::DEC_IDREG_EN::write(1); // 5_1f 7 - GBS::DEC_WEN_MODE::write(1); // 5_1e 7 // 1 keeps ADC phase consistent. around 4 lock positions vs totally random - - // 4 segment - GBS::CAP_SAFE_GUARD_EN::write(0); // 4_21_5 // does more harm than good - // memory timings, anti noise - GBS::PB_CUT_REFRESH::write(1); // helps with PLL=ICLK mode artefacting - GBS::RFF_LREQ_CUT::write(0); // was in motionadaptive toggle function but on, off seems nicer - GBS::CAP_REQ_OVER::write(0); // 4_22 0 1=capture stop at hblank 0=free run - GBS::CAP_STATUS_SEL::write(1); // 4_22 1 1=capture request when FIFO 50%, 0= FIFO 100% - GBS::PB_REQ_SEL::write(3); // PlayBack 11 High request Low request - // 4_2C, 4_2D should be set by preset - GBS::RFF_WFF_OFFSET::write(0x0); // scanline fix - if (rto->videoStandardInput == 3 || rto->videoStandardInput == 4) { - // this also handles mode 14 csync rgbhv - GBS::PB_CAP_OFFSET::write(GBS::PB_FETCH_NUM::read() + 4); // 4_37 to 4_39 (green bar) - } - // 4_12 should be set by preset - } - - if (!rto->outModeHdBypass) { - ResetSDRAM(); - } - - setAndUpdateSogLevel(rto->currentLevelSOG); // use this to cycle SP / ADPLL latches - - if (rto->presetID != 0x06 && rto->presetID != 0x16) { - // IF_VS_SEL = 1 for SD/HD SP mode in HD mode (5_3e 1) - GBS::IF_VS_SEL::write(0); // 0 = "VCR" IF sync, requires VS_FLIP to be on, more stable? - GBS::IF_VS_FLIP::write(1); - } - - GBS::SP_CLP_SRC_SEL::write(0); // 0: 27Mhz clock; 1: pixel clock - GBS::SP_CS_CLP_ST::write(32); - GBS::SP_CS_CLP_SP::write(48); // same as reset parameters - - if (!uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out if needed - } - GBS::DAC_RGBS_PWDNZ::write(1); // DAC on if needed - GBS::DAC_RGBS_SPD::write(0); // 0_45 2 DAC_SVM power down disable, somehow less jailbars - GBS::DAC_RGBS_S0ENZ::write(0); // - GBS::DAC_RGBS_S1EN::write(1); // these 2 also help - - rto->useHdmiSyncFix = 0; // reset flag - - GBS::SP_H_PROTECT::write(0); - if (rto->videoStandardInput >= 5) { - GBS::SP_DIS_SUB_COAST::write(1); // might not disable it at all soon - } - - if (rto->syncTypeCsync) { - GBS::SP_EXT_SYNC_SEL::write(1); // 5_20 3 disconnect HV input - // stays disconnected until reset condition - } - - rto->coastPositionIsSet = false; // re-arm these - rto->clampPositionIsSet = false; - - if (rto->outModeHdBypass) { - GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts - GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status - GBS::INTERRUPT_CONTROL_00::write(0x00); - unfreezeVideo(); // eventhough not used atm - // DAC and Sync out will be enabled later - return; // to setOutModeHdBypass(); - } - - if (GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) { - rto->videoStandardInput = 14; - } - - if (GBS::GBS_OPTION_SCALING_RGBHV::read() == 0) { - unsigned long timeout = millis(); - while ((!getStatus16SpHsStable()) && (millis() - timeout < 2002)) { - delay(4); - handleWiFi(0); - updateSpDynamic(0); - } - while ((getVideoMode() == 0) && (millis() - timeout < 1505)) { - delay(4); - handleWiFi(0); - updateSpDynamic(0); - } - - timeout = millis() - timeout; - if (timeout > 1000) { - Serial.print(F("to1 is: ")); - Serial.println(timeout); - } - if (timeout >= 1500) { - if (rto->currentLevelSOG >= 7) { - optimizeSogLevel(); - delay(300); - } - } - } - - // early attempt - updateClampPosition(); - if (rto->clampPositionIsSet) { - if (GBS::SP_NO_CLAMP_REG::read() == 1) { - GBS::SP_NO_CLAMP_REG::write(0); - } - } - - updateSpDynamic(0); - - if (!rto->syncWatcherEnabled) { - GBS::SP_NO_CLAMP_REG::write(0); - } - - // this was used with ADC write enable, producing about (exactly?) 4 lock positions - // cycling through the phase let it land favorably - //for (uint8_t i = 0; i < 8; i++) { - // advancePhase(); - //} - - setAndUpdateSogLevel(rto->currentLevelSOG); // use this to cycle SP / ADPLL latches - //optimizePhaseSP(); // do this later in run loop - - GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts - GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status - GBS::INTERRUPT_CONTROL_00::write(0x00); - - OutputComponentOrVGA(); - - // presetPreference 10 means the user prefers bypass mode at startup - // it's best to run a normal format detect > apply preset loop, then enter bypass mode - // this can lead to an endless loop, so applyPresetDoneStage = 10 applyPresetDoneStage = 11 - // are introduced to break out of it. - // also need to check for mode 15 - // also make sure to turn off autoBestHtotal - if (uopt->presetPreference == 10 && rto->videoStandardInput != 15) { - rto->autoBestHtotalEnabled = 0; - if (rto->applyPresetDoneStage == 11) { - // we were here before, stop the loop - rto->applyPresetDoneStage = 1; - } else { - rto->applyPresetDoneStage = 10; - } - } else { - // normal modes - rto->applyPresetDoneStage = 1; - } - - unfreezeVideo(); - - if (uopt->enableFrameTimeLock) { - activeFrameTimeLockInitialSteps(); - } - - SerialM.print(F("\npreset applied: ")); - if (rto->presetID == 0x01 || rto->presetID == 0x11) - SerialM.print(F("1280x960")); - else if (rto->presetID == 0x02 || rto->presetID == 0x12) - SerialM.print(F("1280x1024")); - else if (rto->presetID == 0x03 || rto->presetID == 0x13) - SerialM.print(F("1280x720")); - else if (rto->presetID == 0x05 || rto->presetID == 0x15) - SerialM.print(F("1920x1080")); - else if (rto->presetID == 0x06 || rto->presetID == 0x16) - SerialM.print(F("downscale")); - else if (rto->presetID == 0x04) - SerialM.print(F("720x480")); - else if (rto->presetID == 0x14) - SerialM.print(F("768x576")); - else - SerialM.print(F("bypass")); - - if (rto->outModeHdBypass) { - SerialM.print(F(" (bypass)")); - } else if (rto->isCustomPreset) { - SerialM.print(F(" (custom)")); - } - - SerialM.print(F(" for ")); - if (rto->videoStandardInput == 1) - SerialM.print(F("NTSC 60Hz ")); - else if (rto->videoStandardInput == 2) - SerialM.print(F("PAL 50Hz ")); - else if (rto->videoStandardInput == 3) - SerialM.print(F("EDTV 60Hz")); - else if (rto->videoStandardInput == 4) - SerialM.print(F("EDTV 50Hz")); - else if (rto->videoStandardInput == 5) - SerialM.print(F("720p 60Hz HDTV ")); - else if (rto->videoStandardInput == 6) - SerialM.print(F("1080i 60Hz HDTV ")); - else if (rto->videoStandardInput == 7) - SerialM.print(F("1080p 60Hz HDTV ")); - else if (rto->videoStandardInput == 8) - SerialM.print(F("Medium Res ")); - else if (rto->videoStandardInput == 13) - SerialM.print(F("VGA/SVGA/XGA/SXGA")); - else if (rto->videoStandardInput == 14) { - if (rto->syncTypeCsync) - SerialM.print(F("scaling RGB (CSync)")); - else - SerialM.print(F("scaling RGB (HV Sync)")); - } else if (rto->videoStandardInput == 15) { - if (rto->syncTypeCsync) - SerialM.print(F("RGB Bypass (CSync)")); - else - SerialM.print(F("RGB Bypass (HV Sync)")); - } else if (rto->videoStandardInput == 0) - SerialM.print(F("!should not go here!")); - - if (rto->presetID == 0x05 || rto->presetID == 0x15) { - SerialM.print(F("(set your TV aspect ratio to 16:9!)")); - } - if (rto->videoStandardInput == 14) { - SerialM.print(F("\nNote: scaling RGB is still in development")); - } - // presetPreference = OutputCustomized may fail to load (missing) preset file and arrive here with defaults - SerialM.println("\n"); -} - -// TODO replace result with VideoStandardInput enum -void applyPresets(uint8_t result) -{ - if (!rto->boardHasPower) { - SerialM.println(F("GBS board not responding!")); - return; - } - - // if RGBHV scaling and invoked through web ui or custom preset - // need to know syncTypeCsync - if (result == 14) { - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { - rto->inputIsYpBpR = 0; - if (GBS::STATUS_SYNC_PROC_VSACT::read() == 0) { - rto->syncTypeCsync = 1; - } else { - rto->syncTypeCsync = 0; - } - } - } - - boolean waitExtra = 0; - if (rto->outModeHdBypass || rto->videoStandardInput == 15 || rto->videoStandardInput == 0) { - waitExtra = 1; - if (result <= 4 || result == 14 || result == 8 || result == 9) { - GBS::SFTRST_IF_RSTZ::write(1); // early init - GBS::SFTRST_VDS_RSTZ::write(1); - GBS::SFTRST_DEC_RSTZ::write(1); - } - } - rto->presetIsPalForce60 = 0; // the default - rto->outModeHdBypass = 0; // the default at this stage - - // in case it is set; will get set appropriately later in doPostPresetLoadSteps() - GBS::GBS_PRESET_CUSTOM::write(0); - rto->isCustomPreset = false; - - // carry over debug view if possible - if (GBS::ADC_UNUSED_62::read() != 0x00) { - // only if the preset to load isn't custom - // (else the command will instantly disable debug view) - if (uopt->presetPreference != 2) { - serialCommand = 'D'; - } - } - - if (result == 0) { - // Unknown - SerialM.println(F("Source format not properly recognized, using fallback preset!")); - result = 3; // in case of success: override to 480p60 - GBS::ADC_INPUT_SEL::write(1); // RGB - delay(100); - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { - rto->inputIsYpBpR = 0; - rto->syncWatcherEnabled = 1; - if (GBS::STATUS_SYNC_PROC_VSACT::read() == 0) { - rto->syncTypeCsync = 1; - } else { - rto->syncTypeCsync = 0; - } - } else { - GBS::ADC_INPUT_SEL::write(0); // YPbPr - delay(100); - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { - rto->inputIsYpBpR = 1; - rto->syncTypeCsync = 1; - rto->syncWatcherEnabled = 1; - } else { - // found nothing at all, turn off output - - // If we call setResetParameters(), soon afterwards loop() -> - // inputAndSyncDetect() -> goLowPowerWithInputDetection() will - // call setResetParameters() again. But if we don't call - // setResetParameters() here, the second call will never happen. - setResetParameters(); - - // Deselect the output resolution in the web UI. We cannot call - // doPostPresetLoadSteps() to select the right resolution, since - // it *enables* the output (showing a green screen) even if - // previously disabled, and we want to *disable* it. - rto->presetID = 0; - return; - } - } - } - - if (uopt->PalForce60 == 1) { - if (uopt->presetPreference != 2) { // != custom. custom saved as pal preset has ntsc customization - if (result == 2 || result == 4) { - Serial.println(F("PAL@50 to 60Hz")); - rto->presetIsPalForce60 = 1; - } - if (result == 2) { - result = 1; - } - if (result == 4) { - result = 3; - } - } - } - - /// If uopt->presetPreference == OutputCustomized and we load a custom - /// preset, check if it's intended to bypass scaling at the current input - /// resolution. If so, setup bypass and skip the rest of applyPresets(). - auto applySavedBypassPreset = [&result]() -> bool { - /* - Types: - - - Registers: - - Written by applyPresets() -> writeProgramArrayNew(), - loadHdBypassSection(), etc. - - GBS_PRESET_ID @ S1_2B[0:6] - - GBS_PRESET_CUSTOM @ S1_2B[7] - - uopt is source of truth, rto is derived cached state??? - - uopt->presetPreference - - Read by applyPresets() to pick an output resolution. - - rto->presetID - - Written by applyPresets() -> doPostPresetLoadSteps(). - - = register GBS_PRESET_ID. - - rto->isCustomPreset - - Written by applyPresets() -> doPostPresetLoadSteps(). - - = register GBS_PRESET_CUSTOM. - - rto->isCustomPreset and rto->presetID control which button is - highlighted in the web UI (updateWebSocketData() -> - GBSControl.buttonMapping). - - Control flow: - - applyPresets(): - - If uopt->presetPreference == OutputCustomized (yes): - - loadPresetFromSPIFFS() - - All custom presets are saved with GBS_PRESET_CUSTOM = 1. - - writeProgramArrayNew() - - GBS_PRESET_ID = output resolution ID - - GBS_PRESET_CUSTOM = 1 - - applySavedBypassPreset(): - - If GBS_PRESET_ID == PresetHdBypass (yes): - - rto->videoStandardInput = result; (not sure why) - - setOutModeHdBypass(regsInitialized=true) - - rto->outModeHdBypass = 1; - - loadHdBypassSection() - - Overwrites S1_30..5F. - - GBS::GBS_PRESET_ID::write(PresetHdBypass); - - if (!regsInitialized) (false) - - ~~GBS::GBS_PRESET_CUSTOM::write(0);~~ (skipped) - - doPostPresetLoadSteps() - - rto->presetID = GBS::GBS_PRESET_ID::read(); - - PresetHdBypass - - rto->isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); - - true - - Branches based on rto->presetID - - if (rto->outModeHdBypass) (yes) return. - - ... - - rto->outModeHdBypass = 1; (again?!) - */ - - uint8_t rawPresetId = GBS::GBS_PRESET_ID::read(); - if (rawPresetId == PresetHdBypass) { - // Required for switching from 240p to 480p to work. - rto->videoStandardInput = result; - - // Setup video mode passthrough. - setOutModeHdBypass(true); - return true; - } - if (rawPresetId == PresetBypassRGBHV) { - // TODO implement bypassModeSwitch_RGBHV (I don't have RGBHV inputs to verify) - } - return false; - }; - - if (result == 1 || result == 3 || result == 8 || result == 9 || result == 14) { - // NTSC input - if (uopt->presetPreference == 0) { - writeProgramArrayNew(ntsc_240p, false); - } else if (uopt->presetPreference == 1) { - writeProgramArrayNew(ntsc_720x480, false); - } else if (uopt->presetPreference == 3) { - writeProgramArrayNew(ntsc_1280x720, false); - } -#if defined(ESP8266) - else if (uopt->presetPreference == OutputCustomized) { - const uint8_t *preset = loadPresetFromSPIFFS(result); - writeProgramArrayNew(preset, false); - if (applySavedBypassPreset()) { - return; - } - } else if (uopt->presetPreference == 4) { - if (uopt->matchPresetSource && (result != 8) && (GBS::GBS_OPTION_SCALING_RGBHV::read() == 0)) { - SerialM.println(F("matched preset override > 1280x960")); - writeProgramArrayNew(ntsc_240p, false); // pref = x1024 override to x960 - } else { - writeProgramArrayNew(ntsc_1280x1024, false); - } - } -#endif - else if (uopt->presetPreference == 5) { - writeProgramArrayNew(ntsc_1920x1080, false); - } else if (uopt->presetPreference == 6) { - writeProgramArrayNew(ntsc_downscale, false); - } - } else if (result == 2 || result == 4) { - // PAL input - if (uopt->presetPreference == 0) { - if (uopt->matchPresetSource) { - SerialM.println(F("matched preset override > 1280x1024")); - writeProgramArrayNew(pal_1280x1024, false); // pref = x960 override to x1024 - } else { - writeProgramArrayNew(pal_240p, false); - } - } else if (uopt->presetPreference == 1) { - writeProgramArrayNew(pal_768x576, false); - } else if (uopt->presetPreference == 3) { - writeProgramArrayNew(pal_1280x720, false); - } -#if defined(ESP8266) - else if (uopt->presetPreference == OutputCustomized) { - const uint8_t *preset = loadPresetFromSPIFFS(result); - writeProgramArrayNew(preset, false); - if (applySavedBypassPreset()) { - return; - } - } else if (uopt->presetPreference == 4) { - writeProgramArrayNew(pal_1280x1024, false); - } -#endif - else if (uopt->presetPreference == 5) { - writeProgramArrayNew(pal_1920x1080, false); - } else if (uopt->presetPreference == 6) { - writeProgramArrayNew(pal_downscale, false); - } - } else if (result == 5 || result == 6 || result == 7 || result == 13) { - // use bypass mode for these HD sources - rto->videoStandardInput = result; - setOutModeHdBypass(false); - return; - } else if (result == 15) { - SerialM.print(F("RGB/HV ")); - if (rto->syncTypeCsync) { - SerialM.print(F("(CSync) ")); - } - //if (uopt->preferScalingRgbhv) { - // SerialM.print("(prefer scaling mode)"); - //} - SerialM.println(); - bypassModeSwitch_RGBHV(); - // don't go through doPostPresetLoadSteps - return; - } - - rto->videoStandardInput = result; - if (waitExtra) { - // extra time needed for digital resets, so that autobesthtotal works first attempt - //Serial.println("waitExtra 400ms"); - delay(400); // min ~ 300 - } - doPostPresetLoadSteps(); -} - -void unfreezeVideo() -{ - /*if (rto->videoIsFrozen == true) { - GBS::IF_VB_ST::write(GBS::IF_VB_SP::read() - 2); - } - rto->videoIsFrozen = false;*/ - //Serial.print("u"); - GBS::CAPTURE_ENABLE::write(1); -} - -void freezeVideo() -{ - /*if (rto->videoIsFrozen == false) { - GBS::IF_VB_ST::write(GBS::IF_VB_SP::read()); - } - rto->videoIsFrozen = true;*/ - //Serial.print("f"); - GBS::CAPTURE_ENABLE::write(0); -} - -uint8_t getVideoMode() -{ - uint8_t detectedMode = 0; - - if (rto->videoStandardInput >= 14) { // check RGBHV first // not mode 13 here, else mode 13 can't reliably exit - detectedMode = GBS::STATUS_16::read(); - if ((detectedMode & 0x0a) > 0) { // bit 1 or 3 active? - return rto->videoStandardInput; // still RGBHV bypass, 14 or 15 - } else { - return 0; - } - } - - detectedMode = GBS::STATUS_00::read(); - - // note: if stat0 == 0x07, it's supposedly stable. if we then can't find a mode, it must be an MD problem - if ((detectedMode & 0x07) == 0x07) { - if ((detectedMode & 0x80) == 0x80) { // bit 7: SD flag (480i, 480P, 576i, 576P) - if ((detectedMode & 0x08) == 0x08) - return 1; // ntsc interlace - if ((detectedMode & 0x20) == 0x20) - return 2; // pal interlace - if ((detectedMode & 0x10) == 0x10) - return 3; // edtv 60 progressive - if ((detectedMode & 0x40) == 0x40) - return 4; // edtv 50 progressive - } - - detectedMode = GBS::STATUS_03::read(); - if ((detectedMode & 0x10) == 0x10) { - return 5; - } // hdtv 720p - - if (rto->videoStandardInput == 4) { - detectedMode = GBS::STATUS_04::read(); - if ((detectedMode & 0xFF) == 0x80) { - return 4; // still edtv 50 progressive - } - } - } - - detectedMode = GBS::STATUS_04::read(); - if ((detectedMode & 0x20) == 0x20) { // hd mode on - if ((detectedMode & 0x61) == 0x61) { - // hdtv 1080i // 576p mode tends to get misdetected as this, even with all the checks - // real 1080i (PS2): h:199 v:1124 - // misdetected 576p (PS2): h:215 v:1249 - if (GBS::VPERIOD_IF::read() < 1160) { - return 6; - } - } - if ((detectedMode & 0x10) == 0x10) { - if ((detectedMode & 0x04) == 0x04) { // normally HD2376_1250P (PAL FHD?), but using this for 24k - return 8; - } - return 7; // hdtv 1080p - } - } - - // graphic modes, mostly used for ps2 doing rgb over yuv with sog - if ((GBS::STATUS_05::read() & 0x0c) == 0x00) // 2: Horizontal unstable AND 3: Vertical unstable are 0? - { - if (GBS::STATUS_00::read() == 0x07) { // the 3 stat0 stable indicators on, none of the SD indicators on - if ((GBS::STATUS_03::read() & 0x02) == 0x02) // Graphic mode bit on (any of VGA/SVGA/XGA/SXGA at all detected Hz) - { - if (rto->inputIsYpBpR) - return 13; - else - return 15; // switch to RGBS/HV handling - } else { - // this mode looks like it wants to be graphic mode, but the horizontal counter target in MD is very strict - static uint8_t XGA_60HZ = GBS::MD_XGA_60HZ_CNTRL::read(); - static uint8_t XGA_70HZ = GBS::MD_XGA_70HZ_CNTRL::read(); - static uint8_t XGA_75HZ = GBS::MD_XGA_75HZ_CNTRL::read(); - static uint8_t XGA_85HZ = GBS::MD_XGA_85HZ_CNTRL::read(); - - static uint8_t SXGA_60HZ = GBS::MD_SXGA_60HZ_CNTRL::read(); - static uint8_t SXGA_75HZ = GBS::MD_SXGA_75HZ_CNTRL::read(); - static uint8_t SXGA_85HZ = GBS::MD_SXGA_85HZ_CNTRL::read(); - - static uint8_t SVGA_60HZ = GBS::MD_SVGA_60HZ_CNTRL::read(); - static uint8_t SVGA_75HZ = GBS::MD_SVGA_75HZ_CNTRL::read(); - static uint8_t SVGA_85HZ = GBS::MD_SVGA_85HZ_CNTRL::read(); - - static uint8_t VGA_75HZ = GBS::MD_VGA_75HZ_CNTRL::read(); - static uint8_t VGA_85HZ = GBS::MD_VGA_85HZ_CNTRL::read(); - - short hSkew = random(-2, 2); // skew the target a little - //Serial.println(XGA_60HZ + hSkew, HEX); - GBS::MD_XGA_60HZ_CNTRL::write(XGA_60HZ + hSkew); - GBS::MD_XGA_70HZ_CNTRL::write(XGA_70HZ + hSkew); - GBS::MD_XGA_75HZ_CNTRL::write(XGA_75HZ + hSkew); - GBS::MD_XGA_85HZ_CNTRL::write(XGA_85HZ + hSkew); - GBS::MD_SXGA_60HZ_CNTRL::write(SXGA_60HZ + hSkew); - GBS::MD_SXGA_75HZ_CNTRL::write(SXGA_75HZ + hSkew); - GBS::MD_SXGA_85HZ_CNTRL::write(SXGA_85HZ + hSkew); - GBS::MD_SVGA_60HZ_CNTRL::write(SVGA_60HZ + hSkew); - GBS::MD_SVGA_75HZ_CNTRL::write(SVGA_75HZ + hSkew); - GBS::MD_SVGA_85HZ_CNTRL::write(SVGA_85HZ + hSkew); - GBS::MD_VGA_75HZ_CNTRL::write(VGA_75HZ + hSkew); - GBS::MD_VGA_85HZ_CNTRL::write(VGA_85HZ + hSkew); - } - } - } - - detectedMode = GBS::STATUS_00::read(); - if ((detectedMode & 0x2F) == 0x07) { // 0_00 H+V stable, not NTSCI, not PALI - detectedMode = GBS::STATUS_16::read(); - if ((detectedMode & 0x02) == 0x02) { // SP H active - uint16_t lineCount = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - for (uint8_t i = 0; i < 2; i++) { - delay(2); - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() < (lineCount - 1) || - GBS::STATUS_SYNC_PROC_VTOTAL::read() > (lineCount + 1)) { - lineCount = 0; - rto->notRecognizedCounter = 0; - break; - } - detectedMode = GBS::STATUS_00::read(); - if ((detectedMode & 0x2F) != 0x07) { - lineCount = 0; - rto->notRecognizedCounter = 0; - break; - } - } - if (lineCount != 0 && rto->notRecognizedCounter < 255) { - rto->notRecognizedCounter++; - } - } else { - rto->notRecognizedCounter = 0; - } - } else { - rto->notRecognizedCounter = 0; - } - - if (rto->notRecognizedCounter == 255) { - return 9; - } - - return 0; // unknown mode -} - -// if testbus has 0x05, sync is present and line counting active. if it has 0x04, sync is present but no line counting -boolean getSyncPresent() -{ - uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); - uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(0xa); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(0x0f); - } - - uint16_t readout = GBS::TEST_BUS::read(); - - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(debug_backup); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); - } - //if (((readout & 0x0500) == 0x0500) || ((readout & 0x0500) == 0x0400)) { - if (readout > 0x0180) { - return true; - } - - return false; -} - -// returns 0_00 bit 2 = H+V both stable (for the IF, not SP) -boolean getStatus00IfHsVsStable() -{ - return ((GBS::STATUS_00::read() & 0x04) == 0x04) ? 1 : 0; -} - -// used to be a check for the length of the debug bus readout of 5_63 = 0x0f -// now just checks the chip status at 0_16 HS active (and Interrupt bit4 HS active for RGBHV) -boolean getStatus16SpHsStable() -{ - if (rto->videoStandardInput == 15) { // check RGBHV first - if (GBS::STATUS_INT_INP_NO_SYNC::read() == 0) { - return true; - } else { - resetInterruptNoHsyncBadBit(); - return false; - } - } - - // STAT_16 bit 1 is the "hsync active" flag, which appears to be a reliable indicator - // checking the flag replaces checking the debug bus pulse length manually - uint8_t status16 = GBS::STATUS_16::read(); - if ((status16 & 0x02) == 0x02) { - if (rto->videoStandardInput == 1 || rto->videoStandardInput == 2) { - if ((status16 & 0x01) != 0x01) { // pal / ntsc should be sync active low - return true; - } - } else { - return true; // not pal / ntsc - } - } - - return false; -} - -void setOverSampleRatio(uint8_t newRatio, boolean prepareOnly) -{ - uint8_t ks = GBS::PLLAD_KS::read(); - - bool hi_res = rto->videoStandardInput == 8 || rto->videoStandardInput == 4 || rto->videoStandardInput == 3; - bool bypass = rto->presetID == PresetHdBypass; - - switch (newRatio) { - case 1: - if (ks == 0) - GBS::PLLAD_CKOS::write(0); - if (ks == 1) - GBS::PLLAD_CKOS::write(1); - if (ks == 2) - GBS::PLLAD_CKOS::write(2); - if (ks == 3) - GBS::PLLAD_CKOS::write(3); - GBS::ADC_CLK_ICLK2X::write(0); - GBS::ADC_CLK_ICLK1X::write(0); - GBS::DEC1_BYPS::write(1); // dec1 couples to ADC_CLK_ICLK2X - GBS::DEC2_BYPS::write(1); - - // Necessary to avoid a 2x-scaled image for some reason. - if (hi_res && !bypass) { - GBS::ADC_CLK_ICLK1X::write(1); - //GBS::DEC2_BYPS::write(0); - } - - rto->osr = 1; - //if (!prepareOnly) SerialM.println("OSR 1x"); - - break; - case 2: - if (ks == 0) { - setOverSampleRatio(1, false); - return; - } // 2x impossible - if (ks == 1) - GBS::PLLAD_CKOS::write(0); - if (ks == 2) - GBS::PLLAD_CKOS::write(1); - if (ks == 3) - GBS::PLLAD_CKOS::write(2); - GBS::ADC_CLK_ICLK2X::write(0); - GBS::ADC_CLK_ICLK1X::write(1); - GBS::DEC2_BYPS::write(0); - GBS::DEC1_BYPS::write(1); // dec1 couples to ADC_CLK_ICLK2X - - if (hi_res && !bypass) { - //GBS::ADC_CLK_ICLK2X::write(1); - //GBS::DEC1_BYPS::write(0); - // instead increase CKOS by 1 step - GBS::PLLAD_CKOS::write(GBS::PLLAD_CKOS::read() + 1); - } - - rto->osr = 2; - //if (!prepareOnly) SerialM.println("OSR 2x"); - - break; - case 4: - if (ks == 0) { - setOverSampleRatio(1, false); - return; - } // 4x impossible - if (ks == 1) { - setOverSampleRatio(1, false); - return; - } // 4x impossible - if (ks == 2) - GBS::PLLAD_CKOS::write(0); - if (ks == 3) - GBS::PLLAD_CKOS::write(1); - GBS::ADC_CLK_ICLK2X::write(1); - GBS::ADC_CLK_ICLK1X::write(1); - GBS::DEC1_BYPS::write(0); // dec1 couples to ADC_CLK_ICLK2X - GBS::DEC2_BYPS::write(0); - - rto->osr = 4; - //if (!prepareOnly) SerialM.println("OSR 4x"); - - break; - default: - break; - } - - if (!prepareOnly) - latchPLLAD(); -} - -void togglePhaseAdjustUnits() -{ - GBS::PA_SP_BYPSZ::write(0); // yes, 0 means bypass on here - GBS::PA_SP_BYPSZ::write(1); - delay(2); - GBS::PA_ADC_BYPSZ::write(0); - GBS::PA_ADC_BYPSZ::write(1); - delay(2); -} - -void advancePhase() -{ - rto->phaseADC = (rto->phaseADC + 1) & 0x1f; - setAndLatchPhaseADC(); -} - -void movePhaseThroughRange() -{ - for (uint8_t i = 0; i < 128; i++) { // 4x for 4x oversampling? - advancePhase(); - } -} - -void setAndLatchPhaseSP() -{ - GBS::PA_SP_LAT::write(0); // latch off - GBS::PA_SP_S::write(rto->phaseSP); - GBS::PA_SP_LAT::write(1); // latch on -} - -void setAndLatchPhaseADC() -{ - GBS::PA_ADC_LAT::write(0); - GBS::PA_ADC_S::write(rto->phaseADC); - GBS::PA_ADC_LAT::write(1); -} - -void nudgeMD() -{ - GBS::MD_VS_FLIP::write(!GBS::MD_VS_FLIP::read()); - GBS::MD_VS_FLIP::write(!GBS::MD_VS_FLIP::read()); -} - -void updateSpDynamic(boolean withCurrentVideoModeCheck) -{ - if (!rto->boardHasPower || rto->sourceDisconnected) { - return; - } - - uint8_t vidModeReadout = getVideoMode(); - if (vidModeReadout == 0) { - vidModeReadout = getVideoMode(); - } - - if (rto->videoStandardInput == 0 && vidModeReadout == 0) { - if (GBS::SP_DLT_REG::read() > 0x30) - GBS::SP_DLT_REG::write(0x30); // 5_35 - else - GBS::SP_DLT_REG::write(0xC0); - return; - } - // reset condition, allow most formats to detect - // compare 1chip snes and ps2 1080p - if (vidModeReadout == 0 && withCurrentVideoModeCheck) { - if ((rto->noSyncCounter % 16) <= 8 && rto->noSyncCounter != 0) { - GBS::SP_DLT_REG::write(0x30); // 5_35 - } else if ((rto->noSyncCounter % 16) > 8 && rto->noSyncCounter != 0) { - GBS::SP_DLT_REG::write(0xC0); // may want to use lower, around 0x70 - } else { - GBS::SP_DLT_REG::write(0x30); - } - GBS::SP_H_PULSE_IGNOR::write(0x02); - //GBS::SP_DIS_SUB_COAST::write(1); - GBS::SP_H_CST_ST::write(0x10); - GBS::SP_H_CST_SP::write(0x100); - GBS::SP_H_COAST::write(0); // 5_3e 2 (just in case) - GBS::SP_H_TIMER_VAL::write(0x3a); // new: 5_33 default 0x3a, set shorter for better hsync drop detect - if (rto->syncTypeCsync) { - GBS::SP_COAST_INV_REG::write(1); // new, allows SP to see otherwise potentially skipped vlines - } - rto->coastPositionIsSet = false; - return; - } - - if (rto->syncTypeCsync) { - GBS::SP_COAST_INV_REG::write(0); - } - - if (rto->videoStandardInput != 0) { - if (rto->videoStandardInput <= 2) { // SD interlaced - GBS::SP_PRE_COAST::write(7); - GBS::SP_POST_COAST::write(3); - GBS::SP_DLT_REG::write(0xC0); // old: 0x140 works better than 0x130 with psx - GBS::SP_H_TIMER_VAL::write(0x28); // 5_33 - - if (rto->syncTypeCsync) { - uint16_t hPeriod = GBS::HPERIOD_IF::read(); - for (int i = 0; i < 16; i++) { - if (hPeriod == 511 || hPeriod < 200) { - hPeriod = GBS::HPERIOD_IF::read(); // retry / overflow - if (i == 15) { - hPeriod = 300; - break; // give up, use short base to get low ignore value later - } - } else { - break; - } - delayMicroseconds(100); - } - - uint16_t ignoreLength = hPeriod * 0.081f; // hPeriod is base length - if (hPeriod <= 200) { // mode is NTSC / PAL, very likely overflow - ignoreLength = 0x18; // use neutral but low value - } - - // get hpw to ht ratio. stability depends on hpll lock - double ratioHs, ratioHsAverage = 0.0; - uint8_t testOk = 0; - for (int i = 0; i < 30; i++) { - ratioHs = (double)GBS::STATUS_SYNC_PROC_HLOW_LEN::read() / (double)(GBS::STATUS_SYNC_PROC_HTOTAL::read() + 1); - if (ratioHs > 0.041 && ratioHs < 0.152) { // 0.152 : (354 / 2345) is 9.5uS on NTSC (crtemudriver) - testOk++; - ratioHsAverage += ratioHs; - if (testOk == 12) { - ratioHs = ratioHsAverage / testOk; - break; - } - delayMicroseconds(30); - } - } - if (testOk != 12) { - //Serial.print(" testok: "); Serial.println(testOk); - ratioHs = 0.032; // 0.032: (~100 / 2560) is ~2.5uS on NTSC (find with crtemudriver) - } - - //Serial.print(" (debug) hPeriod: "); Serial.println(hPeriod); - //Serial.print(" (debug) ratioHs: "); Serial.println(ratioHs, 5); - //Serial.print(" (debug) ignoreBase: 0x"); Serial.println(ignoreLength,HEX); - uint16_t pllDiv = GBS::PLLAD_MD::read(); - ignoreLength = ignoreLength + (pllDiv * (ratioHs * 0.38)); // for factor: crtemudriver tests - //SerialM.print(" (debug) ign.length: 0x"); SerialM.println(ignoreLength, HEX); - - // > check relies on sync instability (potentially from too large ign. length) getting cought earlier - if (ignoreLength > GBS::SP_H_PULSE_IGNOR::read() || GBS::SP_H_PULSE_IGNOR::read() >= 0x90) { - if (ignoreLength > 0x90) { // if higher, HPERIOD_IF probably was 511 / limit - ignoreLength = 0x90; - } - if (ignoreLength >= 0x1A && ignoreLength <= 0x42) { - ignoreLength = 0x1A; // at the low end should stick to 0x1A - } - if (ignoreLength != GBS::SP_H_PULSE_IGNOR::read()) { - GBS::SP_H_PULSE_IGNOR::write(ignoreLength); - rto->coastPositionIsSet = 0; // mustn't be skipped, needed when input changes dotclock / Hz - SerialM.print(F(" (debug) ign. length: 0x")); - SerialM.println(ignoreLength, HEX); - } - } - } - } else if (rto->videoStandardInput <= 4) { - GBS::SP_PRE_COAST::write(7); // these two were 7 and 6 - GBS::SP_POST_COAST::write(6); // and last 11 and 11 - // 3,3 fixes the ps2 issue but these are too low for format change detects - // update: seems to be an SP bypass only problem (t5t57t6 to 0 also fixes it) - GBS::SP_DLT_REG::write(0xA0); - GBS::SP_H_PULSE_IGNOR::write(0x0E); // ps3: up to 0x3e, ps2: < 0x14 - } else if (rto->videoStandardInput == 5) { // 720p - GBS::SP_PRE_COAST::write(7); // down to 4 ok with ps2 - GBS::SP_POST_COAST::write(7); // down to 6 ok with ps2 // ps3: 8 too much - GBS::SP_DLT_REG::write(0x30); - GBS::SP_H_PULSE_IGNOR::write(0x08); // ps3: 0xd too much - } else if (rto->videoStandardInput <= 7) { // 1080i,p - GBS::SP_PRE_COAST::write(9); - GBS::SP_POST_COAST::write(18); // of 1124 input lines - GBS::SP_DLT_REG::write(0x70); - // ps2 up to 0x06 - // new test shows ps2 alternating between okay and not okay at 0x0a with 5_35=0x70 - GBS::SP_H_PULSE_IGNOR::write(0x06); - } else if (rto->videoStandardInput >= 13) { // 13, 14 and 15 (was just 13 and 15) - if (rto->syncTypeCsync == false) { - GBS::SP_PRE_COAST::write(0x00); - GBS::SP_POST_COAST::write(0x00); - GBS::SP_H_PULSE_IGNOR::write(0xff); // required this because 5_02 0 is on - GBS::SP_DLT_REG::write(0x00); // sometimes enough on it's own, but not always - } else { // csync - GBS::SP_PRE_COAST::write(0x04); // as in bypass mode set function - GBS::SP_POST_COAST::write(0x07); // as in bypass mode set function - GBS::SP_DLT_REG::write(0x70); - GBS::SP_H_PULSE_IGNOR::write(0x02); - } - } - } -} - -void updateCoastPosition(boolean autoCoast) -{ - if (((rto->videoStandardInput == 0) || (rto->videoStandardInput > 14)) || - !rto->boardHasPower || rto->sourceDisconnected) { - return; - } - - uint32_t accInHlength = 0; - uint16_t prevInHlength = GBS::HPERIOD_IF::read(); - for (uint8_t i = 0; i < 8; i++) { - // psx jitters between 427, 428 - uint16_t thisInHlength = GBS::HPERIOD_IF::read(); - if ((thisInHlength > (prevInHlength - 3)) && (thisInHlength < (prevInHlength + 3))) { - accInHlength += thisInHlength; - } else { - return; - } - if (!getStatus16SpHsStable()) { - return; - } - - prevInHlength = thisInHlength; - } - accInHlength = (accInHlength * 4) / 8; - - // 30.09.19 new: especially in low res VGA input modes, it can clip at "511 * 4 = 2044" - // limit to more likely actual value of 430 - if (accInHlength >= 2040) { - accInHlength = 1716; - } - - if (accInHlength <= 240) { - // check for low res, low Hz > can overflow HPERIOD_IF - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() <= 322) { - delay(4); - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() <= 322) { - SerialM.println(F(" (debug) updateCoastPosition: low res, low hz")); - accInHlength = 2000; - // usually need to lower charge pump. todo: write better check - if (rto->syncTypeCsync && rto->videoStandardInput > 0 && rto->videoStandardInput <= 4) { - if (GBS::PLLAD_ICP::read() >= 5 && GBS::PLLAD_FS::read() == 1) { - GBS::PLLAD_ICP::write(5); - GBS::PLLAD_FS::write(0); - latchPLLAD(); - rto->phaseIsSet = 0; - } - } - } - } - } - - // accInHlength around 1732 here / NTSC - // scope on sync-in, enable 5_3e 2 > shows coast borders - if (accInHlength > 32) { - if (autoCoast) { - // autoCoast (5_55 7 = on) - GBS::SP_H_CST_ST::write((uint16_t)(accInHlength * 0.0562f)); // ~0x61, right after color burst - GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.1550f)); // ~0x10C, shortly before sync falling edge - GBS::SP_HCST_AUTO_EN::write(1); - } else { - // test: psx pal black license screen, then ntsc SMPTE color bars 100%; or MS - // scope test psx: t5t11t3, 5_3e = 0x01, 5_36/5_35 = 0x30 5_37 = 0x10 : - // cst sp should be > 0x62b to clean out HS from eq pulses - // cst st should be 0, sp should be 0x69f when t5t57t7 = disabled - //GBS::SP_H_CST_ST::write((uint16_t)(accInHlength * 0.088f)); // ~0x9a, leave some room for SNES 239 mode - // new: with SP_H_PROTECT disabled, even SNES can be a small value. Small value greatly improves Mega Drive - GBS::SP_H_CST_ST::write(0x10); - - GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.968f)); // ~0x678 - // need a bit earlier, making 5_3e 2 more stable - //GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.7383f)); // ~0x4f0, before sync - GBS::SP_HCST_AUTO_EN::write(0); - } - rto->coastPositionIsSet = 1; - - /*Serial.print("coast ST: "); Serial.print("0x"); Serial.print(GBS::SP_H_CST_ST::read(), HEX); - Serial.print(", "); - Serial.print("SP: "); Serial.print("0x"); Serial.print(GBS::SP_H_CST_SP::read(), HEX); - Serial.print(" total: "); Serial.print("0x"); Serial.print(accInHlength, HEX); - Serial.print(" ~ "); Serial.println(accInHlength / 4);*/ - } -} - -void updateClampPosition() -{ - if ((rto->videoStandardInput == 0) || !rto->boardHasPower || rto->sourceDisconnected) { - return; - } - // this is required especially on mode changes with ypbpr - if (getVideoMode() == 0) { - return; - } - - if (rto->inputIsYpBpR) { - GBS::SP_CLAMP_MANUAL::write(0); - } else { - GBS::SP_CLAMP_MANUAL::write(1); // no auto clamp for RGB - } - - // STATUS_SYNC_PROC_HTOTAL is "ht: " value; use with SP_CLP_SRC_SEL = 1 pixel clock - // GBS::HPERIOD_IF::read() is "h: " value; use with SP_CLP_SRC_SEL = 0 osc clock - // update: in RGBHV bypass it seems both clamp source modes use pixel clock for calculation - // but with sog modes, it uses HPERIOD_IF ... k - // update2: if the clamp is already short, yet creeps into active video, check sog invert (t5t20t2) - uint32_t accInHlength = 0; - uint16_t prevInHlength = 0; - uint16_t thisInHlength = 0; - if (rto->syncTypeCsync) - prevInHlength = GBS::HPERIOD_IF::read(); - else - prevInHlength = GBS::STATUS_SYNC_PROC_HTOTAL::read(); - for (uint8_t i = 0; i < 16; i++) { - if (rto->syncTypeCsync) - thisInHlength = GBS::HPERIOD_IF::read(); - else - thisInHlength = GBS::STATUS_SYNC_PROC_HTOTAL::read(); - if ((thisInHlength > (prevInHlength - 3)) && (thisInHlength < (prevInHlength + 3))) { - accInHlength += thisInHlength; - } else { - //Serial.println("updateClampPosition unstable"); - return; - } - if (!getStatus16SpHsStable()) { - return; - } - - prevInHlength = thisInHlength; - delayMicroseconds(100); - } - accInHlength = accInHlength / 16; // for the 16x loop - - // HPERIOD_IF: 9 bits (0-511, represents actual scanline time / 4, can overflow to low values) - // if it overflows, the calculated clamp positions are likely around 1 to 4. good enough - // STATUS_SYNC_PROC_HTOTAL: 12 bits (0-4095) - if (accInHlength > 4095) { - return; - } - - uint16_t oldClampST = GBS::SP_CS_CLP_ST::read(); - uint16_t oldClampSP = GBS::SP_CS_CLP_SP::read(); - float multiSt = rto->syncTypeCsync == 1 ? 0.032f : 0.010f; - float multiSp = rto->syncTypeCsync == 1 ? 0.174f : 0.058f; - uint16_t start = 1 + (accInHlength * multiSt); // HPERIOD_IF: *0.04 seems good - uint16_t stop = 2 + (accInHlength * multiSp); // HPERIOD_IF: *0.178 starts to creep into some EDTV modes - - if (rto->inputIsYpBpR) { - // YUV: // ST shift forward to pass blacker than black HSync, sog: min * 0.08 - multiSt = rto->syncTypeCsync == 1 ? 0.089f : 0.032f; - start = 1 + (accInHlength * multiSt); - - // new: HDBypass rewrite to sync to falling HS edge: move clamp position forward - // RGB can stay the same for now (clamp will start on sync pulse, a benefit in RGB - if (rto->outModeHdBypass) { - if (videoStandardInputIsPalNtscSd()) { - start += 0x60; - stop += 0x60; - } - // raise blank level a bit that's not handled 100% by clamping - GBS::HD_BLK_GY_DATA::write(0x05); - GBS::HD_BLK_BU_DATA::write(0x00); - GBS::HD_BLK_RV_DATA::write(0x00); - } - } - - if ((start < (oldClampST - 1) || start > (oldClampST + 1)) || - (stop < (oldClampSP - 1) || stop > (oldClampSP + 1))) { - GBS::SP_CS_CLP_ST::write(start); - GBS::SP_CS_CLP_SP::write(stop); - /*Serial.print("clamp ST: "); Serial.print("0x"); Serial.print(start, HEX); - Serial.print(", "); - Serial.print("SP: "); Serial.print("0x"); Serial.print(stop, HEX); - Serial.print(" total: "); Serial.print("0x"); Serial.print(accInHlength, HEX); - Serial.print(" / "); Serial.println(accInHlength);*/ - } - - rto->clampPositionIsSet = true; -} - -// use t5t00t2 and adjust t5t11t5 to find this sources ideal sampling clock for this preset (affected by htotal) -// 2431 for psx, 2437 for MD -// in this mode, sampling clock is free to choose -void setOutModeHdBypass(bool regsInitialized) -{ - if (!rto->boardHasPower) { - SerialM.println(F("GBS board not responding!")); - return; - } - - rto->autoBestHtotalEnabled = false; // disable while in this mode - rto->outModeHdBypass = 1; // skips waiting at end of doPostPresetLoadSteps - - externalClockGenResetClock(); - updateSpDynamic(0); - loadHdBypassSection(); // this would be ignored otherwise - if (GBS::ADC_UNUSED_62::read() != 0x00) { - // remember debug view - if (uopt->presetPreference != 2) { - serialCommand = 'D'; - } - } - - GBS::SP_NO_COAST_REG::write(0); // enable vblank coast (just in case) - GBS::SP_COAST_INV_REG::write(0); // also just in case - - FrameSync::cleanup(); - GBS::ADC_UNUSED_62::write(0x00); // clear debug view - GBS::RESET_CONTROL_0x46::write(0x00); // 0_46 all off, nothing needs to be enabled for bp mode - GBS::RESET_CONTROL_0x47::write(0x00); - GBS::PA_ADC_BYPSZ::write(1); // enable phase unit ADC - GBS::PA_SP_BYPSZ::write(1); // enable phase unit SP - - GBS::GBS_PRESET_ID::write(PresetHdBypass); - // If loading from top-level, clear custom preset flag to avoid stale - // values. If loading after applyPresets() called writeProgramArrayNew(), it - // has already set the flag to 1. - if (!regsInitialized) { - GBS::GBS_PRESET_CUSTOM::write(0); - } - doPostPresetLoadSteps(); // todo: remove this, code path for hdbypass is hard to follow - - // doPostPresetLoadSteps() sets rto->presetID = GBS_PRESET_ID::read() = - // PresetHdBypass, and rto->isCustomPreset = GBS_PRESET_CUSTOM::read(). - - resetDebugPort(); - - rto->autoBestHtotalEnabled = false; // need to re-set this - GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP, 0 = sync from VDS - - GBS::PLL_CKIS::write(0); // 0_40 0 // 0: PLL uses OSC clock | 1: PLL uses input clock - GBS::PLL_DIVBY2Z::write(0); // 0_40 1 // 1= no divider (full clock, ie 27Mhz) 0 = halved - //GBS::PLL_ADS::write(0); // 0_40 3 test: input clock is from PCLKIN (disconnected, not ADC clock) - GBS::PAD_OSC_CNTRL::write(1); // test: noticed some wave pattern in 720p source, this fixed it - GBS::PLL648_CONTROL_01::write(0x35); - GBS::PLL648_CONTROL_03::write(0x00); - GBS::PLL_LEN::write(1); // 0_43 - GBS::DAC_RGBS_R0ENZ::write(1); - GBS::DAC_RGBS_G0ENZ::write(1); // 0_44 - GBS::DAC_RGBS_B0ENZ::write(1); - GBS::DAC_RGBS_S1EN::write(1); // 0_45 - // from RGBHV tests: the memory bus can be tri stated for noise reduction - GBS::PAD_TRI_ENZ::write(1); // enable tri state - GBS::PLL_MS::write(2); // select feedback clock (but need to enable tri state!) - GBS::MEM_PAD_CLK_INVERT::write(0); // helps also - GBS::RESET_CONTROL_0x47::write(0x1f); - - // update: found the real use of HDBypass :D - GBS::DAC_RGBS_BYPS2DAC::write(1); - GBS::SP_HS_LOOP_SEL::write(1); - GBS::SP_HS_PROC_INV_REG::write(0); // (5_56_5) do not invert HS - GBS::SP_CS_P_SWAP::write(0); // old default, set here to reset between HDBypass formats - GBS::SP_HS2PLL_INV_REG::write(0); // same - - GBS::PB_BYPASS::write(1); - GBS::PLLAD_MD::write(2345); // 2326 looks "better" on my LCD but 2345 looks just correct on scope - GBS::PLLAD_KS::write(2); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz - setOverSampleRatio(2, true); - GBS::PLLAD_ICP::write(5); - GBS::PLLAD_FS::write(1); - - if (rto->inputIsYpBpR) { - GBS::DEC_MATRIX_BYPS::write(1); // 5_1f 2 = 1 for YUV / 0 for RGB - GBS::HD_MATRIX_BYPS::write(0); // 1_30 1 / input to jacks is yuv, adc leaves it as yuv > convert to rgb for output here - GBS::HD_DYN_BYPS::write(0); // don't bypass color expansion - //GBS::HD_U_OFFSET::write(3); // color adjust via scope - //GBS::HD_V_OFFSET::write(3); // color adjust via scope - } else { - GBS::DEC_MATRIX_BYPS::write(1); // this is normally RGB input for HDBYPASS out > no color matrix at all - GBS::HD_MATRIX_BYPS::write(1); // 1_30 1 / input is rgb, adc leaves it as rgb > bypass matrix - GBS::HD_DYN_BYPS::write(1); // bypass as well - } - - GBS::HD_SEL_BLK_IN::write(0); // 0 enables HDB blank timing (1 would be DVI, not working atm) - - GBS::SP_SDCS_VSST_REG_H::write(0); // S5_3B - GBS::SP_SDCS_VSSP_REG_H::write(0); // S5_3B - GBS::SP_SDCS_VSST_REG_L::write(0); // S5_3F // 3 for SP sync - GBS::SP_SDCS_VSSP_REG_L::write(2); // S5_40 // 10 for SP sync // check with interlaced sources - - GBS::HD_HSYNC_RST::write(0x3ff); // max 0x7ff - GBS::HD_INI_ST::write(0); // todo: test this at 0 / was 0x298 - // timing into HDB is PLLAD_MD with PLLAD_KS divider: KS = 0 > full PLLAD_MD - if (rto->videoStandardInput <= 2) { - // PAL and NTSC are rewrites, the rest is still handled normally - // These 2 formats now have SP_HS2PLL_INV_REG set. That's the only way I know so far that - // produces recovered HSyncs that align to the falling edge of the input - // ToDo: find reliable input active flank detect to then set SP_HS2PLL_INV_REG correctly - // (for PAL/NTSC polarity is known to be active low, but other formats are variable) - GBS::SP_HS2PLL_INV_REG::write(1); //5_56 1 lock to falling HS edge // check > sync issues with MD - GBS::SP_CS_P_SWAP::write(1); //5_3e 0 new: this should negate the problem with inverting HS2PLL - GBS::SP_HS_PROC_INV_REG::write(1); // (5_56_5) invert HS to DEC - // invert mode detect HS/VS triggers, helps PSX NTSC detection. required with 5_3e 0 set - GBS::MD_HS_FLIP::write(1); - GBS::MD_VS_FLIP::write(1); - GBS::OUT_SYNC_SEL::write(2); // new: 0_4f 1=sync from HDBypass, 2=sync from SP, 0 = sync from VDS - GBS::SP_HS_LOOP_SEL::write(0); // 5_57 6 new: use full SP sync, enable HS positioning and pulse length control - GBS::ADC_FLTR::write(3); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - //GBS::HD_INI_ST::write(0x76); // 1_39 - - GBS::HD_HSYNC_RST::write((GBS::PLLAD_MD::read() / 2) + 8); // ADC output pixel count determined - GBS::HD_HB_ST::write(GBS::PLLAD_MD::read() * 0.945f); // 1_3B // no idea why it's not coupled to HD_RST - GBS::HD_HB_SP::write(0x90); // 1_3D - GBS::HD_HS_ST::write(0x80); // 1_3F // but better to use SP sync directly (OUT_SYNC_SEL = 2) - GBS::HD_HS_SP::write(0x00); // 1_41 // - // to use SP sync directly; prepare reasonable out HS length - GBS::SP_CS_HS_ST::write(0xA0); - GBS::SP_CS_HS_SP::write(0x00); - - if (rto->videoStandardInput == 1) { - setCsVsStart(250); // don't invert VS with direct SP sync mode - setCsVsStop(1); // stop relates to HS pulses from CS decoder directly, so mind EQ pulses - GBS::HD_VB_ST::write(500); // 1_43 - GBS::HD_VS_ST::write(3); // 1_47 // but better to use SP sync directly (OUT_SYNC_SEL = 2) - GBS::HD_VS_SP::write(522); // 1_49 // - GBS::HD_VB_SP::write(16); // 1_45 - } - if (rto->videoStandardInput == 2) { - setCsVsStart(301); // don't invert - setCsVsStop(5); // stop past EQ pulses (6 on psx) normally, but HDMI adapter works with -=1 (5) - GBS::HD_VB_ST::write(605); // 1_43 - GBS::HD_VS_ST::write(1); // 1_47 - GBS::HD_VS_SP::write(621); // 1_49 - GBS::HD_VB_SP::write(16); // 1_45 - } - } else if (rto->videoStandardInput == 3 || rto->videoStandardInput == 4) { // 480p, 576p - GBS::ADC_FLTR::write(2); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - GBS::PLLAD_KS::write(1); // 5_16 post divider - GBS::PLLAD_CKOS::write(0); // 5_16 2x OS (with KS=1) - //GBS::HD_INI_ST::write(0x76); // 1_39 - GBS::HD_HB_ST::write(0x864); // 1_3B - // you *must* begin hblank before hsync. - GBS::HD_HB_SP::write(0xa0); // 1_3D - GBS::HD_VB_ST::write(0x00); // 1_43 - GBS::HD_VB_SP::write(0x40); // 1_45 - if (rto->videoStandardInput == 3) { - GBS::HD_HS_ST::write(0x54); // 1_3F - GBS::HD_HS_SP::write(0x864); // 1_41 - GBS::HD_VS_ST::write(0x06); // 1_47 // VS neg - GBS::HD_VS_SP::write(0x00); // 1_49 - setCsVsStart(525 - 5); - setCsVsStop(525 - 3); - } - if (rto->videoStandardInput == 4) { - GBS::HD_HS_ST::write(0x10); // 1_3F - GBS::HD_HS_SP::write(0x880); // 1_41 - GBS::HD_VS_ST::write(0x06); // 1_47 // VS neg - GBS::HD_VS_SP::write(0x00); // 1_49 - setCsVsStart(48); - setCsVsStop(46); - } - } else if (rto->videoStandardInput <= 7 || rto->videoStandardInput == 13) { - //GBS::SP_HS2PLL_INV_REG::write(0); // 5_56 1 use rising edge of tri-level sync // always 0 now - if (rto->videoStandardInput == 5) { // 720p - GBS::PLLAD_MD::write(2474); // override from 2345 - GBS::HD_HSYNC_RST::write(550); // 1_37 - //GBS::HD_INI_ST::write(78); // 1_39 - // 720p has high pllad vco output clock, so don't do oversampling - GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz - GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) - GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) - GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) - GBS::PLLAD_ICP::write(6); // fine at 6 only, FS is 1 - GBS::PLLAD_FS::write(1); - GBS::HD_HB_ST::write(0); // 1_3B - GBS::HD_HB_SP::write(0x140); // 1_3D - GBS::HD_HS_ST::write(0x20); // 1_3F - GBS::HD_HS_SP::write(0x80); // 1_41 - GBS::HD_VB_ST::write(0x00); // 1_43 - GBS::HD_VB_SP::write(0x6c); // 1_45 // ps3 720p tested - GBS::HD_VS_ST::write(0x00); // 1_47 - GBS::HD_VS_SP::write(0x05); // 1_49 - setCsVsStart(2); - setCsVsStop(0); - } - if (rto->videoStandardInput == 6) { // 1080i - // interl. source - GBS::HD_HSYNC_RST::write(0x710); // 1_37 - //GBS::HD_INI_ST::write(2); // 1_39 - GBS::PLLAD_KS::write(1); // 5_16 post divider - GBS::PLLAD_CKOS::write(0); // 5_16 2x OS (with KS=1) - GBS::ADC_FLTR::write(1); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - GBS::HD_HB_ST::write(0); // 1_3B - GBS::HD_HB_SP::write(0xb8); // 1_3D - GBS::HD_HS_ST::write(0x04); // 1_3F - GBS::HD_HS_SP::write(0x50); // 1_41 - GBS::HD_VB_ST::write(0x00); // 1_43 - GBS::HD_VB_SP::write(0x1e); // 1_45 - GBS::HD_VS_ST::write(0x04); // 1_47 - GBS::HD_VS_SP::write(0x09); // 1_49 - setCsVsStart(8); - setCsVsStop(6); - } - if (rto->videoStandardInput == 7) { // 1080p - GBS::PLLAD_MD::write(2749); // override from 2345 - GBS::HD_HSYNC_RST::write(0x710); // 1_37 - //GBS::HD_INI_ST::write(0xf0); // 1_39 - // 1080p has highest pllad vco output clock, so don't do oversampling - GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz - GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) - GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) - GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) - GBS::PLLAD_ICP::write(6); // was 5, fine at 6 as well, FS is 1 - GBS::PLLAD_FS::write(1); - GBS::HD_HB_ST::write(0x00); // 1_3B - GBS::HD_HB_SP::write(0xb0); // 1_3D // d0 - GBS::HD_HS_ST::write(0x20); // 1_3F - GBS::HD_HS_SP::write(0x70); // 1_41 - GBS::HD_VB_ST::write(0x00); // 1_43 - GBS::HD_VB_SP::write(0x2f); // 1_45 - GBS::HD_VS_ST::write(0x04); // 1_47 - GBS::HD_VS_SP::write(0x0A); // 1_49 - } - if (rto->videoStandardInput == 13) { // odd HD mode (PS2 "VGA" over Component) - applyRGBPatches(); // treat mostly as RGB, clamp R/B to gnd - rto->syncTypeCsync = true; // used in loop to set clamps and SP dynamic - GBS::DEC_MATRIX_BYPS::write(1); // overwrite for this mode - GBS::SP_PRE_COAST::write(4); - GBS::SP_POST_COAST::write(4); - GBS::SP_DLT_REG::write(0x70); - GBS::HD_MATRIX_BYPS::write(1); // bypass since we'll treat source as RGB - GBS::HD_DYN_BYPS::write(1); // bypass since we'll treat source as RGB - GBS::SP_VS_PROC_INV_REG::write(0); // don't invert - // same as with RGBHV, the ps2 resolution can vary widely - GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz - GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) - GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) - GBS::ADC_CLK_ICLK2X::write(0); // 5_00 3 (OS=1) - GBS::DEC1_BYPS::write(1); // 5_1f 1 // dec1 disabled (OS=1) - GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) - GBS::PLLAD_MD::write(512); // could try 856 - } - } - - if (rto->videoStandardInput == 13) { - // section is missing HD_HSYNC_RST and HD_INI_ST adjusts - uint16_t vtotal = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - if (vtotal < 532) { // 640x480 or less - GBS::PLLAD_KS::write(3); - GBS::PLLAD_FS::write(1); - } else if (vtotal >= 532 && vtotal < 810) { // 800x600, 1024x768 - //GBS::PLLAD_KS::write(3); // just a little too much at 1024x768 - GBS::PLLAD_FS::write(0); - GBS::PLLAD_KS::write(2); - } else { //if (vtotal > 1058 && vtotal < 1074) { // 1280x1024 - GBS::PLLAD_KS::write(2); - GBS::PLLAD_FS::write(1); - } - } - - GBS::DEC_IDREG_EN::write(1); // 5_1f 7 - GBS::DEC_WEN_MODE::write(1); // 5_1e 7 // 1 keeps ADC phase consistent. around 4 lock positions vs totally random - rto->phaseSP = 8; - rto->phaseADC = 24; // fix value // works best with yuv input in tests - setAndUpdateSogLevel(rto->currentLevelSOG); // also re-latch everything - - rto->outModeHdBypass = 1; - - unsigned long timeout = millis(); - while ((!getStatus16SpHsStable()) && (millis() - timeout < 2002)) { - delay(1); - } - while ((getVideoMode() == 0) && (millis() - timeout < 1502)) { - delay(1); - } - // currently SP is using generic settings, switch to format specific ones - updateSpDynamic(0); - while ((getVideoMode() == 0) && (millis() - timeout < 1502)) { - delay(1); - } - - GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out - delay(200); - optimizePhaseSP(); - SerialM.println(F("pass-through on")); -} - -void bypassModeSwitch_RGBHV() -{ - if (!rto->boardHasPower) { - SerialM.println(F("GBS board not responding!")); - return; - } - - GBS::DAC_RGBS_PWDNZ::write(0); // disable DAC - GBS::PAD_SYNC_OUT_ENZ::write(1); // disable sync out - - loadHdBypassSection(); - externalClockGenResetClock(); - FrameSync::cleanup(); - GBS::ADC_UNUSED_62::write(0x00); // clear debug view - GBS::PA_ADC_BYPSZ::write(1); // enable phase unit ADC - GBS::PA_SP_BYPSZ::write(1); // enable phase unit SP - applyRGBPatches(); - resetDebugPort(); - rto->videoStandardInput = 15; // making sure - rto->autoBestHtotalEnabled = false; // not necessary, since VDS is off / bypassed // todo: mode 14 (works anyway) - rto->clampPositionIsSet = false; - rto->HPLLState = 0; - - GBS::PLL_CKIS::write(0); // 0_40 0 // 0: PLL uses OSC clock | 1: PLL uses input clock - GBS::PLL_DIVBY2Z::write(0); // 0_40 1 // 1= no divider (full clock, ie 27Mhz) 0 = halved clock - GBS::PLL_ADS::write(0); // 0_40 3 test: input clock is from PCLKIN (disconnected, not ADC clock) - GBS::PLL_MS::write(2); // 0_40 4-6 select feedback clock (but need to enable tri state!) - GBS::PAD_TRI_ENZ::write(1); // enable some pad's tri state (they become high-z / inputs), helps noise - GBS::MEM_PAD_CLK_INVERT::write(0); // helps also - GBS::PLL648_CONTROL_01::write(0x35); - GBS::PLL648_CONTROL_03::write(0x00); // 0_43 - GBS::PLL_LEN::write(1); // 0_43 - - GBS::DAC_RGBS_ADC2DAC::write(1); - GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP, (00 = from VDS) - - GBS::SFTRST_HDBYPS_RSTZ::write(1); // enable - GBS::HD_INI_ST::write(0); // needs to be some small value or apparently 0 works - //GBS::DAC_RGBS_BYPS2DAC::write(1); - //GBS::OUT_SYNC_SEL::write(2); // 0_4f sync from SP - //GBS::SFTRST_HDBYPS_RSTZ::write(1); // need HDBypass - //GBS::SP_HS_LOOP_SEL::write(1); // (5_57_6) // can bypass since HDBypass does sync - GBS::HD_MATRIX_BYPS::write(1); // bypass since we'll treat source as RGB - GBS::HD_DYN_BYPS::write(1); // bypass since we'll treat source as RGB - //GBS::HD_SEL_BLK_IN::write(1); // "DVI", not regular - - GBS::PAD_SYNC1_IN_ENZ::write(0); // filter H/V sync input1 (0 = on) - GBS::PAD_SYNC2_IN_ENZ::write(0); // filter H/V sync input2 (0 = on) - - GBS::SP_SOG_P_ATO::write(1); // 5_20 1 corrects hpw readout and slightly affects sync - if (rto->syncTypeCsync == false) { - GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: from hs // use ADC and turn it off = no SOG - GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG // having it 0 drags down the SOG (hsync) input; = 1: need to supress SOG decoding - GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) - GBS::SP_SOG_MODE::write(0); // 5_56 bit 0 // 0: normal, 1: SOG - GBS::SP_NO_COAST_REG::write(1); // vblank coasting off - GBS::SP_PRE_COAST::write(0); - GBS::SP_POST_COAST::write(0); - GBS::SP_H_PULSE_IGNOR::write(0xff); // cancel out SOG decoding - GBS::SP_SYNC_BYPS::write(0); // external H+V sync for decimator (+ sync out) | 1 to mirror in sync, 0 to output processed sync - GBS::SP_HS_POL_ATO::write(1); // 5_55 4 auto polarity for retiming - GBS::SP_VS_POL_ATO::write(1); // 5_55 6 - GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS - GBS::SP_H_PROTECT::write(0); // 5_3e 4 disable for H/V - rto->phaseADC = 16; - rto->phaseSP = 8; - } else { - // todo: SOG SRC can be ADC or HS input pin. HS requires TTL level, ADC can use lower levels - // HS seems to have issues at low PLL speeds - // maybe add detection whether ADC Sync is needed - GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: hs is sog source - GBS::SP_EXT_SYNC_SEL::write(1); // disconnect HV input - GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG - GBS::SP_SOG_MODE::write(1); // apparently needs to be off for HS input (on for ADC) - GBS::SP_NO_COAST_REG::write(0); // vblank coasting on - GBS::SP_PRE_COAST::write(4); // 5_38, > 4 can be seen with clamp invert on the lower lines - GBS::SP_POST_COAST::write(7); - GBS::SP_SYNC_BYPS::write(0); // use regular sync for decimator (and sync out) path - GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS - GBS::SP_H_PROTECT::write(1); // 5_3e 4 enable for SOG - rto->currentLevelSOG = 24; - rto->phaseADC = 16; - rto->phaseSP = 8; - } - GBS::SP_CLAMP_MANUAL::write(1); // needs to be 1 - GBS::SP_COAST_INV_REG::write(0); // just in case - - GBS::SP_DIS_SUB_COAST::write(1); // 5_3e 5 - GBS::SP_HS_PROC_INV_REG::write(0); // 5_56 5 - GBS::SP_VS_PROC_INV_REG::write(0); // 5_56 6 - GBS::PLLAD_KS::write(1); // 0 - 3 - setOverSampleRatio(2, true); // prepare only = true - GBS::DEC_MATRIX_BYPS::write(1); // 5_1f with adc to dac mode - GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz - - GBS::PLLAD_ICP::write(4); - GBS::PLLAD_FS::write(0); // low gain - GBS::PLLAD_MD::write(1856); // 1349 perfect for for 1280x+ ; 1856 allows lower res to detect - - // T4R0x2B Bit: 3 (was 0x7) is now: 0xF - // S0R0x4F (was 0x80) is now: 0xBC - // 0_43 1a - // S5R0x2 (was 0x48) is now: 0x54 - // s5s11sb2 - //0x25, // s0_44 - //0x11, // s0_45 - // new: do without running default preset first - GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 1 // minor SOG clamp effect - GBS::ADC_TEST_04::write(0x02); // 5_04 - GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 - GBS::DAC_RGBS_R0ENZ::write(1); - GBS::DAC_RGBS_G0ENZ::write(1); - GBS::DAC_RGBS_B0ENZ::write(1); - GBS::OUT_SYNC_CNTRL::write(1); - //resetPLL(); // try to avoid this - resetDigital(); // this will leave 0_46 all 0 - resetSyncProcessor(); // required to initialize SOG status - delay(2); - ResetSDRAM(); - delay(2); - resetPLLAD(); - togglePhaseAdjustUnits(); - delay(20); - GBS::PLLAD_LEN::write(1); // 5_11 1 - GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out - - // todo: detect if H-PLL parameters fit the source before aligning clocks (5_11 etc) - - setAndLatchPhaseSP(); // different for CSync and pure HV modes - setAndLatchPhaseADC(); - latchPLLAD(); - - if (uopt->enableAutoGain == 1 && adco->r_gain == 0) { - //SerialM.println("ADC gain: reset"); - setAdcGain(AUTO_GAIN_INIT); - GBS::DEC_TEST_ENABLE::write(1); - } else if (uopt->enableAutoGain == 1 && adco->r_gain != 0) { - /*SerialM.println("ADC gain: keep previous"); - SerialM.print(adco->r_gain, HEX); SerialM.print(" "); - SerialM.print(adco->g_gain, HEX); SerialM.print(" "); - SerialM.print(adco->b_gain, HEX); SerialM.println(" ");*/ - GBS::ADC_RGCTRL::write(adco->r_gain); - GBS::ADC_GGCTRL::write(adco->g_gain); - GBS::ADC_BGCTRL::write(adco->b_gain); - GBS::DEC_TEST_ENABLE::write(1); - } else { - GBS::DEC_TEST_ENABLE::write(0); // no need for decimation test to be enabled - } - - rto->presetID = PresetBypassRGBHV; // bypass flavor 2, used to signal buttons in web ui - GBS::GBS_PRESET_ID::write(PresetBypassRGBHV); - delay(200); -} - -void runAutoGain() -{ - static unsigned long lastTimeAutoGain = millis(); - uint8_t limit_found = 0, greenValue = 0; - uint8_t loopCeiling = 0; - uint8_t status00reg = GBS::STATUS_00::read(); // confirm no mode changes happened - - //GBS::DEC_TEST_SEL::write(5); - - //for (uint8_t i = 0; i < 14; i++) { - // uint8_t greenValue = GBS::TEST_BUS_2E::read(); - // if (greenValue >= 0x28 && greenValue <= 0x2f) { // 0x2c seems to be "highest" (haven't seen 0x2b yet) - // if (getStatus16SpHsStable() && (GBS::STATUS_00::read() == status00reg)) { - // limit_found++; - // } - // else return; - // } - //} - - if ((millis() - lastTimeAutoGain) < 30000) { - loopCeiling = 61; - } else { - loopCeiling = 8; - } - - for (uint8_t i = 0; i < loopCeiling; i++) { - if (i % 20 == 0) { - handleWiFi(0); - limit_found = 0; - } - greenValue = GBS::TEST_BUS_2F::read(); - - if (greenValue == 0x7f) { - if (getStatus16SpHsStable() && (GBS::STATUS_00::read() == status00reg)) { - limit_found++; - // 240p test suite (SNES ver): display vertical lines (hor. line test) - //Serial.print("g: "); Serial.println(greenValue, HEX); - //Serial.print("--"); Serial.println(); - } else - return; - - if (limit_found == 2) { - limit_found = 0; - uint8_t level = GBS::ADC_GGCTRL::read(); - if (level < 0xfe) { - setAdcGain(level + 2); - - // remember these gain settings - adco->r_gain = GBS::ADC_RGCTRL::read(); - adco->g_gain = GBS::ADC_GGCTRL::read(); - adco->b_gain = GBS::ADC_BGCTRL::read(); - - printInfo(); - delay(2); // let it settle a little - lastTimeAutoGain = millis(); - } - } - } - } -} - -void enableScanlines() -{ - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 0) { - //SerialM.println("enableScanlines())"); - - //GBS::RFF_ADR_ADD_2::write(0); - //GBS::RFF_REQ_SEL::write(1); - //GBS::RFF_MASTER_FLAG::write(0x3f); - //GBS::RFF_WFF_OFFSET::write(0); // scanline fix - //GBS::RFF_FETCH_NUM::write(0); - //GBS::RFF_ENABLE::write(1); //GBS::WFF_ENABLE::write(1); - //delay(10); - //GBS::RFF_ENABLE::write(0); //GBS::WFF_ENABLE::write(0); - - // following lines set up UV deinterlacer (on top of normal Y) - GBS::MADPT_UVDLY_PD_SP::write(0); // 2_39 0..3 - GBS::MADPT_UVDLY_PD_ST::write(0); // 2_39 4..7 - GBS::MADPT_EN_UV_DEINT::write(1); // 2_3a 0 - GBS::MADPT_UV_MI_DET_BYPS::write(1); // 2_3a 7 enables 2_3b adjust - GBS::MADPT_UV_MI_OFFSET::write(uopt->scanlineStrength); // 2_3b offset (mixing factor here) - GBS::MADPT_MO_ADP_UV_EN::write(1); // 2_16 5 (try to do this some other way?) - - GBS::DIAG_BOB_PLDY_RAM_BYPS::write(0); // 2_00 7 enabled, looks better - GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 - GBS::RFF_YUV_DEINTERLACE::write(1); // scanline fix 2 - GBS::MADPT_Y_MI_DET_BYPS::write(1); // make sure, so that mixing works - //GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() + 0x30); // more luma gain - //GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 4); - GBS::VDS_WLEV_GAIN::write(0x08); // 3_58 - GBS::VDS_W_LEV_BYPS::write(0); // brightness - GBS::MADPT_VIIR_COEF::write(0x08); // 2_27 VIIR filter strength - GBS::MADPT_Y_MI_OFFSET::write(uopt->scanlineStrength); // 2_0b offset (mixing factor here) - GBS::MADPT_VIIR_BYPS::write(0); // 2_26 6 VIIR line fifo // 1 = off - GBS::RFF_LINE_FLIP::write(1); // clears potential garbage in rff buffer - - GBS::MAPDT_VT_SEL_PRGV::write(0); - GBS::GBS_OPTION_SCANLINES_ENABLED::write(1); - } - rto->scanlinesEnabled = 1; -} - -void disableScanlines() -{ - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { - //SerialM.println("disableScanlines())"); - GBS::MAPDT_VT_SEL_PRGV::write(1); - - // following lines set up UV deinterlacer (on top of normal Y) - GBS::MADPT_UVDLY_PD_SP::write(4); // 2_39 0..3 - GBS::MADPT_UVDLY_PD_ST::write(4); // 2_39 4..77 - GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 - GBS::MADPT_UV_MI_DET_BYPS::write(0); // 2_3a 7 enables 2_3b adjust - GBS::MADPT_UV_MI_OFFSET::write(4); // 2_3b - GBS::MADPT_MO_ADP_UV_EN::write(0); // 2_16 5 - - GBS::DIAG_BOB_PLDY_RAM_BYPS::write(1); // 2_00 7 - GBS::VDS_W_LEV_BYPS::write(1); // brightness - //GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() - 0x30); - //GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() - 4); - GBS::MADPT_Y_MI_OFFSET::write(0xff); // 2_0b offset 0xff disables mixing - GBS::MADPT_VIIR_BYPS::write(1); // 2_26 6 disable VIIR - GBS::MADPT_PD_RAM_BYPS::write(1); - GBS::RFF_LINE_FLIP::write(0); // back to default - - GBS::GBS_OPTION_SCANLINES_ENABLED::write(0); - } - rto->scanlinesEnabled = 0; -} - -void enableMotionAdaptDeinterlace() -{ - freezeVideo(); - GBS::DEINT_00::write(0x19); // 2_00 // bypass angular (else 0x00) - GBS::MADPT_Y_MI_OFFSET::write(0x00); // 2_0b // also used for scanline mixing - //GBS::MADPT_STILL_NOISE_EST_EN::write(1); // 2_0A 5 (was 0 before) - GBS::MADPT_Y_MI_DET_BYPS::write(0); //2_0a_7 // switch to automatic motion indexing - //GBS::MADPT_UVDLY_PD_BYPS::write(0); // 2_35_5 // UVDLY - //GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 - //GBS::MADPT_EN_STILL_FOR_NRD::write(1); // 2_3a 3 (new) - - if (rto->videoStandardInput == 1) - GBS::MADPT_VTAP2_COEFF::write(6); // 2_19 vertical filter - if (rto->videoStandardInput == 2) - GBS::MADPT_VTAP2_COEFF::write(4); - - //GBS::RFF_WFF_STA_ADDR_A::write(0); - //GBS::RFF_WFF_STA_ADDR_B::write(1); - GBS::RFF_ADR_ADD_2::write(1); - GBS::RFF_REQ_SEL::write(3); - //GBS::RFF_MASTER_FLAG::write(0x24); // use preset's value - //GBS::WFF_SAFE_GUARD::write(0); // 4_42 3 - GBS::RFF_FETCH_NUM::write(0x80); // part of RFF disable fix, could leave 0x80 always otherwise - GBS::RFF_WFF_OFFSET::write(0x100); // scanline fix - GBS::RFF_YUV_DEINTERLACE::write(0); // scanline fix 2 - GBS::WFF_FF_STA_INV::write(0); // 4_42_2 // 22.03.19 : turned off // update: only required in PAL? - //GBS::WFF_LINE_FLIP::write(0); // 4_4a_4 // 22.03.19 : turned off // update: only required in PAL? - GBS::WFF_ENABLE::write(1); // 4_42 0 // enable before RFF - GBS::RFF_ENABLE::write(1); // 4_4d 7 - //delay(60); // 55 first good - unfreezeVideo(); - delay(60); - GBS::MAPDT_VT_SEL_PRGV::write(0); // 2_16_7 - rto->motionAdaptiveDeinterlaceActive = true; -} - -void disableMotionAdaptDeinterlace() -{ - GBS::MAPDT_VT_SEL_PRGV::write(1); // 2_16_7 - GBS::DEINT_00::write(0xff); // 2_00 - - GBS::RFF_FETCH_NUM::write(0x1); // RFF disable fix - GBS::RFF_WFF_OFFSET::write(0x1); // RFF disable fix - delay(2); - GBS::WFF_ENABLE::write(0); - GBS::RFF_ENABLE::write(0); // can cause mem reset requirement, procedure above should fix it - - //GBS::WFF_ADR_ADD_2::write(0); - GBS::WFF_FF_STA_INV::write(1); // 22.03.19 : turned off // update: only required in PAL? - //GBS::WFF_LINE_FLIP::write(1); // 22.03.19 : turned off // update: only required in PAL? - GBS::MADPT_Y_MI_OFFSET::write(0x7f); - //GBS::MADPT_STILL_NOISE_EST_EN::write(0); // new - GBS::MADPT_Y_MI_DET_BYPS::write(1); - //GBS::MADPT_UVDLY_PD_BYPS::write(1); // 2_35_5 - //GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 - //GBS::MADPT_EN_STILL_FOR_NRD::write(0); // 2_3a 3 (new) - rto->motionAdaptiveDeinterlaceActive = false; -} - -boolean snapToIntegralFrameRate(void) -{ - - // Fetch the current output frame rate - float ofr = getOutputFrameRate(); - - if (ofr < 1.0f) { - delay(1); - ofr = getOutputFrameRate(); - } - - float target; - if (ofr > 56.5f && ofr < 64.5f) { - target = 60.0f; // NTSC like - } else if (ofr > 46.5f && ofr < 54.5f) { - target = 50.0f; // PAL like - } else { - // too far out of spec for an auto adjust - SerialM.println(F("out of bounds")); - return false; - } - - SerialM.print(F("Snap to ")); - SerialM.print(target, 1); // precission 1 - SerialM.println("Hz"); - - // We'll be adjusting the htotal incrementally, so store current and best match. - uint16_t currentHTotal = GBS::VDS_HSYNC_RST::read(); - uint16_t closestHTotal = currentHTotal; - - // What's the closest we've been to the frame rate? - float closestDifference = fabs(target - ofr); - - // Repeatedly adjust htotals until we find the closest match. - for (;;) { - - delay(0); - - // Try to move closer to the desired framerate. - if (target > ofr) { - if (currentHTotal > 0 && applyBestHTotal(currentHTotal - 1)) { - --currentHTotal; - } else { - return false; - } - } else if (target < ofr) { - if (currentHTotal < 4095 && applyBestHTotal(currentHTotal + 1)) { - ++currentHTotal; - } else { - return false; - } - } else { - return true; - } - - // Are we closer? - ofr = getOutputFrameRate(); - - if (ofr < 1.0f) { - delay(1); - ofr = getOutputFrameRate(); - } - if (ofr < 1.0f) { - return false; - } - - // If we're getting closer, continue trying, otherwise break out of the test loop. - float newDifference = fabs(target - ofr); - if (newDifference < closestDifference) { - closestDifference = newDifference; - closestHTotal = currentHTotal; - } else { - break; - } - } - - // Reapply the closest htotal if need be. - if (closestHTotal != currentHTotal) { - applyBestHTotal(closestHTotal); - } - - return true; -} - -void printInfo() -{ - static char print[121]; // Increase if compiler complains about sprintf - static uint8_t clearIrqCounter = 0; - static uint8_t lockCounterPrevious = 0; - uint8_t lockCounter = 0; - - int32_t wifi = 0; - if ((WiFi.status() == WL_CONNECTED) || (WiFi.getMode() == WIFI_AP)) { - wifi = WiFi.RSSI(); - } - - uint16_t hperiod = GBS::HPERIOD_IF::read(); - uint16_t vperiod = GBS::VPERIOD_IF::read(); - uint8_t stat0FIrq = GBS::STATUS_0F::read(); - char HSp = GBS::STATUS_SYNC_PROC_HSPOL::read() ? '+' : '-'; // 0 = neg, 1 = pos - char VSp = GBS::STATUS_SYNC_PROC_VSPOL::read() ? '+' : '-'; // 0 = neg, 1 = pos - char h = 'H', v = 'V'; - if (!GBS::STATUS_SYNC_PROC_HSACT::read()) { - h = HSp = ' '; - } - if (!GBS::STATUS_SYNC_PROC_VSACT::read()) { - v = VSp = ' '; - } - - //int charsToPrint = - sprintf(print, "h:%4u v:%4u PLL:%01u A:%02x%02x%02x S:%02x.%02x.%02x %c%c%c%c I:%02x D:%04x m:%hu ht:%4d vt:%4d hpw:%4d u:%3x s:%2x S:%2d W:%2d\n", - hperiod, vperiod, lockCounterPrevious, - GBS::ADC_RGCTRL::read(), GBS::ADC_GGCTRL::read(), GBS::ADC_BGCTRL::read(), - GBS::STATUS_00::read(), GBS::STATUS_05::read(), GBS::SP_CS_0x3E::read(), - h, HSp, v, VSp, stat0FIrq, GBS::TEST_BUS::read(), getVideoMode(), - GBS::STATUS_SYNC_PROC_HTOTAL::read(), GBS::STATUS_SYNC_PROC_VTOTAL::read() /*+ 1*/, // emucrt: without +1 is correct line count - GBS::STATUS_SYNC_PROC_HLOW_LEN::read(), rto->noSyncCounter, rto->continousStableCounter, - rto->currentLevelSOG, wifi); - - //SerialM.print("charsToPrint: "); SerialM.println(charsToPrint); - SerialM.print(print); - - if (stat0FIrq != 0x00) { - // clear 0_0F interrupt bits regardless of syncwatcher status - clearIrqCounter++; - if (clearIrqCounter >= 50) { - clearIrqCounter = 0; - GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status - GBS::INTERRUPT_CONTROL_00::write(0x00); - } - } - - yield(); - if (GBS::STATUS_SYNC_PROC_HSACT::read()) { // else source might not be active - for (uint8_t i = 0; i < 9; i++) { - if (GBS::STATUS_MISC_PLLAD_LOCK::read() == 1) { - lockCounter++; - } else { - for (int i = 0; i < 10; i++) { - if (GBS::STATUS_MISC_PLLAD_LOCK::read() == 1) { - lockCounter++; - break; - } - } - } - } - } - lockCounterPrevious = getMovingAverage(lockCounter); -} - -void stopWire() -{ - pinMode(SCL, INPUT); - pinMode(SDA, INPUT); - delayMicroseconds(80); -} - -void startWire() -{ - Wire.begin(); - // The i2c wire library sets pullup resistors on by default. - // Disable these to detect/work with GBS onboard pullups - pinMode(SCL, OUTPUT_OPEN_DRAIN); - pinMode(SDA, OUTPUT_OPEN_DRAIN); - // no issues even at 700k, requires ESP8266 160Mhz CPU clock, else (80Mhz) uses 400k in library - // no problem with Si5351 at 700k either - Wire.setClock(400000); - //Wire.setClock(700000); -} - -void fastSogAdjust() -{ - if (rto->noSyncCounter <= 5) { - uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); - uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(0xa); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(0x0f); - } - - if ((GBS::TEST_BUS_2F::read() & 0x05) != 0x05) { - while ((GBS::TEST_BUS_2F::read() & 0x05) != 0x05) { - if (rto->currentLevelSOG >= 4) { - rto->currentLevelSOG -= 2; - } else { - rto->currentLevelSOG = 13; - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(40); - break; // abort / restart next round - } - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(28); // 4 - } - delay(10); - } - - if (debug_backup != 0xa) { - GBS::TEST_BUS_SEL::write(debug_backup); - } - if (debug_backup_SP != 0x0f) { - GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); - } - } -} - -void runSyncWatcher() -{ - if (!rto->boardHasPower) { - return; - } - - static uint8_t newVideoModeCounter = 0; - static uint16_t activeStableLineCount = 0; - static unsigned long lastSyncDrop = millis(); - static unsigned long lastLineCountMeasure = millis(); - - uint16_t thisStableLineCount = 0; - uint8_t detectedVideoMode = getVideoMode(); - boolean status16SpHsStable = getStatus16SpHsStable(); - - if (rto->outModeHdBypass && status16SpHsStable) { - if (videoStandardInputIsPalNtscSd()) { - if (millis() - lastLineCountMeasure > 765) { - thisStableLineCount = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - for (uint8_t i = 0; i < 3; i++) { - delay(2); - if (GBS::STATUS_SYNC_PROC_VTOTAL::read() < (thisStableLineCount - 3) || - GBS::STATUS_SYNC_PROC_VTOTAL::read() > (thisStableLineCount + 3)) { - thisStableLineCount = 0; - break; - } - } - - if (thisStableLineCount != 0) { - if (thisStableLineCount < (activeStableLineCount - 3) || - thisStableLineCount > (activeStableLineCount + 3)) { - activeStableLineCount = thisStableLineCount; - if (activeStableLineCount < 230 || activeStableLineCount > 340) { - // only doing NTSC/PAL currently, an unusual line count probably means a format change - setCsVsStart(1); - if (getCsVsStop() == 1) { - setCsVsStop(2); - } - // MD likes to get stuck as usual - nudgeMD(); - } else { - setCsVsStart(thisStableLineCount - 9); - } - - Serial.printf("HDBypass CsVsSt: %d\n", getCsVsStart()); - delay(150); - } - } - - lastLineCountMeasure = millis(); - } - } - } - - if (rto->videoStandardInput == 13) { // using flaky graphic modes - if (detectedVideoMode == 0) { - if (GBS::STATUS_INT_SOG_BAD::read() == 0) { - detectedVideoMode = 13; // then keep it - } - } - } - - static unsigned long preemptiveSogWindowStart = millis(); - static const uint16_t sogWindowLen = 3000; // ms - static uint16_t badHsActive = 0; - static boolean lastAdjustWasInActiveWindow = 0; - - if (rto->syncTypeCsync && !rto->inputIsYpBpR && (newVideoModeCounter == 0)) { - // look for SOG instability - if (GBS::STATUS_INT_SOG_BAD::read() == 1 || GBS::STATUS_INT_SOG_SW::read() == 1) { - resetInterruptSogSwitchBit(); - if ((millis() - preemptiveSogWindowStart) > sogWindowLen) { - // start new window - preemptiveSogWindowStart = millis(); - badHsActive = 0; - } - lastVsyncLock = millis(); // best reset this - } - - if ((millis() - preemptiveSogWindowStart) < sogWindowLen) { - for (uint8_t i = 0; i < 16; i++) { - if (GBS::STATUS_INT_SOG_BAD::read() == 1 || GBS::STATUS_SYNC_PROC_HSACT::read() == 0) { - resetInterruptSogBadBit(); - uint16_t hlowStart = GBS::STATUS_SYNC_PROC_HLOW_LEN::read(); - if (rto->videoStandardInput == 0) - hlowStart = 777; // fix initial state no HLOW_LEN - for (int a = 0; a < 20; a++) { - if (GBS::STATUS_SYNC_PROC_HLOW_LEN::read() != hlowStart) { - // okay, source still active so count this one, break back to outer for loop - badHsActive++; - lastVsyncLock = millis(); // delay this - //Serial.print(badHsActive); Serial.print(" "); - break; - } - } - } - if ((i % 3) == 0) { - delay(1); - } else { - delay(0); - } - } - - if (badHsActive >= 17) { - if (rto->currentLevelSOG >= 2) { - rto->currentLevelSOG -= 1; - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(30); - updateSpDynamic(0); - badHsActive = 0; - lastAdjustWasInActiveWindow = 1; - } else if (badHsActive > 40) { - optimizeSogLevel(); - badHsActive = 0; - lastAdjustWasInActiveWindow = 1; - } - preemptiveSogWindowStart = millis(); // restart window - } - } else if (lastAdjustWasInActiveWindow) { - lastAdjustWasInActiveWindow = 0; - if (rto->currentLevelSOG >= 8) { - rto->currentLevelSOG -= 1; - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(30); - updateSpDynamic(0); - badHsActive = 0; - rto->phaseIsSet = 0; - } - } - } - - if ((detectedVideoMode == 0 || !status16SpHsStable) && rto->videoStandardInput != 15) { - rto->noSyncCounter++; - rto->continousStableCounter = 0; - lastVsyncLock = millis(); // best reset this - if (rto->noSyncCounter == 1) { - freezeVideo(); - return; // do nothing else - } - - rto->phaseIsSet = 0; - - if (rto->noSyncCounter <= 3 || GBS::STATUS_SYNC_PROC_HSACT::read() == 0) { - freezeVideo(); - } - - if (newVideoModeCounter == 0) { - LEDOFF; // LEDOFF on sync loss - - if (rto->noSyncCounter == 2) { // this usually repeats - //printInfo(); printInfo(); SerialM.println(); - //rto->printInfos = 0; - if ((millis() - lastSyncDrop) > 1500) { // minimum space between runs - if (rto->printInfos == false) { - SerialM.print("\n."); - } - } else { - if (rto->printInfos == false) { - SerialM.print("."); - } - } - - // if sog is lowest, adjust up - if (rto->currentLevelSOG <= 1 && videoStandardInputIsPalNtscSd()) { - rto->currentLevelSOG += 1; - setAndUpdateSogLevel(rto->currentLevelSOG); - delay(30); - } - lastSyncDrop = millis(); // restart timer - } - } - - if (rto->noSyncCounter == 8) { - GBS::SP_H_CST_ST::write(0x10); - GBS::SP_H_CST_SP::write(0x100); - //GBS::SP_H_PROTECT::write(1); // at noSyncCounter = 32 will alternate on / off - if (videoStandardInputIsPalNtscSd()) { - // this can early detect mode changes (before updateSpDynamic resets all) - GBS::SP_PRE_COAST::write(9); - GBS::SP_POST_COAST::write(9); - // new: test SD<>EDTV changes - uint8_t ignore = GBS::SP_H_PULSE_IGNOR::read(); - if (ignore >= 0x33) { - GBS::SP_H_PULSE_IGNOR::write(ignore / 2); - } - } - rto->coastPositionIsSet = 0; - } - - if (rto->noSyncCounter % 27 == 0) { - // the * check needs to be first (go before auto sog level) to support SD > HDTV detection - SerialM.print("*"); - updateSpDynamic(1); - } - - if (rto->noSyncCounter % 32 == 0) { - if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { - unfreezeVideo(); - } else { - freezeVideo(); - } - } - - if (rto->inputIsYpBpR && (rto->noSyncCounter == 34)) { - GBS::SP_NO_CLAMP_REG::write(1); // unlock clamp - rto->clampPositionIsSet = false; - } - - if (rto->noSyncCounter == 38) { - nudgeMD(); - } - - if (rto->syncTypeCsync) { - if (rto->noSyncCounter > 47) { - if (rto->noSyncCounter % 16 == 0) { - GBS::SP_H_PROTECT::write(!GBS::SP_H_PROTECT::read()); - } - } - } - - if (rto->noSyncCounter % 150 == 0) { - if (rto->noSyncCounter == 150 || rto->noSyncCounter % 900 == 0) { - SerialM.print("\nno signal\n"); - // check whether discrete VSync is present. if so, need to go to input detect - uint8_t extSyncBackup = GBS::SP_EXT_SYNC_SEL::read(); - GBS::SP_EXT_SYNC_SEL::write(0); - delay(240); - printInfo(); - if (GBS::STATUS_SYNC_PROC_VSACT::read() == 1) { - delay(10); - if (GBS::STATUS_SYNC_PROC_VSACT::read() == 1) { - rto->noSyncCounter = 0x07fe; - } - } - GBS::SP_EXT_SYNC_SEL::write(extSyncBackup); - } - GBS::SP_H_COAST::write(0); // 5_3e 2 - GBS::SP_H_PROTECT::write(0); // 5_3e 4 - GBS::SP_H_CST_ST::write(0x10); - GBS::SP_H_CST_SP::write(0x100); // instead of disabling 5_3e 5 coast - GBS::SP_CS_CLP_ST::write(32); // neutral clamp values - GBS::SP_CS_CLP_SP::write(48); // - updateSpDynamic(1); - nudgeMD(); // can fix MD not noticing a line count update - delay(80); - - // prepare optimizeSogLevel - // use STATUS_SYNC_PROC_HLOW_LEN changes to determine whether source is still active - uint16_t hlowStart = GBS::STATUS_SYNC_PROC_HLOW_LEN::read(); - if (GBS::PLLAD_VCORST::read() == 1) { - // exception: we're in startup and pllad isn't locked yet > HLOW_LEN always 0 - hlowStart = 777; // now it'll run optimizeSogLevel if needed - } - for (int a = 0; a < 128; a++) { - if (GBS::STATUS_SYNC_PROC_HLOW_LEN::read() != hlowStart) { - // source still there - if (rto->noSyncCounter % 450 == 0) { - rto->currentLevelSOG = 0; // worst case, sometimes necessary, will be unstable but at least detect - setAndUpdateSogLevel(rto->currentLevelSOG); - } else { - optimizeSogLevel(); - } - break; - } else if (a == 127) { - // set sog to be able to see something - rto->currentLevelSOG = 5; - setAndUpdateSogLevel(rto->currentLevelSOG); - } - delay(0); - } - - resetSyncProcessor(); - delay(8); - resetModeDetect(); - delay(8); - } - - // long no signal time, check other input - if (rto->noSyncCounter % 413 == 0) { - if (GBS::ADC_INPUT_SEL::read() == 1) { - GBS::ADC_INPUT_SEL::write(0); - } else { - GBS::ADC_INPUT_SEL::write(1); - } - delay(40); - unsigned long timeout = millis(); - while (millis() - timeout <= 210) { - if (getStatus16SpHsStable()) { - rto->noSyncCounter = 0x07fe; // will cause a return - break; - } - handleWiFi(0); - delay(1); - } - - if (millis() - timeout > 210) { - if (GBS::ADC_INPUT_SEL::read() == 1) { - GBS::ADC_INPUT_SEL::write(0); - } else { - GBS::ADC_INPUT_SEL::write(1); - } - } - } - - newVideoModeCounter = 0; - // sog unstable check end - } - - // if format changed to valid, potentially new video mode - if (((detectedVideoMode != 0 && detectedVideoMode != rto->videoStandardInput) || - (detectedVideoMode != 0 && rto->videoStandardInput == 0)) && - rto->videoStandardInput != 15) { - // before thoroughly checking for a mode change, watch format via newVideoModeCounter - if (newVideoModeCounter < 255) { - newVideoModeCounter++; - rto->continousStableCounter = 0; // usually already 0, but occasionally not - if (newVideoModeCounter > 1) { // help debug a few commits worth - if (newVideoModeCounter == 2) { - SerialM.println(); - } - SerialM.print(newVideoModeCounter); - } - if (newVideoModeCounter == 3) { - freezeVideo(); - GBS::SP_H_CST_ST::write(0x10); - GBS::SP_H_CST_SP::write(0x100); - rto->coastPositionIsSet = 0; - delay(10); - if (getVideoMode() == 0) { - updateSpDynamic(1); // check ntsc to 480p and back - delay(40); - } - } - } - - if (newVideoModeCounter >= 8) { - uint8_t vidModeReadout = 0; - SerialM.print(F("\nFormat change:")); - for (int a = 0; a < 30; a++) { - vidModeReadout = getVideoMode(); - if (vidModeReadout == 13) { - newVideoModeCounter = 5; - } // treat ps2 quasi rgb as stable - if (vidModeReadout != detectedVideoMode) { - newVideoModeCounter = 0; - } - } - if (newVideoModeCounter != 0) { - // apply new mode - SerialM.print(" "); - SerialM.print(vidModeReadout); - SerialM.println(F(" ")); - //Serial.print("Old: "); Serial.print(rto->videoStandardInput); - //Serial.print(" New: "); Serial.println(detectedVideoMode); - rto->videoIsFrozen = false; - - if (GBS::SP_SOG_MODE::read() == 1) { - rto->syncTypeCsync = true; - } else { - rto->syncTypeCsync = false; - } - boolean wantPassThroughMode = uopt->presetPreference == 10; - - if (((rto->videoStandardInput == 1 || rto->videoStandardInput == 3) && (detectedVideoMode == 2 || detectedVideoMode == 4)) || - rto->videoStandardInput == 0 || - ((rto->videoStandardInput == 2 || rto->videoStandardInput == 4) && (detectedVideoMode == 1 || detectedVideoMode == 3))) { - rto->useHdmiSyncFix = 1; - //SerialM.println("hdmi sync fix: yes"); - } else { - rto->useHdmiSyncFix = 0; - //SerialM.println("hdmi sync fix: no"); - } - - if (!wantPassThroughMode) { - // needs to know the sync type for early updateclamp (set above) - applyPresets(detectedVideoMode); - } else { - rto->videoStandardInput = detectedVideoMode; - setOutModeHdBypass(false); - } - rto->videoStandardInput = detectedVideoMode; - rto->noSyncCounter = 0; - rto->continousStableCounter = 0; // also in postloadsteps - newVideoModeCounter = 0; - activeStableLineCount = 0; - delay(20); // post delay - badHsActive = 0; - preemptiveSogWindowStart = millis(); - } else { - unfreezeVideo(); // (whops) - SerialM.print(" "); - SerialM.print(vidModeReadout); - SerialM.println(F(" ")); - printInfo(); - newVideoModeCounter = 0; - if (rto->videoStandardInput == 0) { - // if we got here from standby mode, return there soon - // but occasionally, this is a regular new mode that needs a SP parameter change to work - // ie: 1080p needs longer post coast, which the syncwatcher loop applies at some point - rto->noSyncCounter = 0x05ff; // give some time in normal loop - } - } - } - } else if (getStatus16SpHsStable() && detectedVideoMode != 0 && rto->videoStandardInput != 15 && (rto->videoStandardInput == detectedVideoMode)) { - // last used mode reappeared / stable again - if (rto->continousStableCounter < 255) { - rto->continousStableCounter++; - } - - static boolean doFullRestore = 0; - if (rto->noSyncCounter >= 150) { - // source was gone for longer // clamp will be updated at continousStableCounter 50 - rto->coastPositionIsSet = false; - rto->phaseIsSet = false; - FrameSync::reset(uopt->frameTimeLockMethod); - doFullRestore = 1; - SerialM.println(); - } - - rto->noSyncCounter = 0; - newVideoModeCounter = 0; - - if (rto->continousStableCounter == 1 && !doFullRestore) { - rto->videoIsFrozen = true; // ensures unfreeze - unfreezeVideo(); - } - - if (rto->continousStableCounter == 2) { - updateSpDynamic(0); - if (doFullRestore) { - delay(20); - optimizeSogLevel(); - doFullRestore = 0; - } - rto->videoIsFrozen = true; // ensures unfreeze - unfreezeVideo(); // called 2nd time here to make sure - } - - if (rto->continousStableCounter == 4) { - LEDON; - } - - if (!rto->phaseIsSet) { - if (rto->continousStableCounter >= 10 && rto->continousStableCounter < 61) { - // added < 61 to make a window, else sources with little pll lock hammer this - if ((rto->continousStableCounter % 10) == 0) { - rto->phaseIsSet = optimizePhaseSP(); - } - } - } - - // 5_3e 2 SP_H_COAST test - //if (rto->continousStableCounter == 11) { - // if (rto->coastPositionIsSet) { - // GBS::SP_H_COAST::write(1); - // } - //} - - if (rto->continousStableCounter == 160) { - resetInterruptSogBadBit(); - } - - if (rto->continousStableCounter == 45) { - GBS::ADC_UNUSED_67::write(0); // clear sync fix temp registers (67/68) - //rto->coastPositionIsSet = 0; // leads to a flicker - rto->clampPositionIsSet = 0; // run updateClampPosition occasionally - } - - if (rto->continousStableCounter % 31 == 0) { - // new: 8 regular interval checks up until 255 - updateSpDynamic(0); - } - - if (rto->continousStableCounter >= 3) { - if ((rto->videoStandardInput == 1 || rto->videoStandardInput == 2) && - !rto->outModeHdBypass && rto->noSyncCounter == 0) { - // deinterlacer and scanline code - static uint8_t timingAdjustDelay = 0; - static uint8_t oddEvenWhenArmed = 0; - boolean preventScanlines = 0; - - if (rto->deinterlaceAutoEnabled) { - uint16_t VPERIOD_IF = GBS::VPERIOD_IF::read(); - static uint8_t filteredLineCountMotionAdaptiveOn = 0, filteredLineCountMotionAdaptiveOff = 0; - static uint16_t VPERIOD_IF_OLD = VPERIOD_IF; // for glitch filter - - if (VPERIOD_IF_OLD != VPERIOD_IF) { - //freezeVideo(); // glitch filter - preventScanlines = 1; - filteredLineCountMotionAdaptiveOn = 0; - filteredLineCountMotionAdaptiveOff = 0; - if (uopt->enableFrameTimeLock || rto->extClockGenDetected) { - if (uopt->deintMode == 1) { // using bob - timingAdjustDelay = 11; // arm timer (always) - oddEvenWhenArmed = VPERIOD_IF % 2; - } - } - } - - if (VPERIOD_IF == 522 || VPERIOD_IF == 524 || VPERIOD_IF == 526 || - VPERIOD_IF == 622 || VPERIOD_IF == 624 || VPERIOD_IF == 626) { // ie v:524, even counts > enable - filteredLineCountMotionAdaptiveOn++; - filteredLineCountMotionAdaptiveOff = 0; - if (filteredLineCountMotionAdaptiveOn >= 2) // at least >= 2 - { - if (uopt->deintMode == 0 && !rto->motionAdaptiveDeinterlaceActive) { - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { // don't rely on rto->scanlinesEnabled - disableScanlines(); - } - enableMotionAdaptDeinterlace(); - if (timingAdjustDelay == 0) { - timingAdjustDelay = 11; // arm timer only if it's not already armed - oddEvenWhenArmed = VPERIOD_IF % 2; - } else { - timingAdjustDelay = 0; // cancel timer - } - preventScanlines = 1; - } - filteredLineCountMotionAdaptiveOn = 0; - } - } else if (VPERIOD_IF == 521 || VPERIOD_IF == 523 || VPERIOD_IF == 525 || - VPERIOD_IF == 623 || VPERIOD_IF == 625 || VPERIOD_IF == 627) { // ie v:523, uneven counts > disable - filteredLineCountMotionAdaptiveOff++; - filteredLineCountMotionAdaptiveOn = 0; - if (filteredLineCountMotionAdaptiveOff >= 2) // at least >= 2 - { - if (uopt->deintMode == 0 && rto->motionAdaptiveDeinterlaceActive) { - disableMotionAdaptDeinterlace(); - if (timingAdjustDelay == 0) { - timingAdjustDelay = 11; // arm timer only if it's not already armed - oddEvenWhenArmed = VPERIOD_IF % 2; - } else { - timingAdjustDelay = 0; // cancel timer - } - } - filteredLineCountMotionAdaptiveOff = 0; - } - } else { - filteredLineCountMotionAdaptiveOn = filteredLineCountMotionAdaptiveOff = 0; - } - - VPERIOD_IF_OLD = VPERIOD_IF; // part of glitch filter - - if (uopt->deintMode == 1) { // using bob - if (rto->motionAdaptiveDeinterlaceActive) { - disableMotionAdaptDeinterlace(); - FrameSync::reset(uopt->frameTimeLockMethod); - GBS::GBS_RUNTIME_FTL_ADJUSTED::write(1); - lastVsyncLock = millis(); - } - if (uopt->wantScanlines && !rto->scanlinesEnabled) { - enableScanlines(); - } else if (!uopt->wantScanlines && rto->scanlinesEnabled) { - disableScanlines(); - } - } - - // timing adjust after a few stable cycles - // should arrive here with either odd or even VPERIOD_IF - /*if (timingAdjustDelay != 0) { - Serial.print(timingAdjustDelay); Serial.print(" "); - }*/ - if (timingAdjustDelay != 0) { - if ((VPERIOD_IF % 2) == oddEvenWhenArmed) { - timingAdjustDelay--; - if (timingAdjustDelay == 0) { - if (uopt->enableFrameTimeLock) { - FrameSync::reset(uopt->frameTimeLockMethod); - GBS::GBS_RUNTIME_FTL_ADJUSTED::write(1); - delay(10); - lastVsyncLock = millis(); - } - externalClockGenSyncInOutRate(); - } - } - /*else { - Serial.println("!!!"); - }*/ - } - } - - // scanlines - if (uopt->wantScanlines) { - if (!rto->scanlinesEnabled && !rto->motionAdaptiveDeinterlaceActive && !preventScanlines) { - enableScanlines(); - } else if (!uopt->wantScanlines && rto->scanlinesEnabled) { - disableScanlines(); - } - } - } - } - } - - if (rto->videoStandardInput >= 14) { // RGBHV checks - static uint16_t RGBHVNoSyncCounter = 0; - - if (uopt->preferScalingRgbhv && rto->continousStableCounter >= 2) { - boolean needPostAdjust = 0; - static uint16_t activePresetLineCount = 0; - // is the source in range for scaling RGBHV and is it currently in mode 15? - uint16 sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); // if sourceLines = 0, might be in some reset state - if ((sourceLines <= 535 && sourceLines != 0) && rto->videoStandardInput == 15) { - uint16_t firstDetectedSourceLines = sourceLines; - boolean moveOn = 1; - for (int i = 0; i < 30; i++) { // not the best check, but we don't want to try if this is not stable (usually is though) - sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - // range needed for interlace - if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { - moveOn = 0; - break; - } - delay(10); - } - if (moveOn) { - SerialM.println(F(" RGB/HV upscale mode")); - rto->isValidForScalingRGBHV = true; - GBS::GBS_OPTION_SCALING_RGBHV::write(1); - rto->autoBestHtotalEnabled = 1; - - if (rto->syncTypeCsync == false) { - GBS::SP_SOG_MODE::write(0); - GBS::SP_NO_COAST_REG::write(1); - GBS::ADC_5_00::write(0x10); // 5_00 might be required - GBS::PLL_IS::write(0); // 0_40 2: this provides a clock for IF and test bus readings - GBS::PLL_VCORST::write(1); // 0_43 5: also required for clock - delay(320); // min 250 - } else { - GBS::SP_SOG_MODE::write(1); - GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values - GBS::SP_H_CST_SP::write(0x80); // will be updated later - GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) - } - delay(4); - - float sourceRate = getSourceFieldRate(1); - Serial.println(sourceRate); - - // todo: this hack is hard to understand when looking at applypreset and mode is suddenly 1,2 or 3 - if (uopt->presetPreference == 2) { - // custom preset defined, try to load (set mode = 14 here early) - rto->videoStandardInput = 14; - } else { - if (sourceLines < 280) { - // this is "NTSC like?" check, seen 277 lines in "512x512 interlaced (emucrt)" - rto->videoStandardInput = 1; - } else if (sourceLines < 380) { - // this is "PAL like?" check, seen vt:369 (MDA mode) - rto->videoStandardInput = 2; - } else if (sourceRate > 44.0f && sourceRate < 53.8f) { - // not low res but PAL = "EDTV" - rto->videoStandardInput = 4; - needPostAdjust = 1; - } else { // sourceRate > 53.8f - // "60Hz EDTV" - rto->videoStandardInput = 3; - needPostAdjust = 1; - } - } - - if (uopt->presetPreference == 10) { - uopt->presetPreference = Output960P; // fix presetPreference which can be "bypass" - } - - activePresetLineCount = sourceLines; - applyPresets(rto->videoStandardInput); - - GBS::GBS_OPTION_SCALING_RGBHV::write(1); - GBS::IF_INI_ST::write(16); // fixes pal(at least) interlace - GBS::SP_SOG_P_ATO::write(1); // 5_20 1 auto SOG polarity (now "hpw" should never be close to "ht") - - GBS::SP_SDCS_VSST_REG_L::write(2); // 5_3f - GBS::SP_SDCS_VSSP_REG_L::write(0); // 5_40 - - rto->coastPositionIsSet = rto->clampPositionIsSet = 0; - rto->videoStandardInput = 14; - - if (GBS::PLLAD_ICP::read() >= 6) { - GBS::PLLAD_ICP::write(5); // reduce charge pump current for more general use - latchPLLAD(); - delay(40); - } - - updateSpDynamic(1); - if (rto->syncTypeCsync == false) { - GBS::SP_SOG_MODE::write(0); - GBS::SP_CLAMP_MANUAL::write(1); - GBS::SP_NO_COAST_REG::write(1); - } else { - GBS::SP_SOG_MODE::write(1); - GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values - GBS::SP_H_CST_SP::write(0x80); // will be updated later - GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) - } - delay(300); - - if (rto->extClockGenDetected) { - // switch to ext clock - if (!rto->outModeHdBypass) { - if (GBS::PLL648_CONTROL_01::read() != 0x35 && GBS::PLL648_CONTROL_01::read() != 0x75) { - // first store original in an option byte in 1_2D - GBS::GBS_PRESET_DISPLAY_CLOCK::write(GBS::PLL648_CONTROL_01::read()); - // enable and switch input - Si.enable(0); - delayMicroseconds(800); - GBS::PLL648_CONTROL_01::write(0x75); - } - } - // sync clocks now - externalClockGenSyncInOutRate(); - } - - // note: this is all duplicated below. unify! - if (needPostAdjust) { - // base preset was "3" / no line doubling - // info: actually the position needs to be adjusted based on hor. freq or "h:" value (todo!) - GBS::IF_HB_ST2::write(0x08); // patches - GBS::IF_HB_SP2::write(0x68); // image - GBS::IF_HBIN_SP::write(0x50); // position - if (rto->presetID == 0x05) { - GBS::IF_HB_ST2::write(0x480); - GBS::IF_HB_SP2::write(0x8E); - } - - float sfr = getSourceFieldRate(0); - if (sfr >= 69.0) { - SerialM.println("source >= 70Hz"); - // increase vscale; vscale -= 57 seems to hit magic factor often - // 512 + 57 = 569 + 57 = 626 + 57 = 683 - GBS::VDS_VSCALE::write(GBS::VDS_VSCALE::read() - 57); - - } else { - // 50/60Hz, presumably - // adjust vposition - GBS::IF_VB_SP::write(8); - GBS::IF_VB_ST::write(6); - } - } - } - } - // if currently in scaling RGB/HV, check for "SD" < > "EDTV" style source changes - else if ((sourceLines <= 535 && sourceLines != 0) && rto->videoStandardInput == 14) { - // todo: custom presets? - if (sourceLines < 280 && activePresetLineCount > 280) { - rto->videoStandardInput = 1; - } else if (sourceLines < 380 && activePresetLineCount > 380) { - rto->videoStandardInput = 2; - } else if (sourceLines > 380 && activePresetLineCount < 380) { - rto->videoStandardInput = 3; - needPostAdjust = 1; - } - - if (rto->videoStandardInput != 14) { - // check thoroughly first - uint16_t firstDetectedSourceLines = sourceLines; - boolean moveOn = 1; - for (int i = 0; i < 30; i++) { - sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { - moveOn = 0; - break; - } - delay(10); - } - - if (moveOn) { - // need to change presets - if (rto->videoStandardInput <= 2) { - SerialM.println(F(" RGB/HV upscale mode base 15kHz")); - } else { - SerialM.println(F(" RGB/HV upscale mode base 31kHz")); - } - - if (uopt->presetPreference == 10) { - uopt->presetPreference = Output960P; // fix presetPreference which can be "bypass" - } - - activePresetLineCount = sourceLines; - applyPresets(rto->videoStandardInput); - - GBS::GBS_OPTION_SCALING_RGBHV::write(1); - GBS::IF_INI_ST::write(16); // fixes pal(at least) interlace - GBS::SP_SOG_P_ATO::write(1); // 5_20 1 auto SOG polarity - - // adjust vposition - GBS::SP_SDCS_VSST_REG_L::write(2); // 5_3f - GBS::SP_SDCS_VSSP_REG_L::write(0); // 5_40 - - rto->coastPositionIsSet = rto->clampPositionIsSet = 0; - rto->videoStandardInput = 14; - - if (GBS::PLLAD_ICP::read() >= 6) { - GBS::PLLAD_ICP::write(5); // reduce charge pump current for more general use - latchPLLAD(); - } - - updateSpDynamic(1); - if (rto->syncTypeCsync == false) { - GBS::SP_SOG_MODE::write(0); - GBS::SP_CLAMP_MANUAL::write(1); - GBS::SP_NO_COAST_REG::write(1); - } else { - GBS::SP_SOG_MODE::write(1); - GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values - GBS::SP_H_CST_SP::write(0x80); // will be updated later - GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) - } - delay(300); - - if (rto->extClockGenDetected) { - // switch to ext clock - if (!rto->outModeHdBypass) { - if (GBS::PLL648_CONTROL_01::read() != 0x35 && GBS::PLL648_CONTROL_01::read() != 0x75) { - // first store original in an option byte in 1_2D - GBS::GBS_PRESET_DISPLAY_CLOCK::write(GBS::PLL648_CONTROL_01::read()); - // enable and switch input - Si.enable(0); - delayMicroseconds(800); - GBS::PLL648_CONTROL_01::write(0x75); - } - } - // sync clocks now - externalClockGenSyncInOutRate(); - } - - // note: this is all duplicated above. unify! - if (needPostAdjust) { - // base preset was "3" / no line doubling - // info: actually the position needs to be adjusted based on hor. freq or "h:" value (todo!) - GBS::IF_HB_ST2::write(0x08); // patches - GBS::IF_HB_SP2::write(0x68); // image - GBS::IF_HBIN_SP::write(0x50); // position - if (rto->presetID == 0x05) { - GBS::IF_HB_ST2::write(0x480); - GBS::IF_HB_SP2::write(0x8E); - } - - float sfr = getSourceFieldRate(0); - if (sfr >= 69.0) { - SerialM.println("source >= 70Hz"); - // increase vscale; vscale -= 57 seems to hit magic factor often - // 512 + 57 = 569 + 57 = 626 + 57 = 683 - GBS::VDS_VSCALE::write(GBS::VDS_VSCALE::read() - 57); - - } else { - // 50/60Hz, presumably - // adjust vposition - GBS::IF_VB_SP::write(8); - GBS::IF_VB_ST::write(6); - } - } - } else { - // was unstable, undo videoStandardInput change - rto->videoStandardInput = 14; - } - } - } - // check whether to revert back to full bypass - else if ((sourceLines > 535) && rto->videoStandardInput == 14) { - uint16_t firstDetectedSourceLines = sourceLines; - boolean moveOn = 1; - for (int i = 0; i < 30; i++) { - sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); - // range needed for interlace - if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { - moveOn = 0; - break; - } - delay(10); - } - if (moveOn) { - SerialM.println(F(" RGB/HV upscale mode disabled")); - rto->videoStandardInput = 15; - rto->isValidForScalingRGBHV = false; - - activePresetLineCount = 0; - applyPresets(rto->videoStandardInput); // exception: apply preset here, not later in syncwatcher - - delay(300); - } - } - } // done preferScalingRgbhv - - if (!uopt->preferScalingRgbhv && rto->videoStandardInput == 14) { - // user toggled the web ui button / revert scaling rgbhv - rto->videoStandardInput = 15; - rto->isValidForScalingRGBHV = false; - applyPresets(rto->videoStandardInput); - delay(300); - } - - // stability check, for CSync and HV separately - uint16_t limitNoSync = 0; - uint8_t VSHSStatus = 0; - boolean stable = 0; - if (rto->syncTypeCsync == true) { - if (GBS::STATUS_INT_SOG_BAD::read() == 1) { - // STATUS_INT_SOG_BAD = 0x0f bit 0, interrupt reg - resetModeDetect(); - stable = 0; - SerialM.print("`"); - delay(10); - resetInterruptSogBadBit(); - } else { - stable = 1; - VSHSStatus = GBS::STATUS_00::read(); - // this status can get stuck (regularly does) - stable = ((VSHSStatus & 0x04) == 0x04); // RGBS > check h+v from 0_00 - } - limitNoSync = 200; // 100 - } else { - VSHSStatus = GBS::STATUS_16::read(); - // this status usually updates when a source goes off - stable = ((VSHSStatus & 0x0a) == 0x0a); // RGBHV > check h+v from 0_16 - limitNoSync = 300; - } - - if (!stable) { - LEDOFF; - RGBHVNoSyncCounter++; - rto->continousStableCounter = 0; - if (RGBHVNoSyncCounter % 20 == 0) { - SerialM.print("`"); - } - } else { - RGBHVNoSyncCounter = 0; - LEDON; - if (rto->continousStableCounter < 255) { - rto->continousStableCounter++; - if (rto->continousStableCounter == 6) { - updateSpDynamic(1); - } - } - } - - if (RGBHVNoSyncCounter > limitNoSync) { - RGBHVNoSyncCounter = 0; - setResetParameters(); - prepareSyncProcessor(); - resetSyncProcessor(); // todo: fix MD being stuck in last mode when sync disappears - //resetModeDetect(); - rto->noSyncCounter = 0; - //Serial.println("RGBHV limit no sync"); - } - - static unsigned long lastTimeSogAndPllRateCheck = millis(); - if ((millis() - lastTimeSogAndPllRateCheck) > 900) { - if (rto->videoStandardInput == 15) { - // start out by adjusting sync polarity, may reset sog unstable interrupt flag - updateHVSyncEdge(); - delay(100); - } - - static uint8_t runsWithSogBadStatus = 0; - static uint8_t oldHPLLState = 0; - if (rto->syncTypeCsync == false) { - if (GBS::STATUS_INT_SOG_BAD::read()) { // SOG source unstable indicator - runsWithSogBadStatus++; - //SerialM.print("test: "); SerialM.println(runsWithSogBadStatus); - if (runsWithSogBadStatus >= 4) { - SerialM.println(F("RGB/HV < > SOG")); - rto->syncTypeCsync = true; - rto->HPLLState = runsWithSogBadStatus = RGBHVNoSyncCounter = 0; - rto->noSyncCounter = 0x07fe; // will cause a return - } - } else { - runsWithSogBadStatus = 0; - } - } - - uint32_t currentPllRate = 0; - static uint32_t oldPllRate = 10; - - // how fast is the PLL running? needed to set charge pump and gain - // typical: currentPllRate: 1560, currentPllRate: 3999 max seen the pll reach: 5008 for 1280x1024@75 - if (GBS::STATUS_INT_SOG_BAD::read() == 0) { - currentPllRate = getPllRate(); - //Serial.println(currentPllRate); - if (currentPllRate > 100 && currentPllRate < 7500) { - if ((currentPllRate < (oldPllRate - 3)) || (currentPllRate > (oldPllRate + 3))) { - delay(40); - if (GBS::STATUS_INT_SOG_BAD::read() == 1) - delay(100); - currentPllRate = getPllRate(); // test again, guards against random spurs - // but don't force currentPllRate to = 0 if these inner checks fail, - // prevents csync <> hvsync changes - if ((currentPllRate < (oldPllRate - 3)) || (currentPllRate > (oldPllRate + 3))) { - oldPllRate = currentPllRate; // okay, it changed - } - } - } else { - currentPllRate = 0; - } - } - - resetInterruptSogBadBit(); - - //short activeChargePumpLevel = GBS::PLLAD_ICP::read(); - //short activeGainBoost = GBS::PLLAD_FS::read(); - //SerialM.print(" rto->HPLLState: "); SerialM.println(rto->HPLLState); - //SerialM.print(" currentPllRate: "); SerialM.println(currentPllRate); - //SerialM.print(" CPL: "); SerialM.print(activeChargePumpLevel); - //SerialM.print(" Gain: "); SerialM.print(activeGainBoost); - //SerialM.print(" KS: "); SerialM.print(GBS::PLLAD_KS::read()); - - oldHPLLState = rto->HPLLState; // do this first, else it can miss events - if (currentPllRate != 0) { - if (currentPllRate < 1030) { - rto->HPLLState = 1; - } else if (currentPllRate < 2300) { - rto->HPLLState = 2; - } else if (currentPllRate < 3200) { - rto->HPLLState = 3; - } else if (currentPllRate < 3800) { - rto->HPLLState = 4; - } else { - rto->HPLLState = 5; - } - } - - if (rto->videoStandardInput == 15) { - if (oldHPLLState != rto->HPLLState) { - if (rto->HPLLState == 1) { - GBS::PLLAD_KS::write(2); // KS = 2 okay - GBS::PLLAD_FS::write(0); - GBS::PLLAD_ICP::write(6); - } else if (rto->HPLLState == 2) { - GBS::PLLAD_KS::write(1); - GBS::PLLAD_FS::write(0); - GBS::PLLAD_ICP::write(6); - } else if (rto->HPLLState == 3) { // KS = 1 okay - GBS::PLLAD_KS::write(1); - GBS::PLLAD_FS::write(1); - GBS::PLLAD_ICP::write(6); // would need 7 but this is risky - } else if (rto->HPLLState == 4) { - GBS::PLLAD_KS::write(0); // KS = 0 from here on - GBS::PLLAD_FS::write(0); - GBS::PLLAD_ICP::write(6); - } else if (rto->HPLLState == 5) { - GBS::PLLAD_KS::write(0); // KS = 0 - GBS::PLLAD_FS::write(1); - GBS::PLLAD_ICP::write(6); - } - - latchPLLAD(); - delay(2); - setOverSampleRatio(4, false); // false = do apply // will auto decrease to max possible factor - SerialM.print(F("(H-PLL) rate: ")); - SerialM.print(currentPllRate); - SerialM.print(F(" state: ")); - SerialM.println(rto->HPLLState); - delay(100); - } - } else if (rto->videoStandardInput == 14) { - if (oldHPLLState != rto->HPLLState) { - SerialM.print(F("(H-PLL) rate: ")); - SerialM.print(currentPllRate); - SerialM.print(F(" state (no change): ")); - SerialM.println(rto->HPLLState); - // need to manage HPLL state change somehow - - //FrameSync::reset(uopt->frameTimeLockMethod); - } - } - - if (rto->videoStandardInput == 14) { - // scanlines - if (uopt->wantScanlines) { - if (!rto->scanlinesEnabled && !rto->motionAdaptiveDeinterlaceActive) { - if (GBS::IF_LD_RAM_BYPS::read() == 0) { // line doubler on? - enableScanlines(); - } - } else if (!uopt->wantScanlines && rto->scanlinesEnabled) { - disableScanlines(); - } - } - } - - rto->clampPositionIsSet = false; // RGBHV should regularly check clamp position - lastTimeSogAndPllRateCheck = millis(); - } - } - - if (rto->noSyncCounter >= 0x07fe) { - // couldn't recover, source is lost - // restore initial conditions and move to input detect - GBS::DAC_RGBS_PWDNZ::write(0); // 0 = disable DAC - rto->noSyncCounter = 0; - SerialM.println(); - goLowPowerWithInputDetection(); // does not further nest, so it can be called here // sets reset parameters - } -} - -boolean checkBoardPower() -{ - GBS::ADC_UNUSED_69::write(0x6a); // 0110 1010 - if (GBS::ADC_UNUSED_69::read() == 0x6a) { - GBS::ADC_UNUSED_69::write(0); - return 1; - } - - GBS::ADC_UNUSED_69::write(0); // attempt to clear - if (rto->boardHasPower == true) { - Serial.println(F("! power / i2c lost !")); - } - - return 0; - - //stopWire(); // sets pinmodes SDA, SCL to INPUT - //uint8_t SCL_SDA = 0; - //for (int i = 0; i < 2; i++) { - // SCL_SDA += digitalRead(SCL); - // SCL_SDA += digitalRead(SDA); - //} - - //if (SCL_SDA != 6) - //{ - // if (rto->boardHasPower == true) { - // Serial.println("! power / i2c lost !"); - // } - // // I2C stays off and pins are INPUT - // return 0; - //} - - //startWire(); - //return 1; -} - -void calibrateAdcOffset() -{ - GBS::PAD_BOUT_EN::write(0); // disable output to pin for test - GBS::PLL648_CONTROL_01::write(0xA5); // display clock to adc = 162mhz - GBS::ADC_INPUT_SEL::write(2); // 10 > R2/G2/B2 as input (not connected, so to isolate ADC) - GBS::DEC_MATRIX_BYPS::write(1); - GBS::DEC_TEST_ENABLE::write(1); - GBS::ADC_5_03::write(0x31); // bottom clamps, filter max (40mhz) - GBS::ADC_TEST_04::write(0x00); // disable bit 1 - GBS::SP_CS_CLP_ST::write(0x00); - GBS::SP_CS_CLP_SP::write(0x00); - GBS::SP_5_56::write(0x05); // SP_SOG_MODE needs to be 1 - GBS::SP_5_57::write(0x80); - GBS::ADC_5_00::write(0x02); - GBS::TEST_BUS_SEL::write(0x0b); // 0x2b - GBS::TEST_BUS_EN::write(1); - resetDigital(); - - uint16_t hitTargetCounter = 0; - uint16_t readout16 = 0; - uint8_t missTargetCounter = 0; - uint8_t readout = 0; - - GBS::ADC_RGCTRL::write(0x7F); - GBS::ADC_GGCTRL::write(0x7F); - GBS::ADC_BGCTRL::write(0x7F); - GBS::ADC_ROFCTRL::write(0x7F); - GBS::ADC_GOFCTRL::write(0x3D); // start - GBS::ADC_BOFCTRL::write(0x7F); - GBS::DEC_TEST_SEL::write(1); // 5_1f = 0x1c - - //unsigned long overallTimer = millis(); - unsigned long startTimer = 0; - for (uint8_t i = 0; i < 3; i++) { - missTargetCounter = 0; - hitTargetCounter = 0; - delay(20); - startTimer = millis(); - - // loop breaks either when the timer runs out, or hitTargetCounter reaches target - while ((millis() - startTimer) < 800) { - readout16 = GBS::TEST_BUS::read() & 0x7fff; - //Serial.println(readout16, HEX); - // readout16 is unsigned, always >= 0 - if (readout16 < 7) { - hitTargetCounter++; - missTargetCounter = 0; - } else if (missTargetCounter++ > 2) { - if (i == 0) { - GBS::ADC_GOFCTRL::write(GBS::ADC_GOFCTRL::read() + 1); // incr. offset - readout = GBS::ADC_GOFCTRL::read(); - Serial.print(" G: "); - } else if (i == 1) { - GBS::ADC_ROFCTRL::write(GBS::ADC_ROFCTRL::read() + 1); - readout = GBS::ADC_ROFCTRL::read(); - Serial.print(" R: "); - } else if (i == 2) { - GBS::ADC_BOFCTRL::write(GBS::ADC_BOFCTRL::read() + 1); - readout = GBS::ADC_BOFCTRL::read(); - Serial.print(" B: "); - } - Serial.print(readout, HEX); - - if (readout >= 0x52) { - // some kind of failure - break; - } - - delay(10); - hitTargetCounter = 0; - missTargetCounter = 0; - startTimer = millis(); // extend timer - } - if (hitTargetCounter > 1500) { - break; - } - } - if (i == 0) { - // G done, prep R - adco->g_off = GBS::ADC_GOFCTRL::read(); - GBS::ADC_GOFCTRL::write(0x7F); - GBS::ADC_ROFCTRL::write(0x3D); - GBS::DEC_TEST_SEL::write(2); // 5_1f = 0x2c - } - if (i == 1) { - adco->r_off = GBS::ADC_ROFCTRL::read(); - GBS::ADC_ROFCTRL::write(0x7F); - GBS::ADC_BOFCTRL::write(0x3D); - GBS::DEC_TEST_SEL::write(3); // 5_1f = 0x3c - } - if (i == 2) { - adco->b_off = GBS::ADC_BOFCTRL::read(); - } - Serial.println(""); - } - - if (readout >= 0x52) { - // there was a problem; revert - adco->r_off = adco->g_off = adco->b_off = 0x40; - } - - GBS::ADC_GOFCTRL::write(adco->g_off); - GBS::ADC_ROFCTRL::write(adco->r_off); - GBS::ADC_BOFCTRL::write(adco->b_off); - - //Serial.println(millis() - overallTimer); -} - -void loadDefaultUserOptions() -{ - uopt->presetPreference = Output960P; // #1 - uopt->enableFrameTimeLock = 0; // permanently adjust frame timing to avoid glitch vertical bar. does not work on all displays! - uopt->presetSlot = 'A'; // - uopt->frameTimeLockMethod = 0; // compatibility with more displays - uopt->enableAutoGain = 0; - uopt->wantScanlines = 0; - uopt->wantOutputComponent = 0; - uopt->deintMode = 0; - uopt->wantVdsLineFilter = 0; - uopt->wantPeaking = 1; - uopt->preferScalingRgbhv = 1; - uopt->wantTap6 = 1; - uopt->PalForce60 = 0; - uopt->matchPresetSource = 1; // #14 - uopt->wantStepResponse = 1; // #15 - uopt->wantFullHeight = 1; // #16 - uopt->enableCalibrationADC = 1; // #17 - uopt->scanlineStrength = 0x30; // #18 - uopt->disableExternalClockGenerator = 0; // #19 -} - -//RF_PRE_INIT() { -// system_phy_set_powerup_option(3); // full RFCAL at boot -//} - -//void preinit() { -// //system_phy_set_powerup_option(3); // 0 = default, use init byte; 3 = full calibr. each boot, extra 200ms -// system_phy_set_powerup_option(0); -//} - -#if !USE_NEW_OLED_MENU -void ICACHE_RAM_ATTR isrRotaryEncoder() -{ - static unsigned long lastInterruptTime = 0; - unsigned long interruptTime = millis(); - - if (interruptTime - lastInterruptTime > 120) { - if (!digitalRead(pin_data)) { - oled_encoder_pos++; - oled_main_pointer += 15; - oled_sub_pointer += 15; - oled_pointer_count++; - // down = true; - // up = false; - } else { - oled_encoder_pos--; - oled_main_pointer -= 15; - oled_sub_pointer -= 15; - oled_pointer_count--; - // down = false; - // up = true; - } - } - lastInterruptTime = interruptTime; -} -#endif - -#if USE_NEW_OLED_MENU -void ICACHE_RAM_ATTR isrRotaryEncoderRotateForNewMenu() -{ - unsigned long interruptTime = millis(); - static unsigned long lastInterruptTime = 0; - static unsigned long lastNavUpdateTime = 0; - static OLEDMenuNav lastNav; - OLEDMenuNav newNav; - if (interruptTime - lastInterruptTime > 150) { - if (!digitalRead(pin_data)) { - newNav = REVERSE_ROTARY_ENCODER_FOR_OLED_MENU ? OLEDMenuNav::DOWN : OLEDMenuNav::UP; - } else { - newNav = REVERSE_ROTARY_ENCODER_FOR_OLED_MENU ? OLEDMenuNav::UP : OLEDMenuNav::DOWN; - } - if (newNav != lastNav && (interruptTime - lastNavUpdateTime < 120)) { - // ignore rapid changes to filter out mis-reads. besides, you are not supposed to rotate the encoder this fast anyway - oledNav = lastNav = OLEDMenuNav::IDLE; - } - else{ - lastNav = oledNav = newNav; - ++rotaryIsrID; - lastNavUpdateTime = interruptTime; - } - lastInterruptTime = interruptTime; - } -} -void ICACHE_RAM_ATTR isrRotaryEncoderPushForNewMenu() -{ - static unsigned long lastInterruptTime = 0; - unsigned long interruptTime = millis(); - if (interruptTime - lastInterruptTime > 500) { - oledNav = OLEDMenuNav::ENTER; - ++rotaryIsrID; - } - lastInterruptTime = interruptTime; -} -#endif - -void setup() -{ - display.init(); //inits OLED on I2C bus - display.flipScreenVertically(); //orientation fix for OLED - - pinMode(pin_clk, INPUT_PULLUP); - pinMode(pin_data, INPUT_PULLUP); - pinMode(pin_switch, INPUT_PULLUP); - -#if USE_NEW_OLED_MENU - attachInterrupt(digitalPinToInterrupt(pin_clk), isrRotaryEncoderRotateForNewMenu, FALLING); - attachInterrupt(digitalPinToInterrupt(pin_switch), isrRotaryEncoderPushForNewMenu, FALLING); - initOLEDMenu(); - initOSD(); -#else - // ISR TO PIN - attachInterrupt(digitalPinToInterrupt(pin_clk), isrRotaryEncoder, FALLING); -#endif - - rto->webServerEnabled = true; - rto->webServerStarted = false; // make sure this is set - - Serial.begin(115200); // Arduino IDE Serial Monitor requires the same 115200 bauds! - Serial.setTimeout(10); - - // millis() at this point: typically 65ms - // start web services as early in boot as possible - WiFi.hostname(device_hostname_partial); // was _full - - startWire(); - // run some dummy commands to init I2C to GBS and cached segments - GBS::SP_SOG_MODE::read(); - writeOneByte(0xF0, 0); - writeOneByte(0x00, 0); - GBS::STATUS_00::read(); - - if (rto->webServerEnabled) { - rto->allowUpdatesOTA = false; // need to initialize for handleWiFi() - WiFi.setSleepMode(WIFI_NONE_SLEEP); // low latency responses, less chance for missing packets - WiFi.setOutputPower(16.0f); // float: min 0.0f, max 20.5f - startWebserver(); - rto->webServerStarted = true; - } else { - //WiFi.disconnect(); // deletes credentials - WiFi.mode(WIFI_OFF); - WiFi.forceSleepBegin(); - } -#ifdef HAVE_PINGER_LIBRARY - pingLastTime = millis(); -#endif - - SerialM.println(F("\nstartup")); - - loadDefaultUserOptions(); - //globalDelay = 0; - - rto->allowUpdatesOTA = false; // ESP over the air updates. default to off, enable via web interface - rto->enableDebugPings = false; - rto->autoBestHtotalEnabled = true; // automatically find the best horizontal total pixel value for a given input timing - rto->syncLockFailIgnore = 16; // allow syncLock to fail x-1 times in a row before giving up (sync glitch immunity) - rto->forceRetime = false; - rto->syncWatcherEnabled = true; // continously checks the current sync status. required for normal operation - rto->phaseADC = 16; - rto->phaseSP = 16; - rto->failRetryAttempts = 0; - rto->presetID = 0; - rto->isCustomPreset = false; - rto->HPLLState = 0; - rto->motionAdaptiveDeinterlaceActive = false; - rto->deinterlaceAutoEnabled = true; - rto->scanlinesEnabled = false; - rto->boardHasPower = true; - rto->presetIsPalForce60 = false; - rto->syncTypeCsync = false; - rto->isValidForScalingRGBHV = false; - rto->medResLineCount = 0x33; // 51*8=408 - rto->osr = 0; - rto->useHdmiSyncFix = 0; - rto->notRecognizedCounter = 0; - - // more run time variables - rto->inputIsYpBpR = false; - rto->videoStandardInput = 0; - rto->outModeHdBypass = false; - rto->videoIsFrozen = false; - if (!rto->webServerEnabled) - rto->webServerStarted = false; - rto->printInfos = false; - rto->sourceDisconnected = true; - rto->isInLowPowerMode = false; - rto->applyPresetDoneStage = 0; - rto->presetVlineShift = 0; - rto->clampPositionIsSet = 0; - rto->coastPositionIsSet = 0; - rto->continousStableCounter = 0; - rto->currentLevelSOG = 5; - rto->thisSourceMaxLevelSOG = 31; // 31 = auto sog has not (yet) run - - adco->r_gain = 0; - adco->g_gain = 0; - adco->b_gain = 0; - adco->r_off = 0; - adco->g_off = 0; - adco->b_off = 0; - - serialCommand = '@'; // ASCII @ = 0 - userCommand = '@'; - - pinMode(DEBUG_IN_PIN, INPUT); - pinMode(LED_BUILTIN, OUTPUT); - LEDON; // enable the LED, lets users know the board is starting up - - //Serial.setDebugOutput(true); // if you want simple wifi debug info - - // delay 1 of 2 - unsigned long initDelay = millis(); - // upped from < 500 to < 1500, allows more time for wifi and GBS startup - while (millis() - initDelay < 1500) { - display.drawXbm(2, 2, gbsicon_width, gbsicon_height, gbsicon_bits); - display.display(); - handleWiFi(0); - delay(1); - } - display.clear(); - // if i2c established and chip running, issue software reset now - GBS::RESET_CONTROL_0x46::write(0); - GBS::RESET_CONTROL_0x47::write(0); - GBS::PLLAD_VCORST::write(1); - GBS::PLLAD_PDZ::write(0); // AD PLL off - - // file system (web page, custom presets, ect) - if (!SPIFFS.begin()) { - SerialM.println(F("SPIFFS mount failed! ((1M SPIFFS) selected?)")); - } else { - // load user preferences file - File f = SPIFFS.open("/preferencesv2.txt", "r"); - if (!f) { - SerialM.println(F("no preferences file yet, create new")); - loadDefaultUserOptions(); - saveUserPrefs(); // if this fails, there must be a spiffs problem - } else { - //on a fresh / spiffs not formatted yet MCU: userprefs.txt open ok //result = 207 - uopt->presetPreference = (PresetPreference)(f.read() - '0'); // #1 - if (uopt->presetPreference > 10) - uopt->presetPreference = Output960P; // fresh spiffs ? - - uopt->enableFrameTimeLock = (uint8_t)(f.read() - '0'); - if (uopt->enableFrameTimeLock > 1) - uopt->enableFrameTimeLock = 0; - - uopt->presetSlot = lowByte(f.read()); - - uopt->frameTimeLockMethod = (uint8_t)(f.read() - '0'); - if (uopt->frameTimeLockMethod > 1) - uopt->frameTimeLockMethod = 0; - - uopt->enableAutoGain = (uint8_t)(f.read() - '0'); - if (uopt->enableAutoGain > 1) - uopt->enableAutoGain = 0; - - uopt->wantScanlines = (uint8_t)(f.read() - '0'); - if (uopt->wantScanlines > 1) - uopt->wantScanlines = 0; - - uopt->wantOutputComponent = (uint8_t)(f.read() - '0'); - if (uopt->wantOutputComponent > 1) - uopt->wantOutputComponent = 0; - - uopt->deintMode = (uint8_t)(f.read() - '0'); - if (uopt->deintMode > 2) - uopt->deintMode = 0; - - uopt->wantVdsLineFilter = (uint8_t)(f.read() - '0'); - if (uopt->wantVdsLineFilter > 1) - uopt->wantVdsLineFilter = 0; - - uopt->wantPeaking = (uint8_t)(f.read() - '0'); - if (uopt->wantPeaking > 1) - uopt->wantPeaking = 1; - - uopt->preferScalingRgbhv = (uint8_t)(f.read() - '0'); - if (uopt->preferScalingRgbhv > 1) - uopt->preferScalingRgbhv = 1; - - uopt->wantTap6 = (uint8_t)(f.read() - '0'); - if (uopt->wantTap6 > 1) - uopt->wantTap6 = 1; - - uopt->PalForce60 = (uint8_t)(f.read() - '0'); - if (uopt->PalForce60 > 1) - uopt->PalForce60 = 0; - - uopt->matchPresetSource = (uint8_t)(f.read() - '0'); // #14 - if (uopt->matchPresetSource > 1) - uopt->matchPresetSource = 1; - - uopt->wantStepResponse = (uint8_t)(f.read() - '0'); // #15 - if (uopt->wantStepResponse > 1) - uopt->wantStepResponse = 1; - - uopt->wantFullHeight = (uint8_t)(f.read() - '0'); // #16 - if (uopt->wantFullHeight > 1) - uopt->wantFullHeight = 1; - - uopt->enableCalibrationADC = (uint8_t)(f.read() - '0'); // #17 - if (uopt->enableCalibrationADC > 1) - uopt->enableCalibrationADC = 1; - - uopt->scanlineStrength = (uint8_t)(f.read() - '0'); // #18 - if (uopt->scanlineStrength > 0x60) - uopt->enableCalibrationADC = 0x30; - - uopt->disableExternalClockGenerator = (uint8_t)(f.read() - '0'); // #19 - if (uopt->disableExternalClockGenerator > 1) - uopt->disableExternalClockGenerator = 0; - - f.close(); - } - } - - - GBS::PAD_CKIN_ENZ::write(1); // disable to prevent startup spike damage - externalClockGenDetectAndInitialize(); - // library may change i2c clock or pins, so restart - startWire(); - GBS::STATUS_00::read(); - GBS::STATUS_00::read(); - GBS::STATUS_00::read(); - - // delay 2 of 2 - initDelay = millis(); - while (millis() - initDelay < 1000) { - handleWiFi(0); - delay(1); - } - - if (WiFi.status() == WL_CONNECTED) { - // nothing - } else if (WiFi.SSID().length() == 0) { - SerialM.println(FPSTR(ap_info_string)); - } else { - SerialM.println(F("(WiFi): still connecting..")); - WiFi.reconnect(); // only valid for station class (ok here) - } - - // dummy commands - GBS::STATUS_00::read(); - GBS::STATUS_00::read(); - GBS::STATUS_00::read(); - - boolean powerOrWireIssue = 0; - if (!checkBoardPower()) { - stopWire(); // sets pinmodes SDA, SCL to INPUT - for (int i = 0; i < 40; i++) { - // I2C SDA probably stuck, attempt recovery (max attempts in tests was around 10) - startWire(); - GBS::STATUS_00::read(); - digitalWrite(SCL, 0); - delayMicroseconds(12); - stopWire(); - if (digitalRead(SDA) == 1) { - break; - } // unstuck - if ((i % 7) == 0) { - delay(1); - } - } - - // restart and dummy - startWire(); - delay(1); - GBS::STATUS_00::read(); - delay(1); - - if (!checkBoardPower()) { - stopWire(); - powerOrWireIssue = 1; // fail - rto->boardHasPower = false; - rto->syncWatcherEnabled = false; - } else { // recover success - rto->syncWatcherEnabled = true; - rto->boardHasPower = true; - SerialM.println(F("recovered")); - } - } - - if (powerOrWireIssue == 0) { - // second init, in cases where i2c got stuck earlier but has recovered - // *if* ext clock gen is installed and *if* i2c got stuck, then clockgen must be already running - if (!rto->extClockGenDetected) { - externalClockGenDetectAndInitialize(); - } - if (rto->extClockGenDetected == 1) { - Serial.println(F("ext clockgen detected")); - } else { - Serial.println(F("no ext clockgen")); - } - - zeroAll(); - setResetParameters(); - prepareSyncProcessor(); - - uint8_t productId = GBS::CHIP_ID_PRODUCT::read(); - uint8_t revisionId = GBS::CHIP_ID_REVISION::read(); - SerialM.print(F("Chip ID: ")); - SerialM.print(productId, HEX); - SerialM.print(" "); - SerialM.println(revisionId, HEX); - - if (uopt->enableCalibrationADC) { - // enabled by default - calibrateAdcOffset(); - } - setResetParameters(); - - delay(4); // help wifi (presets are unloaded now) - handleWiFi(1); - delay(4); - - // startup reliability test routine - /*rto->videoStandardInput = 1; - writeProgramArrayNew(ntsc_240p, 0); - doPostPresetLoadSteps(); - int i = 100000; - while (i-- > 0) loop(); - ESP.restart();*/ - - //rto->syncWatcherEnabled = false; // allows passive operation by disabling syncwatcher here - //inputAndSyncDetect(); - //if (rto->syncWatcherEnabled == true) { - // rto->isInLowPowerMode = true; // just for initial detection; simplifies code later - // for (uint8_t i = 0; i < 3; i++) { - // if (inputAndSyncDetect()) { - // break; - // } - // } - // rto->isInLowPowerMode = false; - //} - } else { - SerialM.println(F("Please check board power and cabling or restart!")); - } - - LEDOFF; // LED behaviour: only light LED on active sync - - // some debug tools leave garbage in the serial rx buffer - if (Serial.available()) { - discardSerialRxData(); - } -} - -#if HAVE_BUTTONS -#define INPUT_SHIFT 0 -#define DOWN_SHIFT 1 -#define UP_SHIFT 2 -#define MENU_SHIFT 3 -#define BACK_SHIFT 4 - -static const uint8_t historySize = 32; -static const uint16_t buttonPollInterval = 100; // microseconds -static uint8_t buttonHistory[historySize]; -static uint8_t buttonIndex; -static uint8_t buttonState; -static uint8_t buttonChanged; - -uint8_t readButtons(void) -{ - return ~((digitalRead(pin_data) << INPUT_SHIFT) | - (digitalRead(pin_clk) << DOWN_SHIFT) | - (digitalRead(pin_data) << UP_SHIFT) | - (digitalRead(pin_switch) << MENU_SHIFT)); -} - -void debounceButtons(void) -{ - buttonHistory[buttonIndex++ % historySize] = readButtons(); - buttonChanged = 0xFF; - for (uint8_t i = 0; i < historySize; ++i) - buttonChanged &= buttonState ^ buttonHistory[i]; - buttonState ^= buttonChanged; -} - -bool buttonDown(uint8_t pos) -{ - return (buttonState & (1 << pos)) && (buttonChanged & (1 << pos)); -} - -void handleButtons(void) -{ -#if USE_NEW_OLED_MENU - OLEDMenuNav btn = OLEDMenuNav::IDLE; - debounceButtons(); - if (buttonDown(MENU_SHIFT)) - btn = OLEDMenuNav::ENTER; - if (buttonDown(DOWN_SHIFT)) - btn = OLEDMenuNav::UP; - if (buttonDown(UP_SHIFT)) - btn = OLEDMenuNav::DOWN; - oledMenu.tick(btn); -#else - debounceButtons(); - if (buttonDown(INPUT_SHIFT)) - Menu::run(MenuInput::BACK); - if (buttonDown(DOWN_SHIFT)) - Menu::run(MenuInput::DOWN); - // if (buttonDown(UP_SHIFT)) - // Menu::run(MenuInput::UP); - if (buttonDown(MENU_SHIFT)) - Menu::run(MenuInput::FORWARD); -#endif -} -#endif - -void discardSerialRxData() -{ - uint16_t maxThrowAway = 0x1fff; - while (Serial.available() && maxThrowAway > 0) { - Serial.read(); - maxThrowAway--; - } -} - -void updateWebSocketData() -{ - if (rto->webServerEnabled && rto->webServerStarted) { - if (webSocket.connectedClients() > 0) { - - constexpr size_t MESSAGE_LEN = 6; - char toSend[MESSAGE_LEN] = {0}; - toSend[0] = '#'; // makeshift ping in slot 0 - - if (rto->isCustomPreset) { - toSend[1] = '9'; - } else switch (rto->presetID) { - case 0x01: - case 0x11: - toSend[1] = '1'; - break; - case 0x02: - case 0x12: - toSend[1] = '2'; - break; - case 0x03: - case 0x13: - toSend[1] = '3'; - break; - case 0x04: - case 0x14: - toSend[1] = '4'; - break; - case 0x05: - case 0x15: - toSend[1] = '5'; - break; - case 0x06: - case 0x16: - toSend[1] = '6'; - break; - case PresetHdBypass: // bypass 1 - case PresetBypassRGBHV: // bypass 2 - toSend[1] = '8'; - break; - default: - toSend[1] = '0'; - break; - } - - toSend[2] = (char)uopt->presetSlot; - - // '@' = 0x40, used for "byte is present" detection; 0x80 not in ascii table - toSend[3] = '@'; - toSend[4] = '@'; - toSend[5] = '@'; - - if (uopt->enableAutoGain) { - toSend[3] |= (1 << 0); - } - if (uopt->wantScanlines) { - toSend[3] |= (1 << 1); - } - if (uopt->wantVdsLineFilter) { - toSend[3] |= (1 << 2); - } - if (uopt->wantPeaking) { - toSend[3] |= (1 << 3); - } - if (uopt->PalForce60) { - toSend[3] |= (1 << 4); - } - if (uopt->wantOutputComponent) { - toSend[3] |= (1 << 5); - } - - if (uopt->matchPresetSource) { - toSend[4] |= (1 << 0); - } - if (uopt->enableFrameTimeLock) { - toSend[4] |= (1 << 1); - } - if (uopt->deintMode) { - toSend[4] |= (1 << 2); - } - if (uopt->wantTap6) { - toSend[4] |= (1 << 3); - } - if (uopt->wantStepResponse) { - toSend[4] |= (1 << 4); - } - if (uopt->wantFullHeight) { - toSend[4] |= (1 << 5); - } - - if (uopt->enableCalibrationADC) { - toSend[5] |= (1 << 0); - } - if (uopt->preferScalingRgbhv) { - toSend[5] |= (1 << 1); - } - if (uopt->disableExternalClockGenerator) { - toSend[5] |= (1 << 2); - } - - // send ping and stats - if (ESP.getFreeHeap() > 14000) { - webSocket.broadcastTXT(toSend, MESSAGE_LEN); - } else { - webSocket.disconnect(); - } - } - } -} - -void handleWiFi(boolean instant) -{ - static unsigned long lastTimePing = millis(); - if (rto->webServerEnabled && rto->webServerStarted) { - MDNS.update(); - persWM.handleWiFi(); // if connected, returns instantly. otherwise it reconnects or opens AP - dnsServer.processNextRequest(); - - if ((millis() - lastTimePing) > 953) { // slightly odd value so not everything happens at once - webSocket.broadcastPing(); - } - if (((millis() - lastTimePing) > 973) || instant) { - if ((webSocket.connectedClients(false) > 0) || instant) { // true = with compliant ping - updateWebSocketData(); - } - lastTimePing = millis(); - } - } - - if (rto->allowUpdatesOTA) { - ArduinoOTA.handle(); - } - yield(); -} - -void myLog(char const* type, char command) { - SerialM.printf("%s command %c at settings source %d, custom slot %d, status %x\n", - type, command, uopt->presetPreference, uopt->presetSlot, rto->presetID); -} - -void loop() -{ - static uint8_t readout = 0; - static uint8_t segmentCurrent = 255; - static uint8_t registerCurrent = 255; - static uint8_t inputToogleBit = 0; - static uint8_t inputStage = 0; - static unsigned long lastTimeSyncWatcher = millis(); - static unsigned long lastTimeSourceCheck = 500; // 500 to start right away (after setup it will be 2790ms when we get here) - static unsigned long lastTimeInterruptClear = millis(); - -#if HAVE_BUTTONS - static unsigned long lastButton = micros(); - if (micros() - lastButton > buttonPollInterval) { - lastButton = micros(); - handleButtons(); - } -#endif - -#if USE_NEW_OLED_MENU - uint8_t oldIsrID = rotaryIsrID; - // make sure no rotary encoder isr happened while menu was updating. - // skipping this check will make the rotary encoder not responsive randomly. - // (oledNav change will be lost if isr happened during menu updating) - oledMenu.tick(oledNav); - if (oldIsrID == rotaryIsrID) { - oledNav = OLEDMenuNav::IDLE; - } -#else - settingsMenuOLED(); - if (oled_encoder_pos != oled_lastCount) { - oled_lastCount = oled_encoder_pos; - } -#endif - - handleWiFi(0); // WiFi + OTA + WS + MDNS, checks for server enabled + started - - // is there a command from Terminal or web ui? - // Serial takes precedence - if (Serial.available()) { - serialCommand = Serial.read(); - } else if (inputStage > 0) { - // multistage with no more data - SerialM.println(F(" abort")); - discardSerialRxData(); - serialCommand = ' '; - } - if (serialCommand != '@') { - // multistage with bad characters? - if (inputStage > 0) { - // need 's', 't' or 'g' - if (serialCommand != 's' && serialCommand != 't' && serialCommand != 'g') { - discardSerialRxData(); - SerialM.println(F(" abort")); - serialCommand = ' '; - } - } - myLog("serial", serialCommand); - - switch (serialCommand) { - case ' ': - // skip spaces - inputStage = segmentCurrent = registerCurrent = 0; // and reset these - break; - case 'd': { - // don't store scanlines - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { - disableScanlines(); - } - // pal forced 60hz: no need to revert here. let the voffset function handle it - - if (uopt->enableFrameTimeLock && FrameSync::getSyncLastCorrection() != 0) { - FrameSync::reset(uopt->frameTimeLockMethod); - } - // dump - for (int segment = 0; segment <= 5; segment++) { - dumpRegisters(segment); - } - SerialM.println("};"); - } break; - case '+': - SerialM.println("hor. +"); - shiftHorizontalRight(); - //shiftHorizontalRightIF(4); - break; - case '-': - SerialM.println("hor. -"); - shiftHorizontalLeft(); - //shiftHorizontalLeftIF(4); - break; - case '*': - shiftVerticalUpIF(); - break; - case '/': - shiftVerticalDownIF(); - break; - case 'z': - SerialM.println(F("scale+")); - scaleHorizontal(2, true); - break; - case 'h': - SerialM.println(F("scale-")); - scaleHorizontal(2, false); - break; - case 'q': - resetDigital(); - delay(2); - ResetSDRAM(); - delay(2); - togglePhaseAdjustUnits(); - //enableVDS(); - break; - case 'D': - SerialM.print(F("debug view: ")); - if (GBS::ADC_UNUSED_62::read() == 0x00) { // "remembers" debug view - //if (uopt->wantPeaking == 0) { GBS::VDS_PK_Y_H_BYPS::write(0); } // 3_4e 0 // enable peaking but don't store - GBS::VDS_PK_LB_GAIN::write(0x3f); // 3_45 - GBS::VDS_PK_LH_GAIN::write(0x3f); // 3_47 - GBS::ADC_UNUSED_60::write(GBS::VDS_Y_OFST::read()); // backup - GBS::ADC_UNUSED_61::write(GBS::HD_Y_OFFSET::read()); - GBS::ADC_UNUSED_62::write(1); // remember to remove on restore - GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 0x24); - GBS::HD_Y_OFFSET::write(GBS::HD_Y_OFFSET::read() + 0x24); - if (!rto->inputIsYpBpR) { - // RGB input that has HD_DYN bypassed, use it now - GBS::HD_DYN_BYPS::write(0); - GBS::HD_U_OFFSET::write(GBS::HD_U_OFFSET::read() + 0x24); - GBS::HD_V_OFFSET::write(GBS::HD_V_OFFSET::read() + 0x24); - } - //GBS::IF_IN_DREG_BYPS::write(1); // enhances noise from not delaying IF processing properly - SerialM.println("on"); - } else { - //if (uopt->wantPeaking == 0) { GBS::VDS_PK_Y_H_BYPS::write(1); } // 3_4e 0 - if (rto->presetID == 0x05) { - GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 - GBS::VDS_PK_LH_GAIN::write(0x0A); // 3_47 - } else { - GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 - GBS::VDS_PK_LH_GAIN::write(0x18); // 3_47 - } - GBS::VDS_Y_OFST::write(GBS::ADC_UNUSED_60::read()); // restore - GBS::HD_Y_OFFSET::write(GBS::ADC_UNUSED_61::read()); - if (!rto->inputIsYpBpR) { - // RGB input, HD_DYN_BYPS again - GBS::HD_DYN_BYPS::write(1); - GBS::HD_U_OFFSET::write(0); // probably just 0 by default - GBS::HD_V_OFFSET::write(0); // probably just 0 by default - } - //GBS::IF_IN_DREG_BYPS::write(0); - GBS::ADC_UNUSED_60::write(0); // .. and clear - GBS::ADC_UNUSED_61::write(0); - GBS::ADC_UNUSED_62::write(0); - SerialM.println("off"); - } - serialCommand = '@'; - break; - case 'C': - SerialM.println(F("PLL: ICLK")); - // display clock in last test best at 0x85 - GBS::PLL648_CONTROL_01::write(0x85); - GBS::PLL_CKIS::write(1); // PLL use ICLK (instead of oscillator) - latchPLLAD(); - //GBS::VDS_HSCALE::write(512); - rto->syncLockFailIgnore = 16; - FrameSync::reset(uopt->frameTimeLockMethod); // adjust htotal to new display clock - rto->forceRetime = true; - //applyBestHTotal(FrameSync::init()); // adjust htotal to new display clock - //applyBestHTotal(FrameSync::init()); // twice - //GBS::VDS_FLOCK_EN::write(1); //risky - delay(200); - break; - case 'Y': - writeProgramArrayNew(ntsc_1280x720, false); - doPostPresetLoadSteps(); - break; - case 'y': - writeProgramArrayNew(pal_1280x720, false); - doPostPresetLoadSteps(); - break; - case 'P': - SerialM.print(F("auto deinterlace: ")); - rto->deinterlaceAutoEnabled = !rto->deinterlaceAutoEnabled; - if (rto->deinterlaceAutoEnabled) { - SerialM.println("on"); - } else { - SerialM.println("off"); - } - break; - case 'p': - if (!rto->motionAdaptiveDeinterlaceActive) { - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { // don't rely on rto->scanlinesEnabled - disableScanlines(); - } - enableMotionAdaptDeinterlace(); - } else { - disableMotionAdaptDeinterlace(); - } - break; - case 'k': - bypassModeSwitch_RGBHV(); - break; - case 'K': - setOutModeHdBypass(false); - uopt->presetPreference = OutputBypass; - saveUserPrefs(); - break; - case 'T': - SerialM.print(F("auto gain ")); - if (uopt->enableAutoGain == 0) { - uopt->enableAutoGain = 1; - setAdcGain(AUTO_GAIN_INIT); - GBS::DEC_TEST_ENABLE::write(1); - SerialM.println("on"); - } else { - uopt->enableAutoGain = 0; - GBS::DEC_TEST_ENABLE::write(0); - SerialM.println("off"); - } - saveUserPrefs(); - break; - case 'e': - writeProgramArrayNew(ntsc_240p, false); - doPostPresetLoadSteps(); - break; - case 'r': - writeProgramArrayNew(pal_240p, false); - doPostPresetLoadSteps(); - break; - case '.': { - if (!rto->outModeHdBypass) { - // bestHtotal recalc - rto->autoBestHtotalEnabled = true; - rto->syncLockFailIgnore = 16; - rto->forceRetime = true; - FrameSync::reset(uopt->frameTimeLockMethod); - - if (!rto->syncWatcherEnabled) { - boolean autoBestHtotalSuccess = 0; - delay(30); - autoBestHtotalSuccess = runAutoBestHTotal(); - if (!autoBestHtotalSuccess) { - SerialM.println(F("(unchanged)")); - } - } - } - } break; - case '!': - //fastGetBestHtotal(); - //readEeprom(); - Serial.print(F("sfr: ")); - Serial.println(getSourceFieldRate(1)); - Serial.print(F("pll: ")); - Serial.println(getPllRate()); - break; - case '$': { - // EEPROM write protect pin (7, next to Vcc) is under original MCU control - // MCU drags to Vcc to write, EEPROM drags to Gnd normally - // This routine only works with that "WP" pin disconnected - // 0x17 = input selector? // 0x18 = input selector related? - // 0x54 = coast start 0x55 = coast end - uint16_t writeAddr = 0x54; - const uint8_t eepromAddr = 0x50; - for (; writeAddr < 0x56; writeAddr++) { - Wire.beginTransmission(eepromAddr); - Wire.write(writeAddr >> 8); // high addr byte, 4 bits + - Wire.write((uint8_t)writeAddr); // mlow addr byte, 8 bits = 12 bits (0xfff max) - Wire.write(0x10); // coast end value ? - Wire.endTransmission(); - delay(5); - } - - //Wire.beginTransmission(eepromAddr); - //Wire.write((uint8_t)0); Wire.write((uint8_t)0); - //Wire.write(0xff); // force eeprom clear probably - //Wire.endTransmission(); - //delay(5); - - Serial.println("done"); - } break; - case 'j': - //resetPLL(); - latchPLLAD(); - break; - case 'J': - resetPLLAD(); - break; - case 'v': - rto->phaseSP += 1; - rto->phaseSP &= 0x1f; - SerialM.print("SP: "); - SerialM.println(rto->phaseSP); - setAndLatchPhaseSP(); - //setAndLatchPhaseADC(); - break; - case 'b': - advancePhase(); - latchPLLAD(); - SerialM.print("ADC: "); - SerialM.println(rto->phaseADC); - break; - case '#': - rto->videoStandardInput = 13; - applyPresets(13); - //Serial.println(getStatus00IfHsVsStable()); - //globalDelay++; - //SerialM.println(globalDelay); - break; - case 'n': { - uint16_t pll_divider = GBS::PLLAD_MD::read(); - pll_divider += 1; - GBS::PLLAD_MD::write(pll_divider); - GBS::IF_HSYNC_RST::write((pll_divider / 2)); - GBS::IF_LINE_SP::write(((pll_divider / 2) + 1) + 0x40); - SerialM.print(F("PLL div: ")); - SerialM.print(pll_divider, HEX); - SerialM.print(" "); - SerialM.println(pll_divider); - // set IF before latching - //setIfHblankParameters(); - latchPLLAD(); - delay(1); - //applyBestHTotal(GBS::VDS_HSYNC_RST::read()); - updateClampPosition(); - updateCoastPosition(0); - } break; - case 'N': { - //if (GBS::RFF_ENABLE::read()) { - // disableMotionAdaptDeinterlace(); - //} - //else { - // enableMotionAdaptDeinterlace(); - //} - - //GBS::RFF_ENABLE::write(!GBS::RFF_ENABLE::read()); - - if (rto->scanlinesEnabled) { - rto->scanlinesEnabled = false; - disableScanlines(); - } else { - rto->scanlinesEnabled = true; - enableScanlines(); - } - } break; - case 'a': - SerialM.print(F("HTotal++: ")); - SerialM.println(GBS::VDS_HSYNC_RST::read() + 1); - if (GBS::VDS_HSYNC_RST::read() < 4095) { - if (uopt->enableFrameTimeLock) { - // syncLastCorrection != 0 check is included - FrameSync::reset(uopt->frameTimeLockMethod); - } - rto->forceRetime = 1; - applyBestHTotal(GBS::VDS_HSYNC_RST::read() + 1); - } - break; - case 'A': - SerialM.print(F("HTotal--: ")); - SerialM.println(GBS::VDS_HSYNC_RST::read() - 1); - if (GBS::VDS_HSYNC_RST::read() > 0) { - if (uopt->enableFrameTimeLock) { - // syncLastCorrection != 0 check is included - FrameSync::reset(uopt->frameTimeLockMethod); - } - rto->forceRetime = 1; - applyBestHTotal(GBS::VDS_HSYNC_RST::read() - 1); - } - break; - case 'M': { - } break; - case 'm': - SerialM.print(F("syncwatcher ")); - if (rto->syncWatcherEnabled == true) { - rto->syncWatcherEnabled = false; - if (rto->videoIsFrozen) { - unfreezeVideo(); - } - SerialM.println("off"); - } else { - rto->syncWatcherEnabled = true; - SerialM.println("on"); - } - break; - case ',': - printVideoTimings(); - break; - case 'i': - rto->printInfos = !rto->printInfos; - break; - case 'c': - SerialM.println(F("OTA Updates on")); - initUpdateOTA(); - rto->allowUpdatesOTA = true; - break; - case 'G': - SerialM.print(F("Debug Pings ")); - if (!rto->enableDebugPings) { - SerialM.println("on"); - rto->enableDebugPings = 1; - } else { - SerialM.println("off"); - rto->enableDebugPings = 0; - } - break; - case 'u': - ResetSDRAM(); - break; - case 'f': - SerialM.print(F("peaking ")); - if (uopt->wantPeaking == 0) { - uopt->wantPeaking = 1; - GBS::VDS_PK_Y_H_BYPS::write(0); - SerialM.println("on"); - } else { - uopt->wantPeaking = 0; - GBS::VDS_PK_Y_H_BYPS::write(1); - SerialM.println("off"); - } - saveUserPrefs(); - break; - case 'F': - SerialM.print(F("ADC filter ")); - if (GBS::ADC_FLTR::read() > 0) { - GBS::ADC_FLTR::write(0); - SerialM.println("off"); - } else { - GBS::ADC_FLTR::write(3); - SerialM.println("on"); - } - break; - case 'L': { - // Component / VGA Output - uopt->wantOutputComponent = !uopt->wantOutputComponent; - OutputComponentOrVGA(); - saveUserPrefs(); - // apply 1280x720 preset now, otherwise a reboot would be required - uint8_t videoMode = getVideoMode(); - if (videoMode == 0) - videoMode = rto->videoStandardInput; - PresetPreference backup = uopt->presetPreference; - uopt->presetPreference = Output720P; - rto->videoStandardInput = 0; // force hard reset - applyPresets(videoMode); - uopt->presetPreference = backup; - } break; - case 'l': - SerialM.println(F("resetSyncProcessor")); - //freezeVideo(); - resetSyncProcessor(); - //delay(10); - //unfreezeVideo(); - break; - case 'Z': { - uopt->matchPresetSource = !uopt->matchPresetSource; - saveUserPrefs(); - uint8_t vidMode = getVideoMode(); - if (uopt->presetPreference == 0 && GBS::GBS_PRESET_ID::read() == 0x11) { - applyPresets(vidMode); - } else if (uopt->presetPreference == 4 && GBS::GBS_PRESET_ID::read() == 0x02) { - applyPresets(vidMode); - } - } break; - case 'W': - uopt->enableFrameTimeLock = !uopt->enableFrameTimeLock; - break; - case 'E': - writeProgramArrayNew(ntsc_1280x1024, false); - doPostPresetLoadSteps(); - break; - case 'R': - writeProgramArrayNew(pal_1280x1024, false); - doPostPresetLoadSteps(); - break; - case '0': - moveHS(4, true); - break; - case '1': - moveHS(4, false); - break; - case '2': - writeProgramArrayNew(pal_768x576, false); // ModeLine "720x576@50" 27 720 732 795 864 576 581 586 625 -hsync -vsync - doPostPresetLoadSteps(); - break; - case '3': - // - break; - case '4': { - // scale vertical + - if (GBS::VDS_VSCALE::read() <= 256) { - SerialM.println("limit"); - break; - } - scaleVertical(2, true); - // actually requires full vertical mask + position offset calculation - } break; - case '5': { - // scale vertical - - if (GBS::VDS_VSCALE::read() == 1023) { - SerialM.println("limit"); - break; - } - scaleVertical(2, false); - // actually requires full vertical mask + position offset calculation - } break; - case '6': - if (videoStandardInputIsPalNtscSd() && !rto->outModeHdBypass) { - if (GBS::IF_HBIN_SP::read() >= 10) { // IF_HBIN_SP: min 2 - GBS::IF_HBIN_SP::write(GBS::IF_HBIN_SP::read() - 8); // canvas move right - if ((GBS::IF_HSYNC_RST::read() - 4) > ((GBS::PLLAD_MD::read() >> 1) + 5)) { - GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() - 4); // shrink 1_0e - GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() - 4); // and 1_22 to go with it - } - } else { - SerialM.println("limit"); - } - } else if (!rto->outModeHdBypass) { - if (GBS::IF_HB_SP2::read() >= 4) - GBS::IF_HB_SP2::write(GBS::IF_HB_SP2::read() - 4); // 1_1a - else - GBS::IF_HB_SP2::write(GBS::IF_HSYNC_RST::read() - 0x30); - if (GBS::IF_HB_ST2::read() >= 4) - GBS::IF_HB_ST2::write(GBS::IF_HB_ST2::read() - 4); // 1_18 - else - GBS::IF_HB_ST2::write(GBS::IF_HSYNC_RST::read() - 0x30); - SerialM.print(F("IF_HB_ST2: ")); - SerialM.print(GBS::IF_HB_ST2::read(), HEX); - SerialM.print(F(" IF_HB_SP2: ")); - SerialM.println(GBS::IF_HB_SP2::read(), HEX); - } - break; - case '7': - if (videoStandardInputIsPalNtscSd() && !rto->outModeHdBypass) { - if (GBS::IF_HBIN_SP::read() < 0x150) { // (arbitrary) max limit - GBS::IF_HBIN_SP::write(GBS::IF_HBIN_SP::read() + 8); // canvas move left - } else { - SerialM.println("limit"); - } - } else if (!rto->outModeHdBypass) { - if (GBS::IF_HB_SP2::read() < (GBS::IF_HSYNC_RST::read() - 0x30)) - GBS::IF_HB_SP2::write(GBS::IF_HB_SP2::read() + 4); // 1_1a - else - GBS::IF_HB_SP2::write(0); - if (GBS::IF_HB_ST2::read() < (GBS::IF_HSYNC_RST::read() - 0x30)) - GBS::IF_HB_ST2::write(GBS::IF_HB_ST2::read() + 4); // 1_18 - else - GBS::IF_HB_ST2::write(0); - SerialM.print(F("IF_HB_ST2: ")); - SerialM.print(GBS::IF_HB_ST2::read(), HEX); - SerialM.print(F(" IF_HB_SP2: ")); - SerialM.println(GBS::IF_HB_SP2::read(), HEX); - } - break; - case '8': - //SerialM.println("invert sync"); - invertHS(); - invertVS(); - //optimizePhaseSP(); - break; - case '9': - writeProgramArrayNew(ntsc_720x480, false); - doPostPresetLoadSteps(); - break; - case 'o': { - if (rto->osr == 1) { - setOverSampleRatio(2, false); - } else if (rto->osr == 2) { - setOverSampleRatio(4, false); - } else if (rto->osr == 4) { - setOverSampleRatio(1, false); - } - delay(4); - optimizePhaseSP(); - SerialM.print("OSR "); - SerialM.print(rto->osr); - SerialM.println("x"); - rto->phaseIsSet = 0; // do it again in modes applicable - } break; - case 'g': - inputStage++; - // we have a multibyte command - if (inputStage > 0) { - if (inputStage == 1) { - segmentCurrent = Serial.parseInt(); - SerialM.print("G"); - SerialM.print(segmentCurrent); - } else if (inputStage == 2) { - char szNumbers[3]; - szNumbers[0] = Serial.read(); - szNumbers[1] = Serial.read(); - szNumbers[2] = '\0'; - //char * pEnd; - registerCurrent = strtol(szNumbers, NULL, 16); - SerialM.print("R"); - SerialM.print(registerCurrent, HEX); - if (segmentCurrent <= 5) { - writeOneByte(0xF0, segmentCurrent); - readFromRegister(registerCurrent, 1, &readout); - SerialM.print(" value: 0x"); - SerialM.println(readout, HEX); - } else { - discardSerialRxData(); - SerialM.println("abort"); - } - inputStage = 0; - } - } - break; - case 's': - inputStage++; - // we have a multibyte command - if (inputStage > 0) { - if (inputStage == 1) { - segmentCurrent = Serial.parseInt(); - SerialM.print("S"); - SerialM.print(segmentCurrent); - } else if (inputStage == 2) { - char szNumbers[3]; - for (uint8_t a = 0; a <= 1; a++) { - // ascii 0x30 to 0x39 for '0' to '9' - if ((Serial.peek() >= '0' && Serial.peek() <= '9') || - (Serial.peek() >= 'a' && Serial.peek() <= 'f') || - (Serial.peek() >= 'A' && Serial.peek() <= 'F')) { - szNumbers[a] = Serial.read(); - } else { - szNumbers[a] = 0; // NUL char - Serial.read(); // but consume the char - } - } - szNumbers[2] = '\0'; - //char * pEnd; - registerCurrent = strtol(szNumbers, NULL, 16); - SerialM.print("R"); - SerialM.print(registerCurrent, HEX); - } else if (inputStage == 3) { - char szNumbers[3]; - for (uint8_t a = 0; a <= 1; a++) { - if ((Serial.peek() >= '0' && Serial.peek() <= '9') || - (Serial.peek() >= 'a' && Serial.peek() <= 'f') || - (Serial.peek() >= 'A' && Serial.peek() <= 'F')) { - szNumbers[a] = Serial.read(); - } else { - szNumbers[a] = 0; // NUL char - Serial.read(); // but consume the char - } - } - szNumbers[2] = '\0'; - //char * pEnd; - inputToogleBit = strtol(szNumbers, NULL, 16); - if (segmentCurrent <= 5) { - writeOneByte(0xF0, segmentCurrent); - readFromRegister(registerCurrent, 1, &readout); - SerialM.print(" (was 0x"); - SerialM.print(readout, HEX); - SerialM.print(")"); - writeOneByte(registerCurrent, inputToogleBit); - readFromRegister(registerCurrent, 1, &readout); - SerialM.print(" is now: 0x"); - SerialM.println(readout, HEX); - } else { - discardSerialRxData(); - SerialM.println("abort"); - } - inputStage = 0; - } - } - break; - case 't': - inputStage++; - // we have a multibyte command - if (inputStage > 0) { - if (inputStage == 1) { - segmentCurrent = Serial.parseInt(); - SerialM.print("T"); - SerialM.print(segmentCurrent); - } else if (inputStage == 2) { - char szNumbers[3]; - for (uint8_t a = 0; a <= 1; a++) { - // ascii 0x30 to 0x39 for '0' to '9' - if ((Serial.peek() >= '0' && Serial.peek() <= '9') || - (Serial.peek() >= 'a' && Serial.peek() <= 'f') || - (Serial.peek() >= 'A' && Serial.peek() <= 'F')) { - szNumbers[a] = Serial.read(); - } else { - szNumbers[a] = 0; // NUL char - Serial.read(); // but consume the char - } - } - szNumbers[2] = '\0'; - //char * pEnd; - registerCurrent = strtol(szNumbers, NULL, 16); - SerialM.print("R"); - SerialM.print(registerCurrent, HEX); - } else if (inputStage == 3) { - if (Serial.peek() >= '0' && Serial.peek() <= '7') { - inputToogleBit = Serial.parseInt(); - } else { - inputToogleBit = 255; // will get discarded next step - } - SerialM.print(" Bit: "); - SerialM.print(inputToogleBit); - inputStage = 0; - if ((segmentCurrent <= 5) && (inputToogleBit <= 7)) { - writeOneByte(0xF0, segmentCurrent); - readFromRegister(registerCurrent, 1, &readout); - SerialM.print(" (was 0x"); - SerialM.print(readout, HEX); - SerialM.print(")"); - writeOneByte(registerCurrent, readout ^ (1 << inputToogleBit)); - readFromRegister(registerCurrent, 1, &readout); - SerialM.print(" is now: 0x"); - SerialM.println(readout, HEX); - } else { - discardSerialRxData(); - inputToogleBit = registerCurrent = 0; - SerialM.println("abort"); - } - } - } - break; - case '<': { - if (segmentCurrent != 255 && registerCurrent != 255) { - writeOneByte(0xF0, segmentCurrent); - readFromRegister(registerCurrent, 1, &readout); - writeOneByte(registerCurrent, readout - 1); // also allow wrapping - Serial.print("S"); - Serial.print(segmentCurrent); - Serial.print("_"); - Serial.print(registerCurrent, HEX); - readFromRegister(registerCurrent, 1, &readout); - Serial.print(" : "); - Serial.println(readout, HEX); - } - } break; - case '>': { - if (segmentCurrent != 255 && registerCurrent != 255) { - writeOneByte(0xF0, segmentCurrent); - readFromRegister(registerCurrent, 1, &readout); - writeOneByte(registerCurrent, readout + 1); - Serial.print("S"); - Serial.print(segmentCurrent); - Serial.print("_"); - Serial.print(registerCurrent, HEX); - readFromRegister(registerCurrent, 1, &readout); - Serial.print(" : "); - Serial.println(readout, HEX); - } - } break; - case '_': { - uint32_t ticks = FrameSync::getPulseTicks(); - Serial.println(ticks); - } break; - case '~': - goLowPowerWithInputDetection(); // test reset + input detect - break; - case 'w': { - //Serial.flush(); - uint16_t value = 0; - String what = Serial.readStringUntil(' '); - - if (what.length() > 5) { - SerialM.println(F("abort")); - inputStage = 0; - break; - } - if (what.equals("f")) { - if (rto->extClockGenDetected) { - Serial.print(F("old freqExtClockGen: ")); - Serial.println((uint32_t)rto->freqExtClockGen); - rto->freqExtClockGen = Serial.parseInt(); - // safety range: 1 - 250 MHz - if (rto->freqExtClockGen >= 1000000 && rto->freqExtClockGen <= 250000000) { - Si.setFreq(0, rto->freqExtClockGen); - rto->clampPositionIsSet = 0; - rto->coastPositionIsSet = 0; - } - Serial.print(F("set freqExtClockGen: ")); - Serial.println((uint32_t)rto->freqExtClockGen); - } - break; - } - - value = Serial.parseInt(); - if (value < 4096) { - SerialM.print("set "); - SerialM.print(what); - SerialM.print(" "); - SerialM.println(value); - if (what.equals("ht")) { - //set_htotal(value); - if (!rto->outModeHdBypass) { - rto->forceRetime = 1; - applyBestHTotal(value); - } else { - GBS::VDS_HSYNC_RST::write(value); - } - } else if (what.equals("vt")) { - set_vtotal(value); - } else if (what.equals("hsst")) { - setHSyncStartPosition(value); - } else if (what.equals("hssp")) { - setHSyncStopPosition(value); - } else if (what.equals("hbst")) { - setMemoryHblankStartPosition(value); - } else if (what.equals("hbsp")) { - setMemoryHblankStopPosition(value); - } else if (what.equals("hbstd")) { - setDisplayHblankStartPosition(value); - } else if (what.equals("hbspd")) { - setDisplayHblankStopPosition(value); - } else if (what.equals("vsst")) { - setVSyncStartPosition(value); - } else if (what.equals("vssp")) { - setVSyncStopPosition(value); - } else if (what.equals("vbst")) { - setMemoryVblankStartPosition(value); - } else if (what.equals("vbsp")) { - setMemoryVblankStopPosition(value); - } else if (what.equals("vbstd")) { - setDisplayVblankStartPosition(value); - } else if (what.equals("vbspd")) { - setDisplayVblankStopPosition(value); - } else if (what.equals("sog")) { - setAndUpdateSogLevel(value); - } else if (what.equals("ifini")) { - GBS::IF_INI_ST::write(value); - //Serial.println(GBS::IF_INI_ST::read()); - } else if (what.equals("ifvst")) { - GBS::IF_VB_ST::write(value); - //Serial.println(GBS::IF_VB_ST::read()); - } else if (what.equals("ifvsp")) { - GBS::IF_VB_SP::write(value); - //Serial.println(GBS::IF_VB_ST::read()); - } else if (what.equals("vsstc")) { - setCsVsStart(value); - } else if (what.equals("vsspc")) { - setCsVsStop(value); - } - } else { - SerialM.println("abort"); - } - } break; - case 'x': { - uint16_t if_hblank_scale_stop = GBS::IF_HBIN_SP::read(); - GBS::IF_HBIN_SP::write(if_hblank_scale_stop + 1); - SerialM.print("1_26: "); - SerialM.println((if_hblank_scale_stop + 1), HEX); - } break; - case 'X': { - uint16_t if_hblank_scale_stop = GBS::IF_HBIN_SP::read(); - GBS::IF_HBIN_SP::write(if_hblank_scale_stop - 1); - SerialM.print("1_26: "); - SerialM.println((if_hblank_scale_stop - 1), HEX); - } break; - case '(': { - writeProgramArrayNew(ntsc_1920x1080, false); - doPostPresetLoadSteps(); - } break; - case ')': { - writeProgramArrayNew(pal_1920x1080, false); - doPostPresetLoadSteps(); - } break; - case 'V': { - SerialM.print(F("step response ")); - uopt->wantStepResponse = !uopt->wantStepResponse; - if (uopt->wantStepResponse) { - GBS::VDS_UV_STEP_BYPS::write(0); - SerialM.println("on"); - } else { - GBS::VDS_UV_STEP_BYPS::write(1); - SerialM.println("off"); - } - saveUserPrefs(); - } break; - case 'S': { - snapToIntegralFrameRate(); - break; - } - case ':': - externalClockGenSyncInOutRate(); - break; - case ';': - externalClockGenResetClock(); - if (rto->extClockGenDetected) { - rto->extClockGenDetected = 0; - Serial.println(F("ext clock gen bypass")); - } else { - rto->extClockGenDetected = 1; - Serial.println(F("ext clock gen active")); - externalClockGenSyncInOutRate(); - } - //{ - // float bla = 0; - // double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; - // bla = esp8266_clock_freq / (double)FrameSync::getPulseTicks(); - // Serial.println(bla, 5); - //} - break; - default: - Serial.print(F("unknown command ")); - Serial.println(serialCommand, HEX); - break; - } - - delay(1); // give some time to read in eventual next chars - - // a web ui or terminal command has finished. good idea to reset sync lock timer - // important if the command was to change presets, possibly others - lastVsyncLock = millis(); - - if (!Serial.available()) { - // in case we handled a Serial or web server command and there's no more extra commands - // but keep debug view command (resets once called) - if (serialCommand != 'D') { - serialCommand = '@'; - } - handleWiFi(1); - } - } - - if (userCommand != '@') { - handleType2Command(userCommand); - userCommand = '@'; // in case we handled web server command - lastVsyncLock = millis(); - handleWiFi(1); - } - - // run FrameTimeLock if enabled - if (uopt->enableFrameTimeLock && rto->sourceDisconnected == false && rto->autoBestHtotalEnabled && - rto->syncWatcherEnabled && FrameSync::ready() && millis() - lastVsyncLock > FrameSyncAttrs::lockInterval && rto->continousStableCounter > 20 && rto->noSyncCounter == 0) - { - uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); - uint16_t pllad = GBS::PLLAD_MD::read(); - - if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { - uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); - if (debug_backup != 0x0) { - GBS::TEST_BUS_SEL::write(0x0); - } - //unsigned long startTime = millis(); - fsDebugPrintf("running frame sync, clock gen enabled = %d\n", rto->extClockGenDetected); - bool success = rto->extClockGenDetected - ? FrameSync::runFrequency() - : FrameSync::runVsync(uopt->frameTimeLockMethod); - if (!success) { - if (rto->syncLockFailIgnore-- == 0) { - FrameSync::reset(uopt->frameTimeLockMethod); // in case run() failed because we lost sync signal - } - } else if (rto->syncLockFailIgnore > 0) { - rto->syncLockFailIgnore = 16; - } - //Serial.println(millis() - startTime); - - if (debug_backup != 0x0) { - GBS::TEST_BUS_SEL::write(debug_backup); - } - } - lastVsyncLock = millis(); - } - - if (rto->syncWatcherEnabled && rto->boardHasPower) { - if ((millis() - lastTimeInterruptClear) > 3000) { - GBS::INTERRUPT_CONTROL_00::write(0xfe); // reset except for SOGBAD - GBS::INTERRUPT_CONTROL_00::write(0x00); - lastTimeInterruptClear = millis(); - } - } - - // information mode - if (rto->printInfos == true) { - printInfo(); - } - - //uint16_t testbus = GBS::TEST_BUS::read() & 0x0fff; - //if (testbus >= 0x0FFD){ - // Serial.println(testbus,HEX); - //} - //if (rto->videoIsFrozen && (rto->continousStableCounter >= 2)) { - // unfreezeVideo(); - //} - - // syncwatcher polls SP status. when necessary, initiates adjustments or preset changes - if (rto->sourceDisconnected == false && rto->syncWatcherEnabled == true && (millis() - lastTimeSyncWatcher) > 20) { - runSyncWatcher(); - lastTimeSyncWatcher = millis(); - - // auto adc gain - if (uopt->enableAutoGain == 1 && !rto->sourceDisconnected && rto->videoStandardInput > 0 && rto->clampPositionIsSet && rto->noSyncCounter == 0 && rto->continousStableCounter > 90 && rto->boardHasPower) { - uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); - uint16_t pllad = GBS::PLLAD_MD::read(); - if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { - uint8_t debugRegBackup = 0, debugPinBackup = 0; - debugPinBackup = GBS::PAD_BOUT_EN::read(); - debugRegBackup = GBS::TEST_BUS_SEL::read(); - GBS::PAD_BOUT_EN::write(0); // disable output to pin for test - GBS::DEC_TEST_SEL::write(1); // luma and G channel - GBS::TEST_BUS_SEL::write(0xb); // decimation - if (GBS::STATUS_INT_SOG_BAD::read() == 0) { - runAutoGain(); - } - GBS::TEST_BUS_SEL::write(debugRegBackup); - GBS::PAD_BOUT_EN::write(debugPinBackup); // debug output pin back on - } - } - } - - // init frame sync + besthtotal routine - if (rto->autoBestHtotalEnabled && !FrameSync::ready() && rto->syncWatcherEnabled) { - if (rto->continousStableCounter >= 10 && rto->coastPositionIsSet && - ((millis() - lastVsyncLock) > 500)) { - if ((rto->continousStableCounter % 5) == 0) { // 5, 10, 15, .., 255 - uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); - uint16_t pllad = GBS::PLLAD_MD::read(); - if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { - runAutoBestHTotal(); - } - } - } - } - - // update clamp + coast positions after preset change // do it quickly - if ((rto->videoStandardInput <= 14 && rto->videoStandardInput != 0) && - rto->syncWatcherEnabled && !rto->coastPositionIsSet) { - if (rto->continousStableCounter >= 7) { - if ((getStatus16SpHsStable() == 1) && (getVideoMode() == rto->videoStandardInput)) { - updateCoastPosition(0); - if (rto->coastPositionIsSet) { - if (videoStandardInputIsPalNtscSd()) { - // todo: verify for other csync formats - GBS::SP_DIS_SUB_COAST::write(0); // enable 5_3e 5 - GBS::SP_H_PROTECT::write(0); // no 5_3e 4 - } - } - } - } - } - - // don't exclude modes 13 / 14 / 15 (rgbhv bypass) - if ((rto->videoStandardInput != 0) && (rto->continousStableCounter >= 4) && - !rto->clampPositionIsSet && rto->syncWatcherEnabled) { - updateClampPosition(); - if (rto->clampPositionIsSet) { - if (GBS::SP_NO_CLAMP_REG::read() == 1) { - GBS::SP_NO_CLAMP_REG::write(0); - } - } - } - - // later stage post preset adjustments - if ((rto->applyPresetDoneStage == 1) && - ((rto->continousStableCounter > 35 && rto->continousStableCounter < 45) || // this - !rto->syncWatcherEnabled)) // or that - { - if (rto->applyPresetDoneStage == 1) { - // 2nd chance - GBS::DAC_RGBS_PWDNZ::write(1); // 2nd chance - if (!uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 2nd chance - } - if (!rto->syncWatcherEnabled) { - updateClampPosition(); - GBS::SP_NO_CLAMP_REG::write(0); // 5_57 0 - } - - if (rto->extClockGenDetected && rto->videoStandardInput != 14) { - // switch to ext clock - if (!rto->outModeHdBypass) { - if (GBS::PLL648_CONTROL_01::read() != 0x35 && GBS::PLL648_CONTROL_01::read() != 0x75) { - // first store original in an option byte in 1_2D - GBS::GBS_PRESET_DISPLAY_CLOCK::write(GBS::PLL648_CONTROL_01::read()); - // enable and switch input - Si.enable(0); - delayMicroseconds(800); - GBS::PLL648_CONTROL_01::write(0x75); - } - } - // sync clocks now - externalClockGenSyncInOutRate(); - } - rto->applyPresetDoneStage = 0; - } - } else if (rto->applyPresetDoneStage == 1 && (rto->continousStableCounter > 35)) { - // 3rd chance - GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC // 3rd chance - if (!uopt->wantOutputComponent) { - GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 3rd chance - } - - // sync clocks now - externalClockGenSyncInOutRate(); - rto->applyPresetDoneStage = 0; // timeout - } - - if (rto->applyPresetDoneStage == 10) { - rto->applyPresetDoneStage = 11; // set first, so we don't loop applying presets - setOutModeHdBypass(false); - } - - if (rto->syncWatcherEnabled == true && rto->sourceDisconnected == true && rto->boardHasPower) { - if ((millis() - lastTimeSourceCheck) >= 500) { - if (checkBoardPower()) { - inputAndSyncDetect(); // source is off or just started; keep looking for new input - } else { - rto->boardHasPower = false; - rto->continousStableCounter = 0; - rto->syncWatcherEnabled = false; - } - lastTimeSourceCheck = millis(); - - // vary SOG slicer level from 2 to 6 - uint8_t currentSOG = GBS::ADC_SOGCTRL::read(); - if (currentSOG >= 3) { - rto->currentLevelSOG = currentSOG - 1; - GBS::ADC_SOGCTRL::write(rto->currentLevelSOG); - } else { - rto->currentLevelSOG = 6; - GBS::ADC_SOGCTRL::write(rto->currentLevelSOG); - } - } - } - - // has the GBS board lost power? // check at 2 points, in case one doesn't register - // low values chosen to not do this check on small sync issues - if ((rto->noSyncCounter == 61 || rto->noSyncCounter == 62) && rto->boardHasPower) { - if (!checkBoardPower()) { - rto->noSyncCounter = 1; // some neutral "no sync" value - rto->boardHasPower = false; - rto->continousStableCounter = 0; - //rto->syncWatcherEnabled = false; - stopWire(); // sets pinmodes SDA, SCL to INPUT - } else { - rto->noSyncCounter = 63; // avoid checking twice - } - } - - // power good now? // added syncWatcherEnabled check to enable passive mode + // power good now? + // added syncWatcherEnabled check to enable passive mode // (passive mode = watching OFW without interrupting) - if (!rto->boardHasPower && rto->syncWatcherEnabled) { // then check if power has come on + if (!rto.boardHasPower && rto.syncWatcherEnabled) { // then check if power has come on if (digitalRead(SCL) && digitalRead(SDA)) { delay(50); if (digitalRead(SCL) && digitalRead(SDA)) { - Serial.println(F("power good")); - delay(350); // i've seen the MTV230 go on briefly on GBS power cycle - startWire(); - { - // run some dummy commands to init I2C - GBS::SP_SOG_MODE::read(); - GBS::SP_SOG_MODE::read(); - writeOneByte(0xF0, 0); - writeOneByte(0x00, 0); // update cached segment - GBS::STATUS_00::read(); - } - rto->syncWatcherEnabled = true; - rto->boardHasPower = true; - delay(100); - goLowPowerWithInputDetection(); - } - } - } - -#ifdef HAVE_PINGER_LIBRARY - // periodic pings for debugging WiFi issues - if (WiFi.status() == WL_CONNECTED) { - if (rto->enableDebugPings && millis() - pingLastTime > 1000) { - // regular interval pings - if (pinger.Ping(WiFi.gatewayIP(), 1, 750) == false) { - Serial.println("Error during last ping command."); - } - pingLastTime = millis(); - } - } -#endif -} - -#if defined(ESP8266) -#include "webui_html.h" -// gzip -c9 webui.html > webui_html && xxd -i webui_html > webui_html.h && rm webui_html && sed -i -e 's/unsigned char webui_html\[]/const uint8_t webui_html[] PROGMEM/' webui_html.h && sed -i -e 's/unsigned int webui_html_len/const unsigned int webui_html_len/' webui_html.h - -void handleType2Command(char argument) -{ - myLog("user", argument); - switch (argument) { - case '0': - SerialM.print(F("pal force 60hz ")); - if (uopt->PalForce60 == 0) { - uopt->PalForce60 = 1; - SerialM.println("on"); - } else { - uopt->PalForce60 = 0; - SerialM.println("off"); - } - saveUserPrefs(); - break; - case '1': - // reset to defaults button - webSocket.close(); - loadDefaultUserOptions(); - saveUserPrefs(); - Serial.println(F("options set to defaults, restarting")); - delay(60); - ESP.reset(); // don't use restart(), messes up websocket reconnects - // - break; - case '2': - // - break; - case '3': // load custom preset - { - uopt->presetPreference = OutputCustomized; // custom - if (rto->videoStandardInput == 14) { - // vga upscale path: let synwatcher handle it - rto->videoStandardInput = 15; - } else { - // normal path - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - } break; - case '4': // save custom preset - savePresetToSPIFFS(); - uopt->presetPreference = OutputCustomized; // custom - saveUserPrefs(); - break; - case '5': - //Frame Time Lock toggle - uopt->enableFrameTimeLock = !uopt->enableFrameTimeLock; - saveUserPrefs(); - if (uopt->enableFrameTimeLock) { - SerialM.println(F("FTL on")); - } else { - SerialM.println(F("FTL off")); - } - if (!rto->extClockGenDetected) { - FrameSync::reset(uopt->frameTimeLockMethod); - } - if (uopt->enableFrameTimeLock) { - activeFrameTimeLockInitialSteps(); - } - break; - case '6': - // - break; - case '7': - uopt->wantScanlines = !uopt->wantScanlines; - SerialM.print(F("scanlines: ")); - if (uopt->wantScanlines) { - SerialM.println(F("on (Line Filter recommended)")); - } else { - disableScanlines(); - SerialM.println("off"); - } - saveUserPrefs(); - break; - case '9': - // - break; - case 'a': - webSocket.close(); - Serial.println(F("restart")); - delay(60); - ESP.reset(); // don't use restart(), messes up websocket reconnects - break; - case 'e': // print files on spiffs - { - Dir dir = SPIFFS.openDir("/"); - while (dir.next()) { - SerialM.print(dir.fileName()); - SerialM.print(" "); - SerialM.println(dir.fileSize()); - delay(1); // wifi stack - } - //// - File f = SPIFFS.open("/preferencesv2.txt", "r"); - if (!f) { - SerialM.println(F("failed opening preferences file")); - } else { - SerialM.print(F("preset preference = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("frame time lock = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("preset slot = ")); - SerialM.println((uint8_t)(f.read())); - SerialM.print(F("frame lock method = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("auto gain = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("scanlines = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("component output = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("deinterlacer mode = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("line filter = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("peaking = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("preferScalingRgbhv = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("6-tap = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("pal force60 = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("matched = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("step response = ")); - SerialM.println((uint8_t)(f.read() - '0')); - SerialM.print(F("disable external clock generator = ")); - SerialM.println((uint8_t)(f.read() - '0')); - - f.close(); - } - } break; - case 'f': - case 'g': - case 'h': - case 'p': - case 's': - case 'L': { - // load preset via webui - uint8_t videoMode = getVideoMode(); - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; // last known good as fallback - //else videoMode stays 0 and we'll apply via some assumptions - - if (argument == 'f') - uopt->presetPreference = Output960P; // 1280x960 - if (argument == 'g') - uopt->presetPreference = Output720P; // 1280x720 - if (argument == 'h') - uopt->presetPreference = Output480P; // 720x480/768x576 - if (argument == 'p') - uopt->presetPreference = Output1024P; // 1280x1024 - if (argument == 's') - uopt->presetPreference = Output1080P; // 1920x1080 - if (argument == 'L') - uopt->presetPreference = OutputDownscale; // downscale - - rto->useHdmiSyncFix = 1; // disables sync out when programming preset - if (rto->videoStandardInput == 14) { - // vga upscale path: let synwatcher handle it - rto->videoStandardInput = 15; - } else { - // normal path - applyPresets(videoMode); - } - saveUserPrefs(); - } break; - case 'i': - // toggle active frametime lock method - if (!rto->extClockGenDetected) { - FrameSync::reset(uopt->frameTimeLockMethod); - } - if (uopt->frameTimeLockMethod == 0) { - uopt->frameTimeLockMethod = 1; - } else if (uopt->frameTimeLockMethod == 1) { - uopt->frameTimeLockMethod = 0; - } - saveUserPrefs(); - activeFrameTimeLockInitialSteps(); - break; - case 'l': - // cycle through available SDRAM clocks - { - uint8_t PLL_MS = GBS::PLL_MS::read(); - uint8_t memClock = 0; - - if (PLL_MS == 0) - PLL_MS = 2; - else if (PLL_MS == 2) - PLL_MS = 7; - else if (PLL_MS == 7) - PLL_MS = 4; - else if (PLL_MS == 4) - PLL_MS = 3; - else if (PLL_MS == 3) - PLL_MS = 5; - else if (PLL_MS == 5) - PLL_MS = 0; - - switch (PLL_MS) { - case 0: - memClock = 108; - break; - case 1: - memClock = 81; - break; // goes well with 4_2C = 0x14, 4_2D = 0x27 - case 2: - memClock = 10; - break; // feedback clock - case 3: - memClock = 162; - break; - case 4: - memClock = 144; - break; - case 5: - memClock = 185; - break; // slight OC - case 6: - memClock = 216; - break; // !OC! - case 7: - memClock = 129; - break; - default: - break; - } - GBS::PLL_MS::write(PLL_MS); - ResetSDRAM(); - if (memClock != 10) { - SerialM.print(F("SDRAM clock: ")); - SerialM.print(memClock); - SerialM.println("Mhz"); - } else { - SerialM.print(F("SDRAM clock: ")); - SerialM.println(F("Feedback clock")); - } - } - break; - case 'm': - SerialM.print(F("Line Filter: ")); - if (uopt->wantVdsLineFilter) { - uopt->wantVdsLineFilter = 0; - GBS::VDS_D_RAM_BYPS::write(1); - SerialM.println("off"); - } else { - uopt->wantVdsLineFilter = 1; - GBS::VDS_D_RAM_BYPS::write(0); - SerialM.println("on"); - } - saveUserPrefs(); - break; - case 'n': - SerialM.print(F("ADC gain++ : ")); - uopt->enableAutoGain = 0; - setAdcGain(GBS::ADC_RGCTRL::read() - 1); - SerialM.println(GBS::ADC_RGCTRL::read(), HEX); - break; - case 'o': - SerialM.print(F("ADC gain-- : ")); - uopt->enableAutoGain = 0; - setAdcGain(GBS::ADC_RGCTRL::read() + 1); - SerialM.println(GBS::ADC_RGCTRL::read(), HEX); - break; - case 'A': { - uint16_t htotal = GBS::VDS_HSYNC_RST::read(); - uint16_t hbstd = GBS::VDS_DIS_HB_ST::read(); - uint16_t hbspd = GBS::VDS_DIS_HB_SP::read(); - if ((hbstd > 4) && (hbspd < (htotal - 4))) { - GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() - 4); - GBS::VDS_DIS_HB_SP::write(GBS::VDS_DIS_HB_SP::read() + 4); - } else { - SerialM.println("limit"); - } - } break; - case 'B': { - uint16_t htotal = GBS::VDS_HSYNC_RST::read(); - uint16_t hbstd = GBS::VDS_DIS_HB_ST::read(); - uint16_t hbspd = GBS::VDS_DIS_HB_SP::read(); - if ((hbstd < (htotal - 4)) && (hbspd > 4)) { - GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() + 4); - GBS::VDS_DIS_HB_SP::write(GBS::VDS_DIS_HB_SP::read() - 4); - } else { - SerialM.println("limit"); - } - } break; - case 'C': { - // vert mask + - uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); - uint16_t vbstd = GBS::VDS_DIS_VB_ST::read(); - uint16_t vbspd = GBS::VDS_DIS_VB_SP::read(); - if ((vbstd > 6) && (vbspd < (vtotal - 4))) { - GBS::VDS_DIS_VB_ST::write(vbstd - 2); - GBS::VDS_DIS_VB_SP::write(vbspd + 2); - } else { - SerialM.println("limit"); - } - } break; - case 'D': { - // vert mask - - uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); - uint16_t vbstd = GBS::VDS_DIS_VB_ST::read(); - uint16_t vbspd = GBS::VDS_DIS_VB_SP::read(); - if ((vbstd < (vtotal - 4)) && (vbspd > 6)) { - GBS::VDS_DIS_VB_ST::write(vbstd + 2); - GBS::VDS_DIS_VB_SP::write(vbspd - 2); - } else { - SerialM.println("limit"); - } - } break; - case 'q': - if (uopt->deintMode != 1) { - uopt->deintMode = 1; - disableMotionAdaptDeinterlace(); - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read()) { - disableScanlines(); - } - saveUserPrefs(); - } - SerialM.println(F("Deinterlacer: Bob")); - break; - case 'r': - if (uopt->deintMode != 0) { - uopt->deintMode = 0; - saveUserPrefs(); - // will enable next loop() - } - SerialM.println(F("Deinterlacer: Motion Adaptive")); - break; - case 't': - // unused now - SerialM.print(F("6-tap: ")); - if (uopt->wantTap6 == 0) { - uopt->wantTap6 = 1; - GBS::VDS_TAP6_BYPS::write(0); - GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() - 1); - SerialM.println("on"); - } else { - uopt->wantTap6 = 0; - GBS::VDS_TAP6_BYPS::write(1); - GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() + 1); - SerialM.println("off"); - } - saveUserPrefs(); - break; - case 'u': - // restart to attempt wifi station mode connect - delay(30); - WiFi.mode(WIFI_STA); - WiFi.hostname(device_hostname_partial); // _full - delay(30); - ESP.reset(); - break; - case 'v': { - uopt->wantFullHeight = !uopt->wantFullHeight; - saveUserPrefs(); - uint8_t vidMode = getVideoMode(); - if (uopt->presetPreference == 5) { - if (GBS::GBS_PRESET_ID::read() == 0x05 || GBS::GBS_PRESET_ID::read() == 0x15) { - applyPresets(vidMode); - } - } - } break; - case 'w': - uopt->enableCalibrationADC = !uopt->enableCalibrationADC; - saveUserPrefs(); - break; - case 'x': - uopt->preferScalingRgbhv = !uopt->preferScalingRgbhv; - SerialM.print(F("preferScalingRgbhv: ")); - if (uopt->preferScalingRgbhv) { - SerialM.println("on"); - } else { - SerialM.println("off"); - } - saveUserPrefs(); - break; - case 'X': - SerialM.print(F("ExternalClockGenerator ")); - if (uopt->disableExternalClockGenerator == 0) { - uopt->disableExternalClockGenerator = 1; - SerialM.println("disabled"); - } else { - uopt->disableExternalClockGenerator = 0; - SerialM.println("enabled"); - } - saveUserPrefs(); - break; - case 'z': - // sog slicer level - if (rto->currentLevelSOG > 0) { - rto->currentLevelSOG -= 1; - } else { - rto->currentLevelSOG = 16; - } - setAndUpdateSogLevel(rto->currentLevelSOG); - optimizePhaseSP(); - SerialM.print("Phase: "); - SerialM.print(rto->phaseSP); - SerialM.print(" SOG: "); - SerialM.print(rto->currentLevelSOG); - SerialM.println(); - break; - case 'E': - // test option for now - SerialM.print(F("IF Auto Offset: ")); - toggleIfAutoOffset(); - if (GBS::IF_AUTO_OFST_EN::read()) { - SerialM.println("on"); - } else { - SerialM.println("off"); - } - break; - case 'F': - // freeze pic - if (GBS::CAPTURE_ENABLE::read()) { - GBS::CAPTURE_ENABLE::write(0); - } else { - GBS::CAPTURE_ENABLE::write(1); - } - break; - case 'K': - // scanline strength - if (uopt->scanlineStrength >= 0x10) { - uopt->scanlineStrength -= 0x10; - } else { - uopt->scanlineStrength = 0x50; - } - if (rto->scanlinesEnabled) { - GBS::MADPT_Y_MI_OFFSET::write(uopt->scanlineStrength); - GBS::MADPT_UV_MI_OFFSET::write(uopt->scanlineStrength); - } - saveUserPrefs(); - SerialM.print(F("Scanline Brightness: ")); - SerialM.println(uopt->scanlineStrength, HEX); - break; - case 'Z': - // brightness++ - GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 1); - SerialM.print(F("Brightness++ : ")); - SerialM.println(GBS::VDS_Y_OFST::read(), DEC); - break; - case 'T': - // brightness-- - GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() - 1); - SerialM.print(F("Brightness-- : ")); - SerialM.println(GBS::VDS_Y_OFST::read(), DEC); - break; - case 'N': - // contrast++ - GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() + 1); - SerialM.print(F("Contrast++ : ")); - SerialM.println(GBS::VDS_Y_GAIN::read(), DEC); - break; - case 'M': - // contrast-- - GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() - 1); - SerialM.print(F("Contrast-- : ")); - SerialM.println(GBS::VDS_Y_GAIN::read(), DEC); - break; - case 'Q': - // pb/u gain++ - GBS::VDS_UCOS_GAIN::write(GBS::VDS_UCOS_GAIN::read() + 1); - SerialM.print(F("Pb/U gain++ : ")); - SerialM.println(GBS::VDS_UCOS_GAIN::read(), DEC); - break; - case 'H': - // pb/u gain-- - GBS::VDS_UCOS_GAIN::write(GBS::VDS_UCOS_GAIN::read() - 1); - SerialM.print(F("Pb/U gain-- : ")); - SerialM.println(GBS::VDS_UCOS_GAIN::read(), DEC); - break; - break; - case 'P': - // pr/v gain++ - GBS::VDS_VCOS_GAIN::write(GBS::VDS_VCOS_GAIN::read() + 1); - SerialM.print(F("Pr/V gain++ : ")); - SerialM.println(GBS::VDS_VCOS_GAIN::read(), DEC); - break; - case 'S': - // pr/v gain-- - GBS::VDS_VCOS_GAIN::write(GBS::VDS_VCOS_GAIN::read() - 1); - SerialM.print(F("Pr/V gain-- : ")); - SerialM.println(GBS::VDS_VCOS_GAIN::read(), DEC); - break; - case 'O': - // info - if (GBS::ADC_INPUT_SEL::read() == 1) - { - SerialM.println("RGB reg"); - SerialM.println(F("------------ ")); - SerialM.print(F("Y_OFFSET: ")); - SerialM.println(GBS::VDS_Y_OFST::read(), DEC); - SerialM.print(F("U_OFFSET: ")); - SerialM.println( GBS::VDS_U_OFST::read(), DEC); - SerialM.print(F("V_OFFSET: ")); - SerialM.println(GBS::VDS_V_OFST::read(), DEC); - SerialM.print(F("Y_GAIN: ")); - SerialM.println(GBS::VDS_Y_GAIN::read(), DEC); - SerialM.print(F("USIN_GAIN: ")); - SerialM.println(GBS::VDS_USIN_GAIN::read(), DEC); - SerialM.print(F("UCOS_GAIN: ")); - SerialM.println(GBS::VDS_UCOS_GAIN::read(), DEC); - } - else - { - SerialM.println("YPbPr reg"); - SerialM.println(F("------------ ")); - SerialM.print(F("Y_OFFSET: ")); - SerialM.println(GBS::VDS_Y_OFST::read(), DEC); - SerialM.print(F("U_OFFSET: ")); - SerialM.println( GBS::VDS_U_OFST::read(), DEC); - SerialM.print(F("V_OFFSET: ")); - SerialM.println(GBS::VDS_V_OFST::read(), DEC); - SerialM.print(F("Y_GAIN: ")); - SerialM.println(GBS::VDS_Y_GAIN::read(), DEC); - SerialM.print(F("USIN_GAIN: ")); - SerialM.println(GBS::VDS_USIN_GAIN::read(), DEC); - SerialM.print(F("UCOS_GAIN: ")); - SerialM.println(GBS::VDS_UCOS_GAIN::read(), DEC); - } - break; - case 'U': - // default - if (GBS::ADC_INPUT_SEL::read() == 1) - { - GBS::VDS_Y_GAIN::write(128); - GBS::VDS_UCOS_GAIN::write(28); - GBS::VDS_VCOS_GAIN::write(41); - GBS::VDS_Y_OFST::write(0); - GBS::VDS_U_OFST::write(0); - GBS::VDS_V_OFST::write(0); - GBS::ADC_ROFCTRL::write(adco->r_off); - GBS::ADC_GOFCTRL::write(adco->g_off); - GBS::ADC_BOFCTRL::write(adco->b_off); - SerialM.println("RGB:defauit"); - } - else - { - GBS::VDS_Y_GAIN::write(128); - GBS::VDS_UCOS_GAIN::write(28); - GBS::VDS_VCOS_GAIN::write(41); - GBS::VDS_Y_OFST::write(254); - GBS::VDS_U_OFST::write(3); - GBS::VDS_V_OFST::write(3); - GBS::ADC_ROFCTRL::write(adco->r_off); - GBS::ADC_GOFCTRL::write(adco->g_off); - GBS::ADC_BOFCTRL::write(adco->b_off); - SerialM.println("YPbPr:defauit"); - } - break; - default: - break; - } -} - -//void webSocketEvent(uint8_t num, uint8_t type, uint8_t * payload, size_t length) { -// switch (type) { -// case WStype_DISCONNECTED: -// //Serial.print("WS: #"); Serial.print(num); Serial.print(" disconnected,"); -// //Serial.print(" remaining: "); Serial.println(webSocket.connectedClients()); -// break; -// case WStype_CONNECTED: -// //Serial.print("WS: #"); Serial.print(num); Serial.print(" connected, "); -// //Serial.print(" total: "); Serial.println(webSocket.connectedClients()); -// updateWebSocketData(); -// break; -// case WStype_PONG: -// //Serial.print("p"); -// updateWebSocketData(); -// break; -// } -//} - -WiFiEventHandler disconnectedEventHandler; - -void startWebserver() -{ - persWM.setApCredentials(ap_ssid, ap_password); - persWM.onConnect([]() { - SerialM.print(F("(WiFi): STA mode connected; IP: ")); - SerialM.println(WiFi.localIP().toString()); - if (MDNS.begin(device_hostname_partial, WiFi.localIP())) { // MDNS request for gbscontrol.local - //Serial.println("MDNS started"); - MDNS.addService("http", "tcp", 80); // Add service to MDNS-SD - MDNS.announce(); - } - SerialM.println(FPSTR(st_info_string)); - }); - persWM.onAp([]() { - SerialM.println(FPSTR(ap_info_string)); - // add mdns announce here as well? - }); - - disconnectedEventHandler = WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected &event) { - Serial.print("Station disconnected, reason: "); - Serial.println(event.reason); - }); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - //Serial.println("sending web page"); - if (ESP.getFreeHeap() > 10000) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", webui_html, webui_html_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - } - }); - - server.on("/sc", HTTP_GET, [](AsyncWebServerRequest *request) { - if (ESP.getFreeHeap() > 10000) { - int params = request->params(); - //Serial.print("got serial request params: "); - //Serial.println(params); - if (params > 0) { - AsyncWebParameter *p = request->getParam(0); - //Serial.println(p->name()); - serialCommand = p->name().charAt(0); - - // hack, problem with '+' command received via url param - if (serialCommand == ' ') { - serialCommand = '+'; - } - } - request->send(200); // reply - } - }); - - server.on("/uc", HTTP_GET, [](AsyncWebServerRequest *request) { - if (ESP.getFreeHeap() > 10000) { - int params = request->params(); - //Serial.print("got user request params: "); - //Serial.println(params); - if (params > 0) { - AsyncWebParameter *p = request->getParam(0); - //Serial.println(p->name()); - userCommand = p->name().charAt(0); - } - request->send(200); // reply - } - }); - - server.on("/wifi/connect", HTTP_POST, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = - request->beginResponse(200, "application/json", "true"); - request->send(response); - - if (request->arg("n").length()) { // n holds ssid - if (request->arg("p").length()) { // p holds password - // false = only save credentials, don't connect - WiFi.begin(request->arg("n").c_str(), request->arg("p").c_str(), 0, 0, false); - } else { - WiFi.begin(request->arg("n").c_str(), emptyString, 0, 0, false); - } - } else { - WiFi.begin(); - } - - userCommand = 'u'; // next loop, set wifi station mode and restart device - }); - - server.on("/bin/slots.bin", HTTP_GET, [](AsyncWebServerRequest *request) { - if (ESP.getFreeHeap() > 10000) { - SlotMetaArray slotsObject; - File slotsBinaryFileRead = SPIFFS.open(SLOTS_FILE, "r"); - - if (!slotsBinaryFileRead) { - File slotsBinaryFileWrite = SPIFFS.open(SLOTS_FILE, "w"); - for (int i = 0; i < SLOTS_TOTAL; i++) { - slotsObject.slot[i].slot = i; - slotsObject.slot[i].presetID = 0; - slotsObject.slot[i].scanlines = 0; - slotsObject.slot[i].scanlinesStrength = 0; - slotsObject.slot[i].wantVdsLineFilter = false; - slotsObject.slot[i].wantStepResponse = true; - slotsObject.slot[i].wantPeaking = true; - char emptySlotName[25] = "Empty "; - strncpy(slotsObject.slot[i].name, emptySlotName, 25); - } - slotsBinaryFileWrite.write((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileWrite.close(); - } else { - slotsBinaryFileRead.close(); - } - - request->send(SPIFFS, "/slots.bin", "application/octet-stream"); - } - }); - - server.on("/slot/set", HTTP_GET, [](AsyncWebServerRequest *request) { - bool result = false; - - if (ESP.getFreeHeap() > 10000) { - int params = request->params(); - - if (params > 0) { - AsyncWebParameter *slotParam = request->getParam(0); - String slotParamValue = slotParam->value(); - char slotValue[2]; - slotParamValue.toCharArray(slotValue, sizeof(slotValue)); - uopt->presetSlot = (uint8_t)slotValue[0]; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - result = true; - } - } - - request->send(200, "application/json", result ? "true" : "false"); - }); - - server.on("/slot/save", HTTP_GET, [](AsyncWebServerRequest *request) { - bool result = false; - - if (ESP.getFreeHeap() > 10000) { - int params = request->params(); - - if (params > 0) { - SlotMetaArray slotsObject; - File slotsBinaryFileRead = SPIFFS.open(SLOTS_FILE, "r"); - - if (slotsBinaryFileRead) { - slotsBinaryFileRead.read((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileRead.close(); - } else { - File slotsBinaryFileWrite = SPIFFS.open(SLOTS_FILE, "w"); - - for (int i = 0; i < SLOTS_TOTAL; i++) { - slotsObject.slot[i].slot = i; - slotsObject.slot[i].presetID = 0; - slotsObject.slot[i].scanlines = 0; - slotsObject.slot[i].scanlinesStrength = 0; - slotsObject.slot[i].wantVdsLineFilter = false; - slotsObject.slot[i].wantStepResponse = true; - slotsObject.slot[i].wantPeaking = true; - char emptySlotName[25] = "Empty "; - strncpy(slotsObject.slot[i].name, emptySlotName, 25); - } - - slotsBinaryFileWrite.write((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileWrite.close(); - } - - // index param - AsyncWebParameter *slotIndexParam = request->getParam(0); - String slotIndexString = slotIndexParam->value(); - uint8_t slotIndex = lowByte(slotIndexString.toInt()); - if (slotIndex >= SLOTS_TOTAL) { - goto fail; - } - - // name param - AsyncWebParameter *slotNameParam = request->getParam(1); - String slotName = slotNameParam->value(); - - char emptySlotName[25] = " "; - strncpy(slotsObject.slot[slotIndex].name, emptySlotName, 25); - - slotsObject.slot[slotIndex].slot = slotIndex; - slotName.toCharArray(slotsObject.slot[slotIndex].name, sizeof(slotsObject.slot[slotIndex].name)); - slotsObject.slot[slotIndex].presetID = rto->presetID; - slotsObject.slot[slotIndex].scanlines = uopt->wantScanlines; - slotsObject.slot[slotIndex].scanlinesStrength = uopt->scanlineStrength; - slotsObject.slot[slotIndex].wantVdsLineFilter = uopt->wantVdsLineFilter; - slotsObject.slot[slotIndex].wantStepResponse = uopt->wantStepResponse; - slotsObject.slot[slotIndex].wantPeaking = uopt->wantPeaking; - - File slotsBinaryOutputFile = SPIFFS.open(SLOTS_FILE, "w"); - slotsBinaryOutputFile.write((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryOutputFile.close(); - - result = true; - } - } - - fail: - request->send(200, "application/json", result ? "true" : "false"); - }); - - server.on("/slot/remove", HTTP_GET, [](AsyncWebServerRequest *request) { - bool result = false; - int params = request->params(); - AsyncWebParameter *p = request->getParam(0); - char param = p->name().charAt(0); - if (params > 0) - { - if (param == '0') - { - SerialM.println("Wait..."); - result = true; - } - else - { - Ascii8 slot = uopt->presetSlot; - Ascii8 nextSlot; - auto currentSlot = slotIndexMap.indexOf(slot); - - SlotMetaArray slotsObject; - File slotsBinaryFileRead = SPIFFS.open(SLOTS_FILE, "r"); - slotsBinaryFileRead.read((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileRead.close(); - String slotName = slotsObject.slot[currentSlot].name; - - // remove preset files - SPIFFS.remove("/preset_ntsc." + String((char)slot)); - SPIFFS.remove("/preset_pal." + String((char)slot)); - SPIFFS.remove("/preset_ntsc_480p." + String((char)slot)); - SPIFFS.remove("/preset_pal_576p." + String((char)slot)); - SPIFFS.remove("/preset_ntsc_720p." + String((char)slot)); - SPIFFS.remove("/preset_ntsc_1080p." + String((char)slot)); - SPIFFS.remove("/preset_medium_res." + String((char)slot)); - SPIFFS.remove("/preset_vga_upscale." + String((char)slot)); - SPIFFS.remove("/preset_unknown." + String((char)slot)); - - uint8_t loopCount = 0; - uint8_t flag = 1; - while (flag != 0) - { - slot = slotIndexMap[currentSlot + loopCount]; - nextSlot = slotIndexMap[currentSlot + loopCount + 1]; - flag = 0; - flag += SPIFFS.rename("/preset_ntsc." + String((char)(nextSlot)), "/preset_ntsc." + String((char)slot)); - flag += SPIFFS.rename("/preset_pal." + String((char)(nextSlot)), "/preset_pal." + String((char)slot)); - flag += SPIFFS.rename("/preset_ntsc_480p." + String((char)(nextSlot)), "/preset_ntsc_480p." + String((char)slot)); - flag += SPIFFS.rename("/preset_pal_576p." + String((char)(nextSlot)), "/preset_pal_576p." + String((char)slot)); - flag += SPIFFS.rename("/preset_ntsc_720p." + String((char)(nextSlot)), "/preset_ntsc_720p." + String((char)slot)); - flag += SPIFFS.rename("/preset_ntsc_1080p." + String((char)(nextSlot)), "/preset_ntsc_1080p." + String((char)slot)); - flag += SPIFFS.rename("/preset_medium_res." + String((char)(nextSlot)), "/preset_medium_res." + String((char)slot)); - flag += SPIFFS.rename("/preset_vga_upscale." + String((char)(nextSlot)), "/preset_vga_upscale." + String((char)slot)); - flag += SPIFFS.rename("/preset_unknown." + String((char)(nextSlot)), "/preset_unknown." + String((char)slot)); - - slotsObject.slot[currentSlot + loopCount].slot = slotsObject.slot[currentSlot + loopCount + 1].slot; - slotsObject.slot[currentSlot + loopCount].presetID = slotsObject.slot[currentSlot + loopCount + 1].presetID; - slotsObject.slot[currentSlot + loopCount].scanlines = slotsObject.slot[currentSlot + loopCount + 1].scanlines; - slotsObject.slot[currentSlot + loopCount].scanlinesStrength = slotsObject.slot[currentSlot + loopCount + 1].scanlinesStrength; - slotsObject.slot[currentSlot + loopCount].wantVdsLineFilter = slotsObject.slot[currentSlot + loopCount + 1].wantVdsLineFilter; - slotsObject.slot[currentSlot + loopCount].wantStepResponse = slotsObject.slot[currentSlot + loopCount + 1].wantStepResponse; - slotsObject.slot[currentSlot + loopCount].wantPeaking = slotsObject.slot[currentSlot + loopCount + 1].wantPeaking; - // slotsObject.slot[currentSlot + loopCount].name = slotsObject.slot[currentSlot + loopCount + 1].name; - strncpy(slotsObject.slot[currentSlot + loopCount].name, slotsObject.slot[currentSlot + loopCount + 1].name, 25); - loopCount++; + _DBGN(F("(!) board power recovered")); + delay(350); // i've seen the MTV230 go on briefly on GBS power cycle + startWire(); + delay(10); + if(powerLossBoardReinit()) { + // { + // // run some dummy commands to init I2C + // writeOneByte(0xF0, 0); + // GBS::SP_SOG_MODE::read(); + // GBS::SP_SOG_MODE::read(); + // // writeOneByte(0x00, 0); // update cached segment + // GBS::STATUS_00::read(); + // } + // rto.syncWatcherEnabled = true; + // utilsCheckBoardPower(); + // rto.boardHasPower = true; + delay(10); + goLowPowerWithInputDetection(); } - - File slotsBinaryFileWrite = SPIFFS.open(SLOTS_FILE, "w"); - slotsBinaryFileWrite.write((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileWrite.close(); - SerialM.println("Preset \"" + slotName + "\" removed"); - result = true; - } - } - - fail: - request->send(200, "application/json", result ? "true" : "false"); - }); - - server.on("/spiffs/upload", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", "true"); - }); - - server.on( - "/spiffs/upload", HTTP_POST, - [](AsyncWebServerRequest *request) { request->send(200, "application/json", "true"); }, - [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - if (!index) { - request->_tempFile = SPIFFS.open("/" + filename, "w"); - } - if (len) { - request->_tempFile.write(data, len); - } - if (final) { - request->_tempFile.close(); - } - }); - - server.on("/spiffs/download", HTTP_GET, [](AsyncWebServerRequest *request) { - if (ESP.getFreeHeap() > 10000) { - int params = request->params(); - if (params > 0) { - request->send(SPIFFS, request->getParam(0)->value(), String(), true); - } else { - request->send(200, "application/json", "false"); - } - } else { - request->send(200, "application/json", "false"); - } - }); - - server.on("/spiffs/dir", HTTP_GET, [](AsyncWebServerRequest *request) { - if (ESP.getFreeHeap() > 10000) { - Dir dir = SPIFFS.openDir("/"); - String output = "["; - - while (dir.next()) { - output += "\""; - output += dir.fileName(); - output += "\","; - delay(1); // wifi stack - } - - output += "]"; - - output.replace(",]", "]"); - - request->send(200, "application/json", output); - return; - } - request->send(200, "application/json", "false"); - }); - - server.on("/spiffs/format", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", SPIFFS.format() ? "true" : "false"); - }); - - server.on("/wifi/status", HTTP_GET, [](AsyncWebServerRequest *request) { - WiFiMode_t wifiMode = WiFi.getMode(); - request->send(200, "application/json", wifiMode == WIFI_AP ? "{\"mode\":\"ap\"}" : "{\"mode\":\"sta\",\"ssid\":\"" + WiFi.SSID() + "\"}"); - }); - - server.on("/gbs/restore-filters", HTTP_GET, [](AsyncWebServerRequest *request) { - SlotMetaArray slotsObject; - File slotsBinaryFileRead = SPIFFS.open(SLOTS_FILE, "r"); - bool result = false; - if (slotsBinaryFileRead) { - slotsBinaryFileRead.read((byte *)&slotsObject, sizeof(slotsObject)); - slotsBinaryFileRead.close(); - auto currentSlot = slotIndexMap.indexOf(uopt->presetSlot); - if (currentSlot == -1) { - goto fail; - } - - uopt->wantScanlines = slotsObject.slot[currentSlot].scanlines; - - SerialM.print(F("slot: ")); - SerialM.println(uopt->presetSlot); - SerialM.print(F("scanlines: ")); - if (uopt->wantScanlines) { - SerialM.println(F("on (Line Filter recommended)")); - } else { - disableScanlines(); - SerialM.println("off"); } - saveUserPrefs(); - - uopt->scanlineStrength = slotsObject.slot[currentSlot].scanlinesStrength; - uopt->wantVdsLineFilter = slotsObject.slot[currentSlot].wantVdsLineFilter; - uopt->wantStepResponse = slotsObject.slot[currentSlot].wantStepResponse; - uopt->wantPeaking = slotsObject.slot[currentSlot].wantPeaking; - result = true; } - - fail: - request->send(200, "application/json", result ? "true" : "false"); - }); - - //webSocket.onEvent(webSocketEvent); - - persWM.setConnectNonBlock(true); - if (WiFi.SSID().length() == 0) { - // no stored network to connect to > start AP mode right away - persWM.setupWiFiHandlers(); - persWM.startApMode(); - } else { - persWM.begin(); // first try connecting to stored network, go AP mode after timeout } - server.begin(); // Webserver for the site - webSocket.begin(); // Websocket for interaction - yield(); - #ifdef HAVE_PINGER_LIBRARY - // pinger library - pinger.OnReceive([](const PingerResponse &response) { - if (response.ReceivedResponse) { - Serial.printf( - "Reply from %s: time=%lums\n", - response.DestIPAddress.toString().c_str(), - response.ResponseTime); - - pingLastTime = millis() - 900; // produce a fast stream of pings if connection is good - } else { - Serial.printf("Request timed out.\n"); - } - - // Return true to continue the ping sequence. - // If current event returns false, the ping sequence is interrupted. - return true; - }); - - pinger.OnEnd([](const PingerResponse &response) { - // detailed info not necessary - return true; - }); -#endif -} - -void initUpdateOTA() -{ - ArduinoOTA.setHostname("GBS OTA"); - - // ArduinoOTA.setPassword("admin"); - // Password can be set with it's md5 value as well - // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 - //ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); - - // update: no password is as (in)secure as this publicly stated hash.. - // rely on the user having to enable the OTA feature on the web ui - - ArduinoOTA.onStart([]() { - String type; - if (ArduinoOTA.getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - - // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() - SPIFFS.end(); - SerialM.println("Start updating " + type); - }); - ArduinoOTA.onEnd([]() { - SerialM.println("\nEnd"); - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - SerialM.printf("Progress: %u%%\r", (progress / (total / 100))); - }); - ArduinoOTA.onError([](ota_error_t error) { - SerialM.printf("Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) - SerialM.println("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) - SerialM.println("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) - SerialM.println("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) - SerialM.println("Receive Failed"); - else if (error == OTA_END_ERROR) - SerialM.println("End Failed"); - }); - ArduinoOTA.begin(); - yield(); -} - -// sets every element of str to 0 (clears array) -void StrClear(char *str, uint16_t length) -{ - for (int i = 0; i < length; i++) { - str[i] = 0; - } -} - -const uint8_t *loadPresetFromSPIFFS(byte forVideoMode) -{ - static uint8_t preset[432]; - String s = ""; - Ascii8 slot = 0; - File f; - - f = SPIFFS.open("/preferencesv2.txt", "r"); - if (f) { - SerialM.println(F("preferencesv2.txt opened")); - uint8_t result[3]; - result[0] = f.read(); // todo: move file cursor manually - result[1] = f.read(); - result[2] = f.read(); - - f.close(); - slot = result[2]; - } else { - // file not found, we don't know what preset to load - SerialM.println(F("please select a preset slot first!")); // say "slot" here to make people save usersettings - if (forVideoMode == 2 || forVideoMode == 4) - return pal_240p; - else - return ntsc_240p; - } - - SerialM.print(F("loading from preset slot ")); - SerialM.print((char)slot); - SerialM.print(": "); - - if (forVideoMode == 1) { - f = SPIFFS.open("/preset_ntsc." + String((char)slot), "r"); - } else if (forVideoMode == 2) { - f = SPIFFS.open("/preset_pal." + String((char)slot), "r"); - } else if (forVideoMode == 3) { - f = SPIFFS.open("/preset_ntsc_480p." + String((char)slot), "r"); - } else if (forVideoMode == 4) { - f = SPIFFS.open("/preset_pal_576p." + String((char)slot), "r"); - } else if (forVideoMode == 5) { - f = SPIFFS.open("/preset_ntsc_720p." + String((char)slot), "r"); - } else if (forVideoMode == 6) { - f = SPIFFS.open("/preset_ntsc_1080p." + String((char)slot), "r"); - } else if (forVideoMode == 8) { - f = SPIFFS.open("/preset_medium_res." + String((char)slot), "r"); - } else if (forVideoMode == 14) { - f = SPIFFS.open("/preset_vga_upscale." + String((char)slot), "r"); - } else if (forVideoMode == 0) { - f = SPIFFS.open("/preset_unknown." + String((char)slot), "r"); - } - - if (!f) { - SerialM.println(F("no preset file for this slot and source")); - if (forVideoMode == 2 || forVideoMode == 4) - return pal_240p; - else - return ntsc_240p; - } else { - SerialM.println(f.name()); - s = f.readStringUntil('}'); - f.close(); - } - - char *tmp; - uint16_t i = 0; - tmp = strtok(&s[0], ","); - while (tmp) { - preset[i++] = (uint8_t)atoi(tmp); - tmp = strtok(NULL, ","); - yield(); // wifi stack - } - - return preset; -} - -void savePresetToSPIFFS() -{ - uint8_t readout = 0; - File f; - Ascii8 slot = 0; - - // first figure out if the user has set a preferenced slot - f = SPIFFS.open("/preferencesv2.txt", "r"); - if (f) { - uint8_t result[3]; - result[0] = f.read(); // todo: move file cursor manually - result[1] = f.read(); - result[2] = f.read(); - - f.close(); - slot = result[2]; // got the slot to save to now - } else { - // file not found, we don't know where to save this preset - SerialM.println(F("please select a preset slot first!")); - return; - } - - SerialM.print(F("saving to preset slot ")); - SerialM.println(String((char)slot)); - - if (rto->videoStandardInput == 1) { - f = SPIFFS.open("/preset_ntsc." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 2) { - f = SPIFFS.open("/preset_pal." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 3) { - f = SPIFFS.open("/preset_ntsc_480p." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 4) { - f = SPIFFS.open("/preset_pal_576p." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 5) { - f = SPIFFS.open("/preset_ntsc_720p." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 6) { - f = SPIFFS.open("/preset_ntsc_1080p." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 8) { - f = SPIFFS.open("/preset_medium_res." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 14) { - f = SPIFFS.open("/preset_vga_upscale." + String((char)slot), "w"); - } else if (rto->videoStandardInput == 0) { - f = SPIFFS.open("/preset_unknown." + String((char)slot), "w"); - } - - if (!f) { - SerialM.println(F("open save file failed!")); - } else { - SerialM.println(F("open save file ok")); - - GBS::GBS_PRESET_CUSTOM::write(1); // use one reserved bit to mark this as a custom preset - // don't store scanlines - if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { - disableScanlines(); - } - - if (!rto->extClockGenDetected) { - if (uopt->enableFrameTimeLock && FrameSync::getSyncLastCorrection() != 0) { - FrameSync::reset(uopt->frameTimeLockMethod); - } - } - - for (int i = 0; i <= 5; i++) { - writeOneByte(0xF0, i); - switch (i) { - case 0: - for (int x = 0x40; x <= 0x5F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - for (int x = 0x90; x <= 0x9F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - break; - case 1: - for (int x = 0x0; x <= 0x2F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - break; - case 2: - // not needed anymore - break; - case 3: - for (int x = 0x0; x <= 0x7F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - break; - case 4: - for (int x = 0x0; x <= 0x5F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - break; - case 5: - for (int x = 0x0; x <= 0x6F; x++) { - readFromRegister(x, 1, &readout); - f.print(readout); - f.println(","); - } - break; + // periodic pings for debugging WiFi issues + if (WiFi.status() == WL_CONNECTED) { + if (rto.enableDebugPings && millis() - pingLastTime > 1000) { + // regular interval pings + if (pinger.Ping(WiFi.gatewayIP(), 1, 750) == false) { + _WSN(F("Error during last ping command.")); } + pingLastTime = millis(); } - f.println("};"); - SerialM.print(F("preset saved as: ")); - SerialM.println(f.name()); - f.close(); } -} +#endif // HAVE_PINGER_LIBRARY -void saveUserPrefs() -{ - File f = SPIFFS.open("/preferencesv2.txt", "w"); - if (!f) { - SerialM.println(F("saveUserPrefs: open file failed")); - return; + // Serial takes precedence + handleSerialCommand(); + // skip the code below if we don't have the web server +#if WEB_SERVER_ENABLE == 1 + // handle user commands + handleUserCommand(); + // web client handler + server.handleClient(); + MDNS.update(); + dnsServer.processNextRequest(); + // websocket event handler + webSocket.loop(); + // handle ArduinoIDE + if (rto.allowUpdatesOTA) { + ArduinoOTA.handle(); } - f.write(uopt->presetPreference + '0'); // #1 - f.write(uopt->enableFrameTimeLock + '0'); - f.write(uopt->presetSlot); - f.write(uopt->frameTimeLockMethod + '0'); - f.write(uopt->enableAutoGain + '0'); - f.write(uopt->wantScanlines + '0'); - f.write(uopt->wantOutputComponent + '0'); - f.write(uopt->deintMode + '0'); - f.write(uopt->wantVdsLineFilter + '0'); - f.write(uopt->wantPeaking + '0'); - f.write(uopt->preferScalingRgbhv + '0'); - f.write(uopt->wantTap6 + '0'); - f.write(uopt->PalForce60 + '0'); - f.write(uopt->matchPresetSource + '0'); // #14 - f.write(uopt->wantStepResponse + '0'); // #15 - f.write(uopt->wantFullHeight + '0'); // #16 - f.write(uopt->enableCalibrationADC + '0'); // #17 - f.write(uopt->scanlineStrength + '0'); // #18 - f.write(uopt->disableExternalClockGenerator + '0'); // #19 - - - f.close(); -} - #endif - -#if !USE_NEW_OLED_MENU -//OLED Functionality -void settingsMenuOLED() -{ - uint8_t videoMode = getVideoMode(); - byte button_nav = digitalRead(pin_switch); - if (button_nav == LOW) { - delay(350); //TODO - oled_subsetFrame++; //this button counter for navigating menu - oled_selectOption++; - } - //main menu - if (oled_page == 0) { - pointerfunction(); - display.clear(); - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.setFont(ArialMT_Plain_16); - display.drawString(0, oled_main_pointer, ">"); - display.drawString(14, 0, String(oled_menu[0])); - display.drawString(14, 15, String(oled_menu[1])); - display.drawString(14, 30, String(oled_menu[2])); - display.drawString(14, 45, String(oled_menu[3])); - display.display(); - } - //cursor location on main menu - if (oled_main_pointer == 0 && oled_subsetFrame == 0) { - oled_pointer_count = 0; - oled_menuItem = 1; - } - if (oled_main_pointer == 15 && oled_subsetFrame == 0) { - oled_pointer_count = 0; - oled_menuItem = 2; - } - if (oled_main_pointer == 30 && oled_subsetFrame == 0) { - oled_pointer_count = 0; - oled_sub_pointer = 0; - oled_menuItem = 3; - } - if (oled_main_pointer == 45 && oled_subsetFrame == 0) { - oled_pointer_count = 0; - oled_menuItem = 4; - } - - - //resolution pages - if (oled_menuItem == 1 && oled_subsetFrame == 1) { - oled_page = 1; - oled_main_pointer = 0; - subpointerfunction(); - display.clear(); - display.drawString(0, oled_sub_pointer, ">"); - display.drawString(14, 0, String(oled_Resolutions[0])); - display.drawString(14, 15, String(oled_Resolutions[1])); - display.drawString(14, 30, String(oled_Resolutions[2])); - display.drawString(14, 45, String(oled_Resolutions[3])); - display.display(); - } else if (oled_menuItem == 1 && oled_subsetFrame == 2) { - subpointerfunction(); - oled_page = 2; - display.clear(); - display.drawString(0, oled_sub_pointer, ">"); - display.drawString(14, 0, String(oled_Resolutions[4])); - display.drawString(14, 15, String(oled_Resolutions[5])); - display.drawString(14, 30, String(oled_Resolutions[6])); - display.drawString(14, 45, "-----Back"); - display.display(); - if (oled_sub_pointer <= -15) { - oled_page = 1; - oled_subsetFrame = 1; - oled_sub_pointer = 45; - display.clear(); - } else if (oled_sub_pointer > 45) { - oled_page = 2; - oled_subsetFrame = 2; - oled_sub_pointer = 45; - } - } - //selection - //1280x960 - if (oled_menuItem == 1) { - if (oled_pointer_count == 0 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "1280x960"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = Output960P; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - //1280x1024 - if (oled_pointer_count == 1 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "1280x1024"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = Output1024P; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - //1280x720 - if (oled_pointer_count == 2 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "1280x720"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = Output720P; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - //1920x1080 - if (oled_pointer_count == 3 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "1920x1080"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = Output1080P; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - //720x480 - if (oled_pointer_count == 4 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "480/576"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = Output480P; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - //downscale - if (oled_pointer_count == 5 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "Downscale"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) - videoMode = rto->videoStandardInput; - uopt->presetPreference = OutputDownscale; - rto->useHdmiSyncFix = 1; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(videoMode); - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - //passthrough/bypass - if (oled_pointer_count == 6 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "Pass-Through"); - display.drawString(0, 30, "Loaded!"); - display.display(); - } - setOutModeHdBypass(false); - uopt->presetPreference = OutputBypass; - if (uopt->presetPreference == 10 && rto->videoStandardInput != 15) { - rto->autoBestHtotalEnabled = 0; - if (rto->applyPresetDoneStage == 11) { - rto->applyPresetDoneStage = 1; - } else { - rto->applyPresetDoneStage = 10; - } - } else { - rto->applyPresetDoneStage = 1; - } - saveUserPrefs(); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - //go back - if (oled_pointer_count == 7 && oled_selectOption == 2) { - oled_page = 0; - oled_subsetFrame = 0; - oled_main_pointer = 0; - oled_sub_pointer = 0; - oled_selectOption = 0; - } - } - //Presets pages - if (oled_menuItem == 2 && oled_subsetFrame == 1) { - oled_page = 1; - oled_main_pointer = 0; - subpointerfunction(); - display.clear(); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset Slot:"); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, String(oled_Presets[oled_pointer_count])); - display.display(); - } else if (oled_menuItem == 2 && oled_subsetFrame == 2) { - oled_page = 2; - subpointerfunction(); - display.clear(); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset Slot:"); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, String(oled_Presets[oled_pointer_count])); - display.display(); - } - //Preset selection - if (oled_menuItem == 2) { - if (oled_pointer_count == 0 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'A'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); //first array element selected - display.drawString(64, -8, "Preset #" + String(oled_Presets[0])); //set to frame that "doesnt exist" - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); //display loading conf - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); //allowing "catchup" - oled_selectOption = 1; //reset select container - oled_subsetFrame = 1; //switch back to prev frame (prev screen) - } - if (oled_pointer_count == 1 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'B'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[1])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - if (oled_pointer_count == 2 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'C'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[2])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - if (oled_pointer_count == 3 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'D'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[3])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - if (oled_pointer_count == 4 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'E'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[4])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - if (oled_pointer_count == 5 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'F'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[5])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - if (oled_pointer_count == 6 && oled_selectOption == 2) { - oled_subsetFrame = 3; - uopt->presetSlot = 'G'; - uopt->presetPreference = OutputCustomized; - saveUserPrefs(); - for (int i = 0; i <= 280; i++) { - display.clear(); - display.setFont(Open_Sans_Regular_20); - display.drawString(64, -8, "Preset #" + String(oled_Presets[6])); - display.setFont(Open_Sans_Regular_35); - display.drawString(64, 15, "Loaded!"); - display.display(); - } - uopt->presetPreference = OutputCustomized; - if (rto->videoStandardInput == 14) { - rto->videoStandardInput = 15; - } else { - applyPresets(rto->videoStandardInput); - } - saveUserPrefs(); - delay(50); - oled_selectOption = 1; - oled_subsetFrame = 2; - } - if (oled_pointer_count == 7 && oled_selectOption == 2) { - oled_page = 0; - oled_subsetFrame = 0; - oled_main_pointer = 0; - oled_sub_pointer = 0; - oled_selectOption = 0; - } - } - //Misc pages - if (oled_menuItem == 3 && oled_subsetFrame == 1) { - oled_page = 1; - oled_main_pointer = 0; - subpointerfunction(); - display.clear(); - display.drawString(0, oled_sub_pointer, ">"); - display.drawString(14, 0, String(oled_Misc[0])); - display.drawString(14, 15, String(oled_Misc[1])); - display.drawString(14, 45, String(oled_Misc[2])); - display.display(); - if (oled_sub_pointer <= 0) { - oled_sub_pointer = 0; - } - if (oled_sub_pointer >= 45) { - oled_sub_pointer = 45; - } - } - //Misc selection - if (oled_menuItem == 3) { - if (oled_pointer_count == 0 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "Resetting GBS"); - display.drawString(0, 30, "Please Wait..."); - display.display(); - } - webSocket.close(); - delay(60); - ESP.reset(); - oled_selectOption = 0; - oled_subsetFrame = 0; - } - - if (oled_pointer_count == 1 && oled_selectOption == 2) { - oled_subsetFrame = 3; - for (int i = 0; i <= 800; i++) { - display.clear(); - display.drawString(0, 10, "Defaults Loading"); - display.drawString(0, 30, "Please Wait..."); - display.display(); - } - webSocket.close(); - loadDefaultUserOptions(); - saveUserPrefs(); - delay(60); - ESP.reset(); - oled_selectOption = 1; - oled_subsetFrame = 1; - } - - if (oled_pointer_count == 3 && oled_selectOption == 2) { - oled_page = 0; - oled_subsetFrame = 0; - oled_main_pointer = 0; - oled_sub_pointer = 0; - oled_selectOption = 0; - } - } - //Current Settings pages - if (oled_menuItem == 4 && oled_subsetFrame == 1) { - boolean vsyncActive = 0; - boolean hsyncActive = 0; - float ofr = getOutputFrameRate(); - uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); - rto->presetID = GBS::GBS_PRESET_ID::read(); - - oled_page = 1; - oled_pointer_count = 0; - oled_main_pointer = 0; - - subpointerfunction(); - display.clear(); - display.setFont(URW_Gothic_L_Book_20); - display.setTextAlignment(TEXT_ALIGN_LEFT); - - if (rto->presetID == 0x01 || rto->presetID == 0x11) { - display.drawString(0, 0, "1280x960"); - } else if (rto->presetID == 0x02 || rto->presetID == 0x12) { - display.drawString(0, 0, "1280x1024"); - } else if (rto->presetID == 0x03 || rto->presetID == 0x13) { - display.drawString(0, 0, "1280x720"); - } else if (rto->presetID == 0x05 || rto->presetID == 0x15) { - display.drawString(0, 0, "1920x1080"); - } else if (rto->presetID == 0x06 || rto->presetID == 0x16) { - display.drawString(0, 0, "Downscale"); - } else if (rto->presetID == 0x04) { - display.drawString(0, 0, "720x480"); - } else if (rto->presetID == 0x14) { - display.drawString(0, 0, "768x576"); - } else { - display.drawString(0, 0, "bypass"); - } - - display.drawString(0, 20, String(ofr, 5) + "Hz"); - - if (currentInput == 1) { - display.drawString(0, 41, "RGB"); - } else { - display.drawString(0, 41, "YpBpR"); - } - - if (currentInput == 1) { - vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); - if (vsyncActive) { - display.drawString(70, 41, "V"); - hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); - if (hsyncActive) { - display.drawString(53, 41, "H"); - } - } - } - display.display(); - } - //current setting Selection - if (oled_menuItem == 4) { - if (oled_pointer_count >= 0 && oled_selectOption == 2) { - oled_page = 0; - oled_subsetFrame = 0; - oled_main_pointer = 0; - oled_sub_pointer = 0; - oled_selectOption = 0; - } - } -} - -void pointerfunction() -{ - if (oled_main_pointer <= 0) { - oled_main_pointer = 0; - } - if (oled_main_pointer >= 45) { //limits - oled_main_pointer = 45; - } - - if (oled_pointer_count <= 0) { - oled_pointer_count = 0; - } else if (oled_pointer_count >= 3) { - oled_pointer_count = 3; - } -} -void subpointerfunction() -{ - if (oled_sub_pointer < 0) { - oled_sub_pointer = 0; - oled_subsetFrame = 1; - oled_page = 1; - } - if (oled_sub_pointer > 45) { //limits to switch between the two pages - oled_sub_pointer = 0; //TODO - oled_subsetFrame = 2; - oled_page = 2; - } - // } if (sub_pointer <= -15){ //TODO: replace/take out - // sub_pointer = 0; - // page = 1; - // subsetFrame = 1; - // } - if (oled_pointer_count <= 0) { - oled_pointer_count = 0; - } else if (oled_pointer_count >= 7) { - oled_pointer_count = 7; - } + // handle reset routine + resetInMSec(); } -#endif \ No newline at end of file diff --git a/generate_translations.py b/generate_translations.py deleted file mode 100644 index 0e67b98d..00000000 --- a/generate_translations.py +++ /dev/null @@ -1,265 +0,0 @@ -import json - -from PIL import Image, ImageDraw, ImageFont - -import json -import os.path -import pathlib -import sys -from argparse import ArgumentParser - -from PIL import Image, ImageDraw, ImageFont - -MENU_WIDTH = 128 -MENU_HEIGHT = 64 -MENU_STATUS_BAR_HEIGHT = MENU_HEIGHT / 4 -LEFT_RIGHT_PADDING = 0 -TOP_BOTTOM_PADDING = 1 -X_OFFSET = 0 -Y_OFFSET = -1 -DEFAULT_FONT_SIZE = 12 - -menu_items = [ - { - "tag": "OM_STATUS_CUSTOM", - "en-US": "Main Menu", - "zh-CN": "主菜单", - # should not be larger than 12 (or adjust according to MENU_STATUS_BAR_HEIGHT) - "size": 12, - }, - { - "tag": "OM_STATUS_BAR_BACK", - "en-US": "←Back", - # should not be larger than 12 (or adjust according to MENU_STATUS_BAR_HEIGHT) - "size": 12 - }, - { - "tag": "OM_SCREEN_SAVER", - "en-US": "Press Any Key", - }, - { - "tag": "OM_RESOLUTION", - "en-US": "Resolutions", - }, - { - "tag": "OM_PASSTHROUGH", - "en-US": "Passthrough", - }, - { - "tag": "OM_DOWNSCALE", - "en-US": "Down-Scale", - }, - { - "tag": "OM_PRESET", - "en-US": "Presets", - }, - { - "tag": "OM_RESET_RESTORE", - "en-US": "Reset/Restore", - }, - { - "tag": "OM_RESET_GBS", - "en-US": "Reset GBS", - }, - { - "tag": "OM_RESET_WIFI", - "en-US": "Clear WiFi Connections", - }, - { - "tag": "OM_RESTORE_FACTORY", - "en-US": "Restore Factory", - }, - { - "tag": "OM_CURRENT", - "en-US": "Current Output", - }, - { - "tag": "OM_WIFI", - "en-US": "WiFi Info", - }, - { - "tag": "TEXT_NO_PRESETS", - "en-US": "No Presets. Please use the Web UI to create one first.", - }, - { - "tag": "TEXT_TOO_MANY_PRESETS", - "en-US": "Please use WebUI to access more presets.", - }, - { - "tag": "TEXT_RESETTING_GBS", - "en-US": "Resetting GBS\nPlease wait\n...", - "size": 16, - }, - { - "tag": "TEXT_RESETTING_WIFI", - "en-US": "Resetting WiFi\nPlease wait\n...", - "size": 16, - }, - { - "tag": "TEXT_RESTORING", - "en-US": "Factory Restoring\nPlease wait\n...", - "size": 16, - }, - { - "tag": "TEXT_WIFI_CONNECT_TO", - "en-US": "Connect to the following SSID (password) before using the Web UI", - }, - { - "tag": "TEXT_WIFI_CONNECTED", - "en-US": "Status: Connected", - }, - { - "tag": "TEXT_WIFI_DISCONNECTED", - "en-US": "Status: Disconnected", - }, - { - "tag": "TEXT_WIFI_URL", - "en-US": "Use one of the following URLs to use the Web UI", - }, - { - "tag": "TEXT_LOADED", - "en-US": "Loaded", - "size": 16 - }, - { - "tag": "TEXT_NO_INPUT", - "en-US": "No Input", - "size": 16 - }, - { - "tag": "OM_OSD", - "en-US": "Open OSD Menu", - }, - - -] - -res = """ -#define %(name)s_WIDTH %(width)s -#define %(name)s_HEIGHT %(height)s -const unsigned char %(name)s [] PROGMEM = { -%(array)s -}; -""" - -tags_map = {} -fonts_map = {} -default_font = None - - -def convert(text, font): - img = Image.new('L', (0, 0), color=0) - draw = ImageDraw.Draw(img) - _, _, width, height = draw.textbbox((0, 0), text, font) - width += 2 * LEFT_RIGHT_PADDING - height += 2 * TOP_BOTTOM_PADDING # expand top and bottom - img = img.resize((width, height)) - draw = ImageDraw.Draw(img) - draw.text((LEFT_RIGHT_PADDING + X_OFFSET, TOP_BOTTOM_PADDING + - Y_OFFSET), text, 255, font, align='center') - byte_index = 0 - number = 0 - data = list(img.getdata()) - bytes_arr = [] - for index, pixel in enumerate(data): - if pixel >= 128: - number += 2 ** byte_index - byte_index += 1 - if byte_index == 8: - byte_index = -1 - # if this was the last pixel of a row or the last pixel of the - # image, fill up the rest of our byte with zeroes so it always contains 8 bits - if (index != 0 and (index + 1) % width == 0) or index == len(data): - byte_index = -1 - if byte_index < 0: - bytes_arr.append(number) - number = 0 - byte_index = 0 - img.save(f'i18n_preview_{tag}.jpg') - return width, height, bytes_arr - - -def collect(lang): - key = lang - if not lang: - key = "en-US" - for obj in menu_items: - if not isinstance(obj, dict): - raise TypeError(f"{obj} is not a dict") - if 'tag' not in obj: - raise KeyError(f'Key "tag" is missing in {obj}') - if key not in obj: - raise KeyError( - f'Key "{key}" does not exist in {json.dumps(obj, ensure_ascii=False)}') - size = obj.get('size') - tag = obj['tag'] - if tag in tags_map: - raise ValueError(f"Duplicated tag: {tag}") - translated = obj[key] - tags_map[tag] = translated, size - - -template = """ -#define %(name)s_WIDTH %(width)s -#define %(name)s_HEIGHT %(height)s -const unsigned char %(name)s [] PROGMEM = { -%(array)s -}; -""" -if __name__ == '__main__': - parser = ArgumentParser() - parser.add_argument('lang', help='Language code', nargs='?') - parser.add_argument('--fonts', '-f', nargs='*', default=[]) - parser.add_argument('--output', '-o', default='OLEDMenuTranslations.h') - args = parser.parse_args() - for font in args.fonts: - tokens = font.split('@') - if len(tokens) == 1: - default_font = tokens[0] - elif len(tokens) > 2: - raise ValueError(f"Too many tokens in {font}. Format: FONT_SIZE@PATH_TO_FONT") from None - else: - font_size, font_path = tokens - try: - font_size = int(font_size) - except ValueError: - raise ValueError(f"No a valid integer: {font}.") from None - fonts_map[font_size] = font_path - collect(args.lang) - tag_res_map = {} - - for _, (_, size) in tags_map.items(): - # pre-checks to avoid a corrupted header file. - if not size: - size = DEFAULT_FONT_SIZE - font = fonts_map.get(size, default_font) - if not font: - raise FileNotFoundError(f"No font for size {size}.") from None - try: - font = ImageFont.truetype(font) - except (OSError, FileNotFoundError): - raise FileNotFoundError(f"Font does not exist: {font}") from None - - with open(args.output, 'w') as fp: - fp.write('#ifndef OLED_MENU_TRANSLATIONS_H_\n') - fp.write('#define OLED_MENU_TRANSLATIONS_H_\n') - for tag, (text, size) in tags_map.items(): - if not size: - size = DEFAULT_FONT_SIZE - font = fonts_map.get(size, default_font) - font = ImageFont.truetype(font, size=size) - width, height, byte_array = convert(text, font) - tmp_str = "" - i = 0 - while i < len(byte_array): - if i + 16 < len(byte_array): - end = i + 16 - else: - end = len(byte_array) - tmp_str += ','.join([hex(x) - for x in byte_array[i:end]]) + ',\n' - i = end - fp.write(template % {'array': tmp_str, - 'width': width, 'height': height, 'name': tag}) - fp.write('#endif') - print(f"Finished. Output file: {pathlib.Path(args.output).absolute()}") diff --git a/options.h b/options.h deleted file mode 100644 index 1d7d743c..00000000 --- a/options.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef _USER_H_ -using Ascii8 = uint8_t; -/// Output resolution requested by user, *given to* applyPresets(). -enum PresetPreference : uint8_t { - Output960P = 0, - Output480P = 1, - OutputCustomized = 2, - Output720P = 3, - Output1024P = 4, - Output1080P = 5, - OutputDownscale = 6, - OutputBypass = 10, -}; - -// userOptions holds user preferences / customizations -struct userOptions -{ - // 0 - normal, 1 - x480/x576, 2 - customized, 3 - 1280x720, 4 - 1280x1024, 5 - 1920x1080, - // 6 - downscale, 10 - bypass - PresetPreference presetPreference; - Ascii8 presetSlot; - uint8_t enableFrameTimeLock; - uint8_t frameTimeLockMethod; - uint8_t enableAutoGain; - uint8_t wantScanlines; - uint8_t wantOutputComponent; - uint8_t deintMode; - uint8_t wantVdsLineFilter; - uint8_t wantPeaking; - uint8_t wantTap6; - uint8_t preferScalingRgbhv; - uint8_t PalForce60; - uint8_t disableExternalClockGenerator; - uint8_t matchPresetSource; - uint8_t wantStepResponse; - uint8_t wantFullHeight; - uint8_t enableCalibrationADC; - uint8_t scanlineStrength; -}; - - -// runTimeOptions holds system variables -struct runTimeOptions -{ - uint32_t freqExtClockGen; - uint16_t noSyncCounter; // is always at least 1 when checking value in syncwatcher - uint8_t presetVlineShift; - uint8_t videoStandardInput; // 0 - unknown, 1 - NTSC like, 2 - PAL like, 3 480p NTSC, 4 576p PAL - uint8_t phaseSP; - uint8_t phaseADC; - uint8_t currentLevelSOG; - uint8_t thisSourceMaxLevelSOG; - uint8_t syncLockFailIgnore; - uint8_t applyPresetDoneStage; - uint8_t continousStableCounter; - uint8_t failRetryAttempts; - uint8_t presetID; // PresetID - bool isCustomPreset; - uint8_t HPLLState; - uint8_t medResLineCount; - uint8_t osr; - uint8_t notRecognizedCounter; - bool isInLowPowerMode; - bool clampPositionIsSet; - bool coastPositionIsSet; - bool phaseIsSet; - bool inputIsYpBpR; - bool syncWatcherEnabled; - bool outModeHdBypass; - bool printInfos; - bool sourceDisconnected; - bool webServerEnabled; - bool webServerStarted; - bool allowUpdatesOTA; - bool enableDebugPings; - bool autoBestHtotalEnabled; - bool videoIsFrozen; - bool forceRetime; - bool motionAdaptiveDeinterlaceActive; - bool deinterlaceAutoEnabled; - bool scanlinesEnabled; - bool boardHasPower; - bool presetIsPalForce60; - bool syncTypeCsync; - bool isValidForScalingRGBHV; - bool useHdmiSyncFix; - bool extClockGenDetected; -}; -// remember adc options across presets -struct adcOptions -{ - // If `uopt->enableAutoGain == 1` and we're not before/during - // doPostPresetLoadSteps(), `adco->r_gain` must match `GBS::ADC_RGCTRL`. - // - // When we either set `uopt->enableAutoGain = 1` or call - // `GBS::ADC_RGCTRL::write()`, we must either call - // `GBS::ADC_RGCTRL::write(adco->r_gain)`, or set `adco->r_gain = - // GBS::ADC_RGCTRL::read()`. - uint8_t r_gain; - uint8_t g_gain; - uint8_t b_gain; - uint8_t r_off; - uint8_t g_off; - uint8_t b_off; -}; -#endif \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..0afec78f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,244 @@ +{ + "name": "gbscontrol-webui", + "version": "1.4.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gbscontrol-webui", + "version": "1.4.0", + "license": "GPL-3.0", + "devDependencies": { + "@node-minify/core": "^8.0.6", + "@node-minify/uglify-js": "^8.0.6", + "@types/node": "^20.14.2", + "prettier": "^3.2.5", + "typescript": "^4.1.3" + } + }, + "node_modules/@node-minify/core": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@node-minify/core/-/core-8.0.6.tgz", + "integrity": "sha512-/vxN46ieWDLU67CmgbArEvOb41zlYFOkOtr9QW9CnTrBLuTyGgkyNWC2y5+khvRw3Br58p2B5ZVSx/PxCTru6g==", + "dev": true, + "dependencies": { + "@node-minify/utils": "8.0.6", + "glob": "9.3.5", + "mkdirp": "1.0.4" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@node-minify/uglify-js": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@node-minify/uglify-js/-/uglify-js-8.0.6.tgz", + "integrity": "sha512-t6NNJwqnCwfFbbYOKv9bY3v43DcEkIUq4aaj4gtElJnx9tQaELiI0vsX9WuvQFrJlRI1xAwiNzYc+U05PWpscw==", + "dev": true, + "dependencies": { + "@node-minify/utils": "8.0.6", + "uglify-js": "3.17.4" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@node-minify/utils": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@node-minify/utils/-/utils-8.0.6.tgz", + "integrity": "sha512-csY4qcR7jUwiZmkreNTJhcypQfts2aY2CK+a+rXgXUImZiZiySh0FvwHjRnlqWKvg+y6ae9lHFzDRjBTmqlTIQ==", + "dev": true, + "dependencies": { + "gzip-size": "6.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..e4e6092c --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "gbscontrol-webui", + "version": "1.4.0", + "description": "gbscontrol-webui", + "author": "", + "license": "GPL-3.0", + "directories": { + "doc": "doc", + "test": "public/test" + }, + "main": "index.js", + "keywords": [ + "GBS-Control", + "GBSC" + ], + "scripts": { + "watch": "run-script-os", + "watch:windows": "tsc --project .\\tsconfig.json --watch", + "watch:linux:darwin": "tsc --project ./tsconfig.json --watch", + "build": "run-script-os", + "build:windows": "tsc --project .\\tsconfig.json && start .\\public\\scripts\\build.bat", + "build:linux:darwin": "./public/scripts/build.sh" + }, + "prettier": { + "trailingComma": "es5", + "tabWidth": 4, + "tabs": false, + "semi": false, + "bracketSpacing": true, + "singleQuote": true, + "bracketSameLine": true, + "requirePragma": false, + "insertPragma": false, + "proseWrap": "preserve" + }, + "devDependencies": { + "@node-minify/core": "^8.0.6", + "@node-minify/uglify-js": "^8.0.6", + "@types/node": "^20.14.2", + "prettier": "^3.2.5", + "typescript": "^4.1.3" + } +} diff --git a/platformio.ini b/platformio.ini index af2d8744..0fd0d986 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,26 +8,37 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [platformio] -lib_dir = ./src/ -src_dir = ./ +default_envs = d1_mini +src_dir = src +data_dir = data [env:d1_mini] -platform = espressif8266@2.6.3 +platform = espressif8266 board = d1_mini framework = arduino board_build.f_cpu = 160000000L board_build.ldscript = eagle.flash.4m1m.ld -upload_speed = 921600 +board_build.filesystem = littlefs +board_build.flash_mode = qio +; upload_protocol = espota +; upload_port = gbsc_ip_address +upload_speed = 57600 +; upload_resetmethod = ck monitor_speed = 115200 -lib_deps = - me-no-dev/ESPAsyncTCP@^1.2.2 - me-no-dev/ESP Async WebServer@^1.2.3 - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.4.0 - bluemurder/ESP8266-ping@^2.0.1 - ;r-downing/PersWiFiManager@^3.0.1 - ;links2004/WebSockets@^2.1.4 +extra_scripts = + pre:scripts/pre.py + scripts/extras.py +lib_deps = + https://github.com/Links2004/arduinoWebSockets.git + https://github.com/pavelmc/Si5351mcu.git + https://github.com/ThingPulse/esp8266-oled-ssd1306.git + https://github.com/bluemurder/esp8266-ping.git build_src_filter = - +<**/*.c> - +<**/*.cpp> - +<**/*.ino> - -<./3rdparty/*> \ No newline at end of file + +<*> + -<**/*.ino> + -<./temp/*> +build_flags = + -fmax-errors=3 + ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED + -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH + -D VTABLES_IN_FLASH \ No newline at end of file diff --git a/public/README.md b/public/README.md deleted file mode 100644 index 1a53bc47..00000000 --- a/public/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# GBSControl webui - -Redesigned UI for the GBSControl with added features: - -- 72 Named Slots avaliable -- Slots save current filters state. -- Slots filter state can be toggled between local/global -- Backup / Restore system -- Option to enable / disable developer options (hidden by default) -- Integrated wifi management in system menu - -## Building - -- `npm install` -- Make changes -- `npm run build` to generate the necesary files webui_html.h -- Compile & upload GBSControl project in Arduino IDE - -## Tips - -* Before every push do a `npm run build` to be sure bin files are updated to the latest. diff --git a/public/assets/fonts/FreeSans.ttf b/public/assets/fonts/FreeSans.ttf new file mode 100644 index 00000000..9db95853 Binary files /dev/null and b/public/assets/fonts/FreeSans.ttf differ diff --git a/public/assets/fonts/OFL.txt b/public/assets/fonts/OFL.txt new file mode 100644 index 00000000..0bf10679 --- /dev/null +++ b/public/assets/fonts/OFL.txt @@ -0,0 +1,450 @@ +OFL FAQ - Frequently Asked Questions about the SIL Open Font License (OFL) +Version 1.1-update7 - November 2023 +The OFL FAQ is Copyright (c) 2005-2023, SIL International (https://www.sil.org) +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +(See https://openfontlicense.org/ofl-faq for updates) + + +CONTENTS OF THIS FAQ +1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL +2 USING OFL FONTS FOR WEBPAGES AND ONLINE WEBFONT SERVICES +3 MODIFYING OFL-LICENSED FONTS +4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL +5 CHOOSING RESERVED FONT NAMES +6 ABOUT THE FONTLOG +7 MAKING CONTRIBUTIONS TO OFL PROJECTS +8 ABOUT THE LICENSE ITSELF +9 ABOUT SIL INTERNATIONAL +APPENDIX A - FONTLOG EXAMPLE + +1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL +1.1 Can I use the fonts for a book or other print publication, to create logos or other graphics, or even to manufacture objects based on their outlines? +Yes. You are very welcome to do so. Authors of fonts released under the OFL allow you to use their font software as such for any kind of design work. No additional license or permission is required, unlike with some other licenses. Some examples of these uses are: logos, posters, business cards, stationery, video titling, signage, t-shirts, personalised fabric, 3D-printed/laser-cut shapes, sculptures, rubber stamps, cookie cutters and lead type. + +1.1.1 Does that restrict the license or distribution of that artwork? +No. You remain the author and copyright holder of that newly derived graphic or object. You are simply using an open font in the design process. It is only when you redistribute, bundle or modify the font itself that other conditions of the license have to be respected (see below for more details). + +1.1.2 Is any kind of acknowledgement required? +No. Font authors may appreciate being mentioned in your artwork's acknowledgements alongside the name of the font, possibly with a link to their website, but that is not required. + +1.2 Can the fonts be included with Free/Libre and Open Source Software collections such as GNU/Linux and BSD distributions and repositories? +Yes! Fonts licensed under the OFL can be freely included alongside other software under FLOSS (Free/Libre and Open Source Software) licenses. Since fonts are typically aggregated with, not merged into, existing software, there is little need to be concerned about incompatibility with existing software licenses. You may also repackage the fonts and the accompanying components in a .rpm or .deb package (or other similar package formats or installers) and include them in distribution CD/DVDs and online repositories. (Also see entry 5.9 about rebuilding from source.) + +1.3 I want to distribute the fonts with my program, does this mean my program also has to be Free/Libre and Open Source Software? +No. Only the portions based on the Font Software are required to be released under the OFL. The intent of the license is to allow aggregation or bundling with software under restricted licensing as well. + +1.4 Can I sell a software package that includes these fonts? +Yes, you can do this with both the Original Version and a Modified Version of the fonts. Examples of bundling made possible by the OFL would include: text editors, word processors, design and publishing applications, training and educational software, games and entertainment software, mobile device applications, etc. + +1.5 Can I include the fonts on a CD of freeware or commercial fonts? +Yes, as long some other font or software is also on the disk, so the OFL font is not sold by itself. + +1.6 Why won't the OFL let me sell the fonts alone? +The intent is to keep people from making money by simply redistributing the fonts. The only people who ought to profit directly from the fonts should be the original authors, and those authors have kindly given up potential direct income to distribute their fonts under the OFL. Please honour and respect their contribution! + +1.7 What about sharing OFL fonts with friends on a CD, DVD or USB stick? +You are very welcome to share open fonts with friends, family and colleagues through removable media. Just remember to include the full font package, including any copyright notices and licensing information as available in OFL.txt. In the case where you sell the font, it has to come bundled with software. + +1.8 Can I host the fonts on a website for others to use? +Yes, as long as you make the full font package available. In most cases it may be best to point users to the main site that distributes the Original Version so they always get the most recent stable and complete version. See also discussion of webfonts in Section 2. + +1.9 Can I host the fonts on a server for use over our internal network? +Yes. If the fonts are transferred from the server to the client computer by means that allow them to be used even if the computer is no longer attached to the network, the full package (copyright notices, licensing information, etc.) should be included. + +1.10 Does the full OFL license text always need to accompany the font? +The only situation in which an OFL font can be distributed without the text of the OFL (either in a separate file or in font metadata), is when a font is embedded in a document or bundled within a program. In the case of metadata included within a font, it is legally sufficient to include only a link to the text of the OFL on https://openfontlicense.org, but we strongly recommend against this. Most modern font formats include metadata fields that will accept the full OFL text, and full inclusion increases the likelihood that users will understand and properly apply the license. + +1.11 What do you mean by 'embedding'? How does that differ from other means of distribution? +By 'embedding' we mean inclusion of the font in a document or file in a way that makes extraction (and redistribution) difficult or clearly discouraged. In many cases the names of embedded fonts might also not be obvious to those reading the document, the font data format might be altered, and only a subset of the font - only the glyphs required for the text - might be included. Any other means of delivering a font to another person is considered 'distribution', and needs to be accompanied by any copyright notices and licensing information available in OFL.txt. + +1.12 So can I embed OFL fonts in my document? +Yes, either in full or a subset. The restrictions regarding font modification and redistribution do not apply, as the font is not intended for use outside the document. + +1.13 Does embedding alter the license of the document itself? +No. Referencing or embedding an OFL font in any document does not change the license of the document itself. The requirement for fonts to remain under the OFL does not apply to any document created using the fonts and their derivatives. Similarly, creating any kind of graphic using a font under the OFL does not make the resulting artwork subject to the OFL. + +1.14 If OFL fonts are extracted from a document in which they are embedded (such as a PDF file), what can be done with them? Is this a risk to author(s)? +The few utilities that can extract fonts embedded in a PDF will typically output limited amounts of outlines - not a complete font. To create a working font from this method is much more difficult and time consuming than finding the source of the original OFL font. So there is little chance that an OFL font would be extracted and redistributed inappropriately through this method. Even so, copyright laws address any misrepresentation of authorship. All Font Software released under the OFL and marked as such by the author(s) is intended to remain under this license regardless of the distribution method, and cannot be redistributed under any other license. We strongly discourage any font extraction - we recommend directly using the font sources instead - but if you extract font outlines from a document, please be considerate: respect the work of the author(s) and the licensing model. + +1.15 What about distributing fonts with a document? Within a compressed folder structure? Is it distribution, bundling or embedding? +Certain document formats may allow the inclusion of an unmodified font within their file structure which may consist of a compressed folder containing the various resources forming the document (such as pictures and thumbnails). Including fonts within such a structure is understood as being different from embedding but rather similar to bundling (or mere aggregation) which the license explicitly allows. In this case the font is conveyed unchanged whereas embedding a font usually transforms it from the original format. The OFL does not allow anyone to extract the font from such a structure to then redistribute it under another license. The explicit permission to redistribute and embed does not cancel the requirement for the Font Software to remain under the license chosen by its author(s). Even if the font travels inside the document as one of its assets, it should not lose its authorship information and licensing. + +1.16 What about ebooks shipping with open fonts? +The requirements differ depending on whether the fonts are linked, embedded or distributed (bundled or aggregated). Some ebook formats use web technologies to do font linking via @font-face, others are designed for font embedding, some use fonts distributed with the document or reading software, and a few rely solely on the fonts already present on the target system. The license requirements depend on the type of inclusion as discussed in 1.15. + +1.17 Can Font Software released under the OFL be subject to URL-based access restrictions methods or DRM (Digital Rights Management) mechanisms? +Yes, but these issues are out of scope for the OFL. The license itself neither encourages their use nor prohibits them since such mechanisms are not implemented in the components of the Font Software but through external software. Such restrictions are put in place for many different purposes corresponding to various usage scenarios. One common example is to limit potentially dangerous cross-site scripting attacks. However, in the spirit of libre/open fonts and unrestricted writing systems, we strongly encourage open sharing and reuse of OFL fonts, and the establishment of an environment where such restrictions are unnecessary. Note that whether you wish to use such mechanisms or you prefer not to, you must still abide by the rules set forth by the OFL when using fonts released by their authors under this license. Derivative fonts must be licensed under the OFL, even if they are part of a service for which you charge fees and/or for which access to source code is restricted. You may not sell the fonts on their own - they must be part of a larger software package, bundle or subscription plan. For example, even if the OFL font is distributed in a software package or via an online service using a DRM mechanism, the user would still have the right to extract that font, use, study, modify and redistribute it under the OFL. + +1.18 I've come across a font released under the OFL. How can I easily get more information about the Original Version? How can I know where it stands compared to the Original Version or other Modified Versions? +Consult the copyright statement(s) in the license for ways to contact the original authors. Consult the FONTLOG (see section 6 for more details and examples) for information on how the font differs from the Original Version, and get in touch with the various contributors via the information in the acknowledgement section. Please consider using the Original Versions of the fonts whenever possible. + +1.19 What do you mean in condition 4 of the OFL's permissions and conditions? Can you provide examples of abusive promotion / endorsement / advertisement vs. normal acknowledgement? +The intent is that the goodwill and reputation of the author(s) should not be used in a way that makes it sound like the original author(s) endorse or approve of a specific Modified Version or software bundle. For example, it would not be right to advertise a word processor by naming the author(s) in a listing of software features, or to promote a Modified Version on a website by saying "designed by ...". However, it would be appropriate to acknowledge the author(s) if your software package has a list of people who deserve thanks. We realize that this can seem to be a grey area, but the standard used to judge an acknowledgement is that if the acknowledgement benefits the author(s) it is allowed, but if it primarily benefits other parties, or could reflect poorly on the author(s), then it is not. + +1.20 I'm writing a small app for mobile platforms, do I need to include the whole package? +If you bundle a font under the OFL with your mobile app you must comply with the terms of the license. At a minimum you must include the copyright statement, the license notice and the license text. A mention of this information in your About box or Changelog, with a link to where the font package is from, is good practice, and the extra space needed to carry these items is very small. You do not, however, need to include the full contents of the font package - only the fonts you use and the copyright and license that apply to them. For example, if you only use the regular weight in your app, you do not need to include the italic and bold versions. + +1.21 What about including OFL fonts by default in my firmware or dedicated operating system? +Many such systems are restricted and turned into appliances so that users cannot study or modify them. Using open fonts to increase quality and language coverage is a great idea, but you need to be aware that if there is a way for users to extract fonts you cannot legally prevent them from doing that. The fonts themselves, including any changes you make to them, must be distributed under the OFL even if your firmware has a more restrictive license. If you do transform the fonts and change their formats when you include them in your firmware you must respect any names reserved by the font authors via the RFN mechanism and pick your own font name. Alternatively if you directly add a font under the OFL to the font folder of your firmware without modifying or optimizing it you are simply bundling the font like with any other software collection, and do not need to make any further changes. + +1.22 Can I make and publish CMS themes or templates that use OFL fonts? Can I include the fonts themselves in the themes or templates? Can I sell the whole package? +Yes, you are very welcome to integrate open fonts into themes and templates for your preferred CMS and make them more widely available. Remember that you can only sell the fonts and your CMS add-on as part of a software bundle. (See entry 1.4 for details and examples about selling bundles). + +1.23 Can OFL fonts be included in services that deliver fonts to the desktop from remote repositories? Even if they contain both OFL and non-OFL fonts? +Yes. Some foundries have set up services to deliver fonts to subscribers directly to desktops from their online repositories; similarly, plugins are available to preview and use fonts directly in your design tool or publishing suite. These services may mix open and restricted fonts in the same channel, however they should make a clear distinction between them to users. These services should also not hinder users (such as through DRM or obfuscation mechanisms) from extracting and using the OFL fonts in other environments, or continuing to use OFL fonts after subscription terms have ended, as those uses are specifically allowed by the OFL. + +1.24 Can services that provide or distribute OFL fonts restrict my use of them? +No. The terms of use of such services cannot replace or restrict the terms of the OFL, as that would be the same as distributing the fonts under a different license, which is not allowed. You are still entitled to use, modify and redistribute them as the original authors have intended outside of the sole control of that particular distribution channel. Note, however, that the fonts provided by these services may differ from the Original Versions. + +1.25 Can a font released under the OFL be used as a source by an AI (Artificial Intelligence), an ML (Machine Learning) model, a NN (neural network), or similar system to create a new font and release it under a different license? +No. Any font produced from such systems whose input or training data contains any source file from a font project licensed under the OFL should be considered a derivative work. All Font Software released under the OFL and marked as such by the author(s) must remain under the OFL regardless of the way the sources might have been transformed, in whole or in part. If you would like to use font sources to produce a font to be released under a different license, then you need to contact the corresponding authors directly to ask for their explicit permission. + +1.26 Can OFL fonts be used by AI-based design tools? +Yes, as long as the resulting work is not intended to be a font. Using such automated systems to produce graphical output - something that is not a font - is considered similar to normal usage. It is equivalent to using an OFL font in the graphic design process as discussed in question 1.1. + + +2 USING OFL FONTS FOR WEBPAGES AND ONLINE WEBFONT SERVICES + +NOTE: This section often refers to a separate paper on 'Webfonts and Reserved Font Names'. This is available at https://openfontlicense.org/webfonts-and-reserved-font-names + +2.1 Can I make webpages using OFL fonts? +Yes! Go ahead! You could ask visitors to download and install the fonts, but loading the fonts dynamically as webfonts through CSS @font-face declarations is a much better method. The referenced fonts can be hosted on the same server as other site assets and content, or loaded from a separate webfont service. This is recommended and explicitly allowed by the licensing model because it is distribution. + +2.2 Can I make and use WOFF (Web Open Font Format) versions of OFL fonts? +Yes, but you need to be careful. A change in font format normally is considered modification, and Reserved Font Names (RFNs) cannot be used. Because of the design of the WOFF and WOFF2 formats, however, it is possible to create a WOFF/WOFF2 version that is not considered modification, and so would not require a name change. + +2.2.1 How can I make sure that a WOFF/WOFF2 version is not considered modification? +You are allowed to create, use and distribute a WOFF version of an OFL font without changing the font name, but only if the original font data remains unchanged except for WOFF compression, and WOFF-specific metadata is either omitted altogether or present and includes, unaltered, the contents of all equivalent metadata in the original font. + +2.2.2 Do WOFF conversion tools and services automatically meet these requirements? +No. Some WOFF conversion tools and online services do not meet the two requirements listed above, and so their output must be considered a Modified Version. So be very careful and check to be sure that the tool or service you're using is compressing unchanged data and completely and accurately reflecting the original font metadata. + +2.3 What about other webfont formats such as EOT/EOTLite/CWT/etc.? +In most cases these formats alter the original font data more than WOFF, and do not completely support appropriate metadata, so their use must be considered modification and RFNs may not be used. However, there may be certain formats or usage scenarios that may allow the use of RFNs. See https://openfontlicense.org/webfonts-and-reserved-font-names + +2.4 Can I make OFL fonts available through webfont online services? +Yes, you are welcome to include OFL fonts in online webfont services as long as you properly meet all the conditions of the license. The origin and open status of the font should be clear among the other fonts you are hosting. Authorship, copyright notices and license information must be sufficiently visible to your users or subscribers so they know where the font comes from and the rights granted by the author(s). Make sure the font file contains the needed copyright notice(s) and licensing information in its metadata. Please double-check the accuracy of every field to prevent contradictory information. Other font formats, including EOT/EOTLite/CWT and superior alternatives like WOFF, already provide fields for this information. Remember that if you modify the font within your library or convert it to another format for any reason the OFL restrictions apply and you need to change the names accordingly. Please respect the author's wishes as expressed in the OFL and do not misrepresent original designers and their work. Don't lump quality open fonts together with dubious freeware or public domain fonts. Consider how you can best work with the original designers and foundries, support their efforts and generate goodwill that will benefit your service. (See entry 1.17 for details related to URL-based access restrictions methods or DRM mechanisms). + +2.5 Some webfont formats and services provide ways of 'optimizing' the font for a particular website or web application; is that allowed? +Yes, it is permitted, but remember that these optimized versions are Modified Versions and so must follow OFL requirements like appropriate renaming. Also you need to bear in mind the other important parameters beyond compression, speed and responsiveness: you need to consider the audience of your particular website or web application, as choosing some optimization parameters may turn out to be less than ideal for them. Subsetting by removing certain glyphs or features may seriously limit functionality of the font in various languages that your users expect. It may also introduce degradation of quality in the rendering or specific bugs on the various target platforms compared to the original font from upstream. In other words, remember that one person's optimized font may be another person's missing feature. Various advanced typographic features (OpenType, Graphite or AAT) are also available through CSS and may provide the desired effects without the need to modify the font. + +2.6 Is subsetting a webfont considered modification? +Yes. Removing any parts of the font when delivering a webfont to a browser, including unused glyphs and smart font code, is considered modification. This is permitted by the OFL but would not normally allow the use of RFNs. Some newer subsetting technologies may be able to subset in a way that allows users to effectively have access to the complete font, including smart font behaviour. See entry 2.8 and https://openfontlicense.org/webfonts-and-reserved-font-names + +2.7 Are there any situations in which a modified webfont could use RFNs? +Yes. If a webfont is optimized only in ways that preserve Functional Equivalence (see entry 2.8), then it may use RFNs, as it reasonably represents the Original Version and respects the intentions of the author(s) and the main purposes of the RFN mechanism (avoids collisions, protects authors, minimizes support, encourages derivatives). However this is technically very difficult and often impractical, so a much better scenario is for the webfont service or provider to sign a separate agreement with the author(s) that allows the use of RFNs for Modified Versions. + +2.8 How do you know if an optimization to a webfont preserves Functional Equivalence? +Functional Equivalence is described in full in the 'Webfonts and Reserved Font Names' paper at https://openfontlicense.org/webfonts-and-reserved-font-names, in general, an optimized font is deemed to be Functionally Equivalent (FE) to the Original Version if it: + +- Supports the same full character inventory. If a character can be properly displayed using the Original Version, then that same character, encoded correctly on a webpage, will display properly. +- Provides the same smart font behavior. Any dynamic shaping behavior that works with the Original Version should work when optimized, unless the browser or environment does not support it. There does not need to be guaranteed support in the client, but there should be no forced degradation of smart font or shaping behavior, such as the removal or obfuscation of OpenType, Graphite or AAT tables. +- Presents text with no obvious degradation in visual quality. The lettershapes should be equally (or more) readable, within limits of the rendering platform. +- Preserves original author, project and license metadata. At a minimum, this should include: Copyright and authorship; The license as stated in the Original Version, whether that is the full text of the OFL or a link to the web version; Any RFN declarations; Information already present in the font or documentation that points back to the Original Version, such as a link to the project or the author's website. + +If an optimized font meets these requirements, and so is considered to be FE, then it's very likely that the original author would feel that the optimized font is a good and reasonable equivalent. If it falls short of any of these requirements, the optimized font does not reasonably represent the Original Version, and so should be considered to be a Modified Version. Like other Modified Versions, it would not be allowed to use any RFNs and you simply need to pick your own font name. + +2.9 Can fonts released under the OFL be used with Incremental Font Transfer (IFT) or similar on-the-fly subsetting and compression technologies? +Yes, if they provide a sufficient level of Functional Equivalence. Extra care should be taken to make sure that such processes - both on the server and on the client - do not break glyph coverage and smart features especially for lesser-known and lesser-resourced languages in the resulting document or app. See the 'Webfonts and Reserved Font Names' paper on https://openfontlicense.org/webfonts-and-reserved-font-names for more about the goals and the rationale. + +2.10 Isn't use of webfonts another form of embedding? +No. Unlike embedded fonts in a PDF, webfonts are not an integrated part of the document itself. They are not specific to a single document and are often applied to thousands of documents around the world. The font data is not stored alongside the document data and often originates from a different location. The ease by which the webfonts used by a document may be identified and downloaded for desktop use demonstrates that they are philosophically and technically separate from the webpages that specify them. See https://openfontlicense.org/webfonts-and-reserved-font-names + +2.11 So would it be better to not use RFNs at all if you want your font to be distributed by a webfont service? +No. Although the OFL does not require authors to use RFNs, the RFN mechanism is an important part of the OFL model and completely compatible with webfont services. If that webfont service modifies the fonts, then the best solution is to sign a separate agreement for the use of any RFNs. It is perfectly valid for an author to not declare any RFNs, but before they do so they need to fully understand the benefits they are giving up, and the overall negative effect of allowing many different versions bearing the same name to be widely distributed. As a result, we don't generally recommend it. + +2.12 What should an agreement for the use of RFNs say? Are there any examples? +There is no prescribed format for this agreement, as legal systems vary, and no recommended examples. Authors may wish to add specific clauses to further restrict use, require author review of Modified Versions, establish user support mechanisms or provide terms for ending the agreement. Such agreements are usually not public, and apply only to the main parties. However, it would be very beneficial for webfont services to clearly state when they have established such agreements, so that the public understands clearly that their service is operating appropriately. + +See the separate paper on 'Webfonts and Reserved Font Names' for in-depth discussion of issues related to the use of RFNs for webfonts. This is available at https://openfontlicense.org/webfonts-and-reserved-font-names + + +3 MODIFYING OFL-LICENSED FONTS + +3.1 Can I change the fonts? Are there any limitations to what things I can and cannot change? +You are allowed to change anything, as long as such changes do not violate the terms of the license. In other words, you are not allowed to remove the copyright statement(s) from the font, but you could put additional information into it that covers your contribution. See the placeholders in the OFL header template for recommendations on where to add your own statements. (Remember that, when authors have reserved names via the RFN mechanism, you need to change the internal names of the font to your own font name when making your modified version even if it is just a small change.) + +3.2 I have a font that needs a few extra glyphs - can I take them from an OFL licensed font and copy them into mine? +Yes, but if you distribute that font to others it must be under the OFL, and include the information mentioned in condition 2 of the license. + +3.3 Can I charge people for my additional work? In other words, if I add a bunch of special glyphs or OpenType/Graphite/AAT code, can I sell the enhanced font? +Not by itself. Derivative fonts must be released under the OFL and cannot be sold by themselves. It is permitted, however, to include them in a larger software package (such as text editors, office suites or operating systems), even if the larger package is sold. In that case, you are strongly encouraged, but not required, to also make that derived font easily and freely available outside of the larger package. + +3.4 Can I pay someone to enhance the fonts for my use and distribution? +Yes. This is a good way to fund the further development of the fonts. Keep in mind, however, that if the font is distributed to others it must be under the OFL. You won't be able to recover your investment by exclusively selling the font, but you will be making a valuable contribution to the community. Please remember how you have benefited from the contributions of others. + +3.5 I need to make substantial revisions to the font to make it work with my program. It will be a lot of work, and a big investment, and I want to be sure that it can only be distributed with my program. Can I restrict its use? +No. If you redistribute a Modified Version of the font it must be under the OFL. You may not restrict it in any way beyond what the OFL permits and requires. This is intended to ensure that all released improvements to the fonts become available to everyone. But you will likely get an edge over competitors by being the first to distribute a bundle with the enhancements. Again, please remember how you have benefited from the contributions of others. + +3.6 Do I have to make any derivative fonts (including extended source files, build scripts, documentation, etc.) publicly available? +No, but please consider sharing your improvements with others. You may find that you receive in return more than what you gave. + +3.7 If a trademark is claimed in the OFL font, does that trademark need to remain in modified fonts? +Yes. Any trademark notices must remain in any derivative fonts to respect trademark laws, but you may add any additional trademarks you claim, officially registered or not. For example if an OFL font called "Foo" contains a notice that "Foo is a trademark of Acme", then if you rename the font to "Bar" when creating a Modified Version, the new trademark notice could say "Foo is a trademark of Acme Inc. - Bar is a trademark of Roadrunner Technologies Ltd.". Trademarks work alongside the OFL and are not subject to the terms of the licensing agreement. The OFL does not grant any rights under trademark law. Bear in mind that trademark law varies from country to country and that there are no international trademark conventions as there are for copyright. You may need to significantly invest in registering and defending a trademark for it to remain valid in the countries you are interested in. This may be costly for an individual independent designer. + +3.8 If I commit changes to a font (or publish a branch in a DVCS) as part of a public open source software project, do I have to change the internal font names? +Only if there are declared RFNs. Making a public commit or publishing a public branch is effectively redistributing your modifications, so any change to the font will require that you do not use the RFNs. Even if there are no RFNs, it may be useful to change the name or add a suffix indicating that a particular version of the font is still in development and not released yet. This will clearly indicate to users and fellow designers that this particular font is not ready for release yet. See section 5 for more details. + + +4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL + +4.1 Can I use the SIL OFL for my own fonts? +Yes! We heartily encourage everyone to use the OFL to distribute their own original fonts. It is a carefully constructed license that allows great freedom along with enough artistic integrity protection for the work of the authors as well as clear rules for other contributors and those who redistribute the fonts. The licensing model is used successfully by various organisations, both for-profit and not-for-profit, to release fonts of varying levels of scope and complexity. + +4.2 What do I have to do to apply the OFL to my font? +If you want to release your fonts under the OFL, we recommend you do the following: + +4.2.1 Put your copyright and Reserved Font Names information at the beginning of the main OFL.txt file in place of the dedicated placeholders (marked with the <> characters). Include this file in your release package. + +4.2.2 Put your copyright and the OFL text with your chosen Reserved Font Name(s) into your font files (the copyright and license fields). A link to the OFL text on the OFL website is an acceptable (but not recommended) alternative. Also add this information to any other components (build scripts, glyph databases, documentation, test files, etc). Accurate metadata in your font files is beneficial to you as an increasing number of applications are exposing this information to the user. For example, clickable links can bring users back to your website and let them know about other work you have done or services you provide. Depending on the format of your fonts and sources, you can use template human-readable headers or machine-readable metadata. You should also double-check that there is no conflicting metadata in the font itself contradicting the license, such as the fstype bits in the os2 table or fields in the name table. + +4.2.3 Write an initial FONTLOG.txt for your font and include it in the release package (see Section 6 and Appendix A for details including a template). + +4.2.4 Include the relevant practical documentation on the license by adding the current OFL-FAQ.txt file in your package. + +4.2.5 If you wish you can use the OFL graphics (https://openfontlicense.org/promotion) on your website. + +4.3 Will you make my font OFL for me? +We won't do the work for you. We can, however, try to answer your questions. Unfortunately we do not have the resources to review and check your font packages for correct use of the OFL. We recommend you turn to designers, foundries or consulting companies with experience in doing open font design to provide this service to you. + +4.4 Will you distribute my OFL font for me? +No. The easiest way for users to always get the most current version of the font is for you to distribute it through your own website. You can also distribute your own font source files, or host them on services such as GitHub or GitLab. You can use various channels, including social media, to promote and get attention to your project. If you want someone else to distribute the font, consider services and sites that already distribute OFL fonts. Some of those are listed on the OFL website (https://openfontlicense.org/ofl-fonts). Contact them to find out how to submit fonts to them. We do not endorse any particular catalog or hosting service. It is your responsibility to determine if the service is right for you and if it treats authors with fairness. + +4.5 Why should I use the OFL for my fonts? +Here are a few of the many good reasons: + +- to meet needs for fonts that can be modified to support lesser-known languages +- to provide a legal and clear way for people to respect your work but still use it (and reduce piracy) +- to involve others in your font project +- to enable your fonts to be expanded with new weights and improved writing system/language support +- to allow more technical font developers to add features to your design (such as OpenType, Graphite or AAT support) +- to renew the life of an old font lying on your hard drive with no business model +- to allow your font to be included in Libre Software operating systems like Ubuntu +- to give your font world status and wide, unrestricted distribution +- to educate students about quality typeface and font design +- to expand your test base and get more useful feedback +- to extend your reach to new markets when users see your metadata and go to your website +- to get your font more easily into one of the webfont online services +- to attract attention for your commercial fonts +- to make money through webfont services +- to make money by bundling fonts with applications +- to make money adjusting and extending existing open fonts +- to get a better chance that foundations, NGOs, charities, or companies who commission fonts will pick you +- to be part of a sharing design and development community +- to give back and contribute to a growing body of font sources + +4.6 Can I cancel or undo the OFL license for a font that I've already released under it? +No, as an author, you cannot cancel or undo the permissions you have granted earlier by releasing a font under the OFL. But as an original author of that specific font you can always re-release it separately under another license of your own choosing. Of course, you cannot re-license a font for which you are not the author. If there are multiple authors they need to be all in official written agreement with the re-licensing. For practical reasons, a different name than an existing and publicly available open font should be chosen. + +4.7 Should I apply the OFL early in the design process, even before the font is complete, or wait until I want to release a completed version? +It is really up to you and the circumstances of your project. But in any case, we would recommend you place appropriate warning messages in your public repository or website to say something like "Please wait for a finished release before using and redistributing this font". We recommend you have a clear versioning scheme and repository tagging to make it as easy as possible to see if the font is a released version or still under development. You can also consider choosing a separate name (or suffix) for the development version, and only give the final name to a released version. + + +5 CHOOSING RESERVED FONT NAMES + +5.1 What are Reserved Font Names? +These are font names, or portions of font names, that the author has chosen to reserve for use only with the Original Version of the font, or for Modified Version(s) created by the original author. + +5.2 Why can't I use the Reserved Font Names in my derivative font names? I'd like people to know where the design came from. +The best way to acknowledge the source of the design is to thank the original authors and any other contributors in the files that are distributed with your revised font (although no acknowledgement is required). The FONTLOG is a natural place to do this. Reserved Font Names ensure that the only fonts that have the original names are the unmodified Original Versions. This allows designers to maintain artistic integrity while allowing collaboration to happen. It eliminates potential confusion and name conflicts. When choosing a name, be creative and avoid names that reuse almost all the same letters in the same order or sound like the original. It will help everyone if Original Versions and Modified Versions can easily be distinguished from one another and from other derivatives. Any substitution and matching mechanism is outside the scope of the license. + +5.3 What do you mean by "primary name as presented to the user"? Are you referring to the font menu name? +Yes, this applies to the font menu name and other mechanisms that specify a font in a document. It would be fine, however, to keep a text reference to the original fonts in the description field, in your modified source file or in documentation provided alongside your derivative as long as no one could be confused that your modified source is the original. But you cannot use the Reserved Font Names in any way to identify the font to the user (unless the Copyright Holder(s) allow(s) it through a separate agreement). Users who install derivatives (Modified Versions) on their systems should not see any of the original Reserved Font Names in their font menus, for example. Again, this is to ensure that users are not confused and do not mistake one font for another and so expect features only another derivative or the Original Version can actually offer. + +5.4 Am I not allowed to use any part of the Reserved Font Names? +You may not use individual words from the Reserved Font Names, but you would be allowed to use parts of words, as long as you do not use any word from the Reserved Font Names entirely. We do not recommend using parts of words because of potential confusion, but it is allowed. For example, if "Foobar" was a Reserved Font Name, you would be allowed to use "Foo" or "bar", although we would not recommend it. Such an unfortunate choice would confuse the users of your fonts as well as make it harder for other designers to contribute. + +5.5 So what should I, as an author, identify as Reserved Font Names? +Original authors are encouraged to name their fonts using clear, distinct names, and only declare the unique parts of the name as Reserved Font Names. For example, the author of a font called "Foobar Sans" would declare "Foobar" as a Reserved Font Name, but not "Sans", as that is a common typographical term, and may be a useful word to use in a derivative font name. Reserved Font Names should also be single words for simplicity and legibility. A font called "Flowing River" should have Reserved Font Names "Flowing" and "River", not "Flowing River". You also need to be very careful about reserving font names which are already linked to trademarks (whether registered or not) which you do not own. + +5.6 Do I, as an author, have to identify any Reserved Font Names? +No. RFNs are optional and not required, but we encourage you to use them. This is primarily to avoid confusion between your work and Modified Versions. As an author you can release a font under the OFL and not declare any Reserved Font Names. There may be situations where you find that using no RFNs and letting your font be changed and modified - including any kind of modification - without having to change the original name is desirable. However you need to be fully aware of the consequences. There will be no direct way for end-users and other designers to distinguish your Original Version from many Modified Versions that may be created. You have to trust whoever is making the changes and the optimizations to not introduce problematic changes. The RFNs you choose for your own creation have value to you as an author because they allow you to maintain artistic integrity and keep some control over the distribution channel to your end-users. For discussion of RFNs and webfonts see section 2. + +5.7 Are any names (such as the main font name) reserved by default? +No. That is a change to the license as of version 1.1. If you want any names to be Reserved Font Names, they must be specified after the copyright statement(s). + +5.8 Is there any situation in which I can use Reserved Font Names for a Modified Version? +The Copyright Holder(s) can give certain trusted parties the right to use any of the Reserved Font Names through separate written agreements. For example, even if "Foobar" is an RFN, you could write up an agreement to give company "XYZ" the right to distribute a modified version with a name that includes "Foobar". This allows for freedom without confusion. The existence of such an agreement should be made as clear as possible to downstream users and designers in the distribution package and the relevant documentation. They need to know if they are a party to the agreement or not and what they are practically allowed to do or not even if all the details of the agreement are not public. + +5.9 Do font rebuilds require a name change? Do I have to change the name of the font when my packaging workflow includes a full rebuild from source? +Yes, all rebuilds which change the font data and the smart code are Modified Versions and the requirements of the OFL apply: you need to respect what the Author(s) have chosen in terms of Reserved Font Names. However if a package (or installer) is simply a wrapper or a compressed structure around the final font - leaving them intact on the inside - then no name change is required. Please get in touch with the author(s) and copyright holder(s) to inquire about the presence of font sources beyond the final font file(s) and the recommended build path. That build path may very well be non-trivial and hard to reproduce accurately by the maintainer. If a full font build path is made available by the upstream author(s) please be aware that any regressions and changes you may introduce when doing a rebuild for packaging purposes is your own responsibility as a package maintainer since you are effectively creating a separate branch. You should make it very clear to your users that your rebuilt version is not the canonical one from upstream. + +5.10 Can I add other Reserved Font Names when making a derivative font? +Yes. List your additional Reserved Font Names after your additional copyright statement, as indicated with example placeholders at the top of the OFL.txt file. Be sure you do not remove any existing RFNs but only add your own. RFN statements should be placed next to the copyright statement of the relevant author as indicated in the OFL.txt template to make them visible to designers wishing to make their separate version. + + +6 ABOUT THE FONTLOG + +6.1 What is this FONTLOG thing exactly? +It has three purposes: 1) to provide basic information on the font to users and other designers and developers, 2) to document changes that have been made to the font or accompanying files, either by the original authors or others, and 3) to provide a place to acknowledge authors and other contributors. Please use it! + +6.2 Is the FONTLOG required? +It is not a requirement of the license, but we strongly recommend you have one. + +6.3 Am I required to update the FONTLOG when making Modified Versions? +No, but users, designers and other developers might get very frustrated with you if you don't. People need to know how derivative fonts differ from the original, and how to take advantage of the changes, or build on them. There are utilities that can help create and maintain a FONTLOG. + +6.4 What should the FONTLOG look like? +It is typically a separate text file (FONTLOG.txt), but can take other formats. It commonly includes these four sections: + +- brief header describing the FONTLOG itself and name of the font family +- Basic Font Information - description of the font family, purpose and breadth +- ChangeLog - chronological listing of changes +- Acknowledgements - list of authors and contributors with contact information + +It could also include other sections, such as: where to find documentation, how to make contributions, information on contributing organizations, source code details, and a short design guide. See Appendix A for an example FONTLOG. + + +7 MAKING CONTRIBUTIONS TO OFL PROJECTS + +7.1 Can I contribute work to OFL projects? +In many cases, yes. It is common for OFL fonts to be developed by a team of people who welcome contributions from the wider community. Contact the original authors for specific information on how to participate in their projects. + +7.2 Why should I contribute my changes back to the original authors? +It would benefit many people if you contributed back in response to what you've received. Your contributions and improvements to the fonts and other components could be a tremendous help and would encourage others to contribute as well and 'give back'. You will then benefit from other people's contributions as well. Sometimes maintaining your own separate version takes more effort than merging back with the original. Be aware that any contributions, however, must be either your own original creation or work that you own, and you may be asked to affirm that clearly when you contribute. + +7.3 I've made some very nice improvements to the font. Will you consider adopting them and putting them into future Original Versions? +Most authors would be very happy to receive such contributions. Keep in mind that it is unlikely that they would want to incorporate major changes that would require additional work on their end. Any contributions would likely need to be made for all the fonts in a family and match the overall design and style. Authors are encouraged to include a guide to the design with the fonts. It would also help to have contributions submitted as patches or clearly marked changes - the use of smart source revision control systems like subversion, mercurial, git or bzr is a good idea. Please follow the recommendations given by the author(s) in terms of preferred source formats and configuration parameters for sending contributions. If this is not indicated in a FONTLOG or other documentation of the font, consider asking them directly. Examples of useful contributions are bug fixes, additional glyphs, stylistic alternates (and the smart font code to access them) or improved hinting. Keep in mind that some kinds of changes (esp. hinting) may be technically difficult to integrate. + +7.4 How can I financially support the development of OFL fonts? +It is likely that most authors of OFL fonts would accept financial contributions - contact them for instructions on how to do this. Such contributions would support future development. You can also pay for others to enhance the fonts and contribute the results back to the original authors for inclusion in the Original Version. + + +8 ABOUT THE LICENSE ITSELF + +8.1 I see that this is version 1.1 of the license. Will there be later changes? +Version 1.1 is the first minor revision of the OFL. We are confident that version 1.1 will meet most needs, but are open to future improvements. Any revisions would be for future font releases, and previously existing licenses would remain in effect. No retroactive changes are possible, although the Copyright Holder(s) can re-release the font under a revised OFL. All versions will be available on our website: https://openfontlicense.org. + +8.2 Does this license restrict the rights of the Copyright Holder(s)? +No. The Copyright Holder(s) still retain(s) all the rights to their creation; they are only releasing a portion of it for use in a specific way. For example, the Copyright Holder(s) may choose to release a 'basic' version of their font under the OFL, but sell a restricted 'enhanced' version under a different license. They may also choose to release the same font under both the OFL and some other license. Only the Copyright Holder(s) can do this, and doing so does not change the terms of the OFL as it applies to that font. + +8.3 Is the OFL a contract or a license? +The OFL is a worldwide license based on international copyright agreements and conventions. It is not a contract and so does not require you to sign it to have legal validity. By using, modifying and redistributing components under the OFL you indicate that you accept the license. + +8.4 I really like the terms of the OFL, but want to change it a little. Am I allowed to take ideas and actual wording from the OFL and put them into my own custom license for distributing my fonts? +We strongly recommend against creating your very own unique open licensing model. Using a modified or derivative license will likely cut you off - along with the font(s) under that license - from the community of designers using the OFL, potentially expose you and your users to legal liabilities, and possibly put your work and rights at risk. The OFL went though a community and legal review process that took years of effort, and that review is only applicable to an unmodified OFL. The text of the OFL has been written by SIL (with review and consultation from the community) and is copyright (c) 2005-2023 SIL International. You may re-use the ideas and wording (in part, not in whole) in another non-proprietary license provided that you call your license by another unambiguous name, that you do not use the preamble, that you do not mention SIL and that you clearly present your license as different from the OFL so as not to cause confusion by being too similar to the original. If you feel the OFL does not meet your needs for an open license, please contact us. + +8.5 Can I quote from the OFL FAQ? +Yes, SIL gives permission to quote from the OFL FAQ (OFL-FAQ.txt), in whole or in part, provided that the quoted text is: + +- unmodified, +- used to help explain the intent of the OFL, rather than cause misunderstanding, and +- accompanied with the following attribution: "From the OFL FAQ (OFL-FAQ.txt), copyright (c) 2005-2023 SIL International. Used by permission. https://openfontlicense.org/OFL-FAQ". + +8.6 Can I translate the license and the FAQ into other languages? +SIL certainly recognises the need for people who are not familiar with English to be able to understand the OFL and its use. Making the license very clear and readable has been a key goal for the OFL, but we know that people understand their own language best. + +If you are an experienced translator, you are very welcome to translate the OFL and OFL-FAQ so that designers and users in your language community can understand the license better. But only the original English version of the license has legal value and has been approved by the community. Translations do not count as legal substitutes and should only serve as a way to explain the original license. SIL - as the author and steward of the license for the community at large - does not approve any translation of the OFL as legally valid because even small translation ambiguities could be abused and create problems. + +SIL gives permission to publish unofficial translations into other languages provided that they comply with the following guidelines: + +Put the following disclaimer in both English and the target language stating clearly that the translation is unofficial: "This is an unofficial translation of the SIL Open Font License into . It was not published by SIL International, and does not legally state the distribution terms for fonts that use the OFL. A release under the OFL is only valid when using the original English text. However, we recognize that this unofficial translation will help users and designers not familiar with English to better understand and use the OFL. We encourage designers who consider releasing their creation under the OFL to read the OFL-FAQ in their own language if it is available. Please go to https://openfontlicense.org for the official version of the license and the accompanying OFL-FAQ." + +Keep your unofficial translation current and update it at our request if needed, for example if there is any ambiguity which could lead to confusion. If you start such an unofficial translation effort of the OFL and OFL-FAQ please let us know. + +8.7 Does the OFL have an explicit expiration term? +No, the implicit intent of the OFL is that the permissions granted are perpetual and irrevocable. + +8.8 Why is there no automatic upgrade clause, a 'version 1.1 or later' like in the GPL? +This is by design, with the goals of establishing clear trust and of preventing any situation where the actual terms could be changed from underneath any user of the license. That would introduce uncertainty and confusion. Any perceived benefits of automatic incremental licensing under newer versions is strongly outweighed by the inherent risks and confusion it would cause. If a new version becomes officially available, Copyright Holder(s) can review the new version and decide whether to re-release their fonts under it. Derivative fonts could not be re-licensed unless the original versions were re-released first. + +8.9 How do you pronounce the name of the license? +The OFL is pronounced as three individual letters /ˈɑː.əf.əl/ or OH-EFF-ELL. + + +9 ABOUT SIL INTERNATIONAL + +9.1 Who is SIL International and what do they do? +SIL is a global, faith-based nonprofit that works with local communities around the world to develop language solutions that expand possibilities for a better life. SIL serves language communities worldwide, building their capacity for sustainable language development, by means of research, translation, training and materials development. SIL makes its services available to all without regard to religious belief, political ideology, gender, race, or ethnic background. SIL's members and volunteers share a Christian commitment. + +9.2 What does this have to do with font licensing? +The ability to read, write, type and publish in one's own language is one of the most critical needs for millions of people around the world. This requires fonts that are widely available and support lesser-known languages. SIL develops - and encourages others to develop - a complete stack of writing systems implementation components available under open licenses. This open stack includes input methods, smart fonts, smart rendering libraries and smart applications. There has been a need for a common open license that is specifically applicable to fonts and related software (a crucial component of this stack), so SIL developed the SIL Open Font License with the help of the Free/Libre and Open Source Software community. + +9.3 How can I contact SIL? +Our main website is: https://www.sil.org/ +Our main site about fonts and software is: https://software.sil.org/ +Our site about complex scripts is: https://scriptsource.org/ +Information about this license (and contact information) is at: https://openfontlicense.org + + +APPENDIX A - FONTLOG EXAMPLE + +Here is an example of the recommended format for a FONTLOG, although other formats are allowed. + +----- +FONTLOG for the GlobalFontFamily fonts + +This file provides detailed information on the GlobalFontFamily Font Software. This information should be distributed along with the GlobalFontFamily fonts and any derivative works. + +Basic Font Information + +GlobalFontFamily is a Unicode typeface family that supports all languages that use the Latin script and its variants, and could be expanded to support other scripts. + +NewWorldFontFamily is based on the GlobalFontFamily and also supports Greek, Hebrew, Cyrillic and Armenian. + +More specifically, this release supports the following Unicode ranges... +This release contains... +Documentation can be found at... +To contribute to the project... + +ChangeLog + +10 December 2010 (Fred Foobar) GlobalFontFamily-devel version 1.4 +- fix new build and testing system (bug #123456) + +1 August 2008 (Tom Parker) GlobalFontFamily version 1.2.1 +- Tweaked the smart font code (Branch merged with main) +- Provided improved build and debugging environment for smart behaviours + +7 February 2007 (Pat Johnson) NewWorldFontFamily Version 1.3 +- Added Greek and Cyrillic glyphs + +7 March 2006 (Fred Foobar) NewWorldFontFamily Version 1.2 +- Tweaked contextual behaviours + +1 Feb 2005 (Jane Doe) NewWorldFontFamily Version 1.1 +- Improved build script performance and verbosity +- Extended the smart code documentation +- Corrected minor typos in the documentation +- Fixed position of combining inverted breve below (U+032F) +- Added OpenType/Graphite smart code for Armenian +- Added Armenian glyphs (U+0531 -> U+0587) +- Released as "NewWorldFontFamily" + +1 Jan 2005 (Joe Smith) GlobalFontFamily Version 1.0 +- Initial release + +Acknowledgements + +If you make modifications be sure to add your name (N), email (E), web-address (if you have one) (W) and description (D). This list is in alphabetical order. + +N: Jane Doe +E: jane@university.edu +W: https://art.university.edu/projects/fonts +D: Contributor - Armenian glyphs and code + +N: Fred Foobar +E: fred@foobar.org +W: https://foobar.org +D: Contributor - misc Graphite fixes + +N: Pat Johnson +E: pat@fontstudio.org +W: https://pat.fontstudio.org +D: Designer - Greek & Cyrillic glyphs based on Roman design + +N: Tom Parker +E: tom@company.com +W: https://www.company.com/tom/projects/fonts +D: Engineer - original smart font code + +N: Joe Smith +E: joe@fontstudio.org +W: https://joe.fontstudio.org +D: Designer - original Roman glyphs + +Fontstudio.org is an not-for-profit design group whose purpose is... +Foobar.org is a distributed community of developers... +Company.com is a small business who likes to support community designers... +University.edu is a renowned educational institution with a strong design department... +----- diff --git a/public/assets/fonts/Oswald Regular.woff2 b/public/assets/fonts/Oswald Regular.woff2 new file mode 100644 index 00000000..b1a7b3b1 Binary files /dev/null and b/public/assets/fonts/Oswald Regular.woff2 differ diff --git a/public/assets/fonts/Roboto Condensed.woff2 b/public/assets/fonts/Roboto Condensed.woff2 new file mode 100644 index 00000000..8bc49d8e Binary files /dev/null and b/public/assets/fonts/Roboto Condensed.woff2 differ diff --git a/public/assets/fonts/material.woff2 b/public/assets/fonts/material.woff2 index 38e24a17..2eb4fb49 100644 Binary files a/public/assets/fonts/material.woff2 and b/public/assets/fonts/material.woff2 differ diff --git a/public/assets/fonts/oswald.woff2 b/public/assets/fonts/oswald.woff2 deleted file mode 100644 index 40b648b4..00000000 Binary files a/public/assets/fonts/oswald.woff2 and /dev/null differ diff --git a/images/gbsicon.xbm b/public/assets/images/gbsicon.xbm similarity index 100% rename from images/gbsicon.xbm rename to public/assets/images/gbsicon.xbm diff --git a/public/package-lock.json b/public/package-lock.json deleted file mode 100644 index e0a95897..00000000 --- a/public/package-lock.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "gbscontrol-webui", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "gbscontrol-webui", - "version": "1.0.0", - "license": "GNU", - "devDependencies": { - "typescript": "^4.1.3" - } - }, - "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - } - }, - "dependencies": { - "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "dev": true - } - } -} diff --git a/public/package.json b/public/package.json deleted file mode 100644 index 7bb23311..00000000 --- a/public/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "gbscontrol-webui", - "version": "1.0.0", - "description": "gbscontrol-webui", - "scripts": { - "start": "tsc --watch ./index.ts", - "build": "tsc ./src/index.ts --target ES6 && cd scripts && node ./build.js && ./html2h.sh" - }, - "author": "", - "license": "GNU", - "devDependencies": { - "typescript": "^4.1.3" - } -} diff --git a/public/scripts/bin/COPYING b/public/scripts/bin/COPYING new file mode 100755 index 00000000..d511905c --- /dev/null +++ b/public/scripts/bin/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/public/scripts/bin/gzip.exe b/public/scripts/bin/gzip.exe new file mode 100755 index 00000000..f189a730 Binary files /dev/null and b/public/scripts/bin/gzip.exe differ diff --git a/public/scripts/build.bat b/public/scripts/build.bat new file mode 100755 index 00000000..b5aa5795 --- /dev/null +++ b/public/scripts/build.bat @@ -0,0 +1,19 @@ +@ECHO OFF + +SET ROOT=%CD% +SET DDIR=%ROOT%\data +SET SDIR=%ROOT%\public\scripts + +IF not exist %DDIR% ( + mkdir %DDIR% + ECHO output directory created: %DDIR% + ECHO +) + +@REM CD %SDIR% +node public\scripts\build.js +%SDIR%\bin\gzip.exe -c9 "%DDIR%\webui.html" > "%DDIR%\__index" +:: cleanup +DEL "%DDIR%\webui.html" + +EXIT 0 \ No newline at end of file diff --git a/public/scripts/build.js b/public/scripts/build.js old mode 100644 new mode 100755 index b897c21e..5a1391cc --- a/public/scripts/build.js +++ b/public/scripts/build.js @@ -1,41 +1,123 @@ -const fs = require("fs"); -const html = fs.readFileSync("./../src/index.html.tpl", "utf-8"); -const js = fs.readFileSync("./../src/index.js", "utf-8"); +const path = require('path'); +const root = path.resolve('.'); +const nodeModulesPath = `${root}/node_modules`; +const dataPath = `${root}/data`; +const webRootPath = `${root}/public`; +const fs = require('fs'); +if (!fs.existsSync(dataPath)) { + fs.mkdirSync(dataPath) +} +const minify = require(`${nodeModulesPath}/@node-minify/core`); +const uglifyJS = require(`${nodeModulesPath}/@node-minify/uglify-js`); +var html = fs + .readFileSync(`${webRootPath}/src/index.html.tpl`, 'utf-8'); +var js = fs + .readFileSync(`${webRootPath}/src/index.js`, 'utf-8'); + // .replaceAll(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm, ''); + +// +// A simple script which does i18n of HTML template. +// If a variable data reqired in sentence the following expressions may be used: +// in HTML: L{TAG_NAME[:VAR1[:VAR2[...]]]} +// in Typescript: 'L{TAG_NAME}'.format([...]) +// mind bracket and quotes type around tags... +// In order to keep things "as is" as possible, let's search and replace a tag both HTML and JS +// +const default_ui_lang = 'en'; +const config = require(`${root}/configure.json`); +const package = require(`${root}/package.json`); +const lang = require(`${root}/translation.webui.json`); +String.prototype.format = function() { + a = this; + for (k in arguments) { + a = a.replace("{" + k + "}", arguments[k]) + } + return a +}; +const replaceLangRegex = function(matchObj, source, mask, data) { + matchObj.forEach((res) => { + let params = []; + const r0 = new String(res[1]); + if(r0 !== 'undefined' && r0.length != 0) + params = r0.substring(1).split(':'); + source = source.replaceAll( + mask, + (params.length != 0) ? data.format(...params) : data.toString() + ); + }); + return source; +}; +for(const l in lang) { + // get sentense with fallback + let sents = new String(lang[l][config['ui-lang']]); + if(sents.length == 0) + sents = new String(lang[l][default_ui_lang]); + const tag = l; + if(tag !== "" && sents.length != 0) { + const regex = new RegExp(String.raw`L{${tag}(\:.+)?}`, 'gm'); + let f = [...html.matchAll(regex)]; + if(f !== "undefined" && f.length != 0) { + html = replaceLangRegex(f, html, regex, sents); + } else { + // try to find this tag in JS + f = [...js.matchAll(regex)]; + // console.log(`searching ${tag} in JS...`) + if(f !== undefined || f.length != 0) { + js = replaceLangRegex(f, js, regex, sents); + } else + console.log(`(!) nothing found for '${tag}', check translation tag names`); + } + } +} +// i18n end const icon1024 = fs - .readFileSync("./../assets/icons/icon-1024-maskable.png") - .toString("base64"); -const oswald = fs - .readFileSync("./../assets/fonts/oswald.woff2") - .toString("base64"); + .readFileSync(`${webRootPath}/assets/icons/icon-1024-maskable.png`) + .toString('base64') +const webUIFont = fs + .readFileSync(`${webRootPath}/assets/fonts/${config['ui-web-font']}.woff2`) + .toString('base64') const material = fs - .readFileSync("./../assets/fonts/material.woff2") - .toString("base64"); + .readFileSync(`${webRootPath}/assets/fonts/material.woff2`) + .toString('base64') const favicon = fs - .readFileSync("./../assets/icons/gbsc-logo.png") - .toString("base64"); + .readFileSync(`${webRootPath}/assets/icons/gbsc-logo.png`) + .toString('base64') const css = fs - .readFileSync("./../src/style.css", "utf-8") - .replace("${oswald}", oswald) - .replace("${material}", material); + .readFileSync(`${webRootPath}/src/style.css`, 'utf-8') + .replaceAll('${webUIFontName}', config['ui-web-font']) + .replaceAll('${webUIFont}', webUIFont) + .replace('${material}', material) const manifest = fs - .readFileSync("./../src/manifest.json", "utf-8") - .replace(/\$\{icon1024\}/g, `data:image/png;base64,${icon1024}`); - -fs.writeFileSync( - "./../../webui.html", - html - .replace("${styles}", css) - .replace("${js}", js) - .replace("${favicon}", `data:image/png;base64,${favicon}`) - .replace( - "${manifest}", - `data:application/json;base64,${Buffer.from(manifest).toString("base64")}` - ) - .replace("${icon1024}", `data:image/png;base64,${icon1024}`), - "utf8" -); + .readFileSync(`${webRootPath}/src/manifest.json`, 'utf-8') + .replaceAll(/\$\{icon1024\}/g, `data:image/png;base64,${icon1024}`) -console.log("webui.html GENERATED"); +// NOTE @node-minify/html-minifier will not work here +minify({ + compressor: uglifyJS, + content: js, + options: { + warnings: true, + mangle: true, + compress: true + } +}).then((minifiedJS) => { + fs.writeFileSync( + 'data/webui.html', + html + .replace('${STYLES}', css) + .replace('${JS}', minifiedJS) + .replace('${FAVICON}', `data:image/png;base64,${favicon}`) + .replace('${VERSION_FIRMWARE}', config['version']) + .replace('${VERSION_UI}', package['version']) + .replace( + '${MANIFEST}', + `data:application/json;base64,${Buffer.from(manifest).toString('base64')}` + ) + .replace('${ICON1024}', `data:image/png;base64,${icon1024}`) + .trim(), + 'utf8' + ); +}); diff --git a/public/scripts/build.sh b/public/scripts/build.sh new file mode 100755 index 00000000..5bc9298b --- /dev/null +++ b/public/scripts/build.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# cd ../../src +# gzip -c9 webui.html > webui_html \ +# && xxd -i webui_html > webui_html.h \ +# && rm webui_html \ +# && sed -i -e 's/unsigned char webui_html\[]/const uint8_t webui_html[] PROGMEM/' webui_html.h \ +# && sed -i -e 's/unsigned int webui_html_len/const unsigned int webui_html_len/' webui_html.h +# rm -f webui_html.h-e webui.html + +ROOT=$(pwd) + +tsc --project ./tsconfig.json +# cd $ROOT/public/scripts +node public/scripts/build.js +cd $ROOT/data +gzip -c9 webui.html > __index +### cleanup +rm -f webui.html .??* + +echo -e "\xE2\x9C\x85 WebUI is ready\n"; \ No newline at end of file diff --git a/public/scripts/html2h.sh b/public/scripts/html2h.sh deleted file mode 100755 index 922c351f..00000000 --- a/public/scripts/html2h.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -cd ../.. -gzip -c9 webui.html > webui_html && xxd -i webui_html > webui_html.h && rm webui_html && sed -i -e 's/unsigned char webui_html\[]/const uint8_t webui_html[] PROGMEM/' webui_html.h && sed -i -e 's/unsigned int webui_html_len/const unsigned int webui_html_len/' webui_html.h -rm -fv webui_html.h-e - -echo "webui_html.h GENERATED"; \ No newline at end of file diff --git a/public/src/index.html.tpl b/public/src/index.html.tpl index ff4c94cf..759c95ad 100644 --- a/public/src/index.html.tpl +++ b/public/src/index.html.tpl @@ -1,1408 +1,962 @@ - + - + + GBS-Control - + - - + + - - - -
-
- - - - - - - -
-
-
-
- -
aspect_ratio
-
Resolution
-
- -
    -
  • Choose an output resolution from these presets.
  • -
  • Your selection will also be used for startup. 1280x960 is recommended for NTSC sources, 1280x1024 for PAL. -
  • -
  • Use the "Matched Presets" option to switch between the two automatically (Preferences tab) -
  • -
  • Selecting a resolution also makes it the new startup preset.
  • -
-
- - - - - - - -
-
-
- -
input
-
Presets
-
- -
    -
  • If you want to save your customizations, first select a slot for your new preset, then save to or load from that slot.
  • -
  • Selecting a slot also makes it the new startup preset.
  • -
-
-
- - -
-
-
- -
+ + - + + +
+
+ +
code
+
L{CONSOLE_OUTPUT_LEGEND}
+
+
+ +
+
+ +
+
-
- -
-
- -
+
- +
- - - +
+ + + + \ No newline at end of file diff --git a/public/src/index.js b/public/src/index.js deleted file mode 100644 index bf643954..00000000 --- a/public/src/index.js +++ /dev/null @@ -1,1088 +0,0 @@ -const Structs = { - slots: [ - { name: "name", type: "string", size: 25 }, - { name: "presetID", type: "byte", size: 1 }, - { name: "scanlines", type: "byte", size: 1 }, - { name: "scanlinesStrength", type: "byte", size: 1 }, - { name: "slot", type: "byte", size: 1 }, - { name: "wantVdsLineFilter", type: "byte", size: 1 }, - { name: "wantStepResponse", type: "byte", size: 1 }, - { name: "wantPeaking", type: "byte", size: 1 }, - ], -}; -const StructParser = { - pos: 0, - parseStructArray(buff, structsDescriptors, struct) { - const currentStruct = structsDescriptors[struct]; - this.pos = 0; - buff = new Uint8Array(buff); - if (currentStruct) { - const structSize = StructParser.getSize(structsDescriptors, struct); - return [...Array(buff.byteLength / structSize)].map(() => { - return currentStruct.reduce((acc, structItem) => { - acc[structItem.name] = this.getValue(buff, structItem); - return acc; - }, {}); - }); - } - return null; - }, - getValue(buff, structItem) { - switch (structItem.type) { - case "byte": - return buff[this.pos++]; - case "string": - const currentPos = this.pos; - this.pos += structItem.size; - return [...Array(structItem.size)] - .map(() => " ") - .map((_char, index) => { - if (buff[currentPos + index] > 31) { - return String.fromCharCode(buff[currentPos + index]); - } - return ""; - }) - .join("") - .trim(); - } - }, - getSize(structsDescriptors, struct) { - const currentStruct = structsDescriptors[struct]; - return currentStruct.reduce((acc, prop) => { - acc += prop.size; - return acc; - }, 0); - }, -}; -/* GBSControl Global Object*/ -const GBSControl = { - buttonMapping: { - 1: "button1280x960", - 2: "button1280x1024", - 3: "button1280x720", - 4: "button720x480", - 5: "button1920x1080", - 6: "button15kHzScaleDown", - 8: "buttonSourcePassThrough", - 9: "buttonLoadCustomPreset", - }, - controlKeysMobileMode: "move", - controlKeysMobile: { - move: { - type: "loadDoc", - left: "7", - up: "*", - right: "6", - down: "/", - }, - scale: { - type: "loadDoc", - left: "h", - up: "4", - right: "z", - down: "5", - }, - borders: { - type: "loadUser", - left: "B", - up: "C", - right: "A", - down: "D", - }, - }, - dataQueued: 0, - isWsActive: false, - maxSlots: 72, - queuedText: "", - scanSSIDDone: false, - serverIP: "", - structs: null, - timeOutWs: 0, - ui: { - backupButton: null, - backupInput: null, - customSlotFilters: null, - developerSwitch: null, - loader: null, - outputClear: null, - presetButtonList: null, - progressBackup: null, - progressRestore: null, - slotButtonList: null, - slotContainer: null, - terminal: null, - toggleList: null, - toggleSwichList: null, - webSocketConnectionWarning: null, - wifiConnect: null, - wifiConnectButton: null, - wifiList: null, - wifiListTable: null, - wifiPasswordInput: null, - wifiSSDInput: null, - wifiApButton: null, - wifiStaButton: null, - wifiStaSSID: null, - alert: null, - alertOk: null, - alertContent: null, - prompt: null, - promptOk: null, - promptCancel: null, - promptContent: null, - promptInput: null, - }, - updateTerminalTimer: 0, - webSocketServerUrl: "", - wifi: { - mode: "ap", - ssid: "", - }, - ws: null, - wsCheckTimer: 0, - wsConnectCounter: 0, - wsNoSuccessConnectingCounter: 0, - wsTimeout: 0, -}; -/** websocket services */ -const checkWebSocketServer = () => { - if (!GBSControl.isWsActive) { - if (GBSControl.ws) { - /* - 0 CONNECTING - 1 OPEN - 2 CLOSING - 3 CLOSED - */ - switch (GBSControl.ws.readyState) { - case 1: - case 2: - GBSControl.ws.close(); - break; - case 3: - GBSControl.ws = null; - break; - } - } - if (!GBSControl.ws) { - createWebSocket(); - } - } -}; -const timeOutWs = () => { - console.log("timeOutWs"); - if (GBSControl.ws) { - GBSControl.ws.close(); - } - GBSControl.isWsActive = false; - displayWifiWarning(true); -}; -const createWebSocket = () => { - if (GBSControl.ws && checkReadyState()) { - return; - } - GBSControl.wsNoSuccessConnectingCounter = 0; - GBSControl.ws = new WebSocket(GBSControl.webSocketServerUrl, ["arduino"]); - GBSControl.ws.onopen = () => { - console.log("ws onopen"); - displayWifiWarning(false); - GBSControl.wsConnectCounter++; - clearTimeout(GBSControl.wsTimeout); - GBSControl.wsTimeout = setTimeout(timeOutWs, 6000); - GBSControl.isWsActive = true; - GBSControl.wsNoSuccessConnectingCounter = 0; - }; - GBSControl.ws.onclose = () => { - console.log("ws.onclose"); - clearTimeout(GBSControl.wsTimeout); - GBSControl.isWsActive = false; - }; - GBSControl.ws.onmessage = (message) => { - clearTimeout(GBSControl.wsTimeout); - GBSControl.wsTimeout = setTimeout(timeOutWs, 2700); - GBSControl.isWsActive = true; - const [messageDataAt0, messageDataAt1, messageDataAt2, messageDataAt3, messageDataAt4, messageDataAt5,] = message.data; - if (messageDataAt0 != "#") { - GBSControl.queuedText += message.data; - GBSControl.dataQueued += message.data.length; - if (GBSControl.dataQueued >= 70000) { - GBSControl.ui.terminal.value = ""; - GBSControl.dataQueued = 0; - } - } - else { - const presetId = GBSControl.buttonMapping[messageDataAt1]; - const presetEl = document.querySelector(`[gbs-element-ref="${presetId}"]`); - const activePresetButton = presetEl - ? presetEl.getAttribute("gbs-element-ref") - : "none"; - GBSControl.ui.presetButtonList.forEach(toggleButtonActive(activePresetButton)); - const slotId = "slot-" + messageDataAt2; - const activeSlotButton = document.querySelector(`[gbs-element-ref="${slotId}"]`); - if (activeSlotButton) { - GBSControl.ui.slotButtonList.forEach(toggleButtonActive(slotId)); - } - if (messageDataAt3 && messageDataAt4 && messageDataAt5) { - const optionByte0 = messageDataAt3.charCodeAt(0); - const optionByte1 = messageDataAt4.charCodeAt(0); - const optionByte2 = messageDataAt5.charCodeAt(0); - const optionButtonList = [ - ...nodelistToArray(GBSControl.ui.toggleList), - ...nodelistToArray(GBSControl.ui.toggleSwichList), - ]; - const toggleMethod = (button, mode) => { - if (button.tagName === "TD") { - button.innerText = mode ? "toggle_on" : "toggle_off"; - } - button = button.tagName !== "TD" ? button : button.parentElement; - if (mode) { - button.setAttribute("active", ""); - } - else { - button.removeAttribute("active"); - } - }; - optionButtonList.forEach((button) => { - const toggleData = button.getAttribute("gbs-toggle") || - button.getAttribute("gbs-toggle-switch"); - switch (toggleData) { - case "adcAutoGain": - toggleMethod(button, (optionByte0 & 0x01) == 0x01); - break; - case "scanlines": - toggleMethod(button, (optionByte0 & 0x02) == 0x02); - break; - case "vdsLineFilter": - toggleMethod(button, (optionByte0 & 0x04) == 0x04); - break; - case "peaking": - toggleMethod(button, (optionByte0 & 0x08) == 0x08); - break; - case "palForce60": - toggleMethod(button, (optionByte0 & 0x10) == 0x10); - break; - case "wantOutputComponent": - toggleMethod(button, (optionByte0 & 0x20) == 0x20); - break; - /** 1 */ - case "matched": - toggleMethod(button, (optionByte1 & 0x01) == 0x01); - break; - case "frameTimeLock": - toggleMethod(button, (optionByte1 & 0x02) == 0x02); - break; - case "motionAdaptive": - toggleMethod(button, (optionByte1 & 0x04) == 0x04); - break; - case "bob": - toggleMethod(button, (optionByte1 & 0x04) != 0x04); - break; - // case "tap6": - // toggleMethod(button, (optionByte1 & 0x08) != 0x04); - // break; - case "step": - toggleMethod(button, (optionByte1 & 0x10) == 0x10); - break; - case "fullHeight": - toggleMethod(button, (optionByte1 & 0x20) == 0x20); - break; - /** 2 */ - case "enableCalibrationADC": - toggleMethod(button, (optionByte2 & 0x01) == 0x01); - break; - case "preferScalingRgbhv": - toggleMethod(button, (optionByte2 & 0x02) == 0x02); - break; - case "disableExternalClockGenerator": - toggleMethod(button, (optionByte2 & 0x04) == 0x04); - break; - } - }); - } - } - }; -}; -const checkReadyState = () => { - if (GBSControl.ws.readyState == 2) { - GBSControl.wsNoSuccessConnectingCounter++; - if (GBSControl.wsNoSuccessConnectingCounter >= 7) { - console.log("ws still closing, force close"); - GBSControl.ws = null; - GBSControl.wsNoSuccessConnectingCounter = 0; - /* fall through */ - createWebSocket(); - return false; - } - else { - return true; - } - } - else if (GBSControl.ws.readyState == 0) { - GBSControl.wsNoSuccessConnectingCounter++; - if (GBSControl.wsNoSuccessConnectingCounter >= 14) { - console.log("ws still connecting, retry"); - GBSControl.ws.close(); - GBSControl.wsNoSuccessConnectingCounter = 0; - } - return true; - } - else { - return true; - } -}; -const createIntervalChecks = () => { - GBSControl.wsCheckTimer = setInterval(checkWebSocketServer, 500); - GBSControl.updateTerminalTimer = setInterval(updateTerminal, 50); -}; -/* API services */ -const loadDoc = (link) => { - return fetch(`http://${GBSControl.serverIP}/sc?${link}&nocache=${new Date().getTime()}`); -}; -const loadUser = (link) => { - if (link == "a" || link == "1") { - GBSControl.isWsActive = false; - GBSControl.ui.terminal.value += "\nRestart\n"; - GBSControl.ui.terminal.scrollTop = GBSControl.ui.terminal.scrollHeight; - } - return fetch(`http://${GBSControl.serverIP}/uc?${link}&nocache=${new Date().getTime()}`); -}; -/** SLOT management */ -const savePreset = () => { - const currentSlot = document.querySelector('[gbs-role="slot"][active]'); - if (!currentSlot) { - return; - } - const key = currentSlot.getAttribute("gbs-element-ref"); - const currentIndex = currentSlot.getAttribute("gbs-slot-id"); - gbsPrompt("Assign a slot name", GBSControl.structs.slots[currentIndex].name || key) - .then((currentName) => { - if (currentName && currentName.trim() !== "Empty") { - currentSlot.setAttribute("gbs-name", currentName); - fetch(`/slot/save?index=${currentIndex}&name=${currentName.substring(0, 24)}&${+new Date()}`).then(() => { - loadUser("4").then(() => { - setTimeout(() => { - fetchSlotNames().then((success) => { - if (success) { - updateSlotNames(); - } - }); - }, 500); - }); - }); - } - }) - .catch(() => { }); -}; -const loadPreset = () => { - loadUser("3").then(() => { - if (GBSStorage.read("customSlotFilters") === true) { - setTimeout(() => { - fetch(`/gbs/restore-filters?${+new Date()}`); - }, 250); - } - }); -}; -const getSlotsHTML = () => { - // prettier-ignore - return [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.', '_', '~', '(', ')', '!', '*', ':', ',' - ].map((chr, idx) => { - return ``; - }).join(''); -}; -const setSlot = (slot) => { - fetch(`/slot/set?slot=${slot}&${+new Date()}`); -}; -const updateSlotNames = () => { - for (let i = 0; i < GBSControl.maxSlots; i++) { - const el = document.querySelector(`[gbs-slot-id="${i}"]`); - el.setAttribute("gbs-name", GBSControl.structs.slots[i].name); - el.setAttribute("gbs-meta", getSlotPresetName(parseInt(GBSControl.structs.slots[i].presetID, 10))); - } -}; -const fetchSlotNames = () => { - return fetch(`/bin/slots.bin?${+new Date()}`) - .then((response) => response.arrayBuffer()) - .then((arrayBuffer) => { - if (arrayBuffer.byteLength === - StructParser.getSize(Structs, "slots") * GBSControl.maxSlots) { - GBSControl.structs = { - slots: StructParser.parseStructArray(arrayBuffer, Structs, "slots"), - }; - return true; - } - return false; - }); -}; -const getSlotPresetName = (presetID) => { - switch (presetID) { - case 0x01: - case 0x011: - return "1280x960"; - case 0x02: - case 0x012: - return "1280x1024"; - case 0x03: - case 0x013: - return "1280x720"; - case 0x05: - case 0x015: - return "1920x1080"; - case 0x06: - case 0x016: - return "DOWNSCALE"; - case 0x04: - return "720x480"; - case 0x14: - return "768x576"; - case 0x21: // bypass 1 - case 0x22: // bypass 2 - return "BYPASS"; - default: - return "CUSTOM"; - } -}; -const fetchSlotNamesErrorRetry = () => { - setTimeout(fetchSlotNamesAndInit, 1000); -}; -const fetchSlotNamesAndInit = () => { - fetchSlotNames() - .then((success) => { - if (!success) { - fetchSlotNamesErrorRetry(); - return; - } - initUIElements(); - wifiGetStatus().then(() => { - initUI(); - updateSlotNames(); - createWebSocket(); - createIntervalChecks(); - setTimeout(hideLoading, 1000); - }); - }, fetchSlotNamesErrorRetry) - .catch(fetchSlotNamesErrorRetry); -}; -/** Promises */ -const serial = (funcs) => funcs.reduce((promise, func) => promise.then((result) => func().then(Array.prototype.concat.bind(result))), Promise.resolve([])); -/** helpers */ -const toggleHelp = () => { - let help = GBSStorage.read("help") || false; - GBSStorage.write("help", !help); - updateHelp(!help); -}; -const toggleDeveloperMode = () => { - const developerMode = GBSStorage.read("developerMode") || false; - GBSStorage.write("developerMode", !developerMode); - updateDeveloperMode(!developerMode); -}; -const toggleCustomSlotFilters = () => { - const customSlotFilters = GBSStorage.read("customSlotFilters"); - GBSStorage.write("customSlotFilters", !customSlotFilters); - updateCustomSlotFilters(!customSlotFilters); -}; -const updateHelp = (help) => { - if (help) { - document.body.classList.remove("gbs-help-hide"); - } - else { - document.body.classList.add("gbs-help-hide"); - } -}; -const updateDeveloperMode = (developerMode) => { - const el = document.querySelector('[gbs-section="developer"]'); - if (developerMode) { - el.removeAttribute("hidden"); - GBSControl.ui.developerSwitch.setAttribute("active", ""); - document.body.classList.remove("gbs-output-hide"); - } - else { - el.setAttribute("hidden", ""); - GBSControl.ui.developerSwitch.removeAttribute("active"); - document.body.classList.add("gbs-output-hide"); - } - GBSControl.ui.developerSwitch.querySelector(".gbs-icon").innerText = developerMode ? "toggle_on" : "toggle_off"; -}; -const updateCustomSlotFilters = (customFilters = GBSStorage.read("customSlotFilters") === true) => { - if (customFilters) { - GBSControl.ui.customSlotFilters.setAttribute("active", ""); - } - else { - GBSControl.ui.customSlotFilters.removeAttribute("active"); - } - GBSControl.ui.customSlotFilters.querySelector(".gbs-icon").innerText = customFilters ? "toggle_on" : "toggle_off"; -}; -const GBSStorage = { - lsObject: {}, - write(key, value) { - GBSStorage.lsObject = GBSStorage.lsObject || {}; - GBSStorage.lsObject[key] = value; - localStorage.setItem("GBSControlSlotNames", JSON.stringify(GBSStorage.lsObject)); - }, - read(key) { - GBSStorage.lsObject = JSON.parse(localStorage.getItem("GBSControlSlotNames") || "{}"); - return GBSStorage.lsObject[key]; - }, -}; -const nodelistToArray = (nodelist) => { - return Array.prototype.slice.call(nodelist); -}; -const toggleButtonActive = (id) => (button, _index, _array) => { - button.removeAttribute("active"); - if (button.getAttribute("gbs-element-ref") === id) { - button.setAttribute("active", ""); - } -}; -const displayWifiWarning = (mode) => { - GBSControl.ui.webSocketConnectionWarning.style.display = mode - ? "block" - : "none"; -}; -const updateTerminal = () => { - if (GBSControl.queuedText.length > 0) { - requestAnimationFrame(() => { - GBSControl.ui.terminal.value += GBSControl.queuedText; - GBSControl.ui.terminal.scrollTop = GBSControl.ui.terminal.scrollHeight; - GBSControl.queuedText = ""; - }); - } -}; -const updateViewPort = () => { - document.documentElement.style.setProperty("--viewport-height", window.innerHeight + "px"); -}; -const hideLoading = () => { - GBSControl.ui.loader.setAttribute("style", "display:none"); -}; -const checkFetchResponseStatus = (response) => { - if (!response.ok) { - throw new Error(`HTTP ${response.status} - ${response.statusText}`); - } - return response; -}; -const readLocalFile = (file) => { - const reader = new FileReader(); - reader.addEventListener("load", (event) => { - doRestore(reader.result); - }); - reader.readAsArrayBuffer(file); -}; -/** backup / restore */ -const doBackup = () => { - let backupFiles; - let done = 0; - let total = 0; - fetch("/spiffs/dir") - .then((r) => r.json()) - .then((files) => { - backupFiles = files; - total = files.length; - const funcs = files.map((path) => () => { - return fetch(`/spiffs/download?file=${path}&${+new Date()}`).then((response) => { - GBSControl.ui.progressBackup.setAttribute("gbs-progress", `${done}/${total}`); - done++; - return checkFetchResponseStatus(response) && response.arrayBuffer(); - }); - }); - return serial(funcs); - }) - .then((files) => { - const headerDescriptor = files.reduce((acc, f, index) => { - acc[backupFiles[index]] = f.byteLength; - return acc; - }, {}); - const backupFilesJSON = JSON.stringify(headerDescriptor); - const backupFilesJSONSize = backupFilesJSON.length; - const mainHeader = [ - (backupFilesJSONSize >> 24) & 255, - (backupFilesJSONSize >> 16) & 255, - (backupFilesJSONSize >> 8) & 255, - (backupFilesJSONSize >> 0) & 255, - ]; - const outputArray = [ - ...mainHeader, - ...backupFilesJSON.split("").map((c) => c.charCodeAt(0)), - ...files.reduce((acc, f, index) => { - acc = acc.concat(Array.from(new Uint8Array(f))); - return acc; - }, []), - ]; - downloadBlob(new Blob([new Uint8Array(outputArray)]), `gbs-control.backup-${+new Date()}.bin`); - GBSControl.ui.progressBackup.setAttribute("gbs-progress", ``); - }); -}; -const doRestore = (file) => { - const { backupInput } = GBSControl.ui; - const fileBuffer = new Uint8Array(file); - const headerCheck = fileBuffer.slice(4, 6); - if (headerCheck[0] !== 0x7b || headerCheck[1] !== 0x22) { - backupInput.setAttribute("disabled", ""); - gbsAlert("Invalid Backup File") - .then(() => { - backupInput.removeAttribute("disabled"); - }, () => { - backupInput.removeAttribute("disabled"); - }) - .catch(() => { - backupInput.removeAttribute("disabled"); - }); - return; - } - const b0 = fileBuffer[0], b1 = fileBuffer[1], b2 = fileBuffer[2], b3 = fileBuffer[3]; - const headerSize = (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - const headerString = Array.from(fileBuffer.slice(4, headerSize + 4)) - .map((c) => String.fromCharCode(c)) - .join(""); - const headerObject = JSON.parse(headerString); - const files = Object.keys(headerObject); - let pos = headerSize + 4; - let total = files.length; - let done = 0; - const funcs = files.map((fileName) => () => { - const fileContents = fileBuffer.slice(pos, pos + headerObject[fileName]); - const formData = new FormData(); - formData.append("file", new Blob([fileContents], { type: "application/octet-stream" }), fileName.substr(1)); - return fetch("/spiffs/upload", { - method: "POST", - body: formData, - }).then((response) => { - GBSControl.ui.progressRestore.setAttribute("gbs-progress", `${done}/${total}`); - done++; - pos += headerObject[fileName]; - return response; - }); - }); - serial(funcs).then(() => { - GBSControl.ui.progressRestore.setAttribute("gbs-progress", ``); - loadUser("a").then(() => { - gbsAlert("Restarting GBSControl.\nPlease wait until wifi reconnects then click OK") - .then(() => { - window.location.reload(); - }) - .catch(() => { }); - }); - }); -}; -const downloadBlob = (blob, name = "file.txt") => { - // Convert your blob into a Blob URL (a special url that points to an object in the browser's memory) - const blobUrl = URL.createObjectURL(blob); - // Create a link element - const link = document.createElement("a"); - // Set link's href to point to the Blob URL - link.href = blobUrl; - link.download = name; - // Append link to the body - document.body.appendChild(link); - // Dispatch click event on the link - // This is necessary as link.click() does not work on the latest firefox - link.dispatchEvent(new MouseEvent("click", { - bubbles: true, - cancelable: true, - view: window, - })); - // Remove link from body - document.body.removeChild(link); -}; -/** WIFI management */ -const wifiGetStatus = () => { - return fetch(`/wifi/status?${+new Date()}`) - .then((r) => r.json()) - .then((wifiStatus) => { - GBSControl.wifi = wifiStatus; - if (GBSControl.wifi.mode === "ap") { - GBSControl.ui.wifiApButton.setAttribute("active", ""); - GBSControl.ui.wifiApButton.classList.add("gbs-button__secondary"); - GBSControl.ui.wifiStaButton.removeAttribute("active", ""); - GBSControl.ui.wifiStaButton.classList.remove("gbs-button__secondary"); - GBSControl.ui.wifiStaSSID.innerHTML = "STA | Scan Network"; - } - else { - GBSControl.ui.wifiApButton.removeAttribute("active", ""); - GBSControl.ui.wifiApButton.classList.remove("gbs-button__secondary"); - GBSControl.ui.wifiStaButton.setAttribute("active", ""); - GBSControl.ui.wifiStaButton.classList.add("gbs-button__secondary"); - GBSControl.ui.wifiStaSSID.innerHTML = `${GBSControl.wifi.ssid}`; - } - }); -}; -const wifiConnect = () => { - const ssid = GBSControl.ui.wifiSSDInput.value; - const password = GBSControl.ui.wifiPasswordInput.value; - if (!password.length) { - GBSControl.ui.wifiPasswordInput.classList.add("gbs-wifi__input--error"); - return; - } - const formData = new FormData(); - formData.append("n", ssid); - formData.append("p", password); - fetch("/wifi/connect", { - method: "POST", - body: formData, - }).then(() => { - gbsAlert(`GBSControl will restart and will connect to ${ssid}. Please wait some seconds then press OK`) - .then(() => { - window.location.href = "http://gbscontrol.local/"; - }) - .catch(() => { }); - }); -}; -const wifiScanSSID = () => { - GBSControl.ui.wifiStaButton.setAttribute("disabled", ""); - GBSControl.ui.wifiListTable.innerHTML = ""; - if (!GBSControl.scanSSIDDone) { - fetch(`/wifi/list?${+new Date()}`).then(() => { - GBSControl.scanSSIDDone = true; - setTimeout(wifiScanSSID, 3000); - }); - return; - } - fetch(`/wifi/list?${+new Date()}`) - .then((e) => e.text()) - .then((result) => { - GBSControl.scanSSIDDone = false; - return result.length - ? result - .split("\n") - .map((line) => line.split(",")) - .map(([strength, encripted, ssid]) => { - return { strength, encripted, ssid }; - }) - : []; - }) - .then((ssids) => { - return ssids.reduce((acc, ssid) => { - return `${acc} - wifi - ${ssid.ssid} - ${ssid.encripted ? "lock" : "lock_open"} - `; - }, ""); - }) - .then((html) => { - GBSControl.ui.wifiStaButton.removeAttribute("disabled"); - if (html.length) { - GBSControl.ui.wifiListTable.innerHTML = html; - GBSControl.ui.wifiList.removeAttribute("hidden"); - GBSControl.ui.wifiConnect.setAttribute("hidden", ""); - } - }); -}; -const wifiSelectSSID = (event) => { - GBSControl.ui - .wifiSSDInput.value = event.target.parentElement.getAttribute("gbs-ssid"); - GBSControl.ui.wifiPasswordInput.classList.remove("gbs-wifi__input--error"); - GBSControl.ui.wifiList.setAttribute("hidden", ""); - GBSControl.ui.wifiConnect.removeAttribute("hidden"); -}; -const wifiSetAPMode = () => { - if (GBSControl.wifi.mode === "ap") { - return; - } - const formData = new FormData(); - formData.append("n", "dummy"); - fetch("/wifi/connect", { - method: "POST", - body: formData, - }).then(() => { - gbsAlert("Switching to AP mode. Please connect to gbscontrol SSID and then click OK") - .then(() => { - window.location.href = "http://192.168.4.1"; - }) - .catch(() => { }); - }); -}; -/** button click management */ -const controlClick = (control) => () => { - const controlKey = control.getAttribute("gbs-control-key"); - const target = GBSControl.controlKeysMobile[GBSControl.controlKeysMobileMode]; - switch (target.type) { - case "loadDoc": - loadDoc(target[controlKey]); - break; - case "loadUser": - loadUser(target[controlKey]); - break; - } -}; -const controlMouseDown = (control) => () => { - clearInterval(control["__interval"]); - const click = controlClick(control); - click(); - control["__interval"] = setInterval(click, 300); -}; -const controlMouseUp = (control) => () => { - clearInterval(control["__interval"]); -}; -/** inits */ -const initMenuButtons = () => { - const menuButtons = nodelistToArray(document.querySelector(".gbs-menu").querySelectorAll("button")); - const sections = nodelistToArray(document.querySelectorAll("section")); - const scroll = document.querySelector(".gbs-scroll"); - menuButtons.forEach((button) => button.addEventListener("click", () => { - const section = button.getAttribute("gbs-section"); - sections.forEach((section) => section.setAttribute("hidden", "")); - document - .querySelector(`section[name="${section}"]`) - .removeAttribute("hidden"); - menuButtons.forEach((btn) => btn.removeAttribute("active")); - button.setAttribute("active", ""); - scroll.scrollTo(0, 1); - })); -}; -const initGBSButtons = () => { - const actions = { - user: loadUser, - action: loadDoc, - setSlot, - }; - const buttons = nodelistToArray(document.querySelectorAll("[gbs-click]")); - buttons.forEach((button) => { - const clickMode = button.getAttribute("gbs-click"); - const message = button.getAttribute("gbs-message"); - const messageType = button.getAttribute("gbs-message-type"); - const action = actions[messageType]; - if (clickMode === "normal") { - button.addEventListener("click", () => { - action(message); - }); - } - if (clickMode === "repeat") { - const callback = () => { - action(message); - }; - button.addEventListener(!("ontouchstart" in window) ? "mousedown" : "touchstart", () => { - callback(); - clearInterval(button["__interval"]); - button["__interval"] = setInterval(callback, 300); - }); - button.addEventListener(!("ontouchstart" in window) ? "mouseup" : "touchend", () => { - clearInterval(button["__interval"]); - }); - } - }); -}; -const initClearButton = () => { - GBSControl.ui.outputClear.addEventListener("click", () => { - GBSControl.ui.terminal.value = ""; - }); -}; -const initControlMobileKeys = () => { - const controls = document.querySelectorAll("[gbs-control-target]"); - const controlsKeys = document.querySelectorAll("[gbs-control-key]"); - controls.forEach((control) => { - control.addEventListener("click", () => { - GBSControl.controlKeysMobileMode = control.getAttribute("gbs-control-target"); - controls.forEach((crtl) => { - crtl.removeAttribute("active"); - }); - control.setAttribute("active", ""); - }); - }); - controlsKeys.forEach((control) => { - control.addEventListener(!("ontouchstart" in window) ? "mousedown" : "touchstart", controlMouseDown(control)); - control.addEventListener(!("ontouchstart" in window) ? "mouseup" : "touchend", controlMouseUp(control)); - }); -}; -const initLegendHelpers = () => { - nodelistToArray(document.querySelectorAll(".gbs-fieldset__legend--help")).forEach((e) => { - e.addEventListener("click", toggleHelp); - }); -}; -const initUnloadListener = () => { - window.addEventListener("unload", () => { - clearInterval(GBSControl.wsCheckTimer); - if (GBSControl.ws) { - if (GBSControl.ws.readyState == 0 || GBSControl.ws.readyState == 1) { - GBSControl.ws.close(); - } - } - }); -}; -const initSlotButtons = () => { - GBSControl.ui.slotContainer.innerHTML = getSlotsHTML(); - GBSControl.ui.slotButtonList = nodelistToArray(document.querySelectorAll('[gbs-role="slot"]')); -}; -const initUIElements = () => { - GBSControl.ui = { - terminal: document.getElementById("outputTextArea"), - webSocketConnectionWarning: document.getElementById("websocketWarning"), - presetButtonList: nodelistToArray(document.querySelectorAll("[gbs-role='preset']")), - slotButtonList: nodelistToArray(document.querySelectorAll('[gbs-role="slot"]')), - toggleList: document.querySelectorAll("[gbs-toggle]"), - toggleSwichList: document.querySelectorAll("[gbs-toggle-switch]"), - wifiList: document.querySelector("[gbs-wifi-list]"), - wifiListTable: document.querySelector(".gbs-wifi__list"), - wifiConnect: document.querySelector(".gsb-wifi__connect"), - wifiConnectButton: document.querySelector("[gbs-wifi-connect-button]"), - wifiSSDInput: document.querySelector('[gbs-input="ssid"]'), - wifiPasswordInput: document.querySelector('[gbs-input="password"]'), - wifiApButton: document.querySelector("[gbs-wifi-ap]"), - wifiStaButton: document.querySelector("[gbs-wifi-station]"), - wifiStaSSID: document.querySelector("[gbs-wifi-station-ssid]"), - loader: document.querySelector(".gbs-loader"), - progressBackup: document.querySelector("[gbs-progress-backup]"), - progressRestore: document.querySelector("[gbs-progress-restore]"), - outputClear: document.querySelector("[gbs-output-clear]"), - slotContainer: document.querySelector("[gbs-slot-html]"), - backupButton: document.querySelector(".gbs-backup-button"), - backupInput: document.querySelector(".gbs-backup-input"), - developerSwitch: document.querySelector("[gbs-dev-switch]"), - customSlotFilters: document.querySelector("[gbs-slot-custom-filters]"), - alert: document.querySelector('section[name="alert"]'), - alertOk: document.querySelector("[gbs-alert-ok]"), - alertContent: document.querySelector("[gbs-alert-content]"), - prompt: document.querySelector('section[name="prompt"]'), - promptOk: document.querySelector("[gbs-prompt-ok]"), - promptCancel: document.querySelector("[gbs-prompt-cancel]"), - promptContent: document.querySelector("[gbs-prompt-content]"), - promptInput: document.querySelector('[gbs-input="prompt-input"]'), - }; -}; -const initGeneralListeners = () => { - window.addEventListener("resize", () => { - updateViewPort(); - }); - GBSControl.ui.backupInput.addEventListener("change", (event) => { - const fileList = event.target["files"]; - readLocalFile(fileList[0]); - GBSControl.ui.backupInput.value = ""; - }); - GBSControl.ui.backupButton.addEventListener("click", doBackup); - GBSControl.ui.wifiListTable.addEventListener("click", wifiSelectSSID); - GBSControl.ui.wifiConnectButton.addEventListener("click", wifiConnect); - GBSControl.ui.wifiApButton.addEventListener("click", wifiSetAPMode); - GBSControl.ui.wifiStaButton.addEventListener("click", wifiScanSSID); - GBSControl.ui.developerSwitch.addEventListener("click", toggleDeveloperMode); - GBSControl.ui.customSlotFilters.addEventListener("click", toggleCustomSlotFilters); - GBSControl.ui.alertOk.addEventListener("click", () => { - GBSControl.ui.alert.setAttribute("hidden", ""); - gbsAlertPromise.resolve(); - }); - GBSControl.ui.promptOk.addEventListener("click", () => { - GBSControl.ui.prompt.setAttribute("hidden", ""); - const value = GBSControl.ui.promptInput.value; - if (value !== undefined || value.length > 0) { - gbsPromptPromise.resolve(GBSControl.ui.promptInput.value); - } - else { - gbsPromptPromise.reject(); - } - }); - GBSControl.ui.promptCancel.addEventListener("click", () => { - GBSControl.ui.prompt.setAttribute("hidden", ""); - gbsPromptPromise.reject(); - }); - GBSControl.ui.promptInput.addEventListener("keydown", (event) => { - if (event.keyCode === 13) { - GBSControl.ui.prompt.setAttribute("hidden", ""); - const value = GBSControl.ui.promptInput.value; - if (value !== undefined || value.length > 0) { - gbsPromptPromise.resolve(GBSControl.ui.promptInput.value); - } - else { - gbsPromptPromise.reject(); - } - } - if (event.keyCode === 27) { - gbsPromptPromise.reject(); - } - }); -}; -const initDeveloperMode = () => { - const devMode = GBSStorage.read("developerMode"); - if (devMode === undefined) { - GBSStorage.write("developerMode", false); - updateDeveloperMode(false); - } - else { - updateDeveloperMode(devMode); - } -}; -const initHelp = () => { - let help = GBSStorage.read("help"); - if (help === undefined) { - help = false; - GBSStorage.write("help", help); - } - updateHelp(help); -}; -const gbsAlertPromise = { - resolve: null, - reject: null, -}; -const alertKeyListener = (event) => { - if (event.keyCode === 13) { - gbsAlertPromise.resolve(); - } - if (event.keyCode === 27) { - gbsAlertPromise.reject(); - } -}; -const gbsAlert = (text) => { - GBSControl.ui.alertContent.textContent = text; - GBSControl.ui.alert.removeAttribute("hidden"); - document.addEventListener("keyup", alertKeyListener); - return new Promise((resolve, reject) => { - gbsAlertPromise.resolve = (e) => { - document.removeEventListener("keyup", alertKeyListener); - GBSControl.ui.alert.setAttribute("hidden", ""); - return resolve(e); - }; - gbsAlertPromise.reject = () => { - document.removeEventListener("keyup", alertKeyListener); - GBSControl.ui.alert.setAttribute("hidden", ""); - return reject(); - }; - }); -}; -const gbsPromptPromise = { - resolve: null, - reject: null, -}; -const gbsPrompt = (text, defaultValue = "") => { - GBSControl.ui.promptContent.textContent = text; - GBSControl.ui.prompt.removeAttribute("hidden"); - GBSControl.ui.promptInput.value = defaultValue; - return new Promise((resolve, reject) => { - gbsPromptPromise.resolve = resolve; - gbsPromptPromise.reject = reject; - GBSControl.ui.promptInput.focus(); - }); -}; -const initUI = () => { - updateCustomSlotFilters(); - initGeneralListeners(); - updateViewPort(); - initSlotButtons(); - initLegendHelpers(); - initMenuButtons(); - initGBSButtons(); - initClearButton(); - initControlMobileKeys(); - initUnloadListener(); - initDeveloperMode(); - initHelp(); -}; -const main = () => { - const ip = location.hostname; - GBSControl.serverIP = ip; - GBSControl.webSocketServerUrl = `ws://${ip}:81/`; - document - .querySelector(".gbs-loader img") - .setAttribute("src", document.head - .querySelector('[rel="apple-touch-icon"]') - .getAttribute("href")); - fetchSlotNamesAndInit(); -}; -main(); diff --git a/public/src/index.ts b/public/src/index.ts index 02002dcf..27f621ae 100644 --- a/public/src/index.ts +++ b/public/src/index.ts @@ -1,1371 +1,1999 @@ -/** STRUCTS */ +/* + * DEVELOPER MEMO: + * 1. WebUI icons: https://jossef.github.io/material-design-icons-iconfont + * 2. prettier config: https://prettier.io/docs/en/options + * + */ + +interface String { + format(...params: string[]): string; +} + +if (!String.prototype.format) { + String.prototype.format = function(...arg) { + const a = arg + return this.replace(/\[(\d+)\]/g, function(val, i) { + return undefined !== typeof(a[i]) ? a[i] : val + }); + } +} + +/** + * Description placeholder + * + * @interface Struct + * @typedef {Struct} + */ interface Struct { - name: string; - type: "byte" | "string"; - size: number; + /** + * Description placeholder + * + * @type {string} + */ + name: string + /** + * Description placeholder + * + * @type {("byte" | "string")} + */ + type: 'byte' | 'string' + /** + * Description placeholder + * + * @type {number} + */ + size: number } +/** + * Description placeholder + * + * @interface StructDescriptors + * @typedef {StructDescriptors} + */ interface StructDescriptors { - [key: string]: Struct[]; + /** + * Description placeholder + */ + [key: string]: Struct[] } +/** + * Must be aligned with slots.h -> SlotMeta structure + * + * @type {StructDescriptors} + */ const Structs: StructDescriptors = { - slots: [ - { name: "name", type: "string", size: 25 }, - { name: "presetID", type: "byte", size: 1 }, - { name: "scanlines", type: "byte", size: 1 }, - { name: "scanlinesStrength", type: "byte", size: 1 }, - { name: "slot", type: "byte", size: 1 }, - { name: "wantVdsLineFilter", type: "byte", size: 1 }, - { name: "wantStepResponse", type: "byte", size: 1 }, - { name: "wantPeaking", type: "byte", size: 1 }, - ], -}; + slots: [ + { name: 'name', type: 'string', size: 25 }, + { name: 'slot', type: 'byte', size: 1 }, + { name: 'resolutionID', type: 'byte', size: 1 }, + + { name: 'scanlines', type: 'byte', size: 1 }, + { name: 'scanlinesStrength', type: 'byte', size: 1 }, + { name: 'vdsLineFilter', type: 'byte', size: 1 }, + { name: 'stepResponse', type: 'byte', size: 1 }, + { name: 'peaking', type: 'byte', size: 1 }, + { name: 'adcAutoGain', type: 'byte', size: 1 }, + { name: 'frameTimeLock', type: 'byte', size: 1 }, + + { name: 'frameTimeLockMethod', type: 'byte', size: 1 }, + { name: 'motionAdaptive', type: 'byte', size: 1 }, + { name: 'bob', type: 'byte', size: 1 }, + { name: 'fullHeight', type: 'byte', size: 1 }, + // { name: 'matchPreset', type: 'byte', size: 1 }, + { name: 'palForce60', type: 'byte', size: 1 }, + ], +} +/** + * Description placeholder + * + * @type {{ pos: number; parseStructArray(buff: ArrayBuffer, structsDescriptors: StructDescriptors, struct: string): any; getValue(buff: {}, structItem: { type: "string" | "byte"; size: number; }): any; getSize(structsDescriptors: StructDescriptors, struct: string): any; }} + */ const StructParser = { - pos: 0, - parseStructArray( - buff: ArrayBuffer, - structsDescriptors: StructDescriptors, - struct: string - ) { - const currentStruct = structsDescriptors[struct]; - - this.pos = 0; - buff = new Uint8Array(buff); - - if (currentStruct) { - const structSize = StructParser.getSize(structsDescriptors, struct); - - return [...Array(buff.byteLength / structSize)].map(() => { - return currentStruct.reduce((acc, structItem) => { - acc[structItem.name] = this.getValue(buff, structItem); - return acc; - }, {}); - }); - } + pos: 0, + parseStructArray( + buff: ArrayBuffer, + structsDescriptors: StructDescriptors, + struct: string + ) { + const currentStruct = structsDescriptors[struct] + + this.pos = 0 + buff = new Uint8Array(buff) + + if (currentStruct) { + const structSize = StructParser.getSize(structsDescriptors, struct) + + return [...Array(buff.byteLength / structSize)].map(() => { + return currentStruct.reduce((acc, structItem) => { + acc[structItem.name] = this.getValue(buff, structItem) + return acc + }, {}) + }) + } - return null; - }, - getValue(buff: any[], structItem: { type: "byte" | "string"; size: number }) { - switch (structItem.type) { - case "byte": - return buff[this.pos++]; - - case "string": - const currentPos = this.pos; - this.pos += structItem.size; - - return [...Array(structItem.size)] - .map(() => " ") - .map((_char, index) => { - if (buff[currentPos + index] > 31) { - return String.fromCharCode(buff[currentPos + index]); - } - return ""; - }) - .join("") - .trim(); - } - }, - getSize(structsDescriptors: StructDescriptors, struct: string) { - const currentStruct = structsDescriptors[struct]; - return currentStruct.reduce((acc, prop) => { - acc += prop.size; - return acc; - }, 0); - }, -}; + return null + }, + getValue( + buff: any[], + structItem: { type: 'byte' | 'string'; size: number } + ) { + switch (structItem.type) { + case 'byte': + return buff[this.pos++] + + case 'string': + const currentPos = this.pos + this.pos += structItem.size + + return [...Array(structItem.size)] + .map(() => ' ') + .map((_char, index) => { + if (buff[currentPos + index] > 31) { + return String.fromCharCode(buff[currentPos + index]) + } + return '' + }) + .join('') + .trim() + } + }, + getSize(structsDescriptors: StructDescriptors, struct: string) { + const currentStruct = structsDescriptors[struct] + return currentStruct.reduce((acc, prop) => { + acc += prop.size + return acc + }, 0) + }, +} /* GBSControl Global Object*/ const GBSControl = { - buttonMapping: { - 1: "button1280x960", - 2: "button1280x1024", - 3: "button1280x720", - 4: "button720x480", - 5: "button1920x1080", - 6: "button15kHzScaleDown", - 8: "buttonSourcePassThrough", - 9: "buttonLoadCustomPreset", - }, - controlKeysMobileMode: "move", - controlKeysMobile: { - move: { - type: "loadDoc", - left: "7", - up: "*", - right: "6", - down: "/", + buttonMapping: { + 0: 'button240p', + 2: 'button960p', + 3: 'button960p', // 50Hz + 4: 'button1024p', + 5: 'button1024p', // 50Hz + 6: 'button720p', + 7: 'button720p', // 50Hz + 8: 'button480p', + 9: 'button480p', // 50Hz + 10: 'button1080p', + 11: 'button1080p', // 50Hz + 12: 'button15kHz', + 13: 'button15kHz', // 50Hz + 15: 'button576p', // 50Hz + 16: 'buttonSourcePassThrough', + // 18: 'buttonSourcePassThrough', // OutputHdBypass + // 20: 'buttonSourcePassThrough', // OutputRGBHVBypass }, - scale: { - type: "loadDoc", - left: "h", - up: "4", - right: "z", - down: "5", + controlKeysMobileMode: 'move', + controlKeysMobile: { + move: { + type: 'loadDoc', + left: '7', + up: '*', + right: '6', + down: '/', + }, + scale: { + type: 'loadDoc', + left: 'h', + up: '4', + right: 'z', + down: '5', + }, + borders: { + type: 'loadUser', + left: 'B', + up: 'C', + right: 'A', + down: 'D', + }, }, - borders: { - type: "loadUser", - left: "B", - up: "C", - right: "A", - down: "D", + activeResolution: '', + dataQueued: 0, + isWsActive: false, + maxSlots: 50, + queuedText: '', + scanSSIDDone: false, + serverIP: '', + structs: null, + // timeOutWs: 0, + ui: { + backupButton: null, + backupInput: null, + // customSlotFilters: null, + developerSwitch: null, + loader: null, + outputClear: null, + presetButtonList: null, + progressBackup: null, + progressRestore: null, + slotButtonList: null, + slotContainer: null, + terminal: null, + registerCmdRegSection: null, + registerCmdRegOp: null, + registerCmdRegData: null, + registerCmdRegSubmit: null, + toggleConsole: null, + toggleList: null, + toggleSwichList: null, + webSocketConnectionWarning: null, + wifiConnect: null, + wifiConnectButton: null, + wifiList: null, + wifiListTable: null, + wifiPasswordInput: null, + wifiSSDInput: null, + wifiApButton: null, + wifiStaButton: null, + wifiStaSSID: null, + alert: null, + alertAck: null, + alertAct: null, + alertContent: null, + prompt: null, + promptOk: null, + promptCancel: null, + promptContent: null, + promptInput: null, + removeSlotButton: null, + createSlotButton: null, }, - }, - dataQueued: 0, - isWsActive: false, - maxSlots: 72, - queuedText: "", - scanSSIDDone: false, - serverIP: "", - structs: null, - timeOutWs: 0, - ui: { - backupButton: null, - backupInput: null, - customSlotFilters: null, - developerSwitch: null, - loader: null, - outputClear: null, - presetButtonList: null, - progressBackup: null, - progressRestore: null, - slotButtonList: null, - slotContainer: null, - terminal: null, - toggleList: null, - toggleSwichList: null, - webSocketConnectionWarning: null, - wifiConnect: null, - wifiConnectButton: null, - wifiList: null, - wifiListTable: null, - wifiPasswordInput: null, - wifiSSDInput: null, - wifiApButton: null, - wifiStaButton: null, - wifiStaSSID: null, - alert: null, - alertOk: null, - alertContent: null, - prompt: null, - promptOk: null, - promptCancel: null, - promptContent: null, - promptInput: null, - }, - updateTerminalTimer: 0, - webSocketServerUrl: "", - wifi: { - mode: "ap", - ssid: "", - }, - ws: null, - wsCheckTimer: 0, - wsConnectCounter: 0, - wsNoSuccessConnectingCounter: 0, - wsTimeout: 0, -}; + updateTerminalTimer: 0, + webSocketServerUrl: '', + wifi: { + mode: 'ap', + ssid: '', + }, + ws: null, + wsCheckTimer: 0, + // wsConnectCounter: 0, + wsNoSuccessConnectingCounter: 0, + developerMode: false, + wsHeartbeatInterval: null + // wsTimeout: 0 +} + +/** + * Description placeholder + * + * @type {({ lsObject: {}; write(key: string, value: any): void; read(key: string): string | number | boolean; })} + */ +const GBSStorage = { + lsObject: {}, + write(key: string, value: any) { + GBSStorage.lsObject = GBSStorage.lsObject || {} + GBSStorage.lsObject[key] = value + localStorage.setItem( + 'GBSControlSlotNames', + JSON.stringify(GBSStorage.lsObject) + ) + }, + read(key: string): string | number | boolean { + GBSStorage.lsObject = JSON.parse( + localStorage.getItem('GBSControlSlotNames') || '{}' + ) + return GBSStorage.lsObject[key] + }, +} + + +/** + * Reset current section(tab) to slots + */ +const resetCurrentPageSection = () => { + GBSStorage.write('section', 'presets') +} + + +/** + * Make active/visible the section which is currently in + * GBSStorage.read('section') + */ +const syncSectionTab = () => { + const menuButtons = nodelistToArray( + document.querySelector('.gbs-menu').querySelectorAll('button') + ) + menuButtons.forEach((button) => { + const sectionName = button.getAttribute('gbs-section') + // get back to the last section after reload + if(GBSStorage.read('section') === sectionName) + button.dispatchEvent(new Event("click")) + }) +} /** websocket services */ const checkWebSocketServer = () => { - if (!GBSControl.isWsActive) { - if (GBSControl.ws) { - /* - 0 CONNECTING - 1 OPEN - 2 CLOSING - 3 CLOSED - */ - switch (GBSControl.ws.readyState) { - case 1: - case 2: - GBSControl.ws.close(); - break; - case 3: - GBSControl.ws = null; - break; - } + if (!GBSControl.isWsActive) { + if (GBSControl.ws) { + /* + 0 CONNECTING + 1 OPEN + 2 CLOSING + 3 CLOSED + */ + switch (GBSControl.ws.readyState) { + case 1: + case 2: + GBSControl.ws.close() + break + case 3: + GBSControl.ws = null + break + } + } + if (!GBSControl.ws) { + createWebSocket() + } } - if (!GBSControl.ws) { - createWebSocket(); +} + +/** + * Description placeholder + */ +// const timeOutWs = () => { +// console.log('timeOutWs') + +// if (GBSControl.ws) { +// GBSControl.ws.close() +// } + +// GBSControl.isWsActive = false +// displayWifiWarning(true) +// } + +/** + * Description placeholder + * + * @template Element + * @param {(| HTMLCollectionOf + * | NodeListOf)} nodelist + * @returns {Element[]} + */ +const nodelistToArray = ( + nodelist: + | HTMLCollectionOf + | NodeListOf +): Element[] => { + return Array.prototype.slice.call(nodelist) +} + +/** + * Description placeholder + * + * @param {string} id + * @returns {(button: HTMLElement, _index: any, _array: any) => void} + */ +const toggleButtonActive = (id: string) => (button: HTMLElement, _index: any, _array: any) => { + button.removeAttribute('active') + + if (button.getAttribute('gbs-element-ref') === id) { + button.setAttribute('active', '') } - } -}; +} -const timeOutWs = () => { - console.log("timeOutWs"); +/** + * Description placeholder + * + * @type {{ resolve: any; reject: any; }} + */ +const gbsAlertPromise = { + resolve: null, + reject: null, +} - if (GBSControl.ws) { - GBSControl.ws.close(); - } +/** + * Description placeholder + * + * @param {*} event + */ +const alertKeyListener = (event: any) => { + if (event.keyCode === 13) { + gbsAlertPromise.resolve() + } + if (event.keyCode === 27) { + gbsAlertPromise.reject() + } +} - GBSControl.isWsActive = false; - displayWifiWarning(true); -}; +const alertActEventListener = (e: any) => { + gbsAlertPromise.reject() +} -const createWebSocket = () => { - if (GBSControl.ws && checkReadyState()) { - return; - } - - GBSControl.wsNoSuccessConnectingCounter = 0; - GBSControl.ws = new WebSocket(GBSControl.webSocketServerUrl, ["arduino"]); - - GBSControl.ws.onopen = () => { - console.log("ws onopen"); - - displayWifiWarning(false); - - GBSControl.wsConnectCounter++; - clearTimeout(GBSControl.wsTimeout); - GBSControl.wsTimeout = setTimeout(timeOutWs, 6000); - GBSControl.isWsActive = true; - GBSControl.wsNoSuccessConnectingCounter = 0; - }; - - GBSControl.ws.onclose = () => { - console.log("ws.onclose"); - - clearTimeout(GBSControl.wsTimeout); - GBSControl.isWsActive = false; - }; - - GBSControl.ws.onmessage = (message: any) => { - clearTimeout(GBSControl.wsTimeout); - GBSControl.wsTimeout = setTimeout(timeOutWs, 2700); - GBSControl.isWsActive = true; - - const [ - messageDataAt0, - messageDataAt1, - messageDataAt2, - messageDataAt3, - messageDataAt4, - messageDataAt5, - ] = message.data; - - if (messageDataAt0 != "#") { - GBSControl.queuedText += message.data; - GBSControl.dataQueued += message.data.length; - - if (GBSControl.dataQueued >= 70000) { - GBSControl.ui.terminal.value = ""; - GBSControl.dataQueued = 0; - } +/** + * Description placeholder + * + * @param {string} text + * @returns {*} + */ +const gbsAlert = (text: string, ackText: string = '', actText: string = '') => { + GBSControl.ui.alertContent.insertAdjacentHTML('afterbegin', text) + GBSControl.ui.alert.removeAttribute('hidden') + document.addEventListener('keyup', alertKeyListener) + if (ackText !== '') { + GBSControl.ui.alertAck.insertAdjacentHTML('afterbegin', ackText) + } else + GBSControl.ui.alertAck.insertAdjacentHTML( + 'afterbegin', + '
done
L{JS_YES}
' + ) + + if (actText !== '') { + GBSControl.ui.alertAct.insertAdjacentHTML('afterbegin', actText) + GBSControl.ui.alertAct.removeAttribute('disabled') + GBSControl.ui.alertAct.addEventListener('click', alertActEventListener) + } + return new Promise((resolve, reject) => { + const gbsAlertClean = () => { + document.removeEventListener('keyup', alertKeyListener) + GBSControl.ui.alertAct.removeEventListener( + 'click', + alertActEventListener + ) + GBSControl.ui.alertAct.setAttribute('disabled', '') + GBSControl.ui.alertAck.textContent = '' + GBSControl.ui.alertAct.textContent = '' + GBSControl.ui.alertContent.textContent = '' + GBSControl.ui.alert.setAttribute('hidden', '') + } + gbsAlertPromise.resolve = (e) => { + gbsAlertClean() + return resolve(e) + } + gbsAlertPromise.reject = () => { + gbsAlertClean() + return reject() + } + }) +} + +/** + * Description placeholder + * + * @type {{ resolve: any; reject: any; }} + */ +const gbsPromptPromise = { + resolve: null, + reject: null, +} + +/** + * Description placeholder + * + * @param {string} text + * @param {string} [defaultValue=""] + * @returns {*} + */ +const gbsPrompt = (text: string, defaultValue = '') => { + GBSControl.ui.promptContent.textContent = text + GBSControl.ui.prompt.removeAttribute('hidden') + GBSControl.ui.promptInput.value = defaultValue + + return new Promise((resolve, reject) => { + gbsPromptPromise.resolve = resolve + gbsPromptPromise.reject = reject + GBSControl.ui.promptInput.focus() + }) +} + +/** + * Description placeholder + * + * @param {boolean} mode + */ +const displayWifiWarning = (mode: boolean) => { + GBSControl.ui.webSocketConnectionWarning.style.display = mode + ? 'block' + : 'none' +} + +/** + * Flip a toggle switch + * + * @param {(HTMLTableCellElement | HTMLElement)} button + * @param {boolean} mode + */ +const toggleButtonCheck = ( + button: HTMLTableCellElement | HTMLElement, + mode: boolean +) => { + if (button.tagName === 'TD') { + button.innerText = mode ? 'toggle_on' : 'toggle_off' + } + button = button.tagName !== 'TD' ? button : button.parentElement + if (mode) { + button.setAttribute('active', '') } else { - const presetId = GBSControl.buttonMapping[messageDataAt1]; - const presetEl = document.querySelector( - `[gbs-element-ref="${presetId}"]` - ); - const activePresetButton = presetEl - ? presetEl.getAttribute("gbs-element-ref") - : "none"; - - GBSControl.ui.presetButtonList.forEach( - toggleButtonActive(activePresetButton) - ); - - const slotId = "slot-" + messageDataAt2; - const activeSlotButton = document.querySelector( - `[gbs-element-ref="${slotId}"]` - ); - - if (activeSlotButton) { - GBSControl.ui.slotButtonList.forEach(toggleButtonActive(slotId)); - } - - if (messageDataAt3 && messageDataAt4 && messageDataAt5) { - const optionByte0 = messageDataAt3.charCodeAt(0); - const optionByte1 = messageDataAt4.charCodeAt(0); - const optionByte2 = messageDataAt5.charCodeAt(0); + button.removeAttribute('active') + } +} + +/** + * Enable / Disable 'remove slot' button depending on active slot + * + * @param {HTMLElement} button this is a slot button HTMLElement + */ +const removeSlotButtonCheck = (button: Element) => { + if (button.hasAttribute('active')) { + const currentName = button.getAttribute('gbs-name') + if (currentName && currentName.trim() !== 'Empty') { + GBSControl.ui.removeSlotButton.removeAttribute('disabled') + } else { + GBSControl.ui.removeSlotButton.setAttribute('disabled', '') + } + } +} + + +/** + * Enable / Disable 'create slot' button depending on active slot + * + * @param {Element} button + */ +const createSlotButtonCheck = (button: Element) => { + if (button.hasAttribute('active')) { + const currentName = button.getAttribute('gbs-name') + if (currentName && currentName.trim() === 'Empty') { + GBSControl.ui.createSlotButton.removeAttribute('disabled') + } else { + GBSControl.ui.createSlotButton.setAttribute('disabled', '') + } + } +} + +/** + * Description placeholder + */ +const updateTerminal = () => { + if (GBSControl.queuedText.length > 0) { + requestAnimationFrame(() => { + GBSControl.ui.terminal.value += GBSControl.queuedText + GBSControl.ui.terminal.scrollTop = + GBSControl.ui.terminal.scrollHeight + GBSControl.queuedText = '' + }) + } +} + +/** + * Description placeholder + */ +const updateViewPort = () => { + document.documentElement.style.setProperty( + '--viewport-height', + window.innerHeight + 'px' + ) +} + +/** + * Handle webSocket response + */ +const createWebSocket = () => { + if (GBSControl.ws && checkReadyState()) { + return + } + + GBSControl.wsNoSuccessConnectingCounter = 0 + GBSControl.ws = new WebSocket(GBSControl.webSocketServerUrl, ['arduino']) + // change message data type + GBSControl.ws.binaryType = "arraybuffer"; + + if(!GBSControl.ws) { + displayWifiWarning(true) + return + } + + GBSControl.ws.onopen = () => { + console.log("ws.open") + displayWifiWarning(false) + GBSControl.isWsActive = true + GBSControl.wsNoSuccessConnectingCounter = 0 + } + + GBSControl.ws.onclose = () => { + console.log("ws.close") + displayWifiWarning(true) + GBSControl.isWsActive = false + } + + GBSControl.ws.onmessage = (message: any) => { + // GBSControl.wsTimeout = window.setTimeout(timeOutWs, 2700) + GBSControl.isWsActive = true + // let buf = null + // try { + // buf = await message.data.arrayBuffer() + // } catch (err) { + // // must not exit here since we're filtering out + // // terminal data and system state data with '#' + // } + if (!(message.data instanceof ArrayBuffer)) + return; + // into array of DEC values + const bufUint8Arr = new Uint8Array(message.data) + const bufArr = Array.from(bufUint8Arr) + const [ + optionByte0, // always # + optionByte1, // current slot ID (int) + optionByte2, // current resolution () + // system preferences (preference file values) + optionByte3, // wantScanlines & wantVdsLineFilter & wantStepResponse & wantPeaking & enableAutoGain & enableFrameTimeLock + optionByte4, // deintMode & wantTap6 & wantFullHeight & matchPresetSource & PalForce60 + optionByte5, // wantOutputComponent & enableCalibrationADC & preferScalingRgbhv & disableExternalClockGenerator + // developer tab + optionByte6, // developerMode, printInfos, invertSync, oversampling, ADC Filter, debugView, freezeCapture + // system tab + optionByte7, // enableOTA + optionByte8, // videoMode + ] = bufArr + + if (optionByte0 != '#'.charCodeAt(0)) { + if (!("TextDecoder" in window)) + GBSControl.queuedText = 'L{DEVELOPER_JS_ALERT_TEXTDECODER}'; + const decoder = new TextDecoder("utf-8") + + GBSControl.queuedText += decoder.decode(bufUint8Arr) + GBSControl.dataQueued += message.data.length + + if (GBSControl.dataQueued >= 70000) { + GBSControl.ui.terminal.value = '' + GBSControl.dataQueued = 0 + } + return + } + + // current slot + // const slotId = `slot-${String.fromCharCode(optionByte1)}` + const slotId = `slot-${optionByte1}` + const activeSlotButton = document.querySelector( + `[gbs-element-ref="${slotId}"]` + ) + if (activeSlotButton) { + GBSControl.ui.slotButtonList.forEach(toggleButtonActive(slotId)) + // control slot remove button + removeSlotButtonCheck(activeSlotButton) + createSlotButtonCheck(activeSlotButton) + } + // curent resolution + // const resID = GBSControl.buttonMapping[String.fromCharCode(optionByte2)] + const resID = GBSControl.buttonMapping[optionByte2] + // somehow indicate that this is passthrough which is scaled + // (?) but not a downscale option + const passThroughButton = document.querySelector('[gbs-message="W"][gbs-message-type="user"]') + if((optionByte5 & 0x04) == 0x04 && optionByte2 != 12 && optionByte2 != 13) { + // we have RGB/HV and scale RGB/HV option enabled, so + // reflect this in UI + passThroughButton.setAttribute('active', '') + passThroughButton.setAttribute('disabled', '') + } else { + passThroughButton.removeAttribute('active') + passThroughButton.removeAttribute('disabled') + } + const resEl = document.querySelector(`[gbs-element-ref="${resID}"]`) + const activePresetButton = resEl + ? resEl.getAttribute('gbs-element-ref') + : 'none' + GBSControl.ui.presetButtonList.forEach( + toggleButtonActive(activePresetButton) + ) + // settings tab & system preferences const optionButtonList = [ - ...nodelistToArray(GBSControl.ui.toggleList), - ...nodelistToArray(GBSControl.ui.toggleSwichList), - ]; - - const toggleMethod = ( - button: HTMLTableCellElement | HTMLElement, - mode: boolean - ) => { - if (button.tagName === "TD") { - button.innerText = mode ? "toggle_on" : "toggle_off"; - } - button = button.tagName !== "TD" ? button : button.parentElement; - if (mode) { - button.setAttribute("active", ""); - } else { - button.removeAttribute("active"); - } - }; + ...nodelistToArray(GBSControl.ui.toggleList), + ...nodelistToArray( + GBSControl.ui.toggleSwichList + ), + ] optionButtonList.forEach((button) => { - const toggleData = - button.getAttribute("gbs-toggle") || - button.getAttribute("gbs-toggle-switch"); - - switch (toggleData) { - case "adcAutoGain": - toggleMethod(button, (optionByte0 & 0x01) == 0x01); - break; - case "scanlines": - toggleMethod(button, (optionByte0 & 0x02) == 0x02); - break; - case "vdsLineFilter": - toggleMethod(button, (optionByte0 & 0x04) == 0x04); - break; - case "peaking": - toggleMethod(button, (optionByte0 & 0x08) == 0x08); - break; - case "palForce60": - toggleMethod(button, (optionByte0 & 0x10) == 0x10); - break; - case "wantOutputComponent": - toggleMethod(button, (optionByte0 & 0x20) == 0x20); - break; - /** 1 */ - - case "matched": - toggleMethod(button, (optionByte1 & 0x01) == 0x01); - break; - case "frameTimeLock": - toggleMethod(button, (optionByte1 & 0x02) == 0x02); - break; - case "motionAdaptive": - toggleMethod(button, (optionByte1 & 0x04) == 0x04); - break; - case "bob": - toggleMethod(button, (optionByte1 & 0x04) != 0x04); - break; - // case "tap6": - // toggleMethod(button, (optionByte1 & 0x08) != 0x04); - // break; - case "step": - toggleMethod(button, (optionByte1 & 0x10) == 0x10); - break; - case "fullHeight": - toggleMethod(button, (optionByte1 & 0x20) == 0x20); - break; - /** 2 */ - case "enableCalibrationADC": - toggleMethod(button, (optionByte2 & 0x01) == 0x01); - break; - case "preferScalingRgbhv": - toggleMethod(button, (optionByte2 & 0x02) == 0x02); - break; - case "disableExternalClockGenerator": - toggleMethod(button, (optionByte2 & 0x04) == 0x04); - break; - } - }); - } + const toggleData = + button.getAttribute('gbs-toggle') || + button.getAttribute('gbs-toggle-switch') + + if (toggleData !== null) { + switch (toggleData) { + /** 0: settings */ + // case "scanlinesStrength": + /** 1 */ + case 'scanlines': + // disable scanlines control button if enabled MotionAdaptive + if((optionByte4 & 0x01) == 0x01 + && (optionByte8 == 1 || optionByte8 == 2 || optionByte8 == 14)) + // MAD enabled + specific video mode + button.setAttribute('disabled', '') + else + toggleButtonCheck(button, (optionByte3 & 0x01) == 0x01) + break + case 'vdsLineFilter': + toggleButtonCheck(button, (optionByte3 & 0x02) == 0x02) + break + case 'stepResponse': + toggleButtonCheck(button, (optionByte3 & 0x04) == 0x04) + break + case 'peaking': + toggleButtonCheck(button, (optionByte3 & 0x08) == 0x08) + break + case 'adcAutoGain': + toggleButtonCheck(button, (optionByte3 & 0x10) == 0x10) + break + case 'frameTimeLock': + toggleButtonCheck(button, (optionByte3 & 0x20) == 0x20) + break + /** 2 */ + // case "fameTimeLockMethod": + /** 3 */ + case 'motionAdaptive': + toggleButtonCheck(button, (optionByte4 & 0x01) == 0x01) + break + case 'bob': + toggleButtonCheck(button, (optionByte4 & 0x02) == 0x02) + break + case 'fullHeight': + toggleButtonCheck(button, (optionByte4 & 0x04) == 0x04) + break + case 'palForce60': + toggleButtonCheck(button, (optionByte4 & 0x08) == 0x08) + break + // case 'matchPreset': + // toggleButtonCheck(button, (optionByte4 & 0x08) == 0x08) + // break + /** 4: system preferences tab */ + case 'wantOutputComponent': + toggleButtonCheck(button, (optionByte5 & 0x01) == 0x01) + break + case 'enableCalibrationADC': + toggleButtonCheck(button, (optionByte5 & 0x02) == 0x02) + break + case 'preferScalingRgbhv': + toggleButtonCheck(button, (optionByte5 & 0x04) == 0x04) + break + case 'disableExternalClockGenerator': + toggleButtonCheck(button, (optionByte5 & 0x08) == 0x08) + break + } + } + }) + // developer tab + const printInfoButton = document.querySelector( + `button[gbs-message="i"][gbs-message-type="action"]` + ) + const invertSync = document.querySelector( + `button[gbs-message="8"][gbs-message-type="action"]` + ) + const oversampling = document.querySelector( + `button[gbs-message="o"][gbs-message-type="action"]` + ) + const adcFilter = document.querySelector( + `button[gbs-message="F"][gbs-message-type="action"]` + ) + const debugView = document.querySelector( + `button[gbs-message="D"][gbs-message-type="action"]` + ) + const freezeCaptureButton = document.querySelector( + `button[gbs-message="F"][gbs-message-type="user"]` + ) + const syncWatcherButton = document.querySelector( + `button[gbs-message="m"][gbs-message-type="action"]` + ) + if ((optionByte6 & 0x01) == 0x01) + GBSControl.developerMode = true; + else + GBSControl.developerMode = false; + toggleDeveloperMode() + + if ((optionByte6 & 0x02) == 0x02) + printInfoButton.setAttribute('active', '') + else + printInfoButton.removeAttribute('active') + if ((optionByte6 & 0x04) == 0x04) + invertSync.setAttribute('active', '') + else + invertSync.removeAttribute('active') + if ((optionByte6 & 0x08) == 0x08) + oversampling.setAttribute('active', '') + else + oversampling.removeAttribute('active') + if ((optionByte6 & 0x10) == 0x10) + adcFilter.setAttribute('active', '') + else + adcFilter.removeAttribute('active') + if ((optionByte6 & 0x20) == 0x20) + debugView.setAttribute('active', '') + else + debugView.removeAttribute('active') + if ((optionByte6 & 0x40) == 0x40) + freezeCaptureButton.setAttribute('active', '') + else + freezeCaptureButton.removeAttribute('active') + if ((optionByte6 & 0x80) == 0x80) + syncWatcherButton.setAttribute('active', '') + else + syncWatcherButton.removeAttribute('active') + + // system tab + const enableOTAButton = document.querySelector( + `button[gbs-message="c"][gbs-message-type="action"]` + ) + if ((optionByte7 & 0x01) == 0x01) + enableOTAButton.setAttribute('active', '') + else enableOTAButton.removeAttribute('active') } - }; -}; +} +/** + * Description placeholder + * + * @returns {boolean} + */ const checkReadyState = () => { - if (GBSControl.ws.readyState == 2) { - GBSControl.wsNoSuccessConnectingCounter++; - - if (GBSControl.wsNoSuccessConnectingCounter >= 7) { - console.log("ws still closing, force close"); - GBSControl.ws = null; - GBSControl.wsNoSuccessConnectingCounter = 0; - /* fall through */ - createWebSocket(); - return false; - } else { - return true; - } - } else if (GBSControl.ws.readyState == 0) { - GBSControl.wsNoSuccessConnectingCounter++; + if (GBSControl.ws.readyState == 2) { + GBSControl.wsNoSuccessConnectingCounter++ + + if (GBSControl.wsNoSuccessConnectingCounter >= 7) { + console.log('ws still closing, force close') + GBSControl.ws = null + GBSControl.wsNoSuccessConnectingCounter = 0 + /* fall through */ + createWebSocket() + return false + } else { + return true + } + } else if (GBSControl.ws.readyState == 0) { + GBSControl.wsNoSuccessConnectingCounter++ - if (GBSControl.wsNoSuccessConnectingCounter >= 14) { - console.log("ws still connecting, retry"); - GBSControl.ws.close(); - GBSControl.wsNoSuccessConnectingCounter = 0; + if (GBSControl.wsNoSuccessConnectingCounter >= 14) { + console.log('ws still connecting, retry') + GBSControl.ws.close() + GBSControl.wsNoSuccessConnectingCounter = 0 + } + return true + } else { + return true } - return true; - } else { - return true; - } -}; +} +/** + * Description placeholder + */ const createIntervalChecks = () => { - GBSControl.wsCheckTimer = setInterval(checkWebSocketServer, 500); - GBSControl.updateTerminalTimer = setInterval(updateTerminal, 50); -}; + GBSControl.wsCheckTimer = window.setInterval(checkWebSocketServer, 500) + GBSControl.updateTerminalTimer = window.setInterval(updateTerminal, 50) +} /* API services */ +/** + * Description placeholder + * + * @param {string} link + * @returns {*} + */ const loadDoc = (link: string) => { - return fetch( - `http://${GBSControl.serverIP}/sc?${link}&nocache=${new Date().getTime()}` - ); -}; + return fetch( + `http://${GBSControl.serverIP}/sc?${link}&nocache=${new Date().getTime()}` + ).catch(() => { + // do something + }) +} +/** + * user command handler + * + * @param {string} link + * @returns {*} + */ const loadUser = (link: string) => { - if (link == "a" || link == "1") { - GBSControl.isWsActive = false; - GBSControl.ui.terminal.value += "\nRestart\n"; - GBSControl.ui.terminal.scrollTop = GBSControl.ui.terminal.scrollHeight; - } - - return fetch( - `http://${GBSControl.serverIP}/uc?${link}&nocache=${new Date().getTime()}` - ); -}; - -/** SLOT management */ + if (link == 'a' || link == '1') { + GBSControl.isWsActive = false + GBSControl.ui.terminal.value += '\nL{DEVICE_RESTARTING_CONSOLE_MESSAGE}\n' + GBSControl.ui.terminal.scrollTop = GBSControl.ui.terminal.scrollHeight + resetCurrentPageSection() + } -const savePreset = () => { - const currentSlot = document.querySelector('[gbs-role="slot"][active]'); - - if (!currentSlot) { - return; - } - - const key = currentSlot.getAttribute("gbs-element-ref"); - const currentIndex = currentSlot.getAttribute("gbs-slot-id"); - gbsPrompt( - "Assign a slot name", - GBSControl.structs.slots[currentIndex].name || key - ) - .then((currentName: string) => { - if (currentName && currentName.trim() !== "Empty") { - currentSlot.setAttribute("gbs-name", currentName); - fetch( - `/slot/save?index=${currentIndex}&name=${currentName.substring( - 0, - 24 - )}&${+new Date()}` - ).then(() => { - loadUser("4").then(() => { - setTimeout(() => { - fetchSlotNames().then((success: boolean) => { - if (success) { - updateSlotNames(); - } - }); - }, 500); - }); - }); - } + return fetch( + `http://${GBSControl.serverIP}/uc?${link}&nocache=${new Date().getTime()}` + ).catch(() => { + // do something }) - .catch(() => {}); -}; - -const loadPreset = () => { - loadUser("3").then(() => { - if (GBSStorage.read("customSlotFilters") === true) { - setTimeout(() => { - fetch(`/gbs/restore-filters?${+new Date()}`); - }, 250); - } - }); -}; +} -const getSlotsHTML = () => { - // prettier-ignore - return [ - 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', - 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', - '0','1','2','3','4','5','6','7','8','9','-','.','_','~','(',')','!','*',':',',' - ].map((chr,idx)=>{ - - return ``; - - }).join(''); -}; +/** WIFI management */ +const wifiGetStatus = () => { + return fetch(`http://${GBSControl.serverIP}/wifi/status?${+new Date()}`) + .then((r) => r.json()) + .then((wifiStatus: { mode: string; ssid: string }) => { + GBSControl.wifi = wifiStatus + if (GBSControl.wifi.mode === 'ap' || GBSControl.wifi.ssid.length == 0) { + GBSControl.ui.wifiApButton.setAttribute('active', '') + GBSControl.ui.wifiApButton.setAttribute('disabled', '') + GBSControl.ui.wifiApButton.classList.add( + 'gbs-button__secondary' + ) + GBSControl.ui.wifiStaButton.removeAttribute('active', '') + GBSControl.ui.wifiStaButton.classList.remove( + 'gbs-button__secondary' + ) + GBSControl.ui.wifiStaSSID.innerHTML = 'STA | Scan Network' + } else { + GBSControl.ui.wifiApButton.removeAttribute('active', '') + GBSControl.ui.wifiApButton.classList.remove( + 'gbs-button__secondary' + ) + GBSControl.ui.wifiStaButton.setAttribute('active', '') + GBSControl.ui.wifiStaButton.classList.add( + 'gbs-button__secondary' + ) + GBSControl.ui.wifiStaSSID.innerHTML = `${GBSControl.wifi.ssid}` + } + }).catch(() => { + // do something + }) +} -const setSlot = (slot: string) => { - fetch(`/slot/set?slot=${slot}&${+new Date()}`); -}; +/** + * Does connect to selected WiFi network + */ +const wifiConnect = () => { + const ssid = GBSControl.ui.wifiSSDInput.value + const password = GBSControl.ui.wifiPasswordInput.value -const updateSlotNames = () => { - for (let i = 0; i < GBSControl.maxSlots; i++) { - const el = document.querySelector(`[gbs-slot-id="${i}"]`); - - el.setAttribute("gbs-name", GBSControl.structs.slots[i].name); - el.setAttribute( - "gbs-meta", - getSlotPresetName(parseInt(GBSControl.structs.slots[i].presetID, 10)) - ); - } -}; + if (!password.length) { + GBSControl.ui.wifiPasswordInput.classList.add('gbs-wifi__input--error') + return + } -const fetchSlotNames = () => { - return fetch(`/bin/slots.bin?${+new Date()}`) - .then((response) => response.arrayBuffer()) - .then((arrayBuffer: ArrayBuffer) => { - if ( - arrayBuffer.byteLength === - StructParser.getSize(Structs, "slots") * GBSControl.maxSlots - ) { - GBSControl.structs = { - slots: StructParser.parseStructArray(arrayBuffer, Structs, "slots"), - }; - return true; - } - return false; - }); -}; + const formData = new FormData() + formData.append('n', ssid) + formData.append('p', password) + + fetch(`http://${GBSControl.serverIP}/wifi/connect`, { + method: 'POST', + body: formData, + }).then(() => { + gbsAlert( + 'L{CONNECT_JS_ALERT_MESSAGE}'.format(ssid) + // `GBSControl will restart and will connect to ${ssid}. Please wait few seconds then press OK` + ) + .then(() => { + window.location.href = 'http://gbscontrol.local/' + }) + .catch(() => {}) + }).catch(() => { + // do something + }) +} -const getSlotPresetName = (presetID: number) => { - switch (presetID) { - case 0x01: - case 0x011: - return "1280x960"; - case 0x02: - case 0x012: - return "1280x1024"; - case 0x03: - case 0x013: - return "1280x720"; - case 0x05: - case 0x015: - return "1920x1080"; - case 0x06: - case 0x016: - return "DOWNSCALE"; - case 0x04: - return "720x480"; - case 0x14: - return "768x576"; - case 0x21: // bypass 1 - case 0x22: // bypass 2 - return "BYPASS"; - default: - return "CUSTOM"; - } -}; +/** + * Query WiFi networks + */ +const wifiScanSSID = () => { + GBSControl.ui.wifiStaButton.setAttribute('disabled', '') + GBSControl.ui.wifiListTable.innerHTML = '' + + if (!GBSControl.scanSSIDDone) { + fetch(`http://${GBSControl.serverIP}/wifi/list?${+new Date()}`, { + method: 'POST', + }).then(() => { + GBSControl.scanSSIDDone = true + window.setTimeout(wifiScanSSID, 3000) + }).catch(() => { + // do something + }) + return + } -const fetchSlotNamesErrorRetry = () => { - setTimeout(fetchSlotNamesAndInit, 1000); -}; + fetch(`http://${GBSControl.serverIP}/wifi/list?${+new Date()}`, { + method: 'POST', + }) + .then((e) => e.text()) + .then((result) => { + GBSControl.scanSSIDDone = false + return result.length + ? result + .split('\n') + .map((line) => line.split(',')) + .map(([strength, encripted, ssid]) => { + return { strength, encripted, ssid } + }) + : [] + }) + .then((ssids) => { + return ssids.reduce((acc, ssid) => { + return `${acc} + wifi + ${ssid.ssid} + ${ssid.encripted ? 'lock' : 'lock_open'} + ` + }, '') + }) + .then((html) => { + GBSControl.ui.wifiStaButton.removeAttribute('disabled') -const fetchSlotNamesAndInit = () => { - fetchSlotNames() - .then((success) => { - if (!success) { - fetchSlotNamesErrorRetry(); - return; - } - initUIElements(); - wifiGetStatus().then(() => { - initUI(); - updateSlotNames(); - createWebSocket(); - createIntervalChecks(); - setTimeout(hideLoading, 1000); - }); - }, fetchSlotNamesErrorRetry) - .catch(fetchSlotNamesErrorRetry); -}; + if (html.length) { + GBSControl.ui.wifiListTable.innerHTML = html + GBSControl.ui.wifiList.removeAttribute('hidden') + GBSControl.ui.wifiConnect.setAttribute('hidden', '') + } + }).catch(() => { + // do something + }) +} -/** Promises */ -const serial = (funcs: (() => Promise)[]) => - funcs.reduce( - (promise, func) => - promise.then((result) => - func().then(Array.prototype.concat.bind(result)) - ), - Promise.resolve([]) - ); +/** + * Description placeholder + * + * @param {Event} event + */ +const wifiSelectSSID = (event: Event) => { + ;(GBSControl.ui.wifiSSDInput as HTMLInputElement).value = ( + event.target as HTMLElement + ).parentElement.getAttribute('gbs-ssid') + GBSControl.ui.wifiPasswordInput.classList.remove('gbs-wifi__input--error') + GBSControl.ui.wifiList.setAttribute('hidden', '') + GBSControl.ui.wifiConnect.removeAttribute('hidden') +} -/** helpers */ +/** + * Description placeholder + * + * @returns {*} + */ +const wifiSetAPMode = () => { + if (GBSControl.wifi.mode === 'ap') { + return + } -const toggleHelp = () => { - let help = GBSStorage.read("help") || false; + return fetch(`http://${GBSControl.serverIP}/wifi/ap`, { + method: 'POST', + // body: formData, + }).then((response) => { + gbsAlert( + 'L{ACCESS_POINT_MODE_JS_ALERT_MESSAGE}' + // 'Switching to AP mode. Please connect to gbscontrol SSID and then click OK' + ) + .then(() => { + window.location.href = 'http://192.168.4.1' + }) + .catch(() => {}) + return response + }).catch(() => { + // do something + }) +} - GBSStorage.write("help", !help); - updateHelp(!help); -}; +/** SLOT management */ -const toggleDeveloperMode = () => { - const developerMode = GBSStorage.read("developerMode") || false; +/** + * Description placeholder + */ +const fetchSlotNamesErrorRetry = () => { + window.setTimeout(fetchSlotNamesAndInit, 1000) +} - GBSStorage.write("developerMode", !developerMode); - updateDeveloperMode(!developerMode); -}; +/** + * Description placeholder + */ +const initUIElements = () => { + GBSControl.ui = { + terminal: document.getElementById('outputTextArea'), + webSocketConnectionWarning: document.getElementById('websocketWarning'), + presetButtonList: nodelistToArray( + document.querySelectorAll("[gbs-role='preset']") + ) as HTMLElement[], + slotButtonList: nodelistToArray( + document.querySelectorAll('[gbs-role="slot"]') + ) as HTMLElement[], + registerCmdRegSection: document.querySelector('[gbs-register-section]'), + registerCmdRegOp: document.querySelector('[gbs-register-operation]'), + registerCmdRegData: document.querySelector('[gbs-register-data]'), + registerCmdRegSubmit: document.querySelector('[gbs-register-submit]'), + toggleConsole: document.querySelector('[gbs-output-toggle]'), + toggleList: document.querySelectorAll('[gbs-toggle]'), + toggleSwichList: document.querySelectorAll('[gbs-toggle-switch]'), + wifiList: document.querySelector('[gbs-wifi-list]'), + wifiListTable: document.querySelector('.gbs-wifi__list'), + wifiConnect: document.querySelector('.gsb-wifi__connect'), + wifiConnectButton: document.querySelector('[gbs-wifi-connect-button]'), + wifiSSDInput: document.querySelector('[gbs-input="ssid"]'), + wifiPasswordInput: document.querySelector('[gbs-input="password"]'), + wifiApButton: document.querySelector('[gbs-wifi-ap]'), + wifiStaButton: document.querySelector('[gbs-wifi-station]'), + wifiStaSSID: document.querySelector('[gbs-wifi-station-ssid]'), + loader: document.querySelector('.gbs-loader'), + progressBackup: document.querySelector('[gbs-progress-backup]'), + progressRestore: document.querySelector('[gbs-progress-restore]'), + outputClear: document.querySelector('[gbs-output-clear]'), + slotContainer: document.querySelector('[gbs-slot-html]'), + backupButton: document.querySelector('.gbs-backup-button'), + backupInput: document.querySelector('.gbs-backup-input'), + developerSwitch: document.querySelector('[gbs-dev-switch]'), + // customSlotFilters: document.querySelector("[gbs-slot-custom-filters]"), + alert: document.querySelector('section[name="alert"]'), + alertAck: document.querySelector('[gbs-alert-ack]'), + alertAct: document.querySelector('[gbs-alert-act]'), + alertContent: document.querySelector('[gbs-alert-content]'), + prompt: document.querySelector('section[name="prompt"]'), + promptOk: document.querySelector('[gbs-prompt-ok]'), + promptCancel: document.querySelector('[gbs-prompt-cancel]'), + promptContent: document.querySelector('[gbs-prompt-content]'), + promptInput: document.querySelector('[gbs-input="prompt-input"]'), + removeSlotButton: document.querySelector( + '[gbs-element-ref="buttonRemoveSlot"]' + ), + createSlotButton: document.querySelector( + '[gbs-element-ref="buttonCreateSlot"]' + ), + } +} -const toggleCustomSlotFilters = () => { - const customSlotFilters = GBSStorage.read("customSlotFilters"); - GBSStorage.write("customSlotFilters", !customSlotFilters); - updateCustomSlotFilters(!customSlotFilters); -}; +/** + * Description placeholder + */ +const fetchSlotNamesAndInit = () => { + fetchSlotNames() + .then((success) => { + if (!success) { + fetchSlotNamesErrorRetry() + return + } + initUIElements() + wifiGetStatus().then(() => { + initUI() + updateSlotNames() + createWebSocket() + createIntervalChecks() + window.setTimeout(hideLoading, 1000) + }) + }, fetchSlotNamesErrorRetry) + .catch(fetchSlotNamesErrorRetry) +} -const updateHelp = (help: boolean) => { - if (help) { - document.body.classList.remove("gbs-help-hide"); - } else { - document.body.classList.add("gbs-help-hide"); - } -}; +/** + * Description placeholder + * + * @returns {*} + */ +const fetchSlotNames = () => { + return fetch(`http://${GBSControl.serverIP}/bin/slots.bin?${+new Date()}`) + .then((response) => response.arrayBuffer()) + .then((arrayBuffer: ArrayBuffer) => { + if ( + arrayBuffer.byteLength === + StructParser.getSize(Structs, 'slots') * GBSControl.maxSlots + ) { + GBSControl.structs = { + slots: StructParser.parseStructArray( + arrayBuffer, + Structs, + 'slots' + ), + } + return true + } + return false + }).catch(() => { + // do something + }) +} -const updateDeveloperMode = (developerMode: boolean) => { - const el = document.querySelector('[gbs-section="developer"]') as HTMLElement; - if (developerMode) { - el.removeAttribute("hidden"); - GBSControl.ui.developerSwitch.setAttribute("active", ""); - document.body.classList.remove("gbs-output-hide"); - } else { - el.setAttribute("hidden", ""); - GBSControl.ui.developerSwitch.removeAttribute("active"); - document.body.classList.add("gbs-output-hide"); - } - - GBSControl.ui.developerSwitch.querySelector( - ".gbs-icon" - ).innerText = developerMode ? "toggle_on" : "toggle_off"; -}; +/** + * Remove slot handler + */ +const removePreset = () => { + const currentSlot = document.querySelector('[gbs-role="slot"][active]') -const updateCustomSlotFilters = ( - customFilters: boolean = GBSStorage.read("customSlotFilters") === true -) => { - if (customFilters) { - GBSControl.ui.customSlotFilters.setAttribute("active", ""); - } else { - GBSControl.ui.customSlotFilters.removeAttribute("active"); - } - - GBSControl.ui.customSlotFilters.querySelector( - ".gbs-icon" - ).innerText = customFilters ? "toggle_on" : "toggle_off"; -}; + if (!currentSlot) { + return + } -const GBSStorage = { - lsObject: {}, - write(key: string, value: any) { - GBSStorage.lsObject = GBSStorage.lsObject || {}; - GBSStorage.lsObject[key] = value; - localStorage.setItem( - "GBSControlSlotNames", - JSON.stringify(GBSStorage.lsObject) - ); - }, - read(key: string): string | number | boolean { - GBSStorage.lsObject = JSON.parse( - localStorage.getItem("GBSControlSlotNames") || "{}" - ); - return GBSStorage.lsObject[key]; - }, -}; + const currentIndex = currentSlot.getAttribute('gbs-message') + const currentName = currentSlot.getAttribute('gbs-name') + if (currentName && currentName.trim() !== 'Empty') { + gbsAlert( + 'L{REMOVE_SLOT_JS_ALERT_MESSAGE}'.format(currentName), + // `

Are you sure to remove slot: ${currentName}?

This action also removes all related presets.

`, + '
done
L{JS_YES}
', + '
close
L{JS_NO}
' + ) + .then(() => { + return fetch( + `http://${GBSControl.serverIP}/slot/remove?index=${currentIndex}&${+new Date()}` + ).then(() => { + console.log('slot removed, reloadng slots...') + fetchSlotNames().then((success: boolean) => { + if (success) { + updateSlotNames() + } else { + fetchSlotNamesErrorRetry() + } + }) + }).catch(() => { + // do something + }) + }) + .catch(() => {}) + } +} -const nodelistToArray = ( - nodelist: - | HTMLCollectionOf - | NodeListOf -): Element[] => { - return Array.prototype.slice.call(nodelist); -}; +/** + * + * @returns + */ +const savePreset = () => { + const currentSlot = document.querySelector('[gbs-role="slot"][active]') -const toggleButtonActive = (id: string) => ( - button: HTMLElement, - _index: any, - _array: any -) => { - button.removeAttribute("active"); + if (!currentSlot) { + return + } - if (button.getAttribute("gbs-element-ref") === id) { - button.setAttribute("active", ""); - } -}; + const key = currentSlot.getAttribute('gbs-element-ref') + const currentIndex = currentSlot.getAttribute('gbs-message') + gbsPrompt( + 'Assign a slot name', + GBSControl.structs.slots[currentIndex].name || key + ) + .then((currentName: string) => { + if (currentName && currentName.trim() !== 'Empty') { + currentSlot.setAttribute('gbs-name', currentName) + fetch( + `http://${GBSControl.serverIP}/slot/save?index=${currentIndex}&name=${currentName.substring( + 0, + 24 + )}&${+new Date()}` + ).then(() => { + // loadUser("4").then(() => { + window.setTimeout(() => { + fetchSlotNames().then((success: boolean) => { + if (success) { + updateSlotNames() + } + }) + }, 500) + // }); + }).catch(() => { + // do something + }) + } + }) + .catch(() => {}) +} -const displayWifiWarning = (mode: boolean) => { - GBSControl.ui.webSocketConnectionWarning.style.display = mode - ? "block" - : "none"; -}; +/** + * Description placeholder + * + * @returns {*} + */ +const getSlotsHTML = () => { + // TODO: 'i' max. rely on SLOTS_TOTAL which is ambigous + let str = `` + for (let i = 0; i != GBSControl.maxSlots; i++) { + str += `` + } + return str +} -const updateTerminal = () => { - if (GBSControl.queuedText.length > 0) { - requestAnimationFrame(() => { - GBSControl.ui.terminal.value += GBSControl.queuedText; - GBSControl.ui.terminal.scrollTop = GBSControl.ui.terminal.scrollHeight; - GBSControl.queuedText = ""; - }); - } -}; +/** + * Description placeholder + * + * @param {string} slot + */ +const setSlot = (slot: string, el: HTMLElement) => { + fetch(`http://${GBSControl.serverIP}/slot/set?index=${slot}&${+new Date()}`) + .catch(() => { + // do something + }) +} -const updateViewPort = () => { - document.documentElement.style.setProperty( - "--viewport-height", - window.innerHeight + "px" - ); -}; +/** + * Description placeholder + */ +const updateSlotNames = () => { + for (let i = 0; i < GBSControl.maxSlots; i++) { + const el = document.querySelector( + `[gbs-message="${i}"][gbs-role="slot"]` + ) + + el.setAttribute('gbs-name', GBSControl.structs.slots[i].name) + el.setAttribute( + 'gbs-meta', + getSlotPresetName(GBSControl.structs.slots[i].resolutionID) + ) + } +} -const hideLoading = () => { - GBSControl.ui.loader.setAttribute("style", "display:none"); -}; -const checkFetchResponseStatus = (response: Response) => { - if (!response.ok) { - throw new Error(`HTTP ${response.status} - ${response.statusText}`); - } - return response; -}; +/** + * Must be aligned with options.h -> OutputResolution + * + * @param {string} resolutionID + * @returns {("1280x960" | "1280x1024" | "1280x720" | "720x480" | "1920x1080" | "DOWNSCALE" | "768×576" | "BYPASS (HD)" | "BYPASS (RGBHV)" | "240p" | "NONE")} + */ +const getSlotPresetName = (resolutionID: number) => { + switch (resolutionID) { + case 2: //'c': + case 3: //'d': + // case 0x011: + return '1280x960' + case 4: //'e': + case 5: //'f': + // case 0x012: + return '1280x1024' + case 6: //'g': + case 7: //'h': + // case 0x013: + return '1280x720' + case 8: //'i': + case 9: //'j': + // case 0x015: + return '720x480' + case 10: //'k': + case 11: //'l': + return '1920x1080' + case 12: //'m': + case 13: //'n': + // case 0x016: + return 'DOWNSCALE' + case 15: //'p': + return '768×576' + case 18: //'s': + return 'BYPASS (HD)' + case 20: //'u': + return 'BYPASS (RGBHV)' + case 0: //'a': + return '240p' + default: + return 'NONE' + } +} -const readLocalFile = (file: File) => { - const reader = new FileReader(); - reader.addEventListener("load", (event) => { - doRestore(reader.result as ArrayBuffer); - }); - reader.readAsArrayBuffer(file); -}; +/** Promises */ +const serial = (funcs: (() => Promise)[]) => + funcs.reduce( + (promise, func) => + promise.then((result) => + func().then(Array.prototype.concat.bind(result)) + ), + Promise.resolve([]) + ) -/** backup / restore */ +/** helpers */ -const doBackup = () => { - let backupFiles: string[]; - let done = 0; - let total = 0; - fetch("/spiffs/dir") - .then((r) => r.json()) - .then((files: string[]) => { - backupFiles = files; - total = files.length; - const funcs = files.map((path: string) => () => { - return fetch(`/spiffs/download?file=${path}&${+new Date()}`).then( - (response) => { - GBSControl.ui.progressBackup.setAttribute( - "gbs-progress", - `${done}/${total}` - ); - done++; - return checkFetchResponseStatus(response) && response.arrayBuffer(); - } - ); - }); - - return serial(funcs); - }) - .then((files: ArrayBuffer[]) => { - const headerDescriptor = files.reduce((acc, f, index) => { - acc[backupFiles[index]] = f.byteLength; - return acc; - }, {}); - - const backupFilesJSON = JSON.stringify(headerDescriptor); - const backupFilesJSONSize = backupFilesJSON.length; - - const mainHeader = [ - (backupFilesJSONSize >> 24) & 255, // size - (backupFilesJSONSize >> 16) & 255, // size - (backupFilesJSONSize >> 8) & 255, // size - (backupFilesJSONSize >> 0) & 255, - ]; - - const outputArray: number[] = [ - ...mainHeader, - ...backupFilesJSON.split("").map((c) => c.charCodeAt(0)), - ...files.reduce((acc, f, index) => { - acc = acc.concat(Array.from(new Uint8Array(f))); - return acc; - }, []), - ]; - - downloadBlob( - new Blob([new Uint8Array(outputArray)]), - `gbs-control.backup-${+new Date()}.bin` - ); - GBSControl.ui.progressBackup.setAttribute("gbs-progress", ``); - }); -}; +const toggleHelp = () => { + let help = GBSStorage.read('help') || false -const doRestore = (file: ArrayBuffer) => { - const { backupInput } = GBSControl.ui; - const fileBuffer = new Uint8Array(file); - const headerCheck = fileBuffer.slice(4, 6); - - if (headerCheck[0] !== 0x7b || headerCheck[1] !== 0x22) { - backupInput.setAttribute("disabled", ""); - gbsAlert("Invalid Backup File") - .then( - () => { - backupInput.removeAttribute("disabled"); - }, - () => { - backupInput.removeAttribute("disabled"); - } - ) - .catch(() => { - backupInput.removeAttribute("disabled"); - }); - return; - } - const b0 = fileBuffer[0], - b1 = fileBuffer[1], - b2 = fileBuffer[2], - b3 = fileBuffer[3]; - const headerSize = (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - const headerString = Array.from(fileBuffer.slice(4, headerSize + 4)) - .map((c) => String.fromCharCode(c)) - .join(""); - - const headerObject = JSON.parse(headerString); - const files = Object.keys(headerObject); - let pos = headerSize + 4; - let total = files.length; - let done = 0; - const funcs = files.map((fileName) => () => { - const fileContents = fileBuffer.slice(pos, pos + headerObject[fileName]); - const formData = new FormData(); - formData.append( - "file", - new Blob([fileContents], { type: "application/octet-stream" }), - fileName.substr(1) - ); - - return fetch("/spiffs/upload", { - method: "POST", - body: formData, - }).then((response) => { - GBSControl.ui.progressRestore.setAttribute( - "gbs-progress", - `${done}/${total}` - ); - done++; - pos += headerObject[fileName]; - return response; - }); - }); - - serial(funcs).then(() => { - GBSControl.ui.progressRestore.setAttribute("gbs-progress", ``); - loadUser("a").then(() => { - gbsAlert( - "Restarting GBSControl.\nPlease wait until wifi reconnects then click OK" - ) - .then(() => { - window.location.reload(); - }) - .catch(() => {}); - }); - }); -}; + GBSStorage.write('help', !help) + updateHelp(!help) +} -const downloadBlob = (blob: Blob, name = "file.txt") => { - // Convert your blob into a Blob URL (a special url that points to an object in the browser's memory) - const blobUrl = URL.createObjectURL(blob); +/** + * Description placeholder + * + * @param {boolean} help + */ +const updateHelp = (help: boolean) => { + if (help) { + document.body.classList.remove('gbs-help-hide') + } else { + document.body.classList.add('gbs-help-hide') + } +} - // Create a link element - const link = document.createElement("a"); - // Set link's href to point to the Blob URL - link.href = blobUrl; - link.download = name; +/** + * A simple functionality that changes visual represetation of register data + * dependint on the operation + */ +const switchRegisterCmdOp = () => { + const dta = GBSControl.ui.registerCmdRegData.value + if(GBSControl.ui.registerCmdRegOp.value === '0') { + // write + GBSControl.ui.registerCmdRegData.value = dta.replaceAll('\u21E5', '\u2190') + } else { + // read + GBSControl.ui.registerCmdRegData.value = dta.replaceAll('\u2190', '\u21E5') + } +} - // Append link to the body - document.body.appendChild(link); +/** + * Prepare and submit register data + */ +const submitRegisterCmd = () => { + const formData = new FormData(); + GBSControl.ui.registerCmdRegSubmit.setAttribute('disabled', '') + formData.append('s', GBSControl.ui.registerCmdRegSection.value.trim()) + formData.append('o', GBSControl.ui.registerCmdRegOp.value.trim()) + const dataStringRaw = GBSControl.ui.registerCmdRegData.value.trim() + if(dataStringRaw.length <= 1) { + GBSControl.ui.registerCmdRegData.focus() + GBSControl.ui.registerCmdRegData.classList.add('gbs-focus-form-element') + GBSControl.ui.registerCmdRegSubmit.removeAttribute('disabled') + console.log('data cannot be empty') + return false + } + const dataRaw = dataStringRaw.split(' ') + var data = new Array() + dataRaw.map((val: string) => { + // there are different delimiters for read and write + const reg = val.split((GBSControl.ui.registerCmdRegOp.value === '0' ? '\u2190' : '\u21E5')) + // only pairs [address <- value | -> length] + if(reg[0] !== undefined && reg[1] !== undefined) { + const a = parseInt(reg[0], 16) + const v = parseInt(reg[1], 16) + data.push(a) + data.push(v) + } + }) + formData.append('d', data.join(',')) - // Dispatch click event on the link - // This is necessary as link.click() does not work on the latest firefox - link.dispatchEvent( - new MouseEvent("click", { - bubbles: true, - cancelable: true, - view: window, + fetch(`http://${GBSControl.serverIP}/data/cmd`, { + method: 'POST', + body: formData, + }).then((response) => { + console.log('data sent, response: ', response.statusText) + GBSControl.ui.registerCmdRegSubmit.removeAttribute('disabled') }) - ); +} - // Remove link from body - document.body.removeChild(link); -}; +/** + * Toggle console visibility (see corresponding button) + * + */ +const updateConsoleVisibility = () => { + // const developerMode = GBSStorage.read('developerMode') || false + if (GBSControl.developerMode) { + const consoleStatus = GBSStorage.read('consoleVisible') as boolean + if (consoleStatus != true) { + GBSStorage.write('consoleVisible', true) + GBSControl.ui.toggleConsole.removeAttribute('active') + document.body.classList.remove('gbs-output-hide') + } else { + GBSStorage.write('consoleVisible', false) + GBSControl.ui.toggleConsole.setAttribute('active', '') + document.body.classList.add('gbs-output-hide') + } + } +} -/** WIFI management */ -const wifiGetStatus = () => { - return fetch(`/wifi/status?${+new Date()}`) - .then((r) => r.json()) - .then((wifiStatus: { mode: string; ssid: string }) => { - GBSControl.wifi = wifiStatus; - if (GBSControl.wifi.mode === "ap") { - GBSControl.ui.wifiApButton.setAttribute("active", ""); - GBSControl.ui.wifiApButton.classList.add("gbs-button__secondary"); - GBSControl.ui.wifiStaButton.removeAttribute("active", ""); - GBSControl.ui.wifiStaButton.classList.remove("gbs-button__secondary"); - GBSControl.ui.wifiStaSSID.innerHTML = "STA | Scan Network"; - } else { - GBSControl.ui.wifiApButton.removeAttribute("active", ""); - GBSControl.ui.wifiApButton.classList.remove("gbs-button__secondary"); - GBSControl.ui.wifiStaButton.setAttribute("active", ""); - GBSControl.ui.wifiStaButton.classList.add("gbs-button__secondary"); - GBSControl.ui.wifiStaSSID.innerHTML = `${GBSControl.wifi.ssid}`; - } - }); +/** + * Toggle developer mode (see WS heartbeat) + */ +const toggleDeveloperMode = () => { + const el = document.querySelector('[gbs-section="developer"]') as HTMLElement + const consoleStatus = GBSStorage.read('consoleVisible') as boolean + if (GBSControl.developerMode) { + el.removeAttribute('hidden') + if(consoleStatus == true) { + document.body.classList.remove('gbs-output-hide') + } + GBSControl.ui.developerSwitch.setAttribute('active', '') + GBSControl.ui.developerSwitch.querySelector('.gbs-icon').innerText = "toggle_on" + } else { + if(GBSStorage.read('section') === 'developer') { + resetCurrentPageSection() + syncSectionTab() + } + el.setAttribute('hidden', '') + GBSStorage.write('consoleVisible', true) + document.body.classList.add('gbs-output-hide') + GBSControl.ui.developerSwitch.removeAttribute('active') + GBSControl.ui.developerSwitch.querySelector('.gbs-icon').innerText = "toggle_off" + window.clearInterval(GBSControl.wsHeartbeatInterval); + } }; -const wifiConnect = () => { - const ssid = GBSControl.ui.wifiSSDInput.value; - const password = GBSControl.ui.wifiPasswordInput.value; - - if (!password.length) { - GBSControl.ui.wifiPasswordInput.classList.add("gbs-wifi__input--error"); - return; - } - - const formData = new FormData(); - formData.append("n", ssid); - formData.append("p", password); - - fetch("/wifi/connect", { - method: "POST", - body: formData, - }).then(() => { - gbsAlert( - `GBSControl will restart and will connect to ${ssid}. Please wait some seconds then press OK` - ) - .then(() => { - window.location.href = "http://gbscontrol.local/"; - }) - .catch(() => {}); - }); -}; -const wifiScanSSID = () => { - GBSControl.ui.wifiStaButton.setAttribute("disabled", ""); - GBSControl.ui.wifiListTable.innerHTML = ""; - - if (!GBSControl.scanSSIDDone) { - fetch(`/wifi/list?${+new Date()}`).then(() => { - GBSControl.scanSSIDDone = true; - setTimeout(wifiScanSSID, 3000); - }); - return; - } - - fetch(`/wifi/list?${+new Date()}`) - .then((e) => e.text()) - .then((result) => { - GBSControl.scanSSIDDone = false; - return result.length - ? result - .split("\n") - .map((line) => line.split(",")) - .map(([strength, encripted, ssid]) => { - return { strength, encripted, ssid }; - }) - : []; - }) - .then((ssids) => { - return ssids.reduce((acc, ssid) => { - return `${acc} - wifi - ${ssid.ssid} - ${ssid.encripted ? "lock" : "lock_open"} - `; - }, ""); - }) - .then((html) => { - GBSControl.ui.wifiStaButton.removeAttribute("disabled"); - - if (html.length) { - GBSControl.ui.wifiListTable.innerHTML = html; - GBSControl.ui.wifiList.removeAttribute("hidden"); - GBSControl.ui.wifiConnect.setAttribute("hidden", ""); - } - }); -}; +/** + * Description placeholder + */ +const hideLoading = () => { + GBSControl.ui.loader.setAttribute('style', 'display:none') +} -const wifiSelectSSID = (event: Event) => { - (GBSControl.ui - .wifiSSDInput as HTMLInputElement).value = (event.target as HTMLElement).parentElement.getAttribute( - "gbs-ssid" - ); - GBSControl.ui.wifiPasswordInput.classList.remove("gbs-wifi__input--error"); - GBSControl.ui.wifiList.setAttribute("hidden", ""); - GBSControl.ui.wifiConnect.removeAttribute("hidden"); -}; +/** + * Description placeholder + * + * @param {Response} response + * @returns {Response} + */ +const checkFetchResponseStatus = (response: Response) => { + if (!response.ok) { + throw new Error(`HTTP ${response.status} - ${response.statusText}`) + } + return response +} -const wifiSetAPMode = () => { - if (GBSControl.wifi.mode === "ap") { - return; - } +/** backup / restore */ - const formData = new FormData(); - formData.append("n", "dummy"); +const doBackup = () => { + window.location.href = `http://${GBSControl.serverIP}/data/backup?ts=${new Date().getTime()}` +} - fetch("/wifi/connect", { - method: "POST", - body: formData, - }).then(() => { +/** + * Restore SLOTS from backup + * + * @param {ArrayBuffer} file + */ +// const doRestore = (file: ArrayBuffer, f: File) => { +const doRestore = (f: File) => { + const { backupInput } = GBSControl.ui + + const bkpTs = f.name.substring( + f.name.lastIndexOf('-') + 1, + f.name.lastIndexOf('.') + ) + const backupDate = new Date(parseInt(bkpTs)) + + backupInput.setAttribute('disabled', '') + const formData = new FormData() + formData.append('gbs-backup.bin', f, f.name) + const setAlertBody = () => { + const fsize = f.size / 1024 + return ( + 'L{RESTORE_JS_ALERT_MESSAGE}'.format(backupDate.toLocaleString(), fsize.toFixed(2)) + // '

Backup File:

Backup date: ' + + // backupDate.toLocaleString() + + // '

Size: ' + + // fsize.toFixed(2) + + // ' kB

' + ) + } gbsAlert( - "Switching to AP mode. Please connect to gbscontrol SSID and then click OK" + setAlertBody() as string, + '
close
L{ALERT_BUTTON_JS_REJECT}
', + '
done
L{ALERT_BUTTON_JS_RESTORE}
' ) - .then(() => { - window.location.href = "http://192.168.4.1"; - }) - .catch(() => {}); - }); -}; + .then( + () => { + backupInput.removeAttribute('disabled') + }, + () => { + return fetch(`http://${GBSControl.serverIP}/data/restore`, { + method: 'POST', + body: formData, + }).then((response) => { + // backupInput.removeAttribute("disabled"); + // start with 1st tab + resetCurrentPageSection() + window.setTimeout(() => { + window.location.reload() + }, 4000) + return response + }).catch(() => { + // do something + }) + } + ) + .catch(() => { + backupInput.removeAttribute('disabled') + }) +} /** button click management */ const controlClick = (control: HTMLButtonElement) => () => { - const controlKey = control.getAttribute("gbs-control-key"); - const target = GBSControl.controlKeysMobile[GBSControl.controlKeysMobileMode]; - - switch (target.type) { - case "loadDoc": - loadDoc(target[controlKey]); - break; - case "loadUser": - loadUser(target[controlKey]); - break; - } -}; + const controlKey = control.getAttribute('gbs-control-key') + const target = + GBSControl.controlKeysMobile[GBSControl.controlKeysMobileMode] + + switch (target.type) { + case 'loadDoc': + loadDoc(target[controlKey]) + break + case 'loadUser': + loadUser(target[controlKey]) + break + } +} +/** + * Description placeholder + * + * @param {HTMLButtonElement} control + * @returns {() => void} + */ const controlMouseDown = (control: HTMLButtonElement) => () => { - clearInterval(control["__interval"]); + clearInterval(control['__interval']) - const click = controlClick(control); - click(); - control["__interval"] = setInterval(click, 300); -}; + const click = controlClick(control) + click() + control['__interval'] = window.setInterval(click, 300) +} +/** + * Description placeholder + * + * @param {HTMLButtonElement} control + * @returns {() => void} + */ const controlMouseUp = (control: HTMLButtonElement) => () => { - clearInterval(control["__interval"]); -}; + clearInterval(control['__interval']) +} /** inits */ const initMenuButtons = () => { - const menuButtons = nodelistToArray( - document.querySelector(".gbs-menu").querySelectorAll("button") - ); - const sections = nodelistToArray( - document.querySelectorAll("section") - ); - const scroll = document.querySelector(".gbs-scroll"); - - menuButtons.forEach((button) => - button.addEventListener("click", () => { - const section = button.getAttribute("gbs-section"); - - sections.forEach((section) => section.setAttribute("hidden", "")); - document - .querySelector(`section[name="${section}"]`) - .removeAttribute("hidden"); - - menuButtons.forEach((btn) => btn.removeAttribute("active")); - button.setAttribute("active", ""); - scroll.scrollTo(0, 1); + const menuButtons = nodelistToArray( + document.querySelector('.gbs-menu').querySelectorAll('button') + ) + const sections = nodelistToArray( + document.querySelectorAll('section') + ) + const scroll = document.querySelector('.gbs-scroll') + + let currentPage = GBSStorage.read('section') || 'presets' + if(!GBSControl.developerMode && currentPage === 'developer') + currentPage = 'presets' + menuButtons.forEach((button) => { + const sectionName = button.getAttribute('gbs-section') + button.addEventListener('click', () => { + const section = sectionName; + GBSStorage.write('section', section) + sections.forEach((section) => section.setAttribute('hidden', '')) + document + .querySelector(`section[name="${section}"]`) + .removeAttribute('hidden') + + menuButtons.forEach((btn) => btn.removeAttribute('active')) + button.setAttribute('active', '') + scroll.scrollTo(0, 1) + }) + // get back to the last section after reload + if(currentPage === sectionName) + button.dispatchEvent(new Event("click")) }) - ); -}; +} +/** + * Description placeholder + */ const initGBSButtons = () => { - const actions = { - user: loadUser, - action: loadDoc, - setSlot, - }; - - const buttons = nodelistToArray( - document.querySelectorAll("[gbs-click]") - ); - - buttons.forEach((button) => { - const clickMode = button.getAttribute("gbs-click"); - const message = button.getAttribute("gbs-message"); - const messageType = button.getAttribute("gbs-message-type"); - const action = actions[messageType]; - - if (clickMode === "normal") { - button.addEventListener("click", () => { - action(message); - }); + const actions = { + user: loadUser, + action: loadDoc, + setSlot, } - if (clickMode === "repeat") { - const callback = () => { - action(message); - }; - - button.addEventListener( - !("ontouchstart" in window) ? "mousedown" : "touchstart", - () => { - callback(); - clearInterval(button["__interval"]); - button["__interval"] = setInterval(callback, 300); + const buttons = nodelistToArray( + document.querySelectorAll('[gbs-click]') + ) + + buttons.forEach((button) => { + const clickMode = button.getAttribute('gbs-click') + const message = button.getAttribute('gbs-message') + const messageType = button.getAttribute('gbs-message-type') + const action = actions[messageType] + + if (clickMode === 'normal') { + // custom events applied for some buttons + button.addEventListener('click', () => { + if(message == '1' && messageType == 'user') { + // reset to defaults (factory) button + gbsAlert( + 'L{RESET_FACTORY_BUTTON_JS_ALERT_MESSAGE}', + '
close
L{JS_NO}
', + '
done
L{ALERT_BUTTON_JS_ACK}
' + ) + .then( + () => { + // do nothing + }, + () => { + button.setAttribute('disabled', '') + action(message, button) + window.setTimeout(() => { + window.location.reload() + }, 5000) + } + ).catch(() => { + }) + } else if(message == '2' && messageType == 'user') { + // reset active slot + gbsAlert( + 'L{RESET_ACTIVE_SLOT_JS_ALERT_MESSAGE}', + '
close
L{JS_NO}
', + '
done
L{ALERT_BUTTON_JS_ACK}
' + ) + .then( + () => { + // do nothing + }, + () => { + button.setAttribute('disabled', '') + action(message, button) + window.setTimeout(() => { + window.location.reload() + }, 5000) + } + ).catch(() => { + }); + } else if(message == 'a' && messageType == 'user') { + // RESTART button + button.setAttribute('disabled', '') + action(message, button) + // restart device and reload page after countdown + let countdown = 10; + const buttonMessage = (val: string) => { + button.innerHTML = `
L{PAGE_RELOAD_IN}
${val} L{SECONDS_SHORT}
` + } + window.setInterval(() => { + buttonMessage(countdown.toString()) + countdown--; + if(countdown == 0) + window.location.reload() + }, 1000) + } else { + // all other buttons + action(message, button) + } + }); } - ); - button.addEventListener( - !("ontouchstart" in window) ? "mouseup" : "touchend", - () => { - clearInterval(button["__interval"]); + + if (clickMode === 'repeat') { + const callback = () => { + action(message) + } + + button.addEventListener( + !('ontouchstart' in window) ? 'mousedown' : 'touchstart', + () => { + callback() + clearInterval(button['__interval']) + button['__interval'] = window.setInterval(callback, 300) + } + ) + button.addEventListener( + !('ontouchstart' in window) ? 'mouseup' : 'touchend', + () => { + clearInterval(button['__interval']) + } + ) } - ); - } - }); -}; + }) +} +/** + * Description placeholder + */ const initClearButton = () => { - GBSControl.ui.outputClear.addEventListener("click", () => { - GBSControl.ui.terminal.value = ""; - }); -}; + GBSControl.ui.outputClear.addEventListener('click', () => { + GBSControl.ui.terminal.value = '' + }) +} +/** + * Description placeholder + */ const initControlMobileKeys = () => { - const controls = document.querySelectorAll("[gbs-control-target]"); - const controlsKeys = document.querySelectorAll("[gbs-control-key]"); - - controls.forEach((control) => { - control.addEventListener("click", () => { - GBSControl.controlKeysMobileMode = control.getAttribute( - "gbs-control-target" - ); - controls.forEach((crtl) => { - crtl.removeAttribute("active"); - }); - control.setAttribute("active", ""); - }); - }); - - controlsKeys.forEach((control) => { - control.addEventListener( - !("ontouchstart" in window) ? "mousedown" : "touchstart", - controlMouseDown(control as HTMLButtonElement) - ); - control.addEventListener( - !("ontouchstart" in window) ? "mouseup" : "touchend", - controlMouseUp(control as HTMLButtonElement) - ); - }); -}; + const controls = document.querySelectorAll('[gbs-control-target]') + const controlsKeys = document.querySelectorAll('[gbs-control-key]') + + controls.forEach((control) => { + control.addEventListener('click', () => { + GBSControl.controlKeysMobileMode = + control.getAttribute('gbs-control-target') + controls.forEach((crtl) => { + crtl.removeAttribute('active') + }) + control.setAttribute('active', '') + }) + }) + controlsKeys.forEach((control) => { + control.addEventListener( + !('ontouchstart' in window) ? 'mousedown' : 'touchstart', + controlMouseDown(control as HTMLButtonElement) + ) + control.addEventListener( + !('ontouchstart' in window) ? 'mouseup' : 'touchend', + controlMouseUp(control as HTMLButtonElement) + ) + }) +} + +/** + * Description placeholder + */ const initLegendHelpers = () => { - nodelistToArray( - document.querySelectorAll(".gbs-fieldset__legend--help") - ).forEach((e) => { - e.addEventListener("click", toggleHelp); - }); -}; + nodelistToArray( + document.querySelectorAll('.gbs-fieldset__legend--help') + ).forEach((e) => { + e.addEventListener('click', toggleHelp) + }) +} +/** + * Description placeholder + */ const initUnloadListener = () => { - window.addEventListener("unload", () => { - clearInterval(GBSControl.wsCheckTimer); - if (GBSControl.ws) { - if (GBSControl.ws.readyState == 0 || GBSControl.ws.readyState == 1) { - GBSControl.ws.close(); - } - } - }); -}; + window.addEventListener('unload', () => { + clearInterval(GBSControl.wsCheckTimer) + if (GBSControl.ws) { + if ( + GBSControl.ws.readyState == 0 || + GBSControl.ws.readyState == 1 + ) { + GBSControl.ws.close() + } + } + }) +} +/** + * Description placeholder + */ const initSlotButtons = () => { - GBSControl.ui.slotContainer.innerHTML = getSlotsHTML(); - GBSControl.ui.slotButtonList = nodelistToArray( - document.querySelectorAll('[gbs-role="slot"]') - ) as HTMLElement[]; -}; - -const initUIElements = () => { - GBSControl.ui = { - terminal: document.getElementById("outputTextArea"), - webSocketConnectionWarning: document.getElementById("websocketWarning"), - presetButtonList: nodelistToArray( - document.querySelectorAll("[gbs-role='preset']") - ) as HTMLElement[], - slotButtonList: nodelistToArray( - document.querySelectorAll('[gbs-role="slot"]') - ) as HTMLElement[], - toggleList: document.querySelectorAll("[gbs-toggle]"), - toggleSwichList: document.querySelectorAll("[gbs-toggle-switch]"), - wifiList: document.querySelector("[gbs-wifi-list]"), - wifiListTable: document.querySelector(".gbs-wifi__list"), - wifiConnect: document.querySelector(".gsb-wifi__connect"), - wifiConnectButton: document.querySelector("[gbs-wifi-connect-button]"), - wifiSSDInput: document.querySelector('[gbs-input="ssid"]'), - wifiPasswordInput: document.querySelector('[gbs-input="password"]'), - wifiApButton: document.querySelector("[gbs-wifi-ap]"), - wifiStaButton: document.querySelector("[gbs-wifi-station]"), - wifiStaSSID: document.querySelector("[gbs-wifi-station-ssid]"), - loader: document.querySelector(".gbs-loader"), - progressBackup: document.querySelector("[gbs-progress-backup]"), - progressRestore: document.querySelector("[gbs-progress-restore]"), - outputClear: document.querySelector("[gbs-output-clear]"), - slotContainer: document.querySelector("[gbs-slot-html]"), - backupButton: document.querySelector(".gbs-backup-button"), - backupInput: document.querySelector(".gbs-backup-input"), - developerSwitch: document.querySelector("[gbs-dev-switch]"), - customSlotFilters: document.querySelector("[gbs-slot-custom-filters]"), - alert: document.querySelector('section[name="alert"]'), - alertOk: document.querySelector("[gbs-alert-ok]"), - alertContent: document.querySelector("[gbs-alert-content]"), - prompt: document.querySelector('section[name="prompt"]'), - promptOk: document.querySelector("[gbs-prompt-ok]"), - promptCancel: document.querySelector("[gbs-prompt-cancel]"), - promptContent: document.querySelector("[gbs-prompt-content]"), - promptInput: document.querySelector('[gbs-input="prompt-input"]'), - }; -}; + GBSControl.ui.slotContainer.innerHTML = getSlotsHTML() + GBSControl.ui.slotButtonList = nodelistToArray( + document.querySelectorAll('[gbs-role="slot"]') + ) as HTMLElement[] +} +/** + * Description placeholder + */ const initGeneralListeners = () => { - window.addEventListener("resize", () => { - updateViewPort(); - }); - - GBSControl.ui.backupInput.addEventListener("change", (event) => { - const fileList: FileList = event.target["files"]; - readLocalFile(fileList[0]); - GBSControl.ui.backupInput.value = ""; - }); - - GBSControl.ui.backupButton.addEventListener("click", doBackup); - GBSControl.ui.wifiListTable.addEventListener("click", wifiSelectSSID); - GBSControl.ui.wifiConnectButton.addEventListener("click", wifiConnect); - GBSControl.ui.wifiApButton.addEventListener("click", wifiSetAPMode); - GBSControl.ui.wifiStaButton.addEventListener("click", wifiScanSSID); - GBSControl.ui.developerSwitch.addEventListener("click", toggleDeveloperMode); - GBSControl.ui.customSlotFilters.addEventListener( - "click", - toggleCustomSlotFilters - ); - - GBSControl.ui.alertOk.addEventListener("click", () => { - GBSControl.ui.alert.setAttribute("hidden", ""); - gbsAlertPromise.resolve(); - }); - - GBSControl.ui.promptOk.addEventListener("click", () => { - GBSControl.ui.prompt.setAttribute("hidden", ""); - const value = GBSControl.ui.promptInput.value; - if (value !== undefined || value.length > 0) { - gbsPromptPromise.resolve(GBSControl.ui.promptInput.value); - } else { - gbsPromptPromise.reject(); - } - }); + window.addEventListener('resize', () => { + updateViewPort() + }) - GBSControl.ui.promptCancel.addEventListener("click", () => { - GBSControl.ui.prompt.setAttribute("hidden", ""); - gbsPromptPromise.reject(); - }); + GBSControl.ui.backupInput.addEventListener('change', (event) => { + const fileList: FileList = event.target['files'] + doRestore(fileList[0]) + // readLocalFile(fileList[0]); + GBSControl.ui.backupInput.value = '' + }) - GBSControl.ui.promptInput.addEventListener("keydown", (event: any) => { - if (event.keyCode === 13) { - GBSControl.ui.prompt.setAttribute("hidden", ""); - const value = GBSControl.ui.promptInput.value; - if (value !== undefined || value.length > 0) { - gbsPromptPromise.resolve(GBSControl.ui.promptInput.value); - } else { - gbsPromptPromise.reject(); - } - } - if (event.keyCode === 27) { - gbsPromptPromise.reject(); - } - }); -}; + GBSControl.ui.backupButton.addEventListener('click', doBackup) + GBSControl.ui.wifiListTable.addEventListener('click', wifiSelectSSID) + GBSControl.ui.wifiConnectButton.addEventListener('click', wifiConnect) + GBSControl.ui.wifiApButton.addEventListener('click', wifiSetAPMode) + GBSControl.ui.wifiStaButton.addEventListener('click', wifiScanSSID) + // GBSControl.ui.developerSwitch.addEventListener('click', () => { + // const developerMode = GBSStorage.read('developerMode') || false + // GBSStorage.write('developerMode', !developerMode) + // updateConsoleVisibility() + // }) + GBSControl.ui.removeSlotButton.addEventListener('click', () => { + removePreset() + }) + GBSControl.ui.createSlotButton.addEventListener('click', () => { + savePreset() + }) -const initDeveloperMode = () => { - const devMode = GBSStorage.read("developerMode") as boolean; - if (devMode === undefined) { - GBSStorage.write("developerMode", false); - updateDeveloperMode(false); - } else { - updateDeveloperMode(devMode); - } -}; + GBSControl.ui.alertAck.addEventListener('click', () => { + GBSControl.ui.alert.setAttribute('hidden', '') + gbsAlertPromise.resolve() + }) -const initHelp = () => { - let help = GBSStorage.read("help") as boolean; - if (help === undefined) { - help = false; - GBSStorage.write("help", help); - } - updateHelp(help); -}; + GBSControl.ui.promptOk.addEventListener('click', () => { + GBSControl.ui.prompt.setAttribute('hidden', '') + const value = GBSControl.ui.promptInput.value + if (value !== undefined || value.length > 0) { + gbsPromptPromise.resolve(GBSControl.ui.promptInput.value) + } else { + gbsPromptPromise.reject() + } + }) -const gbsAlertPromise = { - resolve: null, - reject: null, -}; + GBSControl.ui.promptCancel.addEventListener('click', () => { + GBSControl.ui.prompt.setAttribute('hidden', '') + gbsPromptPromise.reject() + }) -const alertKeyListener = (event: any) => { - if (event.keyCode === 13) { - gbsAlertPromise.resolve(); - } - if (event.keyCode === 27) { - gbsAlertPromise.reject(); - } -}; + GBSControl.ui.promptInput.addEventListener('keydown', (event: any) => { + if (event.keyCode === 13) { + GBSControl.ui.prompt.setAttribute('hidden', '') + const value = GBSControl.ui.promptInput.value + if (value !== undefined || value.length > 0) { + gbsPromptPromise.resolve(GBSControl.ui.promptInput.value) + } else { + gbsPromptPromise.reject() + } + } + if (event.keyCode === 27) { + gbsPromptPromise.reject() + } + }) -const gbsAlert = (text: string) => { - GBSControl.ui.alertContent.textContent = text; - GBSControl.ui.alert.removeAttribute("hidden"); - document.addEventListener("keyup", alertKeyListener); - return new Promise((resolve, reject) => { - gbsAlertPromise.resolve = (e) => { - document.removeEventListener("keyup", alertKeyListener); - GBSControl.ui.alert.setAttribute("hidden", ""); - return resolve(e); - }; - gbsAlertPromise.reject = () => { - document.removeEventListener("keyup", alertKeyListener); - GBSControl.ui.alert.setAttribute("hidden", ""); - return reject(); - }; - }); -}; + // register cmd data filtering function + GBSControl.ui.registerCmdRegData.addEventListener('keydown', (e: KeyboardEvent) => { + const cc = e.key.charCodeAt(0) + const target = e.target as HTMLTextAreaElement; + if(cc != 0x42) { + // not the backspace key + if((cc > 57 && cc < 97) || cc < 48 || cc > 102) { // && cc != 0x20) { + e.preventDefault() + return false + } + GBSControl.ui.registerCmdRegData.classList.remove('gbs-focus-form-element') + const dtaLen = target.value.length + if(dtaLen % 6 == 0) { + target.value = `${target.value} ` + } else if(dtaLen % 3 == 0) { + target.value = (GBSControl.ui.registerCmdRegOp.value === '0' ? `${target.value}\u2190` : `${target.value}\u21E5`) + } + } else { + // backspace + e.preventDefault(); + const lastChar = target.value.charAt(target.value.length-1) + target.value = target.value.substring(0, target.value.length - ((lastChar == ' ' || lastChar == '\u2190' || lastChar == '\u21E5') ? 3 : 1)) + } + }) -const gbsPromptPromise = { - resolve: null, - reject: null, -}; + // register cmd switch operation + GBSControl.ui.registerCmdRegOp.addEventListener('change', () => { + switchRegisterCmdOp() + }) -const gbsPrompt = (text: string, defaultValue = "") => { - GBSControl.ui.promptContent.textContent = text; - GBSControl.ui.prompt.removeAttribute("hidden"); - GBSControl.ui.promptInput.value = defaultValue; + // register cmd submit button in developer tab + GBSControl.ui.registerCmdRegSubmit.addEventListener('click', () => { + submitRegisterCmd() + }) - return new Promise((resolve, reject) => { - gbsPromptPromise.resolve = resolve; - gbsPromptPromise.reject = reject; - GBSControl.ui.promptInput.focus(); - }); -}; + // toggle console visibility button + GBSControl.ui.toggleConsole.addEventListener('click', () => { + updateConsoleVisibility() + }) +} + +/** + * Description placeholder + */ +const initHelp = () => { + let help = GBSStorage.read('help') as boolean + if (help === undefined) { + help = false + GBSStorage.write('help', help) + } + updateHelp(help) +} +/** + * Description placeholder + */ const initUI = () => { - updateCustomSlotFilters(); - initGeneralListeners(); - updateViewPort(); - initSlotButtons(); - initLegendHelpers(); - initMenuButtons(); - initGBSButtons(); - initClearButton(); - initControlMobileKeys(); - initUnloadListener(); - initDeveloperMode(); - initHelp(); -}; + // updateCustomSlotFilters(); + initGeneralListeners() + updateViewPort() + initSlotButtons() + initLegendHelpers() + initMenuButtons() + initGBSButtons() + initClearButton() + initControlMobileKeys() + initUnloadListener() + initHelp() +} +/** + * Description placeholder + */ const main = () => { - const ip = location.hostname; - GBSControl.serverIP = ip; - GBSControl.webSocketServerUrl = `ws://${ip}:81/`; - document - .querySelector(".gbs-loader img") - .setAttribute( - "src", - document.head - .querySelector('[rel="apple-touch-icon"]') - .getAttribute("href") - ); - fetchSlotNamesAndInit(); -}; + GBSControl.serverIP = location.hostname + GBSControl.webSocketServerUrl = `ws://${GBSControl.serverIP}:81/` + document + .querySelector('.gbs-loader img') + .setAttribute( + 'src', + document.head + .querySelector('[rel="apple-touch-icon"]') + .getAttribute('href') + ) + fetchSlotNamesAndInit() +} -main(); +main() \ No newline at end of file diff --git a/public/src/style.css b/public/src/style.css index 2816854f..704663d7 100644 --- a/public/src/style.css +++ b/public/src/style.css @@ -1,22 +1,30 @@ +/* + * DEVELOPER MEMO: + * 1. WebUI icons: https://jossef.github.io/material-design-icons-iconfont + * 2. prettier config: https://prettier.io/docs/en/options + * + */ + /** variables */ :root { - --color-black: black; - --color-cod-gray-light: #181818; - --color-cod-gray: #101010; - --color-mine-shaft-light: #303030; - --color-mine-shaft: #202020; - --color-primary-rgba: 0, 192, 251; - --color-primary: #00c0fb; - --color-scorpion: #808080; - --color-secondary-rgba: 234, 182, 56; - --color-secondary: #eab638; - --color-silver-chalice: #aaa; - --color-warning: red; - --color-white: white; - --viewport-height: 100%; - - /*GBC - --color-black: black; + --color-black: black; + --color-cod-gray-light: #181818; + --color-cod-gray: #101010; + --color-mine-shaft-light: #303030; + --color-mine-shaft: #202020; + --color-primary-rgba: 0, 192, 251; + --color-primary: #00c0fb; + --color-scorpion: #808080; + --color-secondary-rgba: 234, 182, 56; + --color-secondary: #eab638; + --color-silver-chalice: #aaa; + --color-warning: #ff0000; + --color-warning-rgba: 255, 0, 0; + --color-white: 255,255,255; + --viewport-height: 100%; + + /*GBC + --color-black: black; --color-cod-gray-light: #181818; --color-cod-gray: #101010; --color-mine-shaft-light: #0f380f; @@ -34,646 +42,826 @@ /* latin */ @font-face { - font-family: "Oswald"; - font-style: normal; - font-weight: 300; - font-display: swap; - src: url(data:font/woff2;base64,${oswald}) format("woff2"); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, - U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, - U+FEFF, U+FFFD; + font-family: "${webUIFontName}"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('data:font/woff2;base64,${webUIFont}') format("woff2"); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* fallback */ +/* + See: https://github.com/jossef/material-design-icons-iconfont/ + Ex: https://jossef.github.io/material-design-icons-iconfont/ +*/ @font-face { - font-family: "Material Icons"; - font-style: normal; - font-weight: 400; - src: url(data:font/woff2;base64,${material}) format("woff2"); + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + font-display: block; + src: local('Material Icons'), local('MaterialIcons-Regular'), url('data:font/woff2;base64,${material}') format("woff2"); } html, body { - height: 100%; - touch-action: manipulation; - width: 100%; + height: 100%; + touch-action: manipulation; + width: 100%; + margin: 0; + padding: 0; + z-index: 0; } body { - background-color: var(--color-cod-gray); - font-family: "Oswald", sans-serif; - height: 100%; - margin: 0; - overflow: hidden; - padding: 0; - width: 100%; + background-color: var(--color-cod-gray); + font-family: "${webUIFontName}", sans-serif; + overflow: hidden; } * { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +textarea[gbs-register-data=""], select { + appearance: none; + background-color: var(--color-mine-shaft-light); + border-radius: 5px; + /* border: 1px dashed rgba(var(--color-primary-rgba), 0.2); */ + border: 1px solid rgba(var(--color-primary-rgba), .2); + color: rgb(var(--color-white)); + flex-grow: 1; + font-family: inherit; + font-size: 14px; + font-weight: 300; + outline: 0; + width: 100%; +} + +select { + padding: 2px 5px; + cursor: pointer; +} + +textarea[gbs-register-data=""] { + padding: 6px; + height: 150px; + text-transform:uppercase; + resize:vertical; +} + +.gbs-text-center { + text-align: center; } /** main container */ .gbs-container { - background-color: var(--color-mine-shaft); - display: inline-block; - height: 100%; - margin-left: auto; - margin-right: auto; - max-width: 414px; - overflow: hidden; - position: relative; - width: 100%; + background-color: var(--color-mine-shaft); + display: inline-block; + height: 100%; + margin-left: auto; + margin-right: auto; + max-width: 414px; + overflow: hidden; + position: relative; + width: 100%; } /** main screen scrollable area */ .gbs-scroll { - height: calc(100% - 54px); - margin-bottom: 148px; - overflow-x: hidden; - overflow-y: auto; + height: calc(100% - 75px); + /* margin-bottom: 148px; */ + overflow-x: hidden; + overflow-y: auto; } .gbs-scroll::-webkit-scrollbar { - width: 2px; + width: 2px; } .gbs-scroll::-webkit-scrollbar-track { - background: transparent; + background: transparent; } .gbs-scroll::-webkit-scrollbar-thumb { - background-color: var(--color-primary); - border-radius: 20px; + background-color: var(--color-primary); + border-radius: 20px; +} + +.gbs-scroll__footer { + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + display: flex; + margin: 0px; + background-color: var(--color-cod-gray-light); + color: rgba(var(--color-secondary-rgba), 0.7); + border-radius: 0 0 16px 16px; +} + +.gbs-scroll__footer div:first-child { + text-align: left; + padding: 5px 0 8px 35px; + position: relative; +} + +.gbs-scroll__footer div:first-child svg { + position: absolute; + margin: 2px 0 0 -20px; +} + +.gbs-scroll__footer div:last-child { + text-align: right; + padding: 5px 15px 8px; +} + +.gbs-scroll__footer > div { + /* box-shadow: 0 0px 30px -10px rgba(var(--color-primary-rgba), .9); */ + width: 50%; + font-size: 10px; + font-weight: bold; + line-height: normal; +} + +/* menu */ +.gbs-menu { + background-color: var(--color-cod-gray-light); + /* box-shadow: 0 0px 30px -10px rgba(var(--color-primary-rgba), .9); */ + border-top: 1px solid rgba(var(--color-primary-rgba), .4); + bottom: 0; + box-sizing: border-box; + color: var(--color-primary); + display: flex; + height: 75px; + padding: 8px 5px 15px; + position: absolute; + text-align: center; + width: 100%; + z-index: 10; +} + +.gbs-menu__logo { + display: none; + margin: auto; + margin-right: 8px; + width: 20%; +} + +.gbs-menu__button-group { + border: 1px dashed rgba(var(--color-primary-rgba), .65); + /* padding: 2px; */ + width: 60%; + display:flex; + border-radius: 8px; + margin-right: 2px; +} + +.gbs-button__uwidth { + width: 15% !important; +} + +a { + color: rgba(var(--color-secondary-rgba), 0.7); + text-decoration: none; + cursor: pointer; +} + +a:hover { + text-decoration: underline; } /* buttons */ .gbs-button { - appearance: none; - background-color: var(--color-mine-shaft-light); - border-radius: 4px; - border: 1px dashed rgba(var(--color-primary-rgba), 0.2); - color: rgba(var(--color-primary-rgba), 0.6); - cursor: pointer; - flex-grow: 1; - font-family: inherit; - font-size: 14px; - font-weight: 300; - margin: 2px; - outline: 0; - overflow: hidden; - padding: 4px 8px; - position: relative; - text-align: right; - text-overflow: ellipsis; - transition: all 0.2s linear; - user-select: none; - white-space: nowrap; + appearance: none; + background-color: var(--color-mine-shaft-light); + border-radius: 4px; + /* border: 1px dashed rgba(var(--color-primary-rgba), 0.2); */ + border: 1px solid rgba(var(--color-primary-rgba), .2); + color: rgba(var(--color-primary-rgba), 0.6); + cursor: pointer; + flex-grow: 1; + font-family: inherit; + font-size: 14px; + font-weight: 300; + margin: 2px; + outline: 0; + overflow: hidden; + padding: 4px 8px; + position: relative; + text-align: right; + text-overflow: ellipsis; + transition: all 0.2s linear; + user-select: none; + white-space: nowrap; } .gbs-button[disabled] { - opacity: 0.3; - pointer-events: none; + opacity: 0.3; + pointer-events: none; } .gbs-button[active] { - border: 1px solid var(--color-primary); - box-shadow: inset 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2), - 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2); - color: var(--color-primary); + border: 1px solid var(--color-primary); + box-shadow: inset 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2), + 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2); + color: var(--color-primary); } .gbs-button__secondary { - border: 1px dashed rgba(var(--color-secondary-rgba), 0.3); - color: rgba(var(--color-secondary-rgba), 0.7); + border: 1px dashed rgba(var(--color-secondary-rgba), 0.3); + color: rgba(var(--color-secondary-rgba), 0.7); } .gbs-button__secondary[active] { - background-color: rgba(var(--color-secondary-rgba), 0.7); - border: 1px solid rgba(var(--color-secondary-rgba), 0.3); - box-shadow: inset 0 0 6px 4px rgba(var(--color-secondary-rgba), 0.2), - 0 0 6px 8px rgba(var(--color-secondary-rgba), 0.2); - color: var(--color-black); - transform: scale(0.98); + background-color: rgba(var(--color-secondary-rgba), 0.7); + border: 1px solid rgba(var(--color-secondary-rgba), 0.3); + box-shadow: inset 0 0 6px 4px rgba(var(--color-secondary-rgba), 0.2), + 0 0 6px 8px rgba(var(--color-secondary-rgba), 0.2); + color: var(--color-black); + transform: scale(0.98); } .gbs-button__menu { - margin: 2px; - width: 100%; - text-align: center; + margin: 2px; + width: 100%; + text-align: center; } .gbs-button__preset { - flex-grow: 1; - font-size: 12px; - height: 44px; - line-height: 12px; - margin: 1px; - padding: 4px; - text-align: right; - vertical-align: top; - white-space: initial; + flex-grow: 1; + font-size: 12px; + height: 44px; + line-height: 12px; + margin: 1px; + padding: 4px; + text-align: right; + vertical-align: top; + white-space: initial; } .gbs-button__slot { - flex-grow: 1; - line-height: 16px; - margin: 4px; - min-height: 56px; - padding: 8px; - text-align: right; - width: 132px; + flex-grow: 1; + line-height: 16px; + margin: 4px; + min-height: 56px; + padding: 8px; + text-align: right; + width: 132px; } .gbs-button__slot::before { - color: var(--color-secondary); - content: attr(gbs-name); - font-size: 16px; - white-space: normal; + color: var(--color-secondary); + content: attr(gbs-name); + font-size: 16px; + white-space: normal; } .gbs-button__slot::after { - color: var(--color-primary); - content: attr(gbs-meta); - display: block; - font-size: 10px; - line-height: 14px; - white-space: pre; + color: var(--color-primary); + content: attr(gbs-meta); + display: block; + font-size: 10px; + line-height: 14px; + white-space: pre; } .gbs-button__resolution { - flex-grow: 1; - font-size: 14px; - height: 52px; - line-height: 14px; - margin: 1px; - min-width: 40px; - padding: 4px; - text-align: right; - vertical-align: top; - white-space: initial; + flex-grow: 1; + font-size: 13px; + height: 52px; + line-height: 14px; + margin: 1px; + min-width: 40px; + padding: 4px; + text-align: center; + vertical-align: top; + white-space: initial; } .gbs-button__resolution--center { - text-align: center; + text-align: center; } -.gbs-button__resolution--pass-through { - font-size: 10px; - line-height: 10px; - position: relative; - top: -4px; -} +/* .gbs-button__resolution--pass-through { + font-size: 12px; + line-height: 12px; + position: relative; + top: -4px; +} */ .gbs-button__control { - flex-grow: 1; - height: 68px; - margin: 2px; - padding: 6px; - text-align: right; - vertical-align: top; - white-space: initial; - width: 84px; + flex-grow: 1; + height: 68px; + margin: 2px; + padding: 6px; + text-align: right; + vertical-align: top; + white-space: initial; + width: 84px; } .gbs-button__control-action { - flex-grow: 1; - height: 56px; - line-height: 1; - margin: 4px; - text-align: right; + flex-grow: 1; + height: 56px; + line-height: 1; + margin: 4px; + text-align: right; } -/* menu */ -.gbs-menu { - background-color: var(--color-cod-gray-light); - border-top: 1px solid #282828; - bottom: 0; - box-sizing: border-box; - color: var(--color-primary); - display: flex; - height: 54px; - padding: 8px; - position: absolute; - text-align: center; - width: 100%; -} - -.gbs-menu__logo { - display: none; - margin: auto; - margin-right: 8px; - width: 200%; +.gbs-button__reg-cmd-submit { + position: absolute; + bottom: 5px; + right: 5px; + font-size: 12px; } /* fieldset */ .gbs-fieldset { - border-radius: 4px; - border: 1px solid rgba(var(--color-primary-rgba), 0.1); - box-sizing: border-box; - color: var(--color-primary); - font-size: 15px; - margin: 8px; - padding: 8px; - position: relative; + border-radius: 4px; + border: 1px solid rgba(var(--color-primary-rgba), 0.1); + box-sizing: border-box; + color: var(--color-primary); + font-size: 15px; + margin: 8px; + padding: 8px; + position: relative; } .gbs-fieldset__legend { - display: inline-block !important; - font-size: 16px; - position: relative; - text-align: left; - vertical-align: top; + display: inline-block !important; + font-size: 16px; + position: relative; + text-align: left; + vertical-align: top; } .gbs-fieldset__legend--help::after { - color: var(--color-secondary); - content: "help_center"; - cursor: pointer; - font-family: "Material Icons"; - font-size: 24px; - position: relative; - top: 8px; + color: var(--color-secondary); + content: "help_center"; + cursor: pointer; + font-family: "Material Icons"; + font-size: 24px; + position: relative; + top: 8px; } .gbs-show-help .gbs-fieldset__legend::after { - color: var(--color-scorpion); + color: var(--color-scorpion); } .gbs-fieldset__legend div { - display: inline-block; - vertical-align: middle; + display: inline-block; + vertical-align: middle; } /** table */ .gbs-preferences { - width: 100%; + width: 100%; +} + +.gbs-preferences tr > td:first-child { + width: 90%; + text-align: left; +} + +.gbs-preferences tr > td:last-child:hover { + color: rgba(var(--color-secondary-rgba), 0.7); + -webkit-transition: all 0.3s linear; + -moz-transition: all 0.3s linear; + -ms-transition: all 0.3s linear; + -o-transition: all 0.3s linear; + transition: all 0.3s linear; } .gbs-preferences td { - color: var(--color-silver-chalice); - text-align: left; + color: var(--color-silver-chalice); + text-align: left; } .gbs-preferences td[toggle-switch], .gbs-preferences td.gbs-icon { - cursor: pointer; + cursor: pointer; } .gbs-preferences tr[active] td { - color: var(--color-primary); + color: var(--color-primary); } .gbs-preferences tr td.gbs-preferences__child { - color: var(--color-secondary); + color: var(--color-secondary); } .gbs-preferences tr[active] td.gbs-preferences__child { - color: var(--color-secondary); + color: var(--color-secondary); } .gbs-preferences td em { - color: var(--color-silver-chalice); - display: block; - display: none; - font-size: 12px; - font-style: normal; - line-height: 16px; - margin-bottom: 16px; - margin-top: 4px; + color: var(--color-silver-chalice); + display: block; + display: none; + font-size: 12px; + font-style: normal; + line-height: 16px; + margin-bottom: 16px; + margin-top: 4px; } .gbs-preferences .gbs-icon { - font-size: 32px; + font-size: 32px; } /* sections */ .gbs-scroll { - /* self */ - display: flex; - flex-direction: column; + /* self */ + display: flex; + flex-direction: column; } -.gbs-scroll > section[name="presets"] { - flex-grow: 1; - /* self */ - display: flex; - flex-direction: column; - padding: 8px; - gap: 8px; -} -.gbs-scroll > section[name="presets"] > fieldset { - margin: 0; + +.gbs-scroll>section[name="presets"] { + flex-grow: 1; + /* self */ + display: flex; + flex-direction: column; + padding: 8px; + gap: 8px; } -.gbs-resolution { - display: flex; +.gbs-scroll>section[name="presets"]>fieldset { + margin: 0; } -.gbs-scroll > section[name="presets"] > fieldset.presets { - flex-grow: 1; - /* self */ +/* .gbs-resolution { display: flex; - flex-direction: column; +} */ + +.gbs-scroll>section[name="presets"]>fieldset.presets { + flex-grow: 1; + /* self */ + display: flex; + flex-direction: column; } -.gbs-scroll > section[name="presets"] > fieldset.presets > .gbs-presets { - flex-grow: 1; - /* self */ - border-radius: 8px; - display: flex; - flex-wrap: wrap; - justify-content: space-around; - margin-bottom: 16px; - overflow-y: scroll; - overflow: hidden; + +.gbs-scroll>section[name="presets"]>fieldset.presets>.gbs-presets { + flex-grow: 1; + /* self */ + border-radius: 8px; + display: flex; + flex-wrap: wrap; + justify-content: space-around; + margin-bottom: 16px; + overflow-y: scroll; + overflow: hidden; } .gbs-controls__desktop { - display: none; + display: none; } .gbs-output-hide .gbs-output { - display: none; + display: none; } .gbs-output { - position: relative; + position: relative; } .gbs-output__textarea { - appearance: none; - background-color: var(--color-black); - border-radius: 8px; - border: none; - box-sizing: border-box; - color: var(--color-white); - flex-grow: 1; - height: 400px; - outline: 0; - padding: 16px; - resize: none; - scrollbar-color: var(--color-primary) var(--color-black); - scrollbar-width: thin; + appearance: none; + background-color: var(--color-black); + border-radius: 8px; + border: none; + box-sizing: border-box; + color: var(--color-white); + flex-grow: 1; + height: 400px; + outline: 0; + padding: 5px 10px; + resize: none; + scrollbar-color: var(--color-primary) var(--color-black); + scrollbar-width: thin; } .gbs-output__textarea::-webkit-scrollbar { - border-radius: 20px; - width: 20px; + border-radius: 20px; + width: 20px; } .gbs-output__textarea::-webkit-scrollbar-track { - background-color: var(--color-black); - border-radius: 20px; + background-color: var(--color-black); + border-radius: 20px; } .gbs-output__textarea::-webkit-scrollbar-thumb { - background-color: var(--color-primary); - border-radius: 20px; - border: 7px solid var(--color-black); + background-color: var(--color-primary); + border-radius: 20px; + border: 7px solid var(--color-black); } .gbs-loader { - align-items: center; - background-color: var(--color-mine-shaft); - display: flex; - height: 100%; - justify-content: center; - left: 0; - position: fixed; - top: 0; - width: 100%; + align-items: center; + background-color: var(--color-mine-shaft); + display: flex; + height: 100%; + justify-content: center; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index:20; } .gbs-loader img { - border-radius: 16px; - box-shadow: 0 0 64px 4px var(--color-primary); - width: 160px; + border-radius: 16px; + box-shadow: 0 0 64px 4px var(--color-primary); + width: 160px; } .gbs-loader, body { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='152' height='152'%3E%3Cpath fill='%2300c0fb' fill-opacity='0.4' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E"); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='152' height='152'%3E%3Cpath fill='%2300c0fb' fill-opacity='0.4' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E"); } .gbs-wifi__list { - text-align: left; + text-align: left; } .gbs-wifi__list tr { - height: 38px; - line-height: 38px; + height: 38px; + line-height: 38px; } .gbs-wifi__list td { - line-height: 18px; - vertical-align: top; + line-height: 18px; + vertical-align: top; } -.gbs-wifi__list .gbs-icon ~ td { - width: 100%; +.gbs-wifi__list .gbs-icon~td { + width: 100%; } -.gbs-wifi__list td ~ td ~ td { - color: var(--color-secondary); +.gbs-wifi__list td~td~td { + color: var(--color-secondary); } .gbs-wifi__input { - flex-grow: 1; - height: 38px; + flex-grow: 1; + height: 38px; } .gbs-wifi__input--error { - animation: gbs-border-blinker 0.5s linear infinite; + animation: gbs-border-blinker 0.5s linear infinite; } input { - -webkit-user-select: initial !important; - user-select: initial !important; + -webkit-user-select: initial !important; + user-select: initial !important; } .gbs-wifi-warning { - animation: gbs-blinker 0.5s linear infinite; - color: var(--color-warning); - position: absolute; - right: 18px; - top: 10px; - z-index: 1; + animation: gbs-blinker 0.5s linear infinite; + color: var(--color-warning); + position: absolute; + right: 18px; + top: 10px; + z-index: 1; } /* modals */ section[name="prompt"], section[name="alert"] { - background-color: rgba(0, 0, 0, 0.96); - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; + background-color: rgba(0, 0, 0, 0.96); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index:15; } .gbs-modal__message { - text-align: right; - margin-top: 16px; - margin-bottom: 32px; + margin-top: 16px; + margin-bottom: 32px; + text-align: left; } /* HELPERS */ [hidden] { - display: none !important; + display: none !important; } [gbs-progress]::before { - content: attr(gbs-progress); + content: attr(gbs-progress); } .gbs-backup-input { - cursor: pointer; - height: 100%; - left: 0; - opacity: 0; - position: absolute; - top: 0; - width: 100%; + cursor: pointer; + height: 100%; + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; } -.gbs-button[gbs-name="Empty"] ~ .gbs-button[gbs-name="Empty"] { - display: none; +.gbs-button[gbs-name="Empty"]~.gbs-button[gbs-name="Empty"] { + display: none; } .gbs-help { - color: var(--color-scorpion); - display: flex; - flex-direction: column; - font-size: 14px; - line-height: 18px; - margin: 8px 0 16px 0; - padding-left: 28px; - text-align: left; - white-space: pre-line; + color: var(--color-scorpion); + display: flex; + flex-direction: column; + font-size: 14px; + line-height: 18px; + margin: 8px 0 16px 0; + padding-left: 28px; + text-align: left; + white-space: pre-line; } .gbs-help-hide .gbs-help { - display: none; + display: none; } .gbs-icon { - -webkit-font-feature-settings: "liga"; - -webkit-font-smoothing: antialiased; - direction: ltr; - display: inline-block; - font-family: "Material Icons"; - font-size: 24px; - font-style: normal; - font-weight: normal; - letter-spacing: normal; - line-height: 1; - text-transform: none; - white-space: nowrap; - word-wrap: normal; + -webkit-font-feature-settings: "liga"; + -webkit-font-smoothing: antialiased; + direction: ltr; + display: inline-block; + font-family: "Material Icons"; + font-size: 24px; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-height: 1; + text-transform: none; + white-space: nowrap; + word-wrap: normal; + text-rendering: optimizeLegibility; + position: relative; } -.gbs-flex { - display: flex; +.gbs-icon:before { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: .3; } -.gbs-margin__bottom--16 { - margin-bottom: 16px; +.gbs-icon:after { + opacity: 1; } -.gbs-padding__left-16 { - padding-left: 16px; +.gbs-flex { + display: flex; } -.gbs-padding__hor-16 { - padding-left: 16px; - padding-right: 16px; +.gbs-margin__bottom--8 { + margin-bottom: 8px; } -@media (min-width: 415px) { - .gbs-button:hover { - border: 1px solid var(--color-primary); - box-shadow: inset 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2), - 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2); - color: var(--color-primary); - } - - .gbs-button__secondary:hover { - background-color: rgba(var(--color-secondary-rgba), 0.7); - border: 1px solid rgba(var(--color-secondary-rgba), 0.3); - box-shadow: inset 0 0 6px 4px rgba(var(--color-secondary-rgba), 0.2), - 0 0 6px 8px rgba(var(--color-secondary-rgba), 0.2); - color: var(--color-black); - transform: scale(0.98); - } +.gbs-margin__left--8 { + margin-left: 8px; +} - .gbs-button__control { - height: 60px; - } +.gbs-margin__bottom--16 { + margin-bottom: 16px; +} - .gbs-menu { - border-bottom: 1px solid rgba(var(--color-primary-rgba), 0.4); - bottom: initial; - padding-left: 8px; - padding-right: 8px; - position: relative; - top: 0; - } +.gbs-padding__bottom-8 { + padding-bottom: 8px; +} - .gbs-menu__logo { - display: inline-block; - } +.gbs-padding__left-16 { + padding-left: 16px; +} - .gbs-controls { - display: none; - } +.gbs-padding__hor-16 { + padding-left: 16px; + padding-right: 16px; +} - .gbs-controls__desktop { - display: block; - } +.gbs-input-group { + width: 100%; + margin-top: 15px; + position: relative; +} - .gbs-output { - background-color: var(--color-mine-shaft-light); - height: 100vh; - left: 414px; - position: fixed; - top: 0px; - width: calc(100vw - 414px); - z-index: 1; - } +.gbs-input-group legend { + position: absolute; + top: -18px; + left: 0px; + font-size: 10px; +} - .gbs-output__textarea { - height: calc(100vh - 114px); - } +.gbs-focus-form-element { + border: 1px solid rgba(var(--color-warning-rgba), .9)!important; + box-shadow: inset 0 0 6px 4px rgba(var(--color-warning-rgba), 0.2), 0 0 6px 4px rgba(var(--color-warning-rgba), 0.2)!important; +} - .gbs-output-hide .gbs-container { - border-radius: 16px; - box-shadow: 0 0 64px 4px rgba(var(--color-primary-rgba), 0.4); - display: block; - height: calc(100vh - 64px); - margin-top: 32px; - } +@media (max-width: 414px) { + .gbs-scroll__footer { + display: none; + } +} - .gbs-fieldset-output { - height: calc(100vh - 16px); - } +@media (min-width: 415px) { + .gbs-button:hover { + border: 1px solid var(--color-primary); + box-shadow: inset 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2), + 0 0 6px 4px rgba(var(--color-primary-rgba), 0.2); + color: var(--color-primary); + } + + .gbs-button__secondary:hover { + background-color: rgba(var(--color-secondary-rgba), 0.7); + border: 1px solid rgba(var(--color-secondary-rgba), 0.3); + box-shadow: inset 0 0 6px 4px rgba(var(--color-secondary-rgba), 0.2), + 0 0 6px 8px rgba(var(--color-secondary-rgba), 0.2); + color: var(--color-black); + transform: scale(0.98); + } + + .gbs-button__control { + height: 60px; + } + + .gbs-scroll { + height: calc(100% - 85px); + } + + .gbs-menu { + border-bottom: 1px solid rgba(var(--color-primary-rgba), .4); + box-shadow: none; + bottom: initial; + padding: 8px; + position: relative; + top: 0; + height: 55px; + border-radius: 16px 16px 0 0; + } + + .gbs-menu__logo { + display: inline-block; + } + + .gbs-controls { + display: none; + } + + .gbs-controls__desktop { + display: block; + } + + .gbs-output { + background-color: var(--color-mine-shaft-light); + height: 100vh; + left: 414px; + position: fixed; + top: 0px; + width: calc(100vw - 414px); + z-index: 1; + } + + .gbs-output__textarea { + height: calc(100vh - 114px); + } + + .gbs-output-hide .gbs-container { + border-radius: 16px; + box-shadow: 0 0 40px 10px rgba(var(--color-primary-rgba), 0.3); + /* box-shadow: 0 5px 32px 3px rgba(0 0 0, 0.9); */ + display: block; + height: calc(100vh - 64px); + margin: 32px auto; + border: 1px solid rgba(var(--color-primary-rgba), .5); + } + + .gbs-fieldset-output { + height: calc(100vh - 16px); + } } @keyframes gbs-border-blinker { - 50% { - border: 1px solid var(--color-warning); - } + 50% { + border: 1px solid var(--color-warning); + } } @keyframes gbs-blinker { - 50% { - opacity: 0; - } -} + 50% { + opacity: 0; + } +} \ No newline at end of file diff --git a/public/test/.gitkeep b/public/test/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/scripts/extras.py b/scripts/extras.py new file mode 100644 index 00000000..0b95615f --- /dev/null +++ b/scripts/extras.py @@ -0,0 +1,51 @@ +Import('env') +import os +import shutil + +root = os.getcwd() + +# prepare WebUI +def before_buildfs(source, target, env): + print('\n\U0001F37A building WebUI\n') + env.Execute("npm run build") + +env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs) + +# copy FS image to /builds +# def after_buildfs(source, target, env): +# path = target[0].get_abspath() +# shutil.copyfile(path, f'{root}/builds/filesystem.bin') +# print('\n\U0001F37A filesystem.bin has been copied into /builds\n') + +# env.AddPostAction("$BUILD_DIR/littlefs.bin", after_buildfs) + +# prepare for ArduinoIDE +def after_build(source, target, env): + # path = source[0].get_abspath() + fino = f"{root}/gbs-control.ino" + try: + os.remove(fino) + except FileNotFoundError: + pass + shutil.copyfile(f"{root}/src/main.cpp", fino) + ## fix include paths + with open(fino, 'r') as f: + ino = f.read() + + vers = '' + for i in env.get('CPPDEFINES'): + if i[0] == 'VERSION': + vers = i[1] + + ino = ino.replace('#include "', '#include "src/') + ino = f'''//! This is autogenerated file +//! Please do not edit if you\'re using PlatformIO\n +#define VERSION "{vers}"\n +''' + ino + with open(fino, 'w') as f: + f.write(ino) + print("\n\U0001F37A gbs-control.ino updated\n") + # shutil.copyfile(os.path.splitext(path)[0] + ".bin", f'{root}/builds/firmware.bin') + # print("\U0001F37A firmware.bin has been copied into /builds\n") + +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", after_build) \ No newline at end of file diff --git a/scripts/generate_translations.py b/scripts/generate_translations.py new file mode 100644 index 00000000..53f270cd --- /dev/null +++ b/scripts/generate_translations.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- + +import json +import os +import sys +import pathlib +# from argparse import ArgumentParser +from PIL import Image, ImageDraw, ImageFont + +root=os.getcwd() +output=f'{root}/src/OLEDMenuTranslations.h' + +# MENU_WIDTH = 128 +# MENU_HEIGHT = 64 +# MENU_STATUS_BAR_HEIGHT = MENU_HEIGHT / 4 +LEFT_RIGHT_PADDING = 0 +TOP_BOTTOM_PADDING = 1 +X_OFFSET = 0 +Y_OFFSET = -1 +DEFAULT_FONT_SIZE = 12 + +# load translations +with open(os.getcwd() + "/translation.hdwui.json", "r", encoding="utf-8") as data: + menu_items = json.load(data) + +res = """ +#define %(name)s_WIDTH %(width)s +#define %(name)s_HEIGHT %(height)s +const unsigned char %(name)s [] PROGMEM = { +%(array)s +}; +""" + +tags_map = {} +fonts_map = {} +default_font = None + +# we need a temporary directory to exist +tmpPath = os.path.join(os.getcwd(), "tmp") +if os.path.isdir(tmpPath) == False: + os.mkdir(tmpPath) + +def convert(text, font): + img = Image.new("L", (0, 0), color=0) + draw = ImageDraw.Draw(img) + _, _, width, height = draw.textbbox((0, 0), text, font) + width += 2 * LEFT_RIGHT_PADDING + height += 2 * TOP_BOTTOM_PADDING # expand top and bottom + img = img.resize((width, height)) + draw = ImageDraw.Draw(img) + draw.text( + (LEFT_RIGHT_PADDING + X_OFFSET, TOP_BOTTOM_PADDING + Y_OFFSET), + text, + 255, + font, + align="center", + ) + byte_index = 0 + number = 0 + data = list(img.getdata()) + bytes_arr = [] + for index, pixel in enumerate(data): + if pixel >= 128: + number += 2**byte_index + byte_index += 1 + if byte_index == 8: + byte_index = -1 + # if this was the last pixel of a row or the last pixel of the + # image, fill up the rest of our byte with zeroes so it always contains 8 bits + if (index != 0 and (index + 1) % width == 0) or index == len(data): + byte_index = -1 + if byte_index < 0: + bytes_arr.append(number) + number = 0 + byte_index = 0 + img.save(os.path.join(tmpPath, "i18n_preview_{:}.jpg".format(tag))) + return width, height, bytes_arr + + +def collect(lang): + key = lang + if not lang: + key = "en" + for obj in menu_items: + if not isinstance(menu_items[obj], dict): + raise TypeError("{:} is not a dict".format(obj)) + # if "tag" not in obj: + # raise KeyError('Key "tag" is missing in {:}'.format(obj)) + if key not in menu_items[obj]: + raise KeyError( + 'Key "{:}" does not exist in {:}'.format( + key, json.dumps(obj, ensure_ascii=False) + ) + ) + size = menu_items[obj].get("size") + tag = obj + if tag in tags_map: + raise ValueError("Duplicated tag: {:}".format(tag)) + translated = menu_items[obj][key] + tags_map[tag] = translated, size + + +template = """ +#define %(name)s_WIDTH %(width)s +#define %(name)s_HEIGHT %(height)s +const unsigned char %(name)s [] PROGMEM = { +%(array)s +}; +""" + +class ArgObj(object): + fonts = ([],) + lang = "en" + +if __name__ == "__main__": + args = ArgObj() + args.fonts = sys.argv[1].split(',') + args.lang = sys.argv[2] + ### this is cool but doesnt wotk in PIO + # parser = ArgumentParser() + # parser.add_argument('--fonts', '-f', nargs='*', default=[]) + # parser.add_argument('--output', '-o', default='src/OLEDMenuTranslations.h') + # parser.add_argument('--lang', help='Language code', nargs='?', default='en') + # args = parser.parse_args() + for font in args.fonts: + tokens = font.split("@") + if len(tokens) == 1: + default_font = tokens[0] + elif len(tokens) > 2: + raise ValueError( + "Too many tokens in {:}. Format: FONT_SIZE@PATH_TO_FONT".format(font) + ) from None + else: + font_size, font_path = tokens + try: + font_size = int(font_size) + except ValueError: + raise ValueError("Not a valid integer: {:}".format(font_size)) from None + fonts_map[font_size] = f'{root}/public/assets/fonts/{font_path}.ttf' + + collect(args.lang) + tag_res_map = {} + + for _, (_, size) in tags_map.items(): + # pre-checks to avoid a corrupted header file. + if not size: + size = DEFAULT_FONT_SIZE + font = fonts_map.get(size, default_font) + if not font: + raise FileNotFoundError("No font for size {:}".format(size)) from None + try: + font = ImageFont.truetype(font) + except (OSError, FileNotFoundError): + raise FileNotFoundError("Font does not exist: {:}".format(font)) from None + + with open(output, "w") as fp: + fp.write("#ifndef OLED_MENU_TRANSLATIONS_H_\n") + fp.write("#define OLED_MENU_TRANSLATIONS_H_\n") + for tag, (text, size) in tags_map.items(): + if not size: + size = DEFAULT_FONT_SIZE + font = fonts_map.get(size, default_font) + font = ImageFont.truetype(font, size=size) + width, height, byte_array = convert(text, font) + tmp_str = "" + i = 0 + while i < len(byte_array): + if i + 16 < len(byte_array): + end = i + 16 + else: + end = len(byte_array) + tmp_str += ",".join([hex(x) for x in byte_array[i:end]]) + ",\n" + i = end + + fp.write( + template + % {"array": tmp_str, "width": width, "height": height, "name": tag} + ) + + fp.write("#endif") + print(f" Output file: {pathlib.Path(output).absolute()}") diff --git a/scripts/pre.py b/scripts/pre.py new file mode 100644 index 00000000..c31049e9 --- /dev/null +++ b/scripts/pre.py @@ -0,0 +1,48 @@ +Import('env') +import os +import subprocess +import sys +import json + +root = os.getcwd() +# check the project structure +data_dir = os.path.join(os.getcwd(), 'data') +if os.path.isdir(data_dir) == False : + os.mkdir(data_dir) + +# load config data +with open(f'{root}/configure.json', 'r') as data: + conf = json.load(data) + +# silently check if all modules are installed +subprocess.call([sys.executable, '-m', 'pip', 'install', 'pillow'], + stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) +# HardwareUI translations +print(f'\n\U0001F37A generate HardwareUI locale data ({conf["ui-lang"]})\n') + +r = subprocess.Popen([ + sys.executable, + f'{root}/scripts/generate_translations.py', + f'{conf["ui-hdw-fonts"]}', + f'{conf["ui-lang"]}' + ], + stderr=subprocess.STDOUT +) +o, e = r.communicate() +r.wait() +if r.returncode != 0 : + e = str(e) + sta = e.find('Error: ')+7 + end = len(e)-3 + print(f'\n\U0001F383: {e[sta:end]}\n') + sys.exit() + +defs = [('VERSION', conf['version'])] + +for (k, v) in conf[env.get('PIOENV')].items(): + defs.append((k.upper(), v)) + +env.Append(CPPDEFINES=defs) + +# continue execution +print(f"\n\U0001F37A running build of v.{conf['version']}\n") \ No newline at end of file diff --git a/slot.h b/slot.h deleted file mode 100644 index 7550be57..00000000 --- a/slot.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _SLOT_H_ -// SLOTS -#define SLOTS_FILE "/slots.bin" // the file where to store slots metadata -#define SLOTS_TOTAL 72 // max number of slots -#define EMPTY_SLOT_NAME "Empty " -typedef struct -{ - char name[25]; - uint8_t presetID; - uint8_t scanlines; - uint8_t scanlinesStrength; - uint8_t slot; - uint8_t wantVdsLineFilter; - uint8_t wantStepResponse; - uint8_t wantPeaking; -} SlotMeta; - -typedef struct -{ - SlotMeta slot[SLOTS_TOTAL]; // the max avaliable slots that can be encoded in a the charset[A-Za-z0-9-._~()!*:,;] -} SlotMetaArray; -#endif \ No newline at end of file diff --git a/src/LICENSE b/src/LICENSE deleted file mode 100644 index f166cc57..00000000 --- a/src/LICENSE +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! \ No newline at end of file diff --git a/OLEDMenuFonts.h b/src/OLEDMenuFonts.h similarity index 99% rename from OLEDMenuFonts.h rename to src/OLEDMenuFonts.h index c9e980fc..d6ec45f9 100644 --- a/OLEDMenuFonts.h +++ b/src/OLEDMenuFonts.h @@ -1,5 +1,3 @@ -#ifndef OLED_MENU_FONTS_H_ -#define OLED_MENU_FONTS_H_ // Created by http://oleddisplay.squix.ch/ Consider a donation // In case of problems make sure that you are using the font file with the correct version! const uint8_t DejaVu_Sans_Mono_12[] PROGMEM = { @@ -916,6 +914,4 @@ const uint8_t DejaVu_Sans_Mono_10[] PROGMEM = { 0x00, 0x00, 0x20, 0x08, 0xC8, 0x08, 0x04, 0x07, 0xC0, 0x00, 0x20, // 253 0x00, 0x00, 0xFC, 0x0F, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 254 0x00, 0x00, 0x20, 0x08, 0xC4, 0x08, 0x00, 0x07, 0xC4, 0x00, 0x20 // 255 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/src/OLEDMenuImplementation.cpp b/src/OLEDMenuImplementation.cpp new file mode 100644 index 00000000..3bae7afa --- /dev/null +++ b/src/OLEDMenuImplementation.cpp @@ -0,0 +1,624 @@ +#include "OLEDMenuImplementation.h" + +static unsigned long oledMenuFreezeStartTime = 0; +static unsigned long oledMenuFreezeTimeoutInMS = 0; + +/** + * @brief + * + * @param manager + * @param item + * @param isFirstTime + * @return true + * @return false + */ +bool resolutionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) +{ + if (!isFirstTime) { + if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { + manager->unfreeze(); + } + return false; + } + oledMenuFreezeTimeoutInMS = 1000; // freeze for 1s + oledMenuFreezeStartTime = millis(); + OLEDDisplay *display = manager->getDisplay(); + display->clear(); + display->setColor(OLEDDISPLAY_COLOR::WHITE); + display->setFont(ArialMT_Plain_16); + display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); + display->drawString(OLED_MENU_WIDTH / 2, 16, item->str); + display->drawXbm((OLED_MENU_WIDTH - TEXT_LOADED_WIDTH) / 2, OLED_MENU_HEIGHT / 2, IMAGE_ITEM(TEXT_LOADED)); + display->display(); + uint8_t videoMode = getVideoMode(); + // OutputResolution preset = OutputBypass; + OutputResolution preset = Output480; + switch (item->tag) { + case MT1920x1080: + preset = Output1080; + break; + case MT1280x1024: + preset = Output1024; + break; + case MT_1280x960: + preset = Output960; + break; + case MT1280x720: + preset = Output720; + break; + case MT_768x576: + preset = Output576PAL; + break; + case MT_720x480: + preset = Output480; + break; + case MT_DOWNSCALE: + preset = Output15kHz; + break; + case MT_BYPASS: + // FIXME do detection which mode is actually to apply + preset = OutputBypass; + break; + case MT_240p: + preset = Output240p; + break; + default: + break; + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) { + videoMode = rto.videoStandardInput; + } + uopt.resolutionID = preset; + if (item->tag != MT_BYPASS) { + // uopt.presetPreference = preset; + // rto.presetID= preset; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + } else { + // registers unitialized, do post preset + setOutputHdBypassMode(false); + // uopt.presetPreference = preset; + // rto.presetID = preset; + if (rto.videoStandardInput != 15) { + rto.autoBestHtotalEnabled = 0; + if (rto.applyPresetDoneStage == 11) { + rto.applyPresetDoneStage = 1; + } else { + rto.applyPresetDoneStage = 10; + } + } else { + rto.applyPresetDoneStage = 1; + } + } + slotFlush(); + manager->freeze(); + return false; +} + +/** + * @brief + * + * @param manager + * @param item + * @param isFirstTime + * @return true + * @return false + */ +bool presetSelectionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) +{ + if (!isFirstTime) { + if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { + manager->unfreeze(); + } + return false; + } + OLEDDisplay *display = manager->getDisplay(); + display->clear(); + display->setColor(OLEDDISPLAY_COLOR::WHITE); + display->setFont(ArialMT_Plain_16); + display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); + display->drawString(OLED_MENU_WIDTH / 2, 16, item->str); + display->drawXbm((OLED_MENU_WIDTH - TEXT_LOADED_WIDTH) / 2, OLED_MENU_HEIGHT / 2, IMAGE_ITEM(TEXT_LOADED)); + display->display(); + // uopt.slotID = 'A' + item->tag; // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~()!*:, + uopt.slotID = item->tag; + // now we're free to load new slot data + if(!slotLoad(uopt.slotID)) { + _DBGF(PSTR("unable to read %s\n"), FPSTR(slotsFile)); + } + // uopt.presetPreference = OutputResolution::OutputCustomized; + if (rto.videoStandardInput == 14) { + // vga upscale path: let synwatcher handle it + rto.videoStandardInput = 15; + } else { + // normal path + applyPresets(rto.videoStandardInput); + } + manager->freeze(); + oledMenuFreezeTimeoutInMS = 2000; + oledMenuFreezeStartTime = millis(); + + return false; +} + +/** + * @brief hardware menu for slot management + * + * @param manager + * @param item + * @return true + * @return false + */ +bool presetsCreationMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool) +{ + int curNumSlot = 0; + SlotMetaArray slotsObject; + manager->clearSubItems(item); + if(slotGetData(slotsObject) != -1) { + // fs::File slotsBinaryFileRead = LittleFS.open(FPSTR(slotsFile), "r"); + // if (slotsBinaryFileRead) { + // slotsBinaryFileRead.read((byte *)&slotsObject, sizeof(slotsObject)); + // slotsBinaryFileRead.close(); + int i = 0; + String slot_name = String(emptySlotName); + while (i < SLOTS_TOTAL) { + const SlotMeta &slot = slotsObject.slot[i]; + i++; + if (strncmp(slot_name.c_str(), slot.name, sizeof(slot.name)) == 0) { + continue; + } + curNumSlot++; + if (curNumSlot >= OLED_MENU_MAX_SUBITEMS_NUM) { + break; + } + manager->registerItem(item, i/* slot.slot */, slot.name, presetSelectionMenuHandler); + } + } + // show notice for user to go to webUI + if (curNumSlot > OLED_MENU_MAX_SUBITEMS_NUM) { + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_TOO_MANY_PRESETS)); + } + // if no presets created yet + if (!item->numSubItem) { + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_NO_PRESETS)); + } + return true; +} + +/** + * @brief + * + * @param manager + * @param item + * @param isFirstTime + * @return true + * @return false + */ +bool resetMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) +{ + unsigned long resetDelay = 2500; + OLEDDisplay *display = nullptr; + if (!isFirstTime) { + // not precise + if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { + manager->unfreeze(); + goto reset_menu_handler_end; + } + return false; + } + + display = manager->getDisplay(); + display->clear(); + display->setColor(OLEDDISPLAY_COLOR::WHITE); + switch (item->tag) { + case MT_RESET_GBS: + display->drawXbm(CENTER_IMAGE(TEXT_RESETTING_GBS)); + break; + case MT_RESTORE_FACTORY: + display->drawXbm(CENTER_IMAGE(TEXT_RESTORING)); + break; + case MT_RESET_WIFI: + display->drawXbm(CENTER_IMAGE(TEXT_RESETTING_WIFI)); + break; + } + display->display(); + webSocket.close(); + delay(50); + switch (item->tag) { + case MT_RESET_WIFI: + WiFi.disconnect(); + break; + case MT_RESTORE_FACTORY: + fsToFactory(); + break; + } + manager->freeze(); + oledMenuFreezeStartTime = millis(); + oledMenuFreezeTimeoutInMS = resetDelay; // freeze for 2 seconds +reset_menu_handler_end: + resetInMSec(resetDelay); + return false; +} + +/** + * @brief Display current output status in accordance with active slot+preset + * + * @param manager + * @param nav + * @param isFirstTime + * @return true + * @return false + */ +bool currentSettingHandler(OLEDMenuManager *manager, OLEDMenuItem *, OLEDMenuNav nav, bool isFirstTime) +{ + static unsigned long lastUpdateTime = 0; + if (isFirstTime) { + lastUpdateTime = 0; + oledMenuFreezeStartTime = millis(); + oledMenuFreezeTimeoutInMS = 2000; // freeze for 2 seconds if no input + manager->freeze(); + } else if (nav != OLEDMenuNav::IDLE) { + manager->unfreeze(); + return false; + } + if (millis() - lastUpdateTime <= 200) { + return false; + } + OLEDDisplay &display = *manager->getDisplay(); + display.clear(); + display.setColor(OLEDDISPLAY_COLOR::WHITE); + display.setFont(ArialMT_Plain_16); + if (rto.sourceDisconnected || !rto.boardHasPower) { + if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { + manager->unfreeze(); + return false; + } + display.setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); + display.drawXbm(CENTER_IMAGE(TEXT_NO_INPUT)); + } else { + // TODO translations + bool vsyncActive = 0; + bool hsyncActive = 0; + float ofr = getOutputFrameRate(); + uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); + // rto.presetID = static_cast(GBS::GBS_PRESET_ID::read()); + // uopt.resolutionID = static_cast(GBS::GBS_PRESET_ID::read()); + + // display.setFont(URW_Gothic_L_Book_20); + display.setTextAlignment(TEXT_ALIGN_LEFT); + + // if (rto.presetID == 0x01 || rto.presetID == 0x11) { + if (uopt.resolutionID == Output960 || uopt.resolutionID == Output960PAL) { + display.drawString(0, 0, "1280x960"); + // } else if (rto.presetID == 0x02 || rto.presetID == 0x12) { + } else if (uopt.resolutionID == Output1024 || uopt.resolutionID == Output1024PAL) { + display.drawString(0, 0, "1280x1024"); + // } else if (rto.presetID == 0x03 || rto.presetID == 0x13) { + } else if (uopt.resolutionID == Output720 || uopt.resolutionID == Output720PAL) { + display.drawString(0, 0, "1280x720"); + // } else if (rto.presetID == 0x05 || rto.presetID == 0x15) { + } else if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) { + display.drawString(0, 0, "1920x1080"); + // } else if (rto.presetID == 0x06 || rto.presetID == 0x16) { + } else if (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL) { + display.drawString(0, 0, "Downscale"); + // } else if (rto.presetID == 0x04) { + } else if (uopt.resolutionID == Output720) { + display.drawString(0, 0, "720x480"); + // } else if (rto.presetID == 0x14) { + } else if (uopt.resolutionID == Output576PAL) { + display.drawString(0, 0, "768x576"); + } else if (utilsIsPassThroughMode()) { + display.drawString(0, 0, "bypass"); + } else { + display.drawString(0, 0, "240p"); + } + + display.drawString(0, 20, String(ofr, 5) + "Hz"); + + if (currentInput == 1) { + display.drawString(0, 41, "RGB"); + } else { + display.drawString(0, 41, "YPbPr"); + } + + if (currentInput == 1) { + vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); + if (vsyncActive) { + display.drawString(70, 41, "V"); + hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); + if (hsyncActive) { + display.drawString(53, 41, "H"); + } + } + } + } + display.display(); + lastUpdateTime = millis(); + + return false; +} + +/** + * @brief Handle user activity in Active Slot and System-wide Paramters menu + * + * @param manager + * @param item + * @param isFirstTime + * @return true + * @return false + */ +bool settingsMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) { + if (!isFirstTime) { + if (millis() - oledMenuFreezeStartTime >= oledMenuFreezeTimeoutInMS) { + manager->unfreeze(); + } + return false; + } + // prepare display to inform user + OLEDDisplay &display = *manager->getDisplay(); + display.clear(); + display.setColor(OLEDDISPLAY_COLOR::WHITE); + // display.setFont(ArialMT_Plain_10); + // display.setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); + // changing settings on the next loop + switch(item->tag) { + // active slot parameters + case MT_SSET_AUTOGAIN: + serialCommand = 'T'; + uopt.enableAutoGain == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_SCANLINES: + userCommand = '7'; + uopt.wantScanlines == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_LINFILTR: + userCommand = 'm'; + uopt.wantVdsLineFilter == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_PEAKING: + serialCommand = 'f'; + uopt.wantPeaking == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_STPRESP: + serialCommand = 'V'; + uopt.wantStepResponse == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_FULHEIGHT: + userCommand = 'v'; + uopt.wantFullHeight == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_F50FREQ60: + userCommand = '0'; + uopt.PalForce60 == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_FTL: + userCommand = '5'; + uopt.enableFrameTimeLock == 0 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_SSET_FTLMETHOD: + userCommand = 'i'; + uopt.frameTimeLockMethod == 0 ? display.drawXbm(CENTER_IMAGE(OM_FTL_METHOD_0)) : display.drawXbm(CENTER_IMAGE(OM_FTL_METHOD_1)); + break; + case MT_SSET_DEINT_BOB_MAD: + userCommand = 'q'; + uopt.deintMode != 1 ? display.drawXbm(CENTER_IMAGE(OM_BOB_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_MAD_ENABLED)); + break; + + // common settings + case MT_CPRM_UPSCALE: + userCommand = 'x'; + uopt.preferScalingRgbhv != 1 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_CPRM_FORCECOMPOSITE: + serialCommand = 'L'; + uopt.wantOutputComponent != 1 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + case MT_CPRM_DISEXTCLK: + userCommand = 'X'; + uopt.disableExternalClockGenerator != 1 ? display.drawXbm(CENTER_IMAGE(OM_DISABLED)) : display.drawXbm(CENTER_IMAGE(OM_ENABLED)); + break; + case MT_CPRM_ADCCALIBR: + userCommand = 'w'; + uopt.enableCalibrationADC != 1 ? display.drawXbm(CENTER_IMAGE(OM_ENABLED)) : display.drawXbm(CENTER_IMAGE(OM_DISABLED)); + break; + } + display.display(); + + oledMenuFreezeStartTime = millis(); + oledMenuFreezeTimeoutInMS = 2500; + manager->freeze(); + + return true; +} + +/** + * @brief This simple functionality allows to trigger WiFi reconnect + * from WiFi info -> Status: Disconnected + * + * @param manager + * @param item + * @param isFirstTime + * @return true + * @return false + */ +bool handleWiFiDisconnectedStatus(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) { + WiFi.reconnect(); + return true; +} + +/** + * @brief + * + * @param manager + * @param item + * @return true + * @return false + */ +bool wifiMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime) +{ + static char ssid[64]; + static char ip[25]; + static char domain[25]; + WiFiMode_t wifiMode = WiFi.getMode(); + manager->clearSubItems(item); + if (wifiMode == WIFI_STA) { + sprintf(ssid, PSTR("SSID: %s"), WiFi.SSID().c_str()); + manager->registerItem(item, 0, ssid); + if (WiFi.isConnected()) { + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_CONNECTED)); + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_URL)); + sprintf(ip, PSTR("http://%s"), WiFi.localIP().toString().c_str()); + manager->registerItem(item, 0, ip); + sprintf(domain, PSTR("http://%s"), FPSTR(gbsc_device_hostname)); + manager->registerItem(item, 0, domain); + } else { + // shouldn't happen? + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_DISCONNECTED), handleWiFiDisconnectedStatus); + } + } else if (wifiMode == WIFI_AP) { + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_CONNECT_TO)); + sprintf(ssid, PSTR("SSID: %s (%s)"), wifiGetApSSID().c_str(), wifiGetApPASS().c_str()); + manager->registerItem(item, 0, ssid); + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_URL)); + manager->registerItem(item, 0, "http://192.168.4.1"); + sprintf(domain, PSTR("http://%s.local"), FPSTR(gbsc_device_hostname)); + manager->registerItem(item, 0, domain); + } else { + // shouldn't happen? + manager->registerItem(item, 0, IMAGE_ITEM(TEXT_WIFI_DISCONNECTED)); + } + return true; +} + +/** + * @brief + * + * @param manager + * @param nav + * @param isFirstTime + * @return true + * @return false + */ +bool osdMenuHanlder(OLEDMenuManager *manager, OLEDMenuItem *, OLEDMenuNav nav, bool isFirstTime) +{ + static unsigned long start; + static long left; + char buf[30]; + auto display = manager->getDisplay(); + + if (isFirstTime) { + left = OSD_TIMEOUT; + start = millis(); + manager->freeze(); + osdManager.tick(OSDNav::ENTER); + } else { + display->clear(); + display->setColor(OLEDDISPLAY_COLOR::WHITE); + display->setFont(ArialMT_Plain_16); + display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER); + display->drawStringf(OLED_MENU_WIDTH / 2, 16, buf, "OSD (%ds)", left / 1000 + 1); + display->display(); + if (REVERSE_ROTARY_ENCODER_FOR_OLED_MENU){ + // reverse nav back to normal + if(nav == OLEDMenuNav::DOWN) { + nav = OLEDMenuNav::UP; + } else if(nav == OLEDMenuNav::UP) { + nav = OLEDMenuNav::DOWN; + } + } + switch (nav) { + case OLEDMenuNav::ENTER: + osdManager.tick(OSDNav::ENTER); + start = millis(); + break; + case OLEDMenuNav::DOWN: + if(REVERSE_ROTARY_ENCODER_FOR_OSD) { + osdManager.tick(OSDNav::RIGHT); + } else { + osdManager.tick(OSDNav::LEFT); + } + start = millis(); + break; + case OLEDMenuNav::UP: + if(REVERSE_ROTARY_ENCODER_FOR_OSD) { + osdManager.tick(OSDNav::LEFT); + } else { + osdManager.tick(OSDNav::RIGHT); + } + start = millis(); + break; + default: + break; + } + left = OSD_TIMEOUT - (millis() - start); + if (left <= 0) { + manager->unfreeze(); + osdManager.menuOff(); + } + } + return true; +} + +/** + * @brief + * + */ +void initOLEDMenu() +{ + OLEDMenuItem *root = oledMenu.rootItem; + + // OSD Menu + oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_OSD), osdMenuHanlder); + + // Resolutions + OLEDMenuItem *resMenu = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_RESOLUTION)); + const char *resolutions[7] = {"1920x1080", "1280x1024", "1280x960", "1280x720", "768x576", "720x480", "240p" }; + uint8_t tags[7] = {MT1920x1080, MT1280x1024, MT_1280x960, MT1280x720, MT_768x576, MT_720x480, MT_240p}; + for (uint8_t i = 0; i < (sizeof(resolutions)/sizeof(*resolutions)); ++i) { + oledMenu.registerItem(resMenu, tags[i], resolutions[i], resolutionMenuHandler); + } + // downscale and passthrough + oledMenu.registerItem(resMenu, MT_DOWNSCALE, IMAGE_ITEM(OM_DOWNSCALE), resolutionMenuHandler); + oledMenu.registerItem(resMenu, MT_BYPASS, IMAGE_ITEM(OM_PASSTHROUGH), resolutionMenuHandler); + + // Slots + oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_PRESET), presetsCreationMenuHandler); + + // Slot Parameters + OLEDMenuItem *activeSlotParameters = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_ACTIVE_SLOT_PARAMETERS)); + oledMenu.registerItem(activeSlotParameters, MT_SSET_AUTOGAIN, IMAGE_ITEM(OM_SSET_AUTOGAIN), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_SCANLINES, IMAGE_ITEM(OM_SSET_SCANLINES), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_LINFILTR, IMAGE_ITEM(OM_SSET_LINFILTR), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_PEAKING, IMAGE_ITEM(OM_SSET_PEAKING), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_STPRESP, IMAGE_ITEM(OM_SSET_STPRESP), settingsMenuHandler); + + oledMenu.registerItem(activeSlotParameters, MT_SSET_FULHEIGHT, IMAGE_ITEM(OM_SSET_FULHEIGHT), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_F50FREQ60, IMAGE_ITEM(OM_SSET_F50FREQ60), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_FTL, IMAGE_ITEM(OM_SSET_FTL), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_FTLMETHOD, IMAGE_ITEM(OM_SSET_FTLMETHOD), settingsMenuHandler); + oledMenu.registerItem(activeSlotParameters, MT_SSET_DEINT_BOB_MAD, IMAGE_ITEM(OM_SSET_DEINT_BOB_MAD), settingsMenuHandler); + + // System-wide parameters + OLEDMenuItem *systemSettings = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_SYSTEM_PARAMETERS)); + oledMenu.registerItem(systemSettings, MT_CPRM_UPSCALE, IMAGE_ITEM(OM_CPRM_UPSCALE), settingsMenuHandler); + oledMenu.registerItem(systemSettings, MT_CPRM_FORCECOMPOSITE, IMAGE_ITEM(OM_CPRM_FORCECOMPOSITE), settingsMenuHandler); + oledMenu.registerItem(systemSettings, MT_CPRM_DISEXTCLK, IMAGE_ITEM(OM_CPRM_DISEXTCLK), settingsMenuHandler); + oledMenu.registerItem(systemSettings, MT_CPRM_ADCCALIBR, IMAGE_ITEM(OM_CPRM_ADCCALIBR), settingsMenuHandler); + + // WiFi + oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_WIFI), wifiMenuHandler); + + // Current Output status + oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_CURRENT), currentSettingHandler); + + // Reset (Misc.) + OLEDMenuItem *resetMenu = oledMenu.registerItem(root, MT_NULL, IMAGE_ITEM(OM_RESET_RESTORE)); + oledMenu.registerItem(resetMenu, MT_RESET_GBS, IMAGE_ITEM(OM_RESET_GBS), resetMenuHandler); + oledMenu.registerItem(resetMenu, MT_RESET_WIFI, IMAGE_ITEM(OM_RESET_WIFI), resetMenuHandler); + oledMenu.registerItem(resetMenu, MT_RESTORE_FACTORY, IMAGE_ITEM(OM_RESTORE_FACTORY), resetMenuHandler); +} diff --git a/OLEDMenuImplementation.h b/src/OLEDMenuImplementation.h similarity index 69% rename from OLEDMenuImplementation.h rename to src/OLEDMenuImplementation.h index e2473fa1..7f881df1 100644 --- a/OLEDMenuImplementation.h +++ b/src/OLEDMenuImplementation.h @@ -1,20 +1,47 @@ // define menu items and handlers here #ifndef OLED_MENU_IMPLEMENTATION_H_ #define OLED_MENU_IMPLEMENTATION_H_ + +#include +#include "OLEDMenuTranslations.h" #include "OLEDMenuManager.h" +#include "OSDManager.h" +#include "fonts.h" +#include "slot.h" +#include "wserver.h" +#include "video.h" + enum MenuItemTag: uint16_t { // unique identifiers for sub-items MT_NULL, // null tag, used by root menu items, since they can be differentiated by handlers - MT_1280x960, + MT1920x1080, MT1280x1024, + MT_1280x960, MT1280x720, - MT1920x1080, - MT_480s576, + MT_768x576, + MT_720x480, + MT_240p, MT_DOWNSCALE, MT_BYPASS, MT_RESET_GBS, MT_RESTORE_FACTORY, MT_RESET_WIFI, + + MT_SSET_AUTOGAIN, + MT_SSET_SCANLINES, + MT_SSET_LINFILTR, + MT_SSET_PEAKING, + MT_SSET_STPRESP, + MT_SSET_FTL, + MT_SSET_FTLMETHOD, + MT_SSET_FULHEIGHT, + MT_SSET_F50FREQ60, + MT_SSET_DEINT_BOB_MAD, + + MT_CPRM_UPSCALE, + MT_CPRM_FORCECOMPOSITE, + MT_CPRM_DISEXTCLK, + MT_CPRM_ADCCALIBR, }; // declarations of resolutionMenuHandler, presetSelectionMenuHandler, presetsCreationMenuHandler, resetMenuHandler, currentSettingHandler, wifiMenuHandler bool resolutionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); @@ -22,7 +49,9 @@ bool presetSelectionMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OL bool presetsCreationMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); bool resetMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); bool currentSettingHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); +bool settingsMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav, bool isFirstTime); bool wifiMenuHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); bool OSDHandler(OLEDMenuManager *manager, OLEDMenuItem *item, OLEDMenuNav nav, bool isFirstTime); void initOLEDMenu(); + #endif \ No newline at end of file diff --git a/OLEDMenuItem.cpp b/src/OLEDMenuItem.cpp similarity index 94% rename from OLEDMenuItem.cpp rename to src/OLEDMenuItem.cpp index fcf9f823..2a4723b5 100644 --- a/OLEDMenuItem.cpp +++ b/src/OLEDMenuItem.cpp @@ -3,7 +3,7 @@ void OLEDMenuItem::calculate() { if(!this->parent){ - return; // root + return; // root } if (this->str) { size_t strLength = strlen(this->str); @@ -48,17 +48,19 @@ void OLEDMenuItem::calculate() // decide which page this item belongs to uint16_t lastLineAt = 0; - for (int i = 0; i < parent->numSubItem - 1; ++i) { + uint8_t i = 0; + while (i < parent->numSubItem - 1) { // find all items on the last page, see if it fits // put it on the next page if not. // last item in parent->numSubItem is always "this" OLEDMenuItem *item = parent->subItems[i]; + i++; if (item->pageInParent != parent->maxPageIndex) { continue; } lastLineAt += item->imageHeight; } - lastLineAt += imageHeight; // self + lastLineAt += this->imageHeight; // self if (lastLineAt <= OLED_MENU_USABLE_AREA_HEIGHT) { this->pageInParent = parent->maxPageIndex; diff --git a/OLEDMenuItem.h b/src/OLEDMenuItem.h similarity index 91% rename from OLEDMenuItem.h rename to src/OLEDMenuItem.h index 773a6450..b534195c 100644 --- a/OLEDMenuItem.h +++ b/src/OLEDMenuItem.h @@ -1,12 +1,13 @@ -/* - See https://github.com/PSHarold/OLED-SSD1306-Menu +/* + See https://github.com/PSHarold/OLED-SSD1306-Menu for original code, license and documentation */ #ifndef OLED_MENU_ITEM_H_ #define OLED_MENU_ITEM_H_ #include #include "SSD1306Wire.h" -#include "OLEDMenuConfig.h" +#include "OLEDMenuTranslations.h" +#include "options.h" class OLEDMenuItem; class OLEDMenuManager; @@ -45,9 +46,11 @@ class OLEDMenuItem // } void clearSubItems() { - for (int i = 0; i < this->numSubItem; ++i) { + int i = 0; + while (i < this->numSubItem) { subItems[i]->used = false; subItems[i] = nullptr; + i++; } this->numSubItem = 0; this->maxPageIndex = 0; diff --git a/OLEDMenuManager.cpp b/src/OLEDMenuManager.cpp similarity index 78% rename from OLEDMenuManager.cpp rename to src/OLEDMenuManager.cpp index ae100f1e..820e8e9c 100644 --- a/OLEDMenuManager.cpp +++ b/src/OLEDMenuManager.cpp @@ -1,37 +1,90 @@ -/* - See https://github.com/PSHarold/OLED-SSD1306-Menu +/* + See https://github.com/PSHarold/OLED-SSD1306-Menu for original code, license and documentation */ #include "OLEDMenuManager.h" #include "OLEDMenuFonts.h" - -OLEDMenuManager::OLEDMenuManager(SSD1306Wire *display) - : display(display) - , rootItem(registerItem(nullptr, 0, nullptr)) +/** + * @brief Construct a new OLEDMenuManager::OLEDMenuManager object + * + * @param display + */ +OLEDMenuManager::OLEDMenuManager(SSD1306Wire * _display) { + display = _display; + // allocate memory for menu items list + allItems = new OLEDMenuItem * [OLED_MENU_MAX_ITEMS_NUM]; + uint8_t i = 0; + while(i < OLED_MENU_MAX_ITEMS_NUM) { + allItems[i] = nullptr; + i++; + } +} + +/** + * @brief initializer does what constructor can NOT do + * + */ +void OLEDMenuManager::init() { + rootItem = registerItem(nullptr, 0, nullptr); pushItem(rootItem); - randomSeed(millis()); // does this work? + // randomSeed(millis()); // does this work? } + +/** + * @brief + * + * @return OLEDMenuItem* + */ OLEDMenuItem *OLEDMenuManager::allocItem() { - OLEDMenuItem *newItem = nullptr; - for (int i = 0; i < OLED_MENU_MAX_ITEMS_NUM; ++i) { - if (!this->allItems[i].used) { - memset(&this->allItems[i], 0, sizeof(OLEDMenuItem)); - newItem = &this->allItems[i]; - newItem->used = true; + int i = 0; + OLEDMenuItem * newItem = nullptr; + auto lambdaAllocItem = [&newItem]() { + newItem = new OLEDMenuItem(); + newItem->used = true; + }; + while (i < OLED_MENU_MAX_ITEMS_NUM) { + if(this->allItems[i] == nullptr) { + lambdaAllocItem(); + break; + } + else if (!this->allItems[i]->used) + { + delete this->allItems[i]; + lambdaAllocItem(); break; } + // if (!this->allItems[i].used) { + // memset(&this->allItems[i], 0, sizeof(OLEDMenuItem)); + // newItem = &this->allItems[i]; + // newItem->used = true; + // break; + // } + i++; } - if (!newItem) { - char msg[40]; - sprintf(msg, "Maximum number of items reached: %d", OLED_MENU_MAX_ITEMS_NUM); - panicAndDisable(msg); + if (newItem == nullptr) { + // char msg[40]; + _DBGF(PSTR("reached max. menu items: %d\n"), OLED_MENU_MAX_ITEMS_NUM); + // sprintf(msg, PSTR("Maximum number of items reached: %d"), OLED_MENU_MAX_ITEMS_NUM); + // panicAndDisable(msg); } return newItem; } +/** + * @brief + * + * @param parent + * @param tag + * @param imageWidth + * @param imageHeight + * @param xbmImage + * @param handler + * @param alignment + * @return OLEDMenuItem* + */ OLEDMenuItem *OLEDMenuManager::registerItem( OLEDMenuItem *parent, uint16_t tag, @@ -42,12 +95,18 @@ OLEDMenuItem *OLEDMenuManager::registerItem( OLEDDISPLAY_TEXT_ALIGNMENT alignment) { OLEDMenuItem *newItem = allocItem(); + constexpr uint8_t maxMenuItemHeight = OLED_MENU_USABLE_AREA_HEIGHT / (OLED_MENU_ITEMS_PER_SCREEN - 1); + if(newItem == nullptr) + goto register_image_item_end; if (alignment == OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER_BOTH) { alignment = OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_CENTER; } newItem->imageWidth = imageWidth; - newItem->imageHeight = imageHeight; + + // fixing the height of image items (at the first row is always a menu control item) + newItem->imageHeight = (imageHeight > maxMenuItemHeight) ? maxMenuItemHeight : imageHeight; + newItem->xbmImage = xbmImage; newItem->tag = tag; @@ -60,9 +119,22 @@ OLEDMenuItem *OLEDMenuManager::registerItem( itemUnderCursor = rootItem->subItems[0]; } } + +register_image_item_end: return newItem; } +/** + * @brief + * + * @param parent + * @param tag + * @param string + * @param handler + * @param font + * @param alignment + * @return OLEDMenuItem* + */ OLEDMenuItem *OLEDMenuManager::registerItem( OLEDMenuItem *parent, uint16_t tag, @@ -72,6 +144,9 @@ OLEDMenuItem *OLEDMenuManager::registerItem( OLEDDISPLAY_TEXT_ALIGNMENT alignment) { OLEDMenuItem *newItem = allocItem(); + if(newItem == nullptr) + goto register_text_item_end; + newItem->str = string; if (font == nullptr) { font = DejaVu_Sans_Mono_12; @@ -82,9 +157,13 @@ OLEDMenuItem *OLEDMenuManager::registerItem( newItem->alignment = alignment; if (parent) { if (parent->numSubItem == OLED_MENU_MAX_SUBITEMS_NUM) { - char msg[50]; - sprintf(msg, "Maximum number of sub items reached: %d", OLED_MENU_MAX_SUBITEMS_NUM); - panicAndDisable(msg); + _DBGF(PSTR("Maximum number of sub items reached: %d\n"), OLED_MENU_MAX_SUBITEMS_NUM); + delete newItem; + newItem = nullptr; + goto register_text_item_end; + // char msg[50]; + // sprintf(msg, PSTR("Maximum number of sub items reached: %d"), OLED_MENU_MAX_SUBITEMS_NUM); + // panicAndDisable(msg); } parent->addSubItem(newItem); if (parent == rootItem) { @@ -92,9 +171,17 @@ OLEDMenuItem *OLEDMenuManager::registerItem( itemUnderCursor = rootItem->subItems[0]; } } +register_text_item_end: return newItem; } +/** + * @brief + * + * @param item + * @param yOffset + * @param negative + */ void OLEDMenuManager::drawOneItem(OLEDMenuItem *item, uint16_t yOffset, bool negative) { int16_t curScrollOffset = 0; @@ -155,13 +242,20 @@ void OLEDMenuManager::drawOneItem(OLEDMenuItem *item, uint16_t yOffset, bool neg } } } + +/** + * @brief + * + * @param parent + */ void OLEDMenuManager::drawSubItems(OLEDMenuItem *parent) { + uint8_t i = 0; display->clear(); drawStatusBar(itemUnderCursor == nullptr); uint16_t yOffset = OLED_MENU_STATUS_BAR_HEIGHT; uint8_t targetPage = itemUnderCursor == nullptr ? 0 : itemUnderCursor->pageInParent; - for (int i = 0; i < parent->numSubItem; ++i) { + while(i < parent->numSubItem) { OLEDMenuItem *subItem = parent->subItems[i]; #if OLED_MENU_OVER_DRAW if (subItem->pageInParent >= targetPage) { @@ -179,10 +273,16 @@ void OLEDMenuManager::drawSubItems(OLEDMenuItem *parent) break; } } + i++; } display->display(); } +/** + * @brief + * + * @param preserveCursor + */ void OLEDMenuManager::goBack(bool preserveCursor) { // go back one page @@ -196,6 +296,12 @@ void OLEDMenuManager::goBack(bool preserveCursor) resetScroll(); state = OLEDMenuState::GOING_BACK; } + +/** + * @brief + * + * @param preserveCursor + */ void OLEDMenuManager::goMain(bool preserveCursor) { while (peakItem() != rootItem) { @@ -203,6 +309,10 @@ void OLEDMenuManager::goMain(bool preserveCursor) } } +/** + * @brief + * + */ void OLEDMenuManager::nextItem() { resetScroll(); @@ -226,6 +336,11 @@ void OLEDMenuManager::nextItem() itemUnderCursor = parentItem->subItems[++cursor]; } } + +/** + * @brief + * + */ void OLEDMenuManager::prevItem() { resetScroll(); @@ -252,6 +367,10 @@ void OLEDMenuManager::prevItem() } } +/** + * @brief + * + */ void OLEDMenuManager::resetScroll() { leadInFramesLeft = OLED_MENU_SCROLL_LEAD_IN_FRAMES; @@ -267,11 +386,18 @@ void OLEDMenuManager::resetScroll() lastUpdateTime = 0; } +/** + * @brief + * + * @param item + * @param btn + * @param isFirstTime + */ void OLEDMenuManager::enterItem(OLEDMenuItem *item, OLEDMenuNav btn, bool isFirstTime) { bool willEnter = true; if (this->state == OLEDMenuState::IDLE) { - pushItem(item); + if(!pushItem(item)) return; this->state = OLEDMenuState::ITEM_HANDLING; } if (item->handler) { @@ -302,6 +428,11 @@ void OLEDMenuManager::enterItem(OLEDMenuItem *item, OLEDMenuNav btn, bool isFirs this->itemUnderCursor = item->subItems[0]; } +/** + * @brief + * + * @param negative + */ void OLEDMenuManager::drawStatusBar(bool negative) { if (negative) { @@ -334,6 +465,12 @@ void OLEDMenuManager::drawStatusBar(bool negative) this->display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_LEFT); } +/** + * @brief + * + * @param preserveCursor + * @return OLEDMenuItem* + */ OLEDMenuItem *OLEDMenuManager::popItem(bool preserveCursor) { if (itemSP == 1) { @@ -349,13 +486,20 @@ OLEDMenuItem *OLEDMenuManager::popItem(bool preserveCursor) return top; } } - panicAndDisable("invalid item: item cannot be found in its parent's subItems"); + // panicAndDisable("invalid item: item cannot be found in its parent's subItems"); + _DBGN(F("invalid item: item cannot be found in its parent's subItems")); return nullptr; } cursor = 0; itemUnderCursor = top->parent->subItems[0]; return top; } + +/** + * @brief + * + * @param nav + */ void OLEDMenuManager::tick(OLEDMenuNav nav) { if (this->disabled) { diff --git a/OLEDMenuManager.h b/src/OLEDMenuManager.h similarity index 57% rename from OLEDMenuManager.h rename to src/OLEDMenuManager.h index b07ab8ff..a63b46a3 100644 --- a/OLEDMenuManager.h +++ b/src/OLEDMenuManager.h @@ -1,11 +1,15 @@ -/* - See https://github.com/PSHarold/OLED-SSD1306-Menu +/* + See https://github.com/PSHarold/OLED-SSD1306-Menu for original code, license and documentation */ #ifndef OLED_MENU_MANAGER_H_ #define OLED_MENU_MANAGER_H_ + #include "OLEDMenuItem.h" -#include "OLEDMenuConfig.h" +#include "OLEDMenuTranslations.h" +#include "options.h" +#include "wserial.h" + #define IMAGE_ITEM(name) name##_WIDTH, name##_HEIGHT, name #define CENTER_IMAGE(name) (OLED_MENU_WIDTH - name##_WIDTH) / 2, (OLED_MENU_HEIGHT - name##_HEIGHT) / 2, name##_WIDTH, name##_HEIGHT, name enum class OLEDMenuState @@ -26,9 +30,9 @@ enum class OLEDMenuNav class OLEDMenuManager { private: - OLEDDisplay *const display; - OLEDMenuItem allItems[OLED_MENU_MAX_ITEMS_NUM]; - OLEDMenuItem *itemStack[OLED_MENU_MAX_DEPTH]; + OLEDDisplay * display = nullptr; + OLEDMenuItem ** allItems; + OLEDMenuItem * itemStack[OLED_MENU_MAX_DEPTH]; uint8_t itemSP; OLEDMenuItem *itemUnderCursor; // null means the status bar is currently selected OLEDMenuState state; @@ -47,22 +51,26 @@ class OLEDMenuManager void resetScroll(); void drawStatusBar(bool negative = false); - inline void drawOneItem(OLEDMenuItem *item, uint16_t yOffset, bool negative); + void drawOneItem(OLEDMenuItem *item, uint16_t yOffset, bool negative); void drawSubItems(OLEDMenuItem *parent); - inline void enterItem(OLEDMenuItem *item, OLEDMenuNav btn, bool isFirstTime); + void enterItem(OLEDMenuItem *item, OLEDMenuNav btn, bool isFirstTime); void nextItem(); void prevItem(); - void pushItem(OLEDMenuItem *item) + bool pushItem(OLEDMenuItem *item) { if (itemSP == OLED_MENU_MAX_DEPTH - 1) { - char msg[30]; - sprintf(msg, "Maximum depth reached: %d", OLED_MENU_MAX_DEPTH); - panicAndDisable(msg); + // char msg[30]; + // sprintf(msg, PSTR("Maximum depth reached: %d"), OLED_MENU_MAX_DEPTH); + // panicAndDisable(msg); + _DBGF(PSTR("Maximum depth reached: %d\n"), OLED_MENU_MAX_DEPTH); + return false; } itemStack[itemSP++] = item; + return true; } + // ! explanation wanted OLEDMenuItem *popItem(bool preserveCursor = true); OLEDMenuItem *peakItem() { @@ -72,38 +80,64 @@ class OLEDMenuManager } return itemStack[itemSP - 1]; } - void panicAndDisable(const char *msg) - { - this->display->clear(); - this->display->setColor(OLEDDISPLAY_COLOR::WHITE); - this->display->fillRect(0, 0, OLED_MENU_WIDTH, OLED_MENU_HEIGHT); - this->display->setColor(OLEDDISPLAY_COLOR::BLACK); - this->display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_LEFT); - this->display->setFont(ArialMT_Plain_10); - this->display->drawString(0, 0, msg); - this->display->display(); - while (1); - } + // ! this is not informative and disables debug ability + // + // void panicAndDisable(const char *msg) + // { + // this->display->clear(); + // this->display->setColor(OLEDDISPLAY_COLOR::WHITE); + // this->display->fillRect(0, 0, OLED_MENU_WIDTH, OLED_MENU_HEIGHT); + // this->display->setColor(OLEDDISPLAY_COLOR::BLACK); + // this->display->setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT::TEXT_ALIGN_LEFT); + // this->display->setFont(ArialMT_Plain_10); + // this->display->drawString(0, 0, msg); + // this->display->display(); + // while (1); + // } + /** + * @brief Display screen saver + * + */ void drawScreenSaver() { display->clear(); display->setColor(OLEDDISPLAY_COLOR::WHITE); + int16_t versionX = 0; + const String versionStr = String(F("v.")) + String(STRING(VERSION)); + const uint16_t versionStrWidth = this->display->getStringWidth(versionStr.c_str(), versionStr.length()); + const uint8_t versionStrHeight = 10; constexpr int16_t max_x = OLED_MENU_WIDTH - OM_SCREEN_SAVER_WIDTH; - constexpr int16_t max_y = OLED_MENU_HEIGHT - OM_SCREEN_SAVER_HEIGHT; - display->drawXbm(rand() % max_x, rand() % max_y, IMAGE_ITEM(OM_SCREEN_SAVER)); + constexpr int16_t max_y = OLED_MENU_HEIGHT - (OM_SCREEN_SAVER_HEIGHT + versionStrHeight); + const uint16_t rx = rand() % max_x; + const uint16_t ry = rand() % max_y; + // display FW version + versionX = OM_SCREEN_SAVER_WIDTH - versionStrWidth; + if(versionX <= 0) + versionX = rx; + else { + versionX /= 2; + versionX += rx; + } + display->drawXbm(rx, ry, IMAGE_ITEM(OM_SCREEN_SAVER)); + this->display->drawString(versionX, ry + versionStrHeight, versionStr); display->display(); } public: OLEDMenuManager(SSD1306Wire *display); + ~OLEDMenuManager() { + delete[] allItems; + allItems = NULL; + } OLEDMenuItem *allocItem(); OLEDMenuItem *registerItem(OLEDMenuItem *parent, uint16_t tag, uint16_t imageWidth, uint16_t imageHeight, const uint8_t *xbmImage, MenuItemHandler handler = nullptr, OLEDDISPLAY_TEXT_ALIGNMENT alignment = TEXT_ALIGN_CENTER); OLEDMenuItem *registerItem(OLEDMenuItem *parent, uint16_t tag, const char *string, MenuItemHandler handler = nullptr, const uint8_t *font = nullptr, OLEDDISPLAY_TEXT_ALIGNMENT alignment = TEXT_ALIGN_CENTER); + void init(); void tick(OLEDMenuNav btn); void goBack(bool preserveCursor = true); void goMain(bool preserveCursor = true); - OLEDMenuItem *const rootItem; + OLEDMenuItem * rootItem = nullptr; void clearSubItems(OLEDMenuItem *item) { @@ -143,4 +177,7 @@ class OLEDMenuManager this->disabled = false; } }; + +extern OLEDMenuManager oledMenu; + #endif \ No newline at end of file diff --git a/src/OLEDMenuTranslations.h b/src/OLEDMenuTranslations.h new file mode 100644 index 00000000..378de636 --- /dev/null +++ b/src/OLEDMenuTranslations.h @@ -0,0 +1,981 @@ +#ifndef OLED_MENU_TRANSLATIONS_H_ +#define OLED_MENU_TRANSLATIONS_H_ + +#define OM_STATUS_CUSTOM_WIDTH 61 +#define OM_STATUS_CUSTOM_HEIGHT 15 +const unsigned char OM_STATUS_CUSTOM [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x1,0x4,0x80,0x40,0x0,0x0,0x0, +0x86,0x1,0x0,0x80,0x61,0x0,0x0,0x0,0x86,0x1,0x0,0x80,0x61,0x0,0x0,0x0, +0x4a,0x59,0x64,0x83,0x52,0x1e,0x9b,0x8,0x4a,0x81,0x24,0x82,0x52,0x22,0x91,0x8, +0x4a,0xe1,0x24,0x82,0x52,0x3e,0x91,0x8,0x12,0x89,0x24,0x82,0x44,0x2,0x91,0x8, +0x32,0xc9,0x24,0x82,0x4c,0x22,0x91,0xc,0x32,0xf9,0x24,0x82,0x4c,0x1e,0x91,0xf, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_STATUS_BAR_BACK_WIDTH 40 +#define OM_STATUS_BAR_BACK_HEIGHT 15 +const unsigned char OM_STATUS_BAR_BACK [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xe0,0x3,0x0,0x4,0x0,0x20,0x6,0x0,0x4,0x0,0x20,0x4,0x0,0x4,0x8,0x20, +0x64,0xf1,0x24,0x4,0xe0,0x3,0x12,0x14,0x2,0x20,0x84,0xb,0x1c,0x2,0x20,0x24, +0xa,0x14,0x4,0x20,0x24,0x93,0x25,0x8,0xe0,0xe3,0xf3,0x64,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SCREEN_SAVER_WIDTH 76 +#define OM_SCREEN_SAVER_HEIGHT 17 +const unsigned char OM_SCREEN_SAVER [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0, +0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x4, +0x0,0x0,0x42,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x42,0xee,0xf1,0x3c, +0x58,0x6c,0x13,0x24,0xcf,0x4,0x7e,0x22,0x12,0x4,0x80,0x44,0x12,0x14,0x91,0x4, +0x2,0xe2,0x73,0x1c,0xe0,0x44,0x12,0x1c,0x9f,0x4,0x2,0x22,0x80,0x20,0x88,0x44, +0xc,0x14,0x1,0x3,0x2,0x22,0x92,0x24,0xc8,0x44,0xc,0x24,0x11,0x3,0x2,0xe2, +0xf1,0x3c,0xf8,0x44,0xc,0x64,0xf,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0, +0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x80,0x1,0x0,0x0,0x0,0x0, +0x0,0x0,0x2,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_RESOLUTION_WIDTH 65 +#define OM_RESOLUTION_HEIGHT 15 +const unsigned char OM_RESOLUTION [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x40,0x0, +0x8,0x0,0x0,0x0,0xc2,0x0,0x0,0x40,0x0,0x1,0x0,0x0,0x0,0x82,0x0,0x0, +0x40,0x0,0x1,0x0,0x0,0x0,0xc2,0x3c,0x9e,0x47,0x22,0xcb,0x63,0xf3,0x0,0x7e, +0x44,0x82,0x48,0x22,0x49,0x24,0x12,0x0,0x42,0x7c,0xce,0x48,0x22,0x69,0x24,0x72, +0x0,0x82,0x4,0x90,0x48,0x22,0x49,0x24,0x82,0x0,0x82,0x44,0x92,0x48,0x32,0x49, +0x24,0x92,0x0,0x82,0x3c,0x9e,0x47,0x3e,0xcb,0x23,0xf2,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_PASSTHROUGH_WIDTH 69 +#define OM_PASSTHROUGH_HEIGHT 17 +const unsigned char OM_PASSTHROUGH [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x80,0x0, +0x0,0x0,0x80,0x0,0x62,0x0,0x0,0x90,0x0,0x0,0x0,0x80,0x0,0x42,0x0,0x0, +0x90,0x0,0x0,0x0,0x80,0x0,0x42,0x16,0xcf,0xb3,0xcd,0x3d,0x22,0x9f,0xd,0x7e, +0x20,0x41,0x90,0x48,0x44,0x22,0x91,0x8,0x2,0x38,0xc7,0x91,0x48,0x46,0xa2,0x90, +0x8,0x2,0x22,0x8,0x92,0x48,0x44,0xa2,0x90,0x8,0x2,0x32,0x49,0x92,0x48,0x44, +0x32,0x99,0x8,0x2,0x3e,0xcf,0xb3,0x48,0x3c,0x3e,0x9f,0x8,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_DOWNSCALE_WIDTH 67 +#define OM_DOWNSCALE_HEIGHT 15 +const unsigned char OM_DOWNSCALE [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0xc0, +0x3,0x0,0x4,0x0,0x62,0x0,0x0,0x0,0x60,0x6,0x0,0x4,0x0,0xc2,0x0,0x0, +0x0,0x20,0x4,0x0,0x4,0x0,0x82,0x3c,0x99,0x6c,0x60,0xe0,0x59,0xe4,0x1,0x82, +0x44,0x9a,0x44,0xc0,0x23,0x80,0x24,0x2,0x82,0x46,0xaa,0x44,0x6,0x16,0xe0,0xe4, +0x3,0x82,0x44,0x6a,0x44,0x20,0x14,0x88,0x24,0x0,0x42,0x44,0x66,0x44,0x20,0x24, +0xcb,0x24,0x2,0x3e,0x3c,0x64,0x44,0xc0,0xe7,0xf9,0xe4,0x1,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_PRESET_WIDTH 27 +#define OM_PRESET_HEIGHT 15 +const unsigned char OM_PRESET [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x2,0x0,0x0, +0x66,0x2,0x8,0x0,0x42,0x2,0x8,0x0,0x6,0xf2,0xd8,0x3,0x3c,0x12,0x49,0x0, +0x60,0x1a,0xc9,0x1,0x42,0x12,0x9,0x2,0x42,0x12,0x49,0x2,0x7c,0xf2,0xd8,0x3, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_ACTIVE_SLOT_PARAMETERS_WIDTH 86 +#define OM_ACTIVE_SLOT_PARAMETERS_HEIGHT 17 +const unsigned char OM_ACTIVE_SLOT_PARAMETERS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x3c,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x66,0x2,0x8,0x0, +0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x42,0x2,0x8,0x0,0x0,0x0,0x0,0x0,0x8, +0x0,0x0,0x6,0xf2,0x18,0x1e,0x8b,0x5b,0xec,0xf3,0xd8,0xe3,0x1e,0x3c,0x12,0x9, +0x22,0x90,0x80,0x64,0x12,0x49,0x24,0x2,0x60,0x1a,0x9,0x22,0x9c,0xe0,0x64,0xf2, +0xc9,0x27,0xe,0x42,0x12,0x9,0x22,0x91,0x88,0x64,0x12,0x48,0x20,0x10,0x42,0x12, +0x9,0x22,0x99,0xc8,0x64,0x12,0x49,0x24,0x12,0x7c,0xf2,0x18,0x1e,0x9f,0xf8,0x64, +0xf2,0xd8,0x23,0x1e,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_AUTOGAIN_WIDTH 54 +#define OM_SSET_AUTOGAIN_HEIGHT 15 +const unsigned char OM_SSET_AUTOGAIN [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x0,0x80,0x7,0x20,0x0,0x18,0x0,0x1,0x40, +0xc,0x0,0x0,0x38,0x0,0x1,0x20,0x8,0x0,0x0,0x24,0x22,0x7b,0x20,0xc0,0x22, +0x1b,0x24,0x22,0x89,0x20,0xe,0x24,0x11,0x7e,0x22,0x8d,0x20,0x18,0x27,0x11,0x66, +0x22,0x89,0x20,0x58,0x24,0x11,0x42,0x32,0x89,0x60,0x58,0x26,0x11,0xc3,0x3e,0x7b, +0xc0,0xd7,0x27,0x11,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_SCANLINES_WIDTH 54 +#define OM_SSET_SCANLINES_HEIGHT 15 +const unsigned char OM_SSET_SCANLINES [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x20,0x1,0x0,0x0,0x66,0x0,0x0,0x20, +0x0,0x0,0x0,0x42,0x0,0x0,0x20,0x0,0x0,0x0,0x6,0x9e,0xc5,0x26,0xd9,0x3c, +0x1e,0x3c,0x2,0x48,0x24,0x89,0x44,0x2,0x60,0x1,0x4e,0x24,0x89,0x7c,0xe,0x42, +0x81,0x48,0x24,0x89,0x4,0x10,0x42,0xb2,0x4c,0x24,0x89,0x44,0x12,0x7c,0x9e,0x4f, +0x24,0x89,0x3c,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_LINFILTR_WIDTH 54 +#define OM_SSET_LINFILTR_HEIGHT 15 +const unsigned char OM_SSET_LINFILTR [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x2,0x1,0x0,0xf0,0x4b,0x0,0x0,0x2,0x0,0x0,0x10, +0x40,0x2,0x0,0x2,0x0,0x0,0x10,0x40,0x2,0x0,0x2,0xd9,0x3c,0x10,0x48,0xf6, +0x38,0x2,0x89,0x44,0xf0,0x49,0x12,0x9,0x2,0x89,0x7c,0x10,0x48,0xf2,0x9,0x2, +0x89,0x4,0x10,0x48,0x12,0x8,0x2,0x89,0x44,0x10,0x48,0x12,0x9,0x3e,0x89,0x3c, +0x10,0x48,0xf6,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_PEAKING_WIDTH 45 +#define OM_SSET_PEAKING_HEIGHT 17 +const unsigned char OM_SSET_PEAKING [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x3e,0x0,0x80,0x20,0x0,0x0,0x62,0x0,0x80,0x0,0x0,0x0,0x42,0x0, +0x80,0x0,0x0,0x0,0x42,0x1e,0x8b,0x24,0x9b,0xf,0x7e,0x22,0x90,0x22,0x91,0x8, +0x2,0x3e,0x9c,0x23,0x51,0x8,0x2,0x2,0x91,0x22,0x51,0x8,0x2,0x22,0x99,0x24, +0x91,0xc,0x2,0x1e,0x9f,0x2c,0x91,0xf,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0, +0x0,0x0,0x80,0x4,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_STPRESP_WIDTH 79 +#define OM_SSET_STPRESP_HEIGHT 17 +const unsigned char OM_SSET_STPRESP [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x66,0x2,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x42,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0xf6,0x78,0xe0, +0x1e,0xcf,0xe3,0xb1,0x79,0x1e,0x3c,0x12,0x89,0x20,0x22,0x41,0x24,0x12,0x9,0x22, +0x60,0xf2,0x89,0x20,0x3e,0x47,0x34,0x12,0x39,0x3e,0x42,0x12,0x88,0x20,0x2,0x48, +0x24,0x12,0x41,0x2,0x42,0x12,0x89,0x20,0x22,0x49,0x24,0x12,0x49,0x22,0x7c,0xf6, +0x78,0x20,0x1e,0xcf,0xe3,0x11,0x79,0x1e,0x0,0x0,0x8,0x0,0x0,0x40,0x0,0x0, +0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_FULHEIGHT_WIDTH 58 +#define OM_SSET_FULHEIGHT_HEIGHT 17 +const unsigned char OM_SSET_FULHEIGHT [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e,0x80,0x4,0x1,0x40,0x0,0x1,0x0, +0x2,0x80,0x4,0x1,0x0,0x0,0x81,0x0,0x2,0x80,0x4,0x1,0x0,0x0,0x81,0x0, +0x2,0x91,0x4,0x9b,0x47,0x3e,0x9b,0x1,0x3e,0x91,0x4,0x91,0x48,0x22,0x91,0x0, +0x2,0x91,0x4,0x91,0x4f,0x21,0x91,0x0,0x2,0x91,0x4,0x91,0x40,0x21,0x91,0x0, +0x2,0x99,0x4,0x91,0x48,0x32,0x91,0x0,0x2,0x9f,0x4,0x91,0x47,0x3e,0x91,0x1, +0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_F50FREQ60_WIDTH 163 +#define OM_SSET_F50FREQ60_HEIGHT 17 +const unsigned char OM_SSET_F50FREQ60 [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e, +0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x1,0x20,0x0, +0xe0,0x83,0x21,0x0,0x2,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0xb0, +0x78,0x4,0x1,0x10,0x0,0x20,0x86,0x21,0x0,0x2,0x0,0x0,0x0,0x8,0x0,0x0, +0x0,0x0,0x0,0x0,0x10,0x89,0x4,0x1,0x10,0x0,0x20,0x84,0x23,0x0,0x2,0x8f, +0x7b,0x1e,0xd8,0x3d,0x3e,0x91,0xc7,0xe6,0x4d,0x10,0x88,0x4,0x79,0xb0,0xc7,0x21, +0x44,0x22,0x0,0x3e,0x91,0x8,0x22,0x48,0x44,0x22,0x91,0x48,0x24,0x48,0xf0,0x88, +0xfc,0x61,0x90,0x48,0xe0,0x47,0x22,0x0,0x82,0x91,0x4,0x3e,0x48,0x7c,0x21,0x91, +0x4f,0x14,0x48,0x10,0x89,0x4,0x21,0xd0,0x48,0x20,0xe0,0x27,0x0,0x2,0x91,0x4, +0x2,0x48,0x4,0x21,0x91,0x40,0x14,0x30,0x10,0x89,0x4,0x11,0x90,0x48,0x20,0x60, +0x26,0x0,0x2,0x91,0xc8,0x22,0x48,0x44,0x22,0x99,0x48,0x24,0x33,0x10,0x89,0x4, +0x9,0x90,0x48,0x20,0x20,0x24,0x0,0x2,0x8f,0x78,0x1e,0x48,0x3c,0x3e,0x9f,0x47, +0xe4,0x31,0xf0,0x70,0x4,0x7d,0x90,0x47,0x20,0x30,0xec,0x3,0x0,0x0,0x0,0x0, +0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0, +0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_FTL_WIDTH 92 +#define OM_SSET_FTL_HEIGHT 15 +const unsigned char OM_SSET_FTL [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0x0,0xf8,0xb,0x0,0x0,0x4,0x0,0x40,0x0, +0x2,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x4,0x0,0x40,0x0,0x2,0x0,0x0,0x0, +0x40,0x0,0x0,0x0,0x4,0x0,0x40,0x0,0x2,0xb7,0xd8,0xe7,0x41,0xc8,0x3e,0xf, +0x4,0x1e,0x4f,0x2,0x3e,0x1,0xc9,0x24,0x42,0x48,0x26,0x11,0x4,0x22,0x41,0x1, +0x2,0xc1,0xc9,0xe4,0x43,0x48,0x26,0x1f,0x4,0xa3,0xc0,0x1,0x2,0x11,0xc9,0x24, +0x40,0x48,0x26,0x1,0x4,0xa2,0x40,0x1,0x2,0x91,0xc9,0x24,0x42,0x48,0x26,0x11, +0x4,0x22,0x59,0x2,0x2,0xf1,0xc9,0xe4,0x41,0x48,0x26,0xf,0x7c,0x1e,0x4f,0x6, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_FTLMETHOD_WIDTH 174 +#define OM_SSET_FTLMETHOD_HEIGHT 15 +const unsigned char OM_SSET_FTLMETHOD [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x3c,0x0,0x4,0x40,0x0,0x3f,0x0,0x0,0x0,0xfc,0x5,0x0,0x0,0x2, +0x0,0x20,0x40,0x20,0x0,0x4,0x0,0x10,0x66,0x0,0x20,0x40,0x0,0x1,0x0,0x0, +0x0,0x20,0x0,0x0,0x0,0x2,0x0,0x20,0xc0,0x30,0x80,0x4,0x0,0x10,0x42,0x0, +0x20,0x40,0x0,0x1,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x2,0x0,0x20,0xc0,0x30, +0x80,0x4,0x0,0x10,0x6,0x99,0x64,0xcf,0x6,0x81,0x5b,0xec,0xf3,0x20,0x64,0x9f, +0x7,0x2,0x8f,0x27,0x41,0x29,0x8f,0x6d,0x1e,0x1f,0x3c,0x9a,0x24,0x41,0x4,0x9f, +0x80,0x64,0x12,0x21,0x24,0x93,0x8,0x2,0x91,0xa0,0x40,0x29,0x91,0x44,0x22,0x11, +0x60,0xaa,0xa4,0x40,0x4,0x81,0xe0,0x64,0xf2,0x21,0x24,0x93,0xf,0x82,0x51,0xe0, +0x40,0x29,0x9f,0x44,0xa3,0x10,0x42,0x6a,0xa4,0x40,0x4,0x81,0x88,0x64,0x12,0x20, +0x24,0x93,0x0,0x2,0x51,0xa0,0x40,0x22,0x81,0x44,0xa2,0x10,0x42,0x66,0x24,0x59, +0x4,0x81,0xc8,0x64,0x12,0x21,0x24,0x93,0x8,0x2,0x91,0x2c,0x41,0x26,0x91,0x44, +0x22,0x11,0x7c,0x64,0x64,0x4f,0x4,0x81,0xf8,0x64,0xf2,0x20,0x24,0x93,0x7,0x3e, +0x8f,0x27,0x43,0x26,0x8f,0x45,0x1e,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SSET_DEINT_BOB_MAD_WIDTH 112 +#define OM_SSET_DEINT_BOB_MAD_HEIGHT 17 +const unsigned char OM_SSET_DEINT_BOB_MAD [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x4,0x40,0x0,0x1f, +0x0,0x1,0x0,0x0,0x1,0x0,0x1,0x0,0x66,0x0,0x20,0x40,0x0,0x31,0x0,0x0, +0x4,0x0,0x1,0x0,0x0,0x0,0x42,0x0,0x20,0x40,0x0,0x61,0x0,0x0,0x4,0x0, +0x1,0x0,0x0,0x0,0x6,0x99,0x64,0xcf,0x6,0x41,0x1e,0xd9,0xec,0x71,0x59,0x3c, +0xd9,0x7c,0x3c,0x9a,0x24,0x41,0x4,0x41,0x22,0x89,0x24,0x12,0x81,0x4,0x89,0x44, +0x60,0xaa,0xa4,0x40,0x4,0x41,0x3e,0x89,0xe4,0x13,0xe1,0x2,0x89,0x42,0x42,0x6a, +0xa4,0x40,0x4,0x41,0x2,0x89,0x24,0x10,0x89,0x2,0x89,0x42,0x42,0x66,0x24,0x59, +0x4,0x21,0x22,0x89,0x24,0x12,0xc9,0x64,0x89,0x64,0x7c,0x64,0x64,0x4f,0x4,0x1f, +0x1e,0x89,0xec,0x11,0xf9,0x3c,0x89,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x24,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_ENABLED_WIDTH 46 +#define OM_ENABLED_HEIGHT 15 +const unsigned char OM_ENABLED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x7e,0x0,0x0,0x40,0x0,0x10,0x2,0x0,0x80,0x40,0x0,0x10,0x2,0x0, +0x80,0x40,0x0,0x10,0x2,0x36,0x8b,0x4f,0x1e,0x1f,0x7e,0x22,0x90,0x48,0x22,0x11, +0x2,0x22,0x9c,0x48,0xbe,0x10,0x2,0x22,0x91,0x48,0x82,0x10,0x2,0x22,0x99,0x48, +0x22,0x11,0x7e,0x22,0x9f,0x47,0x1e,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_DISABLED_WIDTH 49 +#define OM_DISABLED_HEIGHT 15 +const unsigned char OM_DISABLED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x3e,0x4,0x0,0x0,0x2,0x80,0x0,0x62,0x0,0x0,0x4, +0x2,0x80,0x0,0xc2,0x0,0x0,0x4,0x2,0x80,0x0,0x82,0xe4,0x59,0x7c,0xf2,0xf8, +0x0,0x82,0x24,0x80,0x44,0x12,0x89,0x0,0x82,0xe4,0xe0,0x44,0xf2,0x85,0x0,0x82, +0x4,0x89,0x44,0x12,0x84,0x0,0x42,0x24,0xc9,0x44,0x12,0x89,0x0,0x3e,0xe4,0xf9, +0x3c,0xf2,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_BOB_ENABLED_WIDTH 70 +#define OM_BOB_ENABLED_HEIGHT 15 +const unsigned char OM_BOB_ENABLED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, +0x0,0x40,0x0,0x10,0x62,0x0,0x1,0x0,0x0,0x80,0x40,0x0,0x10,0x42,0x0,0x1, +0x0,0x0,0x80,0x40,0x0,0x10,0x42,0x1e,0x1f,0x3c,0x36,0x8b,0x4f,0x1e,0x1f,0x3e, +0x22,0x11,0x44,0x22,0x90,0x48,0x22,0x11,0x42,0x23,0x11,0x7c,0x22,0x9c,0x48,0xbe, +0x10,0x42,0x22,0x11,0x4,0x22,0x91,0x48,0x82,0x10,0x42,0x22,0x11,0x44,0x22,0x99, +0x48,0x22,0x11,0x3e,0x1e,0xf,0x3c,0x22,0x9f,0x47,0x1e,0x1f,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_MAD_ENABLED_WIDTH 136 +#define OM_MAD_ENABLED_HEIGHT 17 +const unsigned char OM_MAD_ENABLED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x2,0x1,0x20,0x0,0x0,0x18,0x20,0x0,0x0,0x2,0x0,0x0,0x0, +0x0,0x0,0x1,0x40,0x86,0x1,0x4,0x0,0x0,0x18,0x20,0x0,0x40,0x0,0x0,0x0, +0x0,0x0,0x2,0x1,0x40,0x86,0x1,0x4,0x0,0x0,0x38,0x20,0x0,0x40,0x0,0x0, +0x0,0x0,0x0,0x2,0x1,0x40,0x4a,0x79,0x2c,0x8f,0xd,0x24,0x3e,0x8b,0xc7,0x9a, +0x3d,0xf0,0xd8,0x2c,0x3e,0x79,0x7c,0x4a,0x89,0x24,0x91,0x8,0x24,0x22,0x90,0x48, +0x92,0x44,0x10,0x89,0x40,0x22,0x89,0x44,0x4a,0x8d,0xa4,0x91,0x8,0x7e,0x21,0x9c, +0x48,0x92,0x7c,0xf0,0x89,0x70,0x22,0xf9,0x42,0x12,0x89,0x24,0x91,0x8,0x66,0x21, +0x91,0x48,0x52,0x4,0x10,0x88,0x44,0x22,0x9,0x42,0x32,0x89,0x24,0x91,0x8,0x42, +0x22,0x99,0x48,0x62,0x44,0x10,0x89,0x64,0x22,0x89,0x44,0x32,0x79,0x2c,0x8f,0x8, +0xc3,0x3e,0x9f,0xc7,0x62,0x3c,0xf0,0x88,0x7c,0x1e,0x79,0x7c,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0, + +}; + +#define OM_FTL_METHOD_0_WIDTH 74 +#define OM_FTL_METHOD_0_HEIGHT 15 +const unsigned char OM_FTL_METHOD_0 [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x8,0x0,0x8,0xf0,0xf0,0xfc,0x1,0x80,0x0,0x2,0x8,0x0,0x8,0x99,0x99, +0x21,0x0,0x80,0x0,0x2,0x8,0x0,0x8,0x9,0x9,0x21,0x0,0xb3,0x3d,0xb6,0x8, +0x8,0x90,0x19,0x18,0x20,0x0,0x92,0x44,0x2,0x9,0x8,0x90,0xf0,0xf0,0x20,0x0, +0x92,0x46,0xc2,0x9,0x8,0x90,0x80,0x81,0x21,0x0,0x8a,0x44,0x12,0x9,0x3e,0xe0, +0x8,0x9,0x21,0x0,0x8c,0x44,0x92,0x9,0x8,0x60,0x8,0x9,0x21,0x0,0x8c,0x3d, +0xf6,0x9,0x8,0x60,0xf0,0xf1,0x21,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_FTL_METHOD_1_WIDTH 55 +#define OM_FTL_METHOD_1_HEIGHT 17 +const unsigned char OM_FTL_METHOD_1 [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x80,0x0,0x80,0x0,0x2,0x8, +0x0,0x80,0x0,0x80,0x0,0x2,0x8,0x0,0x80,0x0,0xb3,0x3d,0xb6,0x8,0x1e,0x9b, +0x26,0x92,0x44,0x2,0x9,0x22,0x91,0x24,0x92,0x46,0xc2,0x9,0x23,0x91,0x24,0x8a, +0x44,0x12,0x9,0x22,0x91,0x18,0x8c,0x44,0x92,0x9,0x22,0x91,0x18,0x8c,0x3d,0xf6, +0x9,0x1e,0x91,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0, +0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_SYSTEM_PARAMETERS_WIDTH 105 +#define OM_SYSTEM_PARAMETERS_HEIGHT 17 +const unsigned char OM_SYSTEM_PARAMETERS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x66,0x0,0x20,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x40,0x0,0x0,0x0,0x42,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40,0x0,0x0,0x0,0x6,0x93,0x67,0x8f,0x7d,0xf0,0x58,0xdc,0x62,0x9f,0xc7,0x1e, +0xf7,0x0,0x3c,0x92,0x20,0x91,0x4c,0x10,0x81,0x4,0x24,0x93,0x48,0x22,0x11,0x0, +0x60,0x92,0x23,0x9f,0x4c,0x10,0xe1,0x4,0x27,0x93,0x4f,0x3e,0x71,0x0,0x42,0xc, +0x24,0x81,0x4c,0x10,0x89,0x44,0x24,0x93,0x40,0x2,0x81,0x0,0x42,0x8c,0x24,0x91, +0x4c,0x10,0xc9,0x44,0x26,0x93,0x48,0x22,0x91,0x0,0x7c,0x8c,0x67,0x8f,0x4c,0xf0, +0xf8,0xc4,0x27,0x93,0xc7,0x1e,0xf1,0x0,0x0,0x4,0x0,0x0,0x0,0x10,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_CPRM_UPSCALE_WIDTH 161 +#define OM_CPRM_UPSCALE_HEIGHT 17 +const unsigned char OM_CPRM_UPSCALE [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x82, +0x0,0x0,0x0,0x90,0x0,0x0,0x10,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x40,0x0, +0x8,0x0,0x0,0x0,0x82,0x0,0x0,0x0,0x10,0x0,0x0,0x8,0x0,0x10,0x0,0x0, +0x0,0x0,0x0,0x40,0x0,0x1,0x0,0x0,0x0,0x82,0x0,0x0,0x0,0x10,0x0,0x0, +0x8,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x1,0x0,0x0,0x0,0x82,0x3c, +0x9e,0x67,0x91,0x6c,0x3e,0xd8,0xe3,0x10,0x78,0x32,0xc1,0x3d,0x9e,0x47,0x22,0xcb, +0x63,0xf3,0x0,0x82,0x44,0x82,0x0,0x92,0x44,0x22,0x48,0x24,0x10,0x88,0x34,0x41, +0x44,0x82,0x48,0x22,0x49,0x24,0x12,0x0,0x82,0x44,0x4e,0x80,0x93,0x44,0x21,0x68, +0x24,0x10,0x8c,0x54,0x41,0x7c,0xce,0x48,0x22,0x69,0x24,0x72,0x0,0x82,0x44,0x50, +0x20,0x92,0x44,0x21,0x48,0x24,0x10,0x88,0xd4,0x40,0x4,0x90,0x48,0x22,0x49,0x24, +0x82,0x0,0x46,0x44,0x92,0x2c,0x93,0x44,0x32,0x48,0x24,0x10,0x88,0xcc,0x40,0x44, +0x92,0x48,0x32,0x49,0x24,0x92,0x0,0x7c,0x3c,0x9e,0xe7,0x93,0x44,0x3e,0xc8,0x23, +0xf0,0x79,0xc8,0x40,0x3c,0x9e,0x47,0x3e,0xcb,0x23,0xf2,0x0,0x0,0x4,0x0,0x0, +0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_CPRM_FORCECOMPOSITE_WIDTH 195 +#define OM_CPRM_FORCECOMPOSITE_HEIGHT 17 +const unsigned char OM_CPRM_FORCECOMPOSITE [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0xe0,0x3,0x8f,0x8f,0x20,0x1,0xe0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x4,0x1,0x20,0x8c, +0x98,0x98,0x20,0x21,0x12,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x0,0x0, +0x0,0x0,0x0,0x2,0x0,0x4,0x1,0x20,0x48,0x90,0x90,0x20,0x21,0xa,0x2,0x0, +0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x8f,0x7b,0x1e,0x78,0x44,0xf6,0x88,0xc,0x7b, +0x20,0x4c,0x80,0x90,0x20,0x32,0x8,0xf0,0xd8,0xe7,0xf1,0xd8,0x3c,0x36,0x3,0x3e, +0x91,0x8,0x22,0x88,0x44,0x12,0x89,0x4,0x89,0xe0,0x47,0x9c,0x8f,0x3f,0x12,0x9, +0x10,0xc9,0x24,0x12,0x89,0x44,0x22,0x1,0x82,0x91,0x4,0x3e,0x8c,0x44,0x12,0x89, +0x4,0x8d,0x20,0x44,0xb0,0x90,0x20,0x12,0x9,0x18,0xc9,0x24,0x1a,0x89,0x7c,0x22, +0x1,0x2,0x91,0x4,0x2,0x88,0x44,0x12,0x89,0x4,0x89,0x20,0x48,0xb0,0x90,0x20, +0x1c,0x8,0x12,0xc9,0x24,0x12,0x89,0x4,0x22,0x1,0x2,0x91,0xc8,0x22,0x88,0x64, +0x12,0xc9,0x4,0x89,0x20,0xc8,0xb0,0x90,0x20,0x8c,0x18,0x13,0xc9,0x24,0x12,0x89, +0x44,0x22,0x1,0x2,0x8f,0x78,0x1e,0x78,0x7c,0xf6,0xf8,0xc,0x7b,0x20,0x88,0xaf, +0x8f,0x20,0x8c,0xf0,0xf1,0xc8,0xe4,0xf1,0x88,0x3c,0x22,0x3,0x0,0x0,0x0,0x0, +0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_CPRM_DISEXTCLK_WIDTH 137 +#define OM_CPRM_DISEXTCLK_HEIGHT 15 +const unsigned char OM_CPRM_DISEXTCLK [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0x0,0x0,0x8,0x38,0x4,0x0,0x4, +0xe0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x80,0x0,0x0,0x0,0x8,0x44,0x4, +0x0,0x4,0x10,0x3,0x0,0x0,0x0,0x10,0x0,0x0,0x2,0x80,0x0,0x0,0x0,0x8, +0x82,0x4,0x0,0x4,0x8,0x2,0x0,0x0,0x0,0x10,0x0,0x0,0x2,0x92,0x3d,0x6e, +0xb3,0x8,0x2,0xe4,0xf1,0x24,0x8,0xf0,0xd8,0x3c,0x6e,0xb1,0xc7,0x1,0x7e,0x8c, +0x44,0x22,0x2,0x9,0x2,0x24,0x12,0x14,0x88,0x13,0x89,0x44,0x2,0x92,0x48,0x0, +0x2,0x8c,0x7c,0x22,0xc2,0x9,0x2,0x34,0xa,0x1c,0x8,0xf6,0x89,0x7c,0x82,0xd3, +0x48,0x0,0x2,0x8c,0x4,0x22,0x12,0x9,0x82,0x24,0xa,0x14,0x8,0x16,0x88,0x4, +0x22,0x92,0x48,0x0,0x2,0x92,0x44,0x22,0x92,0x9,0xc6,0x24,0x92,0x25,0x18,0x16, +0x89,0x44,0x22,0x93,0x48,0x0,0x7e,0x92,0x3d,0x22,0xf2,0x9,0x7c,0xe4,0xf1,0x64, +0xf0,0xf5,0x88,0x3c,0xe2,0xb3,0x47,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_CPRM_ADCCALIBR_WIDTH 86 +#define OM_CPRM_ADCCALIBR_HEIGHT 15 +const unsigned char OM_CPRM_ADCCALIBR [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x18,0x3e,0x70,0x0,0x0,0x48,0x0,0x0,0x40,0x0,0x0,0x18,0x62,0x88,0x0, +0x0,0x8,0x2,0x0,0x8,0x0,0x0,0x38,0xc2,0x4,0x1,0x0,0x8,0x2,0x0,0x8, +0x0,0x0,0x24,0x82,0x4,0xc0,0xb3,0x48,0x3e,0xb7,0x58,0x1e,0x1b,0x24,0x82,0x4, +0x40,0x0,0x49,0x22,0x1,0x49,0x22,0x11,0x7e,0x82,0x4,0x20,0xc0,0x49,0x22,0xc1, +0x49,0x23,0x11,0x66,0x82,0x4,0x21,0x10,0x49,0x22,0x11,0x49,0x22,0x11,0x42,0x42, +0x8c,0x41,0x96,0x49,0x22,0x91,0x49,0x22,0x11,0xc3,0x3e,0xf8,0xc0,0xf3,0x49,0x1e, +0xf1,0x59,0x1e,0x11,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_RESET_RESTORE_WIDTH 84 +#define OM_RESET_RESTORE_HEIGHT 15 +const unsigned char OM_RESET_RESTORE [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x3e,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0xc2,0x0,0x0,0x40, +0x20,0x84,0x1,0x0,0x1,0x0,0x0,0x82,0x0,0x0,0x40,0x20,0x4,0x1,0x0,0x1, +0x0,0x0,0xc2,0x3c,0x9e,0xc7,0x0,0x84,0x79,0x3c,0x7b,0xdc,0x3,0x7e,0x44,0x82, +0x48,0x10,0xfc,0x88,0x4,0x89,0x44,0x4,0x42,0x7c,0x8e,0x4f,0x10,0x84,0xf8,0x1c, +0x8d,0xc4,0x7,0x82,0x4,0x90,0x40,0x0,0x4,0x9,0x20,0x89,0x44,0x0,0x82,0x44, +0x92,0x48,0x8,0x4,0x89,0x24,0x89,0x44,0x4,0x82,0x3c,0x9e,0xc7,0x8,0x4,0x79, +0x3c,0x7b,0xc4,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_RESET_GBS_WIDTH 78 +#define OM_RESET_GBS_HEIGHT 15 +const unsigned char OM_RESET_GBS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0, +0x0,0x0,0x0,0x80,0x0,0x80,0x0,0x0,0xc2,0x0,0x80,0x0,0x20,0x80,0x0,0x0, +0x0,0x0,0x82,0x0,0x80,0x0,0x20,0x80,0x0,0x0,0x0,0x0,0xc2,0x3c,0x9e,0x2d, +0x6e,0xf8,0x3c,0xb3,0x3c,0xf,0x7e,0x44,0x82,0x40,0x22,0x88,0x44,0x92,0x4,0x11, +0x42,0x7c,0x8e,0x70,0x22,0x84,0x7c,0x92,0x2,0x1f,0x82,0x4,0x90,0x44,0x22,0x84, +0x4,0x8a,0x2,0x1,0x82,0x44,0x92,0x64,0x22,0x88,0x44,0x8c,0x64,0x11,0x82,0x3c, +0x9e,0x7d,0x62,0xf8,0x3c,0x8c,0x3c,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_RESET_WIFI_WIDTH 104 +#define OM_RESET_WIFI_HEIGHT 17 +const unsigned char OM_RESET_WIFI [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0xa1,0xfc,0x2,0x0, +0x0,0x4,0x0,0x0,0xc2,0x0,0x0,0x40,0x10,0x23,0x4,0x0,0x0,0x90,0x0,0x0, +0x0,0x82,0x0,0x0,0x40,0x90,0x33,0x4,0x0,0x0,0x90,0x0,0x0,0x0,0xc2,0x3c, +0x9e,0xc7,0x90,0x92,0x4,0x82,0xe7,0xb1,0x65,0xf3,0x79,0x7e,0x44,0x82,0x48,0x90, +0x92,0x7c,0x82,0x20,0x92,0x24,0x12,0x9,0x42,0x7c,0x8e,0x4f,0xa0,0x94,0x4,0x82, +0xe3,0x93,0x24,0xa,0x39,0x82,0x4,0x90,0x40,0x60,0x9c,0x4,0x2,0x24,0x90,0x24, +0xa,0x41,0x82,0x44,0x92,0x48,0x60,0x8c,0x4,0x82,0x24,0x92,0x24,0x92,0x49,0x82, +0x3c,0x9e,0xc7,0x60,0x88,0x4,0x82,0xe7,0xb1,0x25,0xf2,0x79,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x90,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_RESTORE_FACTORY_WIDTH 86 +#define OM_RESTORE_FACTORY_HEIGHT 17 +const unsigned char OM_RESTORE_FACTORY [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x3e,0x0,0x0,0x0,0x0,0x80,0x1f,0x0,0x0,0x0,0x0,0xc2,0x0,0x80,0x0, +0x0,0x80,0x0,0x0,0x8,0x0,0x0,0x82,0x0,0x80,0x0,0x0,0x80,0x0,0x0,0x8, +0x0,0x0,0xc2,0x3c,0x9e,0x3d,0xee,0x81,0xc0,0xe2,0xd9,0xe3,0x13,0x7e,0x44,0x82, +0x44,0x22,0x82,0xf,0x24,0x48,0x24,0x12,0x42,0x7c,0x8e,0x46,0xe2,0x83,0x0,0x17, +0x68,0x24,0x12,0x82,0x4,0x90,0x44,0x22,0x80,0x40,0x14,0x48,0x24,0xc,0x82,0x44, +0x92,0x44,0x22,0x82,0x40,0x26,0x4b,0x24,0xc,0x82,0x3c,0x9e,0x3d,0xe2,0x81,0xc0, +0xe7,0xd9,0x23,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_CURRENT_WIDTH 71 +#define OM_CURRENT_HEIGHT 17 +const unsigned char OM_CURRENT [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0xc4,0x0,0x2,0x0,0x4,0x40,0x0,0x1,0x0,0x82,0x0,0x2, +0x0,0x4,0x40,0x0,0x1,0x0,0x2,0x45,0xf6,0x88,0xc,0xcf,0x16,0x8b,0x3c,0x3, +0x45,0x12,0x89,0x4,0x41,0x20,0x89,0x4,0x2,0x45,0x12,0x89,0x4,0x47,0x38,0x89, +0x1c,0x82,0x45,0x12,0x89,0x4,0x48,0x22,0x89,0x20,0x86,0x64,0x12,0xc9,0x4,0x49, +0x32,0xc9,0x24,0x7c,0x7c,0xf6,0xf8,0xc,0xcf,0x3e,0xfb,0x3c,0x0,0x0,0x10,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_WIFI_WIDTH 47 +#define OM_WIFI_HEIGHT 15 +const unsigned char OM_WIFI [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x20,0x94,0x5f,0x10,0x80,0x0,0x62,0x84,0x0,0x10,0x40,0x0,0x72,0x86, +0x0,0x10,0x40,0x0,0x52,0x92,0x40,0x90,0xcd,0x1e,0x52,0x92,0x4f,0x90,0x48,0x22, +0x94,0x92,0x40,0x90,0x48,0x23,0x8c,0x93,0x40,0x90,0x48,0x22,0x8c,0x91,0x40,0x90, +0x48,0x22,0xc,0x91,0x40,0x90,0x48,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_NO_PRESETS_WIDTH 287 +#define TEXT_NO_PRESETS_HEIGHT 15 +const unsigned char TEXT_NO_PRESETS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x0,0xf0,0x1, +0x0,0x0,0x0,0x0,0xf8,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x8, +0x1,0x0,0x8,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa0,0x0,0x0, +0x86,0x0,0x10,0x3,0x0,0x0,0x10,0x0,0x88,0x9,0x0,0x0,0x0,0x0,0x0,0x0, +0x48,0x0,0x80,0x18,0x1,0x2,0x8,0x12,0x4,0x0,0x0,0x0,0x80,0x0,0x0,0x0, +0x0,0x10,0x0,0x10,0x8e,0x0,0x10,0x2,0x0,0x0,0x10,0x0,0x8,0x9,0x0,0x0, +0x0,0x0,0x0,0x0,0x48,0x0,0x80,0x9c,0x1,0x2,0x8,0x12,0x4,0x0,0x0,0x0, +0x80,0x0,0x0,0x0,0x0,0x10,0x0,0x10,0x8a,0x3c,0x10,0x72,0x8f,0xe7,0xb1,0x7, +0x8,0xc9,0x63,0xf1,0x3c,0x10,0x79,0x1e,0xd8,0xe6,0x81,0x94,0x3c,0x3e,0x8,0x12, +0xec,0x81,0xe7,0x1e,0x8b,0x3d,0xf0,0xd8,0x3c,0xb0,0xdc,0x33,0x92,0x44,0xf0,0x13, +0x91,0x20,0x92,0x0,0xf8,0x49,0x4,0x12,0x44,0x10,0x9,0x22,0x48,0x24,0x82,0x94, +0x44,0x22,0x8,0x12,0x24,0x82,0x20,0x22,0x90,0x44,0x10,0x89,0x44,0x90,0x44,0x10, +0x92,0x46,0x10,0x10,0x9f,0xe3,0x93,0x3,0x8,0xc8,0x87,0x73,0x7c,0x10,0x39,0x3e, +0x48,0xe4,0x3,0xa5,0x7c,0x22,0x8,0x12,0x34,0x42,0x20,0x3e,0x9c,0x7c,0x18,0x89, +0x7c,0x90,0xc4,0x11,0xa2,0x44,0x10,0x10,0x1,0x24,0x10,0x4,0x8,0x48,0x20,0x82, +0x4,0x10,0x41,0x2,0x48,0x24,0x0,0xe3,0x4,0x22,0x8,0x12,0x24,0x42,0x20,0x2, +0x91,0x4,0x10,0x89,0x4,0x90,0x4,0x12,0xc2,0x44,0x10,0x10,0x91,0x24,0x92,0x4, +0x8,0x48,0x24,0x93,0x44,0x90,0x49,0x22,0x48,0x24,0x2,0x63,0x44,0x22,0x18,0x11, +0x24,0x82,0x2c,0x22,0x99,0x44,0x10,0x89,0x44,0x90,0x44,0x12,0xc2,0x3c,0x10,0x10, +0x8f,0xe7,0xb1,0x27,0x8,0xc8,0xe3,0xf3,0x3c,0xf0,0x79,0x1e,0x58,0xe4,0x1,0x43, +0x3c,0x1e,0xf0,0x11,0xec,0x81,0x27,0x1e,0x9f,0x3d,0xf0,0x88,0x3c,0x90,0xc4,0x33, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_TOO_MANY_PRESETS_WIDTH 229 +#define TEXT_TOO_MANY_PRESETS_HEIGHT 17 +const unsigned char TEXT_TOO_MANY_PRESETS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x20, +0x4,0x0,0x4,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x62,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x62,0x4,0x8,0x4, +0x9,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20, +0x0,0x42,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x72,0x6,0x8,0x4,0x9,0x2,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x42,0xf2, +0x58,0x3c,0xf,0x44,0x9e,0x7,0x52,0xf2,0xf8,0x4,0x9,0xf6,0xc0,0xe2,0x79,0x1e, +0xcf,0x83,0x7d,0x1e,0xf7,0xc0,0xe3,0x1e,0xcf,0x63,0xf,0x7e,0x12,0x81,0x4,0x11, +0x44,0x82,0x8,0x52,0x12,0x89,0x4,0x9,0x12,0x1,0x24,0x8,0x22,0x41,0x80,0x4c, +0x22,0x11,0x41,0x24,0x22,0x41,0x24,0x1,0x2,0xf2,0xe1,0x1c,0x1f,0x44,0x8e,0xf, +0x94,0xf2,0x89,0x4,0x9,0x1a,0x1,0x17,0x4,0x3e,0xc7,0x81,0x4c,0x23,0xf1,0x41, +0x24,0x3e,0xc7,0x27,0x7,0x2,0x12,0x88,0x20,0x1,0x44,0x90,0x0,0x8c,0x13,0x88, +0x4,0x9,0x12,0x41,0x14,0x4,0x2,0x8,0x82,0x4c,0x22,0x11,0x40,0x24,0x2,0x48, +0x20,0x8,0x2,0x12,0xc9,0x24,0x11,0x64,0x92,0x8,0x8c,0x11,0x89,0x8c,0x8,0x12, +0x41,0x26,0xcb,0x22,0x49,0x82,0x4c,0x22,0x11,0x41,0x24,0x22,0x49,0x24,0x9,0x2, +0xf2,0xf8,0x3c,0xf,0x7c,0x9e,0x7,0xc,0xf1,0x78,0xf8,0x8,0xf6,0xc0,0xe7,0x79, +0x1e,0xcf,0x83,0x4c,0x1e,0xf1,0xc0,0x23,0x1e,0xcf,0x63,0xf,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_RESETTING_GBS_WIDTH 64 +#define TEXT_RESETTING_GBS_HEIGHT 46 +const unsigned char TEXT_RESETTING_GBS [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x3,0x0,0x0,0x0,0x10,0x0,0x0, +0x20,0xc,0x0,0x8,0x0,0x2,0x0,0x0,0x20,0x8,0x0,0x8,0x0,0x2,0x0,0x0, +0x20,0xcc,0xe3,0xd9,0xe2,0x96,0xcd,0x7,0xe0,0x47,0x24,0x8,0x24,0x92,0x48,0x4, +0x20,0xc4,0xe7,0x8,0x27,0x92,0x28,0x4,0x20,0x48,0x0,0x49,0x24,0x92,0x28,0x4, +0x20,0x48,0x24,0x49,0x26,0x92,0x48,0x6,0x20,0xc8,0xe3,0xd9,0x27,0x96,0xc8,0x7, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x2, +0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x2,0x0,0x0,0x0,0x0,0x0,0x4, +0x62,0x2,0x0,0x0,0x0,0x0,0x0,0x20,0x42,0x2,0x0,0x0,0x0,0x0,0x0,0x20, +0x42,0xf2,0x58,0x3c,0xf,0x32,0x59,0x64,0x7e,0x12,0x81,0x4,0x11,0x34,0x81,0x24, +0x2,0xf2,0xe1,0x1c,0x1f,0x54,0xe1,0x24,0x2,0x12,0x88,0x20,0x1,0xd4,0x88,0x24, +0x2,0x12,0xc9,0x24,0x11,0xcc,0xc8,0x24,0x2,0xf2,0xf8,0x3c,0xf,0xc8,0xf8,0x64, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x4,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_RESETTING_WIFI_WIDTH 79 +#define TEXT_RESETTING_WIFI_HEIGHT 46 +const unsigned char TEXT_RESETTING_WIFI [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0, +0x0,0x0,0x10,0x0,0x0,0x10,0xca,0x2f,0xc2,0x0,0x0,0x40,0x2,0x0,0x0,0x31, +0x42,0x0,0x82,0x0,0x0,0x40,0x2,0x0,0x0,0x39,0x43,0x0,0xc2,0x3c,0x9e,0xc7, +0x96,0xcd,0x7,0x29,0x49,0x20,0x7e,0x44,0x82,0x48,0x92,0x48,0x4,0x29,0xc9,0x27, +0x42,0x7c,0x8e,0x4f,0x92,0x28,0x4,0x4a,0x49,0x20,0x82,0x4,0x90,0x40,0x92,0x28, +0x4,0xc6,0x49,0x20,0x82,0x44,0x92,0x48,0x92,0x48,0x6,0xc6,0x48,0x20,0x82,0x3c, +0x9e,0xc7,0x96,0xc8,0x7,0x86,0x48,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x80,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e, +0x2,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x62,0x2,0x0,0x0,0x0,0x0,0x0, +0x20,0x0,0x0,0x42,0x2,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x42,0xf2,0x58, +0x3c,0xf,0x32,0x59,0x64,0x0,0x0,0x7e,0x12,0x81,0x4,0x11,0x34,0x81,0x24,0x0, +0x0,0x2,0xf2,0xe1,0x1c,0x1f,0x54,0xe1,0x24,0x0,0x0,0x2,0x12,0x88,0x20,0x1, +0xd4,0x88,0x24,0x0,0x0,0x2,0x12,0xc9,0x24,0x11,0xcc,0xc8,0x24,0x0,0x0,0x2, +0xf2,0xf8,0x3c,0xf,0xc8,0xf8,0x64,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x90,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_RESTORING_WIDTH 86 +#define TEXT_RESTORING_HEIGHT 46 +const unsigned char TEXT_RESTORING [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x7e,0x0,0x0,0x0,0x0,0xf0,0x1,0x0,0x0,0x0,0x0,0x2,0x0,0x20,0x0, +0x0,0x10,0x6,0x0,0x4,0x0,0x0,0x2,0x0,0x20,0x0,0x0,0x10,0x4,0x0,0x4, +0x0,0x0,0x2,0x8b,0x67,0x8f,0x4f,0x10,0xe6,0xf1,0xec,0x71,0xf,0x3e,0x90,0x20, +0x91,0x48,0xf0,0x23,0x12,0x24,0x12,0x11,0x2,0x5c,0xa0,0x91,0x48,0x10,0xe2,0x73, +0x34,0x12,0x1f,0x2,0x51,0x20,0x91,0x30,0x10,0x24,0x80,0x24,0x12,0x1,0x2,0x99, +0x2c,0x91,0x30,0x10,0x24,0x92,0x24,0x12,0x11,0x2,0x9f,0x67,0x8f,0x30,0x10,0xe4, +0xf1,0xec,0x11,0xf,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0xe0,0x23,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x26,0x0, +0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x20,0x24,0x0,0x0,0x0,0x0,0x0,0x0, +0x2,0x0,0x0,0x20,0x24,0x8f,0xc5,0xf3,0x20,0x93,0x45,0x6,0x0,0x0,0xe0,0x27, +0x11,0x48,0x10,0x41,0x13,0x48,0x2,0x0,0x0,0x20,0x20,0x1f,0xce,0xf1,0x41,0x15, +0x4e,0x2,0x0,0x0,0x20,0x20,0x81,0x8,0x12,0x40,0x8d,0x48,0x2,0x0,0x0,0x20, +0x20,0x91,0x4c,0x12,0xc1,0x8c,0x4c,0x2,0x0,0x0,0x20,0x20,0x8f,0xcf,0xf3,0x80, +0x8c,0x4f,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x49,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_WIFI_CONNECT_TO_WIDTH 360 +#define TEXT_WIFI_CONNECT_TO_HEIGHT 17 +const unsigned char TEXT_WIFI_CONNECT_TO [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4, +0x0,0x10,0x20,0x1,0x0,0x8,0x0,0x0,0xf,0x8f,0x7c,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x10,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x1,0x0,0x20, +0x4,0x0,0x20,0x48,0x44,0x0,0x0,0x0,0x0,0x10,0x4,0x80,0x4,0x0,0x8,0x20, +0x1,0x0,0x0,0x0,0x80,0x99,0x99,0xc4,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x90, +0x40,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x1,0x0,0x62,0x4,0x8,0x20, +0x48,0x82,0x0,0x0,0x0,0x0,0x10,0x4,0x80,0x4,0x0,0x8,0x20,0x1,0x0,0x0, +0x0,0x80,0x90,0x90,0x84,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x40,0x0,0x10, +0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x1,0x0,0x72,0x6,0x8,0x20,0x48,0x2,0x3c, +0x36,0x9b,0xc7,0x33,0xec,0x81,0x6d,0x1e,0xd8,0x23,0x79,0x32,0xc9,0xe6,0x83,0x81, +0x81,0x4,0x41,0x3c,0x16,0xcf,0xcb,0xe4,0x71,0x1f,0xc1,0xe7,0xb1,0xc7,0x3d,0x10, +0x79,0xb2,0xf9,0x60,0x9b,0x7,0x52,0xf2,0xf8,0x20,0x48,0x2,0x44,0x22,0x91,0x48, +0x10,0x24,0x82,0x44,0x22,0x48,0x24,0x89,0x34,0x49,0x24,0x2,0xf,0x8f,0x4,0x41, +0x44,0x20,0x41,0xd0,0x24,0x12,0x11,0x41,0x24,0x92,0x48,0x44,0x10,0x9,0x12,0x89, +0x20,0x91,0x8,0x52,0x12,0x89,0x20,0x48,0x2,0x46,0x22,0x91,0x2f,0x10,0x34,0x82, +0x44,0x3e,0x68,0x24,0x8d,0x54,0x49,0x14,0x2,0x18,0x98,0x4,0x41,0x44,0x38,0xc7, +0x51,0x35,0x92,0x10,0x41,0xe4,0xd3,0x48,0x7c,0x10,0x39,0x12,0x85,0x20,0x91,0xf, +0x94,0xf2,0x89,0x20,0x48,0x82,0x44,0x22,0x91,0x20,0x10,0x24,0x82,0x44,0x2,0x48, +0x24,0x89,0xd4,0x48,0x14,0x82,0x90,0x90,0x4,0x41,0x44,0x22,0x8,0x52,0x23,0x92, +0x10,0x41,0x24,0x90,0x48,0x4,0x10,0x41,0x12,0x85,0x20,0x91,0x0,0x8c,0x13,0x88, +0x20,0x48,0xc6,0x44,0x22,0x91,0x48,0x16,0x24,0x82,0x44,0x22,0x48,0x24,0x89,0xcc, +0x48,0x24,0x83,0x90,0x90,0x84,0x40,0x44,0x32,0x49,0x32,0x23,0x12,0x11,0x41,0x24, +0x92,0x48,0x44,0x90,0x49,0x12,0xc9,0x20,0x91,0x8,0x8c,0x11,0x89,0x60,0x44,0x7c, +0x3c,0x22,0x91,0xc7,0x33,0xec,0x81,0x45,0x1e,0xc8,0x23,0x79,0xc8,0x48,0xe4,0x3, +0x1f,0x9f,0x7c,0x40,0x3c,0x3e,0xcf,0x23,0xe3,0x11,0x1f,0xc1,0xe3,0x91,0x47,0x3c, +0xf0,0x79,0x12,0xf9,0x60,0x91,0x7,0xc,0xf1,0x78,0xc0,0x47,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0, +0x80,0x4,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x1,0x0,0x0,0x0,0x80,0x4,0x0, +0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x48,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_WIFI_CONNECTED_WIDTH 100 +#define TEXT_WIFI_CONNECTED_HEIGHT 15 +const unsigned char TEXT_WIFI_CONNECTED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0, +0x0,0x0,0x0,0x4,0x66,0x2,0x8,0x0,0x0,0x44,0x0,0x0,0x0,0x0,0x10,0x0, +0x4,0x42,0x2,0x8,0x0,0x0,0x82,0x0,0x0,0x0,0x0,0x10,0x0,0x4,0x6,0xb6, +0x58,0xe4,0x19,0x2,0x3c,0x36,0x9b,0xc7,0xb3,0xc7,0x7,0x3c,0x2,0x49,0x24,0x0, +0x2,0x44,0x22,0x91,0x48,0x90,0x48,0x4,0x60,0xc2,0x49,0xe4,0x0,0x2,0x46,0x22, +0x91,0x2f,0x90,0x2f,0x4,0x42,0x12,0x49,0x4,0x1,0x82,0x44,0x22,0x91,0x20,0x90, +0x20,0x4,0x42,0x92,0x49,0x26,0x1,0xc6,0x44,0x22,0x91,0x48,0x96,0x48,0x4,0x7c, +0xf6,0xd9,0xe7,0x19,0x7c,0x3c,0x22,0x91,0xc7,0xb3,0xc7,0x7,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0, + +}; + +#define TEXT_WIFI_DISCONNECTED_WIDTH 115 +#define TEXT_WIFI_DISCONNECTED_HEIGHT 15 +const unsigned char TEXT_WIFI_DISCONNECTED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0, +0x0,0x0,0x3e,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x66,0x2,0x8,0x0, +0x0,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x2,0x42,0x2,0x8,0x0,0x0, +0xc2,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x2,0x6,0xb6,0x58,0xe4,0x19,0x82, +0xe4,0x79,0x1e,0x9b,0xcd,0xe3,0xd9,0xe3,0x3,0x3c,0x2,0x49,0x24,0x0,0x82,0x24, +0x8,0x22,0x91,0x48,0x24,0x48,0x24,0x2,0x60,0xc2,0x49,0xe4,0x0,0x82,0xe4,0x4, +0x23,0x91,0xc8,0x17,0xc8,0x17,0x2,0x42,0x12,0x49,0x4,0x1,0x82,0x4,0x5,0x22, +0x91,0x48,0x10,0x48,0x10,0x2,0x42,0x92,0x49,0x26,0x1,0x42,0x24,0xc9,0x22,0x91, +0x48,0x24,0x4b,0x24,0x2,0x7c,0xf6,0xd9,0xe7,0x19,0x3e,0xe4,0x79,0x1e,0x91,0xc8, +0xe3,0xd9,0xe3,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0, + +}; + +#define TEXT_WIFI_URL_WIDTH 264 +#define TEXT_WIFI_URL_HEIGHT 17 +const unsigned char TEXT_WIFI_URL [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x4,0x0,0x10,0x20,0x1, +0x0,0x8,0x0,0x80,0x20,0x1f,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x20, +0x4,0x0,0x20,0x48,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x4,0x0,0x8,0x20, +0x1,0x0,0x0,0x0,0x80,0x20,0x61,0x2,0x0,0x2,0x0,0x0,0x0,0x20,0x1,0x0, +0x62,0x4,0x8,0x20,0x48,0x82,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x4,0x0,0x8, +0x20,0x1,0x0,0x0,0x0,0x80,0x20,0x41,0x2,0x0,0x2,0x0,0x0,0x0,0x20,0x1, +0x0,0x72,0x6,0x8,0x20,0x48,0x82,0x3c,0xf,0x3c,0x36,0xf,0x3c,0x86,0x6d,0x1e, +0xd8,0x23,0x79,0x32,0xc9,0xe6,0x83,0x20,0x61,0x2,0xf,0xf6,0x40,0xe4,0x79,0x60, +0x9b,0x7,0x52,0xf2,0xf8,0x20,0x48,0x82,0x4,0x11,0x44,0x22,0x11,0x44,0x82,0x44, +0x22,0x48,0x24,0x89,0x34,0x49,0x24,0x82,0x20,0x3f,0x2,0x1,0x12,0x41,0x24,0x88, +0x20,0x91,0x8,0x52,0x12,0x89,0x20,0x48,0x82,0x1c,0x1f,0x46,0x22,0x1f,0x46,0x82, +0x44,0x3e,0x68,0x24,0x8d,0x54,0x49,0x14,0x82,0x20,0x21,0x2,0x7,0x1a,0x41,0xe4, +0xf8,0x20,0x91,0xf,0x94,0xf2,0x89,0x20,0x48,0x82,0x20,0x1,0x44,0x22,0x1,0x44, +0x82,0x44,0x2,0x48,0x24,0x89,0xd4,0x48,0x14,0x82,0x20,0x41,0x2,0x8,0x12,0x41, +0x4,0x9,0x20,0x91,0x0,0x8c,0x13,0x88,0x20,0x48,0x46,0x24,0x11,0x44,0x22,0x11, +0x44,0x82,0x44,0x22,0x48,0x24,0x89,0xcc,0x48,0x24,0x83,0x11,0x41,0x2,0x9,0x12, +0x41,0x26,0x89,0x20,0x91,0x8,0x8c,0x11,0x89,0x60,0x44,0x7c,0x3c,0xf,0x3c,0x22, +0xf,0x3c,0x82,0x45,0x1e,0xc8,0x23,0x79,0xc8,0x48,0xe4,0x3,0x1f,0x41,0x3e,0xf, +0xf6,0xc0,0xe7,0x79,0x60,0x91,0x7,0xc,0xf1,0x78,0xc0,0x47,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x1,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0, + +}; + +#define TEXT_LOADED_WIDTH 54 +#define TEXT_LOADED_HEIGHT 19 +const unsigned char TEXT_LOADED [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0, +0x4,0x0,0x10,0x6,0x0,0x0,0x0,0x4,0x0,0x10,0x6,0x0,0x0,0x0,0x4,0x0, +0x10,0x6,0x30,0x60,0xc0,0x4,0x1,0x13,0x6,0xf8,0xf0,0xe1,0xc7,0x87,0x1f,0x6, +0x8c,0x19,0x33,0x66,0xcc,0x18,0x6,0x4,0x1,0x13,0x26,0x48,0x18,0x6,0x4,0xe1, +0x1b,0xe4,0x6f,0x10,0x6,0x4,0x19,0x13,0x24,0x40,0x10,0x6,0x84,0x9,0x13,0x26, +0x48,0x18,0x6,0x8c,0x9,0x33,0x66,0xcc,0x18,0xfe,0xf9,0xf8,0xe3,0xc7,0x87,0x1f, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, + +}; + +#define TEXT_NO_INPUT_WIDTH 61 +#define TEXT_NO_INPUT_HEIGHT 22 +const unsigned char TEXT_NO_INPUT [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x6,0x2,0x0,0x8,0x0,0x0,0x0,0x0,0xe,0x2,0x0,0x8,0x0,0x0,0x0,0x0, +0xe,0x2,0x0,0x8,0x0,0x0,0x0,0x6,0x1e,0x82,0x1,0x8,0x6,0xc,0x0,0x6, +0x16,0xc2,0x7,0xc8,0x8f,0x1f,0x61,0xf,0x26,0x62,0xc,0xc8,0x98,0x31,0x61,0x6, +0x66,0x22,0x8,0xc8,0x98,0x20,0x61,0x6,0x46,0x22,0x8,0x48,0x98,0x20,0x61,0x6, +0xc6,0x22,0x8,0x48,0x98,0x20,0x61,0x6,0x86,0x23,0xc,0x48,0x98,0x21,0x61,0x6, +0x6,0x63,0xc,0x48,0x98,0x31,0x63,0x6,0x6,0xc3,0x7,0x48,0x98,0x1f,0x7e,0xe, +0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; + +#define OM_OSD_WIDTH 93 +#define OM_OSD_HEIGHT 17 +const unsigned char OM_OSD [] PROGMEM = { +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x70,0xf0,0xf8,0x80,0x40,0x0,0x0,0x0, +0xc4,0x0,0x0,0x0,0x88,0x99,0x89,0x81,0x61,0x0,0x0,0x0,0x82,0x0,0x0,0x0, +0x4,0x9,0x9,0x83,0x61,0x0,0x0,0x0,0x2,0x3d,0x1e,0x1b,0x4,0x1a,0x8,0x82, +0x52,0x1e,0x9b,0x8,0x3,0x45,0x22,0x11,0x6,0xf2,0x8,0x82,0x52,0x22,0x91,0x8, +0x2,0x45,0x3e,0x11,0x4,0x82,0x9,0x82,0x52,0x3e,0x91,0x8,0x82,0x45,0x2,0x11, +0x4,0xb,0x9,0x82,0x44,0x2,0x91,0x8,0x86,0x44,0x22,0x11,0xc,0x9,0x9,0x81, +0x4c,0x22,0x91,0xc,0x7c,0x3c,0x1e,0x11,0xf8,0xf0,0xf9,0x80,0x4c,0x1e,0x91,0xf, +0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + +}; +#endif \ No newline at end of file diff --git a/OSDManager.cpp b/src/OSDManager.cpp similarity index 72% rename from OSDManager.cpp rename to src/OSDManager.cpp index 79dfb52c..78747646 100644 --- a/OSDManager.cpp +++ b/src/OSDManager.cpp @@ -1,19 +1,16 @@ #include "OSDManager.h" -#include "options.h" -extern userOptions *uopt; -extern void saveUserPrefs(); -extern void shiftHorizontalRight(); -extern void shiftHorizontalLeft(); -extern void shiftVerticalDownIF(); -extern void shiftVerticalUpIF(); -extern void scaleVertical(uint16_t, bool); -extern void scaleHorizontal(uint16_t, bool); -extern OSDManager osdManager; +/** + * @brief + * + * @param config + * @return true + * @return false + */ bool osdBrightness(OSDMenuConfig &config) { const int16_t STEP = 8; - int8_t cur = GBS::VDS_Y_OFST::read(); + int8_t cur = GBS::VDS_Y_OFST::read(); if (config.onChange) { if (config.inc) { cur = MIN(cur + STEP, 127); @@ -21,7 +18,7 @@ bool osdBrightness(OSDMenuConfig &config) cur = MAX(-128, cur - STEP); } GBS::VDS_Y_OFST::write(cur); - } + } config.barLength = 256 / STEP; config.barActiveLength = (cur + 128 + 1) / STEP; return true; @@ -30,10 +27,11 @@ bool osdAutoGain(OSDMenuConfig &config) { config.barLength = 2; if (config.onChange) { - uopt->enableAutoGain = config.inc ? 1 : 0; - saveUserPrefs(); + uopt.enableAutoGain = config.inc ? 1 : 0; + slotFlush(); + // saveUserPrefs(); } - if (uopt->enableAutoGain == 1) { + if (uopt.enableAutoGain == 1) { config.barActiveLength = 2; } else { config.barActiveLength = 0; @@ -44,25 +42,26 @@ bool osdScanlines(OSDMenuConfig &config) { if (config.onChange) { if (config.inc) { - if (uopt->scanlineStrength > 0) { - uopt->scanlineStrength -= 0x10; + if (uopt.scanlineStrength > 0) { + uopt.scanlineStrength -= 0x10; } } else { - uopt->scanlineStrength = MIN(uopt->scanlineStrength + 0x10, 0x50); + uopt.scanlineStrength = MIN(uopt.scanlineStrength + 0x10, 0x50); } - if (uopt->scanlineStrength == 0x50) { - uopt->wantScanlines = 0; + if (uopt.scanlineStrength == 0x50) { + uopt.wantScanlines = 0; } else { - uopt->wantScanlines = 1; + uopt.wantScanlines = 1; } - GBS::MADPT_Y_MI_OFFSET::write(uopt->scanlineStrength); - saveUserPrefs(); + GBS::MADPT_Y_MI_OFFSET::write(uopt.scanlineStrength); + // saveUserPrefs(); + slotFlush(); } config.barLength = 128; - if (uopt->scanlineStrength == 0) { + if (uopt.scanlineStrength == 0) { config.barActiveLength = 128; } else { - config.barActiveLength = (5 - uopt->scanlineStrength / 0x10) * 25; + config.barActiveLength = (5 - uopt.scanlineStrength / 0x10) * 25; } return true; } @@ -70,11 +69,12 @@ bool osdLineFilter(OSDMenuConfig &config) { config.barLength = 2; if (config.onChange) { - uopt->wantVdsLineFilter = config.inc ? 1 : 0; - GBS::VDS_D_RAM_BYPS::write(!uopt->wantVdsLineFilter); - saveUserPrefs(); + uopt.wantVdsLineFilter = config.inc ? 1 : 0; + GBS::VDS_D_RAM_BYPS::write(!uopt.wantVdsLineFilter); + // saveUserPrefs(); + slotFlush(); } - if (uopt->wantVdsLineFilter == 1) { + if (uopt.wantVdsLineFilter == 1) { config.barActiveLength = 2; } else { config.barActiveLength = 0; @@ -153,12 +153,13 @@ bool osdContrast(OSDMenuConfig &config) const uint8_t STEP = 8; int16_t cur = GBS::ADC_RGCTRL::read(); if (config.onChange) { - if (uopt->enableAutoGain == 1) { - uopt->enableAutoGain = 0; - saveUserPrefs(); - } else { - uopt->enableAutoGain = 0; - } + if (uopt.enableAutoGain) { + uopt.enableAutoGain = false; + // saveUserPrefs(); + slotFlush(); + }/* else { + uopt.enableAutoGain = 0; + } */ if (config.inc) { cur = MAX(0, cur - STEP); } else { diff --git a/OSDManager.h b/src/OSDManager.h similarity index 96% rename from OSDManager.h rename to src/OSDManager.h index 74269582..991bd171 100644 --- a/OSDManager.h +++ b/src/OSDManager.h @@ -1,11 +1,12 @@ #ifndef OSD_MANAGER_H_ #define OSD_MANAGER_H_ + +#include "options.h" #include "tv5725.h" -#define MENU_WIDTH 131 -#define MENU_HEIGHT 19 -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) > (b) ? (b) : (a)) -typedef TV5725 GBS; +#include "presets.h" +#include "slot.h" +#include "prefs.h" + struct OSDMenuConfig { uint8_t barLength; @@ -55,7 +56,8 @@ enum class OSDNav { MENU, BACK }; -typedef TV5725 GBS; + + class OSDManager { private: @@ -63,7 +65,7 @@ class OSDManager BRIGHTNESS = 0x1, // 4'b0001 CONTRAST = 0x2, // 4'b0010 HUE = 0x3, // 4'b0011 - VOLUME = 0x4, // 4'b0100 + VOLUME = 0x4, // 4'b0100 UP_DOWN = 0x8, // 4'b1000 LEFT_RIGHT = 0x9, // 4'b1001 VERTICAL = 0xA, // 4'b1010 @@ -277,4 +279,7 @@ class OSDManager GBS::OSD_COMMAND_FINISH::write(true); } }; -#endif \ No newline at end of file + +extern OSDManager osdManager; + +#endif // OSD_MANAGER_H_ \ No newline at end of file diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 63eef3e2..00000000 --- a/src/README.md +++ /dev/null @@ -1,98 +0,0 @@ -WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.org/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.org/Links2004/arduinoWebSockets) -=========================================== - -a WebSocket Server and Client for Arduino based on RFC6455. - - -##### Supported features of RFC6455 ##### - - text frame - - binary frame - - connection close - - ping - - pong - - continuation frame - -##### Limitations ##### - - max input length is limited to the ram size and the ```WEBSOCKETS_MAX_DATA_SIZE``` define - - max output length has no limit (the hardware is the limit) - - Client send big frames with mask 0x00000000 (on AVR all frames) - - continuation frame reassembly need to be handled in the application code - - ##### Limitations for Async ##### - - Functions called from within the context of the websocket event might not honor `yield()` and/or `delay()`. See [this issue](https://github.com/Links2004/arduinoWebSockets/issues/58#issuecomment-192376395) for more info and a potential workaround. - - wss / SSL is not possible. - -##### Supported Hardware ##### - - ESP8266 [Arduino for ESP8266](https://github.com/esp8266/Arduino/) - - ESP32 [Arduino for ESP32](https://github.com/espressif/arduino-esp32) - - ESP31B - - Particle with STM32 ARM Cortex M3 - - ATmega328 with Ethernet Shield (ATmega branch) - - ATmega328 with enc28j60 (ATmega branch) - - ATmega2560 with Ethernet Shield (ATmega branch) - - ATmega2560 with enc28j60 (ATmega branch) - -###### Note: ###### - - version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch. - - Arduino for AVR not supports std namespace of c++. - -### wss / SSL ### - supported for: - - wss client on the ESP8266 - - wss / SSL is not natively supported in WebSocketsServer however it is possible to achieve secure websockets - by running the device behind an SSL proxy. See [Nginx](examples/Nginx/esp8266.ssl.reverse.proxy.conf) for a - sample Nginx server configuration file to enable this. - -### ESP Async TCP ### - -This libary can run in Async TCP mode on the ESP. - -The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE define). - -[ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) libary is required. - - -### High Level Client API ### - - - `begin` : Initiate connection sequence to the websocket host. -``` -void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); -void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); - ``` - - `onEvent`: Callback to handle for websocket events - - ``` - void onEvent(WebSocketClientEvent cbEvent); - ``` - - - `WebSocketClientEvent`: Handler for websocket events - ``` - void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length) - ``` -Where `WStype_t type` is defined as: - ``` - typedef enum { - WStype_ERROR, - WStype_DISCONNECTED, - WStype_CONNECTED, - WStype_TEXT, - WStype_BIN, - WStype_FRAGMENT_TEXT_START, - WStype_FRAGMENT_BIN_START, - WStype_FRAGMENT, - WStype_FRAGMENT_FIN, - } WStype_t; - ``` - -### Issues ### -Submit issues to: https://github.com/Links2004/arduinoWebSockets/issues - -[![Join the chat at https://gitter.im/Links2004/arduinoWebSockets](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Links2004/arduinoWebSockets?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -### License and credits ### - -The library is licensed under [LGPLv2.1](https://github.com/Links2004/arduinoWebSockets/blob/master/LICENSE) - -[libb64](http://libb64.sourceforge.net/) written by Chris Venter. It is distributed under Public Domain see [LICENSE](https://github.com/Links2004/arduinoWebSockets/blob/master/src/libb64/LICENSE). diff --git a/src/WebSockets.cpp b/src/WebSockets.cpp deleted file mode 100644 index 3a90a402..00000000 --- a/src/WebSockets.cpp +++ /dev/null @@ -1,749 +0,0 @@ -/** - * @file WebSockets.cpp - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 - * - */ - -#include "WebSockets.h" - -#ifdef ESP8266 -#include -#endif - -extern "C" { -#ifdef CORE_HAS_LIBB64 -#include -#else -#include "libb64/cencode_inc.h" -#endif -} - -#ifdef ESP8266 -#include -#elif defined(ESP32) -#include -#else - -extern "C" { -#include "libsha1/libsha1.h" -} - -#endif - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param code uint16_t see RFC - * @param reason ptr to the disconnect reason message - * @param reasonLen length of the disconnect reason message - */ -void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] clientDisconnect code: %u\n", client->num, code); - if(client->status == WSC_CONNECTED && code) { - if(reason) { - sendFrame(client, WSop_close, (uint8_t *)reason, reasonLen); - } else { - uint8_t buffer[2]; - buffer[0] = ((code >> 8) & 0xFF); - buffer[1] = (code & 0xFF); - sendFrame(client, WSop_close, &buffer[0], 2); - } - } - clientDisconnect(client); -} - -/** - * - * @param buf uint8_t * ptr to the buffer for writing - * @param opcode WSopcode_t - * @param length size_t length of the payload - * @param mask bool add dummy mask to the frame (needed for web browser) - * @param maskkey uint8_t[4] key used for payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - */ -uint8_t WebSockets::createHeader(uint8_t * headerPtr, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin) { - uint8_t headerSize; - // calculate header Size - if(length < 126) { - headerSize = 2; - } else if(length < 0xFFFF) { - headerSize = 4; - } else { - headerSize = 10; - } - - if(mask) { - headerSize += 4; - } - - // create header - - // byte 0 - *headerPtr = 0x00; - if(fin) { - *headerPtr |= bit(7); ///< set Fin - } - *headerPtr |= opcode; ///< set opcode - headerPtr++; - - // byte 1 - *headerPtr = 0x00; - if(mask) { - *headerPtr |= bit(7); ///< set mask - } - - if(length < 126) { - *headerPtr |= length; - headerPtr++; - } else if(length < 0xFFFF) { - *headerPtr |= 126; - headerPtr++; - *headerPtr = ((length >> 8) & 0xFF); - headerPtr++; - *headerPtr = (length & 0xFF); - headerPtr++; - } else { - // Normally we never get here (to less memory) - *headerPtr |= 127; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = 0x00; - headerPtr++; - *headerPtr = ((length >> 24) & 0xFF); - headerPtr++; - *headerPtr = ((length >> 16) & 0xFF); - headerPtr++; - *headerPtr = ((length >> 8) & 0xFF); - headerPtr++; - *headerPtr = (length & 0xFF); - headerPtr++; - } - - if(mask) { - *headerPtr = maskKey[0]; - headerPtr++; - *headerPtr = maskKey[1]; - headerPtr++; - *headerPtr = maskKey[2]; - headerPtr++; - *headerPtr = maskKey[3]; - headerPtr++; - } - return headerSize; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param length size_t length of the payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - * @return true if ok - */ -bool WebSockets::sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length, bool fin) { - uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 }; - uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 }; - - uint8_t headerSize = createHeader(&buffer[0], opcode, length, client->cIsClient, maskKey, fin); - - if(write(client, &buffer[0], headerSize) != headerSize) { - return false; - } - - return true; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param payload uint8_t * ptr to the payload - * @param length size_t length of the payload - * @param fin bool can be used to send data in more then one frame (set fin on the last frame) - * @param headerToPayload bool set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!) - * @return true if ok - */ -bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin, bool headerToPayload) { - if(client->tcp && !client->tcp->connected()) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not Connected!?\n", client->num); - return false; - } - - if(client->status != WSC_CONNECTED) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] not in WSC_CONNECTED state!?\n", client->num); - return false; - } - - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] ------- send message frame -------\n", client->num); - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] fin: %u opCode: %u mask: %u length: %u headerToPayload: %u\n", client->num, fin, opcode, client->cIsClient, length, headerToPayload); - - if(opcode == WSop_text) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] text: %s\n", client->num, (payload + (headerToPayload ? 14 : 0))); - } - - uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 }; - uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 }; - - uint8_t headerSize; - uint8_t * headerPtr; - uint8_t * payloadPtr = payload; - bool useInternBuffer = false; - bool ret = true; - - // calculate header Size - if(length < 126) { - headerSize = 2; - } else if(length < 0xFFFF) { - headerSize = 4; - } else { - headerSize = 10; - } - - if(client->cIsClient) { - headerSize += 4; - } - -#ifdef WEBSOCKETS_USE_BIG_MEM - // only for ESP since AVR has less HEAP - // try to send data in one TCP package (only if some free Heap is there) - if(!headerToPayload && ((length > 0) && (length < 1400)) && (GET_FREE_HEAP > 6000)) { - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] pack to one TCP package...\n", client->num); - uint8_t * dataPtr = (uint8_t *)malloc(length + WEBSOCKETS_MAX_HEADER_SIZE); - if(dataPtr) { - memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length); - headerToPayload = true; - useInternBuffer = true; - payloadPtr = dataPtr; - } - } -#endif - - // set Header Pointer - if(headerToPayload) { - // calculate offset in payload - headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize)); - } else { - headerPtr = &buffer[0]; - } - - if(client->cIsClient && useInternBuffer) { - // if we use a Intern Buffer we can modify the data - // by this fact its possible the do the masking - for(uint8_t x = 0; x < sizeof(maskKey); x++) { - maskKey[x] = random(0xFF); - } - } - - createHeader(headerPtr, opcode, length, client->cIsClient, maskKey, fin); - - if(client->cIsClient && useInternBuffer) { - uint8_t * dataMaskPtr; - - if(headerToPayload) { - dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE); - } else { - dataMaskPtr = payloadPtr; - } - - for(size_t x = 0; x < length; x++) { - dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]); - } - } - -#ifndef NODEBUG_WEBSOCKETS - unsigned long start = micros(); -#endif - - if(headerToPayload) { - // header has be added to payload - // payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings - // offset in payload is calculatetd 14 - headerSize - if(write(client, &payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) { - ret = false; - } - } else { - // send header - if(write(client, &buffer[0], headerSize) != headerSize) { - ret = false; - } - - if(payloadPtr && length > 0) { - // send payload - if(write(client, &payloadPtr[0], length) != length) { - ret = false; - } - } - } - - DEBUG_WEBSOCKETS("[WS][%d][sendFrame] sending Frame Done (%luus).\n", client->num, (micros() - start)); - -#ifdef WEBSOCKETS_USE_BIG_MEM - if(useInternBuffer && payloadPtr) { - free(payloadPtr); - } -#endif - - return ret; -} - -/** - * callen when HTTP header is done - * @param client WSclient_t * ptr to the client struct - */ -void WebSockets::headerDone(WSclient_t * client) { - client->status = WSC_CONNECTED; - client->cWsRXsize = 0; - DEBUG_WEBSOCKETS("[WS][%d][headerDone] Header Handling Done.\n", client->num); -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; - handleWebsocket(client); -#endif -} - -/** - * handle the WebSocket stream - * @param client WSclient_t * ptr to the client struct - */ -void WebSockets::handleWebsocket(WSclient_t * client) { - if(client->cWsRXsize == 0) { - handleWebsocketCb(client); - } -} - -/** - * wait for - * @param client - * @param size - */ -bool WebSockets::handleWebsocketWaitFor(WSclient_t * client, size_t size) { - if(!client->tcp || !client->tcp->connected()) { - return false; - } - - if(size > WEBSOCKETS_MAX_HEADER_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d too big!\n", client->num, size); - return false; - } - - if(client->cWsRXsize >= size) { - return true; - } - - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor] size: %d cWsRXsize: %d\n", client->num, size, client->cWsRXsize); - readCb(client, &client->cWsHeader[client->cWsRXsize], (size - client->cWsRXsize), std::bind([](WebSockets * server, size_t size, WSclient_t * client, bool ok) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocketWaitFor][readCb] size: %d ok: %d\n", client->num, size, ok); - if(ok) { - client->cWsRXsize = size; - server->handleWebsocketCb(client); - } else { - DEBUG_WEBSOCKETS("[WS][%d][readCb] failed.\n", client->num); - client->cWsRXsize = 0; - // timeout or error - server->clientDisconnect(client, 1002); - } - }, - this, size, std::placeholders::_1, std::placeholders::_2)); - return false; -} - -void WebSockets::handleWebsocketCb(WSclient_t * client) { - if(!client->tcp || !client->tcp->connected()) { - return; - } - - uint8_t * buffer = client->cWsHeader; - - WSMessageHeader_t * header = &client->cWsHeaderDecode; - uint8_t * payload = NULL; - - uint8_t headerLen = 2; - - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - - // split first 2 bytes in the data - header->fin = ((*buffer >> 7) & 0x01); - header->rsv1 = ((*buffer >> 6) & 0x01); - header->rsv2 = ((*buffer >> 5) & 0x01); - header->rsv3 = ((*buffer >> 4) & 0x01); - header->opCode = (WSopcode_t)(*buffer & 0x0F); - buffer++; - - header->mask = ((*buffer >> 7) & 0x01); - header->payloadLen = (WSopcode_t)(*buffer & 0x7F); - buffer++; - - if(header->payloadLen == 126) { - headerLen += 2; - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - header->payloadLen = buffer[0] << 8 | buffer[1]; - buffer += 2; - } else if(header->payloadLen == 127) { - headerLen += 8; - // read 64bit integer as length - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - - if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) { - // really too big! - header->payloadLen = 0xFFFFFFFF; - } else { - header->payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; - } - buffer += 8; - } - - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ------- read massage frame -------\n", client->num); - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] fin: %u rsv1: %u rsv2: %u rsv3 %u opCode: %u\n", client->num, header->fin, header->rsv1, header->rsv2, header->rsv3, header->opCode); - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] mask: %u payloadLen: %u\n", client->num, header->mask, header->payloadLen); - - if(header->payloadLen > WEBSOCKETS_MAX_DATA_SIZE) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] payload too big! (%u)\n", client->num, header->payloadLen); - clientDisconnect(client, 1009); - return; - } - - if(header->mask) { - headerLen += 4; - if(!handleWebsocketWaitFor(client, headerLen)) { - return; - } - header->maskKey = buffer; - buffer += 4; - } - - if(header->payloadLen > 0) { - // if text data we need one more - payload = (uint8_t *)malloc(header->payloadLen + 1); - - if(!payload) { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] to less memory to handle payload %d!\n", client->num, header->payloadLen); - clientDisconnect(client, 1011); - return; - } - readCb(client, payload, header->payloadLen, std::bind(&WebSockets::handleWebsocketPayloadCb, this, std::placeholders::_1, std::placeholders::_2, payload)); - } else { - handleWebsocketPayloadCb(client, true, NULL); - } -} - -void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload) { - WSMessageHeader_t * header = &client->cWsHeaderDecode; - if(ok) { - if(header->payloadLen > 0) { - payload[header->payloadLen] = 0x00; - - if(header->mask) { - //decode XOR - for(size_t i = 0; i < header->payloadLen; i++) { - payload[i] = (payload[i] ^ header->maskKey[i % 4]); - } - } - } - - switch(header->opCode) { - case WSop_text: - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] text: %s\n", client->num, payload); - // no break here! - case WSop_binary: - case WSop_continuation: - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_ping: - // send pong back - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] ping received (%s)\n", client->num, payload ? (const char *)payload : ""); - sendFrame(client, WSop_pong, payload, header->payloadLen); - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_pong: - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get pong (%s)\n", client->num, payload ? (const char *)payload : ""); - client->pongReceived = true; - messageReceived(client, header->opCode, payload, header->payloadLen, header->fin); - break; - case WSop_close: { -#ifndef NODEBUG_WEBSOCKETS - uint16_t reasonCode = 1000; - if(header->payloadLen >= 2) { - reasonCode = payload[0] << 8 | payload[1]; - } -#endif - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode); - if(header->payloadLen > 2) { - DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2)); - } else { - DEBUG_WEBSOCKETS("\n"); - } - clientDisconnect(client, 1000); - } break; - default: - clientDisconnect(client, 1002); - break; - } - - if(payload) { - free(payload); - } - - // reset input - client->cWsRXsize = 0; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - //register callback for next message - handleWebsocketWaitFor(client, 2); -#endif - - } else { - DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] missing data!\n", client->num); - free(payload); - clientDisconnect(client, 1002); - } -} - -/** - * generate the key for Sec-WebSocket-Accept - * @param clientKey String - * @return String Accept Key - */ -String WebSockets::acceptKey(String & clientKey) { - uint8_t sha1HashBin[20] = { 0 }; -#ifdef ESP8266 - sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]); -#elif defined(ESP32) - String data = clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - esp_sha(SHA1, (unsigned char *)data.c_str(), data.length(), &sha1HashBin[0]); -#else - clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, (const unsigned char *)clientKey.c_str(), clientKey.length()); - SHA1Final(&sha1HashBin[0], &ctx); -#endif - - String key = base64_encode(sha1HashBin, 20); - key.trim(); - - return key; -} - -/** - * base64_encode - * @param data uint8_t * - * @param length size_t - * @return base64 encoded String - */ -String WebSockets::base64_encode(uint8_t * data, size_t length) { - size_t size = ((length * 1.6f) + 1); - char * buffer = (char *)malloc(size); - if(buffer) { - base64_encodestate _state; - base64_init_encodestate(&_state); - int len = base64_encode_block((const char *)&data[0], length, &buffer[0], &_state); - len = base64_encode_blockend((buffer + len), &_state); - - String base64 = String(buffer); - free(buffer); - return base64; - } - return String("-FAIL-"); -} - -/** - * read x byte from tcp or get timeout - * @param client WSclient_t * - * @param out uint8_t * data buffer - * @param n size_t byte count - * @return true if ok - */ -bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - if(!client->tcp || !client->tcp->connected()) { - return false; - } - - client->tcp->readBytes(out, n, std::bind([](WSclient_t * client, bool ok, WSreadWaitCb cb) { - if(cb) { - cb(client, ok); - } - }, - client, std::placeholders::_1, cb)); - -#else - unsigned long t = millis(); - size_t len; - DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t); - while(n > 0) { - if(client->tcp == NULL) { - DEBUG_WEBSOCKETS("[readCb] tcp is null!\n"); - if(cb) { - cb(client, false); - } - return false; - } - - if(!client->tcp->connected()) { - DEBUG_WEBSOCKETS("[readCb] not connected!\n"); - if(cb) { - cb(client, false); - } - return false; - } - - if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) { - DEBUG_WEBSOCKETS("[readCb] receive TIMEOUT! %lu\n", (millis() - t)); - if(cb) { - cb(client, false); - } - return false; - } - - if(!client->tcp->available()) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - continue; - } - - len = client->tcp->read((uint8_t *)out, n); - if(len) { - t = millis(); - out += len; - n -= len; - //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); - } else { - //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - if(cb) { - cb(client, true); - } -#endif - return true; -} - -/** - * write x byte to tcp or get timeout - * @param client WSclient_t * - * @param out uint8_t * data buffer - * @param n size_t byte count - * @return bytes send - */ -size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) { - if(out == NULL) - return 0; - if(client == NULL) - return 0; - unsigned long t = millis(); - size_t len = 0; - size_t total = 0; - DEBUG_WEBSOCKETS("[write] n: %zu t: %lu\n", n, t); - while(n > 0) { - if(client->tcp == NULL) { - DEBUG_WEBSOCKETS("[write] tcp is null!\n"); - break; - } - - if(!client->tcp->connected()) { - DEBUG_WEBSOCKETS("[write] not connected!\n"); - break; - } - - if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) { - DEBUG_WEBSOCKETS("[write] write TIMEOUT! %lu\n", (millis() - t)); - break; - } - - len = client->tcp->write((const uint8_t *)out, n); - if(len) { - t = millis(); - out += len; - n -= len; - total += len; - //DEBUG_WEBSOCKETS("write %d left %d!\n", len, n); - } else { - //DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return total; -} - -size_t WebSockets::write(WSclient_t * client, const char * out) { - if(client == NULL) - return 0; - if(out == NULL) - return 0; - return write(client, (uint8_t *)out, strlen(out)); -} - -/** - * enable ping/pong heartbeat process - * @param client WSclient_t * - * @param pingInterval uint32_t how often ping will be sent - * @param pongTimeout uint32_t millis after which pong should timout if not received - * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect - */ -void WebSockets::enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) { - if(client == NULL) - return; - client->pingInterval = pingInterval; - client->pongTimeout = pongTimeout; - client->disconnectTimeoutCount = disconnectTimeoutCount; - client->pongReceived = false; -} - -/** - * handle ping/pong heartbeat timeout process - * @param client WSclient_t * - */ -void WebSockets::handleHBTimeout(WSclient_t * client) { - if(client->pingInterval) { // if heartbeat is enabled - uint32_t pi = millis() - client->lastPing; - - if(client->pongReceived) { - client->pongTimeoutCount = 0; - } else { - if(pi > client->pongTimeout) { // pong not received in time - client->pongTimeoutCount++; - client->lastPing = millis() - client->pingInterval - 500; // force ping on the next run - - DEBUG_WEBSOCKETS("[HBtimeout] pong TIMEOUT! lp=%d millis=%d pi=%d count=%d\n", client->lastPing, millis(), pi, client->pongTimeoutCount); - - if(client->disconnectTimeoutCount && client->pongTimeoutCount >= client->disconnectTimeoutCount) { - DEBUG_WEBSOCKETS("[HBtimeout] count=%d, DISCONNECTING\n", client->pongTimeoutCount); - clientDisconnect(client); - } - } - } - } -} diff --git a/src/WebSockets.h b/src/WebSockets.h deleted file mode 100644 index d0813d30..00000000 --- a/src/WebSockets.h +++ /dev/null @@ -1,331 +0,0 @@ -/** - * @file WebSockets.h - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 WEBSOCKETS_H_ -#define WEBSOCKETS_H_ - -#ifdef STM32_DEVICE -#include -#define bit(b) (1UL << (b)) // Taken directly from Arduino.h -#else -#include -#include -#endif - -#ifdef ARDUINO_ARCH_AVR -#error Version 2.x.x currently does not support Arduino with AVR since there is no support for std namespace of c++. -#error Use Version 1.x.x. (ATmega branch) -#else -#include -#endif - -#ifndef NODEBUG_WEBSOCKETS -#ifdef DEBUG_ESP_PORT -#define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf(__VA_ARGS__) -#else -//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ ) -#endif -#endif - -#ifndef DEBUG_WEBSOCKETS -#define DEBUG_WEBSOCKETS(...) -#define NODEBUG_WEBSOCKETS -#endif - -#if defined(ESP8266) || defined(ESP32) - -#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024) -#define WEBSOCKETS_USE_BIG_MEM -#define GET_FREE_HEAP ESP.getFreeHeap() -// moves all Header strings to Flash (~300 Byte) -//#define WEBSOCKETS_SAVE_RAM - -#elif defined(STM32_DEVICE) - -#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024) -#define WEBSOCKETS_USE_BIG_MEM -#define GET_FREE_HEAP System.freeMemory() - -#else - -//atmega328p has only 2KB ram! -#define WEBSOCKETS_MAX_DATA_SIZE (1024) -// moves all Header strings to Flash -#define WEBSOCKETS_SAVE_RAM - -#endif - -#define WEBSOCKETS_TCP_TIMEOUT (2000) - -#define NETWORK_ESP8266_ASYNC (0) -#define NETWORK_ESP8266 (1) -#define NETWORK_W5100 (2) -#define NETWORK_ENC28J60 (3) -#define NETWORK_ESP32 (4) -#define NETWORK_ESP32_ETH (5) - -// max size of the WS Message Header -#define WEBSOCKETS_MAX_HEADER_SIZE (14) - -#if !defined(WEBSOCKETS_NETWORK_TYPE) -// select Network type based -#if defined(ESP8266) || defined(ESP31B) -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266 -#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266_ASYNC -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 - -#elif defined(ESP32) -#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32 -//#define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP32_ETH -#else -#define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 - -#endif -#endif - -// Includes and defined based on Network Type -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - -// Note: -// No SSL/WSS support for client in Async mode -// TLS lib need a sync interface! - -#if defined(ESP8266) -#include -#elif defined(ESP32) -#include -#include -#elif defined(ESP31B) -#include -#else -#error "network type ESP8266 ASYNC only possible on the ESP mcu!" -#endif - -#include -#include -#define WEBSOCKETS_NETWORK_CLASS AsyncTCPbuffer -#define WEBSOCKETS_NETWORK_SERVER_CLASS AsyncServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - -#if !defined(ESP8266) && !defined(ESP31B) -#error "network type ESP8266 only possible on the ESP mcu!" -#endif - -#ifdef ESP8266 -#include -#else -#include -#endif -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100) - -#ifdef STM32_DEVICE -#define WEBSOCKETS_NETWORK_CLASS TCPClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS TCPServer -#else -#include -#include -#define WEBSOCKETS_NETWORK_CLASS EthernetClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer -#endif - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60) - -#include -#define WEBSOCKETS_NETWORK_CLASS UIPClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - -#include -#include -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32_ETH) - -#include -#define WEBSOCKETS_NETWORK_CLASS WiFiClient -#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer - -#else -#error "no network type selected!" -#endif - -#ifdef WEBSOCKETS_NETWORK_SSL_CLASS -#define HAS_SSL -#endif - -// moves all Header strings to Flash (~300 Byte) -#ifdef WEBSOCKETS_SAVE_RAM -#define WEBSOCKETS_STRING(var) F(var) -#else -#define WEBSOCKETS_STRING(var) var -#endif - -typedef enum { - WSC_NOT_CONNECTED, - WSC_HEADER, - WSC_CONNECTED -} WSclientsStatus_t; - -typedef enum { - WStype_ERROR, - WStype_DISCONNECTED, - WStype_CONNECTED, - WStype_TEXT, - WStype_BIN, - WStype_FRAGMENT_TEXT_START, - WStype_FRAGMENT_BIN_START, - WStype_FRAGMENT, - WStype_FRAGMENT_FIN, - WStype_PING, - WStype_PONG, -} WStype_t; - -typedef enum { - WSop_continuation = 0x00, ///< %x0 denotes a continuation frame - WSop_text = 0x01, ///< %x1 denotes a text frame - WSop_binary = 0x02, ///< %x2 denotes a binary frame - ///< %x3-7 are reserved for further non-control frames - WSop_close = 0x08, ///< %x8 denotes a connection close - WSop_ping = 0x09, ///< %x9 denotes a ping - WSop_pong = 0x0A ///< %xA denotes a pong - ///< %xB-F are reserved for further control frames -} WSopcode_t; - -typedef struct { - bool fin; - bool rsv1; - bool rsv2; - bool rsv3; - - WSopcode_t opCode; - bool mask; - - size_t payloadLen; - - uint8_t * maskKey; -} WSMessageHeader_t; - -typedef struct { - uint8_t num; ///< connection number - - WSclientsStatus_t status; - - WEBSOCKETS_NETWORK_CLASS * tcp; - - bool isSocketIO; ///< client for socket.io server - -#if defined(HAS_SSL) - bool isSSL; ///< run in ssl mode - WEBSOCKETS_NETWORK_SSL_CLASS * ssl; -#endif - - String cUrl; ///< http url - uint16_t cCode; ///< http code - - bool cIsClient = false; ///< will be used for masking - bool cIsUpgrade; ///< Connection == Upgrade - bool cIsWebsocket; ///< Upgrade == websocket - - String cSessionId; ///< client Set-Cookie (session id) - String cKey; ///< client Sec-WebSocket-Key - String cAccept; ///< client Sec-WebSocket-Accept - String cProtocol; ///< client Sec-WebSocket-Protocol - String cExtensions; ///< client Sec-WebSocket-Extensions - uint16_t cVersion; ///< client Sec-WebSocket-Version - - uint8_t cWsRXsize; ///< State of the RX - uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer - WSMessageHeader_t cWsHeaderDecode; - - String base64Authorization; ///< Base64 encoded Auth request - String plainAuthorization; ///< Base64 encoded Auth request - - String extraHeaders; - - bool cHttpHeadersValid; ///< non-websocket http header validity indicator - size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count - - bool pongReceived; - uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active" - uint32_t lastPing; // millis when last pong has been received - uint32_t pongTimeout; // interval in millis after which pong is considered to timeout - uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect" - uint8_t pongTimeoutCount; // current pong timeout count - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - String cHttpLine; ///< HTTP header lines -#endif - -} WSclient_t; - -class WebSockets { - protected: -#ifdef __AVR__ - typedef void (*WSreadWaitCb)(WSclient_t * client, bool ok); -#else - typedef std::function WSreadWaitCb; -#endif - - virtual void clientDisconnect(WSclient_t * client) = 0; - virtual bool clientIsConnected(WSclient_t * client) = 0; - - void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0); - - virtual void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) = 0; - - uint8_t createHeader(uint8_t * buf, WSopcode_t opcode, size_t length, bool mask, uint8_t maskKey[4], bool fin); - bool sendFrameHeader(WSclient_t * client, WSopcode_t opcode, size_t length = 0, bool fin = true); - bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool fin = true, bool headerToPayload = false); - - void headerDone(WSclient_t * client); - - void handleWebsocket(WSclient_t * client); - - bool handleWebsocketWaitFor(WSclient_t * client, size_t size); - void handleWebsocketCb(WSclient_t * client); - void handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t * payload); - - String acceptKey(String & clientKey); - String base64_encode(uint8_t * data, size_t length); - - bool readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWaitCb cb); - virtual size_t write(WSclient_t * client, uint8_t * out, size_t n); - size_t write(WSclient_t * client, const char * out); - - void enableHeartbeat(WSclient_t * client, uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); - void handleHBTimeout(WSclient_t * client); -}; - -#ifndef UNUSED -#define UNUSED(var) (void)(var) -#endif -#endif /* WEBSOCKETS_H_ */ diff --git a/src/WebSocketsServer.cpp b/src/WebSocketsServer.cpp deleted file mode 100644 index c1bfd9eb..00000000 --- a/src/WebSocketsServer.cpp +++ /dev/null @@ -1,853 +0,0 @@ -/** - * @file WebSocketsServer.cpp - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 - * - */ - -#include "WebSockets.h" -#include "WebSocketsServer.h" - -WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) { - _port = port; - _origin = origin; - _protocol = protocol; - _runnning = false; - - _server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _server->onClient([](void * s, AsyncClient * c) { - ((WebSocketsServer *)s)->newClient(new AsyncTCPbuffer(c)); - }, - this); -#endif - - _cbEvent = NULL; - - _httpHeaderValidationFunc = NULL; - _mandatoryHttpHeaders = NULL; - _mandatoryHttpHeaderCount = 0; - - memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX)); -} - -WebSocketsServer::~WebSocketsServer() { - // disconnect all clients - close(); - - if(_mandatoryHttpHeaders) - delete[] _mandatoryHttpHeaders; - - _mandatoryHttpHeaderCount = 0; -} - -/** - * called to initialize the Websocket server - */ -void WebSocketsServer::begin(void) { - WSclient_t * client; - - // init client storage - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - - client->num = i; - client->status = WSC_NOT_CONNECTED; - client->tcp = NULL; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - client->isSSL = false; - client->ssl = NULL; -#endif - client->cUrl = ""; - client->cCode = 0; - client->cKey = ""; - client->cProtocol = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - - client->base64Authorization = ""; - - client->cWsRXsize = 0; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; -#endif - } - -#ifdef ESP8266 - randomSeed(RANDOM_REG32); -#elif defined(ESP32) -#define DR_REG_RNG_BASE 0x3ff75144 - randomSeed(READ_PERI_REG(DR_REG_RNG_BASE)); -#else - // TODO find better seed - randomSeed(millis()); -#endif - - _runnning = true; - _server->begin(); - - DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); -} - -void WebSocketsServer::close(void) { - _runnning = false; - disconnect(); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - _server->close(); -#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - _server->end(); -#else - // TODO how to close server? -#endif -} - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * called in arduino loop - */ -void WebSocketsServer::loop(void) { - if(_runnning) { - handleNewClients(); - handleClientData(); - } -} -#endif - -/** - * set callback function - * @param cbEvent WebSocketServerEvent - */ -void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) { - _cbEvent = cbEvent; -} - -/* - * Sets the custom http header validator function - * @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function - * @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed - * @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array - */ -void WebSocketsServer::onValidateHttpHeader( - WebSocketServerHttpHeaderValFunc validationFunc, - const char * mandatoryHttpHeaders[], - size_t mandatoryHttpHeaderCount) { - _httpHeaderValidationFunc = validationFunc; - - if(_mandatoryHttpHeaders) - delete[] _mandatoryHttpHeaders; - - _mandatoryHttpHeaderCount = mandatoryHttpHeaderCount; - _mandatoryHttpHeaders = new String[_mandatoryHttpHeaderCount]; - - for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { - _mandatoryHttpHeaders[i] = mandatoryHttpHeaders[i]; - } -} - -/* - * send text data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - if(length == 0) { - length = strlen((const char *)payload); - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_text, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { - return sendTXT(num, (uint8_t *)payload, length); -} - -bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { - return sendTXT(num, (uint8_t *)payload, length, headerToPayload); -} - -bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) { - return sendTXT(num, (uint8_t *)payload, length); -} - -bool WebSocketsServer::sendTXT(uint8_t num, String & payload) { - return sendTXT(num, (uint8_t *)payload.c_str(), payload.length()); -} - -/** - * send text data to client all - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { - WSclient_t * client; - bool ret = true; - if(length == 0) { - length = strlen((const char *)payload); - } - - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_text, payload, length, true, headerToPayload)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) { - return broadcastTXT((uint8_t *)payload, length); -} - -bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) { - return broadcastTXT((uint8_t *)payload, length, headerToPayload); -} - -bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) { - return broadcastTXT((uint8_t *)payload, length); -} - -bool WebSocketsServer::broadcastTXT(String & payload) { - return broadcastTXT((uint8_t *)payload.c_str(), payload.length()); -} - -/** - * send binary data to client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_binary, payload, length, true, headerToPayload); - } - return false; -} - -bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { - return sendBIN(num, (uint8_t *)payload, length); -} - -/** - * send binary data to client all - * @param payload uint8_t * - * @param length size_t - * @param headerToPayload bool (see sendFrame for more details) - * @return true if ok - */ -bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { - WSclient_t * client; - bool ret = true; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_binary, payload, length, true, headerToPayload)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) { - return broadcastBIN((uint8_t *)payload, length); -} - -/** - * sends a WS ping to Client - * @param num uint8_t client id - * @param payload uint8_t * - * @param length size_t - * @return true if ping is send out - */ -bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return false; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return sendFrame(client, WSop_ping, payload, length); - } - return false; -} - -bool WebSocketsServer::sendPing(uint8_t num, String & payload) { - return sendPing(num, (uint8_t *)payload.c_str(), payload.length()); -} - -/** - * sends a WS ping to all Client - * @param payload uint8_t * - * @param length size_t - * @return true if ping is send out - */ -bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) { - WSclient_t * client; - bool ret = true; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - if(!sendFrame(client, WSop_ping, payload, length)) { - ret = false; - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } - return ret; -} - -bool WebSocketsServer::broadcastPing(String & payload) { - return broadcastPing((uint8_t *)payload.c_str(), payload.length()); -} - -/** - * disconnect all clients - */ -void WebSocketsServer::disconnect(void) { - WSclient_t * client; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - WebSockets::clientDisconnect(client, 1000); - } - } -} - -/** - * disconnect one client - * @param num uint8_t client id - */ -void WebSocketsServer::disconnect(uint8_t num) { - if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { - return; - } - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - WebSockets::clientDisconnect(client, 1000); - } -} - -/* - * set the Authorization for the http request - * @param user const char * - * @param password const char * - */ -void WebSocketsServer::setAuthorization(const char * user, const char * password) { - if(user && password) { - String auth = user; - auth += ":"; - auth += password; - _base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length()); - } -} - -/** - * set the Authorizatio for the http request - * @param auth const char * base64 - */ -void WebSocketsServer::setAuthorization(const char * auth) { - if(auth) { - _base64Authorization = auth; - } -} - -/** - * count the connected clients (optional ping them) - * @param ping bool ping the connected clients - */ -int WebSocketsServer::connectedClients(bool ping) { - WSclient_t * client; - int count = 0; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(client->status == WSC_CONNECTED) { - if(ping != true || sendPing(i)) { - count++; - } - } - } - return count; -} - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) -/** - * get an IP for a client - * @param num uint8_t client id - * @return IPAddress - */ -IPAddress WebSocketsServer::remoteIP(uint8_t num) { - if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { - WSclient_t * client = &_clients[num]; - if(clientIsConnected(client)) { - return client->tcp->remoteIP(); - } - } - - return IPAddress(); -} -#endif - -//################################################################################# -//################################################################################# -//################################################################################# - -/** - * handle new client connection - * @param client - */ -bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { - WSclient_t * client; - // search free list entry for client - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - - // state is not connected or tcp connection is lost - if(!clientIsConnected(client)) { - client->tcp = TCPclient; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - client->isSSL = false; - client->tcp->setNoDelay(true); -#endif -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - // set Timeout for readBytesUntil and readStringUntil - client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); -#endif - client->status = WSC_HEADER; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress ip = client->tcp->remoteIP(); - DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]); - (void) ip; -#else - DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num); -#endif - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { - DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num); - - AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp; - if(*sl == obj) { - client->status = WSC_NOT_CONNECTED; - *sl = NULL; - } - return true; - }, - this, std::placeholders::_1, client)); - - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); -#endif - - return true; - break; - } - } - return false; -} - -/** - * - * @param client WSclient_t * ptr to the client struct - * @param opcode WSopcode_t - * @param payload uint8_t * - * @param length size_t - */ -void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { - WStype_t type = WStype_ERROR; - - switch(opcode) { - case WSop_text: - type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START; - break; - case WSop_binary: - type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START; - break; - case WSop_continuation: - type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT; - break; - case WSop_ping: - type = WStype_PING; - break; - case WSop_pong: - type = WStype_PONG; - break; - case WSop_close: - default: - break; - } - - runCbEvent(client->num, type, payload, length); -} - -/** - * Disconnect an client - * @param client WSclient_t * ptr to the client struct - */ -void WebSocketsServer::clientDisconnect(WSclient_t * client) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - if(client->isSSL && client->ssl) { - if(client->ssl->connected()) { - client->ssl->flush(); - client->ssl->stop(); - } - delete client->ssl; - client->ssl = NULL; - client->tcp = NULL; - } -#endif - - if(client->tcp) { - if(client->tcp->connected()) { -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - client->tcp->flush(); -#endif - client->tcp->stop(); - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->status = WSC_NOT_CONNECTED; -#else - delete client->tcp; -#endif - client->tcp = NULL; - } - - client->cUrl = ""; - client->cKey = ""; - client->cProtocol = ""; - client->cVersion = 0; - client->cIsUpgrade = false; - client->cIsWebsocket = false; - - client->cWsRXsize = 0; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->cHttpLine = ""; -#endif - - client->status = WSC_NOT_CONNECTED; - - DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num); - - runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0); -} - -/** - * get client state - * @param client WSclient_t * ptr to the client struct - * @return true = connected - */ -bool WebSocketsServer::clientIsConnected(WSclient_t * client) { - if(!client->tcp) { - return false; - } - - if(client->tcp->connected()) { - if(client->status != WSC_NOT_CONNECTED) { - return true; - } - } else { - // client lost - if(client->status != WSC_NOT_CONNECTED) { - DEBUG_WEBSOCKETS("[WS-Server][%d] client connection lost.\n", client->num); - // do cleanup - clientDisconnect(client); - } - } - - if(client->tcp) { - // do cleanup - DEBUG_WEBSOCKETS("[WS-Server][%d] client list cleanup.\n", client->num); - clientDisconnect(client); - } - - return false; -} -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) -/** - * Handle incoming Connection Request - */ -void WebSocketsServer::handleNewClients(void) { -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - while(_server->hasClient()) { -#endif - bool ok = false; - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - // store new connection - WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#else - WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); -#endif - - if(!tcpClient) { - DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); - return; - } - - ok = newClient(tcpClient); - - if(!ok) { - // no free space to handle client -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress ip = tcpClient->remoteIP(); - DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); -#else - DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n"); -#endif - tcpClient->stop(); - } - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - delay(0); - } -#endif -} - -/** - * Handel incomming data from Client - */ -void WebSocketsServer::handleClientData(void) { - WSclient_t * client; - for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { - client = &_clients[i]; - if(clientIsConnected(client)) { - int len = client->tcp->available(); - if(len > 0) { - //DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len); - switch(client->status) { - case WSC_HEADER: { - String headerLine = client->tcp->readStringUntil('\n'); - handleHeader(client, &headerLine); - } break; - case WSC_CONNECTED: - WebSockets::handleWebsocket(client); - break; - default: - WebSockets::clientDisconnect(client, 1002); - break; - } - } - } -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) - delay(0); -#endif - } -} -#endif - -/* - * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection - * @param headerName String ///< the name of the header being checked - */ -bool WebSocketsServer::hasMandatoryHeader(String headerName) { - for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { - if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName)) - return true; - } - return false; -} - -/** - * handles http header reading for WebSocket upgrade - * @param client WSclient_t * ///< pointer to the client struct - * @param headerLine String ///< the header being read / processed - */ -void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { - static const char * NEW_LINE = "\r\n"; - - headerLine->trim(); // remove \r - - if(headerLine->length() > 0) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str()); - - // websocket requests always start with GET see rfc6455 - if(headerLine->startsWith("GET ")) { - // cut URL out - client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4)); - - //reset non-websocket http header validation state for this client - client->cHttpHeadersValid = true; - client->cMandatoryHeadersCount = 0; - - } else if(headerLine->indexOf(':') >= 0) { - String headerName = headerLine->substring(0, headerLine->indexOf(':')); - String headerValue = headerLine->substring(headerLine->indexOf(':') + 1); - - // remove space in the beginning (RFC2616) - if(headerValue[0] == ' ') { - headerValue.remove(0, 1); - } - - if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) { - headerValue.toLowerCase(); - if(headerValue.indexOf(WEBSOCKETS_STRING("upgrade")) >= 0) { - client->cIsUpgrade = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) { - if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) { - client->cIsWebsocket = true; - } - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { - client->cVersion = headerValue.toInt(); - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Key"))) { - client->cKey = headerValue; - client->cKey.trim(); // see rfc6455 - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) { - client->cProtocol = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) { - client->cExtensions = headerValue; - } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Authorization"))) { - client->base64Authorization = headerValue; - } else { - client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue); - if(_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) { - client->cMandatoryHeadersCount++; - } - } - - } else { - DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); - } - - (*headerLine) = ""; -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) - client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); -#endif - } else { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str()); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid); - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount); - - bool ok = (client->cIsUpgrade && client->cIsWebsocket); - - if(ok) { - if(client->cUrl.length() == 0) { - ok = false; - } - if(client->cKey.length() == 0) { - ok = false; - } - if(client->cVersion != 13) { - ok = false; - } - if(!client->cHttpHeadersValid) { - ok = false; - } - if(client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) { - ok = false; - } - } - - if(_base64Authorization.length() > 0) { - String auth = WEBSOCKETS_STRING("Basic "); - auth += _base64Authorization; - if(auth != client->base64Authorization) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num); - handleAuthorizationFailed(client); - return; - } - } - - if(ok) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num); - - // generate Sec-WebSocket-Accept key - String sKey = acceptKey(client->cKey); - - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - sKey: %s\n", client->num, sKey.c_str()); - - client->status = WSC_CONNECTED; - - String handshake = WEBSOCKETS_STRING( - "HTTP/1.1 101 Switching Protocols\r\n" - "Server: arduino-WebSocketsServer\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Accept: "); - handshake += sKey + NEW_LINE; - - if(_origin.length() > 0) { - handshake += WEBSOCKETS_STRING("Access-Control-Allow-Origin: "); - handshake += _origin + NEW_LINE; - } - - if(client->cProtocol.length() > 0) { - handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: "); - handshake += _protocol + NEW_LINE; - } - - // header end - handshake += NEW_LINE; - - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] handshake %s", client->num, (uint8_t *)handshake.c_str()); - - write(client, (uint8_t *)handshake.c_str(), handshake.length()); - - headerDone(client); - - // send ping - WebSockets::sendFrame(client, WSop_ping); - - runCbEvent(client->num, WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length()); - - } else { - handleNonWebsocketConnection(client); - } - } -} diff --git a/src/WebSocketsServer.h b/src/WebSocketsServer.h deleted file mode 100644 index a517da64..00000000 --- a/src/WebSocketsServer.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @file WebSocketsServer.h - * @date 20.05.2015 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the WebSockets for Arduino. - * - * 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 WEBSOCKETSSERVER_H_ -#define WEBSOCKETSSERVER_H_ - -#include "WebSockets.h" - -#ifndef WEBSOCKETS_SERVER_CLIENT_MAX -#define WEBSOCKETS_SERVER_CLIENT_MAX (2) -#endif - -class WebSocketsServer : protected WebSockets { - public: -#ifdef __AVR__ - typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); - typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue); -#else - typedef std::function WebSocketServerEvent; - typedef std::function WebSocketServerHttpHeaderValFunc; -#endif - - WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino"); - virtual ~WebSocketsServer(void); - - void begin(void); - void close(void); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void loop(void); -#else - // Async interface not need a loop call - void loop(void) __attribute__((deprecated)) {} -#endif - - void onEvent(WebSocketServerEvent cbEvent); - void onValidateHttpHeader( - WebSocketServerHttpHeaderValFunc validationFunc, - const char * mandatoryHttpHeaders[], - size_t mandatoryHttpHeaderCount); - - bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0); - bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false); - bool sendTXT(uint8_t num, const char * payload, size_t length = 0); - bool sendTXT(uint8_t num, String & payload); - - bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); - bool broadcastTXT(const uint8_t * payload, size_t length = 0); - bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false); - bool broadcastTXT(const char * payload, size_t length = 0); - bool broadcastTXT(String & payload); - - bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false); - bool sendBIN(uint8_t num, const uint8_t * payload, size_t length); - - bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false); - bool broadcastBIN(const uint8_t * payload, size_t length); - - bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0); - bool sendPing(uint8_t num, String & payload); - - bool broadcastPing(uint8_t * payload = NULL, size_t length = 0); - bool broadcastPing(String & payload); - - void disconnect(void); - void disconnect(uint8_t num); - - void setAuthorization(const char * user, const char * password); - void setAuthorization(const char * auth); - - int connectedClients(bool ping = false); - -#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) - IPAddress remoteIP(uint8_t num); -#endif - - protected: - uint16_t _port; - String _origin; - String _protocol; - String _base64Authorization; ///< Base64 encoded Auth request - String * _mandatoryHttpHeaders; - size_t _mandatoryHttpHeaderCount; - - WEBSOCKETS_NETWORK_SERVER_CLASS * _server; - - WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; - - WebSocketServerEvent _cbEvent; - WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc; - - bool _runnning; - - bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient); - - void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); - - void clientDisconnect(WSclient_t * client); - bool clientIsConnected(WSclient_t * client); - -#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) - void handleNewClients(void); - void handleClientData(void); -#endif - - void handleHeader(WSclient_t * client, String * headerLine); - - /** - * called if a non Websocket connection is coming in. - * Note: can be override - * @param client WSclient_t * ptr to the client struct - */ - virtual void handleNonWebsocketConnection(WSclient_t * client) { - DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num); - client->tcp->write( - "HTTP/1.1 400 Bad Request\r\n" - "Server: arduino-WebSocket-Server\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 32\r\n" - "Connection: close\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n" - "This is a Websocket server only!"); - clientDisconnect(client); - } - - /** - * called if a non Authorization connection is coming in. - * Note: can be override - * @param client WSclient_t * ptr to the client struct - */ - virtual void handleAuthorizationFailed(WSclient_t * client) { - client->tcp->write( - "HTTP/1.1 401 Unauthorized\r\n" - "Server: arduino-WebSocket-Server\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 45\r\n" - "Connection: close\r\n" - "Sec-WebSocket-Version: 13\r\n" - "WWW-Authenticate: Basic realm=\"WebSocket Server\"" - "\r\n" - "This Websocket server requires Authorization!"); - clientDisconnect(client); - } - - /** - * called for sending a Event to the app - * @param num uint8_t - * @param type WStype_t - * @param payload uint8_t * - * @param length size_t - */ - virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { - if(_cbEvent) { - _cbEvent(num, type, payload, length); - } - } - - /* - * Called at client socket connect handshake negotiation time for each http header that is not - * a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*) - * If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the - * socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected - * This mechanism can be used to enable custom authentication schemes e.g. test the value - * of a session cookie to determine if a user is logged on / authenticated - */ - virtual bool execHttpHeaderValidation(String headerName, String headerValue) { - if(_httpHeaderValidationFunc) { - //return the value of the custom http header validation function - return _httpHeaderValidationFunc(headerName, headerValue); - } - //no custom http header validation so just assume all is good - return true; - } - - private: - /* - * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection - * @param headerName String ///< the name of the header being checked - */ - bool hasMandatoryHeader(String headerName); -}; - -#endif /* WEBSOCKETSSERVER_H_ */ diff --git a/fastpin.h b/src/fastpin.h similarity index 100% rename from fastpin.h rename to src/fastpin.h diff --git a/fonts.h b/src/fonts.h similarity index 100% rename from fonts.h rename to src/fonts.h diff --git a/src/framesync.cpp b/src/framesync.cpp new file mode 100644 index 00000000..75e9e52e --- /dev/null +++ b/src/framesync.cpp @@ -0,0 +1,585 @@ +/* +########################################################################### +# File: framesync.cpp # +# File Created: Sunday, 5th May 2024 12:52:08 pm # +# Author: # +# Last Modified: Tuesday, 25th June 2024 2:07:00 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#include "framesync.h" + +static volatile uint32_t MeasurePeriodStopTime, + MeasurePeriodStartTime, + MeasurePeriodArmed; +bool FrameSyncManager::syncLockReady = false; +uint8_t FrameSyncManager::delayLock = 0; +int16_t FrameSyncManager::syncLastCorrection = 0; +/// Set to -1 if uninitialized. +/// Reset with syncLastCorrection. +float FrameSyncManager::maybeFreqExt_per_videoFps = -1; + +void IRAM_ATTR _risingEdgeISR_measure() +{ + noInterrupts(); + // stopTime = ESP.getCycleCount(); + __asm__ __volatile__("rsr %0,ccount" + : "=a"(MeasurePeriodStopTime)); + detachInterrupt(DEBUG_IN_PIN); + interrupts(); +} + +void IRAM_ATTR _risingEdgeISR_prepare() +{ + noInterrupts(); + // startTime = ESP.getCycleCount(); + __asm__ __volatile__("rsr %0, ccount" + : "=a"(MeasurePeriodStartTime)); + detachInterrupt(DEBUG_IN_PIN); + MeasurePeriodArmed = 1; + attachInterrupt(DEBUG_IN_PIN, _risingEdgeISR_measure, RISING); + interrupts(); +} + +void MeasurePeriodStart() +{ + MeasurePeriodStartTime = 0; + MeasurePeriodStopTime = 0; + MeasurePeriodArmed = 0; + attachInterrupt(DEBUG_IN_PIN, _risingEdgeISR_prepare, RISING); +} + +/** + * @brief + * + * @param start + * @param stop + * @return true + * @return false + */ +bool FrameSyncManager::vsyncOutputSample(uint32_t *start, uint32_t *stop) +{ + yield(); + uint32_t i = 0; + ESP.wdtDisable(); + MeasurePeriodStart(); + + // typical: 300000 at 80MHz, 600000 at 160MHz + while (i < 3000000) + { + if (MeasurePeriodArmed) + { + MeasurePeriodArmed = 0; + delay(7); + WiFi.setSleepMode(WIFI_LIGHT_SLEEP); + } + if (MeasurePeriodStopTime > 0) + { + break; + } + i++; + } + *start = MeasurePeriodStartTime; + *stop = MeasurePeriodStopTime; + ESP.wdtEnable(0); + WiFi.setSleepMode(WIFI_NONE_SLEEP); + + if ((*start >= *stop) || *stop == 0 || *start == 0) + { + // ESP.getCycleCount() overflow oder no pulse, just fail this round + return false; + } + + return true; +} + +/** + * @brief + * + * @param start + * @param stop + * @return true + * @return false + */ +bool FrameSyncManager::vsyncInputSample(uint32_t *start, uint32_t *stop) +{ + yield(); + uint32_t i = 0; + ESP.wdtDisable(); + MeasurePeriodStart(); + + // typical: 300000 at 80MHz, 600000 at 160MHz + while (i < 3000000) + { + if (MeasurePeriodArmed) + { + MeasurePeriodArmed = 0; + delay(7); + WiFi.setSleepMode(WIFI_LIGHT_SLEEP); + } + if (MeasurePeriodStopTime > 0) + { + break; + } + i++; + } + *start = MeasurePeriodStartTime; + *stop = MeasurePeriodStopTime; + ESP.wdtEnable(0); + WiFi.setSleepMode(WIFI_NONE_SLEEP); + + if ((*start >= *stop) || *stop == 0 || *start == 0) + { + // ESP.getCycleCount() overflow oder no pulse, just fail this round + return false; + } + + return true; +} + +// Perform vsync phase locking. This is accomplished by measuring +// the period and phase offset of the input and output vsync +// signals and adjusting the frame size (and thus the output vsync +// frequency) to bring the phase offset closer to the desired +// value. +bool FrameSyncManager::runVsync(uint8_t frameTimeLockMethod) +{ + int32_t period; + int32_t phase; + int32_t target; + int16_t correction; + + if (!syncLockReady) + return false; + + if (delayLock < 2) + { + delayLock++; + return true; + } + + if (!vsyncPeriodAndPhase(&period, NULL, &phase)) + return false; + + target = (syncTargetPhase * period) / 360; + + if (phase > target) + correction = 0; + else + correction = syncCorrection; + +#ifdef FRAMESYNC_DEBUG + _DBGF(PSTR("phase: %7d target: %7d"), phase, target); + if (correction == syncLastCorrection) + { + // terminate line if returning early + _DBGN(); + } +#endif +#ifdef FRAMESYNC_DEBUG_LED + if (correction == 0) + { + digitalWrite(LED_BUILTIN, LOW); // LED ON + } + else + { + digitalWrite(LED_BUILTIN, HIGH); // LED OFF + } +#endif + + // return early? + if (correction == syncLastCorrection) + { + return true; + } + + int16_t delta = correction - syncLastCorrection; + uint16_t vtotal = 0, vsst = 0; + uint16_t timeout = 0; + VRST_SST::read(vtotal, vsst); + vtotal += delta; + if (frameTimeLockMethod == 0) + { // moves VS position + vsst += delta; + } + // else it is method 1: leaves VS position alone + + while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)); + GBS::VDS_VS_ST::write(vsst); + timeout = 0; + while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 400)); + GBS::VDS_VSYNC_RST::write(vtotal); + + syncLastCorrection = correction; + +#ifdef FRAMESYNC_DEBUG + _DBGF(PSTR(" vtotal: %4d\n"), vtotal); +#endif + + return true; +} + +// sets syncLockReady = ready() = false, which in turn starts a new init() +// -> findBestHtotal() run in loop() +/** + * @brief + * + * @param frameTimeLockMethod + */ +void FrameSyncManager::reset(uint8_t frameTimeLockMethod) +{ +#ifdef FRAMESYNC_DEBUG + _DBG(F("FS reset(), with correction: ")); +#endif + if (syncLastCorrection != 0) + { +#ifdef FRAMESYNC_DEBUG + _DBGN(F("Yes")); +#endif + uint16_t vtotal = 0, vsst = 0; + VRST_SST::read(vtotal, vsst); + uint16_t timeout = 0; + vtotal -= syncLastCorrection; + if (frameTimeLockMethod == 0) + { // moves VS position + vsst -= syncLastCorrection; + } + + while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)); + GBS::VDS_VS_ST::write(vsst); + timeout = 0; + while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 400)); + GBS::VDS_VSYNC_RST::write(vtotal); + } +#ifdef FRAMESYNC_DEBUG + else + { + _DBGN(F("No")); + } + _DBGF(PSTR("FrameSyncManager::reset(%d)\n"), frameTimeLockMethod); +#endif + + syncLockReady = false; + syncLastCorrection = 0; + delayLock = 0; + // Don't clear maybeFreqExt_per_videoFps. + // + // Clearing is unsafe, since many callers call reset(), don't + // call externalClockGenSyncInOutRate() -> initFrequency(), then + // expect runFrequency() to keep working. + // + // Not clearing is hopefully safe, since when loading an output + // resolution, externalClockGenResetClock() calls + // FrameSync::clearFrequency() and clears the variable, and + // later someone calls externalClockGenSyncInOutRate() -> + // FrameSync::initFrequency(). +} + +// Perform vsync phase locking. This is accomplished by measuring +// the period and phase offset of the input and output vsync +// signals, then adjusting the output video clock to bring the phase +// offset closer to the desired value. +bool FrameSyncManager::runFrequency() +{ + if (maybeFreqExt_per_videoFps < 0) + { + // NOTE: before must be called externalClockGenSyncInOutRate() + _DBGN( + F("Error: trying to tune external clock frequency while it's uninitialized")); + return true; + } + + // Compare to externalClockGenSyncInOutRate(). + if (GBS::PAD_CKIN_ENZ::read() != 0) + { + // Failed due to external factors (PAD_CKIN_ENZ=0 on + // startup), not bad input signal, don't return frame sync + // error. + #ifdef FRAMESYNC_DEBUG + _DBGN(F("Skipping FrameSyncManager::runFrequency(), GBS::PAD_CKIN_ENZ::read() != 0")); + #endif + return true; + } + + // if (rto.outModeHdBypass) + if (utilsIsPassThroughMode()) + { + // #ifdef FRAMESYNC_DEBUG + // _DBGN(F("Skipping FrameSyncManager::runFrequency(), rto.outModeHdBypass")); + // #endif + return true; + } + if (GBS::PLL648_CONTROL_01::read() != 0x75) + { + _DBGF( + PSTR("Error: trying to tune external clock frequency while set to internal clock, PLL648_CONTROL_01=%d!\n"), + GBS::PLL648_CONTROL_01::read()); + return true; + } + + if (!syncLockReady) + { + #ifdef FRAMESYNC_DEBUG + _DBGN(F("Skipping FrameSyncManager::runFrequency(), !syncLockReady")); + #endif + return false; + } + + // ESP32 FPU only accelerates single-precision float add/mul, not divide, not double. + // https://esp32.com/viewtopic.php?p=82090#p82090 + + // ESP CPU cycles/s + const float esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; + + // ESP CPU cycles + int32_t periodInput = 0; // int32_t periodOutput; + int32_t phase = 0; + + // Frame/s + float fpsInput; + + // Measure input period until we get two consistent measurements. This + // substantially reduces the chance of incorrectly guessing FPS when + // input sync changes (but does not eliminate it, eg. when resetting a + // SNES). + bool success = false; + for (int attempt = 0; attempt < 2; attempt++) + { + // Measure input period and output latency. + bool ret = vsyncPeriodAndPhase(&periodInput, nullptr, &phase); + // TODO make vsyncPeriodAndPhase() restore TEST_BUS_SEL, not the caller? + GBS::TEST_BUS_SEL::write(0x0); + if (!ret) + { + #ifdef FRAMESYNC_DEBUG + _DBGN(F("runFrequency(): vsyncPeriodAndPhase failed, retrying...")); + #endif + continue; + } + + fpsInput = esp8266_clock_freq / (float)periodInput; + if (fpsInput < 47.0f || fpsInput > 86.0f) + { + _DBGF( + PSTR("runFrequency(): fpsInput wrong: %f, retrying...\n"), + fpsInput); + continue; + } + + // Measure input period again. vsyncPeriodAndPhase()/getPulseTicks() + // -> vsyncInputSample() depend on GBS::TEST_BUS_SEL = 0, but + // vsyncPeriodAndPhase() sets it to 2. + GBS::TEST_BUS_SEL::write(0x0); + uint32_t periodInput2 = getPulseTicks(); + if (periodInput2 == 0) + { + _DBGN(F("runFrequency(): getPulseTicks failed, retrying...")); + continue; + } + float fpsInput2 = esp8266_clock_freq / (float)periodInput2; + if (fpsInput2 < 47.0f || fpsInput2 > 86.0f) + { + _DBGF( + PSTR("runFrequency(): fpsInput2 wrong: %f, retrying...\n"), + fpsInput2); + continue; + } + + // Check that the two FPS measurements are sufficiently close. + float diff = fabs(fpsInput2 - fpsInput); + float relDiff = diff / std::min(fpsInput, fpsInput2); + if (relDiff != relDiff || diff > 0.5f || relDiff > 0.00833f) + { + _DBGF( + PSTR("FrameSyncManager::runFrequency() measured inconsistent FPS %f and %f, retrying...\n"), + fpsInput, + fpsInput2); + continue; + } + + success = true; + break; + } + if (!success) + { + _DBGN(F("FrameSyncManager::runFrequency() failed!")); + return false; + } + + // ESP CPU cycles + int32_t target = (syncTargetPhase * periodInput) / 360; + + // Latency error (distance behind target), in fractional frames. + // If latency increases, boost frequency, and vice versa. + const float latency_err_frames = + (float)(phase - target) // cycles + / esp8266_clock_freq // s + * fpsInput; // frames + + // 0.0038f is 2/525, the difference between SNES and Wii 240p. + // This number is somewhat arbitrary, but works well in + // practice. + float correction = 0.0038f * latency_err_frames; + + // Some LCD displays (eg. Dell U2312HM) lose sync when changing + // frequency by 0.1% (switching between 59.94 and 60 FPS). + // + // To ensure long-term FPS stability, clamp the maximum deviation from + // input FPS to 0.06%. This is sufficient as long as fpsInput does not + // vary drastically from frame to frame. + constexpr float MAX_CORRECTION = 0.0006f; + if (correction > MAX_CORRECTION) + correction = MAX_CORRECTION; + if (correction < -MAX_CORRECTION) + correction = -MAX_CORRECTION; + + const float rawFpsOutput = fpsInput * (1 + correction); + + // This has floating-point conversion round-trip rounding errors, which + // is suboptimal, but it's not a big deal. + const float prevFpsOutput = (float)rto.freqExtClockGen / maybeFreqExt_per_videoFps; + + // In case fpsInput is measured incorrectly, rawFpsOutput may be + // drastically different from the previous frame's output FPS. To limit + // the impact of incorrect input FPS measurements, clamp the maximum FPS + // deviation relative to the previous frame's *output* FPS. This + // provides short-term FPS stability. + constexpr float MAX_FPS_CHANGE = 0.0006f; + float fpsOutput = rawFpsOutput; + fpsOutput = std::min(fpsOutput, prevFpsOutput * (1 + MAX_FPS_CHANGE)); + fpsOutput = std::max(fpsOutput, prevFpsOutput * (1 - MAX_FPS_CHANGE)); + + if (fabs(rawFpsOutput - prevFpsOutput) >= 1.f) + { + _DBGF( + PSTR("FPS excursion detected! Measured input FPS %f, previous output FPS %f\n"), + fpsInput, prevFpsOutput); + } + #ifdef FRAMESYNC_DEBUG + _DBGF( + PSTR("periodInput=%d, fpsInput=%f, latency_err_frames=%f from %f, fpsOutput=%f := %f\n"), + periodInput, fpsInput, latency_err_frames, (float)syncTargetPhase / 360.f, + prevFpsOutput, fpsOutput); + #endif + + const auto freqExtClockGen = (uint32_t)(maybeFreqExt_per_videoFps * fpsOutput); + + #ifdef FRAMESYNC_DEBUG + _DBGF(PSTR("Setting clock frequency from %u to %u\n"), + rto.freqExtClockGen, freqExtClockGen); + #endif + + setExternalClockGenFrequencySmooth(freqExtClockGen); + return true; +} + +/** + * @brief Find appropriate htotal that makes output frame time slightly more than the input. + * + * @param bestHtotal + * @return true + * @return false + */ +bool FrameSyncManager::findBestHTotal(uint32_t &bestHtotal) +{ + uint16_t inHtotal = HSYNC_RST::read(); + uint32_t inPeriod, outPeriod; + + if (inHtotal == 0) + { + return false; + } // safety + if (!sampleVsyncPeriods(&inPeriod, &outPeriod)) + { + return false; + } + + if (inPeriod == 0 || outPeriod == 0) + { + return false; + } // safety + + // allow ~4 negative (inPeriod is < outPeriod) clock cycles jitter + if ((inPeriod > outPeriod ? inPeriod - outPeriod : outPeriod - inPeriod) <= 4) + { + /*if (inPeriod >= outPeriod) { + _WS("inPeriod >= out: "); + _WSN(inPeriod - outPeriod); + } + else { + _WS("inPeriod < out: "); + _WSN(outPeriod - inPeriod); + }*/ + bestHtotal = inHtotal; + } + else + { + // large htotal can push intermediates to 33 bits + bestHtotal = (uint64_t)(inHtotal * (uint64_t)inPeriod) / (uint64_t)outPeriod; + } + + // new 08.11.19: skip this step, IF period measurement should be stable enough to give repeatable results + // if (bestHtotal == (inHtotal + 1)) { bestHtotal -= 1; } // works well + // if (bestHtotal == (inHtotal - 1)) { bestHtotal += 1; } // check with SNES + vtotal = 1000 (1280x960) + +#ifdef FRAMESYNC_DEBUG + if (bestHtotal != inHtotal) + { + _DBG(F(" wants new htotal, oldbest: ")); + _DBG(inHtotal); + _DBG(F(" newbest: ")); + _DBGN(bestHtotal); + _DBG(F(" inPeriod: ")); + _DBG(inPeriod); + _DBG(F(" outPeriod: ")); + _DBGN(outPeriod); + } +#endif + return true; +} + +/** + * @brief Sample input and output vsync periods and their phase difference in microseconds + * + * @param periodInput + * @param periodOutput + * @param phase + * @return true + * @return false + */ +bool FrameSyncManager::vsyncPeriodAndPhase(int32_t *periodInput, int32_t *periodOutput, int32_t *phase) +{ + #ifdef FRAMESYNC_DEBUG + _DBGF(PSTR("vsyncPeriodAndPhase(), TEST_BUS_SEL=%d\n"), GBS::TEST_BUS_SEL::read()); + #endif + + uint32_t inStart, inStop, outStart, outStop; + uint32_t inPeriod, outPeriod, diff; + + // calling code needs to ensure debug bus is ready to sample vperiod + if (!vsyncInputSample(&inStart, &inStop)) + { + return false; + } + + GBS::TEST_BUS_SEL::write(0x2); // 0x2 = VDS (t3t50t4) // measure VDS vblank (VB ST/SP) + inPeriod = (inStop - inStart); //>> 1; + if (!vsyncOutputSample(&outStart, &outStop)) + { + return false; + } + outPeriod = (outStop - outStart); // >> 1; + + diff = (outStart - inStart) % inPeriod; + if (periodInput) + *periodInput = inPeriod; + if (periodOutput) + *periodOutput = outPeriod; + if (phase) + *phase = (diff < inPeriod) ? diff : diff - inPeriod; + + return true; +} \ No newline at end of file diff --git a/src/framesync.h b/src/framesync.h new file mode 100644 index 00000000..469c1b97 --- /dev/null +++ b/src/framesync.h @@ -0,0 +1,193 @@ +#ifndef FRAMESYNC_H_ +#define FRAMESYNC_H_ + +#include "utils.h" + +// fast digitalRead() +#if defined(ESP8266) + +#define digitalRead(x) ((GPIO_REG_READ(GPIO_IN_ADDRESS) >> x) & 1) + +#else // defined(ESP8266) + +// Arduino fastest, but non portable (Uno pin 11 = PB3, Mega2560 pin 11 = PB5) +// #define digitalRead(x) bitRead(PINB, 3) +#include "fastpin.h" +#define digitalRead(x) fastRead() +// no define for DEBUG_IN_PIN + +#endif // defined(ESP8266) + +void IRAM_ATTR _risingEdgeISR_measure(); +void IRAM_ATTR _risingEdgeISR_prepare(); +void MeasurePeriodStart(); + +// +// Sync locking tunables/magic numbers +// +struct FrameSyncAttrs +{ + static const uint8_t debugInPin = DEBUG_IN_PIN; + static const uint32_t lockInterval = 100 * 16.70; // every 100 frames + static const int16_t syncCorrection = 2; // Sync correction in scanlines to apply when phase lags target + static const int32_t syncTargetPhase = 90; // Target vsync phase offset (output trails input) in degrees + // to debug: syncTargetPhase = 343 lockInterval = 15 * 16 +}; + +class FrameSyncManager +{ +private: + typedef typename GBS::STATUS_VDS_VERT_COUNT VERT_COUNT; + typedef typename GBS::VDS_HSYNC_RST HSYNC_RST; + typedef typename GBS::VDS_VSYNC_RST VSYNC_RST; + typedef typename GBS::VDS_VS_ST VSST; + typedef typename GBS::template Tie VRST_SST; + + static const uint8_t debugInPin = FrameSyncAttrs::debugInPin; + static const int16_t syncCorrection = FrameSyncAttrs::syncCorrection; + static const int32_t syncTargetPhase = FrameSyncAttrs::syncTargetPhase; + + static bool syncLockReady; + static uint8_t delayLock; + static int16_t syncLastCorrection; + + /// Set to -1 if uninitialized. + /// Reset with syncLastCorrection. + static float maybeFreqExt_per_videoFps; + + // Sample vsync start and stop times from debug pin. + static bool vsyncOutputSample(uint32_t *start, uint32_t *stop); + + // Sample input and output vsync periods and their phase + // difference in microseconds + static bool vsyncPeriodAndPhase(int32_t *periodInput, int32_t *periodOutput, int32_t *phase); + + static bool sampleVsyncPeriods(uint32_t *input, uint32_t *output) + { + int32_t inPeriod, outPeriod; + + if (!vsyncPeriodAndPhase(&inPeriod, &outPeriod, NULL)) + return false; + + *input = inPeriod; + *output = outPeriod; + + return true; + } + + // Find appropriate htotal that makes output frame time slightly more than the input. + static bool findBestHTotal(uint32_t &bestHtotal); + +public: + FrameSyncManager() = delete; + // sets syncLockReady = ready() = false, which in turn starts a new init() + // -> findBestHtotal() run in loop() + static void reset(uint8_t frameTimeLockMethod); + + static void resetWithoutRecalculation() + { + syncLockReady = false; + delayLock = 0; + } + + static uint16_t init() + { + uint32_t bestHTotal = 0; + + // Adjust output horizontal sync timing so that the overall + // frame time is as close to the input as possible while still + // being less. Increasing the vertical frame size slightly + // should then push the output frame time to being larger than + // the input. + if (!findBestHTotal(bestHTotal)) { + return 0; + } + + syncLockReady = true; + delayLock = 0; + return (uint16_t)bestHTotal; + } + + static uint32_t getPulseTicks() + { + uint32_t inStart, inStop; + if (!vsyncInputSample(&inStart, &inStop)) { + return 0; + } + return inStop - inStart; + } + + static bool ready(void) + { + return syncLockReady; + } + + static int16_t getSyncLastCorrection() + { + return syncLastCorrection; + } + + static void cleanup() + { + #ifdef FRAMESYNC_DEBUG + _WSN(F("FrameSyncManager::cleanup(), reset video frequency")); + #endif + + syncLastCorrection = 0; // the important bit + syncLockReady = 0; + delayLock = 0; + + // Should we clear maybeFreqExt_per_videoFps? + // + // Clearing is hopefully safe. cleanup() appears to only be + // called when switching between 15 kHz and 31 kHz inputs, or + // when no video is present for an extended period of time and + // the output shuts off. (cleanup() is not called when switching + // between 240p and 480i.) When a new video signal is present, + // someone calls externalClockGenSyncInOutRate() -> + // FrameSync::initFrequency() to reinitialize the output frame + // sync. + // + // Not clearing is hopefully safe. See reset() for an + // explanation. + maybeFreqExt_per_videoFps = -1; + } + + // Sample vsync start and stop times from debug pin. + static bool vsyncInputSample(uint32_t *start, uint32_t *stop); + + // Perform vsync phase locking. This is accomplished by measuring + // the period and phase offset of the input and output vsync + // signals and adjusting the frame size (and thus the output vsync + // frequency) to bring the phase offset closer to the desired + // value. + static bool runVsync(uint8_t frameTimeLockMethod); + + static void clearFrequency() + { + maybeFreqExt_per_videoFps = -1; + } + + static void initFrequency(float outFramesPerS, uint32_t freqExtClockGen) + { + /* + This value can be interpreted in multiple ways: + + - Each output frame is a fixed number of video clocks long, at a + given output resolution. + - At a given output resolution, the video clock rate should be + proportional to the input FPS. + */ + maybeFreqExt_per_videoFps = (float)freqExtClockGen / outFramesPerS; + } + + // Perform vsync phase locking. This is accomplished by measuring + // the period and phase offset of the input and output vsync + // signals, then adjusting the output video clock to bring the phase + // offset closer to the desired value. + static bool runFrequency(); +}; + +typedef FrameSyncManager FrameSync; + +#endif // FRAMESYNC_H_ diff --git a/images.h b/src/images.h similarity index 100% rename from images.h rename to src/images.h diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..a3ba6c22 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,538 @@ +/* +########################################################################### +# File: main.cpp # +# File Created: Friday, 19th April 2024 3:13:38 pm # +# Author: Robert Neumann # +# Last Modified: Tuesday, 25th June 2024 12:48:15 pm # +# Modified By: Sergey Ko # +# # +# License: GPLv3 # +# GBS-Control # +# Copyright (C) 2024 # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program 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 General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +########################################################################### +*/ + +#include "options.h" +#include +#include +#include "wserial.h" +#include "presets.h" +#include "images.h" +#include "wifiman.h" +#include "menu.h" +#include "wserver.h" +#include "prefs.h" +// ESP8266-ping library to aid debugging WiFi issues, install via Arduino library manager +#ifdef HAVE_PINGER_LIBRARY +#include +#include +unsigned long pingLastTime; +Pinger pinger; // pinger global object to aid debugging WiFi issues +#endif + +#if defined(ESP8266) + // serial mirror class for websocket logs + SerialMirror SerialM; +#else + #define SerialM Serial +#endif + +Si5351mcu Si; +ESP8266WebServer server(80); +DNSServer dnsServer; +WebSocketsServer webSocket(81); +SSD1306Wire display(0x3c, D2, D1); // inits I2C address & pins for OLED + +runTimeOptions rto; +userOptions uopt; +adcOptions adco; +char serialCommand = '@'; // Serial / Web Server commands +char userCommand = '@'; // Serial / Web Server commands +unsigned long lastVsyncLock = 0; +unsigned long resetCountdown = 0; + +/** + * @brief Schedule the device reset + * + * @param millis + */ +void resetInMSec(unsigned long ms) { + if(ms != 0) + resetCountdown = ms + millis(); + if(resetCountdown == 0) + return; + if(millis() >= resetCountdown) { + server.stop(); + webSocket.close(); + LittleFS.end(); + _WSN(F("restarting...")); + delay(100); + ESP.reset(); + } +} + +/** + * @brief This function used to start communication with the board while setup() + * or restart communication after power loss + * (which is actually may never happen on production env.). + * + */ +inline bool powerLossBoardReinit() { + // software reset + utilsZeroAll(); + delay(10); + // put system in the default state + presetsResetParameters(); + prepareSyncProcessor(); + + // prefs data loaded, load current slot + if(!slotLoad(uopt.slotID)) + slotResetFlush(uopt.slotID); + + if(!utilsCheckBoardPower()) { + stopWire(); + _WSN(F("\n (!) Please check board power and cabling or restart\n")); + return false; + } + + if (uopt.enableCalibrationADC) { + // enabled by default + calibrateAdcOffset(); + } + + return true; +} + +/** + * @brief + * + */ +void setup() +{ + unsigned long initDelay = 0; + bool retryExtClockDetect = false; + // bool powerOrWireIssue = false; + lastVsyncLock = millis(); + + pinMode(DEBUG_IN_PIN, INPUT); + pinMode(LED_BUILTIN, OUTPUT); + pinMode(PIN_CLK, INPUT_PULLUP); + pinMode(PIN_DATA, INPUT_PULLUP); + pinMode(PIN_SWITCH, INPUT_PULLUP); + LEDON; // enable the LED, lets users know the board is starting up + + Serial.begin(115200); // Arduino IDE Serial Monitor requires the same 115200 bauds! + Serial.setTimeout(10); + + // filesystem (web page, custom presets, etc) + if (!LittleFS.begin()) { + _DBGN(F("FS mount failed ((1M FS) selected?)")); + return; + } + + // inits OLED on I2C bus + if(!display.init()) + _DBGN(F("display init failed")); + display.flipScreenVertically(); // orientation fix for OLED + + menuInit(); + + startWire(); + +#if WEB_SERVER_ENABLE == 1 + wifiInit(); + serverWebSocketInit(); + serverInit(); + +#ifdef HAVE_PINGER_LIBRARY + pingLastTime = millis(); + // pinger library + pinger.OnReceive([](const PingerResponse &response) { + if (response.ReceivedResponse) { + _DBGF( + PSTR("Reply from %s: time=%lums\n"), + response.DestIPAddress.toString().c_str(), + response.ResponseTime); + + pingLastTime = millis() - 900; // produce a fast stream of pings if connection is good + } else { + _DBGN(F("Request timed out.")); + } + + // Return true to continue the ping sequence. + // If current event returns false, the ping sequence is interrupted. + return true; + }); + + pinger.OnEnd([](const PingerResponse &response) { + // detailed info not necessary + return true; + }); +#endif // HAVE_PINGER_LIBRARY +#else // WEB_SERVER_ENABLE + wifiDisable(); +#endif // WEB_SERVER_ENABLE + + // Splash screen delay + initDelay = millis(); + // upped from < 500 to < 1500, allows more time for wifi and GBS startup + while (millis() - initDelay < 1500) { + display.drawXbm(2, 2, gbsicon_width, gbsicon_height, gbsicon_bits); + display.display(); + optimistic_yield(500); + } + display.clear(); + + // load user preferences file + if(!prefsLoad()) + prefsLoadDefaults(); + + GBS::PAD_CKIN_ENZ::write(1); // disable to prevent startup spike damage + if(utilsExternClockGenInit() == -1) { + retryExtClockDetect = true; + _DBGN(F("(!) unable to detect ext. clock, going to try later...")); + } + + // delay 2 of 2 + // initDelay = millis(); + // while (millis() - initDelay < 1000) { + // // wifiLoop(0); + // delay(10); + // } + + // if (powerOrWireIssue == 0) { + // second init, in cases where i2c got stuck earlier but has recovered + // *if* ext clock gen is installed and *if* i2c got stuck, then clockgen must be already running + if (!rto.extClockGenDetected && retryExtClockDetect + && utilsExternClockGenInit() != 1) { + _WSN(F("\n (!) No external clock detected\n")); + return; + } + + if(!powerLossBoardReinit()) + return; + + // some debug tools leave garbage in the serial rx buffer + discardSerialRxData(); + + _DBGF(PSTR("\n\n GBS-Control v.%s\n\n\nTV id: 0x%02X rev: 0x%02X\n"), + STRING(VERSION), + GBS::CHIP_ID_PRODUCT::read(), + GBS::CHIP_ID_REVISION::read() + ); + // system init is OK + rto.systemInitOK = true; + + LEDOFF; // LED behaviour: only light LED on active sync +} + + +void loop() +{ + // stay in loop_wrapper if setup has not been completed + if(!rto.systemInitOK) return; + + static unsigned long lastTimeSyncWatcher = millis(); + // 500 to start right away (after setup it will be 2790ms when we get here) + static unsigned long lastTimeSourceCheck = 500; + static unsigned long lastTimeInterruptClear = millis(); + + menuLoop(); + wifiLoop(); + + // run FrameTimeLock if enabled + if (uopt.enableFrameTimeLock && !rto.sourceDisconnected + && rto.autoBestHtotalEnabled && rto.syncWatcherEnabled + && FrameSync::ready() && millis() - lastVsyncLock > FrameSyncAttrs::lockInterval + && rto.continousStableCounter > 20 && rto.noSyncCounter == 0) + { + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); + + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); + if (debug_backup != 0x0) { + GBS::TEST_BUS_SEL::write(0x0); + } + // unsigned long startTime = millis(); + _DBGF( + PSTR("running frame sync, clock gen enabled = %d\n"), + rto.extClockGenDetected + ); + bool success = rto.extClockGenDetected ? FrameSync::runFrequency() : FrameSync::runVsync(uopt.frameTimeLockMethod); + if (!success) { + if (rto.syncLockFailIgnore-- == 0) { + FrameSync::reset(uopt.frameTimeLockMethod); // in case run() failed because we lost sync signal + } + } else if (rto.syncLockFailIgnore > 0) { + rto.syncLockFailIgnore = 16; + } + // _WSN(millis() - startTime); + + if (debug_backup != 0x0) { + GBS::TEST_BUS_SEL::write(debug_backup); + } + } + lastVsyncLock = millis(); + } + + // syncWatcherEnabled is enabled by-default + if (rto.syncWatcherEnabled && rto.boardHasPower) { + if ((millis() - lastTimeInterruptClear) > 3000) { + GBS::INTERRUPT_CONTROL_00::write(0xfe); // reset except for SOGBAD + GBS::INTERRUPT_CONTROL_00::write(0x00); + lastTimeInterruptClear = millis(); + } + } + + // TODO heavy load for serial and WS. to reimplement + if (rto.printInfos) { + printInfo(); + } + // uint16_t testbus = GBS::TEST_BUS::read() & 0x0fff; + // if (testbus >= 0x0FFD){ + // _WSN(testbus,HEX); + // } + // if (rto.videoIsFrozen && (rto.continousStableCounter >= 2)) { + // unfreezeVideo(); + // } + + // syncwatcher polls SP status. when necessary, initiates adjustments or preset changes + if (!rto.sourceDisconnected && rto.syncWatcherEnabled + && (millis() - lastTimeSyncWatcher) > 20) + { + runSyncWatcher(); + lastTimeSyncWatcher = millis(); + + // auto adc gain + if (uopt.enableAutoGain && !rto.sourceDisconnected + && rto.videoStandardInput > 0 && rto.clampPositionIsSet + && rto.noSyncCounter == 0 && rto.continousStableCounter > 90 + && rto.boardHasPower) + { + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + uint8_t debugRegBackup = 0, debugPinBackup = 0; + debugPinBackup = GBS::PAD_BOUT_EN::read(); + debugRegBackup = GBS::TEST_BUS_SEL::read(); + GBS::PAD_BOUT_EN::write(0); // disable output to pin for test + GBS::DEC_TEST_SEL::write(1); // luma and G channel + GBS::TEST_BUS_SEL::write(0xb); // decimation + if (GBS::STATUS_INT_SOG_BAD::read() == 0) { + runAutoGain(); + } + GBS::TEST_BUS_SEL::write(debugRegBackup); + GBS::PAD_BOUT_EN::write(debugPinBackup); // debug output pin back on + } + } + } + + // init frame sync + besthtotal routine + // autoBestHtotalEnabled is enabled by default + if (rto.autoBestHtotalEnabled && !FrameSync::ready() && rto.syncWatcherEnabled) { + if (rto.continousStableCounter >= 10 && rto.coastPositionIsSet && + ((millis() - lastVsyncLock) > 500)) { + if ((rto.continousStableCounter % 5) == 0) { // 5, 10, 15, .., 255 + uint16_t htotal = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + uint16_t pllad = GBS::PLLAD_MD::read(); + if (((htotal > (pllad - 3)) && (htotal < (pllad + 3)))) { + runAutoBestHTotal(); + } + } + } + } + + // update clamp + coast positions after preset change // do it quickly + if (rto.videoStandardInput <= 14 && rto.videoStandardInput != 0 && + rto.syncWatcherEnabled && !rto.coastPositionIsSet) { + if (rto.continousStableCounter >= 7) { + if (getStatus16SpHsStable() && getVideoMode() == rto.videoStandardInput) { + updateCoastPosition(0); + if (rto.coastPositionIsSet && videoStandardInputIsPalNtscSd()) { + // TODO: verify for other csync formats + GBS::SP_DIS_SUB_COAST::write(0); // enable 5_3e 5 + GBS::SP_H_PROTECT::write(0); // no 5_3e 4 + } + } + } + } + + // don't exclude modes 13 / 14 / 15 (rgbhv bypass) + if (rto.videoStandardInput != 0 && rto.continousStableCounter >= 4 && + !rto.clampPositionIsSet && rto.syncWatcherEnabled) { + updateClampPosition(); + if (rto.clampPositionIsSet && GBS::SP_NO_CLAMP_REG::read() == 1) { + GBS::SP_NO_CLAMP_REG::write(0); + } + } + + // later stage post preset adjustments + if (rto.applyPresetDoneStage == 1 && + ((rto.continousStableCounter > 35 && rto.continousStableCounter < 45) || // this + !rto.syncWatcherEnabled)) // or that + { + if (rto.applyPresetDoneStage == 1) { + // 2nd chance + GBS::DAC_RGBS_PWDNZ::write(1); // 2nd chance + if (!uopt.wantOutputComponent) { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 2nd chance + } + if (!rto.syncWatcherEnabled) { + updateClampPosition(); + GBS::SP_NO_CLAMP_REG::write(0); // 5_57 0 + } + + if (rto.extClockGenDetected && rto.videoStandardInput != 14) { + // switch to ext clock + // if (!rto.outModeHdBypass) { + if (utilsNotPassThroughMode()) { + uint8_t pll648_value = GBS::PLL648_CONTROL_01::read(); + if (pll648_value != 0x35 && pll648_value != 0x75) { + // first store original in an option byte in 1_2D + // GBS::GBS_PRESET_DISPLAY_CLOCK::write(pll648_value); + rto.presetDisplayClock = pll648_value; + // enable and switch input + Si.enable(0); + delayMicroseconds(800); + GBS::PLL648_CONTROL_01::write(0x75); + } + } + // sync clocks now + externalClockGenSyncInOutRate(); + } + rto.applyPresetDoneStage = 0; + } + } else if (rto.applyPresetDoneStage == 1 && rto.continousStableCounter > 35) { + // 3rd chance + GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC // 3rd chance + if (!uopt.wantOutputComponent) { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // 3rd chance + } + + // sync clocks now + externalClockGenSyncInOutRate(); + rto.applyPresetDoneStage = 0; // timeout + } + + if (rto.applyPresetDoneStage == 10) { + rto.applyPresetDoneStage = 11; // set first, so we don't loop applying presets + // registers uninitialized, do post preset + setOutputHdBypassMode(false); + } + + // Input signal detection + if (rto.syncWatcherEnabled && rto.sourceDisconnected && rto.boardHasPower) { + if ((millis() - lastTimeSourceCheck) >= 500) { + if (utilsCheckBoardPower()) { + inputAndSyncDetect(); + } else { + // rto.boardHasPower = false; + // rto.continousStableCounter = 0; + // rto.syncWatcherEnabled = false; + } + lastTimeSourceCheck = millis(); + + // vary SOG slicer level from 2 to 6 + uint8_t currentSOG = GBS::ADC_SOGCTRL::read(); + if (currentSOG >= 3) { + rto.currentLevelSOG = currentSOG - 1; + GBS::ADC_SOGCTRL::write(rto.currentLevelSOG); + } else { + rto.currentLevelSOG = 6; + GBS::ADC_SOGCTRL::write(rto.currentLevelSOG); + } + } + } + + // has the GBS board lost power? + // check at 2 points, in case one doesn't register + // low values chosen to not do this check on small sync issues + if ((rto.noSyncCounter == 61 || rto.noSyncCounter == 62) && rto.boardHasPower) { + if (!utilsCheckBoardPower()) { + rto.noSyncCounter = 1; // some neutral "no sync" value + // rto.continousStableCounter = 0; + // rto.syncWatcherEnabled = false; + stopWire(); // sets pinmodes SDA, SCL to INPUT + _DBGN(F("(!) TWI has been stopped")); + } else { + rto.noSyncCounter = 63; // avoid checking twice + } + } + + // power good now? + // added syncWatcherEnabled check to enable passive mode + // (passive mode = watching OFW without interrupting) + if (!rto.boardHasPower && rto.syncWatcherEnabled) { // then check if power has come on + if (digitalRead(SCL) && digitalRead(SDA)) { + delay(50); + if (digitalRead(SCL) && digitalRead(SDA)) { + _DBGN(F("(!) board power recovered")); + delay(350); // i've seen the MTV230 go on briefly on GBS power cycle + startWire(); + delay(10); + if(powerLossBoardReinit()) { + // { + // // run some dummy commands to init I2C + // writeOneByte(0xF0, 0); + // GBS::SP_SOG_MODE::read(); + // GBS::SP_SOG_MODE::read(); + // // writeOneByte(0x00, 0); // update cached segment + // GBS::STATUS_00::read(); + // } + // rto.syncWatcherEnabled = true; + // utilsCheckBoardPower(); + // rto.boardHasPower = true; + delay(10); + goLowPowerWithInputDetection(); + } + } + } + } + +#ifdef HAVE_PINGER_LIBRARY + // periodic pings for debugging WiFi issues + if (WiFi.status() == WL_CONNECTED) { + if (rto.enableDebugPings && millis() - pingLastTime > 1000) { + // regular interval pings + if (pinger.Ping(WiFi.gatewayIP(), 1, 750) == false) { + _WSN(F("Error during last ping command.")); + } + pingLastTime = millis(); + } + } +#endif // HAVE_PINGER_LIBRARY + + // Serial takes precedence + handleSerialCommand(); + // skip the code below if we don't have the web server +#if WEB_SERVER_ENABLE == 1 + // handle user commands + handleUserCommand(); + // web client handler + server.handleClient(); + MDNS.update(); + dnsServer.processNextRequest(); + // websocket event handler + webSocket.loop(); + // handle ArduinoIDE + if (rto.allowUpdatesOTA) { + ArduinoOTA.handle(); + } +#endif + // handle reset routine + resetInMSec(); +} diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 00000000..7f1f5e6e --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,863 @@ +/* +########################################################################### +# File: menu.cpp # +# File Created: Thursday, 2nd May 2024 11:31:34 pm # +# Author: # +# Last Modified: Monday, 24th June 2024 1:36:31 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#include "menu.h" + +#ifdef HAVE_BUTTONS + +static const uint8_t historySize = 32; +static const uint16_t buttonPollInterval = 100; // microseconds +static uint8_t buttonHistory[historySize]; +static uint8_t buttonIndex; +static uint8_t buttonState; +static uint8_t buttonChanged; + +uint8_t readButtons(void) +{ + return ~((digitalRead(PIN_DATA) << INPUT_SHIFT) | + (digitalRead(PIN_CLK) << DOWN_SHIFT) | + (digitalRead(PIN_DATA) << UP_SHIFT) | + (digitalRead(PIN_SWITCH) << MENU_SHIFT)); +} + +void debounceButtons(void) +{ + buttonHistory[buttonIndex++ % historySize] = readButtons(); + buttonChanged = 0xFF; + for (uint8_t i = 0; i < historySize; ++i) + buttonChanged &= buttonState ^ buttonHistory[i]; + buttonState ^= buttonChanged; +} + +bool buttonDown(uint8_t pos) +{ + return (buttonState & (1 << pos)) && (buttonChanged & (1 << pos)); +} + +#endif // HAVE_BUTTONS + +#if !USE_NEW_OLED_MENU + +static String oled_menu[4] = {"Resolutions", "Presets", "Misc.", "Current Settings"}; +static String oled_Resolutions[7] = {"1280x960", "1280x1024", "1280x720", "1920x1080", "480/576", "Downscale", "Pass-Through"}; +static String oled_Presets[8] = {"1", "2", "3", "4", "5", "6", "7", "Back"}; +static String oled_Misc[4] = {"Reset GBS", "Restore Factory", "-----Back"}; + +static int oled_menuItem = 1; +static int oled_subsetFrame = 0; +static int oled_selectOption = 0; +static int oled_page = 0; + +static int oled_lastCount = 0; +static volatile int oled_encoder_pos = 0; +static volatile int oled_main_pointer = 0; // volatile vars change done with ISR +static volatile int oled_pointer_count = 0; +static volatile int oled_sub_pointer = 0; + +#ifdef HAVE_BUTTONS + +void handleButtons(void) +{ + debounceButtons(); + if (buttonDown(INPUT_SHIFT)) + Menu::run(MenuInput::BACK); + if (buttonDown(DOWN_SHIFT)) + Menu::run(MenuInput::DOWN); + // if (buttonDown(UP_SHIFT)) + // Menu::run(MenuInput::UP); + if (buttonDown(MENU_SHIFT)) + Menu::run(MenuInput::FORWARD); +} + +#endif // HAVE_BUTTONS + +void IRAM_ATTR isrRotaryEncoder() +{ + static unsigned long lastInterruptTime = 0; + unsigned long interruptTime = millis(); + + if (interruptTime - lastInterruptTime > 120) { + if (!digitalRead(PIN_DATA)) { + oled_encoder_pos++; + oled_main_pointer += 15; + oled_sub_pointer += 15; + oled_pointer_count++; + // down = true; + // up = false; + } else { + oled_encoder_pos--; + oled_main_pointer -= 15; + oled_sub_pointer -= 15; + oled_pointer_count--; + // down = false; + // up = true; + } + } + lastInterruptTime = interruptTime; +} + +// OLED Functionality +void settingsMenuOLED() +{ + uint8_t videoMode = getVideoMode(); + byte button_nav = digitalRead(PIN_SWITCH); + if (button_nav == LOW) { + delay(350); // TODO + oled_subsetFrame++; // this button counter for navigating menu + oled_selectOption++; + } + // main menu + if (oled_page == 0) { + pointerfunction(); + display.clear(); + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setFont(ArialMT_Plain_16); + display.drawString(0, oled_main_pointer, ">"); + display.drawString(14, 0, String(oled_menu[0])); + display.drawString(14, 15, String(oled_menu[1])); + display.drawString(14, 30, String(oled_menu[2])); + display.drawString(14, 45, String(oled_menu[3])); + display.display(); + } + // cursor location on main menu + if (oled_main_pointer == 0 && oled_subsetFrame == 0) { + oled_pointer_count = 0; + oled_menuItem = 1; + } + if (oled_main_pointer == 15 && oled_subsetFrame == 0) { + oled_pointer_count = 0; + oled_menuItem = 2; + } + if (oled_main_pointer == 30 && oled_subsetFrame == 0) { + oled_pointer_count = 0; + oled_sub_pointer = 0; + oled_menuItem = 3; + } + if (oled_main_pointer == 45 && oled_subsetFrame == 0) { + oled_pointer_count = 0; + oled_menuItem = 4; + } + + + // resolution pages + if (oled_menuItem == 1 && oled_subsetFrame == 1) { + oled_page = 1; + oled_main_pointer = 0; + subpointerfunction(); + display.clear(); + display.drawString(0, oled_sub_pointer, ">"); + display.drawString(14, 0, String(oled_Resolutions[0])); + display.drawString(14, 15, String(oled_Resolutions[1])); + display.drawString(14, 30, String(oled_Resolutions[2])); + display.drawString(14, 45, String(oled_Resolutions[3])); + display.display(); + } else if (oled_menuItem == 1 && oled_subsetFrame == 2) { + subpointerfunction(); + oled_page = 2; + display.clear(); + display.drawString(0, oled_sub_pointer, ">"); + display.drawString(14, 0, String(oled_Resolutions[4])); + display.drawString(14, 15, String(oled_Resolutions[5])); + display.drawString(14, 30, String(oled_Resolutions[6])); + display.drawString(14, 45, "-----Back"); + display.display(); + if (oled_sub_pointer <= -15) { + oled_page = 1; + oled_subsetFrame = 1; + oled_sub_pointer = 45; + display.clear(); + } else if (oled_sub_pointer > 45) { + oled_page = 2; + oled_subsetFrame = 2; + oled_sub_pointer = 45; + } + } + // selection + // 1280x960 + if (oled_menuItem == 1) { + if (oled_pointer_count == 0 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "1280x960"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + // uopt.presetPreference = Output960P; + uopt.resolutionID = Output960; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 1; + } + // 1280x1024 + if (oled_pointer_count == 1 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "1280x1024"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + // uopt.presetPreference = Output1024P; + uopt.resolutionID = Output1024; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 1; + } + // 1280x720 + if (oled_pointer_count == 2 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "1280x720"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + // uopt.presetPreference = Output720P; + uopt.resolutionID = Output720; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 1; + } + // 1920x1080 + if (oled_pointer_count == 3 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "1920x1080"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + // uopt.presetPreference = Output1080P; + uopt.resolutionID = Output1080; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 1; + } + // 720x480 + if (oled_pointer_count == 4 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "480/576"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + uopt.resolutionID = Output480; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 2; + } + // downscale + if (oled_pointer_count == 5 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "Downscale"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; + // uopt.presetPreference = OutputDownscale; + uopt.resolutionID = Output15kHz; + rto.useHdmiSyncFix = 1; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(videoMode); + } + oled_selectOption = 1; + oled_subsetFrame = 2; + } + // passthrough/bypass + if (oled_pointer_count == 6 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "Pass-Through"); + display.drawString(0, 30, "Loaded!"); + display.display(); + } + // registers uninitialized do post preset + setOutputHdBypassMode(false); + // uopt.presetPreference = OutputBypass; + // if (uopt.presetPreference == 10 && rto.videoStandardInput != 15) { + if (rto.videoStandardInput != 15) { + rto.autoBestHtotalEnabled = 0; + if (rto.applyPresetDoneStage == 11) { + rto.applyPresetDoneStage = 1; + } else { + rto.applyPresetDoneStage = 10; + } + } else { + rto.applyPresetDoneStage = 1; + } + presetSaveToFS(); + oled_selectOption = 1; + oled_subsetFrame = 2; + } + // go back + if (oled_pointer_count == 7 && oled_selectOption == 2) { + oled_page = 0; + oled_subsetFrame = 0; + oled_main_pointer = 0; + oled_sub_pointer = 0; + oled_selectOption = 0; + } + } + // Presets pages + if (oled_menuItem == 2 && oled_subsetFrame == 1) { + oled_page = 1; + oled_main_pointer = 0; + subpointerfunction(); + display.clear(); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset Slot:"); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, String(oled_Presets[oled_pointer_count])); + display.display(); + } else if (oled_menuItem == 2 && oled_subsetFrame == 2) { + oled_page = 2; + subpointerfunction(); + display.clear(); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset Slot:"); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, String(oled_Presets[oled_pointer_count])); + display.display(); + } + // Preset selection + if (oled_menuItem == 2) { + if (oled_pointer_count == 0 && oled_selectOption == 2) { + oled_subsetFrame = 3; + uopt.slotID = 0; + // uopt.slotID = 'A'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); // first array element selected + display.drawString(64, -8, "Preset #" + String(oled_Presets[0])); // set to frame that "doesnt exist" + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); // display loading conf + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); // allowing "catchup" + oled_selectOption = 1; // reset select container + oled_subsetFrame = 1; // switch back to prev frame (prev screen) + } + if (oled_pointer_count == 1 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'B'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[1])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 1; + } + if (oled_pointer_count == 2 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'C'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[2])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 1; + } + if (oled_pointer_count == 3 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'D'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[3])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 1; + } + if (oled_pointer_count == 4 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'E'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[4])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 2; + } + if (oled_pointer_count == 5 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'F'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[5])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 2; + } + if (oled_pointer_count == 6 && oled_selectOption == 2) { + oled_subsetFrame = 3; + // uopt.slotID = 'G'; + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + // saveUserPrefs(); + for (int i = 0; i <= 280; i++) { + display.clear(); + display.setFont(Open_Sans_Regular_20); + display.drawString(64, -8, "Preset #" + String(oled_Presets[6])); + display.setFont(Open_Sans_Regular_35); + display.drawString(64, 15, "Loaded!"); + display.display(); + } + // uopt.presetPreference = OutputCustomized; + uopt.resolutionID = OutputCustom; + if (rto.videoStandardInput == 14) { + rto.videoStandardInput = 15; + } else { + applyPresets(rto.videoStandardInput); + } + delay(50); + oled_selectOption = 1; + oled_subsetFrame = 2; + } + if (oled_pointer_count == 7 && oled_selectOption == 2) { + oled_page = 0; + oled_subsetFrame = 0; + oled_main_pointer = 0; + oled_sub_pointer = 0; + oled_selectOption = 0; + } + } + // Misc pages + if (oled_menuItem == 3 && oled_subsetFrame == 1) { + oled_page = 1; + oled_main_pointer = 0; + subpointerfunction(); + display.clear(); + display.drawString(0, oled_sub_pointer, ">"); + display.drawString(14, 0, String(oled_Misc[0])); + display.drawString(14, 15, String(oled_Misc[1])); + display.drawString(14, 45, String(oled_Misc[2])); + display.display(); + if (oled_sub_pointer <= 0) { + oled_sub_pointer = 0; + } + if (oled_sub_pointer >= 45) { + oled_sub_pointer = 45; + } + } + // Misc selection + if (oled_menuItem == 3) { + if (oled_pointer_count == 0 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "Resetting GBS"); + display.drawString(0, 30, "Please Wait..."); + display.display(); + } + resetInMSec(1000); + // oled_selectOption = 0; + // oled_subsetFrame = 0; + } + + if (oled_pointer_count == 1 && oled_selectOption == 2) { + oled_subsetFrame = 3; + for (int i = 0; i <= 800; i++) { + display.clear(); + display.drawString(0, 10, "Defaults Loading"); + display.drawString(0, 30, "Please Wait..."); + display.display(); + } + // webSocket.close(); + prefsLoadDefaults(); + // saveUserPrefs(); + prefsSave(); + // delay(60); + // ESP.reset(); + resetInMSec(2000); + // oled_selectOption = 1; + // oled_subsetFrame = 1; + } + + if (oled_pointer_count == 3 && oled_selectOption == 2) { + oled_page = 0; + oled_subsetFrame = 0; + oled_main_pointer = 0; + oled_sub_pointer = 0; + oled_selectOption = 0; + } + } + // Current Settings pages + if (oled_menuItem == 4 && oled_subsetFrame == 1) { + bool vsyncActive = 0; + bool hsyncActive = 0; + float ofr = getOutputFrameRate(); + uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); + // rto.presetID = GBS::GBS_PRESET_ID::read(); + uopt.resolutionID = static_cast(GBS::GBS_PRESET_ID::read()); + + oled_page = 1; + oled_pointer_count = 0; + oled_main_pointer = 0; + + subpointerfunction(); + display.clear(); + display.setFont(URW_Gothic_L_Book_20); + display.setTextAlignment(TEXT_ALIGN_LEFT); + + // if (rto.presetID == 0x01 || rto.presetID == 0x11) { + if (uopt.resolutionID == Output960 || uopt.resolutionID == Output960PAL) { + display.drawString(0, 0, "1280x960"); + // } else if (rto.presetID == 0x02 || rto.presetID == 0x12) { + } else if (uopt.resolutionID == Output1024 || uopt.resolutionID == Output1024PAL) { + display.drawString(0, 0, "1280x1024"); + // } else if (rto.presetID == 0x03 || rto.presetID == 0x13) { + } else if (uopt.resolutionID == Output720 || uopt.resolutionID == Output720PAL) { + display.drawString(0, 0, "1280x720"); + // } else if (rto.presetID == 0x05 || rto.presetID == 0x15) { + } else if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) { + display.drawString(0, 0, "1920x1080"); + // } else if (rto.presetID == 0x06 || rto.presetID == 0x16) { + } else if (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL) { + display.drawString(0, 0, "Downscale"); + // } else if (rto.presetID == 0x04) { + } else if (uopt.resolutionID == Output480) { + display.drawString(0, 0, "720x480"); + // } else if (rto.presetID == 0x14) { + } else if (uopt.resolutionID == Output576PAL) { + display.drawString(0, 0, "768x576"); + } else if (utilsIsPassThroughMode()) { + display.drawString(0, 0, "bypass"); + } else { + display.drawString(0, 0, "240p"); + } + + display.drawString(0, 20, String(ofr, 5) + "Hz"); + + if (currentInput == 1) { + display.drawString(0, 41, "RGB"); + } else { + display.drawString(0, 41, "YpBpR"); + } + + if (currentInput == 1) { + vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); + if (vsyncActive) { + display.drawString(70, 41, "V"); + hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); + if (hsyncActive) { + display.drawString(53, 41, "H"); + } + } + } + display.display(); + } + // current setting Selection + if (oled_menuItem == 4) { + if (oled_pointer_count >= 0 && oled_selectOption == 2) { + oled_page = 0; + oled_subsetFrame = 0; + oled_main_pointer = 0; + oled_sub_pointer = 0; + oled_selectOption = 0; + } + } +} + +void pointerfunction() +{ + if (oled_main_pointer <= 0) { + oled_main_pointer = 0; + } + if (oled_main_pointer >= 45) { // limits + oled_main_pointer = 45; + } + + if (oled_pointer_count <= 0) { + oled_pointer_count = 0; + } else if (oled_pointer_count >= 3) { + oled_pointer_count = 3; + } +} + +void subpointerfunction() +{ + if (oled_sub_pointer < 0) { + oled_sub_pointer = 0; + oled_subsetFrame = 1; + oled_page = 1; + } + if (oled_sub_pointer > 45) { // limits to switch between the two pages + oled_sub_pointer = 0; // TODO + oled_subsetFrame = 2; + oled_page = 2; + } + // } if (sub_pointer <= -15){ //TODO: replace/take out + // sub_pointer = 0; + // page = 1; + // subsetFrame = 1; + // } + if (oled_pointer_count <= 0) { + oled_pointer_count = 0; + } else if (oled_pointer_count >= 7) { + oled_pointer_count = 7; + } +} + + +#else // \! USE_NEW_OLED_MENU + +OLEDMenuManager oledMenu(&display); +OSDManager osdManager; +volatile OLEDMenuNav oledNav = OLEDMenuNav::IDLE; +volatile uint8_t rotaryIsrID = 0; + +#ifdef HAVE_BUTTONS + +void handleButtons(void) +{ + OLEDMenuNav btn = OLEDMenuNav::IDLE; + debounceButtons(); + if (buttonDown(MENU_SHIFT)) + btn = OLEDMenuNav::ENTER; + if (buttonDown(DOWN_SHIFT)) + btn = OLEDMenuNav::UP; + if (buttonDown(UP_SHIFT)) + btn = OLEDMenuNav::DOWN; + oledMenu.tick(btn); +} + +#endif // HAVE_BUTTONS + +/** + * @brief + * + */ +void IRAM_ATTR isrRotaryEncoderRotateForNewMenu() +{ + unsigned long interruptTime = millis(); + static unsigned long lastInterruptTime = 0; + static unsigned long lastNavUpdateTime = 0; + static OLEDMenuNav lastNav; + OLEDMenuNav newNav; + if (interruptTime - lastInterruptTime > 150) { + if (!digitalRead(PIN_DATA)) { + newNav = REVERSE_ROTARY_ENCODER_FOR_OLED_MENU ? OLEDMenuNav::DOWN : OLEDMenuNav::UP; + } else { + newNav = REVERSE_ROTARY_ENCODER_FOR_OLED_MENU ? OLEDMenuNav::UP : OLEDMenuNav::DOWN; + } + if (newNav != lastNav && (interruptTime - lastNavUpdateTime < 120)) { + // ignore rapid changes to filter out mis-reads. besides, you are not supposed to rotate the encoder this fast anyway + oledNav = lastNav = OLEDMenuNav::IDLE; + } else { + lastNav = oledNav = newNav; + ++rotaryIsrID; + lastNavUpdateTime = interruptTime; + } + lastInterruptTime = interruptTime; + } +} + +/** + * @brief + * + */ +void IRAM_ATTR isrRotaryEncoderPushForNewMenu() +{ + static unsigned long lastInterruptTime = 0; + unsigned long interruptTime = millis(); + if (interruptTime - lastInterruptTime > 500) { + oledNav = OLEDMenuNav::ENTER; + ++rotaryIsrID; + } + lastInterruptTime = interruptTime; +} + +#endif // \! USE_NEW_OLED_MENU + +/** + * @brief + * + */ +void menuInit() { + oledMenu.init(); + +#if USE_NEW_OLED_MENU + + attachInterrupt(digitalPinToInterrupt(PIN_CLK), isrRotaryEncoderRotateForNewMenu, FALLING); + attachInterrupt(digitalPinToInterrupt(PIN_SWITCH), isrRotaryEncoderPushForNewMenu, FALLING); + initOLEDMenu(); + initOSD(); + +#else // USE_NEW_OLED_MENU + + // ISR TO PIN + attachInterrupt(digitalPinToInterrupt(PIN_CLK), isrRotaryEncoder, FALLING); + +#endif // USE_NEW_OLED_MENU +} + +/** + * @brief + * + */ +void menuLoop() { +#ifdef HAVE_BUTTONS + static unsigned long lastButton = micros(); + if (micros() - lastButton > buttonPollInterval) { + lastButton = micros(); + handleButtons(); + } +#endif // HAVE_BUTTONS + +#if USE_NEW_OLED_MENU != 1 + + settingsMenuOLED(); + if (oled_encoder_pos != oled_lastCount) { + oled_lastCount = oled_encoder_pos; + } + +#else // \! USE_NEW_OLED_MENU + + uint8_t oldIsrID = rotaryIsrID; + // make sure no rotary encoder isr happened while menu was updating. + // skipping this check will make the rotary encoder not responsive randomly. + // (oledNav change will be lost if isr happened during menu updating) + oledMenu.tick(oledNav); + if (oldIsrID == rotaryIsrID) { + oledNav = OLEDMenuNav::IDLE; + } + +#endif // \! USE_NEW_OLED_MENU +} \ No newline at end of file diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 00000000..26d23979 --- /dev/null +++ b/src/menu.h @@ -0,0 +1,43 @@ +/* +########################################################################### +# File: menu.h # +# File Created: Thursday, 2nd May 2024 11:31:43 pm # +# Author: # +# Last Modified: Sunday, 5th May 2024 4:01:54 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#ifndef _MENU_H_ +#define _MENU_H_ + +#include +#include "options.h" +#include "wserial.h" + +extern SSD1306Wire display; + +void handleButtons(void); + +#if !USE_NEW_OLED_MENU + +void IRAM_ATTR isrRotaryEncoder(); +void settingsMenuOLED(); +void pointerfunction(); +void subpointerfunction(); + +#else // \! USE_NEW_OLED_MENU + +#include "OLEDMenuImplementation.h" + +void IRAM_ATTR isrRotaryEncoderRotateForNewMenu(); +void IRAM_ATTR isrRotaryEncoderPushForNewMenu(); + +#endif // \! USE_NEW_OLED_MENU + +void menuInit(); +void menuLoop(); + +#endif // _MENU_H_ diff --git a/ntsc_1280x1024.h b/src/ntsc_1280x1024.h similarity index 100% rename from ntsc_1280x1024.h rename to src/ntsc_1280x1024.h diff --git a/ntsc_1280x720.h b/src/ntsc_1280x720.h similarity index 100% rename from ntsc_1280x720.h rename to src/ntsc_1280x720.h diff --git a/ntsc_1920x1080.h b/src/ntsc_1920x1080.h similarity index 100% rename from ntsc_1920x1080.h rename to src/ntsc_1920x1080.h diff --git a/ntsc_240p.h b/src/ntsc_240p.h similarity index 100% rename from ntsc_240p.h rename to src/ntsc_240p.h diff --git a/ntsc_720x480.h b/src/ntsc_720x480.h similarity index 100% rename from ntsc_720x480.h rename to src/ntsc_720x480.h diff --git a/ntsc_downscale.h b/src/ntsc_downscale.h similarity index 100% rename from ntsc_downscale.h rename to src/ntsc_downscale.h diff --git a/ofw_RGBS.h b/src/ofw_RGBS.h similarity index 99% rename from ofw_RGBS.h rename to src/ofw_RGBS.h index a4fc0470..28a3b43c 100644 --- a/ofw_RGBS.h +++ b/src/ofw_RGBS.h @@ -1,3 +1,6 @@ +// +// !UNUSED +// const uint8_t ofw_RGBS[] PROGMEM = { 0x7C, // s0_40 0x45, // s0_41 @@ -495,4 +498,4 @@ const uint8_t ofw_RGBS[] PROGMEM = { 0x0, // s5_6D 0x0, // s5_6E 0x0, // s5_6F -}; +}; \ No newline at end of file diff --git a/ofw_ypbpr.h b/src/ofw_ypbpr.h similarity index 100% rename from ofw_ypbpr.h rename to src/ofw_ypbpr.h diff --git a/src/options.h b/src/options.h new file mode 100644 index 00000000..d8ee186a --- /dev/null +++ b/src/options.h @@ -0,0 +1,332 @@ +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +#if defined(ESP8266) + #include +#else + #include +#endif + +// options +// #define FRAMESYNC_DEBUG +// #define FRAMESYNC_DEBUG_LED // just blink LED (off = adjust phase, on = normal phase) +// #define HAVE_BUTTONS +// #define HAVE_PINGER_LIBRARY +#define DEBUG_CODE_ENABLE // include/exclude commented code blocks used only for development +#define PIN_CLK 14 // D5 = GPIO14 (input of one direction for encoder) +#define PIN_DATA 13 // D7 = GPIO13 (input of one direction for encoder) +#define PIN_SWITCH 0 // D3 = GPIO0 pulled HIGH, else boot fail (middle push button for encoder) +#define MENU_WIDTH 131 +#define MENU_HEIGHT 19 +#define AUTO_GAIN_INIT 0x48 +#define SCANLINE_STRENGTH_INIT 0x30 +#define WEBSOCK_HBEAT_INTVAL 1500UL +#define WEBSOCK_HBEAT_PONG_TOUT 1500UL +#define WEBSOCK_HBEAT_DISCONN_CNT 5 +#define WEBSOCK_HBEAT_DEV_INTVAL 600UL +#define WEBSOCK_HBEAT_DEV_PONG_TOUT 1500UL +#define WEBSOCK_HBEAT_DEV_DISCONN_CNT 3 +#define THIS_DEVICE_MASTER +#define WEB_SERVER_ENABLE 1 +#ifdef HAVE_BUTTONS +#define INPUT_SHIFT 0 +#define DOWN_SHIFT 1 +#define UP_SHIFT 2 +#define MENU_SHIFT 3 +#define BACK_SHIFT 4 +#endif // HAVE_BUTTONS +#if !defined(SERIAL_BUFFER_MAX_LEN) +#define SERIAL_BUFFER_MAX_LEN 1024UL // use a number aligned with 4 +#endif // SERIAL_BUFFER_MAX_LEN +#if !defined(DISPLAY_SDA) +// SDA = D2 (Lolin), D14 (Wemos D1) // ESP8266 Arduino default map: SDA +#define DISPLAY_SDA D2 +#endif // DISPLAY_SDA +#if !defined(DISPLAY_SCL) +// SCL = D1 (Lolin), D15 (Wemos D1) // ESP8266 Arduino default map: SCL +#define DISPLAY_SCL D1 +#endif // DISPLAY_SCL +#if !defined(DEBUG_IN_PIN) +// marked "D12/MISO/D6" (Wemos D1) or D6 (Lolin NodeMCU) +#define DEBUG_IN_PIN D6 // 12 +#endif // DEBUG_IN_PIN +#ifndef SLOTS_TOTAL +#define SLOTS_TOTAL 50 // max number of slots (UI: GBSControl.maxSlots) +#endif // SLOTS_TOTAL + +#ifndef USE_NEW_OLED_MENU +#define USE_NEW_OLED_MENU 1 +#endif // USE_NEW_OLED_MENU +#define OLED_MENU_WIDTH 128 +#define OLED_MENU_HEIGHT 64 +#ifndef OLED_MENU_MAX_ITEMS_NUM +#define OLED_MENU_MAX_ITEMS_NUM 64 // should be less than 1024 +#endif // OLED_MENU_MAX_ITEMS_NUM +#ifndef OLED_MENU_MAX_SUBITEMS_NUM +#define OLED_MENU_MAX_SUBITEMS_NUM 16 // should be less than 256 +#endif // OLED_MENU_MAX_SUBITEMS_NUM +#ifndef OLED_MENU_MAX_DEPTH +#define OLED_MENU_MAX_DEPTH 8 // maximum levels of submenus +#endif // OLED_MENU_MAX_DEPTH +#ifndef OLED_MENU_REFRESH_INTERVAL_IN_MS +#define OLED_MENU_REFRESH_INTERVAL_IN_MS 50 // not precise +#endif // OLED_MENU_REFRESH_INTERVAL_IN_MS +#ifndef OLED_MENU_SCREEN_SAVER_REFRESH_INTERVAL_IN_MS +#define OLED_MENU_SCREEN_SAVER_REFRESH_INTERVAL_IN_MS 5000 // not precise +#endif // OLED_MENU_SCREEN_SAVER_REFRESH_INTERVAL_IN_MS +#ifndef OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS +#define OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS 600 // milliseconds before items start to scroll after being selected +#endif // OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS +#ifndef OLED_MENU_SCREEN_SAVER_KICK_IN_SECONDS +#define OLED_MENU_SCREEN_SAVER_KICK_IN_SECONDS 180 // after "OLED_MENU_SCREEN_SAVE_KICK_IN_SECONDS" seconds, screen saver will show up until any key is pressed +#endif // OLED_MENU_SCREEN_SAVER_KICK_IN_SECONDS +#ifndef OLED_MENU_OVER_DRAW +#define OLED_MENU_OVER_DRAW 0 // if set to 0, the last menu item of a page will not be drawn at all if partially outside the screen, and you need to scroll down to see them +#endif // OLED_MENU_OVER_DRAW +#ifndef OLED_MENU_RESET_ALWAYS_SCROLL_ON_SELECTION +#define OLED_MENU_RESET_ALWAYS_SCROLL_ON_SELECTION 0 // if set 1, scrolling items will reset to original position on selection +#endif // OLED_MENU_RESET_ALWAYS_SCROLL_ON_SELECTION +#define OLED_MENU_WRAPPING_SPACE (OLED_MENU_WIDTH / 3) +#ifndef REVERSE_ROTARY_ENCODER_FOR_OLED_MENU +#define REVERSE_ROTARY_ENCODER_FOR_OLED_MENU 0 // if set 1, rotary encoder will be reversed for menu navigation +#endif // REVERSE_ROTARY_ENCODER_FOR_OLED_MENU +#ifndef REVERSE_ROTARY_ENCODER_FOR_OSD +#define REVERSE_ROTARY_ENCODER_FOR_OSD 0 // if set 1, rotary encoder will be reversed for OSD navigation +#endif // REVERSE_ROTARY_ENCODER_FOR_OSD +#ifndef OSD_TIMEOUT +#define OSD_TIMEOUT 8000 // OSD will disappear after OSD_TIMEOUT milliseconds without inputs +#endif // OSD_TIMEOUT + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define _STR(x) #x +#define STRING(x) _STR(x) + +// do not edit these +#ifndef OLED_MENU_ITEMS_PER_SCREEN +#define OLED_MENU_ITEMS_PER_SCREEN 4 +#endif // OLED_MENU_ITEMS_PER_SCREEN +#define OLED_MENU_STATUS_BAR_HEIGHT (OLED_MENU_HEIGHT / OLED_MENU_ITEMS_PER_SCREEN) // status bar uses 1/4 of the screen +#define OLED_MENU_USABLE_AREA_HEIGHT (OLED_MENU_HEIGHT - OLED_MENU_STATUS_BAR_HEIGHT) +#define OLED_MENU_SCROLL_LEAD_IN_FRAMES (OLED_MENU_SCROLL_LEAD_IN_TIME_IN_MS / OLED_MENU_REFRESH_INTERVAL_IN_MS) + +#define LEDON \ + pinMode(LED_BUILTIN, OUTPUT); \ + digitalWrite(LED_BUILTIN, LOW) +#define LEDOFF \ + digitalWrite(LED_BUILTIN, HIGH); \ + pinMode(LED_BUILTIN, INPUT) +// fast ESP8266 digitalRead (21 cycles vs 77), *should* work with all possible input pins +// but only "D7" and "D6" have been tested so far +#define digitalRead(x) ((GPIO_REG_READ(GPIO_IN_ADDRESS) >> x) & 1) + +// Output resolution requested by user, *given to* applyPresets(). +enum OutputResolution : uint8_t { + // RESOLUTION | FREQ | U.CMD. | OLD ID | + Output240p = 0, // 320x240 (512/640?)| ? | 'j' | 0 | + Output960 = 2, // SXGA- | 1280x960 | 60Hz | 'f' | 0x01 | + Output960PAL = 3, // ? SXGA- | 1280x960 | 50Hz | | 0x11 | + Output1024 = 4, // SXGA | 1280x1024 | 60Hz | 'p' | 0x02 | + Output1024PAL = 5, // ? SXGA | 1280x1024 | 50Hz | | 0x12 | + Output720 = 6, // HD | 1280×720 | 60Hz | 'g' | 0x03 | + Output720PAL = 7, // ? HD | 1280×720 | 50Hz | | 0x13 | + Output480 = 8, // SD | 720×480 | 60Hz | 'h' | 0x04 | + Output480PAL = 9, // ? SD | 720×480 | 50Hz | | - | + Output1080 = 10, // FHD | 1920×1080 | 60Hz | 's' | 0x05 | + Output1080PAL = 11, // ? FHD | 1920×1080 | 50Hz | | 0x15 | + Output15kHz = 12, // 15kHz/downscale | 60Hz | 'L' | 0x06 | + Output15kHzPAL = 13, // ? 15kHz/downscale | 50Hz | | 0x16 | + Output576PAL = 15, // PAL | 768×576 | 50Hz | 'k' | 0x14 | + OutputBypass = 16, + + // OutputHdBypass = 18, // | 'K' | 0x21 | + // OutputRGBHVBypass = 20, // | 'k' | 0x22 | +}; + +enum OutputBypasModeType: uint8_t { + None = 0, // default value + OutputHdBypass = 18, // | 'K' | 0x21 | + OutputRGBHVBypass = 20, // | 'k' | 0x22 | +}; + +// userOptions holds user preferences / customizations +typedef struct +{ + uint8_t slotID = 0; + // there is no way for now to recognize if slot is occupied but + // its name. This variable sets duting slot/set process and must + // remain the same until the next slot/set. + // If a slot is custom this means we are allowed + // to store preset files, if it's not no preset file will be + // stored to FS. + // I.E.: custom slot contains custom presets. + bool slotIsCustom = false; + OutputResolution resolutionID = Output480; + bool enableFrameTimeLock = false; + uint8_t frameTimeLockMethod = 0; + bool enableAutoGain = false; + bool wantScanlines = false; + bool wantOutputComponent = false; + uint8_t deintMode = 1; + bool wantVdsLineFilter = false; + bool wantPeaking = false; + bool wantTap6 = false; + bool preferScalingRgbhv = true; + bool PalForce60 = false; + bool disableExternalClockGenerator = false; + // uint8_t matchPresetSource; + bool wantStepResponse = true; + bool wantFullHeight = true; + bool enableCalibrationADC = true; + uint8_t scanlineStrength = SCANLINE_STRENGTH_INIT; + // dev + bool invertSync = false; + bool debugView = false; + bool developerMode = false; + bool adcFilter = true; +} userOptions; + +// runTimeOptions holds system variables +typedef struct +{ + // system state + bool systemInitOK = false; + // source identification + bool boardHasPower = true; + uint8_t continousStableCounter = 0; + bool syncWatcherEnabled = true; + bool inputIsYPbPr = false; + uint8_t currentLevelSOG = 5; + bool isInLowPowerMode = false; + bool sourceDisconnected = true; + /** + * @brief This variable is used to store an active videoID (of the last detection). + * Video input ID (see: getVideoMode()): + * 0 - unknown/none + * 1 - NTSC-like <---------¬ + * 2 - PAL-like <------|-----¬ + * 3 - 480p NTSC (edtv, 60Hz, progressive) <---------| |-- PAL + * 4 - 576p PAL (edtv, 50Hz, progressive) <------|----⨼ + * 5 - hdtv 720p <---|--------¬ + * 6 - ? (hdtv 1080i // 576p) <---|--------| + * 7 - hdtv 1080p <---|--------| + * 8 - normally HD2376_1250P (PAL FHD?), but using this for 24k <-----+-- NTSC | + * 9 - ??? <---------| |-- HD Bypass + * 10 - ??? | | + * 11 - ??? | | + * 12 - ??? | | + * 13 - YPbPr input <---|--------⨼ + * 14 - ? RGB/HV (setOutputRGBHVBypassMode) <---------⨼ + * 15 - RGB/HV (setOutputRGBHVBypassMode) <--- RGBHV Bypass + */ + uint8_t videoStandardInput = 0; + bool syncTypeCsync = false; + uint8_t thisSourceMaxLevelSOG; + uint8_t medResLineCount = 0x33; // 51*8=408; + // + // bool isCustomPreset = false; + uint8_t presetDisplayClock = 0; + uint32_t freqExtClockGen = 0; + uint16_t noSyncCounter = 0; // is always at least 1 when checking value in syncwatcher + uint8_t presetVlineShift = 0; + uint8_t phaseSP = 16; + uint8_t phaseADC = 16; + uint8_t syncLockFailIgnore = 16; + uint8_t applyPresetDoneStage = 0; + uint8_t failRetryAttempts = 0; + uint8_t HPLLState = 0; + uint8_t osr = 0; + uint8_t notRecognizedCounter = 0; + bool clampPositionIsSet = false; + bool coastPositionIsSet = false; + bool phaseIsSet = false; + OutputBypasModeType outModeHdBypass = None; + bool printInfos = false; + bool allowUpdatesOTA = false; +#ifdef HAVE_PINGER_LIBRARY + bool enableDebugPings = false; +#endif + bool autoBestHtotalEnabled = true; + bool videoIsFrozen = false; + bool forceRetime = false; + bool motionAdaptiveDeinterlaceActive = false; + bool deinterlaceAutoEnabled = true; + bool scanlinesEnabled = false; + bool presetIsPalForce60 = false; + bool isValidForScalingRGBHV = false; + bool useHdmiSyncFix = false; + bool extClockGenDetected = false; +} runTimeOptions; + +// remember adc options across presets +typedef struct +{ + // If `uopt.enableAutoGain == 1` and we're not before/during + // doPostPresetLoadSteps(), `adco.r_gain` must match `GBS::ADC_RGCTRL`. + // + // When we either set `uopt.enableAutoGain = 1` or call + // `GBS::ADC_RGCTRL::write()`, we must either call + // `GBS::ADC_RGCTRL::write(adco.r_gain)`, or set `adco.r_gain = + // GBS::ADC_RGCTRL::read()`. + uint8_t r_gain = 0; + uint8_t g_gain = 0; + uint8_t b_gain = 0; + uint8_t r_off = 0; + uint8_t g_off = 0; + uint8_t b_off = 0; +} adcOptions; + +/// Video processing mode, loaded into register GBS_PRESET_ID by applyPresets() +/// and read to rto.presetID by doPostPresetLoadSteps(). Shown on web UI. +// enum PresetID : uint8_t { +// OutputHdBypass = 0x21, +// OutputRGBHVBypass = 0x22, +// }; + +// extern struct runTimeOptions *rto; +extern runTimeOptions rto; +// extern struct userOptions *uopt; +extern userOptions uopt; +// extern struct adcOptions *adco; +extern adcOptions adco; + +// this is probably TODO +// const char preset_ntsc[] PROGMEM = "/preset_ntsc."; +// const char preset_pal[] PROGMEM = "/preset_pal."; +// const char preset_ntsc_480p[] PROGMEM = "/preset_ntsc_480p."; +// const char preset_pal_576p[] PROGMEM = "/preset_pal_576p."; +// const char preset_ntsc_720p[] PROGMEM = "/preset_ntsc_720p."; +// const char preset_ntsc_1080p[] PROGMEM = "/preset_ntsc_1080p."; +// const char preset_medium_res[] PROGMEM = "/preset_medium_res."; +// const char preset_vga_upscale[] PROGMEM = "/preset_vga_upscale."; +// const char preset_unknown[] PROGMEM = "/preset_unknown."; + +// const char * const preset_names[] PROGMEM = { +// preset_unknown, +// preset_ntsc, +// preset_pal, +// preset_ntsc_480p, +// preset_pal_576p, +// preset_ntsc_720p, +// preset_ntsc_1080p, +// preset_medium_res, +// preset_vga_upscale, +// }; + +const char preferencesFile[] PROGMEM = "/prefs.dat"; +const char systemInfo[] PROGMEM = "h:%4u v:%4u PLL:%01u A:%02x%02x%02x S:%02x.%02x.%02x %c%c%c%c I:%02x D:%04x m:%hu ht:%4d vt:%4d hpw:%4d u:%3x s:%2x S:%2d W:%2d\n"; +const char commandDescr[] PROGMEM = "\n> %s: %c (0x%02X) (sID:%d,rID:%d)\n\n"; + +extern void resetInMSec(unsigned long ms = 0); + +#ifdef THIS_DEVICE_MASTER +const char ap_ssid[] PROGMEM = "gbscontrol"; +const char ap_password[] PROGMEM = "qqqqqqqq"; +const char gbsc_device_hostname[] PROGMEM = "gbscontrol"; // for MDNS +#else +const char ap_ssid[] PROGMEM = "gbsslave"; +const char ap_password[] PROGMEM = "qqqqqqqq"; +const char gbsc_device_hostname[] PROGMEM = "gbsslave"; // for MDNS +#endif + +#endif // _OPTIONS_H_ \ No newline at end of file diff --git a/osd.h b/src/osd.h similarity index 94% rename from osd.h rename to src/osd.h index 8cf1102f..a43a36c5 100644 --- a/osd.h +++ b/src/osd.h @@ -1,13 +1,11 @@ #ifndef OSD_H_ #define OSD_H_ +// #include "video.h" + // FIXME: Geometry should really be controlled by a manager class // which we reference by template argument, but in the meantime use // forward declarations to functions in the main file -extern void shiftHorizontal(uint16_t amountToAdd, bool subtracting); -extern void shiftVertical(uint16_t amountToAdd, bool subtracting); -extern void scaleHorizontal(uint16_t amountToAdd, bool subtracting); -extern void scaleVertical(uint16_t amountToAdd, bool subtracting); enum class MenuInput { UP, @@ -213,6 +211,18 @@ class MenuManager } }; +struct MenuAttrs +{ + static const int8_t shiftDelta = 4; + static const int8_t scaleDelta = 4; + static const int16_t vertShiftRange = 300; + static const int16_t horizShiftRange = 400; + static const int16_t vertScaleRange = 100; + static const int16_t horizScaleRange = 130; + static const int16_t barLength = 100; +}; +typedef MenuManager Menu; + template const typename MenuManager::MenuParam MenuManager::menuParams[GBS::OSD_ICON_COUNT] = { {0, 0, 0}, diff --git a/pal_1280x1024.h b/src/pal_1280x1024.h similarity index 100% rename from pal_1280x1024.h rename to src/pal_1280x1024.h diff --git a/pal_1280x720.h b/src/pal_1280x720.h similarity index 100% rename from pal_1280x720.h rename to src/pal_1280x720.h diff --git a/pal_1920x1080.h b/src/pal_1920x1080.h similarity index 100% rename from pal_1920x1080.h rename to src/pal_1920x1080.h diff --git a/pal_240p.h b/src/pal_240p.h similarity index 100% rename from pal_240p.h rename to src/pal_240p.h diff --git a/pal_768x576.h b/src/pal_768x576.h similarity index 100% rename from pal_768x576.h rename to src/pal_768x576.h diff --git a/pal_downscale.h b/src/pal_downscale.h similarity index 100% rename from pal_downscale.h rename to src/pal_downscale.h diff --git a/src/prefs.cpp b/src/prefs.cpp new file mode 100644 index 00000000..d873ecd2 --- /dev/null +++ b/src/prefs.cpp @@ -0,0 +1,73 @@ +/* +########################################################################### +# File: prefs.cpp # +# File Created: Thursday, 13th June 2024 12:16:38 am # +# Author: Sergey Ko # +# Last Modified: Saturday, 22nd June 2024 3:31:37 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#include "prefs.h" + +/** + * @brief + * + */ +void prefsLoadDefaults() +{ + uopt.wantOutputComponent = false; + uopt.preferScalingRgbhv = true; + uopt.enableCalibrationADC = true; + uopt.disableExternalClockGenerator = false; +} + +/** + * @brief Load System paramters & Common preferences + * + * @return true + * @return false + */ +bool prefsLoad() { + fs::File f = LittleFS.open(FPSTR(preferencesFile), "r"); + if (!f) { + _WSN(F("no preferences file yet, create new")); + // prefsLoadDefaults(); + prefsSave(); + return false; + } + uopt.slotID = f.read(); + uopt.wantOutputComponent = static_cast(f.read()); + uopt.preferScalingRgbhv = static_cast(f.read()); + uopt.enableCalibrationADC = static_cast(f.read()); + uopt.disableExternalClockGenerator = static_cast(f.read()); + + f.close(); + return true; +} + +/** + * @brief Save System paramters & Common preferences + * + * @return true + * @return false + */ +bool prefsSave() { + fs::File f = LittleFS.open(FPSTR(preferencesFile), "w"); + if (!f) + { + _WSF(PSTR("open %s file failed\n"), FPSTR(preferencesFile)); + return false; + } + f.write(uopt.slotID); + f.write((uopt.wantOutputComponent ? 1 : 0)); + f.write((uopt.preferScalingRgbhv ? 1 : 0)); + f.write((uopt.enableCalibrationADC ? 1 : 0)); + f.write((uopt.disableExternalClockGenerator ? 1 : 0)); + + f.close(); + _WSF(PSTR("%s update success\n"), FPSTR(preferencesFile)); + return true; +} \ No newline at end of file diff --git a/src/prefs.h b/src/prefs.h new file mode 100644 index 00000000..fe4a1ac1 --- /dev/null +++ b/src/prefs.h @@ -0,0 +1,25 @@ +/* +########################################################################### +# File: prefs.h # +# File Created: Thursday, 13th June 2024 12:16:48 am # +# Author: Sergey Ko # +# Last Modified: Sunday, 16th June 2024 1:45:22 am # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#ifndef _PREFS_H_ +#define _PREFS_H_ + +#include +#include "options.h" +#include "wserial.h" + +void prefsLoadDefaults(); +bool prefsLoad(); +bool prefsSave(); + + +#endif \ No newline at end of file diff --git a/presetDeinterlacerSection.h b/src/presetDeinterlacerSection.h similarity index 100% rename from presetDeinterlacerSection.h rename to src/presetDeinterlacerSection.h diff --git a/presetHdBypassSection.h b/src/presetHdBypassSection.h similarity index 100% rename from presetHdBypassSection.h rename to src/presetHdBypassSection.h diff --git a/presetMdSection.h b/src/presetMdSection.h similarity index 100% rename from presetMdSection.h rename to src/presetMdSection.h diff --git a/src/presets.cpp b/src/presets.cpp new file mode 100644 index 00000000..5b02b51e --- /dev/null +++ b/src/presets.cpp @@ -0,0 +1,1810 @@ +/* +##################################################################################### +# File: preset.cpp # +# File Created: Thursday, 2nd May 2024 6:38:23 pm # +# Author: # +# Last Modified: Tuesday, 25th June 2024 2:13:09 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#include "presets.h" + +/** + * @brief + * + */ +void loadPresetMdSection() +{ + uint16_t index = 0; + uint8_t bank[16]; + writeOneByte(0xF0, 1); + for (int j = 6; j <= 7; j++) + { // start at 0x60 + copyBank(bank, presetMdSection, &index); + writeBytes(j * 16, bank, 16); + } + bank[0] = pgm_read_byte(presetMdSection + index); + bank[1] = pgm_read_byte(presetMdSection + index + 1); + bank[2] = pgm_read_byte(presetMdSection + index + 2); + bank[3] = pgm_read_byte(presetMdSection + index + 3); + writeBytes(8 * 16, bank, 4); // MD section ends at 0x83, not 0x90 +} + +/** + * @brief reset runtime parameters and some registers + * + */ +void presetsResetParameters() +{ + rto.videoStandardInput = 0; + rto.presetDisplayClock = 0; + rto.videoIsFrozen = false; + rto.applyPresetDoneStage = 0; + rto.presetVlineShift = 0; + rto.sourceDisconnected = true; + rto.outModeHdBypass = None; + rto.clampPositionIsSet = 0; + rto.coastPositionIsSet = 0; + rto.phaseIsSet = 0; + rto.continousStableCounter = 0; + rto.noSyncCounter = 0; + rto.isInLowPowerMode = false; + rto.currentLevelSOG = 5; + rto.thisSourceMaxLevelSOG = 31; // 31 = auto sog has not (yet) run + rto.failRetryAttempts = 0; + rto.HPLLState = 0; + rto.motionAdaptiveDeinterlaceActive = false; + rto.scanlinesEnabled = false; + rto.syncTypeCsync = false; + rto.isValidForScalingRGBHV = false; + rto.medResLineCount = 0x33; // 51*8=408 + rto.osr = 0; + rto.useHdmiSyncFix = 0; + rto.notRecognizedCounter = 0; + + // this may not be reset here + // uopt.invertSync = false; + // uopt.debugView = false; + // uopt.developerMode = false; + + adco.r_gain = 0; + adco.g_gain = 0; + adco.b_gain = 0; + adco.r_off = 0; + adco.g_off = 0; + adco.b_off = 0; + + // clear temp storage + // GBS::ADC_UNUSED_64::write(0); + // GBS::ADC_UNUSED_65::write(0); + // GBS::ADC_UNUSED_66::write(0); + // GBS::ADC_UNUSED_67::write(0); + // GBS::GBS_PRESET_CUSTOM::write(0); + // GBS::GBS_OPTION_SCALING_RGBHV::write(0); + // GBS::GBS_OPTION_PALFORCED60_ENABLED::write(0); + GBS::GBS_PRESET_ID::write(0); + + // set minimum IF parameters + GBS::IF_VS_SEL::write(1); + GBS::IF_VS_FLIP::write(1); + GBS::IF_HSYNC_RST::write(0x3FF); + GBS::IF_VB_ST::write(0); + GBS::IF_VB_SP::write(2); + + // could stop ext clock gen output here? + FrameSync::cleanup(); + + GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD + GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 1 // minor SOG clamp effect + GBS::ADC_TEST_04::write(0x02); // 5_04 + GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 + GBS::ADC_CLK_PA::write(0); // 5_00 0/1 PA_ADC input clock = PLLAD CLKO2 + GBS::ADC_SOGEN::write(1); + GBS::SP_SOG_MODE::write(1); + GBS::ADC_INPUT_SEL::write(1); // 1 = RGBS / RGBHV adc data input + GBS::ADC_POWDZ::write(1); // ADC on + setAndUpdateSogLevel(rto.currentLevelSOG); + GBS::RESET_CONTROL_0x46::write(0x00); // all units off + GBS::RESET_CONTROL_0x47::write(0x00); + GBS::GPIO_CONTROL_00::write(0x67); // most GPIO pins regular GPIO + GBS::GPIO_CONTROL_01::write(0x00); // all GPIO outputs disabled + GBS::DAC_RGBS_PWDNZ::write(0); // disable DAC (output) + GBS::PLL648_CONTROL_01::write(0x00); // VCLK(1/2/4) display clock // needs valid for debug bus + GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) + GBS::PAD_CKOUT_ENZ::write(1); // clock output disable + GBS::IF_SEL_ADC_SYNC::write(1); // ! 1_28 2 + GBS::PLLAD_VCORST::write(1); // reset = 1 + GBS::PLL_ADS::write(1); // When = 1, input clock is from ADC ( otherwise, from unconnected clock at pin 40 ) + GBS::PLL_CKIS::write(0); // PLL use OSC clock + GBS::PLL_MS::write(0b010); // fb memory clock can go lower power + GBS::PAD_CONTROL_00_0x48::write(0x2b); // disable digital inputs, enable debug out pin + GBS::PAD_CONTROL_01_0x49::write(0x1f); // pad control pull down/up transistors on + loadHdBypassSection(); // 1_30 to 1_55 + loadPresetMdSection(); // 1_60 to 1_83 + setAdcParametersGainAndOffset(); + GBS::SP_PRE_COAST::write(9); // was 0x07 // need pre / poast to allow all sources to detect + GBS::SP_POST_COAST::write(18); // was 0x10 // ps2 1080p 18 + GBS::SP_NO_COAST_REG::write(0); // can be 1 in some soft reset situations, will prevent sog vsync decoding << really? + GBS::SP_CS_CLP_ST::write(32); // define it to something at start + GBS::SP_CS_CLP_SP::write(48); + GBS::SP_SOG_SRC_SEL::write(0); // SOG source = ADC + GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) + GBS::SP_NO_CLAMP_REG::write(1); + GBS::PLLAD_ICP::write(0); // lowest charge pump current + GBS::PLLAD_FS::write(0); // low gain (have to deal with cold and warm startups) + GBS::PLLAD_5_16::write(0x1f); + GBS::PLLAD_MD::write(0x700); + resetPLL(); // cycles PLL648 + delay(2); + resetPLLAD(); // same for PLLAD + GBS::PLL_VCORST::write(1); // reset on + GBS::PLLAD_CONTROL_00_5x11::write(0x01); // reset on + resetDebugPort(); + + GBS::RESET_CONTROL_0x46::write(0x41); // new 23.07.19 + GBS::RESET_CONTROL_0x47::write(0x17); // new 23.07.19 (was 0x16) + GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts + GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status + GBS::INTERRUPT_CONTROL_00::write(0x00); + GBS::PAD_SYNC_OUT_ENZ::write(0); // sync output enabled, will be low (HC125 fix) + rto.clampPositionIsSet = 0; // some functions override these, so make sure + rto.coastPositionIsSet = 0; + rto.phaseIsSet = 0; + rto.continousStableCounter = 0; + + _DBGN(F("(!) reset preset parameters")); + + serialCommand = '@'; + userCommand = '@'; +} + +/** + * @brief This function does executes some logic after the preset + * registers were written. + * The "forceApply" paramter instructs to skip checking if it's + * custom slot/preset, so additional logic will be applied + * if it's true + * + */ +void doPostPresetLoadSteps(bool forceApply) +{ + bool avoidAutoBest = false; + // unsigned long postLoadTimer = millis(); + // delay(10); + // adco.r_gain gets applied if uopt.enableAutoGain is set. + if (uopt.enableAutoGain) + { + // if (uopt.presetPreference == OutputCustomized) { + if (uopt.slotIsCustom) { + // Loaded custom preset, we want to keep newly loaded gain. Save + // gain written by presetLoadFromFS -> writeProgramArrayNew. + adco.r_gain = GBS::ADC_RGCTRL::read(); + adco.g_gain = GBS::ADC_GGCTRL::read(); + adco.b_gain = GBS::ADC_BGCTRL::read(); + } + // else { + // Loaded fixed preset. Keep adco.r_gain from before + // overwriting registers + // } + } + + // GBS::PAD_SYNC_OUT_ENZ::write(1); // no sync out + // GBS::DAC_RGBS_PWDNZ::write(0); // no DAC + // GBS::SFTRST_MEM_FF_RSTZ::write(0); // mem fifos keep in reset + + if (rto.videoStandardInput == 0) + { + uint8_t videoMode = getVideoMode(); + _WSF(PSTR("post preset: rto.videoStandardInput = %d\n"), videoMode); + // if (videoMode > 0) + // { + rto.videoStandardInput = videoMode; + // } + } + // set output resolution + // rto.isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); + // not existent and not used + // GBS::ADC_UNUSED_64::write(0); + // GBS::ADC_UNUSED_65::write(0); // clear temp storage + // GBS::ADC_UNUSED_66::write(0); + // GBS::ADC_UNUSED_67::write(0); // clear temp storage + GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) + + // if preset is not loaded from FS + // if (!rto.isCustomPreset) + if (!uopt.slotIsCustom || forceApply) + { + prepareSyncProcessor(); // todo: handle modes 14 and 15 better, now that they support scaling + } + + if (rto.videoStandardInput == 14) + { + // copy of code in setOutputRGBHVBypassMode + if (rto.syncTypeCsync == false) + { + GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: from hs // use ADC and turn it off = no SOG + GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG // having it 0 drags down the SOG (hsync) input; = 1: need to supress SOG decoding + GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) + GBS::SP_SOG_MODE::write(0); // 5_56 bit 0 // 0: normal, 1: SOG + GBS::SP_NO_COAST_REG::write(1); // vblank coasting off + GBS::SP_PRE_COAST::write(0); + GBS::SP_POST_COAST::write(0); + GBS::SP_H_PULSE_IGNOR::write(0xff); // cancel out SOG decoding + GBS::SP_SYNC_BYPS::write(0); // external H+V sync for decimator (+ sync out) | 1 to mirror in sync, 0 to output processed sync + GBS::SP_HS_POL_ATO::write(1); // 5_55 4 auto polarity for retiming + GBS::SP_VS_POL_ATO::write(1); // 5_55 6 + GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS + GBS::SP_H_PROTECT::write(0); // 5_3e 4 disable for H/V + rto.phaseADC = 16; + rto.phaseSP = 8; + } + else + { + // todo: SOG SRC can be ADC or HS input pin. HS requires TTL level, ADC can use lower levels + // HS seems to have issues at low PLL speeds + // maybe add detection whether ADC Sync is needed + GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: hs is sog source + GBS::SP_EXT_SYNC_SEL::write(1); // disconnect HV input + GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG + GBS::SP_SOG_MODE::write(1); // apparently needs to be off for HS input (on for ADC) + GBS::SP_NO_COAST_REG::write(0); // vblank coasting on + GBS::SP_PRE_COAST::write(4); // 5_38, > 4 can be seen with clamp invert on the lower lines + GBS::SP_POST_COAST::write(7); + GBS::SP_SYNC_BYPS::write(0); // use regular sync for decimator (and sync out) path + GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS + GBS::SP_H_PROTECT::write(1); // 5_3e 4 enable for SOG + rto.currentLevelSOG = 24; + rto.phaseADC = 16; + rto.phaseSP = 8; + } + } + + GBS::SP_H_PROTECT::write(0); + GBS::SP_COAST_INV_REG::write(0); // just in case + // if (!rto.outModeHdBypass && GBS::GBS_OPTION_SCALING_RGBHV::read() == 0) + if (utilsNotPassThroughMode() && !uopt.preferScalingRgbhv) + { + // setOutputHdBypassMode has it's own and needs to update later + updateStopPositionDynamic(false); // remember: rto.videoStandardInput for RGB(C/HV) in scaling is 1, 2 or 3 here + } + + GBS::SP_NO_CLAMP_REG::write(1); // (keep) clamp disabled, to be enabled when position determined + GBS::OUT_SYNC_CNTRL::write(1); // prepare sync out to PAD + + // auto offset adc prep + GBS::ADC_AUTO_OFST_PRD::write(1); // by line (0 = by frame) + GBS::ADC_AUTO_OFST_DELAY::write(0); // sample delay 0 (1 to 4 pipes) + GBS::ADC_AUTO_OFST_STEP::write(0); // 0 = abs diff, then 1 to 3 steps + GBS::ADC_AUTO_OFST_TEST::write(1); + // U/V ranges to 0 + GBS::ADC_AUTO_OFST_U_RANGE::write(0); + GBS::ADC_AUTO_OFST_V_RANGE::write(0); + + if (rto.inputIsYPbPr == true) + { + applyYuvPatches(); + } + else + { + applyRGBPatches(); + } + + // if (rto.outModeHdBypass) + if (utilsIsPassThroughMode()) + { + GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP + rto.autoBestHtotalEnabled = false; + } + else + { + rto.autoBestHtotalEnabled = true; + } + + rto.phaseADC = GBS::PA_ADC_S::read(); // we can't know which is right, get from preset + rto.phaseSP = 8; // get phase into global variables early: before latching + + if (rto.inputIsYPbPr) + { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 14; + } + else + { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 13; // similar to yuv, allow variations + } + + setAndUpdateSogLevel(rto.currentLevelSOG); + + // if (!rto.isCustomPreset) + if (!uopt.slotIsCustom || forceApply) + { + // Writes ADC_RGCTRL. If auto gain is enabled, ADC_RGCTRL will be + // overwritten further down at `uopt.enableAutoGain == 1`. + setAdcParametersGainAndOffset(); + } + + GBS::GPIO_CONTROL_00::write(0x67); // most GPIO pins regular GPIO + GBS::GPIO_CONTROL_01::write(0x00); // all GPIO outputs disabled + rto.clampPositionIsSet = 0; + rto.coastPositionIsSet = 0; + rto.phaseIsSet = 0; + rto.continousStableCounter = 0; + rto.noSyncCounter = 0; + rto.motionAdaptiveDeinterlaceActive = false; + rto.scanlinesEnabled = false; + rto.failRetryAttempts = 0; + // rto.videoIsFrozen = true; // ensures unfreeze + rto.sourceDisconnected = false; // this must be true if we reached here (no syncwatcher operation) + rto.boardHasPower = true; // same + + // if (rto.presetID == 0x06 || rto.presetID == 0x16) { + // { + // override so it applies section 2 deinterlacer settings + // rto.isCustomPreset = false; + // } + + // if (!rto.isCustomPreset || utilsIsDownscaleMode()) + if (!uopt.slotIsCustom || utilsIsDownscaleMode() || forceApply) + { + if (rto.videoStandardInput == 3 || rto.videoStandardInput == 4 || + rto.videoStandardInput == 8 || rto.videoStandardInput == 9) + { + GBS::IF_LD_RAM_BYPS::write(1); // 1_0c 0 no LD, do this before setIfHblankParameters + } + + // setIfHblankParameters(); // 1_0e, 1_18, 1_1a + GBS::IF_INI_ST::write(0); // 16.08.19: don't calculate, use fixed to 0 + // the following sets a field offset that eliminates 240p content forced to 480i flicker + // GBS::IF_INI_ST::write(GBS::PLLAD_MD::read() * 0.4261f); // upper: * 0.4282f lower: 0.424f + + GBS::IF_HS_INT_LPF_BYPS::write(0); // 1_02 2 + // 0 allows int/lpf for smoother scrolling with non-ideal scaling, also reduces jailbars and even noise + // interpolation or lpf available, lpf looks better + GBS::IF_HS_SEL_LPF::write(1); // 1_02 1 + GBS::IF_HS_PSHIFT_BYPS::write(1); // 1_02 3 nonlinear scale phase shift bypass + // 1_28 1 1:hbin generated write reset 0:line generated write reset + GBS::IF_LD_WRST_SEL::write(1); // at 1 fixes output position regardless of 1_24 + // GBS::MADPT_Y_DELAY_UV_DELAY::write(0); // 2_17 default: 0 // don't overwrite + + GBS::SP_RT_HS_ST::write(0); // 5_49 // retiming hs ST, SP + GBS::SP_RT_HS_SP::write(GBS::PLLAD_MD::read() * 0.93f); + + GBS::VDS_PK_LB_CORE::write(0); // 3_44 0-3 // 1 for anti source jailbars + GBS::VDS_PK_LH_CORE::write(0); // 3_46 0-3 // 1 for anti source jailbars + // if (rto.presetID == 0x05 || rto.presetID == 0x15) { + if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) + { + GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 // peaking HF + GBS::VDS_PK_LH_GAIN::write(0x0A); // 3_47 + } + else + { + GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 + GBS::VDS_PK_LH_GAIN::write(0x18); // 3_47 + } + GBS::VDS_PK_VL_HL_SEL::write(0); // 3_43 0 if 1 then 3_45 HF almost no effect (coring 0xf9) + GBS::VDS_PK_VL_HH_SEL::write(0); // 3_43 1 + + GBS::VDS_STEP_GAIN::write(1); // step response, max 15 (VDS_STEP_DLY_CNTRL set in presets) + + // DAC filters / keep in presets for now + // GBS::VDS_1ST_INT_BYPS::write(1); // disable RGB stage interpolator + // GBS::VDS_2ND_INT_BYPS::write(1); // disable YUV stage interpolator + + // most cases will use osr 2 + setOverSampleRatio(2, true); // prepare only = true + + // full height option + if (uopt.wantFullHeight) + { + if (rto.videoStandardInput == 1 || rto.videoStandardInput == 3) + { + // TODO Why is commented? + // if (rto.presetID == 0x5) + //{ // out 1080p 60 + // GBS::VDS_DIS_VB_ST::write(GBS::VDS_VSYNC_RST::read() - 1); + // GBS::VDS_DIS_VB_SP::write(42); + // GBS::VDS_VB_SP::write(42 - 10); // is VDS_DIS_VB_SP - 10 = 32 // watch for vblank overflow (ps3) + // GBS::VDS_VSCALE::write(455); + // GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 4); + // GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 4); + // _WSN(F("full height")); + // } + } + else if (rto.videoStandardInput == 2 || rto.videoStandardInput == 4) + { + // if (rto.presetID == 0x15) { // out 1080p 50 + if (uopt.resolutionID == Output1080PAL) + { // out 1080p 50 + GBS::VDS_VSCALE::write(455); + GBS::VDS_DIS_VB_ST::write(GBS::VDS_VSYNC_RST::read()); // full = 1125 of 1125 + GBS::VDS_DIS_VB_SP::write(42); + GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 22); + GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 22); + _WSN(F("full height")); + } + } + } + + if (rto.videoStandardInput == 1 || rto.videoStandardInput == 2) + { + // GBS::PLLAD_ICP::write(5); // 5 rather than 6 to work well with CVBS sync as well as CSync + + GBS::ADC_FLTR::write(3); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + GBS::PLLAD_KS::write(2); // 5_16 + setOverSampleRatio(4, true); // prepare only = true + GBS::IF_SEL_WEN::write(0); // 1_02 0; 0 for SD, 1 for EDTV + if (rto.inputIsYPbPr) + { // todo: check other videoStandardInput in component vs rgb + GBS::IF_HS_TAP11_BYPS::write(0); // 1_02 4 Tap11 LPF bypass in YUV444to422 + GBS::IF_HS_Y_PDELAY::write(2); // 1_02 5+6 delays + GBS::VDS_V_DELAY::write(0); // 3_24 2 + GBS::VDS_Y_DELAY::write(3); // 3_24 4/5 delays + } + + // downscale preset: source is SD + // if (rto.presetID == 0x06 || rto.presetID == 0x16) { + if (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL) + { + setCsVsStart(2); // or 3, 0 + setCsVsStop(0); // fixes field position + GBS::IF_VS_SEL::write(1); // 1_00 5 // turn off VHS sync feature + GBS::IF_VS_FLIP::write(0); // 1_01 0 + GBS::IF_LD_RAM_BYPS::write(0); // 1_0c 0 + GBS::IF_HS_DEC_FACTOR::write(1); // 1_0b 4 + GBS::IF_LD_SEL_PROV::write(0); // 1_0b 7 + GBS::IF_HB_ST::write(2); // 1_10 deinterlace offset + GBS::MADPT_Y_VSCALE_BYPS::write(0); // 2_02 6 + GBS::MADPT_UV_VSCALE_BYPS::write(0); // 2_02 7 + GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 one line fifo for line phase adjust + GBS::MADPT_VSCALE_DEC_FACTOR::write(1); // 2_31 0..1 + GBS::MADPT_SEL_PHASE_INI::write(0); // 2_31 2 disable for SD (check 240p content) + if (rto.videoStandardInput == 1) + { + GBS::IF_HB_ST2::write(0x490); // 1_18 + GBS::IF_HB_SP2::write(0x80); // 1_1a + GBS::IF_HB_SP::write(0x4A); // 1_12 deinterlace offset, green bar + GBS::IF_HBIN_SP::write(0xD0); // 1_26 + } + else if (rto.videoStandardInput == 2) + { + GBS::IF_HB_SP2::write(0x74); // 1_1a + GBS::IF_HB_SP::write(0x50); // 1_12 deinterlace offset, green bar + GBS::IF_HBIN_SP::write(0xD0); // 1_26 + } + } + } + if (rto.videoStandardInput == 3 || rto.videoStandardInput == 4 || + rto.videoStandardInput == 8 || rto.videoStandardInput == 9) + { + // EDTV p-scan, need to either double adc data rate and halve vds scaling + // or disable line doubler (better) (50 / 60Hz shared) + + GBS::ADC_FLTR::write(3); // 5_03 4/5 + GBS::PLLAD_KS::write(1); // 5_16 + + // if (rto.presetID != 0x06 && rto.presetID != 0x16) { + if (uopt.resolutionID != Output15kHz && uopt.resolutionID != Output15kHzPAL) + { + setCsVsStart(14); // pal // hm + setCsVsStop(11); // probably setting these for modes 8,9 + GBS::IF_HB_SP::write(0); // 1_12 deinterlace offset, fixes colors (downscale needs diff) + } + setOverSampleRatio(2, true); // with KS = 1 for modes 3, 4, 8 + GBS::IF_HS_DEC_FACTOR::write(0); // 1_0b 4+5 + GBS::IF_LD_SEL_PROV::write(1); // 1_0b 7 + GBS::IF_PRGRSV_CNTRL::write(1); // 1_00 6 + GBS::IF_SEL_WEN::write(1); // 1_02 0 + GBS::IF_HS_SEL_LPF::write(0); // 1_02 1 0 = use interpolator not lpf for EDTV + GBS::IF_HS_TAP11_BYPS::write(0); // 1_02 4 filter + GBS::IF_HS_Y_PDELAY::write(3); // 1_02 5+6 delays (ps2 test on one board clearly says 3, not 2) + GBS::VDS_V_DELAY::write(1); // 3_24 2 // new 24.07.2019 : 1, also set 2_17 to 1 + GBS::MADPT_Y_DELAY_UV_DELAY::write(1); // 2_17 : 1 + GBS::VDS_Y_DELAY::write(3); // 3_24 4/5 delays (ps2 test saying 3 for 1_02 goes with 3 here) + if (rto.videoStandardInput == 9) + { + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() > 650) + { + delay(20); + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() > 650) + { + GBS::PLLAD_KS::write(0); // 5_16 + GBS::VDS_VSCALE_BYPS::write(1); // 3_00 5 no vscale + } + } + } + + // downscale preset: source is EDTV + // if (rto.presetID == 0x06 || rto.presetID == 0x16) { + if (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL) + { + GBS::MADPT_Y_VSCALE_BYPS::write(0); // 2_02 6 + GBS::MADPT_UV_VSCALE_BYPS::write(0); // 2_02 7 + GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 one line fifo for line phase adjust + GBS::MADPT_VSCALE_DEC_FACTOR::write(1); // 2_31 0..1 + GBS::MADPT_SEL_PHASE_INI::write(1); // 2_31 2 enable + GBS::MADPT_SEL_PHASE_INI::write(0); // 2_31 2 disable + } + } + // if (rto.videoStandardInput == 3 && rto.presetID != 0x06) { // ED YUV 60 + if (rto.videoStandardInput == 3 && uopt.resolutionID != Output15kHzPAL) + { // ED YUV 60 + setCsVsStart(16); // ntsc + setCsVsStop(13); // + GBS::IF_HB_ST::write(30); // 1_10; magic number + GBS::IF_HBIN_ST::write(0x20); // 1_24 + GBS::IF_HBIN_SP::write(0x60); // 1_26 + // if (rto.presetID == 0x5) { // out 1080p + if (uopt.resolutionID == Output1080) + { // out 1080p + GBS::IF_HB_SP2::write(0xB0); // 1_1a + GBS::IF_HB_ST2::write(0x4BC); // 1_18 + // } else if (rto.presetID == 0x3) { // out 720p + } + else if (uopt.resolutionID == Output720) + { // out 720p + GBS::VDS_VSCALE::write(683); // same as base preset + GBS::IF_HB_ST2::write(0x478); // 1_18 + GBS::IF_HB_SP2::write(0x84); // 1_1a + // } else if (rto.presetID == 0x2) { // out x1024 + } + else if (uopt.resolutionID == Output1024) + { // out x1024 + GBS::IF_HB_SP2::write(0x84); // 1_1a + GBS::IF_HB_ST2::write(0x478); // 1_18 + // } else if (rto.presetID == 0x1) { // out x960 + } + else if (uopt.resolutionID == Output960) + { // out x960 + GBS::IF_HB_SP2::write(0x84); // 1_1a + GBS::IF_HB_ST2::write(0x478); // 1_18 + // } else if (rto.presetID == 0x3) { // out x480 + } + else if (uopt.resolutionID == Output720) + { // out x480 + GBS::IF_HB_ST2::write(0x478); // 1_18 + GBS::IF_HB_SP2::write(0x90); // 1_1a + } + // } else if (rto.videoStandardInput == 4 && rto.presetID != 0x16) { // ED YUV 50 + } + else if (rto.videoStandardInput == 4 && uopt.resolutionID != Output15kHzPAL) + { // ED YUV 50 + GBS::IF_HBIN_SP::write(0x40); // 1_26 was 0x80 test: ps2 videomodetester 576p mode + GBS::IF_HBIN_ST::write(0x20); // 1_24, odd but need to set this here (blue bar) + GBS::IF_HB_ST::write(0x30); // 1_10 + // if (rto.presetID == 0x15) { // out 1080p + if (uopt.resolutionID == Output1080PAL) + { // out 1080p + GBS::IF_HB_ST2::write(0x4C0); // 1_18 + GBS::IF_HB_SP2::write(0xC8); // 1_1a + } + // } else if (rto.presetID == 0x13) { // out 720p + else if (uopt.resolutionID == Output720PAL) + { // out 720p + GBS::IF_HB_ST2::write(0x478); // 1_18 + GBS::IF_HB_SP2::write(0x88); // 1_1a + } + // } else if (rto.presetID == 0x12) { // out x1024 + else if (uopt.resolutionID == Output1024PAL) + { // out x1024 + // VDS_VB_SP -= 12 used to shift pic up, but seems not necessary anymore + // GBS::VDS_VB_SP::write(GBS::VDS_VB_SP::read() - 12); + GBS::IF_HB_ST2::write(0x454); // 1_18 + GBS::IF_HB_SP2::write(0x88); // 1_1a + } + // } else if (rto.presetID == 0x11) { // out x960 + else if (uopt.resolutionID == Output960PAL) + { // out x960 + GBS::IF_HB_ST2::write(0x454); // 1_18 + GBS::IF_HB_SP2::write(0x88); // 1_1a + } + // } else if (rto.presetID == 0x14) { // out x576 + else if (uopt.resolutionID == Output576PAL) + { // out x576 + GBS::IF_HB_ST2::write(0x478); // 1_18 + GBS::IF_HB_SP2::write(0x90); // 1_1a + } + } + else if (rto.videoStandardInput == 5) + { // 720p + GBS::ADC_FLTR::write(1); // 5_03 + GBS::IF_PRGRSV_CNTRL::write(1); // progressive + GBS::IF_HS_DEC_FACTOR::write(0); + GBS::INPUT_FORMATTER_02::write(0x74); + GBS::VDS_Y_DELAY::write(3); + } + else if (rto.videoStandardInput == 6 || rto.videoStandardInput == 7) + { // 1080i/p + GBS::ADC_FLTR::write(1); // 5_03 + GBS::PLLAD_KS::write(0); // 5_16 + GBS::IF_PRGRSV_CNTRL::write(1); + GBS::IF_HS_DEC_FACTOR::write(0); + GBS::INPUT_FORMATTER_02::write(0x74); + GBS::VDS_Y_DELAY::write(3); + } + else if (rto.videoStandardInput == 8) + { // 25khz + + // TODO: this mode for HV sync + uint32_t pllRate = 0; + for (int i = 0; i < 8; i++) + { + pllRate += getPllRate(); + } + pllRate /= 8; + + _DBGF(PSTR("(H-PLL) rate: %ld\n"), pllRate); + if (pllRate > 200) + { // is PLL even working? + if (pllRate < 1800) + { // rate very low? + GBS::PLLAD_FS::write(0); // then low gain + } + } + GBS::PLLAD_ICP::write(6); // all 25khz submodes have more lines than NTSC + GBS::ADC_FLTR::write(1); // 5_03 + GBS::IF_HB_ST::write(30); // 1_10; magic number + // GBS::IF_HB_ST2::write(0x60); // 1_18 + // GBS::IF_HB_SP2::write(0x88); // 1_1a + GBS::IF_HBIN_SP::write(0x60); // 1_26 works for all output presets + if (uopt.resolutionID == Output960) + { // out x960 + GBS::VDS_VSCALE::write(410); + } + else if (uopt.resolutionID == Output1024) + { // out x1024 + GBS::VDS_VSCALE::write(402); + } + else if (uopt.resolutionID == Output720) + { // out 720p + GBS::VDS_VSCALE::write(546); + } + else if (uopt.resolutionID == Output1080) + { // out 1080p + GBS::VDS_VSCALE::write(400); + } + } + } + + resetDebugPort(); + + if (rto.syncTypeCsync) + { + if (GBS::TEST_BUS_2F::read() == 0) + { + delay(4); + if (GBS::TEST_BUS_2F::read() == 0) + { + optimizeSogLevel(); + avoidAutoBest = 1; + delay(4); + } + } + } + + latchPLLAD(); // besthtotal reliable with this (EDTV modes, possibly others) + + // if (rto.isCustomPreset) + if (uopt.slotIsCustom || forceApply) + { + // patch in segments not covered in custom preset files (currently seg 2) + if (rto.videoStandardInput == 3 || rto.videoStandardInput == 4 || rto.videoStandardInput == 8) + { + GBS::MADPT_Y_DELAY_UV_DELAY::write(1); // 2_17 : 1 + } + + // get OSR + if (GBS::DEC1_BYPS::read() && GBS::DEC2_BYPS::read()) + { + rto.osr = 1; + } + else if (GBS::DEC1_BYPS::read() && !GBS::DEC2_BYPS::read()) + { + rto.osr = 2; + } + else + { + rto.osr = 4; + } + + // always start with internal clock active first + // if (GBS::PLL648_CONTROL_01::read() == 0x75 && GBS::GBS_PRESET_DISPLAY_CLOCK::read() != 0) + if (GBS::PLL648_CONTROL_01::read() == 0x75 && rto.presetDisplayClock != 0) + { + // GBS::PLL648_CONTROL_01::write(GBS::GBS_PRESET_DISPLAY_CLOCK::read()); + GBS::PLL648_CONTROL_01::write(rto.presetDisplayClock); + } + // else if (GBS::GBS_PRESET_DISPLAY_CLOCK::read() == 0) + else if (rto.presetDisplayClock == 0) + { + _WSN(F("no stored display clock to use!")); + } + } + + if (rto.presetIsPalForce60) + { + // if (GBS::GBS_OPTION_PALFORCED60_ENABLED::read() != 1) + if (!uopt.PalForce60) + { + _WSN(F("pal forced 60hz: apply vshift")); + uint16_t vshift = 56; // default shift + // if (rto.presetID == 0x5) { + if (uopt.resolutionID == Output1080) + { + GBS::IF_VB_SP::write(4); + } // out 1080p + else + { + GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + vshift); + } + GBS::IF_VB_ST::write(GBS::IF_VB_SP::read() - 2); + // TODO enabling uopt.PalForce60 ? + uopt.PalForce60 = true; + // GBS::GBS_OPTION_PALFORCED60_ENABLED::write(1); + } + } + + // freezeVideo(); + + GBS::ADC_TEST_04::write(0x02); // 5_04 + GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 + GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 + + // auto ADC gain + if (uopt.enableAutoGain) + { + if (adco.r_gain == 0) + { + // SerialM.printf("ADC gain: reset %x := %x\n", GBS::ADC_RGCTRL::read(), AUTO_GAIN_INIT); + setAdcGain(AUTO_GAIN_INIT); + GBS::DEC_TEST_ENABLE::write(1); + } + else + { + // SerialM.printf("ADC gain: transferred %x := %x\n", GBS::ADC_RGCTRL::read(), adco.r_gain); + GBS::ADC_RGCTRL::write(adco.r_gain); + GBS::ADC_GGCTRL::write(adco.g_gain); + GBS::ADC_BGCTRL::write(adco.b_gain); + GBS::DEC_TEST_ENABLE::write(1); + } + } + else + { + GBS::DEC_TEST_ENABLE::write(0); // no need for decimation test to be enabled + } + + // ADC offset if measured + if (adco.r_off != 0 && adco.g_off != 0 && adco.b_off != 0) + { + GBS::ADC_ROFCTRL::write(adco.r_off); + GBS::ADC_GOFCTRL::write(adco.g_off); + GBS::ADC_BOFCTRL::write(adco.b_off); + } + + _WSF( + PSTR("ADC offset: R: 0x%04X G: 0x%04X B: 0x%04X\n"), + GBS::ADC_ROFCTRL::read(), + GBS::ADC_GOFCTRL::read(), + GBS::ADC_BOFCTRL::read() + ); + + GBS::IF_AUTO_OFST_U_RANGE::write(0); // 0 seems to be full range, else 1 to 15 + GBS::IF_AUTO_OFST_V_RANGE::write(0); // 0 seems to be full range, else 1 to 15 + GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame ; by line is easier to spot + GBS::IF_AUTO_OFST_EN::write(0); // not reliable yet + // to get it working with RGB: + // leave RGB to YUV at the ADC DEC stage (s5_1f 2 = 0) + // s5s07s42, 1_2a to 0, s5_06 + s5_08 to 0x40 + // 5_06 + 5_08 will be the target center value, 5_07 sets general offset + // s3s3as00 s3s3bs00 s3s3cs00 + + if (uopt.wantVdsLineFilter) + { + GBS::VDS_D_RAM_BYPS::write(0); + } + else + { + GBS::VDS_D_RAM_BYPS::write(1); + } + + if (uopt.wantPeaking) + { + GBS::VDS_PK_Y_H_BYPS::write(0); + } + else + { + GBS::VDS_PK_Y_H_BYPS::write(1); + } + + // unused now + GBS::VDS_TAP6_BYPS::write(0); + // if (uopt.wantTap6) { GBS::VDS_TAP6_BYPS::write(0); } + // else { + // GBS::VDS_TAP6_BYPS::write(1); + // if (!isCustomPreset) { + // GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() + 1); + // } + // } + + if (uopt.wantStepResponse) + { + // step response requested, but exclude 1080p presets + // if (rto.presetID != 0x05 && rto.presetID != 0x15) { + if (uopt.resolutionID != Output1080 && uopt.resolutionID != Output1080PAL) + { + GBS::VDS_UV_STEP_BYPS::write(0); + } + else + { + GBS::VDS_UV_STEP_BYPS::write(1); + } + } + else + { + GBS::VDS_UV_STEP_BYPS::write(1); + } + + // transfer preset's display clock to ext. gen + externalClockGenResetClock(); + + // unfreezeVideo(); + // initialize OSD menu + Menu::init(); + FrameSync::cleanup(); + rto.syncLockFailIgnore = 16; + + // undo eventual rto.useHdmiSyncFix (not using this method atm) + GBS::VDS_SYNC_EN::write(0); + GBS::VDS_FLOCK_EN::write(0); + + // if (!rto.outModeHdBypass && rto.autoBestHtotalEnabled && + if (utilsNotPassThroughMode() && rto.autoBestHtotalEnabled && + // GBS::GBS_OPTION_SCALING_RGBHV::read() == 0 && !avoidAutoBest && + !uopt.preferScalingRgbhv && !avoidAutoBest && + (rto.videoStandardInput >= 1 && rto.videoStandardInput <= 4)) + { + // autobesthtotal + updateCoastPosition(0); + delay(10); + resetInterruptNoHsyncBadBit(); + resetInterruptSogBadBit(); + delay(10); + // works reliably now on my test HDMI dongle + if (rto.useHdmiSyncFix && !uopt.wantOutputComponent) + { + GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out + } + delay(100); // minimum delay without random failures: TBD + + for (uint8_t i = 0; i < 4; i++) + { + if (GBS::STATUS_INT_SOG_BAD::read() == 1) + { + optimizeSogLevel(); + resetInterruptSogBadBit(); + delay(40); + } + else if (getStatus16SpHsStable() && getStatus16SpHsStable()) + { + // delay(1); // wifi + if (getVideoMode() == rto.videoStandardInput) + { + bool ok = 0; + float sfr = getSourceFieldRate(0); + // _WSN(sfr, 3); + if (rto.videoStandardInput == 1 || rto.videoStandardInput == 3) + { + if (sfr > 58.6f && sfr < 61.4f) + ok = 1; + } + else if (rto.videoStandardInput == 2 || rto.videoStandardInput == 4) + { + if (sfr > 49.1f && sfr < 51.1f) + ok = 1; + } + if (ok) + { // else leave it for later + runAutoBestHTotal(); + // delay(1); // wifi + break; + } + } + } + delay(10); + } + } + else + { + // scaling rgbhv, HD modes, no autobesthtotal + delay(10); + // works reliably now on my test HDMI dongle + if (rto.useHdmiSyncFix && !uopt.wantOutputComponent) + { + GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out + } + // delay(20); + updateCoastPosition(0); + updateClampPosition(); + } + + // _WS(F("pp time: ")); _WSN(millis() - postLoadTimer); + + // make sure + if (rto.useHdmiSyncFix && !uopt.wantOutputComponent) + { + GBS::PAD_SYNC_OUT_ENZ::write(0); // sync out + } + + // late adjustments that require some delay time first + // if (!rto.isCustomPreset) + if (!uopt.slotIsCustom || forceApply) + { + // if (videoStandardInputIsPalNtscSd() && !rto.outModeHdBypass) + if (videoStandardInputIsPalNtscSd() && utilsNotPassThroughMode()) + { + // SNES has less total lines and a slight offset (only relevant in 60Hz) + if (GBS::VPERIOD_IF::read() == 523) + { + GBS::IF_VB_SP::write(GBS::IF_VB_SP::read() + 4); + GBS::IF_VB_ST::write(GBS::IF_VB_ST::read() + 4); + } + } + } + + // new, might be useful (3_6D - 3_72) + GBS::VDS_EXT_HB_ST::write(GBS::VDS_DIS_HB_ST::read()); + GBS::VDS_EXT_HB_SP::write(GBS::VDS_DIS_HB_SP::read()); + GBS::VDS_EXT_VB_ST::write(GBS::VDS_DIS_VB_ST::read()); + GBS::VDS_EXT_VB_SP::write(GBS::VDS_DIS_VB_SP::read()); + // VDS_VSYN_SIZE1 + VDS_VSYN_SIZE2 to VDS_VSYNC_RST + 2 + GBS::VDS_VSYN_SIZE1::write(GBS::VDS_VSYNC_RST::read() + 2); + GBS::VDS_VSYN_SIZE2::write(GBS::VDS_VSYNC_RST::read() + 2); + GBS::VDS_FRAME_RST::write(4); // 3_19 + // VDS_FRAME_NO, VDS_FR_SELECT + GBS::VDS_FRAME_NO::write(1); // 3_1f 0-3 + GBS::VDS_FR_SELECT::write(1); // 3_1b, 3_1c, 3_1d, 3_1e + + // noise starts here! + resetDigital(); + + resetPLLAD(); // also turns on pllad + GBS::PLLAD_LEN::write(1); // 5_11 1 + + // if (!rto.isCustomPreset) + if (!uopt.slotIsCustom || forceApply) + { + GBS::VDS_IN_DREG_BYPS::write(0); // 3_40 2 // 0 = input data triggered on falling clock edge, 1 = bypass + GBS::PLLAD_R::write(3); + GBS::PLLAD_S::write(3); + GBS::PLL_R::write(1); // PLL lock detector skew + GBS::PLL_S::write(2); + GBS::DEC_IDREG_EN::write(1); // 5_1f 7 + GBS::DEC_WEN_MODE::write(1); // 5_1e 7 // 1 keeps ADC phase consistent. around 4 lock positions vs totally random + + // 4 segment + GBS::CAP_SAFE_GUARD_EN::write(0); // 4_21_5 // does more harm than good + // memory timings, anti noise + GBS::PB_CUT_REFRESH::write(1); // helps with PLL=ICLK mode artefacting + GBS::RFF_LREQ_CUT::write(0); // was in motionadaptive toggle function but on, off seems nicer + GBS::CAP_REQ_OVER::write(0); // 4_22 0 1=capture stop at hblank 0=free run + GBS::CAP_STATUS_SEL::write(1); // 4_22 1 1=capture request when FIFO 50%, 0= FIFO 100% + GBS::PB_REQ_SEL::write(3); // PlayBack 11 High request Low request + // 4_2C, 4_2D should be set by preset + GBS::RFF_WFF_OFFSET::write(0x0); // scanline fix + if (rto.videoStandardInput == 3 || rto.videoStandardInput == 4) + { + // this also handles mode 14 csync rgbhv + GBS::PB_CAP_OFFSET::write(GBS::PB_FETCH_NUM::read() + 4); // 4_37 to 4_39 (green bar) + } + // 4_12 should be set by preset + } + + // if (!rto.outModeHdBypass) + if (utilsNotPassThroughMode()) + { + ResetSDRAM(); + } + + setAndUpdateSogLevel(rto.currentLevelSOG); // use this to cycle SP / ADPLL latches + + // if (rto.presetID != 0x06 && rto.presetID != 0x16) { + if (uopt.resolutionID != Output15kHz && uopt.resolutionID != Output15kHzPAL) + { + // IF_VS_SEL = 1 for SD/HD SP mode in HD mode (5_3e 1) + GBS::IF_VS_SEL::write(0); // 0 = "VCR" IF sync, requires VS_FLIP to be on, more stable? + GBS::IF_VS_FLIP::write(1); + } + + GBS::SP_CLP_SRC_SEL::write(0); // 0: 27Mhz clock; 1: pixel clock + GBS::SP_CS_CLP_ST::write(32); + GBS::SP_CS_CLP_SP::write(48); // same as reset parameters + + if (!uopt.wantOutputComponent) + { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out if needed + } + GBS::DAC_RGBS_PWDNZ::write(1); // DAC on if needed + GBS::DAC_RGBS_SPD::write(0); // 0_45 2 DAC_SVM power down disable, somehow less jailbars + GBS::DAC_RGBS_S0ENZ::write(0); // + GBS::DAC_RGBS_S1EN::write(1); // these 2 also help + + rto.useHdmiSyncFix = 0; // reset flag + + GBS::SP_H_PROTECT::write(0); + if (rto.videoStandardInput >= 5) + { + GBS::SP_DIS_SUB_COAST::write(1); // might not disable it at all soon + } + + if (rto.syncTypeCsync) + { + GBS::SP_EXT_SYNC_SEL::write(1); // 5_20 3 disconnect HV input + // stays disconnected until reset condition + } + + rto.coastPositionIsSet = false; // re-arm these + rto.clampPositionIsSet = false; + + // if (rto.outModeHdBypass) + if (utilsIsPassThroughMode()) + { + GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts + GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status + GBS::INTERRUPT_CONTROL_00::write(0x00); + unfreezeVideo(); // eventhough not used atm + // DAC and Sync out will be enabled later + return; // to setOutputHdBypassMode(); + } + + // if (GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) + if (uopt.preferScalingRgbhv) + { + rto.videoStandardInput = 14; + } + else + // if (GBS::GBS_OPTION_SCALING_RGBHV::read() == 0) + { + unsigned long timeout = millis(); + while ((!getStatus16SpHsStable()) && (millis() - timeout < 2002)) + { + delay(10); + // wifiLoop(0); + updateStopPositionDynamic(false); + } + while ((getVideoMode() == 0) && (millis() - timeout < 1505)) + { + delay(10); + // wifiLoop(0); + updateStopPositionDynamic(false); + } + + timeout = millis() - timeout; + if (timeout > 1000) + { + _WSF(PSTR("to1 is: %l\n"), timeout); + } + if (timeout >= 1500) + { + if (rto.currentLevelSOG >= 7) + { + optimizeSogLevel(); + delay(300); + } + } + } + + // early attempt + updateClampPosition(); + if (rto.clampPositionIsSet) + { + if (GBS::SP_NO_CLAMP_REG::read() == 1) + { + GBS::SP_NO_CLAMP_REG::write(0); + } + } + + updateStopPositionDynamic(false); + + if (!rto.syncWatcherEnabled) + { + GBS::SP_NO_CLAMP_REG::write(0); + } + + // this was used with ADC write enable, producing about (exactly?) 4 lock positions + // cycling through the phase let it land favorably + // for (uint8_t i = 0; i < 8; i++) { + // advancePhase(); + //} + + setAndUpdateSogLevel(rto.currentLevelSOG); // use this to cycle SP / ADPLL latches + // optimizePhaseSP(); // do this later in run loop + + GBS::INTERRUPT_CONTROL_01::write(0xff); // enable interrupts + GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status + GBS::INTERRUPT_CONTROL_00::write(0x00); + + OutputComponentOrVGA(); + + // presetPreference 10 means the user prefers bypass mode at startup + // it's best to run a normal format detect > apply preset loop, then enter bypass mode + // this can lead to an endless loop, so applyPresetDoneStage = 10 applyPresetDoneStage = 11 + // are introduced to break out of it. + // also need to check for mode 15 + // also make sure to turn off autoBestHtotal + // if (uopt.presetPreference == 10 && rto.videoStandardInput != 15) { + if (utilsIsPassThroughMode() && rto.videoStandardInput != 15) + { + rto.autoBestHtotalEnabled = 0; + if (rto.applyPresetDoneStage == 11) + { + // we were here before, stop the loop + rto.applyPresetDoneStage = 1; + } + else + { + rto.applyPresetDoneStage = 10; + } + } + else + { + // normal modes + rto.applyPresetDoneStage = 1; + } + + unfreezeVideo(); + + if (uopt.enableFrameTimeLock) + { + activeFrameTimeLockInitialSteps(); + } + + _WS(F("\npreset applied: ")); + if (uopt.resolutionID == Output960 || uopt.resolutionID == Output960PAL) + _WS(F("1280x960")); + else if (uopt.resolutionID == Output1024 || uopt.resolutionID == Output1024PAL) + _WS(F("1280x1024")); + else if (uopt.resolutionID == Output720 || uopt.resolutionID == Output720PAL) + _WS(F("1280x720")); + else if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) + _WS(F("1920x1080")); + else if (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL) + _WS(F("downscale")); + else if (uopt.resolutionID == Output480) + _WS(F("720x480")); + else if (uopt.resolutionID == Output576PAL) + _WS(F("720x576")); + else if (utilsIsPassThroughMode()) + _WS(F("bypass")); + else if (uopt.resolutionID == Output240p) + _WS(F("240p")); + else + _WS(F("UNKNOWN")); + + // if (rto.outModeHdBypass) + // if (utilsIsPassThroughMode()) + // _WS(F(" (bypass)")); + // else if (uopt.slotIsCustom) + // _WS(F(" (custom)")); + + _WS(F(" for ")); + if (rto.videoStandardInput == 1) + _WS(F("NTSC 60Hz ")); + else if (rto.videoStandardInput == 2) + _WS(F("PAL 50Hz ")); + else if (rto.videoStandardInput == 3) + _WS(F("EDTV 60Hz")); + else if (rto.videoStandardInput == 4) + _WS(F("EDTV 50Hz")); + else if (rto.videoStandardInput == 5) + _WS(F("720p 60Hz HDTV ")); + else if (rto.videoStandardInput == 6) + _WS(F("1080i 60Hz HDTV ")); + else if (rto.videoStandardInput == 7) + _WS(F("1080p 60Hz HDTV ")); + else if (rto.videoStandardInput == 8) + _WS(F("Medium Res ")); + else if (rto.videoStandardInput == 13) + _WS(F("VGA/SVGA/XGA/SXGA")); + else if (rto.videoStandardInput == 14) + { + if (rto.syncTypeCsync) + _WSN(F("scaling RGB (CSync)")); + else + _WSN(F("scaling RGB (HV Sync)")); + } + else if (rto.videoStandardInput == 15) + { + if (rto.syncTypeCsync) + _WSN(F("RGB Bypass (CSync)")); + else + _WSN(F("RGB Bypass (HV Sync)")); + } + else if (rto.videoStandardInput == 0) + _WSN(F("!should not go here!")); // TODO ??? + + // if (rto.presetID == 0x05 || rto.presetID == 0x15) { + if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) + { + _WSN(F("(set your TV aspect ratio to 16:9)")); + } + if (rto.videoStandardInput == 14) + { + _WSN(F("\nNote: scaling RGB is still in development")); + } + // presetPreference = OutputCustomized may fail to load (missing) preset file and arrive here with defaults +} + +/** + * @brief This func. does preparations for preset to be loaded by doPostPresetLoadSteps, + * in case of a OutputBypass it is searching FS for matching preset + * and does its loading if it has been found... + * + * @param videoMode + */ +void applyPresets(uint8_t videoMode) +{ + bool waitExtra = false; + + // TODO replace videoMode with VideoStandardInput enum + if (!rto.boardHasPower) + { + _WSN(F("(!) board not responding!")); + return; + } + + // if RGBHV scaling and invoked through web ui or custom preset + // need to know syncTypeCsync + if (videoMode == 14) + { + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) + { + rto.inputIsYPbPr = 0; + if (GBS::STATUS_SYNC_PROC_VSACT::read() == 0) + { + rto.syncTypeCsync = 1; + } + else + { + rto.syncTypeCsync = 0; + } + } + } + + // if (rto.outModeHdBypass || rto.videoStandardInput == 15 || rto.videoStandardInput == 0) + if (utilsIsPassThroughMode() || rto.videoStandardInput == 15 || rto.videoStandardInput == 0) + { + waitExtra = true; + if (videoMode <= 4 || videoMode == 14 || videoMode == 8 || videoMode == 9) + { + GBS::SFTRST_IF_RSTZ::write(1); // early init + GBS::SFTRST_VDS_RSTZ::write(1); + GBS::SFTRST_DEC_RSTZ::write(1); + } + } + rto.presetIsPalForce60 = 0; // the default + rto.outModeHdBypass = None; // the default at this stage + + if (videoMode == 0) + { + // Unknown + _WSF( + PSTR("(!) source format not properly recognized, videoMode: %d, resolutionID: %c\n"), + videoMode, + uopt.resolutionID + ); + videoMode = 3; // in case of success: override to 480p60 + GBS::ADC_INPUT_SEL::write(1); // RGB + delay(10); + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) + { + rto.inputIsYPbPr = false; + rto.syncWatcherEnabled = true; + if (GBS::STATUS_SYNC_PROC_VSACT::read() == 0) + { + rto.syncTypeCsync = true; + } + else + { + rto.syncTypeCsync = false; + } + } + else + { + GBS::ADC_INPUT_SEL::write(0); // YPbPr + delay(10); + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) + { + rto.inputIsYPbPr = true; + rto.syncTypeCsync = true; + rto.syncWatcherEnabled = true; + } + else + { + // found nothing at all, turn off output + + // If we call presetsResetParameters(), soon afterwards loop() -> + // inputAndSyncDetect() -> goLowPowerWithInputDetection() will + // call presetsResetParameters() again. But if we don't call + // presetsResetParameters() here, the second call will never happen. + _DBGN(F("(!) reset runtime parameters while applying preset")); + presetsResetParameters(); + + // Deselect the output resolution in the web UI. We cannot call + // doPostPresetLoadSteps() to select the right resolution, since + // it *enables* the output (showing a green screen) even if + // previously disabled, and we want to *disable* it. + // rto.presetID = Output240p; + uopt.resolutionID = Output480; + return; + } + } + } + + if (uopt.PalForce60) + { + // not equal to custom, saved as pal preset has ntsc customization + // if (uopt.presetPreference != 2) { + // if (!rto.isCustomPreset) { + if (!uopt.slotIsCustom) { + _DBG(F("not a custom preset, ")); + if (videoMode == 2 || videoMode == 4) + { + _DBGF( + PSTR("video mode %d, set PAL@50 to 60Hz\n"), + videoMode + ); + rto.presetIsPalForce60 = 1; + } + if (videoMode == 2) + { + _DBGN(F("video mode #2, switched to #1")); + videoMode = 1; + } + if (videoMode == 4) + { + _DBGN(F("video mode #4, switched to #3")); + videoMode = 3; + } + } + } + + /// If uopt.presetPreference == OutputCustomized and we load a custom + /// preset, check if it's intended to bypass scaling at the current input + /// resolution. If so, setup bypass and skip the rest of applyPresets(). + auto applySavedBypassPreset = [&videoMode]() -> bool + { + // TODO the following description difers from reality, requires an update + /* + Types: + + - Registers: + - Written by applyPresets() -> writeProgramArrayNew(), + loadHdBypassSection(), etc. + - GBS_PRESET_ID @ S1_2B[0:6] + - GBS_PRESET_CUSTOM @ S1_2B[7] + - uopt is source of truth, rto is derived cached state??? + - uopt.presetPreference + - Read by applyPresets() to pick an output resolution. + - rto.presetID + - Written by applyPresets() -> doPostPresetLoadSteps(). + - = register GBS_PRESET_ID. + - rto.isCustomPreset + - Written by applyPresets() -> doPostPresetLoadSteps(). + - = register GBS_PRESET_CUSTOM. + - rto.isCustomPreset and rto.presetID control which button is + highlighted in the web UI (updateWebSocketData() -> + GBSControl.buttonMapping). + + Control flow: + + applyPresets(): + - If uopt.presetPreference == OutputCustomized (yes): + - presetLoadFromFS() + - All custom presets are saved with GBS_PRESET_CUSTOM = 1. + - writeProgramArrayNew() + - GBS_PRESET_ID = output resolution ID + - GBS_PRESET_CUSTOM = 1 + - applySavedBypassPreset(): + - If GBS_PRESET_ID == OutputHdBypass (yes): + - rto.videoStandardInput = videoMode; (not sure why) + - setOutputHdBypassMode(regsInitialized=true) + - rto.outModeHdBypass = 1; + - loadHdBypassSection() + - Overwrites S1_30..5F. + - GBS::GBS_PRESET_ID::write(OutputHdBypass); + - if (!regsInitialized) (false) + - ~~GBS::GBS_PRESET_CUSTOM::write(0);~~ (skipped) + - doPostPresetLoadSteps() + - rto.presetID = GBS::GBS_PRESET_ID::read(); + - OutputHdBypass + - rto.isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); + - true + - Branches based on rto.presetID + - if (rto.outModeHdBypass) (yes) return. + - ... + - rto.outModeHdBypass = 1; (again?!) + */ + + // uint8_t rawPresetId = GBS::GBS_PRESET_ID::read(); + // if (rawPresetId == OutputHdBypass) + if (rto.outModeHdBypass == OutputHdBypass) + { + // Required for switching from 240p to 480p to work. + rto.videoStandardInput = videoMode; + // Setup video mode passthrough. + setOutputHdBypassMode(); + _DBGN(F("OutputHDBypass mode active")); + return true; + } + // if (rawPresetId == OutputRGBHVBypass) + if (rto.outModeHdBypass == OutputRGBHVBypass) + { + // TODO implement setOutputRGBHVBypassMode (I don't have RGBHV inputs to verify) + } + return false; + }; + + // if we're using ESP8266, check if there is saved preset data first +#if defined(ESP8266) + // skip loading from FS if we changing resolution + if(uopt.resolutionID != (OutputResolution)GBS::GBS_PRESET_ID::read() && uopt.slotIsCustom) { + const uint8_t *preset = presetLoadFromFS(videoMode); + if(preset != nullptr) { + writeProgramArrayNew(preset, false); + if (applySavedBypassPreset()) + { + _DBGN(F("Bypass preset applied")); + return; + } + delete preset; + goto apply_presets_skip_preset_loading; + } + } + // else if (uopt.presetPreference == OutputCustomized) { + // { + // + // } else if (uopt.presetPreference == 4) { + // else if (uopt.resolutionID == Output1024) + // { + // writeProgramArrayNew(pal_1280x1024, false); + // _WSN(F("pal_1280x1024 is now active")); + // } +#endif // defined(ESP8266) + + if (videoMode == 1 || videoMode == 3 || videoMode == 8 || videoMode == 9 || videoMode == 14) + { + // if (uopt.presetPreference == OutputCustomized) { + // { + // const uint8_t *preset = presetLoadFromFS(videoMode); + // writeProgramArrayNew(preset, false); + // if (applySavedBypassPreset()) + // { + // _DBGN(F("Bypass preset applied")); + // return; + // } + // } + // } else if (uopt.presetPreference == 4) { + // else if (uopt.resolutionID == Output1024) + // { + // comments are misleading, the functionality is unknown + // if (uopt.matchPresetSource && (videoMode != 8) && (GBS::GBS_OPTION_SCALING_RGBHV::read() == 0)) + // { + // writeProgramArrayNew(ntsc_240p, false); // pref = x1024 override to x960 + // _WSN(F("ntsc_240p is now active")); + // } + // else + // { + // writeProgramArrayNew(ntsc_1280x1024, false); + // _WSN(F("ntsc_1280x1024 is now active")); + // } + // } + // ! + // ! NTSC input + // ! + // if (uopt.presetPreference == 0) { + if (uopt.resolutionID == Output240p) + { + writeProgramArrayNew(ntsc_240p, false); + _WSN(F("ntsc_240p is now active")); + // } else if (uopt.presetPreference == 1) { + } + else if (uopt.resolutionID == Output480) + { + writeProgramArrayNew(ntsc_720x480, false); + _WSN(F("ntsc_720x480 is now active")); + // } else if (uopt.presetPreference == 3) { + } + else if (uopt.resolutionID == Output720) + { + writeProgramArrayNew(ntsc_1280x720, false); + _WSN(F("ntsc_1280x720 is now active")); + } // else if (uopt.presetPreference == 5) { + else if (uopt.resolutionID == Output1080) + { + writeProgramArrayNew(ntsc_1920x1080, false); + _WSN(F("ntsc_1920x1080 is now active")); + // } else if (uopt.presetPreference == 6) { + } + else if (uopt.resolutionID == Output15kHz) + { + writeProgramArrayNew(ntsc_downscale, false); + _WSN(F("ntsc_downscale is now active")); + } + } + else if (videoMode == 2 || videoMode == 4) + { + // ! + // ! PAL input + // ! + // if (uopt.presetPreference == 0) { + if (uopt.resolutionID == Output240p) + { + // if (uopt.matchPresetSource) + // { + // writeProgramArrayNew(pal_1280x1024, false); // pref = x960 override to x1024 + // _WSN(F("pal_1280x1024 is now active")); + // } + // else + // { + writeProgramArrayNew(pal_240p, false); + _WSN(F("pal_240p is now active")); + // } + // } else if (uopt.presetPreference == 1) { + } + else if (uopt.resolutionID == Output576PAL) + { + writeProgramArrayNew(pal_768x576, false); // 4:3 square pixel + _WSN(F("pal_768x576 is now active")); + // } else if (uopt.presetPreference == 3) { + } + else if (uopt.resolutionID == Output720) + { + writeProgramArrayNew(pal_1280x720, false); + _WSN(F("pal_1280x720 is now active")); + } + // else if (uopt.presetPreference == 5) { + else if (uopt.resolutionID == Output1080) + { + writeProgramArrayNew(pal_1920x1080, false); + _WSN(F("pal_1920x1080 is now active")); + // } else if (uopt.presetPreference == 6) { + } + else if (uopt.resolutionID == Output15kHz) + { + writeProgramArrayNew(pal_downscale, false); + _WSN(F("pal_downscale is now active")); + } + } + else if (videoMode == 5 || videoMode == 6 || videoMode == 7 || videoMode == 13) + { + // use bypass mode for these HD sources + rto.videoStandardInput = videoMode; + // registers unitialized, do post preset + setOutputHdBypassMode(false); + _WSN(F("HD Bypass is now active")); + // don't go through doPostPresetLoadSteps + goto apply_presets_end; + } + else if (videoMode == 15) + { + _WS(F("RGB/HV ")); + if (rto.syncTypeCsync) + { + _WS(F("(CSync) ")); + } + if (uopt.preferScalingRgbhv) { + _WS(F("(prefer scaling mode")); + } + _WSN(); + setOutputRGBHVBypassMode(); + // don't go through doPostPresetLoadSteps + goto apply_presets_end; + } + +apply_presets_skip_preset_loading: + rto.videoStandardInput = videoMode; + _DBGF(PSTR("video mode set: %d\n"), videoMode); + if (waitExtra) + { + // extra time needed for digital resets, so that autobesthtotal works first attempt + // _WSN("waitExtra 400ms"); + delay(400); // min ~ 300 + } + doPostPresetLoadSteps(); + +apply_presets_end: + // since we probably load all new register values + // presetSaveToFS(); + return; +} + +/** + * @brief + * + */ +void loadPresetDeinterlacerSection() +{ + uint16_t index = 0; + uint8_t bank[16]; + writeOneByte(0xF0, 2); + for (int j = 0; j <= 3; j++) + { // start at 0x00 + copyBank(bank, presetDeinterlacerSection, &index); + writeBytes(j * 16, bank, 16); + } +} + +#if defined(ESP8266) + +/** + * @brief Read preset preferences from "preset_name.slotID", + * file for active Slot, into an array that + * MUST be DELETED + * afterwards. If preset file doesn't esists, returns nullptr. + * + * @param forVideoMode + * @return const uint8_t* + */ +const uint8_t * presetLoadFromFS(byte forVideoMode) +{ + static uint8_t * preset = nullptr; + String s = ""; + char buffer[32] = ""; + fs::File f; + char *tmp; + uint16_t i = 0; + + utilsGetPresetsFileNameFor(forVideoMode, buffer); + + // reading preset data + f = LittleFS.open(buffer, "r"); + if (!f) + { + _WSF(PSTR("no preset file for: %s\n"), buffer); + // if (forVideoMode == 2 || forVideoMode == 4) + // return pal_240p; + // else + // return ntsc_240p; + goto load_preset_from_fs_end; + } + else + { + _WSF(PSTR("found preset data: %s\n"), f.name()); + s = f.readStringUntil('}'); + f.close(); + } + + tmp = strtok(&s[0], ","); + preset = new uint8_t[432]; + while (tmp) + { + preset[i++] = (uint8_t)atoi(tmp); + tmp = strtok(NULL, ","); + optimistic_yield(100); + } + +load_preset_from_fs_end: + return preset; +} + +/** + * @brief Save "preset.active_slotID" data if the active slot is custom. + * If preset file exists it will be overriden + * Logic: + * - create preset file ("preset.current_slot"). Preset name identified by input video signal + * - read all registers and save the data into preset file. In other words the snapshot with + * all the previous changes being saved into preset file and will be autoloaded next time + * if the current slot is active and the input video signal matches preset. + */ +void presetSaveToFS() +{ + // saving ONLY if the active slot is "custom" + if(!uopt.slotIsCustom) return; + + uint8_t readout = 0; + fs::File f; + uint8_t i = 0; + char buffer[32] = ""; + + utilsGetPresetsFileNameFor(rto.videoStandardInput, buffer); + + // open preset file + f = LittleFS.open(buffer, "w"); + if (!f) + { + _WSF(PSTR("failed to open preset file: %s\n"), buffer); + } + else + { + _WSF(PSTR("preset data saved into: %s\n"), buffer); + + // GBS::GBS_PRESET_CUSTOM::write(1); // use one reserved bit to mark this as a custom preset + // TODO don't store scanlines - WHY? + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) + // if (uopt.wantScanlines) + // { + // disableScanlines(); + // } + + if (!rto.extClockGenDetected) + { + if (uopt.enableFrameTimeLock && FrameSync::getSyncLastCorrection() != 0) + { + FrameSync::reset(uopt.frameTimeLockMethod); + } + } + + while(i <= 5) + { + writeOneByte(0xF0, i); + switch (i) + { + case 0: + // misc registers + for (int x = 0x40; x <= 0x5F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + // OSD registers + for (int x = 0x90; x <= 0x9F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + break; + case 1: + // Input Formatter + HD-bypass + Mode Detect + for (int x = 0x0; x <= 0x2F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + break; + case 2: + // De-interlace (00-3F) + // not needed anymore - ??? + break; + case 3: + // Video Processor + PIP + for (int x = 0x0; x <= 0x7F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + break; + case 4: + // Memory + Capture & Playback + Read FIFO, Write FIFO + for (int x = 0x0; x <= 0x5F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + break; + case 5: + // ADC + Sync Proc + for (int x = 0x0; x <= 0x6F; x++) + { + readFromRegister(x, 1, &readout); + f.print(readout); + f.println(","); + } + break; + } + delay(1); + i++; + } + // ? EOF symbol + f.println("};"); + f.close(); + } +} + +#endif // defined(ESP8266) \ No newline at end of file diff --git a/src/presets.h b/src/presets.h new file mode 100644 index 00000000..8c46bb5b --- /dev/null +++ b/src/presets.h @@ -0,0 +1,52 @@ +/* +##################################################################################### +# File: presets.h # +# File Created: Thursday, 2nd May 2024 6:38:29 pm # +# Author: # +# Last Modified: Saturday, 22nd June 2024 4:58:21 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#ifndef _PRESET_H_ +#define _PRESET_H_ + +#include +#include "options.h" +#include "prefs.h" +#include "video.h" +#include "osd.h" +#include "ntsc_240p.h" +#include "pal_240p.h" +#include "ntsc_720x480.h" +#include "pal_768x576.h" +#include "ntsc_1280x720.h" +#include "ntsc_1280x1024.h" +#include "ntsc_1920x1080.h" +#include "ntsc_downscale.h" +#include "pal_1280x720.h" +#include "pal_1280x1024.h" +#include "pal_1920x1080.h" +#include "pal_downscale.h" +#include "presetMdSection.h" +#include "presetDeinterlacerSection.h" + +extern char serialCommand; +extern char userCommand; + +void loadPresetMdSection(); +void presetsResetParameters(); +void doPostPresetLoadSteps(bool forceApply = false); +void applyPresets(uint8_t result); +void loadPresetDeinterlacerSection(); + +#if defined(ESP8266) + +const uint8_t * presetLoadFromFS(byte forVideoMode); +void presetSaveToFS(); + +#endif // defined(ESP8266) + +#endif // _PRESET_H_ diff --git a/rgbhv.h b/src/rgbhv.h similarity index 100% rename from rgbhv.h rename to src/rgbhv.h diff --git a/src/si5351mcu.cpp b/src/si5351mcu.cpp deleted file mode 100644 index 4c6c6a7a..00000000 --- a/src/si5351mcu.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/* - * si5351mcu - Si5351 library for Arduino MCU tuned for size and click-less - * - * Copyright (C) 2017 Pavel Milanes - * - * Many chunk of codes are derived-from/copied from other libs - * all GNU GPL licenced: - * - Linux Kernel (www.kernel.org) - * - Hans Summers libs and demo code (qrp-labs.com) - * - Etherkit (NT7S) Si5351 libs on github - * - DK7IH example. - * - Jerry Gaffke integer routines for the bitx20 group - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Arduino.h" -#include "si5351mcu.h" - -// wire library loading, if not defined -#ifndef WIRE_H - #include "Wire.h" -#endif - -/***************************************************************************** - * This is the default init procedure, it set the Si5351 with this params: - * XTAL 27.000 Mhz - *****************************************************************************/ - void Si5351mcu::init(void) { - // init with the default freq - init(int_xtal); -} - - -/***************************************************************************** - * This is the custom init procedure, it's used to pass a custom xtal - * and has the duty of init the I2C protocol handshake - *****************************************************************************/ - void Si5351mcu::init(uint32_t nxtal) { - // set the new base xtal freq - base_xtal = int_xtal = nxtal; - - // start I2C (wire) procedures - Wire.begin(); - - // shut off the spread spectrum by default, DWaite contibuted code - uint8_t regval; - regval = i2cRead(149); - regval &= ~0x80; // set bit 7 LOW to turn OFF spread spectrum mode - i2cWrite(149, regval); - - // power off all the outputs - off(); -} - - -/***************************************************************************** - * This function set the freq of the corresponding clock. - * - * In my tests my Si5351 can work between 7,8 Khz and ~225 Mhz [~250 MHz with - * overclocking] as usual YMMV - * - * Click noise: - * - The lib has a reset programmed [aka: click noise] every time it needs to - * change the output divider of a particular MSynth, if you move in big steps - * this can lead to an increased rate of click noise per tunning step. - * - If you move at a pace of a few Hz each time the output divider will - * change at a low rate, hence less click noise per tunning step. - * - The output divider moves [change] faster at high frequencies, so at HF the - * clikc noise is at the real minimum possible. - * - * [See the README.md file for other details] - ****************************************************************************/ -void Si5351mcu::setFreq(uint8_t clk, uint32_t freq) { - uint8_t a, R = 1, pll_stride = 0, msyn_stride = 0; - uint32_t b, c, f, fvco, outdivider; - uint32_t MSx_P1, MSNx_P1, MSNx_P2, MSNx_P3; - - // Overclock option - #ifdef SI_OVERCLOCK - // user a overclock setting for the VCO, max value in my hardware - // was 1.05 to 1.1 GHz, as usual YMMV [See README.md for details] - outdivider = SI_OVERCLOCK / freq; - #else - // normal VCO from the datasheet and AN - // With 900 MHz beeing the maximum internal PLL-Frequency - outdivider = 900000000 / freq; - #endif - - // use additional Output divider ("R") - while (outdivider > 900) { - R = R * 2; - outdivider = outdivider / 2; - } - - // finds the even divider which delivers the intended Frequency - if (outdivider % 2) outdivider--; - - // Calculate the PLL-Frequency (given the even divider) - fvco = outdivider * R * freq; - - // Convert the Output Divider to the bit-setting required in register 44 - switch (R) { - case 1: R = 0; break; - case 2: R = 16; break; - case 4: R = 32; break; - case 8: R = 48; break; - case 16: R = 64; break; - case 32: R = 80; break; - case 64: R = 96; break; - case 128: R = 112; break; - } - - // we have now the integer part of the output msynth - // the b & c is fixed below - - MSx_P1 = 128 * outdivider - 512; - - // calc the a/b/c for the PLL Msynth - /*************************************************************************** - * We will use integer only on the b/c relation, and will >> 5 (/32) both - * to fit it on the 1048 k limit of C and keep the relation - * the most accurate possible, this works fine with xtals from - * 24 to 28 Mhz. - * - * This will give errors of about +/- 2 Hz maximum - * as per my test and simulations in the worst case, well below the - * XTAl ppm error... - * - * This will free more than 1K of the final eeprom - * - ****************************************************************************/ - a = fvco / int_xtal; - b = (fvco % int_xtal) >> 5; // Integer part of the fraction - // scaled to match "c" limits - c = int_xtal >> 5; // "c" scaled to match it's limits - // in the register - - // f is (128*b)/c to mimic the Floor(128*(b/c)) from the datasheet - f = (128 * b) / c; - - // build the registers to write - MSNx_P1 = 128 * a + f - 512; - MSNx_P2 = 128 * b - f * c; - MSNx_P3 = c; - - // PLLs and CLK# registers are allocated with a stride, we handle that with - // the stride var to make code smaller - if (clk > 0 ) pll_stride = 8; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnarrowing" - // HEX makes it easier to human read on bit shifts - uint8_t reg_bank_26[] = { - (MSNx_P3 & 0xFF00) >> 8, // Bits [15:8] of MSNx_P3 in register 26 - MSNx_P3 & 0xFF, - (MSNx_P1 & 0x030000L) >> 16, - (MSNx_P1 & 0xFF00) >> 8, // Bits [15:8] of MSNx_P1 in register 29 - MSNx_P1 & 0xFF, // Bits [7:0] of MSNx_P1 in register 30 - ((MSNx_P3 & 0x0F0000L) >> 12) | ((MSNx_P2 & 0x0F0000) >> 16), // Parts of MSNx_P3 and MSNx_P1 - (MSNx_P2 & 0xFF00) >> 8, // Bits [15:8] of MSNx_P2 in register 32 - MSNx_P2 & 0xFF // Bits [7:0] of MSNx_P2 in register 33 - }; -#pragma GCC diagnostic pop - - // We could do this here - but move it next to the reg_bank_42 write - // i2cWriteBurst(26 + pll_stride, reg_bank_26, sizeof(reg_bank_26)); - - // Write the output divider msynth only if we need to, in this way we can - // speed up the frequency changes almost by half the time most of the time - // and the main goal is to avoid the nasty click noise on freq change - if (omsynth[clk] != outdivider || o_Rdiv[clk] != R ) { - - // CLK# registers are exactly 8 * clk# bytes stride from a base register. - msyn_stride = clk * 8; - - // keep track of the change - omsynth[clk] = (uint16_t) outdivider; - o_Rdiv[clk] = R; // cache it now, before we OR mask up R for special divide by 4 - - // See datasheet, special trick when MSx == 4 - // MSx_P1 is always 0 if outdivider == 4, from the above equations, so there is - // no need to set it to 0. ... MSx_P1 = 128 * outdivider - 512; - // - // See para 4.1.3 on the datasheet. - // - - if ( outdivider == 4 ) { - R |= 0x0C; // bit set OR mask for MSYNTH divide by 4, for reg 44 {3:2] - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnarrowing" - // HEX makes it easier to human read on bit shifts - uint8_t reg_bank_42[] = { - 0, // Bits [15:8] of MS0_P3 (always 0) in register 42 - 1, // Bits [7:0] of MS0_P3 (always 1) in register 43 - ((MSx_P1 & 0x030000L ) >> 16) | R, // Bits [17:16] of MSx_P1 in bits [1:0] and R in [7:4] | [3:2] - (MSx_P1 & 0xFF00) >> 8, // Bits [15:8] of MSx_P1 in register 45 - MSx_P1 & 0xFF, // Bits [7:0] of MSx_P1 in register 46 - 0, // Bits [19:16] of MS0_P2 and MS0_P3 are always 0 - 0, // Bits [15:8] of MS0_P2 are always 0 - 0 // Bits [7:0] of MS0_P2 are always 0 - }; -#pragma GCC diagnostic pop - - // Get the two write bursts as close together as possible, - // to attempt to reduce any more click glitches. This is - // at the expense of only 24 increased bytes compilation size in AVR 328. - // Everything is already precalculated above, reducing any delay, - // by not doing calculations between the burst writes. - - i2cWriteBurst(26 + pll_stride, reg_bank_26, sizeof(reg_bank_26)); - i2cWriteBurst(42 + msyn_stride, reg_bank_42, sizeof(reg_bank_42)); - - // - // https://www.silabs.com/documents/public/application-notes/Si5350-Si5351%20FAQ.pdf - // - // 11.1 "The Int, R and N register values inside the Interpolative Dividers are updated - // when the LSB of R is written via I2C." - Q. does this mean reg 44 or 49 (misprint ?) ??? - // - // 10.1 "All outputs are within +/- 500ps of one another at power up (if pre-programmed) - // or if PLLA and PLLB are reset simultaneously via register 177." - // - // 17.1 "The PLL can track any abrupt input frequency changes of 3–4% without losing - // lock to it. Any input frequency changes greater than this amount will not - // necessarily track from the input to the output - - // must reset the so called "PLL", in fact the output msynth - reset(); - - } - else { - i2cWriteBurst(26 + pll_stride, reg_bank_26, sizeof(reg_bank_26)); - } - -} - - -/***************************************************************************** - * Reset of the PLLs and multisynths output enable - * - * This must be called to soft reset the PLLs and cycle the output of the - * multisynths: this is the "click" noise source in the RF spectrum. - * - * So it must be avoided at all costs, so this lib just call it at the - * initialization of the PLLs and when a correction is applied - * - * If you are concerned with accuracy you can implement a reset every - * other Mhz to be sure it get exactly on spot. - ****************************************************************************/ -void Si5351mcu::reset(void) { - // This soft-resets PLL A & B (32 + 128) in just one step - i2cWrite(177, 0xA0); -} - - -/***************************************************************************** - * Function to disable all outputs - * - * The PLL are kept running, just the m-synths are powered off. - * - * This allows to keep the chip warm and exactly on freq the next time you - * enable an output. - ****************************************************************************/ -void Si5351mcu::off(void) { - // This disable all the CLK outputs - for (byte i=0; i < SICHANNELS; i++) { - disable(i); - } -} - - -/***************************************************************************** - * Function to set the correction in Hz over the Si5351 XTAL. - * - * This will call a reset of the PLLs and multi-synths so it will produce a - * click every time it's called - ****************************************************************************/ -void Si5351mcu::correction(int32_t diff) { - // apply some corrections to the xtal - int_xtal = base_xtal + diff; - - // reset the PLLs to apply the correction - reset(); -} - - -/***************************************************************************** - * This function enables the selected output - * - * Beware: ZERO is clock output enabled, in register 16+CLK - *****************************************************************************/ -void Si5351mcu::enable(uint8_t clk) { - // var to handle the mask of the registers value - uint8_t m = SICLK0_R; - - if (clk > 0) { - m = SICLK12_R; - } - - // write the register value - i2cWrite(16 + clk, m + clkpower[clk]); - - // 1 & 2 are mutually exclusive - if (clk == 1) disable(2); - if (clk == 2) disable(1); - - // update the status of the clk - clkOn[clk] = 1; -} - - -/***************************************************************************** - * This function disables the selected output - * - * Beware: ONE is clock output disabled, in register 16+CLK - * *****************************************************************************/ -void Si5351mcu::disable(uint8_t clk) { - // send - i2cWrite(16 + clk, 0x80); - - // update the status of the clk - clkOn[clk] = 0; -} - - -/**************************************************************************** - * Set the power output for each output independently - ***************************************************************************/ -void Si5351mcu::setPower(uint8_t clk, uint8_t power) { - // set the power to the correct var - clkpower[clk] = power; - - // now enable the output to get it applied - enable(clk); -} - -/**************************************************************************** - * method to send multi-byte burst register data. - ***************************************************************************/ -uint8_t Si5351mcu::i2cWriteBurst( const uint8_t start_register, - const uint8_t *data, - const uint8_t numbytes) { - - // This method saves the massive overhead of having to keep opening - // and closing the I2C bus for consecutive register writes. It - // also saves numbytes - 1 writes for register address selection. - Wire.beginTransmission(SIADDR); - - Wire.write(start_register); - Wire.write(data, numbytes); - // All of the bytes queued up in the above write() calls are buffered - // up and will be sent to the slave in one "burst", on the call to - // endTransmission(). This also sends the I2C STOP to the Slave. - return Wire.endTransmission(); - // returns non zero on error -} - -/**************************************************************************** - * function to send the register data to the Si5351, arduino way. - ***************************************************************************/ -void Si5351mcu::i2cWrite( const uint8_t regist, const uint8_t value) { - // Using the "burst" method instead of - // doing it longhand saves a few bytes - i2cWriteBurst( regist, &value, 1); - -} - -/**************************************************************************** - * Read i2C register, returns -1 on error or timeout - ***************************************************************************/ -int16_t Si5351mcu::i2cRead( const uint8_t regist ) { - int value; - - Wire.beginTransmission(SIADDR); - Wire.write(regist); - Wire.endTransmission(); - - Wire.requestFrom(SIADDR, 1); - if ( Wire.available() ) { - value = Wire.read(); - } - else { - value = -1; // "EOF" in C - } - - return value; -} diff --git a/src/si5351mcu.h b/src/si5351mcu.h deleted file mode 100644 index 238f20ff..00000000 --- a/src/si5351mcu.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * si5351mcu - Si5351 library for Arduino MCU tuned for size and click-less - * - * Copyright (C) 2017 Pavel Milanes - * - * Many chunk of codes are derived-from/copied from other libs - * all GNU GPL licenced: - * - Linux Kernel (www.kernel.org) - * - Hans Summers libs and demo code (qrp-labs.com) - * - Etherkit (NT7S) Si5351 libs on github - * - DK7IH example. - * - Jerry Gaffke integer routines for the bitx20 group - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -/**************************************************************************** - * This lib tricks: - * - * CLK0 will use PLLA - * CLK1 will use PLLB - * CLK2 will use PLLB - * - * Lib defaults - * - XTAL is 27 Mhz. - * - Always put the internal 8pF across the xtal legs to GND - * - lowest power output (2mA) - * - After the init all outputs are off, you need to enable them in your code. - * - * The correction procedure is not for the PPM as other libs, this - * is just +/- Hz to the XTAL freq, you may get a click noise after - * applying a correction - * - * The init procedure is mandatory as it set the Xtal (the default or a custom - * one) and prepare the Wire (I2C) library for operation. - ****************************************************************************/ - -#ifndef SI5351MCU_H -#define SI5351MCU_H - -// rigor includes -#include "Arduino.h" -#include "Wire.h" - -// default I2C address of the Si5351A - other variants may differ -#define SIADDR 0x60 - -// The number of output channels - 3 for Si5351A 10 pin -#define SICHANNELS 3 - -// register's power modifiers -#define SIOUT_2mA 0 -#define SIOUT_4mA 1 -#define SIOUT_6mA 2 -#define SIOUT_8mA 3 - -// registers base (2mA by default) -#define SICLK0_R 76 // 0b01001100 -#define SICLK12_R 108 // 0b01101100 - -class Si5351mcu { - private: - // base xtal freq, over this we apply the correction factor - // by default 27 MHz - uint32_t base_xtal = 27000000L; - - // this is the work value, with the correction applied - // via the correction() procedure - uint32_t int_xtal = base_xtal; - - // clk# power holders (2ma by default) - uint8_t clkpower[SICHANNELS] = { 0 }; - - // local var to keep track of when to reset the "pll" - /********************************************************* - * BAD CONCEPT on the datasheet and AN: - * - * The chip has a soft-reset for PLL A & B but in - * practice the PLL does not need to be reseted. - * - * Test shows that if you fix the Msynth output - * dividers and move any of the VCO from bottom to top - * the frequency moves smooth and clean, no reset needed - * - * The reset is needed when you changes the value of the - * Msynth output divider, even so it's not always needed - * so we use this var to keep track of all three and only - * reset the "PLL" when this value changes to be sure - * - * It's a word (16 bit) because the final max value is 900 - *********************************************************/ - uint16_t omsynth[SICHANNELS] = { 0 }; - uint8_t o_Rdiv[SICHANNELS] = { 0 }; - - public: - // var to check the clock state - bool clkOn[SICHANNELS] = { 0 }; // This should not really be public - use isEnabled() - - public: - // default init procedure - void init(void); - - // custom init procedure (XTAL in Hz); - void init(uint32_t); - - // reset all PLLs - static void reset(void); - - // set CLKx(0..2) to freq (Hz) - void setFreq(uint8_t, uint32_t); - - // pass a correction factor - void correction(int32_t); - - // enable some CLKx output - void enable(uint8_t); - - // disable some CLKx output - void disable(uint8_t); - - // disable all outputs - void off(void); - - // set power output to a specific clk - void setPower(uint8_t, uint8_t); - - // used to talk with the chip, via Arduino Wire lib - // - // declared as static, since they do not reference any this-> class attributes - // - static void i2cWrite( uint8_t reg, uint8_t val ); - static uint8_t i2cWriteBurst( uint8_t start_register, const uint8_t *data, uint8_t numbytes ); - static int16_t i2cRead( uint8_t reg ); - - inline bool isEnabled( const uint8_t channel ) { - return channel < SICHANNELS && clkOn[ channel ] != 0; - }; - - inline uint8_t getPower( const uint8_t channel ) { - return channel < SICHANNELS ? clkpower[ channel ] : 0; - }; - - inline uint32_t getXtalBase( void ) { - return base_xtal; - }; - - inline uint32_t getXtalCurrent( void ) { - return int_xtal; - }; - -}; - - -#endif //SI5351MCU_H diff --git a/src/si5351mcu.md b/src/si5351mcu.md deleted file mode 100644 index e599da7e..00000000 --- a/src/si5351mcu.md +++ /dev/null @@ -1 +0,0 @@ -Si5351 0.7.1 (https://github.com/pavelmc/Si5351mcu/commit/cbbd8067e9c8e35ca2b9c886c2c97d8d553c97ed), modified to fix compiler warnings. diff --git a/src/slot.cpp b/src/slot.cpp new file mode 100644 index 00000000..e107be4e --- /dev/null +++ b/src/slot.cpp @@ -0,0 +1,276 @@ +/* +########################################################################### +# File: slot.cpp # +# File Created: Friday, 31st May 2024 8:41:15 am # +# Author: Sergey Ko # +# Last Modified: Monday, 24th June 2024 2:16:13 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#include "slot.h" + +/** + * @brief Load slot data + * + * @param slotIndex + * @return true + * @return false + */ +bool slotLoad(const uint8_t & slotIndex) { + SlotMetaArray slotsObject; + uopt.slotID = slotIndex; + fs::File slotsBinaryFile = LittleFS.open(FPSTR(slotsFile), "r"); + // reset custom slot indicator + uopt.slotIsCustom = false; + if (slotsBinaryFile) + { + slotsBinaryFile.read((byte *)&slotsObject, sizeof(slotsObject)); + slotsBinaryFile.close(); + // update parameters + uopt.resolutionID = slotsObject.slot[slotIndex].resolutionID; + GBS::GBS_PRESET_ID::write((uint8_t)uopt.resolutionID); + uopt.wantScanlines = (bool)slotsObject.slot[slotIndex].scanlines; + uopt.scanlineStrength = slotsObject.slot[slotIndex].scanlinesStrength; + uopt.wantVdsLineFilter = (bool)slotsObject.slot[slotIndex].wantVdsLineFilter; + uopt.wantStepResponse = (bool)slotsObject.slot[slotIndex].wantStepResponse; + uopt.wantPeaking = (bool)slotsObject.slot[slotIndex].wantPeaking; + uopt.enableAutoGain = (bool)slotsObject.slot[slotIndex].enableAutoGain; + uopt.enableFrameTimeLock = (bool)slotsObject.slot[slotIndex].enableFrameTimeLock; + uopt.frameTimeLockMethod = slotsObject.slot[slotIndex].frameTimeLockMethod; + uopt.deintMode = slotsObject.slot[slotIndex].deintMode; + uopt.wantTap6 = (bool)slotsObject.slot[slotIndex].wantTap6; + uopt.wantFullHeight = (bool)slotsObject.slot[slotIndex].wantFullHeight; + // uopt.matchPresetSource = slotsObject.slot[slotIndex].matchPresetSource; + uopt.PalForce60 = (bool)slotsObject.slot[slotIndex].PalForce60; + // identify if slot is customized + String slot_name = String(emptySlotName); + if(strcmp(slotsObject.slot[slotIndex].name, slot_name.c_str()) != 0) { + uopt.slotIsCustom = true; + } + return true; + } + return false; +} + +/** + * @brief update slot[slotIndex] data. If no need to update slotName, + * it can be equal an empty string. + * + * @param slotsObject + * @param slotIndex + * @param slotName + */ +void slotUpdate(SlotMetaArray & slotsObject, const uint8_t & slotIndex, String * slotName) { + if(slotName != nullptr) { + const char space = 0x20; + uint8_t k = slotName->length(); + uint8_t nameMaxLen = sizeof(slotsObject.slot[slotIndex].name); + strcpy(slotsObject.slot[slotIndex].name, slotName->c_str()); + while(k < nameMaxLen - 1) { + slotsObject.slot[slotIndex].name[k] = space; + k ++; + } + } + slotsObject.slot[slotIndex].resolutionID = uopt.resolutionID; + slotsObject.slot[slotIndex].scanlines = (uopt.wantScanlines ? 1 : 0); + slotsObject.slot[slotIndex].scanlinesStrength = uopt.scanlineStrength; + slotsObject.slot[slotIndex].wantVdsLineFilter = (uopt.wantVdsLineFilter ? 1 : 0); + slotsObject.slot[slotIndex].wantStepResponse = (uopt.wantStepResponse ? 1 : 0); + slotsObject.slot[slotIndex].wantPeaking = (uopt.wantPeaking ? 1 : 0); + slotsObject.slot[slotIndex].enableAutoGain = (uopt.enableAutoGain ? 1 : 0); + slotsObject.slot[slotIndex].enableFrameTimeLock = (uopt.enableFrameTimeLock ? 1 : 0); + slotsObject.slot[slotIndex].frameTimeLockMethod = uopt.frameTimeLockMethod; + slotsObject.slot[slotIndex].deintMode = uopt.deintMode; + slotsObject.slot[slotIndex].wantTap6 = (uopt.wantTap6 ? 1 : 0); + slotsObject.slot[slotIndex].wantFullHeight = (uopt.wantFullHeight ? 1 : 0); + // slotsObject.slot[slotIndex].matchPresetSource = uopt.matchPresetSource; + slotsObject.slot[slotIndex].PalForce60 = (uopt.PalForce60 ? 1 : 0); +} + +/** + * @brief Read slot data into slotsObject + * + * @param slotsObject + * @returns 1 = file exists and data has been read + * @returns 0 = file has been created, slotsObject contains defaults + * @returns -1 = slots.bin is not accessible + */ +int8_t slotGetData(SlotMetaArray & slotsObject) { + uint8_t i = 0; + fs::File slotsBinaryFile = LittleFS.open(FPSTR(slotsFile), "r"); + + if (slotsBinaryFile) + { + // read data into slotsObject + slotsBinaryFile.read((byte *)&slotsObject, sizeof(slotsObject)); + slotsBinaryFile.close(); + return 1; + } + + _DBGF(PSTR("%s not found\n"), FPSTR(slotsFile)); + String slot_name = String(emptySlotName); + while (i < SLOTS_TOTAL) + { + slotsObject.slot[i].scanlines = 0; + slotsObject.slot[i].resolutionID = Output480; + slotsObject.slot[i].scanlinesStrength = 0x30; + slotsObject.slot[i].wantVdsLineFilter = 0; + slotsObject.slot[i].wantStepResponse = 1; + slotsObject.slot[i].wantPeaking = 1; + slotsObject.slot[i].enableAutoGain = 0; + slotsObject.slot[i].enableFrameTimeLock = 0; + slotsObject.slot[i].frameTimeLockMethod = 0; + slotsObject.slot[i].deintMode = 0; + slotsObject.slot[i].wantTap6 = 0; + slotsObject.slot[i].wantFullHeight = 0; + // slotsObject.slot[i].matchPresetSource = 0; + slotsObject.slot[i].PalForce60 = 0; + strncpy(slotsObject.slot[i].name, + slot_name.c_str(), + sizeof(slotsObject.slot[i].name) + ); + i++; + delay(1); + } + // file doesn't exist, let's create one + _DBGF(PSTR("attempt to write to %s..."), FPSTR(slotsFile)); + slotsBinaryFile = LittleFS.open(FPSTR(slotsFile), "w"); + if(slotsBinaryFile) { + slotsBinaryFile.write((byte *)&slotsObject, sizeof(slotsObject)); + slotsBinaryFile.close(); + _DBGN(F("ok")); + return 0; + } + _DBGN(F("fail")); + + return -1; +} + +/** + * @brief Save slot data into slots.bin + * + * @return true if data has been saved + * @return false if file is not accessible + */ +bool slotSetData(SlotMetaArray & slotsObject) { + fs::File slotsBinaryFile = LittleFS.open(FPSTR(slotsFile), "w"); + if(slotsBinaryFile) { + slotsBinaryFile.write((byte *)&slotsObject, sizeof(slotsObject)); + slotsBinaryFile.close(); + String slot_name = String(emptySlotName); + if(strcmp(slotsObject.slot[uopt.slotID].name, slot_name.c_str()) != 0) { + // now it's a custom preset + uopt.slotIsCustom = true; + // dump preset data + presetSaveToFS(); + } + return true; + } + return false; +} + +/** + * @brief Updates slots.bin with new parameter values of the current slot + * + * @return true + * @return false + */ +bool slotFlush() { + // proceed with update ONLY if it's previously + // created (slot/set) slot + if(!uopt.slotIsCustom) { + _DBGN(F("(!) this is not a custom slot, omit update...")); + return false; + } + + SlotMetaArray slotObject; + // retrieve data + if(slotGetData(slotObject) == -1) + return false; + // update current slot + slotUpdate(slotObject, uopt.slotID); + // write back the data + if(!slotSetData(slotObject)) + return false; + + _DBGF(PSTR("slotID: %d has been updated\n"), uopt.slotID); + return true; +} + +/** + * @brief This does slot[slotIndex] parameter reset to + * default values (see: slotResetDefaults) and saves it into slots.bin + * + * @return true + * @return false + */ +bool slotResetFlush(const uint8_t & slotIndex) { + SlotMetaArray slotObject; + // retrieve data + if(slotGetData(slotObject) == -1) + return false; + slotResetDefaults(slotObject, slotIndex); + // write back the data + if(!slotSetData(slotObject)) + return false; + + _DBGF(PSTR("slotID: %d reset success\n"), slotIndex); + return true; +} + +/** + * @brief Set dafault values in slot[slotIndex] + * + * @param slotsObject + * @param slotIndex + */ +void slotResetDefaults(SlotMetaArray & slotsObject, const uint8_t & slotIndex) { + // here could be memcpy of a new object... + String slot_name = String(emptySlotName); + slotsObject.slot[slotIndex].resolutionID = Output480; + slotsObject.slot[slotIndex].scanlines = 0; + slotsObject.slot[slotIndex].scanlinesStrength = 0x30; + slotsObject.slot[slotIndex].wantVdsLineFilter = 0; + slotsObject.slot[slotIndex].wantStepResponse = 1; + slotsObject.slot[slotIndex].wantPeaking = 1; + slotsObject.slot[slotIndex].enableAutoGain = 0; + slotsObject.slot[slotIndex].enableFrameTimeLock = 0; + slotsObject.slot[slotIndex].frameTimeLockMethod = 0; + slotsObject.slot[slotIndex].deintMode = 0; + slotsObject.slot[slotIndex].wantTap6 = 0; + slotsObject.slot[slotIndex].wantFullHeight = 0; + // slotsObject.slot[slotIndex].matchPresetSource = 0; + slotsObject.slot[slotIndex].PalForce60 = 0; + strncpy( + slotsObject.slot[slotIndex].name, + slot_name.c_str(), + sizeof(slotsObject.slot[slotIndex].name) + ); + // if that was current slot, also reset the runtime paramters + // TODO: see prefsLoadDefaults() + if(slotIndex == uopt.slotID) { + uopt.resolutionID = Output480; + GBS::GBS_PRESET_ID::write((uint8_t)uopt.resolutionID); + uopt.wantScanlines = false; + uopt.scanlineStrength = SCANLINE_STRENGTH_INIT; + uopt.wantVdsLineFilter = false; + uopt.wantStepResponse = true; + uopt.wantPeaking = true; + uopt.enableAutoGain = false; + uopt.enableFrameTimeLock = false; // permanently adjust frame timing to avoid glitch vertical bar. does not work on all displays! + uopt.frameTimeLockMethod = false; // compatibility with more displays + uopt.deintMode = false; + uopt.wantTap6 = true; + uopt.wantFullHeight = true; + // uopt.matchPresetSource = 1; + uopt.PalForce60 = false; + + // uopt.wantOutputComponent = 0; + // uopt.preferScalingRgbhv = 1; + // uopt.enableCalibrationADC = 1; + // uopt.disableExternalClockGenerator = 0; + } +} diff --git a/src/slot.h b/src/slot.h new file mode 100644 index 00000000..d4a0bb21 --- /dev/null +++ b/src/slot.h @@ -0,0 +1,47 @@ +#ifndef _SLOT_H_ +#define _SLOT_H_ + +#include +#include "options.h" +#include "tv5725.h" +#include "wserial.h" +#include "presets.h" + +// SLOTS +const char slotsFile[] PROGMEM = "/slots.bin"; // the file where to store slots metadata +const char emptySlotName[] PROGMEM = "Empty "; + +typedef struct +{ + char name[25]; + uint8_t slot; + OutputResolution resolutionID; + uint8_t scanlines; + uint8_t scanlinesStrength; + uint8_t wantVdsLineFilter; + uint8_t wantStepResponse; + uint8_t wantPeaking; + uint8_t enableAutoGain; + uint8_t enableFrameTimeLock; + uint8_t frameTimeLockMethod; + uint8_t deintMode; + uint8_t wantTap6; + uint8_t wantFullHeight; + // uint8_t matchPresetSource; + uint8_t PalForce60; +} SlotMeta; + +typedef struct +{ + SlotMeta slot[SLOTS_TOTAL]; +} SlotMetaArray; + +bool slotLoad(const uint8_t & slotIndex); +void slotUpdate(SlotMetaArray & slotsObject, const uint8_t & slotIndex, String * slotName = nullptr); +int8_t slotGetData(SlotMetaArray & slotsObject); +bool slotSetData(SlotMetaArray & slotsObject); +bool slotFlush(); +bool slotResetFlush(const uint8_t & slotIndex); +void slotResetDefaults(SlotMetaArray & slotsObject, const uint8_t & slotIndex); + +#endif // _SLOT_H_ \ No newline at end of file diff --git a/src/tv5725.h b/src/tv5725.h new file mode 100644 index 00000000..1c90d4ef --- /dev/null +++ b/src/tv5725.h @@ -0,0 +1,1458 @@ +#ifndef TV5725_H_ +#define TV5725_H_ + +#include "tw.h" + +#define GBS_ADDR 0x17 // 7 bit GBS I2C Address + +namespace detail +{ + struct TVAttrs + { + // Segment register at 0xf0, no bit offset, 8 bits, initial value assumed invalid + static const uint8_t SegByteOffset = 0xf0; + static const uint8_t SegBitOffset = 0; + static const uint8_t SegBitWidth = 8; + static const uint8_t SegInitial = 0xff; + }; +} // namespace detail + +template +class TV5725 : public tw::SegmentedSlave +{ +private: + // Stupid template boilerplate + typedef tw::SegmentedSlave Base; + using typename Base::SegValue; + template + using Register = typename Base::template Register; + template + using UReg = Register; + +public: + // + // STATUS Registers (all registers RO) + // + typedef UReg<0x00, 0x00, 0, 8> STATUS_00; // INPUT MODE STATUS 00 + typedef UReg<0x00, 0x00, 0, 1> STATUS_IF_VT_OK; // Vertical stable indicator (When =1, means input vertical timing is stable) + typedef UReg<0x00, 0x00, 1, 1> STATUS_IF_HT_OK; // Horizontal stable indicator (When =1, means input horizontal timing is table) + typedef UReg<0x00, 0x00, 2, 1> STATUS_IF_HVT_OK; // H & V stable indicator (When =1, means input H/V timing are both stable) + typedef UReg<0x00, 0x00, 3, 1> STATUS_IF_INP_NTSC_INT; // NTSC interlace indicator (When =1, means input is NTSC interlace (480i) source) + typedef UReg<0x00, 0x00, 4, 1> STATUS_IF_INP_NTSC_PRG; // NTSC progressive indicator (When =1, means input is NTSC progressive (480P) source) + typedef UReg<0x00, 0x00, 5, 1> STATUS_IF_INP_PAL_INT; // PAL interlace indicator (When =1, means input is PAL interlace (576i) source) + typedef UReg<0x00, 0x00, 6, 1> STATUS_IF_INP_PAL_PRG; // PAL progressive indicator (When =1, means input is PAL progressive (576P) source) + typedef UReg<0x00, 0x00, 7, 1> STATUS_IF_INP_SD; // SD mode indicator (When =1, means input is SD mode (480i, 480P, 576i, 576P)) + typedef UReg<0x00, 0x01, 0, 1> STATUS_IF_INP_VGA60; // VGA 60Hz mode (When =1, means input is VGA (640x480) 60Hz mode) + typedef UReg<0x00, 0x01, 1, 1> STATUS_IF_INP_VGA75; // VGA 75Hz mode (When =1, means input is VGA (640x480) 75Hz mode) + typedef UReg<0x00, 0x01, 2, 1> STATUS_IF_INP_VGA86; // VGA 85 Hz mode (When =1, means input is VGA (640x480) 85Hz mode) + typedef UReg<0x00, 0x01, 3, 1> STATUS_IF_INP_VGA; // VGA mode indicator (When =1, means input is VGA (640x480) source, include 60Hz/75Hz/85Hz) + typedef UReg<0x00, 0x01, 4, 1> STATUS_IF_INP_SVGA60; // SVGA 60Hz mode (When =1, means input is SVGA (800x600) 60Hz mode) + typedef UReg<0x00, 0x01, 5, 1> STATUS_IF_INP_SVGA75; // SVGA 75Hz mode (When =1, means input is SVGA (800x600) 75Hz mode) + typedef UReg<0x00, 0x01, 6, 1> STATUS_IF_INP_SVGA85; // SVGA 85Hz mode (When =1, means input is SVGA (800x600) 85Hz mode) + typedef UReg<0x00, 0x01, 7, 1> STATUS_IF_INP_SVGA; // SVGA mode indicator (When =1, means input is SVGA (800x600) source, include 60Hz/75Hz/85Hz) + typedef UReg<0x00, 0x02, 0, 1> STATUS_IF_INP_XGA60; // XGA 60Hz mode (When =1, means input is XGA (1024x768) 60Hz mode) + typedef UReg<0x00, 0x02, 1, 1> STATUS_IF_INP_XGA70; // XGA 70Hz mode (When =1, means input is XGA (1024x768) 70Hz mode) + typedef UReg<0x00, 0x02, 2, 1> STATUS_IF_INP_XGA75; // XGA 75Hz mode (When =1, means input is XGA (1024x768) 75Hz mode) + typedef UReg<0x00, 0x02, 3, 1> STATUS_IF_INP_XGA85; // XGA 85Hz mode (When =1, means input is XGA (1024x768) 85Hz mode) + typedef UReg<0x00, 0x02, 4, 1> STATUS_IF_INP_XGA; // XGA mode indicator (When =1, means input is XGA (1024x768) source, include 60/70/75/85Hz) + typedef UReg<0x00, 0x02, 5, 1> STATUS_IF_INP_SXGA60; // SXGA 60Hz mode (When =1, means input is SXGA (1280x1024) 60Hz mode) + typedef UReg<0x00, 0x02, 6, 1> STATUS_IF_INP_SXGA75; // SXGA 75Hz mode (When =1, means input is SXGA (1280x1024) 75Hz mode) + typedef UReg<0x00, 0x02, 7, 1> STATUS_IF_INP_SXGA85; // SXGA 85Hz mode (When =1, means input is SXGA (1280x1024) 85Hz mode) + typedef UReg<0x00, 0x03, 0, 8> STATUS_03; // INPUT MODE STATUS 03 + typedef UReg<0x00, 0x03, 0, 1> STATUS_IF_INP_SXGA; // SXGA mode indicator (When =1, means input is SXGA (1280x1024) mode, include 60/75/85Hz) + typedef UReg<0x00, 0x03, 1, 1> STATUS_IF_INP_PC; // Graphic mode indicator (When =1, means input is graphic mode input, include VGA/SVGA/XGA/SXGA) + typedef UReg<0x00, 0x03, 2, 1> STATUS_IF_INP_720P50; // HD720P 50Hz mode (When =1, means input is HD720P (1280x720) 50Hz mode) + typedef UReg<0x00, 0x03, 3, 1> STATUS_IF_INP_720P60; // HD720P 60Hz mode (When =1, means input is HD720P (1280x720) 60Hz mode) + typedef UReg<0x00, 0x03, 4, 1> STATUS_IF_INP_720; // HD720P mode indicator (When =1, means input is HD720P source, include 50Hz/60Hz) + typedef UReg<0x00, 0x03, 5, 1> STATUS_IF_INP_2200_1125I; // HD2200_1125 interlace (When =1, means input is 2200x1125i mode) + typedef UReg<0x00, 0x03, 6, 1> STATUS_IF_INP_2376_1250I; // HD2376_1250 interlace (When =1, means input is 2376x1250i mode) + typedef UReg<0x00, 0x03, 7, 1> STATUS_IF_INP_2640_1125I; // HD2640_1125 interlace (When =1, means input is 2640x1125i mode) + typedef UReg<0x00, 0x04, 0, 8> STATUS_04; // INPUT MODE STATUS 04 + typedef UReg<0x00, 0x04, 0, 1> STATUS_IF_INP_1080I; // HD1808i indicator (When =1, means input is HD1080i source, include 2200x1125i, 2376x1250i, 2640x1125i modes) + typedef UReg<0x00, 0x04, 1, 1> STATUS_IF_INP_2200_1125P; // HD2200_1125P (When =1, means input is HD 2200x1125P mode) + typedef UReg<0x00, 0x04, 2, 1> STATUS_IF_INP_2376_1250P; // HD2376_1250P (When =1, means input is HD 2376x1250P mode) + typedef UReg<0x00, 0x04, 3, 1> STATUS_IF_INP_2640_1125P; // HD2640_1125P (When =1, means input is HD 2640x1125P mode) + typedef UReg<0x00, 0x04, 4, 1> STATUS_IF_INP_1808P; // HD 1080P indicator (When =1, means input is 1080P source, include 2200x1250P, 2376x1125P) + typedef UReg<0x00, 0x04, 5, 1> STATUS_IF_INP_HD; // HD mode indicator (When =1, means input is HD source, include 720P, 1080i, 1080P) + typedef UReg<0x00, 0x04, 6, 1> STATUS_IF_INP_INT; // Interlace video indicator (When =1, means input is interlace video source, include 480i, 576i, 1080i) + typedef UReg<0x00, 0x04, 7, 1> STATUS_IF_INP_PRG; // Progressive video indicator (When =1, means input is progressive video source, include 480P , 1080P modes) + typedef UReg<0x00, 0x05, 0, 8> STATUS_05; // INPUT MODE STATUS 05 + typedef UReg<0x00, 0x05, 0, 1> STATUS_IF_INP_USER; // User define mode (When =1, means input is the mode which match user define resolution) + typedef UReg<0x00, 0x05, 1, 1> STATUS_IF_NO_SYNC; // No sync indicator (When =1, means input is not sync timing) + typedef UReg<0x00, 0x05, 2, 1> STATUS_IF_HT_BAD; // Horizontal unstable indicator (When =1, means input H sync is not stable) + typedef UReg<0x00, 0x05, 3, 1> STATUS_IF_VT_BAD; // Vertical unstable indicator (When =1, means input V sync is not stable) + typedef UReg<0x00, 0x05, 4, 1> STATUS_IF_INP_SW; // Mode switch indicator (When =1, means input source switch the mode) + // 06_6:2 - reserved + + typedef UReg<0x00, 0x06, 0, 9> HPERIOD_IF; // Input source H total measurement result (The value = input source H total pixels / 4) + typedef UReg<0x00, 0x07, 1, 11> VPERIOD_IF; // Input source V total measurement result (The value = input source V total pixels / 4) + // 08_4:4 - reserved + // 09_0:6 - reserved + typedef UReg<0x00, 0x09, 6, 1> STATUS_MISC_PLL648_LOCK; // LOCK indicator from PLL648 + typedef UReg<0x00, 0x09, 7, 1> STATUS_MISC_PLLAD_LOCK; // LOCK indicator from PLLAD + typedef UReg<0x00, 0x0A, 0, 1> STATUS_MISC_PIP_EN_V; // PIP enable signal in Vertical (When =1, means sub picture’s vertical period in PIP mode) + typedef UReg<0x00, 0x0A, 1, 1> STATUS_MISC_PIP_EN_H; // PIP enable signal in Horizontal (When =1, means sub picture’s horizontal period in PIP mode) + // 0A_2:2 - reserved + typedef UReg<0x00, 0x0A, 4, 1> STATUS_MISC_VBLK; // Display output Vertical Blank (When =1, means in display vertical blanking) + typedef UReg<0x00, 0x0A, 5, 1> STATUS_MISC_HBLK; // Display output Horizontal Blank (When =1, means in display horizontal blanking) + typedef UReg<0x00, 0x0A, 6, 1> STATUS_MISC_VSYNC; // Display output Vertical Sync (When =1, means in display vertical sync (the output sync is high active)) + typedef UReg<0x00, 0x0A, 7, 1> STATUS_MISC_HSYNC; // Display output Horizontal Sync (When =1, means in display horizontal sync (the output sync is high active)) + + typedef UReg<0x00, 0x0B, 0, 8> CHIP_ID_FOUNDRY; + typedef UReg<0x00, 0x0C, 0, 8> CHIP_ID_PRODUCT; + typedef UReg<0x00, 0x0D, 0, 8> CHIP_ID_REVISION; + + typedef UReg<0x00, 0x0E, 0, 1> STATUS_GPIO_GPIO; // GPIO bit0 (GPIO pin76) status + typedef UReg<0x00, 0x0E, 1, 1> STATUS_GPIO_HALF; // GPIO bit1 (HALF pin77) status + typedef UReg<0x00, 0x0E, 2, 1> STATUS_GPIO_SCLSA; // GPIO bit2 (SCLSA pin43) status + typedef UReg<0x00, 0x0E, 3, 1> STATUS_GPIO_MBA; // GPIO bit3 (MBA pin107) status + typedef UReg<0x00, 0x0E, 4, 1> STATUS_GPIO_MCS1; // GPIO bit4 (MCS1 pin109) status + typedef UReg<0x00, 0x0E, 5, 1> STATUS_GPIO_HBOUT; // GPIO bit5 (HBOUT pin6) status + typedef UReg<0x00, 0x0E, 6, 1> STATUS_GPIO_VBOUT; // GPIO bit6 (VBOUT pin7) status + typedef UReg<0x00, 0x0E, 7, 1> STATUS_GPIO_CLKOUT; // GPIO bit7 (CLKOUT pin4) status + + typedef UReg<0x00, 0x0F, 0, 8> STATUS_0F; // INTERRUPT STATUS 00 + typedef UReg<0x00, 0x0F, 0, 1> STATUS_INT_SOG_BAD; // Interrupt status bit0, SOG unstable (When =1, means input SOG source is unstable) + typedef UReg<0x00, 0x0F, 1, 1> STATUS_INT_SOG_SW; // Interrupt status bit1, SOG switch (When =1, means input SOG source switch the mode) + typedef UReg<0x00, 0x0F, 2, 1> STATUS_INT_SOG_OK; // Interrupt status bit2, SOG stable (When =1, means input SOG source is stable) + typedef UReg<0x00, 0x0F, 3, 1> STATUS_INT_INP_SW; // Interrupt status bit3, mode switch (When =1, means input source switch the mode) + typedef UReg<0x00, 0x0F, 4, 1> STATUS_INT_INP_NO_SYNC; // Interrupt status bit4, no sync (When =1, means input source is not H-sync input.) + typedef UReg<0x00, 0x0F, 5, 1> STATUS_INT_INP_HSYNC; // Interrupt status bit5, H-sync status (When =1, means input H-sync status is changed between stable and unstable) + typedef UReg<0x00, 0x0F, 6, 1> STATUS_INT_INP_VSYNC; // Interrupt status bi6, V-sync status (When =1, means input V-sync status is changed between stable and unstable) + typedef UReg<0x00, 0x0F, 7, 1> STATUS_INT_INP_CSYNC; // Interrupt status bit7, H-sync status (When =1, means input H-sync status is changed between stable and unstable) + + typedef UReg<0x00, 0x10, 0, 4> STATUS_VDS_FR_NUM; // Frame number + typedef UReg<0x00, 0x10, 4, 1> STATUS_VDS_OUT_VSYNC; // Output Vertical Sync + typedef UReg<0x00, 0x10, 5, 1> STATUS_VDS_OUT_HSYNC; // Output Horizontal Sync + // 10_6:2 - reserved + typedef UReg<0x00, 0x11, 0, 1> STATUS_VDS_FIELD; // Field Index (When =0, in display top field; When =1, in display bottom field) + typedef UReg<0x00, 0x11, 1, 1> STATUS_VDS_OUT_BLANK; // Composite Blanking (When =0, in display active period; When =1, in display blanking period) + // 11_2:2 - reserved + typedef UReg<0x00, 0x11, 4, 11> STATUS_VDS_VERT_COUNT; // Vertical counter bit [3:0] (Vertical counter value, indicate the line number in display) + // 12_7:1 - reserved + typedef UReg<0x00, 0x13, 0, 1> STATUS_MEM_FF_WFF_FIFO_FULL; // WFF FIFO full indicator (When =1, means WFF FIFO is full) + typedef UReg<0x00, 0x13, 1, 1> STATUS_MEM_FF_WFF_FIFO_EMPTY; // WFF FIFO empty indicator (When =1, means WFF FIFO is empty) + typedef UReg<0x00, 0x13, 2, 1> STATUS_MEM_FF_RFF_FIFO_FULL; // RFF FIFO full indicator (When =1, means RFF FIFO is full) + typedef UReg<0x00, 0x13, 3, 1> STATUS_MEM_FF_RFF_FIFO_EMPTY; // RFF FIFO empty indicator (When =1, means RFF FIFO is empty) + typedef UReg<0x00, 0x13, 4, 1> STATUS_MEM_FF_CAP_FIFO_FULL; // Capture FIFO full indicator (When =1, means capture FIFO is full) + typedef UReg<0x00, 0x13, 5, 1> STATUS_MEM_FF_CAP_FIFO_EMPTY; // Capture FIFO empty indicator (When =1, means capture FIFO is empty) + typedef UReg<0x00, 0x13, 6, 1> STATUS_MEM_FF_PLY_FIFO_FULL; // Playback FIFO full indicator (When =1, means playback FIFO is full) + typedef UReg<0x00, 0x13, 7, 1> STATUS_MEM_FF_PLY_FIFO_EMPTY; // Playback FIFO empty indicator (When =1, means playback FIFO is empty) + typedef UReg<0x00, 0x14, 0, 1> STATUS_MEM_FF_EXT_FIN; // Memory control initial indicator (When =1, means external memory chip initial is finished) + // 14_1:6 - reserved + // 15_0:6 - reserved + typedef UReg<0x00, 0x15, 7, 1> STATUS_DEINT_PULLDN; // 3:2 pull-down indicator (When =1, means de-interlace is in 3:2 pull-down mode) + + typedef UReg<0x00, 0x16, 0, 8> STATUS_16; // SYNC PROC STATUS 00 + typedef UReg<0x00, 0x16, 0, 1> STATUS_SYNC_PROC_HSPOL; // HS polarity (When =0, means input H-sync is low active When =1, means input H-sync is high active) + typedef UReg<0x00, 0x16, 1, 1> STATUS_SYNC_PROC_HSACT; // HS active + typedef UReg<0x00, 0x16, 2, 1> STATUS_SYNC_PROC_VSPOL; // VS polarity (When =0, means input V-sync is low active When =1, means input V-sync is high active) + typedef UReg<0x00, 0x16, 3, 1> STATUS_SYNC_PROC_VSACT; // VS active + // 16_4:3 - reserved + typedef UReg<0x00, 0x17, 0, 12> STATUS_SYNC_PROC_HTOTAL; // H total value (Input source H-total value) + // 18_4:4 - reserved + typedef UReg<0x00, 0x19, 0, 12> STATUS_SYNC_PROC_HLOW_LEN; // H low pulse length value (Input H-sync low active pulse length (for H-sync polarity detection)) + // 1A_4:4 - reserved + typedef UReg<0x00, 0x1B, 0, 11> STATUS_SYNC_PROC_VTOTAL; // V total value (Input source V-total lines value) + // 1C_3:5 - reserved + // 1D_0:8 - reserved + // 1E_0:8 - reserved + typedef UReg<0x00, 0x1F, 0, 8> TEST_BUS_1F; // reserved (RO) + typedef UReg<0x00, 0x20, 0, 16> TEST_FF_STATUS; // reserved (RO) + typedef UReg<0x00, 0x22, 0, 8> CRC_REGOUT_RFF; // reserved (RO) + typedef UReg<0x00, 0x23, 0, 8> CRC_REGOUT_PB; // reserved (RO) + typedef UReg<0x00, 0x24, 0, 80> CRC_STATUS; // reserved (RO) + typedef UReg<0x00, 0x2E, 0, 16> TEST_BUS; // reserved (RO) + typedef UReg<0x00, 0x2E, 0, 8> TEST_BUS_2E; // reserved (RO) + typedef UReg<0x00, 0x2F, 0, 8> TEST_BUS_2F; // reserved (RO) + + // + // Miscellaneous Registers (all registers R/W) + // + typedef UReg<0x00, 0x40, 0, 1> PLL_CKIS; // CKIS, PLL source clock selection (When = 0, PLL use OSC clock When = 1, PLL use input clock) + typedef UReg<0x00, 0x40, 1, 1> PLL_DIVBY2Z; // DIVBY2Z, PLL source clock divide bypass (When = 0, PLL source clock divide by two When = 1, PLL source clock bypass divide) + typedef UReg<0x00, 0x40, 2, 1> PLL_IS; // IS, ICLK source selection (When = 0, ICLK use PLL clock When = 1, ICLK use input clock) + typedef UReg<0x00, 0x40, 3, 1> PLL_ADS; // ADS, input clock selection (When = 0, input clock is from PCLKIN(pin40) When = 1, input clock is from ADC) + typedef UReg<0x00, 0x40, 4, 3> PLL_MS; // Memory clock control: + // When = 000, memory clock = 108MHz + // When = 001, memory clock = 81MHz + // When = 010, memory clock from FBCLK (pin 110) + // When = 011, memory clock = 162MHz + // When = 100, memory clock = 144MHz + // When = 101, memory clock = 185MHz + // When = 110, memory clock = 216MHz + // When = 111, memory clock = 129.6Mhz + typedef UReg<0x00, 0x41, 0, 8> PLL648_CONTROL_01; // See DEVELOPER_NOTES.md -> S0_41 + typedef UReg<0x00, 0x41, 0, 2> PLL_VS; // Display clock tuning register + typedef UReg<0x00, 0x41, 2, 2> PLL_VS2; // Display clock tuning register + typedef UReg<0x00, 0x41, 4, 2> PLL_VS4; // Display clock tuning register + typedef UReg<0x00, 0x41, 6, 1> PLL_2XV; // Display clock tuning register + typedef UReg<0x00, 0x41, 7, 1> PLL_4XV; // Display clock tuning register + // S0_42 - reserved + typedef UReg<0x00, 0x43, 0, 8> PLL648_CONTROL_03; // + typedef UReg<0x00, 0x43, 0, 2> PLL_R; // Skew control for testing + typedef UReg<0x00, 0x43, 2, 2> PLL_S; // Skew control for testing + typedef UReg<0x00, 0x43, 4, 1> PLL_LEN; // Lock Enable + typedef UReg<0x00, 0x43, 5, 1> PLL_VCORST; // VCO control voltage reset bit (When = 1, reset VCO control voltage) + typedef UReg<0x00, 0x44, 0, 1> DAC_RGBS_PWDNZ; // DAC enable (When = 0, DAC (R,G,B,S) in power down mode When = 1, DAC (R,G,B,S) is enable) + typedef UReg<0x00, 0x44, 1, 1> DAC_RGBS_RPD; // RPD, RDAC power down control (When = 0, RDAC work normally; When = 1, RDAC is in power down mode) + typedef UReg<0x00, 0x44, 2, 1> DAC_RGBS_R0ENZ; // R0ENZ, DAC min output bypass (When = 0, RDAC output Min voltage; When = 1, RDAC output follow input R data) + typedef UReg<0x00, 0x44, 3, 1> DAC_RGBS_R1EN; // R1EN, RDAC max output control (When = 0, RDAC output follow input R data When = 1, RDAC output Max voltage) + typedef UReg<0x00, 0x44, 4, 1> DAC_RGBS_GPD; // GPD, GDAC power down control (When = 0, GDAC work normally; When = 1, GDAC is in power down mode) + typedef UReg<0x00, 0x44, 5, 1> DAC_RGBS_G0ENZ; // G0ENZ, GDAC min output bypass (When = 0, GDAC output Min voltage; When = 1, GDAC output follow input G data) + typedef UReg<0x00, 0x44, 6, 1> DAC_RGBS_G1EN; // R1EN, RDAC max output control (When = 0, RDAC output follow input R data When = 1, RDAC output Max voltage) + typedef UReg<0x00, 0x44, 7, 1> DAC_RGBS_BPD; // BPD, BDAC power down control (When = 0, BDAC work normally; When = 1, BDAC is in power down mode) + typedef UReg<0x00, 0x45, 0, 1> DAC_RGBS_B0ENZ; // B0ENZ, BDAC min output bypass (When = 0, BDAC output Min voltage; When = 1, BDAC output follow input B data) + typedef UReg<0x00, 0x45, 1, 1> DAC_RGBS_B1EN; // B1EN, BDAC max output control (When = 0, BDAC output follow input B data; When = 1, BDAC output Max voltage) + typedef UReg<0x00, 0x45, 2, 1> DAC_RGBS_SPD; // SPD, SDAC power down control (When = 0, GDAC work normally; When = 1, GDAC is in power down mode) + typedef UReg<0x00, 0x45, 3, 1> DAC_RGBS_S0ENZ; // S0ENZ, SDAC min output bypass (When = 0, SDAC output Min voltage; When = 1, SDAC output follow input S data) + typedef UReg<0x00, 0x45, 4, 1> DAC_RGBS_S1EN; // S1EN, SDAC max output control (When = 0, SDAC output follow input S data; When = 1, SDAC output Max voltage) + // S0_45_5:1 - reserverd + typedef UReg<0x00, 0x45, 6, 2> CKT_FF_CNTRL; // CKT used to control FIFO + typedef UReg<0x00, 0x46, 0, 8> RESET_CONTROL_0x46; // CONTROL 00 + typedef UReg<0x00, 0x46, 0, 1> SFTRST_IF_RSTZ; // Input formatter reset control (When = 0, input formatter is in reset status; When = 1, input formatter work normally) + typedef UReg<0x00, 0x46, 1, 1> SFTRST_DEINT_RSTZ; // Deint_madpt3 reset control (When = 0, deint_madpt3 is in reset status; When = 1, deint_madpt3 work normally) + typedef UReg<0x00, 0x46, 2, 1> SFTRST_MEM_FF_RSTZ; // Mem_ff (wff/rff/playback/capture) reset control (When = 0, mem_ff is in reset status; When = 1, mem_ff work normally) + typedef UReg<0x00, 0x46, 3, 1> SFTRST_MEM_RSTZ; // Mem controller reset control (When = 0, mem controller is in reset status; When = 1, mem controller work normally) + typedef UReg<0x00, 0x46, 4, 1> SFTRST_FIFO_RSTZ; // FIFO reset control (When = 0, all FIFO (FF64/FF512) is in reset status; When = 1, all FIFO work normally) + typedef UReg<0x00, 0x46, 5, 1> SFTRST_OSD_RSTZ; // OSD reset control (When = 0, OSD generator is in reset status; When = 1, OSD generator work normally) + typedef UReg<0x00, 0x46, 6, 1> SFTRST_VDS_RSTZ; // Vds_proc reset control (When = 0, vds_proc is in reset status; When = 1, vds_proc work normally) + // 46_7:1 - reserved + typedef UReg<0x00, 0x47, 0, 8> RESET_CONTROL_0x47; // CONTROL 01 + typedef UReg<0x00, 0x47, 0, 1> SFTRST_DEC_RSTZ; // Decimation reset control (When = 0, decimation is in reset status; When = 1, decimation work normally) + typedef UReg<0x00, 0x47, 1, 1> SFTRST_MODE_RSTZ; // Mode detection reset control (When = 0, mode detection is in reset status When = 1, mode detection work normally) + typedef UReg<0x00, 0x47, 2, 1> SFTRST_SYNC_RSTZ; // Sync processor reset control (When = 0, sync processor is in reset status When = 1, sync processor work normally) + typedef UReg<0x00, 0x47, 3, 1> SFTRST_HDBYPS_RSTZ; // HD bypass channel reset control (When = 0, HD bypass is in reset status; When = 1, HD bypasswork normally) + typedef UReg<0x00, 0x47, 4, 1> SFTRST_INT_RSTZ; // Interrupt generator reset control (When = 0, interrupt generator is in reset status; When = 1, interrupt generator work normally) + // 47_5:3 - reserved + typedef UReg<0x00, 0x48, 0, 8> PAD_CONTROL_00_0x48; // CONTROL 00 + typedef UReg<0x00, 0x48, 0, 1> PAD_BOUT_EN; // VB_[7:0] output control aka debug pin (When = 0, disable VB_[7:0] (test_out_[7:0]) output; When = 1, enable VB_[7:0] (test_out_[7:0]) output) + typedef UReg<0x00, 0x48, 1, 1> PAD_BIN_ENZ; // VB_[7:0] input control (When = 0, enable VB_[7:0] input; When = 1, disable VB_[7:0] input) + typedef UReg<0x00, 0x48, 2, 1> PAD_ROUT_EN; // VR_[7:0] output control (When = 0, disable VR_[7:0] (test_out_[15:8]) output; When = 1, enable VR_[7:0] (test_out_[15:8]) output) + typedef UReg<0x00, 0x48, 3, 1> PAD_RIN_ENZ; // VR_[7:0] input control (When = 0, enable VR_[7:0] input; When = 1, disable VR_[7:0] input) + typedef UReg<0x00, 0x48, 4, 1> PAD_GOUT_EN; // VG_[7:0] output control (When = 0, disable VG_[7:0] (test_out_[23:16]) output; When = 1, enable VG_[7:0] (test_out_[23:16]) output) + typedef UReg<0x00, 0x48, 5, 1> PAD_GIN_ENZ; // VG_[7:0] input control (When = 0, enable VG_[7:0] input; When = 1, disable VG_[7:0] input) + typedef UReg<0x00, 0x48, 6, 1> PAD_SYNC1_IN_ENZ; // H/V sync1 input control (When = 0, enable H/V sync1 input filter; When = 1, disable H/V sync1 input filter) + typedef UReg<0x00, 0x48, 7, 1> PAD_SYNC2_IN_ENZ; // H/V sync2 input control (When = 0, enable H/V sync2 input filter; When = 1, disable H/V sync2 input filter) + typedef UReg<0x00, 0x49, 0, 8> PAD_CONTROL_01_0x49; // CONTROL 01 + typedef UReg<0x00, 0x49, 0, 1> PAD_CKIN_ENZ; // PCLKIN control (When = 0, PCLKIN input enable When = 1, PCLKIN input disable) + typedef UReg<0x00, 0x49, 1, 1> PAD_CKOUT_ENZ; // CLKOUT control (When = 0, CLKOUT output enable When = 1, CLKOUT output disable) + typedef UReg<0x00, 0x49, 2, 1> PAD_SYNC_OUT_ENZ; // HSOUT/VSOUT control (When = 0, HSOUT/VSOUT output enable When = 1, HSOUT/VSOUT output disable) + typedef UReg<0x00, 0x49, 3, 1> PAD_BLK_OUT_ENZ; // HBOUT/VBOUT control (When = 0, HBOUT/VBOUT output enable When = 1, HBOUT/VBOUT output disable) + typedef UReg<0x00, 0x49, 4, 1> PAD_TRI_ENZ; // Tri-state gate control (When = 0, enable output pad’s tri-state gate When = 1, disable output pad’s tri-state gate) + typedef UReg<0x00, 0x49, 5, 1> PAD_PLDN_ENZ; // Pull-down control (When = 0, enable pad’s pull-down transistor; When = 1, disable pad’s pull-down transistor) + typedef UReg<0x00, 0x49, 6, 1> PAD_PLUP_ENZ; // Pull-up control (When = 0, enable pad’s pull-up transistor; When = 1, disable pad’s pull-up transistor) + // 49_7:1 - reserved + typedef UReg<0x00, 0x4A, 0, 3> PAD_OSC_CNTRL; // OSC pad C2/C1/C0 control + typedef UReg<0x00, 0x4A, 3, 1> PAD_XTOUT_TTL; // OSC pad output control (When = 0, enable OSC pad output by schmitt When = 1, enable OSC pad output by TTL) + typedef UReg<0x00, 0x4B, 0, 1> DAC_RGBS_BYPS_IREG; // DAC input DFF control (When = 0, DAC input DFF is falling edge D-flipflop When = 1, bypass falling edge D-flipflop) + typedef UReg<0x00, 0x4B, 1, 1> DAC_RGBS_BYPS2DAC; // HD bypass to DAC control (When = 0, disable HD bypass channel to DAC; When = 1, enable HD bypass channel to DAC directly) + typedef UReg<0x00, 0x4B, 2, 1> DAC_RGBS_ADC2DAC; // ADC to DAC control (When = 0, disable ADC (with decimation) to DAC; When = 1, enable ADC (with decimation) to DAC directly) + typedef UReg<0x00, 0x4D, 0, 5> TEST_BUS_SEL; // Test bus selection + typedef UReg<0x00, 0x4D, 5, 1> TEST_BUS_EN; // Test bus enable (When = 0, disable test bus output; When = 1, test bus output to VR_[7:0], VB_[7:0] (test_out_[15:0])) + // 4D_6:2 - reserved + typedef UReg<0x00, 0x4E, 0, 1> DIGOUT_BYPS2PAD; // HD bypass channel to digital output control (When = 0, disable HD bypass to digital output; When = 1, enable HD bypass to digital output (VG_[7:0], VR_[7:0], VB_[7:0])) + typedef UReg<0x00, 0x4E, 1, 1> DIGOUT_ADC2PAD; // ADC to digital output control (When = 0, disable ADC to digital output; When = 1, enable ADC (with decimation) to digital output (VG, VR, VB)) + // 4E_2:6 - reserved + typedef UReg<0x00, 0x4F, 0, 1> DAC_RGBS_V4CLK_INVT; // V4CLK invert control (When = 0, V4CLK to DAC directly; When = 1, V4CLK will invert before go to DAC) + typedef UReg<0x00, 0x4F, 1, 1> OUT_CLK_PHASE_CNTRL; // CLKOUT invert control (When = 0, CLKOUT output no invert; When = 1, CLKOUT will invert before output) + typedef UReg<0x00, 0x4F, 2, 2> OUT_CLK_EN; // CLKOUT selection control: + // When = 00, CLKOUT = V4CLK + // When = 01, CLKOUT = V2CLK + // When = 10, CLKOUT = VCLK + // When = 11, CLKOUT = ADC output clock + typedef UReg<0x00, 0x4F, 4, 1> CLKOUT_EN; // CLKOUT enable control (When = 0, disable CLKOUT to PAD When = 1, enable CLKOUT to PAD) + typedef UReg<0x00, 0x4F, 5, 1> OUT_SYNC_CNTRL; // H/V sync output enable (When = 0, disable H/V sync output to PAD When = 1, enable H/V sync output to PAD) + typedef UReg<0x00, 0x4F, 6, 2> OUT_SYNC_SEL; // H/V sync output selection control + // When = 00, H/V sync output are from vds_proc + // When = 01, H/V sync output are from HD bypass + // When = 10, H/V sync output are from sync processor + // When = 11, reserved + typedef UReg<0x00, 0x50, 0, 1> OUT_BLANK_SEL_0; // HBOUT/VBUT selection control (When = 0, VBOUT output Vertical Blank; When = 1, VBOUT output composite Display Enable) + typedef UReg<0x00, 0x50, 1, 1> OUT_BLANK_SEL_1; // HBOUT/VBOUT selection control (When = 0, HBOUT/VBOUT is from vds_proc When = 1, HBOUT/VBOUT is from HD bypass) + // 50_2:2 - reserved + typedef UReg<0x00, 0x50, 4, 1> IN_BLANK_SEL; // Input blank selection (When = 0, disable input composite Display Enable When = 1, enable input composite Display Enable) + typedef UReg<0x00, 0x50, 5, 1> IN_BLANK_IREG_BYPS; // Input blank IREG bypas (When = 0, input composite Display Enable latched by falling edge DFF When = 1, bypass falling edge DFF) + // 50_6:2 - reserved + // 51_0:8 - not described + + typedef UReg<0x00, 0x52, 0, 8> GPIO_CONTROL_00; // CONTROL 00 + typedef UReg<0x00, 0x52, 0, 1> GPIO_SEL_0; // GPIO bit0 selection (When = 0, GPIO (pin76) is used as INTZ output When = 1, GPIO (pin76) is used as GPIO bit0) + typedef UReg<0x00, 0x52, 1, 1> GPIO_SEL_1; // GPIO bit1 selection (When = 0, HALF (pin77) is used as half tone input When = 1, HALF (pin77) is used as GPIO bit1) + typedef UReg<0x00, 0x52, 2, 1> GPIO_SEL_2; // GPIO bit2 selection (When = 0, SCLSA (pin43) is used as two wire serial bus slave address selection When = 1, SCLSA (pin43) is used as GPIO bit2) + typedef UReg<0x00, 0x52, 3, 1> GPIO_SEL_3; // GPIO bit3 selection (When = 0, MBA (pin107) is used as external memory BA When = 1, MBA (pin107) is used as GPIO bit3) + typedef UReg<0x00, 0x52, 4, 1> GPIO_SEL_4; // GPIO bit4 selection (When = 0, MCS1 (pin109) is used as external memory CS1 When = 1, MCS1 (pin109) is used as GPIO bit4) + typedef UReg<0x00, 0x52, 5, 1> GPIO_SEL_5; // GPIO bit5 selection (When = 0, HBOUT (pin6) is used as H-blank output When = 1, HBOUT (pin6) is used as GPIO bit5) + typedef UReg<0x00, 0x52, 6, 1> GPIO_SEL_6; // GPIO bit6 selection (When = 0, VBOUT (pin7) is used as V-blank output When = 1, VBOUT (pin7) is used as GPIO bit6) + typedef UReg<0x00, 0x52, 7, 1> GPIO_SEL_7; // GPIO bit7 selection (When = 0, CLKOUT (pin4) is used as clock output When = 1, CLKOUT (pin4) is used as GPIO bit7) + typedef UReg<0x00, 0x53, 0, 8> GPIO_CONTROL_01; // CONTROL 01 + typedef UReg<0x00, 0x53, 0, 1> GPIO_EN_0; // GPIO bit0 output enable (When = 0, GPIO bit0 output disable When = 1, GPIO bit0 output enable) + typedef UReg<0x00, 0x53, 1, 1> GPIO_EN_1; // GPIO bit1 output enable (When = 0, GPIO bit1 output disable When = 1, GPIO bit1 output enable) + typedef UReg<0x00, 0x53, 2, 1> GPIO_EN_2; // GPIO bit2 output enable (When = 0, GPIO bit2 output disable When = 1, GPIO bit2 output enable) + typedef UReg<0x00, 0x53, 3, 1> GPIO_EN_3; // GPIO bit3 output enable (When = 0, GPIO bit3 output disable When = 1, GPIO bit3 output enable) + typedef UReg<0x00, 0x53, 4, 1> GPIO_EN_4; // GPIO bit4 output enable (When = 0, GPIO bit4 output disable When = 1, GPIO bit4 output enable) + typedef UReg<0x00, 0x53, 5, 1> GPIO_EN_5; // GPIO bit5 output enable (When = 0, GPIO bit5 output disable When = 1, GPIO bit5 output enable) + typedef UReg<0x00, 0x53, 6, 1> GPIO_EN_6; // GPIO bit6 output enable (When = 0, GPIO bit6 output disable When = 1, GPIO bit6 output enable) + typedef UReg<0x00, 0x53, 7, 1> GPIO_EN_7; // GPIO bit7 output enable (When = 0, GPIO bit7 output disable When = 1, GPIO bit7 output enable) + typedef UReg<0x00, 0x54, 0, 8> GPIO_CONTROL_02; // CONTROL 02 + typedef UReg<0x00, 0x54, 0, 1> GPIO_VAL_0; // GPIO bit0 output value + typedef UReg<0x00, 0x54, 1, 1> GPIO_VAL_1; // GPIO bit1 output value + typedef UReg<0x00, 0x54, 2, 1> GPIO_VAL_2; // GPIO bit2 output value + typedef UReg<0x00, 0x54, 3, 1> GPIO_VAL_3; // GPIO bit3 output value + typedef UReg<0x00, 0x54, 4, 1> GPIO_VAL_4; // GPIO bit4 output value + typedef UReg<0x00, 0x54, 5, 1> GPIO_VAL_5; // GPIO bit5 output value + typedef UReg<0x00, 0x54, 6, 1> GPIO_VAL_6; // GPIO bit6 output value + typedef UReg<0x00, 0x54, 7, 1> GPIO_VAL_7; // GPIO bit7 output value + // 55 - not described + typedef UReg<0x00, 0x57, 7, 1> INVT_RING_EN; // Enable invert ring (When = 0, disable invert ring; When = 1, enable invert ring for processing test) + typedef UReg<0x00, 0x58, 0, 8> INTERRUPT_CONTROL_00; // CONTROL 00 + typedef UReg<0x00, 0x58, 0, 1> INT_CONTROL_RST_SOGBAD; // Interrupt bit0 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 1, 1> INT_CONTROL_RST_SOGSWITCH; // Interrupt bit1 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 2, 1> INT_RST_2; // Interrupt bit2 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 3, 1> INT_RST_3; // Interrupt bit3 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 4, 1> INT_CONTROL_RST_NOHSYNC; // Interrupt bit4 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 5, 1> INT_RST_5; // Interrupt bit5 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 6, 1> INT_RST_6; // Interrupt bit6 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x58, 7, 1> INT_RST_7; // Interrupt bit7 reset control (When = 1, interrupt bit status will be reset to zero) + typedef UReg<0x00, 0x59, 0, 8> INTERRUPT_CONTROL_01; // CONTROL 01 + typedef UReg<0x00, 0x59, 0, 1> INT_ENABLE0; // Interrupt bit0 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 1, 1> INT_ENABLE1; // Interrupt bit1 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 2, 1> INT_ENABLE2; // Interrupt bit2 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 3, 1> INT_ENABLE3; // Interrupt bit3 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 4, 1> INT_ENABLE4; // Interrupt bit4 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 5, 1> INT_ENABLE5; // Interrupt bit5 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 6, 1> INT_ENABLE6; // Interrupt bit6 enable (When = 1, enable interrupt bit generator) + typedef UReg<0x00, 0x59, 7, 1> INT_ENABLE7; // Interrupt bit7 enable (When = 1, enable interrupt bit generator) + + // + // Input Formatter Registers (all registers R/W) + // + typedef UReg<0x01, 0x00, 0, 1> IF_IN_DREG_BYPS; // Input pipe by pass (Use the falling or rising edge of clock to get the input data. 0: Clock input data on the falling edge of ICLK.; 1: Clock input date on the rising edge of ICLK.) + typedef UReg<0x01, 0x00, 1, 1> IF_MATRIX_BYPS; // Rgb2yuv matrix bypass (If source is yuv24bit, bypass the rgb2yuv matrix. 0:source is 24bit RGB. Do rgb2yuv; 1: data bypass) + typedef UReg<0x01, 0x00, 2, 1> IF_UV_REVERT; // 8bit to 16bit convert Y/UV flip control (If input is 8bit data, when it convert to 16bit, this bit control Y and UV order: 0: Keep the designed order; 1: Flip the Y and UV order) + typedef UReg<0x01, 0x00, 3, 1> IF_SEL_656; // Select CCIR656 data (If input data is 8bit CCIR656 mode, choose the 656 data path. 0: input is CCIR 601 mode. Choose the CCIR601mode timing. 1: input is CCIR 656 mode. Choose the CCIR656 mode timing) + typedef UReg<0x01, 0x00, 4, 1> IF_SEL16BIT; // Select 16bit data (If source data is 16bit. Choose the 16bits data path. Use in conjunction with register sel_24bit to choose the input data format.) + typedef UReg<0x01, 0x00, 5, 1> IF_VS_SEL; // Vertical sync select (Choose the periodical or virtual vertical timing. 0: choose the VCR mode timing generation. 1: choose the normal mode timing generation) (see: DEVELOPER_NOTES.md -> S1_00) + typedef UReg<0x01, 0x00, 6, 1> IF_PRGRSV_CNTRL; // Select progressive data (Progressive mode. Choose the progressive data. 0: source is interlaced; 1: source is progressive) + typedef UReg<0x01, 0x00, 7, 1> IF_HS_FLIP; // Horizontal sync flip control (Control the horizontal sync output from CCIR process 0: keep the original horizontal sync; 1: flip horizontal sync.) + typedef UReg<0x01, 0x01, 0, 1> IF_VS_FLIP; // Vertical sync flip control (Control the vertical sync output from CCIR process 0: keep original vertical sync; 1: flip vertical sync.) + typedef UReg<0x01, 0x01, 1, 1> IF_UV_FLIP; // YUV 422to444 UV flip control (Control the U and V order in yuv422to444 conversion. 0: keep original U and V order; 1: exchange the U and V order) + typedef UReg<0x01, 0x01, 2, 1> IF_U_DELAY; // U data select in YUV 422to444 conversion (Select original U data or 1-clock delayed U data, so that it can align with V data. 0: select original U data after dmux; 1: select 1-clock delayed U data after dmux) + typedef UReg<0x01, 0x01, 3, 1> IF_V_DELAY; // V data select in YUV 422to444 conversion (Select original V data or 1-clock delayed V data, so that it can align with U data. 0: select original V data after dmux; 1: select 1-clock delayed V data after dmux) + typedef UReg<0x01, 0x01, 4, 1> IF_TAP6_BYPS; // Tap6 interpolator bypass control in YUV 422to444 conversion (Select the data if pass the tap6 interpolator or not. 0: the data will pass the tap6 interpolator; 1: the data will not pass the tap6 interpolator) + typedef UReg<0x01, 0x01, 5, 2> IF_Y_DELAY; // Y data pipes control in YUV422to444 conversion (Control the Y data pipe delay, so that it can align with U and V. see: DEVELOPER_NOTES.md -> S01_01) + typedef UReg<0x01, 0x01, 7, 1> IF_SEL24BIT; // Select 24bit data (If input source is 24bit data, choose the 24bit data path.) + typedef UReg<0x01, 0x02, 0, 8> INPUT_FORMATTER_02; // INPUT_FORMATTER 02 + typedef UReg<0x01, 0x02, 0, 1> IF_SEL_WEN; // Select the write enable for line double (If the input is HD source, this bit will be set to 1. 0: if the source is SD data; 1: if the source is HD data) + typedef UReg<0x01, 0x02, 1, 1> IF_HS_SEL_LPF; // Low pass filter or interpolator selection (The low pass filter and interpolator data path is combined together. 0: select interpolator data path; 1: select low pass filter data path) + typedef UReg<0x01, 0x02, 2, 1> IF_HS_INT_LPF_BYPS; // Combined INT and LPF data path bypass control (If the data can’t do horizontal scaling-down, bypass the INT/LPF data path. 0: select the INT/LPF data path; 1: bypass the INT/LPF data path) + typedef UReg<0x01, 0x02, 3, 1> IF_HS_PSHIFT_BYPS; // Phase adjustment bypass control (If the data can’t do phase adjustment, this bit should be set to 1. 0: select phase adjustment data path; 1: bypass phase adjustment) + typedef UReg<0x01, 0x02, 4, 1> IF_HS_TAP11_BYPS; // Tap11 LPF bypass control in YUV444to422 conversion (Select the data if pass the tap11 LPF or not. 0: the data will pass the tap11 low pass filter; 1: the data will not pass the tap11 low pass filter) + typedef UReg<0x01, 0x02, 5, 2> IF_HS_Y_PDELAY; // Y data pipes control in YUV444to422 conversion - Control the Y data pipe delay, so that it can align with UV. (see: DEVELOPER_NOTE.md -> S1_02) + typedef UReg<0x01, 0x02, 7, 1> IF_HS_UV_SIGN2UNSIGN; // UV data select (If UV is signed, select the unsigned UV data 0: select the original UV; 1: select the UV after sign processing) + typedef UReg<0x01, 0x03, 0, 8> IF_HS_RATE_SEG0; // Horizontal non-linear scaling-down 1st segment DDA increment [11:4] (total 12 bits) + // The entire segment share the lowest 4bit, that is to say, the whole scale ration is + // hscale = {hscale0, hscale_low}. Assume the scaling ratio is n/m, then the value should be 4095x(m-n)/n + typedef UReg<0x01, 0x04, 0, 8> IF_HS_RATE_SEG1; // Horizontal non-linear scaling-down 2nd segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x05, 0, 8> IF_HS_RATE_SEG2; // Horizontal non-linear scaling-down 3rd segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x06, 0, 8> IF_HS_RATE_SEG3; // Horizontal non-linear scaling-down 4th segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x07, 0, 8> IF_HS_RATE_SEG4; // Horizontal non-linear scaling-down 5th segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x08, 0, 8> IF_HS_RATE_SEG5; // Horizontal non-linear scaling-down 6th segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x09, 0, 8> IF_HS_RATE_SEG6; // Horizontal non-linear scaling-down 7th segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x0A, 0, 8> IF_HS_RATE_SEG7; // Horizontal non-linear scaling-down 8th segment DDA increment [11:4] (total 12 bits) + typedef UReg<0x01, 0x0B, 0, 4> IF_HS_RATE_LOW; // Horizontal non-linear scaling-down DDA increment shared lowest 4 bits [3:0] (total 12 bits) + typedef UReg<0x01, 0x0B, 4, 2> IF_HS_DEC_FACTOR; // Horizontal non-linear scaling-down factor select + // If the scaling ratio is less than 1⁄2, use it and DDA to generate the we and phase + // 00: scaling-ratio is more than 1⁄2 + // 01: scaling-ratio is less than 1⁄2 + // 10: scaling-ratio is less than 1⁄4 + typedef UReg<0x01, 0x0B, 6, 1> IF_SEL_HSCALE; // Select the data path after horizontal scaling-down + // If the data have do scaling-down, this bit should be open. + // 0: select the data and write enable from CCIR to line double. + // 1: select the scaling-down data and write enable to line double) + typedef UReg<0x01, 0x0B, 7, 1> IF_LD_SEL_PROV; // Line double read reset select + // If source is progressive data, choose the related progressive timing as read reset timing. + // 0: select read reset timing of interlace data. + // 1: select read reset timing of progressive data + typedef UReg<0x01, 0x0c, 0, 1> IF_LD_RAM_BYPS; // Line double bypass control + // If the interlace data can’t do line double, if the progressive data can’t do scaling- down, line double FIFO should be bypass. + // 0: select interlace line double data from FIFO. + // 1: bypass line double FIFO + typedef UReg<0x01, 0x0c, 1, 4> IF_LD_ST; // Line double write reset generation start position (If the internal counter equals the defined value the write reset will be high pulse.) + typedef UReg<0x01, 0x0c, 5, 11> IF_INI_ST; // Initial position (Start position indicator of vertical blanking. For the internal line_counter, the detail pixel’s shift that the line_counter count compare to the horizontal sync) + typedef UReg<0x01, 0x0e, 0, 11> IF_HSYNC_RST; // Total pixel number per line (Use to generate progressive timing if input is interlace data [10:0]) + + typedef UReg<0x01, 0x10, 0, 11> IF_HB_ST; // Horizontal blanking (set 0) start position [10:0]. + typedef UReg<0x01, 0x12, 0, 11> IF_HB_SP; // Horizontal blanking (set 0) stop position [10:0] + typedef UReg<0x01, 0x14, 0, 11> IF_HB_ST1; // Horizontal blanking (set 1) start position [10:0] + typedef UReg<0x01, 0x16, 0, 11> IF_HB_SP1; // Horizontal blanking (set 1) stop position [10:0] + typedef UReg<0x01, 0x18, 0, 11> IF_HB_ST2; // Horizontal blanking (set 2) start position [10:0]. + typedef UReg<0x01, 0x1a, 0, 11> IF_HB_SP2; // Horizontal blanking (set 2) stop position [10:0] + typedef UReg<0x01, 0x1c, 0, 11> IF_VB_ST; // Vertical blanking start position [10:0]. + typedef UReg<0x01, 0x1e, 0, 11> IF_VB_SP; // Vertical blanking stop position [10:0]. + typedef UReg<0x01, 0x20, 0, 12> IF_LINE_ST; // Progressive line start position. + typedef UReg<0x01, 0x22, 0, 12> IF_LINE_SP; // Progressive line stop position. + typedef UReg<0x01, 0x24, 0, 12> IF_HBIN_ST; // Horizontal blank for scale down line reset start position [11:0] + typedef UReg<0x01, 0x26, 0, 12> IF_HBIN_SP; // Horizontal blank for scale down line reset stop position [11:0] + typedef UReg<0x01, 0x28, 1, 1> IF_LD_WRST_SEL; // Select hbin/line write reset (0 - select line generated write reset, 1 - select hbin generated write reset) + typedef UReg<0x01, 0x28, 2, 1> IF_SEL_ADC_SYNC; // Select ADC sync to data path + typedef UReg<0x01, 0x28, 3, 1> IF_TEST_EN; // IF test bus control enable - Enable test signal. + typedef UReg<0x01, 0x28, 4, 4> IF_TEST_SEL; // Test signals select bits - Select which signal to the test bus. + typedef UReg<0x01, 0x29, 0, 1> IF_AUTO_OFST_EN; // Auto offset adjustment enable (1 - enable, 0 - disable) + typedef UReg<0x01, 0x29, 1, 1> IF_AUTO_OFST_PRD; // Auto offset adjustment period control (1 - by frame, 0 - by line) + typedef UReg<0x01, 0x2A, 0, 4> IF_AUTO_OFST_U_RANGE; // U channel offset detection range + typedef UReg<0x01, 0x2A, 4, 4> IF_AUTO_OFST_V_RANGE; // V channel offset detection range + // 01_2B:2F - not described registers + typedef UReg<0x01, 0x2B, 0, 7> GBS_PRESET_ID; // used to store output resolutionID + + // ! @sk: supressed for now + // typedef UReg<0x01, 0x2B, 7, 1> GBS_PRESET_CUSTOM; + // typedef UReg<0x01, 0x2C, 0, 1> GBS_OPTION_SCANLINES_ENABLED; + // typedef UReg<0x01, 0x2C, 1, 1> GBS_OPTION_SCALING_RGBHV; + // typedef UReg<0x01, 0x2C, 2, 1> GBS_OPTION_PALFORCED60_ENABLED; + // typedef UReg<0x01, 0x2C, 3, 1> GBS_RUNTIME_UNUSED_BIT; + // typedef UReg<0x01, 0x2C, 4, 1> GBS_RUNTIME_FTL_ADJUSTED; + // typedef UReg<0x01, 0x2D, 0, 8> GBS_PRESET_DISPLAY_CLOCK; + + // + // HDBypass (all registers R/W) + // + typedef UReg<0x01, 0x30, 1, 1> HD_MATRIX_BYPS; // Available only when input source is YUV source + typedef UReg<0x01, 0x30, 2, 1> HD_DYN_BYPS; // If the input is YUV data, it must do dynamic range. + typedef UReg<0x01, 0x30, 3, 1> HD_SEL_BLK_IN; // Choose the input blank or generated blank use sync. + typedef UReg<0x01, 0x31, 0, 8> HD_Y_GAIN; // The gain value of Y dynamic range. + typedef UReg<0x01, 0x32, 0, 8> HD_Y_OFFSET; // The offset value of Y dynamic range. + typedef UReg<0x01, 0x33, 0, 8> HD_U_GAIN; // The gain value of U dynamic range. + typedef UReg<0x01, 0x34, 0, 8> HD_U_OFFSET; // The offset value of U dynamic range. + typedef UReg<0x01, 0x35, 0, 8> HD_V_GAIN; // The gain value of V dynamic range. + typedef UReg<0x01, 0x36, 0, 8> HD_V_OFFSET; // The offset value of V dynamic range. + typedef UReg<0x01, 0x37, 0, 11> HD_HSYNC_RST; // Horizontal counter reset value [10:0]. + typedef UReg<0x01, 0x39, 0, 11> HD_INI_ST; // Vertical counter write enable, adjust the distance between hblank and vblank [10:0]. + typedef UReg<0x01, 0x3B, 0, 12> HD_HB_ST; // Generate horizontal blank to select programmed data [11:0] + typedef UReg<0x01, 0x3D, 0, 12> HD_HB_SP; // Generate horizontal blank to select programmed data [11:0]. + typedef UReg<0x01, 0x3F, 0, 12> HD_HS_ST; // Output sync to DAC start position [11:0] + typedef UReg<0x01, 0x41, 0, 12> HD_HS_SP; // Output sync to DAC stop position [11:0] + typedef UReg<0x01, 0x43, 0, 12> HD_VB_ST; // Generate blank to select program data in blank [11:0] + typedef UReg<0x01, 0x45, 0, 12> HD_VB_SP; // Generate blank to select program data in blank [11:0] + typedef UReg<0x01, 0x47, 0, 12> HD_VS_ST; // Output vertical sync to DAC start position [11:0] + typedef UReg<0x01, 0x49, 0, 12> HD_VS_SP; // Output vertical sync to DAC stop position [11:0] + typedef UReg<0x01, 0x4B, 0, 12> HD_EXT_VB_ST; // Output vertical blank to DAC for DIV mode start position [11:0] + typedef UReg<0x01, 0x4D, 0, 12> HD_EXT_VB_SP; // Output vertical blank to DAC for DIV mode stop position [11:0] + typedef UReg<0x01, 0x4F, 0, 12> HD_EXT_HB_ST; // Output horizontal blank to DAC for DIV mode start position [11:0] + typedef UReg<0x01, 0x51, 0, 12> HD_EXT_HB_SP; // Output horizontal blank to DAC for DIV mode stop position [11:0] + typedef UReg<0x01, 0x53, 0, 8> HD_BLK_GY_DATA; // Force the blank of GY data to the defined programmed data + typedef UReg<0x01, 0x54, 0, 8> HD_BLK_BU_DATA; // Force the blank of BU data to the defined programmed data + typedef UReg<0x01, 0x55, 0, 8> HD_BLK_RV_DATA; // Force the blank of BU data to the defined programmed data + + // + // Mode Detect (all registers R/W) + // + typedef UReg<0x01, 0x60, 0, 5> MD_HPERIOD_LOCK_VALUE; // Mode Detect Horizontal Period Lock Value (If the continuous stabled line number is equal to the defined value, the horizontal stable indicator will be high) + typedef UReg<0x01, 0x60, 5, 3> MD_HPERIOD_UNLOCK_VALUE; // Mode Detect Horizontal Period Unlock Value (If the continuous unstable line number is equal to the defined value, the horizontal stable indicator will be low) + typedef UReg<0x01, 0x61, 0, 5> MD_VPERIOD_LOCK_VALUE; // Mode Detect Vertical Period Lock Value (If the continuous stabled frame number is equal to the defined value, the vertical stable indicator will be high) + typedef UReg<0x01, 0x61, 5, 3> MD_VPERIOD_UNLOCK_VALUE; // Mode Detect Vertical Period Unlock Value (If the continuous unstable frame number is equal to the defined value, the vertical stable indicator will be low) + typedef UReg<0x01, 0x62, 0, 6> MD_NTSC_INT_CNTRL; // NTSC Interlace Mode Detect Value (If the vertical period number is equal to the defined value, This mode is NTSC Interlace mode) + typedef UReg<0x01, 0x62, 6, 2> MD_WEN_CNTRL; // Horizontal Stable Estimation Error Range Control (The continuous line is stable in the defined error range. see: DEVELOPER_NOTES.md -> S1_62) + typedef UReg<0x01, 0x63, 0, 5> MD_PAL_INT_CNTRL; // PAL Interlace Mode Detect Value (If the vertical period number is equal to the defined value, This mode is PAL interlace mode) + typedef UReg<0x01, 0x63, 6, 1> MD_HS_FLIP; // Input Horizontal sync polarity Control (When set it to 1, the input horizontal sync will be inverted.) + typedef UReg<0x01, 0x63, 7, 1> MD_VS_FLIP; // Input Vertical sync polarity Control (When set it to 1, the input vertical sync will be inverted) + typedef UReg<0x01, 0x64, 0, 7> MD_NTSC_PRG_CNTRL; // NTSC Progressive Mode Detect Value (If the vertical period number is equal to the defined value, This mode is NTSC progressive mode or VGA 60HZ mode) + // 64_7:1 - reserved + typedef UReg<0x01, 0x65, 0, 7> MD_VGA_CNTRL; // VGA Mode Vertical Detect Value (If the vertical period number is equal to the defined value, this mode is VGA mode, except VGA 60HZ mode) + typedef UReg<0x01, 0x65, 7, 1> MD_SEL_VGA60; // Select VGA 60HZ mode: Program this bit to distinguish between VGA 60Hz mode and NTSC progressive mode; + // When set to 1, select VGA 60Hz mode + // When set to 0, select NTSC progressive mode + typedef UReg<0x01, 0x66, 0, 8> MD_VGA_75HZ_CNTRL; // VGA 75Hz Horizontal Detect Value (If the horizontal period number is equal to the defined value, in VGA mode, this mode Is VGA 75Hz mode) + typedef UReg<0x01, 0x67, 0, 8> MD_VGA_85HZ_CNTRL; // VGA 85Hz Horizontal Detect Value (If the horizontal period number is equal to the defined value, in VGA mode, this mode Is VGA 85Hz mode) + typedef UReg<0x01, 0x68, 0, 7> MD_V1250_VCNTRL; // Vertical 1250 Line Mode Vertical Detect Value + // 68_7:1 - reserved + typedef UReg<0x01, 0x69, 0, 8> MD_V1250_HCNTRL; // Vertical 1250 Line Mode Horizontal Detect Value, horizontal 866 pixels mode detect value + typedef UReg<0x01, 0x6A, 0, 8> MD_SVGA_60HZ_CNTRL; // SVGA 60HZ Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SVGA mode, it’s SVGA 60Hz mode.) + typedef UReg<0x01, 0x6B, 0, 8> MD_SVGA_75HZ_CNTRL; // SVGA 75HZ Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SVGA mode, it’s SVGA 75Hz mode) + typedef UReg<0x01, 0x6C, 0, 8> MD_SVGA_85HZ_CNTRL; // SVGA 85HZ Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SVGA mode, it’s SVGA 85Hz mode) + typedef UReg<0x01, 0x6D, 0, 7> MD_XGA_CNTRL; // XGA Mode Vertical Detect Value (If the vertical period number is equal to the defined value, it’s XGA mode.) + // 6D_7:1 - reserved + typedef UReg<0x01, 0x6E, 0, 8> MD_XGA_60HZ_CNTRL; // XGA 60Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in XGA modes, It’s XGA 60Hz mode) + typedef UReg<0x01, 0x6F, 0, 7> MD_XGA_70HZ_CNTRL; // XGA 70Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in XGA modes, It’s XGA 70Hz mode) + // 6F_7:1 - reserved + typedef UReg<0x01, 0x70, 0, 7> MD_XGA_75HZ_CNTRL; // XGA 75Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in XGA modes, It’s XGA 75Hz mode) + // 70_7:1 - reserved + typedef UReg<0x01, 0x71, 0, 7> MD_XGA_85HZ_CNTRL; // XGA 85Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in XGA modes, It’s XGA 85Hz mode) + // 71_7:1 - reserved + typedef UReg<0x01, 0x72, 0, 8> MD_SXGA_CNTRL; // SXGA Mode Vertical Detect Value (If the vertical period number is equal to the defined value, It’s SXGA mode) + typedef UReg<0x01, 0x73, 0, 7> MD_SXGA_60HZ_CNTRL; // SXGA 60Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SXGA modes, It’s SXGA 60Hz mode) + // 73_7:1 - reserved + typedef UReg<0x01, 0x74, 0, 7> MD_SXGA_75HZ_CNTRL; // SXGA 75Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SXGA modes, It’s SXGA 75Hz mode) + // 74_7:1 - reserved + typedef UReg<0x01, 0x75, 0, 7> MD_SXGA_85HZ_CNTRL; // SXGA 85Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in SXGA modes, It’s SXGA 85Hz mode) + // 75_7:1 - reserved + typedef UReg<0x01, 0x76, 0, 7> MD_HD720P_CNTRL; // HD720P Vertical Detect Value (If the vertical period number is equal to the defined value, It’s HD720P mode) + // 76_7:1 - reserved + typedef UReg<0x01, 0x77, 0, 8> MD_HD720P_60HZ_CNTRL; // HD720P 60Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in HD720P mode. It is HD720P 60Hz mode) + typedef UReg<0x01, 0x78, 0, 8> MD_HD720P_50HZ_CNTRL; // HD720P 50Hz Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, in HD720P mode. It is HD720P 50Hz mode) + typedef UReg<0x01, 0x79, 0, 7> MD_HD1125I_CNTRL; // 1080I Mode 1125 Line Vertical Detect Value (If the vertical period number is equal to the defined value, It’s 1125I mode) + // 79_7:1 - reserved + typedef UReg<0x01, 0x7A, 0, 8> MD_HD2200_1125I_CNTRL; // 1080I Mode 2200x1125I Horizontal Detect Value (If the horizontal period number is equal to the defined value, in 1080I mode. It is HD2200x1125I mode) + typedef UReg<0x01, 0x7B, 0, 8> MD_HD2640_1125I_CNTRL; // 1080I Mode 2640x1125I Horizontal Detect Value (If the horizontal period number is equal to the defined value, in 1080I mode. It is HD2640x1125I mode) + typedef UReg<0x01, 0x7C, 0, 8> MD_HD1125P_CNTRL; // 1080P Mode 1125 Line Vertical Detect Value (If the vertical period number is equal to the defined value, It is HD1125P mode) + typedef UReg<0x01, 0x7D, 0, 7> MD_HD2200_1125P_CNTRL; // 1080P Mode 2200x1125P Horizontal Detect Value (If the horizontal period number is equal to the defined value, in 1080P mode, It is HD2200x1125P mode) + // 7D_7:1 - reserved + typedef UReg<0x01, 0x7E, 0, 7> MD_HD2640_1125P_CNTRL; // 1080P Mode 2640x1125P Horizontal Detect Value (If the horizontal period number is equal to the defined value, in 1080P mode, It is HD2640x1125P mode) + // 7E_7:1 - reserved + typedef UReg<0x01, 0x7F, 0, 8> MD_HD1250P_CNTRL; // [changed to meaning 24khz] 1080P Mode 2640x1125P Horizontal Detect Value (If the horizontal period number is equal to the defined value, in 1080P mode, It is HD2640x1125P mode) + typedef UReg<0x01, 0x80, 0, 8> MD_USER_DEF_VCNTRL; // User Defined Mode Vertical Detect Value (If the vertical period number is equal to the defined value, It is user-defined mode) + typedef UReg<0x01, 0x81, 0, 8> MD_USER_DEF_HCNTRL; // User Defined Mode Horizontal Detect Value (If the horizontal period number is equal to the defined value, It is user-defined mode) + typedef UReg<0x01, 0x82, 0, 1> MD_NOSYNC_DET_EN; // Sync Connection Detect Enable (Detect the horizontal sync signal if connect or not. 0: user mode; 1: auto detect) + typedef UReg<0x01, 0x82, 1, 1> MD_NOSYNC_USER_ID; // Sync Connection Detect User Defined ID (User defined indicator in user mode. 0: sync connected; 1: no sync connected) + typedef UReg<0x01, 0x82, 2, 1> MD_SW_DET_EN; // Mode Switch Detect Enable (Enable bit of auto detect if the mode changed or not. 0: user mode; 1: auto detect) + typedef UReg<0x01, 0x82, 3, 1> MD_SW_USER_ID; // Mode Switch Detect User Defined ID (User defined indicator in user mode. 0->1: mode changed; 1->0: mode changed) + typedef UReg<0x01, 0x82, 4, 1> MD_TIMER_DET_EN_H; // Horizontal Unstable Estimation Timer Detect Enable (Enable the timer detect result in horizontal unstable estimation. 0: use the hstable indicator in hperiod detect; 1: use the timer detected unstable indicator) + typedef UReg<0x01, 0x82, 5, 1> MD_TIMER_DET_EN_V; // Vertical Unstable Estimation Timer Detect Enable (Enable the timer detect result in vertical unstable estimation. 0: use the vstable indicator in vperiod detect.; 1: use the timer detected unstable indicator) + typedef UReg<0x01, 0x82, 6, 1> MD_DET_BYPS_H; // Horizontal Unstable Estimation Bypass Control (Bypass the horizontal unstable estimation 0: auto mode; 1: user mode) + typedef UReg<0x01, 0x82, 7, 1> MD_H_USER_ID; // Horizontal Unstable Estimation User Defined ID (User defined indicator in user mode. 0: stable; 1: unstable) + typedef UReg<0x01, 0x83, 0, 1> MD_DET_BYPS_V; // Vertical Unstable Estimation Bypass Control (Bypass the vertical unstable estimation auto detect 0: auto mode; 1: user mode) + typedef UReg<0x01, 0x83, 1, 1> MD_V_USER_ID; // Vertical Unstable Estimation User Defined ID (User defined indicator in user mode. 0: stable; 1: unstable) + typedef UReg<0x01, 0x83, 2, 4> MD_UNSTABLE_LOCK_VALUE; // Unstable Estimation Lock Value (If the internal counter equals the defined value, the unstable indicator will be high. Horizontal and vertical estimation shared this value) + // 83_6:2 - reserved + + // + // Deinterlacer / Scaledown registers + // + typedef UReg<0x02, 0x00, 0, 8> DEINT_00; // DEINTERLACER 00 + typedef UReg<0x02, 0x00, 0, 1> DIAG_BOB_MIN_BYPS; // Diagonal Function Bypass Control (When set to 1, bypass diagonal min selection for Y. No diagonal detection, just vertically two pixels average.) + typedef UReg<0x02, 0x00, 1, 1> DIAG_BOB_COEF_SEL; // Diagonal Bob Low pass Filter Coefficient Selection (see DEVELOPER_NOTES.md -> Diagonal Bob Low pass Filter Coefficient Selection) + typedef UReg<0x02, 0x00, 2, 1> DIAG_BOB_WEAVE_BYPS; // Weave Function Bypass Control (When set to 1, weave function will bypass. Just repeat original data.) + typedef UReg<0x02, 0x00, 3, 2> DIAG_BOB_DET_BYPS; // Diagonal Bob Deinterlacer Angle Detect Bypass Control (When set to 1, bypass the detection of angle arctan (1/4):(1/6).) + typedef UReg<0x02, 0x00, 5, 1> DIAG_BOB_YTAP3_BYPS; // Diagonal Bob Deinterlacer Y Tap3 Filter Bypass control (When set to 1, bypass the tap3 filter for Y.) + typedef UReg<0x02, 0x00, 6, 1> DIAG_BOB_MIN_CBYPS; // Diagonal Bob Min Control For UV (When set to 1, bypass diagonal min select for UV. No diagonal detection, just vertically two pixels average.) + typedef UReg<0x02, 0x00, 7, 1> DIAG_BOB_PLDY_RAM_BYPS; // Bypass Control For Pdelayer FIFO (When set to 1, bypass FIFO for pdelayer.) + typedef UReg<0x02, 0x01, 0, 9> DIAG_BOB_PLDY_SP; // The Distance Control of Pdelayer Reset [7:0] (In pdelayer, adjust the delay between read reset and write reset.) + // 02_1:4 - reserved + typedef UReg<0x02, 0x02, 5, 1> MADPT_SEL_22; // 2:2 pull-down selection (When set to 1, enable 2:2 pull-down detection; When set to 0, enable 3:2 pull-down detection.) + typedef UReg<0x02, 0x02, 6, 1> MADPT_Y_VSCALE_BYPS; // Bypass Y phase adjustment in vertical scaling down (When set to 1, Y phase adjustment in vertical scaling down will be bypass) + typedef UReg<0x02, 0x02, 7, 1> MADPT_UV_VSCALE_BYPS; // Bypass UV phase adjustment in vertical scaling down (When set to 1, UV phase adjustment in vertical scaling down will be bypass) + typedef UReg<0x02, 0x03, 0, 1> MADPT_NOISE_DET_SEL; // Noise detection selection (When set to 1, noise detection is in video active period. When set to 0, noise detection is in video blanking period.) + typedef UReg<0x02, 0x03, 1, 2> MADPT_NOISE_DET_SHIFT; // Noise detection shift + // When set to 3, noise detection drop 15bits + // When set to 2, noise detection drop 16bits + // When set to 1, noise detection drop 17bits + // When set to 0, noise detection drop 18bits + typedef UReg<0x02, 0x03, 3, 2> MADPT_NOISE_DET_RST; // Noise detection time reset value + // When set to 3, time counter reset at 1023. + // When set to 2, time counter reset at 511. + // When set to 1, time counter reset at 255. + // When set to 0, time counter reset at 127. + // 03_5:3 - reserved + typedef UReg<0x02, 0x04, 0, 6> MADPT_NOISE_THRESHOLD_NOUT; // Auto noise detect threshold for NOUT - Threshold for NOUT signal. + typedef UReg<0x02, 0x05, 0, 6> MADPT_NOISE_THRESHOLD_VDS; // Auto noise detect threshold for nout_vds_proc - Threshold for nout_vds_proc signal. + typedef UReg<0x02, 0x06, 0, 8> MADPT_GM_NOISE_VALUE; // Global noise low/global noise auto detect offset low + // In global motion noise manual mode, global motion detection noise bit [3:0] + // In global motion noise auto-detect mode, global motion noise’s offset bit [3:0] + // In global motion noise manual mode, global motion detection noise bit [7:4] + // In global motion noise auto-detect mode, global motion noise’s offset bit [7:4] + typedef UReg<0x02, 0x07, 0, 8> MADPT_STILL_NOISE_VALUE; // Global still control value (In manual mode, still-noise value bit; In auto-detect mode, still-noise’s offset bit.) + typedef UReg<0x02, 0x08, 0, 8> MADPT_LESS_NOISE_VALUE; // Less-still noise value (User defined less still noise value.) + typedef UReg<0x02, 0x09, 0, 4> MADPT_NOISE_EST_GAIN; // Global motion noise gain (in auto-detect mode) + typedef UReg<0x02, 0x09, 4, 8> MADPT_STILL_NOISE_EST_GAIN; // Still-noise gain (in auto-detect mode) + // 0A_0:4 - reserved + typedef UReg<0x02, 0x0A, 4, 1> MADPT_NOISE_EST_EN; // Global noise auto detection enable (When set to 1,global noise detection is in auto mode.; When set to 0,global noise detection is in manual mode.) + typedef UReg<0x02, 0x0A, 5, 1> MADPT_STILL_NOISE_EST_EN; // Still-noise auto detection enable (When set to 1, still-noise is in auto detection; When set to 0, still-noise is in manual mode.) + // 0A_6:1 - reserved + typedef UReg<0x02, 0x0A, 7, 1> MADPT_Y_MI_DET_BYPS; // MADPT_Y_MI_DET_BYPS (When set to 1, Y motion index generation is in manual mode) + typedef UReg<0x02, 0x0B, 0, 7> MADPT_Y_MI_OFFSET; // Y motion index offset (In auto mode, Y motion index’s offset.; In manual mode, Y motion index’s user value.) + // 0B_7:1 - reserved + typedef UReg<0x02, 0x0C, 0, 4> MADPT_Y_MI_GAIN; // Y motion index gain + typedef UReg<0x02, 0x0C, 4, 1> MADPT_MI_1BIT_BYPS; // Motion index feedback-bit bypass (When set to 1, motion index feedback-bit function will be bypass) + typedef UReg<0x02, 0x0C, 5, 1> MADPT_MI_1BIT_FRAME2_EN; // Enable Frame-two feedback-bit (When set to 1, enable frame-two feedback-bit.) + // 0C_7:1 - reserved + typedef UReg<0x02, 0x0D, 0, 7> MADPT_MI_THRESHOLD_D; // Motion index feedback-bit generation’s threshold bit + typedef UReg<0x02, 0x0E, 0, 7> MADPT_MI_THRESHOLD_E; // Motion index fixed value + typedef UReg<0x02, 0x0F, 0, 1> MADPT_STILL_DET_EN; // MStill detection enable (When set to 1, still detection is in auto mode. When set to 0, still detection is in manual mode.) + typedef UReg<0x02, 0x0F, 1, 1> MADPT_STILL_ID; // Still indicator defined by user (in manual mode only) (Still indicator defined by user, only useful in STILL_DET_EN =0.) + typedef UReg<0x02, 0x0F, 2, 2> MADPT_STILL_UNLOCK; // Still detection’s auto unlock value (When unlock counter equals unlock value, “still” will go inactive.) + typedef UReg<0x02, 0x0F, 4, 4> MADPT_STILL_LOCK; // Still detection’s auto lock value (When lock counter equals lock value, “still” will go active.) + typedef UReg<0x02, 0x10, 0, 1> MADPT_LESS_STILL_DET_EN; // Less still detection enable (When set to 1, less-still detection is in auto mode. When set to 0, less-still detection is in manual mode.) + typedef UReg<0x02, 0x10, 1, 1> MADPT_LESS_STILL_ID; // Less still indicator defined by user (in manual mode only) (Less-still indicator defined by user, only useful in LESS_STILL_DET_EN =0) + typedef UReg<0x02, 0x10, 2, 2> MADPT_LESS_STILL_UNLOCK; // Less still detection’s auto unlock value (When unlock counter equals unlock value, “less-still” will go inactive.) + typedef UReg<0x02, 0x10, 4, 4> MADPT_LESS_STILL_LOCK; // Less still detection’s auto lock value (When lock counter equals lock value, “less-still” will go active.) + // 11_0:2 - reserved + typedef UReg<0x02, 0x11, 3, 1> MADPT_EN_PULLDOWN32; // 3:2 pull-down detection enable (When set to 1, 3:2 pull-down detection is in auto mode. When set to 0, 3:2 pull-down detection is in manual mode.) + typedef UReg<0x02, 0x11, 4, 1> MADPT_PULLDOWN32_ID; // 3:2 pull-down indicator defined by user (in manual mode) (3:2 pull-down indicator by user, only useful in 32PULLDOWN_EN =0) + typedef UReg<0x02, 0x11, 5, 3> MADPT_PULLDOWN32_OFFSET; // 3:2 pull-down sequence offset + typedef UReg<0x02, 0x12, 0, 7> MADPT_PULLDOWN32_LOCK_RST; // 3:2 pull-down auto lock value bit (When lock counter equals lock value, 3:2 pull-down is in active.) + // 12_7:1 - reserved + typedef UReg<0x02, 0x13, 0, 1> EN_22PULLDOWN; // 2:2 pull-down detection enable (When set to 1, 2:2 pull-down detection is in auto mode. When set to 0, 2:2 pull-down detection is in manual mode.) + typedef UReg<0x02, 0x13, 1, 1> ID_22PULLDOWN; // 2:2 pull-down indicator defined by user (in manual mode) (2:2 pull-down indicator by user, only useful in 22PULLDOWN_EN =0) + typedef UReg<0x02, 0x13, 2, 1> MADPT_PULLDOWN22_OFFSET; // 2:2 pull-down sequence offset + // 13_3:1 - reserved + typedef UReg<0x02, 0x13, 4, 3> MADPT_PULLDOWN22_DET_CNTRL; // 2:2 pull-down detection control bit + // 13_7:1 - reserved + typedef UReg<0x02, 0x14, 0, 18> MADPT_PULLDOWN22_THRESHOLD; // 2:2 pull-down detection threshold bit [7:0] + // 16_2:2 - reserved + typedef UReg<0x02, 0x16, 4, 1> MADPT_MO_ADP_Y_EN; // Enable pull-down in Y motion adaptive (When set to 1, enable pull-down for Y data motion adaptive.) + typedef UReg<0x02, 0x16, 5, 1> MADPT_MO_ADP_UV_EN; // Enable pull-down in UV motion adaptive (When set to 1, enable pull-down for UV data motion adaptive.) + typedef UReg<0x02, 0x16, 6, 1> MADPT_VT_FILTER_CNTRL; // Vertical Temporal Filter Control (When set to 1, do motion adaptive in interpolated line only; When set to 0, do motion adaptive in every line.) + typedef UReg<0x02, 0x16, 7, 1> MAPDT_VT_SEL_PRGV; // Select original data in progressive mode in VT filter (If the input is progressive mode or graphic mode, this bit must be set to 1) + typedef UReg<0x02, 0x17, 0, 8> MADPT_Y_DELAY_UV_DELAY; // + typedef UReg<0x02, 0x17, 0, 4> MADPT_Y_DELAY; // Y delay pipe control (see: DEVELOPER_NOTES.md -> Y delay pipe control) + typedef UReg<0x02, 0x17, 4, 4> MADPT_UV_DELAY; // UV delay pipe control (see: DEVELOPER_NOTES.md -> UV delay pipe control) + typedef UReg<0x02, 0x18, 0, 1> MADPT_DIVID_BYPS; // Motion index divide bypass (When = 1, motion index no divide.; When = 0, motion index will by divided by 2 or 4) + typedef UReg<0x02, 0x18, 1, 1> MADPT_DIVID_SEL; // Motion index divide selection (When = 1, motion index will be divided by 2 in still. When = 0, motion index will be divided by 4 in still.) + // 18_2:1 - reserved + typedef UReg<0x02, 0x18, 3, 1> MADPT_HTAP_BYPS; // Motion index horizontal filter bypass (When =1, motion index horizontal filter will be bypass) + typedef UReg<0x02, 0x18, 4, 4> MADPT_HTAP_COEFF; // Motion index horizontal filter coefficient + typedef UReg<0x02, 0x19, 0, 1> MADPT_BIT_STILL_EN; // Enable pixel base still (When set to 1, pixel base still function will enable.) + // 19_1:1 - reserved + typedef UReg<0x02, 0x19, 2, 1> MADPT_VTAP2_BYPS; // Motion index vertical filter bypass (When = 1, motion index’s vertical filter will be bypass.) + typedef UReg<0x02, 0x19, 3, 1> MADPT_VTAP2_ROUND_SEL; // Motion index vertical filter round selection (When set to 1, the input data will be divided by 2.) + typedef UReg<0x02, 0x19, 4, 4> MADPT_VTAP2_COEFF; // Motion index vertical filter coefficient + typedef UReg<0x02, 0x1A, 0, 8> MADPT_PIXEL_STILL_THRESHOLD_1; // Pixel base still threshold level 1 + typedef UReg<0x02, 0x1B, 0, 8> MADPT_PIXEL_STILL_THRESHOLD_2; // Pixel base still threshold level 2 + // 1C_0:8 - reserved + // 1D_0:8 - reserved + // 1E_0:8 - reserved + typedef UReg<0x02, 0x1F, 0, 8> MADPT_HFREQ_NOISE; // High-frequency detection noise value - The noise value for high-frequency detection. + typedef UReg<0x02, 0x20, 0, 1> MADPT_HFREQ_DET_EN; // High-frequency detection enable (When set to 1, high-frequency detection is in auto mode. When set to 0, high-frequency detection is in manual mode.) + typedef UReg<0x02, 0x20, 1, 1> MADPT_HFREQ_ID; // High-frequency indicator by user (in manual mode) (High-frequency indicator by user, only useful in HFREQ_DET_EN =0) + // 20_2:2 - reserved + typedef UReg<0x02, 0x20, 4, 4> MADPT_HFREQ_LOCK; // High-frequency auto lock value (When high-frequency lock counter equals lock value, high-frequency will be active) + typedef UReg<0x02, 0x21, 0, 3> MADPT_HFREQ_UNLOCK; // High-frequency auto unlock value (When high-frequency unlock counter equals unlock value, high-frequency will be inactive) + // 21_3:1 - reserved + typedef UReg<0x02, 0x21, 4, 1> MADPT_EN_NOUT_FOR_STILL; // Enable NOUT for still detection + typedef UReg<0x02, 0x21, 5, 1> MADPT_EN_NOUT_FOR_LESS_STILL; // Enable NOUT for less-still detection + // 21_6:2 - reserved + typedef UReg<0x02, 0x22, 0, 5> MADPT_PD_SP; // Scaling down line buffer WRSTZ position adjustment bits (Adjust the position of write reset in vertical IIR filter line buffer, and phase adjustment line buffer.) + // 22_5:3 - reserved + typedef UReg<0x02, 0x23, 0, 5> MADPT_PD_ST; // Scaling down line buffer WRSTZ position adjustment bits (Adjust the position of write reset in vertical IIR filter line buffer, and phase adjustment line buffer.) + // 23_5:3 - reserved + typedef UReg<0x02, 0x24, 2, 1> MADPT_PD_RAM_BYPS; // Bypass scaling down’s line buffer (When set to 1, scaling down’s line buffer will be bypass.) + // 25_0:8 - reserved + typedef UReg<0x02, 0x26, 6, 1> MADPT_VIIR_BYPS; // Bypass V-IIR filter in vertical scaling down (When set to 1, V-IIR filter in vertical scaling down will be bypass.) + typedef UReg<0x02, 0x26, 7, 1> MADPT_VIIR_ROUND_SEL; // V-IIR filter in vertical scaling down round selection (When set to 1, the input data will be divided by 2) + typedef UReg<0x02, 0x27, 0, 7> MADPT_VIIR_COEF; // V-IIR filter coefficient + // 27_7:1 - reserved + // 28_0:4 - reserved + typedef UReg<0x02, 0x28, 4, 4> MADPT_VSCALE_RATE_LOW; // Vertical non-linear scale down DDA increment shared low 4-bit - All the segment DDA increment share low 4bit + typedef UReg<0x02, 0x29, 0, 8> MADPT_VSCALE_RATE_SEG0; // Vertical non-linear scale down 1st segment DDA increment value (The actual DDA increment is vscale={vscale0, vscale_low}. Assume the scale factor is n/m, then vscale= 4095x(m-n)/n) + typedef UReg<0x02, 0x2A, 0, 8> MADPT_VSCALE_RATE_SEG1; // Vertical non-linear scale down 2nd segment DDA increment value (The actual DDA increment is vscale={vscale1, vscale_low}) + typedef UReg<0x02, 0x2B, 0, 8> MADPT_VSCALE_RATE_SEG2; // Vertical non-linear scale down 3rd segment DDA increment value (The actual DDA increment is vscale={vscale2, vscale_low}.) + typedef UReg<0x02, 0x2C, 0, 8> MADPT_VSCALE_RATE_SEG3; // Vertical non-linear scale down 4th segment DDA increment value (The actual DDA increment is vscale={vscale3, vscale_low}.) + typedef UReg<0x02, 0x2D, 0, 8> MADPT_VSCALE_RATE_SEG4; // Vertical non-linear scale down 5th segment DDA increment value (The actual DDA increment is vscale={vscale4, vscale_low}.) + typedef UReg<0x02, 0x2E, 0, 8> MADPT_VSCALE_RATE_SEG5; // Vertical non-linear scale down 6th segment DDA increment value (The actual DDA increment is vscale={vscale5, vscale_low}.) + typedef UReg<0x02, 0x2F, 0, 8> MADPT_VSCALE_RATE_SEG6; // Vertical non-linear scale down 7th segment DDA increment value (The actual DDA increment is vscale={vscale6, vscale_low}.) + typedef UReg<0x02, 0x30, 0, 8> MADPT_VSCALE_RATE_SEG7; // Vertical non-linear scale down 8th segment DDA increment value (The actual DDA increment is vscale={vscale7, vscale_l + typedef UReg<0x02, 0x31, 0, 2> MADPT_VSCALE_DEC_FACTOR; // Vertical non-linear scaling-down factor select + // If the scaling ratio is less than 1⁄2, use it and DDA to generate the we and phase 00: scaling-ratio is more than 1⁄2. + // 01: scaling-ratio is less than 1⁄2. + // 10: scaling-ratio is less than 1⁄4. + typedef UReg<0x02, 0x31, 2, 1> MADPT_SEL_PHASE_INI; // Vertical scaling down initial phase selection + typedef UReg<0x02, 0x31, 3, 1> MADPT_TET_EN; // Test bus output enable (Internal hardware debugging use only.) + typedef UReg<0x02, 0x31, 4, 4> MADPT_TEST_SEL; // Test bus select (Internal hardware debugging use only.) + typedef UReg<0x02, 0x32, 0, 4> MADPT_Y_HTAP_CNTRL; // Y horizontal filter control for background reduction (Y_HTAP_CNTRL[3:0] could bypass four tap3 FIR filter.) + typedef UReg<0x02, 0x32, 4, 3> MADPT_Y_VTAP_CNTRL; // Y vertical filter control for background reduction + // Y_VTAP_CNTRL[0]: when set to1, bypass vertical filter + // Y_VTAP_CNTRL[1]: when set to 1, enable FIR filter + // Y_VTAP_CNTRL[2]: when set to 1, bypass IIR filter + typedef UReg<0x02, 0x32, 7, 1> MADPT_NRD_SEL; // Background reduction selection control (Only set it to 1 in huge noise condition) + typedef UReg<0x02, 0x33, 0, 4> MADPT_M_HTAP_CNTRL; // Background noise reduction H filter control in huge noise condition (M_HTAP_CNTRL[3:0] could bypass four tap3 FIR filter.) + typedef UReg<0x02, 0x33, 4, 3> MADPT_M_VTAP_CNTRL; // Background noise reduction V filter control in huge noise condition + // M_VTAP_CNTRL[0]: when set to1, bypass vertical filter + // M_VTAP_CNTRL[1]: when set to 1, enable FIR filter + // M_VTAP_CNTRL[2]: when set to 1, bypass IIR filter + // 33_7:1 - reserved + typedef UReg<0x02, 0x34, 0, 1> MADPT_Y_WOUT_BYPS; // Bypass Y WOUT + typedef UReg<0x02, 0x34, 1, 3> MADPT_Y_WOUT; // Coefficient for Y noise reduction + typedef UReg<0x02, 0x34, 4, 1> MADPT_UV_WOUT_BYPS; // Bypass UV WOUT + typedef UReg<0x02, 0x34, 5, 3> MADPT_UV_WOUT; // Coefficient for UV noise reduction + typedef UReg<0x02, 0x35, 0, 1> MADPT_Y_NRD_ENABLE; // Enable background noise reduction in Y domain (When set to 1, enable background noise reduction in Y domain.) + typedef UReg<0x02, 0x35, 1, 1> MADPT_UV_NRD_ENABLE; // Enable background noise reduction in UV domain (When set to 1, enable background noise reduction in UV domain.) + typedef UReg<0x02, 0x35, 2, 1> MADPT_NRD_OUT_SEL; // NRD output selection (Only set it to 1 in huge noise condition) + typedef UReg<0x02, 0x35, 3, 1> MADPT_DD0_SEL; // DD0 select control (Set it to 1 when background noise reduction enable; Set it to 0 when background noise reduction disable) + typedef UReg<0x02, 0x35, 4, 1> MADPT_NRD_VIIR_PD_BYPS; // Bypass NRD VIIR line buffer + typedef UReg<0x02, 0x35, 5, 1> MADPT_UVDLY_PD_BYPS; // Bypass UV delay line buffer + typedef UReg<0x02, 0x35, 6, 1> MADPT_CMP_EN; // Motion compare enable (When set to 1, enable motion compare; When set to 0, motion compare is in manual mode) + typedef UReg<0x02, 0x35, 7, 1> MADPT_CMP_USER_ID; // Motion compare result defined by user (in manual mode) (Motion compare result defined by user when CMP_EN = 0) + typedef UReg<0x02, 0x36, 0, 8> MADPT_CMP_LOW_THRESHOLD; // Motion compare low level threshold + typedef UReg<0x02, 0x37, 0, 8> MADPT_CMP_HIGH_THRESHOLD; // Motion compare high level threshold + typedef UReg<0x02, 0x38, 0, 4> MADPT_NRD_VIIR_PD_SP; // NRD line buffer WRSTZ position adjustment + typedef UReg<0x02, 0x38, 4, 4> MADPT_NRD_VIIR_PD_ST; // NRD line buffer RRSTZ position adjustment + typedef UReg<0x02, 0x39, 0, 4> MADPT_UVDLY_PD_SP; // UV delay line buffer WRSTZ position adjustment + typedef UReg<0x02, 0x39, 4, 4> MADPT_UVDLY_PD_ST; // UV delay line buffer RRSTZ position adjustment + typedef UReg<0x02, 0x3a, 0, 1> MADPT_EN_UV_DEINT; // Enable UV deinterlacer (When set to 1, enable UV deinterlacer) + typedef UReg<0x02, 0x3a, 1, 1> MADPT_EN_PULLDWN_FOR_NRD; // Enable pull-down to block STILL for NRD (Set it to 1, background noise reduction will in low noise level when in 32/22 pull- down source) + typedef UReg<0x02, 0x3a, 2, 1> MADPT_EN_NOUT_FOR_NRD; // Enable NOUT for background noise reduction + typedef UReg<0x02, 0x3a, 3, 1> MADPT_EN_STILL_FOR_NRD; // Enable still for background noise reduction + typedef UReg<0x02, 0x3a, 4, 1> MADPT_EN_STILL_FOR_PULLDWN; // Enable STILL to reset pull-down detection (When set to 1, still will be used to reset 3:2/2:2 pull-down detection) + typedef UReg<0x02, 0x3a, 5, 2> MADPT_MI_1BIT_DLY; // Delay pipe control for motion index feedback-bit (see: DEVELOPER_NOTES.md -> Delay pipe control for motion index feedback-bit) + typedef UReg<0x02, 0x3a, 7, 1> MADPT_UV_MI_DET_BYPS; // UV motion index generation bypass (When set to 1, UV motion index generation is in manual mode.) + typedef UReg<0x02, 0x3b, 0, 7> MADPT_UV_MI_OFFSET; // UV motion index offset (In auto mode, UV motion index offset; In manual mode, UV motion index user defined value) + // 3B_7:1 - reserved + typedef UReg<0x02, 0x3C, 0, 4> MADPT_UV_MI_GAIN; // UV motion index gain (UV motion index gain.) + typedef UReg<0x02, 0x3C, 4, 3> MADPT_MI_DELAY; // Motion index delay control (Control motion index (both Y and UV’s) delay pipes, so that the motion index can align with corresponding data.) + // see: DEVELOPER_NOTES.md -> Motion index delay control + // 3C_7:1 - reserved + + // + // Video Processor Registers (all registers R/W) + // + typedef UReg<0x03, 0x00, 0, 1> VDS_SYNC_EN; // External sync enable, active high - This bit enable sync lock mode (see: DEVELOPER_NOTES.md -> S3_00) + typedef UReg<0x03, 0x00, 1, 1> VDS_FIELDAB_EN; // ABAB double field mode enable (In field double mode, when this bit is 1, VDS works in ABAB mode, otherwise it works in AABB mode.) + typedef UReg<0x03, 0x00, 2, 1> VDS_DFIELD_EN; // Double field mode enable active high (This bit enable field double mode, ex, frame rate from 50Hz to 100Hz, or from 60Hz to 120Hz. When this bit is 1, the output timing is interlaced) + typedef UReg<0x03, 0x00, 3, 1> VDS_FIELD_FLIP; // Flip field control (This bit is field flip control bit, it only used in interlace mode. When it is 1, it inverts the output field) + typedef UReg<0x03, 0x00, 4, 1> VDS_HSCALE_BYPS; // Horizontal scale up bypass control, active high (When this bit is 1, data will bypass horizontal scale up process) + typedef UReg<0x03, 0x00, 5, 1> VDS_VSCALE_BYPS; // Vertical scale up bypass control, active high (When this bit is 1, data will bypass vertical scale up process) + typedef UReg<0x03, 0x00, 6, 1> VDS_HALF_EN; // Horizontal scale up bypass control, active high + typedef UReg<0x03, 0x00, 7, 1> VDS_SRESET; // Horizontal scale up bypass control, active high (When this bit is 1, it reset the VDS_PROC internal module ds_video_enhance) + typedef UReg<0x03, 0x01, 0, 12> VDS_HSYNC_RST; // Internal Horizontal period control bit[7:0], Half of total pixels in field double mode. + // This field contains horizontal total value minus 1. + // EX: Horizontal pixels is A, then HSYNC_RST[9:0] = A-1, in field double mode, HSYNC_RST[9:0] = (A/2 –1)) + typedef UReg<0x03, 0x02, 4, 11> VDS_VSYNC_RST; // Internal Vertical period control bit (This field contains vertical total value minus 1) + // 02_7:1 - reserved + typedef UReg<0x03, 0x04, 0, 12> VDS_HB_ST; // Horizontal blanking start position control bit (This field is used to program horizontal blanking start position, this blanking is used to get data from memory) + typedef UReg<0x03, 0x05, 4, 12> VDS_HB_SP; // Horizontal blanking stop position control bit (This field is used to program horizontal blanking stop position, this blanking is used to get data from memory) + typedef UReg<0x03, 0x07, 0, 11> VDS_VB_ST; // Vertical blanking start position control bit (This field is used to program vertical blanking start position) + // 08_3:1 - reserved + typedef UReg<0x03, 0x08, 4, 11> VDS_VB_SP; // Vertical blanking stop position control bit (This field is used to program vertical blanking stop position) + // 09_7:1 - reserved + typedef UReg<0x03, 0x0A, 0, 12> VDS_HS_ST; // Horizontal sync start position control bit (This field is used to program horizontal sync start position) + typedef UReg<0x03, 0x0B, 4, 12> VDS_HS_SP; // Horizontal sync stop position control bit (This field is used to program horizontal sync stop position) + typedef UReg<0x03, 0x0D, 0, 11> VDS_VS_ST; // Vertical sync start position control bit (This field is used to program vertical sync start position) + // 0E_3:1 - reserved + typedef UReg<0x03, 0x0E, 4, 11> VDS_VS_SP; // Vertical sync stop position control bit (This field is used to program vertical sync stop position) + typedef UReg<0x03, 0x10, 0, 12> VDS_DIS_HB_ST; // Final display horizontal blanking start position control bit (This field contains final display horizontal blanking start position control, this blanking is used to clean the output data in blanking) + typedef UReg<0x03, 0x11, 4, 12> VDS_DIS_HB_SP; // Final display horizontal blanking stop position control bit (This field contains final display horizontal blanking stop position control, this blanking is used to clean the output data in blanking) + typedef UReg<0x03, 0x13, 0, 11> VDS_DIS_VB_ST; // Final display vertical blanking start position control bit (This field contains final display vertical blanking start position control, this blanking is used to clean the output data in blanking) + // 14_3:1 - reserved + typedef UReg<0x03, 0x14, 4, 11> VDS_DIS_VB_SP; // Final display vertical blanking stop position control bit (This field contains final display vertical blanking stop position control, this blanking is used to clean the output data in blanking) + typedef UReg<0x03, 0x16, 0, 10> VDS_HSCALE; // Horizontal scaling coefficient bit. + // This field indicates the ratio of scaling up. + // HSCALE = 1024 * (resolution of input) / (resolution of output) + // EX: 720 * 480 -> 800 * 480, HSCALE = 1024 * 720 / 800 + // 17_2:2 - reserved + typedef UReg<0x03, 0x17, 4, 10> VDS_VSCALE; // Vertical scaling up coefficient bit. + // This field indicates the ratio of vertical scaling up. + // VSCALE = 1024 * (resolution of input / resolution of output) + // EX: 720*480 -> 720*576, VSCALE = 1024 * 480 /576 + // 18_6:2 - reserved + typedef UReg<0x03, 0x19, 0, 10> VDS_FRAME_RST; // Frame reset period control bit + // This field indicates how many frames VSD_PROC locked at each time, it based on the input vertical sync. + // EX: FRAME_RST=4, this means VDS_PROC will lock every 5 frames, + // (This frame number is counts at every input vertical sync, the frame number of VDS_PROC output maybe different) + // 1A_2:2 - reserved + typedef UReg<0x03, 0x1A, 4, 1> VDS_FLOCK_EN; // Frame lock enable, active high + // This bit enables the frame lock mode, when this bit is 1, VDS_PROC output + // timing will lock with its input timing (from INPUT_FORMATTER) at every 2 or more frames. + typedef UReg<0x03, 0x1A, 5, 1> VDS_FREERUN_FID; // Enable internal free run field index generation, active high + // When this bit is 1, the output field index is internal free run field, + // otherwise the output field index is based on input field index. + typedef UReg<0x03, 0x1A, 6, 1> VDS_FID_AA_DLY; // Enable internal free run AABB field delay 1 frame, active high (When this bit is 1, the internal free run AABB field will delay 1 frame) + typedef UReg<0x03, 0x1A, 7, 1> VDS_FID_RST; // Enable internal free run field index reset, active high (When this bit is 1, internal free run field index will reset at every frame number is 0) + + typedef UReg<0x03, 0x1B, 0, 32> VDS_FR_SELECT; // Frame size select control bit (FR_SELECT[2n+1:2n] is for frame n selection. 0 select VSYNC_RST; 1 select VSYNC_SIZE1; 2 select VSYNC_SIZE2) + typedef UReg<0x03, 0x1F, 0, 4> VDS_FRAME_NO; // Programmable repeat frame number control bit (This field defines the repeated frame number, EX: if frame_no = 2, then the frame will repeat every 3 frame) see: DEVELOPER_NOTES.md -> S3_1F + typedef UReg<0x03, 0x1F, 4, 1> VDS_DIF_FR_SEL_EN; // Enable the different frame size, active high (When this bit is 1, VDS_PROC can generate a sequence of different frame size) + typedef UReg<0x03, 0x1F, 5, 1> VDS_EN_FR_NUM_RST; // Enable frame number reset, active high (When this bit is 1, frame number will be reset to 1 when frame lock is occur) + // 1F_6:2 - reserved + typedef UReg<0x03, 0x20, 0, 11> VDS_VSYN_SIZE1; // Programmable vertical total size 1 control bit + // This field contains the vertical total line number minus 1. It can be the same + // as vsync_rst and vsync_size2, it also can different with them, and it + // can be used to define different frame size. + // 20_3:5 - reserved + typedef UReg<0x03, 0x22, 0, 11> VDS_VSYN_SIZE2; // Programmable vertical total size 2 control bit + // This field contains the vertical total line number minus 1. + // It can be the same as vsync_rst and vsync_size1, it also can different + // with them, and it can be used to define different frame size. + // 23_3:5 - reserved + typedef UReg<0x03, 0x24, 0, 8> VDS_3_24; // VDS_PROC 36 + typedef UReg<0x03, 0x24, 0, 1> VDS_UV_FLIP; // 422 to 444 conversion UV flip control (This bit is used to flip UV, when this bit is 1, UV position will be flipped) + typedef UReg<0x03, 0x24, 1, 1> VDS_U_DELAY; // UV 422 to 444 conversion U delay (When this bit is 1, U will delay 1 clock, otherwise, no delay for internal pipe) + typedef UReg<0x03, 0x24, 2, 1> VDS_V_DELAY; // UV 422 to 444 conversion V delay (When this bit is 1, V will delay 1 clock, otherwise, no delay for internal pipe) + typedef UReg<0x03, 0x24, 3, 1> VDS_TAP6_BYPS; // Tap6 filter in 422 to 444 conversion bypass control, active high (This bit is the UV interpolation filter enable control; when this bit is 1, UV bypass the filter) + typedef UReg<0x03, 0x24, 4, 2> VDS_Y_DELAY; // Y compensation delay control bit [1:0] in 422 to 444 conversion (To compensation the pipe of UV, program this field can delay Y from 1 to 4 clocks) (see: DEVELOPER_NOTES.md -> S3_24_4) + typedef UReg<0x03, 0x24, 6, 2> VDS_WEN_DELAY; // Compensation delay control bit [1:0] for horizontal write enable (This two-bit register defines the compensation delay of horizontal scale up write enable and phase) (see: DEVELOPER_NOTES.md -> S3_24_6) + typedef UReg<0x03, 0x25, 0, 10> VDS_D_SP; // Line buffer write reset position control bit (This field contains the write reset position of the line buffer, this position is also the write start position of the buffer) + // 26_2:4 - reserved + typedef UReg<0x03, 0x26, 6, 1> VDS_D_RAM_BYPS; // Line buffer one line delay data bypass, active high (When this bit is 1, data will bypass the line buffer) + typedef UReg<0x03, 0x26, 7, 1> VDS_BLEV_AUTO_EN; // Y minimum and maximum level auto detection enable, active high + // This bit is the Y min and max auto detection enable bit for black/white level expansion, + // when this bit is 1, the min and max value of Y in every frame will be detected, + // otherwise, the min and max value are defined by register + typedef UReg<0x03, 0x27, 0, 4> VDS_USER_MIN; // Programmable minimum value control bit (This field is the user defined min value for black level expansion, the actual min value in use is 2*blev_det_min+1) + typedef UReg<0x03, 0x27, 4, 4> VDS_USER_MAX; // Programmable maximum value control bit (This field is the user defined max value for black level expansion, the actual min value in use is 16*blev_det_max+15) + typedef UReg<0x03, 0x28, 0, 8> VDS_BLEV_LEVEL; // Black level expansion level control bit (This field defines the black level expansion threshold level value, data larger than this level will have no black level expansion process) + typedef UReg<0x03, 0x29, 0, 8> VDS_BLEV_GAIN; // Black level expansion gain control bit (This field contains the gain control of black level expansion, its range is (0~16)*16) + typedef UReg<0x03, 0x2A, 0, 1> VDS_BLEV_BYPS; // Black level expansion bypass control, active high (This bit is the bypass control bit of black level expansion, when it is 1, data will bypass black level expansion process) + // 2A_1:3 - reserved + typedef UReg<0x03, 0x2A, 4, 2> VDS_STEP_DLY_CNTRL; // UV step response data select control bit (see: DEVELOPER_NOTES.md -> S3_2A) + // 2A_6:2 - reserved + // typedef UReg<0x03, 0x2A, 6, 2> VDS_0X2A_RESERVED_2BITS; + typedef UReg<0x03, 0x2B, 0, 4> VDS_STEP_GAIN; // UV Step response gain control bit (This field register can adjust the UV edge improvement, the larger value of this register, the sharper edge will appear, the range of this gain is (0~4)*4) + typedef UReg<0x03, 0x2B, 4, 3> VDS_STEP_CLIP; // UV step response clip control bit (This filed contains the clip control value of UV step response) + typedef UReg<0x03, 0x2B, 7, 1> VDS_UV_STEP_BYPS; // UV step response bypass control, active high (When this bit is 1, UV data will don’t do step response) + + typedef UReg<0x03, 0x2C, 0, 8> VDS_SK_U_CENTER; // Skin color correction U center position control bit (This field contains the skin color center position U value, the value is 2’s) + typedef UReg<0x03, 0x2D, 0, 8> VDS_SK_V_CENTER; // Skin color correction V center position control bit (This field contains the skin color center position U value, the value is 2’s) + typedef UReg<0x03, 0x2E, 0, 8> VDS_SK_Y_LOW_TH; // Skin color correction Y low threshold control bit (Y low threshold value for skin color correction, if y less than this threshold, no skin color correction done) + typedef UReg<0x03, 0x2F, 0, 8> VDS_SK_Y_HIGH_TH; // Skin color correction Y high threshold control bit (Y high threshold value for skin color correction, if y larger than this threshold, no skin color correction done) + typedef UReg<0x03, 0x30, 0, 8> VDS_SK_RANGE; // Skin color correction range control bit (The skin color correction will done just when the value abs(u-u_center)+abs(v- v_enter) less than this programmable range) + typedef UReg<0x03, 0x31, 0, 4> VDS_SK_GAIN; // Skin color correction gain control bit (This register defines the degree of the skin color correction, the higher the value, the more skin color correction done. Its range is (0~1)*16) + typedef UReg<0x03, 0x31, 4, 1> VDS_SK_Y_EN; // Skin color Y detect enable, active high (When this bit is 1, take the Y value as the condition of skin color correction, just when the Y value larger than y_low_th and less the y_high_th, the correction can be done) + typedef UReg<0x03, 0x31, 5, 1> VDS_SK_BYPS; // Skin color correction bypass control, active high (When this bit is 1, the skin color correction will be bypassed) + // 31_6:2 - reserved + typedef UReg<0x03, 0x32, 0, 2> VDS_SVM_BPF_CNTRL; // SVM data generation select control (see: DEVELOPER_NOTES.md -> S3_32) + typedef UReg<0x03, 0x32, 2, 1> VDS_SVM_POL_FLIP; // SVM polarity flip control bit (When this bit is 1, the SVM signal’s polarity will be flipped, otherwise, SVM remains the original phase) + typedef UReg<0x03, 0x32, 3, 1> VDS_SVM_2ND_BYPS; // 2nd order SVM signal generation bypass, active high (When this bit is 1, SVM signal is 1st order, otherwise, it is 2nd order derivative signal) + typedef UReg<0x03, 0x32, 4, 3> VDS_SVM_VCLK_DELAY; // To match YUV pipe, SVM data delay by VCLK control bit (This field define the SVM compensation delay from 1 to 8 VCLKs) + typedef UReg<0x03, 0x32, 7, 1> VDS_SVM_SIGMOID_BYPS; // SVM bypass the sigmoid function, active high (When this bit is 1, SVM signal bypass a sigmoid function. This function can make the SVM signal sharper) + typedef UReg<0x03, 0x33, 0, 8> VDS_SVM_GAIN; // SVM gain control bit (This field contains the gain value of SVM data., its range is (0~16)*16) + typedef UReg<0x03, 0x34, 0, 8> VDS_SVM_OFFSET; // SVM offset control bit (This field contains the offset value of SVM data, its range is 0~255) + + typedef UReg<0x03, 0x35, 0, 8> VDS_Y_GAIN; // Y dynamic range expansion gain control bit (This field contains the Y gain value in dynamic range expansion process, its range is (0 ~ 2)*128) + typedef UReg<0x03, 0x36, 0, 8> VDS_UCOS_GAIN; // U dynamic range expansion cos gain control bit (This field contains the U gain value in dynamic range expansion process, its range is (-4 ~ 4)*32) + typedef UReg<0x03, 0x37, 0, 8> VDS_VCOS_GAIN; // V dynamic range expansion gain control bit (This field contains the V gain value in dynamic range expansion process, its range is (-4 ~ 4)*32) + typedef UReg<0x03, 0x38, 0, 8> VDS_USIN_GAIN; // U dynamic range expansion sin gain control bit (This field contains the U sin gain value in dynamic range expansion process, its range is (-4 ~ 4)*32) + typedef UReg<0x03, 0x39, 0, 8> VDS_VSIN_GAIN; // V dynamic range expansion sin gain control bit (This field contains the V sin gain value in dynamic range expansion process, its range is (-4 ~ 4)*32) + typedef UReg<0x03, 0x3A, 0, 8> VDS_Y_OFST; // Y dynamic range expansion offset control bit (This field contains the Y offset value in dynamic range expansion process, its range is –128 ~ 127) + typedef UReg<0x03, 0x3B, 0, 8> VDS_U_OFST; // U dynamic range expansion offset control bit (This field contains the U offset value in dynamic range expansion process, its range is –128 ~ 127) + typedef UReg<0x03, 0x3C, 0, 8> VDS_V_OFST; // V dynamic range expansion offset control bit (This field contains the V offset value in dynamic range expansion process., its range is –128 ~ 127) + + typedef UReg<0x03, 0x3D, 0, 9> VDS_SYNC_LEV; // Sync level bit + // This field contains the composite sync level value, this value will add on Y, + // outside the composite sync interval. If the Y out is 1V, sync is 0.3V, + // then this value is (0.3/1)*1024=307, and the output sync’s max voltage is 0.5V + // 3E_1:2 - reserved + typedef UReg<0x03, 0x3E, 3, 1> VDS_CONVT_BYPS; // YUV to RGB color space conversion bypass control, active high + // When this bit is 1, YUV data will bypass the YUV to RGB conversion, the output will still be YUV data. + // When this bit is 0, YUV data will do YUV to RGB conversion, the output will be RGB data. + typedef UReg<0x03, 0x3E, 4, 1> VDS_DYN_BYPS; // Dynamic range expansion bypass control, active high (When this bit is 1, data will bypass the dynamic range expansion process) + // 3E_5:2 - reserved + typedef UReg<0x03, 0x3E, 7, 1> VDS_BLK_BF_EN; // Blanking set up enable, active high (When this bit is 1, final composite blank (dis_hb|dis_vb) will cut the garbage data in blanking interval) + typedef UReg<0x03, 0x3F, 0, 8> VDS_UV_BLK_VAL; // UV blanking amplitude value control bit (This filed indicates the amplitude value of UV in blanking interval, the highest bit of this programmable register is sign bit) + typedef UReg<0x03, 0x40, 0, 1> VDS_1ST_INT_BYPS; // The 1st stage interpolation bypass control, active high (When this bit is 1, the 1st stage interpolation (in YUV domain) will be bypassed, Y use tap19, and UV use tap7) + typedef UReg<0x03, 0x40, 1, 1> VDS_2ND_INT_BYPS; // The 2nd stage interpolation bypass control, active high (When this bit is 1, the 2nd stage interpolation (in RGB domain) will be bypassed, all RGB use tap11) + typedef UReg<0x03, 0x40, 2, 1> VDS_IN_DREG_BYPS; // Input data bypass the negedge trigger control, active high: + // When this bit is 0, input data will triggered by falling edge clock, + // When this bit is 1, the input data will bypass this falling edge clock delay.) + // 40_3:1 - reserved + typedef UReg<0x03, 0x40, 4, 2> VDS_SVM_V4CLK_DELAY; // SVM delay be V2CLK control bit (see: DEVELOPER_NOTES.md -> S3_40) + // 40_6:2 - reserved + typedef UReg<0x03, 0x41, 0, 10> VDS_PK_LINE_BUF_SP; // Line buffer for 2D peaking write reset position control bit (This field contains the write reset position of the line buffer, this position is also the write start position of the buffer.) + // 42_2:4 - reserved + typedef UReg<0x03, 0x42, 6, 1> VDS_PK_RAM_BYPS; // Line buffer for 2D peaking one line delay data bypass, active high (When this bit is 1, data will bypass the line buffer) + // 42_7:1 - reserved + typedef UReg<0x03, 0x43, 0, 1> VDS_PK_VL_HL_SEL; // 2D peaking vertical low-pass signal select the horizontal split filter control (low-pass filter select, 1 for tap3 and 0 for tap5) + typedef UReg<0x03, 0x43, 1, 1> VDS_PK_VL_HH_SEL; // 2D peaking vertical low-pass signal select the horizontal split filter control (for high-pass filter select, 1 for tap3 and 0 for tap5) + typedef UReg<0x03, 0x43, 2, 1> VDS_PK_VH_HL_SEL; // 2D peaking vertical high-pass signal select the horizontal split filter control (high-pass filter select, 1 for tap3 and 0 for tap5) + typedef UReg<0x03, 0x43, 3, 1> VDS_PK_VH_HH_SEL; // 2D peaking vertical high-pass signal select the horizontal split filter control (low-pass filter select, 1 for tap3 and 0 for tap5) + // 43_4:4 - reserved + typedef UReg<0x03, 0x44, 0, 3> VDS_PK_LB_CORE; // 2D peaking vertical low-pass horizontal band-pass signal coring level (Vertical low-pass and horizontal band-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + typedef UReg<0x03, 0x44, 3, 5> VDS_PK_LB_CMP; // 2D peaking vertical low-pass horizontal band-pass signal threshold level (Vertical low-pass and horizontal band-pass signal larger than this coring level will remain unchanged, otherwise the gain will added on it) + typedef UReg<0x03, 0x45, 0, 6> VDS_PK_LB_GAIN; // 2D peaking vertical low-pass horizontal band-pass signal gain control (Vertical low-pass horizontal band-pass signal gain, its range is (0~4)*16) + // 45_6:2 - reserved + typedef UReg<0x03, 0x46, 0, 3> VDS_PK_LH_CORE; // 2D peaking vertical low-pass horizontal high-pass signal coring level (Vertical low-pass and horizontal high-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + typedef UReg<0x03, 0x46, 3, 5> VDS_PK_LH_CMP; // 2D peaking vertical low-pass horizontal high-pass signal threshold level (Vertical low-pass and horizontal high-pass signal larger than this coring level will remain unchanged, otherwise the gain will added on it) + typedef UReg<0x03, 0x47, 0, 6> VDS_PK_LH_GAIN; // 2D peaking vertical low-pass horizontal high-pass signal gain control (Vertical low-pass horizontal high-pass signal gain, its range is (0~4)*16) + // 47_6:2 - reserved + typedef UReg<0x03, 0x48, 0, 3> VDS_PK_HL_CORE; // 2D peaking vertical high-pass horizontal low-pass signal coring level (Vertical high-pass and horizontal low-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + typedef UReg<0x03, 0x48, 3, 5> VDS_PK_HL_CMP; // 2D peaking vertical high-pass horizontal low-pass signal threshold level (Vertical high-pass and horizontal low-pass signal larger than this coring level will remain unchanged, otherwise the gain will added on it) + typedef UReg<0x03, 0x49, 0, 6> VDS_PK_HL_GAIN; // 2D peaking vertical high-pass horizontal low-pass signal gain control (Vertical high-pass horizontal low-pass signal gain, its range is (0~4)*16) + // 49_6:2 - reserved + typedef UReg<0x03, 0x4A, 0, 3> VDS_PK_HB_CORE; // 2D peaking vertical high-pass horizontal band-pass signal coring level (Vertical high-pass and horizontal band-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + typedef UReg<0x03, 0x4A, 3, 5> VDS_PK_HB_CMP; // 2D peaking vertical high-pass horizontal band-pass signal threshold level (Vertical high-pass and horizontal band-pass signal larger than this coring level will remain unchanged, otherwise the gain will added on it) + typedef UReg<0x03, 0x4B, 0, 6> VDS_PK_HB_GAIN; // 2D peaking vertical high-pass horizontal band-pass signal gain control (Vertical high-pass horizontal band-pass signal gain, its range is (0~4)*16) + typedef UReg<0x03, 0x4C, 0, 3> VDS_PK_HH_CORE; // 2D peaking vertical high-pass horizontal high-pass signal coring level (Vertical high-pass and horizontal high-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + typedef UReg<0x03, 0x4C, 3, 5> VDS_PK_HH_CMP; // 2D peaking vertical high-pass horizontal high-pass signal threshold level (Vertical high-pass and horizontal high-pass signal larger than this coring level will remain unchanged, otherwise the gain will added on it) + typedef UReg<0x03, 0x4D, 0, 6> VDS_PK_HH_GAIN; // 2D peaking vertical high-pass horizontal high-pass signal gain control (Vertical high-pass horizontal high-pass signal gain, its range is (0~4)*16) + // 4D_6:2 - reserved + typedef UReg<0x03, 0x4E, 0, 1> VDS_PK_Y_H_BYPS; // Y horizontal peaking bypass control, active high (When this bit is 1, Y horizontal peaking will be bypassed) + typedef UReg<0x03, 0x4E, 1, 1> VDS_PK_Y_V_BYPS; // Y vertical peaking bypass control, active high (When this bit is 1, Y vertical peaking will be bypassed) + // 4E_2:1 - reserved + typedef UReg<0x03, 0x4E, 3, 1> VDS_C_VPK_BYPS; // UV vertical peaking bypass control, active high (When this bit is 1, UV vertical peaking will be bypassed) + typedef UReg<0x03, 0x4E, 4, 3> VDS_C_VPK_CORE; // UV vertical peaking coring level (UV vertical high-pass signal larger than this coring level will remain unchanged, otherwise it will be cut to 0) + // 4E_7:1 - reserved + typedef UReg<0x03, 0x4F, 0, 6> VDS_C_VPK_GAIN; // UV vertical peaking gain control bit (UV vertical high-pass signal gain control, its range is (0~4)*16) + // 4F_6:2 - reserved + typedef UReg<0x03, 0x50, 0, 4> VDS_TEST_BUS_SEL; // Test out select control bit (This register is used to select internal status bus to test bus) + typedef UReg<0x03, 0x50, 4, 1> VDS_TEST_EN; // Test enable, active high (This bit is the test bus out enable bit, when this bit is 1, the test bus can output the internal status, and otherwise, the test bus is 0Xaaaa) + typedef UReg<0x03, 0x50, 5, 1> VDS_DO_UV_DEV_BYPS; // 16-bit digital out UV decimation filter bypass control, active high (When this bit is 1, 16-bit 422 YUV digital out UV decimation will be bypassed) + typedef UReg<0x03, 0x50, 6, 1> VDS_DO_UVSEL_FLIP; // 16-bit digital out UV flip control (When this bit is 1, 16-bit 422 YUV digital out UV position will be flipped) + typedef UReg<0x03, 0x50, 7, 1> VDS_DO_16B_EN; // 16-bit digital out (422 format yuv) enable (When this bit is 1, digital out is 16-bit 422 YUV format; When it is 0, digital out is 24-bit) + + typedef UReg<0x03, 0x51, 7, 11> VDS_GLB_NOISE; // Global still detection threshold value control bit: + // This field contains the global noise threshold value. If the total difference of two + // frame less than this programmable value, the picture is taken as still, + // otherwise, the picture is taken as moving picture. + // 52_3:1 - reserved + typedef UReg<0x03, 0x52, 4, 1> VDS_NR_Y_BYPS; // Y bypass the noise reduction process control (When this bit is 1, Y data will bypass the noise reduction process) + typedef UReg<0x03, 0x52, 5, 1> VDS_NR_C_BYPS; // UV bypass the noise reduction process control (When this bit is 1, UV data will bypass the noise reduction process) + typedef UReg<0x03, 0x52, 6, 1> VDS_NR_DIF_LPF5_BYPS; // Bypass control of the tap5 low-pass filter used for Y difference between two frames (When this bit is 1, Y difference data will bypass the tap5 low-pass filter) + typedef UReg<0x03, 0x52, 7, 1> VDS_NR_MI_TH_EN; // Noise reduction threshold control enable (This bit will enable the threshold control, active high) + typedef UReg<0x03, 0x53, 0, 7> VDS_NR_MI_OFFSET; // Motion index offset control bit (The offset control for motion index generation; When ds_mig_en is 1, ds_mig_offset[3:0] is user-defined motion index) + typedef UReg<0x03, 0x53, 7, 1> VDS_NR_MIG_USER_EN; // Motion index generation user mode enable (When this bit is 1, the motion index generation will use nr_mig_offt[3:0] as Motion index) + typedef UReg<0x03, 0x54, 0, 4> VDS_NR_MI_GAIN; // Motion index generation gain control bit (Motion index generation gain control, its range is (0~8)*2) + typedef UReg<0x03, 0x54, 4, 4> VDS_NR_STILL_GAIN; // Motion index generation gain control bit for still picture (When picture is still, this field contains the motion index generation gain, its range is (0~8)*2) + typedef UReg<0x03, 0x55, 0, 4> VDS_NR_MI_THRES; // Noise reduction threshold value bit (Noise-reduction threshold value. When MI is smaller than the threshold value, the noise reduction is enabled. Otherwise it is not) + typedef UReg<0x03, 0x55, 4, 1> VDS_NR_EN_H_NOISY; // High noisy picture index enable, active high (Enable high noisy index from de-interlacer, it means the picture’s noise is very large) + // 55_5:1 - reserved + typedef UReg<0x03, 0x55, 6, 1> VDS_NR_EN_GLB_STILL; // Global still index enable, active high (This bit enables the global still signal) + typedef UReg<0x03, 0x55, 7, 1> VDS_NR_GLB_STILL_MENU; // Menu mode control for global still index (used for debug) (see: DEVELOPER_NOTES.md -> S3_55) + typedef UReg<0x03, 0x56, 0, 7> VDS_NR_NOISY_OFFSET; // Motion index generation offset control bit for high noisy picture (When the picture is high noisy picture, this field contains the offset control for motion index generation) + typedef UReg<0x03, 0x56, 7, 1> VDS_W_LEV_BYPS; // White level expansion bypass control, active high (When this bit is 1, Y don’t do white level expansion) + typedef UReg<0x03, 0x57, 0, 8> VDS_W_LEV; // White level expansion level control bit (This field defines the white level expansion threshold level value; data less than this level will have no white level expansion process) + typedef UReg<0x03, 0x58, 0, 8> VDS_WLEV_GAIN; // White level expansion gain control bit (This field defines the white level expansion threshold level value; data less than this level will have no white level expansion process) + typedef UReg<0x03, 0x59, 0, 8> VDS_NS_U_CENTER; // Non-linear saturation center position U value control bit (This field contains the non-linear saturation center position U value, the value is 2’s) + typedef UReg<0x03, 0x5A, 0, 8> VDS_NS_V_CENTER; // Non-linear saturation center position V value control bit (This field contains the non-linear saturation center position V value, the value is 2’s) + typedef UReg<0x03, 0x5B, 0, 7> VDS_NS_U_GAIN; // Non-linear saturation U gain control bit (This field contains the U gain control for U component in the area which should do non-linear saturation, its range is (0~1)*128) + typedef UReg<0x03, 0x5B, 7, 15> VDS_NS_SQUARE_RAD; // Non-linear saturation range control bit (Non-linear saturation only did When (u-u_center)^2 + (v-v_center)^2 less than this programmable range value) + typedef UReg<0x03, 0x5D, 6, 8> VDS_NS_Y_HIGH_TH; // Non-linear saturation Y high threshold control bit (This filed defines the Y high threshold value for non-linear saturation, when y detect enable (60[3]=1), if y larger than this programmable value, no non-linear did) + typedef UReg<0x03, 0x5E, 6, 7> VDS_NS_V_GAIN; // Non-linear saturation V gain control bit (This field contains the V gain control for V component in the area which should do non-linear saturation, its range is (0~1)*128) + typedef UReg<0x03, 0x5F, 5, 5> VDS_NS_Y_LOW_TH; // Non-linear saturation Y low threshold control bit (This filed defines the Y low threshold value for non-linear saturation, when y detect enable (60[3]=1), if y less than this programmable value, no non-linear did) + typedef UReg<0x03, 0x60, 2, 1> VDS_NS_BYPS; // Non-linear saturation bypass control, active high (When this bit is 1, the process non-linear saturation will be bypassed) + typedef UReg<0x03, 0x60, 3, 1> VDS_NS_Y_ACTIVE_EN; // Non-linear saturation Y detect enable, active high (When this bit is 1, the process non-linear saturation only done when the Y larger than the value ns_y_low_th and less than the value ns_y_high_th) + + typedef UReg<0x03, 0x60, 4, 10> VDS_C1_TAG_LOW_SLOPE; // Red enhance angle tan value low threshold value control bit: + // This filed contains the low threshold value for red enhance angle tan value, + // when the input UV angle tan value less than this programmable value, + // no enhancement did + typedef UReg<0x03, 0x61, 6, 10> VDS_C1_TAG_HIGH_SLOPE; // Red enhance angle tan value high threshold value control bit: + // This filed contains the high threshold value for red enhance angle tan value, + // when the input UV angle tan value larger than this programmable value, + // no enhancement did. + typedef UReg<0x03, 0x63, 0, 4> VDS_C1_GAIN; // Red enhance gain control bit (This field contains the gain control for red enhance, its range is (0~1)*16) + typedef UReg<0x03, 0x63, 4, 8> VDS_C1_U_LOW; // Red enhance U low threshold value control bit (This field contains the low threshold value for U component, if input U less then this programmable value, no enhancement did) + typedef UReg<0x03, 0x64, 4, 8> VDS_C1_U_HIGH; // Red enhance U high threshold value control bit (This field contains the high threshold value for U component, if input U larger then this programmable value, no enhancement did) + typedef UReg<0x03, 0x65, 4, 1> VDS_C1_BYPS; // Red enhance bypass control, active high (When this bit is 1, red enhancement will be bypassed) + typedef UReg<0x03, 0x65, 5, 8> VDS_C1_Y_THRESH; // Red enhance Y threshold value control bit (This field contains the Y threshold for red enhancement, when input Y larger than this programmable value, no enhancement did) + + typedef UReg<0x03, 0x66, 5, 10> VDS_C2_TAG_LOW_SLOPE; // Green enhance angle tan value low threshold value control bit: + // This filed contains the low threshold value for green enhance angle tan value, + // when the input UV angle tan value less than this programmable value, no enhancement did. + typedef UReg<0x03, 0x67, 7, 10> VDS_C2_TAG_HIGH_SLOPE; //Green enhance angle tan value high threshold value control bit: + // This filed contains the high threshold value for green enhance angle tan value, + // when the input UV angle tan value larger than this programmable value, + // no enhancement did. + typedef UReg<0x03, 0x69, 1, 4> VDS_C2_GAIN; // Color enhance gain control bit (This field contains the gain control for green enhance, its range is (0~1)*16) + typedef UReg<0x03, 0x69, 5, 8> VDS_C2_U_LOW; // Green enhance U low threshold value control bit (This field contains the low threshold value for U component, if input U less then this programmable value, no enhancement did) + typedef UReg<0x03, 0x6A, 5, 8> VDS_C2_U_HIGH; // Green enhance U high threshold value control bit (This field contains the high threshold value for U component, if input U larger then this programmable value, no enhancement did) + typedef UReg<0x03, 0x6B, 5, 1> VDS_C2_BYPS; // Green enhance bypass control (When this bit is 1, color enhancement will be bypassed) + typedef UReg<0x03, 0x6B, 6, 8> VDS_C2_Y_THRESH; // Green enhance Y threshold value control bit (This field contains the Y threshold for green enhancement, when input Y larger than this programmable value, no enhancement did) + // 6C_6:2 - reserved + typedef UReg<0x03, 0x6D, 0, 12> VDS_EXT_HB_ST; // External used horizontal blanking start position control bit (This field is used to program horizontal blanking start position, this blanking is for external used) + typedef UReg<0x03, 0x6E, 4, 12> VDS_EXT_HB_SP; // External used horizontal blanking stop position control bit (This field is used to program horizontal blanking stop position, this blanking is for external used) + typedef UReg<0x03, 0x70, 0, 11> VDS_EXT_VB_ST; // External used vertical blanking start position control bit (This field is used to program vertical blanking start position, this blanking is for external used) + // 71_3:1 - reserved + typedef UReg<0x03, 0x71, 4, 11> VDS_EXT_VB_SP; // External used vertical blanking stop position control bit (This field is used to program vertical blanking stop position, this blanking is for external used) + typedef UReg<0x03, 0x72, 7, 1> VDS_SYNC_IN_SEL; // VDS module input sync selection control (When this bit is 1, the sync to VDS module is from external (out of the CHIP); When this bit is 0, the sync to VDS module is from IF module) + + typedef UReg<0x03, 0x73, 0, 3> VDS_BLUE_RANGE; // Blue extend range control bit (see: DEVELOPER_NOTES.md -> S3_73) + typedef UReg<0x03, 0x73, 3, 1> VDS_BLUE_BYPS; // Blue extend bypass control, active high (When this bit is 1, the blue extend process will be bypassed) + typedef UReg<0x03, 0x73, 4, 4> VDS_BLUE_UGAIN; // Blue extend U gain control bit (This field defines the U gain for U component in the area which should do blue extend, its range is (0~1)*16) + typedef UReg<0x03, 0x74, 0, 4> VDS_BLUE_VGAIN; // Blue extend V gain control bit (This field defines the V gain for V component in the area which should do blue extend, its range is (0~1)*16) + typedef UReg<0x03, 0x74, 4, 4> VDS_BLUE_Y_LEV; // Blue extend Y level threshold control bit: + // This field defines the Y threshold value of blue extend, the real level in the + // circuit is 16*blue_y_th + 15, the blue extend process done + // only when Y value larger than this level (real level). + + // + // Video Processor Registers -> PIP Registers + // + typedef UReg<0x03, 0x80, 0, 1> PIP_UV_FLIP; // 422 to 444 conversion UV flip control (This bit is used to flip UV, when this bit is 1, UV position will be flipped) + typedef UReg<0x03, 0x80, 1, 1> PIP_U_DELAY; // UV 422 to 444 conversion U delay (When this bit is 1, U will delay 1 clock, otherwise, no delay for internal pipe) + typedef UReg<0x03, 0x80, 2, 1> PIP_V_DELAY; // UV 422 to 444 conversion V delay (When this bit is 1, V will delay 1 clock, otherwise, no delay for internal pipe) + typedef UReg<0x03, 0x80, 3, 1> PIP_TAP3_BYPS; // Tap3 filter in 422 to 444 conversion bypass control, active high (This bit is the UV interpolation filter enable control; when this bit is 1, UV bypass the filter) + typedef UReg<0x03, 0x80, 4, 2> PIP_Y_DELAY; // Y compensation delay control bit in 422 to 444 conversion (see: DEVELOPER_NOTES.md -> S3_80) + typedef UReg<0x03, 0x80, 6, 1> PIP_SUB_16B_SEL; // PIP 16-bit sub-picture select, active high (When this bit is 1, select 16-bit sub-picture; When it is 0, select 24-bit sub-picture) + typedef UReg<0x03, 0x80, 7, 1> PIP_DYN_BYPS; // Dynamic range expansion bypass control, active high (When this bit is 1, data will bypass the dynamic range expansion process) + typedef UReg<0x03, 0x81, 0, 1> PIP_CONVT_BYPS; // YUV to RGB color space conversion bypass control, active high: + // When this bit is 1, YUV data will bypass the YUV to RGB conversion, the output will still be YUV data. + // When this bit is 0, YUV data will do YUV to RGB conversion, the output will be RGB data + // 81_1:2 - reserved + typedef UReg<0x03, 0x81, 3, 1> PIP_DREG_BYPS; // Input data bypass the negedge trigger control, active high: + // When this bit is 0, input data will triggered by falling edge clock, + // When this bit is 1, the input data will bypass this falling edge clock delay + // 81_4:3 - reserved + typedef UReg<0x03, 0x81, 7, 1> PIP_EN; // PIP enable, active high (When this bit is 1, PIP insertion is enabled, otherwise, no PIP) + typedef UReg<0x03, 0x82, 0, 8> PIP_Y_GAIN; // Y dynamic range expansion gain control bit (This field contains the Y gain value in dynamic range expansion process, its range is (0 ~ 2)*128) + typedef UReg<0x03, 0x83, 0, 8> PIP_U_GAIN; // U dynamic range expansion gain control bit (This field contains the U gain value in dynamic range expansion process, its range is (0 ~ 4)*64) + typedef UReg<0x03, 0x84, 0, 8> PIP_V_GAIN; // V dynamic range expansion gain control bit (This field contains the V gain value in dynamic range expansion process, its range is (0 ~ 4)*64) + typedef UReg<0x03, 0x85, 0, 8> PIP_Y_OFST; // Y dynamic range expansion offset control bit (This field contains the Y offset value in dynamic range expansion process, its range is –128 ~ 127) + typedef UReg<0x03, 0x86, 0, 8> PIP_U_OFST; // U dynamic range expansion offset control bit (This field contains the U offset value in dynamic range expansion process, its range is –128 ~ 127) + typedef UReg<0x03, 0x87, 0, 8> PIP_V_OFST; // V dynamic range expansion offset control bit (This field contains the V offset value in dynamic range expansion process, its range is –128 ~ 127) + typedef UReg<0x03, 0x88, 0, 12> PIP_H_ST; // PIP window horizontal start position control bit (This field contains the horizontal start position of PIP window.) + // 89_4:4 - reserved + typedef UReg<0x03, 0x8A, 0, 12> PIP_H_SP; // PIP window horizontal stop position control bit (This field contains the horizontal stop position of PIP window) + // 8B_4:4 - reserved + typedef UReg<0x03, 0x8C, 0, 11> PIP_V_ST; // PIP window vertical start position control bit (This field contains the vertical start position of PIP window) + // 8D_3:5 - reserved + typedef UReg<0x03, 0x8E, 0, 11> PIP_V_SP; // PIP window vertical stop position control (This field contains the vertical stop position of PIP window) + // 8F_3:5 - reserved + + // + // Memory Controller Registers + // + typedef UReg<0x04, 0x00, 0, 8> SDRAM_RESET_CONTROL; // MEMORY CONTROLLER 00 + typedef UReg<0x04, 0x00, 0, 1> MEM_INI_REG_0; // SDRAM Idle Period Control and IDLE Done Select: (default 0) (see: DEVELOPER_NOTES.md -> S4_00) + typedef UReg<0x04, 0x00, 0, 1> MEM_INI_REG_1; // Software Control SDRAM Idle Period (When this bit is 1, software programming will control the idle period to access memory.this bit is useful only when the register r_mslidl[1:0] sets 2’b11) + // 00_3:1 - reserved + typedef UReg<0x04, 0x00, 4, 1> SDRAM_RESET_SIGNAL; // SDRAM Reset Signal (When this bit is 1, will generate 5-mmclk pulse, and reset memory controller timing, data pipe and state machine) + // 00_5:1 - reserved + typedef UReg<0x04, 0x00, 6, 1> MEM_INI_REG_6; // Initial Cycle Mode Select (When this bit is 1, then during initial period, the mode cycle will go before refresh cycle; otherwise refresh cycle will be before mode cycle) + typedef UReg<0x04, 0x00, 7, 1> SDRAM_START_INITIAL_CYCLE; // SDRAM Start Initial Cycle (This register should work with the register 80/[2:0]; When this bit is 1, memory controller initial cycle enable; When this bit is 0, memory controller initial cycle disable) + // TODO fine tuning memory registers + typedef UReg<0x04, 0x12, 0, 1> MEM_INTER_DLYCELL_SEL; // Select SDRAM Delay Cell (This register is control the delay of data/address/command; When it is at 0, select bypass delay cell, when it is at 1, select DLY8LV cell) + typedef UReg<0x04, 0x12, 1, 1> MEM_CLK_DLYCELL_SEL; // Select SDRAM Delay Cell (This register is only control the delay of clock send to PAD; When it is at 0, select bypass delay cell, when it is at 1, select DLY8LV cell) + typedef UReg<0x04, 0x12, 2, 1> MEM_FBK_CLK_DLYCELL_SEL; // Select SDRAM Delay Cell (This register is only control the delay of feed back clock; When it is at 0, select bypass delay cell, when it is at 1, select DLY8LV cell) + // 12_3:5 - reserved + typedef UReg<0x04, 0x13, 0, 1> MEM_PAD_CLK_INVERT; // Invert Memory Rising Edge Clock to PAD (When this bit is 1, invert memory clock and send to PAD; When this bit is 0, will bypass memory clock and send to PAD) + typedef UReg<0x04, 0x13, 1, 1> MEM_RD_DATA_CLK_INVERT; // Read memory data with Memory Clock rising or falling edge (When this bit is 1, with Memory clock falling edge; When this bit is 0, with Memory clock rising edge) + typedef UReg<0x04, 0x13, 2, 1> MEM_FBK_CLK_INVERT; // Control feedback clock register (When this bit is at 1, will invert feedback clock; When it’s at 0, will bypass feedback clock) + // 13_3:5 - reserved + // TODO fine tuning memory registers + typedef UReg<0x04, 0x15, 0, 1> MEM_REQ_PBH_RFFH; // Play back high request priority exchange with read FIFO high request (When this bit is 1, read FIFO high request > play back high request; When this bit is 0, play back high request >read FIFO high request) + typedef UReg<0x04, 0x1b, 0, 3> MEM_ADR_DLY_REG; // Capture request exchange with PlayBack low request and Read FIFO low request (When this bit is 0: play back low req > read FIFO low req > capture req; When this bit is 1: cap req > play back low req > read FIFO low req) + typedef UReg<0x04, 0x1b, 4, 3> MEM_CLK_DLY_REG; // Write FIFO request priority exchange with capture request (When this bit is 1, capture request >write FIFO request, When this bit is 0, write FIFO request > capture request) + // 15_3:5 - reserved + // TODO fine tuning memory registers + + // + // Playback / Capture / Memory Registers + // + typedef UReg<0x04, 0x20, 0, 3> CAP_CNTRL_TST; // Capture Test logic control (Bit [2:0]: select capture internal test bus) + // 20_3:2 - reserved + typedef UReg<0x04, 0x20, 5, 3> CAP_NR_STATUS_OFFSET; // Capture Noise Reduction Frame Status Offset: + // For NTSC and PAL, Noise Reduction will save 4 or 6 frame data, for + // Play back read which frame at first, set different value, + // will read different frame data firstly, default 0. + + typedef UReg<0x04, 0x21, 0, 1> CAPTURE_ENABLE; // Enable capture (When it’s set 1, capture will be turn on; When it’s set 0, capture will be turn off) + typedef UReg<0x04, 0x21, 1, 1> CAP_FF_HALF_REQ; // Request generated when capture FIFO half (When set to 1, request generated when capture FIFO half; When set to 0, request generated when capture FIFO write pointer is 1) + + typedef UReg<0x04, 0x21, 2, 1> CAP_BUF_STA_INV; // Capture double buffer status invert before output (When set to 1, double buffer status invert; When set to 0, double buffer status doesn’t change) + typedef UReg<0x04, 0x21, 3, 1> CAP_DOUBLE_BUFFER; // Enable double buffer (When set to 1, enable double buffer; When set to 0, disable double buffer) + // 21_4:1 - reserved + typedef UReg<0x04, 0x21, 5, 1> CAP_SAFE_GUARD_EN; // Enable safe guard function (When set to 1, turn on safe guard function; When set to 0, turn off safe guard function) + typedef UReg<0x04, 0x21, 6, 1> CAP_VRST_FFRST_EN; // Enable input v-sync reset FIFO (When set to 1, enable feed back v-sync reset FIFO; When set to 0, disable feed back v-sync reset FIFO) + typedef UReg<0x04, 0x21, 7, 1> CAP_ADR_ADD_2; // Enable address add by 2 (When set to 1,address added by 2 per pixel; When set to 0,added by 1 per pixel) + typedef UReg<0x04, 0x22, 0, 1> CAP_REQ_OVER; // Horizontal request end (When this bit set 1, the final capture request of one line is in the horizontal blank rising edge, set 0 capture request will free run) + typedef UReg<0x04, 0x22, 1, 1> CAP_STATUS_SEL; // Capture FIFO half status select (When set to 1, request generated when capture FIFO is half; When set to 0, request generated when capture FIFO is delm’s value) + typedef UReg<0x04, 0x22, 2, 1> CAP_LAST_POP_CTL; // Capture POP data control (When set to 1, horizontal or vertical load start address will check if there is pop; When set to 0, horizontal or vertical load start address will not check) + typedef UReg<0x04, 0x22, 3, 1> CAP_REQ_FREEZ; // Capture Request Freeze (When set to 1, capture FIFO will pause the FIFO write and read; When set to 0, capture FIFO will operate normally) + // 22_4:4 - reserved + typedef UReg<0x04, 0x23, 0, 8> CAP_FF_STATUS; // Capture FIFO status (When cap_cntrl_[17] set 1’b1, this register will be valid, this value will less than 64) + typedef UReg<0x04, 0x24, 0, 21> CAP_SAFE_GUARD_A; // Safe Guard Address For Buffer A (Safe guard address A [7:0], Mapping to 32bits width data bus field) + // 26_5:3 - reserved + typedef UReg<0x04, 0x27, 0, 21> CAP_SAFE_GUARD_B; // Safe Guard Address For Buffer B (Safe guard address B [7:0]; Mapping to 32bits width data bus field) + // 29_5:3 - reserved + typedef UReg<0x04, 0x2b, 0, 1> PB_CUT_REFRESH; // Disable refresh request generation (When set to 1, disable refresh request generation; When set to 0, enable refresh request generation) + typedef UReg<0x04, 0x2b, 1, 2> PB_REQ_SEL; // Enable playback request mode (see: DEVELOPER_NOTES.md -> S4_28) + typedef UReg<0x04, 0x2b, 3, 1> PB_BYPASS; // Enable VDS input to select playback output or de-interlace data out (When this bit is 1, select de-interlace data out to VDS; When this bit is 0, select playback output to VDS) + typedef UReg<0x04, 0x2b, 4, 1> PB_DB_FIELD_EN; // Enable double field display (When set to 1, enable double field display; When set to 0, disable double field display) + typedef UReg<0x04, 0x2b, 5, 1> PB_DB_BUFFER_EN; // Enable double buffer (When set to 1, enable double field display; When set to 0, disable double field display) + typedef UReg<0x04, 0x2b, 6, 1> PB_2FRAME_EXCHG; // Exchange playback two frames output data (When set to 1, exchange playback current frame with past frame and output; When set to 0, don’t exchange) + typedef UReg<0x04, 0x2b, 7, 1> PB_ENABLE; // Enable Playback (When it’s set 1, play back will be on work, or will not work) + typedef UReg<0x04, 0x2c, 0, 8> PB_MAST_FLAG_REG; // Master line flag (Playback FIFO policy master value: This field will define FIFO high request timing) + // 2C_6:2 - reserved + typedef UReg<0x04, 0x2d, 0, 8> PB_GENERAL_FLAG_REG; // General line flag (Playback FIFO policy general value: This field will define FIFO low request timing) + // 2D_6:2 - reserved + typedef UReg<0x04, 0x2E, 0, 1> PB_RBUF_INV; // When rate convert from up to down, capture FIFO will refer to the play back buffer status, this bit is invert play back buffer status + typedef UReg<0x04, 0x2E, 1, 1> PB_RBUF_SEL; // When rate convert from up to down, capture FIFO will refer to the play back buffer status, this bit will be set to 1. Otherwise, it will be set to 0. + // 2E_2:5 - reserved + typedef UReg<0x04, 0x2E, 7, 1> PB_DOUBLE_REFRESH_EN; // Refresh Double (When set to 1, refresh request will at the rising and falling edge of hbout. When set to 0, refresh will be only at the rising edge of hbout) + typedef UReg<0x04, 0x2F, 0, 4> PB_TST_REG; // PlayBack Test Logic (To select playback test bus, total 8 groups can be selected.) + // 2F_4:4 - reserved + typedef UReg<0x04, 0x30, 0, 4> PB_CAP_NOISE_CMD; // Capture Noise Reduction Command: + // 0: disable noise reduce function + // 1: turn on PAL mode 2 (50hz to 50hz) and storage in memory 5 frames + // 2: turn on PAL mode 3 + // 5: turn on NTSC mode 2 and storage memory 3 frames + // 6: turn on NTSC mode 3 + // 9: turn on PAL mode 2 (50hz to 50hz, 50hz to 60hz, 50hz to 100hz) and storage memory 6 frames. + // D: turn on NTSC mode 2 (60hz to 60hz, 60hz to 120hz) and storage memory 4 frames + // Note: in 50 to 100hz and 60 to 120,we must turn on [4] = 1 In playback + // 30_4:4 - reserved + typedef UReg<0x04, 0x31, 0, 21> PB_CAP_BUF_STA_ADDR_A; // Capture and Play Back Buffer A START ADDRESS (Mapping to 32bits width data bus field) + // 33_5:3 - reserved + typedef UReg<0x04, 0x34, 0, 21> PB_CAP_BUF_STA_ADDR_B; // Buffer B START address (When in double buffer mode, this is defined as capture and playback buffer B start address. Mapping to 32bits width data bus field) + + typedef UReg<0x04, 0x37, 0, 10> PB_CAP_OFFSET; // Capture and Play Back Offset (Offset [7:0] will determine next line start address, Mapping to 64bits width data bus field) + // 38_2:6 - reserved + typedef UReg<0x04, 0x39, 0, 10> PB_FETCH_NUM; // Fetch number [7:0] will determine to fetch the number of pixels from memory, Mapping to 64bits width data bus field. + // 3A_2:6 - reserved + typedef UReg<0x04, 0x3B, 0, 21> PB_CAP_BUF_STA_ADDR_C; // Capture and playback Buffer C Start Address (When in noise reduction mode, this is defined as capture and playback buffer C start address. Mapping to 32 bits width data bus field) + // 3D_5:3 - reserved + typedef UReg<0x04, 0x3E, 0, 21> PB_CAP_BUF_STA_ADDR_D; // Capture and Play Back Buffer D Start Address (When in noise reduction mode, this is defined as capture and playback buffer D start address. Mapping to 32 bits width data bus field) + // 40_5:3 - reserved + + // + // Video Processor Registers - Write & Read FIFO registers + // + // 41 - WRITE FIFO Test logic control + typedef UReg<0x04, 0x42, 0, 1> WFF_ENABLE; // Enable write FIFO (When it’s set 1, write FIFO will be turn on. When it’s set 0, write FIFO will be turn off) + typedef UReg<0x04, 0x42, 1, 1> WFF_FF_HALF_REQ; // Request generated when FIFO half (When set to 1, request generated when FIFO half; When set to 0, request generate when FIFO write pointer is 1) + typedef UReg<0x04, 0x42, 2, 1> WFF_FF_STA_INV; // Write FIFO status invert (When set to 1, write FIFO status invert; When set to 0, write FIFO status don’t change) + typedef UReg<0x04, 0x42, 3, 1> WFF_SAFE_GUARD; // Enable write FIFO safe guard (When set to 1, enable write FIFO safe guard. When set to 0, disable write FIFO safe guard.) + typedef UReg<0x04, 0x42, 4, 1> WFF_VRST_FF_RST; // Enable input V-sync reset FIFO (When set to 1, enable feedback v-sync reset FIFO. When set to 0, disable feedback v-sync reset FIFO) + typedef UReg<0x04, 0x42, 5, 1> WFF_ADR_ADD_2; // WRITE FIFO Address count select: (When it’s set to 1, address added by 2 per pixel. When it’s set to 0, address added by 1 per pixel) + typedef UReg<0x04, 0x42, 6, 1> WFF_REQ_OVER; // WRITE FIFO Horizontal Request End (When this bit set 1, the final write FIFO request of one line is in the horizontal blank rising edge, set 0 write FIFO request will free run) + typedef UReg<0x04, 0x42, 7, 1> WFF_FF_STATUS_SEL; // Write fifo half status select (When set to 1, request generated when FIFO is half; When set to 0, request generated when c FIFO is delm’s value) + typedef UReg<0x04, 0x43, 0, 8> WFF_FF_STATUS; // Write FIFO status (When wff_cntrl_[15] set 1’b1, this register will be valid, this value will less than 64) + typedef UReg<0x04, 0x44, 0, 21> WFF_SAFE_GUARD_A; // Write FIFO Buffer A Safe Guard Address (Safe guard address buffer A [7:0], Mapping to 32bits width data bus field) + // 46_5:3 - reserved + typedef UReg<0x04, 0x47, 0, 21> WFF_SAFE_GUARD_B; // Write FIFO Buffer B Safe Guard Address (Safe guard address buffer B [7:0], Mapping to 32bits width data bus field) + // 49_5:3 - reserved + typedef UReg<0x04, 0x4a, 0, 1> WFF_YUV_DEINTERLACE; // WRITE FIFO YUV DE-INTERLACE (When set 1, write FIFO will write one field YUV, set 0, will write one frame Y) + // 4A_1:3 - reserved + typedef UReg<0x04, 0x4a, 4, 1> WFF_LINE_FLIP; // WRITE FIFO LINE INVERT (When set 1, line id will be inverted; When set 0, line id will be normal) + // 4A_5:2 - reserved + typedef UReg<0x04, 0x4a, 7, 1> WFF_LAST_POP_CTL; // When set to 1, horizontal or vertical load start address will check if there is pop When set to 0, horizontal or vertical load start address will not check. + + typedef UReg<0x04, 0x4b, 0, 3> WFF_HB_DELAY; // Write FIFO H-Timing Programmable Delay: + // 4B_3:1 - reserved + typedef UReg<0x04, 0x4b, 4, 3> WFF_VB_DELAY; // Write FIFO V-Timing Programmable Delay + // 4B_7:1 - reserved + typedef UReg<0x04, 0x4d, 0, 4> RFF_NEW_PAGE; // Read buffer page select from 1 to 16 (see: DEVELOPER_NOTES.md -> S4_4D_0) + typedef UReg<0x04, 0x4d, 4, 1> RFF_ADR_ADD_2; // Enable read FIFO address add by 2: Default 0 for added by 1 (When set 1, read FIFO address will count by 2, When set 0, read FIFO address will count by 1) + typedef UReg<0x04, 0x4d, 5, 2> RFF_REQ_SEL; // Enable read FIFO request mode (see: DEVELOPER_NOTES.md -> S4_4D_5) + typedef UReg<0x04, 0x4d, 7, 1> RFF_ENABLE; // Enable Read FIFO (When set 1, read FIFO will be turned on; When set 0, read FIFO will be turned off) + typedef UReg<0x04, 0x4e, 0, 6> RFF_MASTER_FLAG; // Master line flag (Read FIFO policy master value: This field will define FIFO high request timing) + // 4E_6:2 - reserved + typedef UReg<0x04, 0x4F, 0, 6> RFF_GENERAL_FLAG; // General line flag (Read FIFO policy master value: This field will define FIFO low request timing) + // 4F_6:2 - reserved + typedef UReg<0x04, 0x50, 0, 3> RFF_TST_REG; // General Test Logic (Read FIFO test bus select) + // 50_4:1 - reserved + typedef UReg<0x04, 0x50, 5, 1> RFF_LINE_FLIP; // Line ID Invert (When set 1, line ID will be inverted; When set 0, line ID will be normal) + typedef UReg<0x04, 0x50, 6, 1> RFF_YUV_DEINTERLACE; // Read FIFO YUV De-interlace: + // When set 1, Read FIFO will read Frame 2 YUV data in line = 1, line =0, read Frame 1 YUV data. + // When set 0, Read FIFO will read Frame 2 Y data in line = 1, line =0 , read Frame 1 Y data + typedef UReg<0x04, 0x50, 7, 1> RFF_LREQ_CUT; // Read fifo low request cut enable (Cut the read FIFO low request, only output high request to memory) + typedef UReg<0x04, 0x51, 0, 21> RFF_WFF_STA_ADDR_A; // Read FIFO AND Write FIFO START Address buffer A (Mapping to 32bits width data bus field.) + // 53_5:3 - reserved + typedef UReg<0x04, 0x54, 0, 21> RFF_WFF_STA_ADDR_B; // Read FIFO AND Write FIFO START Address Buffer B (Mapping to 32bits width data bus field) + // 56_5:3 - reserved + typedef UReg<0x04, 0x57, 0, 10> RFF_WFF_OFFSET; // Read FIFO and Write FIFO offset (Offset will determine next horizontal line start address, Mapping to 64bits width data bus field.) + // 58_2:6 - reserved + typedef UReg<0x04, 0x59, 0, 10> RFF_FETCH_NUM; // Fetch number (READ FIFO USE ONLY) (This will determine to fetch the number of pixels from memory each horizontal line. Mapping to 64bits width data bus field.) + // 5A_2:6 - reserved + // 5B_0:7 - reserved + typedef UReg<0x04, 0x5B, 7, 1> MEM_FF_TOP_FF_SEL; // All FIFO Status Output Enable (When set 1, all FIFO status output, can read FIFO status through test bus; When set 0, not FIFO status output.) + + // + // OSD Registers (all registers R/W) + // + typedef UReg<0x00, 0x90, 0, 1> OSD_SW_RESET; // Software reset for module , active high (When this bit is 1, it reset osd_top module) + typedef UReg<0x00, 0x90, 1, 3> OSD_HORIZONTAL_ZOOM; // Osd horizontal zoom select (see: DEVELOPER_NOTES.md -> S0_90_1) + typedef UReg<0x00, 0x90, 4, 2> OSD_VERTICAL_ZOOM; // Osd vertical zoom select (see: DEVELOPER_NOTES.md -> S0_90_4) + typedef UReg<0x00, 0x90, 6, 1> OSD_DISP_EN; // Osd display enable, active high (When this bit is 1, osd can display on screen) + typedef UReg<0x00, 0x90, 7, 1> OSD_MENU_EN; // Osd menu display enable, active high (When this bit is 1, osd state will jump to menu display state) + typedef UReg<0x00, 0x91, 0, 4> OSD_MENU_ICON_SEL; // Osd menu icons select (see: DEVELOPER_NOTES.md -> S0_91_0) + typedef UReg<0x00, 0x91, 4, 4> OSD_MENU_MOD_SEL; // Osd icons modification select (see: DEVELOPER_NOTES.md -> S0_90_4) + typedef UReg<0x00, 0x92, 0, 3> OSD_MENU_BAR_FONT_FORCOR; // Menu font or bar foreground color (For bar and menu will not display on screen at the same time, so they are shared) + typedef UReg<0x00, 0x92, 3, 3> OSD_MENU_BAR_FONT_BGCOR; // Menu font or bar background color (For bar and menu will not display on screen at the same time, so they are shared) + typedef UReg<0x00, 0x92, 6, 3> OSD_MENU_BAR_BORD_COR; // Menu or bar border color (It is the low 2 bits of menu or bar border color, for bar and menu will not display on screen at the same time, so they are shared) + typedef UReg<0x00, 0x93, 1, 3> OSD_MENU_SEL_FORCOR; // Selected icon or bar’s icon foreground color + typedef UReg<0x00, 0x93, 4, 3> OSD_MENU_SEL_BGCOR; // Selected icon or bar’s icon background color + typedef UReg<0x00, 0x93, 7, 1> OSD_COMMAND_FINISH; // Command finished status: + // WHEN THIS BIT IS 1, IT MEANS CPU HAS FINISHED COMMAND AND HARDWARE CAN EXECUTE THE COMMAND, + // ELSE HARDWARE WILL DO LAST OPERATION. IN ORDER TO AVOID TEARING, WHEN YOU WANT TO ACCESS OSD, + // PULL THIS BIT DOWN FIRST AND PULL UP THIS BIT WHEN YOU FINISH PROGRAMMING OSD RESPONDING REGISTERS. + typedef UReg<0x00, 0x94, 0, 1> OSD_MENU_DISP_STYLE; // Menu display in row or column mode (When 1, osd menu displays in row style, else in column style) + typedef UReg<0x00, 0x94, 2, 1> OSD_YCBCR_RGB_FORMAT; // YCbCr or RGB output (Osd display in YCbCr or RGB format, when set to 1, display in YCbCr mode) + typedef UReg<0x00, 0x94, 3, 1> OSD_INT_NG_LAT; // V2clk latch osd data with negative enable (When set to 1, V2CLK clock can latch osd data with negative edge) + typedef UReg<0x00, 0x94, 4, 4> OSD_TEST_SEL; // Test logic output select: + // TEST_SEL[0], test logic output enable, when set to 1, test logic can output. + // TEST_SEL[3:1] select 8 test logics to test bus. + typedef UReg<0x00, 0x95, 0, 8> OSD_MENU_HORI_START; // Menu or bar horizontal start address (The real address is { MENU_BAR_HORZ_START [7:0], 3’h0}) + typedef UReg<0x00, 0x96, 0, 8> OSD_MENU_VER_START; // Menu or bar vertical start address (The real address is { MENU_BAR_VIRT_START [7:0], 3’h0}) + typedef UReg<0x00, 0x97, 0, 8> OSD_BAR_LENGTH; // Bar display total length (Bar display on screen’s total length, when horizontal zoom is 0.) + typedef UReg<0x00, 0x98, 0, 8> OSD_BAR_FOREGROUND_VALUE; // Bar foreground color value (The value of this register indicates the real value of icon, such as brightness’s value is 8’hf0, then this register is also programmed to 8’hf0) + + // + // ADC, SP Registers (all registers R/W) + // + typedef UReg<0x05, 0x00, 0, 8> ADC_5_00; // ADC CLK CONTROL 00 + typedef UReg<0x05, 0x00, 0, 2> ADC_CLK_PA; // Clock selection for PA_ADC: + // When = 00, PA_ADC input clock is from PLLAD’s CLKO2 + // When = 01, PA_ADC input clock is from PCLKIN + // When = 10, PA_ADC input clock is from V4CLK + // When = 11, reserved + typedef UReg<0x05, 0x00, 2, 1> ADC_CLK_PLLAD; // Clock selection for PLLAD (When = 0, PLLAD input clock is from sync processor When = 1, PLLAD input clock is from OSC) + typedef UReg<0x05, 0x00, 3, 1> ADC_CLK_ICLK2X; // ICLK2X control (When = 0, ICLK2X = ADC output clock When = 1, ICLK2X = ADC output clock / 2) + typedef UReg<0x05, 0x00, 4, 1> ADC_CLK_ICLK1X; // ICLK1X control (When = 0, ICLK1X = ICLK2X When = 1, ICLK1X = ICLK2X /2) + // 00_5:3 - reserved + typedef UReg<0x05, 0x02, 0, 1> ADC_SOGEN; // ADC SOG enable (When = 0, ADC disable SOG mode When = 1, ADC enable SOG mode) + typedef UReg<0x05, 0x02, 1, 5> ADC_SOGCTRL; // SOG control signal + typedef UReg<0x05, 0x02, 6, 2> ADC_INPUT_SEL; // ADC input selection: + // When = 00, R0/G0/B0/SOG0 as input + // When = 01, R1/G1/B1/SOG1 as input + // When = 10, R2/G2/B2 as input + // When = 11, reserved + typedef UReg<0x05, 0x03, 0, 8> ADC_5_03; // ADC CONTROL 01 + typedef UReg<0x05, 0x03, 0, 1> ADC_POWDZ; // ADC power down control (When = 0, ADC in power down mode; When = 1, ADC work normally) + typedef UReg<0x05, 0x03, 1, 1> ADC_RYSEL_R; // Clamp to ground or midscale for R ADC (When = 0, clamp to GND When = 1, clamp to midscale) + typedef UReg<0x05, 0x03, 2, 1> ADC_RYSEL_G; // Clamp to ground or midscale for G ADC (When = 0, clamp to GND When = 1, clamp to midscale) + typedef UReg<0x05, 0x03, 3, 1> ADC_RYSEL_B; // Clamp to ground or midscale for B ADC (When = 0, clamp to GND When = 1, clamp to midscale) + typedef UReg<0x05, 0x03, 4, 2> ADC_FLTR; // ADC internal filter control (When = 00, 150MHz; When = 01, 110MHz; When = 10, 70MHz; When = 11, 40MHz) + // 03_6:2 - reserved + typedef UReg<0x05, 0x04, 0, 8> ADC_TEST_04; // ADC CONTROL 02 + typedef UReg<0x05, 0x04, 0, 2> ADC_TR_RSEL; // REF test resistor selection + typedef UReg<0x05, 0x04, 2, 3> ADC_TR_ISEL; // REF test currents selection + // 04_5:3 - reserved + typedef UReg<0x05, 0x05, 0, 8> ADC_TA_05_CTRL; // ADC CONTROL 03 + typedef UReg<0x05, 0x05, 0, 1> ADC_TA_05_EN; // ADC test enable (When = 0, ADC work normally; When = 1, ADC is in test mode) + typedef UReg<0x05, 0x05, 1, 4> ADC_TA_CTRL; // ADC test bus control bit + // 05_5:3 - reserved + typedef UReg<0x05, 0x06, 0, 7> ADC_ROFCTRL; // Offset control for R channel of ADC + // 06_7:1 - reserved + typedef UReg<0x05, 0x07, 0, 7> ADC_GOFCTRL; // Offset control for G channel of ADC + // 07_7:1 - reserved + typedef UReg<0x05, 0x08, 0, 7> ADC_BOFCTRL; // Offset control for B channel of ADC + // 08_7:1 - reserved + typedef UReg<0x05, 0x09, 0, 8> ADC_RGCTRL; // Gain control for R channel of ADC + typedef UReg<0x05, 0x0A, 0, 8> ADC_GGCTRL; // Gain control for G channel of ADC + typedef UReg<0x05, 0x0B, 0, 8> ADC_BGCTRL; // Gain control for B channel of ADC + typedef UReg<0x05, 0x0C, 0, 8> ADC_TEST_0C; // ADC CONTROL 10 + typedef UReg<0x05, 0x0C, 0, 1> ADC_CKBS; // ADC output clock invert control (When = 0, default; When = 1, ADC output clock will be invert) + typedef UReg<0x05, 0x0C, 1, 4> ADC_TEST; // For ADC test reserved + // 0C_5:3 - reserved + typedef UReg<0x05, 0x0E, 0, 1> ADC_AUTO_OFST_EN; // Auto offset adjustment enable (When = 0, auto offset adjustment disable; When = 1, auto offset adjustment enable) + typedef UReg<0x05, 0x0E, 1, 1> ADC_AUTO_OFST_PRD; // Offset adjustment by frame (When = 0, offset adjustment by frame; When = 1, offset adjustment by line) + typedef UReg<0x05, 0x0E, 2, 2> ADC_AUTO_OFST_DELAY; // Horizontal sample delay control: + // When = 00, offset adjustment horizontal sample delay 1 pipe + // When = 01, offset adjustment horizontal sample delay 2 pipe + // When = 10, offset adjustment horizontal sample delay 3 pipe + // When = 11, offset adjustment horizontal sample delay 4 pipe + typedef UReg<0x05, 0x0E, 4, 2> ADC_AUTO_OFST_STEP; // Offset adjustment step control: + // When = 00, offset adjustment by absolute difference + // When = 01, offset adjustment by 1 + // When = 10, offset adjustment by 2 + // When = 11, offset adjustment by 3 + // 0E_6:1 - reserved + typedef UReg<0x05, 0x0E, 7, 1> ADC_AUTO_OFST_TEST; // Auto offset adjustment test control + typedef UReg<0x05, 0x0F, 0, 4> ADC_AUTO_OFST_U_RANGE; // U channel offset detection range (Define U channel offset detection range 0~15) + typedef UReg<0x05, 0x0F, 4, 4> ADC_AUTO_OFST_V_RANGE; // V channel offset detection range (Define V channel offset detection range 0~15) + typedef UReg<0x05, 0x11, 0, 8> PLLAD_CONTROL_00_5x11; // PLLAD CONTROL 00 + typedef UReg<0x05, 0x11, 0, 1> PLLAD_VCORST; // Initial VCO control voltage + typedef UReg<0x05, 0x11, 1, 1> PLLAD_LEN; // Enable signal for clock + typedef UReg<0x05, 0x11, 2, 1> PLLAD_TEST; // Test clock selection + typedef UReg<0x05, 0x11, 3, 1> PLLAD_TS; // Test clock selection and HSL clock selection + typedef UReg<0x05, 0x11, 4, 1> PLLAD_PDZ; // PDZ (When = 0, PLLAD is power down mode; When = 1, PLLAD work normally) + typedef UReg<0x05, 0x11, 5, 1> PLLAD_FS; // FS, VCO gain selection (When = 0, default; When = 1, high gain selected) + typedef UReg<0x05, 0x11, 6, 1> PLLAD_BPS; // BPS (When = 0, default; When = 1, bypass input clock to CKO1 and CKO2) + typedef UReg<0x05, 0x11, 7, 1> PLLAD_LAT; // Latch control for PLLAD control - This bit’s rising edge is used to trigger PLLAD control bit: ND, MD, KS, CKOS, ICP + typedef UReg<0x05, 0x12, 0, 12> PLLAD_MD; // PLLAD feedback divider control + // 13_4:4 - reserved + typedef UReg<0x05, 0x14, 0, 12> PLLAD_ND; // PLLAD input divider control + // 15_4:4 - reserved + typedef UReg<0x05, 0x16, 0, 8> PLLAD_5_16; // PLLAD CONTROL 05 + typedef UReg<0x05, 0x16, 0, 2> PLLAD_R; // Skew control for testing + typedef UReg<0x05, 0x16, 2, 2> PLLAD_S; // Skew control for testing + typedef UReg<0x05, 0x16, 4, 2> PLLAD_KS; // VCO post divider control, it is determined by CKO frequency: + // When = 00, divide by 1 (162MHz~80MHz) + // When = 01, divide by 2 (80MHz~40MHz) + // When = 10, divide by 4 (40MHz~20MHz) + // When = 11, divide by 8 (20MHz~min MHz) + typedef UReg<0x05, 0x16, 6, 2> PLLAD_CKOS; // PLLAD CKO2 output clock selection (see: DEVELOPER_NOTES.md -> S5_16) + typedef UReg<0x05, 0x17, 0, 3> PLLAD_ICP; // ICP - Charge pump current selection: + // When = 000, Icp = 50uA + // When = 001, Icp = 100uA + // When = 010, Icp = 150uA + // When = 011, Icp = 250uA + // When = 100, Icp = 350uA + // When = 101, Icp = 500uA + // When = 110, Icp = 750uA + // When = 111, Icp = 1mA + // 17_3:5 - reserved + typedef UReg<0x05, 0x18, 0, 1> PA_ADC_BYPSZ; // BYPSZ, PA for ADC bypass control (When = 0, PA_ADC is bypass When = 1, PA_ADC work normally) + typedef UReg<0x05, 0x18, 1, 5> PA_ADC_S; // PA_ADC phase control + typedef UReg<0x05, 0x18, 6, 1> PA_ADC_LOCKOFF; // LOCKOFF (When = 0, default; When = 1, PA_ADC lock circuit disable) + typedef UReg<0x05, 0x18, 7, 1> PA_ADC_LAT; // PA_ADC latch signal (This bit’s rising edge is used to trigger PA_ADC_CNTRL) + typedef UReg<0x05, 0x19, 0, 1> PA_SP_BYPSZ; // BYPSZ, PA for PLLAD bypass control (When = 0, PA_PLLAD is bypass; When = 1, PA_PLLAD work normally) + typedef UReg<0x05, 0x19, 1, 5> PA_SP_S; // PA_PLLAD phase control + typedef UReg<0x05, 0x19, 6, 1> PA_SP_LOCKOFF; // LOCKOFF (When = 0, default; When = 1, PA_PLLAD lock circuit disable) + typedef UReg<0x05, 0x19, 7, 1> PA_SP_LAT; // PA_PLLAD latch signal (This bit’s rising edge is used to trigger PA_PLLAD_CNTRL) + // 20 - 1D - not described + // 1E_0:7 - reserved + typedef UReg<0x05, 0x1E, 7, 1> DEC_WEN_MODE; // Write enable mode enable (When this bit is 1, then decimator will drop data by write enable signal generated by horizontal sync, else write enable is not used.) + typedef UReg<0x05, 0x1F, 0, 8> DEC_REG_01; // DEC_REG_01 + typedef UReg<0x05, 0x1F, 0, 1> DEC1_BYPS; // The 4x to 2x decimator bypass enable (When 1, the 4x to 2x decimator bypass.) + typedef UReg<0x05, 0x1F, 1, 1> DEC2_BYPS; // The 2x to 1x decimator bypass enable (When 1, the 2x to 1x decimator hypass) + typedef UReg<0x05, 0x1F, 2, 1> DEC_MATRIX_BYPS; // Color space convert bypass enable (When set to 1, color space convert module bypass.) + typedef UReg<0x05, 0x1F, 3, 1> DEC_TEST_ENABLE; // Test logic output select (test logic output enable, when set to 1, test logic can output.) + typedef UReg<0x05, 0x1F, 4, 3> DEC_TEST_SEL; // Test logic output select (select 8 test logics to test bus) + typedef UReg<0x05, 0x1F, 7, 1> DEC_IDREG_EN; // Negative clock edge latch input hsync and vsync enable (When set to 1, decimator 4x clock will latch HSYNC and VSYNC with falling edge) + + // + // Sync Proc (all registers R/W) + // + typedef UReg<0x05, 0x20, 0, 1> SP_SOG_SRC_SEL; // SOG signal source select (0: from ADC; 1: select hs as sog source) + typedef UReg<0x05, 0x20, 1, 1> SP_SOG_P_ATO; // SOG auto correct polarity + typedef UReg<0x05, 0x20, 2, 1> SP_SOG_P_INV; // Invert sog. + typedef UReg<0x05, 0x20, 3, 1> SP_EXT_SYNC_SEL; // Ext 2 set Hs_Hs select + typedef UReg<0x05, 0x20, 4, 1> SP_JITTER_SYNC; // Sync using both rising and falling trigger (Use falling and rising edge to sync input Hsync) + // 20_5:3 - reserved + typedef UReg<0x05, 0x21, 0, 16> SP_SYNC_TGL_THD; // h active detect control (Sync toggle times threshold) + // 23_0:8 - reserved + typedef UReg<0x05, 0x24, 0, 12> SP_T_DLT_REG; // H active detect control (H total width different threshold) + // 25:4:4 - reserved + typedef UReg<0x05, 0x26, 0, 12> SP_SYNC_PD_THD; // H active detect control (H sync pulse width threshold) + // 27_4:4 - reserved + typedef UReg<0x05, 0x2A, 0, 8> SP_PRD_EQ_THD; // H active detect control (How many continue legal line as valid) + // 2B - 2C - not described + typedef UReg<0x05, 0x2D, 0, 8> SP_VSYNC_TGL_THD; // V active detect control (V sync toggle times threshold) + typedef UReg<0x05, 0x2E, 0, 8> SP_SYNC_WIDTH_DTHD; // V active detect control (V sync pulse width threshod) + typedef UReg<0x05, 0x2F, 0, 8> SP_V_PRD_EQ_THD; // V active detect control (How many continue legal v sync as valid) + typedef UReg<0x05, 0x31, 0, 8> SP_VT_DLT_REG; // V active detect control (V total different threshold) + typedef UReg<0x05, 0x32, 0, 1> SP_VSIN_INV_REG; // V active detect control (Input v sync invert to v active detect) + // 32_1:7 - reserved + typedef UReg<0x05, 0x33, 0, 8> SP_H_TIMER_VAL; // Timer value control (H timer value for h detect) + typedef UReg<0x05, 0x34, 0, 8> SP_V_TIMER_VAL; // Timer value control (V timer for V detect) + typedef UReg<0x05, 0x35, 0, 12> SP_DLT_REG; // Sync separation control (MSB for sync pulse width difference compare value) + // 36_4:4 - reserved + typedef UReg<0x05, 0x37, 0, 8> SP_H_PULSE_IGNOR; // Sync separation control (H pulse less than this value will be ignore this counter is start when sync large different) + typedef UReg<0x05, 0x38, 0, 8> SP_PRE_COAST; // Sync separation control (Set the coast will valid before vertical sync (line number)) + typedef UReg<0x05, 0x39, 0, 8> SP_POST_COAST; // Sync separation control (When line cnt reach this value coast goes down) + typedef UReg<0x05, 0x3A, 0, 8> SP_H_TOTAL_EQ_THD; // Sync separation control (How many regular line regard it as legal) + typedef UReg<0x05, 0x3B, 0, 3> SP_SDCS_VSST_REG_H; // Sync separation control (High bit of SD vs. start position) + // 3B_3:1 - reserved + typedef UReg<0x05, 0x3B, 4, 3> SP_SDCS_VSSP_REG_H; // Sync separation control (High bit of SD vs. stop position) + // 3B_7:1 - reserved + typedef UReg<0x05, 0x3E, 0, 8> SP_CS_0x3E; // SYNC_PROC 23 + typedef UReg<0x05, 0x3E, 0, 1> SP_CS_P_SWAP; // Sync separation control (cs_p_swap cs edge reference select default rising edge) + typedef UReg<0x05, 0x3E, 1, 1> SP_HD_MODE; // hd_mode 1: HD mode 0: SD mode + typedef UReg<0x05, 0x3E, 2, 1> SP_H_COAST; // h_coast 1: with sub coast out + typedef UReg<0x05, 0x3E, 3, 1> SP_CS_INV_REG; // cs_inv_reg cs input invert + typedef UReg<0x05, 0x3E, 4, 1> SP_H_PROTECT; // H count overflow protect + typedef UReg<0x05, 0x3E, 5, 1> SP_DIS_SUB_COAST; // Disable sub coast + // 3E_6:2 - reserved + typedef UReg<0x05, 0x3F, 0, 8> SP_SDCS_VSST_REG_L; // Sync separation control (SD vs. start position) + typedef UReg<0x05, 0x40, 0, 8> SP_SDCS_VSSP_REG_L; // Sync separation control (SD vs. stop position) + typedef UReg<0x05, 0x41, 0, 12> SP_CS_CLP_ST; // Sync separation control (SOG clamp start position MSB...LSB) + // 42_4:4 - reserved + typedef UReg<0x05, 0x43, 0, 12> SP_CS_CLP_SP; // Sync separation control (SOG clamp stop position MSB...LSB) + // 42_4:4 - reserved + typedef UReg<0x05, 0x45, 0, 12> SP_CS_HS_ST; // Sync separation control (If the horizontal period number is equal to the defined value, in XGA modes, It’s XGA 75Hz mode) + // 46_4:4 - reserved + typedef UReg<0x05, 0x47, 0, 12> SP_CS_HS_SP; // Sync separation control (SOG hs stop position) + // 48_4:4 - reserved + typedef UReg<0x05, 0x49, 0, 12> SP_RT_HS_ST; // Retiming control (Retiming hs start position) + // 4A_4:4 - reserved + typedef UReg<0x05, 0x4B, 0, 12> SP_RT_HS_SP; // Retiming control (Retiming hs stop postion) + // 4C_4:4 - reserved + typedef UReg<0x05, 0x4D, 0, 12> SP_H_CST_ST; // Retiming control (H coast start position (total-this value)) + // 4E_4:4 - reserved + typedef UReg<0x05, 0x4F, 0, 12> SP_H_CST_SP; // Retiming control (H coast stop position) + // 50_4:4 - reserved + typedef UReg<0x05, 0x51, 0, 12> SP_RT_VS_ST; // Retiming control (Retiming vs start position) + // 52_4:4 - reserved + typedef UReg<0x05, 0x53, 0, 12> SP_RT_VS_SP; // Retiming control (Retiming vs stop position) + // 54_4:4 - reserved + typedef UReg<0x05, 0x55, 0, 2> SP_HS_EP_DLY_SEL; // Retiming control (Hs pulse delay sel for ( sync with vs )) + typedef UReg<0x05, 0x55, 3, 1> SP_HS_INV_REG; // Retiming control (hs_inv_reg inver hs to retimming module + typedef UReg<0x05, 0x55, 4, 1> SP_HS_POL_ATO; // Retiming control (hs auto correct in retiming module) + typedef UReg<0x05, 0x55, 5, 1> SP_VS_INV_REG; // Retiming control (vs inv_reg invert hs to retiming module) + typedef UReg<0x05, 0x55, 6, 1> SP_VS_POL_ATO; // Retiming control (vs auto correct in retiming module) + typedef UReg<0x05, 0x55, 7, 1> SP_HCST_AUTO_EN; // Retiming control (If enable h coast will start at ( V total - hcst_st)) + typedef UReg<0x05, 0x56, 0, 8> SP_5_56; // SYNC_PROC 48 + typedef UReg<0x05, 0x56, 0, 1> SP_SOG_MODE; // Out control (1: SOG mode; 0: normal mode) + typedef UReg<0x05, 0x56, 1, 1> SP_HS2PLL_INV_REG; // Out control (When =1, HS to PLL invert) + typedef UReg<0x05, 0x56, 2, 1> SP_CLAMP_MANUAL; // Out control (1: clamp turn on off by control by software (default) 0: for test) + typedef UReg<0x05, 0x56, 3, 1> SP_CLP_SRC_SEL; // Out control (Clamp source select - 1: pixel clock generate; 0: 27Mhz clock generate) + typedef UReg<0x05, 0x56, 4, 1> SP_SYNC_BYPS; // Out control (External sync bypass to decimator) + typedef UReg<0x05, 0x56, 5, 1> SP_HS_PROC_INV_REG; // Out control (HS to decimator invert) + typedef UReg<0x05, 0x56, 6, 1> SP_VS_PROC_INV_REG; // Out control (VS to decimator invert) + typedef UReg<0x05, 0x56, 7, 1> SP_CLAMP_INV_REG; // Out control (Clamp to ADC invert) + typedef UReg<0x05, 0x57, 0, 8> SP_5_57; // SYNC_PROC 49 + typedef UReg<0x05, 0x57, 0, 1> SP_NO_CLAMP_REG; // Out control (Clamp always be 0) + typedef UReg<0x05, 0x57, 1, 1> SP_COAST_INV_REG; // Out control (Coast invert) + typedef UReg<0x05, 0x57, 2, 1> SP_NO_COAST_REG; // Out control (Coast always be REG S5_57[3]) + typedef UReg<0x05, 0x57, 3, 1> SP_COAST_VALUE_REG; // Out control (Coast use 1x clk generate) + // 57_4:2 - reserved + typedef UReg<0x05, 0x57, 6, 1> SP_HS_LOOP_SEL; // Out control (Bypass PLL HS to 57 core) + typedef UReg<0x05, 0x57, 7, 1> SP_HS_REG; // Out control (When sub_coast enable will select this value) + typedef UReg<0x05, 0x58, 0, 12> SP_HT_DIFF_REG; // Auto clamp control (H total difference less this value as valid for auto clamp enable control) + // 59_4:4 - reserved + typedef UReg<0x05, 0x5A, 0, 12> SP_VT_DIFF_REG; // Auto clamp control (V total difference less this value as valid for auto clamp enable control) + // 5B_4:4 - reserved + typedef UReg<0x05, 0x5C, 0, 8> SP_STBLE_CNT_REG; // Auto clamp control (Stable indicate frame threshold for auto clamp enable control) + // 5D - 62 - not described + // typedef UReg<0x05, 0x60, 0, 8> ADC_UNUSED_60; + // typedef UReg<0x05, 0x61, 0, 8> ADC_UNUSED_61; + // typedef UReg<0x05, 0x62, 0, 8> ADC_UNUSED_62; + typedef UReg<0x05, 0x63, 0, 8> TEST_BUS_SP_SEL; // SYNC_PROC 55 + typedef UReg<0x05, 0x63, 0, 1> SP_TEST_EN; // Test bus enable + typedef UReg<0x05, 0x63, 1, 3> SP_TEST_MODULE; // test module select: + // # 0 none + // # 1 hs_pol_det module + // # 2 hs_act_det module + // # 3 vs_pol_det module + // # 4 vs_act_det module + // # 5 cs_sep module + // # 6 retiming module + // # 7 out proc module + typedef UReg<0x05, 0x63, 4, 2> SP_TEST_SIGNAL_SEL; // Test signal select + // 63_7:1 - reserved + // + // there is no more registers ahead... + // + // typedef UReg<0x05, 0x64, 0, 8> ADC_UNUSED_64; + // typedef UReg<0x05, 0x65, 0, 8> ADC_UNUSED_65; + // typedef UReg<0x05, 0x66, 0, 8> ADC_UNUSED_66; + // typedef UReg<0x05, 0x67, 0, 16> ADC_UNUSED_67; // + ADC_UNUSED_68; + // typedef UReg<0x05, 0x69, 0, 8> ADC_UNUSED_69; + + typedef UReg<0x05, 0xD0, 0, 32> VERYWIDEDUMMYREG; + + static const uint8_t OSD_ZOOM_1X = 0; + static const uint8_t OSD_ZOOM_2X = 1; + static const uint8_t OSD_ZOOM_3X = 2; + static const uint8_t OSD_ZOOM_4X = 3; + static const uint8_t OSD_ZOOM_5X = 4; + static const uint8_t OSD_ZOOM_6X = 5; + static const uint8_t OSD_ZOOM_7X = 6; + static const uint8_t OSD_ZOOM_8X = 7; + + static const uint8_t OSD_MENU_DISP_STYLE_VERTICAL = 0; + static const uint8_t OSD_MENU_DISP_STYLE_HORIZONTAL = 1; + + static const uint8_t OSD_ICON_NONE = 0; + static const uint8_t OSD_ICON_BRIGHTNESS = 1; + static const uint8_t OSD_ICON_CONTRAST = 2; + static const uint8_t OSD_ICON_HUE = 3; + static const uint8_t OSD_ICON_SOUND = 4; + static const uint8_t OSD_ICON_UP_DOWN = 8; + static const uint8_t OSD_ICON_LEFT_RIGHT = 9; + static const uint8_t OSD_ICON_VERTICAL_SIZE = 10; + static const uint8_t OSD_ICON_HORIZONTAL_SIZE = 11; + static const uint8_t OSD_ICON_COUNT = 8; + + static inline uint8_t osdIcon(uint8_t index) + { + static const uint8_t osdIcons[8] = { + OSD_ICON_BRIGHTNESS, + OSD_ICON_CONTRAST, + OSD_ICON_HUE, + OSD_ICON_SOUND, + OSD_ICON_UP_DOWN, + OSD_ICON_LEFT_RIGHT, + OSD_ICON_VERTICAL_SIZE, + OSD_ICON_HORIZONTAL_SIZE, + }; + return osdIcons[index]; + } + + static const uint8_t OSD_COLOR_BLACK = 0; + static const uint8_t OSD_COLOR_BLUE = 1; + static const uint8_t OSD_COLOR_GREEN = 2; + static const uint8_t OSD_COLOR_CYAN = 3; + static const uint8_t OSD_COLOR_RED = 4; + static const uint8_t OSD_COLOR_MAGENTA = 5; + static const uint8_t OSD_COLOR_YELLOW = 6; + static const uint8_t OSD_COLOR_WHITE = 7; + + static const uint8_t OSD_FORMAT_YCBCR = 1; + static const uint8_t OSD_FORMAT_RGB = 0; +}; + +typedef TV5725 GBS; + +#endif diff --git a/tw.h b/src/tw.h similarity index 97% rename from tw.h rename to src/tw.h index 2d0340a2..63426f09 100644 --- a/tw.h +++ b/src/tw.h @@ -75,22 +75,22 @@ namespace tw } #if 0 - Serial.print("READ "); Serial.print(addr, HEX); Serial.print("@"); Serial.print(reg, HEX); Serial.print(": "); + _WS(F("READ ")); _WSF("%04X", addr); _WS(F("@")); _WSF("%04X", reg); _WS(F(": ")); for (uint8_t i = 0; i < size; ++i) { - Serial.print(output[i] >> 4, HEX); Serial.print(output[i] & 0xF, HEX); + _WS(output[i] >> 4, HEX); _WS(output[i] & 0xF, HEX); } - Serial.println(); + _WSN(); #endif } inline void rawWrite(uint8_t addr, uint8_t reg, uint8_t const *input, uint8_t size) { #if 0 - Serial.print("WRITE "); Serial.print(addr, HEX); Serial.print("@"); Serial.print(reg, HEX); Serial.print(": "); + _WS(F("WRITE ")); _WSF("%04X", addr); _WS(F("@")); _WSF("%04X", reg); _WS(F(": ")); for (uint8_t i = 0; i < size; ++i) { - Serial.print(input[i] >> 4, HEX); Serial.print(input[i] & 0xF, HEX); + _WS(input[i] >> 4, HEX); _WS(input[i] & 0xF, HEX); } - Serial.println(); + _WSN(); #endif Wire.beginTransmission(addr); Wire.write(reg); diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 00000000..ed0f271a --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,998 @@ +/* +##################################################################################### +# File: utils.cpp # +# File Created: Thursday, 2nd May 2024 5:37:47 pm # +# Author: # +# Last Modified: Tuesday, 25th June 2024 1:01:10 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ +#include "utils.h" + +// GBS segment for direct access +static uint8_t lastSegment = 0xFF; + +/** + * @brief a simple getter to prevent parameters from spreading in code + * + * @return true if it is Passthrough / Bypass mode + * @return false + */ +bool utilsIsPassThroughMode() { + return (rto.outModeHdBypass == OutputHdBypass || rto.outModeHdBypass == OutputRGBHVBypass); +} + +/** + * @brief a simple getter to prevent parameters from spreading in code + * + * @return true if it is NOT a Passthrough / Bypass mode + * @return false + */ +bool utilsNotPassThroughMode() { + return (rto.outModeHdBypass != OutputHdBypass && rto.outModeHdBypass != OutputRGBHVBypass); +} + +/** + * @brief a simple getter to prevent parameters from + * spreading in code (15kHz/Downscale mode) + * + * @return true + * @return false + */ +bool utilsIsDownscaleMode() { + return (uopt.resolutionID == Output15kHz || uopt.resolutionID == Output15kHzPAL); +} + +/** + * @brief a simple getter to prevent parameters from spreading in code + * + * @return true + * @return false + */ +bool utilsNotDownscaleMode() { + return (uopt.resolutionID != Output15kHz && uopt.resolutionID != Output15kHzPAL); +} + +/** + * @brief + * + */ +void latchPLLAD() +{ + GBS::PLLAD_LAT::write(0); + // delayMicroseconds(128); + delay(100); + GBS::PLLAD_LAT::write(1); +} + +/** + * @brief + * + */ +void resetPLLAD() +{ + GBS::PLLAD_VCORST::write(1); + GBS::PLLAD_PDZ::write(1); // in case it was off + latchPLLAD(); + GBS::PLLAD_VCORST::write(0); + delay(1); + latchPLLAD(); + rto.clampPositionIsSet = 0; // test, but should be good + rto.continousStableCounter = 1; +} + +/** + * @brief + * + */ +void resetPLL() +{ + GBS::PLL_VCORST::write(1); + delay(1); + GBS::PLL_VCORST::write(0); + delay(1); + rto.clampPositionIsSet = 0; // test, but should be good + rto.continousStableCounter = 1; +} + +/** + * @brief + * + */ +void ResetSDRAM() +{ + // GBS::SDRAM_RESET_CONTROL::write(0x87); // enable "Software Control SDRAM Idle Period" and "SDRAM_START_INITIAL_CYCLE" + // GBS::SDRAM_RESET_SIGNAL::write(1); + // GBS::SDRAM_RESET_SIGNAL::write(0); + // GBS::SDRAM_START_INITIAL_CYCLE::write(0); + GBS::SDRAM_RESET_CONTROL::write(0x02); + GBS::SDRAM_RESET_SIGNAL::write(1); + GBS::SDRAM_RESET_SIGNAL::write(0); + GBS::SDRAM_RESET_CONTROL::write(0x82); +} + +/** + * @brief Set the Cs Vs Start object + * + * @param start + */ +void setCsVsStart(uint16_t start) +{ + GBS::SP_SDCS_VSST_REG_H::write(start >> 8); + GBS::SP_SDCS_VSST_REG_L::write(start & 0xff); +} + +/** + * @brief Set the Cs Vs Stop object + * + * @param stop + */ +void setCsVsStop(uint16_t stop) +{ + GBS::SP_SDCS_VSSP_REG_H::write(stop >> 8); + GBS::SP_SDCS_VSSP_REG_L::write(stop & 0xff); +} + +/** + * @brief + * + */ +void freezeVideo() +{ + // GBS::IF_VB_ST::write(GBS::IF_VB_SP::read()); + GBS::CAPTURE_ENABLE::write(0); + rto.videoIsFrozen = true; +} + +/** + * @brief + * + */ +void unfreezeVideo() +{ + // GBS::IF_VB_ST::write(GBS::IF_VB_SP::read() - 2); + GBS::CAPTURE_ENABLE::write(1); + rto.videoIsFrozen = false; +} + +/** + * @brief soft reset cycle + * This restarts all chip units, which is sometimes required + * when important config bits are changed. + */ +void resetDigital() +{ + bool keepBypassActive = 0; + if (GBS::SFTRST_HDBYPS_RSTZ::read() == 1) { // if HDBypass enabled + keepBypassActive = 1; + } + + // GBS::RESET_CONTROL_0x47::write(0x00); + GBS::RESET_CONTROL_0x47::write(0x17); // new, keep 0,1,2,4 on (DEC,MODE,SYNC,INT) //MODE okay? + + // if (rto.outModeHdBypass) { // if currently in bypass + if (utilsIsPassThroughMode()) { // if currently in bypass + GBS::RESET_CONTROL_0x46::write(0x00); + GBS::RESET_CONTROL_0x47::write(0x1F); + return; // 0x46 stays all 0 + } + + GBS::RESET_CONTROL_0x46::write(0x41); // keep VDS (6) + IF (0) enabled, reset rest + if (keepBypassActive == 1) { // if HDBypass enabled + GBS::RESET_CONTROL_0x47::write(0x1F); + } + // else { + // GBS::RESET_CONTROL_0x47::write(0x17); + // } + GBS::RESET_CONTROL_0x46::write(0x7f); +} + +/** + * @brief + * + */ +void resetDebugPort() +{ + GBS::PAD_BOUT_EN::write(1); // output to pad enabled + GBS::IF_TEST_EN::write(1); + GBS::IF_TEST_SEL::write(3); // IF vertical period signal + GBS::TEST_BUS_SEL::write(0xa); // test bus to SP + GBS::TEST_BUS_EN::write(1); + GBS::TEST_BUS_SP_SEL::write(0x0f); // SP test signal select (vsync in, after SOG separation) + GBS::MEM_FF_TOP_FF_SEL::write(1); // g0g13/14 shows FIFO stats (capture, rff, wff, etc) + // SP test bus enable bit is included in TEST_BUS_SP_SEL + GBS::VDS_TEST_EN::write(1); // VDS test enable +} + +/** + * @brief Returns videoMode ID, idntified by TV chip + * + * @return uint8_t + */ +uint8_t getVideoMode() +{ + uint8_t detectedMode = 0; + + if (rto.videoStandardInput >= 14) { // check RGBHV first // not mode 13 here, else mode 13 can't reliably exit + detectedMode = GBS::STATUS_16::read(); + if ((detectedMode & 0x0a) > 0) { // bit 1 or 3 active? + return rto.videoStandardInput; // still RGBHV bypass, 14 or 15 + } else { + return 0; + } + } + + detectedMode = GBS::STATUS_00::read(); + + // note: if stat0 == 0x07, it's supposedly stable. if we then can't find a mode, it must be an MD problem + if ((detectedMode & 0x07) == 0x07) { + if ((detectedMode & 0x80) == 0x80) { // bit 7: SD flag (480i, 480P, 576i, 576P) + if ((detectedMode & 0x08) == 0x08) + return 1; // ntsc interlace + if ((detectedMode & 0x20) == 0x20) + return 2; // pal interlace + if ((detectedMode & 0x10) == 0x10) + return 3; // edtv 60 progressive + if ((detectedMode & 0x40) == 0x40) + return 4; // edtv 50 progressive + } + + detectedMode = GBS::STATUS_03::read(); + if ((detectedMode & 0x10) == 0x10) { + return 5; + } // hdtv 720p + + if (rto.videoStandardInput == 4) { + detectedMode = GBS::STATUS_04::read(); + if ((detectedMode & 0xFF) == 0x80) { + return 4; // still edtv 50 progressive + } + } + } + + detectedMode = GBS::STATUS_04::read(); + if ((detectedMode & 0x20) == 0x20) { // hd mode on + if ((detectedMode & 0x61) == 0x61) { + // hdtv 1080i // 576p mode tends to get misdetected as this, even with all the checks + // real 1080i (PS2): h:199 v:1124 + // misdetected 576p (PS2): h:215 v:1249 + if (GBS::VPERIOD_IF::read() < 1160) { + return 6; + } + } + if ((detectedMode & 0x10) == 0x10) { + if ((detectedMode & 0x04) == 0x04) { + // normally HD2376_1250P (PAL FHD?), but using this for 24k + return 8; + } + return 7; // hdtv 1080p + } + } + + // graphic modes, mostly used for ps2 doing rgb over yuv with sog + if ((GBS::STATUS_05::read() & 0x0c) == 0x00) // 2: Horizontal unstable AND 3: Vertical unstable are 0? + { + if (GBS::STATUS_00::read() == 0x07) { // the 3 stat0 stable indicators on, none of the SD indicators on + if ((GBS::STATUS_03::read() & 0x02) == 0x02) // Graphic mode bit on (any of VGA/SVGA/XGA/SXGA at all detected Hz) + { + if (rto.inputIsYPbPr) + return 13; + else + return 15; // switch to RGBS/HV handling + } else { + // this mode looks like it wants to be graphic mode, but the horizontal counter target in MD is very strict + static uint8_t XGA_60HZ = GBS::MD_XGA_60HZ_CNTRL::read(); + static uint8_t XGA_70HZ = GBS::MD_XGA_70HZ_CNTRL::read(); + static uint8_t XGA_75HZ = GBS::MD_XGA_75HZ_CNTRL::read(); + static uint8_t XGA_85HZ = GBS::MD_XGA_85HZ_CNTRL::read(); + + static uint8_t SXGA_60HZ = GBS::MD_SXGA_60HZ_CNTRL::read(); + static uint8_t SXGA_75HZ = GBS::MD_SXGA_75HZ_CNTRL::read(); + static uint8_t SXGA_85HZ = GBS::MD_SXGA_85HZ_CNTRL::read(); + + static uint8_t SVGA_60HZ = GBS::MD_SVGA_60HZ_CNTRL::read(); + static uint8_t SVGA_75HZ = GBS::MD_SVGA_75HZ_CNTRL::read(); + static uint8_t SVGA_85HZ = GBS::MD_SVGA_85HZ_CNTRL::read(); + + static uint8_t VGA_75HZ = GBS::MD_VGA_75HZ_CNTRL::read(); + static uint8_t VGA_85HZ = GBS::MD_VGA_85HZ_CNTRL::read(); + + short hSkew = random(-2, 2); // skew the target a little + // _WSF("0x%04X\n", XGA_60HZ + hSkew); + GBS::MD_XGA_60HZ_CNTRL::write(XGA_60HZ + hSkew); + GBS::MD_XGA_70HZ_CNTRL::write(XGA_70HZ + hSkew); + GBS::MD_XGA_75HZ_CNTRL::write(XGA_75HZ + hSkew); + GBS::MD_XGA_85HZ_CNTRL::write(XGA_85HZ + hSkew); + GBS::MD_SXGA_60HZ_CNTRL::write(SXGA_60HZ + hSkew); + GBS::MD_SXGA_75HZ_CNTRL::write(SXGA_75HZ + hSkew); + GBS::MD_SXGA_85HZ_CNTRL::write(SXGA_85HZ + hSkew); + GBS::MD_SVGA_60HZ_CNTRL::write(SVGA_60HZ + hSkew); + GBS::MD_SVGA_75HZ_CNTRL::write(SVGA_75HZ + hSkew); + GBS::MD_SVGA_85HZ_CNTRL::write(SVGA_85HZ + hSkew); + GBS::MD_VGA_75HZ_CNTRL::write(VGA_75HZ + hSkew); + GBS::MD_VGA_85HZ_CNTRL::write(VGA_85HZ + hSkew); + } + } + } + + detectedMode = GBS::STATUS_00::read(); + if ((detectedMode & 0x2F) == 0x07) { + // 0_00 H+V stable, not NTSCI, not PALI + detectedMode = GBS::STATUS_16::read(); + if ((detectedMode & 0x02) == 0x02) { // SP H active + uint16_t lineCount = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + for (uint8_t i = 0; i < 2; i++) { + delay(2); + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() < (lineCount - 1) || + GBS::STATUS_SYNC_PROC_VTOTAL::read() > (lineCount + 1)) { + lineCount = 0; + rto.notRecognizedCounter = 0; + break; + } + detectedMode = GBS::STATUS_00::read(); + if ((detectedMode & 0x2F) != 0x07) { + lineCount = 0; + rto.notRecognizedCounter = 0; + break; + } + } + if (lineCount != 0 && rto.notRecognizedCounter < 255) { + rto.notRecognizedCounter++; + } + } else { + rto.notRecognizedCounter = 0; + } + } else { + rto.notRecognizedCounter = 0; + } + // ??? + if (rto.notRecognizedCounter == 255) { + return 9; + } + + return 0; // unknown mode +} + +/** + * @brief Set the And Latch Phase A D C object + * + */ +void setAndLatchPhaseADC() +{ + GBS::PA_ADC_LAT::write(0); + GBS::PA_ADC_S::write(rto.phaseADC); + GBS::PA_ADC_LAT::write(1); +} + +/** + * @brief + * + */ +void nudgeMD() +{ + GBS::MD_VS_FLIP::write(!GBS::MD_VS_FLIP::read()); + GBS::MD_VS_FLIP::write(!GBS::MD_VS_FLIP::read()); +} + +/** + * @brief + * + * @param slaveRegister + * @param values + * @param numValues + */ +void writeBytes(uint8_t slaveRegister, uint8_t *values, uint8_t numValues) +{ + if (slaveRegister == 0xF0 && numValues == 1) { + lastSegment = *values; + } else + GBS::write(lastSegment, slaveRegister, values, numValues); +} + +/** + * @brief + * + * @param slaveRegister + * @param value + */ +void writeOneByte(uint8_t slaveRegister, uint8_t value) +{ + writeBytes(slaveRegister, &value, 1); +} + +/** + * @brief + * + * @param reg + * @param bytesToRead + * @param output + */ +void readFromRegister(uint8_t reg, int bytesToRead, uint8_t *output) +{ + return GBS::read(lastSegment, reg, output, bytesToRead); +} + +/** + * @brief + * + */ +void loadHdBypassSection() +{ + uint16_t index = 0; + uint8_t bank[16]; + writeOneByte(0xF0, 1); + for (int j = 3; j <= 5; j++) { // start at 0x30 + copyBank(bank, presetHdBypassSection, &index); + writeBytes(j * 16, bank, 16); + } +} + +/** + * @brief Get the Single Byte From Preset object + * + * @param programArray + * @param offset + * @return uint8_t + */ +uint8_t getSingleByteFromPreset(const uint8_t *programArray, unsigned int offset) +{ + return pgm_read_byte(programArray + offset); +} + +/** + * @brief + * + * @param bank + * @param programArray + * @param index + */ +void copyBank(uint8_t *bank, const uint8_t *programArray, uint16_t *index) +{ + for (uint8_t x = 0; x < 16; ++x) { + bank[x] = pgm_read_byte(programArray + *index); + (*index)++; + } +} + +/** + * @brief + * + * @param seg + * @param reg + */ +void printReg(uint8_t seg, uint8_t reg) +{ + uint8_t readout; + readFromRegister(reg, 1, &readout); + // didn't think this HEX trick would work, but it does! (?) + _WSF(PSTR("0x%02X, // s%d_0x%04X\n"), readout, seg, reg); + // old: + // _WS(readout); _WS(F(", // s")); _WS(seg); _WS(F("_")); _WSF("0x%04X", reg); +} + +/** + * @brief dumps the current chip configuration in a format + * that's ready to use as new preset :) + * + * @param segment + */ +void dumpRegisters(byte segment) +{ + if (segment > 5) + return; + + writeOneByte(0xF0, segment); + int x = 0x40; + switch (segment) { + case 0: + do { + printReg(0, x); + x++; + } while(x <= 0x5F); + x = 0x90; + do { + printReg(0, x); + x++; + } while(x <= 0x9F); + break; + case 1: + x = 0x0; + do { + printReg(1, x); + x++; + } while(x <= 0x2F); + break; + case 2: + x = 0x0; + do { + printReg(2, x); + x++; + } while(x <= 0x3F); + break; + case 3: + x = 0x0; + do { + printReg(3, x); + x++; + } while(x <= 0x7F); + break; + case 4: + x = 0x0; + do { + printReg(4, x); + x++; + } while(x <= 0x5F); + break; + case 5: + x = 0x0; + do { + printReg(5, x); + x++; + } while(x <= 0x6F); + break; + } +} + +/** + * @brief + * + */ +// void readEeprom() +// { +// int addr = 0; +// const uint8_t eepromAddr = 0x50; +// Wire.beginTransmission(eepromAddr); +// // if (addr >= 0x1000) { addr = 0; } +// Wire.write(addr >> 8); // high addr byte, 4 bits + +// Wire.write((uint8_t)addr); // low addr byte, 8 bits = 12 bits (0xfff max) +// Wire.endTransmission(); +// Wire.requestFrom(eepromAddr, (uint8_t)128); +// uint8_t readData = 0; +// uint8_t i = 0; +// while (Wire.available()) { +// readData = Wire.read(); +// _WSF(PSTR("addr 0x%04X : 0x%04X\n"), i, readData); +// // addr++; +// i++; +// } +// } + +/** + * @brief + * + */ +void stopWire() +{ + pinMode(SCL, INPUT); + pinMode(SDA, INPUT); + delayMicroseconds(80); +} + +/** + * @brief + * + */ +void startWire() +{ + Wire.begin(); + // The i2c wire library sets pullup resistors on by default. + // Disable these to detect/work with GBS onboard pullups + pinMode(SCL, OUTPUT_OPEN_DRAIN); + pinMode(SDA, OUTPUT_OPEN_DRAIN); + // no issues even at 700k, requires ESP8266 160Mhz CPU clock, else (80Mhz) uses 400k in library + // no problem with Si5351 at 700k either + Wire.setClock(400000); + // Wire.setClock(700000); + // run some dummy commands to init I2C + writeOneByte(0xF0, 0); + GBS::SP_SOG_MODE::read(); + GBS::SP_SOG_MODE::read(); + GBS::STATUS_00::read(); +} + +/** + * @brief Detect if external clock installed + * + * @return int8_t + * 1 = device ready, init completed, + * 0 - no device detected + * -1 - any other error + */ +int8_t utilsExternClockGenInit() +{ + const uint8_t xtal_cl = 0xD2; // 10pF, other choices are 8pF (0x92) and 6pF (0x52) NOTE: Per AN619, the low bytes should be written 0b010010 + + // MHz: 27, 32.4, 40.5, 54, 64.8, 81, 108, 129.6, 162 + rto.freqExtClockGen = 81000000; + rto.extClockGenDetected = 0; + + if (uopt.disableExternalClockGenerator) { + _DBGN(F("(!) external clock generator disabled, skipping detection")); + return 0; + } + + uint8_t retVal = 0; + Wire.beginTransmission(SIADDR); + // returns: + // 4 = line busy + // 3 = received NACK on transmit of data + // 2 = received NACK on transmit of address + // 0 = success + retVal = Wire.endTransmission(); + _DBGF(PSTR("(i) external clock, status: %d\n"), retVal); + if (retVal != 0) { + return -1; + } + + Wire.beginTransmission(SIADDR); + Wire.write(0); // Device Status + Wire.endTransmission(); + size_t bytes_read = Wire.requestFrom((uint8_t)SIADDR, (size_t)1, false); + + if (bytes_read == 1) { + retVal = Wire.read(); + if ((retVal & 0x80) == 0) { + // SYS_INIT indicates device is ready. + rto.extClockGenDetected = 1; + } else { + return 0; + } + } else { + return -1; + } + + _DBGN(F("external clock detected")); + + Si.init(25000000L); // many Si5351 boards come with 25MHz crystal; 27000000L for one with 27MHz + Wire.beginTransmission(SIADDR); + Wire.write(183); // XTAL_CL + Wire.write(xtal_cl); + Wire.endTransmission(); + Si.setPower(0, SIOUT_6mA); + Si.setFreq(0, rto.freqExtClockGen); + Si.disable(0); + return 1; +} + +/** + * @brief Check if TV chip is acting as expeced when all systems are powered-on + * (this function sets rto.boardHasPower status variable) + * + * @return true + * @return false + */ +bool utilsCheckBoardPower() +{ + // check DAC (disabled by default) + if(!rto.isInLowPowerMode && GBS::DAC_RGBS_PWDNZ::read() == 0) { + _DBGN(F("(i) DAC is in power down mode")); + // goto board_power_bad; + } + + // check ADC + if(GBS::ADC_POWDZ::read() == 0) { + _DBGN(F("(!) ADC is in power down mode")); + goto board_power_bad; + } + + // check PLL power + // if(GBS::PLLAD_PDZ::read() == 0) { + // _DBGN(F("(i) PLL is in power down mode")); + // // goto board_power_bad; + // } + + rto.boardHasPower = true; + rto.syncWatcherEnabled = true; + goto board_power_end; + +board_power_bad: + rto.boardHasPower = false; + rto.syncWatcherEnabled = false; + rto.continousStableCounter = 0; + +board_power_end: + return rto.boardHasPower; + + // GBS::ADC_UNUSED_69::write(0x6a); // 0110 1010 + // if (GBS::ADC_UNUSED_69::read() == 0x6a) { + // GBS::ADC_UNUSED_69::write(0); + // rto.boardHasPower = true; + // return true; + // } + + // GBS::ADC_UNUSED_69::write(0); // attempt to clear + // if (rto.boardHasPower == true) { + // _WSN(F("! power / i2c lost !")); + // } + // rto.boardHasPower = false; + + // return false; +} + +/** + * @brief Ref.13.2.2 Software reset: "In 5725, there are also some software reset register bits, + * these software reset only could reset state machine and internal + * timing, but could not reset register bits’ value. And host interface’s + * state machine is only reset by external reset..." + * + */ +// void utilsResetAllOffline() { +// GBS::PLL_VCORST::write(1); + +// GBS::ADC_POWDZ::write(0); +// GBS::PLLAD_PDZ::write(0); +// GBS::PLLAD_LEN::write(0); +// GBS::DAC_RGBS_PWDNZ::write(0); +// GBS::OUT_SYNC_CNTRL::write(0); +// GBS::SFTRST_VDS_RSTZ::write(0); +// GBS::SFTRST_SYNC_RSTZ::write(0); +// GBS::SFTRST_DEC_RSTZ::write(0); +// GBS::SFTRST_IF_RSTZ::write(0); +// GBS::SFTRST_DEINT_RSTZ::write(0); +// GBS::SFTRST_MEM_FF_RSTZ::write(0); +// GBS::SFTRST_MEM_RSTZ::write(0); +// GBS::SFTRST_FIFO_RSTZ::write(0); +// GBS::SFTRST_OSD_RSTZ::write(0); +// GBS::SFTRST_MODE_RSTZ::write(0); +// GBS::SFTRST_HDBYPS_RSTZ::write(0); +// GBS::SFTRST_INT_RSTZ::write(0); + +// GBS::PAD_CONTROL_00_0x48::write(0); +// GBS::PAD_CONTROL_01_0x49::write(0); +// } + +/** + * @brief All systems online + * + */ +// void utilsResetOnline() { +// GBS::ADC_POWDZ::write(1); +// resetDigital(); +// resetPLLAD(); +// GBS::PLLAD_LEN::write(1); +// GBS::DAC_RGBS_PWDNZ::write(1); +// GBS::OUT_SYNC_CNTRL::write(1); +// GBS::SFTRST_SYNC_RSTZ::write(1); +// GBS::SFTRST_DEC_RSTZ::write(1); +// GBS::SFTRST_IF_RSTZ::write(1); +// GBS::SFTRST_DEINT_RSTZ::write(1); +// GBS::SFTRST_MEM_FF_RSTZ::write(1); +// GBS::SFTRST_MEM_RSTZ::write(1); +// GBS::SFTRST_FIFO_RSTZ::write(1); +// GBS::SFTRST_OSD_RSTZ::write(1); +// GBS::SFTRST_VDS_RSTZ::write(1); +// GBS::SFTRST_MODE_RSTZ::write(1); +// GBS::SFTRST_HDBYPS_RSTZ::write(1); +// GBS::SFTRST_INT_RSTZ::write(1); + +// // GBS::PAD_CONTROL_00_0x48::write(0x2b); +// GBS::PAD_CKIN_ENZ::write(1); +// GBS::PAD_CKOUT_ENZ::write(1); +// GBS::PAD_SYNC_OUT_ENZ::write(1); +// GBS::PAD_BLK_OUT_ENZ::write(1); +// GBS::PAD_TRI_ENZ::write(1); +// } + +/** + * @brief Clear tv5725 registers + * "All registers (except chapter 01 status register is read only) + * have default value “0x00” after power up." + * "All registers require segment for access. + * Segment is defined in address F0." + * + */ +void utilsZeroAll() +{ + // this goes into utilsResetAllOffline() + // turn processing units off first + // writeOneByte(0xF0, 0); + // writeOneByte(0x46, 0x00); // reset controls 1 + // writeOneByte(0x47, 0x00); // reset controls 2 + + // zero out entire register space = (6 segments * 255 bytes) + uint8_t y = 0; + uint8_t z = 0; + + while (y < 6) { + writeOneByte(0xF0, y); + // skip RO registers + if(y == 0) z = 3; + while (z < 16) { + // while(w < 16) { + // bank[w] = 0; + // exceptions + // if (y == 5 && z == 0 && w == 2) { + // bank[w] = 0x51; // 5_02 + //} + // if (y == 5 && z == 5 && w == 6) { + // bank[w] = 0x01; // 5_56 + //} + // if (y == 5 && z == 5 && w == 7) { + // bank[w] = 0xC0; // 5_57 + //} + // w++; + // } + uint8_t bank[16]; + memset(bank, 0, 16); + writeBytes(z * 16, bank, 16); + z++; + } + z = 0; + y++; + } + _DBGN(F("(!) all registers reset")); +} + +/** + * @brief A simple getter for preset file names depending on videoMode ID + * + * @param videoMode + * @param buffer + */ +void utilsGetPresetsFileNameFor(uint8_t & videoMode, char * buffer) { + if (rto.videoStandardInput == 1) + sprintf(buffer, PSTR("/preset_ntsc.%d"), uopt.slotID); + else if (rto.videoStandardInput == 2) + sprintf(buffer, PSTR("/preset_pal.%d"), uopt.slotID); + else if (rto.videoStandardInput == 3) + sprintf(buffer, PSTR("/preset_ntsc_480p.%d"), uopt.slotID); + else if (rto.videoStandardInput == 4) + sprintf(buffer, PSTR("/preset_pal_576p.%d"), uopt.slotID); + else if (rto.videoStandardInput == 5) + sprintf(buffer, PSTR("/preset_ntsc_720p.%d"), uopt.slotID); + else if (rto.videoStandardInput == 6) + sprintf(buffer, PSTR("/preset_ntsc_1080p.%d"), uopt.slotID); + else if (rto.videoStandardInput == 8) + sprintf(buffer, PSTR("/preset_medium_res.%d"), uopt.slotID); + else if (rto.videoStandardInput == 14) + sprintf(buffer, PSTR("/preset_vga_upscale.%d"), uopt.slotID); + else // if (rto.videoStandardInput == 0) + sprintf(buffer, PSTR("/preset_unknown.%d"), uopt.slotID); +} + +/** + * @brief + * + */ +void calibrateAdcOffset() +{ + GBS::PAD_BOUT_EN::write(0); // disable output to pin for test + GBS::PLL648_CONTROL_01::write(0xA5); // display clock to adc = 162mhz + GBS::ADC_INPUT_SEL::write(2); // 10 > R2/G2/B2 as input (not connected, so to isolate ADC) + GBS::DEC_MATRIX_BYPS::write(1); + GBS::DEC_TEST_ENABLE::write(1); + GBS::ADC_5_03::write(0x31); // bottom clamps, filter max (40mhz) + GBS::ADC_TEST_04::write(0x00); // disable bit 1 + GBS::SP_CS_CLP_ST::write(0x00); + GBS::SP_CS_CLP_SP::write(0x00); + GBS::SP_5_56::write(0x05); // SP_SOG_MODE needs to be 1 + GBS::SP_5_57::write(0x80); + GBS::ADC_5_00::write(0x02); + GBS::TEST_BUS_SEL::write(0x0b); // 0x2b + GBS::TEST_BUS_EN::write(1); + resetDigital(); + + uint16_t hitTargetCounter = 0; + uint16_t readout16 = 0; + uint8_t missTargetCounter = 0; + uint8_t readout = 0; + + GBS::ADC_RGCTRL::write(0x7F); + GBS::ADC_GGCTRL::write(0x7F); + GBS::ADC_BGCTRL::write(0x7F); + GBS::ADC_ROFCTRL::write(0x7F); + GBS::ADC_GOFCTRL::write(0x3D); // start + GBS::ADC_BOFCTRL::write(0x7F); + GBS::DEC_TEST_SEL::write(1); // 5_1f = 0x1c + + // unsigned long overallTimer = millis(); + unsigned long startTimer = 0; + for (uint8_t i = 0; i < 3; i++) { + missTargetCounter = 0; + hitTargetCounter = 0; + delay(20); + startTimer = millis(); + + // loop breaks either when the timer runs out, or hitTargetCounter reaches target + while ((millis() - startTimer) < 800) { + readout16 = GBS::TEST_BUS::read() & 0x7fff; + // _WSN(readout16, HEX); + // readout16 is unsigned, always >= 0 + if (readout16 < 7) { + hitTargetCounter++; + missTargetCounter = 0; + } else if (missTargetCounter++ > 2) { + if (i == 0) { + GBS::ADC_GOFCTRL::write(GBS::ADC_GOFCTRL::read() + 1); // incr. offset + readout = GBS::ADC_GOFCTRL::read(); + _WS(F(" G: ")); + } else if (i == 1) { + GBS::ADC_ROFCTRL::write(GBS::ADC_ROFCTRL::read() + 1); + readout = GBS::ADC_ROFCTRL::read(); + _WS(F(" R: ")); + } else if (i == 2) { + GBS::ADC_BOFCTRL::write(GBS::ADC_BOFCTRL::read() + 1); + readout = GBS::ADC_BOFCTRL::read(); + _WS(F(" B: ")); + } + _WSF(PSTR("0x%04X"), readout); + + if (readout >= 0x52) { + // some kind of failure + break; + } + + delay(10); + hitTargetCounter = 0; + missTargetCounter = 0; + startTimer = millis(); // extend timer + } + if (hitTargetCounter > 1500) { + break; + } + } + if (i == 0) { + // G done, prep R + adco.g_off = GBS::ADC_GOFCTRL::read(); + GBS::ADC_GOFCTRL::write(0x7F); + GBS::ADC_ROFCTRL::write(0x3D); + GBS::DEC_TEST_SEL::write(2); // 5_1f = 0x2c + } + if (i == 1) { + adco.r_off = GBS::ADC_ROFCTRL::read(); + GBS::ADC_ROFCTRL::write(0x7F); + GBS::ADC_BOFCTRL::write(0x3D); + GBS::DEC_TEST_SEL::write(3); // 5_1f = 0x3c + } + if (i == 2) { + adco.b_off = GBS::ADC_BOFCTRL::read(); + } + _WSN(); + } + + if (readout >= 0x52) { + // there was a problem; revert + adco.r_off = adco.g_off = adco.b_off = 0x40; + } + + GBS::ADC_GOFCTRL::write(adco.g_off); + GBS::ADC_ROFCTRL::write(adco.r_off); + GBS::ADC_BOFCTRL::write(adco.b_off); + + // _WSN(millis() - overallTimer); +} + +/** + * @brief Set the External Clock Gen Frequency Smooth object + * + * @param freq + */ +void setExternalClockGenFrequencySmooth(uint32_t freq) { + uint32_t current = rto.freqExtClockGen; + + rto.freqExtClockGen = freq; + + constexpr uint32_t STEP_SIZE_HZ = 1000; + + if (current > rto.freqExtClockGen) { + if ((current - rto.freqExtClockGen) < 750000) { + while (current > (rto.freqExtClockGen + STEP_SIZE_HZ)) { + current -= STEP_SIZE_HZ; + Si.setFreq(0, current); + // wifiLoop(0); + } + } + } else if (current < rto.freqExtClockGen) { + if ((rto.freqExtClockGen - current) < 750000) { + while ((current + STEP_SIZE_HZ) < rto.freqExtClockGen) { + current += STEP_SIZE_HZ; + Si.setFreq(0, current); + // wifiLoop(0); + } + } + } + + Si.setFreq(0, rto.freqExtClockGen); +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 00000000..0931c242 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,67 @@ +/* +##################################################################################### +# File: utils.h # +# File Created: Thursday, 2nd May 2024 5:38:14 pm # +# Author: # +# Last Modified: Friday, 21st June 2024 10:20:49 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include +#include "options.h" +#include "tv5725.h" +#include "wifiman.h" +#include "wserial.h" +#include "presetHdBypassSection.h" + +extern Si5351mcu Si; + +bool utilsIsPassThroughMode(); +bool utilsNotPassThroughMode(); +bool utilsIsDownscaleMode(); +bool utilsNotDownscaleMode(); +void latchPLLAD(); +void resetPLLAD(); +void resetPLL(); +uint32_t getPllRate(); +void ResetSDRAM(); +void setCsVsStart(uint16_t start); +void setCsVsStop(uint16_t stop); +void freezeVideo(); +void unfreezeVideo(); +void resetDigital(); +void resetDebugPort(); +uint8_t getVideoMode(); +void setAndLatchPhaseADC(); +void nudgeMD(); +void writeBytes(uint8_t slaveRegister, uint8_t *values, uint8_t numValues); +void writeOneByte(uint8_t slaveRegister, uint8_t value); +void readFromRegister(uint8_t reg, int bytesToRead, uint8_t *output); +void loadHdBypassSection(); + +uint8_t getSingleByteFromPreset(const uint8_t *programArray, unsigned int offset); +void copyBank(uint8_t *bank, const uint8_t *programArray, uint16_t *index); +void printReg(uint8_t seg, uint8_t reg); +void dumpRegisters(byte segment); +// @sk: not used +// void readEeprom(); + +void stopWire(); +void startWire(); +int8_t utilsExternClockGenInit(); +bool utilsCheckBoardPower(); +// void utilsResetAllOffline(); +// void utilsResetOnline(); +void utilsZeroAll(); +void utilsGetPresetsFileNameFor(uint8_t & videoMode, char * buffer); +void calibrateAdcOffset(); +void setExternalClockGenFrequencySmooth(uint32_t freq); + + +#endif // _UTILS_H_ \ No newline at end of file diff --git a/src/video.cpp b/src/video.cpp new file mode 100644 index 00000000..2fa3a326 --- /dev/null +++ b/src/video.cpp @@ -0,0 +1,5188 @@ +/* +##################################################################################### +# File: video.cpp # +# File Created: Thursday, 2nd May 2024 4:07:57 pm # +# Author: # +# Last Modified: Friday, 28th June 2024 1:20:04 am # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ +#include "video.h" + +/** + * @brief + * + */ +void resetInterruptSogSwitchBit() +{ + GBS::INT_CONTROL_RST_SOGSWITCH::write(1); + GBS::INT_CONTROL_RST_SOGSWITCH::write(0); +} + +/** + * @brief + * + */ +void resetInterruptSogBadBit() +{ + GBS::INT_CONTROL_RST_SOGBAD::write(1); + GBS::INT_CONTROL_RST_SOGBAD::write(0); +} + +/** + * @brief + * + */ +void resetInterruptNoHsyncBadBit() +{ + GBS::INT_CONTROL_RST_NOHSYNC::write(1); + GBS::INT_CONTROL_RST_NOHSYNC::write(0); +} + +/** + * @brief + * + * @return true + * @return false + */ +bool videoStandardInputIsPalNtscSd() +{ + if (rto.videoStandardInput == 1 || rto.videoStandardInput == 2) { + return true; + } + return false; +} + +/** + * @brief + * + */ +void prepareSyncProcessor() +{ + writeOneByte(0xF0, 5); + GBS::SP_SOG_P_ATO::write(0); // 5_20 disable sog auto polarity // hpw can be > ht, but auto is worse + GBS::SP_JITTER_SYNC::write(0); + // H active detect control + writeOneByte(0x21, 0x18); // SP_SYNC_TGL_THD H Sync toggle time threshold 0x20; lower than 5_33(not always); 0 to turn off (?) 0x18 for 53.69 system @ 33.33 + writeOneByte(0x22, 0x0F); // SP_L_DLT_REG Sync pulse width difference threshold (less than this = equal) + writeOneByte(0x23, 0x00); // UNDOCUMENTED range from 0x00 to at least 0x1d + writeOneByte(0x24, 0x40); // SP_T_DLT_REG H total width difference threshold rgbhv: b // range from 0x02 upwards + writeOneByte(0x25, 0x00); // SP_T_DLT_REG + writeOneByte(0x26, 0x04); // SP_SYNC_PD_THD H sync pulse width threshold // from 0(?) to 0x50 // in yuv 720p range only to 0x0a! + writeOneByte(0x27, 0x00); // SP_SYNC_PD_THD + writeOneByte(0x2a, 0x0F); // SP_PRD_EQ_THD How many legal lines as valid; scales with 5_33 (needs to be below) + // V active detect control + // these 4 only have effect with HV input; test: s5s2ds34 s5s2es24 s5s2fs16 s5s31s84 + writeOneByte(0x2d, 0x03); // SP_VSYNC_TGL_THD V sync toggle time threshold // at 5 starts to drop many 0_16 vsync events + writeOneByte(0x2e, 0x00); // SP_SYNC_WIDTH_DTHD V sync pulse width threshold + writeOneByte(0x2f, 0x02); // SP_V_PRD_EQ_THD How many continue legal v sync as valid // at 4 starts to drop 0_16 vsync events + writeOneByte(0x31, 0x2f); // SP_VT_DLT_REG V total difference threshold + // Timer value control + writeOneByte(0x33, 0x3a); // SP_H_TIMER_VAL H timer value for h detect (was 0x28) + writeOneByte(0x34, 0x06); // SP_V_TIMER_VAL V timer for V detect // 0_16 vsactive // was 0x05 + // Sync separation control + if (rto.videoStandardInput == 0) + GBS::SP_DLT_REG::write(0x70); // 5_35 130 too much for ps2 1080i, 0xb0 for 1080p + else if (rto.videoStandardInput <= 4) + GBS::SP_DLT_REG::write(0xC0); // old: extended to 0x150 later if mode = 1 or 2 + else if (rto.videoStandardInput <= 6) + GBS::SP_DLT_REG::write(0xA0); + else if (rto.videoStandardInput == 7) + GBS::SP_DLT_REG::write(0x70); + else + GBS::SP_DLT_REG::write(0x70); + + if (videoStandardInputIsPalNtscSd()) { + GBS::SP_H_PULSE_IGNOR::write(0x6b); + } else { + GBS::SP_H_PULSE_IGNOR::write(0x02); // test with MS / Genesis mode (wsog 2) vs ps2 1080p (0x13 vs 0x05) + } + // leave out pre / post coast here + // 5_3a attempted 2 for 1chip snes 239 mode intermittency, works fine except for MD in MS mode + // make sure this is stored in the presets as well, as it affects sync time + GBS::SP_H_TOTAL_EQ_THD::write(3); + + GBS::SP_SDCS_VSST_REG_H::write(0); + GBS::SP_SDCS_VSSP_REG_H::write(0); + GBS::SP_SDCS_VSST_REG_L::write(4); // 5_3f // was 12 + GBS::SP_SDCS_VSSP_REG_L::write(1); // 5_40 // was 11 + + GBS::SP_CS_HS_ST::write(0x10); // 5_45 + GBS::SP_CS_HS_SP::write(0x00); // 5_47 720p source needs ~20 range, may be necessary to adjust at runtime, based on source res + + writeOneByte(0x49, 0x00); // retime HS start for RGB+HV rgbhv: 20 + writeOneByte(0x4a, 0x00); // + writeOneByte(0x4b, 0x44); // retime HS stop rgbhv: 50 + writeOneByte(0x4c, 0x00); // + + writeOneByte(0x51, 0x02); // 0x00 rgbhv: 2 + writeOneByte(0x52, 0x00); // 0xc0 + writeOneByte(0x53, 0x00); // 0x05 rgbhv: 6 + writeOneByte(0x54, 0x00); // 0xc0 + + // if (rto.videoStandardInput != 15 && (GBS::GBS_OPTION_SCALING_RGBHV::read() != 1)) { + if (rto.videoStandardInput != 15 && !uopt.preferScalingRgbhv) { + GBS::SP_CLAMP_MANUAL::write(0); // 0 = automatic on/off possible + GBS::SP_CLP_SRC_SEL::write(0); // clamp source 1: pixel clock, 0: 27mhz // was 1 but the pixel clock isn't available at first + GBS::SP_NO_CLAMP_REG::write(1); // 5_57_0 unlock clamp + GBS::SP_SOG_MODE::write(1); + GBS::SP_H_CST_ST::write(0x10); // 5_4d + GBS::SP_H_CST_SP::write(0x100); // 5_4f + GBS::SP_DIS_SUB_COAST::write(0); // 5_3e 5 + GBS::SP_H_PROTECT::write(1); // SP_H_PROTECT on for detection + GBS::SP_HCST_AUTO_EN::write(0); + GBS::SP_NO_COAST_REG::write(0); + } + + GBS::SP_HS_REG::write(1); // 5_57 7 + GBS::SP_HS_PROC_INV_REG::write(0); // no SP sync inversion + GBS::SP_VS_PROC_INV_REG::write(0); // + + writeOneByte(0x58, 0x05); // rgbhv: 0 + writeOneByte(0x59, 0x00); // rgbhv: 0 + writeOneByte(0x5a, 0x01); // rgbhv: 0 // was 0x05 but 480p ps2 doesnt like it + writeOneByte(0x5b, 0x00); // rgbhv: 0 + writeOneByte(0x5c, 0x03); // rgbhv: 0 + writeOneByte(0x5d, 0x02); // rgbhv: 0 // range: 0 - 0x20 (how long should clamp stay off) +} + +/** + * @brief Get the Status16 Sp Hs Stable object + * used to be a check for the length of the debug bus readout of 5_63 = 0x0f + * now just checks the chip status at 0_16 HS active (and Interrupt bit4 HS active for RGBHV) + * @return true + * @return false + */ +bool getStatus16SpHsStable() +{ + if (rto.videoStandardInput == 15) { // check RGBHV first + if (GBS::STATUS_INT_INP_NO_SYNC::read() == 0) { + return true; + } else { + resetInterruptNoHsyncBadBit(); + return false; + } + } + + // STAT_16 bit 1 is the "hsync active" flag, which appears to be a reliable indicator + // checking the flag replaces checking the debug bus pulse length manually + uint8_t status16 = GBS::STATUS_16::read(); + if ((status16 & 0x02) == 0x02) { + if (rto.videoStandardInput == 1 || rto.videoStandardInput == 2) { + if ((status16 & 0x01) != 0x01) { // pal / ntsc should be sync active low + return true; + } + } else { + return true; // not pal / ntsc + } + } + + return false; +} + +/** + * @brief Get the Source Field Rate object + * + * @param useSPBus + * @return float + */ +float getSourceFieldRate(bool useSPBus) +{ + double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; + uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); + uint8_t spBusSelBackup = GBS::TEST_BUS_SP_SEL::read(); + uint8_t ifBusSelBackup = GBS::IF_TEST_SEL::read(); + uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); + + if (debugPinBackup != 1) + GBS::PAD_BOUT_EN::write(1); // enable output to pin for test + + if (ifBusSelBackup != 3) + GBS::IF_TEST_SEL::write(3); // IF averaged frame time + + if (useSPBus) { + if (rto.syncTypeCsync) { + // _DBGN("TestBus for csync"); + if (testBusSelBackup != 0xa) + GBS::TEST_BUS_SEL::write(0xa); + } else { + // _DBGN("TestBus for HV Sync"); + if (testBusSelBackup != 0x0) + GBS::TEST_BUS_SEL::write(0x0); // RGBHV: TB 0x20 has vsync + } + if (spBusSelBackup != 0x0f) + GBS::TEST_BUS_SP_SEL::write(0x0f); + } else { + if (testBusSelBackup != 0) + GBS::TEST_BUS_SEL::write(0); // needs decimation + if + } + + float retVal = 0; + + uint32_t fieldTimeTicks = FrameSync::getPulseTicks(); + if (fieldTimeTicks == 0) { + // try again + fieldTimeTicks = FrameSync::getPulseTicks(); + } + + if (fieldTimeTicks > 0) { + retVal = esp8266_clock_freq / (double)fieldTimeTicks; + if (retVal < 47.0f || retVal > 86.0f) { + // try again + fieldTimeTicks = FrameSync::getPulseTicks(); + if (fieldTimeTicks > 0) { + retVal = esp8266_clock_freq / (double)fieldTimeTicks; + } + } + } + + GBS::TEST_BUS_SEL::write(testBusSelBackup); + GBS::PAD_BOUT_EN::write(debugPinBackup); + if (spBusSelBackup != 0x0f) + GBS::TEST_BUS_SP_SEL::write(spBusSelBackup); + if (ifBusSelBackup != 3) + GBS::IF_TEST_SEL::write(ifBusSelBackup); + + return retVal; +} + +/** + * @brief Get the Output Frame Rate object + * + * @return float + */ +float getOutputFrameRate() +{ + double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; + uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); + uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); + + if (debugPinBackup != 1) + GBS::PAD_BOUT_EN::write(1); // enable output to pin for test + + if (testBusSelBackup != 2) + GBS::TEST_BUS_SEL::write(2); // 0x4d = 0x22 VDS test + + float retVal = 0; + + uint32_t fieldTimeTicks = FrameSync::getPulseTicks(); + if (fieldTimeTicks == 0) { + // try again + fieldTimeTicks = FrameSync::getPulseTicks(); + } + + if (fieldTimeTicks > 0) { + retVal = esp8266_clock_freq / (double)fieldTimeTicks; + if (retVal < 47.0f || retVal > 86.0f) { + // try again + fieldTimeTicks = FrameSync::getPulseTicks(); + if (fieldTimeTicks > 0) { + retVal = esp8266_clock_freq / (double)fieldTimeTicks; + } + } + } + + GBS::TEST_BUS_SEL::write(testBusSelBackup); + GBS::PAD_BOUT_EN::write(debugPinBackup); + + return retVal; +} + +/** + * @brief + * + */ +void externalClockGenSyncInOutRate() +{ + // NOTE initially here OutputHdBypass instead of utilsIsPassThroughMode() + if (!rto.extClockGenDetected || GBS::PAD_CKIN_ENZ::read() != 0 + || utilsIsPassThroughMode() + || GBS::PLL648_CONTROL_01::read() != 0x75) { + return; + } + + int32_t diff = 0; + uint32_t old = rto.freqExtClockGen; + float sfr = getSourceFieldRate(0); + float ofr = getOutputFrameRate(); + + if (sfr < 47.0f || sfr > 86.0f) { + _DBGF(PSTR("ext. clock sync skipped SFR wrong: %.02f\n"), sfr); + return; + } + + if (ofr < 47.0f || ofr > 86.0f) { + _DBGF(PSTR("ext. clock sync skipped OFR wrong: %.02f\n"), ofr); + return; + } + + FrameSync::initFrequency(ofr, old); + + setExternalClockGenFrequencySmooth((sfr / ofr) * rto.freqExtClockGen); + + diff = rto.freqExtClockGen - old; + + _DBGF(PSTR("source Hz: %.5f new out: %.5f clock: %u (%s%d)\n"), + sfr, + ofr, + rto.freqExtClockGen, + (diff >= 0 ? "+" : ""), + diff); +} + +/** + * @brief + * + */ +void externalClockGenResetClock() +{ + if (!rto.extClockGenDetected) { + _DBGN(F(" no ext.clock detected")); + return; + } + + uint8_t activeDisplayClock = GBS::PLL648_CONTROL_01::read(); + + if (activeDisplayClock == 0x25) + rto.freqExtClockGen = 40500000; + else if (activeDisplayClock == 0x45) + rto.freqExtClockGen = 54000000; + else if (activeDisplayClock == 0x55) + rto.freqExtClockGen = 64800000; + else if (activeDisplayClock == 0x65) + rto.freqExtClockGen = 81000000; + else if (activeDisplayClock == 0x85) + rto.freqExtClockGen = 108000000; + else if (activeDisplayClock == 0x95) + rto.freqExtClockGen = 129600000; + else if (activeDisplayClock == 0xa5) + rto.freqExtClockGen = 162000000; + else if (activeDisplayClock == 0x35) + rto.freqExtClockGen = 81000000; // clock unused + else if (activeDisplayClock == 0) + rto.freqExtClockGen = 81000000; // no preset loaded + // else if (!rto.outModeHdBypass) { + else if (utilsNotPassThroughMode()) { + _DBGF(PSTR("preset display clock: 0x%02X\n"), activeDisplayClock); + } + + // problem: around 108MHz the library seems to double the clock + // maybe there are regs to check for this and resetPLL + if (rto.freqExtClockGen == 108000000) { + Si.setFreq(0, 87000000); + delay(1); // quick fix + } + // same thing it seems at 40500000 + if (rto.freqExtClockGen == 40500000) { + Si.setFreq(0, 48500000); + delay(1); // quick fix + } + + Si.setFreq(0, rto.freqExtClockGen); + GBS::PAD_CKIN_ENZ::write(0); // 0 = clock input enable (pin40) + FrameSync::clearFrequency(); + + _DBGF(PSTR("reset ext. clock gen. to: %ld\n"), rto.freqExtClockGen); +} + +/** + * @brief + * + * @param bestHTotal + * @return true + * @return false + */ +bool applyBestHTotal(uint16_t bestHTotal) +{ + // if (rto.outModeHdBypass) { + if (utilsIsPassThroughMode()) { + return true; // false? doesn't matter atm + } + + uint16_t orig_htotal = GBS::VDS_HSYNC_RST::read(); + int diffHTotal = bestHTotal - orig_htotal; + uint16_t diffHTotalUnsigned = abs(diffHTotal); + + if (((diffHTotalUnsigned == 0) || (rto.extClockGenDetected && diffHTotalUnsigned == 1)) && // all this + !rto.forceRetime) // and that + { + if (!uopt.enableFrameTimeLock) { // FTL can double throw this when it resets to adjust + _WS(F("HTotal Adjust (skipped)")); + + if (!rto.extClockGenDetected) { + float sfr = getSourceFieldRate(0); + yield(); // wifi + float ofr = getOutputFrameRate(); + if (sfr < 1.0f) { + sfr = getSourceFieldRate(0); // retry + } + if (ofr < 1.0f) { + ofr = getOutputFrameRate(); // retry + } + _WSF(PSTR(", source Hz: %.3f, output Hz: %.3f\n"), sfr, ofr); + } else { + _WSN(); + } + } + return true; // nothing to do + } + + // if (GBS::GBS_OPTION_PALFORCED60_ENABLED::read() == 1) { + if (uopt.PalForce60) { + // source is 50Hz, preset has to stay at 60Hz: return + return true; + } + + bool isLargeDiff = (diffHTotalUnsigned > (orig_htotal * 0.06f)) ? true : false; // typical diff: 1802 to 1794 (=8) + + if (isLargeDiff && (getVideoMode() == 8 || rto.videoStandardInput == 14)) { + // arcade stuff syncs down from 60 to 52 Hz.. + isLargeDiff = (diffHTotalUnsigned > (orig_htotal * 0.16f)) ? true : false; + } + + if (isLargeDiff) { + _WSN(F("ABHT: large diff")); + } + + // rto.forceRetime = true means the correction should be forced (command '.') + if (isLargeDiff && (rto.forceRetime == false)) { + if (rto.videoStandardInput != 14) { + rto.failRetryAttempts++; + if (rto.failRetryAttempts < 8) { + _WSN(F("retry")); + FrameSync::reset(uopt.frameTimeLockMethod); + delay(60); + } else { + _WSN(F("give up")); + rto.autoBestHtotalEnabled = false; + } + } + return false; // large diff, no forced + } + + // bestHTotal 0? could be an invald manual retime + if (bestHTotal == 0) { + _WSN(F("bestHTotal 0")); + return false; + } + + if (rto.forceRetime == false) { + if (GBS::STATUS_INT_SOG_BAD::read() == 1) { + // _WSN("prevented in apply"); + return false; + } + } + + rto.failRetryAttempts = 0; // else all okay!, reset to 0 + + // move blanking (display) + uint16_t h_blank_display_start_position = GBS::VDS_DIS_HB_ST::read(); + uint16_t h_blank_display_stop_position = GBS::VDS_DIS_HB_SP::read(); + uint16_t h_blank_memory_start_position = GBS::VDS_HB_ST::read(); + uint16_t h_blank_memory_stop_position = GBS::VDS_HB_SP::read(); + + // new 25.10.2019 + // uint16_t blankingAreaTotal = bestHTotal * 0.233f; + // h_blank_display_start_position += (diffHTotal / 2); + // h_blank_display_stop_position += (diffHTotal / 2); + // h_blank_memory_start_position = bestHTotal - (blankingAreaTotal * 0.212f); + // h_blank_memory_stop_position = blankingAreaTotal * 0.788f; + + // h_blank_memory_start_position usually is == h_blank_display_start_position + if (h_blank_memory_start_position == h_blank_display_start_position) { + h_blank_display_start_position += (diffHTotal / 2); + h_blank_display_stop_position += (diffHTotal / 2); + h_blank_memory_start_position = h_blank_display_start_position; // normal case + h_blank_memory_stop_position += (diffHTotal / 2); + } else { + h_blank_display_start_position += (diffHTotal / 2); + h_blank_display_stop_position += (diffHTotal / 2); + h_blank_memory_start_position += (diffHTotal / 2); // the exception (currently 1280x1024) + h_blank_memory_stop_position += (diffHTotal / 2); + } + + if (diffHTotal < 0) { + h_blank_display_start_position &= 0xfffe; + h_blank_display_stop_position &= 0xfffe; + h_blank_memory_start_position &= 0xfffe; + h_blank_memory_stop_position &= 0xfffe; + } else if (diffHTotal > 0) { + h_blank_display_start_position += 1; + h_blank_display_start_position &= 0xfffe; + h_blank_display_stop_position += 1; + h_blank_display_stop_position &= 0xfffe; + h_blank_memory_start_position += 1; + h_blank_memory_start_position &= 0xfffe; + h_blank_memory_stop_position += 1; + h_blank_memory_stop_position &= 0xfffe; + } + + // don't move HSync with small diffs + uint16_t h_sync_start_position = GBS::VDS_HS_ST::read(); + uint16_t h_sync_stop_position = GBS::VDS_HS_SP::read(); + + // fix over / underflows + if (h_blank_display_start_position > (bestHTotal - 8) || isLargeDiff) { + // typically happens when scaling Hz up (60 to 70) + // _WSN("overflow h_blank_display_start_position"); + h_blank_display_start_position = bestHTotal * 0.936f; + } + if (h_blank_display_stop_position > bestHTotal || isLargeDiff) { + // _WSN("overflow h_blank_display_stop_position"); + h_blank_display_stop_position = bestHTotal * 0.178f; + } + if ((h_blank_memory_start_position > bestHTotal) || (h_blank_memory_start_position > h_blank_display_start_position) || isLargeDiff) { + // _WSN("overflow h_blank_memory_start_position"); + h_blank_memory_start_position = h_blank_display_start_position * 0.971f; + } + if (h_blank_memory_stop_position > bestHTotal || isLargeDiff) { + // _WSN("overflow h_blank_memory_stop_position"); + h_blank_memory_stop_position = h_blank_display_stop_position * 0.64f; + } + + // check whether HS spills over HBSPD + if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync + if (h_sync_start_position >= h_blank_display_stop_position) { + h_sync_start_position = h_blank_display_stop_position * 0.8f; + h_sync_stop_position = 4; // good idea to move this close to 0 as well + } + } else { + if (h_sync_stop_position >= h_blank_display_stop_position) { + h_sync_stop_position = h_blank_display_stop_position * 0.8f; + h_sync_start_position = 4; // + } + } + + // just fix HS + if (isLargeDiff) { + if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync + h_sync_stop_position = 4; + // stop = at least start, then a bit outwards + h_sync_start_position = 16 + (h_blank_display_stop_position * 0.3f); + } else { + h_sync_start_position = 4; + h_sync_stop_position = 16 + (h_blank_display_stop_position * 0.3f); + } + } + + // finally, fix forced timings with large diff + // update: doesn't seem necessary anymore + // if (isLargeDiff) { + // h_blank_display_start_position = bestHTotal * 0.946f; + // h_blank_display_stop_position = bestHTotal * 0.22f; + // h_blank_memory_start_position = h_blank_display_start_position * 0.971f; + // h_blank_memory_stop_position = h_blank_display_stop_position * 0.64f; + + // if (h_sync_start_position > h_sync_stop_position && (h_sync_start_position < (bestHTotal / 2))) { // is neg HSync + // h_sync_stop_position = 0; + // // stop = at least start, then a bit outwards + // h_sync_start_position = 16 + (h_blank_display_stop_position * 0.4f); + // } + // else { + // h_sync_start_position = 0; + // h_sync_stop_position = 16 + (h_blank_display_stop_position * 0.4f); + // } + //} + + if (diffHTotal != 0) { // apply + // delay the change to field start, a bit more compatible + uint16_t timeout = 0; + while ((GBS::STATUS_VDS_FIELD::read() == 1) && (++timeout < 400)) + ; + while ((GBS::STATUS_VDS_FIELD::read() == 0) && (++timeout < 800)) + ; + + GBS::VDS_HSYNC_RST::write(bestHTotal); + GBS::VDS_DIS_HB_ST::write(h_blank_display_start_position); + GBS::VDS_DIS_HB_SP::write(h_blank_display_stop_position); + GBS::VDS_HB_ST::write(h_blank_memory_start_position); + GBS::VDS_HB_SP::write(h_blank_memory_stop_position); + GBS::VDS_HS_ST::write(h_sync_start_position); + GBS::VDS_HS_SP::write(h_sync_stop_position); + } + + bool print = 1; + if (uopt.enableFrameTimeLock) { + // TODO logic! + // if ((GBS::GBS_RUNTIME_FTL_ADJUSTED::read() == 1) && !rto.forceRetime) { + if (!rto.forceRetime) { + // FTL enabled and regular update, so don't print + print = 0; + } + uopt.enableFrameTimeLock = false; + // GBS::GBS_RUNTIME_FTL_ADJUSTED::write(0); + } + + rto.forceRetime = false; + + if (print) { + _WS(F("HTotal Adjust: ")); + if (diffHTotal >= 0) { + _WS(F(" ")); // formatting to align with negative value readouts + } + _WS(diffHTotal); + + if (!rto.extClockGenDetected) { + float sfr = getSourceFieldRate(0); + delay(0); + float ofr = getOutputFrameRate(); + if (sfr < 1.0f) { + sfr = getSourceFieldRate(0); // retry + } + if (ofr < 1.0f) { + ofr = getOutputFrameRate(); // retry + } + _WSF(PSTR(", source Hz: %.3f, output Hz: %.3f\n"), sfr, ofr); + } else { + _WSN(); + } + } + + return true; +} + +/** + * @brief + * + * @return true + * @return false + */ +bool runAutoBestHTotal() +{ + if (!FrameSync::ready() && rto.autoBestHtotalEnabled == true + && rto.videoStandardInput > 0 && rto.videoStandardInput < 15) { + + // _DBGN("running"); + // unsigned long startTime = millis(); + + bool stableNow = 1; + + for (uint8_t i = 0; i < 64; i++) { + if (!getStatus16SpHsStable()) { + stableNow = 0; + // _WSN("prevented: !getStatus16SpHsStable"); + break; + } + } + + if (stableNow) { + if (GBS::STATUS_INT_SOG_BAD::read()) { + // _WSN("prevented_2!"); + resetInterruptSogBadBit(); + delay(40); + stableNow = false; + } + resetInterruptSogBadBit(); + + if (stableNow && (getVideoMode() == rto.videoStandardInput)) { + uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); + uint8_t vdsBusSelBackup = GBS::VDS_TEST_BUS_SEL::read(); + uint8_t ifBusSelBackup = GBS::IF_TEST_SEL::read(); + + if (testBusSelBackup != 0) + GBS::TEST_BUS_SEL::write(0); // needs decimation + if + if (vdsBusSelBackup != 0) + GBS::VDS_TEST_BUS_SEL::write(0); // VDS test # 0 = VBlank + if (ifBusSelBackup != 3) + GBS::IF_TEST_SEL::write(3); // IF averaged frame time + + yield(); + uint16_t bestHTotal = FrameSync::init(); // critical task + yield(); + + GBS::TEST_BUS_SEL::write(testBusSelBackup); // always restore from backup (TB has changed) + if (vdsBusSelBackup != 0) + GBS::VDS_TEST_BUS_SEL::write(vdsBusSelBackup); + if (ifBusSelBackup != 3) + GBS::IF_TEST_SEL::write(ifBusSelBackup); + + if (GBS::STATUS_INT_SOG_BAD::read()) { + // _WSN("prevented_5 INT_SOG_BAD!"); + stableNow = false; + } + for (uint8_t i = 0; i < 16; i++) { + if (!getStatus16SpHsStable()) { + stableNow = 0; + // _WSN("prevented_5: !getStatus16SpHsStable"); + break; + } + } + resetInterruptSogBadBit(); + + if (bestHTotal > 4095) { + if (!rto.forceRetime) { + stableNow = false; + } else { + // roll with it + bestHTotal = 4095; + } + } + + if (stableNow) { + for (uint8_t i = 0; i < 24; i++) { + delay(1); + if (!getStatus16SpHsStable()) { + stableNow = false; + // _WSN("prevented_3!"); + break; + } + } + } + + if (bestHTotal > 0 && stableNow) { + bool success = applyBestHTotal(bestHTotal); + if (success) { + rto.syncLockFailIgnore = 16; + // _WS(F("ok, took: ")); + // _WSN(millis() - startTime); + return true; // success + } + } + } + } + + // reaching here can happen even if stableNow == 1 + if (!stableNow) { + FrameSync::reset(uopt.frameTimeLockMethod); + + if (rto.syncLockFailIgnore > 0) { + rto.syncLockFailIgnore--; + if (rto.syncLockFailIgnore == 0) { + GBS::DAC_RGBS_PWDNZ::write(1); // xth chance + if (!uopt.wantOutputComponent) { + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out // xth chance + } + rto.autoBestHtotalEnabled = false; + } + } + _DBGF(PSTR("bestHtotal retry (%d)\n"), rto.syncLockFailIgnore); + } + } else if (FrameSync::ready()) { + // FS ready but mode is 0 or 15 or autoBestHtotal is off + return true; + } + + if (rto.continousStableCounter != 0 && rto.continousStableCounter != 255) { + rto.continousStableCounter++; // stop repetitions + } + + return false; +} + +/** + * @brief + * + * @return true + * @return false + */ +bool snapToIntegralFrameRate(void) +{ + // Fetch the current output frame rate + float ofr = getOutputFrameRate(); + + if (ofr < 1.0f) { + delay(1); + ofr = getOutputFrameRate(); + } + + float target; + if (ofr > 56.5f && ofr < 64.5f) { + target = 60.0f; // NTSC like + } else if (ofr > 46.5f && ofr < 54.5f) { + target = 50.0f; // PAL like + } else { + // too far out of spec for an auto adjust + _WSN(F("out of bounds")); + return false; + } + + _WSF(PSTR("Snap to %.2fHz\n"), target); + + // We'll be adjusting the htotal incrementally, so store current and best match. + uint16_t currentHTotal = GBS::VDS_HSYNC_RST::read(); + uint16_t closestHTotal = currentHTotal; + + // What's the closest we've been to the frame rate? + float closestDifference = fabs(target - ofr); + + // Repeatedly adjust htotals until we find the closest match. + for (;;) { + + delay(0); + + // Try to move closer to the desired framerate. + if (target > ofr) { + if (currentHTotal > 0 && applyBestHTotal(currentHTotal - 1)) { + --currentHTotal; + } else { + return false; + } + } else if (target < ofr) { + if (currentHTotal < 4095 && applyBestHTotal(currentHTotal + 1)) { + ++currentHTotal; + } else { + return false; + } + } else { + return true; + } + + // Are we closer? + ofr = getOutputFrameRate(); + + if (ofr < 1.0f) { + delay(1); + ofr = getOutputFrameRate(); + } + if (ofr < 1.0f) { + return false; + } + + // If we're getting closer, continue trying, otherwise break out of the test loop. + float newDifference = fabs(target - ofr); + if (newDifference < closestDifference) { + closestDifference = newDifference; + closestHTotal = currentHTotal; + } else { + break; + } + } + + // Reapply the closest htotal if need be. + if (closestHTotal != currentHTotal) { + applyBestHTotal(closestHTotal); + } + + return true; +} + +/** + * @brief blue only mode: t0t44t1 t0t44t4 + * + */ +void applyRGBPatches() +{ + GBS::ADC_RYSEL_R::write(0); // gnd clamp red + GBS::ADC_RYSEL_B::write(0); // gnd clamp blue + GBS::ADC_RYSEL_G::write(0); // gnd clamp green + GBS::DEC_MATRIX_BYPS::write(0); // 5_1f 2 = 1 for YUV / 0 for RGB << using DEC matrix + GBS::IF_MATRIX_BYPS::write(1); + + // if (GBS::GBS_PRESET_CUSTOM::read() == 0) { + // if (!rto.isCustomPreset) { + if (!uopt.slotIsCustom) { + // colors + GBS::VDS_Y_GAIN::write(0x80); // 0x80 = 0 + GBS::VDS_UCOS_GAIN::write(0x1c); + GBS::VDS_VCOS_GAIN::write(0x29); // 0x27 when using IF matrix, 0x29 for DEC matrix + GBS::VDS_Y_OFST::write(0x00); // 0 + GBS::VDS_U_OFST::write(0x00); // 2 + GBS::VDS_V_OFST::write(0x00); // 2 + } + + if (uopt.wantOutputComponent) { + applyComponentColorMixing(); + } +} + +/** + * @brief Set the And Latch Phase S P object + * + */ +void setAndLatchPhaseSP() +{ + GBS::PA_SP_LAT::write(0); // latch off + GBS::PA_SP_S::write(rto.phaseSP); + GBS::PA_SP_LAT::write(1); // latch on +} + +/** + * @brief Set the And Update Sync On Green (SOG) Level object + * Sync detect resolution: 5bits; comparator voltage range 10mv~320mv.-> 10mV + * per step; if cables and source are to standard (level 6 = 60mV) + * @param level + */ +void setAndUpdateSogLevel(uint8_t level) +{ + rto.currentLevelSOG = level & 0x1f; + GBS::ADC_SOGCTRL::write(level); + setAndLatchPhaseSP(); + setAndLatchPhaseADC(); + latchPLLAD(); + GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status + GBS::INTERRUPT_CONTROL_00::write(0x00); + // _DBGF(PSTR("update SOG: %d\n"), rto.currentLevelSOG); +} + +/** + * @brief + * + * @return true + * @return false + */ +bool optimizePhaseSP() +{ + uint16_t pixelClock = GBS::PLLAD_MD::read(); + uint8_t badHt = 0, prevBadHt = 0, worstBadHt = 0, worstPhaseSP = 0, prevPrevBadHt = 0, goodHt = 0; + bool runTest = 1; + + if (GBS::STATUS_SYNC_PROC_HTOTAL::read() < (pixelClock - 8)) { + return 0; + } + if (GBS::STATUS_SYNC_PROC_HTOTAL::read() > (pixelClock + 8)) { + return 0; + } + + if (rto.currentLevelSOG <= 2) { + // not very stable, use fixed values + rto.phaseSP = 16; + rto.phaseADC = 16; + if (rto.videoStandardInput > 0 && rto.videoStandardInput <= 4) { + if (rto.osr == 4) { + rto.phaseADC += 16; + rto.phaseADC &= 0x1f; + } + } + delay(8); // a bit longer, to match default run time + runTest = 0; // skip to end + } + + // unsigned long startTime = millis(); + + if (runTest) { + // 32 distinct phase settings, 3 average samples (missing 2 phase steps) > 34 + for (uint8_t u = 0; u < 34; u++) { + rto.phaseSP++; + rto.phaseSP &= 0x1f; + setAndLatchPhaseSP(); + badHt = 0; + delayMicroseconds(256); + for (uint8_t i = 0; i < 20; i++) { + if (GBS::STATUS_SYNC_PROC_HTOTAL::read() != pixelClock) { + badHt++; + delayMicroseconds(384); + } + } + // if average 3 samples has more badHt than seen yet, this phase step is worse + if ((badHt + prevBadHt + prevPrevBadHt) > worstBadHt) { + worstBadHt = (badHt + prevBadHt + prevPrevBadHt); + worstPhaseSP = (rto.phaseSP - 1) & 0x1f; // medium of 3 samples + } + + if (badHt == 0) { + // count good readings as well, to know whether the entire run is valid + goodHt++; + } + + prevPrevBadHt = prevBadHt; + prevBadHt = badHt; + // _WS(rto.phaseSP); _WS(" badHt: "); _WSN(badHt); + } + + // _WSN(goodHt); + + if (goodHt < 17) { + // _WSN("pxClk unstable"); + return 0; + } + + // adjust global phase values according to test results + if (worstBadHt != 0) { + rto.phaseSP = (worstPhaseSP + 16) & 0x1f; + // assume color signals arrive at same time: phase adc = phase sp + // test in hdbypass mode shows this is more related to sog.. the assumptions seem fine at sog = 8 + rto.phaseADC = 16; //(rto.phaseSP) & 0x1f; + + // different OSR require different phase angles, also depending on bypass, etc + // shift ADC phase 180 degrees for the following + if (rto.videoStandardInput >= 5 && rto.videoStandardInput <= 7) { + if (rto.osr == 2) { + // _WSN("shift adc phase"); + rto.phaseADC += 16; + rto.phaseADC &= 0x1f; + } + } else if (rto.videoStandardInput > 0 && rto.videoStandardInput <= 4) { + if (rto.osr == 4) { + // _WSN("shift adc phase"); + rto.phaseADC += 16; + rto.phaseADC &= 0x1f; + } + } + } else { + // test was always good, so choose any reasonable value + rto.phaseSP = 16; + rto.phaseADC = 16; + if (rto.videoStandardInput > 0 && rto.videoStandardInput <= 4) { + if (rto.osr == 4) { + rto.phaseADC += 16; + rto.phaseADC &= 0x1f; + } + } + } + } + + // _WSN(millis() - startTime); + // _WSN("worstPhaseSP: "); _WSN(worstPhaseSP); + + /*static uint8_t lastLevelSOG = 99; + if (lastLevelSOG != rto.currentLevelSOG) { + _WS(F("Phase: ")); _WS(rto.phaseSP); + _WS(F(" SOG: ")); _WS(rto.currentLevelSOG); + _WSN(); + } + lastLevelSOG = rto.currentLevelSOG;*/ + + setAndLatchPhaseSP(); + delay(1); + setAndLatchPhaseADC(); + + return 1; +} + +/** + * @brief Set the Over Sample Ratio object + * + * @param newRatio + * @param prepareOnly + */ +void setOverSampleRatio(uint8_t newRatio, bool prepareOnly) +{ + uint8_t ks = GBS::PLLAD_KS::read(); + + bool hi_res = rto.videoStandardInput == 8 || rto.videoStandardInput == 4 || rto.videoStandardInput == 3; + // bool bypass = rto.presetID == OutputHdBypass; + // bool bypass = uopt.resolutionID == OutputHdBypass; + + switch (newRatio) { + case 1: + if (ks == 0) + GBS::PLLAD_CKOS::write(0); + if (ks == 1) + GBS::PLLAD_CKOS::write(1); + if (ks == 2) + GBS::PLLAD_CKOS::write(2); + if (ks == 3) + GBS::PLLAD_CKOS::write(3); + GBS::ADC_CLK_ICLK2X::write(0); + GBS::ADC_CLK_ICLK1X::write(0); + GBS::DEC1_BYPS::write(1); // dec1 couples to ADC_CLK_ICLK2X + GBS::DEC2_BYPS::write(1); + + // Necessary to avoid a 2x-scaled image for some reason. + // if (hi_res && !bypass) { + if (hi_res && utilsNotPassThroughMode()) { + GBS::ADC_CLK_ICLK1X::write(1); + // GBS::DEC2_BYPS::write(0); + } + + rto.osr = 1; + // if (!prepareOnly) _WSN(F("OSR 1x")); + + break; + case 2: + if (ks == 0) { + setOverSampleRatio(1, false); + return; + } // 2x impossible + if (ks == 1) + GBS::PLLAD_CKOS::write(0); + if (ks == 2) + GBS::PLLAD_CKOS::write(1); + if (ks == 3) + GBS::PLLAD_CKOS::write(2); + GBS::ADC_CLK_ICLK2X::write(0); + GBS::ADC_CLK_ICLK1X::write(1); + GBS::DEC2_BYPS::write(0); + GBS::DEC1_BYPS::write(1); // dec1 couples to ADC_CLK_ICLK2X + + // if (hi_res && !bypass) { + if (hi_res && utilsNotPassThroughMode()) { + // GBS::ADC_CLK_ICLK2X::write(1); + // GBS::DEC1_BYPS::write(0); + // instead increase CKOS by 1 step + GBS::PLLAD_CKOS::write(GBS::PLLAD_CKOS::read() + 1); + } + + rto.osr = 2; + // if (!prepareOnly) _WSN(F("OSR 2x")); + + break; + case 4: + if (ks == 0) { + setOverSampleRatio(1, false); + return; + } // 4x impossible + if (ks == 1) { + setOverSampleRatio(1, false); + return; + } // 4x impossible + if (ks == 2) + GBS::PLLAD_CKOS::write(0); + if (ks == 3) + GBS::PLLAD_CKOS::write(1); + GBS::ADC_CLK_ICLK2X::write(1); + GBS::ADC_CLK_ICLK1X::write(1); + GBS::DEC1_BYPS::write(0); // dec1 couples to ADC_CLK_ICLK2X + GBS::DEC2_BYPS::write(0); + + rto.osr = 4; + // if (!prepareOnly) _WSN(F("OSR 4x")); + + break; + default: + break; + } + + if (!prepareOnly) + latchPLLAD(); +} + +/** + * @brief + * + * @param withCurrentVideoModeCheck + */ +void updateStopPositionDynamic(bool withCurrentVideoModeCheck) +{ + if (!rto.boardHasPower || rto.sourceDisconnected) { + return; + } + + // _DBGF(PSTR("updateStopPositionDynamic %s video mode check\n"), withCurrentVideoModeCheck ? PSTR("WITH") : PSTR("NO")); + + uint8_t vidModeReadout = getVideoMode(); + // ambigous, best is to check logic sequence or + // delays if an issue occures while reading + // if (vidModeReadout == 0) { + // vidModeReadout = getVideoMode(); + // } + + if (rto.videoStandardInput == 0 && vidModeReadout == 0) { + if (GBS::SP_DLT_REG::read() > 0x30) + GBS::SP_DLT_REG::write(0x30); // 5_35 + else + GBS::SP_DLT_REG::write(0xC0); + return; + } + // reset condition, allow most formats to detect + // compare 1chip snes and ps2 1080p + if (vidModeReadout == 0 && withCurrentVideoModeCheck) { + if ((rto.noSyncCounter % 16) <= 8 && rto.noSyncCounter != 0) { + GBS::SP_DLT_REG::write(0x30); // 5_35 + } else if ((rto.noSyncCounter % 16) > 8 && rto.noSyncCounter != 0) { + GBS::SP_DLT_REG::write(0xC0); // may want to use lower, around 0x70 + } else { + GBS::SP_DLT_REG::write(0x30); + } + GBS::SP_H_PULSE_IGNOR::write(0x02); + // GBS::SP_DIS_SUB_COAST::write(1); + GBS::SP_H_CST_ST::write(0x10); + GBS::SP_H_CST_SP::write(0x100); + GBS::SP_H_COAST::write(0); // 5_3e 2 (just in case) + GBS::SP_H_TIMER_VAL::write(0x3a); // new: 5_33 default 0x3a, set shorter for better hsync drop detect + if (rto.syncTypeCsync) { + GBS::SP_COAST_INV_REG::write(1); // new, allows SP to see otherwise potentially skipped vlines + } + rto.coastPositionIsSet = false; + return; + } + + if (rto.syncTypeCsync) { + GBS::SP_COAST_INV_REG::write(0); + } + + if (rto.videoStandardInput != 0) { + if (rto.videoStandardInput <= 2) { // SD interlaced + GBS::SP_PRE_COAST::write(7); + GBS::SP_POST_COAST::write(3); + GBS::SP_DLT_REG::write(0xC0); // old: 0x140 works better than 0x130 with psx + GBS::SP_H_TIMER_VAL::write(0x28); // 5_33 + + if (rto.syncTypeCsync) { + uint16_t hPeriod = GBS::HPERIOD_IF::read(); + for (int i = 0; i < 16; i++) { + if (hPeriod == 511 || hPeriod < 200) { + hPeriod = GBS::HPERIOD_IF::read(); // retry / overflow + if (i == 15) { + hPeriod = 300; + break; // give up, use short base to get low ignore value later + } + } else { + break; + } + delayMicroseconds(100); + } + + uint16_t ignoreLength = hPeriod * 0.081f; // hPeriod is base length + if (hPeriod <= 200) { // mode is NTSC / PAL, very likely overflow + ignoreLength = 0x18; // use neutral but low value + } + + // get hpw to ht ratio. stability depends on hpll lock + double ratioHs, ratioHsAverage = 0.0; + uint8_t testOk = 0; + for (int i = 0; i < 30; i++) { + ratioHs = (double)GBS::STATUS_SYNC_PROC_HLOW_LEN::read() / (double)(GBS::STATUS_SYNC_PROC_HTOTAL::read() + 1); + if (ratioHs > 0.041 && ratioHs < 0.152) { // 0.152 : (354 / 2345) is 9.5uS on NTSC (crtemudriver) + testOk++; + ratioHsAverage += ratioHs; + if (testOk == 12) { + ratioHs = ratioHsAverage / testOk; + break; + } + delayMicroseconds(30); + } + } + if (testOk != 12) { + // _WS(" testok: "); _WSN(testOk); + ratioHs = 0.032; // 0.032: (~100 / 2560) is ~2.5uS on NTSC (find with crtemudriver) + } + + // _WS(" (debug) hPeriod: "); _WSN(hPeriod); + // _WS(" (debug) ratioHs: "); _WSN(ratioHs, 5); + // _WS(" (debug) ignoreBase: 0x"); _WSF("0x%04X\n", ignoreLength); + uint16_t pllDiv = GBS::PLLAD_MD::read(); + ignoreLength = ignoreLength + (pllDiv * (ratioHs * 0.38)); // for factor: crtemudriver tests + // _WS(F(" (debug) ign.length: 0x"); _WSF("0x%04X\n", ignoreLength); + + // > check relies on sync instability (potentially from too large ign. length) getting cought earlier + if (ignoreLength > GBS::SP_H_PULSE_IGNOR::read() || GBS::SP_H_PULSE_IGNOR::read() >= 0x90) { + if (ignoreLength > 0x90) { // if higher, HPERIOD_IF probably was 511 / limit + ignoreLength = 0x90; + } + if (ignoreLength >= 0x1A && ignoreLength <= 0x42) { + ignoreLength = 0x1A; // at the low end should stick to 0x1A + } + if (ignoreLength != GBS::SP_H_PULSE_IGNOR::read()) { + GBS::SP_H_PULSE_IGNOR::write(ignoreLength); + rto.coastPositionIsSet = 0; // mustn't be skipped, needed when input changes dotclock / Hz + _DBGF(PSTR("ignore Sync H pulses less than length: 0x%04X\n"), ignoreLength); + } + } + } + } else if (rto.videoStandardInput <= 4) { + GBS::SP_PRE_COAST::write(7); // these two were 7 and 6 + GBS::SP_POST_COAST::write(6); // and last 11 and 11 + // 3,3 fixes the ps2 issue but these are too low for format change detects + // update: seems to be an SP bypass only problem (t5t57t6 to 0 also fixes it) + GBS::SP_DLT_REG::write(0xA0); + GBS::SP_H_PULSE_IGNOR::write(0x0E); // ps3: up to 0x3e, ps2: < 0x14 + } else if (rto.videoStandardInput == 5) { // 720p + GBS::SP_PRE_COAST::write(7); // down to 4 ok with ps2 + GBS::SP_POST_COAST::write(7); // down to 6 ok with ps2 // ps3: 8 too much + GBS::SP_DLT_REG::write(0x30); + GBS::SP_H_PULSE_IGNOR::write(0x08); // ps3: 0xd too much + } else if (rto.videoStandardInput <= 7) { // 1080i,p + GBS::SP_PRE_COAST::write(9); + GBS::SP_POST_COAST::write(18); // of 1124 input lines + GBS::SP_DLT_REG::write(0x70); + // ps2 up to 0x06 + // new test shows ps2 alternating between okay and not okay at 0x0a with 5_35=0x70 + GBS::SP_H_PULSE_IGNOR::write(0x06); + } else if (rto.videoStandardInput >= 13) { // 13, 14 and 15 (was just 13 and 15) + if (rto.syncTypeCsync == false) { + GBS::SP_PRE_COAST::write(0x00); + GBS::SP_POST_COAST::write(0x00); + GBS::SP_H_PULSE_IGNOR::write(0xff); // required this because 5_02 0 is on + GBS::SP_DLT_REG::write(0x00); // sometimes enough on it's own, but not always + } else { // csync + GBS::SP_PRE_COAST::write(0x04); // as in bypass mode set function + GBS::SP_POST_COAST::write(0x07); // as in bypass mode set function + GBS::SP_DLT_REG::write(0x70); + GBS::SP_H_PULSE_IGNOR::write(0x02); + } + } + } +} + +/** + * @brief Set the Out Mode Hd Bypass object + * use t5t00t2 and adjust t5t11t5 to find this sources ideal sampling + * clock for this preset (affected by htotal) 2431 for psx, 2437 for MD + * in this mode, sampling clock is free to choose + */ +void setOutputHdBypassMode(bool regsInitialized) +{ + if (!rto.boardHasPower) { + _WSN(F("(!) board not responding")); + return; + } + + rto.autoBestHtotalEnabled = false; // disable while in this mode + rto.outModeHdBypass = OutputHdBypass; // skips waiting at end of doPostPresetLoadSteps + + externalClockGenResetClock(); + updateStopPositionDynamic(false); + loadHdBypassSection(); // this would be ignored otherwise + + // TODO: needs clarification (see: uopt.debugView) + // if (GBS::ADC_UNUSED_62::read() != 0x00) { + // remember debug view + // if (uopt.presetPreference != 2) { + // if (uopt.resolutionID != OutputCustom) { + // serialCommand = 'D'; + // } + // } + + GBS::SP_NO_COAST_REG::write(0); // enable vblank coast (just in case) + GBS::SP_COAST_INV_REG::write(0); // also just in case + + FrameSync::cleanup(); + // GBS::ADC_UNUSED_62::write(0x00); // clear debug view + GBS::RESET_CONTROL_0x46::write(0x00); // 0_46 all off, nothing needs to be enabled for bp mode + GBS::RESET_CONTROL_0x47::write(0x00); + GBS::PA_ADC_BYPSZ::write(1); // enable phase unit ADC + GBS::PA_SP_BYPSZ::write(1); // enable phase unit SP + + // If loading from top-level, clear custom preset flag to avoid stale + // values. If loading after applyPresets() called writeProgramArrayNew(), it + // has already set the flag to 1. + if (!regsInitialized) { + // GBS::GBS_PRESET_CUSTOM::write(0); + // setting force paramter if !registersInitialized + doPostPresetLoadSteps(true); + } + doPostPresetLoadSteps(false); // todo: remove this, code path for hdbypass is hard to follow + + // doPostPresetLoadSteps() sets rto.presetID = GBS_PRESET_ID::read() = + // OutputHdBypass, and rto.isCustomPreset = GBS_PRESET_CUSTOM::read(). + + resetDebugPort(); + + rto.autoBestHtotalEnabled = false; // need to re-set this + GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP, 0 = sync from VDS + + GBS::PLL_CKIS::write(0); // 0_40 0 // 0: PLL uses OSC clock | 1: PLL uses input clock + GBS::PLL_DIVBY2Z::write(0); // 0_40 1 // 1= no divider (full clock, ie 27Mhz) 0 = halved + // GBS::PLL_ADS::write(0); // 0_40 3 test: input clock is from PCLKIN (disconnected, not ADC clock) + GBS::PAD_OSC_CNTRL::write(1); // test: noticed some wave pattern in 720p source, this fixed it + GBS::PLL648_CONTROL_01::write(0x35); + GBS::PLL648_CONTROL_03::write(0x00); + GBS::PLL_LEN::write(1); // 0_43 + GBS::DAC_RGBS_R0ENZ::write(1); + GBS::DAC_RGBS_G0ENZ::write(1); // 0_44 + GBS::DAC_RGBS_B0ENZ::write(1); + GBS::DAC_RGBS_S1EN::write(1); // 0_45 + // from RGBHV tests: the memory bus can be tri stated for noise reduction + GBS::PAD_TRI_ENZ::write(1); // enable tri state + GBS::PLL_MS::write(0b010); // select feedback clock (but need to enable tri state!) + GBS::MEM_PAD_CLK_INVERT::write(0); // helps also + GBS::RESET_CONTROL_0x47::write(0x1f); + + // update: found the real use of HDBypass :D + GBS::DAC_RGBS_BYPS2DAC::write(1); + GBS::SP_HS_LOOP_SEL::write(1); + GBS::SP_HS_PROC_INV_REG::write(0); // (5_56_5) do not invert HS + GBS::SP_CS_P_SWAP::write(0); // old default, set here to reset between HDBypass formats + GBS::SP_HS2PLL_INV_REG::write(0); // same + + GBS::PB_BYPASS::write(1); + GBS::PLLAD_MD::write(2345); // 2326 looks "better" on my LCD but 2345 looks just correct on scope + GBS::PLLAD_KS::write(2); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz + setOverSampleRatio(2, true); + GBS::PLLAD_ICP::write(5); + GBS::PLLAD_FS::write(1); + + if (rto.inputIsYPbPr) { + GBS::DEC_MATRIX_BYPS::write(1); // 5_1f 2 = 1 for YUV / 0 for RGB + GBS::HD_MATRIX_BYPS::write(0); // 1_30 1 / input to jacks is yuv, adc leaves it as yuv > convert to rgb for output here + GBS::HD_DYN_BYPS::write(0); // don't bypass color expansion + // GBS::HD_U_OFFSET::write(3); // color adjust via scope + // GBS::HD_V_OFFSET::write(3); // color adjust via scope + } else { + GBS::DEC_MATRIX_BYPS::write(1); // this is normally RGB input for HDBYPASS out > no color matrix at all + GBS::HD_MATRIX_BYPS::write(1); // 1_30 1 / input is rgb, adc leaves it as rgb > bypass matrix + GBS::HD_DYN_BYPS::write(1); // bypass as well + } + + GBS::HD_SEL_BLK_IN::write(0); // 0 enables HDB blank timing (1 would be DVI, not working atm) + + GBS::SP_SDCS_VSST_REG_H::write(0); // S5_3B + GBS::SP_SDCS_VSSP_REG_H::write(0); // S5_3B + GBS::SP_SDCS_VSST_REG_L::write(0); // S5_3F // 3 for SP sync + GBS::SP_SDCS_VSSP_REG_L::write(2); // S5_40 // 10 for SP sync // check with interlaced sources + + GBS::HD_HSYNC_RST::write(0x3ff); // max 0x7ff + GBS::HD_INI_ST::write(0); // todo: test this at 0 / was 0x298 + // timing into HDB is PLLAD_MD with PLLAD_KS divider: KS = 0 > full PLLAD_MD + if (rto.videoStandardInput <= 2) { + // PAL and NTSC are rewrites, the rest is still handled normally + // These 2 formats now have SP_HS2PLL_INV_REG set. That's the only way I know so far that + // produces recovered HSyncs that align to the falling edge of the input + // ToDo: find reliable input active flank detect to then set SP_HS2PLL_INV_REG correctly + // (for PAL/NTSC polarity is known to be active low, but other formats are variable) + GBS::SP_HS2PLL_INV_REG::write(1); // 5_56 1 lock to falling HS edge // check > sync issues with MD + GBS::SP_CS_P_SWAP::write(1); // 5_3e 0 new: this should negate the problem with inverting HS2PLL + GBS::SP_HS_PROC_INV_REG::write(1); // (5_56_5) invert HS to DEC + // invert mode detect HS/VS triggers, helps PSX NTSC detection. required with 5_3e 0 set + GBS::MD_HS_FLIP::write(1); + GBS::MD_VS_FLIP::write(1); + GBS::OUT_SYNC_SEL::write(2); // new: 0_4f 1=sync from HDBypass, 2=sync from SP, 0 = sync from VDS + GBS::SP_HS_LOOP_SEL::write(0); // 5_57 6 new: use full SP sync, enable HS positioning and pulse length control + GBS::ADC_FLTR::write(3); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + // GBS::HD_INI_ST::write(0x76); // 1_39 + + GBS::HD_HSYNC_RST::write((GBS::PLLAD_MD::read() / 2) + 8); // ADC output pixel count determined + GBS::HD_HB_ST::write(GBS::PLLAD_MD::read() * 0.945f); // 1_3B // no idea why it's not coupled to HD_RST + GBS::HD_HB_SP::write(0x90); // 1_3D + GBS::HD_HS_ST::write(0x80); // 1_3F // but better to use SP sync directly (OUT_SYNC_SEL = 2) + GBS::HD_HS_SP::write(0x00); // 1_41 // + // to use SP sync directly; prepare reasonable out HS length + GBS::SP_CS_HS_ST::write(0xA0); + GBS::SP_CS_HS_SP::write(0x00); + + if (rto.videoStandardInput == 1) { + setCsVsStart(250); // don't invert VS with direct SP sync mode + setCsVsStop(1); // stop relates to HS pulses from CS decoder directly, so mind EQ pulses + GBS::HD_VB_ST::write(500); // 1_43 + GBS::HD_VS_ST::write(3); // 1_47 // but better to use SP sync directly (OUT_SYNC_SEL = 2) + GBS::HD_VS_SP::write(522); // 1_49 // + GBS::HD_VB_SP::write(16); // 1_45 + } + if (rto.videoStandardInput == 2) { + setCsVsStart(301); // don't invert + setCsVsStop(5); // stop past EQ pulses (6 on psx) normally, but HDMI adapter works with -=1 (5) + GBS::HD_VB_ST::write(605); // 1_43 + GBS::HD_VS_ST::write(1); // 1_47 + GBS::HD_VS_SP::write(621); // 1_49 + GBS::HD_VB_SP::write(16); // 1_45 + } + } else if (rto.videoStandardInput == 3 || rto.videoStandardInput == 4) { // 480p, 576p + GBS::ADC_FLTR::write(2); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + GBS::PLLAD_KS::write(1); // 5_16 post divider + GBS::PLLAD_CKOS::write(0); // 5_16 2x OS (with KS=1) + // GBS::HD_INI_ST::write(0x76); // 1_39 + GBS::HD_HB_ST::write(0x864); // 1_3B + // you *must* begin hblank before hsync. + GBS::HD_HB_SP::write(0xa0); // 1_3D + GBS::HD_VB_ST::write(0x00); // 1_43 + GBS::HD_VB_SP::write(0x40); // 1_45 + if (rto.videoStandardInput == 3) { + GBS::HD_HS_ST::write(0x54); // 1_3F + GBS::HD_HS_SP::write(0x864); // 1_41 + GBS::HD_VS_ST::write(0x06); // 1_47 // VS neg + GBS::HD_VS_SP::write(0x00); // 1_49 + setCsVsStart(525 - 5); + setCsVsStop(525 - 3); + } + if (rto.videoStandardInput == 4) { + GBS::HD_HS_ST::write(0x10); // 1_3F + GBS::HD_HS_SP::write(0x880); // 1_41 + GBS::HD_VS_ST::write(0x06); // 1_47 // VS neg + GBS::HD_VS_SP::write(0x00); // 1_49 + setCsVsStart(48); + setCsVsStop(46); + } + } else if (rto.videoStandardInput <= 7 || rto.videoStandardInput == 13) { + // GBS::SP_HS2PLL_INV_REG::write(0); // 5_56 1 use rising edge of tri-level sync // always 0 now + if (rto.videoStandardInput == 5) { // 720p + GBS::PLLAD_MD::write(2474); // override from 2345 + GBS::HD_HSYNC_RST::write(550); // 1_37 + // GBS::HD_INI_ST::write(78); // 1_39 + // 720p has high pllad vco output clock, so don't do oversampling + GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz + GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) + GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) + GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) + GBS::PLLAD_ICP::write(6); // fine at 6 only, FS is 1 + GBS::PLLAD_FS::write(1); + GBS::HD_HB_ST::write(0); // 1_3B + GBS::HD_HB_SP::write(0x140); // 1_3D + GBS::HD_HS_ST::write(0x20); // 1_3F + GBS::HD_HS_SP::write(0x80); // 1_41 + GBS::HD_VB_ST::write(0x00); // 1_43 + GBS::HD_VB_SP::write(0x6c); // 1_45 // ps3 720p tested + GBS::HD_VS_ST::write(0x00); // 1_47 + GBS::HD_VS_SP::write(0x05); // 1_49 + setCsVsStart(2); + setCsVsStop(0); + } + if (rto.videoStandardInput == 6) { // 1080i + // interl. source + GBS::HD_HSYNC_RST::write(0x710); // 1_37 + // GBS::HD_INI_ST::write(2); // 1_39 + GBS::PLLAD_KS::write(1); // 5_16 post divider + GBS::PLLAD_CKOS::write(0); // 5_16 2x OS (with KS=1) + GBS::ADC_FLTR::write(1); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + GBS::HD_HB_ST::write(0); // 1_3B + GBS::HD_HB_SP::write(0xb8); // 1_3D + GBS::HD_HS_ST::write(0x04); // 1_3F + GBS::HD_HS_SP::write(0x50); // 1_41 + GBS::HD_VB_ST::write(0x00); // 1_43 + GBS::HD_VB_SP::write(0x1e); // 1_45 + GBS::HD_VS_ST::write(0x04); // 1_47 + GBS::HD_VS_SP::write(0x09); // 1_49 + setCsVsStart(8); + setCsVsStop(6); + } + if (rto.videoStandardInput == 7) { // 1080p + GBS::PLLAD_MD::write(2749); // override from 2345 + GBS::HD_HSYNC_RST::write(0x710); // 1_37 + // GBS::HD_INI_ST::write(0xf0); // 1_39 + // 1080p has highest pllad vco output clock, so don't do oversampling + GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz + GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) + GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) + GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) + GBS::PLLAD_ICP::write(6); // was 5, fine at 6 as well, FS is 1 + GBS::PLLAD_FS::write(1); + GBS::HD_HB_ST::write(0x00); // 1_3B + GBS::HD_HB_SP::write(0xb0); // 1_3D // d0 + GBS::HD_HS_ST::write(0x20); // 1_3F + GBS::HD_HS_SP::write(0x70); // 1_41 + GBS::HD_VB_ST::write(0x00); // 1_43 + GBS::HD_VB_SP::write(0x2f); // 1_45 + GBS::HD_VS_ST::write(0x04); // 1_47 + GBS::HD_VS_SP::write(0x0A); // 1_49 + } + if (rto.videoStandardInput == 13) { // odd HD mode (PS2 "VGA" over Component) + applyRGBPatches(); // treat mostly as RGB, clamp R/B to gnd + rto.syncTypeCsync = true; // used in loop to set clamps and SP dynamic + GBS::DEC_MATRIX_BYPS::write(1); // overwrite for this mode + GBS::SP_PRE_COAST::write(4); + GBS::SP_POST_COAST::write(4); + GBS::SP_DLT_REG::write(0x70); + GBS::HD_MATRIX_BYPS::write(1); // bypass since we'll treat source as RGB + GBS::HD_DYN_BYPS::write(1); // bypass since we'll treat source as RGB + GBS::SP_VS_PROC_INV_REG::write(0); // don't invert + // same as with RGBHV, the ps2 resolution can vary widely + GBS::PLLAD_KS::write(0); // 5_16 post divider 0 : FCKO1 > 87MHz, 3 : FCKO1<23MHz + GBS::PLLAD_CKOS::write(0); // 5_16 1x OS (with KS=CKOS=0) + GBS::ADC_CLK_ICLK1X::write(0); // 5_00 4 (OS=1) + GBS::ADC_CLK_ICLK2X::write(0); // 5_00 3 (OS=1) + GBS::DEC1_BYPS::write(1); // 5_1f 1 // dec1 disabled (OS=1) + GBS::DEC2_BYPS::write(1); // 5_1f 1 // dec2 disabled (OS=1) + GBS::PLLAD_MD::write(512); // could try 856 + } + } + + if (rto.videoStandardInput == 13) { + // section is missing HD_HSYNC_RST and HD_INI_ST adjusts + uint16_t vtotal = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + if (vtotal < 532) { // 640x480 or less + GBS::PLLAD_KS::write(3); + GBS::PLLAD_FS::write(1); + } else if (vtotal >= 532 && vtotal < 810) { // 800x600, 1024x768 + // GBS::PLLAD_KS::write(3); // just a little too much at 1024x768 + GBS::PLLAD_FS::write(0); + GBS::PLLAD_KS::write(2); + } else { // if (vtotal > 1058 && vtotal < 1074) // 1280x1024 + GBS::PLLAD_KS::write(2); + GBS::PLLAD_FS::write(1); + } + } + + GBS::DEC_IDREG_EN::write(1); // 5_1f 7 + GBS::DEC_WEN_MODE::write(1); // 5_1e 7 // 1 keeps ADC phase consistent. around 4 lock positions vs totally random + rto.phaseSP = 8; + rto.phaseADC = 24; // fix value // works best with yuv input in tests + setAndUpdateSogLevel(rto.currentLevelSOG); // also re-latch everything + + // FIXME: double reset? + rto.outModeHdBypass = OutputHdBypass; + + unsigned long timeout = millis(); + while ((!getStatus16SpHsStable()) && (millis() - timeout < 2002)) { + delay(1); + } + while ((getVideoMode() == 0) && (millis() - timeout < 1502)) { + delay(1); + } + // currently SP is using generic settings, switch to format specific ones + updateStopPositionDynamic(false); + while ((getVideoMode() == 0) && (millis() - timeout < 1502)) { + delay(1); + } + + GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out + GBS::GBS_PRESET_ID::write(OutputHdBypass); + + delay(200); + + optimizePhaseSP(); +} + +/** + * @brief Set the Adc Gain object + * Write ADC gain registers, and save in adco.r_gain to properly transfer it + * across loading presets or passthrough. + * @param gain + */ +void setAdcGain(uint8_t gain) +{ + // gain is actually range, increasing it dims the image. + GBS::ADC_RGCTRL::write(gain); + GBS::ADC_GGCTRL::write(gain); + GBS::ADC_BGCTRL::write(gain); + + // Save gain for applying preset. (Gain affects passthrough presets, and + // loading a passthrough preset loads from adco but doesn't save to it.) + adco.r_gain = gain; + adco.g_gain = gain; + adco.b_gain = gain; +} + +/** + * @brief + * + */ +void resetSyncProcessor() +{ + GBS::SFTRST_SYNC_RSTZ::write(0); + delayMicroseconds(10); + GBS::SFTRST_SYNC_RSTZ::write(1); + // rto.clampPositionIsSet = false; // resetSyncProcessor is part of autosog + // rto.coastPositionIsSet = false; +} + +/** + * @brief + * + */ +void togglePhaseAdjustUnits() +{ + GBS::PA_SP_BYPSZ::write(0); // yes, 0 means bypass on here + GBS::PA_SP_BYPSZ::write(1); + delay(2); + GBS::PA_ADC_BYPSZ::write(0); + GBS::PA_ADC_BYPSZ::write(1); + delay(2); +} + +/** + * @brief + * + */ +void setOutputRGBHVBypassMode() +{ + if (!rto.boardHasPower) { + _WSN(F("(!) board not responding!")); + return; + } + + GBS::DAC_RGBS_PWDNZ::write(0); // disable DAC + GBS::PAD_SYNC_OUT_ENZ::write(1); // disable sync out + + rto.outModeHdBypass = OutputRGBHVBypass; // bypass flavor 2, used to signal buttons in web ui + loadHdBypassSection(); + externalClockGenResetClock(); + FrameSync::cleanup(); + // GBS::ADC_UNUSED_62::write(0x00); // clear debug view + GBS::PA_ADC_BYPSZ::write(1); // enable phase unit ADC + GBS::PA_SP_BYPSZ::write(1); // enable phase unit SP + applyRGBPatches(); + resetDebugPort(); + rto.videoStandardInput = 15; // making sure + rto.autoBestHtotalEnabled = false; // not necessary, since VDS is off / bypassed // todo: mode 14 (works anyway) + rto.clampPositionIsSet = false; + rto.HPLLState = 0; + + GBS::PLL_CKIS::write(0); // 0_40 0 // 0: PLL uses OSC clock | 1: PLL uses input clock + GBS::PLL_DIVBY2Z::write(0); // 0_40 1 // 1= no divider (full clock, ie 27Mhz) 0 = halved clock + GBS::PLL_ADS::write(0); // 0_40 3 test: input clock is from PCLKIN (disconnected, not ADC clock) + GBS::PLL_MS::write(0b010); // 0_40 4-6 select feedback clock (but need to enable tri state!) + GBS::PAD_TRI_ENZ::write(1); // enable some pad's tri state (they become high-z / inputs), helps noise + GBS::MEM_PAD_CLK_INVERT::write(0); // helps also + GBS::PLL648_CONTROL_01::write(0x35); + GBS::PLL648_CONTROL_03::write(0x00); // 0_43 + GBS::PLL_LEN::write(1); // 0_43 + + GBS::DAC_RGBS_ADC2DAC::write(1); + GBS::OUT_SYNC_SEL::write(1); // 0_4f 1=sync from HDBypass, 2=sync from SP, (00 = from VDS) + + GBS::SFTRST_HDBYPS_RSTZ::write(1); // enable + GBS::HD_INI_ST::write(0); // needs to be some small value or apparently 0 works + // GBS::DAC_RGBS_BYPS2DAC::write(1); + // GBS::OUT_SYNC_SEL::write(2); // 0_4f sync from SP + // GBS::SFTRST_HDBYPS_RSTZ::write(1); // need HDBypass + // GBS::SP_HS_LOOP_SEL::write(1); // (5_57_6) // can bypass since HDBypass does sync + GBS::HD_MATRIX_BYPS::write(1); // bypass since we'll treat source as RGB + GBS::HD_DYN_BYPS::write(1); // bypass since we'll treat source as RGB + // GBS::HD_SEL_BLK_IN::write(1); // "DVI", not regular + + GBS::PAD_SYNC1_IN_ENZ::write(0); // filter H/V sync input1 (0 = on) + GBS::PAD_SYNC2_IN_ENZ::write(0); // filter H/V sync input2 (0 = on) + + GBS::SP_SOG_P_ATO::write(1); // 5_20 1 corrects hpw readout and slightly affects sync + if (rto.syncTypeCsync == false) { + GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: from hs // use ADC and turn it off = no SOG + GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG // having it 0 drags down the SOG (hsync) input; = 1: need to supress SOG decoding + GBS::SP_EXT_SYNC_SEL::write(0); // connect HV input ( 5_20 bit 3 ) + GBS::SP_SOG_MODE::write(0); // 5_56 bit 0 // 0: normal, 1: SOG + GBS::SP_NO_COAST_REG::write(1); // vblank coasting off + GBS::SP_PRE_COAST::write(0); + GBS::SP_POST_COAST::write(0); + GBS::SP_H_PULSE_IGNOR::write(0xff); // cancel out SOG decoding + GBS::SP_SYNC_BYPS::write(0); // external H+V sync for decimator (+ sync out) | 1 to mirror in sync, 0 to output processed sync + GBS::SP_HS_POL_ATO::write(1); // 5_55 4 auto polarity for retiming + GBS::SP_VS_POL_ATO::write(1); // 5_55 6 + GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS + GBS::SP_H_PROTECT::write(0); // 5_3e 4 disable for H/V + rto.phaseADC = 16; + rto.phaseSP = 8; + } else { + // todo: SOG SRC can be ADC or HS input pin. HS requires TTL level, ADC can use lower levels + // HS seems to have issues at low PLL speeds + // maybe add detection whether ADC Sync is needed + GBS::SP_SOG_SRC_SEL::write(0); // 5_20 0 | 0: from ADC 1: hs is sog source + GBS::SP_EXT_SYNC_SEL::write(1); // disconnect HV input + GBS::ADC_SOGEN::write(1); // 5_02 0 ADC SOG + GBS::SP_SOG_MODE::write(1); // apparently needs to be off for HS input (on for ADC) + GBS::SP_NO_COAST_REG::write(0); // vblank coasting on + GBS::SP_PRE_COAST::write(4); // 5_38, > 4 can be seen with clamp invert on the lower lines + GBS::SP_POST_COAST::write(7); + GBS::SP_SYNC_BYPS::write(0); // use regular sync for decimator (and sync out) path + GBS::SP_HS_LOOP_SEL::write(1); // 5_57_6 | 0 enables retiming on SP | 1 to bypass input to HDBYPASS + GBS::SP_H_PROTECT::write(1); // 5_3e 4 enable for SOG + rto.currentLevelSOG = 24; + rto.phaseADC = 16; + rto.phaseSP = 8; + } + GBS::SP_CLAMP_MANUAL::write(1); // needs to be 1 + GBS::SP_COAST_INV_REG::write(0); // just in case + + GBS::SP_DIS_SUB_COAST::write(1); // 5_3e 5 + GBS::SP_HS_PROC_INV_REG::write(0); // 5_56 5 + GBS::SP_VS_PROC_INV_REG::write(0); // 5_56 6 + GBS::PLLAD_KS::write(1); // 0 - 3 + setOverSampleRatio(2, true); // prepare only = true + GBS::DEC_MATRIX_BYPS::write(1); // 5_1f with adc to dac mode + GBS::ADC_FLTR::write(0); // 5_03 4/5 ADC filter 3=40, 2=70, 1=110, 0=150 Mhz + + GBS::PLLAD_ICP::write(4); + GBS::PLLAD_FS::write(0); // low gain + GBS::PLLAD_MD::write(1856); // 1349 perfect for for 1280x+ ; 1856 allows lower res to detect + + // T4R0x2B Bit: 3 (was 0x7) is now: 0xF + // S0R0x4F (was 0x80) is now: 0xBC + // 0_43 1a + // S5R0x2 (was 0x48) is now: 0x54 + // s5s11sb2 + // 0x25, // s0_44 + // 0x11, // s0_45 + // new: do without running default preset first + GBS::ADC_TA_05_CTRL::write(0x02); // 5_05 1 // minor SOG clamp effect + GBS::ADC_TEST_04::write(0x02); // 5_04 + GBS::ADC_TEST_0C::write(0x12); // 5_0c 1 4 + GBS::DAC_RGBS_R0ENZ::write(1); + GBS::DAC_RGBS_G0ENZ::write(1); + GBS::DAC_RGBS_B0ENZ::write(1); + GBS::OUT_SYNC_CNTRL::write(1); + // resetPLL(); // try to avoid this + resetDigital(); // this will leave 0_46 all 0 + resetSyncProcessor(); // required to initialize SOG status + delay(2); + ResetSDRAM(); + delay(2); + resetPLLAD(); + togglePhaseAdjustUnits(); + delay(20); + GBS::PLLAD_LEN::write(1); // 5_11 1 + GBS::DAC_RGBS_PWDNZ::write(1); // enable DAC + GBS::PAD_SYNC_OUT_ENZ::write(0); // enable sync out + + // todo: detect if H-PLL parameters fit the source before aligning clocks (5_11 etc) + + setAndLatchPhaseSP(); // different for CSync and pure HV modes + setAndLatchPhaseADC(); + latchPLLAD(); + + if (uopt.enableAutoGain == 1 && adco.r_gain == 0) { + // _WSN(F("ADC gain: reset")); + setAdcGain(AUTO_GAIN_INIT); + GBS::DEC_TEST_ENABLE::write(1); + } else if (uopt.enableAutoGain == 1 && adco.r_gain != 0) { + /*_WSN(F("ADC gain: keep previous")); + _WSF("0x%04X", adco.r_gain); _WS(F(" ")); + _WSF("0x%04X", adco.g_gain); _WS(F(" ")); + _WSF("0x%04X", adco.b_gain); _WSN(F(" "));*/ + GBS::ADC_RGCTRL::write(adco.r_gain); + GBS::ADC_GGCTRL::write(adco.g_gain); + GBS::ADC_BGCTRL::write(adco.b_gain); + GBS::DEC_TEST_ENABLE::write(1); + } else { + GBS::DEC_TEST_ENABLE::write(0); // no need for decimation test to be enabled + } + + // rto.presetID = OutputRGBHVBypass; // bypass flavor 2, used to signal buttons in web ui + GBS::GBS_PRESET_ID::write(OutputRGBHVBypass); + delay(200); +} + +/** + * @brief + * + */ +void runAutoGain() +{ + static unsigned long lastTimeAutoGain = millis(); + uint8_t limit_found = 0, greenValue = 0; + uint8_t loopCeiling = 0; + uint8_t status00reg = GBS::STATUS_00::read(); // confirm no mode changes happened + + // GBS::DEC_TEST_SEL::write(5); + + // for (uint8_t i = 0; i < 14; i++) { + // uint8_t greenValue = GBS::TEST_BUS_2E::read(); + // if (greenValue >= 0x28 && greenValue <= 0x2f) { // 0x2c seems to be "highest" (haven't seen 0x2b yet) + // if (getStatus16SpHsStable() && (GBS::STATUS_00::read() == status00reg)) { + // limit_found++; + // } + // else return; + // } + // } + + if ((millis() - lastTimeAutoGain) < 30000) { + loopCeiling = 61; + } else { + loopCeiling = 8; + } + + for (uint8_t i = 0; i < loopCeiling; i++) { + if (i % 20 == 0) { + // wifiLoop(0); + limit_found = 0; + } + greenValue = GBS::TEST_BUS_2F::read(); + + if (greenValue == 0x7f) { + if (getStatus16SpHsStable() && (GBS::STATUS_00::read() == status00reg)) { + limit_found++; + // 240p test suite (SNES ver): display vertical lines (hor. line test) + // _WS("g: "); _WSN(greenValue, HEX); + // _WS("--"); _WSN(); + } else + return; + + if (limit_found == 2) { + limit_found = 0; + uint8_t level = GBS::ADC_GGCTRL::read(); + if (level < 0xfe) { + setAdcGain(level + 2); + + // remember these gain settings + adco.r_gain = GBS::ADC_RGCTRL::read(); + adco.g_gain = GBS::ADC_GGCTRL::read(); + adco.b_gain = GBS::ADC_BGCTRL::read(); + // @sk: suspended + // printInfo(); + // delay(2); // let it settle a little + lastTimeAutoGain = millis(); + } + } + } + } +} + +/** + * @brief + * + */ +void enableScanlines() +{ + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 0) { + + // GBS::RFF_ADR_ADD_2::write(0); + // GBS::RFF_REQ_SEL::write(1); + // GBS::RFF_MASTER_FLAG::write(0x3f); + // GBS::RFF_WFF_OFFSET::write(0); // scanline fix + // GBS::RFF_FETCH_NUM::write(0); + // GBS::RFF_ENABLE::write(1); //GBS::WFF_ENABLE::write(1); + // delay(10); + // GBS::RFF_ENABLE::write(0); //GBS::WFF_ENABLE::write(0); + + // following lines set up UV deinterlacer (on top of normal Y) + GBS::MADPT_UVDLY_PD_SP::write(0); // 2_39 0..3 + GBS::MADPT_UVDLY_PD_ST::write(0); // 2_39 4..7 + GBS::MADPT_EN_UV_DEINT::write(1); // 2_3a 0 + GBS::MADPT_UV_MI_DET_BYPS::write(1); // 2_3a 7 enables 2_3b adjust + GBS::MADPT_UV_MI_OFFSET::write(uopt.scanlineStrength); // 2_3b offset (mixing factor here) + GBS::MADPT_MO_ADP_UV_EN::write(1); // 2_16 5 (try to do this some other way?) + + GBS::DIAG_BOB_PLDY_RAM_BYPS::write(0); // 2_00 7 enabled, looks better + GBS::MADPT_PD_RAM_BYPS::write(0); // 2_24 2 + GBS::RFF_YUV_DEINTERLACE::write(1); // scanline fix 2 + GBS::MADPT_Y_MI_DET_BYPS::write(1); // make sure, so that mixing works + // GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() + 0x30); // more luma gain + // GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 4); + GBS::VDS_WLEV_GAIN::write(0x08); // 3_58 + GBS::VDS_W_LEV_BYPS::write(0); // brightness + GBS::MADPT_VIIR_COEF::write(0x08); // 2_27 VIIR filter strength + GBS::MADPT_Y_MI_OFFSET::write(uopt.scanlineStrength); // 2_0b offset (mixing factor here) + GBS::MADPT_VIIR_BYPS::write(0); // 2_26 6 VIIR line fifo // 1 = off + GBS::RFF_LINE_FLIP::write(1); // clears potential garbage in rff buffer + + GBS::MAPDT_VT_SEL_PRGV::write(0); + // GBS::GBS_OPTION_SCANLINES_ENABLED::write(1); + uopt.wantScanlines = true; + // } + rto.scanlinesEnabled = true; +} + +/** + * @brief + * + */ +void disableScanlines() +{ + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { + GBS::MAPDT_VT_SEL_PRGV::write(1); + // following lines set up UV deinterlacer (on top of normal Y) + GBS::MADPT_UVDLY_PD_SP::write(4); // 2_39 0..3 + GBS::MADPT_UVDLY_PD_ST::write(4); // 2_39 4..77 + GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 + GBS::MADPT_UV_MI_DET_BYPS::write(0); // 2_3a 7 enables 2_3b adjust + GBS::MADPT_UV_MI_OFFSET::write(4); // 2_3b + GBS::MADPT_MO_ADP_UV_EN::write(0); // 2_16 5 + + GBS::DIAG_BOB_PLDY_RAM_BYPS::write(1); // 2_00 7 + GBS::VDS_W_LEV_BYPS::write(1); // brightness + // GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() - 0x30); + // GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() - 4); + GBS::MADPT_Y_MI_OFFSET::write(0xff); // 2_0b offset 0xff disables mixing + GBS::MADPT_VIIR_BYPS::write(1); // 2_26 6 disable VIIR + GBS::MADPT_PD_RAM_BYPS::write(1); + GBS::RFF_LINE_FLIP::write(0); // back to default + + // GBS::GBS_OPTION_SCANLINES_ENABLED::write(0); + uopt.wantScanlines = false; + // } + rto.scanlinesEnabled = false; +} + +/** + * @brief + * + */ +void enableMotionAdaptDeinterlace() +{ + freezeVideo(); + GBS::DEINT_00::write(0x19); // 2_00 // bypass angular (else 0x00) + GBS::MADPT_Y_MI_OFFSET::write(0x00); // 2_0b // also used for scanline mixing + // GBS::MADPT_STILL_NOISE_EST_EN::write(1); // 2_0A 5 (was 0 before) + GBS::MADPT_Y_MI_DET_BYPS::write(0); // 2_0a_7 // switch to automatic motion indexing + // GBS::MADPT_UVDLY_PD_BYPS::write(0); // 2_35_5 // UVDLY + // GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 + // GBS::MADPT_EN_STILL_FOR_NRD::write(1); // 2_3a 3 (new) + + if (rto.videoStandardInput == 1) + GBS::MADPT_VTAP2_COEFF::write(6); // 2_19 vertical filter + if (rto.videoStandardInput == 2) + GBS::MADPT_VTAP2_COEFF::write(4); + + // GBS::RFF_WFF_STA_ADDR_A::write(0); + // GBS::RFF_WFF_STA_ADDR_B::write(1); + GBS::RFF_ADR_ADD_2::write(1); + GBS::RFF_REQ_SEL::write(3); + // GBS::RFF_MASTER_FLAG::write(0x24); // use preset's value + // GBS::WFF_SAFE_GUARD::write(0); // 4_42 3 + GBS::RFF_FETCH_NUM::write(0x80); // part of RFF disable fix, could leave 0x80 always otherwise + GBS::RFF_WFF_OFFSET::write(0x100); // scanline fix + GBS::RFF_YUV_DEINTERLACE::write(0); // scanline fix 2 + GBS::WFF_FF_STA_INV::write(0); // 4_42_2 // 22.03.19 : turned off // update: only required in PAL? + // GBS::WFF_LINE_FLIP::write(0); // 4_4a_4 // 22.03.19 : turned off // update: only required in PAL? + GBS::WFF_ENABLE::write(1); // 4_42 0 // enable before RFF + GBS::RFF_ENABLE::write(1); // 4_4d 7 + // delay(60); // 55 first good + unfreezeVideo(); + delay(60); + GBS::MAPDT_VT_SEL_PRGV::write(0); // 2_16_7 + rto.motionAdaptiveDeinterlaceActive = true; +} + +/** + * @brief + * + */ +void disableMotionAdaptDeinterlace() +{ + GBS::MAPDT_VT_SEL_PRGV::write(1); // 2_16_7 + GBS::DEINT_00::write(0xff); // 2_00 + + GBS::RFF_FETCH_NUM::write(0x1); // RFF disable fix + GBS::RFF_WFF_OFFSET::write(0x1); // RFF disable fix + delay(2); + GBS::WFF_ENABLE::write(0); + GBS::RFF_ENABLE::write(0); // can cause mem reset requirement, procedure above should fix it + + // GBS::WFF_ADR_ADD_2::write(0); + GBS::WFF_FF_STA_INV::write(1); // 22.03.19 : turned off // update: only required in PAL? + // GBS::WFF_LINE_FLIP::write(1); // 22.03.19 : turned off // update: only required in PAL? + GBS::MADPT_Y_MI_OFFSET::write(0x7f); + // GBS::MADPT_STILL_NOISE_EST_EN::write(0); // new + GBS::MADPT_Y_MI_DET_BYPS::write(1); + // GBS::MADPT_UVDLY_PD_BYPS::write(1); // 2_35_5 + // GBS::MADPT_EN_UV_DEINT::write(0); // 2_3a 0 + // GBS::MADPT_EN_STILL_FOR_NRD::write(0); // 2_3a 3 (new) + rto.motionAdaptiveDeinterlaceActive = false; +} + +/** + * @brief programs all valid registers (the register map has holes in + * it, so it's not straight forward) 'index' keeps track of the current + * preset data location. + * + * @param programArray + * @param skipMDSection + */ +void writeProgramArrayNew(const uint8_t *programArray, bool skipMDSection) +{ + uint16_t index = 0; + uint8_t bank[16]; + uint8_t y = 0; + + // GBS::PAD_SYNC_OUT_ENZ::write(1); + // GBS::DAC_RGBS_PWDNZ::write(0); // no DAC + // GBS::SFTRST_MEM_FF_RSTZ::write(0); // stop mem fifos + + FrameSync::cleanup(); + + // should only be possible if previously was in RGBHV bypass, then hit a manual preset switch + if (rto.videoStandardInput == 15) { + rto.videoStandardInput = 0; + } + // ! reset Bypass + rto.outModeHdBypass = None; // the default at this stage + + if (GBS::ADC_INPUT_SEL::read() == 0) { + // if (rto.inputIsYPbPr == 0) _WSN(F("rto.inputIsYPbPr was 0, fixing to 1"); + rto.inputIsYPbPr = 1; // new: update the var here, allow manual preset loads + } else { + // if (rto.inputIsYPbPr == 1) _WSN(F("rto.inputIsYPbPr was 1, fixing to 0"); + rto.inputIsYPbPr = 0; + } + + uint8_t reset46 = GBS::RESET_CONTROL_0x46::read(); // for keeping these as they are now + uint8_t reset47 = GBS::RESET_CONTROL_0x47::read(); + + while(y < 6) { + writeOneByte(0xF0, y); + switch (y) { + case 0: + for (int j = 0; j <= 1; j++) { // 2 times + for (int x = 0; x <= 15; x++) { + if (j == 0 && x == 4) { + // keep DAC off + if (rto.useHdmiSyncFix) { + bank[x] = pgm_read_byte(programArray + index) & ~(1 << 0); + } else { + bank[x] = pgm_read_byte(programArray + index); + } + } else if (j == 0 && x == 6) { + bank[x] = reset46; + } else if (j == 0 && x == 7) { + bank[x] = reset47; + } else if (j == 0 && x == 9) { + // keep sync output off + if (rto.useHdmiSyncFix) { + bank[x] = pgm_read_byte(programArray + index) | (1 << 2); + } else { + bank[x] = pgm_read_byte(programArray + index); + } + } else { + // use preset values + bank[x] = pgm_read_byte(programArray + index); + } + + index++; + } + writeBytes(0x40 + (j * 16), bank, 16); + } + copyBank(bank, programArray, &index); + writeBytes(0x90, bank, 16); + break; + case 1: + for (int j = 0; j <= 2; j++) { // 3 times + copyBank(bank, programArray, &index); + if (j == 0) { + bank[0] = bank[0] & ~(1 << 5); // clear 1_00 5 + bank[1] = bank[1] | (1 << 0); // set 1_01 0 + bank[12] = bank[12] & 0x0f; // clear 1_0c upper bits + bank[13] = 0; // clear 1_0d + } + writeBytes(j * 16, bank, 16); + } + if (!skipMDSection) { + loadPresetMdSection(); + if (rto.syncTypeCsync) + GBS::MD_SEL_VGA60::write(0); // EDTV possible + else + GBS::MD_SEL_VGA60::write(1); // VGA 640x480 more likely + + GBS::MD_HD1250P_CNTRL::write(rto.medResLineCount); // patch med res support + } + break; + case 2: + loadPresetDeinterlacerSection(); + break; + case 3: + for (int j = 0; j <= 7; j++) { // 8 times + copyBank(bank, programArray, &index); + // if (rto.useHdmiSyncFix) { + // if (j == 0) { + // bank[0] = bank[0] | (1 << 0); // 3_00 0 sync lock + // } + // if (j == 1) { + // bank[10] = bank[10] | (1 << 4); // 3_1a 4 frame lock + // } + // } + writeBytes(j * 16, bank, 16); + } + // blank out VDS PIP registers, otherwise they can end up uninitialized + for (int x = 0; x <= 15; x++) { + writeOneByte(0x80 + x, 0x00); + } + break; + case 4: + for (int j = 0; j <= 5; j++) { // 6 times + copyBank(bank, programArray, &index); + writeBytes(j * 16, bank, 16); + } + break; + case 5: + for (int j = 0; j <= 6; j++) { // 7 times + for (int x = 0; x <= 15; x++) { + bank[x] = pgm_read_byte(programArray + index); + if (index == 322) { // s5_02 bit 6+7 = input selector (only bit 6 is relevant) + if (rto.inputIsYPbPr) + bitClear(bank[x], 6); + else + bitSet(bank[x], 6); + } + if (index == 323) { // s5_03 set clamps according to input channel + if (rto.inputIsYPbPr) { + bitClear(bank[x], 2); // G bottom clamp + bitSet(bank[x], 1); // R mid clamp + bitSet(bank[x], 3); // B mid clamp + } else { + bitClear(bank[x], 2); // G bottom clamp + bitClear(bank[x], 1); // R bottom clamp + bitClear(bank[x], 3); // B bottom clamp + } + } + // if (index == 324) { // s5_04 reset(0) for ADC REF init + // bank[x] = 0x00; + // } + if (index == 352) { // s5_20 always force to 0x02 (only SP_SOG_P_ATO) + bank[x] = 0x02; + } + if (index == 375) { // s5_37 + if (videoStandardInputIsPalNtscSd()) { + bank[x] = 0x6b; + } else { + bank[x] = 0x02; + } + } + if (index == 382) { // s5_3e + bitSet(bank[x], 5); // SP_DIS_SUB_COAST = 1 + } + if (index == 407) { // s5_57 + bitSet(bank[x], 0); // SP_NO_CLAMP_REG = 1 + } + index++; + } + writeBytes(j * 16, bank, 16); + } + break; + } + y++; + } + + // scaling RGBHV mode + if (uopt.preferScalingRgbhv && rto.isValidForScalingRGBHV) { + // GBS::GBS_OPTION_SCALING_RGBHV::write(1); + rto.videoStandardInput = 3; + } +} + +/** + * @brief + * + */ +void activeFrameTimeLockInitialSteps() +{ + // skip if using external clock gen + if (rto.extClockGenDetected) { + _WSN(F("Active FrameTime Lock enabled, adjusting external clock gen frequency")); + return; + } + // skip when out mode = bypass + // if (rto.presetID != OutputHdBypass && rto.presetID != OutputRGBHVBypass) { + if (utilsNotPassThroughMode()) { + _WS(F("Active FrameTime Lock enabled, disable if display unstable or stays blank! Method: ")); + if (uopt.frameTimeLockMethod == 0) { + _WSN(F("0 (vtotal + VSST)")); + } + if (uopt.frameTimeLockMethod == 1) { + _WSN(F("1 (vtotal only)")); + } + if (GBS::VDS_VS_ST::read() == 0) { + // VS_ST needs to be at least 1, so method 1 can decrease it when needed (but currently only increases VS_ST) + // don't force this here, instead make sure to have all presets follow the rule (easier dev) + _WSN(F("Warning: Check VDS_VS_ST!")); + } + } +} + +/** + * @brief + * + */ +void applyComponentColorMixing() +{ + GBS::VDS_Y_GAIN::write(0x64); // 3_35 + GBS::VDS_UCOS_GAIN::write(0x19); // 3_36 + GBS::VDS_VCOS_GAIN::write(0x19); // 3_37 + GBS::VDS_Y_OFST::write(0xfe); // 3_3a + GBS::VDS_U_OFST::write(0x01); // 3_3b +} + +/** + * @brief blue only mode: t0t44t1 t0t44t4 + * + */ +void applyYuvPatches() +{ + GBS::ADC_RYSEL_R::write(1); // midlevel clamp red + GBS::ADC_RYSEL_B::write(1); // midlevel clamp blue + GBS::ADC_RYSEL_G::write(0); // gnd clamp green + GBS::DEC_MATRIX_BYPS::write(1); // ADC + GBS::IF_MATRIX_BYPS::write(1); + + // if (GBS::GBS_PRESET_CUSTOM::read() == 0) { + // if (!rto.isCustomPreset) { + if (!uopt.slotIsCustom) { + // colors + GBS::VDS_Y_GAIN::write(0x80); // 3_25 + GBS::VDS_UCOS_GAIN::write(0x1c); // 3_26 + GBS::VDS_VCOS_GAIN::write(0x29); // 3_27 + GBS::VDS_Y_OFST::write(0xFE); + GBS::VDS_U_OFST::write(0x03); + GBS::VDS_V_OFST::write(0x03); + if (rto.videoStandardInput >= 5 && rto.videoStandardInput <= 7) { + // todo: Rec. 709 (vs Rec. 601 used normally + // needs this on VDS and HDBypass + } + } + + // if using ADC auto offset for yuv input / rgb output + // GBS::ADC_AUTO_OFST_EN::write(1); + // GBS::VDS_U_OFST::write(0x36); //3_3b + // GBS::VDS_V_OFST::write(0x4d); //3_3c + + if (uopt.wantOutputComponent) { + applyComponentColorMixing(); + } +} + +/** + * @brief + * + */ +void OutputComponentOrVGA() +{ + // bool isCustomPreset = GBS::GBS_PRESET_CUSTOM::read(); + if (uopt.wantOutputComponent) { + _WSN(F("Output Format: Component")); + GBS::VDS_SYNC_LEV::write(0x80); // 0.25Vpp sync (leave more room for Y) + GBS::VDS_CONVT_BYPS::write(1); // output YUV + GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD + } else { + GBS::VDS_SYNC_LEV::write(0); + GBS::VDS_CONVT_BYPS::write(0); // output RGB + GBS::OUT_SYNC_CNTRL::write(1); // H / V sync out enable + } + + // if (!rto.isCustomPreset) { + if (!uopt.slotIsCustom) { + if (rto.inputIsYPbPr == true) { + applyYuvPatches(); + } else { + applyRGBPatches(); + } + } +} + +/** + * @brief + * + */ +void toggleIfAutoOffset() +{ + if (GBS::IF_AUTO_OFST_EN::read() == 0) { + // and different ADC offsets + GBS::ADC_ROFCTRL::write(0x40); + GBS::ADC_GOFCTRL::write(0x42); + GBS::ADC_BOFCTRL::write(0x40); + // enable + GBS::IF_AUTO_OFST_EN::write(1); + GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame + } else { + if (adco.r_off != 0 && adco.g_off != 0 && adco.b_off != 0) { + GBS::ADC_ROFCTRL::write(adco.r_off); + GBS::ADC_GOFCTRL::write(adco.g_off); + GBS::ADC_BOFCTRL::write(adco.b_off); + } + // adco.r_off = 0: auto calibration on boot failed, leave at current values + GBS::IF_AUTO_OFST_EN::write(0); + GBS::IF_AUTO_OFST_PRD::write(0); // 0 = by line, 1 = by frame + } +} + +/** + * @brief Set the Adc Parameters Gain And Offset object + * + */ +void setAdcParametersGainAndOffset() +{ + GBS::ADC_ROFCTRL::write(0x40); + GBS::ADC_GOFCTRL::write(0x40); + GBS::ADC_BOFCTRL::write(0x40); + // Do not call setAdcGain() and overwrite adco.r_gain. This function should + // only be called during startup, or during doPostPresetLoadSteps(), and if + // `uopt.enableAutoGain == 1` then doPostPresetLoadSteps() will revert + // these writes with `adco.r_gain`. + GBS::ADC_RGCTRL::write(0x7B); + GBS::ADC_GGCTRL::write(0x7B); + GBS::ADC_BGCTRL::write(0x7B); +} + +/** + * @brief + * + */ +void updateHVSyncEdge() +{ + static uint8_t printHS = 0, printVS = 0; + uint16_t temp = 0; + + if (GBS::STATUS_INT_SOG_BAD::read() == 1) { + resetInterruptSogBadBit(); + return; + } + + uint8_t syncStatus = GBS::STATUS_16::read(); + if (rto.syncTypeCsync) { + // sog check, only check H + if ((syncStatus & 0x02) != 0x02) + return; + } else { + // HV check, check H + V + if ((syncStatus & 0x0a) != 0x0a) + return; + } + + if ((syncStatus & 0x02) != 0x02) // if !hs active + { + // _WSN(F("(SP) can't detect sync edge")); + } else { + if ((syncStatus & 0x01) == 0x00) { + if (printHS != 1) { + _WSN(F("(SP) HS active low")); + } + printHS = 1; + + temp = GBS::HD_HS_SP::read(); + if (GBS::HD_HS_ST::read() < temp) { // if out sync = ST < SP + GBS::HD_HS_SP::write(GBS::HD_HS_ST::read()); + GBS::HD_HS_ST::write(temp); + GBS::SP_HS2PLL_INV_REG::write(1); + // GBS::SP_SOG_P_INV::write(0); // 5_20 2 //could also use 5_20 1 "SP_SOG_P_ATO" + } + } else { + if (printHS != 2) { + _WSN(F("(SP) HS active high")); + } + printHS = 2; + + temp = GBS::HD_HS_SP::read(); + if (GBS::HD_HS_ST::read() > temp) { // if out sync = ST > SP + GBS::HD_HS_SP::write(GBS::HD_HS_ST::read()); + GBS::HD_HS_ST::write(temp); + GBS::SP_HS2PLL_INV_REG::write(0); + // GBS::SP_SOG_P_INV::write(1); // 5_20 2 //could also use 5_20 1 "SP_SOG_P_ATO" + } + } + + // VS check, but only necessary for separate sync (CS should have VS always active low) + if (rto.syncTypeCsync == false) { + if ((syncStatus & 0x08) != 0x08) // if !vs active + { + _WSN(F("VS can't detect sync edge")); + } else { + if ((syncStatus & 0x04) == 0x00) { + if (printVS != 1) { + _WSN(F("(SP) VS active low")); + } + printVS = 1; + + temp = GBS::HD_VS_SP::read(); + if (GBS::HD_VS_ST::read() < temp) { // if out sync = ST < SP + GBS::HD_VS_SP::write(GBS::HD_VS_ST::read()); + GBS::HD_VS_ST::write(temp); + } + } else { + if (printVS != 2) { + _WSN(F("(SP) VS active high")); + } + printVS = 2; + + temp = GBS::HD_VS_SP::read(); + if (GBS::HD_VS_ST::read() > temp) { // if out sync = ST > SP + GBS::HD_VS_SP::write(GBS::HD_VS_ST::read()); + GBS::HD_VS_ST::write(temp); + } + } + } + } + } +} + +/** + * @brief Generally, the ADC has to stay enabled to perform SOG separation and + * thus "see" a source. It is possible to run in low power mode. Function + * should not further nest, so it can be called in syncwatcher + * + * before making changes, see: utilsCheckBoardPower() + * + * in operation: t5t04t1 for 10% lower power on ADC + * also: s0s40s1c for 5% (lower memclock of 108mhz) + * for some reason: t0t45t2 t0t45t4 (enable SDAC, output max voltage) 5% lower done in presets + * t0t4ft4 clock out should be off + * s4s01s20 (was 30) faster latency, unstable at 108mhz + * both phase controls off saves some power 506ma > 493ma + * oversample ratio can save 10% at 1x + * t3t24t3 VDS_TAP6_BYPS on can save 2% + */ +void goLowPowerWithInputDetection() +{ + GBS::OUT_SYNC_CNTRL::write(0); // no H / V sync out to PAD + GBS::DAC_RGBS_PWDNZ::write(0); // direct disableDAC() + // utilsZeroAll(); + _DBGN(F("(!) reset runtime parameters while going LowPower")); + presetsResetParameters(); // includes rto.videoStandardInput = 0 + prepareSyncProcessor(); + delay(100); + rto.isInLowPowerMode = true; + _DBGN(F("Scanning inputs for sources ...")); + LEDOFF; +} + +/** + * @brief Intents to adjust the Sync-On-Green level + * + */ +void optimizeSogLevel() +{ + if (rto.boardHasPower == false) // utilsCheckBoardPower is too invasive now + { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 13; + return; + } + if (rto.videoStandardInput == 15 || GBS::SP_SOG_MODE::read() != 1 || rto.syncTypeCsync == false) { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 13; + return; + } + + if (rto.inputIsYPbPr) { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 14; + } else { + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG = 13; // similar to yuv, allow variations + } + setAndUpdateSogLevel(rto.currentLevelSOG); + + uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); + uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); + if (debug_backup != 0xa) { + GBS::TEST_BUS_SEL::write(0xa); + delay(1); + } + if (debug_backup_SP != 0x0f) { + GBS::TEST_BUS_SP_SEL::write(0x0f); + delay(1); + } + + GBS::TEST_BUS_EN::write(1); + + delay(100); + while (1) { + uint16_t syncGoodCounter = 0; + unsigned long timeout = millis(); + while ((millis() - timeout) < 60) { + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { + syncGoodCounter++; + if (syncGoodCounter >= 60) { + break; + } + } else if (syncGoodCounter >= 4) { + syncGoodCounter -= 3; + } + } + + if (syncGoodCounter >= 60) { + syncGoodCounter = 0; + // if (getVideoMode() != 0) + if (GBS::TEST_BUS_2F::read() > 0) { + delay(20); + for (int a = 0; a < 50; a++) { + syncGoodCounter++; + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 0 || GBS::TEST_BUS_2F::read() == 0) { + syncGoodCounter = 0; + break; + } + } + if (syncGoodCounter >= 49) { + // _WS(F("OK @SOG ")); _WSN(rto.currentLevelSOG); printInfo(); + break; // found, exit + } else { + // _WS(F(" inner test failed syncGoodCounter: "); _WSN(syncGoodCounter)); + } + } else { // getVideoMode() == 0 + // _WS(F("sog-- syncGoodCounter: "); _WSN(syncGoodCounter)); + } + } else { // syncGoodCounter < 40 + // _WS(F("outer test failed syncGoodCounter: ")); _WSN(syncGoodCounter); + } + + if (rto.currentLevelSOG >= 2) { + rto.currentLevelSOG -= 1; + setAndUpdateSogLevel(rto.currentLevelSOG); + delay(8); // time for sog to settle + } else { + rto.currentLevelSOG = 13; // leave at default level + setAndUpdateSogLevel(rto.currentLevelSOG); + delay(8); + break; // break and exit + } + } + + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG; + if (rto.thisSourceMaxLevelSOG == 0) { + rto.thisSourceMaxLevelSOG = 1; // fail safe + } + + if (debug_backup != 0xa) { + GBS::TEST_BUS_SEL::write(debug_backup); + } + if (debug_backup_SP != 0x0f) { + GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); + } +} + +/** + * @brief + * + */ +void resetModeDetect() +{ + GBS::SFTRST_MODE_RSTZ::write(0); + delay(1); // needed + GBS::SFTRST_MODE_RSTZ::write(1); + // rto.clampPositionIsSet = false; + // rto.coastPositionIsSet = false; +} + +/** + * @brief + * + * @param amountToShift + * @param subtracting + */ +void shiftHorizontal(uint16_t amountToShift, bool subtracting) +{ + uint16_t hrst = GBS::VDS_HSYNC_RST::read(); + uint16_t hbst = GBS::VDS_HB_ST::read(); + uint16_t hbsp = GBS::VDS_HB_SP::read(); + + // Perform the addition/subtraction + if (subtracting) { + if ((int16_t)hbst - amountToShift >= 0) { + hbst -= amountToShift; + } else { + hbst = hrst - (amountToShift - hbst); + } + if ((int16_t)hbsp - amountToShift >= 0) { + hbsp -= amountToShift; + } else { + hbsp = hrst - (amountToShift - hbsp); + } + } else { + if ((int16_t)hbst + amountToShift <= hrst) { + hbst += amountToShift; + // also extend hbst_d to maximum hrst-1 + if (hbst > GBS::VDS_DIS_HB_ST::read()) { + GBS::VDS_DIS_HB_ST::write(hbst); + } + } else { + hbst = 0 + (amountToShift - (hrst - hbst)); + } + if ((int16_t)hbsp + amountToShift <= hrst) { + hbsp += amountToShift; + } else { + hbsp = 0 + (amountToShift - (hrst - hbsp)); + } + } + + GBS::VDS_HB_ST::write(hbst); + GBS::VDS_HB_SP::write(hbsp); + // _WS("hbst: "); _WSN(hbst); + // _WS("hbsp: "); _WSN(hbsp); +} + +/** + * @brief + * + */ +void shiftHorizontalLeft() +{ + shiftHorizontal(4, true); +} + +/** + * @brief + * + */ +void shiftHorizontalRight() +{ + shiftHorizontal(4, false); +} + +/** + * @brief unused but may become useful + * + * @param amount + */ +// void shiftHorizontalLeftIF(uint8_t amount) +// { +// uint16_t IF_HB_ST2 = GBS::IF_HB_ST2::read() + amount; +// uint16_t IF_HB_SP2 = GBS::IF_HB_SP2::read() + amount; +// uint16_t PLLAD_MD = GBS::PLLAD_MD::read(); + +// if (rto.videoStandardInput <= 2) { +// GBS::IF_HSYNC_RST::write(PLLAD_MD / 2); // input line length from pll div +// } else if (rto.videoStandardInput <= 7) { +// GBS::IF_HSYNC_RST::write(PLLAD_MD); +// } +// uint16_t IF_HSYNC_RST = GBS::IF_HSYNC_RST::read(); + +// GBS::IF_LINE_SP::write(IF_HSYNC_RST + 1); + +// // start +// if (IF_HB_ST2 < IF_HSYNC_RST) { +// GBS::IF_HB_ST2::write(IF_HB_ST2); +// } else { +// GBS::IF_HB_ST2::write(IF_HB_ST2 - IF_HSYNC_RST); +// } +// // _WS(F("IF_HB_ST2: ")); _WSN(GBS::IF_HB_ST2::read()); + +// // stop +// if (IF_HB_SP2 < IF_HSYNC_RST) { +// GBS::IF_HB_SP2::write(IF_HB_SP2); +// } else { +// GBS::IF_HB_SP2::write((IF_HB_SP2 - IF_HSYNC_RST) + 1); +// } +// // _WS(F("IF_HB_SP2: ")); _WSN(GBS::IF_HB_SP2::read()); +// } + +/** + * @brief unused but may become useful + * + * @param amount + */ +// void shiftHorizontalRightIF(uint8_t amount) +// { +// int16_t IF_HB_ST2 = GBS::IF_HB_ST2::read() - amount; +// int16_t IF_HB_SP2 = GBS::IF_HB_SP2::read() - amount; +// uint16_t PLLAD_MD = GBS::PLLAD_MD::read(); + +// if (rto.videoStandardInput <= 2) { +// GBS::IF_HSYNC_RST::write(PLLAD_MD / 2); // input line length from pll div +// } else if (rto.videoStandardInput <= 7) { +// GBS::IF_HSYNC_RST::write(PLLAD_MD); +// } +// int16_t IF_HSYNC_RST = GBS::IF_HSYNC_RST::read(); + +// GBS::IF_LINE_SP::write(IF_HSYNC_RST + 1); + +// if (IF_HB_ST2 > 0) { +// GBS::IF_HB_ST2::write(IF_HB_ST2); +// } else { +// GBS::IF_HB_ST2::write(IF_HSYNC_RST - 1); +// } +// // _WS(F("IF_HB_ST2: ")); _WSN(GBS::IF_HB_ST2::read()); + +// if (IF_HB_SP2 > 0) { +// GBS::IF_HB_SP2::write(IF_HB_SP2); +// } else { +// GBS::IF_HB_SP2::write(IF_HSYNC_RST - 1); +// // GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() - 2); +// } +// // _WS(F("IF_HB_SP2: ")); _WSN(GBS::IF_HB_SP2::read()); +// } + +/** + * @brief Output video control horizontal scale serial commands (h, z) + * + * @param amountToScale + * @param subtracting + */ +void scaleHorizontal(uint16_t amountToScale, bool subtracting) +{ + uint16_t hscale = GBS::VDS_HSCALE::read(); + + // smooth out areas of interest + if (subtracting && (hscale == 513 || hscale == 512)) + amountToScale = 1; + if (!subtracting && (hscale == 511 || hscale == 512)) + amountToScale = 1; + + if (subtracting && (((int)hscale - amountToScale) <= 256)) { + hscale = 256; + GBS::VDS_HSCALE::write(hscale); + _WSN(F("limit")); + return; + } + + if (subtracting && (hscale - amountToScale > 255)) { + hscale -= amountToScale; + } else if (hscale + amountToScale < 1023) { + hscale += amountToScale; + } else if (hscale + amountToScale == 1023) { // exact max > bypass but apply VDS fetch changes + hscale = 1023; + GBS::VDS_HSCALE::write(hscale); + GBS::VDS_HSCALE_BYPS::write(1); + } else if (hscale + amountToScale > 1023) { // max + overshoot > bypass and no VDS fetch adjust + hscale = 1023; + GBS::VDS_HSCALE::write(hscale); + GBS::VDS_HSCALE_BYPS::write(1); + _WSN(F("limit")); + return; + } + + // will be scaling + GBS::VDS_HSCALE_BYPS::write(0); + + // move within VDS VB fetch area (within reason) + uint16_t htotal = GBS::VDS_HSYNC_RST::read(); + uint16_t toShift = 0; + if (hscale < 540) + toShift = 4; + else if (hscale < 640) + toShift = 3; + else + toShift = 2; + + if (subtracting) { + shiftHorizontal(toShift, true); + if ((GBS::VDS_HB_ST::read() + 5) < GBS::VDS_DIS_HB_ST::read()) { + GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 5); + } else if ((GBS::VDS_DIS_HB_ST::read() + 5) < htotal) { + GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() + 5); + GBS::VDS_HB_ST::write(GBS::VDS_DIS_HB_ST::read()); // dis_hbst = hbst + } + + // fix HB_ST > HB_SP conditions + if (GBS::VDS_HB_SP::read() < (GBS::VDS_HB_ST::read() + 16)) { // HB_SP < HB_ST + if ((GBS::VDS_HB_SP::read()) > (htotal / 2)) { // but HB_SP > some small value + GBS::VDS_HB_ST::write(GBS::VDS_HB_SP::read() - 16); + } + } + } + + // !subtracting check just for readability + if (!subtracting) { + shiftHorizontal(toShift, false); + if ((GBS::VDS_HB_ST::read() - 5) > 0) { + GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() - 5); + } + } + + // fix scaling < 512 glitch: factor even, htotal even: hbst / hbsp should be even, etc + if (hscale < 512) { + if (hscale % 2 == 0) { // hscale 512 / even + if (GBS::VDS_HB_ST::read() % 2 == 1) { + GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 1); + } + if (htotal % 2 == 1) { + if (GBS::VDS_HB_SP::read() % 2 == 0) { + GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); + } + } else { + if (GBS::VDS_HB_SP::read() % 2 == 1) { + GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); + } + } + } else { // hscale 499 / uneven + if (GBS::VDS_HB_ST::read() % 2 == 1) { + GBS::VDS_HB_ST::write(GBS::VDS_HB_ST::read() + 1); + } + if (htotal % 2 == 0) { + if (GBS::VDS_HB_SP::read() % 2 == 1) { + GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); + } + } else { + if (GBS::VDS_HB_SP::read() % 2 == 0) { + GBS::VDS_HB_SP::write(GBS::VDS_HB_SP::read() - 1); + } + } + } + // if scaling was < 512 and HB_ST moved, align with VDS_DIS_HB_ST + if (GBS::VDS_DIS_HB_ST::read() < GBS::VDS_HB_ST::read()) { + GBS::VDS_DIS_HB_ST::write(GBS::VDS_HB_ST::read()); + } + } + + // _WS(F("HB_ST: ")); _WSN(GBS::VDS_HB_ST::read()); + // _WS(F("HB_SP: ")); _WSN(GBS::VDS_HB_SP::read()); + _WSF(PSTR("HScale: %d\n"), hscale); + GBS::VDS_HSCALE::write(hscale); +} + +/** + * @brief moves horizontal sync (VDS or HDB as needed) + * + * @param amountToAdd + * @param subtracting + */ +void moveHS(uint16_t amountToAdd, bool subtracting) +{ + // if (rto.outModeHdBypass) { + if (utilsIsPassThroughMode()) { + uint16_t SP_CS_HS_ST = GBS::SP_CS_HS_ST::read(); + uint16_t SP_CS_HS_SP = GBS::SP_CS_HS_SP::read(); + uint16_t htotal = GBS::HD_HSYNC_RST::read(); + + if (videoStandardInputIsPalNtscSd()) { + htotal -= 8; // account for the way hdbypass is setup in setOutputHdBypassMode() + htotal *= 2; + } + + if (htotal == 0) + return; // safety + int16_t amount = subtracting ? (0 - amountToAdd) : amountToAdd; + + if (SP_CS_HS_ST + amount < 0) { + SP_CS_HS_ST = htotal + SP_CS_HS_ST; // yep, this works :p + } + if (SP_CS_HS_SP + amount < 0) { + SP_CS_HS_SP = htotal + SP_CS_HS_SP; + } + + GBS::SP_CS_HS_ST::write((SP_CS_HS_ST + amount) % htotal); + GBS::SP_CS_HS_SP::write((SP_CS_HS_SP + amount) % htotal); + + _WSF(PSTR("HSST: %d HSSP: %d\n"), GBS::SP_CS_HS_ST::read(), GBS::SP_CS_HS_SP::read()); + } else { + uint16_t VDS_HS_ST = GBS::VDS_HS_ST::read(); + uint16_t VDS_HS_SP = GBS::VDS_HS_SP::read(); + uint16_t htotal = GBS::VDS_HSYNC_RST::read(); + + if (htotal == 0) + return; // safety + int16_t amount = subtracting ? (0 - amountToAdd) : amountToAdd; + + if (VDS_HS_ST + amount < 0) { + VDS_HS_ST = htotal + VDS_HS_ST; // yep, this works :p + } + if (VDS_HS_SP + amount < 0) { + VDS_HS_SP = htotal + VDS_HS_SP; + } + + GBS::VDS_HS_ST::write((VDS_HS_ST + amount) % htotal); + GBS::VDS_HS_SP::write((VDS_HS_SP + amount) % htotal); + + // _WS(F("HSST: ")); _WS(GBS::VDS_HS_ST::read()); + // _WS(F(" HSSP: ")); _WSN(GBS::VDS_HS_SP::read()); + } + printVideoTimings(); +} + +/** + * @brief + * + * @param amountToAdd + * @param subtracting + */ +// void moveVS(uint16_t amountToAdd, bool subtracting) +// { +// uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); +// if (vtotal == 0) +// return; // safety +// uint16_t VDS_DIS_VB_ST = GBS::VDS_DIS_VB_ST::read(); +// uint16_t newVDS_VS_ST = GBS::VDS_VS_ST::read(); +// uint16_t newVDS_VS_SP = GBS::VDS_VS_SP::read(); + +// if (subtracting) { +// if ((newVDS_VS_ST - amountToAdd) > VDS_DIS_VB_ST) { +// newVDS_VS_ST -= amountToAdd; +// newVDS_VS_SP -= amountToAdd; +// } else +// _WSN(F("limit")); +// } else { +// if ((newVDS_VS_SP + amountToAdd) < vtotal) { +// newVDS_VS_ST += amountToAdd; +// newVDS_VS_SP += amountToAdd; +// } else +// _WSN(F("limit")); +// } +// // _WS(F("VSST: ")); _WS(newVDS_VS_ST); +// // _WS(F(" VSSP: ")); _WSN(newVDS_VS_SP); + +// GBS::VDS_VS_ST::write(newVDS_VS_ST); +// GBS::VDS_VS_SP::write(newVDS_VS_SP); +// } + +/** + * @brief + * + */ +void invertHS() +{ + uint8_t high, low; + uint16_t newST, newSP; + + writeOneByte(0xf0, 3); + readFromRegister(0x0a, 1, &low); + readFromRegister(0x0b, 1, &high); + newST = ((((uint16_t)high) & 0x000f) << 8) | (uint16_t)low; + readFromRegister(0x0b, 1, &low); + readFromRegister(0x0c, 1, &high); + newSP = ((((uint16_t)high) & 0x00ff) << 4) | ((((uint16_t)low) & 0x00f0) >> 4); + + uint16_t temp = newST; + newST = newSP; + newSP = temp; + + writeOneByte(0x0a, (uint8_t)(newST & 0x00ff)); + writeOneByte(0x0b, ((uint8_t)(newSP & 0x000f) << 4) | ((uint8_t)((newST & 0x0f00) >> 8))); + writeOneByte(0x0c, (uint8_t)((newSP & 0x0ff0) >> 4)); +} + +/** + * @brief + * + */ +void invertVS() +{ + uint8_t high, low; + uint16_t newST, newSP; + + writeOneByte(0xf0, 3); + readFromRegister(0x0d, 1, &low); + readFromRegister(0x0e, 1, &high); + newST = ((((uint16_t)high) & 0x000f) << 8) | (uint16_t)low; + readFromRegister(0x0e, 1, &low); + readFromRegister(0x0f, 1, &high); + newSP = ((((uint16_t)high) & 0x00ff) << 4) | ((((uint16_t)low) & 0x00f0) >> 4); + + uint16_t temp = newST; + newST = newSP; + newSP = temp; + + writeOneByte(0x0d, (uint8_t)(newST & 0x00ff)); + writeOneByte(0x0e, ((uint8_t)(newSP & 0x000f) << 4) | ((uint8_t)((newST & 0x0f00) >> 8))); + writeOneByte(0x0f, (uint8_t)((newSP & 0x0ff0) >> 4)); +} + +/** + * @brief + * + * @param amountToScale + * @param subtracting + */ +void scaleVertical(uint16_t amountToScale, bool subtracting) +{ + uint16_t vscale = GBS::VDS_VSCALE::read(); + + // least invasive "is vscaling enabled" check + if (vscale == 1023) { + GBS::VDS_VSCALE_BYPS::write(0); + } + + // smooth out areas of interest + if (subtracting && (vscale == 513 || vscale == 512)) + amountToScale = 1; + if (subtracting && (vscale == 684 || vscale == 683)) + amountToScale = 1; + if (!subtracting && (vscale == 511 || vscale == 512)) + amountToScale = 1; + if (!subtracting && (vscale == 682 || vscale == 683)) + amountToScale = 1; + + if (subtracting && (vscale - amountToScale > 128)) { + vscale -= amountToScale; + } else if (subtracting) { + vscale = 128; + } else if (vscale + amountToScale <= 1023) { + vscale += amountToScale; + } else if (vscale + amountToScale > 1023) { + vscale = 1023; + // don't enable vscale bypass here, since that disables ie line filter + } + + _WSF(PSTR("VScale: %d\n"), vscale); + GBS::VDS_VSCALE::write(vscale); +} + +/** + * @brief modified to move VBSP, set VBST to VBSP-2 + * + * @param amountToAdd + * @param subtracting + */ +void shiftVertical(uint16_t amountToAdd, bool subtracting) +{ + typedef GBS::Tie Regs; + uint16_t vrst = GBS::VDS_VSYNC_RST::read() - FrameSync::getSyncLastCorrection(); + uint16_t vbst = 0, vbsp = 0; + int16_t newVbst = 0, newVbsp = 0; + + Regs::read(vbst, vbsp); + newVbst = vbst; + newVbsp = vbsp; + + if (subtracting) { + // newVbst -= amountToAdd; + newVbsp -= amountToAdd; + } else { + // newVbst += amountToAdd; + newVbsp += amountToAdd; + } + + // handle the case where hbst or hbsp have been decremented below 0 + if (newVbst < 0) { + newVbst = vrst + newVbst; + } + if (newVbsp < 0) { + newVbsp = vrst + newVbsp; + } + + // handle the case where vbst or vbsp have been incremented above vrstValue + if (newVbst > (int16_t)vrst) { + newVbst = newVbst - vrst; + } + if (newVbsp > (int16_t)vrst) { + newVbsp = newVbsp - vrst; + } + + // mod: newVbsp needs to be at least newVbst+2 + if (newVbsp < (newVbst + 2)) { + newVbsp = newVbst + 2; + } + // mod: -= 2 + newVbst = newVbsp - 2; + + Regs::write(newVbst, newVbsp); + // _WS(F("VSST: ")); _WS(newVbst); _WS(F(" VSSP: ")); _WSN(newVbsp); +} + +/** + * @brief + * + */ +// void shiftVerticalUp() +// { +// shiftVertical(1, true); +// } + +/** + * @brief + * + */ +// void shiftVerticalDown() +// { +// shiftVertical(1, false); +// } + +/** + * @brief + * + */ +void shiftVerticalUpIF() +{ + // -4 to allow variance in source line count + uint8_t offset = rto.videoStandardInput == 2 ? 4 : 1; + uint16_t sourceLines = GBS::VPERIOD_IF::read() - offset; + // add an override for sourceLines, in case where the IF data is not available + // if ((GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) && rto.videoStandardInput == 14) { + if (uopt.preferScalingRgbhv && rto.videoStandardInput == 14) { + sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + } + int16_t stop = GBS::IF_VB_SP::read(); + int16_t start = GBS::IF_VB_ST::read(); + + if (stop < (sourceLines - 1) && start < (sourceLines - 1)) { + stop += 2; + start += 2; + } else { + start = 0; + stop = 2; + } + GBS::IF_VB_SP::write(stop); + GBS::IF_VB_ST::write(start); +} + +/** + * @brief + * + */ +void shiftVerticalDownIF() +{ + uint8_t offset = rto.videoStandardInput == 2 ? 4 : 1; + uint16_t sourceLines = GBS::VPERIOD_IF::read() - offset; + // add an override for sourceLines, in case where the IF data is not available + // if ((GBS::GBS_OPTION_SCALING_RGBHV::read() == 1) && rto.videoStandardInput == 14) { + if (uopt.preferScalingRgbhv && rto.videoStandardInput == 14) { + sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + } + + int16_t stop = GBS::IF_VB_SP::read(); + int16_t start = GBS::IF_VB_ST::read(); + + if (stop > 1 && start > 1) { + stop -= 2; + start -= 2; + } else { + start = sourceLines - 2; + stop = sourceLines; + } + GBS::IF_VB_SP::write(stop); + GBS::IF_VB_ST::write(start); +} + +/** + * @brief + * + * @param value + */ +void setHSyncStartPosition(uint16_t value) +{ + // if (rto.outModeHdBypass) { + if (utilsIsPassThroughMode()) { + // GBS::HD_HS_ST::write(value); + GBS::SP_CS_HS_ST::write(value); + } else { + GBS::VDS_HS_ST::write(value); + } +} + +/** + * @brief + * + * @param value + */ +void setHSyncStopPosition(uint16_t value) +{ + // if (rto.outModeHdBypass) { + if (utilsIsPassThroughMode()) { + // GBS::HD_HS_SP::write(value); + GBS::SP_CS_HS_SP::write(value); + } else { + GBS::VDS_HS_SP::write(value); + } +} + +/** + * @brief Set the Memory Hblank Start Position object + * + * @param value + */ +void setMemoryHblankStartPosition(uint16_t value) +{ + GBS::VDS_HB_ST::write(value); + GBS::HD_HB_ST::write(value); +} + +/** + * @brief Set the Memory Hblank Stop Position object + * + * @param value + */ +void setMemoryHblankStopPosition(uint16_t value) +{ + GBS::VDS_HB_SP::write(value); + GBS::HD_HB_SP::write(value); +} + +/** + * @brief Set the Display Hblank Start Position object + * + * @param value + */ +void setDisplayHblankStartPosition(uint16_t value) +{ + GBS::VDS_DIS_HB_ST::write(value); +} + +/** + * @brief Set the Display Hblank Stop Position object + * + * @param value + */ +void setDisplayHblankStopPosition(uint16_t value) +{ + GBS::VDS_DIS_HB_SP::write(value); +} + +/** + * @brief + * + * @param value + */ +void setVSyncStartPosition(uint16_t value) +{ + GBS::VDS_VS_ST::write(value); + GBS::HD_VS_ST::write(value); +} + +/** + * @brief + * + * @param value + */ +void setVSyncStopPosition(uint16_t value) +{ + GBS::VDS_VS_SP::write(value); + GBS::HD_VS_SP::write(value); +} + +/** + * @brief Set the Memory Vblank Start Position object + * + * @param value + */ +void setMemoryVblankStartPosition(uint16_t value) +{ + GBS::VDS_VB_ST::write(value); + GBS::HD_VB_ST::write(value); +} + +/** + * @brief Set the Memory Vblank Stop Position object + * + * @param value + */ +void setMemoryVblankStopPosition(uint16_t value) +{ + GBS::VDS_VB_SP::write(value); + GBS::HD_VB_SP::write(value); +} + +/** + * @brief Set the Display Vblank Start Position object + * + * @param value + */ +void setDisplayVblankStartPosition(uint16_t value) +{ + GBS::VDS_DIS_VB_ST::write(value); +} + +/** + * @brief Set the Display Vblank Stop Position object + * + * @param value + */ +void setDisplayVblankStopPosition(uint16_t value) +{ + GBS::VDS_DIS_VB_SP::write(value); +} + +/** + * @brief Get the Cs Vs Start object + * + * @return uint16_t + */ +uint16_t getCsVsStart() +{ + return (GBS::SP_SDCS_VSST_REG_H::read() << 8) + GBS::SP_SDCS_VSST_REG_L::read(); +} + +/** + * @brief Get the Cs Vs Stop object + * + * @return uint16_t + */ +uint16_t getCsVsStop() +{ + return (GBS::SP_SDCS_VSSP_REG_H::read() << 8) + GBS::SP_SDCS_VSSP_REG_L::read(); +} + +/** + * @brief Set the htotal object + * + * @param htotal + */ +// void set_htotal(uint16_t htotal) +// { +// // ModeLine "1280x960" 108.00 1280 1376 1488 1800 960 961 964 1000 +HSync +VSync +// // front porch: H2 - H1: 1376 - 1280 +// // back porch : H4 - H3: 1800 - 1488 +// // sync pulse : H3 - H2: 1488 - 1376 + +// uint16_t h_blank_display_start_position = htotal - 1; +// uint16_t h_blank_display_stop_position = htotal - ((htotal * 3) / 4); +// uint16_t center_blank = ((h_blank_display_stop_position / 2) * 3) / 4; // a bit to the left +// uint16_t h_sync_start_position = center_blank - (center_blank / 2); +// uint16_t h_sync_stop_position = center_blank + (center_blank / 2); +// uint16_t h_blank_memory_start_position = h_blank_display_start_position - 1; +// uint16_t h_blank_memory_stop_position = h_blank_display_stop_position - (h_blank_display_stop_position / 50); + +// GBS::VDS_HSYNC_RST::write(htotal); +// GBS::VDS_HS_ST::write(h_sync_start_position); +// GBS::VDS_HS_SP::write(h_sync_stop_position); +// GBS::VDS_DIS_HB_ST::write(h_blank_display_start_position); +// GBS::VDS_DIS_HB_SP::write(h_blank_display_stop_position); +// GBS::VDS_HB_ST::write(h_blank_memory_start_position); +// GBS::VDS_HB_SP::write(h_blank_memory_stop_position); +// } + +/** + * @brief Set the vtotal object + * + * @param vtotal + */ +void set_vtotal(uint16_t vtotal) +{ + uint16_t VDS_DIS_VB_ST = vtotal - 2; // just below vtotal + uint16_t VDS_DIS_VB_SP = (vtotal >> 6) + 8; // positive, above new sync stop position + uint16_t VDS_VB_ST = ((uint16_t)(vtotal * 0.016f)) & 0xfffe; // small fraction of vtotal + uint16_t VDS_VB_SP = VDS_VB_ST + 2; // always VB_ST + 2 + uint16_t v_sync_start_position = 1; + uint16_t v_sync_stop_position = 5; + // most low line count formats have negative sync! + // exception: 1024x768 (1344x806 total) has both sync neg. // also 1360x768 (1792x795 total) + if ((vtotal < 530) || (vtotal >= 803 && vtotal <= 809) || (vtotal >= 793 && vtotal <= 798)) { + uint16_t temp = v_sync_start_position; + v_sync_start_position = v_sync_stop_position; + v_sync_stop_position = temp; + } + + GBS::VDS_VSYNC_RST::write(vtotal); + GBS::VDS_VS_ST::write(v_sync_start_position); + GBS::VDS_VS_SP::write(v_sync_stop_position); + GBS::VDS_VB_ST::write(VDS_VB_ST); + GBS::VDS_VB_SP::write(VDS_VB_SP); + GBS::VDS_DIS_VB_ST::write(VDS_DIS_VB_ST); + GBS::VDS_DIS_VB_SP::write(VDS_DIS_VB_SP); + + // VDS_VSYN_SIZE1 + VDS_VSYN_SIZE2 to VDS_VSYNC_RST + 2 + GBS::VDS_VSYN_SIZE1::write(GBS::VDS_VSYNC_RST::read() + 2); + GBS::VDS_VSYN_SIZE2::write(GBS::VDS_VSYNC_RST::read() + 2); +} + +/** + * @brief Set the If Hblank Parameters object + * + */ +// void setIfHblankParameters() +// { +// if (!rto.outModeHdBypass) { +// uint16_t pll_divider = GBS::PLLAD_MD::read(); + +// // if line doubling (PAL, NTSC), div 2 + a couple pixels +// GBS::IF_HSYNC_RST::write(((pll_divider >> 1) + 13) & 0xfffe); // 1_0e +// GBS::IF_LINE_SP::write(GBS::IF_HSYNC_RST::read() + 1); // 1_22 +// if (rto.presetID == 0x05) { +// // override for 1080p manually for now (pll_divider alone isn't correct :/) +// GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() + 32); +// GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() + 32); +// } +// if (rto.presetID == 0x15) { +// GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() + 20); +// GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() + 20); +// } + +// if (GBS::IF_LD_RAM_BYPS::read()) { +// // no LD = EDTV or similar +// GBS::IF_HB_SP2::write((uint16_t)((float)pll_divider * 0.06512f) & 0xfffe); // 1_1a // 0.06512f +// // pll_divider / 2 - 3 is minimum IF_HB_ST2 +// GBS::IF_HB_ST2::write((uint16_t)((float)pll_divider * 0.4912f) & 0xfffe); // 1_18 +// } else { +// // LD mode (PAL, NTSC) +// GBS::IF_HB_SP2::write(4 + ((uint16_t)((float)pll_divider * 0.0224f) & 0xfffe)); // 1_1a +// GBS::IF_HB_ST2::write((uint16_t)((float)pll_divider * 0.4550f) & 0xfffe); // 1_18 + +// if (GBS::IF_HB_ST2::read() >= 0x420) { +// // limit (fifo?) (0x420 = 1056) (might be 0x424 instead) +// // limit doesn't apply to EDTV modes, where 1_18 typically = 0x4B0 +// GBS::IF_HB_ST2::write(0x420); +// } + +// if (rto.presetID == 0x05 || rto.presetID == 0x15) { +// // override 1_1a for 1080p manually for now (pll_divider alone isn't correct :/) +// GBS::IF_HB_SP2::write(0x2A); +// } + +// // position move via 1_26 and reserve for deinterlacer: add IF RST pixels +// // seems no extra pixels available at around PLLAD:84A or 2122px +// // uint16_t currentRst = GBS::IF_HSYNC_RST::read(); +// // GBS::IF_HSYNC_RST::write((currentRst + (currentRst / 15)) & 0xfffe); // 1_0e +// // GBS::IF_LINE_SP::write(GBS::IF_HSYNC_RST::read() + 1); // 1_22 +// } +// } +// } + +// +/** + * @brief Get the Sync Present object + * if testbus has 0x05, sync is present and line counting active. if it has 0x04, + * sync is present but no line counting + * @return true + * @return false + */ +bool getSyncPresent() +{ + uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); + uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); + if (debug_backup != 0xa) { + GBS::TEST_BUS_SEL::write(0xa); + } + if (debug_backup_SP != 0x0f) { + GBS::TEST_BUS_SP_SEL::write(0x0f); + } + + uint16_t readout = GBS::TEST_BUS::read(); + + if (debug_backup != 0xa) { + GBS::TEST_BUS_SEL::write(debug_backup); + } + if (debug_backup_SP != 0x0f) { + GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); + } + // if (((readout & 0x0500) == 0x0500) || ((readout & 0x0500) == 0x0400)) { + if (readout > 0x0180) { + return true; + } + + return false; +} + +/** + * @brief Get the Status00 If Hs Vs Stable object + * returns 0_00 bit 2 = H+V both stable (for the IF, not SP) + * @return true + * @return false + */ +// bool getStatus00IfHsVsStable() +// { +// return ((GBS::STATUS_00::read() & 0x04) == 0x04) ? 1 : 0; +// } + +/** + * @brief + * + */ +void advancePhase() +{ + rto.phaseADC = (rto.phaseADC + 1) & 0x1f; + setAndLatchPhaseADC(); +} + +/** + * @brief + * + */ +// void movePhaseThroughRange() +// { +// for (uint8_t i = 0; i < 128; i++) { // 4x for 4x oversampling? +// advancePhase(); +// } +// } + +/** + * @brief + * + * @param autoCoast + */ +void updateCoastPosition(bool autoCoast) +{ + if (((rto.videoStandardInput == 0) || (rto.videoStandardInput > 14)) || + !rto.boardHasPower || rto.sourceDisconnected) { + return; + } + + uint32_t accInHlength = 0; + uint16_t prevInHlength = GBS::HPERIOD_IF::read(); + for (uint8_t i = 0; i < 8; i++) { + // psx jitters between 427, 428 + uint16_t thisInHlength = GBS::HPERIOD_IF::read(); + if ((thisInHlength > (prevInHlength - 3)) && (thisInHlength < (prevInHlength + 3))) { + accInHlength += thisInHlength; + } else { + return; + } + if (!getStatus16SpHsStable()) { + return; + } + + prevInHlength = thisInHlength; + } + accInHlength = (accInHlength * 4) / 8; + + // 30.09.19 new: especially in low res VGA input modes, it can clip at "511 * 4 = 2044" + // limit to more likely actual value of 430 + if (accInHlength >= 2040) { + accInHlength = 1716; + } + + if (accInHlength <= 240) { + // check for low res, low Hz > can overflow HPERIOD_IF + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() <= 322) { + delay(4); + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() <= 322) { + _WSN(F(" (debug) updateCoastPosition: low res, low hz")); + accInHlength = 2000; + // usually need to lower charge pump. todo: write better check + if (rto.syncTypeCsync && rto.videoStandardInput > 0 && rto.videoStandardInput <= 4) { + if (GBS::PLLAD_ICP::read() >= 5 && GBS::PLLAD_FS::read() == 1) { + GBS::PLLAD_ICP::write(5); + GBS::PLLAD_FS::write(0); + latchPLLAD(); + rto.phaseIsSet = 0; + } + } + } + } + } + + // accInHlength around 1732 here / NTSC + // scope on sync-in, enable 5_3e 2 > shows coast borders + if (accInHlength > 32) { + if (autoCoast) { + // autoCoast (5_55 7 = on) + GBS::SP_H_CST_ST::write((uint16_t)(accInHlength * 0.0562f)); // ~0x61, right after color burst + GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.1550f)); // ~0x10C, shortly before sync falling edge + GBS::SP_HCST_AUTO_EN::write(1); + } else { + // test: psx pal black license screen, then ntsc SMPTE color bars 100%; or MS + // scope test psx: t5t11t3, 5_3e = 0x01, 5_36/5_35 = 0x30 5_37 = 0x10 : + // cst sp should be > 0x62b to clean out HS from eq pulses + // cst st should be 0, sp should be 0x69f when t5t57t7 = disabled + // GBS::SP_H_CST_ST::write((uint16_t)(accInHlength * 0.088f)); // ~0x9a, leave some room for SNES 239 mode + // new: with SP_H_PROTECT disabled, even SNES can be a small value. Small value greatly improves Mega Drive + GBS::SP_H_CST_ST::write(0x10); + + GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.968f)); // ~0x678 + // need a bit earlier, making 5_3e 2 more stable + // GBS::SP_H_CST_SP::write((uint16_t)(accInHlength * 0.7383f)); // ~0x4f0, before sync + GBS::SP_HCST_AUTO_EN::write(0); + } + rto.coastPositionIsSet = 1; + + /*_WS("coast ST: "); _WS("0x"); _WSF("0x%04X", GBS::SP_H_CST_ST::read()); + _WS(", "); + _WS("SP: "); _WS("0x"); _WSF("0x%04X", GBS::SP_H_CST_SP::read()); + _WS(" total: "); _WS("0x"); _WSF("0x%04X", accInHlength); + _WS(" ~ "); _WSN(accInHlength / 4);*/ + } +} + +/** + * @brief + * + */ +void updateClampPosition() +{ + if ((rto.videoStandardInput == 0) || !rto.boardHasPower || rto.sourceDisconnected) { + return; + } + // this is required especially on mode changes with ypbpr + if (getVideoMode() == 0) { + return; + } + + if (rto.inputIsYPbPr) { + GBS::SP_CLAMP_MANUAL::write(0); + } else { + GBS::SP_CLAMP_MANUAL::write(1); // no auto clamp for RGB + } + + // STATUS_SYNC_PROC_HTOTAL is "ht: " value; use with SP_CLP_SRC_SEL = 1 pixel clock + // GBS::HPERIOD_IF::read() is "h: " value; use with SP_CLP_SRC_SEL = 0 osc clock + // update: in RGBHV bypass it seems both clamp source modes use pixel clock for calculation + // but with sog modes, it uses HPERIOD_IF ... k + // update2: if the clamp is already short, yet creeps into active video, check sog invert (t5t20t2) + uint32_t accInHlength = 0; + uint16_t prevInHlength = 0; + uint16_t thisInHlength = 0; + if (rto.syncTypeCsync) + prevInHlength = GBS::HPERIOD_IF::read(); + else + prevInHlength = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + for (uint8_t i = 0; i < 16; i++) { + if (rto.syncTypeCsync) + thisInHlength = GBS::HPERIOD_IF::read(); + else + thisInHlength = GBS::STATUS_SYNC_PROC_HTOTAL::read(); + if ((thisInHlength > (prevInHlength - 3)) && (thisInHlength < (prevInHlength + 3))) { + accInHlength += thisInHlength; + } else { + // _WSN("updateClampPosition unstable"); + return; + } + if (!getStatus16SpHsStable()) { + return; + } + + prevInHlength = thisInHlength; + delayMicroseconds(100); + } + accInHlength = accInHlength / 16; // for the 16x loop + + // HPERIOD_IF: 9 bits (0-511, represents actual scanline time / 4, can overflow to low values) + // if it overflows, the calculated clamp positions are likely around 1 to 4. good enough + // STATUS_SYNC_PROC_HTOTAL: 12 bits (0-4095) + if (accInHlength > 4095) { + return; + } + + uint16_t oldClampST = GBS::SP_CS_CLP_ST::read(); + uint16_t oldClampSP = GBS::SP_CS_CLP_SP::read(); + float multiSt = rto.syncTypeCsync == 1 ? 0.032f : 0.010f; + float multiSp = rto.syncTypeCsync == 1 ? 0.174f : 0.058f; + uint16_t start = 1 + (accInHlength * multiSt); // HPERIOD_IF: *0.04 seems good + uint16_t stop = 2 + (accInHlength * multiSp); // HPERIOD_IF: *0.178 starts to creep into some EDTV modes + + if (rto.inputIsYPbPr) { + // YUV: // ST shift forward to pass blacker than black HSync, sog: min * 0.08 + multiSt = rto.syncTypeCsync == 1 ? 0.089f : 0.032f; + start = 1 + (accInHlength * multiSt); + + // new: HDBypass rewrite to sync to falling HS edge: move clamp position forward + // RGB can stay the same for now (clamp will start on sync pulse, a benefit in RGB + // if (rto.outModeHdBypass) { + if (utilsIsPassThroughMode()) { + if (videoStandardInputIsPalNtscSd()) { + start += 0x60; + stop += 0x60; + } + // raise blank level a bit that's not handled 100% by clamping + GBS::HD_BLK_GY_DATA::write(0x05); + GBS::HD_BLK_BU_DATA::write(0x00); + GBS::HD_BLK_RV_DATA::write(0x00); + } + } + + if ((start < (oldClampST - 1) || start > (oldClampST + 1)) || + (stop < (oldClampSP - 1) || stop > (oldClampSP + 1))) { + GBS::SP_CS_CLP_ST::write(start); + GBS::SP_CS_CLP_SP::write(stop); + /*_WS("clamp ST: "); _WS("0x"); _WS(start, HEX); + _WS(", "); + _WS("SP: "); _WS("0x"); _WS(stop, HEX); + _WS(" total: "); _WS("0x"); _WS(accInHlength, HEX); + _WS(" / "); _WSN(accInHlength);*/ + } + + rto.clampPositionIsSet = true; +} + +/** + * @brief + * + */ +// void fastSogAdjust() +// { +// if (rto.noSyncCounter <= 5) { +// uint8_t debug_backup = GBS::TEST_BUS_SEL::read(); +// uint8_t debug_backup_SP = GBS::TEST_BUS_SP_SEL::read(); +// if (debug_backup != 0xa) { +// GBS::TEST_BUS_SEL::write(0xa); +// } +// if (debug_backup_SP != 0x0f) { +// GBS::TEST_BUS_SP_SEL::write(0x0f); +// } + +// if ((GBS::TEST_BUS_2F::read() & 0x05) != 0x05) { +// while ((GBS::TEST_BUS_2F::read() & 0x05) != 0x05) { +// if (rto.currentLevelSOG >= 4) { +// rto.currentLevelSOG -= 2; +// } else { +// rto.currentLevelSOG = 13; +// setAndUpdateSogLevel(rto.currentLevelSOG); +// delay(40); +// break; // abort / restart next round +// } +// setAndUpdateSogLevel(rto.currentLevelSOG); +// delay(28); // 4 +// } +// delay(10); +// } + +// if (debug_backup != 0xa) { +// GBS::TEST_BUS_SEL::write(debug_backup); +// } +// if (debug_backup_SP != 0x0f) { +// GBS::TEST_BUS_SP_SEL::write(debug_backup_SP); +// } +// } +// } + +/** + * @brief Get the Pll Rate object + * used for RGBHV to determine the ADPLL speed "level" / can jitter with SOG Sync + * @return uint32_t + */ +uint32_t getPllRate() +{ + uint32_t esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; + uint8_t testBusSelBackup = GBS::TEST_BUS_SEL::read(); + uint8_t spBusSelBackup = GBS::TEST_BUS_SP_SEL::read(); + uint8_t debugPinBackup = GBS::PAD_BOUT_EN::read(); + + if (testBusSelBackup != 0xa) { + GBS::TEST_BUS_SEL::write(0xa); + } + if (rto.syncTypeCsync) { + if (spBusSelBackup != 0x6b) + GBS::TEST_BUS_SP_SEL::write(0x6b); + } else { + if (spBusSelBackup != 0x09) + GBS::TEST_BUS_SP_SEL::write(0x09); + } + GBS::PAD_BOUT_EN::write(1); // enable output to pin for test + yield(); // BOUT signal and wifi + delayMicroseconds(200); + uint32_t ticks = FrameSync::getPulseTicks(); + + // restore + GBS::PAD_BOUT_EN::write(debugPinBackup); + if (testBusSelBackup != 0xa) { + GBS::TEST_BUS_SEL::write(testBusSelBackup); + } + GBS::TEST_BUS_SP_SEL::write(spBusSelBackup); + + uint32_t retVal = 0; + if (ticks > 0) { + retVal = esp8266_clock_freq / ticks; + } + + return retVal; +} + +/** + * @brief The main function for detecting video + * signal paramters and its type. + * Called once from main loop + * + */ +void runSyncWatcher() +{ + if (!rto.boardHasPower) { + _WSN(F("(!) board not responding!")); + return; + } + + static uint8_t newVideoModeCounter = 0; + static uint16_t activeStableLineCount = 0; + // static unsigned long lastSyncDrop = millis(); + static unsigned long lastLineCountMeasure = millis(); + static unsigned long preemptiveSogWindowStart = millis(); + static const uint16_t sogWindowLen = 3000; // ms + static uint16_t badHsActive = 0; + static bool lastAdjustWasInActiveWindow = 0; + + uint16_t thisStableLineCount = 0; + uint8_t detectedVideoMode = getVideoMode(); + bool status16SpHsStable = getStatus16SpHsStable(); + + // if (rto.outModeHdBypass && status16SpHsStable) { + if (utilsIsPassThroughMode() && status16SpHsStable) { + if (videoStandardInputIsPalNtscSd()) { + if (millis() - lastLineCountMeasure > 765) { + thisStableLineCount = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + for (uint8_t i = 0; i < 3; i++) { + delay(2); + if (GBS::STATUS_SYNC_PROC_VTOTAL::read() < (thisStableLineCount - 3) || + GBS::STATUS_SYNC_PROC_VTOTAL::read() > (thisStableLineCount + 3)) { + thisStableLineCount = 0; + break; + } + } + + if (thisStableLineCount != 0) { + if (thisStableLineCount < (activeStableLineCount - 3) || + thisStableLineCount > (activeStableLineCount + 3)) { + activeStableLineCount = thisStableLineCount; + if (activeStableLineCount < 230 || activeStableLineCount > 340) { + // only doing NTSC/PAL currently, an unusual line count probably means a format change + setCsVsStart(1); + if (getCsVsStop() == 1) { + setCsVsStop(2); + } + // MD likes to get stuck as usual + nudgeMD(); + } else { + setCsVsStart(thisStableLineCount - 9); + } + + _DBGF(PSTR("HDBypass CsVsSt: %d\n"), getCsVsStart()); + delay(150); + } + } + + lastLineCountMeasure = millis(); + } + } + } + + if (rto.videoStandardInput == 13) { // using flaky graphic modes + if (detectedVideoMode == 0) { + if (GBS::STATUS_INT_SOG_BAD::read() == 0) { + detectedVideoMode = 13; // then keep it + } + } + } + + if (rto.syncTypeCsync && !rto.inputIsYPbPr && (newVideoModeCounter == 0)) { + // look for SOG instability + if (GBS::STATUS_INT_SOG_BAD::read() == 1 || GBS::STATUS_INT_SOG_SW::read() == 1) { + resetInterruptSogSwitchBit(); + if ((millis() - preemptiveSogWindowStart) > sogWindowLen) { + // start new window + preemptiveSogWindowStart = millis(); + badHsActive = 0; + } + lastVsyncLock = millis(); // best reset this + } + + if ((millis() - preemptiveSogWindowStart) < sogWindowLen) { + for (uint8_t i = 0; i < 16; i++) { + if (GBS::STATUS_INT_SOG_BAD::read() == 1 || GBS::STATUS_SYNC_PROC_HSACT::read() == 0) { + resetInterruptSogBadBit(); + uint16_t hlowStart = GBS::STATUS_SYNC_PROC_HLOW_LEN::read(); + if (rto.videoStandardInput == 0) + hlowStart = 777; // fix initial state no HLOW_LEN + for (int a = 0; a < 20; a++) { + if (GBS::STATUS_SYNC_PROC_HLOW_LEN::read() != hlowStart) { + // okay, source still active so count this one, break back to outer for loop + badHsActive++; + lastVsyncLock = millis(); // delay this + // _WS(badHsActive); _WS(" "); + break; + } + } + } + if ((i % 3) == 0) { + delay(1); + } else { + delay(0); + } + } + + if (badHsActive >= 17) { + if (rto.currentLevelSOG >= 2) { + rto.currentLevelSOG -= 1; + setAndUpdateSogLevel(rto.currentLevelSOG); + delay(30); + updateStopPositionDynamic(false); + badHsActive = 0; + lastAdjustWasInActiveWindow = 1; + } else if (badHsActive > 40) { + optimizeSogLevel(); + badHsActive = 0; + lastAdjustWasInActiveWindow = 1; + } + preemptiveSogWindowStart = millis(); // restart window + } + } else if (lastAdjustWasInActiveWindow) { + lastAdjustWasInActiveWindow = 0; + if (rto.currentLevelSOG >= 8) { + rto.currentLevelSOG -= 1; + setAndUpdateSogLevel(rto.currentLevelSOG); + delay(30); + updateStopPositionDynamic(false); + badHsActive = 0; + rto.phaseIsSet = 0; + } + } + } + + if ((detectedVideoMode == 0 || !status16SpHsStable) && rto.videoStandardInput != 15) { + rto.noSyncCounter++; + rto.continousStableCounter = 0; + lastVsyncLock = millis(); // best reset this + if (rto.noSyncCounter == 1) { + freezeVideo(); + return; // do nothing else + } + + rto.phaseIsSet = 0; + + if (rto.noSyncCounter <= 3 || GBS::STATUS_SYNC_PROC_HSACT::read() == 0) { + freezeVideo(); + } + + if (newVideoModeCounter == 0) { + LEDOFF; // LEDOFF on sync loss + + if (rto.noSyncCounter == 2) { // this usually repeats + // printInfo(); printInfo(); _WSN(); + // rto.printInfos = 0; + // if ((millis() - lastSyncDrop) > 1500) { // minimum space between runs + // if (rto.printInfos == false) { + // _DBGN(F(".")); + // } + // } else { + // if (rto.printInfos == false) { + // _DBGN(F(".")); + // } + // } + + // if sog is lowest, adjust up + if (rto.currentLevelSOG <= 1 && videoStandardInputIsPalNtscSd()) { + rto.currentLevelSOG += 1; + setAndUpdateSogLevel(rto.currentLevelSOG); + delay(30); + } + // lastSyncDrop = millis(); // restart timer + } + } + + if (rto.noSyncCounter == 8) { + GBS::SP_H_CST_ST::write(0x10); + GBS::SP_H_CST_SP::write(0x100); + // GBS::SP_H_PROTECT::write(1); // at noSyncCounter = 32 will alternate on / off + if (videoStandardInputIsPalNtscSd()) { + // this can early detect mode changes (before updateStopPositionDynamic resets all) + GBS::SP_PRE_COAST::write(9); + GBS::SP_POST_COAST::write(9); + // new: test SD<>EDTV changes + uint8_t ignore = GBS::SP_H_PULSE_IGNOR::read(); + if (ignore >= 0x33) { + GBS::SP_H_PULSE_IGNOR::write(ignore / 2); + } + } + rto.coastPositionIsSet = 0; + } + + if (rto.noSyncCounter % 27 == 0) { + // the * check needs to be first (go before auto sog level) to support SD > HDTV detection + updateStopPositionDynamic(true); + } + + if (rto.noSyncCounter % 32 == 0) { + if (GBS::STATUS_SYNC_PROC_HSACT::read() == 1) { + unfreezeVideo(); + } else { + freezeVideo(); + } + } + + if (rto.inputIsYPbPr && (rto.noSyncCounter == 34)) { + GBS::SP_NO_CLAMP_REG::write(1); // unlock clamp + rto.clampPositionIsSet = false; + } + + if (rto.noSyncCounter == 38) { + nudgeMD(); + } + + if (rto.syncTypeCsync) { + if (rto.noSyncCounter > 47) { + if (rto.noSyncCounter % 16 == 0) { + GBS::SP_H_PROTECT::write(!GBS::SP_H_PROTECT::read()); + } + } + } + + if (rto.noSyncCounter % 150 == 0) { + if (rto.noSyncCounter == 150 || rto.noSyncCounter % 900 == 0) { + _DBGN(F("\nno signal")); + // check whether discrete VSync is present. if so, need to go to input detect + uint8_t extSyncBackup = GBS::SP_EXT_SYNC_SEL::read(); + GBS::SP_EXT_SYNC_SEL::write(0); + delay(240); + printInfo(); + if (GBS::STATUS_SYNC_PROC_VSACT::read() == 1) { + delay(10); + if (GBS::STATUS_SYNC_PROC_VSACT::read() == 1) { + rto.noSyncCounter = 0x07fe; + } + } + GBS::SP_EXT_SYNC_SEL::write(extSyncBackup); + } + GBS::SP_H_COAST::write(0); // 5_3e 2 + GBS::SP_H_PROTECT::write(0); // 5_3e 4 + GBS::SP_H_CST_ST::write(0x10); + GBS::SP_H_CST_SP::write(0x100); // instead of disabling 5_3e 5 coast + GBS::SP_CS_CLP_ST::write(32); // neutral clamp values + GBS::SP_CS_CLP_SP::write(48); // + updateStopPositionDynamic(true); + nudgeMD(); // can fix MD not noticing a line count update + delay(80); + + // prepare optimizeSogLevel + // use STATUS_SYNC_PROC_HLOW_LEN changes to determine whether source is still active + uint16_t hlowStart = GBS::STATUS_SYNC_PROC_HLOW_LEN::read(); + if (GBS::PLLAD_VCORST::read() == 1) { + // exception: we're in startup and pllad isn't locked yet > HLOW_LEN always 0 + hlowStart = 777; // now it'll run optimizeSogLevel if needed + } + for (int a = 0; a < 128; a++) { + if (GBS::STATUS_SYNC_PROC_HLOW_LEN::read() != hlowStart) { + // source still there + if (rto.noSyncCounter % 450 == 0) { + rto.currentLevelSOG = 0; // worst case, sometimes necessary, will be unstable but at least detect + setAndUpdateSogLevel(rto.currentLevelSOG); + } else { + optimizeSogLevel(); + } + break; + } else if (a == 127) { + // set sog to be able to see something + rto.currentLevelSOG = 5; + setAndUpdateSogLevel(rto.currentLevelSOG); + } + delay(0); + } + + resetSyncProcessor(); + delay(8); + resetModeDetect(); + delay(8); + } + + // long no signal time, check other input + if (rto.noSyncCounter % 413 == 0) { + if (GBS::ADC_INPUT_SEL::read() == 1) { + GBS::ADC_INPUT_SEL::write(0); + } else { + GBS::ADC_INPUT_SEL::write(1); + } + delay(40); + unsigned long timeout = millis(); + while (millis() - timeout <= 210) { + if (getStatus16SpHsStable()) { + rto.noSyncCounter = 0x07fe; // will cause a return + break; + } + // wifiLoop(0); + delay(1); + } + + if (millis() - timeout > 210) { + if (GBS::ADC_INPUT_SEL::read() == 1) { + GBS::ADC_INPUT_SEL::write(0); + } else { + GBS::ADC_INPUT_SEL::write(1); + } + } + } + + newVideoModeCounter = 0; + // sog unstable check end + } + + // if format changed to valid, potentially new video mode + if (((detectedVideoMode != 0 && detectedVideoMode != rto.videoStandardInput) || + (detectedVideoMode != 0 && rto.videoStandardInput == 0)) && + rto.videoStandardInput != 15) + { + // before thoroughly checking for a mode change, watch format via newVideoModeCounter + if (newVideoModeCounter < 255) { + newVideoModeCounter++; + rto.continousStableCounter = 0; // usually already 0, but occasionally not +#if defined(DEBUG_CODE_ENABLED) + if (newVideoModeCounter > 1) { // help debug a few commits worth + // if (newVideoModeCounter == 2) { + _WSF(PSTR("video mode counter: %d\n"), newVideoModeCounter); + // } + } +#endif + if (newVideoModeCounter == 3) { + freezeVideo(); + GBS::SP_H_CST_ST::write(0x10); + GBS::SP_H_CST_SP::write(0x100); + rto.coastPositionIsSet = 0; + delay(10); + if (getVideoMode() == 0) { + updateStopPositionDynamic(true); // check ntsc to 480p and back + delay(40); + } + } + } + + if (newVideoModeCounter >= 8) { + uint8_t vidModeReadout = 0; + _WS(F("\nFormat change:")); + for (int a = 0; a < 30; a++) { + vidModeReadout = getVideoMode(); + if (vidModeReadout == 13) { + newVideoModeCounter = 5; + } + // treat ps2 quasi rgb as stable + if (vidModeReadout != detectedVideoMode) { + newVideoModeCounter = 0; + } + } + if (newVideoModeCounter != 0) { + // apply new mode + _WSF(PSTR(" %d (%d -> %d)\n"), vidModeReadout, rto.videoStandardInput, detectedVideoMode); + // _WS("Old: "); _WS(rto.videoStandardInput); + // _WS(" New: "); _WSN(detectedVideoMode); + + if (GBS::SP_SOG_MODE::read() == 1) { + rto.syncTypeCsync = true; + } else { + rto.syncTypeCsync = false; + } + // bool wantPassThroughMode = uopt.presetPreference == 10; + bool wantPassThroughMode = utilsIsPassThroughMode(); + + if (((rto.videoStandardInput == 1 || rto.videoStandardInput == 3) && (detectedVideoMode == 2 || detectedVideoMode == 4)) || + rto.videoStandardInput == 0 || + ((rto.videoStandardInput == 2 || rto.videoStandardInput == 4) && (detectedVideoMode == 1 || detectedVideoMode == 3))) { + rto.useHdmiSyncFix = 1; + _WSN(F("hdmi sync fix: yes")); + } else { + rto.useHdmiSyncFix = 0; + _WSN(F("hdmi sync fix: no")); + } + + if (!wantPassThroughMode) { + // needs to know the sync type for early updateclamp (set above) + applyPresets(detectedVideoMode); + } else { + rto.videoStandardInput = detectedVideoMode; + // registers uninitialized do post preset + setOutputHdBypassMode(false); + } + rto.videoStandardInput = detectedVideoMode; + rto.noSyncCounter = 0; + rto.continousStableCounter = 0; // also in postloadsteps + newVideoModeCounter = 0; + activeStableLineCount = 0; + delay(20); // post delay + badHsActive = 0; + preemptiveSogWindowStart = millis(); + } else { + unfreezeVideo(); // (whops) + _WSF(PSTR(" %d \n"), vidModeReadout); + printInfo(); + newVideoModeCounter = 0; + if (rto.videoStandardInput == 0) { + // if we got here from standby mode, return there soon + // but occasionally, this is a regular new mode that needs a SP parameter change to work + // ie: 1080p needs longer post coast, which the syncwatcher loop applies at some point + rto.noSyncCounter = 0x05ff; // give some time in normal loop + } + } + } + } else if (getStatus16SpHsStable() && detectedVideoMode != 0 + && rto.videoStandardInput != 15 + && (rto.videoStandardInput == detectedVideoMode)) { + // last used mode reappeared / stable again + if (rto.continousStableCounter < 255) { + rto.continousStableCounter++; + } + + static bool doFullRestore = 0; + if (rto.noSyncCounter >= 150) { + // source was gone for longer // clamp will be updated at continousStableCounter 50 + rto.coastPositionIsSet = false; + rto.phaseIsSet = false; + FrameSync::reset(uopt.frameTimeLockMethod); + doFullRestore = 1; + _WSN(); + } + + rto.noSyncCounter = 0; + newVideoModeCounter = 0; + + if (rto.continousStableCounter == 1 && !doFullRestore) { + rto.videoIsFrozen = true; // ensures unfreeze + unfreezeVideo(); + } + + if (rto.continousStableCounter == 2) { + updateStopPositionDynamic(false); + if (doFullRestore) { + delay(20); + optimizeSogLevel(); + doFullRestore = 0; + } + rto.videoIsFrozen = true; // ensures unfreeze + unfreezeVideo(); // called 2nd time here to make sure + } + + if (rto.continousStableCounter == 4) { + LEDON; + } + + if (!rto.phaseIsSet) { + if (rto.continousStableCounter >= 10 && rto.continousStableCounter < 61) { + // added < 61 to make a window, else sources with little pll lock hammer this + if ((rto.continousStableCounter % 10) == 0) { + rto.phaseIsSet = optimizePhaseSP(); + } + } + } + + // 5_3e 2 SP_H_COAST test + // if (rto.continousStableCounter == 11) { + // if (rto.coastPositionIsSet) { + // GBS::SP_H_COAST::write(1); + // } + //} + + if (rto.continousStableCounter == 160) { + resetInterruptSogBadBit(); + } + + if (rto.continousStableCounter == 45) { + // GBS::ADC_UNUSED_67::write(0); // clear sync fix temp registers (67/68) + // rto.coastPositionIsSet = 0; // leads to a flicker + rto.clampPositionIsSet = 0; // run updateClampPosition occasionally + } + + if (rto.continousStableCounter % 31 == 0) { + // new: 8 regular interval checks up until 255 + updateStopPositionDynamic(false); + } + + if (rto.continousStableCounter >= 3) { + if ((rto.videoStandardInput == 1 || rto.videoStandardInput == 2) && + utilsNotPassThroughMode() && rto.noSyncCounter == 0) { + // !rto.outModeHdBypass && rto.noSyncCounter == 0) { + // deinterlacer and scanline code + static uint8_t timingAdjustDelay = 0; + static uint8_t oddEvenWhenArmed = 0; + bool preventScanlines = 0; + + if (rto.deinterlaceAutoEnabled) { + uint16_t VPERIOD_IF = GBS::VPERIOD_IF::read(); + static uint8_t filteredLineCountMotionAdaptiveOn = 0, filteredLineCountMotionAdaptiveOff = 0; + static uint16_t VPERIOD_IF_OLD = VPERIOD_IF; // for glitch filter + + if (VPERIOD_IF_OLD != VPERIOD_IF) { + // freezeVideo(); // glitch filter + preventScanlines = 1; + filteredLineCountMotionAdaptiveOn = 0; + filteredLineCountMotionAdaptiveOff = 0; + if (uopt.enableFrameTimeLock || rto.extClockGenDetected) { + if (uopt.deintMode == 1) { // using bob + timingAdjustDelay = 11; // arm timer (always) + oddEvenWhenArmed = VPERIOD_IF % 2; + } + } + } + + if (VPERIOD_IF == 522 || VPERIOD_IF == 524 || VPERIOD_IF == 526 || + VPERIOD_IF == 622 || VPERIOD_IF == 624 || VPERIOD_IF == 626) { // ie v:524, even counts > enable + filteredLineCountMotionAdaptiveOn++; + filteredLineCountMotionAdaptiveOff = 0; + if (filteredLineCountMotionAdaptiveOn >= 2) // at least >= 2 + { + if (uopt.deintMode == 0 && !rto.motionAdaptiveDeinterlaceActive) { + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) { // don't rely on rto.scanlinesEnabled + if (rto.scanlinesEnabled) { + _DBGN(F("disable SL 01")); + disableScanlines(); + } + enableMotionAdaptDeinterlace(); + if (timingAdjustDelay == 0) { + timingAdjustDelay = 11; // arm timer only if it's not already armed + oddEvenWhenArmed = VPERIOD_IF % 2; + } else { + timingAdjustDelay = 0; // cancel timer + } + preventScanlines = 1; + } + filteredLineCountMotionAdaptiveOn = 0; + } + } else if (VPERIOD_IF == 521 || VPERIOD_IF == 523 || VPERIOD_IF == 525 || + VPERIOD_IF == 623 || VPERIOD_IF == 625 || VPERIOD_IF == 627) { // ie v:523, uneven counts > disable + filteredLineCountMotionAdaptiveOff++; + filteredLineCountMotionAdaptiveOn = 0; + if (filteredLineCountMotionAdaptiveOff >= 2) // at least >= 2 + { + if (uopt.deintMode == 0 && rto.motionAdaptiveDeinterlaceActive) { + disableMotionAdaptDeinterlace(); + if (timingAdjustDelay == 0) { + timingAdjustDelay = 11; // arm timer only if it's not already armed + oddEvenWhenArmed = VPERIOD_IF % 2; + } else { + timingAdjustDelay = 0; // cancel timer + } + } + filteredLineCountMotionAdaptiveOff = 0; + } + } else { + filteredLineCountMotionAdaptiveOn = filteredLineCountMotionAdaptiveOff = 0; + } + + VPERIOD_IF_OLD = VPERIOD_IF; // part of glitch filter + + if (uopt.deintMode == 1) { // using bob + if (rto.motionAdaptiveDeinterlaceActive) { + disableMotionAdaptDeinterlace(); + FrameSync::reset(uopt.frameTimeLockMethod); + // TODO logic! + uopt.enableFrameTimeLock = true; + // GBS::GBS_RUNTIME_FTL_ADJUSTED::write(1); + lastVsyncLock = millis(); + } + if (uopt.wantScanlines && !rto.scanlinesEnabled) { + enableScanlines(); + _DBGN(F("enable SL 02")); + } else if (!uopt.wantScanlines && rto.scanlinesEnabled) { + disableScanlines(); + _DBGN(F("disable SL 03")); + } + } + + // timing adjust after a few stable cycles + // should arrive here with either odd or even VPERIOD_IF + /*if (timingAdjustDelay != 0) { + _WS(timingAdjustDelay); _WS(" "); + }*/ + if (timingAdjustDelay != 0) { + if ((VPERIOD_IF % 2) == oddEvenWhenArmed) { + timingAdjustDelay--; + if (timingAdjustDelay == 0) { + if (uopt.enableFrameTimeLock) { + FrameSync::reset(uopt.frameTimeLockMethod); + // TODO logic! + uopt.enableFrameTimeLock = true; + // GBS::GBS_RUNTIME_FTL_ADJUSTED::write(1); + delay(10); + lastVsyncLock = millis(); + } + externalClockGenSyncInOutRate(); + } + } + } + } + + // scanlines + if (uopt.wantScanlines) { + if (!rto.scanlinesEnabled && !rto.motionAdaptiveDeinterlaceActive && !preventScanlines) { + enableScanlines(); + _DBGN(F("enable SL 04")); + // } else if (!uopt.wantScanlines && rto.scanlinesEnabled) { // this will never happen + } else if (rto.scanlinesEnabled) { + disableScanlines(); + _DBGN(F("disable SL 05")); + } + } + } + } + } + + // RGBHV checks + if (rto.videoStandardInput >= 14) { + static uint16_t RGBHVNoSyncCounter = 0; + + if (uopt.preferScalingRgbhv && rto.continousStableCounter >= 2) { + bool needPostAdjust = 0; + static uint16_t activePresetLineCount = 0; + // is the source in range for scaling RGBHV and is it currently in mode 15? + uint16 sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); // if sourceLines = 0, might be in some reset state + if ((sourceLines <= 535 && sourceLines != 0) && rto.videoStandardInput == 15) { + uint16_t firstDetectedSourceLines = sourceLines; + bool moveOn = 1; + for (int i = 0; i < 30; i++) { // not the best check, but we don't want to try if this is not stable (usually is though) + sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + // range needed for interlace + if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { + moveOn = 0; + break; + } + delay(10); + } + if (moveOn) { + _WSN(F("RGB/HV upscale mode")); + rto.isValidForScalingRGBHV = true; + // GBS::GBS_OPTION_SCALING_RGBHV::write(1); + rto.autoBestHtotalEnabled = 1; + + if (rto.syncTypeCsync == false) { + GBS::SP_SOG_MODE::write(0); + GBS::SP_NO_COAST_REG::write(1); + GBS::ADC_5_00::write(0x10); // 5_00 might be required + GBS::PLL_IS::write(0); // 0_40 2: this provides a clock for IF and test bus readings + GBS::PLL_VCORST::write(1); // 0_43 5: also required for clock + delay(320); // min 250 + } else { + GBS::SP_SOG_MODE::write(1); + GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values + GBS::SP_H_CST_SP::write(0x80); // will be updated later + GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) + } + delay(4); + + float sourceRate = getSourceFieldRate(1); + _WSN(sourceRate); + + // todo: this hack is hard to understand when looking at applypreset and mode is suddenly 1,2 or 3 + // if (uopt.presetPreference == 2) { + if(utilsNotPassThroughMode()) { + // custom preset defined, try to load (set mode = 14 here early) + rto.videoStandardInput = 14; + } else { + if (sourceLines < 280) { + // this is "NTSC like?" check, seen 277 lines in "512x512 interlaced (emucrt)" + rto.videoStandardInput = 1; + } else if (sourceLines < 380) { + // this is "PAL like?" check, seen vt:369 (MDA mode) + rto.videoStandardInput = 2; + } else if (sourceRate > 44.0f && sourceRate < 53.8f) { + // not low res but PAL = "EDTV" + rto.videoStandardInput = 4; + needPostAdjust = 1; + } else { // sourceRate > 53.8f + // "60Hz EDTV" + rto.videoStandardInput = 3; + needPostAdjust = 1; + } + } + + // if (uopt.presetPreference == 10) { + if (utilsIsPassThroughMode()) { + // uopt.presetPreference = Output960P; // fix presetPreference which can be "bypass" + uopt.resolutionID = Output960; // fix presetPreference which can be "bypass" + } + + activePresetLineCount = sourceLines; + applyPresets(rto.videoStandardInput); + + // TODO enabling Upscaling here? + uopt.preferScalingRgbhv = true; + // GBS::GBS_OPTION_SCALING_RGBHV::write(1); + GBS::IF_INI_ST::write(16); // fixes pal(at least) interlace + GBS::SP_SOG_P_ATO::write(1); // 5_20 1 auto SOG polarity (now "hpw" should never be close to "ht") + + GBS::SP_SDCS_VSST_REG_L::write(2); // 5_3f + GBS::SP_SDCS_VSSP_REG_L::write(0); // 5_40 + + rto.coastPositionIsSet = rto.clampPositionIsSet = 0; + rto.videoStandardInput = 14; + + if (GBS::PLLAD_ICP::read() >= 6) { + GBS::PLLAD_ICP::write(5); // reduce charge pump current for more general use + latchPLLAD(); + delay(40); + } + + updateStopPositionDynamic(true); + if (rto.syncTypeCsync == false) { + GBS::SP_SOG_MODE::write(0); + GBS::SP_CLAMP_MANUAL::write(1); + GBS::SP_NO_COAST_REG::write(1); + } else { + GBS::SP_SOG_MODE::write(1); + GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values + GBS::SP_H_CST_SP::write(0x80); // will be updated later + GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) + } + delay(300); + + if (rto.extClockGenDetected) { + // switch to ext clock + // if (!rto.outModeHdBypass) { + if (utilsNotPassThroughMode()) { + uint8_t pll648_value = GBS::PLL648_CONTROL_01::read(); + if (pll648_value != 0x35 && pll648_value != 0x75) { + // first store original in an option byte in 1_2D + // GBS::GBS_PRESET_DISPLAY_CLOCK::write(GBS::PLL648_CONTROL_01::read()); + rto.presetDisplayClock = pll648_value; + // enable and switch input + Si.enable(0); + delayMicroseconds(800); + GBS::PLL648_CONTROL_01::write(0x75); + } + } + // sync clocks now + externalClockGenSyncInOutRate(); + } + + // note: this is all duplicated below. unify! + if (needPostAdjust) { + // base preset was "3" / no line doubling + // info: actually the position needs to be adjusted based on hor. freq or "h:" value (todo!) + GBS::IF_HB_ST2::write(0x08); // patches + GBS::IF_HB_SP2::write(0x68); // image + GBS::IF_HBIN_SP::write(0x50); // position + // if (rto.presetID == 0x05) { + if (uopt.resolutionID == Output1080) { + GBS::IF_HB_ST2::write(0x480); + GBS::IF_HB_SP2::write(0x8E); + } + + float sfr = getSourceFieldRate(0); + if (sfr >= 69.0) { + _WSN(F("source >= 70Hz")); + // increase vscale; vscale -= 57 seems to hit magic factor often + // 512 + 57 = 569 + 57 = 626 + 57 = 683 + GBS::VDS_VSCALE::write(GBS::VDS_VSCALE::read() - 57); + + } else { + // 50/60Hz, presumably + // adjust vposition + GBS::IF_VB_SP::write(8); + GBS::IF_VB_ST::write(6); + } + } + } + } + // if currently in scaling RGB/HV, check for "SD" < > "EDTV" style source changes + else if ((sourceLines <= 535 && sourceLines != 0) && rto.videoStandardInput == 14) { + // todo: custom presets? + if (sourceLines < 280 && activePresetLineCount > 280) { + rto.videoStandardInput = 1; + } else if (sourceLines < 380 && activePresetLineCount > 380) { + rto.videoStandardInput = 2; + } else if (sourceLines > 380 && activePresetLineCount < 380) { + rto.videoStandardInput = 3; + needPostAdjust = 1; + } + + if (rto.videoStandardInput != 14) { + // check thoroughly first + uint16_t firstDetectedSourceLines = sourceLines; + bool moveOn = 1; + for (int i = 0; i < 30; i++) { + sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { + moveOn = 0; + break; + } + delay(10); + } + + if (moveOn) { + // need to change presets + if (rto.videoStandardInput <= 2) { + _WSN(F("RGB/HV upscale mode base 15kHz")); + } else { + _WSN(F("RGB/HV upscale mode base 31kHz")); + } + + // if (uopt.presetPreference == 10) { + if (utilsIsPassThroughMode()) { + // uopt.presetPreference = Output960P; // fix presetPreference which can be "bypass" + uopt.resolutionID = Output960; // fix presetPreference which can be "bypass" + } + + activePresetLineCount = sourceLines; + applyPresets(rto.videoStandardInput); + + // TODO enabling Upscale here? + uopt.preferScalingRgbhv = true; + // GBS::GBS_OPTION_SCALING_RGBHV::write(1); + GBS::IF_INI_ST::write(16); // fixes pal(at least) interlace + GBS::SP_SOG_P_ATO::write(1); // 5_20 1 auto SOG polarity + + // adjust vposition + GBS::SP_SDCS_VSST_REG_L::write(2); // 5_3f + GBS::SP_SDCS_VSSP_REG_L::write(0); // 5_40 + + rto.coastPositionIsSet = rto.clampPositionIsSet = 0; + rto.videoStandardInput = 14; + + if (GBS::PLLAD_ICP::read() >= 6) { + GBS::PLLAD_ICP::write(5); // reduce charge pump current for more general use + latchPLLAD(); + } + + updateStopPositionDynamic(true); + if (rto.syncTypeCsync == false) { + GBS::SP_SOG_MODE::write(0); + GBS::SP_CLAMP_MANUAL::write(1); + GBS::SP_NO_COAST_REG::write(1); + } else { + GBS::SP_SOG_MODE::write(1); + GBS::SP_H_CST_ST::write(0x10); // 5_4d // set some default values + GBS::SP_H_CST_SP::write(0x80); // will be updated later + GBS::SP_H_PROTECT::write(1); // some modes require this (or invert SOG) + } + delay(300); + + if (rto.extClockGenDetected) { + // switch to ext clock + // if (!rto.outModeHdBypass) { + if (utilsNotPassThroughMode()) { + uint8_t pll648_value = GBS::PLL648_CONTROL_01::read(); + if (pll648_value != 0x35 && pll648_value != 0x75) { + // first store original in an option byte in 1_2D + // GBS::GBS_PRESET_DISPLAY_CLOCK::write(GBS::PLL648_CONTROL_01::read()); + rto.presetDisplayClock = pll648_value; + // enable and switch input + Si.enable(0); + delayMicroseconds(800); + GBS::PLL648_CONTROL_01::write(0x75); + } + } + // sync clocks now + externalClockGenSyncInOutRate(); + } + + // note: this is all duplicated above. unify! + if (needPostAdjust) { + // base preset was "3" / no line doubling + // info: actually the position needs to be adjusted based on hor. freq or "h:" value (todo!) + GBS::IF_HB_ST2::write(0x08); // patches + GBS::IF_HB_SP2::write(0x68); // image + GBS::IF_HBIN_SP::write(0x50); // position + // if (rto.presetID == 0x05) { + if (uopt.resolutionID == Output1080) { + GBS::IF_HB_ST2::write(0x480); + GBS::IF_HB_SP2::write(0x8E); + } + + float sfr = getSourceFieldRate(0); + if (sfr >= 69.0) { + _WSN(F("source >= 70Hz")); + // increase vscale; vscale -= 57 seems to hit magic factor often + // 512 + 57 = 569 + 57 = 626 + 57 = 683 + GBS::VDS_VSCALE::write(GBS::VDS_VSCALE::read() - 57); + + } else { + // 50/60Hz, presumably + // adjust vposition + GBS::IF_VB_SP::write(8); + GBS::IF_VB_ST::write(6); + } + } + } else { + // was unstable, undo videoStandardInput change + rto.videoStandardInput = 14; + } + } + } + // check whether to revert back to full bypass + else if ((sourceLines > 535) && rto.videoStandardInput == 14) { + uint16_t firstDetectedSourceLines = sourceLines; + bool moveOn = 1; + for (int i = 0; i < 30; i++) { + sourceLines = GBS::STATUS_SYNC_PROC_VTOTAL::read(); + // range needed for interlace + if ((sourceLines < firstDetectedSourceLines - 3) || (sourceLines > firstDetectedSourceLines + 3)) { + moveOn = 0; + break; + } + delay(10); + } + if (moveOn) { + _WSN(F("RGB/HV upscale mode disabled")); + rto.videoStandardInput = 15; + rto.isValidForScalingRGBHV = false; + + activePresetLineCount = 0; + applyPresets(rto.videoStandardInput); // exception: apply preset here, not later in syncwatcher + + delay(300); + } + } + } // done preferScalingRgbhv + + if (!uopt.preferScalingRgbhv && rto.videoStandardInput == 14) { + // user toggled the web ui button / revert scaling rgbhv + rto.videoStandardInput = 15; + rto.isValidForScalingRGBHV = false; + applyPresets(rto.videoStandardInput); + delay(300); + } + + // stability check, for CSync and HV separately + uint16_t limitNoSync = 0; + uint8_t VSHSStatus = 0; + bool stable = 0; + if (rto.syncTypeCsync == true) { + if (GBS::STATUS_INT_SOG_BAD::read() == 1) { + // STATUS_INT_SOG_BAD = 0x0f bit 0, interrupt reg + resetModeDetect(); + stable = 0; + _WS(F(".")); + delay(10); + resetInterruptSogBadBit(); + } else { + stable = 1; + VSHSStatus = GBS::STATUS_00::read(); + // this status can get stuck (regularly does) + stable = ((VSHSStatus & 0x04) == 0x04); // RGBS > check h+v from 0_00 + } + limitNoSync = 200; // 100 + } else { + VSHSStatus = GBS::STATUS_16::read(); + // this status usually updates when a source goes off + stable = ((VSHSStatus & 0x0a) == 0x0a); // RGBHV > check h+v from 0_16 + limitNoSync = 300; + } + + if (!stable) { + LEDOFF; + RGBHVNoSyncCounter++; + rto.continousStableCounter = 0; + if (RGBHVNoSyncCounter % 20 == 0) { + _WS(F(".")); + } + } else { + RGBHVNoSyncCounter = 0; + LEDON; + if (rto.continousStableCounter < 255) { + rto.continousStableCounter++; + if (rto.continousStableCounter == 6) { + updateStopPositionDynamic(true); + } + } + } + + if (RGBHVNoSyncCounter > limitNoSync) { + RGBHVNoSyncCounter = 0; + _DBGN(F("(!) reset runtime parameters while running syncWatcher")); + presetsResetParameters(); + prepareSyncProcessor(); + resetSyncProcessor(); // todo: fix MD being stuck in last mode when sync disappears + // resetModeDetect(); + rto.noSyncCounter = 0; + // _WSN("RGBHV limit no sync"); + } + + static unsigned long lastTimeSogAndPllRateCheck = millis(); + if ((millis() - lastTimeSogAndPllRateCheck) > 900) { + if (rto.videoStandardInput == 15) { + // start out by adjusting sync polarity, may reset sog unstable interrupt flag + updateHVSyncEdge(); + delay(100); + } + + static uint8_t runsWithSogBadStatus = 0; + static uint8_t oldHPLLState = 0; + if (rto.syncTypeCsync == false) { + if (GBS::STATUS_INT_SOG_BAD::read()) { // SOG source unstable indicator + runsWithSogBadStatus++; + // _WS(F("test: ")); _WSN(runsWithSogBadStatus); + if (runsWithSogBadStatus >= 4) { + _WSN(F("RGB/HV < > SOG")); + rto.syncTypeCsync = true; + rto.HPLLState = runsWithSogBadStatus = RGBHVNoSyncCounter = 0; + rto.noSyncCounter = 0x07fe; // will cause a return + } + } else { + runsWithSogBadStatus = 0; + } + } + + uint32_t currentPllRate = 0; + static uint32_t oldPllRate = 10; + + // how fast is the PLL running? needed to set charge pump and gain + // typical: currentPllRate: 1560, currentPllRate: 3999 max seen the pll reach: 5008 for 1280x1024@75 + if (GBS::STATUS_INT_SOG_BAD::read() == 0) { + currentPllRate = getPllRate(); + // _WSN(currentPllRate); + if (currentPllRate > 100 && currentPllRate < 7500) { + if ((currentPllRate < (oldPllRate - 3)) || (currentPllRate > (oldPllRate + 3))) { + delay(40); + if (GBS::STATUS_INT_SOG_BAD::read() == 1) + delay(100); + currentPllRate = getPllRate(); // test again, guards against random spurs + // but don't force currentPllRate to = 0 if these inner checks fail, + // prevents csync <> hvsync changes + if ((currentPllRate < (oldPllRate - 3)) || (currentPllRate > (oldPllRate + 3))) { + oldPllRate = currentPllRate; // okay, it changed + } + } + } else { + currentPllRate = 0; + } + } + + resetInterruptSogBadBit(); + + // short activeChargePumpLevel = GBS::PLLAD_ICP::read(); + // short activeGainBoost = GBS::PLLAD_FS::read(); + // _WS(F(" rto.HPLLState: ")); _WSN(rto.HPLLState); + // _WS(F(" currentPllRate: ")); _WSN(currentPllRate); + // _WS(F(" CPL: ")); _WS(activeChargePumpLevel); + // _WS(F(" Gain: ")); _WS(activeGainBoost); + // _WS(F(" KS: ")); _WS(GBS::PLLAD_KS::read()); + + oldHPLLState = rto.HPLLState; // do this first, else it can miss events + if (currentPllRate != 0) { + if (currentPllRate < 1030) { + rto.HPLLState = 1; + } else if (currentPllRate < 2300) { + rto.HPLLState = 2; + } else if (currentPllRate < 3200) { + rto.HPLLState = 3; + } else if (currentPllRate < 3800) { + rto.HPLLState = 4; + } else { + rto.HPLLState = 5; + } + } + + if (rto.videoStandardInput == 15) { + if (oldHPLLState != rto.HPLLState) { + if (rto.HPLLState == 1) { + GBS::PLLAD_KS::write(2); // KS = 2 okay + GBS::PLLAD_FS::write(0); + GBS::PLLAD_ICP::write(6); + } else if (rto.HPLLState == 2) { + GBS::PLLAD_KS::write(1); + GBS::PLLAD_FS::write(0); + GBS::PLLAD_ICP::write(6); + } else if (rto.HPLLState == 3) { // KS = 1 okay + GBS::PLLAD_KS::write(1); + GBS::PLLAD_FS::write(1); + GBS::PLLAD_ICP::write(6); // would need 7 but this is risky + } else if (rto.HPLLState == 4) { + GBS::PLLAD_KS::write(0); // KS = 0 from here on + GBS::PLLAD_FS::write(0); + GBS::PLLAD_ICP::write(6); + } else if (rto.HPLLState == 5) { + GBS::PLLAD_KS::write(0); // KS = 0 + GBS::PLLAD_FS::write(1); + GBS::PLLAD_ICP::write(6); + } + + latchPLLAD(); + delay(2); + setOverSampleRatio(4, false); // false = do apply // will auto decrease to max possible factor + _DBGF(PSTR("(H-PLL) rate: %ld state: %d\n"), currentPllRate, rto.HPLLState); + delay(100); + } + } else if (rto.videoStandardInput == 14) { + if (oldHPLLState != rto.HPLLState) { + _DBGF(PSTR("(H-PLL) rate: %ld state (no change): %d\n"), currentPllRate, rto.HPLLState); + // need to manage HPLL state change somehow + // FrameSync::reset(uopt.frameTimeLockMethod); + } + + // scanlines + if (uopt.wantScanlines) { + if (!rto.scanlinesEnabled && !rto.motionAdaptiveDeinterlaceActive) { + if (GBS::IF_LD_RAM_BYPS::read() == 0) { // line doubler on? + _DBGN(F("enable SL 06")); + enableScanlines(); + } + // } else if (!uopt.wantScanlines && rto.scanlinesEnabled) { // this will never happen + } else if (rto.scanlinesEnabled) { + disableScanlines(); + _DBGN(F("disable SL 07")); + } + } + } + + rto.clampPositionIsSet = false; // RGBHV should regularly check clamp position + lastTimeSogAndPllRateCheck = millis(); + } + } + + if (rto.noSyncCounter >= 0x07fe) { + // couldn't recover, source is lost + // restore initial conditions and move to input detect + GBS::DAC_RGBS_PWDNZ::write(0); // 0 = disable DAC + rto.noSyncCounter = 0; + yield(); + goLowPowerWithInputDetection(); // does not further nest, so it can be called here // sets reset parameters + } +} + +/** + * @brief Get the Moving Average object + * feed the current measurement, get back the moving average + * @param item + * @return uint8_t + */ +uint8_t getMovingAverage(uint8_t item) +{ + static const uint8_t sz = 16; + static uint8_t arr[sz] = {0}; + static uint8_t pos = 0; + + arr[pos] = item; + if (pos < (sz - 1)) { + pos++; + } else { + pos = 0; + } + + uint16_t sum = 0; + for (uint8_t i = 0; i < sz; i++) { + sum += arr[i]; + } + return sum >> 4; // for array size 16 +} + +/** + * @brief GBS boards have 2 potential sync sources: + * - RCA connectors + * - VGA input / 5 pin RGBS header / 8 pin VGA header (all 3 are shared electrically) + * This routine looks for sync on the currently active input. If it finds it, + * the input is returned. If it doesn't find sync, it switches the input and + * returns 0, so that an active input will be found eventually. + * + * @return uint8_t + */ +uint8_t detectAndSwitchToActiveInput() +{ + uint8_t currentInput = GBS::ADC_INPUT_SEL::read(); + unsigned long timeout = millis(); + while (millis() - timeout < 450) { + delay(10); + + bool stable = getStatus16SpHsStable(); + if (stable) { + currentInput = GBS::ADC_INPUT_SEL::read(); + _WS(F("Activity detected, input: ")); + if (currentInput == 1) + _WSN(F("RGB")); + else + _WSN(F("Component")); + + if (currentInput == 1) { // RGBS or RGBHV (R1/G1/B1/SOG1) + bool vsyncActive = 0; + rto.inputIsYPbPr = false; // declare for MD + rto.currentLevelSOG = 13; // test startup with MD and MS separately! + setAndUpdateSogLevel(rto.currentLevelSOG); + + unsigned long timeOutStart = millis(); + // vsync test + // 360ms good up to 5_34 SP_V_TIMER_VAL = 0x0b + while (!vsyncActive && ((millis() - timeOutStart) < 360)) { + vsyncActive = GBS::STATUS_SYNC_PROC_VSACT::read(); + delay(1); + } + + // if VSync is active, it's RGBHV or RGBHV with CSync on HS pin + if (vsyncActive) { + _WSN(F("VSync: present")); + GBS::MD_SEL_VGA60::write(1); // VGA 640x480 more likely than EDTV + bool hsyncActive = 0; + + timeOutStart = millis(); + while (!hsyncActive && millis() - timeOutStart < 400) { + hsyncActive = GBS::STATUS_SYNC_PROC_HSACT::read(); + delay(1); + } + + if (hsyncActive) { + _WS(F("HSync: present")); + // The HSync and SOG pins are setup to detect CSync, if present + // (SOG mode on, coasting setup, debug bus setup, etc) + // SP_H_PROTECT is needed for CSync with a VS source present as well + GBS::SP_H_PROTECT::write(1); + delay(120); + + short decodeSuccess = 0; + for (int i = 0; i < 3; i++) { + // no success if: no signal at all (returns 0.0f), no embedded VSync (returns ~18.5f) + // todo: this takes a while with no csync present + rto.syncTypeCsync = 1; // temporary for test + float sfr = getSourceFieldRate(1); + rto.syncTypeCsync = 0; // undo + if (sfr > 40.0f) + decodeSuccess++; // properly decoded vsync from 40 to xx Hz + } + + if (decodeSuccess >= 2) { + _WSN(F(" (with CSync)")); + GBS::SP_PRE_COAST::write(0x10); // increase from 9 to 16 (EGA 364) + delay(40); + rto.syncTypeCsync = true; + } else { + _WSN(); + rto.syncTypeCsync = false; + } + + // check for 25khz, all regular SOG modes first // update: only check for mode 8 + // MD reg for medium res starts at 0x2C and needs 16 loops to ramp to max of 0x3C (vt 360 .. 496) + // if source is HS+VS, can't detect via MD unit, need to set 5_11=0x92 and look at vt: counter + for (uint8_t i = 0; i < 16; i++) { + // printInfo(); + uint8_t innerVideoMode = getVideoMode(); + if (innerVideoMode == 8) { + setAndUpdateSogLevel(rto.currentLevelSOG); + rto.medResLineCount = GBS::MD_HD1250P_CNTRL::read(); + _WSN(F("med res")); + + return 1; + } + // update 25khz detection + GBS::MD_HD1250P_CNTRL::write(GBS::MD_HD1250P_CNTRL::read() + 1); + // _WSF("0x%04X", GBS::MD_HD1250P_CNTRL::read()); + delay(30); + } + + rto.videoStandardInput = 15; + // exception: apply preset here, not later in syncwatcher + applyPresets(rto.videoStandardInput); + delay(100); + + return 3; + } else { + // need to continue looking + _WSN(F("but no HSync!")); + } + } + + if (!vsyncActive) { // then do RGBS check + rto.syncTypeCsync = true; + GBS::MD_SEL_VGA60::write(0); // EDTV60 more likely than VGA60 + uint16_t testCycle = 0; + timeOutStart = millis(); + while ((millis() - timeOutStart) < 6000) { + delay(2); + if (getVideoMode() > 0) { + if (getVideoMode() != 8) { // if it's mode 8, need to set stuff first + return 1; + } + } + testCycle++; + // post coast 18 can mislead occasionally (SNES 239 mode) + // but even then it still detects the video mode pretty well + if ((testCycle % 150) == 0) { + if (rto.currentLevelSOG == 1) { + rto.currentLevelSOG = 2; + } else { + rto.currentLevelSOG += 2; + } + if (rto.currentLevelSOG >= 15) { + rto.currentLevelSOG = 1; + } + setAndUpdateSogLevel(rto.currentLevelSOG); + } + + // new: check for 25khz, use regular scaling route for those + if (getVideoMode() == 8) { + rto.currentLevelSOG = rto.thisSourceMaxLevelSOG = 13; + setAndUpdateSogLevel(rto.currentLevelSOG); + rto.medResLineCount = GBS::MD_HD1250P_CNTRL::read(); + _WSN(F("med res")); + return 1; + } + + uint8_t currentMedResLineCount = GBS::MD_HD1250P_CNTRL::read(); + if (currentMedResLineCount < 0x3c) { + GBS::MD_HD1250P_CNTRL::write(currentMedResLineCount + 1); + } else { + GBS::MD_HD1250P_CNTRL::write(0x33); + } + // _WSF("0x%04X", GBS::MD_HD1250P_CNTRL::read()); + } + + // rto.currentLevelSOG = rto.thisSourceMaxLevelSOG = 13; + // setAndUpdateSogLevel(rto.currentLevelSOG); + + return 1; // anyway, let later stage deal with it + } + + GBS::SP_SOG_MODE::write(1); + resetSyncProcessor(); + resetModeDetect(); // there was some signal but we lost it. MD is stuck anyway, so reset + delay(40); + } else if (currentInput == 0) { // YUV (R0/G0/B0/SOG0) + uint16_t testCycle = 0; + rto.inputIsYPbPr = true; // declare for MD + GBS::MD_SEL_VGA60::write(0); // EDTV more likely than VGA 640x480 + + unsigned long timeOutStart = millis(); + while ((millis() - timeOutStart) < 6000) { + delay(2); + if (getVideoMode() > 0) { + return 2; + } + + testCycle++; + if ((testCycle % 180) == 0) { + if (rto.currentLevelSOG == 1) { + rto.currentLevelSOG = 2; + } else { + rto.currentLevelSOG += 2; + } + if (rto.currentLevelSOG >= 16) { + rto.currentLevelSOG = 1; + } + setAndUpdateSogLevel(rto.currentLevelSOG); + rto.thisSourceMaxLevelSOG = rto.currentLevelSOG; + } + } + + rto.currentLevelSOG = rto.thisSourceMaxLevelSOG = 14; + setAndUpdateSogLevel(rto.currentLevelSOG); + + return 2; // anyway, let later stage deal with it + } + + _WSN(F(" lost..")); + rto.currentLevelSOG = 2; + setAndUpdateSogLevel(rto.currentLevelSOG); + } + + GBS::ADC_INPUT_SEL::write(!currentInput); // can only be 1 or 0 + delay(200); + } + + // don't do the check on the new input here, wait till next run + return 0; +} + +/** + * @brief This sets the following runtime variables: + * rto.videoStandardInput + * rto.sourceDisconnected + * rto.currentLevelSOG + * rto.inputIsYPbPr + * rto.isInLowPowerMode + * rto.syncTypeCsync + * rto.thisSourceMaxLevelSOG + * rto.medResLineCount (only RGB/Component) + * + * @return uint8_t + */ +uint8_t inputAndSyncDetect() +{ + uint8_t syncFound = detectAndSwitchToActiveInput(); + + if (syncFound == 0) { + if (!getSyncPresent()) { + if (rto.isInLowPowerMode == false) { + rto.sourceDisconnected = true; + rto.videoStandardInput = 0; + // reset to base settings, then go to low power + GBS::SP_SOG_MODE::write(1); + goLowPowerWithInputDetection(); + delay(10); + // rto.isInLowPowerMode = true; + } + } + return 0; + } else if (syncFound == 1) { // input is RGBS + rto.inputIsYPbPr = 0; + rto.sourceDisconnected = false; + rto.isInLowPowerMode = false; + resetDebugPort(); + applyRGBPatches(); + LEDON; + return 1; + } else if (syncFound == 2) { // YUV (PAL) + rto.inputIsYPbPr = 1; + rto.sourceDisconnected = false; + rto.isInLowPowerMode = false; + resetDebugPort(); + applyYuvPatches(); + LEDON; + return 2; + } else if (syncFound == 3) { // input is RGBHV + // already applied + rto.isInLowPowerMode = false; + rto.inputIsYPbPr = 0; + rto.sourceDisconnected = false; + rto.videoStandardInput = 15; + resetDebugPort(); + LEDON; + return 3; + } + + return 0; +} \ No newline at end of file diff --git a/src/video.h b/src/video.h new file mode 100644 index 00000000..34ab4a75 --- /dev/null +++ b/src/video.h @@ -0,0 +1,116 @@ +/* +##################################################################################### +# File: video.h # +# File Created: Thursday, 2nd May 2024 4:08:03 pm # +# Author: # +# Last Modified: Sunday, 23rd June 2024 12:15:28 am # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include "options.h" +#include "wserial.h" +#include "framesync.h" + +extern unsigned long lastVsyncLock; +extern void doPostPresetLoadSteps(bool forceApply); +extern void printInfo(); +extern void loadPresetMdSection(); +extern void loadPresetDeinterlacerSection(); +extern void presetsResetParameters(); +extern void printVideoTimings(); +extern void applyPresets(uint8_t result); + +void resetInterruptSogSwitchBit(); +void resetInterruptSogBadBit(); +void resetInterruptNoHsyncBadBit(); +bool videoStandardInputIsPalNtscSd(); +void prepareSyncProcessor(); +bool getStatus16SpHsStable(); +float getSourceFieldRate(bool useSPBus); +float getOutputFrameRate(); +void externalClockGenSyncInOutRate(); +void externalClockGenResetClock(); +bool applyBestHTotal(uint16_t bestHTotal); +bool runAutoBestHTotal(); +bool snapToIntegralFrameRate(void); +void applyRGBPatches(); +void setAndLatchPhaseSP(); +void setAndUpdateSogLevel(uint8_t level); +bool optimizePhaseSP(); +void setOverSampleRatio(uint8_t newRatio, bool prepareOnly); +void updateStopPositionDynamic(bool withCurrentVideoModeCheck); +void setOutputHdBypassMode(bool regsInitialized = true); +void setAdcGain(uint8_t gain); +void resetSyncProcessor(); +void togglePhaseAdjustUnits(); +void setOutputRGBHVBypassMode(); +void runAutoGain(); +void enableScanlines(); +void disableScanlines(); +void enableMotionAdaptDeinterlace(); +void disableMotionAdaptDeinterlace(); +void writeProgramArrayNew(const uint8_t *programArray, bool skipMDSection); +void activeFrameTimeLockInitialSteps(); +void applyComponentColorMixing(); +void applyYuvPatches(); +void OutputComponentOrVGA(); +void toggleIfAutoOffset(); +void setAdcParametersGainAndOffset(); +void updateHVSyncEdge(); +void goLowPowerWithInputDetection(); +void optimizeSogLevel(); +void resetModeDetect(); +void shiftHorizontal(uint16_t amountToShift, bool subtracting); +void shiftHorizontalLeft(); +void shiftHorizontalRight(); +// void shiftHorizontalLeftIF(uint8_t amount); +// void shiftHorizontalRightIF(uint8_t amount); +void scaleHorizontal(uint16_t amountToScale, bool subtracting); +void moveHS(uint16_t amountToAdd, bool subtracting); +// void moveVS(uint16_t amountToAdd, bool subtracting); +void invertHS(); +void invertVS(); +void scaleVertical(uint16_t amountToScale, bool subtracting); +void shiftVertical(uint16_t amountToAdd, bool subtracting); +// void shiftVerticalUp(); +// void shiftVerticalDown(); +void shiftVerticalUpIF(); +void shiftVerticalDownIF(); +void setHSyncStartPosition(uint16_t value); +void setHSyncStopPosition(uint16_t value); +void setMemoryHblankStartPosition(uint16_t value); +void setMemoryHblankStopPosition(uint16_t value); +void setDisplayHblankStartPosition(uint16_t value); +void setDisplayHblankStopPosition(uint16_t value); +void setVSyncStartPosition(uint16_t value); +void setVSyncStopPosition(uint16_t value); +void setMemoryVblankStartPosition(uint16_t value); +void setMemoryVblankStopPosition(uint16_t value); +void setDisplayVblankStartPosition(uint16_t value); +void setDisplayVblankStopPosition(uint16_t value); +uint16_t getCsVsStart(); +uint16_t getCsVsStop(); +// void set_htotal(uint16_t htotal); +void set_vtotal(uint16_t vtotal); +// void setIfHblankParameters(); +bool getSyncPresent(); +// bool getStatus00IfHsVsStable(); +void advancePhase(); +// void movePhaseThroughRange(); +void updateCoastPosition(bool autoCoast); +void updateClampPosition(); +// void fastSogAdjust(); +uint32_t getPllRate(); +void runSyncWatcher(); +uint8_t getMovingAverage(uint8_t item); +uint8_t detectAndSwitchToActiveInput(); +uint8_t inputAndSyncDetect(); + + +#endif // _VIDEO_H_ \ No newline at end of file diff --git a/src/wifiman.cpp b/src/wifiman.cpp new file mode 100644 index 00000000..693756a9 --- /dev/null +++ b/src/wifiman.cpp @@ -0,0 +1,237 @@ +/* +##################################################################################### +# File: wifiman.cpp # +# File Created: Friday, 19th April 2024 2:25:33 pm # +# Author: Sergey Ko # +# Last Modified: Monday, 24th June 2024 9:16:38 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#include "wifiman.h" + +static unsigned long _connectCheckTime = 0; +// static unsigned long _lastTimePing = 0; + +#ifdef THIS_DEVICE_MASTER + +static const char ap_info_string[] PROGMEM = + "(WiFi): AP mode (SSID: gbscontrol, pass 'qqqqqqqq'): Access 'gbscontrol.local' in your browser"; +const char st_info_string[] PROGMEM = + "(WiFi): Access 'http://gbscontrol:80' or 'http://gbscontrol.local' (or device IP) in your browser"; + +#else + +static const char ap_info_string[] PROGMEM = + "(WiFi): AP mode (SSID: gbsslave, pass 'qqqqqqqq'): Access 'gbsslave.local' in your browser"; +static const char st_info_string[] PROGMEM = + "(WiFi): Access 'http://gbsslave:80' or 'http://gbsslave.local' (or device IP) in your browser"; + +#endif + +/** + * @brief + * + * @param e + */ +static void wifiEventHandler(System_Event_t *e) +{ + if (e->event == WIFI_EVENT_STAMODE_CONNECTED) + { + // _DBGN(F("(WiFi): STA mode connected")); + _connectCheckTime = 0; + } + else if(e->event == WIFI_EVENT_STAMODE_GOT_IP) + { + _DBGF(PSTR("(WiFi): got IP: %s\n"), WiFi.localIP().toString()); + if (MDNS.begin(String(gbsc_device_hostname).c_str(), WiFi.localIP())) { // MDNS request for gbscontrol.local + MDNS.addService("http", "tcp", 80); // Add service to MDNS-SD + MDNS.announce(); + } + _DBGN(FPSTR(st_info_string)); + } + else if(e->event == WIFI_EVENT_MODE_CHANGE) + { + if(e->event_info.opmode_changed.new_opmode == WIFI_AP) { + MDNS.end(); + } + _DBGF(PSTR("(WiFi) mode changed, now: %d\n"), WiFi.getMode()); + } + else if(e->event == WIFI_EVENT_STAMODE_DISCONNECTED) + { + _connectCheckTime = millis(); + _DBGN(F("disconnected from AP, reconnect...")); + } + else if(e->event == WIFI_EVENT_SOFTAPMODE_STACONNECTED) + { + uint8_t * mac = e->event_info.sta_connected.mac; + _DBGF(PSTR("station connected, MAC: %02X:%02X:%02X:%02X:%02X:%02X\n"), + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else if(e->event == WIFI_EVENT_SOFTAPMODE_STADISCONNECTED) + { + uint8_t * mac = e->event_info.sta_disconnected.mac; + _DBGF(PSTR("station disconnected, MAC: %02X:%02X:%02X:%02X:%02X:%02X\n"), + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } +} + +/** + * @brief + * + */ +void wifiInit() { + wifi_set_event_handler_cb(wifiEventHandler); + WiFi.persistent(true); + WiFi.setAutoReconnect(false); + WiFi.hostname(String(gbsc_device_hostname).c_str()); + WiFi.setSleepMode(WIFI_NONE_SLEEP); + WiFi.setOutputPower(16.0f); // float: min 0.0f, max 20.5f + + if (!wifiStartStaMode("")) { + _connectCheckTime = millis(); + // no stored network to connect to -> start AP mode at once + // wifiStartApMode(); + } +} + +/** + * @brief + * + */ +void wifiDisable() { + //WiFi.disconnect(); // deletes credentials + WiFi.mode(WIFI_OFF); + WiFi.forceSleepBegin(); +} + +/** + * @brief + * + */ +bool wifiStartStaMode(const String & ssid, const String & pass) { + // int8_t cntr = 10; + // and off we go... + WiFi.mode(WIFI_STA); + if (ssid.length()) { + WiFi.begin(ssid.c_str(), pass.c_str()); + } else { + // using credentials stored in flash + WiFi.begin(); + } + _DBGF(PSTR("connecting to: %s...\n"), ssid.c_str()); + // no fancy stuffs here :) + // while(WiFi.status() == WL_DISCONNECTED && cntr != 0) { + // delay(500); + // cntr--; + // } + delay(100); + return (WiFi.status() == WL_CONNECTED); +} + +/** + * @brief + * + */ +bool wifiStartApMode() { + bool ret = false; + // delay(100); + IPAddress apIP(192, 168, 4, 1); + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + + ret = WiFi.softAP(wifiGetApSSID().c_str(), strlen_P(ap_password) != 0 ? wifiGetApPASS().c_str() : NULL, 1, 0 ,2); + if(ret) { + dnsServer.stop(); + dnsServer.setTTL(300); // (in seconds) as per example + dnsServer.start(53, "*", apIP); + dnsServer.setErrorReplyCode(DNSReplyCode::NoError); + if(!dnsServer.start((byte)53, "*", apIP)) //used for captive portal in AP mode + _DBGN(F("DNS no sockets available...")); + + _DBGN(FPSTR(ap_info_string)); + } + return ret; +} + +/** + * @brief + * + * @return true + * @return false + */ +bool wifiStartWPS() { + _DBGN(F("starting WPS")); + WiFi.disconnect(); + delay(100); + WiFi.mode(WIFI_STA); + bool ret = WiFi.beginWPSConfig(); + if(ret) { + String newSSID = WiFi.SSID(); + if(newSSID.length() > 0) { + _DBGF(PSTR("WPS connected to SSID: %s\n"), newSSID.c_str()); + ret = true; + } else { + _DBGN(F("WPS failed. please try again")); + ret = false; + } + } + return ret; +} + +/** + * @brief Put this method inside of main loop + * + */ +void wifiLoop() { + if(WiFi.status() != WL_CONNECTED + && _connectCheckTime != 0 + && millis() > (_connectCheckTime + 5000UL)) { + // if empty - use last stored credentials + String s = WiFi.SSID(); + if(s.length() != 0) { + _DBGF(PSTR("(!) trying to reconnect to SSID: %s\n"), WiFi.SSID().c_str()); + _connectCheckTime = millis(); + WiFi.reconnect(); + } else { + _DBGN(F("(!) switched to AP mode")); + wifiStartApMode(); + _connectCheckTime = 0; + } + } +} + +/** + * @brief Temporary solution + * @todo this function is used by wserver since ap_ssid is not available there. + * + * @return String + */ +const String wifiGetApSSID() { + return String(ap_ssid); +} + +/** + * @brief Temporary solution + * + * @return String + */ +const String wifiGetApPASS() { + return String(ap_password); +} + +/** + * @brief Returns 0 if NOT connected to AP or NOT in AP_STA mode + * + * @param r + * @return true + * @return false + */ +int8_t wifiGetRSSI() { + if ((WiFi.status() == WL_CONNECTED) || (WiFi.getMode() == WIFI_AP)) { + return (int8_t)wifi_station_get_rssi(); + } + return 0; +} \ No newline at end of file diff --git a/src/wifiman.h b/src/wifiman.h new file mode 100644 index 00000000..adc45e06 --- /dev/null +++ b/src/wifiman.h @@ -0,0 +1,51 @@ +/* +##################################################################################### +# File: wifiman.h # +# File Created: Friday, 19th April 2024 2:25:42 pm # +# Author: Sergey Ko # +# Last Modified: Thursday, 13th June 2024 4:40:11 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#ifndef _WIFIMAN_H_ +#define _WIFIMAN_H_ + +#include +#include +#include +#include +#include "tv5725.h" +#include "options.h" +#include "wserial.h" + +extern DNSServer dnsServer; + +// HOWTO: Rely on the previously implemented logic +// __________ _____________ __________________ yes _____________________ +// | if ssid | -> | connect AP | -> | connect failed? | ---> | fallback to APmode | +// ---------- ------------- ------------------ --------------------- +// ^ _________________ |_____________ +// | | yes v no | +// | no ____________________ _______________ | +// ---- | is now connected? | < -- | continue ops | < -- +// -------------------- --------------- +// +// THE OBJECTIVE: Do not rely on build-in autoreconnect routine, +// use the custom one instead. + +// void updateWebSocketData(); +void wifiInit(); +void wifiDisable(); +bool wifiStartStaMode(const String & ssid, const String & pass = ""); +bool wifiStartApMode(); +bool wifiStartWPS(); +void wifiLoop(); +const String wifiGetApSSID(); +const String wifiGetApPASS(); +int8_t wifiGetRSSI(); +// void wifiReset(); + +#endif // _WIFIMAN_H_ \ No newline at end of file diff --git a/src/wserial.cpp b/src/wserial.cpp new file mode 100644 index 00000000..4e4bf627 --- /dev/null +++ b/src/wserial.cpp @@ -0,0 +1,86 @@ +/* +########################################################################### +# File: wserial.cpp # +# File Created: Friday, 19th April 2024 4:13:35 pm # +# Author: Sergey Ko # +# Last Modified: Tuesday, 18th June 2024 1:29:36 pm # +# Modified By: Sergey Ko # +########################################################################### +# CHANGELOG: # +########################################################################### +*/ + +#include "wserial.h" + +static char * serialBuffer = nullptr; + +/** + * @brief If developer mode enabled serialBuffer will be created. + * If developer mode disabled serialBuffer will be destroyed. + */ +void serialDevModeToggle() { + if(uopt.developerMode) { + if(serialBuffer == nullptr) { + serialBuffer = (char *)malloc(SERIAL_BUFFER_MAX_LEN); + serialBufferClean(); + } + return; + } + // destroy buffer if not the developer mode + free(serialBuffer); + serialBuffer = nullptr; +} + +/** + * @brief + * + */ +void discardSerialRxData() +{ + uint16_t maxThrowAway = 0x1fff; + while (Serial.available() && maxThrowAway > 0) { + Serial.read(); + maxThrowAway--; + } +} + +/** + * @brief Returns serial buffer data. bufferLength (string length) + * may be retrieved by passing bufferLength argumentß + * + * @param bufferLength + * @return const uint8_t* + */ +const char * serialGetBuffer() { + return serialBuffer; +} + +/** + * @brief Empty serial buffer + * + */ +void serialBufferClean() { + memset(serialBuffer, '\0', SERIAL_BUFFER_MAX_LEN); +} + +/** + * @brief adding serial output data to accumulator (serialBuffer) + * + * @param data + * @param size + */ +void SerialMirror::pushToBuffer(void * data, size_t size) { + if(!uopt.developerMode) + return; + uint16_t i = 0; + const char * d = reinterpret_cast(data); + size_t buffLen = strlen(serialBuffer); + while((buffLen + i) < SERIAL_BUFFER_MAX_LEN && i < size) { + *(serialBuffer + buffLen + i) = *(d + i); + i++; + } + // do not clog the output, use only for debug + // if(i < size) + // _DBGN(F("(!) serial buffer is full, data truncated...")); +} + diff --git a/src/wserial.h b/src/wserial.h new file mode 100644 index 00000000..a0492b91 --- /dev/null +++ b/src/wserial.h @@ -0,0 +1,133 @@ +/* +##################################################################################### +# File: wserial.h # +# File Created: Friday, 19th April 2024 4:13:41 pm # +# Author: Sergey Ko # +# Last Modified: Thursday, 13th June 2024 4:35:52 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#ifndef _WSERIAL_H_ +#define _WSERIAL_H_ + +#include +#include "options.h" + +extern char serialCommand; +extern char userCommand; +extern WebSocketsServer webSocket; + +// TODO: useless ? +/* #define LOMEM_SP ((ESP.getFreeHeap() > 10000)) +#define ASSERT_LOMEM_SP() do { \ + if(LOMEM_SP) webSocket.disconnect(); \ +} while(0) */ + +void discardSerialRxData(); +void serialDevModeToggle(); +const char * serialGetBuffer(); +void serialBufferClean(); + +#if defined(ESP8266) +// serial mirror class for websocket logs +class SerialMirror : public Stream +{ + void pushToBuffer(void * data, size_t size); + + size_t write(const uint8_t *data, size_t size) + { + pushToBuffer((void *)data, size); + Serial.write(data, size); + return size; + } + + size_t write(const char *data, size_t size) + { + pushToBuffer((void *)data, size); + Serial.write(data, size); + return size; + } + + size_t write(uint8_t data) + { + size_t s = 1; + pushToBuffer(&data, s); + Serial.write(data); + return 1; + } + + size_t write(char data) + { + size_t s = 1; + pushToBuffer(&data, s); + Serial.write(data); + return 1; + } + + int available() + { + return 0; + } + int read() + { + return -1; + } + int peek() + { + return -1; + } + void flush() {} +}; + +extern SerialMirror SerialM; + +// console at websocket +#define _WSF(D, ...) \ +do { \ + SerialM.printf(D, ##__VA_ARGS__); \ +} while(0) +#define _WSN(D) \ +do { \ + SerialM.println(D); \ +} while(0) +#define _WS(D) \ +do { \ + SerialM.print(D); \ +} while(0) + +#else // ESP8266 + +#define _WSF(D, ...) (void)0 +#define _WSN(D) (void)0 +#define _WS(D) (void)0 + +#endif // ESP8266 + +#if defined(DEBUG_CODE_ENABLE) + +// logging via Serial +#define _DBGF(D, ...) \ +do { \ + Serial.printf(D, ##__VA_ARGS__); \ +} while(0) +#define _DBGN(D) \ +do { \ + Serial.println(D); \ +} while(0) +#define _DBG(D) \ +do { \ + Serial.print(D); \ +} while(0) + +#else // DEBUG_CODE_ENABLE + +#define _DBGF(D, ...) (void)0 +#define _DBGN(D) (void)0 +#define _DBGS(D) (void)0 + +#endif // DEBUG_CODE_ENABLE + +#endif // _WSERIAL_H_ \ No newline at end of file diff --git a/src/wserver.cpp b/src/wserver.cpp new file mode 100644 index 00000000..31d187ba --- /dev/null +++ b/src/wserver.cpp @@ -0,0 +1,3013 @@ +/* +##################################################################################### +# fs::File: server.cpp # +# fs::File Created: Friday, 19th April 2024 3:11:40 pm # +# Author: Sergey Ko # +# Last Modified: Tuesday, 25th June 2024 2:13:09 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ + +#include "wserver.h" + +static debugRegister * dbgReg = nullptr; + +#define LOMEM_WEB ((ESP.getFreeHeap() < 1024UL)) +#define ASSERT_LOMEM_RETURN() \ + do \ + { \ + if (LOMEM_WEB) \ + { \ + char msg[128] = ""; \ + sprintf_P(msg, lomemMessage, (float)(ESP.getFreeHeap()/1024.0)); \ + server.send(500, mimeTextHtml, msg); \ + return; \ + } \ + } while (0) +#define ASSERT_LOMEM_GOTO(G) \ + do \ + { \ + if (LOMEM_WEB) \ + goto G; \ + } while (0) + +/** + * @brief Initializer + * + */ +void serverInit() +{ + server.on(F("/"), HTTP_GET, serverHome); + server.on(F("/sc"), HTTP_GET, serverSC); + server.on(F("/uc"), HTTP_GET, serverUC); + server.on(F("/bin/slots.bin"), HTTP_GET, serverSlots); + server.on(F("/slot/set"), HTTP_GET, serverSlotSet); + server.on(F("/slot/save"), HTTP_GET, serverSlotSave); + server.on(F("/slot/remove"), HTTP_GET, serverSlotRemove); + // server.on(F("/data/upload"), HTTP_GET, serverFsUpload); + server.on(F("/data/restore"), HTTP_POST, serverFsUploadResponder, serverFsUploadHandler); + server.on(F("/data/backup"), HTTP_GET, serverBackupDownload); + server.on(F("/data/cmd"), HTTP_POST, serverRegisterCmd); + // server.on(F("/data/dir"), HTTP_GET, serverFsDir); + server.on(F("/wifi/status"), HTTP_GET, serverWiFiStatus); + // server.on(F("/gbs/restore-filters"), HTTP_GET, serverRestoreFilters); + // WiFi API + server.on(F("/wifi/list"), HTTP_POST, serverWiFiList); + server.on("/wifi/wps", HTTP_POST, serverWiFiWPS); + server.on("/wifi/connect", HTTP_POST, serverWiFiConnect); + server.on("/wifi/ap", HTTP_POST, serverWiFiAP); + server.on("/wifi/rst", HTTP_POST, serverWiFiReset); + + // in case if something went wrong last time + LittleFS.remove(FPSTR(backupFile)); + + server.begin(); // Webserver for the site +} + +/** + * @brief If uopt.developerMode is true decrease timings on webSocket + * + */ +void serverWebSocketToggleDeveloperMode() { + webSocket.disableHeartbeat(); + delay(10); + if(uopt.developerMode) { + webSocket.enableHeartbeat( + WEBSOCK_HBEAT_DEV_INTVAL, + WEBSOCK_HBEAT_DEV_PONG_TOUT, + WEBSOCK_HBEAT_DEV_DISCONN_CNT + ); + return; + } + webSocket.enableHeartbeat( + WEBSOCK_HBEAT_INTVAL, + WEBSOCK_HBEAT_PONG_TOUT, + WEBSOCK_HBEAT_DISCONN_CNT + ); +} + +/** + * @brief Initialize web socket server + * Should be only called once on setup() + * + */ +void serverWebSocketInit() { + webSocket.begin(); + webSocket.onEvent(webSocketEvent); + serverWebSocketToggleDeveloperMode(); +} + +/** + * @brief + * + */ +void serverHome() +{ + ASSERT_LOMEM_RETURN(); + server.sendHeader(F("Content-Encoding"), F("gzip")); + fs::File index = LittleFS.open(FPSTR(indexPage), "r"); + if (index) + { + server.streamFile(index, mimeTextHtml); + index.close(); + return; + } + server.send_P(200, mimeTextHtml, notFouldMessage); +} + +/** + * @brief Serial Command + * + */ +void serverSC() +{ + ASSERT_LOMEM_RETURN(); + if (server.args() > 0) + { + String p = server.argName(0); + serialCommand = p.charAt(0); + + // hack, problem with '+' command received via url param + if (serialCommand == ' ') + { + serialCommand = '+'; + } + } + server.send(200, mimeAppJson, F("[]")); +} + +/** + * @brief User Command + * + */ +void serverUC() +{ + ASSERT_LOMEM_RETURN(); + if (server.args() > 0) + { + String p = server.argName(0); + userCommand = p.charAt(0); + } + server.send(200, mimeAppJson, F("[]")); +} + +/** + * @brief Sends the slots data to WebUI + * + */ +void serverSlots() +{ + ASSERT_LOMEM_RETURN(); + SlotMetaArray slotsObject; + fs::File slotsBinaryFile; + if(slotGetData(slotsObject) == -1) + { + _DBGF(PSTR("unable to create %s\n"), FPSTR(slotsFile)); + goto stream_slots_bin_failed; + } + slotsBinaryFile = LittleFS.open(FPSTR(slotsFile), "r"); + server.streamFile(slotsBinaryFile, mimeOctetStream); + slotsBinaryFile.close(); + return; +stream_slots_bin_failed: + server.send(500, mimeAppJson, F("[\"fail\"]")); +} + +/** + * @brief This function does: + * 1. Update current slot in user preferences + * 2. Load new slot + * + */ +void serverSlotSet() +{ + ASSERT_LOMEM_GOTO(server_slot_set_failure); + + if (server.args() > 0) + { + uint8_t slotIndex = lowByte(server.arg(String(F("index"))).toInt()); + if(!slotLoad(slotIndex)) { + _DBGF(PSTR("unable to read: %s\n"), FPSTR(slotsFile)); + goto server_slot_set_failure; + } + _WSF(PSTR("active slotID: %d\n"), uopt.slotID); + server.send(200, mimeAppJson, F("[\"ok\"]")); + // begin loading new preset on the next loop + userCommand = '3'; + return; + } +server_slot_set_failure: + server.send(500, mimeAppJson, F("[\"fail\"]")); +} + +/** + * @brief Create new server slot + * + */ +void serverSlotSave() +{ + bool result = false; + ASSERT_LOMEM_GOTO(server_slot_save_end); + if (server.args() > 0) + { + // slot name + String slotName = server.arg(String(F("name"))); + uint8_t slotIndex = server.arg(String(F("index"))).toInt(); + SlotMetaArray slotsObject; + if(slotGetData(slotsObject) == -1) { + _DBGF(PSTR("unable to access to %s\n"), FPSTR(slotsFile)); + goto server_slot_save_end; + } + // updating the SlotMetaObject with data received + // uint8_t slotIndex = lowByte(slotIndexString.toInt()); + uint8_t nameMaxLen = sizeof(slotsObject.slot[slotIndex].name); + if (slotIndex >= SLOTS_TOTAL) + { + _WSF(PSTR("too much slots, max allowed: %d\n"), (uint8_t)SLOTS_TOTAL); + goto server_slot_save_end; + } + // fail proof + if(slotName.length() >= nameMaxLen) { + _WSF(PSTR("slot name is too long, max allowed: %d\n"), nameMaxLen); + goto server_slot_save_end; + } + slotUpdate(slotsObject, slotIndex, &slotName); + + if(!slotSetData(slotsObject)) + _DBGF(PSTR("failed to write to %s\n"), FPSTR(slotsFile)); + + result = true; + } + +server_slot_save_end: + server.send(200, mimeAppJson, result ? F("[\"ok\"]") : F("[\"fail\"]")); +} + +/** + * @brief Remove slot request + * + */ +void serverSlotRemove() +{ + bool result = false; + int16_t slotIndex = server.arg(String(F("index"))).toInt(); + SlotMetaArray slotsObject; + if (server.args() > 0 && slotIndex >= 0) + { + char buffer[4] = ""; + // auto currentSlot = String(slotIndexMap).charAt(slotIndex); + if (slotIndex > SLOTS_TOTAL || slotIndex < 0) + { + _DBGN(F("wrong slot index, abort")); + goto server_slot_remove_end; + } + // preset file extension + sprintf(buffer, PSTR(".%d"), slotIndex); + + if(slotGetData(slotsObject) == -1) { + _DBGF(PSTR("unable to access to %s\n"), FPSTR(slotsFile)); + goto server_slot_remove_end; + } + _DBGF( + PSTR("removing slot: %s and related presets...\n"), + slotsObject.slot[slotIndex].name + ); + + // remove every preset file of this slot + fs::Dir root = LittleFS.openDir("/"); + while (root.next()) + { + String fn = root.fileName(); + if (fn.lastIndexOf(buffer) == (int)(fn.length() - 3)) + LittleFS.remove(fn); + delay(10); + } + // reset the slot data in binary file + slotResetDefaults(slotsObject, slotIndex); + + if(!slotSetData(slotsObject)) + _DBGF(PSTR("failed to write to %s\n"), FPSTR(slotsFile)); + else + result = true; + } + // reset parameters + presetsResetParameters(); + _DBGN(F("(!) slot has been removed, parameters now reset to defaults")); + +server_slot_remove_end: + server.send(200, mimeAppJson, result ? F("[\"ok\"]") : F("[\"fail\"]")); +} + +/** + * @brief Upload file final response + * + */ +void serverFsUploadResponder() +{ + server.send(200, mimeAppJson, F("[\"ok\"]")); +} + +/** + * @brief Upload file handler + * + */ +void serverFsUploadHandler() +{ + HTTPUpload &upload = server.upload(); + static fs::File _tempFile; + static bool err = false; + if (upload.status == UPLOAD_FILE_START) + { + webSocket.close(); + dnsServer.stop(); + _tempFile = LittleFS.open(FPSTR(backupFile), "w"); + _DBGF(PSTR("uploading file: %s"), upload.filename.c_str()); + } + else if (upload.status == UPLOAD_FILE_WRITE && !err) + { + if (_tempFile.write(upload.buf, upload.currentSize) != upload.currentSize) + { + err = true; + _DBGN(F(" write failed, abort")); + goto upload_file_close; + } + else + { + _DBG(F(".")); + } + } + else if (upload.status == UPLOAD_FILE_END) + { + _DBGN(F(" complete")); + err = false; + // extract from backup at the next loop() + userCommand = 'u'; + goto upload_file_close; + } + else if (upload.status == UPLOAD_FILE_ABORTED) + { + err = false; + LittleFS.remove(FPSTR(backupFile)); + _DBGN(F(" aborted")); + delay(10); + goto upload_file_close; + } + return; +upload_file_close: + _tempFile.close(); +} + +/** + * @brief Backup slots and its presets + * The commented code below may be used in future in case of large size + * of data to backup. It does the following: + * 1. creates backup file with all data needed to backup + * 2. streams backup file to client + * 3. removes backup file + */ +void serverBackupDownload() +{ + // fs::File _b = LittleFS.open(FPSTR(backupFile), "w"); + // if(!_b) { + // _DBGN(F("failed to create backup file, can not continue...")); + // return; + // } + StreamString _b; + // size_t contentLength = 0; + fs::Dir dir = LittleFS.openDir("/"); + String ts = server.arg(String(F("ts"))); + webSocket.close(); + // ASSERT_LOMEM_GOTO(fs_dl_handle_fail); + while (dir.next()) + { + if (dir.isFile() && dir.fileName().indexOf(PSTR("__")) == -1) + { + fs::File _f = LittleFS.open(dir.fileName(), "r"); + if (_f) + { + // write file name + _b.print(dir.fileName()); + _b.println(); + // slots.bin will be processed differently + // if(dir.fileName().compareTo(String(slotsFile).substring(1)) != 0) { + // file size + _b.print(dir.fileSize()); + _b.println(); + // write file contents + while(_f.available()) { + _b.write(_f.read()); + } + _DBGF(PSTR("%s dump complete\n"), dir.fileName().c_str()); + /* } else { + SlotMetaArray slotsObject; + // reading into mem + _f.read((byte *)&slotsObject, sizeof(slotsObject)); + _f.close(); + uint8_t i = 0; + String slot_name = String(emptySlotName); + while(i < SLOTS_TOTAL) { + if(strcmp(slotsObject.slot[i].name, slot_name.c_str()) != 0) { + _DBGF(PSTR("slot: %s\n"), slotsObject.slot[i].name); + _b.println(i); + _b.println(slotsObject.slot[i].name); + _b.println(static_cast(slotsObject.slot[i].resolutionID)); + _b.println(slotsObject.slot[i].scanlines); + _b.println(slotsObject.slot[i].scanlinesStrength); + _b.println(slotsObject.slot[i].wantVdsLineFilter); + _b.println(slotsObject.slot[i].wantStepResponse); + _b.println(slotsObject.slot[i].wantPeaking); + } else + break; + i++; + } + // since we're unable to have number of not empty slots beforehand, + // let's leave here a "stop string" for now. The principle of + // slots storage may need to change to allow the simplier logic. + _b.println("\t\t"); + _DBGF(PSTR("%s dump complete\n"), FPSTR(slotsFile)); + } */ + _f.close(); + } + } + } + delay(100); + server.sendHeader(PSTR("Content-Disposition"), String(PSTR("attachment; filename=\"gbs-backup-")) + ts + String(PSTR(".bin\""))); + server.sendHeader(PSTR("Cache-Control"), PSTR("private, max-age=0")); + server.sendHeader(PSTR("Content-Description"), PSTR("File Transfer")); + server.sendHeader(PSTR("Content-Transfer-Encoding"), PSTR("binary")); + server.send(200, mimeOctetStream, _b.c_str(), _b.length()); + /* server.streamFile(_b, mimeOctetStream); + // cleanup + _b.close(); + LittleFS.remove(FPSTR(backupFile)); */ + + webSocket.begin(); +} + +/** + * @brief Receives and executes GBSC register data + * + */ +void serverRegisterCmd() { + uint8_t op = server.arg(String(F("o"))).toInt(); + uint8_t seg = server.arg(String(F("s"))).toInt(); + String dta = server.arg(String(F("d"))); + uint16_t i = 0; + char addr[4] = ""; + char val[4] = ""; + + if(op != 0 && op != 1) { + _DBGF(PSTR("(!) operation [%d] is not recognised"), op); + return; + } + + if(seg > 5) { + _DBGF(PSTR("(!) wrong segment [%d]"), seg); + return; + } + + if(dta.length() == 0) { + _DBGN(F("(!) expecting some data")); + return; + } + + auto nextNumber = [&dta, &i](char * buff) { + uint8_t k = 0; + while(i < dta.length()) { + char c = dta.charAt(i); + // only numbers < 0xFF + if(c == ',' || k > 2) break; + *(buff + k) = c; + k++; + i++; + } + // skip comma + i++; + }; + + while(i < dta.length()) { + nextNumber(addr); + nextNumber(val); + uint8_t a = atoi(addr); + uint8_t v = atoi(val); + if(op == 0) { + _WSF( + PSTR("write segm: %d addr: %d <- val: %d\n"), + seg, + a, + v + ); + GBS::write(seg, a, &v, 1); + } else { + String ro = ""; + uint8_t readout[v]; + uint8_t j = 0; + memset(readout, 0, v); + GBS::read(seg, a, readout, v); + delay(10); + // array to string of HEX values + while(j < v) { + char c[9] = ""; + c[0] = (readout[j] & 0x80) != 0 ? '1' : '0'; + c[1] = (readout[j] & 0x40) != 0 ? '1' : '0'; + c[2] = (readout[j] & 0x20) != 0 ? '1' : '0'; + c[3] = (readout[j] & 0x10) != 0 ? '1' : '0'; + c[4] = (readout[j] & 0x08) != 0 ? '1' : '0'; + c[5] = (readout[j] & 0x04) != 0 ? '1' : '0'; + c[6] = (readout[j] & 0x02) != 0 ? '1' : '0'; + c[7] = (readout[j] & 0x01) != 0 ? '1' : '0'; + if((j != 0 && j+1 % 4 == 0)) + c[8] = 0x0A; // new line + else + c[8] = 0x20; // space + ro += c; + j++; + } + _WSF( + PSTR("read segm: %d start addr: %d, leng: %d ->\n%s\n"), + seg, + a, + v, + ro.c_str() + ); + } + optimistic_yield(1000); + } + + server.send(200, mimeAppJson, F("[\"ok\"]")); +} + +/** + * @brief Restore data from backupFile + * + */ +void extractBackup() { + char buffer[32] = ""; + char fname[32] = ""; + size_t fsize = 0; + fs::File _f; + fs::File _b = LittleFS.open(FPSTR(backupFile), "r"); + if(!_b) { + _DBGN(F("failed to access backup file, abort...")); + return; + } + // process files + while(_b.available()) { + // name + if(_b.readBytesUntil('\n', buffer, 32) != 0) { + strncpy(fname, buffer, 32); + // fix last captured character + fname[strlen(fname)-1] = '\0'; + memset(buffer, '\0', 32); + // it is not slots.bin file + // if(strcmp(fname, String(slotsFile).substring(1).c_str()) != 0) { + if(_b.readBytesUntil('\n', buffer, 32) != 0) { + fsize = (size_t)String(buffer).toInt(); + if(fsize != 0) { + size_t cursor = 0; + _f = LittleFS.open(fname, "w"); + // transfer data + if(_f) { + while(_b.available() && cursor != fsize) { + _f.write(_b.read()); + cursor ++; + } + _f.close(); + _DBGF(PSTR("%s extraction complete, size: %ld\n"), fname, fsize); + } else + _DBGF(PSTR("unable to open/create %s (size: %ld)\n"), fname, fsize); + } + } + /* } else { + // it is slots.bin file + _f = LittleFS.open(FPSTR(slotsFile), "r"); + if(_f) { + SlotMetaArray slotsObject; + _f.read((byte *)&slotsObject, sizeof(slotsObject)); + _f.close(); + uint8_t k = 0; + String data = ""; + while(_b.available()) { + // starts from slotID, so it's stop string or slotID + data =_b.readString(); + // stop condition, see serverBackupDownload() + if(data.compareTo(String(F("\t\t"))) == 0) + break; + // mind data order! + k = data.toInt(); + strcpy(slotsObject.slot[k].name, _b.readString().c_str()); + slotsObject.slot[k].resolutionID = static_cast(_b.readString().charAt(0)); + slotsObject.slot[k].scanlines = _b.readString().toInt(); + slotsObject.slot[k].scanlinesStrength = _b.readString().toInt(); + slotsObject.slot[k].wantVdsLineFilter = _b.readString().toInt(); + slotsObject.slot[k].wantStepResponse = _b.readString().toInt(); + slotsObject.slot[k].wantPeaking = _b.readString().toInt(); + } + // open for writing + _f = LittleFS.open(FPSTR(slotsFile), "w"); + _f.write((byte *)&slotsObject, sizeof(slotsObject)); + _f.close(); + _DBGF(PSTR("%s extraction complete\n"), FPSTR(slotsFile)); + } else + _DBGF(PSTR("unable to open/create %s\n"), FPSTR(slotsFile)); + } */ + } + } + _b.close(); + // cleanup + LittleFS.remove(FPSTR(backupFile)); + delay(10); + _DBGN(F("restore success, restarting...")); +} + +/** + * @brief + * + */ +// void serverFsDir() +// { +// String output = "["; +// fs::Dir dir = LittleFS.openDir("/"); +// ASSERT_LOMEM_GOTO(server_fs_dir_failure); + +// while (dir.next()) +// { +// if (dir.fileName().indexOf(PSTR(".html")) == -1) +// { +// output += "\""; +// output += dir.fileName(); +// output += "\","; +// delay(1); // wifi stack +// } +// } + +// output += "]"; + +// output.replace(",]", "]"); + +// server.send(200, mimeAppJson, output); +// return; + +// server_fs_dir_failure: +// server.send_P(200, mimeAppJson, PSTR("[\"fail\"]")); +// } + +/** + * @brief + * + */ +void serverWiFiStatus() +{ + WiFiMode_t wifiMode = WiFi.getMode(); + server.send(200, mimeAppJson, + (wifiMode == WIFI_AP) + ? F("{\"mode\":\"ap\"}") + : String(F("{\"mode\":\"sta\",\"ssid\":\"") + WiFi.SSID() + F("\"}"))); +} + +/** + * @brief + * + */ +// void serverRestoreFilters() +// { +// SlotMetaArray slotsObject; +// bool result = false; +// if (slotGetData(slotsObject)) +// { +// uopt.wantScanlines = slotsObject.slot[uopt.slotID].scanlines; + +// _WSF(PSTR("slot: %s (ID %d) scanlines: "), slotsObject.slot[uopt.slotID].name, uopt.slotID); +// if (uopt.wantScanlines) +// { +// _WSN(F("on (Line Filter recommended)")); +// } +// else +// { +// disableScanlines(); +// _WSN(F("off")); +// } +// saveUserPrefs(); + +// uopt.scanlineStrength = slotsObject.slot[uopt.slotID].scanlinesStrength; +// uopt.wantVdsLineFilter = slotsObject.slot[uopt.slotID].wantVdsLineFilter; +// uopt.wantStepResponse = slotsObject.slot[uopt.slotID].wantStepResponse; +// uopt.wantPeaking = slotsObject.slot[uopt.slotID].wantPeaking; +// result = true; +// } + +// // server_restore_filters_end: +// server.send(200, mimeAppJson, result ? F("[\"ok\"]") : F("[\"fail\"]")); +// } + +/** + * @brief + * + */ +void serverWiFiList() +{ + String s = ""; + uint8_t i = 0; + int8_t n = WiFi.scanNetworks(); + while (n == -1) + { + n = WiFi.scanComplete(); + yield(); + } + if (n > 0) + { + // TODO: fuzzy logic + // build array of indices + int ix[n]; + for (i = 0; i < n; i++) + ix[i] = i; + + // sort by signal strength + for (i = 0; i < n; i++) + { + for (int j = 1; j < n - i; j++) + { + if (WiFi.RSSI(ix[j]) > WiFi.RSSI(ix[j - 1])) + { + std::swap(ix[j], ix[j - 1]); + } + } + } + // remove duplicates + for (i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + if (WiFi.SSID(ix[i]).equals(WiFi.SSID(ix[j])) && WiFi.encryptionType(ix[i]) == WiFi.encryptionType(ix[j])) + ix[j] = -1; + } + } + // TODO: END + i = 0; + server.chunkedResponseModeStart(200, mimeTextHtml); + while (i < n && ix[i] != -1) + { // check s.length to limit memory usage + s = String(i ? "\n" : "") + ((constrain(WiFi.RSSI(ix[i]), -100, -50) + 100) * 2) + "," + ((WiFi.encryptionType(ix[i]) == ENC_TYPE_NONE) ? 0 : 1) + "," + WiFi.SSID(ix[i]); + server.sendContent(s.c_str()); + i++; + } + server.chunkedResponseFinalize(); + } + else + server.send(200, mimeTextHtml, F("")); + + WiFi.scanDelete(); +} + +/** + * @brief + * + */ +void serverWiFiWPS() +{ + // if (WiFi.status() != WL_CONNECTED) { + if (wifiStartWPS()) + server.send(200, mimeTextHtml, F("WPS successful")); + else + server.send(200, mimeTextHtml, F("WPS failed")); + // } +} + +/** + * @brief switch WiFi in STA mode + * + */ +void serverWiFiConnect() +{ + String ssid = server.arg(String(F("n"))); + String pwd = server.arg(String(F("p"))); + + if (ssid.length() > 0) { + server.send(200, mimeAppJson, F("[]")); + wifiStartStaMode(ssid, pwd); + } else + server.send(406, mimeAppJson, F("[]")); + + resetInMSec(2000); +} + +/** + * @brief + * + */ +void serverWiFiAP() +{ + String msg = String(F("access point: ")); + msg += wifiGetApSSID(); + server.send(200, mimeTextHtml, msg.c_str()); + wifiStartApMode(); +} + +/** + * @brief + * + */ +void serverWiFiReset() +{ + server.send(200, mimeTextHtml, PSTR("Rebooting...")); + delay(100); + ESP.restart(); +} + +/** + * @brief Prints current system & video + * into WS and Serial output + * + */ +void printInfo() +{ + char print[128] = ""; // Increase if compiler complains about sprintf + static uint8_t clearIrqCounter = 0; + static uint8_t lockCounterPrevious = 0; + uint8_t lockCounter = 0; + + int8_t wifi = wifiGetRSSI(); + + uint16_t hperiod = GBS::HPERIOD_IF::read(); + uint16_t vperiod = GBS::VPERIOD_IF::read(); + uint8_t stat0FIrq = GBS::STATUS_0F::read(); + char HSp = GBS::STATUS_SYNC_PROC_HSPOL::read() ? '+' : '-'; // 0 = neg, 1 = pos + char VSp = GBS::STATUS_SYNC_PROC_VSPOL::read() ? '+' : '-'; // 0 = neg, 1 = pos + char h = 'H', v = 'V'; + if (!GBS::STATUS_SYNC_PROC_HSACT::read()) + { + h = HSp = ' '; + } + if (!GBS::STATUS_SYNC_PROC_VSACT::read()) + { + v = VSp = ' '; + } + + // int charsToPrint = + sprintf_P(print, + systemInfo, + hperiod, vperiod, lockCounterPrevious, + GBS::ADC_RGCTRL::read(), GBS::ADC_GGCTRL::read(), GBS::ADC_BGCTRL::read(), + GBS::STATUS_00::read(), GBS::STATUS_05::read(), GBS::SP_CS_0x3E::read(), + h, HSp, v, VSp, stat0FIrq, GBS::TEST_BUS::read(), getVideoMode(), + GBS::STATUS_SYNC_PROC_HTOTAL::read(), GBS::STATUS_SYNC_PROC_VTOTAL::read() /*+ 1*/, // emucrt: without +1 is correct line count + GBS::STATUS_SYNC_PROC_HLOW_LEN::read(), rto.noSyncCounter, rto.continousStableCounter, + rto.currentLevelSOG, wifi); + + // _WS(F("charsToPrint: ")); _WSN(charsToPrint); + _WS(print); + + if (stat0FIrq != 0x00) + { + // clear 0_0F interrupt bits regardless of syncwatcher status + clearIrqCounter++; + if (clearIrqCounter >= 50) + { + clearIrqCounter = 0; + GBS::INTERRUPT_CONTROL_00::write(0xff); // reset irq status + GBS::INTERRUPT_CONTROL_00::write(0x00); + } + } + + yield(); + + if (GBS::STATUS_SYNC_PROC_HSACT::read()) + { // else source might not be active + for (uint8_t i = 0; i < 9; i++) + { + if (GBS::STATUS_MISC_PLLAD_LOCK::read() == 1) + { + lockCounter++; + } + else + { + for (int i = 0; i < 10; i++) + { + if (GBS::STATUS_MISC_PLLAD_LOCK::read() == 1) + { + lockCounter++; + break; + } + } + } + } + } + delay(10); + lockCounterPrevious = getMovingAverage(lockCounter); +} + +/** + * @brief + * + */ +void printVideoTimings() +{ + // if (rto.presetID < 0x20) { + if (utilsNotPassThroughMode()) + { + // horizontal + _WSF( + PSTR("\nHT / scale : %d %d\nHS ST/SP : %d %d\nHB ST/SP(d) : %d %d\nHB ST/SP : %d %d\n------\n"), + GBS::VDS_HSYNC_RST::read(), + GBS::VDS_HSCALE::read(), + GBS::VDS_HS_ST::read(), + GBS::VDS_HS_SP::read(), + GBS::VDS_DIS_HB_ST::read(), + GBS::VDS_DIS_HB_SP::read(), + GBS::VDS_HB_ST::read(), + GBS::VDS_HB_SP::read()); + // vertical + _WSF( + PSTR("VT / scale : %d %d\nVS ST/SP : %d %d\nVB ST/SP(d) : %d %d\nVB ST/SP : %d %d\n"), + GBS::VDS_VSYNC_RST::read(), + GBS::VDS_VSCALE::read(), + GBS::VDS_VS_ST::read(), + GBS::VDS_VS_SP::read(), + GBS::VDS_DIS_VB_ST::read(), + GBS::VDS_DIS_VB_SP::read(), + GBS::VDS_VB_ST::read(), + GBS::VDS_VB_SP::read()); + // IF V offset + _WSF( + PSTR("IF VB ST/SP : %d %d\n"), + GBS::IF_VB_ST::read(), + GBS::IF_VB_SP::read()); + } + else + { + _WSF( + PSTR("\nHD_HSYNC_RST : %d\nHD_INI_ST : %d\nHS ST/SP : %d %d\nHB ST/SP : %d %d\n------\n"), + GBS::HD_HSYNC_RST::read(), + GBS::HD_INI_ST::read(), + GBS::SP_CS_HS_ST::read(), + GBS::SP_CS_HS_SP::read(), + GBS::HD_HB_ST::read(), + GBS::HD_HB_SP::read()); + // vertical + _WSF( + PSTR("VS ST/SP : %d %d\nVB ST/SP : %d %d\n"), + GBS::HD_VS_ST::read(), + GBS::HD_VS_SP::read(), + GBS::HD_VB_ST::read(), + GBS::HD_VB_SP::read()); + } + + _WSF( + PSTR("CsVT : %d\nCsVS_ST/SP : %d %d\n"), + GBS::STATUS_SYNC_PROC_VTOTAL::read(), + getCsVsStart(), + getCsVsStop()); +} + +/** + * @brief + * + */ +void fastGetBestHtotal() +{ + uint32_t inStart, inStop; + signed long inPeriod = 1; + double inHz = 1.0; + GBS::TEST_BUS_SEL::write(0xa); + if (FrameSync::vsyncInputSample(&inStart, &inStop)) + { + inPeriod = (inStop - inStart) >> 1; + if (inPeriod > 1) + { + inHz = (double)1000000 / (double)inPeriod; + } + _WSF(PSTR("inPeriod: %ld in Hz: %d\n"), inPeriod, inHz); + } + else + { + _WSN(F("error")); + } + + uint16_t newVtotal = GBS::VDS_VSYNC_RST::read(); + double bestHtotal = 108000000 / ((double)newVtotal * inHz); // 107840000 + double bestHtotal50 = 108000000 / ((double)newVtotal * 50); + double bestHtotal60 = 108000000 / ((double)newVtotal * 60); + _WSF( + PSTR("newVtotal: %d\nbestHtotal: %d\nbestHtotal50: %d\nbestHtotal60: %d\n"), + newVtotal, + // display clock probably not exact 108mhz + bestHtotal, + bestHtotal50, + bestHtotal60); + // if (bestHtotal > 800 && bestHtotal < 3200) { + // applyBestHTotal((uint16_t)bestHtotal); + // FrameSync::resetWithoutRecalculation(); // was single use of this function, function has changed since + // } +} + +#if defined(ESP8266) + +/** + * @brief extrated from main.cpp->loop() + * + */ +void handleSerialCommand() +{ + static uint8_t readout = 0; + static uint8_t segmentCurrent = 255; + static uint8_t registerCurrent = 255; + static uint8_t inputToogleBit = 0; + static uint8_t inputStage = 0; + + if (Serial.available()) + { + serialCommand = Serial.read(); + } + else if (inputStage > 0) + { + // multistage with no more data + _WSN(F(" abort")); + discardSerialRxData(); + serialCommand = ' '; + } + + if (serialCommand == '@') + return; + + _WSF( + commandDescr, + PSTR("Scmd"), + serialCommand, + serialCommand, + uopt.slotID, + uopt.resolutionID + ); + + // multistage with bad characters? + if (inputStage > 0) + { + // need 's', 't' or 'g' + if (serialCommand != 's' && serialCommand != 't' && serialCommand != 'g') + { + discardSerialRxData(); + _WSN(F(" abort")); + serialCommand = ' '; + } + } + + switch (serialCommand) + { + case ' ': + // skip spaces + inputStage = segmentCurrent = registerCurrent = 0; // and reset these + break; + case 'd': + { + // TODO don't store scanlines - WHY? + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) + // if (uopt.wantScanlines) + // { + // disableScanlines(); + // } + // pal forced 60hz: no need to revert here. let the voffset function handle it + + if (uopt.enableFrameTimeLock && FrameSync::getSyncLastCorrection() != 0) + { + FrameSync::reset(uopt.frameTimeLockMethod); + } + // dump + for (int segment = 0; segment <= 5; segment++) + { + dumpRegisters(segment); + } + _WSN(F("};")); + } + break; + case '+': + _WSN(F("hor. +")); + shiftHorizontalRight(); + // shiftHorizontalRightIF(4); + break; + case '-': + _WSN(F("hor. -")); + shiftHorizontalLeft(); + // shiftHorizontalLeftIF(4); + break; + case '*': + shiftVerticalUpIF(); + break; + case '/': + shiftVerticalDownIF(); + break; + case 'z': + _WSN(F("scale+")); + scaleHorizontal(2, true); + break; + case 'h': + _WSN(F("scale-")); + scaleHorizontal(2, false); + break; + case 'q': + resetDigital(); + delay(2); + ResetSDRAM(); + delay(2); + togglePhaseAdjustUnits(); + // enableVDS(); + break; + case 'D': // toggle debug mode + _WS(F("debug view: ")); + + // if (GBS::ADC_UNUSED_62::read() == 0x00) + if (!uopt.debugView) + { + dbgReg = new debugRegister(); + dbgReg->HD_Y_OFFSET = GBS::HD_Y_OFFSET::read(); + dbgReg->VDS_Y_OFST = GBS::VDS_Y_OFST::read(); + // if (uopt.wantPeaking == 0) { GBS::VDS_PK_Y_H_BYPS::write(0); } // 3_4e 0 // enable peaking but don't store + GBS::VDS_PK_LB_GAIN::write(0x3f); // 3_45 + GBS::VDS_PK_LH_GAIN::write(0x3f); // 3_47 + // GBS::ADC_UNUSED_60::write(GBS::VDS_Y_OFST::read()); // backup + // GBS::ADC_UNUSED_61::write(GBS::HD_Y_OFFSET::read()); + // GBS::ADC_UNUSED_62::write(1); // remember to remove on restore + GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 0x24); + GBS::HD_Y_OFFSET::write(GBS::HD_Y_OFFSET::read() + 0x24); + if (!rto.inputIsYPbPr) + { + // RGB input that has HD_DYN bypassed, use it now + GBS::HD_DYN_BYPS::write(0); + GBS::HD_U_OFFSET::write(GBS::HD_U_OFFSET::read() + 0x24); + GBS::HD_V_OFFSET::write(GBS::HD_V_OFFSET::read() + 0x24); + } + // GBS::IF_IN_DREG_BYPS::write(1); // enhances noise from not delaying IF processing properly + uopt.debugView = true; + _WSN(F("on")); + } + else + { + // if (uopt.wantPeaking == 0) { GBS::VDS_PK_Y_H_BYPS::write(1); } // 3_4e 0 + // if (rto.presetID == 0x05) { + if (uopt.resolutionID == Output1080) + { + GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 + GBS::VDS_PK_LH_GAIN::write(0x0A); // 3_47 + } + else + { + GBS::VDS_PK_LB_GAIN::write(0x16); // 3_45 + GBS::VDS_PK_LH_GAIN::write(0x18); // 3_47 + } + // GBS::VDS_Y_OFST::write(GBS::ADC_UNUSED_60::read()); // restore + // GBS::HD_Y_OFFSET::write(GBS::ADC_UNUSED_61::read()); + GBS::VDS_Y_OFST::write(dbgReg->VDS_Y_OFST); // restore + GBS::HD_Y_OFFSET::write(dbgReg->HD_Y_OFFSET); + if (!rto.inputIsYPbPr) + { + // RGB input, HD_DYN_BYPS again + GBS::HD_DYN_BYPS::write(1); + GBS::HD_U_OFFSET::write(0); // probably just 0 by default + GBS::HD_V_OFFSET::write(0); // probably just 0 by default + } + // GBS::IF_IN_DREG_BYPS::write(0); + // GBS::ADC_UNUSED_60::write(0); // .. and clear + // GBS::ADC_UNUSED_61::write(0); + // GBS::ADC_UNUSED_62::write(0); + uopt.debugView = false; + delete dbgReg; + dbgReg = NULL; + _WSN(F("off")); + } + // serialCommand = '@'; + break; + case 'C': + _WSN(F("PLL: ICLK")); + // display clock in last test best at 0x85 + GBS::PLL648_CONTROL_01::write(0x85); + GBS::PLL_CKIS::write(1); // PLL use ICLK (instead of oscillator) + latchPLLAD(); + // GBS::VDS_HSCALE::write(512); + rto.syncLockFailIgnore = 16; + FrameSync::reset(uopt.frameTimeLockMethod); // adjust htotal to new display clock + rto.forceRetime = true; + // applyBestHTotal(FrameSync::init()); // adjust htotal to new display clock + // applyBestHTotal(FrameSync::init()); // twice + // GBS::VDS_FLOCK_EN::write(1); //risky + delay(200); + break; + case 'Y': + writeProgramArrayNew(ntsc_1280x720, false); + doPostPresetLoadSteps(); + break; + case 'y': + writeProgramArrayNew(pal_1280x720, false); + doPostPresetLoadSteps(); + break; + case 'P': + rto.deinterlaceAutoEnabled = !rto.deinterlaceAutoEnabled; + _WSF(PSTR("auto deinterlace: %s\n"), (rto.deinterlaceAutoEnabled ? F("on") : F("off"))); + break; + case 'p': + if (!rto.motionAdaptiveDeinterlaceActive) + { + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read() == 1) + if (uopt.wantScanlines) + { + disableScanlines(); + } + enableMotionAdaptDeinterlace(); + } + else + { + disableMotionAdaptDeinterlace(); + } + break; + case 'k': // set OutputRGBHVBypass + setOutputRGBHVBypassMode(); + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSN(F("OutputRGBHVBypass mode is now active")); + break; + case 'K': // set OutputHdBypass + setOutputHdBypassMode(false); + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSN(F("OutputHdBypass mode is now active")); + break; + case 'T': // toggle auto gain + uopt.enableAutoGain = !uopt.enableAutoGain; + if (!uopt.enableAutoGain) + { + setAdcGain(AUTO_GAIN_INIT); + GBS::DEC_TEST_ENABLE::write(1); + } + else + GBS::DEC_TEST_ENABLE::write(0); + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSF(PSTR("auto gain: %s\n"), (uopt.enableAutoGain ? F("on") : F("off"))); + break; + case 'e': + writeProgramArrayNew(ntsc_240p, false); + doPostPresetLoadSteps(); + break; + case 'r': + writeProgramArrayNew(pal_240p, false); + doPostPresetLoadSteps(); + break; + case '.': // resync HTotal + { + // if (!rto.outModeHdBypass) + if (utilsNotPassThroughMode()) + { + // bestHtotal recalc + rto.autoBestHtotalEnabled = true; + rto.syncLockFailIgnore = 16; + rto.forceRetime = true; + FrameSync::reset(uopt.frameTimeLockMethod); + + if (!rto.syncWatcherEnabled) + { + bool autoBestHtotalSuccess = 0; + delay(30); + autoBestHtotalSuccess = runAutoBestHTotal(); + if (!autoBestHtotalSuccess) + { + _WSN(F("HTotal is unchanged")); + } else + _WSN(F("resync HTotal success")); + } + } + } + break; + case '!': + // fastGetBestHtotal(); + // readEeprom(); + _WSF(PSTR("sfr: %.02f\n pll: %l\n"), getSourceFieldRate(1), getPllRate()); + break; + case '$': + { + // EEPROM write protect pin (7, next to Vcc) is under original MCU control + // MCU drags to Vcc to write, EEPROM drags to Gnd normally + // This routine only works with that "WP" pin disconnected + // 0x17 = input selector? // 0x18 = input selector related? + // 0x54 = coast start 0x55 = coast end + uint16_t writeAddr = 0x54; + const uint8_t eepromAddr = 0x50; + for (; writeAddr < 0x56; writeAddr++) + { + Wire.beginTransmission(eepromAddr); + Wire.write(writeAddr >> 8); // high addr byte, 4 bits + + Wire.write((uint8_t)writeAddr); // mlow addr byte, 8 bits = 12 bits (0xfff max) + Wire.write(0x10); // coast end value ? + Wire.endTransmission(); + delay(5); + } + + // Wire.beginTransmission(eepromAddr); + // Wire.write((uint8_t)0); Wire.write((uint8_t)0); + // Wire.write(0xff); // force eeprom clear probably + // Wire.endTransmission(); + // delay(5); + + _WSN(F("done")); + } + break; + case 'j': + // resetPLL(); + latchPLLAD(); + break; + case 'J': + resetPLLAD(); + break; + case 'v': + rto.phaseSP += 1; + rto.phaseSP &= 0x1f; + _WSF(PSTR("SP: %d\n"), rto.phaseSP); + setAndLatchPhaseSP(); + // setAndLatchPhaseADC(); + break; + case 'b': + advancePhase(); + latchPLLAD(); + _WSF(PSTR("ADC: %d\n"), rto.phaseADC); + break; + case '#': + rto.videoStandardInput = 13; + applyPresets(rto.videoStandardInput); + // _WSN(getStatus00IfHsVsStable()); + // globalDelay++; + // _WSN(globalDelay); + break; + case 'n': + { + uint16_t pll_divider = GBS::PLLAD_MD::read(); + pll_divider += 1; + GBS::PLLAD_MD::write(pll_divider); + GBS::IF_HSYNC_RST::write((pll_divider / 2)); + GBS::IF_LINE_SP::write(((pll_divider / 2) + 1) + 0x40); + _WSF(PSTR("PLL div: 0x%04X %d\n"), pll_divider, pll_divider); + // set IF before latching + // setIfHblankParameters(); + latchPLLAD(); + delay(1); + // applyBestHTotal(GBS::VDS_HSYNC_RST::read()); + updateClampPosition(); + updateCoastPosition(0); + } + break; + case 'N': // toggle scanlines + { + // if (GBS::RFF_ENABLE::read()) { + // disableMotionAdaptDeinterlace(); + // } + // else { + // enableMotionAdaptDeinterlace(); + // } + + // GBS::RFF_ENABLE::write(!GBS::RFF_ENABLE::read()); + if (uopt.wantScanlines) + disableScanlines(); + else + enableScanlines(); + _WSF(PSTR("scanlines: %s\n"), (uopt.wantScanlines ? F("on") : F("off"))); + } + break; + case 'a': + _WSF(PSTR("HTotal++: %d\n"), GBS::VDS_HSYNC_RST::read() + 1); + if (GBS::VDS_HSYNC_RST::read() < 4095) + { + if (uopt.enableFrameTimeLock) + { + // syncLastCorrection != 0 check is included + FrameSync::reset(uopt.frameTimeLockMethod); + } + rto.forceRetime = 1; + applyBestHTotal(GBS::VDS_HSYNC_RST::read() + 1); + } + break; + case 'A': + _WSF(PSTR("HTotal--: %d\n"), GBS::VDS_HSYNC_RST::read() - 1); + if (GBS::VDS_HSYNC_RST::read() > 0) + { + if (uopt.enableFrameTimeLock) + { + // syncLastCorrection != 0 check is included + FrameSync::reset(uopt.frameTimeLockMethod); + } + rto.forceRetime = 1; + applyBestHTotal(GBS::VDS_HSYNC_RST::read() - 1); + } + break; + // case 'M': + // + // break; + case 'm': // toggle syncWatcher + if (rto.syncWatcherEnabled == true) + { + rto.syncWatcherEnabled = false; + if (rto.videoIsFrozen) + { + unfreezeVideo(); + } + } + else + rto.syncWatcherEnabled = true; + + _WSF(PSTR("syncwatcher: %s\n"), (rto.syncWatcherEnabled ? F("on") : F("off"))); + break; + case ',': + printVideoTimings(); + break; + case 'i': + rto.printInfos = !rto.printInfos; + break; + case 'c': // enableOTA mode + initUpdateOTA(); + rto.allowUpdatesOTA = true; + _WSN(F("OTA Updates on")); + break; +#ifdef HAVE_PINGER_LIBRARY + case 'G': + _WS(F("Debug Pings ")); + if (!rto.enableDebugPings) + { + _WSN(F("on")); + rto.enableDebugPings = 1; + } + else + { + _WSN(F("off")); + rto.enableDebugPings = 0; + } + break; +#endif + case 'u': + ResetSDRAM(); + break; + case 'f': // toggle peaking + uopt.wantPeaking = !uopt.wantPeaking; + if (uopt.wantPeaking) + GBS::VDS_PK_Y_H_BYPS::write(0); + else + GBS::VDS_PK_Y_H_BYPS::write(1); + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSF(PSTR("peaking: %s\n"), (uopt.wantPeaking ? F("on") : F("off"))); + break; + case 'F': // switch ADC filter button (dev.mode) + if (GBS::ADC_FLTR::read() != 0) + { + GBS::ADC_FLTR::write(0); + uopt.adcFilter = false; + } + else + { + GBS::ADC_FLTR::write(3); + uopt.adcFilter = true; + } + _WSF(PSTR("ADC filter: %s\n"), (GBS::ADC_FLTR::read() != 0 ? F("on") : F("off"))); + break; + case 'L': // force output component + { + // Component / VGA Output + uopt.wantOutputComponent = !uopt.wantOutputComponent; + OutputComponentOrVGA(); + // apply 1280x720 preset now, otherwise a reboot would be required + uint8_t videoMode = getVideoMode(); + if (videoMode == 0) + videoMode = rto.videoStandardInput; + // OutputResolution backup = uopt.resolutionID; + // uopt.presetPreference = Output720P; + // uopt.resolutionID = Output720; + rto.videoStandardInput = 0; // force hard reset + applyPresets(videoMode); + // uopt.resolutionID = backup; + prefsSave(); + } + break; + case 'l': + _WSN(F("reset Sync Processor")); + // freezeVideo(); + resetSyncProcessor(); + // delay(10); + // unfreezeVideo(); + break; + // case 'Z': + // { + // uopt.matchPresetSource = !uopt.matchPresetSource; + // // saveUserPrefs(); + // slotFlush(); + // uint8_t vidMode = getVideoMode(); + // // if (uopt.presetPreference == 0 && GBS::GBS_PRESET_ID::read() == 0x11) { + // if (uopt.resolutionID == Output240p && GBS::GBS_PRESET_ID::read() == Output960PAL) + // { + // applyPresets(vidMode); + // // } else if (uopt.presetPreference == 4 && GBS::GBS_PRESET_ID::read() == 0x02) { + // } + // else if (uopt.resolutionID == Output1024 && GBS::GBS_PRESET_ID::read() == Output1024) + // { + // applyPresets(vidMode); + // } + // } + // break; + case 'W': + uopt.enableFrameTimeLock = !uopt.enableFrameTimeLock; + break; + case 'E': + writeProgramArrayNew(ntsc_1280x1024, false); + _WSN(F("ntsc_1280x1024 is now active")); + doPostPresetLoadSteps(); + break; + case 'R': + writeProgramArrayNew(pal_1280x1024, false); + doPostPresetLoadSteps(); + _WSN(F("pal_1280x1024 is now active")); + break; + case '0': + moveHS(4, true); + break; + case '1': + moveHS(4, false); + break; + case '2': + writeProgramArrayNew(pal_768x576, false); // ModeLine "720x576@50" 27 720 732 795 864 576 581 586 625 -hsync -vsync + doPostPresetLoadSteps(); + _WSN(F("pal_768x576 is now active")); + break; + // case '3': + // break; + case '4': + { + // scale vertical + + if (GBS::VDS_VSCALE::read() <= 256) + { + _WSN(F("limit")); + break; + } + scaleVertical(2, true); + // actually requires full vertical mask + position offset calculation + } + break; + case '5': + { + // scale vertical - + if (GBS::VDS_VSCALE::read() == 1023) + { + _WSN(F("limit")); + break; + } + scaleVertical(2, false); + // actually requires full vertical mask + position offset calculation + } + break; + case '6': + // if (videoStandardInputIsPalNtscSd() && !rto.outModeHdBypass) + if (videoStandardInputIsPalNtscSd() && utilsNotPassThroughMode()) + { + if (GBS::IF_HBIN_SP::read() >= 10) + { // IF_HBIN_SP: min 2 + GBS::IF_HBIN_SP::write(GBS::IF_HBIN_SP::read() - 8); // canvas move right + if ((GBS::IF_HSYNC_RST::read() - 4) > ((GBS::PLLAD_MD::read() >> 1) + 5)) + { + GBS::IF_HSYNC_RST::write(GBS::IF_HSYNC_RST::read() - 4); // shrink 1_0e + GBS::IF_LINE_SP::write(GBS::IF_LINE_SP::read() - 4); // and 1_22 to go with it + } + } + else + { + _WSN(F("limit")); + } + } + // else if (!rto.outModeHdBypass) + else if (utilsNotPassThroughMode()) + { + if (GBS::IF_HB_SP2::read() >= 4) + GBS::IF_HB_SP2::write(GBS::IF_HB_SP2::read() - 4); // 1_1a + else + GBS::IF_HB_SP2::write(GBS::IF_HSYNC_RST::read() - 0x30); + if (GBS::IF_HB_ST2::read() >= 4) + GBS::IF_HB_ST2::write(GBS::IF_HB_ST2::read() - 4); // 1_18 + else + GBS::IF_HB_ST2::write(GBS::IF_HSYNC_RST::read() - 0x30); + _WSF(PSTR("IF_HB_ST2: 0x%04X IF_HB_SP2: 0x%04X\n"), + GBS::IF_HB_ST2::read(), GBS::IF_HB_SP2::read()); + } + break; + case '7': + // if (videoStandardInputIsPalNtscSd() && !rto.outModeHdBypass) + if (videoStandardInputIsPalNtscSd() && utilsNotPassThroughMode()) + { + if (GBS::IF_HBIN_SP::read() < 0x150) + { // (arbitrary) max limit + GBS::IF_HBIN_SP::write(GBS::IF_HBIN_SP::read() + 8); // canvas move left + } + else + { + _WSN(F("limit")); + } + } + // else if (!rto.outModeHdBypass) + else if (utilsNotPassThroughMode()) + { + if (GBS::IF_HB_SP2::read() < (GBS::IF_HSYNC_RST::read() - 0x30)) + GBS::IF_HB_SP2::write(GBS::IF_HB_SP2::read() + 4); // 1_1a + else + GBS::IF_HB_SP2::write(0); + if (GBS::IF_HB_ST2::read() < (GBS::IF_HSYNC_RST::read() - 0x30)) + GBS::IF_HB_ST2::write(GBS::IF_HB_ST2::read() + 4); // 1_18 + else + GBS::IF_HB_ST2::write(0); + _WSF(PSTR("IF_HB_ST2: 0x%04X IF_HB_SP2: 0x%04X\n"), + GBS::IF_HB_ST2::read(), GBS::IF_HB_SP2::read()); + } + break; + case '8': // invert sync button (dev. mode) + // _WSN("invert sync"); + uopt.invertSync = !uopt.invertSync; + invertHS(); + invertVS(); + // optimizePhaseSP(); + break; + case '9': + writeProgramArrayNew(ntsc_720x480, false); + doPostPresetLoadSteps(); + break; + case 'o': + { // oversampring button (dev.mode) + if (rto.osr == 1) + { + setOverSampleRatio(2, false); + } + else if (rto.osr == 2) + { + setOverSampleRatio(4, false); + } + else if (rto.osr == 4) + { + setOverSampleRatio(1, false); + } + delay(4); + optimizePhaseSP(); + _WSF(PSTR("OSR 0x%02X\n"), rto.osr); + rto.phaseIsSet = 0; // do it again in modes applicable + } + break; + case 'g': + inputStage++; + // we have a multibyte command + if (inputStage > 0) + { + if (inputStage == 1) + { + segmentCurrent = Serial.parseInt(); + _WSF(PSTR("G%d"), segmentCurrent); + } + else if (inputStage == 2) + { + char szNumbers[3]; + szNumbers[0] = Serial.read(); + szNumbers[1] = Serial.read(); + szNumbers[2] = '\0'; + // char * pEnd; + registerCurrent = strtol(szNumbers, NULL, 16); + _WSF(PSTR("R 0x%04X"), registerCurrent); + if (segmentCurrent <= 5) + { + writeOneByte(0xF0, segmentCurrent); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" value: 0x%02X\n"), readout); + } + else + { + discardSerialRxData(); + _WSN(F("abort")); + } + inputStage = 0; + } + } + break; + case 's': + inputStage++; + // we have a multibyte command + if (inputStage > 0) + { + if (inputStage == 1) + { + segmentCurrent = Serial.parseInt(); + _WSF(PSTR("S%d"), segmentCurrent); + } + else if (inputStage == 2) + { + char szNumbers[3]; + for (uint8_t a = 0; a <= 1; a++) + { + // ascii 0x30 to 0x39 for '0' to '9' + if ((Serial.peek() >= '0' && Serial.peek() <= '9') || + (Serial.peek() >= 'a' && Serial.peek() <= 'f') || + (Serial.peek() >= 'A' && Serial.peek() <= 'F')) + { + szNumbers[a] = Serial.read(); + } + else + { + szNumbers[a] = 0; // NUL char + Serial.read(); // but consume the char + } + } + szNumbers[2] = '\0'; + // char * pEnd; + registerCurrent = strtol(szNumbers, NULL, 16); + _WSF(PSTR("R 0x%04X"), registerCurrent); + } + else if (inputStage == 3) + { + char szNumbers[3]; + for (uint8_t a = 0; a <= 1; a++) + { + if ((Serial.peek() >= '0' && Serial.peek() <= '9') || + (Serial.peek() >= 'a' && Serial.peek() <= 'f') || + (Serial.peek() >= 'A' && Serial.peek() <= 'F')) + { + szNumbers[a] = Serial.read(); + } + else + { + szNumbers[a] = 0; // NUL char + Serial.read(); // but consume the char + } + } + szNumbers[2] = '\0'; + // char * pEnd; + inputToogleBit = strtol(szNumbers, NULL, 16); + if (segmentCurrent <= 5) + { + writeOneByte(0xF0, segmentCurrent); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" (was 0x%04X)"), readout); + writeOneByte(registerCurrent, inputToogleBit); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" is now: 0x%02X\n"), readout); + } + else + { + discardSerialRxData(); + _WSN(F("abort")); + } + inputStage = 0; + } + } + break; + case 't': + inputStage++; + // we have a multibyte command + if (inputStage > 0) + { + if (inputStage == 1) + { + segmentCurrent = Serial.parseInt(); + _WSF(PSTR("T%d"), segmentCurrent); + } + else if (inputStage == 2) + { + char szNumbers[3]; + for (uint8_t a = 0; a <= 1; a++) + { + // ascii 0x30 to 0x39 for '0' to '9' + if ((Serial.peek() >= '0' && Serial.peek() <= '9') || + (Serial.peek() >= 'a' && Serial.peek() <= 'f') || + (Serial.peek() >= 'A' && Serial.peek() <= 'F')) + { + szNumbers[a] = Serial.read(); + } + else + { + szNumbers[a] = 0; // NUL char + Serial.read(); // but consume the char + } + } + szNumbers[2] = '\0'; + // char * pEnd; + registerCurrent = strtol(szNumbers, NULL, 16); + _WSF(PSTR("R 0x%04X"), registerCurrent); + } + else if (inputStage == 3) + { + if (Serial.peek() >= '0' && Serial.peek() <= '7') + { + inputToogleBit = Serial.parseInt(); + } + else + { + inputToogleBit = 255; // will get discarded next step + } + _WSF(PSTR(" Bit: %d"), inputToogleBit); + inputStage = 0; + if ((segmentCurrent <= 5) && (inputToogleBit <= 7)) + { + writeOneByte(0xF0, segmentCurrent); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" (was 0x%04X)"), readout); + writeOneByte(registerCurrent, readout ^ (1 << inputToogleBit)); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" is now: 0x%02X\n"), readout); + } + else + { + discardSerialRxData(); + inputToogleBit = registerCurrent = 0; + _WSN(F("abort")); + } + } + } + break; + case '<': + { + if (segmentCurrent != 255 && registerCurrent != 255) + { + writeOneByte(0xF0, segmentCurrent); + readFromRegister(registerCurrent, 1, &readout); + writeOneByte(registerCurrent, readout - 1); // also allow wrapping + _WSF(PSTR("S%d_0x%04X"), segmentCurrent, registerCurrent); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" : 0x%04X\n"), readout); + } + } + break; + case '>': + { + if (segmentCurrent != 255 && registerCurrent != 255) + { + writeOneByte(0xF0, segmentCurrent); + readFromRegister(registerCurrent, 1, &readout); + writeOneByte(registerCurrent, readout + 1); + _WSF(PSTR("S%d_0x%04X"), segmentCurrent, registerCurrent); + readFromRegister(registerCurrent, 1, &readout); + _WSF(PSTR(" : 0x%04X\n"), readout); + } + } + break; + case '_': + { + uint32_t ticks = FrameSync::getPulseTicks(); + _WSN(ticks); + } + break; + case '~': + goLowPowerWithInputDetection(); // test reset + input detect + break; + case 'w': + { + // Serial.flush(); + uint16_t value = 0; + String what = Serial.readStringUntil(' '); + + if (what.length() > 5) + { + _WSN(F("abort")); + inputStage = 0; + break; + } + if (what.equals("f")) + { + if (rto.extClockGenDetected) + { + _WSF(PSTR("old freqExtClockGen: %l\n"), rto.freqExtClockGen); + rto.freqExtClockGen = Serial.parseInt(); + // safety range: 1 - 250 MHz + if (rto.freqExtClockGen >= 1000000 && rto.freqExtClockGen <= 250000000) + { + Si.setFreq(0, rto.freqExtClockGen); + rto.clampPositionIsSet = 0; + rto.coastPositionIsSet = 0; + } + _WSF(PSTR("set freqExtClockGen: %l\n"), rto.freqExtClockGen); + } + break; + } + + value = Serial.parseInt(); + if (value < 4096) + { + _WSF(PSTR("set %s %d\n"), what.c_str(), value); + if (what.equals("ht")) + { + // set_htotal(value); + // if (!rto.outModeHdBypass) + if (utilsNotPassThroughMode()) + { + rto.forceRetime = 1; + applyBestHTotal(value); + } + else + { + GBS::VDS_HSYNC_RST::write(value); + } + } + else if (what.equals("vt")) + { + set_vtotal(value); + } + else if (what.equals("hsst")) + { + setHSyncStartPosition(value); + } + else if (what.equals("hssp")) + { + setHSyncStopPosition(value); + } + else if (what.equals("hbst")) + { + setMemoryHblankStartPosition(value); + } + else if (what.equals("hbsp")) + { + setMemoryHblankStopPosition(value); + } + else if (what.equals("hbstd")) + { + setDisplayHblankStartPosition(value); + } + else if (what.equals("hbspd")) + { + setDisplayHblankStopPosition(value); + } + else if (what.equals("vsst")) + { + setVSyncStartPosition(value); + } + else if (what.equals("vssp")) + { + setVSyncStopPosition(value); + } + else if (what.equals("vbst")) + { + setMemoryVblankStartPosition(value); + } + else if (what.equals("vbsp")) + { + setMemoryVblankStopPosition(value); + } + else if (what.equals("vbstd")) + { + setDisplayVblankStartPosition(value); + } + else if (what.equals("vbspd")) + { + setDisplayVblankStopPosition(value); + } + else if (what.equals("sog")) + { + setAndUpdateSogLevel(value); + } + else if (what.equals("ifini")) + { + GBS::IF_INI_ST::write(value); + // _WSN(GBS::IF_INI_ST::read()); + } + else if (what.equals("ifvst")) + { + GBS::IF_VB_ST::write(value); + // _WSN(GBS::IF_VB_ST::read()); + } + else if (what.equals("ifvsp")) + { + GBS::IF_VB_SP::write(value); + // _WSN(GBS::IF_VB_ST::read()); + } + else if (what.equals("vsstc")) + { + setCsVsStart(value); + } + else if (what.equals("vsspc")) + { + setCsVsStop(value); + } + } + else + { + _WSN(F("abort")); + } + } + break; + case 'x': + { + uint16_t if_hblank_scale_stop = GBS::IF_HBIN_SP::read(); + GBS::IF_HBIN_SP::write(if_hblank_scale_stop + 1); + _WSF(PSTR("1_26: 0x%04X\n"), (if_hblank_scale_stop + 1)); + } + break; + case 'X': + { + uint16_t if_hblank_scale_stop = GBS::IF_HBIN_SP::read(); + GBS::IF_HBIN_SP::write(if_hblank_scale_stop - 1); + _WSF(PSTR("1_26: 0x%04X\n"), (if_hblank_scale_stop - 1)); + } + break; + case '(': + { + writeProgramArrayNew(ntsc_1920x1080, false); + doPostPresetLoadSteps(); + } + break; + case ')': + { + writeProgramArrayNew(pal_1920x1080, false); + doPostPresetLoadSteps(); + } + break; + case 'V': // toggle step response + { + _WS(F("step response ")); + uopt.wantStepResponse = !uopt.wantStepResponse; + if (uopt.wantStepResponse) + { + GBS::VDS_UV_STEP_BYPS::write(0); + _WSN(F("on")); + } + else + { + GBS::VDS_UV_STEP_BYPS::write(1); + _WSN(F("off")); + } + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + } + break; + case 'S': + snapToIntegralFrameRate(); + break; + case ':': + externalClockGenSyncInOutRate(); + break; + case ';': + externalClockGenResetClock(); + if (rto.extClockGenDetected) + { + rto.extClockGenDetected = 0; + _WSN(F("ext clock gen bypass")); + } + else + { + rto.extClockGenDetected = 1; + _WSN(F("ext clock gen active")); + externalClockGenSyncInOutRate(); + } + //{ + // float bla = 0; + // double esp8266_clock_freq = ESP.getCpuFreqMHz() * 1000000; + // bla = esp8266_clock_freq / (double)FrameSync::getPulseTicks(); + // _WSN(bla, 5); + //} + break; + default: + _WSF(PSTR("unknown command: 0x%04X\n"), serialCommand); + break; + } + + delay(1); // give some time to read in eventual next chars + + // a web ui or terminal command has finished. good idea to reset sync lock timer + // important if the command was to change presets, possibly others + lastVsyncLock = millis(); + + // if (!Serial.available()) + // { + // // in case we handled a Serial or web server command and there's no more extra commands + // // but keep debug view command (resets once called) + // // TODO: we have uopt.debugView + // if (serialCommand != 'D') + // { + // serialCommand = '@'; + // } + // wifiLoop(1); + // } + serialCommand = '@'; +} + +/** + * @brief initially was Type2 command + * + */ +void handleUserCommand() +{ + if (userCommand == '@') + return; + + _WSF( + commandDescr, + PSTR("Ucmd"), + userCommand, + userCommand, + uopt.slotID, + uopt.resolutionID + ); + + switch (userCommand) + { + case '0': // force increase frequency to 60Hz for PAL 50Hz + uopt.PalForce60 = !uopt.PalForce60; + // TODO apply presets here! + slotFlush(); + _WSF(PSTR("pal force 60hz %s\n"), (uopt.PalForce60 == 1 ? F("on") : F("off"))); + break; + case '1': // reset to factory defaults button + // active slot settings reset + fsToFactory(); + // reset common parameters + prefsLoadDefaults(); + prefsSave(); + _WSN(F("(!) factory defaults has been restored, restarting")); + resetInMSec(2000); + break; + case '2': // reset only active slot and active preset + { + char buffer[64] = ""; + // get active preset + utilsGetPresetsFileNameFor(rto.videoStandardInput, buffer); + if(*buffer != '\0') + LittleFS.remove(buffer); + // reset slot + slotResetFlush(uopt.slotID); + _WSN(F("(i) slot has been reset, restarting")); + resetInMSec(2000); + } + break; + case '3': // load new preset on slot change + { + // TODO: unknown logic + if (rto.videoStandardInput == 14) { + // vga upscale path: let synwatcher handle it + rto.videoStandardInput = 15; + } else + applyPresets(rto.videoStandardInput); + } + break; + // case '4': + // break; + case '5': // Frame Time Lock toggle + uopt.enableFrameTimeLock = !uopt.enableFrameTimeLock; + // saveUserPrefs(); + if (uopt.enableFrameTimeLock) + { + _WSN(F("FTL on")); + } + else + { + _WSN(F("FTL off")); + } + if (!rto.extClockGenDetected) + { + FrameSync::reset(uopt.frameTimeLockMethod); + } + if (uopt.enableFrameTimeLock) + { + activeFrameTimeLockInitialSteps(); + } + slotFlush(); + break; + // case '6': + // break; + case '7': // toggle scanlines + if (!uopt.wantScanlines) + enableScanlines(); + else + disableScanlines(); + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSF(PSTR("scanlines: %s\n"), (uopt.wantScanlines ? F("on (Line Filter recommended)") : F("off"))); + // saveUserPrefs(); + break; + // case '9': + // + // break; + case 'a': // device restart + resetInMSec(2000); + break; + case 'd': // toggle developer mode + uopt.developerMode = !uopt.developerMode; + serverWebSocketToggleDeveloperMode(); + serialDevModeToggle(); + break; + case 'e': // print files on data + { + _WSN(F("file system:")); + fs::Dir dir = LittleFS.openDir("/"); + while (dir.next()) + { + _WSF( + PSTR(" %s %ld\n"), + dir.fileName().c_str(), + dir.fileSize()); + } + // + fs::File f = LittleFS.open(FPSTR(preferencesFile), "r"); + if (!f) + { + _WSN(F("\nfailed to read system preferences")); + } + else + { + _WSF( + PSTR("\nsystem preferences:\n active slotID: %d\n component out.: %d\n scaling RGBHV: %d\n" \ + " ADC calibration: %d\n ext. clock gen.: %d\n"), + f.read(), + f.read(), + f.read(), + f.read(), + f.read() + ); + + f.close(); + } + // + _WSF( + PSTR("\nruntime parameters:\n"\ + " slotIsCustom: %d\n" \ + " boardHasPower: %d\n"\ + " syncWatcherEnabled: %d\n" \ + " inputIsYPbPr: %d\n"\ + " isInLowPowerMode: %d\n"\ + " outModeHdBypass: %d\n" \ + " sourceDisconnected: %d\n" \ + " videoStandardInput: %d\n"\ + " continousStableCounter: %d\n" \ + " currentLevelSOG: %d\n" \ + " syncTypeCsync: %d\n" \ + " thisSourceMaxLevelSOG: %d\n" \ + " medResLineCount: %d\n" \ + " presetDisplayClock: %d\n" \ + " freqExtClockGen: %ld\n" \ + " noSyncCounter: %d\n" \ + " presetVlineShift: %d\n" \ + " phaseSP: %d\n" \ + " phaseADC: %d\n" \ + " syncLockFailIgnore: %d\n" \ + " applyPresetDoneStage: %d\n" \ + " failRetryAttempts: %d\n" \ + " HPLLState: %d\n" \ + " osr: %d\n" \ + " notRecognizedCounter: %d\n" \ + " clampPositionIsSet: %d\n" \ + " coastPositionIsSet: %d\n" \ + " phaseIsSet: %d\n" \ + " printInfos: %d\n" \ + " allowUpdatesOTA: %d\n" \ + " autoBestHtotalEnabled: %d\n" \ + " forceRetime: %d\n" \ + " motionAdaptiveDeinterlaceActive: %d\n" \ + " deinterlaceAutoEnabled: %d\n" \ + " presetIsPalForce60: %d\n" \ + " isValidForScalingRGBHV: %d\n" \ + " useHdmiSyncFix: %d\n" \ + " extClockGenDetected: %d\n\n" + ), + uopt.slotIsCustom, + rto.boardHasPower, + rto.syncWatcherEnabled, + rto.inputIsYPbPr, + rto.isInLowPowerMode, + (uint8_t)rto.outModeHdBypass, + rto.sourceDisconnected, + rto.videoStandardInput, + rto.continousStableCounter, + rto.currentLevelSOG, + rto.syncTypeCsync, + rto.thisSourceMaxLevelSOG, + rto.medResLineCount, + rto.presetDisplayClock, + rto.freqExtClockGen, + rto.noSyncCounter, + rto.presetVlineShift, + rto.phaseSP, + rto.phaseADC, + rto.syncLockFailIgnore, + rto.applyPresetDoneStage, + rto.failRetryAttempts, + rto.HPLLState, + rto.osr, + rto.notRecognizedCounter, + rto.clampPositionIsSet, + rto.coastPositionIsSet, + rto.phaseIsSet, + rto.printInfos, + rto.allowUpdatesOTA, + rto.autoBestHtotalEnabled, + rto.forceRetime, + rto.motionAdaptiveDeinterlaceActive, + rto.deinterlaceAutoEnabled, + rto.presetIsPalForce60, + rto.isValidForScalingRGBHV, + rto.useHdmiSyncFix, + rto.extClockGenDetected + ); + } + break; + /** + * 1. change resolution + * 2. update registers if videoStandardInput != 14 + * 3. update/save preset data + */ + case 's': // 1080p + case 'p': // 1024p + case 'f': // 960p + case 'g': // 720p + case 'k': // 576p + case 'h': // 480p + case 'j': // 240p + case 'L': // 15kHz/downscale + case 'W': // bypass + { + // load preset via webui + uint8_t videoMode = getVideoMode(); + if (videoMode == 0 && GBS::STATUS_SYNC_PROC_HSACT::read()) + videoMode = rto.videoStandardInput; // last known good as fallback + + // else videoMode stays 0 and we'll apply via some assumptions + if (userCommand == 'f') + // uopt.presetPreference = Output960P; // 1280x960 + uopt.resolutionID = Output960; // 1280x960 + else if (userCommand == 'g') + // uopt.presetPreference = Output720P; // 1280x720 + uopt.resolutionID = Output720; // 1280x720 + else if (userCommand == 'h') + // uopt.presetPreference = Output480P; // 720x480/768x576 + uopt.resolutionID = Output480; // 720x480/768x576 + else if (userCommand == 'p') + // uopt.presetPreference = Output1024P; // 1280x1024 + uopt.resolutionID = Output1024; // 1280x1024 + else if (userCommand == 's') + // uopt.presetPreference = Output1080P; // 1920x1080 + uopt.resolutionID = Output1080; // 1920x1080 + else if (userCommand == 'L') + // uopt.presetPreference = OutputDownscale; // downscale + uopt.resolutionID = Output15kHz; // downscale + else if (userCommand == 'k') + uopt.resolutionID = Output576PAL; // PAL + else if (userCommand == 'j') + uopt.resolutionID = Output240p; // 240p + else if (userCommand == 'W') + uopt.resolutionID = OutputBypass; + + rto.useHdmiSyncFix = 1; // disables sync out when programming preset + if (rto.videoStandardInput == 14) + { + // vga upscale path: let synwatcher handle it + _DBGN(F("video input is #14, switch to #15")); + rto.videoStandardInput = 15; + } + else + { + applyPresets(videoMode); + // // resolution is stored in GBSC registers + // // doing this after applyPresets to be able to find if resolution has changed + GBS::GBS_PRESET_ID::write(uopt.resolutionID); + // // slotFlush also does presetSaveToFS() + slotFlush(); + } + } + break; + case 'i': // toggle active frametime lock method + // enable FTL if disabled + if (uopt.enableFrameTimeLock == 0) { + _WS(F("FTL enabled, ")); + uopt.enableFrameTimeLock = 1; + } + if (!rto.extClockGenDetected) + { + FrameSync::reset(uopt.frameTimeLockMethod); + } + + if (uopt.frameTimeLockMethod == 0) + { + uopt.frameTimeLockMethod = 1; + } + else if (uopt.frameTimeLockMethod == 1) + { + uopt.frameTimeLockMethod = 0; + } + _WSF(PSTR("lock method: %d\n"), uopt.frameTimeLockMethod); + // saveUserPrefs(); + activeFrameTimeLockInitialSteps(); + slotFlush(); + break; + case 'l': // cycle through available SDRAM clocks + { + _WS(F("SDRAM clock: ")); + uint8_t PLL_MS = GBS::PLL_MS::read(); + + if (PLL_MS == 0) { + _WS(F("100MHz -> ")); + PLL_MS = 0b001; + } else if (PLL_MS == 0x001) { + _WS(F("81MHz ->")); + PLL_MS = 0b010; + } else if (PLL_MS == 0b010) { + _WS(F("feedback clock -> ")); + PLL_MS = 0b011; + } else if (PLL_MS == 0b011) { + _WS(F("162MHz -> ")); + PLL_MS = 0b100; + } else if (PLL_MS == 0b100) { + _WS(F("144MHz -> ")); + PLL_MS = 0b101; + } else if (PLL_MS == 0b101) { + _WS(F("185MHz -> ")); + PLL_MS = 0b110; + } else if (PLL_MS == 0b110) { + _WS(F("216MHz -> ")); + PLL_MS = 0b111; + } else { + _WS(F("129.6 -> ")); + PLL_MS = 0; + } + + switch (PLL_MS) { + case 0: + _WSN(F("100MHz")); + break; + case 1: + _WSN(F("81MHz")); + break; // goes well with 4_2C = 0x14, 4_2D = 0x27 + case 2: + _WSN(F("feedback clock (pin 110)")); + break; // feedback clock + case 3: + _WSN(F("162MHz")); + break; + case 4: + _WSN(F("144MHz")); + break; + case 5: + _WSN(F("185MHz")); + break; // slight OC + case 6: + _WSN(F("216MHz")); + break; // !OC! + case 7: + _WSN(F("129.6MHz")); + break; + default: + break; + } + GBS::PLL_MS::write(PLL_MS); + ResetSDRAM(); + } + break; + case 'm': // toggle line filter + _WS(F("Line Filter: ")); + if (uopt.wantVdsLineFilter) + { + uopt.wantVdsLineFilter = 0; + GBS::VDS_D_RAM_BYPS::write(1); + _WSN(F("off")); + } + else + { + uopt.wantVdsLineFilter = 1; + GBS::VDS_D_RAM_BYPS::write(0); + _WSN(F("on")); + } + // slotFlush also does presetSaveToFS() + slotFlush(); + // saveUserPrefs(); + break; + case 'n': + uopt.enableAutoGain = 0; + setAdcGain(GBS::ADC_RGCTRL::read() - 1); + _WSF(PSTR("ADC gain++ : 0x%04X\n"), GBS::ADC_RGCTRL::read()); + break; + case 'o': + uopt.enableAutoGain = 0; + setAdcGain(GBS::ADC_RGCTRL::read() + 1); + _WSF(PSTR("ADC gain-- : 0x%04X\n"), GBS::ADC_RGCTRL::read()); + break; + case 'A': + { + uint16_t htotal = GBS::VDS_HSYNC_RST::read(); + uint16_t hbstd = GBS::VDS_DIS_HB_ST::read(); + uint16_t hbspd = GBS::VDS_DIS_HB_SP::read(); + if ((hbstd > 4) && (hbspd < (htotal - 4))) + { + GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() - 4); + GBS::VDS_DIS_HB_SP::write(GBS::VDS_DIS_HB_SP::read() + 4); + } + else + { + _WSN(F("limit")); + } + } + break; + case 'B': + { + uint16_t htotal = GBS::VDS_HSYNC_RST::read(); + uint16_t hbstd = GBS::VDS_DIS_HB_ST::read(); + uint16_t hbspd = GBS::VDS_DIS_HB_SP::read(); + if ((hbstd < (htotal - 4)) && (hbspd > 4)) + { + GBS::VDS_DIS_HB_ST::write(GBS::VDS_DIS_HB_ST::read() + 4); + GBS::VDS_DIS_HB_SP::write(GBS::VDS_DIS_HB_SP::read() - 4); + } + else + { + _WSN(F("limit")); + } + } + break; + case 'C': + { + // vert mask + + uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); + uint16_t vbstd = GBS::VDS_DIS_VB_ST::read(); + uint16_t vbspd = GBS::VDS_DIS_VB_SP::read(); + if ((vbstd > 6) && (vbspd < (vtotal - 4))) + { + GBS::VDS_DIS_VB_ST::write(vbstd - 2); + GBS::VDS_DIS_VB_SP::write(vbspd + 2); + } + else + { + _WSN(F("limit")); + } + } + break; + case 'D': + { + // vert mask - + uint16_t vtotal = GBS::VDS_VSYNC_RST::read(); + uint16_t vbstd = GBS::VDS_DIS_VB_ST::read(); + uint16_t vbspd = GBS::VDS_DIS_VB_SP::read(); + if ((vbstd < (vtotal - 4)) && (vbspd > 6)) + { + GBS::VDS_DIS_VB_ST::write(vbstd + 2); + GBS::VDS_DIS_VB_SP::write(vbspd - 2); + } + else + { + _WSN(F("limit")); + } + } + break; + case 'q': // bob / motionAdaptive + if (uopt.deintMode != 1) + { + // switch to bob mode + uopt.deintMode = 1; + disableMotionAdaptDeinterlace(); + // TODO why disable scanlines? + // if (GBS::GBS_OPTION_SCANLINES_ENABLED::read()) + if (uopt.wantScanlines) + { + disableScanlines(); + } + // saveUserPrefs(); + _WSN(F("Deinterlacer: Bob")); + } else { + // switch to motion adaptive mode + uopt.deintMode = 0; + // saveUserPrefs(); + _WSN(F("Deinterlacer: Motion Adaptive")); + } + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + break; + // case 'r': + // break; + case 't': + // unused now + _WS(F("6-tap: ")); + if (uopt.wantTap6 == 0) + { + uopt.wantTap6 = 1; + GBS::VDS_TAP6_BYPS::write(0); + GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() - 1); + _WSN(F("on")); + } + else + { + uopt.wantTap6 = 0; + GBS::VDS_TAP6_BYPS::write(1); + GBS::MADPT_Y_DELAY_UV_DELAY::write(GBS::MADPT_Y_DELAY_UV_DELAY::read() + 1); + _WSN(F("off")); + } + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + break; + case 'u': // extract backup + extractBackup(); + // load new prefs for resetting slotID + prefsLoad(); + // reset active slot + uopt.slotID = 0; + prefsSave(); + // reset device to apply new configuration + resetInMSec(2000); + break; + case 'v': // toggle full Height + { + uopt.wantFullHeight = !uopt.wantFullHeight; + uint8_t vidMode = getVideoMode(); + // if (uopt.presetPreference == 5) { + // if (uopt.resolutionID == Output1080 || uopt.resolutionID == Output1080PAL) + // { + applyPresets(vidMode); + // } + slotFlush(); + } + break; + case 'w': // ADC calibration + uopt.enableCalibrationADC = !uopt.enableCalibrationADC; + // slotFlush also does presetSaveToFS() + prefsSave(); + _WSF(PSTR("ADC calibration: %s\n"), (uopt.enableCalibrationADC ? F("on") : F("off"))); + break; + case 'x': // do upscaling on low resolutions (preferScalingRgbhv) + { + uopt.preferScalingRgbhv = !uopt.preferScalingRgbhv; + _WSF(PSTR("preferScalingRgbhv: %s\n"), (uopt.preferScalingRgbhv ? F("on") : F("off"))); + uint8_t videomode = getVideoMode(); + applyPresets(videomode); + prefsSave(); + } + break; + case 'X': // enable/disable ext. clock generator + _WS(F("external clock generator: ")); + if (uopt.disableExternalClockGenerator == false) + { + _WSN(F("off")); + uopt.disableExternalClockGenerator = true; + } + else + { + _WSN(F("on, detecting...")); + uopt.disableExternalClockGenerator = false; + utilsExternClockGenInit(); + } + // TODO do restart here? + prefsSave(); + break; + case 'z': // sog slicer level + if (rto.currentLevelSOG > 0) + rto.currentLevelSOG -= 1; + else + rto.currentLevelSOG = 16; + setAndUpdateSogLevel(rto.currentLevelSOG); + optimizePhaseSP(); + _WSF( + PSTR("Phase: %d SOG: %d\n"), + rto.phaseSP, + rto.currentLevelSOG); + break; + case 'E': + // test option for now + toggleIfAutoOffset(); + _WSF(PSTR("IF auto offset: "), (GBS::IF_AUTO_OFST_EN::read() ? F("on") : F("off"))); + break; + case 'F': // freeze pic + if (GBS::CAPTURE_ENABLE::read() == 0) + { + unfreezeVideo(); + _WSN(F("capture: disabled")); + } + else + { + freezeVideo(); + _WSN(F("capture: enabled")); + } + break; + case 'K': // scanline strength + if (uopt.scanlineStrength >= 0x10) + uopt.scanlineStrength -= 0x10; + else + uopt.scanlineStrength = 0x50; + if (rto.scanlinesEnabled) + { + GBS::MADPT_Y_MI_OFFSET::write(uopt.scanlineStrength); + GBS::MADPT_UV_MI_OFFSET::write(uopt.scanlineStrength); + } + // since we update registers + // slotFlush also does presetSaveToFS() + slotFlush(); + _WSF(PSTR("scanline strength set: 0x%04X\n"), uopt.scanlineStrength); + break; + case 'Z': // brightness++ + GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() + 1); + _WSF( + PSTR("Brightness++ : %d\n"), + GBS::VDS_Y_OFST::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'T': // brightness-- + GBS::VDS_Y_OFST::write(GBS::VDS_Y_OFST::read() - 1); + _WSF( + PSTR("Brightness-- : %d\n"), + GBS::VDS_Y_OFST::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'N': // contrast++ + GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() + 1); + _WSF( + PSTR("Contrast++ : %d\n"), + GBS::VDS_Y_GAIN::read()); + // since we update registers + presetSaveToFS(); + break; + case 'M': // contrast-- + GBS::VDS_Y_GAIN::write(GBS::VDS_Y_GAIN::read() - 1); + _WSF( + PSTR("Contrast-- : %d\n"), + GBS::VDS_Y_GAIN::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'Q': // pb/u gain++ + GBS::VDS_UCOS_GAIN::write(GBS::VDS_UCOS_GAIN::read() + 1); + _WSF( + PSTR("Pb/U gain++ : %d\n"), + GBS::VDS_UCOS_GAIN::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'H': // pb/u gain-- + GBS::VDS_UCOS_GAIN::write(GBS::VDS_UCOS_GAIN::read() - 1); + _WSF( + PSTR("Pb/U gain-- : %d\n"), + GBS::VDS_UCOS_GAIN::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'P': // pr/v gain++ + GBS::VDS_VCOS_GAIN::write(GBS::VDS_VCOS_GAIN::read() + 1); + _WSF( + PSTR("Pr/V gain++ : %d\n"), + GBS::VDS_VCOS_GAIN::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'S': // pr/v gain-- + GBS::VDS_VCOS_GAIN::write(GBS::VDS_VCOS_GAIN::read() - 1); + _WSF( + PSTR("Pr/V gain-- : %d\n"), + GBS::VDS_VCOS_GAIN::read() + ); + // since we update registers + presetSaveToFS(); + break; + case 'O': // info + if (GBS::ADC_INPUT_SEL::read() == 1) + { + _WSF( + PSTR("RGB reg\n------------\nY_OFFSET: %d\n" \ + "U_OFFSET: %d\nV_OFFSET: %d\nY_GAIN: %d\n" \ + "USIN_GAIN: %d\nUCOS_GAIN: %d\n"), + GBS::VDS_Y_OFST::read(), + GBS::VDS_U_OFST::read(), + GBS::VDS_V_OFST::read(), + GBS::VDS_Y_GAIN::read(), + GBS::VDS_USIN_GAIN::read(), + GBS::VDS_UCOS_GAIN::read()); + } + else + { + _WSF( + PSTR("YPbPr reg\n------------\nY_OFFSET: %d\n" + "U_OFFSET: %d\nV_OFFSET: %d\nY_GAIN: %d\n" + "USIN_GAIN: %d\nUCOS_GAIN: %d\n"), + GBS::VDS_Y_OFST::read(), + GBS::VDS_U_OFST::read(), + GBS::VDS_V_OFST::read(), + GBS::VDS_Y_GAIN::read(), + GBS::VDS_USIN_GAIN::read(), + GBS::VDS_UCOS_GAIN::read()); + } + // since we update registers + presetSaveToFS(); + break; + case 'U': // default + if (GBS::ADC_INPUT_SEL::read() == 1) + { + GBS::VDS_Y_GAIN::write(128); + GBS::VDS_UCOS_GAIN::write(28); + GBS::VDS_VCOS_GAIN::write(41); + GBS::VDS_Y_OFST::write(0); + GBS::VDS_U_OFST::write(0); + GBS::VDS_V_OFST::write(0); + GBS::ADC_ROFCTRL::write(adco.r_off); + GBS::ADC_GOFCTRL::write(adco.g_off); + GBS::ADC_BOFCTRL::write(adco.b_off); + _WSN(F("RGB:defauit")); + } + else + { + GBS::VDS_Y_GAIN::write(128); + GBS::VDS_UCOS_GAIN::write(28); + GBS::VDS_VCOS_GAIN::write(41); + GBS::VDS_Y_OFST::write(254); + GBS::VDS_U_OFST::write(3); + GBS::VDS_V_OFST::write(3); + GBS::ADC_ROFCTRL::write(adco.r_off); + GBS::ADC_GOFCTRL::write(adco.g_off); + GBS::ADC_BOFCTRL::write(adco.b_off); + _WSN(F("YPbPr:defauit")); + } + // since we update registers + presetSaveToFS(); + break; + default: + break; + } + + userCommand = '@'; // in case we handled web server command + lastVsyncLock = millis(); +} + +/** + * @brief + * + */ +void initUpdateOTA() +{ + // @sk: MDNS already started + // ArduinoOTA.setHostname("GBS OTA"); + // ArduinoOTA.setPassword("admin"); + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + // update: no password is as (in)secure as this publicly stated hash.. + // rely on the user having to enable the OTA feature on the web ui + + ArduinoOTA.onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "firmware"; + else // U_SPIFFS + type = "filesystem"; + + // NOTE: if updating LittleFS this would be the place to unmount LittleFS using LittleFS.end() + LittleFS.end(); + _WSF( + PSTR("%s OTA update start\n"), + type.c_str() + ); + }); + ArduinoOTA.onEnd([]() { + _WSN(F("OTA update end")); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + _WSF(PSTR("progress: %u%%\n"), (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + _WSF(PSTR("OTA error[%u]: "), error); + if (error == OTA_AUTH_ERROR) + _WSN(F("Auth Failed")); + else if (error == OTA_BEGIN_ERROR) + _WSN(F("Begin Failed")); + else if (error == OTA_CONNECT_ERROR) + _WSN(F("Connect Failed")); + else if (error == OTA_RECEIVE_ERROR) + _WSN(F("Receive Failed")); + else if (error == OTA_END_ERROR) + _WSN(F("End Failed")); + }); + ArduinoOTA.begin(); +} + + +/** + * @brief This is destructive method for all the previously saved + * slots and presets. As a result you'll get completely clean + * filesystem just as before the first start. + * + * @return true + * @return false + */ +void fsToFactory() { + fs::Dir root = LittleFS.openDir("/"); + String index = String(indexPage).substring(1); + while (root.next()) + { + String fn = root.fileName(); + if (fn.compareTo(index) != 0) + LittleFS.remove(fn); + delay(50); + } + // set default slot ID + uopt.slotID = 0; +} + +/** + * @brief webSocket events handler + * + * @param num + * @param type + * @param payload + * @param length + */ +void webSocketEvent(uint8_t num, uint8_t type, uint8_t * payload, size_t length) { + switch (type) { + case WStype_DISCONNECTED: + case WStype_CONNECTED: + _DBGF(PSTR("(ws) %d client(s) connected\n"), num+1); + break; + case WStype_PONG: + if (webSocket.connectedClients() > 0) { + // debug output + if(uopt.developerMode) { + const char * buff = serialGetBuffer(); + if(*buff != '\0') { + // sending to all clients + webSocket.broadcastBIN((uint8_t *)buff, SERIAL_BUFFER_MAX_LEN); + serialBufferClean(); + return; + } + } + // system status values for an ordinary heartbeat + constexpr size_t MESSAGE_LEN = 9; + uint8_t toSend[MESSAGE_LEN]; + memset(toSend, 0, MESSAGE_LEN); + // special character # used for message filtering in WebUI + toSend[0] = '#'; + toSend[1] = uopt.slotID; + toSend[2] = (uint8_t)uopt.resolutionID; + // + if (uopt.wantScanlines) + toSend[3] |= (1 << 0); + if (uopt.wantVdsLineFilter) + toSend[3] |= (1 << 1); + if (uopt.wantStepResponse) + toSend[3] |= (1 << 2); + if (uopt.wantPeaking) + toSend[3] |= (1 << 3); + if (uopt.enableAutoGain) + toSend[3] |= (1 << 4); + if (uopt.enableFrameTimeLock) + toSend[3] |= (1 << 5); + + // + if (uopt.deintMode == 0) // motion adaptive if == 0 + toSend[4] |= (1 << 0); + if (uopt.deintMode == 1) // bob if == 1 + toSend[4] |= (1 << 1); + // if (uopt.wantTap6) { + // toSend[4] |= (1 << 1); + // } + if (uopt.wantFullHeight) + toSend[4] |= (1 << 2); + // if (uopt.matchPresetSource) + // toSend[4] |= (1 << 3); + if (uopt.PalForce60 == 1) + toSend[4] |= (1 << 3); + + // system preferences + if (uopt.wantOutputComponent) + toSend[5] |= (1 << 0); + if (uopt.enableCalibrationADC) + toSend[5] |= (1 << 1); + if (uopt.preferScalingRgbhv) + toSend[5] |= (1 << 2); + if (uopt.disableExternalClockGenerator) + toSend[5] |= (1 << 3); + + // developer panel controls status + if(uopt.developerMode) + toSend[6] |= (1 << 0); + if(rto.printInfos) + toSend[6] |= (1 << 1); + if(uopt.invertSync) + toSend[6] |= (1 << 2); + if(rto.osr != 0) + toSend[6] |= (1 << 3); + if(uopt.adcFilter) + toSend[6] |= (1 << 4); + if(uopt.debugView) + toSend[6] |= (1 << 5); + if(rto.videoIsFrozen) + toSend[6] |= (1 << 6); + if(rto.syncWatcherEnabled) + toSend[6] |= (1 << 7); + + // system tab controls + if(rto.allowUpdatesOTA) + toSend[7] |= (1 << 0); + + // special values + toSend[8] = rto.videoStandardInput; + + webSocket.sendBIN(num, toSend, MESSAGE_LEN); + } + break; + } +} + +#endif // defined(ESP8266) \ No newline at end of file diff --git a/src/wserver.h b/src/wserver.h new file mode 100644 index 00000000..5536b7c0 --- /dev/null +++ b/src/wserver.h @@ -0,0 +1,92 @@ +/* +##################################################################################### +# File: wserver.h # +# File Created: Friday, 19th April 2024 3:11:47 pm # +# Author: Sergey Ko # +# Last Modified: Thursday, 20th June 2024 11:06:06 pm # +# Modified By: Sergey Ko # +##################################################################################### +# CHANGELOG: # +##################################################################################### +*/ +/* + DEVELOPER MEMO: + 1. WS messages (_WS, _WSN, _WSF) must not begin with '#' (hash symbol) since + WebUI filters it, so messages withou hash going to terminal (developer mode) + and those with hash are treated as a binary data + +*/ + +#ifndef _ESPWSERVER_H_ +#define _ESPWSERVER_H_ + +#include +#include +#include +#include +#include "options.h" +#include "presets.h" +#include "tv5725.h" +#include "slot.h" +#include "wserial.h" +#include "wifiman.h" + +extern ESP8266WebServer server; +extern char serialCommand; +extern char userCommand; + +// see: serialCommand = 'D' +typedef struct { + uint8_t VDS_Y_OFST = 0; + uint8_t HD_Y_OFFSET = 0; +} debugRegister; + +const char indexPage[] PROGMEM = "/__index"; +const char backupFile[] PROGMEM = "/__backup"; +const char notFouldMessage[] PROGMEM = "

404 | Page Not Found

"; +const char lomemMessage[] PROGMEM = "

Not enough memory to continue (%.2f kb).

Please, try again in a few moments...

"; +const char mimeTextHtml[] PROGMEM = "text/html"; +const char mimeOctetStream[] PROGMEM = "application/octet-stream"; +const char mimeAppJson[] PROGMEM = "application/json"; + +void serverInit(); +void serverWebSocketToggleDeveloperMode(); +void serverWebSocketInit(); +void serverHome(); +void serverSC(); +void serverUC(); +// void serverWiFiConnect(); +void serverSlots(); +void serverSlotSet(); +void serverSlotSave(); +void serverSlotRemove(); +void serverFsUploadResponder(); +void serverFsUploadHandler(); +void serverBackupDownload(); +void serverRegisterCmd(); +void extractBackup(); +// void serverFsDir(); +// void serverFsFormat(); +void serverWiFiStatus(); +// void serverRestoreFilters(); +void serverWiFiList(); +void serverWiFiWPS(); +void serverWiFiConnect(); +void serverWiFiAP(); +void serverWiFiReset(); +// utils +void printInfo(); +void printVideoTimings(); +void fastGetBestHtotal(); + +#if defined(ESP8266) + +void handleSerialCommand(); +void handleUserCommand(); +void initUpdateOTA(); +void fsToFactory(); +void webSocketEvent(uint8_t num, uint8_t type, uint8_t * payload, size_t length); + +#endif // defined(ESP8266) + +#endif // _ESPWSERVER_H_ \ No newline at end of file diff --git a/test/.gitkeep b/test/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/translation.hdwui.json b/translation.hdwui.json new file mode 100644 index 00000000..7a62832a --- /dev/null +++ b/translation.hdwui.json @@ -0,0 +1,250 @@ +{ + "OM_STATUS_CUSTOM": { + "en": "Main Menu", + "zh": "主菜单", + "es": "Menu Principal", + "ru": "Главное меню", + "size": 12 + }, + "OM_STATUS_BAR_BACK": { + "en": "←Back", + "es": "←Atras", + "ru": "←Назад", + "size": 12 + }, + "OM_SCREEN_SAVER": { + "en": "Press any key", + "es": "Presione el botón", + "ru": "Нажмите кнопку" + }, + "OM_RESOLUTION": { + "en": "Resolutions", + "es": "Resolución de imagen", + "ru": "Выходное разрешение" + }, + "OM_PASSTHROUGH": { + "en": "Passthrough", + "es": "Sin cambios", + "ru": "Без изменений" + }, + "OM_DOWNSCALE": { + "en": "Down-Scale", + "es": "Imagen reducida", + "ru": "Меньший размер картинки" + }, + "OM_PRESET": { + "en": "Slots", + "es": "Perfiles", + "ru": "Профили" + }, + "OM_ACTIVE_SLOT_PARAMETERS": { + "en": "Slot parameters", + "es": "Parameters de Perfil", + "ru": "Настройки Профиля" + }, + "OM_SSET_AUTOGAIN": { + "en": "Auto Gain", + "es": "Aumento automatico", + "ru": "Авто. усиление" + }, + "OM_SSET_SCANLINES": { + "en": "Scanlines", + "es": "Scanlines", + "ru": "Строчность" + }, + "OM_SSET_LINFILTR": { + "en": "Line Filter", + "es": "Filtro lineal", + "ru": "Строчный фильтр" + }, + "OM_SSET_PEAKING": { + "en": "Peaking", + "es": "Sensibilidad", + "ru": "Чувствительность" + }, + "OM_SSET_STPRESP": { + "en": "Step response", + "es": "Respuesta Escalonada", + "ru": "Ступенчатая хар-ка" + }, + "OM_SSET_FULHEIGHT": { + "en": "Full height", + "es": "Estirar en altura", + "ru": "Растягивать по-высоте" + }, + "OM_SSET_F50FREQ60": { + "en": "Force frequency 60Hz for PAL", + "es": "Forzar frequencia de 60Hz para", + "ru": "Повышать частоту до 60Гц для PAL" + }, + "OM_SSET_FTL": { + "en": "FrameTime Lock", + "es": "Cambiar bloqueo de FrameTime", + "ru": "Блокировка FrameTime" + }, + "OM_SSET_FTLMETHOD": { + "en": "Switch FrameTime Lock Method", + "es": "Cambiar método de bloqueo de FrameTime", + "ru": "Переключить метод блокировки FrameTime" + }, + "OM_SSET_DEINT_BOB_MAD": { + "en": "Switch Deinterlacing", + "es": "Cambiar método de Desentrelazado", + "ru": "Переключить Деинтерлейсинг" + }, + "OM_ENABLED": { + "en": "Enabled", + "es": "Encendido", + "ru": "Включено" + }, + "OM_DISABLED": { + "en": "Disabled", + "es": "Apagado", + "ru": "Выключено" + }, + "OM_BOB_ENABLED": { + "en": "Bob enabled", + "es": "método Bob activado", + "ru": "Bob-метод" + }, + "OM_MAD_ENABLED": { + "en": "Motion Adaptive enabled", + "es": "Motion Adaptive activado", + "ru": "Motion Adaptive" + }, + "OM_FTL_METHOD_0": { + "en": "vtotal + VSST", + "es": "vtotal y VSST", + "ru": "vtotal и VSST" + }, + "OM_FTL_METHOD_1": { + "en": "vtotal only", + "es": "solo vtotal", + "ru": "только vtotal" + }, + "OM_SYSTEM_PARAMETERS": { + "en": "System parameters", + "es": "Configuración de Sistema", + "ru": "Общесистемные настройки", + "zh": "" + }, + "OM_CPRM_UPSCALE": { + "en": "Upscaling for Low resolutions", + "es": "Usar Ampliación (Upscaling) para resoluciones bajas", + "ru": "Использовать масштабирование (Upsacale)", + "zh": "" + }, + "OM_CPRM_FORCECOMPOSITE": { + "en": "Force output to RGBHV/Component", + "es": "Forzar salida a RGBHV/Componente", + "ru": "Изменять выход на RGBHV/Компонентный", + "zh": "" + }, + "OM_CPRM_DISEXTCLK": { + "en": "External Clock Generator", + "es": "Generador de reloj externo", + "ru": "Внешний тактовый генератор", + "zh": "" + }, + "OM_CPRM_ADCCALIBR": { + "en": "ADC calibration", + "es": "Calibración del CAD", + "ru": "Калибровка АЦП", + "zh": "" + }, + "OM_RESET_RESTORE": { + "en": "Reset / Restore", + "es": "Resetear / Restaurar", + "ru": "Сброс / Восстановление" + }, + "OM_RESET_GBS": { + "en": "Restart device", + "es": "Reiniciar dispositivo", + "ru": "Перезагрузить" + }, + "OM_RESET_WIFI": { + "en": "Reset WiFi settings", + "es": "Borrar ajustes de WiFi", + "ru": "Сброс настроек WiFi" + }, + "OM_RESTORE_FACTORY": { + "en": "Restore Factory", + "es": "Ajustes de Fabrica", + "ru": "Восстановить заводские настройки" + }, + "OM_CURRENT": { + "en": "Output status", + "es": "Señal de salida", + "ru": "Выходной сигнал" + }, + "OM_WIFI": { + "en": "WiFi Info", + "es": "Informacion de WiFi", + "ru": "Параметры WiFi" + }, + "TEXT_NO_PRESETS": { + "en": "No Presets. Please use the Web UI to create one first", + "es": "No hay perfiles. Usa navegador para crear uno nuevo", + "ru": "Ничего не найдено. Для создания профиля используйте браузер" + }, + "TEXT_TOO_MANY_PRESETS": { + "en": "Please use WebUI to access more presets", + "es": "Por favor usa navegador para acceder a los demás perfiles", + "ru": "Для доступа к другим профилям используйте браузер" + }, + "TEXT_RESETTING_GBS": { + "en": "Restarting\nPlease wait\n...", + "es": "Reiniciando\nPor favor espere\n...", + "ru": "Перезагрузка\nПожалуйста подождите\n...", + "size": 12 + }, + "TEXT_RESETTING_WIFI": { + "en": "Resetting WiFi\nPlease wait\n...", + "es": "Reseteando WiFi\nPor favor espere\n...", + "ru": "Сброс WiFi\nПожалуйста подождите\n...", + "size": 12 + }, + "TEXT_RESTORING": { + "en": "Factory Restore\nPlease wait\n...", + "es": "Reseteando\nPor favor espere\n...", + "ru": "Пожалуйста подождите\n...", + "size": 12 + }, + "TEXT_WIFI_CONNECT_TO": { + "en": "Connect to the following SSID (password) before using the Web UI", + "es": "Conecta al siguiente SSID para acceder al Panel de Control", + "ru": "Для доступа к Панели управления подключитесь к указанной сети" + }, + "TEXT_WIFI_CONNECTED": { + "en": "Status: Connected", + "es": "Estado: Conectado", + "ru": "Состояние: Подключено" + }, + "TEXT_WIFI_DISCONNECTED": { + "en": "Status: Disconnected", + "es": "Estado: Desconectado", + "ru": "Состояние: Отключено" + }, + "TEXT_WIFI_URL": { + "en": "Use one of the following URLs to use the Web UI", + "es": "Usa uno de los siguientes enlaces para acceder al Panel de Control", + "ru": "Для доступа к Панели управления перейдите по одной из следующих ссылок" + }, + "TEXT_LOADED": { + "en": "Loaded", + "es": "activado", + "ru": "активирован", + "size": 16 + }, + "TEXT_NO_INPUT": { + "en": "No Input", + "es": "No hay señal", + "ru": "Нет сигнала", + "size": 16 + }, + "OM_OSD": { + "en": "Open OSD Menu", + "es": "Abrir menu de pantalla", + "ru": "Показать экранное меню" + } +} \ No newline at end of file diff --git a/translation.webui.json b/translation.webui.json new file mode 100644 index 00000000..c6a2ea88 --- /dev/null +++ b/translation.webui.json @@ -0,0 +1,877 @@ +{ + "SLOTS": { + "en": "Slots", + "es": "Perfiles", + "ru": "Профили настроек", + "zh": "设置配置文件" + }, + "SLOTS_HELP_1": { + "en": "The selected Slot will be loaded on the next power-on.", + "es": "El Perfil seleccionado se activará después de reiniciar su GBS-Control.", + "ru": "Выбранный Профиль сохраняется в настройках так, что он активируется при следующем включении устройства.", + "zh": "" + }, + "REMOVE_SLOT": { + "en": "remove slot", + "es": "borrar perfil", + "ru": "удалить профиль", + "zh": "" + }, + "REMOVE_SLOT_JS_ALERT_MESSAGE": { + "en": "

Are you sure to remove Slot: [0]?

This action also removes all related presets, except sistem-wide settings.

", + "es": "

Está seguro de eliminar Perfil: [0]?

Esta acción también elimina todos los ajustes relacionados, excepto la Configuración común.

", + "ru": "

Продолжить удаление Профиля: [0]?

При этом будут удалены все связанные настройки за исключением общесистемных.

", + "zh": "" + }, + "SAVE_PRESET": { + "en": "create slot", + "es": "crear perfil", + "ru": "создать профиль", + "zh": "" + }, + "OUTPUT_RESOLUTION": { + "en": "Output resolution", + "es": "Resolució de salida", + "ru": "Выходное разршение", + "zh": "" + }, + "OUT_RES_HELP_1": { + "en": "The selected resolution will stay active on the next power-on.", + "es": "La resolución seleccionada permanecerá activa en el próximo encendido.", + "ru": "Выбранное разрешение будет активировано при следующем включении.", + "zh": "" + }, + "OUT_RES_HELP_2": { + "en": "1280x960 is recommended for NTSC sources, 1280x1024 for PAL.", + "es": "Se recomienda resolución de 1280x960 para fuentes NTSC y 1280x1024 para PAL.", + "ru": "Для NTSC рекомендуется разрешение 1280x960, для PAL — 1280x1024.", + "zh": "" + }, + + + + + "OUT_RES_HELP_3": { + "en": "Use the \"Matched Presets\" option to switch between the two automatically (Preferences tab)", + "es": "Utilice la opción \"Preajustes coincidentes\" para cambiar entre los dos automáticamente (pestaña Preferencias)", + "ru": "Используйте опцию \"Соответствующие пресеты\" для автоматического переключения между ними (вкладка \"Настройки\").", + "zh": "" + }, + + + + + "DOWNSCALE": { + "en": "Downscale", + "es": "Reducido", + "ru": "Сжатый", + "zh": "" + }, + "PASS_THROUGH": { + "en": "Passthrough", + "es": "Sin cambios", + "ru": "Без изменений", + "zh": "" + }, + "ADC_GAIN_LEGEND": { + "en": "ADC Gain (brightness)", + "es": "Aumento de CAD (brillo)", + "ru": "Усиление АЦП (яркость)", + "zh": "" + }, + "ADC_GAIN_LEGEND_HELP_1": { + "en": "Auto Gain is the mechanism for controlling image brightness within specified limits (clipping). Calibrate for a few seconds on a white screen.", + "es": "Auto Gain es un mecanismo para controlar el brillo de la imagen dentro de límites predeterminados. Se necesita calibrar con la pantalla en color blanco.", + "ru": "Auto Gain механизм контроля яркости изображения в заданных пределах (clipping). Требуется калибровка в течение нескольких секунд на белом экране.", + "zh": "" + }, + "GAIN_BUTTON": { + "en": "gain", + "es": "aumento", + "ru": "усиление", + "zh": "" + }, + "AUTO_GAIN_BUTTON": { + "en": "Auto Gain", + "es": "Aumento automatico", + "ru": "Авто. усиление", + "zh": "" + }, + "COLOR_CORRECTION_LEGEND": { + "en": "Color correction", + "es": "Corrección de color", + "ru": "Коррекция цвета", + "zh": "" + }, + "BRIGHTNESS_CTRL_BUTTON": { + "en": "Brightness", + "es": "Brillo", + "ru": "Яркость", + "zh": "" + }, + "CONTRAST_CTRL_BUTTON": { + "en": "Contrast", + "es": "Contraste", + "ru": "Котраст", + "zh": "" + }, + "PB_U_GAIN_CTRL_BUTTON": { + "en": "Pb/U gain", + "es": "Aumento Pb/U", + "ru": "Усиление Pb/U", + "zh": "" + }, + "PR_V_GAIN_CTRL_BUTTON": { + "en": "Pr/V gain", + "es": "Aumento Pr/V", + "ru": "Усиление Pr/V", + "zh": "" + }, + "COLOR_CORRECTION_HELP_0": { + "en": "Pb/U gain - change blue-luma gain.", + "es": "Aumento Pr/U - cambia el aumento de luma de canal azul.", + "ru": "Усиление Pr/U - изменяет усиление яркости синего канала.", + "zh": "" + }, + "COLOR_CORRECTION_HELP_1": { + "en": "Pr/V gain - change red-luma gain.", + "es": "Aumento Pr/V - cambia el aumento de luma de canal rojo.", + "ru": "Усиление Pr/V - изменяет усиление яркости красного канала.", + "zh": "" + }, + "COLOR_INFO_CTRL_BUTTON": { + "en": "Color info", + "es": "Info. de color", + "ru": "Инфо.", + "zh": "" + }, + "RESET_DEFAULT_COLOR_CTRL_BUTTON": { + "en": "Restore defaults", + "es": "Restaurar colores", + "ru": "Восстановить", + "zh": "" + }, + "PICTURE_CONTROL_LEGEND": { + "en": "Picture Control", + "es": "Control de imagen", + "ru": "Управление изображением", + "zh": "" + }, + "MOVE_BUTTON": { + "en": "move", + "es": "mover", + "ru": "сдвиг", + "zh": "" + }, + "SCALE_BUTTON": { + "en": "scale", + "es": "escala", + "ru": "масштаб", + "zh": "" + }, + "BORDERS_BUTTON": { + "en": "borders", + "es": "orillas", + "ru": "границы", + "zh": "" + }, + "FILTERS_LEGEND": { + "en": "Filters", + "es": "Filtros", + "ru": "Фильтры", + "zh": "" + }, + "SCANLINES_BUTTON": { + "en": "scanlines", + "es": "scanlines", + "ru": "строчность", + "zh": "" + }, + "INTENSITY_BUTTON": { + "en": "intensity", + "es": "intensidad", + "ru": "интенсивность", + "zh": "" + }, + "LINE_FILTER_BUTTON": { + "en": "line filter", + "es": "filtro lineal", + "ru": "строчный фильтр", + "zh": "" + }, + "FILTERS_HELP_1": { + "en": "Scanlines only work with 240p sources, or 480i with Bob deinterlacing.", + "es": "Scanlines solo funcionan señal de entrada de 240p o 480i con desentrelazado Bob.", + "ru": "Строки развёртки работают только с источниками входного сигнала 240p или 480i с Bob-деинтерлейсингом.", + "zh": "" + }, + "FILTERS_HELP_2": { + "en": "Line Filter eliminates blocky-pixel artifacts when upscaling beyond 480p. Recommended to keep it active.", + "es": "El filtro líneal elimina los artefactos de píxeles en bloques cuando se escala más allá de 480p. Se recomienda activarlo.", + "ru": "Строчный Фильтр устраняет артефакты при масштабировании выше 480p. Рекомендуется включить.", + "zh": "" + }, + "PEAKING_BUTTON": { + "en": "peaking", + "es": "sensibilidad", + "ru": "чувствительность", + "zh": "" + }, + "STEP_RESPONSE_BUTTON": { + "en": "step response", + "es": "respuesta escalonada", + "ru": "ступенчатая хар-ка", + "zh": "" + }, + "PEAKING_HELP_1": { + "en": "Peaking increases the contrast around areas of high brightness, which improves image sharpness. Recommended to keep it active.", + "es": "La \"Sensibilidad\" aumenta el contraste alrededor de áreas de alto brillo, lo que mejora la nitidez de la imagen. Se recomienda activarlo.", + "ru": "Параметр Чувствительность увеличивает контраст вокруг областей повышенной яркости, это позволяет повысить чёткость и детализацию изображения. Рекомендуется включить.", + "zh": "" + }, + "PEAKING_HELP_2": { + "en": "Step Response increases the sharpness of horizontal color steps. Recommended to keep it active.", + "es": "La respuesta al paso aumenta la nitidez de las transiciones de color horizontales. Se recomienda activarlo.", + "ru": "Step Response увеличивает резкость горизонтальных цветовых переходов. Рекомендуется включить.", + "zh": "" + }, + "SLOT_SETTINGS_LEGEND": { + "en": "Active Slot parameters", + "es": "Parámetros de Perfil activo", + "ru": "Параиетры активного Профиля", + "zh": "" + }, + + + + "MATCH_PRESETS_SWITCH": { + "en": "Matched Presets", + "es": "Coincidir con el Perfil", + "ru": "Соответствать Профилю", + "zh": "" + }, + "MATCH_PRESETS_SWITCH_HELP_1": { + "en": "If enabled, default to 1280x960 for NTSC 60 and 1280x1024 for PAL 50 (does not apply for 720p / 1080p presets).", + "es": "Si está habilitado, el valor predeterminado es 1280x960 para NTSC 60 y 1280x1024 para PAL 50 (no se aplica a los ajustes preestablecidos de 720p/1080p).", + "ru": "Если этот параметр включен, по умолчанию используется разрешение 1280x960 для NTSC 60 и 1280x1024 для PAL 50 (не применяется к предустановкам 720p/1080p).", + "zh": "" + }, + + + + + + + "FULL_HEIGHT_SWITCH": { + "en": "Full Height", + "es": "Estirar en altura", + "ru": "Растягивать по-высоте", + "zh": "" + }, + "FULL_HEIGHT_SWITCH_HELP_1": { + "en": "In some cases, the device generates an output signal resolution that does not use the full height of the screen; dark bars appear at the top and bottom.", + "es": "En algunos casos, el dispositivo genera una resolución de señal de salida que no utiliza toda la altura de la pantalla; Aparecen barras oscuras en la parte superior e inferior.", + "ru": "В некоторых случаях устройство формирует разрешение выходного сигнала который не используют полную высоту экрана, появляются тёмные полосы вверху и внизу.", + "zh": "" + }, + "FULL_HEIGHT_SWITCH_HELP_2": { + "en": "With \"Full Height\" enabled, these presets will instead scale to fill more of the screen height.", + "es": "Con \"Estirar en altura\" habilitada, la señal de salida aumentará para ocupar una mayor parte de la altura de la pantalla", + "ru": "Если включена функция \"Растягивать по-высоте\", выходной сигнал будет масштабироваться, чтобы заполнить большую часть экрана по высоте", + "zh": "" + }, + "FULL_HEIGHT_SWITCH_HELP_3": { + "en": "This currently only works with 1920 x 1080 (1080p) resolution", + "es": "Actualmente esto sólo funcciona con la resolucion 1920 x 1080 (1080p)", + "ru": "На данный момент эта функция работает только с выходным разрешением 1920 x 1080 (1080p)", + "zh": "" + }, + "FORCE_FRAME_RATE_SWITCH": { + "en": "Force increase frequency for PAL 50Hz to 60Hz", + "es": "Forzar el aumento de la frequencia de salida PAL 50 Hz hasta 60 Hz", + "ru": "Принудительно повышать частоту для PAL 50 Гц до 60 Гц", + "zh": "" + }, + "FORCE_FRAME_RATE_SWITCH_HELP_1": { + "en": "Try this option if your TV does not support 50Hz sources (some non-standard input signal formats). When this feature is enabled, the frame rate may be unstable. Reboot required.", + "es": "Pruebe esta opción si su televisor no admite fuentes de 50Hz (algunos formatos de señal de entrada desconocidos). Cuando esta función está habilitada, la frequencia de salida puede ser inestable. Se require reiniciar GBS-Control.", + "ru": "Используйте эту функцию, если ваш телевизор не поддерживает источники с частотой 50Гц (некоторые нестандартные форматы входного сигнала). При включении этой функции, может нарушаться частота кадров. Требуется перезагрузка.", + "zh": "" + }, + "ACTIVE_FRAME_LOCK_SWITCH": { + "en": "Active FrameTime Lock", + "es": "Bloqueo Activo de FrameTime", + "ru": "Активная блокировка FrameTime", + "zh": "" + }, + "ACTIVE_FRAME_LOCK_SWITCH_HELP_1": { + "en": "This option keeps the input and output timings aligned, fixing the horizontal screen tearing lines.", + "es": "Esta opción mantiene alineados las cadencias de señales de entrada y salida. Se usa para corregir líneas horizontales de corte/desgarro en el video.", + "ru": "Эта опция позволяет согласованность входной и выходной сигналы, исправляя горизонтальные линии сдвига/разрыва выходного сигнала.", + "zh": "" + }, + "ACTIVE_FRAME_LOCK_SWITCH_HELP_2": { + "en": "Two methods are available. Try switching methods if your display goes blank or shifts vertically.", + "es": "Hay dos métodos disponibles. Intente cambiar de método si la pantalla se queda en blanco o se desplaza verticalmente.", + "ru": "Доступны два метода. Попробуйте переключить методы, если изображение пропадает или смещается по вертикали.", + "zh": "" + }, + "FRAME_LOCK_SWITCH_GROUP": { + "en": "FrameTime Lock", + "es": "Bloqueo de FrameTime", + "ru": "Блокировка FrameTime", + "zh": "" + }, + "LOCK_METHOD_SWITCH": { + "en": "Switch Lock Method", + "es": "Cambiar método", + "ru": "Переключить метод", + "zh": "" + }, + "DEINTERLACE_METHOD_SWITCH_GROUP": { + "en": "Deinterlacing filter", + "es": "Filtro de desentrelazado", + "ru": "Деинтерлейсинг (устранение чересстрочности)", + "zh": "" + }, + "DEINTERLACE_METHOD_SWITCH_GROUP_HELP_1": { + "en": "GBS-Control detects interlaced content and automatically toggles \"Deinterlacing\".", + "es": "GBS-Control detecta contenido entrelazado y automáticamente activa el \"Filtro de desentrelazado\".", + "ru": "GBS-Control обнаруживает чересстрочный контент и автоматически включает Деинтерлейсинг.", + "zh": "" + }, + "DEINTERLACE_METHOD_SWITCH_GROUP_HELP_2": { + "en": "Bob Method: essentially no \"Deinterlacing\", does not add delay, but flickering is possible. Works well with the \"Scanlines\".", + "es": "Método Bob: esencialmente sin \"Desentrelazado\", no presenta retrasos, pero es posible el parpadeo. Funciona bien con las \"Scanlines\"", + "ru": "Bob-метод: практически не фильтрует Чересстрочность, не добавляет задержки, но возможны мерцания. Хорошо работает вместе с функцией Строчности.", + "zh": "" + }, + "DEINTERLACE_METHOD_SWITCH_GROUP_HELP_3": { + "en": "Motion Adaptive: eliminates flickering and artifacts on moving frame areas.", + "es": "Motion Adaptive: elimina el parpadeo y unos artefactos en las áreas de movimiento en fotograma.", + "ru": "Motion Adaptive: устраняет мерцание и некоторые искажения движущихся зон кадра.", + "zh": "" + }, + "DEINTERLACE_METHOD_SWITCH_GROUP_HELP_4": { + "en": "Configure the source for progressive output if possible. Otherwise, using \"Motion Adaptive\" is recommended.", + "es": "Configure la fuente de señal para salida progresiva si es posible. De lo contrario, se recomienda utilizar \"Motion Adaptive\".", + "ru": "Если возможно, установите прогрессивный выходной сигнал на источнике. В противном случае рекомендуется использовать \"Motion Adaptive\".", + "zh": "" + }, + "MOTION_ADAPTIVE_SWITCH": { + "en": "Motion Adaptive", + "es": "Motion Adaptive", + "ru": "Motion Adaptive", + "zh": "" + }, + "BOB_SWITCH": { + "en": "Bob (vertical interpolation)", + "es": "Método Bob (interpolación vertical)", + "ru": "Bob-метод (вертикальная интерполяция)", + "zh": "" + }, + "SYSTEM_PREFERENCES_LEGEND": { + "en": "System parameters", + "es": "Configuración de Sistema", + "ru": "Общесистемные настройки", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH": { + "en": "Upscaling for Low resolutions", + "es": "Usar Ampliación (Upscaling) para resoluciones bajas", + "ru": "При низком разрешении использовать масштабирование (Upsacale)", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH_HELP_1": { + "en": "Pass-through or Upscale for Low resolution on VGA input", + "es": "Usar modo \"Sin cambios\" (Pass-through) o Ampliación (Upscale) para resoluciones bajas de entrada VGA", + "ru": "При низком разрешении на входе VGA использовать режим \"Без изменений\" или Масштабирование (Upscale)", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH_HELP_2": { + "en": "Low resolution sources can be either Passed through directly or get Upscaled.", + "es": "Las fuentes de baja resolución se pueden pasar directamente (Sin cambios) o Ampliar (Upscale)", + "ru": "Источники с низким разрешением можно либо передать напрямую без изменений, либо масштабировать.", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH_HELP_3": { + "en": "While using Upscaling a border around an output image may appear.", + "es": "La ampliación puede tener un borde alrededor de la imagen de salida.", + "ru": "При Масштабировании могут измениться границы вокруг выходного изображения", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH_HELP_4": { + "en": "Refresh rates other than 60Hz are not well supported yet.", + "es": "Frecuencias de fotogramas distintas de 60Hz aún no son compatibles.", + "ru": "Частоты входного сигнала, отличные от 60Гц, пока не поддерживаются поддерживается.", + "zh": "" + }, + "LOW_RES_UPSCALE_SWITCH_HELP_5": { + "en": "Low resolution is currently set at below or equal to 640x480 (525 active lines).", + "es": "Baja resolución actualmente está configurada en 640x480 (525 líneas activas) o menos.", + "ru": "В настоящее время низким разрешением считаеются 640x480 (525 активных строк) и ниже.", + "zh": "" + }, + "FORCE_COMPONENET_OUT_SWITCH": { + "en": "Force output to RGBHV/Component", + "es": "Forzar salida a RGBHV/Componente", + "ru": "Принудительно изменять выход на RGBHV/Компонентный", + "zh": "" + }, + "FORCE_COMPONENET_OUT_SWITCH_HELP_1": { + "en": "The default output mode is RGBHV, suitable for use with VGA cables or HDMI converters.", + "es": "El modo de salida predeterminado es RGBHV, adecuado para usar con cables VGA o convertidores HDMI.", + "ru": "Режим вывода по-умолчанию — RGBHV. Подходит для использования с кабелями VGA или преобразователями HDMI.", + "zh": "" + }, + "FORCE_COMPONENET_OUT_SWITCH_HELP_2": { + "en": "An experimental YPbPr mode can also be selected. Compatibility is still spotty.", + "es": "También se puede seleccionar un modo YPbPr experimental. La compatibilidad sigue siendo irregular.", + "ru": "Также можно выбрать экспериментальный режим YPbPr. Совместимость по-прежнему нестабильна.", + "zh": "" + }, + "DISABLE_EXT_CLOCK_SWITCH": { + "en": "Disable External Clock Generator", + "es": "Deshabilitar el generador de reloj externo", + "ru": "Отключить внешний тактовый генератор", + "zh": "" + }, + "DISABLE_EXT_CLOCK_SWITCH_HELP_1": { + "en": "By default the external clock generator is enabled (when installed).", + "es": "El generador de reloj externo está habilitado de forma predeterminada (cuando esta instalado).", + "ru": "По-умолчанию внешний тактовый генератор включен (если он установлен).", + "zh": "" + }, + "DISABLE_EXT_CLOCK_SWITCH_HELP_2": { + "en": "You can disable it if you have issues with other options, e.g \"Force increase frequency for PAL 50Hz to 60Hz\". Reboot required.", + "es": "Puede desactivarlo si tiene problemas con otras opciones, por ejemplo, \"Forzar el aumento de la frequencia de salida PAL 50 Hz hasta 60 Hz\". Reinicio requerido.", + "ru": "Вы можете отключить его, если есть проблемы с другими параметрами, например, \"Принудительно повышать частоту для PAL 50 Гц до 60 Гц\". Требуется перезагрузка.", + "zh": "" + }, + "ADC_CALIBRATION_SWITCH": { + "en": "ADC calibration", + "es": "Calibración del CAD", + "ru": "Калибровка АЦП", + "zh": "" + }, + "ADC_CALIBRATION_SWITCH_HELP_1": { + "en": "GBS-Control calibrates the ADC offsets on startup.", + "es": "GBS-Control calibra las compensaciones del CAD al inicio.", + "ru": "GBS-Control калибрует смещения АЦП при запуске.", + "zh": "" + }, + "ADC_CALIBRATION_SWITCH_HELP_2": { + "en": "In case of color shift problems, try disabling this function.", + "es": "En caso de problemas de cambio de color, intente desactivar esta función.", + "ru": "В случае проблем с цветопередачей попробуйте отключить эту функцию.", + "zh": "" + }, + "DEVELOPER_MODE_SWITCH": { + "en": "Developer Mode", + "es": "Modo desarrollador", + "ru": "Режим разработчика", + "zh": "" + }, + "DEVELOPER_MODE_SWITCH_HELP_1": { + "en": "Enables the developer menu and real time debug console which contains various debugging tools", + "es": "Habilita el menú de desarrollador y consola de registro que contiene varias herramientas adicionales.", + "ru": "Включает меню разработчика и консоль отладки, содержащее различные инструменты отладки.", + "zh": "" + }, + "DEVELOPER_LEGEND": { + "en": "Developer", + "es": "Desarrollador", + "ru": "Разработчик", + "zh": "" + }, + "REGISTER_CMD_SEGMENT": { + "en": "segment", + "es": "segmento", + "ru": "сегмент", + "zh": "" + }, + "REGISTER_CMD_OPERATION": { + "en": "operation", + "es": "operación", + "ru": "операция", + "zh": "" + }, + "REGISTER_DATA_LEGEND": { + "en": "Register data (format: HEX_OCTET_ADDR←(HEX_OCTET_VALUE or HEX_OCTET_LENGTH if reading))", + "es": "Valores de registros (formato: HEX_OCTET_ADDR←(HEX_OCTET_VALUE o HEX_OCTET_LENGTH si es recepción))", + "ru": "Формат данных: HEX_OCTET_РЕГИСТР←(HEX_OCTET_ЗНАЧЕНИЕ или HEX_OCTET_ДЛИНА если чтение))", + "zh": "" + }, + "WRITE": { + "en": "Write", + "es": "Enviar", + "ru": "Запись", + "zh": "" + }, + "READ": { + "en": "Read", + "es": "Recibir", + "ru": "Чтение", + "zh": "" + }, + "DEVELOPER_JS_ALERT_TEXTDECODER": { + "en": "This browser does not support TextDecoder feature...", + "es": "Este navegador no es compatible con la función TextDecoder...", + "ru": "Этот браузер не поддерживает функцию TextDecoder...", + "zh": "" + }, + "TOGGLE_CONSOLE_BUTTON": { + "en": "Toggle Console", + "es": "Ocultar/Mostrar consola", + "ru": "Скрыть/Показать консоль", + "zh": "" + }, + "MEM_LEFT_BUTTON": { + "en": "← MEM", + "es": "← MEM", + "ru": "← Память", + "zh": "" + }, + "MEM_RIGHT_BUTTON": { + "en": "MEM →", + "es": "MEM →", + "ru": "Память →", + "zh": "" + }, + "HS_LEFT_BUTTON": { + "en": "← HS", + "es": "← HS", + "ru": "← HS", + "zh": "" + }, + "HS_RIGHT_BUTTON": { + "en": "HS →", + "es": "HS →", + "ru": "HS →", + "zh": "" + }, + "LIST_OPTIONS_BUTTON": { + "en": "FS+Runtime", + "es": "Parám.Tmp.Ejec.", + "ru": "ФС+ПВВ", + "zh": "" + }, + "PRINT_INFO_BUTTON": { + "en": "Print Debug Info", + "es": "Mostrar Debug Info", + "ru": "Отладочная информация", + "zh": "" + }, + "GET_VIDEO_TIMING_BUTTON": { + "en": "Get Video Timings", + "es": "Obtener Video Timings", + "ru": "Video Timings", + "zh": "" + }, + "FREEZE_CAPTURE_BUTTON": { + "en": "Freeze Capture", + "es": "Hacer Captura", + "ru": "Стоп-кадр", + "zh": "" + }, + "ADC_FILTER_BUTTON": { + "en": "ADC Filter", + "es": "Filtro CAD", + "ru": "Фильтр АЦП", + "zh": "" + }, + "CYCLE_SDRAM_BUTTON": { + "en": "SDRAM refresh rate", + "es": "frecuencia de SDRAM", + "ru": "частота обновления SDRAM", + "zh": "" + }, + "DEBUG_VIEW_BUTTON": { + "en": "Debug View", + "es": "Debug View", + "ru": "Режим отладки", + "zh": "" + }, + "HTOTAL_INCR_BUTTON": { + "en": "HTotal++", + "es": "HTotal++", + "ru": "HTotal++", + "zh": "" + }, + "HTOTAL_DECR_BUTTON": { + "en": "HTotal--", + "es": "HTotal--", + "ru": "HTotal--", + "zh": "" + }, + "RESYNC_HTOTAL_BUTTON": { + "en": "Resync HTotal", + "es": "Resync HTotal", + "ru": "Resync HTotal", + "zh": "" + }, + "PLL_DIVIDER_INCR_BUTTON": { + "en": "PLL divider++", + "es": "Divisor PLL++", + "ru": "Делитель PLL++", + "zh": "" + }, + "INVERT_SYNC_BUTTON": { + "en": "Invert Sync.", + "es": "Invertir Sinc.", + "ru": "Инвертировать Sync.", + "zh": "" + }, + "SYNC_WATCHER_BUTTON": { + "en": "SyncWatcher", + "es": "SyncWatcher", + "ru": "SyncWatcher", + "zh": "" + }, + "SYNC_PROCESSOR_BUTTON": { + "en": "SyncProcessor", + "es": "SyncProcessor", + "ru": "SyncProcessor", + "zh": "" + }, + "OVERSAMPLING_BUTTON": { + "en": "Oversampling", + "es": "Oversampling", + "ru": "Oversampling", + "zh": "" + }, + "HDMI_50FREQ60_BUTTON": { + "en": "60/50Hz HDMI", + "es": "60/50Hz HDMI", + "ru": "60/50Hz HDMI", + "zh": "" + }, + "IF_AUTO_OFFSET_BUTTON": { + "en": "IF Auto Offset", + "es": "IF Auto Offset", + "ru": "IF Auto Offset", + "zh": "" + }, + "SOG_LEVEL_DECR_BUTTON": { + "en": "SOG Level--", + "es": "Nivel SOG--", + "ru": "Уровень SOG--", + "zh": "" + }, + "RESET_CHIP_BUTTON": { + "en": "Reset Chip", + "es": "Resetear Chip", + "ru": "Сбросить Чип", + "zh": "" + }, + "DEVICE_MANAGEMENT_LEGEND": { + "en": "Device management", + "es": "Administración del dispositivo", + "ru": "Управление устройством", + "zh": "" + }, + "ENABLE_OTA_BUTTON": { + "en": "Enable OTA", + "es": "Habilitar OTA", + "ru": "Включить OTA", + "zh": "" + }, + "RESTART_DEVICE_BUTTON": { + "en": "Restart device", + "es": "Reiniciar", + "ru": "Перезагрузить", + "zh": "" + }, + "RESET_ACTIVE_SLOT": { + "en": "Reset active Slot", + "es": "Resetear Perfil activo", + "ru": "Сброс активного Профиля", + "zh": "" + }, + "RESET_ACTIVE_SLOT_JS_ALERT_MESSAGE": { + "en": "

Reset active Slot to its initial state. The data to be deleted:

  • Active Slot and its active Preset data

The device will be restarted. Are you ready to continue?

", + "es": "

Esta acción restablecerá el Perfil activa a su estado inicial. Los siguientes datos serán eliminados:

  • Perfil activo y sus ajustes

El dispositivo se reiniciará. Está seguro de continuar?

", + "ru": "

Сброс активного Профиля в исходное состояние. Следующие данные будут удалены:

  • Активный Профиль и его активные настройки (preset)

Устройство будет перезапущено. Желаете продолжить?

", + "zh": "" + }, + "RESET_DEFAULTS_BUTTON": { + "en": "Restore factory defaults", + "es": "Restablecer el estado de fábrica", + "ru": "Сброс к заводским настройкам", + "zh": "" + }, + "RESET_FACTORY_BUTTON_JS_ALERT_MESSAGE": { + "en": "

This action will reset your device to factory state. The data to be deleted:

  • All Slots and Presets data,
  • System parameters

The device will be restarted. Are you ready to continue?

", + "es": "

Restablecer el estado de fábrica. Los siguientes datos serán eliminados:

  • Todos Perfiles y sus ajustes,
  • Configuración común

El dispositivo se reiniciará. Está seguro de continuar?

", + "ru": "

Сброс устройства к заводскому состоянию. Следующие данные будут удалены:

  • Все Профили и предустановки (presets),
  • Общесистемные параметры

Устройство будет перезапущено. Желаете продолжить?

", + "zh": "" + }, + "BACKUP_LEGEND": { + "en": "Backup and Restore", + "es": "Copia de seguridad", + "ru": "Резервное копирование", + "zh": "" + }, + "BACKUP_BUTTON_HELP_1": { + "en": "Restore backup data may fail if devices have different firmware versions", + "es": "La Restauración de datos de copia de seguridad puede fallar si los dispositivos tienen diferentes versiones de firmware", + "ru": "Восстановление данных из резервной копии может оказаться неудачным, если на устройствах установлены разные версии прошивки.", + "zh": "" + }, + "BACKUP_BUTTON": { + "en": "Backup", + "es": "Respaldar", + "ru": "Копировать", + "zh": "" + }, + "RESTORE_BUTTON": { + "en": "Restore", + "es": "Restaurar", + "ru": "Восстановить", + "zh": "" + }, + "RESTORE_JS_ALERT_MESSAGE": { + "en": "

Backup File:

Backup date: [0]

Size: [1] kB

", + "es": "

Backup File:

Backup date: [0]

Size: [1] kB

", + "ru": "

Backup File:

Backup date: [0]

Size: [1] kB

", + "zh": "" + }, + "WIFI_LEGEND": { + "en": "WiFi", + "es": "WiFi", + "ru": "Параметры WiFi", + "zh": "" + }, + "ACCESS_POINT_MODE_BUTTON": { + "en": "Access Point", + "es": "Punto de acceso", + "ru": "Точка доступа", + "zh": "" + }, + "ACCESS_POINT_MODE_JS_ALERT_MESSAGE": { + "en": "Switching to AP mode. Please connect to \"gbscontrol\" and then click OK", + "es": "Punto de Acceso ha sido activado. Conéctese a la red \"gbscontrol\" y luego haga clic en OK", + "ru": "Переключение в режим Точки Доступа. Подключитесь к сети \"gbscontrol\" и нажмите \"ОК\"", + "zh": "" + }, + "STATION_MODE_BUTTON": { + "en": "Station", + "es": "Estación", + "ru": "Станция", + "zh": "" + }, + "SSID_SELECT_LEGEND": { + "en": "Select SSID", + "es": "Seleccione SSID", + "ru": "Выберите SSID", + "zh": "" + }, + "CONNECTO_TO_SSID_BUTTON": { + "en": "Connect to SSID", + "es": "Conectar a SSID", + "ru": "Подключиться к SSID", + "zh": "" + }, + "CONNECT_BUTTON": { + "en": "Connect", + "es": "Conectar", + "ru": "Подключиться", + "zh": "" + }, + "CONNECT_JS_ALERT_MESSAGE": { + "en": "GBS-Control is now connecting to [0]. If connection fails GBS-Control will switch back to Access Point mode. Please wait a few seconds.", + "es": "GBS-Control está conectando a [0]. Si la conexión falla, GBS-Control volverá al modo Punto de Acceso. Espere unos segundos.", + "ru": "GBS-Control пытается подключиться к [0]. Если соединение не удастся, GBS-Control переключится обратно в режим Точки Доступа. Пожалуйста, подождите несколько секунд.", + "zh": "" + }, + "PROMPT_LEGEND": { + "en": "Prompt", + "es": "Prompt", + "ru": "Prompt", + "zh": "" + }, + "CANCEL_BUTTON": { + "en": "CANCEL", + "es": "CANCELAR", + "ru": "ОТМЕНА", + "zh": "" + }, + "OK_BUTTON": { + "en": "OK", + "es": "PROCEDER", + "ru": "ПРОДОЛЖИТЬ", + "zh": "" + }, + "ALERT_LEGEND": { + "en": "ALERT", + "es": "ALERTA", + "ru": "УВЕДОМЛЕНИЕ", + "zh": "" + }, + "CONSOLE_OUTPUT_LEGEND": { + "en": "Console", + "es": "Consola", + "ru": "Консоль", + "zh": "" + }, + "SSID_PLACEHOLDER": { + "en": "SSID", + "es": "SSID", + "ru": "SSID", + "zh": "" + }, + "PASSWORD_PLACEHOLDER": { + "en": "password", + "es": "contraseña", + "ru": "Пароль", + "zh": "" + }, + "ALERT_BUTTON_JS_REJECT": { + "en": "Cancel", + "es": "Cancelar", + "ru": "Отмена", + "zh": "" + }, + "ALERT_BUTTON_JS_ACK": { + "en": "Accept", + "es": "Aceptar", + "ru": "Продолжить", + "zh": "" + }, + "ALERT_BUTTON_JS_RESTORE": { + "en": "Restore", + "es": "Restaurar", + "ru": "Восстановить", + "zh": "" + }, + "JS_NO": { + "en": "No", + "es": "No", + "ru": "Нет", + "zh": "" + }, + "JS_YES": { + "en": "Yes", + "es": "Si", + "ru": "Да", + "zh": "" + }, + "DEVICE_RESTARTING_CONSOLE_MESSAGE": { + "en": "GBS-Control is now restarting...", + "es": "GBS-Control está reiniciando...", + "ru": "GBS-Control перезагружается...", + "zh": "" + }, + "PAGE_RELOAD_IN": { + "en": "reload in:", + "es": "reinicio en:", + "ru": "перезагрузка через:", + "zh": "" + }, + "SECONDS_SHORT": { + "en": "sec", + "es": "sec", + "ru": "сек", + "zh": "" + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..1454824a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["DOM","ES6"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "CommonJS", /* Specify what module code is generated. */ + "rootDir": "./public/src/", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + // "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": false, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/tv5725.h b/tv5725.h deleted file mode 100644 index 39f9ca54..00000000 --- a/tv5725.h +++ /dev/null @@ -1,809 +0,0 @@ -#ifndef TV5725_H_ -#define TV5725_H_ - -#include "tw.h" - -#define GBS_ADDR 0x17 // 7 bit GBS I2C Address - -namespace detail -{ - struct TVAttrs - { - // Segment register at 0xf0, no bit offset, 8 bits, initial value assumed invalid - static const uint8_t SegByteOffset = 0xf0; - static const uint8_t SegBitOffset = 0; - static const uint8_t SegBitWidth = 8; - static const uint8_t SegInitial = 0xff; - }; -} // namespace detail - -template -class TV5725 : public tw::SegmentedSlave -{ -private: - // Stupid template boilerplate - typedef tw::SegmentedSlave Base; - using typename Base::SegValue; - template - using Register = typename Base::template Register; - template - using UReg = Register; - -public: - // STATUS Registers - // Arbitary names for STATUS_IF register - typedef UReg<0x00, 0x00, 0, 8> STATUS_00; // whole register for convenience - typedef UReg<0x00, 0x00, 0, 1> STATUS_IF_VT_OK; - typedef UReg<0x00, 0x00, 1, 1> STATUS_IF_HT_OK; - typedef UReg<0x00, 0x00, 2, 1> STATUS_IF_HVT_OK; - typedef UReg<0x00, 0x00, 3, 1> STATUS_IF_INP_NTSC_INT; - typedef UReg<0x00, 0x00, 4, 1> STATUS_IF_INP_NTSC_PRG; - typedef UReg<0x00, 0x00, 5, 1> STATUS_IF_INP_PAL_INT; - typedef UReg<0x00, 0x00, 6, 1> STATUS_IF_INP_PAL_PRG; - typedef UReg<0x00, 0x00, 7, 1> STATUS_IF_INP_SD; - typedef UReg<0x00, 0x01, 0, 1> STATUS_IF_INP_VGA60; - typedef UReg<0x00, 0x01, 1, 1> STATUS_IF_INP_VGA75; - typedef UReg<0x00, 0x01, 2, 1> STATUS_IF_INP_VGA86; - typedef UReg<0x00, 0x01, 3, 1> STATUS_IF_INP_VGA; - typedef UReg<0x00, 0x01, 4, 1> STATUS_IF_INP_SVGA60; - typedef UReg<0x00, 0x01, 5, 1> STATUS_IF_INP_SVGA75; - typedef UReg<0x00, 0x01, 6, 1> STATUS_IF_INP_SVGA85; - typedef UReg<0x00, 0x01, 7, 1> STATUS_IF_INP_SVGA; - typedef UReg<0x00, 0x02, 0, 1> STATUS_IF_INP_XGA60; - typedef UReg<0x00, 0x02, 1, 1> STATUS_IF_INP_XGA70; - typedef UReg<0x00, 0x02, 2, 1> STATUS_IF_INP_XGA75; - typedef UReg<0x00, 0x02, 3, 1> STATUS_IF_INP_XGA85; - typedef UReg<0x00, 0x02, 4, 1> STATUS_IF_INP_XGA; - typedef UReg<0x00, 0x02, 5, 1> STATUS_IF_INP_SXGA60; - typedef UReg<0x00, 0x02, 6, 1> STATUS_IF_INP_SXGA75; - typedef UReg<0x00, 0x02, 7, 1> STATUS_IF_INP_SXGA85; - typedef UReg<0x00, 0x03, 0, 8> STATUS_03; // whole register for convenience - typedef UReg<0x00, 0x03, 0, 1> STATUS_IF_INP_SXGA; - typedef UReg<0x00, 0x03, 1, 1> STATUS_IF_INP_PC; - typedef UReg<0x00, 0x03, 2, 1> STATUS_IF_INP_720P50; - typedef UReg<0x00, 0x03, 3, 1> STATUS_IF_INP_720P60; - typedef UReg<0x00, 0x03, 4, 1> STATUS_IF_INP_720; - typedef UReg<0x00, 0x03, 5, 1> STATUS_IF_INP_2200_1125I; - typedef UReg<0x00, 0x03, 6, 1> STATUS_IF_INP_2376_1250I; - typedef UReg<0x00, 0x03, 7, 1> STATUS_IF_INP_2640_1125I; - typedef UReg<0x00, 0x04, 0, 8> STATUS_04; // whole register for convenience - typedef UReg<0x00, 0x04, 0, 1> STATUS_IF_INP_1080I; - typedef UReg<0x00, 0x04, 1, 1> STATUS_IF_INP_2200_1125P; - typedef UReg<0x00, 0x04, 2, 1> STATUS_IF_INP_2376_1250P; - typedef UReg<0x00, 0x04, 3, 1> STATUS_IF_INP_2640_1125P; - typedef UReg<0x00, 0x04, 4, 1> STATUS_IF_INP_1808P; - typedef UReg<0x00, 0x04, 5, 1> STATUS_IF_INP_HD; - typedef UReg<0x00, 0x04, 6, 1> STATUS_IF_INP_INT; - typedef UReg<0x00, 0x04, 7, 1> STATUS_IF_INP_PRG; - typedef UReg<0x00, 0x05, 0, 8> STATUS_05; // whole register for convenience - typedef UReg<0x00, 0x05, 0, 1> STATUS_IF_INP_USER; - typedef UReg<0x00, 0x05, 1, 1> STATUS_IF_NO_SYNC; - typedef UReg<0x00, 0x05, 2, 1> STATUS_IF_HT_BAD; - typedef UReg<0x00, 0x05, 3, 1> STATUS_IF_VT_BAD; - typedef UReg<0x00, 0x05, 4, 1> STATUS_IF_INP_SW; - - typedef UReg<0x00, 0x06, 0, 9> HPERIOD_IF; - typedef UReg<0x00, 0x07, 1, 11> VPERIOD_IF; - - typedef UReg<0x00, 0x09, 6, 1> STATUS_MISC_PLL648_LOCK; - typedef UReg<0x00, 0x09, 7, 1> STATUS_MISC_PLLAD_LOCK; - typedef UReg<0x00, 0x0A, 0, 1> STATUS_MISC_PIP_EN_V; - typedef UReg<0x00, 0x0A, 1, 1> STATUS_MISC_PIP_EN_H; - typedef UReg<0x00, 0x0A, 4, 1> STATUS_MISC_VBLK; - typedef UReg<0x00, 0x0A, 5, 1> STATUS_MISC_HBLK; - typedef UReg<0x00, 0x0A, 6, 1> STATUS_MISC_VSYNC; - typedef UReg<0x00, 0x0A, 7, 1> STATUS_MISC_HSYNC; - - typedef UReg<0x00, 0x0B, 0, 8> CHIP_ID_FOUNDRY; - typedef UReg<0x00, 0x0C, 0, 8> CHIP_ID_PRODUCT; - typedef UReg<0x00, 0x0D, 0, 8> CHIP_ID_REVISION; - - typedef UReg<0x00, 0x0E, 0, 1> STATUS_GPIO_GPIO; - typedef UReg<0x00, 0x0E, 1, 1> STATUS_GPIO_HALF; - typedef UReg<0x00, 0x0E, 2, 1> STATUS_GPIO_SCLSA; - typedef UReg<0x00, 0x0E, 3, 1> STATUS_GPIO_MBA; - typedef UReg<0x00, 0x0E, 4, 1> STATUS_GPIO_MCS1; - typedef UReg<0x00, 0x0E, 5, 1> STATUS_GPIO_HBOUT; - typedef UReg<0x00, 0x0E, 6, 1> STATUS_GPIO_VBOUT; - typedef UReg<0x00, 0x0E, 7, 1> STATUS_GPIO_CLKOUT; - - typedef UReg<0x00, 0x0F, 0, 8> STATUS_0F; // whole register for convenience - typedef UReg<0x00, 0x0F, 0, 1> STATUS_INT_SOG_BAD; - typedef UReg<0x00, 0x0F, 1, 1> STATUS_INT_SOG_SW; - typedef UReg<0x00, 0x0F, 2, 1> STATUS_INT_SOG_OK; - typedef UReg<0x00, 0x0F, 3, 1> STATUS_INT_INP_SW; - typedef UReg<0x00, 0x0F, 4, 1> STATUS_INT_INP_NO_SYNC; - typedef UReg<0x00, 0x0F, 5, 1> STATUS_INT_INP_HSYNC; - typedef UReg<0x00, 0x0F, 6, 1> STATUS_INT_INP_VSYNC; - typedef UReg<0x00, 0x0F, 7, 1> STATUS_INT_INP_CSYNC; //Needs confirmation - - typedef UReg<0x00, 0x10, 0, 4> STATUS_VDS_FR_NUM; - typedef UReg<0x00, 0x10, 4, 1> STATUS_VDS_OUT_VSYNC; - typedef UReg<0x00, 0x10, 5, 1> STATUS_VDS_OUT_HSYNC; - typedef UReg<0x00, 0x11, 0, 1> STATUS_VDS_FIELD; - typedef UReg<0x00, 0x11, 1, 1> STATUS_VDS_OUT_BLANK; - typedef UReg<0x00, 0x11, 4, 11> STATUS_VDS_VERT_COUNT; - - typedef UReg<0x00, 0x13, 0, 1> STATUS_MEM_FF_WFF_FIFO_FULL; - typedef UReg<0x00, 0x13, 1, 1> STATUS_MEM_FF_WFF_FIFO_EMPTY; - typedef UReg<0x00, 0x13, 2, 1> STATUS_MEM_FF_RFF_FIFO_FULL; - typedef UReg<0x00, 0x13, 3, 1> STATUS_MEM_FF_RFF_FIFO_EMPTY; - typedef UReg<0x00, 0x13, 4, 1> STATUS_MEM_FF_CAP_FIFO_FULL; - typedef UReg<0x00, 0x13, 5, 1> STATUS_MEM_FF_CAP_FIFO_EMPTY; - typedef UReg<0x00, 0x13, 6, 1> STATUS_MEM_FF_PLY_FIFO_FULL; - typedef UReg<0x00, 0x13, 7, 1> STATUS_MEM_FF_PLY_FIFO_EMPTY; - typedef UReg<0x00, 0x14, 0, 1> STATUS_MEM_FF_EXT_FIN; - - typedef UReg<0x00, 0x15, 7, 1> STATUS_DEINT_PULLDN; - - typedef UReg<0x00, 0x16, 0, 8> STATUS_16; // whole register for convenience - typedef UReg<0x00, 0x16, 0, 1> STATUS_SYNC_PROC_HSPOL; - typedef UReg<0x00, 0x16, 1, 1> STATUS_SYNC_PROC_HSACT; - typedef UReg<0x00, 0x16, 2, 1> STATUS_SYNC_PROC_VSPOL; - typedef UReg<0x00, 0x16, 3, 1> STATUS_SYNC_PROC_VSACT; - typedef UReg<0x00, 0x17, 0, 12> STATUS_SYNC_PROC_HTOTAL; - typedef UReg<0x00, 0x19, 0, 12> STATUS_SYNC_PROC_HLOW_LEN; - typedef UReg<0x00, 0x1B, 0, 11> STATUS_SYNC_PROC_VTOTAL; - typedef UReg<0x00, 0x1F, 0, 8> TEST_BUS_1F; - typedef UReg<0x00, 0x20, 0, 16> TEST_FF_STATUS; - typedef UReg<0x00, 0x23, 0, 8> TEST_BUS_23; - typedef UReg<0x00, 0x2E, 0, 16> TEST_BUS; - typedef UReg<0x00, 0x2E, 0, 8> TEST_BUS_2E; - typedef UReg<0x00, 0x2F, 0, 8> TEST_BUS_2F; - - // Miscellaneous Registers - typedef UReg<0x00, 0x40, 0, 1> PLL_CKIS; - typedef UReg<0x00, 0x40, 1, 1> PLL_DIVBY2Z; - typedef UReg<0x00, 0x40, 2, 1> PLL_IS; - typedef UReg<0x00, 0x40, 3, 1> PLL_ADS; - typedef UReg<0x00, 0x40, 4, 3> PLL_MS; - typedef UReg<0x00, 0x41, 0, 8> PLL648_CONTROL_01; - typedef UReg<0x00, 0x43, 0, 8> PLL648_CONTROL_03; - typedef UReg<0x00, 0x43, 0, 2> PLL_R; - typedef UReg<0x00, 0x43, 2, 2> PLL_S; - typedef UReg<0x00, 0x43, 4, 1> PLL_LEN; - typedef UReg<0x00, 0x43, 5, 1> PLL_VCORST; - typedef UReg<0x00, 0x44, 0, 1> DAC_RGBS_PWDNZ; - typedef UReg<0x00, 0x44, 2, 1> DAC_RGBS_R0ENZ; - typedef UReg<0x00, 0x44, 5, 1> DAC_RGBS_G0ENZ; - typedef UReg<0x00, 0x45, 0, 1> DAC_RGBS_B0ENZ; - typedef UReg<0x00, 0x45, 2, 1> DAC_RGBS_SPD; - typedef UReg<0x00, 0x45, 3, 1> DAC_RGBS_S0ENZ; - typedef UReg<0x00, 0x45, 4, 1> DAC_RGBS_S1EN; - typedef UReg<0x00, 0x46, 0, 8> RESET_CONTROL_0x46; // fake name - typedef UReg<0x00, 0x46, 0, 1> SFTRST_IF_RSTZ; - typedef UReg<0x00, 0x46, 1, 1> SFTRST_DEINT_RSTZ; - typedef UReg<0x00, 0x46, 2, 1> SFTRST_MEM_FF_RSTZ; - typedef UReg<0x00, 0x46, 4, 1> SFTRST_FIFO_RSTZ; - typedef UReg<0x00, 0x46, 6, 1> SFTRST_VDS_RSTZ; - typedef UReg<0x00, 0x47, 0, 8> RESET_CONTROL_0x47; // fake name - typedef UReg<0x00, 0x47, 0, 1> SFTRST_DEC_RSTZ; - typedef UReg<0x00, 0x47, 1, 1> SFTRST_MODE_RSTZ; - typedef UReg<0x00, 0x47, 2, 1> SFTRST_SYNC_RSTZ; - typedef UReg<0x00, 0x47, 3, 1> SFTRST_HDBYPS_RSTZ; - typedef UReg<0x00, 0x47, 4, 1> SFTRST_INT_RSTZ; - typedef UReg<0x00, 0x48, 0, 8> PAD_CONTROL_00_0x48; - typedef UReg<0x00, 0x48, 0, 1> PAD_BOUT_EN; // aka debug pin - typedef UReg<0x00, 0x48, 6, 1> PAD_SYNC1_IN_ENZ; - typedef UReg<0x00, 0x48, 7, 1> PAD_SYNC2_IN_ENZ; - typedef UReg<0x00, 0x49, 0, 8> PAD_CONTROL_01_0x49; // fake name - typedef UReg<0x00, 0x49, 0, 1> PAD_CKIN_ENZ; - typedef UReg<0x00, 0x49, 1, 1> PAD_CKOUT_ENZ; - typedef UReg<0x00, 0x49, 2, 1> PAD_SYNC_OUT_ENZ; - typedef UReg<0x00, 0x49, 4, 1> PAD_TRI_ENZ; - typedef UReg<0x00, 0x4A, 0, 3> PAD_OSC_CNTRL; - typedef UReg<0x00, 0x4B, 1, 1> DAC_RGBS_BYPS2DAC; - typedef UReg<0x00, 0x4B, 2, 1> DAC_RGBS_ADC2DAC; - typedef UReg<0x00, 0x4D, 0, 5> TEST_BUS_SEL; - typedef UReg<0x00, 0x4D, 5, 1> TEST_BUS_EN; - typedef UReg<0x00, 0x4F, 5, 1> OUT_SYNC_CNTRL; - typedef UReg<0x00, 0x4F, 6, 2> OUT_SYNC_SEL; - - typedef UReg<0x00, 0x52, 0, 8> GPIO_CONTROL_00; - typedef UReg<0x00, 0x53, 0, 8> GPIO_CONTROL_01; - typedef UReg<0x00, 0x58, 0, 8> INTERRUPT_CONTROL_00; - typedef UReg<0x00, 0x58, 0, 1> INT_CONTROL_RST_SOGBAD; - typedef UReg<0x00, 0x58, 1, 1> INT_CONTROL_RST_SOGSWITCH; - typedef UReg<0x00, 0x58, 4, 1> INT_CONTROL_RST_NOHSYNC; - typedef UReg<0x00, 0x59, 0, 8> INTERRUPT_CONTROL_01; - - // IF Registers - typedef UReg<0x01, 0x00, 0, 1> IF_IN_DREG_BYPS; - typedef UReg<0x01, 0x00, 1, 1> IF_MATRIX_BYPS; - typedef UReg<0x01, 0x00, 2, 1> IF_UV_REVERT; - typedef UReg<0x01, 0x00, 3, 1> IF_SEL_656; - typedef UReg<0x01, 0x00, 4, 1> IF_SEL16BIT; - typedef UReg<0x01, 0x00, 5, 1> IF_VS_SEL; - typedef UReg<0x01, 0x00, 6, 1> IF_PRGRSV_CNTRL; - typedef UReg<0x01, 0x00, 7, 1> IF_HS_FLIP; - typedef UReg<0x01, 0x01, 0, 1> IF_VS_FLIP; - typedef UReg<0x01, 0x01, 7, 1> IF_SEL24BIT; - typedef UReg<0x01, 0x02, 0, 8> INPUT_FORMATTER_02; // convenience - typedef UReg<0x01, 0x02, 0, 1> IF_SEL_WEN; - typedef UReg<0x01, 0x02, 1, 1> IF_HS_SEL_LPF; - typedef UReg<0x01, 0x02, 2, 1> IF_HS_INT_LPF_BYPS; - typedef UReg<0x01, 0x02, 3, 1> IF_HS_PSHIFT_BYPS; - typedef UReg<0x01, 0x02, 4, 1> IF_HS_TAP11_BYPS; - typedef UReg<0x01, 0x02, 5, 2> IF_HS_Y_PDELAY; - typedef UReg<0x01, 0x0b, 4, 2> IF_HS_DEC_FACTOR; - typedef UReg<0x01, 0x0b, 6, 1> IF_SEL_HSCALE; - typedef UReg<0x01, 0x0b, 7, 1> IF_LD_SEL_PROV; - typedef UReg<0x01, 0x0c, 0, 1> IF_LD_RAM_BYPS; - typedef UReg<0x01, 0x0c, 1, 4> IF_LD_ST; - typedef UReg<0x01, 0x0c, 5, 11> IF_INI_ST; - typedef UReg<0x01, 0x0e, 0, 11> IF_HSYNC_RST; - typedef UReg<0x01, 0x10, 0, 11> IF_HB_ST; - typedef UReg<0x01, 0x12, 0, 11> IF_HB_SP; - typedef UReg<0x01, 0x16, 0, 11> IF_HB_SP1; - typedef UReg<0x01, 0x18, 0, 11> IF_HB_ST2; - typedef UReg<0x01, 0x1a, 0, 11> IF_HB_SP2; - typedef UReg<0x01, 0x1c, 0, 11> IF_VB_ST; - typedef UReg<0x01, 0x1e, 0, 11> IF_VB_SP; - typedef UReg<0x01, 0x20, 0, 12> IF_LINE_ST; - typedef UReg<0x01, 0x22, 0, 12> IF_LINE_SP; - typedef UReg<0x01, 0x24, 0, 12> IF_HBIN_ST; - typedef UReg<0x01, 0x26, 0, 12> IF_HBIN_SP; - typedef UReg<0x01, 0x28, 1, 1> IF_LD_WRST_SEL; - typedef UReg<0x01, 0x28, 2, 1> IF_SEL_ADC_SYNC; - typedef UReg<0x01, 0x28, 3, 1> IF_TEST_EN; - typedef UReg<0x01, 0x28, 4, 4> IF_TEST_SEL; - typedef UReg<0x01, 0x29, 0, 1> IF_AUTO_OFST_EN; - typedef UReg<0x01, 0x29, 1, 1> IF_AUTO_OFST_PRD; - typedef UReg<0x01, 0x2A, 0, 4> IF_AUTO_OFST_U_RANGE; - typedef UReg<0x01, 0x2A, 4, 4> IF_AUTO_OFST_V_RANGE; - typedef UReg<0x01, 0x2B, 0, 7> GBS_PRESET_ID; - typedef UReg<0x01, 0x2B, 7, 1> GBS_PRESET_CUSTOM; - typedef UReg<0x01, 0x2C, 0, 1> GBS_OPTION_SCANLINES_ENABLED; - typedef UReg<0x01, 0x2C, 1, 1> GBS_OPTION_SCALING_RGBHV; - typedef UReg<0x01, 0x2C, 2, 1> GBS_OPTION_PALFORCED60_ENABLED; - typedef UReg<0x01, 0x2C, 3, 1> GBS_RUNTIME_UNUSED_BIT; - typedef UReg<0x01, 0x2C, 4, 1> GBS_RUNTIME_FTL_ADJUSTED; - typedef UReg<0x01, 0x2D, 0, 8> GBS_PRESET_DISPLAY_CLOCK; - - // HDBypass - typedef UReg<0x01, 0x30, 1, 1> HD_MATRIX_BYPS; - typedef UReg<0x01, 0x30, 2, 1> HD_DYN_BYPS; - typedef UReg<0x01, 0x30, 3, 1> HD_SEL_BLK_IN; - typedef UReg<0x01, 0x32, 0, 8> HD_Y_OFFSET; - typedef UReg<0x01, 0x34, 0, 8> HD_U_OFFSET; - typedef UReg<0x01, 0x36, 0, 8> HD_V_OFFSET; - typedef UReg<0x01, 0x37, 0, 11> HD_HSYNC_RST; - typedef UReg<0x01, 0x39, 0, 11> HD_INI_ST; - typedef UReg<0x01, 0x3B, 0, 12> HD_HB_ST; - typedef UReg<0x01, 0x3D, 0, 12> HD_HB_SP; - typedef UReg<0x01, 0x3F, 0, 12> HD_HS_ST; - typedef UReg<0x01, 0x41, 0, 12> HD_HS_SP; - typedef UReg<0x01, 0x43, 0, 12> HD_VB_ST; - typedef UReg<0x01, 0x45, 0, 12> HD_VB_SP; - typedef UReg<0x01, 0x47, 0, 12> HD_VS_ST; - typedef UReg<0x01, 0x49, 0, 12> HD_VS_SP; - typedef UReg<0x01, 0x53, 0, 8> HD_BLK_GY_DATA; - typedef UReg<0x01, 0x54, 0, 8> HD_BLK_BU_DATA; - typedef UReg<0x01, 0x55, 0, 8> HD_BLK_RV_DATA; - - // Mode Detect - typedef UReg<0x01, 0x60, 0, 5> MD_HPERIOD_LOCK_VALUE; - typedef UReg<0x01, 0x60, 5, 3> MD_HPERIOD_UNLOCK_VALUE; - typedef UReg<0x01, 0x61, 0, 5> MD_VPERIOD_LOCK_VALUE; - typedef UReg<0x01, 0x61, 5, 3> MD_VPERIOD_UNLOCK_VALUE; - typedef UReg<0x01, 0x63, 6, 1> MD_HS_FLIP; - typedef UReg<0x01, 0x63, 7, 1> MD_VS_FLIP; - typedef UReg<0x01, 0x65, 0, 7> MD_VGA_CNTRL; - typedef UReg<0x01, 0x65, 7, 1> MD_SEL_VGA60; - typedef UReg<0x01, 0x66, 0, 8> MD_VGA_75HZ_CNTRL; - typedef UReg<0x01, 0x67, 0, 8> MD_VGA_85HZ_CNTRL; - typedef UReg<0x01, 0x6A, 0, 8> MD_SVGA_60HZ_CNTRL; - typedef UReg<0x01, 0x6B, 0, 8> MD_SVGA_75HZ_CNTRL; - typedef UReg<0x01, 0x6C, 0, 8> MD_SVGA_85HZ_CNTRL; - typedef UReg<0x01, 0x6E, 0, 8> MD_XGA_60HZ_CNTRL; - typedef UReg<0x01, 0x6F, 0, 7> MD_XGA_70HZ_CNTRL; - typedef UReg<0x01, 0x70, 0, 7> MD_XGA_75HZ_CNTRL; - typedef UReg<0x01, 0x71, 0, 7> MD_XGA_85HZ_CNTRL; - typedef UReg<0x01, 0x73, 0, 7> MD_SXGA_60HZ_CNTRL; - typedef UReg<0x01, 0x74, 0, 7> MD_SXGA_75HZ_CNTRL; - typedef UReg<0x01, 0x75, 0, 7> MD_SXGA_85HZ_CNTRL; - typedef UReg<0x01, 0x7F, 0, 7> MD_HD1250P_CNTRL; // changed to meaning 24khz - - // Deinterlacer / Scaledown registers - typedef UReg<0x02, 0x00, 0, 8> DEINT_00; - typedef UReg<0x02, 0x00, 7, 1> DIAG_BOB_PLDY_RAM_BYPS; - typedef UReg<0x02, 0x02, 6, 1> MADPT_Y_VSCALE_BYPS; - typedef UReg<0x02, 0x02, 7, 1> MADPT_UV_VSCALE_BYPS; - typedef UReg<0x02, 0x0A, 5, 1> MADPT_STILL_NOISE_EST_EN; - typedef UReg<0x02, 0x0A, 7, 1> MADPT_Y_MI_DET_BYPS; - typedef UReg<0x02, 0x0B, 0, 7> MADPT_Y_MI_OFFSET; - typedef UReg<0x02, 0x0C, 4, 1> MADPT_MI_1BIT_BYPS; - typedef UReg<0x02, 0x0C, 5, 1> MADPT_MI_1BIT_FRAME2_EN; - typedef UReg<0x02, 0x16, 5, 1> MADPT_MO_ADP_UV_EN; - typedef UReg<0x02, 0x16, 6, 1> MADPT_VT_FILTER_CNTRL; - typedef UReg<0x02, 0x16, 7, 1> MAPDT_VT_SEL_PRGV; - typedef UReg<0x02, 0x17, 0, 8> MADPT_Y_DELAY_UV_DELAY; // convenience - typedef UReg<0x02, 0x17, 0, 4> MADPT_Y_DELAY; - typedef UReg<0x02, 0x17, 4, 4> MADPT_UV_DELAY; - typedef UReg<0x02, 0x18, 3, 1> MADPT_HTAP_BYPS; - typedef UReg<0x02, 0x19, 0, 1> MADPT_BIT_STILL_EN; - typedef UReg<0x02, 0x19, 2, 1> MADPT_VTAP2_BYPS; - typedef UReg<0x02, 0x19, 3, 1> MADPT_VTAP2_ROUND_SEL; - typedef UReg<0x02, 0x19, 4, 4> MADPT_VTAP2_COEFF; - typedef UReg<0x02, 0x21, 4, 1> MADPT_EN_NOUT_FOR_STILL; - typedef UReg<0x02, 0x21, 5, 1> MADPT_EN_NOUT_FOR_LESS_STILL; - typedef UReg<0x02, 0x24, 2, 1> MADPT_PD_RAM_BYPS; - typedef UReg<0x02, 0x26, 6, 1> MADPT_VIIR_BYPS; - typedef UReg<0x02, 0x27, 0, 7> MADPT_VIIR_COEF; - typedef UReg<0x02, 0x31, 0, 2> MADPT_VSCALE_DEC_FACTOR; - typedef UReg<0x02, 0x31, 2, 1> MADPT_SEL_PHASE_INI; - typedef UReg<0x02, 0x35, 3, 1> MADPT_DD0_SEL; - typedef UReg<0x02, 0x35, 4, 1> MADPT_NRD_VIIR_PD_BYPS; - typedef UReg<0x02, 0x35, 5, 1> MADPT_UVDLY_PD_BYPS; - typedef UReg<0x02, 0x35, 6, 1> MADPT_CMP_EN; - typedef UReg<0x02, 0x39, 0, 4> MADPT_UVDLY_PD_SP; - typedef UReg<0x02, 0x39, 4, 4> MADPT_UVDLY_PD_ST; - typedef UReg<0x02, 0x3a, 0, 1> MADPT_EN_UV_DEINT; - typedef UReg<0x02, 0x3a, 3, 1> MADPT_EN_STILL_FOR_NRD; - typedef UReg<0x02, 0x3a, 5, 2> MADPT_MI_1BIT_DLY; - typedef UReg<0x02, 0x3a, 7, 1> MADPT_UV_MI_DET_BYPS; - typedef UReg<0x02, 0x3b, 0, 7> MADPT_UV_MI_OFFSET; - - // VDS Registers - typedef UReg<0x03, 0x00, 0, 1> VDS_SYNC_EN; - typedef UReg<0x03, 0x00, 1, 1> VDS_FIELDAB_EN; - typedef UReg<0x03, 0x00, 2, 1> VDS_DFIELD_EN; - typedef UReg<0x03, 0x00, 3, 1> VDS_FIELD_FLIP; - typedef UReg<0x03, 0x00, 4, 1> VDS_HSCALE_BYPS; - typedef UReg<0x03, 0x00, 5, 1> VDS_VSCALE_BYPS; - typedef UReg<0x03, 0x00, 6, 1> VDS_HALF_EN; - typedef UReg<0x03, 0x00, 7, 1> VDS_SRESET; - typedef UReg<0x03, 0x01, 0, 12> VDS_HSYNC_RST; - typedef UReg<0x03, 0x02, 4, 11> VDS_VSYNC_RST; - typedef UReg<0x03, 0x04, 0, 12> VDS_HB_ST; - typedef UReg<0x03, 0x05, 4, 12> VDS_HB_SP; - typedef UReg<0x03, 0x07, 0, 11> VDS_VB_ST; - typedef UReg<0x03, 0x08, 4, 11> VDS_VB_SP; - typedef UReg<0x03, 0x0A, 0, 12> VDS_HS_ST; - typedef UReg<0x03, 0x0B, 4, 12> VDS_HS_SP; - typedef UReg<0x03, 0x0D, 0, 11> VDS_VS_ST; - typedef UReg<0x03, 0x0E, 4, 11> VDS_VS_SP; - typedef UReg<0x03, 0x10, 0, 12> VDS_DIS_HB_ST; - typedef UReg<0x03, 0x11, 4, 12> VDS_DIS_HB_SP; - typedef UReg<0x03, 0x13, 0, 11> VDS_DIS_VB_ST; - typedef UReg<0x03, 0x14, 4, 11> VDS_DIS_VB_SP; - typedef UReg<0x03, 0x16, 0, 10> VDS_HSCALE; - typedef UReg<0x03, 0x17, 4, 10> VDS_VSCALE; - typedef UReg<0x03, 0x19, 0, 10> VDS_FRAME_RST; - typedef UReg<0x03, 0x1A, 4, 1> VDS_FLOCK_EN; - typedef UReg<0x03, 0x1A, 5, 1> VDS_FREERUN_FID; - typedef UReg<0x03, 0x1A, 6, 1> VDS_FID_AA_DLY; - typedef UReg<0x03, 0x1A, 7, 1> VDS_FID_RST; - - typedef UReg<0x03, 0x1B, 0, 32> VDS_FR_SELECT; - typedef UReg<0x03, 0x1F, 0, 4> VDS_FRAME_NO; - typedef UReg<0x03, 0x1F, 4, 1> VDS_DIF_FR_SEL_EN; - typedef UReg<0x03, 0x1F, 5, 1> VDS_EN_FR_NUM_RST; - typedef UReg<0x03, 0x20, 0, 11> VDS_VSYN_SIZE1; - typedef UReg<0x03, 0x22, 0, 11> VDS_VSYN_SIZE2; - typedef UReg<0x03, 0x24, 0, 8> VDS_3_24; // convenience - typedef UReg<0x03, 0x24, 0, 1> VDS_UV_FLIP; - typedef UReg<0x03, 0x24, 1, 1> VDS_U_DELAY; - typedef UReg<0x03, 0x24, 2, 1> VDS_V_DELAY; - typedef UReg<0x03, 0x24, 3, 1> VDS_TAP6_BYPS; - typedef UReg<0x03, 0x24, 4, 2> VDS_Y_DELAY; - typedef UReg<0x03, 0x24, 6, 2> VDS_WEN_DELAY; - typedef UReg<0x03, 0x25, 0, 10> VDS_D_SP; - typedef UReg<0x03, 0x26, 6, 1> VDS_D_RAM_BYPS; - typedef UReg<0x03, 0x26, 7, 1> VDS_BLEV_AUTO_EN; - typedef UReg<0x03, 0x27, 0, 4> VDS_USER_MIN; - typedef UReg<0x03, 0x27, 4, 4> VDS_USER_MAX; - typedef UReg<0x03, 0x28, 0, 8> VDS_BLEV_LEVEL; - typedef UReg<0x03, 0x29, 0, 8> VDS_BLEV_GAIN; - typedef UReg<0x03, 0x2A, 0, 1> VDS_BLEV_BYPS; - typedef UReg<0x03, 0x2A, 4, 2> VDS_STEP_DLY_CNTRL; - typedef UReg<0x03, 0x2A, 6, 2> VDS_0X2A_RESERVED_2BITS; - typedef UReg<0x03, 0x2B, 0, 4> VDS_STEP_GAIN; - typedef UReg<0x03, 0x2B, 4, 3> VDS_STEP_CLIP; - typedef UReg<0x03, 0x2B, 7, 1> VDS_UV_STEP_BYPS; - - typedef UReg<0x03, 0x2C, 0, 8> VDS_SK_U_CENTER; - typedef UReg<0x03, 0x2D, 0, 8> VDS_SK_V_CENTER; - typedef UReg<0x03, 0x2E, 0, 8> VDS_SK_Y_LOW_TH; - typedef UReg<0x03, 0x2F, 0, 8> VDS_SK_Y_HIGH_TH; - typedef UReg<0x03, 0x30, 0, 8> VDS_SK_RANGE; - typedef UReg<0x03, 0x31, 0, 4> VDS_SK_GAIN; - typedef UReg<0x03, 0x31, 4, 1> VDS_SK_Y_EN; - typedef UReg<0x03, 0x31, 5, 1> VDS_SK_BYPS; - - typedef UReg<0x03, 0x32, 0, 2> VDS_SVM_BPF_CNTRL; - typedef UReg<0x03, 0x32, 2, 1> VDS_SVM_POL_FLIP; - typedef UReg<0x03, 0x32, 3, 1> VDS_SVM_2ND_BYPS; - typedef UReg<0x03, 0x32, 4, 3> VDS_SVM_VCLK_DELAY; - typedef UReg<0x03, 0x32, 7, 1> VDS_SVM_SIGMOID_BYPS; - typedef UReg<0x03, 0x33, 0, 8> VDS_SVM_GAIN; - typedef UReg<0x03, 0x34, 0, 8> VDS_SVM_OFFSET; - - typedef UReg<0x03, 0x35, 0, 8> VDS_Y_GAIN; - typedef UReg<0x03, 0x36, 0, 8> VDS_UCOS_GAIN; - typedef UReg<0x03, 0x37, 0, 8> VDS_VCOS_GAIN; - typedef UReg<0x03, 0x38, 0, 8> VDS_USIN_GAIN; - typedef UReg<0x03, 0x39, 0, 8> VDS_VSIN_GAIN; - typedef UReg<0x03, 0x3A, 0, 8> VDS_Y_OFST; - typedef UReg<0x03, 0x3B, 0, 8> VDS_U_OFST; - typedef UReg<0x03, 0x3C, 0, 8> VDS_V_OFST; - - typedef UReg<0x03, 0x3D, 0, 9> VDS_SYNC_LEV; - typedef UReg<0x03, 0x3E, 3, 1> VDS_CONVT_BYPS; - typedef UReg<0x03, 0x3E, 4, 1> VDS_DYN_BYPS; - typedef UReg<0x03, 0x3E, 7, 1> VDS_BLK_BF_EN; - typedef UReg<0x03, 0x3F, 0, 8> VDS_UV_BLK_VAL; - typedef UReg<0x03, 0x40, 0, 1> VDS_1ST_INT_BYPS; - typedef UReg<0x03, 0x40, 1, 1> VDS_2ND_INT_BYPS; - typedef UReg<0x03, 0x40, 2, 1> VDS_IN_DREG_BYPS; - typedef UReg<0x03, 0x40, 4, 2> VDS_SVM_V4CLK_DELAY; - - typedef UReg<0x03, 0x41, 0, 10> VDS_PK_LINE_BUF_SP; - typedef UReg<0x03, 0x42, 6, 1> VDS_PK_RAM_BYPS; - typedef UReg<0x03, 0x43, 0, 1> VDS_PK_VL_HL_SEL; - typedef UReg<0x03, 0x43, 1, 1> VDS_PK_VL_HH_SEL; - typedef UReg<0x03, 0x43, 2, 1> VDS_PK_VH_HL_SEL; - typedef UReg<0x03, 0x43, 3, 1> VDS_PK_VH_HH_SEL; - typedef UReg<0x03, 0x44, 0, 3> VDS_PK_LB_CORE; - typedef UReg<0x03, 0x44, 3, 5> VDS_PK_LB_CMP; - typedef UReg<0x03, 0x45, 0, 6> VDS_PK_LB_GAIN; - typedef UReg<0x03, 0x46, 0, 3> VDS_PK_LH_CORE; - typedef UReg<0x03, 0x46, 3, 5> VDS_PK_LH_CMP; - typedef UReg<0x03, 0x47, 0, 6> VDS_PK_LH_GAIN; - typedef UReg<0x03, 0x48, 0, 3> VDS_PK_HL_CORE; - typedef UReg<0x03, 0x48, 3, 5> VDS_PK_HL_CMP; - typedef UReg<0x03, 0x49, 0, 6> VDS_PK_HL_GAIN; - typedef UReg<0x03, 0x4A, 0, 3> VDS_PK_HB_CORE; - typedef UReg<0x03, 0x4A, 3, 5> VDS_PK_HB_CMP; - typedef UReg<0x03, 0x4B, 0, 6> VDS_PK_HB_GAIN; - typedef UReg<0x03, 0x4C, 0, 3> VDS_PK_HH_CORE; - typedef UReg<0x03, 0x4C, 3, 5> VDS_PK_HH_CMP; - typedef UReg<0x03, 0x4D, 0, 6> VDS_PK_HH_GAIN; - typedef UReg<0x03, 0x4E, 0, 1> VDS_PK_Y_H_BYPS; - typedef UReg<0x03, 0x4E, 1, 1> VDS_PK_Y_V_BYPS; - typedef UReg<0x03, 0x4E, 3, 1> VDS_C_VPK_BYPS; - typedef UReg<0x03, 0x4E, 4, 3> VDS_C_VPK_CORE; - typedef UReg<0x03, 0x4F, 0, 6> VDS_C_VPK_GAIN; - - typedef UReg<0x03, 0x50, 0, 4> VDS_TEST_BUS_SEL; - typedef UReg<0x03, 0x50, 4, 1> VDS_TEST_EN; - typedef UReg<0x03, 0x50, 5, 1> VDS_DO_UV_DEV_BYPS; - typedef UReg<0x03, 0x50, 6, 1> VDS_DO_UVSEL_FLIP; - typedef UReg<0x03, 0x50, 7, 1> VDS_DO_16B_EN; - - typedef UReg<0x03, 0x51, 7, 11> VDS_GLB_NOISE; - typedef UReg<0x03, 0x52, 4, 1> VDS_NR_Y_BYPS; - typedef UReg<0x03, 0x52, 5, 1> VDS_NR_C_BYPS; - typedef UReg<0x03, 0x52, 6, 1> VDS_NR_DIF_LPF5_BYPS; - typedef UReg<0x03, 0x52, 7, 1> VDS_NR_MI_TH_EN; - typedef UReg<0x03, 0x53, 0, 7> VDS_NR_MI_OFFSET; - typedef UReg<0x03, 0x53, 7, 1> VDS_NR_MIG_USER_EN; - typedef UReg<0x03, 0x54, 0, 4> VDS_NR_MI_GAIN; - typedef UReg<0x03, 0x54, 4, 4> VDS_NR_STILL_GAIN; - typedef UReg<0x03, 0x55, 0, 4> VDS_NR_MI_THRES; - typedef UReg<0x03, 0x55, 4, 1> VDS_NR_EN_H_NOISY; - typedef UReg<0x03, 0x55, 6, 1> VDS_NR_EN_GLB_STILL; - typedef UReg<0x03, 0x55, 7, 1> VDS_NR_GLB_STILL_MENU; - typedef UReg<0x03, 0x56, 0, 7> VDS_NR_NOISY_OFFSET; - typedef UReg<0x03, 0x56, 7, 1> VDS_W_LEV_BYPS; - typedef UReg<0x03, 0x57, 0, 8> VDS_W_LEV; - typedef UReg<0x03, 0x58, 0, 8> VDS_WLEV_GAIN; - typedef UReg<0x03, 0x59, 0, 8> VDS_NS_U_CENTER; - typedef UReg<0x03, 0x5A, 0, 8> VDS_NS_V_CENTER; - typedef UReg<0x03, 0x5B, 0, 7> VDS_NS_U_GAIN; - typedef UReg<0x03, 0x5B, 7, 15> VDS_NS_SQUARE_RAD; - typedef UReg<0x03, 0x5D, 6, 8> VDS_NS_Y_HIGH_TH; - typedef UReg<0x03, 0x5E, 6, 7> VDS_NS_V_GAIN; - typedef UReg<0x03, 0x5F, 5, 5> VDS_NS_Y_LOW_TH; - typedef UReg<0x03, 0x60, 2, 1> VDS_NS_BYPS; - typedef UReg<0x03, 0x60, 3, 1> VDS_NS_Y_ACTIVE_EN; - - typedef UReg<0x03, 0x60, 4, 10> VDS_C1_TAG_LOW_SLOPE; - typedef UReg<0x03, 0x61, 6, 10> VDS_C1_TAG_HIGH_SLOPE; - typedef UReg<0x03, 0x63, 0, 4> VDS_C1_GAIN; - typedef UReg<0x03, 0x63, 4, 8> VDS_C1_U_LOW; - typedef UReg<0x03, 0x64, 4, 8> VDS_C1_U_HIGH; - typedef UReg<0x03, 0x65, 4, 1> VDS_C1_BYPS; - typedef UReg<0x03, 0x65, 5, 8> VDS_C1_Y_THRESH; - - typedef UReg<0x03, 0x66, 5, 10> VDS_C2_TAG_LOW_SLOPE; - typedef UReg<0x03, 0x67, 7, 10> VDS_C2_TAG_HIGH_SLOPE; - typedef UReg<0x03, 0x69, 1, 4> VDS_C2_GAIN; - typedef UReg<0x03, 0x69, 5, 8> VDS_C2_U_LOW; - typedef UReg<0x03, 0x6A, 5, 8> VDS_C2_U_HIGH; - typedef UReg<0x03, 0x6B, 5, 1> VDS_C2_BYPS; - typedef UReg<0x03, 0x6B, 6, 8> VDS_C2_Y_THRESH; - - typedef UReg<0x03, 0x6D, 0, 12> VDS_EXT_HB_ST; - typedef UReg<0x03, 0x6E, 4, 12> VDS_EXT_HB_SP; - typedef UReg<0x03, 0x70, 0, 11> VDS_EXT_VB_ST; - typedef UReg<0x03, 0x71, 4, 11> VDS_EXT_VB_SP; - typedef UReg<0x03, 0x72, 7, 1> VDS_SYNC_IN_SEL; - - typedef UReg<0x03, 0x73, 0, 3> VDS_BLUE_RANGE; - typedef UReg<0x03, 0x73, 3, 1> VDS_BLUE_BYPS; - typedef UReg<0x03, 0x73, 4, 4> VDS_BLUE_UGAIN; - typedef UReg<0x03, 0x74, 0, 4> VDS_BLUE_VGAIN; - typedef UReg<0x03, 0x74, 4, 4> VDS_BLUE_Y_LEV; - - // PIP Registers - typedef UReg<0x03, 0x80, 0, 1> PIP_UV_FLIP; - typedef UReg<0x03, 0x80, 1, 1> PIP_U_DELAY; - typedef UReg<0x03, 0x80, 2, 1> PIP_V_DELAY; - typedef UReg<0x03, 0x80, 3, 1> PIP_TAP3_BYPS; - typedef UReg<0x03, 0x80, 4, 2> PIP_Y_DELAY; - typedef UReg<0x03, 0x80, 6, 1> PIP_SUB_16B_SEL; - typedef UReg<0x03, 0x80, 7, 1> PIP_DYN_BYPS; - typedef UReg<0x03, 0x81, 0, 1> PIP_CONVT_BYPS; - typedef UReg<0x03, 0x81, 3, 1> PIP_DREG_BYPS; - typedef UReg<0x03, 0x81, 7, 1> PIP_EN; - typedef UReg<0x03, 0x82, 0, 8> PIP_Y_GAIN; - typedef UReg<0x03, 0x83, 0, 8> PIP_U_GAIN; - typedef UReg<0x03, 0x84, 0, 8> PIP_V_GAIN; - typedef UReg<0x03, 0x85, 0, 8> PIP_Y_OFST; - typedef UReg<0x03, 0x86, 0, 8> PIP_U_OFST; - typedef UReg<0x03, 0x87, 0, 8> PIP_V_OFST; - typedef UReg<0x03, 0x88, 0, 12> PIP_H_ST; - typedef UReg<0x03, 0x8A, 0, 12> PIP_H_SP; - typedef UReg<0x03, 0x8C, 0, 11> PIP_V_ST; - typedef UReg<0x03, 0x8E, 0, 11> PIP_V_SP; - - // Memory Controller Registers - typedef UReg<0x04, 0x00, 0, 8> SDRAM_RESET_CONTROL; // fake name - typedef UReg<0x04, 0x00, 4, 1> SDRAM_RESET_SIGNAL; - typedef UReg<0x04, 0x00, 7, 1> SDRAM_START_INITIAL_CYCLE; - typedef UReg<0x04, 0x12, 0, 1> MEM_INTER_DLYCELL_SEL; - typedef UReg<0x04, 0x12, 1, 1> MEM_CLK_DLYCELL_SEL; - typedef UReg<0x04, 0x12, 2, 1> MEM_FBK_CLK_DLYCELL_SEL; - typedef UReg<0x04, 0x13, 0, 1> MEM_PAD_CLK_INVERT; - typedef UReg<0x04, 0x13, 1, 1> MEM_RD_DATA_CLK_INVERT; - typedef UReg<0x04, 0x13, 2, 1> MEM_FBK_CLK_INVERT; - typedef UReg<0x04, 0x15, 0, 1> MEM_REQ_PBH_RFFH; - typedef UReg<0x04, 0x1b, 0, 3> MEM_ADR_DLY_REG; - typedef UReg<0x04, 0x1b, 4, 3> MEM_CLK_DLY_REG; - - // Playback / Capture / Memory Registers - typedef UReg<0x04, 0x21, 0, 1> CAPTURE_ENABLE; - typedef UReg<0x04, 0x21, 1, 1> CAP_FF_HALF_REQ; - typedef UReg<0x04, 0x21, 5, 1> CAP_SAFE_GUARD_EN; - typedef UReg<0x04, 0x22, 0, 1> CAP_REQ_OVER; - typedef UReg<0x04, 0x22, 1, 1> CAP_STATUS_SEL; - typedef UReg<0x04, 0x22, 3, 1> CAP_REQ_FREEZ; - typedef UReg<0x04, 0x24, 0, 21> CAP_SAFE_GUARD_A; - typedef UReg<0x04, 0x27, 0, 21> CAP_SAFE_GUARD_B; - typedef UReg<0x04, 0x2b, 0, 1> PB_CUT_REFRESH; - typedef UReg<0x04, 0x2b, 1, 2> PB_REQ_SEL; - typedef UReg<0x04, 0x2b, 3, 1> PB_BYPASS; - typedef UReg<0x04, 0x2b, 5, 1> PB_DB_BUFFER_EN; - typedef UReg<0x04, 0x2b, 7, 1> PB_ENABLE; - typedef UReg<0x04, 0x2c, 0, 8> PB_MAST_FLAG_REG; - typedef UReg<0x04, 0x2d, 0, 8> PB_GENERAL_FLAG_REG; - typedef UReg<0x04, 0x37, 0, 10> PB_CAP_OFFSET; - typedef UReg<0x04, 0x39, 0, 10> PB_FETCH_NUM; - typedef UReg<0x04, 0x42, 0, 1> WFF_ENABLE; - typedef UReg<0x04, 0x42, 2, 1> WFF_FF_STA_INV; - typedef UReg<0x04, 0x42, 3, 1> WFF_SAFE_GUARD; - typedef UReg<0x04, 0x42, 5, 1> WFF_ADR_ADD_2; - typedef UReg<0x04, 0x42, 7, 1> WFF_FF_STATUS_SEL; - typedef UReg<0x04, 0x44, 0, 21> WFF_SAFE_GUARD_A; - typedef UReg<0x04, 0x47, 0, 21> WFF_SAFE_GUARD_B; - typedef UReg<0x04, 0x4a, 0, 1> WFF_YUV_DEINTERLACE; - typedef UReg<0x04, 0x4a, 4, 1> WFF_LINE_FLIP; - typedef UReg<0x04, 0x4b, 0, 3> WFF_HB_DELAY; - typedef UReg<0x04, 0x4b, 4, 3> WFF_VB_DELAY; - typedef UReg<0x04, 0x4d, 4, 1> RFF_ADR_ADD_2; - typedef UReg<0x04, 0x4d, 5, 2> RFF_REQ_SEL; - typedef UReg<0x04, 0x4d, 7, 1> RFF_ENABLE; - typedef UReg<0x04, 0x4e, 0, 8> RFF_MASTER_FLAG; - typedef UReg<0x04, 0x50, 5, 1> RFF_LINE_FLIP; - typedef UReg<0x04, 0x50, 6, 1> RFF_YUV_DEINTERLACE; - typedef UReg<0x04, 0x50, 7, 1> RFF_LREQ_CUT; - typedef UReg<0x04, 0x51, 0, 21> RFF_WFF_STA_ADDR_A; - typedef UReg<0x04, 0x54, 0, 21> RFF_WFF_STA_ADDR_B; - typedef UReg<0x04, 0x57, 0, 10> RFF_WFF_OFFSET; - typedef UReg<0x04, 0x59, 0, 10> RFF_FETCH_NUM; - typedef UReg<0x04, 0x5B, 7, 1> MEM_FF_TOP_FF_SEL; - - // OSD Registers - typedef UReg<0x00, 0x90, 0, 1> OSD_SW_RESET; - typedef UReg<0x00, 0x90, 1, 3> OSD_HORIZONTAL_ZOOM; - typedef UReg<0x00, 0x90, 4, 2> OSD_VERTICAL_ZOOM; - typedef UReg<0x00, 0x90, 6, 1> OSD_DISP_EN; - typedef UReg<0x00, 0x90, 7, 1> OSD_MENU_EN; - typedef UReg<0x00, 0x91, 0, 4> OSD_MENU_ICON_SEL; - typedef UReg<0x00, 0x91, 4, 4> OSD_MENU_MOD_SEL; - typedef UReg<0x00, 0x92, 0, 3> OSD_MENU_BAR_FONT_FORCOR; - typedef UReg<0x00, 0x92, 3, 3> OSD_MENU_BAR_FONT_BGCOR; - typedef UReg<0x00, 0x92, 6, 3> OSD_MENU_BAR_BORD_COR; - typedef UReg<0x00, 0x93, 1, 3> OSD_MENU_SEL_FORCOR; - typedef UReg<0x00, 0x93, 4, 3> OSD_MENU_SEL_BGCOR; - typedef UReg<0x00, 0x93, 7, 1> OSD_COMMAND_FINISH; - typedef UReg<0x00, 0x94, 0, 1> OSD_MENU_DISP_STYLE; - typedef UReg<0x00, 0x94, 2, 1> OSD_YCBCR_RGB_FORMAT; - typedef UReg<0x00, 0x94, 3, 1> OSD_INT_NG_LAT; - typedef UReg<0x00, 0x94, 4, 4> OSD_TEST_SEL; - typedef UReg<0x00, 0x95, 0, 8> OSD_MENU_HORI_START; - typedef UReg<0x00, 0x96, 0, 8> OSD_MENU_VER_START; - typedef UReg<0x00, 0x97, 0, 8> OSD_BAR_LENGTH; - typedef UReg<0x00, 0x98, 0, 8> OSD_BAR_FOREGROUND_VALUE; - - // ADC, SP Registers - typedef UReg<0x05, 0x00, 0, 8> ADC_5_00; // convenience - typedef UReg<0x05, 0x00, 0, 2> ADC_CLK_PA; - typedef UReg<0x05, 0x00, 3, 1> ADC_CLK_ICLK2X; - typedef UReg<0x05, 0x00, 4, 1> ADC_CLK_ICLK1X; - typedef UReg<0x05, 0x02, 0, 1> ADC_SOGEN; - typedef UReg<0x05, 0x02, 1, 5> ADC_SOGCTRL; - typedef UReg<0x05, 0x02, 6, 2> ADC_INPUT_SEL; - typedef UReg<0x05, 0x03, 0, 8> ADC_5_03; // convenience - typedef UReg<0x05, 0x03, 0, 1> ADC_POWDZ; - typedef UReg<0x05, 0x03, 1, 1> ADC_RYSEL_R; - typedef UReg<0x05, 0x03, 2, 1> ADC_RYSEL_G; - typedef UReg<0x05, 0x03, 3, 1> ADC_RYSEL_B; - typedef UReg<0x05, 0x03, 4, 2> ADC_FLTR; - typedef UReg<0x05, 0x04, 0, 8> ADC_TEST_04; - typedef UReg<0x05, 0x04, 0, 2> ADC_TR_RSEL; - typedef UReg<0x05, 0x04, 1, 1> ADC_TR_RSEL_04_BIT1; - typedef UReg<0x05, 0x04, 2, 3> ADC_TR_ISEL; - typedef UReg<0x05, 0x05, 0, 1> ADC_TA_05_EN; - typedef UReg<0x05, 0x05, 0, 8> ADC_TA_05_CTRL; - typedef UReg<0x05, 0x06, 0, 8> ADC_ROFCTRL; - typedef UReg<0x05, 0x07, 0, 8> ADC_GOFCTRL; - typedef UReg<0x05, 0x08, 0, 8> ADC_BOFCTRL; - typedef UReg<0x05, 0x09, 0, 8> ADC_RGCTRL; - typedef UReg<0x05, 0x0A, 0, 8> ADC_GGCTRL; - typedef UReg<0x05, 0x0B, 0, 8> ADC_BGCTRL; - typedef UReg<0x05, 0x0C, 0, 8> ADC_TEST_0C; - typedef UReg<0x05, 0x0C, 1, 1> ADC_TEST_0C_BIT1; - typedef UReg<0x05, 0x0C, 3, 1> ADC_TEST_0C_BIT3; - typedef UReg<0x05, 0x0C, 4, 1> ADC_TEST_0C_BIT4; - typedef UReg<0x05, 0x0E, 0, 1> ADC_AUTO_OFST_EN; - typedef UReg<0x05, 0x0E, 1, 1> ADC_AUTO_OFST_PRD; - typedef UReg<0x05, 0x0E, 2, 2> ADC_AUTO_OFST_DELAY; - typedef UReg<0x05, 0x0E, 4, 2> ADC_AUTO_OFST_STEP; - typedef UReg<0x05, 0x0E, 7, 1> ADC_AUTO_OFST_TEST; - typedef UReg<0x05, 0x0F, 0, 8> ADC_AUTO_OFST_RANGE_REG; - typedef UReg<0x05, 0x11, 0, 8> PLLAD_CONTROL_00_5x11; // fake name - typedef UReg<0x05, 0x11, 0, 1> PLLAD_VCORST; - typedef UReg<0x05, 0x11, 1, 1> PLLAD_LEN; - typedef UReg<0x05, 0x11, 2, 1> PLLAD_TEST; - typedef UReg<0x05, 0x11, 3, 1> PLLAD_TS; - typedef UReg<0x05, 0x11, 4, 1> PLLAD_PDZ; - typedef UReg<0x05, 0x11, 5, 1> PLLAD_FS; - typedef UReg<0x05, 0x11, 6, 1> PLLAD_BPS; - typedef UReg<0x05, 0x11, 7, 1> PLLAD_LAT; - typedef UReg<0x05, 0x12, 0, 12> PLLAD_MD; - typedef UReg<0x05, 0x16, 0, 8> PLLAD_5_16; // fake name - typedef UReg<0x05, 0x16, 0, 2> PLLAD_R; - typedef UReg<0x05, 0x16, 2, 2> PLLAD_S; - typedef UReg<0x05, 0x16, 4, 2> PLLAD_KS; - typedef UReg<0x05, 0x16, 6, 2> PLLAD_CKOS; - typedef UReg<0x05, 0x17, 0, 3> PLLAD_ICP; - typedef UReg<0x05, 0x18, 0, 1> PA_ADC_BYPSZ; - typedef UReg<0x05, 0x18, 1, 5> PA_ADC_S; - typedef UReg<0x05, 0x18, 6, 1> PA_ADC_LOCKOFF; - typedef UReg<0x05, 0x18, 7, 1> PA_ADC_LAT; - typedef UReg<0x05, 0x19, 0, 1> PA_SP_BYPSZ; - typedef UReg<0x05, 0x19, 1, 5> PA_SP_S; - typedef UReg<0x05, 0x19, 6, 1> PA_SP_LOCKOFF; - typedef UReg<0x05, 0x19, 7, 1> PA_SP_LAT; - typedef UReg<0x05, 0x1E, 7, 1> DEC_WEN_MODE; - typedef UReg<0x05, 0x1F, 0, 8> DEC_5_1F; // convenience - typedef UReg<0x05, 0x1F, 0, 1> DEC1_BYPS; - typedef UReg<0x05, 0x1F, 1, 1> DEC2_BYPS; - typedef UReg<0x05, 0x1F, 2, 1> DEC_MATRIX_BYPS; - typedef UReg<0x05, 0x1F, 3, 1> DEC_TEST_ENABLE; // fake name - typedef UReg<0x05, 0x1F, 4, 3> DEC_TEST_SEL; - typedef UReg<0x05, 0x1F, 7, 1> DEC_IDREG_EN; - typedef UReg<0x05, 0x20, 0, 1> SP_SOG_SRC_SEL; - typedef UReg<0x05, 0x20, 1, 1> SP_SOG_P_ATO; - typedef UReg<0x05, 0x20, 2, 1> SP_SOG_P_INV; - typedef UReg<0x05, 0x20, 3, 1> SP_EXT_SYNC_SEL; - typedef UReg<0x05, 0x20, 4, 1> SP_JITTER_SYNC; - typedef UReg<0x05, 0x26, 0, 12> SP_SYNC_PD_THD; - typedef UReg<0x05, 0x33, 0, 8> SP_H_TIMER_VAL; - typedef UReg<0x05, 0x35, 0, 12> SP_DLT_REG; - typedef UReg<0x05, 0x37, 0, 8> SP_H_PULSE_IGNOR; - typedef UReg<0x05, 0x38, 0, 8> SP_PRE_COAST; - typedef UReg<0x05, 0x39, 0, 8> SP_POST_COAST; - typedef UReg<0x05, 0x3A, 0, 8> SP_H_TOTAL_EQ_THD; - typedef UReg<0x05, 0x3B, 0, 3> SP_SDCS_VSST_REG_H; - typedef UReg<0x05, 0x3B, 4, 3> SP_SDCS_VSSP_REG_H; - typedef UReg<0x05, 0x3E, 0, 8> SP_CS_0x3E; // fake name - typedef UReg<0x05, 0x3E, 0, 1> SP_CS_P_SWAP; - typedef UReg<0x05, 0x3E, 1, 1> SP_HD_MODE; - typedef UReg<0x05, 0x3E, 2, 1> SP_H_COAST; - typedef UReg<0x05, 0x3E, 4, 1> SP_H_PROTECT; - typedef UReg<0x05, 0x3E, 5, 1> SP_DIS_SUB_COAST; - typedef UReg<0x05, 0x3F, 0, 8> SP_SDCS_VSST_REG_L; - typedef UReg<0x05, 0x40, 0, 8> SP_SDCS_VSSP_REG_L; - typedef UReg<0x05, 0x41, 0, 12> SP_CS_CLP_ST; - typedef UReg<0x05, 0x43, 0, 12> SP_CS_CLP_SP; - typedef UReg<0x05, 0x45, 0, 12> SP_CS_HS_ST; - typedef UReg<0x05, 0x47, 0, 12> SP_CS_HS_SP; - typedef UReg<0x05, 0x49, 0, 12> SP_RT_HS_ST; - typedef UReg<0x05, 0x4B, 0, 12> SP_RT_HS_SP; - typedef UReg<0x05, 0x4D, 0, 12> SP_H_CST_ST; - typedef UReg<0x05, 0x4F, 0, 12> SP_H_CST_SP; - typedef UReg<0x05, 0x55, 4, 1> SP_HS_POL_ATO; - typedef UReg<0x05, 0x55, 6, 1> SP_VS_POL_ATO; - typedef UReg<0x05, 0x55, 7, 1> SP_HCST_AUTO_EN; - typedef UReg<0x05, 0x56, 0, 8> SP_5_56; // convenience - typedef UReg<0x05, 0x56, 0, 1> SP_SOG_MODE; - typedef UReg<0x05, 0x56, 1, 1> SP_HS2PLL_INV_REG; - typedef UReg<0x05, 0x56, 2, 1> SP_CLAMP_MANUAL; - typedef UReg<0x05, 0x56, 3, 1> SP_CLP_SRC_SEL; - typedef UReg<0x05, 0x56, 4, 1> SP_SYNC_BYPS; - typedef UReg<0x05, 0x56, 5, 1> SP_HS_PROC_INV_REG; - typedef UReg<0x05, 0x56, 6, 1> SP_VS_PROC_INV_REG; - typedef UReg<0x05, 0x56, 7, 1> SP_CLAMP_INV_REG; - typedef UReg<0x05, 0x57, 0, 8> SP_5_57; // convenience - typedef UReg<0x05, 0x57, 0, 1> SP_NO_CLAMP_REG; - typedef UReg<0x05, 0x57, 1, 1> SP_COAST_INV_REG; - typedef UReg<0x05, 0x57, 2, 1> SP_NO_COAST_REG; - typedef UReg<0x05, 0x57, 6, 1> SP_HS_LOOP_SEL; - typedef UReg<0x05, 0x57, 7, 1> SP_HS_REG; - typedef UReg<0x05, 0x60, 0, 8> ADC_UNUSED_60; - typedef UReg<0x05, 0x61, 0, 8> ADC_UNUSED_61; - typedef UReg<0x05, 0x62, 0, 8> ADC_UNUSED_62; - typedef UReg<0x05, 0x63, 0, 8> TEST_BUS_SP_SEL; - typedef UReg<0x05, 0x64, 0, 8> ADC_UNUSED_64; - typedef UReg<0x05, 0x65, 0, 8> ADC_UNUSED_65; - typedef UReg<0x05, 0x66, 0, 8> ADC_UNUSED_66; - typedef UReg<0x05, 0x67, 0, 16> ADC_UNUSED_67; // + ADC_UNUSED_68; - typedef UReg<0x05, 0x69, 0, 8> ADC_UNUSED_69; - - typedef UReg<0x05, 0xD0, 0, 32> VERYWIDEDUMMYREG; - - static const uint8_t OSD_ZOOM_1X = 0; - static const uint8_t OSD_ZOOM_2X = 1; - static const uint8_t OSD_ZOOM_3X = 2; - static const uint8_t OSD_ZOOM_4X = 3; - static const uint8_t OSD_ZOOM_5X = 4; - static const uint8_t OSD_ZOOM_6X = 5; - static const uint8_t OSD_ZOOM_7X = 6; - static const uint8_t OSD_ZOOM_8X = 7; - - static const uint8_t OSD_MENU_DISP_STYLE_VERTICAL = 0; - static const uint8_t OSD_MENU_DISP_STYLE_HORIZONTAL = 1; - - static const uint8_t OSD_ICON_NONE = 0; - static const uint8_t OSD_ICON_BRIGHTNESS = 1; - static const uint8_t OSD_ICON_CONTRAST = 2; - static const uint8_t OSD_ICON_HUE = 3; - static const uint8_t OSD_ICON_SOUND = 4; - static const uint8_t OSD_ICON_UP_DOWN = 8; - static const uint8_t OSD_ICON_LEFT_RIGHT = 9; - static const uint8_t OSD_ICON_VERTICAL_SIZE = 10; - static const uint8_t OSD_ICON_HORIZONTAL_SIZE = 11; - static const uint8_t OSD_ICON_COUNT = 8; - - static inline uint8_t osdIcon(uint8_t index) - { - static const uint8_t osdIcons[8] = { - OSD_ICON_BRIGHTNESS, - OSD_ICON_CONTRAST, - OSD_ICON_HUE, - OSD_ICON_SOUND, - OSD_ICON_UP_DOWN, - OSD_ICON_LEFT_RIGHT, - OSD_ICON_VERTICAL_SIZE, - OSD_ICON_HORIZONTAL_SIZE, - }; - return osdIcons[index]; - } - - static const uint8_t OSD_COLOR_BLACK = 0; - static const uint8_t OSD_COLOR_BLUE = 1; - static const uint8_t OSD_COLOR_GREEN = 2; - static const uint8_t OSD_COLOR_CYAN = 3; - static const uint8_t OSD_COLOR_RED = 4; - static const uint8_t OSD_COLOR_MAGENTA = 5; - static const uint8_t OSD_COLOR_YELLOW = 6; - static const uint8_t OSD_COLOR_WHITE = 7; - - static const uint8_t OSD_FORMAT_YCBCR = 1; - static const uint8_t OSD_FORMAT_RGB = 0; -}; - -#endif diff --git a/webui.html b/webui.html deleted file mode 100644 index d0bc8f8d..00000000 --- a/webui.html +++ /dev/null @@ -1,3309 +0,0 @@ - - - - - GBS-Control - - - - - - - - - -
-
- - - - - - - -
-
-
-
- -
aspect_ratio
-
Resolution
-
- -
    -
  • Choose an output resolution from these presets.
  • -
  • Your selection will also be used for startup. 1280x960 is recommended for NTSC sources, 1280x1024 for PAL. -
  • -
  • Use the "Matched Presets" option to switch between the two automatically (Preferences tab) -
  • -
  • Selecting a resolution also makes it the new startup preset.
  • -
-
- - - - - - - -
-
-
- -
input
-
Presets
-
- -
    -
  • If you want to save your customizations, first select a slot for your new preset, then save to or load from that slot.
  • -
  • Selecting a slot also makes it the new startup preset.
  • -
-
-
- - - -
-
-
- - - - - - - - - - - -
-
- -
code
-
Output
-
-
- -
-
- -
-
-
-
-
-
-
- -
- - - diff --git a/webui_html.h b/webui_html.h deleted file mode 100644 index 0ea97405..00000000 --- a/webui_html.h +++ /dev/null @@ -1,14199 +0,0 @@ -const uint8_t webui_html[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x08, 0xe5, 0xc0, 0xf4, 0x64, 0x02, 0x03, 0x77, 0x65, - 0x62, 0x75, 0x69, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0xbc, 0xfd, 0x6d, - 0xb3, 0xab, 0xba, 0x96, 0x2e, 0x08, 0x7e, 0xcf, 0x5f, 0xb1, 0xfb, 0x54, - 0x74, 0x44, 0xc7, 0x5d, 0x79, 0x62, 0xf2, 0x62, 0x3c, 0xa7, 0xf3, 0xe5, - 0x46, 0x1b, 0x83, 0xc0, 0xd8, 0xc8, 0x13, 0x81, 0x24, 0xd0, 0x37, 0x40, - 0x5e, 0xc6, 0x20, 0x30, 0xb6, 0xb1, 0x8d, 0xa9, 0xe8, 0xff, 0xde, 0x83, - 0xb5, 0xf7, 0x39, 0x79, 0xf2, 0x46, 0xde, 0x5b, 0x55, 0xd1, 0xd5, 0x7b, - 0xaf, 0x58, 0x7b, 0xce, 0x65, 0x63, 0x84, 0xa4, 0x31, 0x9e, 0x17, 0x90, - 0x86, 0xff, 0xed, 0xff, 0xe1, 0x1c, 0x36, 0x49, 0xf6, 0xed, 0xfe, 0x56, - 0x0d, 0xad, 0xfa, 0xef, 0xff, 0xf4, 0x6f, 0xf3, 0x8f, 0xdf, 0x54, 0xde, - 0x9d, 0xfe, 0xfd, 0x2f, 0xc7, 0xee, 0x2f, 0xff, 0xfd, 0x9f, 0x7e, 0xfb, - 0xed, 0xdf, 0xaa, 0x63, 0x2e, 0xe7, 0x5f, 0xe0, 0xd7, 0xf6, 0x38, 0xe4, - 0xbf, 0x95, 0x55, 0x7e, 0xbb, 0x1f, 0x87, 0x7f, 0xff, 0x0b, 0x4d, 0xd0, - 0x5f, 0xbf, 0xfe, 0xf2, 0xdb, 0xc7, 0x1f, 0x6f, 0x0e, 0xe7, 0x41, 0x1d, - 0xff, 0xbb, 0x67, 0xc7, 0x7f, 0xdd, 0x5c, 0xba, 0xe1, 0x76, 0x51, 0xff, - 0xf6, 0xf1, 0xfb, 0x4b, 0xbf, 0xbf, 0xad, 0xce, 0x5d, 0xf3, 0xdb, 0xed, - 0xa8, 0xfe, 0xfd, 0x2f, 0x6d, 0xde, 0x9d, 0x7f, 0x1e, 0xef, 0xc3, 0x5f, - 0x7e, 0xab, 0x6e, 0xc7, 0x9f, 0xff, 0xfe, 0x17, 0x99, 0x0f, 0xf9, 0xbf, - 0xe4, 0x7d, 0xaf, 0xce, 0x65, 0x3e, 0x9c, 0x2f, 0xdd, 0x47, 0x7d, 0xbf, - 0x74, 0xff, 0x5a, 0xe4, 0xf7, 0xe3, 0x72, 0xf1, 0xcf, 0xc7, 0xd7, 0xe5, - 0xb4, 0xdd, 0x04, 0x53, 0xee, 0xad, 0xde, 0x12, 0xad, 0x1e, 0x19, 0xd7, - 0xd5, 0xb6, 0x86, 0xd7, 0x1a, 0xb9, 0xa1, 0x1a, 0x7e, 0x16, 0x1d, 0x79, - 0x17, 0xc6, 0xeb, 0xbc, 0x5f, 0xff, 0x3a, 0xee, 0xff, 0xe8, 0xfd, 0x7b, - 0xc6, 0xad, 0xee, 0xd7, 0xfb, 0x2d, 0x7b, 0x6c, 0xcf, 0xaf, 0xdd, 0x76, - 0xb3, 0x3e, 0x0b, 0x8f, 0x4d, 0x99, 0x19, 0xf4, 0xa5, 0x4f, 0xfa, 0xc2, - 0x58, 0x9c, 0x0f, 0xe7, 0xf5, 0x99, 0x68, 0x41, 0x12, 0x19, 0xab, 0x87, - 0xf4, 0x83, 0x67, 0xb1, 0xb1, 0x63, 0xc1, 0xf5, 0xa7, 0xf4, 0xe8, 0xdf, - 0xce, 0x73, 0xce, 0x38, 0xbe, 0x09, 0x33, 0x78, 0x4a, 0x6e, 0x35, 0xa9, - 0x01, 0xed, 0xc0, 0xf5, 0xfd, 0x3a, 0xef, 0x39, 0x7c, 0x87, 0xce, 0xf6, - 0x15, 0xd6, 0xeb, 0xbf, 0x1d, 0xab, 0xe5, 0x1e, 0x1b, 0x04, 0x5b, 0xd5, - 0x85, 0x31, 0x3e, 0xcb, 0xf3, 0x76, 0xb9, 0xdd, 0x6c, 0xeb, 0xd0, 0xb1, - 0xeb, 0xd0, 0x13, 0xe7, 0xff, 0xb8, 0x06, 0xf5, 0xfb, 0xe7, 0xdb, 0x51, - 0x83, 0x63, 0xee, 0x9b, 0xf3, 0x1a, 0x7e, 0x27, 0x7d, 0x69, 0xda, 0xf7, - 0x2c, 0x6d, 0x7e, 0x5d, 0x93, 0xe8, 0xd8, 0xbd, 0xf0, 0x71, 0x5d, 0xb6, - 0x4c, 0x15, 0x7f, 0x3f, 0x66, 0xf5, 0xce, 0x39, 0x7b, 0x48, 0x0f, 0x69, - 0x39, 0x5f, 0x3d, 0x7e, 0x9d, 0xa3, 0xb3, 0x9f, 0x25, 0xf4, 0x3b, 0xe3, - 0x4a, 0xdb, 0xa7, 0x36, 0xbc, 0xaf, 0x57, 0x65, 0xd7, 0xfc, 0xed, 0x7a, - 0x5e, 0xf0, 0xf9, 0x56, 0xa4, 0xc1, 0x4f, 0xf8, 0x09, 0xe7, 0x26, 0x4a, - 0xa0, 0x55, 0x55, 0xfa, 0xf6, 0x3d, 0xe7, 0xb8, 0x92, 0x9e, 0x82, 0x31, - 0x0b, 0xa1, 0x3d, 0xbb, 0xcd, 0xf8, 0x38, 0x89, 0xf8, 0xf7, 0xeb, 0x83, - 0xf7, 0xfe, 0xf6, 0x7a, 0xf1, 0xab, 0xdd, 0x8d, 0xfd, 0xf9, 0xfb, 0xcf, - 0xf5, 0xaf, 0xf9, 0x29, 0xdb, 0xf0, 0xf7, 0x6b, 0x84, 0xeb, 0xc8, 0x92, - 0xbe, 0x2f, 0x38, 0xea, 0x44, 0xbc, 0x7a, 0x15, 0x6d, 0xf9, 0x99, 0xb5, - 0x68, 0x12, 0x49, 0xa6, 0xed, 0x3d, 0xc5, 0xa3, 0x66, 0x15, 0xcb, 0xc9, - 0xde, 0x13, 0x43, 0x3e, 0x23, 0x8a, 0xec, 0x88, 0x5a, 0x09, 0xe3, 0x15, - 0x62, 0x5c, 0xc2, 0xef, 0x41, 0x48, 0xe7, 0xd7, 0x58, 0xf8, 0x8a, 0x34, - 0x84, 0x7f, 0xbd, 0xdf, 0xac, 0x2e, 0x19, 0x95, 0xf1, 0xaf, 0xdf, 0x59, - 0x33, 0x46, 0x8d, 0xce, 0x09, 0xa3, 0xfa, 0xd1, 0xcb, 0x16, 0xf0, 0x5a, - 0xc7, 0x68, 0xe0, 0x1c, 0x5d, 0xc6, 0x19, 0x95, 0x4f, 0xe1, 0x6d, 0xf5, - 0x38, 0x45, 0x43, 0x69, 0xdc, 0x47, 0x19, 0xaf, 0x02, 0xe2, 0x8a, 0x4b, - 0xe8, 0xf5, 0x97, 0x18, 0xda, 0x4b, 0x18, 0xc3, 0xa1, 0x29, 0xa3, 0x5c, - 0x93, 0x01, 0x35, 0xe5, 0x90, 0xb7, 0x41, 0x27, 0xcd, 0x40, 0x27, 0x94, - 0xf8, 0x39, 0x43, 0x87, 0xa4, 0x1d, 0x6a, 0x8e, 0xd4, 0xf6, 0xe0, 0xf7, - 0x9a, 0x48, 0x31, 0x67, 0x7a, 0x25, 0xa8, 0x0a, 0xee, 0x30, 0x47, 0x0d, - 0x4e, 0xf1, 0x3e, 0x41, 0xc4, 0x94, 0xe9, 0xda, 0xca, 0x8d, 0x20, 0x2f, - 0x74, 0xa5, 0x15, 0x93, 0x22, 0x31, 0xed, 0xaf, 0x34, 0xc5, 0x8f, 0x83, - 0x53, 0x41, 0x3c, 0xac, 0x26, 0xca, 0xd6, 0x23, 0xe5, 0x55, 0x1b, 0x6b, - 0x3a, 0x65, 0xae, 0x24, 0x30, 0xdf, 0xd0, 0x87, 0xd5, 0x77, 0xe8, 0x30, - 0x18, 0x07, 0x3d, 0x4f, 0x34, 0xe8, 0x03, 0x1f, 0x6f, 0xa1, 0x37, 0x22, - 0xca, 0x44, 0x8c, 0x9d, 0x40, 0x3f, 0x36, 0x41, 0xf7, 0xab, 0xcf, 0x14, - 0x39, 0x11, 0x5f, 0x45, 0x61, 0x67, 0x7b, 0xb8, 0x1d, 0x9c, 0xdf, 0xc7, - 0xe6, 0xff, 0xef, 0x7f, 0x7d, 0xe2, 0x6c, 0x35, 0xf2, 0x1f, 0xff, 0xc6, - 0xf9, 0x79, 0xa5, 0xd1, 0x46, 0x30, 0xa6, 0x04, 0xff, 0x13, 0xfe, 0x0a, - 0x96, 0xa8, 0xef, 0xa8, 0xf9, 0x7b, 0xfb, 0x51, 0x7c, 0x5e, 0x9d, 0x29, - 0x0b, 0xf8, 0x9f, 0xd4, 0x7e, 0x4a, 0x98, 0xed, 0x0a, 0xfd, 0x8f, 0xf6, - 0xb9, 0x8c, 0x8e, 0x9e, 0xf0, 0x43, 0x57, 0xfc, 0x59, 0xed, 0x37, 0x39, - 0x25, 0xb6, 0xd4, 0xd8, 0x1f, 0xfd, 0x57, 0xd1, 0x5e, 0xaf, 0xe2, 0xc2, - 0xfd, 0x93, 0xfa, 0xdf, 0x88, 0x36, 0x6b, 0x25, 0xf9, 0x7b, 0x3c, 0xa4, - 0x2a, 0xda, 0x4d, 0x08, 0x31, 0xf5, 0x27, 0xb5, 0xdf, 0x56, 0x34, 0x74, - 0x08, 0xfa, 0x7b, 0xfb, 0x49, 0xf5, 0x38, 0xa4, 0x64, 0x43, 0xd4, 0x9f, - 0x35, 0xfe, 0x8a, 0x1c, 0xdc, 0xd5, 0x26, 0xfa, 0x5b, 0xfe, 0xc5, 0x2b, - 0xef, 0xe0, 0x05, 0x84, 0xfd, 0x59, 0xed, 0xd7, 0x41, 0x90, 0xc0, 0xfc, - 0xff, 0x91, 0xff, 0xb6, 0x78, 0x7f, 0x59, 0xc2, 0x95, 0xec, 0x4f, 0xea, - 0x3f, 0x63, 0x2d, 0xd1, 0x0b, 0x63, 0xc6, 0x27, 0xfb, 0x19, 0x99, 0xc8, - 0x2e, 0x4c, 0x71, 0x11, 0x2c, 0x78, 0x96, 0x14, 0x91, 0x9c, 0xc9, 0x5b, - 0xd6, 0x35, 0xcf, 0xa3, 0xb7, 0x78, 0x53, 0x5a, 0x89, 0xb2, 0x0e, 0x5e, - 0x79, 0x22, 0xdf, 0xa5, 0x23, 0xe9, 0x4e, 0x93, 0x93, 0x40, 0xff, 0x13, - 0x4c, 0xd1, 0x1a, 0x2d, 0xe4, 0xab, 0x4b, 0xd9, 0x8a, 0x3b, 0x47, 0x68, - 0x99, 0x27, 0xe8, 0x1c, 0x69, 0xf8, 0x0d, 0x38, 0x9c, 0x92, 0xe4, 0xf4, - 0xce, 0x34, 0x52, 0xf1, 0x76, 0x4c, 0x69, 0x53, 0x31, 0xe2, 0xa1, 0xbc, - 0x40, 0x32, 0x8e, 0xf5, 0xde, 0xe3, 0x29, 0x12, 0xac, 0x1d, 0xd2, 0x82, - 0x05, 0x03, 0x31, 0x46, 0x8f, 0x37, 0xe2, 0x99, 0xeb, 0xfd, 0xbd, 0xd0, - 0x83, 0x81, 0xb6, 0x68, 0x57, 0x30, 0x91, 0x93, 0xd4, 0xbe, 0xb1, 0x56, - 0xbd, 0x72, 0xf8, 0x4c, 0xc6, 0x7a, 0x9f, 0x73, 0xc4, 0xe6, 0xcf, 0xe4, - 0xf0, 0x19, 0x66, 0x54, 0xfe, 0xfc, 0x99, 0x82, 0xf5, 0x3c, 0xd7, 0xf1, - 0x40, 0x95, 0xdc, 0x17, 0x14, 0x3e, 0xd3, 0xd9, 0x37, 0xde, 0x56, 0x2f, - 0xaa, 0x04, 0xdd, 0x6b, 0x2c, 0x8f, 0x5b, 0x7c, 0x98, 0xb1, 0x18, 0x3e, - 0x47, 0x43, 0xda, 0x0f, 0x49, 0x0d, 0xc1, 0xde, 0x92, 0x6b, 0x68, 0x68, - 0x6f, 0xae, 0xc4, 0x8d, 0x26, 0xe1, 0xeb, 0xe8, 0xbb, 0x66, 0xe1, 0x8d, - 0x8b, 0x22, 0xb1, 0xad, 0x58, 0x07, 0x3e, 0x6f, 0x87, 0x86, 0x18, 0x56, - 0x80, 0xb9, 0x0e, 0xed, 0x06, 0x43, 0xd4, 0x22, 0x38, 0x3f, 0x06, 0x8e, - 0xab, 0xd2, 0x5c, 0x0f, 0xe0, 0xe7, 0x78, 0x61, 0xc6, 0x2a, 0x86, 0x31, - 0x7b, 0x09, 0x5d, 0x3e, 0x79, 0x2b, 0xd3, 0xd2, 0x1b, 0x58, 0x61, 0xda, - 0x4f, 0xd6, 0xd9, 0x88, 0xa7, 0xf6, 0x8b, 0x33, 0x31, 0x42, 0x60, 0xdd, - 0x4b, 0xa6, 0xbc, 0x92, 0x4a, 0x41, 0x3a, 0x94, 0x93, 0x66, 0xd8, 0x67, - 0x54, 0x54, 0xb4, 0x91, 0xfb, 0x8c, 0x49, 0x2f, 0xe3, 0x95, 0x1f, 0xc3, - 0xb9, 0xe1, 0xfc, 0x97, 0x82, 0x06, 0x15, 0x8c, 0x45, 0x02, 0xdc, 0xbd, - 0xe0, 0x74, 0xf5, 0x60, 0xaa, 0x3a, 0xe7, 0x1d, 0x8b, 0x0e, 0xc9, 0x49, - 0x3b, 0x38, 0xd9, 0x2b, 0x37, 0xfa, 0x40, 0xba, 0xd5, 0x95, 0x99, 0x04, - 0xcb, 0x9a, 0x6a, 0x85, 0x0a, 0x17, 0xf0, 0xd3, 0xc0, 0x8e, 0x6c, 0x63, - 0x2a, 0xf5, 0xe4, 0xfd, 0x75, 0x13, 0xec, 0xa4, 0x0b, 0x4e, 0xaa, 0x8c, - 0x89, 0x2b, 0x33, 0xfa, 0x05, 0x5c, 0x9f, 0xce, 0x3d, 0x6b, 0x11, 0x9a, - 0xa5, 0x95, 0x35, 0x8b, 0x1b, 0x31, 0x91, 0x0a, 0xcf, 0x2b, 0x60, 0x40, - 0xba, 0xc8, 0xda, 0xc0, 0x60, 0xfe, 0xc9, 0xc2, 0xb5, 0x5d, 0xe7, 0x0d, - 0xd3, 0xb0, 0xb9, 0xd6, 0x99, 0xb6, 0x6a, 0xb2, 0xee, 0x72, 0xcb, 0xeb, - 0xf2, 0x75, 0x54, 0x41, 0x14, 0x3a, 0xeb, 0xa9, 0x9c, 0x70, 0x78, 0x40, - 0xe5, 0x8b, 0xf0, 0x1e, 0x49, 0x47, 0xc2, 0xeb, 0xd2, 0x28, 0x9d, 0x6c, - 0xa2, 0x89, 0x9a, 0x0e, 0x88, 0x2c, 0x77, 0x26, 0xbe, 0x63, 0x25, 0x61, - 0x2e, 0xab, 0xb1, 0x48, 0x21, 0xbf, 0x75, 0xb2, 0x2f, 0x4d, 0xf1, 0x4a, - 0xe8, 0x48, 0x93, 0x2e, 0x7c, 0x85, 0x66, 0x10, 0xc5, 0x9d, 0x9d, 0x42, - 0xff, 0xcf, 0xa4, 0xa9, 0x9a, 0xa4, 0x45, 0xa1, 0x4c, 0x81, 0x06, 0xea, - 0xe6, 0x19, 0xb5, 0xd8, 0x0d, 0xe1, 0xdc, 0x07, 0x3f, 0xd8, 0x48, 0x64, - 0x5f, 0x65, 0x0b, 0xd7, 0x67, 0x58, 0x0d, 0x33, 0xdd, 0x5b, 0x9e, 0xe0, - 0x3c, 0x6b, 0x23, 0x03, 0xfa, 0xd2, 0x15, 0x7c, 0x61, 0xf1, 0x96, 0x5a, - 0x99, 0xf1, 0xba, 0x25, 0x94, 0x99, 0x94, 0x92, 0x3d, 0x6d, 0x67, 0xdc, - 0x40, 0x1e, 0x51, 0x41, 0x9d, 0xd5, 0x5b, 0x6b, 0x3f, 0xa1, 0xef, 0x50, - 0x61, 0x5a, 0xfa, 0xd1, 0x3b, 0x9f, 0xb6, 0x46, 0xac, 0x55, 0x7d, 0x5c, - 0x13, 0x76, 0xf4, 0xb4, 0x45, 0x9e, 0xe2, 0x1d, 0x4d, 0x98, 0x38, 0xb6, - 0x62, 0x93, 0x19, 0x72, 0x22, 0x4d, 0x5f, 0x95, 0x94, 0x2d, 0x09, 0x5d, - 0x81, 0x64, 0xea, 0x8d, 0xa3, 0x8b, 0x0f, 0xc4, 0xb5, 0x42, 0xdc, 0x90, - 0x8e, 0x76, 0xf6, 0x46, 0xa0, 0x7e, 0x77, 0x4c, 0xd4, 0x32, 0x53, 0xcc, - 0x2a, 0xba, 0x60, 0x77, 0xa4, 0x03, 0x34, 0x2b, 0xde, 0xa2, 0x95, 0x4e, - 0x64, 0x12, 0x33, 0x32, 0xed, 0xd7, 0xb1, 0x85, 0x7e, 0x53, 0x35, 0x51, - 0x0f, 0xe6, 0x99, 0xaf, 0xfc, 0x8c, 0x65, 0x6f, 0x51, 0xaf, 0x5f, 0x39, - 0x1d, 0xf7, 0xac, 0xc9, 0x26, 0x92, 0xac, 0x6f, 0xd4, 0x00, 0x9d, 0x95, - 0xba, 0x46, 0xcc, 0x64, 0x1b, 0x4e, 0xa4, 0xce, 0x27, 0x52, 0x51, 0x33, - 0x80, 0x38, 0xc4, 0x2a, 0x31, 0x64, 0x57, 0x26, 0xe2, 0x89, 0xeb, 0x8a, - 0xb2, 0x74, 0xfb, 0xa2, 0xa6, 0xe0, 0xa5, 0x12, 0x7d, 0xa6, 0xb0, 0xc6, - 0xe8, 0xb0, 0x28, 0x40, 0x41, 0x91, 0x46, 0x77, 0x8b, 0x36, 0x38, 0x48, - 0xd0, 0x27, 0xa4, 0xfd, 0xa5, 0x3f, 0x6b, 0xe9, 0xf7, 0x7a, 0x82, 0x90, - 0x20, 0x6a, 0x3b, 0x52, 0x1f, 0x5d, 0x8e, 0x6c, 0xfd, 0xe4, 0x7e, 0x4f, - 0xe3, 0xf6, 0x3e, 0x15, 0x28, 0xba, 0xc5, 0xaa, 0x7a, 0xc5, 0x0a, 0xbf, - 0x12, 0x2e, 0x9e, 0x61, 0xfb, 0x32, 0xf3, 0x84, 0x70, 0x9c, 0xaa, 0x20, - 0x37, 0xab, 0xa4, 0xe4, 0xe4, 0x19, 0xa9, 0x80, 0x88, 0xb6, 0x32, 0x13, - 0x07, 0xbb, 0x98, 0x5a, 0x7d, 0xb1, 0xf9, 0xd2, 0x25, 0xc3, 0xde, 0x81, - 0x56, 0x3c, 0x4b, 0xf1, 0x1b, 0x5a, 0x57, 0x0c, 0xa1, 0x5b, 0xe9, 0x8a, - 0x8a, 0x25, 0x32, 0x91, 0x29, 0xd1, 0x89, 0x57, 0x35, 0x19, 0xb3, 0xbb, - 0xc4, 0x41, 0x35, 0x6d, 0x82, 0xb4, 0xf0, 0xc4, 0x83, 0x6a, 0xf2, 0x76, - 0x74, 0xec, 0x96, 0x40, 0x1e, 0x32, 0x83, 0x68, 0xa1, 0x57, 0xf5, 0x39, - 0xba, 0x68, 0xc2, 0x97, 0xd7, 0x6c, 0x82, 0x5c, 0x34, 0x59, 0x28, 0x7c, - 0xc8, 0xbf, 0xf7, 0xca, 0x87, 0x71, 0x1d, 0x21, 0xde, 0xaf, 0xb1, 0x4e, - 0x36, 0xa5, 0xde, 0x47, 0x58, 0xd3, 0x77, 0x22, 0xb5, 0x75, 0xee, 0x56, - 0x37, 0xd1, 0x5c, 0xc6, 0xc8, 0x74, 0xdf, 0x85, 0x23, 0x63, 0xca, 0x58, - 0xbe, 0x9f, 0x82, 0xc7, 0x91, 0x22, 0x18, 0x63, 0xb2, 0xc7, 0xcd, 0x0a, - 0x09, 0xb7, 0xef, 0xa5, 0x71, 0xbf, 0x25, 0xcd, 0x2a, 0x4b, 0x14, 0x0e, - 0x99, 0x8f, 0x93, 0x78, 0x92, 0x31, 0x07, 0x28, 0x4f, 0x78, 0xb3, 0xa0, - 0x7c, 0x7c, 0x95, 0x3a, 0xda, 0xee, 0xb5, 0xf0, 0x95, 0x6b, 0x54, 0xa7, - 0xda, 0xd6, 0xcc, 0x68, 0xd0, 0x10, 0xfe, 0x05, 0xf9, 0x0d, 0x2d, 0x37, - 0xb8, 0x3f, 0x20, 0xfc, 0x3a, 0x76, 0x38, 0x87, 0x76, 0x3b, 0xc0, 0x82, - 0x20, 0x4f, 0x5c, 0x93, 0xd7, 0x64, 0x7b, 0xac, 0xed, 0x29, 0xa4, 0x41, - 0x9a, 0x43, 0x7f, 0xa2, 0xb9, 0x3f, 0x28, 0xa8, 0x4a, 0xae, 0xda, 0xbd, - 0x86, 0xb9, 0x6c, 0x41, 0x0b, 0xa2, 0xca, 0x04, 0xad, 0x99, 0x52, 0x13, - 0xbd, 0x63, 0xc3, 0xca, 0x4a, 0xea, 0xbe, 0x93, 0x69, 0x3d, 0xe6, 0x49, - 0x05, 0xf9, 0x4f, 0x3c, 0xd0, 0x51, 0x96, 0x38, 0xdf, 0xf5, 0x4c, 0x07, - 0x6c, 0x83, 0x6b, 0x2d, 0x8d, 0x5e, 0x91, 0xd6, 0xd5, 0x0a, 0x84, 0xb3, - 0x9d, 0x41, 0x5c, 0xda, 0x05, 0x15, 0xd3, 0x04, 0xe4, 0x88, 0x9c, 0xa4, - 0xd6, 0x07, 0x21, 0xc2, 0xdf, 0xb2, 0x75, 0xcd, 0x68, 0x22, 0x5a, 0xdc, - 0x89, 0xfe, 0x90, 0x20, 0x1b, 0xda, 0x4a, 0xf3, 0x44, 0xe8, 0x09, 0xc3, - 0x01, 0x7b, 0x0f, 0x66, 0x89, 0x82, 0x04, 0x62, 0x23, 0xcb, 0x5d, 0xe1, - 0x64, 0x9a, 0xbc, 0x86, 0xca, 0x56, 0x99, 0x4e, 0xad, 0xd8, 0xab, 0x76, - 0x4c, 0xeb, 0x9d, 0xd2, 0x41, 0xd7, 0xb8, 0xab, 0xb6, 0x85, 0x13, 0x54, - 0xd8, 0x11, 0xd0, 0xe3, 0xf2, 0x25, 0xd3, 0x20, 0x2a, 0x18, 0x68, 0x09, - 0xa3, 0x4f, 0x4a, 0x98, 0x3b, 0xc8, 0xb1, 0x7b, 0xa8, 0x04, 0x78, 0x1f, - 0x79, 0x15, 0x89, 0xea, 0x33, 0xca, 0x32, 0xce, 0x5f, 0x93, 0xe0, 0x8b, - 0x09, 0x70, 0x70, 0x3a, 0x72, 0xe5, 0xb3, 0x09, 0x74, 0xb0, 0xa9, 0xda, - 0xd2, 0xa9, 0x06, 0xe2, 0x43, 0x7c, 0x24, 0xf8, 0xcc, 0x3a, 0x14, 0x86, - 0x8d, 0xc5, 0x89, 0xf1, 0xb5, 0x90, 0xae, 0x34, 0xcb, 0x16, 0xa5, 0xc5, - 0x66, 0x38, 0x17, 0x1c, 0x6f, 0x42, 0x57, 0xf2, 0x48, 0x01, 0xde, 0x79, - 0x3a, 0x0d, 0xdb, 0x31, 0x06, 0x6c, 0xce, 0x88, 0xe9, 0xbe, 0x68, 0x3b, - 0x4f, 0x8a, 0x6a, 0x04, 0x8c, 0xe1, 0xc1, 0x67, 0x2f, 0xd9, 0x05, 0x01, - 0xd5, 0x83, 0x73, 0xde, 0xac, 0x76, 0x98, 0xf6, 0xaf, 0x18, 0x55, 0x0c, - 0x72, 0x38, 0x4f, 0x12, 0xe5, 0x25, 0x90, 0x5b, 0x80, 0x6b, 0xaf, 0xdd, - 0x74, 0x7a, 0x72, 0xd6, 0xb3, 0x24, 0xb1, 0xdf, 0x85, 0xa9, 0xf4, 0xd0, - 0xd3, 0x43, 0xd0, 0xe4, 0xb4, 0x6c, 0xe4, 0xb6, 0x74, 0xab, 0x5c, 0xe8, - 0x22, 0xc3, 0x2e, 0xc1, 0xa5, 0xbe, 0x36, 0xb1, 0xc9, 0x02, 0x68, 0x73, - 0xd6, 0xe2, 0x46, 0x41, 0xd9, 0x20, 0x75, 0xd7, 0x22, 0x89, 0x98, 0x20, - 0x9d, 0x6b, 0xc8, 0x15, 0xbf, 0x9c, 0xaa, 0x86, 0xd1, 0xf1, 0x4d, 0x90, - 0x40, 0xc4, 0x40, 0x3c, 0x54, 0xfd, 0x23, 0x03, 0xa6, 0xc1, 0x1d, 0x02, - 0x0c, 0x62, 0x0d, 0x68, 0xad, 0x9c, 0xba, 0xc1, 0x23, 0x34, 0xc8, 0x23, - 0x49, 0x99, 0x81, 0x21, 0xb2, 0xca, 0x24, 0xa8, 0xcb, 0x04, 0x65, 0xb1, - 0x26, 0xdf, 0x82, 0x07, 0x77, 0xec, 0x2a, 0x33, 0x9c, 0xd4, 0x2e, 0x36, - 0xee, 0x66, 0x42, 0xab, 0x4b, 0x58, 0x83, 0x35, 0x55, 0x80, 0xac, 0x6e, - 0x68, 0x26, 0xda, 0xa8, 0x91, 0x56, 0x66, 0x07, 0x16, 0xec, 0x24, 0x0d, - 0x96, 0xb1, 0x91, 0xcd, 0xf9, 0xcf, 0x88, 0xdf, 0x4c, 0x72, 0xa2, 0x2f, - 0xdc, 0x55, 0xdf, 0xc4, 0x25, 0x08, 0x2b, 0x95, 0x03, 0x57, 0xf0, 0xc2, - 0xc5, 0x11, 0x4b, 0xd9, 0x1b, 0xb0, 0xc5, 0x4e, 0x5c, 0x15, 0x15, 0x86, - 0x7c, 0xd3, 0x94, 0x2d, 0xc5, 0x1c, 0xb3, 0xb4, 0x5c, 0x84, 0x7e, 0x05, - 0x2c, 0x8c, 0xb7, 0x40, 0x65, 0x3c, 0x34, 0xe4, 0x52, 0xd2, 0xf0, 0x55, - 0x34, 0x8a, 0x48, 0x6d, 0xab, 0x13, 0xf0, 0xaf, 0xf0, 0xda, 0xab, 0xe0, - 0xfd, 0xb7, 0x6c, 0xd8, 0x3b, 0xf1, 0x2c, 0x17, 0xbb, 0xaf, 0xa7, 0x34, - 0x51, 0xc8, 0x9b, 0xde, 0x85, 0x98, 0x6b, 0x0a, 0x8f, 0xa5, 0x25, 0x1d, - 0x2a, 0x9e, 0xc8, 0xee, 0x00, 0x79, 0x2b, 0x98, 0x3d, 0x1c, 0x13, 0xa4, - 0xc3, 0x71, 0x66, 0xcc, 0x07, 0x4e, 0x1d, 0xd9, 0x67, 0xc6, 0x40, 0x42, - 0xad, 0x7f, 0x65, 0x06, 0xcb, 0x19, 0x2b, 0x9f, 0xb9, 0xab, 0xce, 0x80, - 0x19, 0x0e, 0x6e, 0x46, 0x94, 0x77, 0x81, 0x5e, 0xa4, 0x52, 0x4b, 0x50, - 0x9f, 0x32, 0xca, 0x74, 0xc8, 0x10, 0x23, 0x4a, 0x45, 0x46, 0xdd, 0x11, - 0xc6, 0x5a, 0x7d, 0x53, 0x4e, 0x26, 0xd0, 0x64, 0x03, 0x46, 0xd1, 0x8b, - 0xe8, 0x99, 0xc5, 0xe3, 0x01, 0xb8, 0x34, 0x7b, 0xe6, 0x48, 0x2d, 0x99, - 0x16, 0x02, 0x56, 0x22, 0x02, 0x71, 0x02, 0xb8, 0x29, 0xb4, 0xd2, 0xd5, - 0x45, 0xac, 0xc8, 0x86, 0x7a, 0xb8, 0x17, 0x1d, 0xb9, 0x94, 0x8d, 0x45, - 0x80, 0xb3, 0xdc, 0xb2, 0xb9, 0x1b, 0x72, 0xf6, 0x68, 0x75, 0x90, 0x60, - 0xde, 0xef, 0xc3, 0x94, 0xb5, 0xa1, 0x6f, 0x3f, 0xf1, 0x54, 0x21, 0xee, - 0xc9, 0x1d, 0x70, 0xd9, 0xbb, 0x34, 0x74, 0xb3, 0xa4, 0x10, 0x47, 0xed, - 0xa8, 0x87, 0xa9, 0xed, 0xb2, 0xcd, 0x60, 0xcb, 0x66, 0x40, 0x59, 0x27, - 0xed, 0xa4, 0xb9, 0x9b, 0x11, 0xa5, 0xb7, 0x02, 0x58, 0xa9, 0x70, 0xf0, - 0x93, 0x36, 0xee, 0x3b, 0xf4, 0x83, 0x17, 0xd3, 0xa4, 0x81, 0xdd, 0xec, - 0x05, 0xd7, 0xf8, 0xe2, 0xa8, 0x17, 0x10, 0x4f, 0x35, 0x33, 0x74, 0xcc, - 0xf9, 0xd6, 0x24, 0x29, 0xf1, 0x63, 0xc0, 0x3f, 0x8c, 0x82, 0x05, 0xc4, - 0xda, 0x37, 0x60, 0xfc, 0xe1, 0x48, 0x2f, 0xba, 0x6c, 0x60, 0x3c, 0x26, - 0x85, 0x20, 0x06, 0xc6, 0x1d, 0x8c, 0x3b, 0xa5, 0xca, 0x26, 0x26, 0x21, - 0xb9, 0x66, 0xe5, 0x70, 0x7d, 0x0c, 0x73, 0x14, 0x94, 0xed, 0xea, 0x82, - 0x1b, 0x15, 0x62, 0x53, 0x3c, 0xe3, 0x76, 0xa5, 0xa2, 0xb4, 0x7a, 0xee, - 0xb5, 0xcc, 0xca, 0x79, 0xf3, 0x24, 0xe7, 0xe1, 0x8d, 0xf9, 0xf0, 0xca, - 0x12, 0x0a, 0x39, 0x11, 0x4d, 0x70, 0x4d, 0x99, 0xd4, 0x7b, 0x1d, 0xb0, - 0x18, 0xb0, 0x51, 0x0d, 0x19, 0x30, 0x56, 0xd9, 0x60, 0x24, 0x13, 0x84, - 0x8b, 0xa9, 0xda, 0x61, 0x6f, 0xb8, 0x64, 0x53, 0xa9, 0x49, 0xbf, 0xca, - 0x13, 0x8f, 0x74, 0x92, 0xa3, 0x3c, 0xd3, 0x2e, 0x0b, 0xc0, 0x10, 0x4d, - 0x76, 0x32, 0x17, 0xbc, 0x5a, 0x16, 0xda, 0x1d, 0x3c, 0xf9, 0x6a, 0x64, - 0x3e, 0xc4, 0x4d, 0x57, 0x0d, 0x30, 0x26, 0xdb, 0x9d, 0x09, 0xac, 0xa1, - 0x57, 0x1b, 0xe6, 0x92, 0x67, 0xe8, 0x86, 0xda, 0xde, 0x24, 0x31, 0x6f, - 0x24, 0xcc, 0xab, 0xf0, 0x0a, 0xa5, 0x9a, 0x03, 0x0a, 0x1a, 0xf0, 0xef, - 0x51, 0xce, 0xc4, 0x52, 0x9a, 0x7d, 0x22, 0xb9, 0xba, 0x42, 0xfc, 0x23, - 0x89, 0x84, 0x9f, 0x3b, 0xcc, 0xa6, 0x5d, 0x66, 0x32, 0xdd, 0xd5, 0xb0, - 0x21, 0x61, 0x32, 0x03, 0x47, 0x34, 0x43, 0x78, 0x6c, 0x4a, 0x4b, 0x6a, - 0x30, 0xaf, 0x7c, 0xcc, 0x32, 0xce, 0x58, 0xd1, 0x0a, 0x2c, 0x5b, 0xc5, - 0x70, 0xd3, 0x68, 0x54, 0x5b, 0xe9, 0x79, 0x1a, 0xec, 0x12, 0x24, 0x2b, - 0x66, 0xda, 0x57, 0x51, 0x93, 0x68, 0x67, 0xaa, 0x3a, 0x31, 0x03, 0x04, - 0xe7, 0x0b, 0x62, 0x17, 0x3f, 0xa4, 0x86, 0xb2, 0x63, 0x53, 0x75, 0x45, - 0x8a, 0x74, 0x40, 0x1a, 0xab, 0xf4, 0x56, 0x2a, 0xaf, 0x6d, 0xef, 0xd8, - 0x35, 0x8b, 0x38, 0xb1, 0x01, 0x37, 0x88, 0x83, 0xb5, 0xc1, 0x93, 0xee, - 0x38, 0xc6, 0x70, 0xdd, 0x49, 0x2b, 0x22, 0xce, 0x07, 0x8d, 0xb6, 0xaf, - 0xd7, 0x11, 0xad, 0x17, 0x3b, 0xe3, 0xf4, 0xa4, 0x9d, 0x3c, 0x84, 0x35, - 0xa1, 0xa5, 0xd6, 0x53, 0x36, 0x31, 0x51, 0xd2, 0x2a, 0x3a, 0x52, 0x6a, - 0xfc, 0x43, 0xfb, 0x89, 0x48, 0xc1, 0xc7, 0x3b, 0x41, 0x22, 0xfc, 0xcb, - 0x08, 0x9a, 0xf1, 0x99, 0xf8, 0xa7, 0x57, 0x5c, 0x57, 0xe7, 0x43, 0xc2, - 0xba, 0xac, 0x25, 0x77, 0x4e, 0xbf, 0x5e, 0x42, 0xd9, 0x67, 0xe2, 0x6a, - 0x66, 0x61, 0x30, 0xad, 0xac, 0x19, 0x05, 0x8f, 0x7f, 0x85, 0x31, 0x34, - 0x72, 0x76, 0x1a, 0x81, 0xbf, 0x88, 0x30, 0xac, 0x36, 0xd1, 0x56, 0xaf, - 0x9d, 0x31, 0x28, 0xea, 0x49, 0x5f, 0x70, 0xd9, 0x51, 0x8e, 0x62, 0x0a, - 0x73, 0x06, 0x9c, 0x1f, 0x24, 0x9a, 0xf2, 0x43, 0x24, 0x31, 0x60, 0xa5, - 0x91, 0xd0, 0x00, 0xf0, 0x5c, 0x04, 0x85, 0xa6, 0x40, 0xb7, 0x8d, 0xbb, - 0xbc, 0x66, 0x01, 0xae, 0xd9, 0x1b, 0x7b, 0xe3, 0x25, 0x6b, 0xfb, 0x09, - 0xbb, 0xab, 0x65, 0xd1, 0x84, 0x8b, 0xd0, 0x5d, 0x21, 0xd9, 0x9d, 0x16, - 0x84, 0xb2, 0xf3, 0x6e, 0x0a, 0x26, 0xc6, 0x44, 0x4b, 0x6b, 0x52, 0x81, - 0xd7, 0x4f, 0x80, 0x3b, 0x44, 0x4e, 0x33, 0xe0, 0x5b, 0x76, 0x0d, 0x59, - 0x69, 0xd1, 0xd4, 0x06, 0x6d, 0x33, 0x1c, 0x78, 0x93, 0x2d, 0xe8, 0x64, - 0x6b, 0xd4, 0x1b, 0x70, 0xec, 0x0b, 0x9b, 0x37, 0x80, 0xf5, 0x2e, 0xf4, - 0x7f, 0xf3, 0xb5, 0x38, 0xfa, 0x84, 0x86, 0x06, 0xbe, 0x62, 0x4d, 0x79, - 0xb9, 0x63, 0x1b, 0xc0, 0xa7, 0xcb, 0xdc, 0x64, 0xdf, 0xa0, 0xa5, 0x46, - 0xda, 0x8a, 0x1b, 0xcc, 0xf6, 0x37, 0xc4, 0x8b, 0x8a, 0xdb, 0x20, 0x4d, - 0x1a, 0xfd, 0x1b, 0x70, 0x19, 0xe7, 0x2e, 0xf0, 0x3f, 0x68, 0xe8, 0xd8, - 0xef, 0x9d, 0x82, 0x53, 0x13, 0xb4, 0xe6, 0x22, 0xa2, 0x9a, 0xc9, 0x5d, - 0xf1, 0x94, 0x8e, 0x32, 0x04, 0x1c, 0x7e, 0x4c, 0xa4, 0x4d, 0xb9, 0x14, - 0xbc, 0xb3, 0xb7, 0xac, 0x59, 0x3c, 0x49, 0x8a, 0xc2, 0x9d, 0xa6, 0x8d, - 0x45, 0xc7, 0xce, 0x61, 0x8d, 0x19, 0x31, 0x04, 0x89, 0xda, 0x6c, 0x91, - 0xbb, 0x72, 0xe6, 0xe7, 0x28, 0x44, 0x6a, 0x93, 0x77, 0x76, 0xce, 0x26, - 0x79, 0x4e, 0xb4, 0x61, 0x0b, 0xef, 0x8d, 0xd8, 0x5f, 0x1b, 0xb1, 0xab, - 0x20, 0x57, 0xb7, 0x8b, 0x42, 0x03, 0x4e, 0x01, 0xed, 0x20, 0x9c, 0xea, - 0x1b, 0x72, 0x71, 0x02, 0x3c, 0xbd, 0x60, 0x2f, 0x30, 0x25, 0xf0, 0x78, - 0xee, 0x57, 0x8b, 0x03, 0x1f, 0x77, 0x24, 0xc1, 0x55, 0xe8, 0x93, 0x1d, - 0x9b, 0xef, 0xcb, 0x74, 0xe5, 0xc8, 0x53, 0xf6, 0x28, 0x7d, 0x69, 0x01, - 0x6f, 0x57, 0xbb, 0x79, 0xae, 0xcd, 0x20, 0x63, 0x3e, 0x7a, 0xd0, 0x4e, - 0x34, 0xc7, 0xb6, 0xca, 0x0f, 0x9e, 0xb0, 0x41, 0xcf, 0x2c, 0x0b, 0x0a, - 0xbc, 0xc0, 0x2e, 0x06, 0x60, 0x9b, 0x4f, 0x9b, 0xc5, 0x48, 0x14, 0x33, - 0x40, 0x53, 0x78, 0x87, 0x54, 0x09, 0x59, 0x57, 0x87, 0xdc, 0xb3, 0xe2, - 0xd2, 0x08, 0x02, 0xec, 0xb3, 0x2b, 0xf6, 0x70, 0x13, 0x37, 0x03, 0x93, - 0xe7, 0xaf, 0x27, 0xf6, 0x15, 0x03, 0x5f, 0x52, 0xd1, 0x1a, 0x51, 0xe6, - 0x57, 0x7b, 0x3a, 0xe1, 0x3e, 0xa6, 0xc1, 0x3d, 0x4a, 0xf1, 0x55, 0xb8, - 0xd4, 0x10, 0x31, 0x78, 0x09, 0x70, 0xf7, 0xb9, 0x31, 0xa6, 0x45, 0x27, - 0xe2, 0x70, 0xb3, 0x8a, 0xc2, 0x06, 0x74, 0x7b, 0x0a, 0xf3, 0x5e, 0x93, - 0x59, 0xf5, 0xf5, 0x54, 0x35, 0xc0, 0x7d, 0xab, 0x45, 0xc9, 0xe8, 0x33, - 0x4b, 0x82, 0x33, 0x78, 0x93, 0x1d, 0x68, 0x18, 0x0d, 0xda, 0xdf, 0x33, - 0xc6, 0x40, 0x2f, 0x10, 0xc8, 0xf9, 0x31, 0x11, 0xc6, 0x18, 0x4b, 0x27, - 0xa0, 0x39, 0xa0, 0x03, 0xd5, 0xf4, 0x09, 0x33, 0x95, 0xe6, 0xad, 0x3b, - 0xc6, 0x08, 0xf2, 0x8d, 0xd1, 0x17, 0x68, 0x45, 0x11, 0x35, 0xf2, 0x46, - 0x3a, 0x81, 0x4a, 0x77, 0x8c, 0x78, 0x53, 0x21, 0x96, 0x84, 0x37, 0xc0, - 0x7d, 0x3f, 0xe7, 0x2a, 0x10, 0x14, 0xe2, 0x13, 0x62, 0x0f, 0xbf, 0x57, - 0x49, 0x9c, 0x8a, 0x3d, 0xd6, 0xbe, 0x0c, 0x52, 0x03, 0x0e, 0x69, 0x84, - 0x97, 0xb5, 0x68, 0x85, 0x6e, 0xbb, 0x07, 0x17, 0x78, 0xa7, 0x16, 0x58, - 0xe8, 0xa4, 0x15, 0x93, 0xba, 0xe6, 0xc0, 0x95, 0x39, 0xb7, 0xbc, 0x64, - 0xb2, 0x15, 0x68, 0xd3, 0x3b, 0xef, 0xc8, 0x9d, 0xb8, 0xab, 0x77, 0xde, - 0xaa, 0x07, 0x6b, 0xc8, 0x24, 0xbb, 0xcb, 0x3b, 0x53, 0x30, 0x9e, 0x7c, - 0xd0, 0x05, 0x5b, 0xeb, 0x1c, 0xfa, 0xc0, 0x5c, 0x98, 0xbb, 0x39, 0xd6, - 0xfc, 0xca, 0x10, 0x2e, 0x9c, 0x2b, 0xb5, 0x37, 0xdc, 0x97, 0x30, 0x36, - 0x08, 0xe2, 0x1a, 0x69, 0xa0, 0x2f, 0x62, 0x51, 0xe3, 0x8e, 0x37, 0x56, - 0x15, 0x6b, 0x8c, 0xf1, 0xf3, 0xfd, 0x26, 0x54, 0x85, 0x73, 0x13, 0xf1, - 0x92, 0x12, 0x4d, 0x80, 0xa4, 0xce, 0xdd, 0xaf, 0x17, 0xa7, 0xa3, 0xca, - 0x6a, 0xb5, 0xcd, 0x9a, 0x1e, 0xc7, 0x1d, 0x16, 0x22, 0xed, 0xb3, 0x84, - 0xd9, 0xbb, 0x23, 0x1f, 0xce, 0x79, 0x0a, 0x5c, 0x08, 0x6d, 0x94, 0x5c, - 0xe6, 0x00, 0x95, 0x1e, 0x71, 0x47, 0xd0, 0xb5, 0x56, 0x7c, 0x40, 0xe8, - 0x5a, 0xd6, 0x8d, 0x79, 0x88, 0x87, 0x99, 0x17, 0x9f, 0x19, 0x0f, 0x50, - 0x02, 0x63, 0x82, 0x3d, 0xa5, 0xcb, 0xb4, 0x02, 0xcd, 0xad, 0x1c, 0xe9, - 0xb9, 0xb7, 0xb8, 0xb1, 0x52, 0xd9, 0x35, 0x6f, 0xc6, 0xc7, 0x2b, 0xa6, - 0x7a, 0xc8, 0x3d, 0x05, 0xb6, 0x48, 0x45, 0x09, 0xc5, 0x4f, 0xac, 0x2a, - 0x1d, 0x62, 0xc2, 0x14, 0x46, 0x78, 0xe3, 0x3e, 0xfa, 0x16, 0x0e, 0xd6, - 0xc1, 0x97, 0x7a, 0x99, 0xde, 0xb3, 0x63, 0x22, 0xf0, 0x91, 0x55, 0x2f, - 0xac, 0xb3, 0x20, 0xf7, 0xc1, 0x1b, 0x19, 0xd5, 0x24, 0x93, 0x20, 0x8c, - 0xdb, 0x8a, 0x31, 0x2a, 0x7d, 0xea, 0x34, 0x26, 0xd5, 0x30, 0x0d, 0x41, - 0xdd, 0x96, 0x49, 0x36, 0x1d, 0xfd, 0x00, 0xf4, 0xb7, 0xd2, 0xa4, 0x06, - 0x78, 0x56, 0xdb, 0x8c, 0x3b, 0x6a, 0x57, 0x32, 0xb1, 0xa0, 0x74, 0x75, - 0x83, 0x9c, 0x05, 0xbf, 0xa7, 0x9e, 0xc4, 0x0c, 0xf6, 0xc4, 0x50, 0x09, - 0x4e, 0xed, 0x84, 0xfa, 0x01, 0xc9, 0x75, 0xd6, 0x46, 0x1a, 0xc4, 0x13, - 0x78, 0xd5, 0x58, 0x1b, 0x6d, 0x32, 0x05, 0x1d, 0x60, 0xa5, 0x41, 0x5d, - 0xb8, 0x1e, 0x88, 0x0f, 0xe1, 0x59, 0xaf, 0x03, 0x92, 0x6d, 0xa2, 0xa4, - 0x59, 0x50, 0xbc, 0x01, 0x5f, 0xda, 0x40, 0x44, 0x8c, 0x30, 0x76, 0x1d, - 0x68, 0xb3, 0x1b, 0x6d, 0xc8, 0x39, 0xf4, 0xfb, 0x4d, 0xc1, 0x07, 0x2f, - 0x76, 0x07, 0x5a, 0xa0, 0x0a, 0xae, 0x68, 0xb5, 0x08, 0xdb, 0x15, 0x68, - 0x77, 0x6c, 0x81, 0xe7, 0xa1, 0xf3, 0x98, 0xee, 0xf5, 0xed, 0x42, 0x4e, - 0x28, 0x8e, 0xdb, 0xcb, 0x33, 0x54, 0xd5, 0x15, 0x9f, 0xbf, 0x16, 0xe1, - 0x04, 0x28, 0xe2, 0x41, 0x16, 0x69, 0xaf, 0x97, 0x74, 0xfb, 0x65, 0xcc, - 0xab, 0x0b, 0xa7, 0x90, 0x53, 0x09, 0xbb, 0x27, 0x06, 0xe1, 0xb4, 0xae, - 0xb6, 0x10, 0x9b, 0x3a, 0x78, 0x3b, 0x55, 0x72, 0x36, 0x81, 0x7e, 0x20, - 0x91, 0x29, 0x46, 0xe6, 0x8a, 0x7d, 0x09, 0xf8, 0x9a, 0x4f, 0x8c, 0x1f, - 0x15, 0x6a, 0x32, 0x13, 0x11, 0x4c, 0xc5, 0x58, 0xb8, 0xae, 0xc5, 0xcf, - 0x03, 0x66, 0xcd, 0xeb, 0xc5, 0x5d, 0x6c, 0x12, 0xa3, 0x7f, 0xf1, 0x36, - 0xe8, 0x43, 0x77, 0xd4, 0x80, 0x73, 0x76, 0x80, 0x97, 0x26, 0xe7, 0x38, - 0x00, 0xfd, 0xff, 0xa2, 0x86, 0xb4, 0xe3, 0x9a, 0x6d, 0x98, 0x31, 0xdc, - 0x62, 0xa6, 0x5e, 0x91, 0xca, 0x34, 0xec, 0x90, 0x25, 0xd5, 0x94, 0x06, - 0x9a, 0x30, 0x67, 0xfa, 0x69, 0xa2, 0x46, 0x70, 0x03, 0xaf, 0x71, 0x2d, - 0x9b, 0xad, 0x9e, 0x53, 0xb9, 0x29, 0xdf, 0x2b, 0x87, 0xf2, 0x0c, 0xce, - 0x89, 0xe3, 0x82, 0x92, 0x7c, 0xaf, 0x03, 0x37, 0xb6, 0x52, 0x17, 0x3a, - 0xf2, 0x00, 0xef, 0xdc, 0x63, 0x2b, 0xe3, 0xd2, 0x9d, 0xbd, 0x01, 0x19, - 0x72, 0x55, 0x25, 0x99, 0xb9, 0x7d, 0x15, 0x8e, 0xb8, 0x70, 0x16, 0x6c, - 0x58, 0x57, 0x5d, 0x84, 0xc9, 0xd4, 0x51, 0xe1, 0x74, 0xa7, 0x2b, 0xb6, - 0xd7, 0x50, 0x7c, 0x60, 0x72, 0x71, 0xec, 0xec, 0x83, 0xd0, 0x82, 0x03, - 0xf8, 0x3b, 0x93, 0x82, 0x06, 0x2b, 0x13, 0x99, 0x1f, 0xbd, 0x51, 0x3f, - 0xa6, 0xc8, 0x95, 0x33, 0x16, 0xf9, 0xa0, 0x91, 0x37, 0xc3, 0x2b, 0x61, - 0xac, 0x8f, 0x0c, 0x10, 0x0b, 0x6d, 0x03, 0x1a, 0x3f, 0xd8, 0x1e, 0x41, - 0xdd, 0x83, 0x26, 0xd6, 0x48, 0x1a, 0xbe, 0x4a, 0x8d, 0xde, 0xc2, 0xa9, - 0x31, 0x0a, 0x17, 0x68, 0xcf, 0x60, 0x23, 0xa9, 0x51, 0x53, 0x68, 0xc3, - 0x52, 0x7a, 0x3a, 0x80, 0x90, 0x78, 0x11, 0x54, 0x5a, 0x07, 0x24, 0x1c, - 0x66, 0xbc, 0x0c, 0x82, 0xdc, 0x91, 0x72, 0xbd, 0x13, 0x9a, 0x00, 0x0e, - 0x50, 0x0d, 0xa9, 0xa3, 0xe9, 0x08, 0xfa, 0x83, 0x1a, 0x4a, 0x83, 0xcf, - 0x8d, 0x54, 0x97, 0x1a, 0x68, 0xc1, 0x3c, 0x37, 0x18, 0x68, 0x1c, 0xd0, - 0x24, 0xda, 0x62, 0x91, 0x41, 0x9e, 0xc0, 0x98, 0xf9, 0xd1, 0xe4, 0x1a, - 0x49, 0x22, 0x17, 0xb9, 0x52, 0x17, 0xc6, 0xbf, 0x80, 0xf3, 0xd9, 0x36, - 0xf6, 0x83, 0x06, 0xf8, 0x82, 0x94, 0x9d, 0xd8, 0x0a, 0xaf, 0x52, 0xc2, - 0x09, 0x2e, 0xb1, 0x31, 0x78, 0x19, 0x8b, 0x46, 0xc8, 0x72, 0x04, 0x1a, - 0x01, 0x7c, 0x01, 0x4e, 0xb1, 0xd6, 0x23, 0xa1, 0x37, 0xef, 0xa3, 0x27, - 0x96, 0xd8, 0xc7, 0x0f, 0x4e, 0xd1, 0x95, 0x36, 0x30, 0xa3, 0xd4, 0x02, - 0xad, 0x14, 0xea, 0x7b, 0x1d, 0x35, 0x25, 0x78, 0x8e, 0x98, 0xde, 0x5f, - 0xa0, 0xcf, 0xfc, 0x9d, 0xa6, 0xeb, 0x65, 0x1b, 0x8c, 0xa1, 0x91, 0x01, - 0xf6, 0x82, 0x4e, 0xd6, 0xb0, 0x8d, 0x13, 0x65, 0x4b, 0x27, 0xb3, 0x8e, - 0xe7, 0x55, 0x9f, 0xe8, 0xc2, 0x21, 0x09, 0x7b, 0x50, 0x27, 0x83, 0xfc, - 0x09, 0x6e, 0xa4, 0x45, 0x24, 0xe4, 0x16, 0xe8, 0x4a, 0xc9, 0xcb, 0x0e, - 0x9f, 0xa5, 0x63, 0xd7, 0xb2, 0xd5, 0xeb, 0x43, 0x9a, 0x2d, 0x42, 0x2f, - 0xbc, 0x95, 0x69, 0x04, 0x3e, 0xd6, 0x05, 0xcf, 0x5f, 0x29, 0xa6, 0x97, - 0x26, 0xe1, 0xc8, 0x4e, 0x14, 0x20, 0x37, 0x03, 0x1c, 0x68, 0x85, 0x4f, - 0x3a, 0xf2, 0x92, 0xe0, 0x51, 0x73, 0xd4, 0x27, 0x09, 0x6b, 0xde, 0x51, - 0x12, 0x80, 0x37, 0xc1, 0x9d, 0x04, 0x7d, 0x94, 0x20, 0x05, 0xca, 0x4a, - 0x4d, 0x9c, 0xd9, 0xe0, 0x01, 0x7b, 0x88, 0x15, 0x79, 0x4b, 0x66, 0x1c, - 0xf5, 0x46, 0x0f, 0x0c, 0xd9, 0x08, 0xbe, 0xd1, 0x22, 0x5c, 0xda, 0xbc, - 0x96, 0x96, 0xe4, 0x7a, 0x5d, 0xb6, 0xe4, 0xc9, 0xa0, 0x6f, 0x38, 0x11, - 0xa0, 0xa7, 0xad, 0xab, 0x98, 0x84, 0x9b, 0x34, 0x6a, 0xbf, 0xd7, 0xc0, - 0x51, 0x74, 0xfd, 0x8e, 0x73, 0xb2, 0xe1, 0x94, 0xd9, 0xb1, 0x51, 0x5d, - 0x49, 0xbb, 0xf2, 0xa3, 0x4e, 0x5e, 0x19, 0x47, 0xd7, 0xfd, 0xfb, 0xeb, - 0xc6, 0xba, 0x70, 0xe4, 0xee, 0x02, 0xae, 0x50, 0xdd, 0x0a, 0x5d, 0xdd, - 0x71, 0x5b, 0x2d, 0x41, 0x93, 0x1d, 0x8e, 0x1e, 0x70, 0x33, 0x0d, 0x28, - 0x9d, 0xb6, 0x0b, 0x88, 0xd4, 0x1d, 0xf8, 0xb7, 0x45, 0xce, 0xfa, 0x07, - 0xe0, 0xd7, 0x12, 0xe6, 0x33, 0x04, 0x8d, 0x93, 0x44, 0x10, 0x47, 0xa0, - 0xb7, 0xcd, 0xa8, 0xc9, 0xde, 0x59, 0x03, 0x5a, 0xb1, 0x0b, 0xee, 0xac, - 0x13, 0x5d, 0xd2, 0xf4, 0x3d, 0x56, 0x88, 0x27, 0x9e, 0xda, 0x94, 0x0e, - 0x69, 0x12, 0x4e, 0xe2, 0x78, 0xaa, 0x7a, 0xa2, 0xd6, 0x5a, 0xd1, 0x92, - 0x33, 0xe8, 0x6a, 0x2d, 0x9e, 0xf5, 0x05, 0xed, 0x0f, 0xe0, 0x76, 0xdf, - 0xd8, 0x94, 0x07, 0xe0, 0x82, 0x1b, 0xe8, 0xe3, 0x1d, 0x33, 0xe5, 0x3e, - 0x32, 0x86, 0x4d, 0x96, 0x54, 0xe0, 0x04, 0x84, 0x11, 0x99, 0xd5, 0xed, - 0xc8, 0x50, 0x90, 0x3b, 0xd1, 0xab, 0xd0, 0xed, 0x28, 0xd3, 0x83, 0x31, - 0x76, 0x22, 0x9d, 0x37, 0xe1, 0x8b, 0x6a, 0xe2, 0x19, 0xb5, 0xa5, 0x4e, - 0x98, 0x34, 0x92, 0xa9, 0xd1, 0x29, 0x62, 0x67, 0x6c, 0xe0, 0x79, 0x1c, - 0x75, 0xd1, 0x9e, 0x6e, 0x91, 0x26, 0x6c, 0xf0, 0xd5, 0x1e, 0x75, 0x4a, - 0x33, 0x47, 0xc2, 0x0b, 0x3d, 0xc0, 0x27, 0xaf, 0x22, 0xd2, 0x5d, 0xa5, - 0xa5, 0x5e, 0xd9, 0x61, 0x83, 0x1f, 0xa5, 0x62, 0xa0, 0x7b, 0x5f, 0xc6, - 0xc1, 0xb1, 0x15, 0x78, 0x99, 0x25, 0xe8, 0xca, 0xef, 0x63, 0xab, 0x7c, - 0xde, 0x7c, 0xcd, 0xe7, 0x7f, 0x13, 0xae, 0x19, 0x8c, 0x66, 0x66, 0x38, - 0xe7, 0x52, 0x1d, 0x0c, 0x24, 0xad, 0xb6, 0x3b, 0x5d, 0x46, 0xb2, 0xc5, - 0x84, 0xba, 0x84, 0x1c, 0xdd, 0xad, 0x59, 0xf0, 0x55, 0x1a, 0x7a, 0x63, - 0x15, 0x37, 0xe1, 0x94, 0x53, 0x71, 0x88, 0x35, 0x7c, 0x60, 0x86, 0xb8, - 0x48, 0xa5, 0x1e, 0x61, 0x67, 0xeb, 0x82, 0x82, 0x67, 0x9b, 0xd8, 0x33, - 0xa4, 0x72, 0xe2, 0xca, 0x6e, 0x62, 0x33, 0x03, 0xdd, 0x13, 0xde, 0x88, - 0x33, 0x3f, 0x77, 0xaa, 0x66, 0x2c, 0xdb, 0x51, 0x53, 0x40, 0xbb, 0xe3, - 0x9d, 0x79, 0x2f, 0x88, 0x7f, 0xf0, 0x86, 0x8e, 0x00, 0x9f, 0x8f, 0x4c, - 0xdc, 0x96, 0x6f, 0xdc, 0x8a, 0x9e, 0x4e, 0xb2, 0xa7, 0x3a, 0x5c, 0x4f, - 0xb2, 0x35, 0x18, 0x78, 0xb5, 0xa4, 0x61, 0x6e, 0xd8, 0x65, 0x6f, 0xe2, - 0x56, 0x8b, 0x9d, 0x56, 0x4e, 0xbc, 0xed, 0xcf, 0xb4, 0x51, 0xe7, 0xa3, - 0x8b, 0x2f, 0x10, 0xc7, 0x36, 0xf6, 0xd8, 0x8d, 0xb6, 0x24, 0x88, 0xe7, - 0x67, 0x31, 0x93, 0xdd, 0x45, 0x53, 0x00, 0x3a, 0x5f, 0x9d, 0x33, 0x2a, - 0x32, 0xa1, 0x55, 0x80, 0x6b, 0xca, 0xc2, 0x89, 0x74, 0xf7, 0x9a, 0xfe, - 0xe6, 0xad, 0xf5, 0x2e, 0x3d, 0x3c, 0x80, 0x97, 0x42, 0xa2, 0xc1, 0x4b, - 0xe9, 0xdb, 0x67, 0x9e, 0x40, 0x1c, 0x24, 0xb6, 0x05, 0xba, 0xf6, 0xfb, - 0xc8, 0x00, 0xbf, 0xcd, 0xc0, 0x15, 0x0c, 0xf0, 0xdf, 0x65, 0xef, 0xd2, - 0x69, 0xde, 0x49, 0x63, 0x0d, 0xb4, 0x66, 0x7b, 0xf0, 0xd7, 0x5e, 0xd9, - 0x56, 0xdd, 0x2f, 0x1c, 0xf2, 0xe1, 0xd8, 0xa6, 0xea, 0xa3, 0x94, 0xd9, - 0x90, 0xab, 0xe0, 0x51, 0xc0, 0x0b, 0xb5, 0xa3, 0x5d, 0x78, 0xe5, 0x0d, - 0x1b, 0x8a, 0x11, 0xd5, 0xfb, 0x7f, 0x1c, 0x2f, 0x72, 0x26, 0xb5, 0xac, - 0x0d, 0x96, 0x7b, 0xc3, 0x0a, 0x8a, 0x96, 0xa1, 0xbc, 0x85, 0xf1, 0x70, - 0x33, 0xad, 0x04, 0x6f, 0x04, 0x7c, 0xc2, 0xb3, 0x54, 0x3c, 0x12, 0x04, - 0xf9, 0xa6, 0xa9, 0x21, 0xd7, 0xc4, 0x35, 0xf1, 0xe9, 0x2b, 0x37, 0x05, - 0xe8, 0x9f, 0xca, 0x14, 0xdd, 0x65, 0x8a, 0xb4, 0x85, 0x26, 0xe9, 0x48, - 0x69, 0xba, 0x1e, 0x45, 0x2a, 0x41, 0x05, 0xc8, 0x28, 0x4b, 0x83, 0x06, - 0xfc, 0x6d, 0x9f, 0x78, 0x6c, 0x0f, 0xd8, 0xa1, 0x43, 0xce, 0xd5, 0x07, - 0x66, 0x67, 0x94, 0x8f, 0x02, 0x7c, 0xac, 0xca, 0x9d, 0xe0, 0xcd, 0x3d, - 0x0b, 0x54, 0x39, 0x7e, 0x0b, 0xfd, 0xf2, 0x04, 0x4c, 0xae, 0xc1, 0x0f, - 0x9d, 0xa5, 0x87, 0xb5, 0x22, 0x21, 0xe0, 0xdd, 0xb3, 0xb7, 0xe8, 0x18, - 0x82, 0x7e, 0xa8, 0xd0, 0x0c, 0x6c, 0xe2, 0x50, 0x73, 0x6f, 0x20, 0x0c, - 0x5a, 0xf2, 0x1c, 0x53, 0xd2, 0xe2, 0x54, 0xfa, 0x80, 0x3d, 0x5d, 0x88, - 0x40, 0x33, 0x77, 0xf6, 0x85, 0x1a, 0xba, 0x96, 0xf1, 0xd1, 0x06, 0x5d, - 0x78, 0xff, 0x85, 0x3f, 0xe7, 0x21, 0x28, 0xcd, 0x20, 0x8d, 0x93, 0xc8, - 0xc0, 0x8e, 0x9d, 0xf2, 0x46, 0x8f, 0xc4, 0x44, 0x4c, 0xea, 0x91, 0x2a, - 0x6c, 0x75, 0x78, 0x4d, 0x54, 0xf2, 0x3d, 0x74, 0x2c, 0x8d, 0xfe, 0xf8, - 0xfc, 0xa0, 0x83, 0x47, 0x23, 0x2c, 0x25, 0xbb, 0xb0, 0x5d, 0x58, 0x45, - 0x2d, 0x2f, 0xb1, 0x1e, 0x5a, 0x78, 0x22, 0xe0, 0x13, 0x57, 0xdb, 0x52, - 0x5b, 0xb9, 0xf9, 0x66, 0x58, 0x1e, 0xdc, 0xd5, 0x02, 0x3c, 0xe1, 0xa3, - 0xa8, 0x05, 0xc2, 0x06, 0xdb, 0xe5, 0xae, 0xb5, 0x81, 0xd8, 0xc6, 0x19, - 0x27, 0x77, 0xd0, 0x22, 0x46, 0xf1, 0x5e, 0xd5, 0xbc, 0x41, 0x29, 0x75, - 0xb1, 0x13, 0xb6, 0xbd, 0x46, 0x4c, 0x06, 0x9e, 0x7a, 0x61, 0xd0, 0x04, - 0xce, 0xeb, 0xa0, 0x1b, 0x45, 0x6a, 0x0b, 0xba, 0x26, 0x2b, 0xc0, 0xf3, - 0xc4, 0x4a, 0xc5, 0x21, 0x67, 0x09, 0x6b, 0x57, 0xb7, 0x52, 0x55, 0x76, - 0xa4, 0x30, 0x96, 0x35, 0xe8, 0x1d, 0x5f, 0x3e, 0x63, 0x57, 0x56, 0x05, - 0x87, 0x7e, 0xd4, 0x62, 0x60, 0xf3, 0x3d, 0x28, 0x45, 0x2e, 0xac, 0xb9, - 0x6b, 0x89, 0xa1, 0xf6, 0x07, 0xd7, 0xd5, 0xc0, 0x4b, 0x04, 0xe0, 0x5e, - 0x13, 0xe9, 0xcd, 0x7e, 0x51, 0x39, 0x90, 0xef, 0x9b, 0xd2, 0x40, 0xb9, - 0x68, 0x57, 0x28, 0xf1, 0x03, 0xeb, 0xa8, 0x9a, 0x51, 0xe8, 0x62, 0x0f, - 0x3e, 0xea, 0x05, 0x33, 0x02, 0x18, 0x39, 0x7c, 0x43, 0x1c, 0x36, 0x45, - 0x52, 0x65, 0x51, 0x57, 0x01, 0x86, 0x08, 0xc2, 0x1a, 0x3d, 0xc0, 0x3a, - 0x66, 0x39, 0xf8, 0x0a, 0x3c, 0x21, 0xc8, 0x4c, 0x3b, 0x0b, 0x53, 0xb1, - 0x39, 0xb8, 0x08, 0xb4, 0x1d, 0x03, 0xef, 0xc9, 0x92, 0x38, 0xc1, 0x64, - 0x6f, 0xa2, 0x0d, 0x6e, 0x2a, 0xf0, 0x9f, 0xaf, 0xd9, 0x8b, 0xbe, 0x7e, - 0x69, 0x35, 0xa4, 0xf4, 0xbc, 0x23, 0x01, 0xf0, 0xa3, 0x79, 0xec, 0xe8, - 0x4d, 0xc4, 0x2b, 0x97, 0x72, 0x01, 0xfc, 0xa7, 0x67, 0x39, 0xc4, 0x19, - 0x75, 0xab, 0x08, 0xb7, 0x6c, 0x91, 0x40, 0x3f, 0x32, 0xf5, 0x2b, 0xdf, - 0x83, 0x1d, 0xa8, 0x6f, 0x68, 0xef, 0x06, 0x7a, 0x0f, 0x34, 0x82, 0xae, - 0x61, 0x5f, 0x7e, 0xc7, 0xcc, 0x5d, 0x60, 0xd3, 0xc6, 0x07, 0xd0, 0x02, - 0x14, 0x74, 0x57, 0x04, 0x99, 0xbf, 0x9f, 0x58, 0x7e, 0x6c, 0xd9, 0x12, - 0x64, 0xa4, 0x45, 0x1d, 0x25, 0x60, 0xfe, 0xfe, 0xc0, 0x23, 0x16, 0x44, - 0xc6, 0x98, 0x67, 0xa0, 0x0d, 0x44, 0x5a, 0x61, 0xe1, 0xc9, 0xe7, 0x11, - 0xb4, 0x7b, 0xd1, 0xd9, 0x0e, 0x87, 0x98, 0x8d, 0x1a, 0x4d, 0xcb, 0x34, - 0x76, 0x10, 0xde, 0xf8, 0xe4, 0x9d, 0x7b, 0x93, 0x9b, 0xbb, 0x75, 0xf0, - 0x06, 0x22, 0x5c, 0xd5, 0x03, 0xd6, 0xa7, 0x09, 0xd7, 0x4c, 0x70, 0xe7, - 0x56, 0x99, 0x56, 0xf7, 0xdc, 0x01, 0xdf, 0xce, 0xad, 0x34, 0x61, 0xc1, - 0xf5, 0xa8, 0x48, 0x58, 0x7a, 0x21, 0x30, 0x50, 0x39, 0x46, 0x1d, 0xa3, - 0x45, 0x33, 0x5e, 0x0b, 0x24, 0x86, 0xbc, 0x76, 0x17, 0xd2, 0x13, 0x1a, - 0x61, 0x55, 0x12, 0x73, 0xfd, 0x06, 0x73, 0xf0, 0x7d, 0x54, 0xec, 0x3b, - 0x9c, 0x70, 0x1a, 0x9f, 0xef, 0x1a, 0x78, 0xb2, 0xa8, 0x30, 0x33, 0x2d, - 0x37, 0x20, 0x8e, 0x75, 0x3b, 0x0e, 0xe9, 0xb0, 0x80, 0x18, 0x9b, 0x68, - 0x1d, 0x90, 0xc4, 0x94, 0x79, 0x04, 0x3e, 0x21, 0x7b, 0xaf, 0x76, 0xa1, - 0x8b, 0x01, 0xe7, 0xd8, 0x25, 0x4b, 0x88, 0x8a, 0xf9, 0x10, 0xd2, 0xd6, - 0x5a, 0x26, 0x35, 0x20, 0xbb, 0x6f, 0x0f, 0x89, 0x1e, 0xe8, 0x59, 0xc3, - 0x9e, 0x91, 0x8e, 0x3a, 0x3a, 0x05, 0xdb, 0x4c, 0x43, 0xf7, 0xa4, 0x19, - 0x9e, 0x59, 0xab, 0xac, 0x63, 0xc2, 0xae, 0x59, 0x82, 0xcc, 0x03, 0xeb, - 0x05, 0xe8, 0xe5, 0x30, 0x9a, 0x64, 0x55, 0x02, 0x06, 0xc9, 0x74, 0xfb, - 0x2c, 0xdd, 0xf0, 0x0d, 0x98, 0x78, 0xcb, 0xc1, 0x67, 0xc4, 0x9d, 0xba, - 0x85, 0xac, 0xcf, 0x76, 0xa6, 0x30, 0xb1, 0x31, 0xb2, 0x12, 0x09, 0x17, - 0x1b, 0x43, 0x9e, 0xa9, 0xcb, 0x82, 0xa7, 0xc8, 0x00, 0x0e, 0x07, 0x7f, - 0x99, 0x3d, 0x0b, 0x7d, 0x3d, 0x25, 0xe6, 0x56, 0x83, 0xf1, 0xd2, 0x72, - 0x07, 0x81, 0xfe, 0x20, 0x5d, 0xec, 0x49, 0xc0, 0x31, 0xdc, 0x80, 0x9f, - 0x1b, 0x42, 0x16, 0x34, 0x31, 0x57, 0x51, 0x8e, 0x82, 0x6f, 0x98, 0xaf, - 0x27, 0x79, 0x7f, 0x99, 0xb3, 0xaf, 0x95, 0x6c, 0x7e, 0x36, 0x2d, 0x21, - 0x06, 0x82, 0x9e, 0xf8, 0xe2, 0x0e, 0x5e, 0x27, 0x3b, 0xb8, 0xe5, 0x02, - 0xfc, 0x71, 0x18, 0x19, 0x8d, 0x1e, 0x2a, 0xd1, 0xe5, 0xed, 0xfc, 0x0c, - 0x64, 0xf1, 0x3c, 0x42, 0xbc, 0x02, 0x47, 0xc0, 0x98, 0x8c, 0xe7, 0x88, - 0xae, 0x50, 0x0e, 0xfa, 0x0e, 0xf4, 0xf6, 0x3b, 0x49, 0x6d, 0x94, 0x74, - 0xaa, 0x2e, 0xf4, 0xfe, 0x02, 0x3e, 0x6e, 0x3a, 0xb2, 0x48, 0xdb, 0x1b, - 0xd5, 0x9b, 0x3b, 0xa4, 0x0f, 0xe3, 0x55, 0x02, 0xba, 0xd8, 0xcd, 0x68, - 0x69, 0x1d, 0x99, 0x7c, 0x84, 0xef, 0x21, 0x2d, 0x5d, 0x96, 0x81, 0xbe, - 0xbd, 0x80, 0x4a, 0xa8, 0x00, 0x89, 0x46, 0xc0, 0xa1, 0xa6, 0x44, 0xe5, - 0x2d, 0xd1, 0xf4, 0x67, 0x3e, 0xad, 0xdf, 0xb2, 0x8d, 0x6e, 0x89, 0x21, - 0xdd, 0x9d, 0x4e, 0x8c, 0x63, 0x5d, 0x4e, 0xa2, 0xc5, 0xe1, 0xc1, 0xc3, - 0x1e, 0xe4, 0xcf, 0x0b, 0xf0, 0x35, 0x81, 0x78, 0x87, 0x9c, 0x52, 0xde, - 0x91, 0xdf, 0x47, 0xae, 0x84, 0x9d, 0x73, 0x6c, 0x73, 0x15, 0x6a, 0xe0, - 0x47, 0x3d, 0x9c, 0x8a, 0xdb, 0x01, 0x30, 0x2a, 0xa6, 0xa7, 0xe7, 0x5e, - 0x53, 0x4e, 0xac, 0x4a, 0x0d, 0x3e, 0x6f, 0xc5, 0x3e, 0xba, 0x12, 0x14, - 0xf0, 0xd0, 0xab, 0x80, 0x3f, 0xee, 0x6f, 0xca, 0x71, 0x4e, 0x94, 0xc4, - 0xdc, 0x03, 0x6d, 0x40, 0xc1, 0xbb, 0x74, 0x81, 0x83, 0x21, 0x07, 0xc1, - 0xc3, 0x86, 0xdc, 0x91, 0x87, 0xbd, 0x0e, 0x1c, 0xe2, 0xd8, 0x9d, 0xa4, - 0xe5, 0x8b, 0xa8, 0x13, 0xf8, 0x11, 0x71, 0x2b, 0xe8, 0x08, 0x1a, 0x81, - 0x59, 0x09, 0x78, 0xc3, 0x32, 0x25, 0x11, 0x78, 0xa1, 0x4b, 0x98, 0x10, - 0x18, 0xc7, 0xf2, 0x0d, 0x7d, 0x6b, 0x42, 0x83, 0xb9, 0xd1, 0x7b, 0x30, - 0x8e, 0x09, 0xca, 0x12, 0x2a, 0x39, 0x68, 0xd4, 0x0c, 0x9b, 0x55, 0xf0, - 0x07, 0x1f, 0x8a, 0x23, 0xe8, 0xad, 0xf9, 0x8e, 0xb3, 0x68, 0xb7, 0x93, - 0x00, 0xad, 0x83, 0x75, 0xfb, 0xb5, 0x37, 0xd9, 0x50, 0x7a, 0x6c, 0xdc, - 0x4d, 0x6c, 0x17, 0xa9, 0xe8, 0x95, 0x38, 0x78, 0xc0, 0x5a, 0xb5, 0x04, - 0x6e, 0x1a, 0x72, 0x3d, 0xd8, 0x4a, 0x63, 0xb5, 0xcd, 0x38, 0x7a, 0x40, - 0x4c, 0xea, 0xf3, 0xfd, 0x2e, 0xd9, 0x34, 0x0b, 0xd0, 0x6f, 0xa0, 0x23, - 0x95, 0x1b, 0xea, 0x41, 0x9d, 0x31, 0x35, 0x3f, 0x37, 0xe8, 0x41, 0x73, - 0x7c, 0x43, 0xcc, 0x42, 0x4f, 0xf4, 0x3f, 0xc6, 0x47, 0x6e, 0xc0, 0xe3, - 0x1c, 0x00, 0xfb, 0x55, 0x5c, 0xa3, 0xb7, 0xd0, 0x5e, 0x8b, 0x03, 0x78, - 0x69, 0x9c, 0xb8, 0x6f, 0x9c, 0x9e, 0x9e, 0x82, 0x89, 0x7b, 0xa4, 0x59, - 0x56, 0x42, 0xc7, 0xed, 0xc1, 0x17, 0x3b, 0xac, 0xc4, 0x0b, 0xf4, 0x5d, - 0x0c, 0xf9, 0xb4, 0x27, 0x0d, 0x68, 0x36, 0xd4, 0x93, 0x64, 0xda, 0x3e, - 0x71, 0xfc, 0xf5, 0x4c, 0x6a, 0x66, 0x86, 0x53, 0x35, 0xe6, 0xad, 0x04, - 0x2f, 0xa4, 0xce, 0x51, 0xeb, 0x6a, 0x34, 0x65, 0xec, 0xd8, 0x62, 0xe8, - 0x83, 0xb2, 0xc0, 0xe3, 0x07, 0x60, 0xa0, 0x04, 0xd3, 0xfa, 0x0e, 0xeb, - 0xa8, 0xc2, 0xfa, 0x09, 0x74, 0x6d, 0xa4, 0x81, 0xcf, 0xda, 0x96, 0x26, - 0xba, 0x26, 0xed, 0x4a, 0x97, 0xef, 0xfb, 0x58, 0x32, 0xf2, 0xc4, 0x5c, - 0xdc, 0x58, 0x4d, 0xb5, 0xf9, 0x9e, 0x36, 0x45, 0x38, 0x28, 0xb8, 0xee, - 0x45, 0x1a, 0xdb, 0x40, 0x1c, 0x3f, 0x0a, 0x2e, 0xf5, 0xb2, 0x41, 0xaa, - 0xa8, 0xc9, 0x77, 0xae, 0xc8, 0x3e, 0xd2, 0xc8, 0x7b, 0x3f, 0xd9, 0xd7, - 0xdc, 0x17, 0x4f, 0x18, 0xdf, 0xdb, 0x7c, 0x2f, 0x39, 0x04, 0x8c, 0x88, - 0xf9, 0x09, 0xf4, 0xd8, 0xca, 0xa2, 0x9d, 0x7d, 0xcb, 0x14, 0x71, 0x24, - 0x70, 0x10, 0xe8, 0xb7, 0x2e, 0x4e, 0xc4, 0x26, 0x4a, 0x4a, 0x98, 0xff, - 0x60, 0x29, 0x29, 0xc4, 0x9e, 0xa1, 0x60, 0x22, 0xd0, 0x81, 0xf1, 0xe0, - 0x1b, 0x9f, 0x87, 0x43, 0xa1, 0x90, 0x41, 0x4c, 0x09, 0x56, 0x0d, 0xf0, - 0x4d, 0x13, 0xf1, 0xb1, 0xde, 0xbe, 0xca, 0xce, 0x6e, 0x31, 0x72, 0x8d, - 0xa8, 0xbd, 0x2c, 0x0e, 0x34, 0x60, 0x25, 0xd7, 0x0f, 0x2c, 0x15, 0x0d, - 0x51, 0x95, 0x73, 0x70, 0x87, 0x50, 0xf2, 0x71, 0x3a, 0xf8, 0x70, 0x0e, - 0xbd, 0x4a, 0x00, 0x93, 0x5f, 0x33, 0x5e, 0x44, 0x86, 0xb4, 0xa2, 0x94, - 0x6c, 0x8e, 0x5d, 0xa3, 0xb1, 0xf7, 0xca, 0x07, 0x2f, 0x65, 0x26, 0xc6, - 0xd0, 0x65, 0x13, 0x8c, 0x35, 0xaf, 0xb6, 0xe0, 0x59, 0xeb, 0xb8, 0xcb, - 0xac, 0x3c, 0x45, 0xa0, 0x99, 0x85, 0x1b, 0x72, 0x7d, 0x11, 0x33, 0xd0, - 0x15, 0x26, 0x99, 0x22, 0x1a, 0x04, 0xc7, 0x78, 0xd8, 0x82, 0x0e, 0xd9, - 0xc5, 0x8e, 0xdc, 0x00, 0x5e, 0x7a, 0x71, 0xdb, 0x37, 0xf1, 0x84, 0xe3, - 0x30, 0x1e, 0xc0, 0xaf, 0xe3, 0x20, 0xe3, 0xc3, 0x3b, 0x31, 0xc4, 0x0e, - 0x22, 0xe5, 0xbb, 0x74, 0x55, 0x4a, 0x75, 0x3c, 0x15, 0x93, 0xdc, 0xc3, - 0x10, 0x2b, 0xf0, 0x0c, 0xdb, 0xc2, 0x2f, 0xe7, 0xe7, 0x4b, 0x36, 0x68, - 0xc3, 0x67, 0x61, 0xf4, 0x31, 0x9c, 0xe7, 0x41, 0x9a, 0xcb, 0x3b, 0x36, - 0x40, 0x0b, 0x76, 0x36, 0x3d, 0xa6, 0x80, 0xfb, 0xe0, 0xef, 0x0b, 0x63, - 0x78, 0x83, 0xef, 0x32, 0x0b, 0xdf, 0xae, 0x12, 0xba, 0xaa, 0xa5, 0x51, - 0xd5, 0x80, 0x3f, 0x22, 0x66, 0xf8, 0x11, 0x7b, 0x3d, 0x8f, 0x99, 0x4d, - 0x40, 0xcb, 0xef, 0x81, 0xcf, 0x13, 0xea, 0x54, 0x3b, 0xea, 0x6d, 0xdf, - 0xb9, 0xa7, 0x7e, 0x8f, 0x9f, 0xa6, 0xda, 0x1f, 0xf9, 0x98, 0x33, 0x33, - 0x30, 0x38, 0x62, 0x06, 0xeb, 0x20, 0xf7, 0x92, 0xea, 0x1b, 0xa3, 0xe8, - 0x09, 0xda, 0x65, 0x07, 0xfc, 0xeb, 0xb0, 0x49, 0x2e, 0xca, 0xf7, 0xe0, - 0xc9, 0xe6, 0xa4, 0x41, 0x5b, 0x17, 0xd0, 0x9b, 0xfb, 0xa3, 0xa7, 0xa6, - 0x12, 0x55, 0x90, 0x0d, 0x8a, 0x60, 0xbd, 0xd7, 0x39, 0xef, 0x1f, 0xa0, - 0x99, 0xf2, 0x90, 0x0f, 0x24, 0x33, 0xaa, 0x10, 0xe2, 0xc4, 0xc9, 0xc1, - 0xd3, 0x64, 0x4a, 0x5e, 0xa3, 0xe4, 0xa4, 0x95, 0xac, 0x0f, 0x18, 0xf8, - 0x56, 0x89, 0x58, 0x18, 0xe9, 0x80, 0x05, 0xee, 0xcb, 0x48, 0x7c, 0xf8, - 0x5d, 0x9d, 0x74, 0x6c, 0xf6, 0xbb, 0xbc, 0x46, 0x9b, 0xa8, 0xae, 0x36, - 0xb2, 0x16, 0x4e, 0x46, 0x17, 0x66, 0x82, 0xa2, 0x31, 0xa4, 0xc8, 0x4a, - 0x3a, 0xe4, 0x96, 0x0c, 0x7b, 0x39, 0xf4, 0x91, 0x50, 0xe4, 0x52, 0x13, - 0x3f, 0x0e, 0xa8, 0x57, 0x58, 0xb3, 0x8c, 0x83, 0x2b, 0x40, 0xd5, 0xad, - 0x6c, 0x0a, 0x57, 0x16, 0xa6, 0x41, 0x98, 0x1b, 0x42, 0x2b, 0x41, 0xef, - 0x01, 0x1e, 0x71, 0xd1, 0x58, 0xfb, 0xdc, 0x08, 0xc8, 0xce, 0xc4, 0x99, - 0x48, 0x00, 0x0b, 0x6b, 0xe9, 0x50, 0xd0, 0xdf, 0xe0, 0x35, 0x06, 0xea, - 0x29, 0x11, 0x1b, 0xf2, 0x02, 0xb3, 0x5f, 0xe7, 0x53, 0xf9, 0xdc, 0xe9, - 0xec, 0xce, 0x9a, 0xe1, 0xc5, 0xd4, 0xc9, 0x82, 0x98, 0x48, 0xc1, 0x63, - 0x86, 0xa1, 0x5e, 0x0d, 0xb2, 0xd1, 0x9d, 0xf9, 0x1e, 0x7b, 0x82, 0xe4, - 0x23, 0xf7, 0xac, 0x96, 0x33, 0x79, 0x87, 0xd8, 0x79, 0x46, 0xd3, 0xfa, - 0x09, 0x8a, 0x44, 0xe5, 0xa9, 0x1d, 0x08, 0x6d, 0xe4, 0x85, 0x86, 0x9f, - 0x91, 0xea, 0xdb, 0x63, 0x7b, 0xd1, 0x0b, 0x2e, 0x2e, 0xb9, 0x17, 0x34, - 0xd2, 0xcc, 0xac, 0xb2, 0x01, 0x6c, 0x50, 0xb2, 0x3f, 0xa6, 0xe4, 0x0a, - 0xd8, 0x7f, 0x66, 0xa6, 0x3d, 0x11, 0x4d, 0x2d, 0x84, 0x2f, 0x17, 0x52, - 0x5d, 0x9e, 0xa0, 0x11, 0x5c, 0xd0, 0x01, 0x23, 0x68, 0xa5, 0x25, 0xf8, - 0x97, 0x73, 0x7e, 0x1e, 0x6e, 0x79, 0xaa, 0x68, 0xe8, 0xa2, 0x3b, 0xf8, - 0x98, 0x70, 0xbe, 0x2f, 0x1f, 0xa5, 0xb6, 0x00, 0x5d, 0x60, 0x72, 0x47, - 0x45, 0xb8, 0xce, 0x5e, 0x71, 0x3b, 0x92, 0x68, 0x22, 0xfd, 0xd1, 0x9d, - 0xef, 0x3d, 0xeb, 0xa0, 0xdd, 0xd6, 0x5a, 0xc9, 0xad, 0x1d, 0x69, 0x03, - 0x1a, 0xbb, 0x4c, 0x4f, 0x7c, 0xbb, 0x65, 0x74, 0x7b, 0x23, 0x29, 0x7a, - 0xc3, 0x31, 0x2a, 0x04, 0x3c, 0x05, 0x9c, 0x72, 0x43, 0x27, 0xb8, 0x42, - 0x8e, 0x85, 0xc7, 0xae, 0x37, 0xc1, 0x3a, 0xc1, 0x88, 0xea, 0x6d, 0xd8, - 0xa2, 0x18, 0xfc, 0x5b, 0x90, 0x31, 0x16, 0x1f, 0x99, 0x80, 0xeb, 0xed, - 0xdb, 0xa2, 0x46, 0xcf, 0x38, 0x09, 0xec, 0xac, 0xa9, 0x58, 0xee, 0xa3, - 0x8c, 0xd4, 0xf6, 0xad, 0x30, 0x44, 0x16, 0xb6, 0x56, 0xbe, 0x37, 0x4e, - 0xaf, 0xa2, 0x21, 0x69, 0xa2, 0xb2, 0x27, 0x07, 0x2c, 0x8b, 0x6b, 0xb9, - 0xc9, 0x1b, 0x06, 0x5a, 0x9d, 0x5a, 0x05, 0x62, 0xe0, 0x39, 0xe0, 0x38, - 0x5d, 0x2e, 0xc1, 0x87, 0xaa, 0x43, 0x52, 0xe9, 0xa2, 0x06, 0xed, 0xc7, - 0xd1, 0x77, 0xd8, 0x28, 0x74, 0x74, 0x23, 0xeb, 0xd8, 0x58, 0x3b, 0x88, - 0x8b, 0x0a, 0x78, 0xf6, 0x8d, 0x75, 0x02, 0x9e, 0xcd, 0x7e, 0x51, 0x37, - 0xd2, 0xca, 0x6e, 0xbb, 0x10, 0x4a, 0x5c, 0x40, 0xdb, 0x04, 0x90, 0x23, - 0x49, 0xe1, 0x8e, 0xf9, 0xaf, 0x7b, 0x95, 0x8d, 0xe0, 0xe1, 0x66, 0x95, - 0x44, 0x89, 0x32, 0x71, 0x3c, 0x44, 0x0c, 0xf4, 0x32, 0x78, 0x98, 0x0d, - 0x69, 0xaa, 0x1b, 0xef, 0xc8, 0x35, 0xe3, 0x81, 0x1f, 0x7a, 0xc3, 0x24, - 0x50, 0x05, 0x8a, 0x15, 0xdb, 0xf3, 0x7d, 0x14, 0xe2, 0xea, 0x6f, 0x41, - 0xd1, 0x2e, 0xa1, 0x55, 0x5a, 0xfa, 0xae, 0x76, 0xe4, 0xdb, 0xd7, 0xd1, - 0xb7, 0x17, 0x07, 0x8f, 0x69, 0x34, 0x71, 0x35, 0xec, 0xac, 0x4d, 0xd6, - 0x91, 0x90, 0x68, 0xcc, 0x01, 0x5e, 0x05, 0x1f, 0x18, 0x82, 0x3a, 0x06, - 0x9f, 0xe0, 0xbb, 0xf3, 0x1a, 0xa7, 0x1d, 0x71, 0x84, 0x4b, 0xd3, 0xe8, - 0x26, 0x1b, 0xf2, 0xa2, 0x3e, 0x5c, 0x4f, 0x87, 0x02, 0xd9, 0x0c, 0x57, - 0xf0, 0xe6, 0x55, 0xee, 0x41, 0x4e, 0x38, 0xea, 0x00, 0x31, 0x6e, 0x27, - 0x1a, 0x7b, 0x80, 0x86, 0x7d, 0x27, 0x8e, 0x3d, 0xc4, 0xd0, 0x0f, 0x9e, - 0x08, 0x60, 0xb2, 0xd5, 0xb3, 0xf0, 0xac, 0x37, 0x43, 0xae, 0x1e, 0x03, - 0x16, 0xc5, 0x0c, 0x82, 0xfd, 0x3d, 0xf4, 0x45, 0x2a, 0xb7, 0xc9, 0xfb, - 0x6e, 0xc5, 0x0d, 0xe8, 0x0f, 0x6f, 0xa1, 0x11, 0x87, 0x1c, 0x4a, 0x43, - 0xb9, 0xe0, 0x69, 0x6e, 0xa5, 0x36, 0xe6, 0x1c, 0xb8, 0x0b, 0x70, 0x2c, - 0x91, 0xc6, 0xd8, 0x1e, 0x1d, 0xe9, 0x72, 0x3a, 0x5a, 0x10, 0xf3, 0x1b, - 0xf0, 0x25, 0x67, 0xa9, 0x57, 0x29, 0x6d, 0x56, 0xd3, 0xc1, 0xbb, 0x2f, - 0x12, 0x85, 0xc2, 0xdc, 0x67, 0x29, 0x4f, 0xec, 0x07, 0xe4, 0x7f, 0x25, - 0x38, 0xeb, 0x0b, 0xb3, 0x6a, 0xe2, 0x56, 0x55, 0xe0, 0xfb, 0xbf, 0xa5, - 0x03, 0xee, 0x8f, 0xaa, 0x51, 0xea, 0x0d, 0xe0, 0x1f, 0x36, 0x8a, 0x14, - 0x74, 0xf9, 0x24, 0xad, 0x98, 0x5b, 0x31, 0x66, 0x64, 0xc6, 0x99, 0x1b, - 0x7c, 0x96, 0x93, 0xc9, 0x5d, 0xc4, 0xd4, 0x3a, 0x83, 0x17, 0x1d, 0x21, - 0xa6, 0xe7, 0xf8, 0xd4, 0xa8, 0x2b, 0x79, 0x98, 0x6e, 0xdf, 0x71, 0xd3, - 0x5b, 0xa1, 0x2f, 0x75, 0x06, 0x2a, 0x6c, 0xa7, 0x91, 0xd9, 0x93, 0x71, - 0x66, 0x54, 0xcd, 0x0e, 0x78, 0x3e, 0x71, 0xf5, 0x27, 0xe0, 0xe1, 0x1d, - 0xa7, 0xd9, 0x53, 0xfa, 0x41, 0xf5, 0x47, 0xbc, 0xe5, 0x2c, 0x09, 0xa0, - 0xef, 0x77, 0xe3, 0x08, 0x79, 0xc9, 0x34, 0x39, 0x45, 0x66, 0x30, 0x24, - 0xed, 0xfd, 0x05, 0xb9, 0x84, 0x73, 0xc4, 0x06, 0xec, 0xa1, 0xad, 0x74, - 0x87, 0x07, 0x78, 0x50, 0x03, 0x9b, 0xe4, 0x00, 0xf1, 0x07, 0x3a, 0x28, - 0x48, 0x61, 0x1e, 0x5e, 0x18, 0x85, 0x2f, 0xe9, 0x56, 0xf7, 0x90, 0xbb, - 0x96, 0xd0, 0x30, 0x83, 0xf9, 0xb4, 0x92, 0x49, 0x2e, 0x33, 0xa3, 0x17, - 0xdc, 0xc3, 0x22, 0x3b, 0x0f, 0x56, 0xae, 0x80, 0x27, 0x93, 0xea, 0x16, - 0x4e, 0x08, 0x58, 0xd8, 0xae, 0x39, 0xc2, 0x49, 0x0e, 0x71, 0x0e, 0xfe, - 0x2a, 0x83, 0xb9, 0xcd, 0xc0, 0x23, 0x9b, 0x11, 0x0b, 0xec, 0x43, 0x7a, - 0x19, 0x13, 0xbd, 0x31, 0x93, 0x96, 0x2e, 0xc0, 0x5d, 0x6c, 0x84, 0x6b, - 0x59, 0x79, 0xeb, 0x3e, 0x8f, 0x1d, 0xbb, 0x1c, 0x53, 0xa9, 0x15, 0xde, - 0x78, 0xa6, 0xef, 0x01, 0x95, 0x7e, 0xd0, 0x1f, 0x13, 0xa2, 0x25, 0x49, - 0x70, 0x97, 0x66, 0xf5, 0x08, 0x3d, 0x72, 0x4b, 0x74, 0x55, 0xc5, 0x90, - 0xb7, 0xc4, 0xfd, 0x32, 0x81, 0xa3, 0xc4, 0xbc, 0xc6, 0x30, 0x9a, 0x9f, - 0x29, 0xf8, 0xf8, 0x4d, 0x95, 0x4a, 0x41, 0x1f, 0x5e, 0xc1, 0x4b, 0xcc, - 0x6b, 0x0a, 0x72, 0xc1, 0xca, 0x77, 0x48, 0xa9, 0x15, 0xce, 0xcf, 0x9e, - 0x1c, 0xd6, 0x93, 0x09, 0xf9, 0x47, 0xca, 0x40, 0x83, 0x81, 0xfe, 0x51, - 0x8d, 0x49, 0x6a, 0x92, 0x93, 0x54, 0x99, 0xd2, 0x15, 0x97, 0x8c, 0x61, - 0x96, 0xe8, 0x88, 0x97, 0xcc, 0xd5, 0x13, 0x4f, 0xe8, 0x84, 0x82, 0x3f, - 0xe6, 0x41, 0x45, 0x9a, 0xa1, 0x39, 0xb6, 0xfd, 0x2b, 0xa2, 0xb8, 0x01, - 0xae, 0x80, 0x4c, 0xc9, 0x16, 0x61, 0x63, 0x05, 0xec, 0x6f, 0xf1, 0x88, - 0x10, 0x82, 0xbc, 0x4c, 0x81, 0x87, 0xbd, 0x4c, 0x23, 0x29, 0xc4, 0xa0, - 0x8a, 0x9b, 0x20, 0xd9, 0xeb, 0x08, 0x8b, 0xcd, 0x70, 0x01, 0x9f, 0x13, - 0xc6, 0x8c, 0x78, 0x79, 0xb7, 0xbe, 0xc5, 0x2e, 0x6a, 0xc1, 0x87, 0xa4, - 0xd4, 0x54, 0x5a, 0xe1, 0xe2, 0x43, 0x4c, 0xf1, 0x21, 0x82, 0x98, 0x15, - 0xac, 0xbf, 0x64, 0xca, 0xfe, 0x2e, 0xd3, 0x20, 0xcb, 0xb4, 0xd5, 0xb7, - 0x8c, 0x87, 0x00, 0x30, 0x9e, 0x96, 0x4e, 0x50, 0x49, 0x98, 0x57, 0xe0, - 0x20, 0x53, 0x7a, 0xe3, 0x3d, 0x6b, 0xee, 0xaf, 0x58, 0x17, 0x1e, 0xeb, - 0x24, 0x86, 0x7f, 0x6f, 0xb1, 0x1b, 0x8d, 0x85, 0xc1, 0x3c, 0xc0, 0xd5, - 0x83, 0xa4, 0xf2, 0x1e, 0x37, 0x55, 0x45, 0xc0, 0x83, 0x24, 0x40, 0xa8, - 0xa0, 0x49, 0x7e, 0x1f, 0x7f, 0x6f, 0x04, 0xb5, 0x20, 0x3a, 0xf2, 0xbe, - 0xdf, 0x88, 0x1e, 0x5c, 0x32, 0x6d, 0xf1, 0x02, 0xcc, 0x59, 0x60, 0xf7, - 0xfe, 0x4a, 0xfc, 0xfe, 0x16, 0x69, 0x41, 0x72, 0xa0, 0xac, 0xa5, 0x1d, - 0x3e, 0x17, 0x0d, 0x5b, 0xe4, 0x26, 0xc9, 0x01, 0xff, 0xad, 0xf9, 0xfc, - 0x45, 0x53, 0x3d, 0xc0, 0xbb, 0xd2, 0x82, 0xf5, 0xb8, 0xa0, 0x68, 0x93, - 0xb5, 0xaf, 0x27, 0xe8, 0x1c, 0x8d, 0xb9, 0x63, 0xc6, 0x59, 0x03, 0x3a, - 0x98, 0xbd, 0xa8, 0xce, 0xce, 0xc0, 0x77, 0x71, 0x6e, 0x00, 0x5e, 0xd0, - 0x8b, 0x46, 0xdb, 0x21, 0x3a, 0xf8, 0xd8, 0xa1, 0x70, 0xee, 0x1c, 0xd9, - 0x76, 0x94, 0x56, 0x06, 0x78, 0x31, 0x9d, 0xa0, 0xca, 0x86, 0x38, 0x15, - 0xd2, 0x44, 0x07, 0x18, 0x1f, 0xa7, 0x64, 0x62, 0xcf, 0x6a, 0xa4, 0x33, - 0xc5, 0x14, 0xe8, 0x1b, 0x2d, 0x81, 0xeb, 0x09, 0xdd, 0xe6, 0x55, 0x98, - 0x36, 0xcd, 0xdd, 0x13, 0xcc, 0xb9, 0x70, 0x12, 0x83, 0x9d, 0x41, 0x73, - 0x0e, 0x31, 0xcb, 0xc6, 0x2c, 0x51, 0xd1, 0xc1, 0x8d, 0x80, 0x07, 0xef, - 0x63, 0x0c, 0x5a, 0xa9, 0x74, 0xd4, 0x19, 0x78, 0x5d, 0x10, 0xf0, 0x2f, - 0xcc, 0xd0, 0xef, 0x11, 0x78, 0xb5, 0x8c, 0xf6, 0x38, 0x4c, 0x50, 0xc5, - 0x3d, 0xe2, 0xc5, 0xc8, 0x76, 0xc3, 0x44, 0xd4, 0xf0, 0x1a, 0xcc, 0x9c, - 0x7e, 0x85, 0x78, 0x02, 0xfd, 0xa1, 0x5f, 0x31, 0x07, 0xbf, 0x4e, 0xab, - 0x47, 0x94, 0x00, 0x5e, 0xea, 0xa2, 0x2b, 0x15, 0x60, 0x74, 0x43, 0x16, - 0xa5, 0x86, 0xe2, 0x84, 0xa2, 0xe6, 0xe8, 0x0b, 0x93, 0xab, 0x7e, 0xbb, - 0x37, 0xfa, 0x67, 0x91, 0xf6, 0x51, 0xd1, 0x91, 0x5b, 0xc6, 0xc8, 0x76, - 0x0f, 0x0e, 0x64, 0xa7, 0xa9, 0xf4, 0xe8, 0x05, 0x59, 0x62, 0x8c, 0x6f, - 0xf0, 0x26, 0x51, 0x39, 0xd9, 0x2e, 0x7e, 0xdf, 0x75, 0xc0, 0x01, 0x9f, - 0xf0, 0x6a, 0x43, 0x94, 0xed, 0xc8, 0x66, 0xe5, 0x95, 0x1e, 0xce, 0xa0, - 0xbd, 0x07, 0xa5, 0x2b, 0xb8, 0x1c, 0x30, 0x2e, 0xba, 0xdd, 0x92, 0x3a, - 0xb8, 0x80, 0xbf, 0x25, 0xc2, 0x18, 0x76, 0x42, 0x53, 0x49, 0xa2, 0xf5, - 0xef, 0x48, 0x1b, 0x31, 0xf3, 0x2e, 0xef, 0x48, 0xef, 0x13, 0xd0, 0x87, - 0xbc, 0x30, 0xf1, 0x1b, 0xbc, 0xd3, 0xa5, 0x84, 0xf1, 0x49, 0x10, 0xe0, - 0x60, 0x8b, 0x52, 0x88, 0xa3, 0x01, 0xbc, 0xd8, 0xa5, 0x30, 0x15, 0x91, - 0xde, 0x05, 0xfc, 0x5a, 0xe5, 0x24, 0xb4, 0x07, 0x9f, 0x10, 0xe4, 0xb2, - 0xc3, 0x56, 0x04, 0xe1, 0x9d, 0xa7, 0x30, 0xd6, 0x74, 0x6c, 0x4b, 0x9d, - 0xd9, 0xa0, 0x43, 0xf8, 0xde, 0xac, 0x3c, 0xea, 0xf6, 0x66, 0x51, 0xe3, - 0x5d, 0x6e, 0xda, 0x5b, 0x92, 0x56, 0x75, 0xae, 0x55, 0xb9, 0x68, 0x46, - 0x17, 0x5c, 0x2c, 0xe5, 0xe0, 0xaf, 0x8e, 0x3e, 0x0a, 0x7f, 0x79, 0xdf, - 0x16, 0x8e, 0x73, 0xc4, 0x21, 0xeb, 0x94, 0xcd, 0x5c, 0xf4, 0xcd, 0xa8, - 0x9a, 0x40, 0x8f, 0x6c, 0x62, 0x8a, 0x06, 0xfc, 0xfe, 0x02, 0x7c, 0x7c, - 0x41, 0x3e, 0x56, 0x39, 0xe4, 0x93, 0x07, 0x5a, 0xec, 0x16, 0xd2, 0xca, - 0xc8, 0xfd, 0x4a, 0xcf, 0x80, 0xe3, 0xf3, 0x64, 0xfb, 0xe2, 0x3c, 0x60, - 0x0c, 0xbc, 0x6e, 0x98, 0x80, 0x76, 0x04, 0xee, 0x13, 0x7e, 0xb5, 0x9d, - 0x8f, 0x87, 0xf9, 0x7c, 0x33, 0x8a, 0x2a, 0xd0, 0xe4, 0x69, 0xa4, 0x47, - 0x4f, 0xa2, 0x4b, 0xc5, 0x59, 0x68, 0x90, 0x06, 0x74, 0x76, 0x5d, 0x45, - 0xbf, 0xee, 0x15, 0x75, 0xd2, 0x8c, 0x3a, 0x89, 0x20, 0xf6, 0x8d, 0xb8, - 0x89, 0x0c, 0x18, 0xf7, 0xb4, 0x34, 0xe5, 0x25, 0xe3, 0xd1, 0x2b, 0x6b, - 0x25, 0x8d, 0x26, 0xb6, 0x07, 0x2f, 0xa5, 0x45, 0x54, 0x1b, 0x89, 0x53, - 0x61, 0xec, 0xb9, 0x56, 0xd1, 0x89, 0x89, 0xbb, 0xac, 0x8a, 0x12, 0x14, - 0x1e, 0x39, 0xb9, 0x15, 0x53, 0x30, 0x00, 0x36, 0xde, 0x8e, 0xde, 0xc9, - 0xa0, 0x4a, 0x84, 0x47, 0xda, 0xf7, 0xb1, 0x9e, 0x69, 0x49, 0x8b, 0xa2, - 0x90, 0x6b, 0x2f, 0x79, 0x5e, 0x29, 0x9e, 0x56, 0xe0, 0xa1, 0x71, 0x27, - 0x95, 0x02, 0x9e, 0xed, 0x97, 0x98, 0x61, 0x05, 0xb9, 0x18, 0xc6, 0x93, - 0x3d, 0x10, 0x66, 0x27, 0x05, 0x1f, 0xf5, 0x08, 0x7c, 0x7d, 0xa6, 0x57, - 0x1a, 0x07, 0x3f, 0x7b, 0xf0, 0xf4, 0xee, 0x88, 0x4e, 0xef, 0xb2, 0x2b, - 0x9f, 0x65, 0xcd, 0xae, 0xc0, 0x2f, 0xdf, 0xb4, 0x1d, 0x53, 0xe0, 0xc1, - 0x29, 0x53, 0x41, 0x72, 0xf4, 0x46, 0x0d, 0x34, 0xda, 0x53, 0xd4, 0x78, - 0xc2, 0x49, 0x35, 0x45, 0x6c, 0xf6, 0xb7, 0x7a, 0x5d, 0xb8, 0xfa, 0x85, - 0x02, 0xf7, 0xd0, 0x86, 0x55, 0xc2, 0xd0, 0x1f, 0xbc, 0x56, 0xbb, 0xb8, - 0xc3, 0xa0, 0x6b, 0xd5, 0x2e, 0x8f, 0x57, 0x7b, 0xf0, 0x90, 0x3b, 0xd0, - 0x71, 0xd7, 0x03, 0x93, 0xe0, 0x6d, 0x54, 0x44, 0x59, 0xb5, 0x03, 0x5c, - 0x19, 0x85, 0x21, 0x36, 0x38, 0x01, 0x4f, 0xeb, 0xae, 0xb6, 0x91, 0x51, - 0xfd, 0x9e, 0x7f, 0xbe, 0x8d, 0x88, 0xf1, 0x02, 0x66, 0x59, 0x9d, 0x4b, - 0x8a, 0xb4, 0xd0, 0x04, 0xcf, 0xda, 0x20, 0xc6, 0x55, 0x70, 0x39, 0xfa, - 0xbd, 0x01, 0x7e, 0x19, 0xb4, 0x03, 0xa9, 0x41, 0xf7, 0x1d, 0x42, 0xa7, - 0x19, 0xb1, 0xa9, 0x0e, 0xc0, 0x2f, 0x57, 0xf0, 0x82, 0xef, 0x18, 0x21, - 0x70, 0xa1, 0x6c, 0x37, 0xb7, 0x02, 0xbe, 0xef, 0xcc, 0xe9, 0x69, 0xe4, - 0x49, 0xe0, 0xc6, 0x3a, 0xbc, 0x5a, 0x57, 0x3b, 0x39, 0x49, 0x16, 0xba, - 0x64, 0xc3, 0x5b, 0xfd, 0x2e, 0x13, 0xe1, 0x83, 0x56, 0x17, 0xcc, 0x00, - 0xcc, 0xf4, 0x10, 0xe8, 0x4d, 0xdc, 0x85, 0x13, 0xe3, 0x98, 0x47, 0xcf, - 0xa4, 0x93, 0xd7, 0xb8, 0xb6, 0x21, 0x6f, 0x65, 0x17, 0x37, 0xe1, 0x08, - 0x31, 0x3b, 0x46, 0x6d, 0xb0, 0x8c, 0xd5, 0xdf, 0xf8, 0x64, 0xfd, 0x94, - 0xae, 0xb2, 0x8a, 0x14, 0x28, 0x8e, 0xe3, 0xd7, 0xc1, 0xef, 0x7d, 0x89, - 0x40, 0xbf, 0xf9, 0x30, 0x6f, 0x1d, 0x71, 0x71, 0x1a, 0x9a, 0x80, 0x8d, - 0x84, 0xfb, 0x7d, 0x9c, 0xd1, 0x95, 0x01, 0xf3, 0xbf, 0x00, 0xfd, 0x12, - 0x82, 0x6f, 0x48, 0x59, 0x63, 0x1d, 0xb0, 0x8e, 0x55, 0x31, 0xd9, 0x17, - 0xa1, 0xe9, 0x97, 0x83, 0x27, 0x86, 0xfd, 0xbc, 0xce, 0xce, 0xeb, 0x11, - 0x49, 0x10, 0xc9, 0xa7, 0xca, 0xc2, 0xae, 0xe8, 0x62, 0xbf, 0xdf, 0x16, - 0xae, 0x55, 0x01, 0xde, 0x98, 0xb8, 0xb6, 0x77, 0x18, 0xf4, 0x42, 0xcc, - 0x65, 0x9c, 0x78, 0xcd, 0xb3, 0x68, 0xfa, 0x7b, 0xe8, 0x93, 0xb7, 0x68, - 0xd0, 0x13, 0xb8, 0x2d, 0x91, 0x8c, 0xb0, 0x88, 0x8e, 0x5d, 0x64, 0xf4, - 0x7d, 0xe2, 0x5a, 0x98, 0x03, 0x76, 0x43, 0xbe, 0x8b, 0x50, 0x23, 0xe0, - 0xdd, 0xc4, 0x39, 0x99, 0xe7, 0xbb, 0x6e, 0x16, 0x92, 0x07, 0xb1, 0x48, - 0x20, 0x07, 0x99, 0xfb, 0x66, 0x4a, 0x21, 0x56, 0xcb, 0x1e, 0x38, 0x4d, - 0x44, 0xed, 0x18, 0x97, 0xba, 0xcd, 0xc2, 0x66, 0xf1, 0xa2, 0x6c, 0x7d, - 0x0b, 0x0d, 0xe9, 0x47, 0xec, 0x74, 0xc3, 0xf3, 0x93, 0x1e, 0x24, 0xbd, - 0x5f, 0xf9, 0xa9, 0xd0, 0x06, 0xfc, 0x32, 0x2b, 0x55, 0x36, 0x4a, 0xc3, - 0x1a, 0x8e, 0x0e, 0xba, 0x47, 0x6d, 0x15, 0x80, 0x16, 0x57, 0xbc, 0xad, - 0xe6, 0xcf, 0x37, 0x30, 0x7f, 0x10, 0x57, 0xc1, 0x12, 0xf2, 0xde, 0x17, - 0x69, 0x64, 0x08, 0x24, 0x6e, 0x31, 0x84, 0x2c, 0xd3, 0xa9, 0x91, 0xd0, - 0xa1, 0xca, 0x9b, 0xe1, 0x97, 0x5e, 0x2b, 0x79, 0x10, 0x1c, 0xe8, 0x60, - 0x85, 0x13, 0x61, 0xb1, 0xcf, 0xc6, 0xbd, 0x81, 0x87, 0x83, 0xfb, 0x7a, - 0x67, 0xe6, 0xfa, 0x19, 0x32, 0x25, 0x4a, 0x27, 0x1a, 0x13, 0x3e, 0xb6, - 0xdc, 0xc7, 0x49, 0x68, 0xda, 0x4d, 0xd9, 0x2a, 0x1d, 0xb8, 0x23, 0x93, - 0xcd, 0x08, 0x3e, 0x6d, 0xb5, 0x8c, 0xeb, 0x80, 0xc3, 0x95, 0x59, 0x92, - 0xf5, 0x07, 0xc8, 0x59, 0x33, 0xa4, 0x78, 0x4a, 0x80, 0x76, 0x48, 0xa7, - 0x14, 0x4d, 0xd0, 0x28, 0x37, 0xab, 0x3e, 0xd2, 0x56, 0x59, 0xd9, 0x36, - 0xc6, 0xb1, 0x71, 0x75, 0xda, 0x08, 0x1b, 0x3b, 0xe4, 0x16, 0xb6, 0x99, - 0x71, 0xa0, 0x25, 0x60, 0xae, 0x6e, 0x24, 0x48, 0x24, 0x82, 0xaa, 0x07, - 0xf1, 0x88, 0x51, 0xd6, 0xe8, 0x8a, 0xa7, 0xe6, 0x96, 0x38, 0x28, 0x8e, - 0x95, 0xed, 0x67, 0x35, 0x62, 0x85, 0x86, 0x66, 0xdd, 0x26, 0x28, 0xe0, - 0x7b, 0x88, 0xaa, 0x80, 0xb5, 0x55, 0x75, 0x6c, 0xd4, 0xc4, 0xe6, 0xf5, - 0x45, 0x35, 0xe2, 0x07, 0xe0, 0x76, 0x66, 0x36, 0xe6, 0xb1, 0xab, 0xc0, - 0xdb, 0x92, 0xae, 0xf4, 0xd0, 0x0b, 0x3c, 0x7f, 0x25, 0xfc, 0xad, 0x56, - 0xba, 0x03, 0xa8, 0xb7, 0xed, 0x28, 0xb4, 0xea, 0xce, 0xea, 0x79, 0x1d, - 0xbf, 0x18, 0x69, 0xb3, 0x30, 0x70, 0x33, 0xbc, 0x69, 0x53, 0x79, 0xa0, - 0xb9, 0x1f, 0xac, 0x56, 0x0b, 0xbe, 0x19, 0xce, 0x61, 0x33, 0x1e, 0xe2, - 0x5a, 0x6c, 0x33, 0x03, 0xf8, 0xc7, 0xc4, 0x56, 0xe2, 0xd2, 0x57, 0x9e, - 0x6e, 0x4d, 0x88, 0x59, 0x33, 0xe4, 0x24, 0xdf, 0x19, 0x90, 0xcb, 0x8c, - 0x74, 0xb4, 0x55, 0x8f, 0x9c, 0x2f, 0x0c, 0xda, 0xe2, 0x03, 0x70, 0x93, - 0xcb, 0xa6, 0x2a, 0x04, 0x5e, 0x09, 0xf6, 0x53, 0x10, 0x96, 0x3a, 0x39, - 0x10, 0x4e, 0x00, 0xbb, 0x94, 0x3b, 0xdf, 0x27, 0x2c, 0x74, 0xec, 0x45, - 0x8a, 0x71, 0xe1, 0x44, 0x53, 0xa8, 0xaf, 0x6f, 0xdc, 0xd5, 0x73, 0xea, - 0xa1, 0x06, 0x38, 0x37, 0x04, 0x2d, 0xe0, 0xca, 0x06, 0xbd, 0x92, 0x0e, - 0xab, 0xbd, 0x59, 0x3e, 0x21, 0xbf, 0xbd, 0x92, 0x49, 0x2f, 0xe4, 0xcc, - 0x92, 0xed, 0xc2, 0x82, 0xfe, 0xea, 0xa4, 0x96, 0x07, 0xf0, 0x5e, 0x61, - 0xa8, 0x2a, 0x17, 0x34, 0x84, 0x97, 0x4f, 0x6a, 0x23, 0x38, 0x06, 0xcd, - 0xd7, 0x18, 0x91, 0x31, 0xde, 0x73, 0x0d, 0xa1, 0x68, 0xc2, 0x53, 0x66, - 0xca, 0x26, 0x4a, 0xe0, 0xca, 0xdb, 0x68, 0x94, 0xa9, 0x4c, 0x80, 0x1b, - 0x4c, 0xc0, 0xf0, 0x45, 0x6c, 0x04, 0x87, 0x78, 0x12, 0x93, 0x30, 0xab, - 0x08, 0xa7, 0xd8, 0xca, 0x34, 0xb4, 0xcf, 0x95, 0x1d, 0x70, 0x7e, 0x9f, - 0x24, 0x9d, 0xd7, 0x38, 0xd0, 0xe7, 0x1e, 0x5c, 0x55, 0x3c, 0xad, 0xa7, - 0x63, 0x8a, 0xfc, 0x8c, 0xbb, 0xd3, 0x91, 0x55, 0x69, 0x42, 0x45, 0x7d, - 0x48, 0x45, 0x9b, 0x98, 0x38, 0x12, 0xa6, 0x5d, 0x95, 0x29, 0x22, 0xe0, - 0xef, 0x6f, 0x8c, 0xf7, 0xa9, 0xf4, 0xd4, 0x15, 0x38, 0x6d, 0x88, 0x53, - 0x69, 0x84, 0x7a, 0xb0, 0x04, 0x3f, 0xa1, 0x01, 0x4f, 0xe7, 0xe4, 0xbd, - 0x02, 0x85, 0x1f, 0x2c, 0x99, 0x1e, 0xd4, 0xa0, 0xd3, 0xdf, 0xd8, 0x91, - 0x0b, 0xc0, 0xc3, 0x89, 0xf2, 0x8b, 0xb5, 0x37, 0xc6, 0x4b, 0xe1, 0xe9, - 0x63, 0x69, 0xe0, 0x3b, 0x78, 0x64, 0x5d, 0x24, 0xeb, 0x17, 0xe6, 0xfa, - 0xfb, 0xe0, 0xad, 0x92, 0xbc, 0xd1, 0xcc, 0xc2, 0x13, 0x99, 0x74, 0xdc, - 0x49, 0x30, 0x94, 0x62, 0xe8, 0x43, 0xe1, 0xca, 0x9a, 0x25, 0xf2, 0x56, - 0x34, 0x9a, 0x91, 0x37, 0xc1, 0x13, 0x72, 0xe7, 0x12, 0x25, 0xf3, 0xf3, - 0x67, 0xe6, 0x84, 0x9a, 0x65, 0xc7, 0xef, 0x15, 0x49, 0xda, 0x20, 0x2f, - 0x01, 0x83, 0xc0, 0x8f, 0x7d, 0x4b, 0x2f, 0xb0, 0x8e, 0x8c, 0x0c, 0xb2, - 0xeb, 0xbf, 0xe7, 0x67, 0xdd, 0x02, 0x7c, 0xef, 0xb1, 0xc6, 0xa0, 0x8b, - 0x08, 0xa5, 0x2c, 0xb4, 0x76, 0xef, 0xaf, 0x85, 0x34, 0x40, 0x93, 0xeb, - 0xd8, 0xdd, 0xe9, 0xeb, 0x27, 0x36, 0x66, 0x1d, 0xfb, 0xeb, 0xd9, 0x6d, - 0x46, 0xda, 0x79, 0x0d, 0xef, 0xd8, 0xef, 0x0d, 0x74, 0xce, 0x5b, 0xe2, - 0x53, 0xaf, 0x7f, 0x94, 0xdd, 0xc9, 0x82, 0x18, 0xbc, 0xe4, 0x29, 0x1d, - 0xa3, 0xf3, 0x7d, 0xdc, 0x6b, 0x3a, 0x2d, 0x36, 0xab, 0xef, 0xc2, 0x55, - 0x79, 0xa4, 0x88, 0x9e, 0x35, 0xf2, 0x11, 0x73, 0x3c, 0xcf, 0xa3, 0x02, - 0x0f, 0xdd, 0x1c, 0x9b, 0x00, 0x49, 0xbf, 0xb7, 0x49, 0x1a, 0x59, 0x58, - 0xc9, 0x54, 0x24, 0x28, 0xce, 0x75, 0x9c, 0xee, 0xcd, 0xbe, 0xe1, 0x1d, - 0x1a, 0x99, 0xb3, 0x9e, 0x98, 0xa7, 0xdf, 0x0f, 0x29, 0x7e, 0x48, 0xe3, - 0x64, 0x84, 0xe6, 0x65, 0x81, 0x6b, 0x6c, 0xc4, 0x8e, 0xc0, 0x89, 0x2b, - 0x52, 0xe2, 0xdd, 0xe1, 0x7d, 0x12, 0x49, 0xb7, 0xc7, 0xc0, 0x93, 0x97, - 0x72, 0x5e, 0x57, 0xba, 0x59, 0x5d, 0x01, 0xdb, 0x1e, 0xd8, 0x0f, 0x10, - 0xb8, 0x95, 0x03, 0x35, 0xab, 0x37, 0xd3, 0xd9, 0x1e, 0x3c, 0x91, 0x1b, - 0xba, 0xa7, 0xb1, 0x64, 0xca, 0x01, 0x2c, 0xab, 0x0f, 0x09, 0xf2, 0x59, - 0x12, 0x1a, 0x6c, 0x73, 0x37, 0x40, 0x73, 0x44, 0xb9, 0x1b, 0x54, 0x6c, - 0xbe, 0x7f, 0x51, 0x67, 0x80, 0x97, 0xb8, 0x02, 0xff, 0x12, 0x01, 0xc6, - 0xa5, 0x92, 0xd9, 0xe9, 0x91, 0x81, 0xcf, 0x69, 0x2d, 0x50, 0x9a, 0x95, - 0xc3, 0x28, 0x7e, 0x84, 0xb3, 0xbe, 0xf4, 0x2c, 0x1a, 0xea, 0xe0, 0x87, - 0x9b, 0xd7, 0xb3, 0xe0, 0x56, 0x28, 0xc1, 0xf3, 0x53, 0xbd, 0xdf, 0xd1, - 0x6e, 0x6b, 0x48, 0x6e, 0xd9, 0xb8, 0x81, 0xf8, 0x6d, 0x47, 0x5c, 0xd6, - 0x36, 0x8c, 0x5f, 0xa9, 0x17, 0x1a, 0x68, 0xcd, 0x4e, 0xf2, 0xd2, 0x18, - 0xe6, 0xb5, 0x9a, 0x03, 0x47, 0xdb, 0x27, 0x05, 0x8c, 0x3a, 0xb8, 0x2b, - 0x8f, 0x76, 0xd5, 0x26, 0xef, 0x18, 0x4b, 0x12, 0xcc, 0x40, 0xc7, 0x05, - 0xc9, 0x66, 0x05, 0xda, 0x71, 0x78, 0x11, 0x1a, 0x4e, 0xa0, 0x6d, 0xac, - 0x50, 0xc7, 0xf3, 0xf3, 0xaa, 0xe5, 0xce, 0x10, 0x2e, 0xf1, 0x5c, 0xd0, - 0xb1, 0x2b, 0xc6, 0x9d, 0x93, 0x59, 0xd6, 0x44, 0xb0, 0x96, 0xf4, 0x79, - 0x1a, 0x7c, 0x33, 0x6f, 0x60, 0xa0, 0xa7, 0xaa, 0xdc, 0x65, 0x61, 0xac, - 0x40, 0xf5, 0x23, 0x14, 0x1e, 0x1c, 0xdb, 0x4b, 0x7c, 0x45, 0x98, 0x13, - 0xbc, 0x99, 0xb9, 0xbe, 0x11, 0x4d, 0x68, 0x7b, 0x43, 0x85, 0x89, 0x87, - 0x20, 0x30, 0x47, 0x46, 0xbd, 0x95, 0x41, 0x41, 0x0b, 0x26, 0x6d, 0xff, - 0xa4, 0x2a, 0x83, 0xbc, 0xb7, 0xce, 0xb1, 0x26, 0xf6, 0xf0, 0x57, 0x65, - 0x14, 0xf4, 0xaa, 0x3b, 0xa2, 0xa8, 0x11, 0x0c, 0x77, 0x7d, 0x5e, 0xb4, - 0xa7, 0x17, 0x71, 0xc7, 0xb8, 0x30, 0xdd, 0x31, 0x74, 0xab, 0x6b, 0xcc, - 0x7a, 0x83, 0xb7, 0xec, 0x55, 0x18, 0x68, 0x97, 0x1b, 0xea, 0x99, 0xd4, - 0x54, 0x2f, 0xb9, 0xec, 0x73, 0x5e, 0xb5, 0x05, 0xaf, 0x62, 0xde, 0xae, - 0xf6, 0x45, 0x67, 0x3f, 0xb0, 0x19, 0x6c, 0x20, 0xff, 0x4c, 0xda, 0xc8, - 0xbe, 0x44, 0xd5, 0xf9, 0x30, 0xdf, 0x67, 0x77, 0xc8, 0x39, 0x36, 0x83, - 0x00, 0x7c, 0x81, 0x9d, 0xd3, 0xd5, 0x98, 0x78, 0xd5, 0x32, 0xd1, 0xc0, - 0x7c, 0x79, 0x78, 0x07, 0xd7, 0x9c, 0xc4, 0xa6, 0x7d, 0xa1, 0xb5, 0x4d, - 0x21, 0xce, 0x95, 0x54, 0x08, 0x7c, 0xab, 0xf4, 0x0b, 0x75, 0x32, 0x63, - 0xd4, 0xf3, 0x7c, 0x02, 0x34, 0xae, 0x49, 0x15, 0x37, 0x72, 0x20, 0x4d, - 0x60, 0xe7, 0x29, 0xbb, 0xcb, 0x89, 0x11, 0xc0, 0x77, 0x53, 0xd4, 0x32, - 0xc6, 0x9e, 0x55, 0x03, 0xf7, 0xd4, 0xf9, 0x66, 0xf0, 0x65, 0x07, 0x9e, - 0x31, 0x09, 0x06, 0x91, 0xf6, 0x1b, 0xc9, 0xaa, 0x45, 0xd4, 0xf4, 0xd0, - 0x33, 0x99, 0x02, 0x0e, 0x22, 0xe1, 0xb2, 0x5e, 0x82, 0x46, 0x2a, 0x37, - 0xf3, 0x7a, 0xb2, 0x5e, 0x2f, 0x5c, 0x36, 0xb7, 0x1f, 0x44, 0xc6, 0x0a, - 0x01, 0xde, 0xec, 0x13, 0x2d, 0x78, 0x81, 0x63, 0xbb, 0x81, 0x3f, 0xc8, - 0xc4, 0xe6, 0xeb, 0x26, 0xb4, 0xde, 0x2e, 0xdc, 0xcb, 0x74, 0xe4, 0x7a, - 0x10, 0x9a, 0xec, 0x7e, 0xf4, 0x4a, 0xf0, 0x42, 0x38, 0xcf, 0x78, 0x65, - 0x43, 0x2c, 0x69, 0x14, 0xa9, 0x5c, 0x28, 0x0c, 0xde, 0x43, 0xd7, 0x40, - 0x97, 0xb4, 0x45, 0xda, 0xbc, 0x8f, 0x35, 0xd9, 0x14, 0x86, 0x45, 0x69, - 0x2a, 0x34, 0xe0, 0x3e, 0x1d, 0xb0, 0xe1, 0x1b, 0xf4, 0x84, 0x8b, 0xdd, - 0xa0, 0xa6, 0x0e, 0x98, 0x75, 0x4d, 0x2e, 0x59, 0xda, 0xbf, 0x92, 0x49, - 0x3d, 0x80, 0x1b, 0x2e, 0xa0, 0x73, 0xbb, 0x43, 0x22, 0x53, 0x98, 0xdf, - 0x2c, 0x8a, 0x87, 0x57, 0xd1, 0xac, 0xb4, 0xd8, 0x03, 0xdf, 0xd7, 0x9e, - 0xf4, 0x58, 0x03, 0x4e, 0x9b, 0xc4, 0x2e, 0x4c, 0x7b, 0xe3, 0xa8, 0xc0, - 0x33, 0xfb, 0x6b, 0x33, 0x74, 0xaa, 0xdd, 0x5e, 0x3b, 0x59, 0xd8, 0xc7, - 0x53, 0xec, 0x45, 0x56, 0xd6, 0xe2, 0x6b, 0x51, 0xb3, 0xf9, 0x1e, 0x79, - 0x58, 0x98, 0xe1, 0x18, 0x2a, 0x64, 0x4b, 0xcf, 0x5a, 0x82, 0xce, 0xb7, - 0x60, 0x9c, 0xa3, 0xc2, 0x09, 0xe6, 0xe7, 0x58, 0xa0, 0x9e, 0x31, 0x0d, - 0xdb, 0xc6, 0xca, 0x5d, 0xf1, 0xe4, 0x28, 0x78, 0x63, 0x60, 0x27, 0xea, - 0x90, 0x7b, 0x01, 0x18, 0x5d, 0xf8, 0x95, 0x9f, 0x18, 0x27, 0x9d, 0xc6, - 0xab, 0x81, 0xb6, 0x20, 0x70, 0xdb, 0xea, 0x7d, 0x44, 0xa0, 0xcd, 0x13, - 0xf5, 0x2c, 0xda, 0x00, 0xef, 0x8d, 0x55, 0xcb, 0x80, 0x0b, 0xc1, 0x53, - 0x8a, 0x78, 0x7e, 0x46, 0xc3, 0x14, 0xe7, 0x74, 0x65, 0x49, 0x55, 0x79, - 0x07, 0xce, 0xe6, 0x67, 0x17, 0x08, 0x7c, 0x1f, 0x11, 0x26, 0xd9, 0x83, - 0xe7, 0xd2, 0x0a, 0x43, 0x4f, 0xa2, 0xd6, 0xd5, 0x0f, 0xbe, 0x3c, 0x43, - 0xdc, 0x85, 0xa0, 0x19, 0x1b, 0x6a, 0xa2, 0xef, 0xa2, 0x19, 0x70, 0x91, - 0x90, 0x26, 0x84, 0x3c, 0x62, 0xbc, 0x52, 0x47, 0xd0, 0xa4, 0x80, 0x8f, - 0xfc, 0x98, 0x62, 0xc0, 0x3c, 0x94, 0x84, 0xae, 0xa5, 0x4a, 0x2a, 0x20, - 0x77, 0xe0, 0x7a, 0x1b, 0x7d, 0x7b, 0x4c, 0x82, 0x1e, 0x77, 0x80, 0x01, - 0xcd, 0x78, 0x3b, 0x20, 0xf1, 0x9d, 0x01, 0x67, 0xc8, 0x49, 0xc4, 0x85, - 0x83, 0xb7, 0xa1, 0x17, 0xec, 0x44, 0x07, 0x5c, 0xe8, 0x90, 0x57, 0x69, - 0x9c, 0x2c, 0x9e, 0x88, 0x5b, 0xd2, 0x82, 0x1f, 0x57, 0x01, 0x05, 0x6f, - 0x3f, 0x64, 0xda, 0xf6, 0x15, 0x69, 0xbd, 0x8f, 0x79, 0x45, 0xe0, 0xf3, - 0x6c, 0x37, 0xb1, 0x05, 0x78, 0x12, 0x23, 0xd3, 0x64, 0x3a, 0xeb, 0x0d, - 0x6c, 0x8a, 0x08, 0x7c, 0x77, 0x9b, 0x78, 0x3d, 0xcb, 0xdd, 0x72, 0xe6, - 0xd6, 0xec, 0xe0, 0x59, 0xef, 0xd2, 0xc5, 0x1a, 0xbc, 0x8e, 0x31, 0xeb, - 0x41, 0xd7, 0xe3, 0x80, 0xa7, 0xb6, 0x1f, 0x25, 0xb2, 0x82, 0xf7, 0xef, - 0xa2, 0x56, 0x36, 0xe6, 0x92, 0x60, 0xad, 0xaf, 0x4a, 0xd4, 0xef, 0x0f, - 0x5c, 0x3c, 0x88, 0x81, 0xbf, 0xb9, 0x2b, 0x02, 0xc0, 0x54, 0x2a, 0x5c, - 0x88, 0x77, 0x53, 0x05, 0x12, 0x7a, 0x9b, 0x68, 0xcd, 0x08, 0xfe, 0x76, - 0x49, 0xcf, 0x83, 0xce, 0x8c, 0xfe, 0x01, 0x7a, 0x76, 0x2c, 0x6a, 0x39, - 0x15, 0xc8, 0x86, 0xe4, 0x24, 0xd1, 0x5e, 0x63, 0x3c, 0xf6, 0xd8, 0x7e, - 0xaf, 0xcd, 0xeb, 0xa7, 0x86, 0xf9, 0xee, 0xc0, 0xec, 0x27, 0x06, 0xde, - 0x08, 0x3d, 0xf4, 0x56, 0xdb, 0x9c, 0x9f, 0xde, 0xd8, 0x23, 0xcb, 0xdc, - 0xd3, 0x7b, 0xe1, 0x13, 0x14, 0xb5, 0x10, 0xa3, 0x8d, 0xae, 0x93, 0x66, - 0x3c, 0x17, 0x66, 0x34, 0x66, 0xc6, 0x2a, 0xcb, 0x13, 0x3c, 0x31, 0x0a, - 0x5a, 0xa9, 0xa9, 0x12, 0x11, 0x7f, 0x8d, 0x8c, 0xb1, 0x73, 0xc9, 0xfa, - 0x4c, 0x00, 0xbf, 0x4b, 0x03, 0xbd, 0x33, 0xbe, 0xba, 0x82, 0x26, 0xde, - 0xc7, 0xcd, 0xb0, 0x8f, 0x6b, 0xf7, 0x95, 0x6b, 0xc3, 0x05, 0x78, 0x26, - 0x66, 0xde, 0xd6, 0x8c, 0xcc, 0x3e, 0xcf, 0x4c, 0xd0, 0x32, 0xa0, 0x21, - 0x4a, 0x04, 0xce, 0x7e, 0x6a, 0x2c, 0xc8, 0x93, 0x37, 0xf8, 0x06, 0x0d, - 0x1b, 0x6c, 0x8b, 0xa7, 0x40, 0x93, 0x35, 0xe0, 0x15, 0x12, 0x23, 0x6f, - 0xc5, 0xae, 0xe8, 0x02, 0x12, 0x2a, 0xb5, 0x09, 0x11, 0x8c, 0xb7, 0x0b, - 0x1a, 0x2d, 0x61, 0x0b, 0xe9, 0xe9, 0x94, 0x01, 0xf6, 0x97, 0x09, 0xe0, - 0x1f, 0x2a, 0xf5, 0x18, 0x38, 0x21, 0xe2, 0xa0, 0x5b, 0x75, 0xa2, 0x12, - 0x25, 0x46, 0x3c, 0x55, 0x46, 0x62, 0x60, 0xe0, 0xbc, 0xfb, 0xbb, 0xa4, - 0xe3, 0x78, 0xa4, 0x02, 0x70, 0x00, 0x54, 0xac, 0x21, 0x72, 0xee, 0x07, - 0x04, 0xb8, 0x77, 0x0f, 0x73, 0xa5, 0x97, 0x1a, 0xf8, 0x12, 0x3f, 0x68, - 0x4a, 0xad, 0xb9, 0xe5, 0x5d, 0xf3, 0x3a, 0xfa, 0x55, 0x7d, 0xac, 0xab, - 0x0e, 0xfa, 0x18, 0x00, 0x87, 0x2e, 0xc1, 0x3e, 0x58, 0x05, 0xbb, 0x3c, - 0xe1, 0x9a, 0x92, 0x9d, 0xb1, 0xba, 0x63, 0x67, 0x3d, 0xaf, 0x27, 0xa6, - 0x25, 0x6a, 0x4c, 0xc0, 0xbf, 0x06, 0x4f, 0x62, 0x0f, 0xfa, 0xc2, 0x9e, - 0xd7, 0x7b, 0x65, 0x89, 0xbd, 0xa5, 0x8d, 0x02, 0xbd, 0x66, 0x81, 0xe6, - 0xad, 0x2e, 0xa2, 0xb1, 0x62, 0x32, 0x55, 0x53, 0x36, 0xa9, 0x57, 0x0c, - 0xde, 0x36, 0xf6, 0x21, 0x1d, 0x5c, 0x45, 0x40, 0xeb, 0x3d, 0x8b, 0xba, - 0x62, 0x65, 0x47, 0xc7, 0x78, 0x22, 0x71, 0xe1, 0x8d, 0x9c, 0x3b, 0x01, - 0x4d, 0x4c, 0xf0, 0xf7, 0xf4, 0x62, 0x82, 0x1e, 0x1b, 0x89, 0x36, 0x6c, - 0xe0, 0xf7, 0x57, 0xa8, 0x2e, 0x26, 0xf3, 0x42, 0xc0, 0x53, 0xe4, 0xe2, - 0x69, 0xfb, 0x2a, 0x50, 0xf8, 0x3c, 0xaa, 0xca, 0x39, 0x36, 0x77, 0x4b, - 0x1a, 0x2a, 0x2f, 0x3c, 0x16, 0x53, 0xc3, 0x7a, 0xb0, 0xa6, 0xfa, 0xce, - 0x6a, 0x49, 0x20, 0xaf, 0x05, 0xa8, 0x8a, 0x57, 0xd6, 0x5d, 0x16, 0xb1, - 0x29, 0x1a, 0xc1, 0x11, 0x82, 0xb6, 0x7d, 0xf1, 0x5e, 0x79, 0x04, 0xbc, - 0x36, 0xc4, 0xf7, 0x08, 0xd7, 0xe5, 0xd1, 0x29, 0x9c, 0x80, 0xbf, 0xb7, - 0x21, 0xf8, 0xdb, 0xc4, 0x58, 0x55, 0xe4, 0x3c, 0x1c, 0xb0, 0x8a, 0x6e, - 0x05, 0xbf, 0x3f, 0x23, 0x3a, 0x3c, 0x72, 0x5f, 0xf2, 0xbd, 0x2e, 0x28, - 0x31, 0x86, 0xa1, 0xd8, 0x0c, 0x8f, 0xc3, 0xbc, 0xbe, 0xd9, 0xb3, 0x30, - 0xe8, 0xa9, 0x31, 0x64, 0xfd, 0x84, 0x6b, 0x35, 0x60, 0x63, 0xa5, 0x98, - 0xc1, 0x40, 0x63, 0x8e, 0x5e, 0x91, 0x54, 0x80, 0xcd, 0x56, 0x06, 0xda, - 0x60, 0x4c, 0x6a, 0xd4, 0x1f, 0x5b, 0xf1, 0x02, 0x0e, 0x64, 0x2c, 0x15, - 0x1b, 0xea, 0x30, 0x06, 0x7d, 0x42, 0x3b, 0xc3, 0x32, 0x4a, 0xae, 0xea, - 0xa4, 0x85, 0x98, 0x6e, 0x83, 0x07, 0x53, 0xc1, 0x23, 0xf1, 0x5c, 0x43, - 0x24, 0x4c, 0x15, 0x20, 0xff, 0x8f, 0x4c, 0xc6, 0x99, 0x92, 0x31, 0x68, - 0xa9, 0x01, 0xfa, 0x6c, 0x16, 0xda, 0x0a, 0x74, 0x38, 0x7a, 0x15, 0xf1, - 0x00, 0x6e, 0xb5, 0xaa, 0xe8, 0xbc, 0x7f, 0x63, 0xda, 0xea, 0xf3, 0xda, - 0xa5, 0x72, 0x6a, 0x5e, 0x18, 0x3c, 0x8e, 0xf0, 0x91, 0x7d, 0x60, 0xea, - 0x8e, 0x95, 0x80, 0xf9, 0x00, 0x6f, 0xc8, 0xd9, 0x05, 0xf2, 0xfb, 0x99, - 0x51, 0x05, 0xfe, 0x71, 0xfb, 0xda, 0xe9, 0x82, 0xc7, 0xe8, 0x32, 0xca, - 0xa6, 0x31, 0x92, 0xc6, 0x7a, 0x16, 0xc6, 0xe2, 0xcd, 0x5a, 0xcb, 0x04, - 0xac, 0x3a, 0x33, 0x50, 0x65, 0x21, 0x78, 0x4f, 0xd0, 0x34, 0x6f, 0xc2, - 0xad, 0x73, 0x64, 0x34, 0x23, 0x6d, 0x81, 0x03, 0x1d, 0x7b, 0x10, 0xc6, - 0x8a, 0x94, 0xf3, 0x7e, 0x13, 0x6d, 0x61, 0x32, 0xa7, 0x62, 0xa1, 0x87, - 0x80, 0x0f, 0x03, 0x7f, 0x5e, 0xdb, 0x12, 0xea, 0xb2, 0x02, 0xce, 0x9b, - 0x32, 0x83, 0x45, 0x91, 0x46, 0xdc, 0x98, 0xb3, 0x74, 0xf7, 0x5e, 0xf9, - 0x09, 0xcf, 0x74, 0xce, 0xaa, 0xfa, 0xe0, 0x2b, 0x60, 0x33, 0x0b, 0xb4, - 0x0f, 0x79, 0xf2, 0x34, 0xe8, 0x62, 0x4e, 0x40, 0x5f, 0xcb, 0xe6, 0xe8, - 0xc8, 0x30, 0x36, 0xe8, 0x0b, 0xe2, 0x20, 0xdd, 0x19, 0x7d, 0x5e, 0xf2, - 0x15, 0x68, 0xaa, 0xf0, 0x1d, 0x81, 0x1e, 0xc2, 0x3a, 0xea, 0xf8, 0x79, - 0xa0, 0xe0, 0x07, 0x19, 0x60, 0x77, 0x5a, 0x70, 0xf1, 0x1d, 0xa9, 0x70, - 0xa2, 0x5e, 0xc5, 0x78, 0x8b, 0x69, 0xae, 0x54, 0x9c, 0x77, 0x04, 0xf0, - 0x59, 0xe5, 0x61, 0xab, 0x58, 0xc6, 0x41, 0x97, 0xb6, 0xb2, 0x4e, 0xc0, - 0x53, 0x25, 0xc6, 0x18, 0xe5, 0x7a, 0xe5, 0x94, 0x8e, 0xbc, 0x48, 0x5e, - 0x81, 0xb6, 0x0c, 0xdf, 0xa1, 0x36, 0xcc, 0x39, 0xa6, 0x15, 0x75, 0xd0, - 0xec, 0x27, 0xf5, 0xcc, 0x55, 0x10, 0xee, 0xcc, 0xc0, 0x8a, 0xa7, 0xe0, - 0x5a, 0x7a, 0xe3, 0x35, 0xd3, 0x2c, 0xe0, 0xf5, 0x00, 0x5c, 0xb5, 0xbc, - 0x1c, 0x9d, 0x6a, 0x04, 0x3d, 0x5e, 0x91, 0xc4, 0x76, 0x42, 0xbf, 0x7f, - 0xc9, 0xf9, 0xfe, 0x54, 0x2d, 0xe6, 0xfb, 0x7b, 0x2d, 0x35, 0x58, 0x02, - 0x5a, 0x73, 0x5f, 0xb6, 0x99, 0x55, 0xd4, 0x6b, 0x93, 0x69, 0xe3, 0x42, - 0x78, 0x43, 0x12, 0x32, 0x82, 0x12, 0xae, 0xa7, 0xc2, 0xb5, 0xc6, 0x9d, - 0x59, 0x8e, 0x7b, 0x93, 0x80, 0x7f, 0x5a, 0xf5, 0x05, 0x6b, 0x6e, 0x47, - 0x8e, 0xac, 0x7c, 0x5e, 0x43, 0x5d, 0xcb, 0x7d, 0xc2, 0x57, 0x43, 0x8e, - 0xfa, 0xb1, 0x48, 0x94, 0xc7, 0x98, 0x48, 0xc2, 0x16, 0x3c, 0x0a, 0x8b, - 0xf4, 0xa2, 0x41, 0x02, 0xce, 0x13, 0x24, 0x3e, 0x36, 0x0a, 0xa5, 0x3c, - 0xec, 0xcd, 0x6b, 0xbe, 0x18, 0x05, 0x6f, 0xe1, 0x16, 0xfc, 0xa2, 0x83, - 0xd6, 0x3f, 0x94, 0x2e, 0xf8, 0xed, 0xce, 0xce, 0xe2, 0x79, 0x55, 0x1d, - 0x68, 0x89, 0x3c, 0xc9, 0x6e, 0x61, 0x22, 0xe3, 0x5c, 0x55, 0xac, 0xa8, - 0x33, 0x3d, 0x9e, 0x39, 0xa6, 0x66, 0xaa, 0x64, 0xd5, 0x3d, 0xd1, 0x46, - 0x9f, 0xe8, 0xeb, 0xf7, 0xd1, 0x61, 0xe0, 0xb7, 0xed, 0x85, 0x34, 0x4f, - 0x53, 0xa2, 0x81, 0xc7, 0x30, 0x56, 0x1d, 0x78, 0xbe, 0x48, 0x34, 0x10, - 0x43, 0x6d, 0xf0, 0x9c, 0xf7, 0x53, 0x73, 0x9f, 0x6d, 0x93, 0x06, 0xed, - 0x45, 0x1b, 0xec, 0x8e, 0x3c, 0x78, 0xe0, 0x46, 0xaf, 0x71, 0x2d, 0xbe, - 0x45, 0x13, 0xec, 0x33, 0x33, 0x7b, 0x1f, 0xf8, 0xea, 0x21, 0xe6, 0x35, - 0x2d, 0x4e, 0x60, 0xe5, 0x5c, 0x1d, 0xb2, 0xe6, 0x72, 0x3b, 0x82, 0xb7, - 0x0c, 0x9b, 0x4a, 0x0b, 0xe9, 0x62, 0x04, 0x8d, 0xa5, 0x27, 0xcc, 0xee, - 0xcb, 0xae, 0xc2, 0x80, 0xf9, 0xdf, 0xb2, 0x1d, 0x02, 0xd6, 0x81, 0x7f, - 0xd4, 0x65, 0x1f, 0x35, 0xab, 0x7d, 0xee, 0xa1, 0x7d, 0xe1, 0xd8, 0xaf, - 0x98, 0x0a, 0xe0, 0xd4, 0xc8, 0x8a, 0x5d, 0xec, 0x08, 0x13, 0xe2, 0x9d, - 0xea, 0x06, 0x60, 0x66, 0x47, 0x50, 0xf0, 0x0d, 0xf3, 0x12, 0x90, 0x4e, - 0x88, 0x88, 0xc1, 0x67, 0x8c, 0xc6, 0x84, 0xf1, 0x38, 0xe7, 0x3a, 0x05, - 0xbf, 0x83, 0xf6, 0xa0, 0x69, 0x37, 0x39, 0x15, 0x15, 0xd3, 0x18, 0x12, - 0x2d, 0x9d, 0x0a, 0xd5, 0x4f, 0xbc, 0xa6, 0x0b, 0xec, 0x82, 0xd6, 0x76, - 0xd1, 0x81, 0xd4, 0xe2, 0x72, 0x74, 0x11, 0x8c, 0x09, 0xf6, 0x43, 0x4f, - 0x1e, 0x40, 0x97, 0x25, 0x71, 0xcb, 0x02, 0x86, 0xe4, 0x54, 0xba, 0xca, - 0x2b, 0x7d, 0x81, 0x32, 0x3a, 0xcc, 0xfb, 0x90, 0x88, 0xa0, 0xc3, 0x53, - 0xa6, 0x2c, 0x0e, 0xf9, 0x38, 0x61, 0x55, 0xdd, 0xa8, 0x86, 0x82, 0x1c, - 0x54, 0x0e, 0x46, 0xc1, 0x93, 0x33, 0xf0, 0x65, 0x5c, 0x44, 0x78, 0x42, - 0x35, 0xf8, 0xc2, 0x06, 0xb0, 0xee, 0x0d, 0x7e, 0xc4, 0x86, 0xeb, 0x53, - 0xa5, 0x87, 0x49, 0xe2, 0xe1, 0x65, 0xde, 0x89, 0x54, 0x34, 0xf3, 0xfd, - 0x01, 0xb5, 0x14, 0x35, 0xb6, 0x40, 0x8f, 0x69, 0x94, 0xe2, 0xa7, 0x54, - 0x14, 0xbc, 0xaa, 0x78, 0xf1, 0x84, 0x50, 0xd6, 0x04, 0x63, 0x9c, 0xa8, - 0x51, 0xfa, 0xb6, 0x96, 0x01, 0x5e, 0xe7, 0xcd, 0x18, 0x45, 0x54, 0xb7, - 0x67, 0x7c, 0x4d, 0x14, 0x7a, 0xd3, 0x54, 0xba, 0x58, 0x0f, 0x6f, 0xcc, - 0x27, 0xe0, 0x89, 0xc1, 0x9b, 0x24, 0x6b, 0x8d, 0x76, 0x80, 0xe3, 0x8d, - 0xcc, 0x21, 0xb6, 0xa2, 0x58, 0x63, 0xa0, 0xcb, 0x82, 0x0a, 0x9b, 0x55, - 0x0a, 0x7a, 0x2e, 0x06, 0x2e, 0x69, 0x61, 0x1c, 0x77, 0xc7, 0x96, 0xd4, - 0x25, 0x1d, 0xae, 0x99, 0x19, 0x8c, 0x25, 0xdf, 0x2e, 0x8e, 0x49, 0x65, - 0xe7, 0xbf, 0xc6, 0x9b, 0x40, 0x6e, 0x02, 0x8b, 0x1a, 0xc3, 0x1e, 0xb8, - 0x37, 0x00, 0xad, 0x1a, 0x32, 0x46, 0xde, 0x31, 0x62, 0xdf, 0xa1, 0x8f, - 0x83, 0xc4, 0x9d, 0x55, 0x41, 0xff, 0x04, 0x4e, 0x81, 0x1c, 0xe9, 0x07, - 0xd0, 0xa6, 0x1b, 0xa1, 0x29, 0x01, 0xda, 0x2d, 0x3f, 0x52, 0x85, 0xa8, - 0x16, 0x04, 0x90, 0xdf, 0x63, 0xdc, 0x58, 0x97, 0xbd, 0x1e, 0x1a, 0x39, - 0x23, 0x1b, 0xa6, 0xbd, 0x74, 0x18, 0x15, 0x7f, 0x37, 0x61, 0xb7, 0x60, - 0x41, 0x05, 0xbe, 0xb0, 0xa2, 0xb3, 0x5f, 0x40, 0x41, 0x50, 0x1a, 0xab, - 0x67, 0xa1, 0x8b, 0x27, 0x01, 0x34, 0x0b, 0x67, 0x6f, 0xd3, 0xaa, 0x3e, - 0x6a, 0x51, 0x4f, 0x67, 0xbe, 0x9f, 0xfb, 0xa7, 0xa9, 0xa0, 0xf0, 0x51, - 0x40, 0xda, 0xd1, 0x4f, 0x26, 0x7b, 0x8e, 0xe1, 0xe8, 0x08, 0x7a, 0xbb, - 0x30, 0x14, 0xcf, 0x12, 0x44, 0xb0, 0x1e, 0xa4, 0x92, 0x33, 0xd0, 0xc6, - 0x04, 0x74, 0x79, 0xcf, 0xcb, 0x79, 0x0f, 0x80, 0x57, 0x9d, 0xb3, 0x1a, - 0xd3, 0xd2, 0xad, 0x38, 0x60, 0xa2, 0xc7, 0x8c, 0xe1, 0xbb, 0xa4, 0x98, - 0x83, 0xfe, 0x63, 0x54, 0x1b, 0x05, 0xf4, 0x9b, 0xcf, 0xb7, 0xb3, 0xe0, - 0xf8, 0x7b, 0x49, 0xfb, 0x38, 0x4e, 0x49, 0x5f, 0x98, 0x36, 0x87, 0x9f, - 0x0e, 0x60, 0x44, 0x5a, 0x18, 0x23, 0xca, 0x93, 0x60, 0x9f, 0xf3, 0x91, - 0xe5, 0x89, 0xbd, 0x8f, 0xf4, 0xbe, 0xca, 0x67, 0x49, 0x8f, 0xd4, 0x18, - 0x83, 0x73, 0x4b, 0x10, 0x7a, 0xc6, 0xed, 0x38, 0xc6, 0x2a, 0x98, 0x79, - 0xec, 0x59, 0x22, 0x11, 0xc0, 0x2c, 0x74, 0x05, 0x93, 0x4f, 0xd0, 0x9e, - 0x7d, 0xd8, 0x0c, 0x7d, 0x81, 0xe0, 0xa7, 0x3b, 0x38, 0x1c, 0xfa, 0xc2, - 0x1c, 0xe2, 0x0a, 0xbe, 0xba, 0x33, 0x63, 0x15, 0x81, 0x43, 0x4d, 0xcb, - 0x1a, 0xbc, 0xe1, 0x64, 0x43, 0x3e, 0x54, 0x0b, 0x56, 0x8b, 0x08, 0x70, - 0xff, 0xff, 0xf2, 0xde, 0x6e, 0xa1, 0x6d, 0x2d, 0x6c, 0xe0, 0x7f, 0xd8, - 0x47, 0xbe, 0xa2, 0xe0, 0xbf, 0xbb, 0x3c, 0x45, 0x63, 0xf9, 0xa7, 0xfc, - 0xc5, 0x81, 0xa0, 0x15, 0x5c, 0xc7, 0x1f, 0xed, 0x33, 0x7b, 0xd8, 0x6b, - 0xd6, 0x33, 0x36, 0xff, 0xac, 0xf6, 0x03, 0x3b, 0x76, 0x03, 0x33, 0xfe, - 0xa3, 0xff, 0x94, 0xad, 0x0d, 0x88, 0xc7, 0x2a, 0xfa, 0x93, 0xda, 0x8f, - 0x4d, 0xb6, 0x8c, 0xfe, 0x61, 0x6f, 0x75, 0xae, 0xaf, 0xad, 0x12, 0x78, - 0xf0, 0xcf, 0x1a, 0xff, 0xc8, 0xb0, 0x34, 0xa9, 0xa9, 0xbf, 0xc7, 0x03, - 0x66, 0x6b, 0xe0, 0x65, 0xbc, 0x2f, 0xff, 0xa4, 0xf6, 0xc1, 0xc3, 0x6b, - 0x99, 0xf6, 0x1f, 0x71, 0xbb, 0x33, 0xb6, 0x8b, 0xb0, 0x95, 0xe3, 0x9f, - 0xd5, 0x7e, 0xa9, 0x01, 0xae, 0xba, 0xa8, 0xfb, 0xbd, 0xfd, 0xc0, 0xde, - 0x9b, 0x2e, 0xf8, 0x84, 0xd5, 0x9f, 0xd3, 0x7f, 0xbe, 0x1a, 0xb1, 0xa6, - 0xfb, 0xff, 0x51, 0xd7, 0x00, 0x13, 0xc8, 0xbd, 0x29, 0xef, 0xd0, 0x9f, - 0x34, 0xfe, 0xf6, 0x5e, 0x24, 0x78, 0xde, 0xd7, 0xfe, 0x7b, 0xff, 0x35, - 0xf2, 0xdc, 0xbf, 0x07, 0x0d, 0x34, 0x87, 0x53, 0x68, 0xff, 0x37, 0xd6, - 0x8f, 0x60, 0x95, 0xcd, 0x7c, 0xdb, 0x4b, 0x26, 0xfa, 0x16, 0x7c, 0xa8, - 0x40, 0xee, 0xfe, 0x6d, 0xbc, 0x77, 0x54, 0x51, 0x9d, 0xa4, 0xc1, 0x2d, - 0x6e, 0xc1, 0x99, 0x4f, 0xda, 0xea, 0x8f, 0x3a, 0x27, 0xbf, 0xd7, 0x0b, - 0xe9, 0xc8, 0x7c, 0x5f, 0xed, 0x57, 0xbd, 0x90, 0xb9, 0x36, 0x89, 0x30, - 0xe8, 0xb3, 0xf4, 0xac, 0xee, 0x3f, 0x1f, 0x83, 0x41, 0xc7, 0xb2, 0xe9, - 0x57, 0x3d, 0x13, 0xf0, 0x30, 0x61, 0x4d, 0x16, 0x61, 0xb2, 0x7e, 0xe3, - 0xcd, 0x1f, 0x75, 0x4f, 0x7e, 0xaf, 0x3b, 0x32, 0xef, 0x75, 0x7c, 0x15, - 0x26, 0xfe, 0xbd, 0xe6, 0x4b, 0xab, 0x57, 0xa5, 0x31, 0x54, 0x59, 0x3b, - 0xaa, 0xed, 0xe9, 0xf2, 0xeb, 0x98, 0x9f, 0xf1, 0x1f, 0xe7, 0xf4, 0xef, - 0xff, 0x78, 0xee, 0x77, 0xf6, 0x9e, 0xeb, 0xb0, 0x04, 0x4d, 0x96, 0x92, - 0xea, 0xd0, 0xaa, 0x21, 0xe3, 0x52, 0xed, 0x4d, 0xfb, 0x21, 0xa6, 0xe1, - 0x9c, 0xa5, 0x58, 0xe1, 0x3a, 0xba, 0xe7, 0x4c, 0x6c, 0x12, 0x3d, 0x30, - 0x01, 0xa7, 0x7d, 0xe0, 0xac, 0x5f, 0x7d, 0x4e, 0xd4, 0xbc, 0x3e, 0x10, - 0xd4, 0xd4, 0x3c, 0x8e, 0xcd, 0xf8, 0x2b, 0xbf, 0xe9, 0x64, 0x3b, 0x33, - 0xe7, 0xc2, 0xef, 0x9b, 0xc4, 0xa8, 0x2a, 0xa2, 0x07, 0xbf, 0x8e, 0xe5, - 0x09, 0xfc, 0x9b, 0x09, 0xc4, 0xc0, 0x33, 0x89, 0xba, 0x9a, 0xeb, 0x4b, - 0xb0, 0xa8, 0xc1, 0x0b, 0xc2, 0x04, 0x23, 0xc6, 0xaa, 0xc9, 0x6a, 0x16, - 0x80, 0xef, 0x9a, 0xf2, 0x09, 0xe9, 0x7b, 0x4d, 0xb9, 0xa4, 0x3d, 0xbd, - 0xf2, 0xb6, 0xda, 0x43, 0x7b, 0x18, 0x88, 0x68, 0x92, 0xba, 0x7d, 0x23, - 0x9a, 0x4a, 0xa4, 0xa1, 0x5f, 0xb3, 0x56, 0x9a, 0x65, 0xc7, 0x10, 0x01, - 0xaf, 0x49, 0xa9, 0x75, 0xc8, 0x0d, 0x9c, 0x71, 0x7a, 0x9a, 0xd7, 0xac, - 0xa9, 0x52, 0x17, 0xe9, 0xbc, 0x4d, 0x68, 0xde, 0x67, 0x25, 0xda, 0x08, - 0x7c, 0xd5, 0x30, 0x3f, 0x37, 0xd2, 0x4b, 0x47, 0xdd, 0x32, 0xd5, 0x83, - 0x0e, 0x26, 0xcf, 0x03, 0x43, 0xf3, 0x7a, 0x00, 0x52, 0x1a, 0x8b, 0xc5, - 0xc1, 0x0b, 0x2a, 0x18, 0x33, 0x42, 0x1d, 0x44, 0x72, 0x4f, 0xec, 0x13, - 0xf0, 0xb0, 0x44, 0x47, 0xc0, 0x4d, 0xba, 0x9d, 0x68, 0x5f, 0x2f, 0x9c, - 0xda, 0x8f, 0x82, 0xf5, 0xdf, 0x73, 0x1f, 0x0a, 0xef, 0xfe, 0x02, 0xce, - 0x22, 0x4c, 0x6d, 0xb5, 0xb0, 0xfb, 0x47, 0x4c, 0xc3, 0x76, 0x01, 0x9a, - 0xaf, 0x74, 0x33, 0x23, 0xd7, 0xb0, 0xfd, 0xe7, 0xd4, 0x2b, 0x91, 0x2e, - 0xc4, 0xc1, 0x7f, 0xd4, 0x8b, 0xa0, 0xfa, 0x75, 0xde, 0x17, 0x47, 0x14, - 0xfb, 0xb3, 0xea, 0x45, 0xb0, 0x03, 0xfd, 0x7b, 0xbd, 0x88, 0x99, 0xd3, - 0x76, 0x7b, 0x23, 0x20, 0xf4, 0x4f, 0xab, 0x57, 0x21, 0x11, 0x75, 0x49, - 0xf7, 0xf7, 0x7a, 0x11, 0xba, 0xbd, 0x10, 0xcd, 0xbc, 0xd6, 0xee, 0x4f, - 0x6a, 0xbf, 0x25, 0x3d, 0x71, 0x91, 0xf9, 0xb7, 0x7a, 0x31, 0xf1, 0xbc, - 0xd7, 0x1c, 0x05, 0xf7, 0xe8, 0x4f, 0x6a, 0x9f, 0xb4, 0xe2, 0xfc, 0xf7, - 0x5a, 0x2d, 0xf0, 0xf7, 0x38, 0x3f, 0xff, 0xa1, 0x8c, 0xff, 0x59, 0xe3, - 0x9f, 0xa3, 0xe8, 0x85, 0x5d, 0xf6, 0xf7, 0xf6, 0x0f, 0xde, 0xc2, 0x92, - 0x6e, 0xe0, 0xfd, 0x59, 0xf5, 0x42, 0x38, 0x73, 0x17, 0x89, 0x16, 0xfc, - 0x8d, 0x53, 0xec, 0xbd, 0x96, 0x2d, 0x32, 0x85, 0xfe, 0xac, 0x5a, 0x35, - 0x3c, 0x6c, 0x14, 0x86, 0xf9, 0xff, 0x9b, 0xa6, 0xe9, 0xc0, 0xdb, 0x36, - 0x44, 0x67, 0x7f, 0x52, 0xff, 0x19, 0x17, 0x3e, 0x7b, 0x16, 0x80, 0x4f, - 0xa1, 0xb7, 0x72, 0x4a, 0x8a, 0x9e, 0xb2, 0xad, 0x14, 0x6d, 0x57, 0x63, - 0xc4, 0x40, 0x43, 0x1b, 0xc3, 0xf9, 0x18, 0xaf, 0x16, 0xe0, 0xed, 0x48, - 0x8c, 0xd4, 0x3b, 0xec, 0xec, 0x1e, 0x9b, 0xc1, 0x0b, 0xeb, 0xd1, 0x8d, - 0x98, 0xb8, 0xa1, 0xff, 0x35, 0xa6, 0x38, 0x71, 0x32, 0xaf, 0xcf, 0xa8, - 0xde, 0xa2, 0x1d, 0x33, 0x9a, 0xf6, 0x7d, 0xc8, 0x03, 0x27, 0x32, 0xb7, - 0x2f, 0xf0, 0x69, 0xe8, 0xe0, 0x04, 0xf5, 0xdf, 0x6b, 0x94, 0x20, 0xe6, - 0x66, 0xac, 0xbf, 0x33, 0x3d, 0xd8, 0xf3, 0x46, 0x88, 0x92, 0x29, 0x9e, - 0xeb, 0x72, 0xbe, 0x6f, 0xea, 0x17, 0xae, 0xc8, 0x49, 0xbb, 0xba, 0xf1, - 0x76, 0x7c, 0xc2, 0xbf, 0xe3, 0xf9, 0xd9, 0x0f, 0x53, 0x3d, 0x2a, 0xbd, - 0x81, 0xe7, 0xa9, 0x7d, 0x81, 0xcf, 0x54, 0xbc, 0x91, 0x22, 0x63, 0x6c, - 0xfe, 0x4c, 0x0f, 0xc7, 0xa4, 0xb9, 0x2b, 0xe7, 0xcf, 0x0c, 0xbf, 0x6a, - 0x8e, 0x18, 0x7a, 0xcc, 0xb4, 0x61, 0x20, 0xaa, 0xf7, 0xe0, 0x33, 0x79, - 0xee, 0x43, 0x6a, 0xa9, 0x08, 0x3c, 0x4f, 0xbf, 0xcb, 0x34, 0xeb, 0xf1, - 0x7b, 0x4d, 0x93, 0x68, 0x8c, 0x5b, 0xfd, 0x70, 0xa0, 0x2a, 0x17, 0xde, - 0x65, 0x2a, 0x92, 0x60, 0xae, 0x61, 0x42, 0xc2, 0xc9, 0x5e, 0x94, 0x89, - 0xbc, 0x17, 0x7e, 0x35, 0x84, 0xbe, 0xda, 0xd3, 0x69, 0xfb, 0xce, 0x0d, - 0xe2, 0x17, 0x4d, 0xa3, 0xcf, 0x5e, 0x0a, 0xda, 0xda, 0x64, 0x1c, 0xec, - 0xba, 0xa1, 0x86, 0x1c, 0xc9, 0x1b, 0x05, 0xae, 0x2b, 0xbc, 0x2a, 0x2d, - 0xf4, 0xa0, 0x67, 0xa6, 0xdd, 0x81, 0xe7, 0xc8, 0x85, 0x2e, 0x5f, 0xb9, - 0xce, 0x80, 0x83, 0x57, 0xbc, 0x74, 0x99, 0x28, 0xfd, 0x79, 0x9d, 0x1c, - 0x42, 0x9c, 0x8f, 0x23, 0xa7, 0x62, 0x24, 0x3a, 0xf8, 0x5a, 0xd6, 0x7b, - 0xb1, 0x36, 0x54, 0xa4, 0x45, 0x31, 0x81, 0x9f, 0x0c, 0x3c, 0x1a, 0xf4, - 0x61, 0x07, 0xe7, 0x86, 0xf3, 0x57, 0xff, 0x51, 0x13, 0xe5, 0xd7, 0x3d, - 0x11, 0x8b, 0x73, 0x2f, 0xb8, 0x4a, 0xb6, 0xb6, 0x0e, 0x4e, 0xb4, 0xc0, - 0xb5, 0x7d, 0xcb, 0x1b, 0xa5, 0xc5, 0x1e, 0xf8, 0x4f, 0x57, 0x37, 0x70, - 0x42, 0x1e, 0x74, 0xaa, 0xe0, 0x27, 0x28, 0x44, 0x43, 0x04, 0xc4, 0x64, - 0xdf, 0xa0, 0x4f, 0x14, 0x77, 0x60, 0xa6, 0x3d, 0x54, 0xb1, 0xb6, 0x4f, - 0xf3, 0xae, 0x82, 0xeb, 0x63, 0x59, 0xd1, 0x9d, 0x26, 0x39, 0xa9, 0x73, - 0x72, 0x1e, 0xfc, 0x92, 0xd3, 0xf7, 0x5e, 0x07, 0x06, 0x4c, 0xc0, 0xbf, - 0x75, 0x82, 0x1e, 0x9d, 0xc6, 0x08, 0x3d, 0x7c, 0x25, 0x69, 0x64, 0x96, - 0x0e, 0x4b, 0x13, 0x83, 0x9c, 0x8f, 0xe7, 0xe1, 0x0a, 0xde, 0x69, 0x49, - 0xd5, 0xfa, 0x15, 0x3a, 0x78, 0x0a, 0xb5, 0xd7, 0x82, 0x4d, 0x36, 0xfa, - 0xbd, 0xa6, 0x89, 0xbd, 0x64, 0xa6, 0x78, 0xe1, 0x1a, 0x93, 0x43, 0x1a, - 0x2e, 0x98, 0x7f, 0xb9, 0x95, 0xc6, 0xcb, 0x60, 0x3a, 0xcc, 0xa5, 0x8f, - 0x86, 0x23, 0x8a, 0x26, 0xe6, 0x0e, 0x93, 0xec, 0x6c, 0x0c, 0xd6, 0xf1, - 0x50, 0x4e, 0xeb, 0xa9, 0x54, 0xf6, 0xae, 0x44, 0xd2, 0x2b, 0x79, 0xe0, - 0xc5, 0x1e, 0x39, 0x64, 0x74, 0x04, 0xaf, 0xca, 0x0e, 0x87, 0x78, 0xb5, - 0xc9, 0xb4, 0xe8, 0xc5, 0xa6, 0xf5, 0x02, 0x7c, 0xbb, 0x46, 0xbd, 0xde, - 0x00, 0x42, 0x9e, 0x8a, 0x16, 0xfc, 0x5b, 0x3c, 0xf4, 0xa1, 0xde, 0x9f, - 0x85, 0x23, 0xa0, 0x2f, 0x72, 0x28, 0x6a, 0x98, 0xb3, 0x44, 0xd5, 0xc5, - 0x66, 0xc0, 0x24, 0x95, 0x84, 0xb8, 0xf3, 0x9a, 0xe1, 0xc0, 0xa3, 0x54, - 0x78, 0xe0, 0xed, 0xce, 0x61, 0xdd, 0x3c, 0x43, 0xfa, 0xf5, 0x06, 0xc5, - 0xf4, 0x92, 0x4e, 0x70, 0x0b, 0x6b, 0xb1, 0x8f, 0x3d, 0xb5, 0xc3, 0x88, - 0x2d, 0x8a, 0xa4, 0xea, 0x4b, 0xad, 0x27, 0x98, 0xa9, 0xa5, 0x68, 0x82, - 0x5a, 0x98, 0xd8, 0x8b, 0x5b, 0x34, 0x92, 0xb4, 0x47, 0x89, 0x5e, 0xe5, - 0xbc, 0x13, 0x8b, 0x48, 0xb3, 0xdc, 0xa4, 0x79, 0x19, 0xc4, 0xfb, 0xb5, - 0xe7, 0xae, 0xe1, 0x4d, 0x6f, 0x1d, 0xd2, 0xfe, 0xcc, 0x52, 0xf5, 0x28, - 0xe1, 0xf7, 0x58, 0xc7, 0x84, 0x75, 0x41, 0x2b, 0x34, 0xec, 0x48, 0x5f, - 0x3a, 0x30, 0xbf, 0xcb, 0xcc, 0x78, 0xe9, 0x71, 0x8a, 0x23, 0x01, 0xf3, - 0x5c, 0xfc, 0xda, 0x23, 0x19, 0xb4, 0xa1, 0x63, 0xf7, 0x89, 0x3b, 0x70, - 0x52, 0x63, 0x14, 0x6e, 0x86, 0xa4, 0x30, 0x40, 0x4b, 0x82, 0xc7, 0x67, - 0x46, 0x36, 0x61, 0x0f, 0xdf, 0xb0, 0x87, 0x92, 0x52, 0x45, 0xe0, 0x2d, - 0xd8, 0xb7, 0x30, 0xe4, 0x88, 0xdb, 0x2f, 0xe3, 0x80, 0x08, 0x2b, 0x6b, - 0x3b, 0x91, 0x4a, 0xbc, 0x59, 0xab, 0xce, 0x74, 0xbe, 0xb7, 0x6c, 0x56, - 0x4f, 0x50, 0x50, 0x5e, 0x42, 0xc9, 0x23, 0x6b, 0x2c, 0x1d, 0xf4, 0x89, - 0x97, 0x19, 0x43, 0x57, 0xb6, 0x58, 0x3b, 0x76, 0x0c, 0x20, 0x5b, 0x79, - 0x14, 0x7c, 0x7a, 0xc9, 0x2b, 0x8b, 0x6e, 0x56, 0xd9, 0x51, 0x91, 0x5d, - 0x3e, 0xe1, 0x3b, 0xdb, 0x0c, 0x3b, 0xee, 0xdb, 0x3b, 0x6a, 0xda, 0x58, - 0xb4, 0x5f, 0x73, 0x0d, 0x90, 0x1e, 0xa3, 0x4c, 0x3f, 0x52, 0x75, 0x3b, - 0x22, 0x3c, 0x0a, 0x6f, 0xb5, 0x01, 0xcf, 0xdf, 0xe6, 0xbe, 0x0c, 0x43, - 0x2d, 0xd2, 0x93, 0x56, 0xdd, 0xf7, 0xf3, 0x33, 0x22, 0x2d, 0xb3, 0x62, - 0x24, 0xaa, 0xd2, 0xdc, 0x9a, 0x84, 0x33, 0x4a, 0xf9, 0xf0, 0x82, 0x38, - 0x65, 0x58, 0xc7, 0xba, 0xf4, 0x99, 0x9b, 0x7b, 0xa4, 0xa2, 0x1e, 0x7c, - 0x86, 0xe3, 0x38, 0x52, 0xf2, 0x2e, 0x5a, 0x2b, 0x21, 0xc6, 0xb0, 0x08, - 0x3d, 0xe1, 0x43, 0x0c, 0xa7, 0xc2, 0x8f, 0x5e, 0xb9, 0xa7, 0x2e, 0xbc, - 0x26, 0x8d, 0x34, 0xfa, 0x1a, 0x6b, 0xc3, 0x53, 0xd2, 0xb1, 0x91, 0xac, - 0xdf, 0xef, 0xb5, 0x12, 0xb2, 0x09, 0x62, 0xd2, 0xe8, 0xf7, 0xcc, 0x0d, - 0x26, 0xae, 0xd6, 0x66, 0x42, 0x7b, 0x55, 0xfa, 0x2c, 0x8b, 0xbd, 0xa1, - 0x8d, 0x6b, 0xe4, 0x94, 0x49, 0x70, 0xc7, 0x7a, 0x40, 0x18, 0xbb, 0x3c, - 0xc3, 0xd6, 0xb2, 0xa2, 0x54, 0x3a, 0xf3, 0x1a, 0xbe, 0x44, 0x63, 0xf3, - 0x7a, 0x42, 0x33, 0x7f, 0x0f, 0x07, 0x98, 0xab, 0x03, 0xd5, 0x46, 0x5a, - 0xea, 0x78, 0x0f, 0xc7, 0xe6, 0xcc, 0xb5, 0x70, 0x9e, 0x54, 0xa4, 0xf0, - 0xed, 0x89, 0xd2, 0xd3, 0x33, 0x9a, 0x40, 0xeb, 0x25, 0x2c, 0x89, 0x6a, - 0x59, 0x45, 0x2d, 0x41, 0xc5, 0x14, 0xe4, 0x14, 0x66, 0x34, 0x32, 0x9a, - 0x05, 0x8c, 0xc7, 0xb2, 0xd4, 0x2f, 0x66, 0xc2, 0xe5, 0xa3, 0xa0, 0xaa, - 0x0f, 0x13, 0x99, 0x63, 0xb7, 0x5a, 0x86, 0x7e, 0x38, 0x42, 0x7f, 0x2e, - 0xd0, 0x1f, 0x67, 0xee, 0x0f, 0x85, 0xb8, 0xc8, 0x79, 0xf6, 0x8c, 0x74, - 0x61, 0x64, 0xa0, 0x05, 0xb9, 0x2f, 0x41, 0x6b, 0xca, 0x04, 0xbc, 0xf0, - 0xbe, 0x50, 0xd5, 0x18, 0xcd, 0x6b, 0x77, 0x1d, 0xd4, 0x1f, 0x20, 0xff, - 0x85, 0x2b, 0x50, 0x94, 0xaa, 0x76, 0x37, 0xb1, 0x9a, 0x23, 0xe6, 0xc1, - 0xb5, 0x4e, 0x79, 0xcb, 0xbc, 0x2c, 0x21, 0x77, 0xaa, 0x9f, 0x6e, 0xc2, - 0x25, 0xf1, 0x5c, 0xef, 0x83, 0x74, 0x97, 0x9b, 0x34, 0xb1, 0x19, 0x37, - 0xcd, 0x8b, 0x6a, 0x2b, 0x23, 0x4b, 0xa4, 0x83, 0x7d, 0xb2, 0x93, 0x6d, - 0x63, 0x85, 0xd4, 0x85, 0xb6, 0x60, 0x8e, 0x3a, 0x86, 0xa9, 0xa6, 0xd2, - 0x9d, 0x29, 0x5f, 0x80, 0x01, 0xdf, 0x42, 0xaf, 0x2e, 0xa4, 0xc1, 0x35, - 0x31, 0x2e, 0x6f, 0xea, 0xb1, 0x9a, 0x25, 0x6a, 0x9b, 0xbb, 0x7d, 0x1a, - 0x37, 0xf8, 0x15, 0xf2, 0x7e, 0x77, 0x9c, 0xd7, 0x28, 0xb6, 0xae, 0x86, - 0x3b, 0xe8, 0xf1, 0x64, 0xeb, 0x90, 0x63, 0x03, 0x07, 0x2d, 0x91, 0x2b, - 0xfc, 0xa2, 0xf3, 0xfa, 0x7b, 0xfe, 0x82, 0x58, 0x1a, 0xc1, 0x17, 0xf4, - 0xea, 0xc0, 0x55, 0x45, 0x58, 0x25, 0x0a, 0x07, 0xab, 0xa2, 0xc6, 0x3c, - 0x37, 0xb1, 0x95, 0x53, 0x99, 0xce, 0xf7, 0xe3, 0x8e, 0x5c, 0xbc, 0x0e, - 0x9e, 0xee, 0x1e, 0xe7, 0x31, 0x31, 0x02, 0x5e, 0xd2, 0xd7, 0x3b, 0x51, - 0xc2, 0x2f, 0xa6, 0x4a, 0x23, 0xa6, 0x7c, 0x67, 0x4c, 0xde, 0x77, 0x46, - 0xf0, 0xeb, 0x99, 0x10, 0xd1, 0xc5, 0x06, 0xf0, 0xae, 0x29, 0x58, 0xf4, - 0x2e, 0x50, 0x80, 0x4a, 0x54, 0xf9, 0x65, 0x62, 0xc7, 0x39, 0x4c, 0x0a, - 0xe7, 0xa4, 0x11, 0xed, 0x62, 0x21, 0x53, 0xdb, 0x28, 0x1b, 0x95, 0xd0, - 0x36, 0xb8, 0x26, 0xda, 0x45, 0x8f, 0x3b, 0x7b, 0xae, 0xcb, 0x51, 0x01, - 0x96, 0xe3, 0x03, 0x15, 0x07, 0xc8, 0x2d, 0xce, 0xfd, 0xf5, 0xed, 0xb0, - 0x59, 0x09, 0xae, 0x18, 0x0e, 0xfd, 0xe0, 0x79, 0x4c, 0xe9, 0xab, 0xa0, - 0x63, 0x4f, 0x19, 0x79, 0x13, 0xad, 0x7a, 0xc5, 0xa8, 0xef, 0x98, 0x3a, - 0x69, 0xc4, 0xd5, 0xa7, 0x79, 0x6f, 0x9f, 0xa4, 0xaa, 0x29, 0xd2, 0x59, - 0x8b, 0x8b, 0x81, 0x70, 0xdd, 0xa4, 0x89, 0x42, 0xb8, 0xc3, 0x98, 0x41, - 0xde, 0x53, 0x4d, 0x4e, 0x07, 0x8f, 0xb0, 0xc4, 0x0f, 0x5c, 0xd6, 0xb0, - 0x5f, 0x35, 0x83, 0x78, 0x6b, 0x55, 0xc0, 0x34, 0x06, 0x78, 0x38, 0x4c, - 0x38, 0x81, 0x6c, 0xea, 0xa3, 0xa8, 0x5d, 0x4c, 0xc2, 0xb3, 0xb0, 0x4c, - 0x33, 0x13, 0x22, 0x6b, 0x0c, 0x7f, 0x3d, 0x07, 0xa8, 0xf6, 0xc4, 0x0c, - 0x14, 0xcc, 0xb3, 0x16, 0xa7, 0xe5, 0x74, 0xa0, 0xfd, 0x3e, 0x9f, 0x24, - 0x8e, 0xbd, 0xd3, 0xfb, 0xc0, 0x83, 0xf7, 0x7c, 0xd7, 0x36, 0x9a, 0xe4, - 0x77, 0xe2, 0x13, 0x4f, 0xe8, 0x27, 0x8b, 0x36, 0xbd, 0x1e, 0x75, 0xfd, - 0x5e, 0xd4, 0x90, 0xff, 0xc0, 0x65, 0xc7, 0x04, 0x9b, 0x38, 0x59, 0x1b, - 0x47, 0x77, 0xe5, 0x12, 0x97, 0x1a, 0x9c, 0xf5, 0x15, 0xe8, 0xa8, 0x7b, - 0xa4, 0xdb, 0x0c, 0x3c, 0x15, 0x4a, 0x34, 0x14, 0xc6, 0xcc, 0x7e, 0x0a, - 0x33, 0x20, 0x32, 0x9d, 0xf7, 0x28, 0x04, 0x82, 0x4c, 0xa7, 0xd7, 0x5c, - 0x1f, 0x8f, 0x6a, 0x15, 0x50, 0x59, 0x36, 0x09, 0x13, 0xce, 0x39, 0xd9, - 0x8f, 0x98, 0x21, 0x33, 0xaa, 0x99, 0x1f, 0x19, 0x5f, 0xf0, 0x9a, 0x3d, - 0xe4, 0xcd, 0xca, 0x00, 0xef, 0x17, 0x16, 0x4d, 0xa4, 0x25, 0x9b, 0xd5, - 0x5c, 0xd7, 0x23, 0x8f, 0x1b, 0x92, 0x0a, 0x8f, 0xdc, 0x05, 0x93, 0x63, - 0x6c, 0x20, 0x81, 0x8d, 0xd2, 0xa2, 0x9a, 0x50, 0xd4, 0xd3, 0xad, 0x30, - 0xa5, 0x5a, 0xe2, 0xc8, 0x20, 0xd7, 0x45, 0x84, 0x0d, 0x55, 0xe7, 0xba, - 0x3b, 0xc1, 0xd8, 0xd7, 0x82, 0xf5, 0x8c, 0xbd, 0x57, 0x97, 0x98, 0xcf, - 0x75, 0x21, 0x43, 0x23, 0x71, 0xd9, 0x15, 0x3c, 0xd0, 0x20, 0x4d, 0x12, - 0x72, 0x25, 0x19, 0x49, 0x21, 0x43, 0x7c, 0x61, 0x4b, 0x55, 0x45, 0x89, - 0x5f, 0x9a, 0x47, 0xba, 0x22, 0xc2, 0x0f, 0x2d, 0xe9, 0x69, 0x1a, 0x73, - 0x6c, 0x9f, 0xd5, 0x4a, 0xec, 0x4c, 0xe0, 0xd2, 0xf3, 0xea, 0xc2, 0xd3, - 0x3e, 0x8d, 0x26, 0xc0, 0xca, 0x79, 0x8f, 0x2b, 0xab, 0xf2, 0x79, 0xbd, - 0x6c, 0xc2, 0xd4, 0x0e, 0x72, 0x3a, 0xca, 0x0c, 0xd5, 0x4a, 0xaf, 0x82, - 0xd8, 0x41, 0x57, 0x49, 0xc9, 0x3b, 0x9e, 0xe6, 0x3d, 0x4e, 0xa0, 0x77, - 0x54, 0xa8, 0xe7, 0xcd, 0x7d, 0x94, 0x3c, 0x7b, 0x95, 0xde, 0x97, 0x79, - 0x70, 0x59, 0x26, 0xb4, 0xfe, 0x96, 0x77, 0xc1, 0x04, 0x73, 0x3a, 0x26, - 0x28, 0xf0, 0x0a, 0x9f, 0x8e, 0xa5, 0x4b, 0xe8, 0x4e, 0x43, 0x46, 0xac, - 0xb1, 0xb3, 0xd4, 0xd0, 0x21, 0x9e, 0xa4, 0x4d, 0xe2, 0xe1, 0x19, 0x99, - 0xf2, 0x1e, 0x1a, 0xab, 0x38, 0x4a, 0x7e, 0xed, 0x99, 0x48, 0x89, 0x99, - 0x69, 0xa4, 0xb6, 0xe1, 0x1a, 0xed, 0x8c, 0x2b, 0x75, 0x28, 0x3d, 0x9c, - 0x16, 0x54, 0x17, 0x59, 0x2d, 0x91, 0x74, 0xe5, 0x96, 0x6d, 0xee, 0x1a, - 0xed, 0x2a, 0x88, 0xb5, 0x95, 0x17, 0x37, 0x96, 0x15, 0xd7, 0xcc, 0x20, - 0x30, 0x1e, 0x07, 0xca, 0xa2, 0xa8, 0x73, 0x6f, 0x30, 0xee, 0x24, 0xa6, - 0xc8, 0x97, 0x73, 0x4d, 0x1f, 0xd5, 0xc3, 0xf5, 0x51, 0x3d, 0xa3, 0xea, - 0x5d, 0x18, 0x27, 0x23, 0xa6, 0x2f, 0x53, 0xb6, 0xab, 0x5d, 0x61, 0x30, - 0xfb, 0xe8, 0x7d, 0x3d, 0x49, 0xad, 0xfa, 0x3c, 0x5e, 0x79, 0x3b, 0x73, - 0xab, 0xe7, 0xa6, 0x5d, 0xe1, 0x04, 0x72, 0xc2, 0xc1, 0x90, 0xaf, 0x95, - 0xc9, 0x3b, 0xd6, 0x95, 0x0a, 0xeb, 0x47, 0xae, 0x9f, 0xe9, 0x24, 0xde, - 0x91, 0xc6, 0xf4, 0x90, 0xea, 0xcf, 0x83, 0x7b, 0xd1, 0x72, 0xa3, 0xaa, - 0xf1, 0x44, 0xb4, 0x23, 0xea, 0x43, 0xe1, 0xc9, 0x79, 0x8f, 0x48, 0x1d, - 0xd7, 0x15, 0x60, 0x08, 0x31, 0xa4, 0xde, 0xab, 0xdc, 0xef, 0x9f, 0xf1, - 0x34, 0xd7, 0xe9, 0x41, 0xe0, 0xc6, 0xa8, 0x71, 0xf4, 0x74, 0x18, 0x93, - 0xd3, 0x4d, 0x02, 0x6b, 0x70, 0x37, 0xa0, 0xc4, 0xfb, 0x7a, 0x45, 0x53, - 0xf4, 0x94, 0x28, 0xc8, 0x89, 0x49, 0x35, 0xc8, 0xac, 0x07, 0xe7, 0x11, - 0x60, 0x13, 0x79, 0x0b, 0x66, 0xf7, 0xac, 0xeb, 0xcd, 0x23, 0xb4, 0x9d, - 0xf3, 0x1e, 0xe2, 0x9f, 0x01, 0x42, 0xca, 0x0b, 0xa6, 0x28, 0x96, 0xb5, - 0x4c, 0x69, 0x12, 0x99, 0x42, 0x87, 0xc9, 0x6c, 0x70, 0x1b, 0x6b, 0xe3, - 0x92, 0x4c, 0xca, 0x84, 0x79, 0xd5, 0x0b, 0x54, 0x55, 0x82, 0xb1, 0x87, - 0x68, 0x74, 0x23, 0x67, 0xd4, 0x88, 0x13, 0x92, 0x24, 0x26, 0xeb, 0x81, - 0xdb, 0x42, 0x66, 0xcc, 0xb5, 0x0d, 0xfa, 0x16, 0xa3, 0x35, 0xe0, 0x01, - 0xfe, 0x2e, 0x1b, 0x06, 0xe7, 0x53, 0xdb, 0xc8, 0xb0, 0xcc, 0x88, 0x55, - 0xcb, 0xd8, 0x93, 0x43, 0x39, 0xaf, 0x8e, 0x4e, 0xd4, 0x0b, 0xc6, 0xe6, - 0x1a, 0xba, 0x62, 0x79, 0x4c, 0xe6, 0xfd, 0x45, 0xba, 0x3b, 0xd7, 0xf3, - 0x89, 0x35, 0xa1, 0x25, 0x3e, 0xda, 0x12, 0x6f, 0x75, 0x10, 0xca, 0x16, - 0x39, 0xf8, 0xc9, 0xc2, 0xb1, 0x17, 0xd4, 0x39, 0xdd, 0xf2, 0xcd, 0x2a, - 0x96, 0xda, 0xe2, 0x8d, 0x11, 0x99, 0x62, 0x45, 0x52, 0xe0, 0xe0, 0x31, - 0x46, 0xf6, 0x5c, 0x6f, 0xe8, 0x3f, 0xda, 0xd7, 0xb1, 0x2a, 0x6b, 0xb6, - 0x0d, 0xd5, 0xbc, 0x67, 0x0c, 0x21, 0xc0, 0x86, 0xf0, 0xe8, 0xd8, 0xbb, - 0x83, 0xb7, 0xb5, 0x30, 0x97, 0x67, 0xe1, 0x8d, 0x22, 0x99, 0xec, 0x96, - 0x7a, 0x81, 0x9b, 0x24, 0xf2, 0x29, 0x52, 0xf2, 0xc6, 0x8c, 0xec, 0x43, - 0xaf, 0x87, 0x31, 0x14, 0x3d, 0x77, 0x90, 0x4e, 0x75, 0xd4, 0x15, 0xad, - 0xf8, 0x4e, 0xcc, 0xf5, 0x2d, 0x37, 0x58, 0x24, 0x34, 0x60, 0x53, 0x43, - 0x92, 0x8c, 0x05, 0x11, 0xcc, 0x59, 0x2d, 0x34, 0xf5, 0x1d, 0xd3, 0xf2, - 0xc5, 0xe6, 0x7d, 0xe0, 0x9d, 0xc0, 0x51, 0x17, 0xec, 0x45, 0xa3, 0x9e, - 0x31, 0x93, 0xe0, 0xcd, 0xfb, 0x2b, 0xa6, 0x8d, 0x81, 0xd3, 0xed, 0xbc, - 0x06, 0xf4, 0x9c, 0x77, 0xa1, 0x96, 0x98, 0xfd, 0x23, 0x82, 0x5c, 0x05, - 0x4c, 0x37, 0x8e, 0x4e, 0x85, 0x08, 0xdf, 0xde, 0xc2, 0x0e, 0x33, 0xd6, - 0x8a, 0x18, 0x38, 0x1c, 0xbc, 0x3e, 0x5e, 0x86, 0x48, 0xf5, 0xe4, 0x3c, - 0xec, 0x18, 0xbf, 0x8c, 0x6c, 0x52, 0xa4, 0x04, 0x6d, 0x33, 0xd7, 0xc0, - 0x21, 0x30, 0xd7, 0xa1, 0x4f, 0xa2, 0x5c, 0xd3, 0xb7, 0xb2, 0x41, 0x39, - 0xf1, 0xc9, 0x96, 0x20, 0xf2, 0xda, 0x4f, 0xd5, 0x42, 0xa2, 0xb9, 0x76, - 0xca, 0xc5, 0x8c, 0xa9, 0xb8, 0x84, 0xbe, 0x08, 0xc3, 0xb4, 0xbf, 0x49, - 0xc8, 0xb9, 0x43, 0x8a, 0x62, 0xd1, 0x0e, 0xe6, 0x5c, 0xc3, 0x25, 0xe3, - 0x6c, 0x97, 0x29, 0x79, 0x48, 0xe8, 0x0a, 0x70, 0x59, 0xbf, 0x44, 0x8d, - 0x65, 0x82, 0x86, 0xde, 0x1e, 0x1b, 0x3c, 0x08, 0xe0, 0x2d, 0x61, 0x56, - 0x36, 0x8c, 0x43, 0x06, 0xda, 0x57, 0x3b, 0xa4, 0xa2, 0xe1, 0x2c, 0xb0, - 0xb0, 0x86, 0x08, 0xcc, 0x7b, 0x3e, 0xdf, 0x8f, 0x4f, 0xce, 0x2b, 0x04, - 0x38, 0x7e, 0x4b, 0x12, 0xf4, 0x90, 0x7c, 0xfb, 0x0e, 0x75, 0xe6, 0x0b, - 0x85, 0x36, 0xa2, 0x06, 0x4e, 0x31, 0x81, 0x9f, 0xf5, 0xf5, 0x8b, 0xd3, - 0xe0, 0x5a, 0xa2, 0x3e, 0xc5, 0x46, 0xf0, 0x1d, 0x6b, 0x15, 0xbc, 0xe7, - 0x6a, 0x80, 0xaf, 0xdb, 0x98, 0xde, 0xc7, 0xb2, 0xae, 0x9e, 0x64, 0xde, - 0x77, 0xea, 0xc8, 0xe6, 0xe0, 0xae, 0x20, 0x17, 0x71, 0xc5, 0xbc, 0x93, - 0x96, 0x75, 0x72, 0xe6, 0xf1, 0xcb, 0xd1, 0x3f, 0x59, 0x30, 0x66, 0x28, - 0x34, 0xdc, 0xb9, 0xce, 0x02, 0x15, 0xf3, 0x3e, 0x99, 0x09, 0x09, 0xc9, - 0xad, 0x97, 0x34, 0xff, 0xa8, 0x51, 0x01, 0x73, 0x5d, 0xaa, 0x8a, 0x96, - 0xdc, 0x8a, 0x65, 0x4b, 0x96, 0x39, 0xba, 0x80, 0xcf, 0x46, 0x5e, 0x92, - 0xf6, 0xc3, 0xcc, 0x0b, 0xbc, 0x16, 0x80, 0x6d, 0x32, 0x4e, 0x6a, 0xe4, - 0xb1, 0x54, 0xc4, 0x51, 0x93, 0x59, 0x47, 0xa6, 0x8c, 0x83, 0x6b, 0x5d, - 0x0a, 0x15, 0x4c, 0x59, 0xd3, 0x68, 0x92, 0x5f, 0xb4, 0xcc, 0x20, 0xbb, - 0x58, 0x67, 0xc6, 0xfe, 0xfd, 0xa5, 0x1d, 0x19, 0x23, 0xb1, 0x87, 0xe2, - 0x90, 0x11, 0x7a, 0x74, 0x87, 0x24, 0x34, 0x54, 0x10, 0xb5, 0xa3, 0x5d, - 0x1a, 0x7d, 0x03, 0xf1, 0xa4, 0x76, 0xe0, 0x25, 0x24, 0x62, 0x37, 0xf0, - 0x1a, 0x0f, 0xa9, 0xb6, 0xaf, 0xbd, 0xbe, 0x7e, 0x47, 0x5c, 0x27, 0x47, - 0x5a, 0xbe, 0xb1, 0x3f, 0xab, 0x3e, 0x15, 0xf3, 0x64, 0x7e, 0x06, 0x54, - 0x8d, 0x2c, 0x5e, 0x55, 0x61, 0x0b, 0xde, 0xc4, 0xed, 0x17, 0x30, 0x57, - 0xd0, 0xfe, 0xc0, 0x58, 0x0a, 0x9a, 0xc2, 0x57, 0x7d, 0x01, 0xec, 0x02, - 0xfc, 0xa6, 0x85, 0x8a, 0xcc, 0x7b, 0xb2, 0x93, 0x24, 0x0d, 0x75, 0xce, - 0xe4, 0xbc, 0x6f, 0x72, 0x0b, 0xf9, 0xa6, 0xb3, 0xc4, 0x76, 0x13, 0xa5, - 0x36, 0xa0, 0x17, 0x3c, 0xd9, 0xb0, 0x57, 0x82, 0xec, 0x3c, 0x76, 0xd9, - 0xbc, 0xb7, 0x82, 0x49, 0x2a, 0xfb, 0x9c, 0xaa, 0x79, 0x9d, 0x42, 0x90, - 0xb1, 0xad, 0xb9, 0xd7, 0x71, 0x20, 0x9b, 0xbb, 0x99, 0x00, 0xfb, 0xcc, - 0xb8, 0x4c, 0x90, 0x98, 0xf7, 0x7b, 0x77, 0xd4, 0x8d, 0x16, 0x51, 0xfb, - 0x32, 0x70, 0xa3, 0x77, 0xcc, 0x13, 0xdd, 0x81, 0xf7, 0x3d, 0xe0, 0x75, - 0x5f, 0x34, 0xe2, 0x3b, 0xf4, 0xd8, 0x48, 0xf8, 0x98, 0x4b, 0x6f, 0x74, - 0x13, 0x33, 0xb8, 0xe6, 0xdc, 0xe2, 0xc4, 0xc7, 0xc6, 0xb1, 0x0e, 0xce, - 0x94, 0x5b, 0x24, 0x37, 0x99, 0xa2, 0x0e, 0x13, 0xd0, 0x07, 0x0a, 0x73, - 0xe7, 0xcc, 0xb1, 0x76, 0xf4, 0x45, 0x43, 0x1a, 0x5d, 0x01, 0xbf, 0x66, - 0x52, 0x9b, 0x9f, 0x6f, 0xca, 0x57, 0x96, 0x46, 0x56, 0xc8, 0x40, 0x93, - 0x1a, 0x32, 0x4f, 0x5a, 0xb4, 0x07, 0x71, 0x95, 0xef, 0xde, 0x43, 0xcb, - 0x5d, 0xfd, 0x56, 0xce, 0xb5, 0x14, 0xfd, 0x79, 0xad, 0x41, 0x75, 0x81, - 0xdc, 0x12, 0x89, 0xc7, 0xce, 0x07, 0x5a, 0x9d, 0xe3, 0x46, 0xdf, 0x95, - 0xba, 0x52, 0x47, 0x55, 0x61, 0xea, 0xf6, 0x73, 0xad, 0xde, 0xfe, 0xc8, - 0x83, 0x09, 0xda, 0x18, 0x85, 0xde, 0x67, 0xb4, 0x11, 0x6e, 0xe2, 0x81, - 0xae, 0x55, 0xdb, 0x05, 0xe5, 0xfd, 0xfb, 0x90, 0x94, 0xd6, 0x4e, 0x03, - 0x0e, 0x6b, 0x57, 0x55, 0xd6, 0xb0, 0x03, 0x31, 0xee, 0x5a, 0x9e, 0x32, - 0xfd, 0xe8, 0x57, 0xfd, 0x91, 0x62, 0x2d, 0x8b, 0x87, 0x5d, 0xa2, 0xa4, - 0x71, 0x4c, 0x02, 0x56, 0x78, 0x17, 0x3d, 0xa1, 0x63, 0x96, 0x03, 0x7f, - 0x70, 0x66, 0x63, 0xe0, 0x3a, 0x83, 0xfb, 0xa0, 0x9b, 0x52, 0xd9, 0x65, - 0xef, 0x21, 0x2b, 0xe9, 0xaa, 0x09, 0x4d, 0x06, 0xbe, 0x54, 0xd4, 0xa0, - 0x0d, 0x2c, 0x18, 0x1b, 0x0b, 0xb4, 0x82, 0xc9, 0xa8, 0xba, 0x80, 0x8e, - 0x7a, 0xe6, 0x3e, 0xd6, 0xc3, 0x66, 0xdc, 0xe5, 0x08, 0x02, 0x41, 0x93, - 0xd1, 0x21, 0x91, 0x49, 0x04, 0x9e, 0x2e, 0xd3, 0x41, 0x47, 0xd7, 0x78, - 0x51, 0x82, 0x3e, 0x3f, 0x00, 0x43, 0xfc, 0xaa, 0x59, 0x86, 0x58, 0x06, - 0x7c, 0x3e, 0xb2, 0xae, 0x22, 0x89, 0x31, 0x40, 0xce, 0x5e, 0xa6, 0x9c, - 0xaf, 0xfc, 0xb2, 0x19, 0xfc, 0x9c, 0x85, 0x7a, 0x89, 0x70, 0x54, 0x2a, - 0x74, 0xfb, 0xb5, 0x6a, 0x12, 0xe2, 0x09, 0xbc, 0xea, 0x3e, 0x71, 0x91, - 0x1f, 0xb6, 0x80, 0x95, 0xbe, 0x88, 0xa2, 0xf7, 0x20, 0x20, 0x3e, 0x9a, - 0xa2, 0x5b, 0x2f, 0x98, 0x21, 0x0e, 0xcc, 0x94, 0x43, 0xa4, 0x05, 0x71, - 0xc6, 0x41, 0x19, 0x26, 0xe0, 0x1d, 0x3c, 0x09, 0xda, 0x6c, 0x88, 0x89, - 0xb7, 0x7d, 0x1d, 0x9b, 0x60, 0xde, 0xc3, 0xbe, 0x8d, 0x75, 0x72, 0xe7, - 0x3e, 0x68, 0x6a, 0xf3, 0xf4, 0xfe, 0xb5, 0x26, 0xd3, 0x9c, 0x3d, 0x1f, - 0x81, 0x31, 0xd5, 0x9e, 0xb4, 0xae, 0x4c, 0x98, 0x8b, 0x5d, 0x7e, 0xfe, - 0x7a, 0xf3, 0x5f, 0xeb, 0xdb, 0x4f, 0x13, 0x9e, 0xeb, 0xc5, 0xa0, 0xd0, - 0x4c, 0x1c, 0x5b, 0x8b, 0xbb, 0x3e, 0xc8, 0xbd, 0x4a, 0x44, 0x86, 0x3b, - 0x62, 0x3e, 0x7e, 0x0b, 0x24, 0xe2, 0x83, 0x5b, 0x41, 0x6c, 0xb2, 0x80, - 0x18, 0x6c, 0x14, 0x29, 0x9e, 0xf7, 0x38, 0x3a, 0xb2, 0x03, 0xec, 0x69, - 0x06, 0xd0, 0xf5, 0xf6, 0x0d, 0x33, 0xb1, 0xa4, 0xc0, 0x19, 0xf3, 0x5e, - 0x0e, 0xd2, 0xa1, 0x7b, 0x94, 0xa8, 0x7c, 0xa7, 0xe9, 0x1c, 0xce, 0x97, - 0x01, 0x6f, 0xfa, 0x73, 0x3d, 0xa2, 0xac, 0x6d, 0x5e, 0xa0, 0x5f, 0x14, - 0x68, 0xc7, 0x7d, 0xe8, 0x83, 0x7f, 0xd6, 0xd4, 0x86, 0x76, 0x76, 0x22, - 0x34, 0xb4, 0xc3, 0x73, 0x9d, 0x3e, 0x63, 0x98, 0xd7, 0xe9, 0x6c, 0x58, - 0x1d, 0x69, 0xd8, 0xef, 0x93, 0x38, 0x25, 0xb7, 0x23, 0xeb, 0x53, 0xee, - 0x80, 0xb3, 0x6c, 0x07, 0xed, 0xd8, 0xf6, 0x6f, 0xd0, 0x25, 0x3d, 0xd1, - 0x82, 0x69, 0xaf, 0x61, 0x22, 0x6a, 0x38, 0xa7, 0x1e, 0x0c, 0x04, 0x5d, - 0x9e, 0x1c, 0xb8, 0x51, 0x98, 0xac, 0x03, 0x0f, 0x96, 0x84, 0x2e, 0x59, - 0x0a, 0x3d, 0x78, 0xfd, 0xf2, 0x06, 0x9e, 0x7e, 0xe5, 0x08, 0xd7, 0xe0, - 0x69, 0xe6, 0x7a, 0x13, 0x82, 0x36, 0x01, 0x3f, 0x7a, 0x55, 0x27, 0x39, - 0x5b, 0x52, 0xbd, 0xbc, 0xcd, 0x75, 0x76, 0x22, 0xb6, 0xb5, 0x98, 0x59, - 0x2d, 0x4b, 0xd7, 0xea, 0x00, 0xdf, 0xc0, 0xdf, 0xc9, 0x28, 0x06, 0x3d, - 0x80, 0xf5, 0x7e, 0x51, 0xf8, 0xcc, 0x9a, 0x6b, 0xe9, 0xcc, 0xb5, 0x3b, - 0x40, 0x23, 0x2f, 0x40, 0x7f, 0x60, 0xc6, 0x95, 0x03, 0xe3, 0xbe, 0xcb, - 0x13, 0xfb, 0x16, 0x35, 0xd5, 0x12, 0xf2, 0x08, 0x34, 0x31, 0x41, 0xe5, - 0x64, 0x4f, 0x24, 0xbe, 0x4f, 0x87, 0x44, 0xdc, 0x89, 0xaa, 0x12, 0x91, - 0x22, 0x2f, 0xe4, 0xe4, 0x19, 0x9b, 0xbd, 0x56, 0x70, 0xf5, 0x7b, 0xcd, - 0x91, 0xa9, 0x59, 0xb0, 0x06, 0x74, 0xc2, 0xbc, 0x97, 0x0a, 0x4c, 0x69, - 0xc1, 0x65, 0x47, 0x80, 0x03, 0x62, 0x4e, 0x3c, 0xec, 0xe0, 0x25, 0xb4, - 0x97, 0xe4, 0x29, 0xf1, 0xc2, 0x14, 0x25, 0xcc, 0x8c, 0xb4, 0x98, 0xf5, - 0x37, 0x31, 0x6b, 0x1c, 0x97, 0xa4, 0x49, 0x5d, 0x55, 0x90, 0x27, 0x1b, - 0xda, 0x48, 0x27, 0x4c, 0x04, 0xc6, 0x66, 0x75, 0xe5, 0xbc, 0x62, 0x05, - 0x70, 0x3e, 0xa1, 0xd5, 0xb6, 0x6c, 0xc9, 0x39, 0x57, 0xe8, 0x2d, 0x9b, - 0xaa, 0xc9, 0xe7, 0xfd, 0x01, 0x6d, 0xb5, 0x87, 0x58, 0xa8, 0x98, 0x83, - 0x5a, 0xd1, 0xcc, 0x1a, 0x81, 0x79, 0x91, 0x5e, 0x82, 0xf6, 0x67, 0x1d, - 0x4f, 0x82, 0x85, 0xe8, 0x2e, 0xe0, 0x86, 0x2c, 0x11, 0xf1, 0x3e, 0x26, - 0x30, 0xa3, 0x49, 0x43, 0xde, 0xd1, 0x44, 0x9f, 0x73, 0x8d, 0x38, 0x88, - 0xac, 0xe0, 0x57, 0x0d, 0xae, 0xa6, 0xbc, 0x25, 0x29, 0x7b, 0x67, 0x9d, - 0x3b, 0x89, 0x1a, 0x57, 0x90, 0x0b, 0xdf, 0x91, 0xe6, 0xea, 0x07, 0x8a, - 0x34, 0x5c, 0xab, 0xe5, 0xde, 0x50, 0xdf, 0xd0, 0x1f, 0x84, 0xb9, 0x15, - 0xe1, 0x1a, 0xce, 0xdf, 0xce, 0xf5, 0x51, 0xdc, 0x11, 0xf8, 0xcf, 0x67, - 0xba, 0x78, 0x97, 0x06, 0x60, 0x17, 0xa0, 0x4d, 0xc1, 0x41, 0xc7, 0xd5, - 0xa7, 0x17, 0xe4, 0xd6, 0x28, 0x1d, 0xf0, 0xb1, 0xe0, 0xf9, 0xe1, 0x1a, - 0x53, 0x36, 0x49, 0x94, 0x51, 0x74, 0x60, 0x73, 0xdd, 0xd4, 0xb9, 0x06, - 0x67, 0x23, 0x3d, 0xe9, 0xdb, 0xfa, 0x5c, 0xd3, 0x82, 0x2b, 0x8c, 0xe1, - 0x3a, 0xed, 0x79, 0xbd, 0x1b, 0xe0, 0x86, 0x11, 0x2a, 0x16, 0x02, 0xf6, - 0xb9, 0xc7, 0x14, 0x8b, 0xb9, 0xce, 0x01, 0x9f, 0xeb, 0x0d, 0x1a, 0xc3, - 0x01, 0x70, 0x74, 0x31, 0xef, 0x41, 0x3b, 0xa4, 0xae, 0x15, 0xfb, 0x0a, - 0x41, 0x3c, 0xe5, 0xd8, 0x54, 0x7a, 0xc1, 0xf1, 0x1b, 0x3c, 0x26, 0x27, - 0x5d, 0xa8, 0xe3, 0xa6, 0xdf, 0x17, 0x2d, 0xe8, 0xde, 0x86, 0x1c, 0x60, - 0x2e, 0x9f, 0x44, 0x23, 0xc6, 0xb1, 0xe9, 0x05, 0xf8, 0x76, 0x41, 0x28, - 0xda, 0xe7, 0x5e, 0xef, 0x81, 0x6f, 0xde, 0x80, 0x5f, 0x64, 0x19, 0xbf, - 0xcc, 0xcf, 0x57, 0x78, 0x39, 0xa1, 0x2c, 0xa9, 0xd9, 0x74, 0xe4, 0xc3, - 0x93, 0xf3, 0x97, 0x91, 0xfb, 0x17, 0x53, 0x36, 0xd6, 0x62, 0xae, 0x67, - 0x16, 0x29, 0x92, 0x84, 0x75, 0x05, 0x91, 0xda, 0x83, 0x7f, 0xab, 0x7a, - 0xd0, 0xf9, 0x2a, 0xe9, 0x7a, 0x02, 0xde, 0xc1, 0x4c, 0x10, 0x76, 0x20, - 0x8e, 0x42, 0x88, 0xa1, 0x0d, 0x01, 0x9c, 0x8c, 0x3a, 0x9b, 0x97, 0xed, - 0xc8, 0x65, 0x2b, 0x0f, 0x71, 0xdb, 0x18, 0x74, 0x5e, 0x8f, 0x4f, 0x83, - 0x17, 0xf6, 0x08, 0x16, 0x28, 0xd8, 0x1f, 0x3c, 0xf0, 0xcf, 0x0e, 0x79, - 0x08, 0x2f, 0xc8, 0xe3, 0x8e, 0x04, 0x73, 0x8d, 0x28, 0xd0, 0x8b, 0x3a, - 0x06, 0xff, 0x2b, 0x35, 0x8b, 0x31, 0x3e, 0xcc, 0xf5, 0x01, 0x53, 0xc0, - 0x52, 0x27, 0xd7, 0x82, 0xea, 0xe0, 0x82, 0x13, 0xe8, 0x84, 0x73, 0xf4, - 0x06, 0x8b, 0x02, 0x1e, 0x61, 0xc7, 0x7e, 0x52, 0x64, 0xd7, 0xb4, 0x43, - 0x5b, 0xec, 0xb0, 0x1c, 0x34, 0x7c, 0x02, 0x7c, 0xbc, 0x11, 0x13, 0x43, - 0xcc, 0x14, 0xdf, 0x87, 0x84, 0x45, 0x8c, 0x6f, 0xcd, 0xcc, 0x80, 0x8b, - 0x32, 0x59, 0x9b, 0x6f, 0x06, 0x87, 0x34, 0x88, 0x42, 0xae, 0x44, 0x78, - 0x92, 0x17, 0xd6, 0x64, 0x7f, 0xd4, 0x3c, 0x40, 0x5a, 0x32, 0xef, 0xf9, - 0x76, 0xdd, 0x37, 0xe8, 0xad, 0x37, 0x4b, 0xa5, 0x9d, 0x38, 0x73, 0x8d, - 0x19, 0xf0, 0x32, 0xe9, 0xbc, 0x77, 0x66, 0xb5, 0x04, 0xaf, 0x96, 0x27, - 0xf3, 0xf9, 0xbb, 0x00, 0x15, 0x89, 0x60, 0x90, 0xf1, 0xd3, 0x9c, 0x4b, - 0x61, 0xab, 0xa3, 0xa3, 0x7b, 0xba, 0x31, 0xdd, 0x36, 0x32, 0x1d, 0x45, - 0x04, 0xa1, 0x05, 0x78, 0xdf, 0xa1, 0xd0, 0xcb, 0x57, 0xe1, 0xa1, 0x5d, - 0x34, 0xe1, 0x9e, 0x34, 0xd6, 0x3e, 0xd2, 0xac, 0x54, 0xb4, 0x95, 0xc1, - 0xf9, 0xe2, 0x0d, 0x9e, 0x5b, 0x45, 0x89, 0x9d, 0x60, 0xfe, 0x35, 0x12, - 0x13, 0xe7, 0x30, 0xa7, 0x7b, 0x59, 0x6f, 0x35, 0x88, 0x11, 0x77, 0xae, - 0x71, 0x72, 0x74, 0x67, 0x2c, 0xeb, 0x13, 0xd9, 0xac, 0x96, 0x85, 0x37, - 0xd2, 0xc2, 0xa9, 0xaa, 0x78, 0xee, 0x2f, 0xc4, 0x56, 0x96, 0x96, 0x86, - 0x98, 0xb6, 0x86, 0x68, 0x55, 0x02, 0x5c, 0x96, 0x30, 0xb8, 0x9e, 0xb0, - 0x16, 0x29, 0x53, 0xd5, 0x81, 0xd0, 0xe8, 0x2d, 0xeb, 0xc0, 0x8d, 0xfd, - 0xd3, 0x8d, 0x4c, 0x38, 0xcf, 0xdb, 0x20, 0x06, 0xcf, 0xb1, 0x88, 0x8c, - 0xea, 0x9d, 0x35, 0xae, 0x26, 0xf8, 0x1f, 0x7b, 0xbc, 0x35, 0x95, 0x84, - 0x1e, 0xe4, 0x52, 0xc3, 0xce, 0xc7, 0x79, 0x5d, 0xb0, 0xaa, 0xba, 0x18, - 0x21, 0xe7, 0x98, 0x36, 0x3a, 0xb8, 0xad, 0x67, 0x02, 0x1c, 0x5c, 0x74, - 0xc1, 0x2b, 0x33, 0xf4, 0x8a, 0x36, 0xac, 0x8d, 0x20, 0x8f, 0x4b, 0x2f, - 0x10, 0x07, 0xff, 0xa2, 0x87, 0xfe, 0xac, 0x6b, 0x57, 0x16, 0x67, 0xa1, - 0x59, 0x36, 0x44, 0xf1, 0x44, 0x46, 0xe0, 0x91, 0x5e, 0x87, 0x24, 0x38, - 0x24, 0xad, 0x1e, 0x63, 0xc0, 0x8b, 0xb9, 0xa6, 0x4b, 0xee, 0xc9, 0x5f, - 0x38, 0x54, 0x42, 0x1f, 0x62, 0x4f, 0xd9, 0x92, 0x22, 0xc8, 0xd5, 0x20, - 0x02, 0x2f, 0xc4, 0x0b, 0x17, 0xdd, 0xc5, 0xfb, 0x6e, 0xe6, 0x8c, 0x79, - 0xbc, 0x29, 0x7f, 0x3f, 0x1e, 0x74, 0x1c, 0x33, 0xc9, 0x39, 0xeb, 0x2e, - 0xcf, 0xa2, 0x51, 0x0f, 0x41, 0xd9, 0x75, 0x1e, 0x0f, 0x52, 0x83, 0x1f, - 0x05, 0xdd, 0x00, 0xbe, 0xb7, 0x92, 0x2d, 0x50, 0x29, 0xb7, 0x7e, 0xaf, - 0xd9, 0xd0, 0xf6, 0xa1, 0x04, 0x1c, 0x92, 0xad, 0xfb, 0x3a, 0xfa, 0xb2, - 0x3d, 0xd6, 0xd8, 0x49, 0x6a, 0xa2, 0x03, 0xb4, 0x90, 0xd2, 0x41, 0x4a, - 0xea, 0xa0, 0x02, 0x74, 0xbb, 0x02, 0x6c, 0xc0, 0xa1, 0xa7, 0x42, 0x41, - 0x07, 0xc0, 0x0e, 0x86, 0x32, 0xc8, 0x47, 0x8a, 0x2a, 0x52, 0x20, 0x05, - 0x3e, 0x96, 0x5d, 0xc2, 0x2e, 0xc8, 0x0a, 0x25, 0x18, 0x35, 0x83, 0x8e, - 0x9f, 0x57, 0x89, 0x30, 0xf0, 0x98, 0x78, 0x81, 0x96, 0x99, 0x64, 0xc0, - 0x30, 0x17, 0xa2, 0x0e, 0x5a, 0x49, 0xd9, 0xbd, 0x6c, 0xe9, 0x54, 0x36, - 0xc8, 0xc5, 0x49, 0xf9, 0xcc, 0xa8, 0x0e, 0x3a, 0x3b, 0x08, 0x88, 0x07, - 0xac, 0xa7, 0xc9, 0x73, 0xde, 0x96, 0x2f, 0x0e, 0x1a, 0xaa, 0xf4, 0xaa, - 0xa4, 0x48, 0x49, 0x05, 0xfd, 0x03, 0x5d, 0x38, 0xfe, 0xc2, 0x9f, 0x9d, - 0xa6, 0xa6, 0x52, 0xc9, 0x00, 0x3b, 0x99, 0x16, 0x22, 0x88, 0x21, 0x66, - 0x77, 0xd8, 0x97, 0x91, 0xf0, 0xdc, 0x77, 0x91, 0x66, 0x1a, 0x6e, 0x91, - 0xb9, 0x33, 0x24, 0x93, 0xce, 0xef, 0x9f, 0xcf, 0x4d, 0xfa, 0x2a, 0x11, - 0x82, 0x6c, 0xbf, 0xbc, 0x8b, 0x5a, 0x3d, 0xb0, 0x31, 0xd7, 0x84, 0x6b, - 0xcc, 0xb9, 0x42, 0x5b, 0xa2, 0x55, 0x53, 0xa2, 0x91, 0xcb, 0xce, 0xbc, - 0x2c, 0x12, 0xb3, 0x12, 0x3b, 0xc3, 0x7a, 0xe0, 0x86, 0x9a, 0x82, 0xf6, - 0x97, 0xa4, 0x09, 0x20, 0xb6, 0xf5, 0x0a, 0x74, 0x3a, 0x68, 0x11, 0xf1, - 0xdc, 0x1b, 0x38, 0x8f, 0x98, 0x8c, 0x22, 0x2d, 0x7c, 0xe7, 0x1d, 0xf1, - 0x65, 0x2a, 0x71, 0x52, 0x0b, 0x82, 0xdd, 0xcb, 0x2b, 0xe4, 0x43, 0xc4, - 0x69, 0xe5, 0x26, 0x7a, 0x75, 0x17, 0x5a, 0xb5, 0xe3, 0x6c, 0x3b, 0x8a, - 0xbf, 0xed, 0x19, 0x77, 0xd1, 0x86, 0x6a, 0xba, 0x71, 0xe0, 0x16, 0x9d, - 0xeb, 0x0f, 0x00, 0x8f, 0x0f, 0x02, 0xfa, 0x81, 0x5b, 0x9d, 0x49, 0xd0, - 0x09, 0xcc, 0xab, 0x78, 0x3c, 0x91, 0xef, 0x9c, 0xde, 0x17, 0x51, 0x02, - 0x5e, 0x82, 0xfe, 0xda, 0xa3, 0x0e, 0xee, 0x03, 0xcd, 0x7b, 0x0c, 0x79, - 0xd9, 0x04, 0x73, 0x6d, 0xa7, 0xb6, 0xd0, 0x58, 0x58, 0x76, 0x6a, 0xc9, - 0x13, 0xd4, 0xb1, 0xe6, 0xfe, 0x9c, 0xb1, 0x4d, 0xf2, 0xc1, 0xcb, 0xb5, - 0x2f, 0x88, 0x43, 0x32, 0x1c, 0x50, 0xb5, 0x39, 0xba, 0x7f, 0xd4, 0x30, - 0xa2, 0x8d, 0x49, 0x75, 0x76, 0x49, 0x92, 0xf2, 0xd7, 0xbe, 0x92, 0x12, - 0x9d, 0x46, 0xd9, 0x6c, 0x17, 0x11, 0x1c, 0x0f, 0xd7, 0x7d, 0xc7, 0x0c, - 0x07, 0xa1, 0xee, 0x3e, 0x4b, 0xba, 0x35, 0x62, 0xdf, 0x4e, 0xc1, 0x8b, - 0x83, 0x17, 0xb5, 0x67, 0xad, 0x06, 0x7e, 0x98, 0xcd, 0x6b, 0xe7, 0x81, - 0x1f, 0xe5, 0x52, 0xc6, 0x83, 0xda, 0x6b, 0x84, 0x08, 0x88, 0xbb, 0x82, - 0x55, 0x57, 0x98, 0x87, 0x28, 0x46, 0x6b, 0x43, 0xa4, 0x55, 0x08, 0xfd, - 0x38, 0xff, 0x9e, 0xef, 0xcd, 0x8d, 0x34, 0xa5, 0x49, 0x8d, 0xa1, 0x3b, - 0xa4, 0xa0, 0x11, 0xd2, 0x48, 0x93, 0xda, 0x2a, 0xa0, 0xc9, 0xc9, 0x2c, - 0x5d, 0x6d, 0x21, 0x10, 0x26, 0xa0, 0xbb, 0x36, 0x90, 0xf9, 0x4f, 0xcc, - 0xfa, 0xa5, 0x48, 0x7b, 0xc2, 0xe6, 0xfd, 0x80, 0xac, 0x01, 0x3c, 0xff, - 0x03, 0x8f, 0xa8, 0x72, 0x0a, 0xd4, 0x9f, 0x41, 0x1b, 0xa8, 0xa3, 0xab, - 0x37, 0xc2, 0x58, 0x2d, 0x45, 0x8d, 0x1e, 0xa5, 0x8b, 0x73, 0x88, 0xd9, - 0x4d, 0x92, 0x40, 0xd4, 0x52, 0xab, 0x29, 0xbc, 0x55, 0x5e, 0xc6, 0x83, - 0xb6, 0x03, 0xee, 0xcb, 0x75, 0x34, 0xd7, 0xe0, 0x00, 0xac, 0x97, 0xb8, - 0x48, 0xc0, 0x9d, 0x4f, 0x6a, 0x3c, 0x7a, 0xe3, 0x05, 0xbb, 0x01, 0x29, - 0x94, 0xc4, 0xb4, 0xed, 0x97, 0x40, 0x1f, 0xaf, 0x6c, 0x66, 0xa0, 0x09, - 0x6d, 0x24, 0x23, 0x8f, 0xc4, 0xeb, 0xef, 0xac, 0xd5, 0xaf, 0x80, 0xb3, - 0xda, 0xbc, 0xe2, 0x8b, 0xff, 0xaa, 0x99, 0x30, 0x78, 0xcc, 0x5d, 0x2d, - 0x19, 0xfd, 0x9a, 0x42, 0x5d, 0xee, 0x76, 0x13, 0x69, 0x01, 0x03, 0x9f, - 0xa0, 0x84, 0x6e, 0x10, 0xc7, 0x29, 0x45, 0xdb, 0x31, 0x36, 0x2b, 0x88, - 0x31, 0x1c, 0x87, 0x0a, 0x7d, 0x83, 0xd7, 0xb5, 0xc1, 0x27, 0xd4, 0x7b, - 0xed, 0xf2, 0x8a, 0x74, 0xa4, 0x11, 0x5e, 0x55, 0xf3, 0x9e, 0xea, 0x5c, - 0x1b, 0xe3, 0xa2, 0xeb, 0x0f, 0x21, 0x20, 0x7b, 0xe9, 0xe9, 0xdf, 0xb4, - 0x63, 0x67, 0xc2, 0xe7, 0x5a, 0x68, 0x32, 0x09, 0x1b, 0xc0, 0x77, 0x3e, - 0x1e, 0x62, 0x63, 0x35, 0xd7, 0xc9, 0x03, 0xff, 0xd7, 0x57, 0x61, 0x5a, - 0x5a, 0x5c, 0x35, 0x8b, 0xa8, 0x19, 0x1d, 0x6c, 0xa0, 0xb7, 0x98, 0x02, - 0xbd, 0x3c, 0xaf, 0xfe, 0xa1, 0x26, 0x47, 0xb5, 0xfb, 0xbd, 0x26, 0x07, - 0x78, 0xe8, 0xae, 0x34, 0x0b, 0xc4, 0x5e, 0xac, 0x89, 0xcc, 0x5c, 0xef, - 0xcf, 0xbc, 0xae, 0x44, 0x99, 0x0a, 0xe0, 0x70, 0xb6, 0xc5, 0xe7, 0xd5, - 0x93, 0x3a, 0xe0, 0x6f, 0x6b, 0xf2, 0x28, 0x7d, 0x72, 0x09, 0xd3, 0x6a, - 0x09, 0xcc, 0xb7, 0x15, 0x26, 0xe0, 0x98, 0x41, 0x96, 0xa1, 0xa7, 0x8d, - 0x73, 0x4d, 0xa5, 0x9c, 0xd9, 0x17, 0xda, 0x7c, 0xbd, 0x66, 0xbd, 0xb8, - 0x9f, 0xe4, 0xec, 0x6b, 0x75, 0x4a, 0x75, 0x9b, 0x68, 0x5b, 0x23, 0x6a, - 0x95, 0x2b, 0xdb, 0x51, 0x48, 0x76, 0x5a, 0x90, 0xa9, 0x32, 0x23, 0x3a, - 0x3a, 0x79, 0x42, 0xdf, 0xac, 0x95, 0xd7, 0xf9, 0x19, 0x48, 0x71, 0x5e, - 0x2d, 0x21, 0x5e, 0x2d, 0x0a, 0x3a, 0xaa, 0xf0, 0x82, 0x79, 0x5f, 0xf6, - 0x0d, 0xf4, 0xd8, 0xad, 0x4c, 0x03, 0x5c, 0xba, 0xec, 0x00, 0xfe, 0xfa, - 0xc9, 0xdb, 0x0a, 0x7c, 0x1c, 0xb6, 0x98, 0x13, 0x81, 0xa6, 0x0d, 0x32, - 0xec, 0x35, 0x23, 0xf8, 0x84, 0x2c, 0xa7, 0xa4, 0x82, 0xb9, 0xb1, 0x98, - 0xb1, 0x98, 0xc0, 0xcb, 0xfc, 0x51, 0xf3, 0x01, 0xc6, 0xd3, 0x40, 0x35, - 0x99, 0x10, 0xe8, 0x5a, 0xf2, 0x62, 0xef, 0xe1, 0x3b, 0xe1, 0xab, 0x5b, - 0xe8, 0x04, 0x86, 0xd8, 0x0c, 0xdf, 0x42, 0x8b, 0x6e, 0xe0, 0xee, 0x96, - 0x78, 0xc2, 0x6d, 0xa6, 0xbd, 0x16, 0x99, 0x26, 0x8c, 0x43, 0x6a, 0x3b, - 0xe0, 0xa5, 0x7f, 0xd5, 0x28, 0xe0, 0x54, 0x58, 0xf9, 0x84, 0x72, 0xd6, - 0xa0, 0x3e, 0x03, 0x8e, 0xa6, 0x13, 0xc9, 0x89, 0x0b, 0xd8, 0xd1, 0xde, - 0x17, 0x80, 0x51, 0x41, 0xbc, 0xf9, 0x7a, 0x42, 0xee, 0xec, 0x18, 0xcc, - 0x65, 0x66, 0xaa, 0x6d, 0xc9, 0x7b, 0x97, 0x2a, 0x88, 0x55, 0xe0, 0x8f, - 0x78, 0x0a, 0x48, 0xa6, 0xf7, 0x1e, 0x78, 0xe6, 0x4c, 0x18, 0xa2, 0x9f, - 0xbd, 0x4b, 0xd9, 0x84, 0x46, 0x3c, 0x81, 0x87, 0xd5, 0xc6, 0x0c, 0x6b, - 0x8b, 0x27, 0x33, 0x71, 0x06, 0x78, 0xae, 0x83, 0x5f, 0xf4, 0xf8, 0x66, - 0x45, 0xe7, 0xb5, 0xaf, 0x89, 0x0f, 0x1a, 0x21, 0x55, 0x21, 0x78, 0xc3, - 0x51, 0xce, 0x6b, 0xb6, 0xf9, 0x69, 0x04, 0xdc, 0xd9, 0x92, 0x29, 0x80, - 0xbe, 0x45, 0x93, 0xa0, 0xc4, 0xd9, 0x99, 0x02, 0x00, 0xb5, 0xc2, 0x80, - 0xad, 0x79, 0xa6, 0x4e, 0xe6, 0xd1, 0x6d, 0xfe, 0x56, 0x03, 0xc8, 0x02, - 0xbd, 0xe5, 0x33, 0x57, 0xb4, 0x59, 0x8d, 0xdb, 0xbd, 0x01, 0xf9, 0xe9, - 0xaf, 0x9f, 0x92, 0xeb, 0x2f, 0x91, 0xba, 0x37, 0x4c, 0xfb, 0x0d, 0x73, - 0xec, 0x30, 0x34, 0x34, 0x33, 0xf6, 0xfb, 0x6a, 0xc6, 0x63, 0xda, 0x54, - 0x66, 0xa1, 0x55, 0x55, 0xc6, 0x2d, 0x88, 0xc9, 0xb9, 0xea, 0xe4, 0xca, - 0x88, 0x93, 0x8a, 0x03, 0xd7, 0x59, 0x47, 0x0a, 0xea, 0xaa, 0x05, 0x0d, - 0xc5, 0x07, 0x4c, 0xb8, 0xda, 0xe7, 0xee, 0x0a, 0x62, 0x96, 0xa0, 0xe2, - 0x8f, 0x1a, 0x0e, 0x4c, 0x0b, 0x2c, 0xf0, 0xec, 0xe7, 0xac, 0x65, 0xbb, - 0x30, 0x0d, 0xba, 0xc4, 0x39, 0x81, 0x97, 0x76, 0xf5, 0x30, 0xd9, 0xea, - 0xc7, 0xcd, 0x4a, 0xb1, 0x76, 0x74, 0x92, 0x4e, 0xe1, 0xc4, 0x3d, 0x2d, - 0x64, 0x73, 0x31, 0x40, 0x4f, 0xee, 0x73, 0x3d, 0x68, 0x62, 0x3a, 0x78, - 0xd1, 0x5c, 0x33, 0x17, 0xe2, 0x3c, 0x3c, 0x7f, 0xe9, 0xfb, 0xf7, 0xea, - 0x80, 0xe7, 0x7b, 0x88, 0x3e, 0xba, 0x42, 0x4e, 0x56, 0x39, 0x0f, 0x36, - 0x59, 0x42, 0x88, 0x64, 0x6c, 0x09, 0x1a, 0xc0, 0xe4, 0xa9, 0x22, 0x07, - 0x3a, 0xd7, 0x0c, 0x52, 0x69, 0xdc, 0x02, 0x06, 0x70, 0xd7, 0xe4, 0x0e, - 0xe8, 0x5a, 0x87, 0x80, 0xcf, 0xaa, 0x26, 0x18, 0xf7, 0x43, 0x61, 0x32, - 0x73, 0x37, 0xa1, 0x91, 0x79, 0x5f, 0xba, 0x68, 0x07, 0x8e, 0x93, 0x68, - 0xbe, 0xa7, 0x1d, 0xcd, 0x35, 0xb2, 0x0a, 0x2a, 0x1c, 0xe0, 0xb0, 0x79, - 0x1f, 0xcd, 0x00, 0x9a, 0x1b, 0x7c, 0x2d, 0x7b, 0x60, 0x77, 0x75, 0x65, - 0x2e, 0xe8, 0x0a, 0x7f, 0xfb, 0x9c, 0xbf, 0xa3, 0x45, 0xb6, 0x2b, 0x18, - 0xdf, 0xa1, 0xc7, 0x1d, 0x9d, 0x00, 0x23, 0x82, 0xdc, 0x01, 0x3d, 0x66, - 0xaa, 0xb8, 0xf4, 0x86, 0x33, 0x73, 0xb1, 0x09, 0x1c, 0x54, 0xf1, 0x16, - 0xf8, 0xa0, 0x09, 0x6c, 0xfc, 0xbe, 0x83, 0x5f, 0xea, 0x75, 0xe2, 0x35, - 0x53, 0x4e, 0x59, 0x15, 0x52, 0x8b, 0x65, 0xcd, 0x97, 0xb1, 0xd3, 0xac, - 0x07, 0x4d, 0x85, 0x2f, 0x35, 0x3d, 0xe1, 0xf3, 0xde, 0x13, 0x15, 0x2c, - 0xc3, 0xda, 0x7e, 0x97, 0x5e, 0xa6, 0xd1, 0x44, 0x6c, 0xf2, 0xfa, 0x64, - 0x45, 0x8a, 0x8d, 0x05, 0x1c, 0x0f, 0xbe, 0xde, 0xe3, 0x6e, 0xb8, 0x88, - 0xb5, 0x11, 0x3c, 0x53, 0xb8, 0x28, 0xa9, 0x95, 0x02, 0x4e, 0xa4, 0xd4, - 0xb4, 0x67, 0xbc, 0x70, 0x84, 0x09, 0xdc, 0xeb, 0x06, 0xcb, 0x23, 0x60, - 0xf5, 0x5e, 0x93, 0xe0, 0xa5, 0xe4, 0x77, 0x6e, 0xc8, 0x3a, 0x6c, 0x01, - 0x03, 0xdc, 0x2a, 0x3a, 0x7a, 0x78, 0x27, 0x6b, 0xd5, 0x97, 0xbc, 0xda, - 0x8b, 0x26, 0x9a, 0x6b, 0xdd, 0xff, 0x5e, 0x93, 0xc3, 0xc7, 0x76, 0xd4, - 0x28, 0xf0, 0x95, 0x15, 0xe8, 0x90, 0x7e, 0x8b, 0xb5, 0xa0, 0x3b, 0x50, - 0xb1, 0xcb, 0x5b, 0xb2, 0x0f, 0xf5, 0xed, 0xb8, 0x33, 0xc1, 0xaf, 0x6b, - 0xaa, 0xca, 0xcd, 0xe0, 0x5b, 0x34, 0xbd, 0x2b, 0x9a, 0xd5, 0x2b, 0x66, - 0x32, 0xa1, 0x26, 0x7e, 0x62, 0x6d, 0xc8, 0x58, 0x4b, 0x17, 0xf0, 0xd9, - 0xbb, 0x7c, 0xcf, 0xcf, 0x97, 0x90, 0x99, 0x78, 0xab, 0x79, 0xfd, 0xf0, - 0x16, 0x1b, 0x96, 0x17, 0xd7, 0xc1, 0x3e, 0x63, 0xe2, 0x50, 0x22, 0x62, - 0x95, 0x3a, 0x9b, 0xfd, 0xfd, 0x13, 0xce, 0x23, 0xe6, 0xfb, 0x8c, 0xa5, - 0x87, 0x70, 0x62, 0x60, 0x33, 0xf7, 0xf0, 0x21, 0xd6, 0x55, 0x40, 0x0d, - 0x6b, 0x9b, 0x2b, 0x11, 0x50, 0x34, 0x6b, 0xf9, 0xa1, 0x2a, 0x15, 0x8e, - 0x0e, 0x6e, 0x1f, 0x65, 0x75, 0x70, 0xc9, 0xff, 0x88, 0x9f, 0xd8, 0x1d, - 0x2c, 0x18, 0xeb, 0xb4, 0xec, 0x44, 0xc6, 0x52, 0xc1, 0x8f, 0xa9, 0x6d, - 0x1f, 0xdc, 0x2f, 0x8d, 0x6d, 0x56, 0x2d, 0xe8, 0x54, 0xe0, 0x6d, 0x9c, - 0x82, 0x67, 0x98, 0x76, 0x90, 0x97, 0xb1, 0x43, 0x9e, 0xb9, 0x51, 0xe5, - 0x71, 0x33, 0xcc, 0xf5, 0xf3, 0x5f, 0x73, 0x7d, 0x93, 0x98, 0xb9, 0xf3, - 0xbd, 0x44, 0x91, 0xb7, 0x56, 0x9e, 0xab, 0xcb, 0x08, 0x58, 0x5d, 0xe7, - 0xee, 0x08, 0x46, 0x1b, 0xdf, 0xc0, 0xd3, 0x9c, 0x99, 0xd1, 0xdb, 0x07, - 0x87, 0x8c, 0xbc, 0x51, 0x29, 0xb4, 0xa9, 0x31, 0xc0, 0x1b, 0x36, 0x81, - 0x66, 0x74, 0x44, 0x28, 0xe9, 0xb8, 0xe1, 0x0e, 0x35, 0x41, 0x53, 0x5f, - 0x43, 0x1a, 0x6c, 0x0e, 0x6e, 0x60, 0xe0, 0x06, 0x57, 0x49, 0x2d, 0x43, - 0xe6, 0xb8, 0x63, 0x94, 0xaa, 0x03, 0xf8, 0xa8, 0xf1, 0x8f, 0x9a, 0x4e, - 0x28, 0xa2, 0x24, 0x99, 0xd7, 0xae, 0xf0, 0x96, 0x9a, 0x49, 0x97, 0x2d, - 0x48, 0x83, 0x81, 0x2b, 0x51, 0x24, 0x8c, 0x68, 0x2c, 0x9b, 0xf1, 0x06, - 0x38, 0xff, 0x02, 0xbd, 0x97, 0x61, 0x24, 0xda, 0xa4, 0x19, 0x6e, 0x99, - 0x72, 0x6f, 0xa5, 0x5e, 0xa9, 0xb0, 0xf9, 0x7a, 0x63, 0xf0, 0x7e, 0xa0, - 0xbf, 0xc1, 0x6b, 0xe8, 0x51, 0xce, 0xd4, 0x5e, 0x18, 0x15, 0xcc, 0x3e, - 0xbe, 0xe1, 0xb9, 0xc6, 0x20, 0x1f, 0x79, 0x6c, 0xda, 0x9c, 0x3b, 0x8a, - 0x49, 0x35, 0x7b, 0xcc, 0xd7, 0xc4, 0x3d, 0xdd, 0x48, 0xe8, 0xaf, 0x7b, - 0xec, 0x21, 0x33, 0xac, 0x0b, 0x78, 0x13, 0xc1, 0x8c, 0x97, 0x15, 0xb5, - 0x2b, 0x27, 0xdc, 0xac, 0x9c, 0xcc, 0x60, 0x7d, 0xe9, 0xaa, 0x2e, 0x41, - 0x62, 0x5e, 0xd3, 0xbc, 0xe1, 0xad, 0x58, 0xe6, 0x35, 0x1b, 0x40, 0xa7, - 0x5e, 0xb2, 0x96, 0x98, 0x10, 0x17, 0xef, 0x19, 0x1b, 0x7e, 0xdf, 0xa3, - 0x7f, 0x59, 0x44, 0x6d, 0x90, 0x96, 0x3e, 0xf6, 0xe3, 0xb4, 0x6a, 0xa4, - 0x09, 0x5a, 0xf6, 0xbc, 0xa2, 0x52, 0x8b, 0x40, 0x07, 0xa0, 0x01, 0x7c, - 0xab, 0x27, 0xbd, 0xe0, 0xba, 0x83, 0xd8, 0x3f, 0xb2, 0xe8, 0x05, 0xfc, - 0x71, 0xe1, 0xcd, 0x6b, 0xbe, 0x2f, 0x6f, 0x97, 0x48, 0xf1, 0xb2, 0x9b, - 0x6b, 0x8d, 0xaf, 0x8d, 0x79, 0x5f, 0x6d, 0x31, 0xd7, 0xec, 0xf6, 0xd4, - 0x22, 0x99, 0xef, 0x3d, 0xa7, 0xb2, 0x2d, 0x61, 0x6c, 0x8b, 0xa6, 0xf7, - 0x32, 0x45, 0xb6, 0x24, 0x05, 0xdd, 0xe0, 0x09, 0x16, 0x9d, 0x07, 0x04, - 0x78, 0xbd, 0x48, 0x38, 0x7d, 0x01, 0x9e, 0x5a, 0x21, 0x8d, 0x5e, 0xe1, - 0x5c, 0x67, 0xd4, 0x1d, 0x97, 0x47, 0x38, 0x17, 0x45, 0x14, 0xbc, 0x65, - 0xf6, 0xce, 0x58, 0x00, 0xfe, 0x4d, 0x55, 0x8c, 0x01, 0xae, 0x75, 0xea, - 0x1d, 0xb7, 0xe2, 0x11, 0xf2, 0x55, 0x10, 0x36, 0xe8, 0x1c, 0x23, 0x76, - 0x29, 0x59, 0xe5, 0x01, 0x6f, 0x3f, 0x85, 0x02, 0xae, 0x57, 0x97, 0x67, - 0xee, 0xd8, 0x0f, 0x82, 0xe4, 0x81, 0x9d, 0x57, 0x19, 0xf8, 0xd4, 0x1d, - 0xc4, 0xf5, 0x95, 0xb0, 0xf2, 0x25, 0x12, 0x75, 0x67, 0x90, 0x4f, 0x4c, - 0x9d, 0x26, 0x66, 0xf6, 0xe0, 0x5f, 0xa9, 0x75, 0xf0, 0x59, 0x8b, 0x29, - 0x1b, 0x32, 0xfa, 0xf5, 0x8e, 0x29, 0x5b, 0x10, 0x47, 0x2d, 0xe7, 0xba, - 0x8b, 0x19, 0x47, 0x29, 0xf5, 0xb7, 0xe6, 0x5c, 0xe9, 0xb4, 0xf4, 0xed, - 0x88, 0x38, 0xe4, 0x5d, 0xd6, 0x55, 0xcb, 0xda, 0x93, 0x26, 0xa8, 0xda, - 0xe5, 0x0a, 0xdf, 0x13, 0x74, 0x99, 0xef, 0x55, 0x72, 0x02, 0x38, 0x0e, - 0xbc, 0x62, 0x1f, 0xd2, 0x52, 0xdf, 0xe9, 0x36, 0xe3, 0x09, 0xf8, 0x86, - 0x66, 0x7e, 0x06, 0x3b, 0xe4, 0xd2, 0xeb, 0xab, 0x0c, 0xf4, 0x6f, 0x6e, - 0xe2, 0x86, 0x23, 0xa9, 0x97, 0x9a, 0x3b, 0xdf, 0x47, 0x71, 0x41, 0x7f, - 0xab, 0x88, 0xf6, 0x38, 0x46, 0xf2, 0x55, 0x26, 0xc4, 0xca, 0x6a, 0x7b, - 0x51, 0xfa, 0x27, 0xf0, 0x5f, 0x84, 0x84, 0x09, 0x28, 0x3a, 0x47, 0x72, - 0xe9, 0x8e, 0x3e, 0xa1, 0x58, 0x94, 0x7c, 0x38, 0x00, 0x9f, 0xe8, 0xb3, - 0x4f, 0x28, 0xe3, 0x79, 0x8d, 0x53, 0xef, 0x82, 0xd7, 0x23, 0x72, 0x33, - 0x18, 0x04, 0xae, 0x0d, 0xb4, 0xca, 0xae, 0xa4, 0xca, 0x88, 0x8d, 0xfe, - 0x4e, 0x5a, 0x74, 0x11, 0x9b, 0x55, 0x73, 0xa0, 0x8b, 0x31, 0xd7, 0xd0, - 0x37, 0xe1, 0x56, 0x40, 0xfc, 0x20, 0x0c, 0x3d, 0x7d, 0x37, 0x3f, 0x2b, - 0xc7, 0x9d, 0xd0, 0x12, 0x63, 0x75, 0x07, 0xed, 0x4f, 0x69, 0xc2, 0x82, - 0xac, 0x01, 0x5d, 0xc4, 0xe8, 0xb4, 0x33, 0xd4, 0x20, 0xb5, 0xea, 0x7b, - 0x37, 0xa9, 0x5d, 0xc2, 0x07, 0xb7, 0xa8, 0x89, 0x8b, 0x5d, 0x0b, 0x30, - 0x8b, 0x80, 0xa7, 0x19, 0xa6, 0x04, 0xf5, 0x39, 0x70, 0x97, 0x4e, 0x10, - 0x9e, 0xf7, 0x77, 0x2e, 0xb0, 0x46, 0x44, 0xe2, 0x2b, 0x88, 0xf9, 0x20, - 0x65, 0x6d, 0x60, 0x42, 0xdf, 0xe2, 0xc4, 0x0c, 0x17, 0xf9, 0x54, 0x1d, - 0x28, 0x1d, 0x2f, 0xa0, 0x76, 0x45, 0xe8, 0x59, 0x07, 0xc8, 0x75, 0x25, - 0xb8, 0x7a, 0x1e, 0x3d, 0x32, 0xd7, 0x80, 0x49, 0x98, 0xb6, 0xd2, 0xe6, - 0x67, 0x9d, 0x71, 0x8a, 0x4c, 0x9e, 0x08, 0xbf, 0x34, 0xc5, 0x50, 0x82, - 0x2e, 0x07, 0x4f, 0x1b, 0x14, 0x6a, 0xab, 0x33, 0xe8, 0x1b, 0xb4, 0x27, - 0x42, 0x24, 0x7c, 0xd0, 0x44, 0x41, 0xd2, 0x06, 0xe0, 0x45, 0x91, 0xf8, - 0x7d, 0x0f, 0x3b, 0x89, 0x88, 0x9e, 0x8d, 0x65, 0x1d, 0xec, 0xe2, 0xae, - 0x79, 0x49, 0x93, 0xa5, 0xa4, 0x8e, 0x6e, 0xe0, 0xc7, 0xc0, 0x93, 0x89, - 0x34, 0xf7, 0xa2, 0x1b, 0xf0, 0x7c, 0x08, 0xbc, 0x6d, 0x4b, 0xef, 0xa5, - 0xcb, 0xf3, 0x4a, 0x2b, 0x5b, 0xf4, 0x7b, 0xbc, 0xa1, 0x9e, 0x85, 0xd0, - 0xf7, 0x78, 0x12, 0x90, 0x97, 0xf0, 0x39, 0x13, 0x3b, 0x65, 0xab, 0x1f, - 0xf2, 0xc9, 0x66, 0xb2, 0xd1, 0x2f, 0x8c, 0x6b, 0x5a, 0x46, 0x2b, 0x2d, - 0x36, 0xac, 0xea, 0xe0, 0x67, 0xa6, 0x74, 0xad, 0xb9, 0xae, 0x3c, 0xf0, - 0x3b, 0xcc, 0x83, 0xbf, 0xd6, 0xe6, 0xba, 0xd8, 0xb1, 0xf7, 0x9a, 0xeb, - 0x46, 0x74, 0x91, 0x3e, 0xd7, 0x50, 0x54, 0xdf, 0xd8, 0xec, 0xeb, 0x5c, - 0xa9, 0x2c, 0xd3, 0xd5, 0x79, 0x67, 0xaa, 0x2b, 0x07, 0x9e, 0x3c, 0x78, - 0xf7, 0x29, 0x64, 0xd8, 0xff, 0x55, 0xb3, 0x41, 0xc7, 0x17, 0x88, 0xf3, - 0x8a, 0xaa, 0x6a, 0x51, 0xa2, 0x8a, 0xcb, 0x4e, 0xda, 0xb4, 0x71, 0xad, - 0x63, 0x8d, 0xbe, 0xc1, 0x53, 0x1d, 0x44, 0x52, 0x01, 0xda, 0x07, 0x0d, - 0xf0, 0xde, 0x35, 0x8b, 0x57, 0x4b, 0xc9, 0x2b, 0x4b, 0x9a, 0xe4, 0x0e, - 0x7a, 0x26, 0xd9, 0x69, 0xec, 0x55, 0xb6, 0xa0, 0xcb, 0x7c, 0xf0, 0x36, - 0xed, 0x68, 0x1e, 0xbd, 0xc5, 0x4b, 0x78, 0xc3, 0x37, 0xe7, 0x68, 0x0b, - 0x79, 0xeb, 0x26, 0x93, 0xac, 0x08, 0x52, 0x95, 0xf4, 0x98, 0x53, 0x7a, - 0x3d, 0xa8, 0xdd, 0x20, 0x9e, 0xeb, 0x16, 0x14, 0x6d, 0x0f, 0x5e, 0x62, - 0x5e, 0x53, 0xd0, 0x2b, 0x36, 0x6d, 0x47, 0x92, 0x34, 0x23, 0x49, 0xa9, - 0x86, 0xb9, 0xf2, 0x43, 0x2a, 0x2d, 0xf0, 0x71, 0xe8, 0x40, 0xc9, 0x19, - 0xda, 0xf7, 0x30, 0xea, 0xd1, 0x5c, 0x1f, 0x85, 0xb4, 0x55, 0x05, 0xda, - 0xfc, 0x1b, 0xbc, 0xfb, 0x08, 0x31, 0x11, 0xce, 0xb5, 0x1b, 0x09, 0xf8, - 0xe3, 0xac, 0x45, 0x5e, 0x0c, 0x7a, 0x2d, 0xef, 0x6c, 0x3b, 0x32, 0xc8, - 0x5c, 0x0b, 0x82, 0xb2, 0xfa, 0xf4, 0x86, 0x5c, 0xe4, 0x7f, 0x8b, 0x47, - 0x0a, 0x9c, 0xc6, 0x98, 0xac, 0x72, 0x2a, 0x6a, 0xc8, 0x39, 0x88, 0xc1, - 0xb9, 0xce, 0x59, 0xf8, 0x04, 0x1d, 0xd7, 0xec, 0x8c, 0xd3, 0xab, 0x74, - 0xc7, 0x00, 0x34, 0xc6, 0xb5, 0xdc, 0x0c, 0xdb, 0x88, 0x0b, 0xf0, 0x21, - 0x32, 0x39, 0xa6, 0x64, 0xae, 0x4d, 0x16, 0xc0, 0xdf, 0x0d, 0xc4, 0xec, - 0xbc, 0xcf, 0xfd, 0x4c, 0xdd, 0xd5, 0x08, 0xfa, 0xb2, 0x4e, 0xb4, 0x95, - 0x0e, 0x7e, 0x6a, 0xde, 0xe6, 0x0f, 0x58, 0x00, 0x5a, 0x16, 0x89, 0x18, - 0x38, 0xe3, 0x57, 0x0d, 0x97, 0xf9, 0xbb, 0xd1, 0xe6, 0xda, 0x40, 0xc0, - 0x99, 0x5a, 0xe1, 0x9e, 0x34, 0xe2, 0xa0, 0xa7, 0x00, 0x9f, 0x2f, 0x34, - 0x4b, 0x27, 0xc6, 0xb8, 0x8b, 0x3d, 0xe4, 0x83, 0x07, 0xc1, 0x09, 0x67, - 0xfc, 0x6f, 0xe3, 0x5f, 0x78, 0x18, 0xd0, 0x47, 0xfa, 0xbb, 0xf7, 0xe0, - 0xd3, 0x16, 0xce, 0x5f, 0xdb, 0x80, 0x39, 0x27, 0x88, 0x03, 0x3b, 0x3c, - 0xce, 0xdf, 0x5d, 0xa6, 0x42, 0x8b, 0x70, 0x31, 0xd7, 0xed, 0x7e, 0x90, - 0xb4, 0xba, 0x49, 0xe0, 0x18, 0xd0, 0xc3, 0x70, 0xfe, 0xea, 0x11, 0x7b, - 0x96, 0xc7, 0x15, 0x19, 0x78, 0xa3, 0x0f, 0x11, 0x0d, 0xce, 0xc5, 0x66, - 0x65, 0xc1, 0xb5, 0xd3, 0x04, 0x55, 0x82, 0xc7, 0xf7, 0x91, 0xa5, 0x76, - 0xc2, 0x38, 0xf0, 0x9d, 0x1e, 0xdc, 0x00, 0x2f, 0x58, 0x5c, 0x93, 0x38, - 0xd7, 0xd7, 0x8b, 0x52, 0xc3, 0x11, 0x9c, 0xfb, 0x42, 0x5d, 0x64, 0x1f, - 0xfd, 0xec, 0x15, 0xa6, 0xcc, 0xe5, 0xae, 0x0b, 0x71, 0xaa, 0x4c, 0xe0, - 0xee, 0x5d, 0xd4, 0xe0, 0x91, 0x35, 0x03, 0x87, 0xd7, 0xe1, 0x4a, 0x99, - 0x17, 0xa5, 0x24, 0x8c, 0xa7, 0xf5, 0x2b, 0x4e, 0xec, 0x27, 0xf0, 0xe5, - 0x05, 0xf8, 0x0b, 0x03, 0xbf, 0x7c, 0x0b, 0xbe, 0xbd, 0x31, 0x4f, 0x0f, - 0x58, 0x8d, 0x2a, 0xc0, 0xd5, 0x05, 0xd9, 0x00, 0x0f, 0x4e, 0x28, 0x00, - 0xad, 0xf4, 0x3a, 0xf0, 0x20, 0x3a, 0x22, 0xe5, 0x83, 0x7f, 0x49, 0x0b, - 0x0e, 0xda, 0x98, 0x0e, 0x55, 0xdc, 0x68, 0x63, 0xc8, 0x51, 0x26, 0x5c, - 0xb1, 0xa5, 0x6e, 0x34, 0x62, 0xd0, 0x63, 0xb1, 0x8a, 0x8c, 0x84, 0xf7, - 0xc9, 0xce, 0x68, 0xa6, 0x79, 0xbf, 0x4c, 0xa6, 0xe4, 0x00, 0xfd, 0xb2, - 0x67, 0xbc, 0x04, 0x2d, 0xfd, 0x66, 0x9e, 0x5a, 0x12, 0x7f, 0xae, 0x39, - 0x11, 0x60, 0xd0, 0x59, 0x8b, 0xb9, 0xce, 0x3f, 0x6f, 0x4e, 0xcf, 0xbc, - 0x5d, 0x0d, 0x47, 0x65, 0x3f, 0xa4, 0x37, 0x54, 0xcc, 0x3d, 0x3d, 0xc1, - 0x81, 0xdc, 0x80, 0xfb, 0x17, 0x99, 0xaa, 0xbe, 0x0b, 0x3f, 0x58, 0x32, - 0x66, 0x4f, 0xa1, 0x1b, 0x81, 0x8e, 0x62, 0x22, 0x71, 0x25, 0xca, 0xe7, - 0x35, 0x22, 0x2e, 0x36, 0x12, 0x4d, 0xbc, 0x32, 0xbd, 0x82, 0xf6, 0x2c, - 0x92, 0xcc, 0x97, 0x43, 0x91, 0x43, 0x3d, 0xe1, 0x85, 0xed, 0x09, 0xfc, - 0x2d, 0xea, 0x72, 0xad, 0xef, 0x62, 0x86, 0xbf, 0xe3, 0x2e, 0x70, 0x12, - 0x57, 0xa7, 0x79, 0x1d, 0x38, 0x5c, 0xe1, 0x37, 0x03, 0x7d, 0x00, 0x31, - 0x5c, 0x51, 0x5e, 0xbd, 0x61, 0x7c, 0x42, 0xc8, 0xd0, 0x38, 0x63, 0xe5, - 0x93, 0x72, 0x3d, 0x85, 0xbc, 0x78, 0xfe, 0xaa, 0x4b, 0x58, 0x67, 0xcf, - 0x83, 0x8b, 0x71, 0xdc, 0x82, 0x4f, 0x50, 0xbd, 0x51, 0x82, 0xee, 0x81, - 0xf0, 0xee, 0x61, 0xac, 0xfb, 0xc4, 0x13, 0x13, 0x9b, 0x6b, 0xca, 0xe8, - 0xd9, 0xf3, 0xe8, 0x8a, 0x28, 0xee, 0xe4, 0x23, 0xd4, 0xfa, 0x5b, 0xe9, - 0x56, 0x08, 0xf4, 0xcf, 0x2d, 0x46, 0x7d, 0x9b, 0xb8, 0x11, 0x20, 0x0f, - 0x11, 0xe0, 0xaf, 0x40, 0x43, 0x8d, 0xb3, 0xf7, 0xdd, 0xe5, 0x1d, 0x78, - 0xcf, 0xc6, 0x3a, 0x1f, 0x81, 0x6c, 0x22, 0xba, 0x62, 0x71, 0x8a, 0x83, - 0x79, 0xdf, 0x47, 0xc4, 0x35, 0x73, 0x3f, 0xb1, 0xa0, 0x70, 0xc8, 0x5c, - 0x93, 0x6b, 0x49, 0x1b, 0x31, 0x16, 0xe0, 0x7d, 0x62, 0x5f, 0x5c, 0x8e, - 0x3e, 0xab, 0xa2, 0xb9, 0xfe, 0x5c, 0x6d, 0x8b, 0x4c, 0x31, 0x2a, 0x78, - 0x34, 0x86, 0x9a, 0xba, 0x1f, 0x98, 0xdd, 0xcc, 0xeb, 0x05, 0xe6, 0x1a, - 0x5e, 0xa0, 0xe9, 0x59, 0xc4, 0x91, 0x22, 0xe0, 0xfa, 0x41, 0xa3, 0xf8, - 0xcc, 0x60, 0x82, 0x4e, 0xc2, 0x4b, 0x8c, 0xc6, 0x38, 0x20, 0x7b, 0xbe, - 0x57, 0xc4, 0xa5, 0x29, 0x37, 0x52, 0x63, 0x67, 0xea, 0x8b, 0xb9, 0xfe, - 0x54, 0xce, 0x95, 0x9c, 0xa4, 0x51, 0x55, 0xc2, 0xb1, 0xcf, 0x42, 0x27, - 0x0e, 0xa6, 0xc3, 0x16, 0xd7, 0xc4, 0x4e, 0x12, 0xe4, 0x1e, 0x5c, 0xc0, - 0xa7, 0x44, 0x3d, 0x64, 0x87, 0xb3, 0xb9, 0x06, 0x72, 0x48, 0x47, 0x0b, - 0xf0, 0xe0, 0x19, 0xb6, 0x3a, 0x60, 0x23, 0xe8, 0x1c, 0x47, 0xc4, 0xac, - 0x19, 0xad, 0xb8, 0x55, 0x7b, 0x56, 0x93, 0x43, 0xc6, 0xd6, 0x63, 0x91, - 0xd8, 0xc6, 0x1e, 0xda, 0x3d, 0xfa, 0x73, 0x8d, 0x54, 0x69, 0x70, 0xe0, - 0xd9, 0xbc, 0xbb, 0xe8, 0xd4, 0x60, 0x5b, 0xf0, 0x53, 0x7b, 0xe0, 0x04, - 0x44, 0x11, 0x1e, 0x0a, 0x9f, 0x6d, 0xc0, 0x9b, 0xd4, 0xdc, 0x27, 0x59, - 0xe1, 0x7d, 0x2d, 0x0a, 0x2e, 0x17, 0xdc, 0x09, 0xde, 0xa0, 0xeb, 0xde, - 0xe0, 0x0b, 0x81, 0x5f, 0x56, 0x71, 0x31, 0xaf, 0x2b, 0xf2, 0xf1, 0x99, - 0x2a, 0xbc, 0x28, 0x7c, 0x52, 0x95, 0xed, 0xaa, 0x0d, 0xcd, 0x50, 0x3f, - 0x80, 0x86, 0x64, 0xb3, 0xbf, 0xe5, 0xc0, 0x87, 0xbc, 0x8a, 0x80, 0x7b, - 0x62, 0xb8, 0xbe, 0xae, 0xe0, 0x56, 0x7e, 0xa0, 0xfd, 0xae, 0xd4, 0x83, - 0x25, 0xfc, 0xec, 0xf7, 0xda, 0x90, 0x90, 0xa6, 0x7f, 0xc7, 0xde, 0xc5, - 0x9a, 0xbf, 0x8b, 0x63, 0xae, 0x4d, 0xc7, 0xdd, 0xde, 0x8e, 0x4c, 0xd4, - 0x89, 0x66, 0xab, 0x87, 0x68, 0xfb, 0x4a, 0xb4, 0xca, 0xc9, 0xff, 0xc8, - 0x3f, 0xf0, 0x70, 0x7e, 0xe1, 0x30, 0xf0, 0x25, 0x01, 0xe8, 0xab, 0x08, - 0x74, 0xbb, 0x8c, 0x23, 0xc6, 0x72, 0xc8, 0xe1, 0xc5, 0xb1, 0x13, 0xd7, - 0x30, 0x1e, 0xe0, 0x8a, 0x30, 0xe8, 0xbe, 0xc5, 0xeb, 0x90, 0xb8, 0xe6, - 0x91, 0xce, 0x35, 0xc6, 0xfa, 0x1b, 0xc4, 0xe6, 0x96, 0x32, 0xf0, 0x35, - 0xb4, 0x87, 0x56, 0xc0, 0xf7, 0x79, 0x81, 0x88, 0x1d, 0x24, 0xc2, 0x86, - 0xec, 0x99, 0xcf, 0x38, 0xe8, 0x4a, 0x13, 0xeb, 0x73, 0x1d, 0xfc, 0x20, - 0x9f, 0xeb, 0xb4, 0xe0, 0x46, 0x56, 0x5c, 0xa9, 0x34, 0x9b, 0xec, 0x45, - 0x96, 0x06, 0x97, 0xcc, 0x28, 0x27, 0xcc, 0x32, 0x1d, 0xfa, 0x71, 0x90, - 0x46, 0xbf, 0x0b, 0xe7, 0xbc, 0x35, 0xe4, 0x2e, 0x9a, 0x10, 0xc4, 0x2c, - 0xc4, 0x57, 0xd7, 0xef, 0xd8, 0xdf, 0xf8, 0x64, 0xb3, 0xd2, 0xe2, 0x54, - 0x0d, 0x90, 0x87, 0x22, 0x33, 0xd7, 0x8b, 0xe3, 0xfc, 0x8d, 0x2d, 0x90, - 0xfb, 0x92, 0x0e, 0x3b, 0x09, 0xb1, 0x06, 0x2a, 0x00, 0xb0, 0x11, 0x65, - 0x47, 0x15, 0x54, 0x89, 0x29, 0x60, 0xfe, 0x2b, 0x0b, 0xe6, 0xa8, 0xc7, - 0xc0, 0x29, 0x49, 0xb3, 0x30, 0x61, 0x1e, 0xc0, 0x4f, 0x54, 0x5d, 0xc2, - 0x81, 0xf7, 0x5b, 0xed, 0x99, 0xbb, 0x32, 0xcb, 0x1b, 0x86, 0x42, 0x86, - 0x6e, 0x07, 0xbf, 0x99, 0xbf, 0xbb, 0x65, 0x7b, 0x6c, 0xaa, 0x7b, 0xd2, - 0x22, 0x01, 0x9a, 0xc2, 0x08, 0xdd, 0x8b, 0x0e, 0x7a, 0x21, 0x10, 0x7a, - 0x10, 0xe6, 0xf1, 0xea, 0x11, 0xb7, 0xaf, 0x97, 0xf4, 0x83, 0x36, 0xe2, - 0x2b, 0x06, 0x3e, 0x54, 0x67, 0x88, 0xd9, 0x89, 0x27, 0x9d, 0xbc, 0x55, - 0x61, 0xd2, 0xe8, 0x79, 0x6c, 0x44, 0x90, 0xef, 0xcd, 0x44, 0x3c, 0xfd, - 0x06, 0x1c, 0xfd, 0x0d, 0xf3, 0xed, 0xcd, 0xf5, 0xd9, 0x32, 0x15, 0xa8, - 0x03, 0xc3, 0x98, 0x26, 0x01, 0x84, 0x04, 0xe3, 0xd8, 0x98, 0x39, 0x4d, - 0x6d, 0x0a, 0x14, 0x4c, 0x90, 0x06, 0x6f, 0xc0, 0x48, 0x42, 0x37, 0xf7, - 0x49, 0x68, 0xd2, 0xe6, 0x9b, 0xbb, 0x49, 0x4c, 0x02, 0xfd, 0xfa, 0x95, - 0x9f, 0x67, 0x4a, 0x03, 0xf0, 0xcb, 0xec, 0x0d, 0x98, 0x64, 0x16, 0xad, - 0xbe, 0x08, 0xf9, 0xb8, 0xc9, 0x5d, 0x65, 0x1f, 0x3c, 0x96, 0xe7, 0xf3, - 0xe7, 0x3d, 0x92, 0xe6, 0x1c, 0xe2, 0xaa, 0xeb, 0x1d, 0xea, 0x82, 0x4a, - 0x75, 0x44, 0xc3, 0xda, 0xb9, 0xfe, 0x94, 0x9d, 0xb2, 0x44, 0xe0, 0xd8, - 0x40, 0xd7, 0x58, 0xff, 0xa5, 0xd7, 0xc6, 0xac, 0x69, 0xac, 0xd8, 0x6c, - 0x26, 0x8c, 0xd8, 0x56, 0xa6, 0xee, 0x33, 0x33, 0xb4, 0x45, 0xe2, 0x04, - 0x75, 0xb9, 0xf9, 0x1a, 0x39, 0x53, 0x2f, 0xec, 0x20, 0x3c, 0xd7, 0x92, - 0x28, 0xf5, 0x70, 0x2a, 0x3d, 0xf2, 0xce, 0xd3, 0x5f, 0x7b, 0x0c, 0x8d, - 0xc4, 0x05, 0x9f, 0x66, 0xc2, 0xdc, 0x28, 0x01, 0xd7, 0xa6, 0x74, 0xde, - 0x58, 0x01, 0x35, 0xcb, 0x31, 0x32, 0x71, 0x48, 0xf5, 0xb9, 0x6e, 0x28, - 0x23, 0x61, 0x8a, 0xe6, 0x9a, 0x02, 0x4e, 0xa2, 0x57, 0xef, 0x3c, 0x11, - 0xcb, 0x28, 0x61, 0x31, 0x69, 0x5c, 0x0d, 0x7b, 0xf7, 0xb7, 0xa8, 0x33, - 0x8b, 0x4c, 0x20, 0xb3, 0x52, 0x11, 0x32, 0x85, 0x55, 0xcc, 0x2d, 0x57, - 0xf8, 0xe2, 0x1d, 0xf2, 0xcb, 0xfc, 0x9d, 0x00, 0xe1, 0xfc, 0xfc, 0x08, - 0xae, 0xfd, 0x1c, 0x32, 0xf6, 0x8c, 0xd2, 0x59, 0xb7, 0xa9, 0x24, 0xe3, - 0xee, 0x8b, 0xbb, 0x8a, 0x83, 0x5f, 0x5f, 0x02, 0x46, 0xd0, 0x79, 0x7d, - 0x51, 0xc8, 0x32, 0x0b, 0xb8, 0x3d, 0x3d, 0x26, 0x72, 0x79, 0x74, 0xad, - 0xb3, 0xf0, 0xe6, 0x67, 0x81, 0x6b, 0xf0, 0xfc, 0xa8, 0x29, 0x6b, 0xf2, - 0x8a, 0x4d, 0x42, 0x41, 0xbb, 0x74, 0xb1, 0x37, 0x72, 0xd0, 0x89, 0x6f, - 0xd1, 0xa1, 0x38, 0xa9, 0x33, 0x23, 0x06, 0xae, 0x8e, 0xdd, 0x59, 0x73, - 0x5b, 0xfc, 0x90, 0x56, 0xd9, 0xce, 0xd8, 0xbe, 0x13, 0xd7, 0xda, 0xe1, - 0xa6, 0xaa, 0xc5, 0xec, 0x71, 0x4c, 0x15, 0x92, 0xc4, 0xee, 0xcb, 0x5a, - 0x42, 0xcc, 0x96, 0xa3, 0x00, 0x9d, 0x09, 0xb9, 0xac, 0x33, 0x4f, 0xc6, - 0x39, 0xb7, 0xfa, 0xa2, 0x16, 0x71, 0xa6, 0x01, 0x37, 0x35, 0x24, 0x3d, - 0xb8, 0xaf, 0x1b, 0x71, 0x9b, 0x67, 0xd8, 0x8c, 0x13, 0x73, 0x2d, 0x24, - 0xdc, 0x20, 0x88, 0xc1, 0xf7, 0x93, 0x46, 0x7f, 0x82, 0x1f, 0xd9, 0x30, - 0x26, 0x1a, 0xec, 0x84, 0x13, 0xdd, 0x0c, 0x59, 0xc2, 0xc0, 0x53, 0xcd, - 0xf5, 0x4c, 0xb4, 0x11, 0xb4, 0xc0, 0xfc, 0xdd, 0x39, 0xf6, 0xa1, 0x34, - 0xe8, 0x13, 0xf2, 0x3c, 0x2e, 0x5c, 0x31, 0x32, 0x2d, 0x1b, 0x45, 0xaa, - 0x8c, 0xa2, 0x86, 0xfe, 0xa6, 0xcc, 0xc3, 0xd0, 0x46, 0xae, 0xbd, 0xde, - 0x1c, 0xb8, 0x84, 0x50, 0x71, 0x3b, 0xd0, 0x40, 0x65, 0xa6, 0x1a, 0x41, - 0xb7, 0x39, 0xc0, 0xc7, 0xb7, 0x88, 0x32, 0x27, 0x34, 0x71, 0x2d, 0x41, - 0x1b, 0xe0, 0x5a, 0x78, 0xc2, 0x41, 0xba, 0xd4, 0xf1, 0x92, 0xa5, 0xf2, - 0x1d, 0x75, 0xd5, 0x3e, 0x6b, 0xac, 0x3d, 0xee, 0x70, 0x77, 0x44, 0xeb, - 0xb9, 0x2e, 0x7a, 0x1d, 0xd1, 0xe1, 0x4a, 0x5d, 0x25, 0xf2, 0x09, 0x50, - 0x38, 0x51, 0x2f, 0x11, 0x7f, 0x3d, 0xa9, 0x29, 0xf7, 0xa1, 0x83, 0xad, - 0x92, 0xca, 0x2a, 0x4b, 0xb0, 0x05, 0x3a, 0x12, 0x93, 0x36, 0xb4, 0x64, - 0x2b, 0xbe, 0x4b, 0xdd, 0x9e, 0xeb, 0xbf, 0x8c, 0x25, 0xc8, 0x11, 0xc9, - 0x07, 0x96, 0x2b, 0xa9, 0x41, 0x8e, 0x57, 0x71, 0xab, 0x07, 0xd2, 0xcc, - 0x26, 0x88, 0x31, 0x2f, 0xeb, 0xc8, 0x03, 0xb0, 0xdd, 0xdf, 0x1b, 0xa0, - 0xf0, 0xbb, 0x3e, 0xa5, 0x2d, 0x06, 0x9d, 0xbe, 0xd5, 0xc0, 0x0b, 0xc6, - 0xac, 0xc3, 0x24, 0xaf, 0x9b, 0x67, 0xe1, 0x55, 0xf7, 0x22, 0x45, 0x53, - 0x66, 0x80, 0xaf, 0x48, 0x98, 0x0a, 0x9d, 0xb5, 0x5e, 0xcc, 0xdf, 0x15, - 0xa2, 0xe3, 0x6b, 0x92, 0xc8, 0xbb, 0x50, 0x95, 0x16, 0x26, 0x58, 0x51, - 0x56, 0x1a, 0xd0, 0x87, 0x3b, 0x31, 0x30, 0xc3, 0xc6, 0xf0, 0x48, 0x12, - 0x71, 0x05, 0x1f, 0x05, 0xb9, 0x53, 0xcd, 0x75, 0x33, 0x7e, 0xaf, 0x7b, - 0xd1, 0xa0, 0xfd, 0x5e, 0x47, 0x87, 0x4c, 0xf5, 0x6f, 0xc0, 0x20, 0x1e, - 0x83, 0x9e, 0xcd, 0x3a, 0x65, 0x01, 0x4f, 0x1b, 0xc7, 0xe6, 0xd7, 0xb3, - 0xee, 0x0e, 0x7c, 0xef, 0x32, 0xd4, 0x40, 0x17, 0x21, 0x42, 0xe8, 0xd4, - 0xdc, 0xf6, 0x53, 0x65, 0x02, 0x9e, 0x74, 0x54, 0x8b, 0x6e, 0x74, 0xf3, - 0x65, 0x0a, 0xd0, 0xb1, 0xf1, 0xfc, 0xec, 0x16, 0x81, 0xfe, 0xe3, 0xc0, - 0x83, 0x5e, 0x33, 0x7f, 0x07, 0xc5, 0x55, 0xb8, 0x32, 0x02, 0x7f, 0xfa, - 0x3e, 0x3a, 0x2a, 0x0c, 0x79, 0xd5, 0xcb, 0x04, 0x6d, 0x76, 0x93, 0xfb, - 0x4c, 0x18, 0xb9, 0xef, 0xb5, 0xd5, 0x3d, 0x66, 0xfd, 0x06, 0x30, 0xec, - 0x3c, 0x7f, 0xbf, 0x5f, 0x66, 0xc0, 0x3c, 0x1a, 0x0c, 0x3c, 0x34, 0x59, - 0x46, 0x0d, 0xd3, 0x8e, 0x0d, 0x42, 0xd2, 0x69, 0x0c, 0xa6, 0x4b, 0x05, - 0xf1, 0x7b, 0xa3, 0x7a, 0xf9, 0x3c, 0xb6, 0x24, 0x2f, 0x53, 0x44, 0x61, - 0x7c, 0x69, 0xc1, 0x5f, 0x56, 0x69, 0x58, 0x66, 0xee, 0x64, 0xd3, 0xb1, - 0x9e, 0x6b, 0x96, 0x88, 0x2d, 0x6e, 0xf4, 0x90, 0x28, 0xe9, 0xc2, 0x7c, - 0x50, 0x81, 0x40, 0xdf, 0x36, 0xfa, 0x2d, 0xf6, 0xaa, 0x79, 0x5d, 0xe9, - 0x6b, 0x6f, 0xf4, 0x5a, 0xcc, 0x17, 0x5a, 0xd9, 0x50, 0x70, 0x2b, 0x56, - 0x72, 0xf4, 0x41, 0xe7, 0xd3, 0x21, 0x05, 0x5d, 0x31, 0xef, 0x51, 0x1f, - 0x39, 0xc5, 0x16, 0x83, 0x79, 0x02, 0x4d, 0xc9, 0xc2, 0x49, 0xd0, 0xdd, - 0x04, 0x9a, 0x03, 0xd9, 0x97, 0xa8, 0x45, 0x74, 0xbe, 0x7f, 0x81, 0x41, - 0xe3, 0x46, 0x06, 0xf2, 0x09, 0xb3, 0x9f, 0x21, 0xf8, 0x1e, 0x8a, 0xa4, - 0x45, 0x13, 0xb2, 0x2c, 0x14, 0xd5, 0xb9, 0x8b, 0x59, 0x64, 0x2c, 0x46, - 0xd0, 0x97, 0x6e, 0xa1, 0xa2, 0x89, 0x75, 0xe4, 0x9d, 0x6c, 0x56, 0x43, - 0xd1, 0x8c, 0x1a, 0x78, 0xfe, 0x84, 0x37, 0x7d, 0x5c, 0xd6, 0x42, 0x2f, - 0x1a, 0x17, 0x66, 0x55, 0xb4, 0x85, 0xab, 0xbf, 0x43, 0x6f, 0xd5, 0xb1, - 0x89, 0x3d, 0x81, 0x4f, 0xcf, 0x52, 0x17, 0x53, 0x0e, 0x9a, 0xaf, 0x34, - 0xf4, 0x8c, 0x9e, 0x57, 0x04, 0x30, 0x6a, 0x91, 0xcc, 0xf5, 0x5e, 0xdd, - 0x79, 0x1d, 0x2f, 0xc3, 0xa1, 0xce, 0x6e, 0xd2, 0x55, 0xe1, 0x5e, 0x17, - 0x31, 0xf8, 0xe5, 0xb9, 0xa6, 0x0e, 0x8e, 0xd2, 0x66, 0xa2, 0xe6, 0xfc, - 0xbc, 0xea, 0x72, 0x13, 0x0d, 0x71, 0xb3, 0x04, 0x74, 0xac, 0xce, 0xb2, - 0x83, 0x23, 0xdf, 0x18, 0xbc, 0xab, 0xf0, 0x54, 0x5f, 0x36, 0x2b, 0x9a, - 0xeb, 0x0c, 0xf4, 0x14, 0xba, 0x10, 0x3a, 0xee, 0xa8, 0x46, 0x5f, 0x94, - 0xbe, 0x16, 0xa1, 0x2b, 0x42, 0xd0, 0x1f, 0x34, 0xec, 0xc0, 0x1b, 0x6f, - 0x06, 0x9f, 0x74, 0xc0, 0x2b, 0x74, 0x0c, 0x33, 0xca, 0x50, 0x82, 0x58, - 0x54, 0x98, 0x82, 0x80, 0x16, 0x3c, 0x80, 0x66, 0x8a, 0x81, 0x7b, 0x5f, - 0xe0, 0x59, 0xf6, 0xf3, 0xf7, 0x25, 0x92, 0x96, 0x55, 0xa4, 0x11, 0x34, - 0x71, 0xd9, 0x86, 0x28, 0x6a, 0x1c, 0x55, 0xff, 0x00, 0x6f, 0xea, 0x26, - 0x28, 0x78, 0x96, 0x89, 0xfb, 0x8a, 0xbd, 0x3e, 0xe0, 0x9d, 0xc8, 0x45, - 0x6a, 0x3f, 0x33, 0xda, 0xdf, 0x72, 0xbe, 0x3a, 0xe0, 0x84, 0x8d, 0xc2, - 0x50, 0x7d, 0xee, 0x89, 0x01, 0xf0, 0x34, 0x2f, 0xb4, 0xe1, 0x51, 0x7a, - 0x8b, 0xb9, 0xfe, 0xcf, 0xed, 0x90, 0xca, 0x98, 0x18, 0xea, 0xc5, 0xbd, - 0xad, 0x05, 0xf9, 0xe0, 0x62, 0x2f, 0xd8, 0x97, 0x4d, 0xf3, 0x12, 0x2e, - 0xea, 0x13, 0x73, 0xae, 0x11, 0xd9, 0x7f, 0xc7, 0x74, 0xf6, 0xd2, 0x97, - 0x45, 0x88, 0xf0, 0xbe, 0xf4, 0xaa, 0x38, 0x44, 0xd1, 0xa2, 0x30, 0x98, - 0x41, 0x39, 0xf8, 0x56, 0x4d, 0x3e, 0xb8, 0x23, 0xb7, 0xf3, 0x3a, 0x6e, - 0x9c, 0xb2, 0x79, 0x7d, 0xcd, 0x8e, 0x18, 0xba, 0x17, 0x35, 0xa8, 0x97, - 0x7c, 0x34, 0x31, 0x43, 0x67, 0x0a, 0x6a, 0x19, 0xeb, 0x5b, 0xad, 0x68, - 0xf1, 0xf6, 0xd8, 0xe2, 0xcb, 0x4e, 0x93, 0x86, 0xec, 0x84, 0x0e, 0x3a, - 0x43, 0x1d, 0x9b, 0x40, 0xe7, 0x7e, 0xb5, 0x89, 0x3b, 0xe8, 0x99, 0x2e, - 0x97, 0xe0, 0x97, 0x1b, 0xc2, 0x95, 0x0e, 0x1a, 0xe9, 0x05, 0x7e, 0xe5, - 0x7c, 0xec, 0xd8, 0x9d, 0xfc, 0x6a, 0x5f, 0x39, 0x85, 0xc6, 0xb2, 0x84, - 0x0e, 0xdf, 0x51, 0x67, 0xeb, 0xd9, 0x7b, 0xa8, 0x72, 0x56, 0x35, 0xfb, - 0xf7, 0xd0, 0xc5, 0x0d, 0xba, 0xc7, 0xf3, 0xfe, 0x60, 0xda, 0x4c, 0xd0, - 0xe6, 0x42, 0x00, 0xaf, 0xd2, 0x79, 0x4f, 0xaa, 0xeb, 0x5a, 0x61, 0x4a, - 0x22, 0xce, 0xfa, 0x16, 0x30, 0xc1, 0x2e, 0x52, 0x32, 0x00, 0xf6, 0x0f, - 0xc7, 0x24, 0x58, 0x62, 0x37, 0x78, 0x16, 0x0a, 0xfc, 0x6e, 0x47, 0x02, - 0x61, 0x52, 0x4b, 0x36, 0x2b, 0xd0, 0x13, 0x91, 0x06, 0x7e, 0x24, 0x3a, - 0x24, 0xcd, 0x8d, 0x98, 0x3d, 0x3b, 0x76, 0xf6, 0xf7, 0x81, 0x5b, 0x46, - 0xe2, 0x9d, 0x40, 0xe7, 0x96, 0x16, 0xd6, 0x4b, 0x98, 0xdf, 0xca, 0xde, - 0x99, 0xf6, 0x23, 0x31, 0xc9, 0x36, 0x9f, 0xc4, 0x32, 0x77, 0xd8, 0x9e, - 0x68, 0x73, 0x15, 0xb3, 0xcb, 0x08, 0x1a, 0x62, 0x49, 0x29, 0xe8, 0x0c, - 0xa7, 0x7c, 0x1d, 0xdc, 0xcb, 0x33, 0x76, 0x1a, 0xad, 0x34, 0xf1, 0x56, - 0x38, 0xea, 0x9c, 0x19, 0xfd, 0x03, 0xff, 0xba, 0x47, 0x3e, 0x3e, 0xcb, - 0xc9, 0x7d, 0x53, 0x8a, 0xb4, 0xa2, 0xeb, 0xb7, 0xe0, 0x51, 0xfb, 0x44, - 0xb7, 0xef, 0xa1, 0x9a, 0x9f, 0x63, 0xb1, 0xb6, 0xd4, 0x23, 0xe0, 0x16, - 0x75, 0x21, 0xed, 0x2a, 0xa3, 0xdd, 0xd6, 0x64, 0x89, 0x8c, 0xb0, 0x37, - 0x3e, 0x00, 0xa3, 0xef, 0x47, 0x57, 0x7e, 0x43, 0x7b, 0x64, 0x6f, 0xe8, - 0x71, 0xc1, 0xd5, 0x01, 0x7c, 0xe9, 0x82, 0x72, 0x24, 0xe6, 0x3d, 0xe3, - 0x59, 0xa3, 0x3d, 0x0b, 0x43, 0x30, 0xe0, 0x42, 0x2d, 0x46, 0x6a, 0x0b, - 0xd7, 0x39, 0x70, 0x26, 0x44, 0x62, 0x2a, 0x83, 0xbb, 0x99, 0x25, 0x68, - 0x69, 0x52, 0x0d, 0xe2, 0x58, 0xa1, 0x4e, 0xba, 0x03, 0x78, 0x2e, 0xf2, - 0x2c, 0x18, 0xde, 0xfc, 0xfa, 0x1e, 0x2f, 0x23, 0x80, 0xb8, 0x1b, 0xcf, - 0xc0, 0xb3, 0x49, 0x49, 0x41, 0x03, 0x68, 0xfa, 0x80, 0xbd, 0xe8, 0x05, - 0xe3, 0xc3, 0x72, 0x8f, 0x59, 0xa0, 0x49, 0x41, 0xf3, 0x0b, 0xc8, 0xf5, - 0xea, 0x9e, 0xb1, 0x10, 0x62, 0x91, 0x8d, 0x70, 0x7d, 0xdd, 0x7c, 0xbd, - 0x09, 0xad, 0xac, 0x70, 0xae, 0xdd, 0xe5, 0x64, 0xef, 0xc4, 0xbb, 0x2f, - 0x58, 0xb3, 0xaa, 0x81, 0x33, 0x4c, 0x3c, 0x7f, 0x77, 0xb4, 0x76, 0x7a, - 0x65, 0x4d, 0xdf, 0x1e, 0x81, 0x0b, 0xb1, 0x6f, 0x4f, 0xf9, 0x5c, 0xbb, - 0xbd, 0x1d, 0x0e, 0xc2, 0xed, 0x3d, 0xaa, 0x48, 0x9c, 0x18, 0x7a, 0x1d, - 0xd5, 0xb6, 0x13, 0x37, 0xa5, 0x9e, 0x23, 0xf7, 0x9d, 0x20, 0x0a, 0x31, - 0x74, 0x5a, 0x80, 0x6e, 0xad, 0x89, 0x2e, 0x41, 0x6f, 0x68, 0xa6, 0x54, - 0x36, 0xf8, 0x6e, 0x11, 0xe6, 0x8a, 0x5d, 0xc8, 0x34, 0x73, 0xeb, 0x69, - 0x31, 0x3f, 0x63, 0x8c, 0x4c, 0x62, 0x4b, 0x57, 0x03, 0x9e, 0x06, 0x7e, - 0xd6, 0x94, 0x28, 0x5d, 0x69, 0x63, 0x03, 0x64, 0x4e, 0x3b, 0xb6, 0x07, - 0xea, 0xea, 0x42, 0x77, 0xcd, 0xb8, 0x45, 0x2f, 0xde, 0xdc, 0x2d, 0xd1, - 0x5a, 0x7e, 0xa6, 0xad, 0x32, 0xd2, 0x00, 0xa6, 0x22, 0xd2, 0x40, 0xbc, - 0x4f, 0x47, 0xaa, 0x0c, 0x92, 0xc8, 0xef, 0x38, 0x41, 0x37, 0x98, 0x87, - 0x78, 0x07, 0xbe, 0x1f, 0x70, 0xd2, 0xe0, 0x29, 0x7a, 0x60, 0x13, 0xdf, - 0xa9, 0x07, 0xca, 0x07, 0xad, 0x01, 0x1b, 0xc4, 0x56, 0xd0, 0xfb, 0x33, - 0xea, 0xc0, 0x87, 0x6a, 0xf3, 0xdd, 0x81, 0xd9, 0x4f, 0xe8, 0x39, 0xe9, - 0xe8, 0xab, 0xd0, 0xaa, 0x3e, 0x77, 0xb6, 0x9a, 0xf0, 0xe7, 0x1a, 0xe6, - 0xaa, 0x91, 0x90, 0x93, 0x10, 0xa3, 0x79, 0x02, 0x3c, 0x97, 0x78, 0xc1, - 0x53, 0x3a, 0xa8, 0x2e, 0xf4, 0xaa, 0x07, 0x3e, 0x63, 0xa4, 0x0d, 0x0e, - 0x31, 0xc2, 0x6a, 0x3f, 0x21, 0x06, 0xfe, 0x6e, 0xe4, 0xaa, 0x6a, 0x81, - 0xdf, 0x4d, 0xd0, 0x87, 0x55, 0x61, 0xf4, 0x6f, 0xd0, 0xe5, 0xbb, 0x58, - 0x1b, 0x76, 0x73, 0x4d, 0x8c, 0xd8, 0x00, 0x9e, 0x51, 0x01, 0xcd, 0x6a, - 0xe9, 0x40, 0x7e, 0xd7, 0x12, 0xb1, 0x3d, 0x68, 0x88, 0x17, 0xf3, 0x32, - 0xf3, 0x90, 0xa8, 0x96, 0x99, 0xc1, 0x58, 0xa4, 0x91, 0x29, 0xe8, 0xc9, - 0x0c, 0x3b, 0x62, 0x84, 0xe7, 0x55, 0xc4, 0x3a, 0x94, 0x8b, 0xa6, 0x7f, - 0x94, 0xca, 0x7d, 0x73, 0xba, 0x7d, 0x31, 0xdf, 0x7e, 0x81, 0x46, 0xeb, - 0x71, 0x5a, 0x69, 0x05, 0x03, 0x96, 0xe1, 0xd5, 0x18, 0xd6, 0x62, 0xfe, - 0x9e, 0x80, 0x1d, 0x70, 0x82, 0x2d, 0x7c, 0x50, 0x9c, 0x1e, 0x3b, 0xb0, - 0xce, 0x35, 0x0f, 0xbe, 0xf8, 0xce, 0x4c, 0xe0, 0xbc, 0x29, 0x18, 0x13, - 0x1f, 0x59, 0xa4, 0x1d, 0xe6, 0x5d, 0xec, 0x9d, 0x50, 0x7d, 0x56, 0x2a, - 0xb4, 0x04, 0x8c, 0x8e, 0x13, 0x93, 0x4d, 0xbf, 0x6a, 0x24, 0xb4, 0x64, - 0x8a, 0xe3, 0xe1, 0x7a, 0x4c, 0xec, 0x05, 0x78, 0xa0, 0xe5, 0xc1, 0x93, - 0x75, 0x31, 0x7f, 0x4f, 0x4e, 0xda, 0x87, 0x74, 0x52, 0x03, 0x3f, 0x7f, - 0x99, 0xa1, 0x0a, 0x6f, 0x85, 0xf1, 0xd2, 0x42, 0xc7, 0x36, 0x4a, 0x45, - 0x5e, 0x3c, 0x99, 0x6b, 0x4a, 0x80, 0x92, 0x6a, 0x06, 0xd0, 0x17, 0x68, - 0x5e, 0xef, 0x55, 0x85, 0x6e, 0x15, 0xc7, 0x7c, 0x18, 0x0b, 0x08, 0xfb, - 0x83, 0x57, 0xb5, 0x89, 0x0a, 0x7c, 0xd0, 0xfd, 0xf5, 0x21, 0xb5, 0xb7, - 0xe0, 0x61, 0xb7, 0x52, 0xf5, 0x34, 0x66, 0x48, 0xc9, 0xcd, 0xea, 0x71, - 0x40, 0xec, 0x0d, 0xbc, 0xb5, 0xc7, 0x28, 0xb8, 0x17, 0x48, 0x64, 0xe1, - 0x5c, 0x77, 0xbf, 0xad, 0xaa, 0xb8, 0x96, 0xda, 0xde, 0x44, 0x7e, 0xac, - 0x05, 0xf0, 0xfb, 0xfa, 0xcd, 0x6b, 0x49, 0xb3, 0x09, 0xf0, 0x94, 0x46, - 0x26, 0xc4, 0xec, 0x9d, 0xbe, 0x57, 0x4b, 0xe0, 0x85, 0x65, 0x3c, 0x29, - 0x33, 0x67, 0xfd, 0x5d, 0xb0, 0x20, 0x29, 0x5a, 0x8b, 0xc7, 0xee, 0xea, - 0x8c, 0x75, 0x64, 0xcc, 0xdf, 0xe5, 0x22, 0x27, 0xfb, 0x7c, 0xac, 0xab, - 0xbd, 0x6c, 0x89, 0x02, 0xec, 0xdd, 0x02, 0xf7, 0x74, 0x7b, 0x4d, 0xb8, - 0xe0, 0xff, 0x20, 0xbe, 0x51, 0x9b, 0x34, 0x22, 0x09, 0x27, 0x7c, 0x27, - 0xda, 0x69, 0x04, 0x7d, 0xf9, 0x5d, 0x18, 0xc8, 0xdb, 0x69, 0x0b, 0x83, - 0x6d, 0x86, 0x21, 0x7f, 0xaf, 0xec, 0xd8, 0xb0, 0x2e, 0x12, 0xfc, 0x21, - 0x53, 0xc4, 0xcf, 0x0d, 0xfd, 0xbe, 0x33, 0x16, 0x16, 0xe8, 0x93, 0xb0, - 0x68, 0xf4, 0x38, 0x33, 0xdd, 0x91, 0x77, 0xa1, 0x71, 0xe0, 0xbf, 0xbe, - 0xa7, 0x2d, 0x15, 0x14, 0x34, 0xa6, 0x2b, 0x86, 0x83, 0x6f, 0x03, 0xf6, - 0x54, 0x8a, 0xa6, 0xe8, 0x10, 0x72, 0xb5, 0x14, 0x9d, 0x9d, 0x52, 0x08, - 0x0b, 0xd9, 0x04, 0x11, 0x66, 0x4c, 0xdb, 0x6b, 0x14, 0x62, 0x52, 0x8c, - 0x39, 0xc7, 0x07, 0x61, 0x80, 0x2e, 0x80, 0x6b, 0xa6, 0xad, 0x15, 0x66, - 0x89, 0x50, 0x98, 0xb3, 0x81, 0x21, 0x61, 0x31, 0x3d, 0x38, 0xc3, 0x5f, - 0x0f, 0xda, 0x84, 0x3e, 0xcb, 0x27, 0xe4, 0x92, 0x17, 0xa6, 0xf6, 0xb0, - 0x33, 0x32, 0x1d, 0xf4, 0xe4, 0x5c, 0x9e, 0xf0, 0x3b, 0xac, 0xe9, 0xbc, - 0x76, 0x69, 0x3a, 0x24, 0x6b, 0x03, 0x3c, 0x4e, 0x53, 0x52, 0xd7, 0x9a, - 0xd7, 0x65, 0xb0, 0x4e, 0xa6, 0xc2, 0x11, 0x42, 0xf0, 0x0a, 0xf2, 0x7b, - 0x55, 0xc5, 0xbc, 0x31, 0xc2, 0x7a, 0x7d, 0x63, 0x4a, 0x6c, 0x79, 0x8d, - 0x8c, 0x38, 0x11, 0x87, 0xa4, 0x5d, 0x3d, 0x8b, 0x3a, 0xe0, 0x45, 0x57, - 0xbe, 0x29, 0x0f, 0x66, 0x55, 0x36, 0x82, 0xf7, 0x04, 0x4d, 0x13, 0xa0, - 0xa2, 0x0d, 0x9c, 0x3c, 0x41, 0x71, 0x36, 0xe1, 0xf9, 0x1e, 0x60, 0x57, - 0xe8, 0xe8, 0x4d, 0xd5, 0x7a, 0x4a, 0x60, 0xfc, 0x0f, 0x08, 0xb0, 0x3a, - 0xbd, 0xdc, 0xb2, 0x46, 0x7a, 0x51, 0x7b, 0x9f, 0x98, 0x81, 0x76, 0x14, - 0xf4, 0x9c, 0x60, 0xb6, 0x43, 0x5c, 0xc0, 0x5a, 0x56, 0xde, 0xf6, 0x9a, - 0xc4, 0xa2, 0x66, 0x82, 0x7b, 0x73, 0xad, 0x45, 0xd2, 0x14, 0x0a, 0x1d, - 0x84, 0xb7, 0x12, 0x65, 0x0b, 0x3e, 0xc4, 0x53, 0x0e, 0x31, 0xc8, 0x02, - 0x6b, 0xe3, 0x5e, 0x24, 0x36, 0xc4, 0x41, 0x79, 0xcb, 0x55, 0x3f, 0x16, - 0xa6, 0xbc, 0xc3, 0xdc, 0x6e, 0x8e, 0xcd, 0x97, 0x49, 0xb9, 0xcc, 0x77, - 0x3a, 0xe9, 0x0a, 0xc6, 0xc0, 0xb7, 0xc8, 0x41, 0x34, 0xab, 0x0d, 0x9d, - 0x70, 0x94, 0x23, 0x96, 0x67, 0x3a, 0xb9, 0x72, 0x06, 0x9c, 0xed, 0x03, - 0x3e, 0xb3, 0xcb, 0x3b, 0x67, 0xac, 0xca, 0x40, 0x97, 0x0a, 0x03, 0x63, - 0xf0, 0x54, 0xdf, 0x05, 0xb2, 0x6f, 0x10, 0x13, 0x2f, 0x6c, 0x54, 0x7a, - 0xee, 0x23, 0xf0, 0x53, 0xdb, 0x29, 0xd6, 0x21, 0xc7, 0x7c, 0xf2, 0x08, - 0xdb, 0xe8, 0x09, 0x58, 0x7a, 0xa5, 0xcd, 0xeb, 0x56, 0x76, 0x6a, 0x1f, - 0xb6, 0xfd, 0xab, 0xf0, 0xfa, 0x3a, 0xe9, 0x4e, 0xef, 0xa8, 0x05, 0x1f, - 0x66, 0x54, 0x8b, 0x83, 0x8f, 0x5e, 0x19, 0x47, 0x28, 0x74, 0xc3, 0x17, - 0xf0, 0x83, 0x39, 0xdf, 0x9f, 0xc2, 0xad, 0x55, 0x1d, 0x3c, 0x91, 0x08, - 0x06, 0x5a, 0xd3, 0x1d, 0xe6, 0xef, 0xdd, 0x7a, 0x84, 0x8e, 0x4c, 0x13, - 0xbf, 0x6a, 0x72, 0x3d, 0x1c, 0x99, 0xcb, 0x70, 0x01, 0xb3, 0x9b, 0xcc, - 0xdf, 0x41, 0x01, 0xda, 0x4b, 0xa2, 0x66, 0x4a, 0x0c, 0xc8, 0x95, 0x78, - 0xb0, 0xb2, 0x54, 0x5d, 0x0b, 0x9f, 0xbe, 0xb1, 0x36, 0xe0, 0xc2, 0xd0, - 0x2f, 0xbc, 0x43, 0xc3, 0x81, 0xce, 0xdf, 0x3f, 0x1f, 0xbe, 0xb3, 0xf9, - 0xb3, 0x0e, 0x7b, 0x44, 0x4c, 0x35, 0xb9, 0xa6, 0xc2, 0xd2, 0x14, 0x0f, - 0x4e, 0x33, 0xc8, 0x35, 0x7b, 0x33, 0xd7, 0x9c, 0x00, 0xbd, 0x3d, 0xe4, - 0x35, 0xcb, 0x76, 0x9a, 0xf5, 0x4a, 0xc0, 0x6f, 0x97, 0x08, 0xe2, 0x38, - 0x01, 0x64, 0xec, 0x48, 0x8f, 0xcf, 0xf7, 0x11, 0xeb, 0xc1, 0x95, 0x23, - 0xf6, 0xc0, 0x35, 0x04, 0xbe, 0x6e, 0x03, 0xff, 0xb0, 0x91, 0x7b, 0xe3, - 0x77, 0xe2, 0xce, 0xdf, 0x17, 0x16, 0x2c, 0x30, 0x07, 0xbf, 0xed, 0x57, - 0xe6, 0xd1, 0xc1, 0xdf, 0x51, 0xba, 0x86, 0x18, 0x05, 0xdd, 0xa5, 0xec, - 0x36, 0x36, 0x32, 0x23, 0x6b, 0x57, 0xce, 0x5c, 0x53, 0x47, 0xd2, 0xea, - 0x00, 0x1a, 0xbb, 0x05, 0x1c, 0xb7, 0xb2, 0x76, 0x61, 0x24, 0x3c, 0x34, - 0x70, 0xb3, 0x6a, 0xa3, 0x66, 0xa8, 0x65, 0xbd, 0xb5, 0xe0, 0x18, 0x45, - 0xea, 0xf2, 0x15, 0x76, 0xa0, 0x2f, 0xa8, 0x75, 0x8e, 0xcf, 0xc3, 0x22, - 0x69, 0xdd, 0x77, 0xec, 0x47, 0x73, 0x2d, 0x9e, 0x77, 0xe8, 0x33, 0x4c, - 0x3d, 0x35, 0xd7, 0x0f, 0xf7, 0x68, 0xb3, 0x32, 0xa0, 0x1f, 0xbc, 0x04, - 0xff, 0xc8, 0x0c, 0xb5, 0x49, 0xb4, 0xe1, 0x92, 0xd1, 0xe1, 0x1e, 0xfa, - 0x76, 0x40, 0x3a, 0xfb, 0x41, 0x1c, 0xb5, 0x8d, 0x34, 0xdc, 0x95, 0xad, - 0xc5, 0xc0, 0x47, 0x01, 0x66, 0x4a, 0x17, 0x3e, 0xf3, 0x08, 0x1b, 0xe5, - 0x49, 0xa5, 0x6c, 0xf8, 0x0c, 0xc4, 0x9d, 0x7c, 0x44, 0x3c, 0xb8, 0xb1, - 0x24, 0x88, 0xe1, 0xba, 0xc2, 0x90, 0x06, 0x3d, 0x99, 0xf7, 0x69, 0x50, - 0xd6, 0x8a, 0x04, 0x3f, 0xf8, 0xfc, 0xbd, 0xb6, 0xc9, 0x49, 0x23, 0xc6, - 0x70, 0x8f, 0xa8, 0xe5, 0x61, 0xf0, 0xf6, 0xe0, 0xf5, 0xcd, 0x48, 0x2b, - 0x5f, 0x42, 0xb3, 0x40, 0x97, 0xe1, 0x1d, 0xe4, 0x21, 0x65, 0x26, 0xfe, - 0x55, 0x23, 0x45, 0x36, 0xac, 0x8a, 0x35, 0x01, 0x7c, 0x84, 0x54, 0x6c, - 0xac, 0x74, 0xc9, 0xb6, 0x63, 0xe1, 0x87, 0x06, 0xf7, 0x86, 0x24, 0xa2, - 0xea, 0x0a, 0x2a, 0x47, 0xa3, 0xed, 0x4a, 0x50, 0xf0, 0x65, 0x42, 0xad, - 0xcd, 0x90, 0xe3, 0x80, 0x1a, 0x04, 0xb0, 0x2e, 0x78, 0x83, 0xc6, 0x71, - 0x69, 0xcb, 0x5e, 0x99, 0x8e, 0xc2, 0xcc, 0xec, 0xaf, 0xe0, 0x4c, 0xdb, - 0x68, 0xbe, 0x3f, 0x90, 0xf6, 0x6d, 0x68, 0x2a, 0xd0, 0x63, 0x84, 0x44, - 0xc6, 0xca, 0x60, 0xf1, 0x5c, 0xa3, 0xc5, 0x16, 0x18, 0x11, 0x1e, 0x75, - 0x28, 0x38, 0x80, 0x8f, 0x2c, 0x7d, 0x72, 0x06, 0xbc, 0xbe, 0x26, 0xc8, - 0xb6, 0x13, 0x8a, 0x66, 0x7c, 0x3d, 0xd0, 0x34, 0x20, 0x52, 0x8b, 0x4c, - 0xfa, 0x1e, 0xa8, 0x74, 0x83, 0x57, 0xac, 0xa4, 0x1e, 0x3a, 0x24, 0x96, - 0x9e, 0x7e, 0x25, 0x7a, 0x0f, 0x3e, 0xc6, 0xde, 0x13, 0x8a, 0xfa, 0xa8, - 0x75, 0xcd, 0x23, 0x92, 0x3d, 0x68, 0x39, 0xe0, 0x12, 0x01, 0xe3, 0xd8, - 0x2f, 0x85, 0x87, 0xc7, 0xd8, 0xe8, 0xeb, 0xb2, 0x43, 0x63, 0x56, 0x57, - 0xd6, 0xc1, 0x9d, 0xbf, 0x53, 0x6b, 0x65, 0x08, 0x04, 0xb9, 0x69, 0xca, - 0x2e, 0xd7, 0x06, 0x81, 0x1b, 0x75, 0x8e, 0x9a, 0x71, 0xae, 0x39, 0xb5, - 0x65, 0xf4, 0xeb, 0x55, 0x42, 0x4c, 0x41, 0x6b, 0x1a, 0x6f, 0x57, 0x2d, - 0x83, 0x11, 0xcb, 0x5b, 0x0d, 0xb4, 0x69, 0xd0, 0x01, 0xf9, 0xf4, 0x92, - 0xf5, 0x16, 0x68, 0xb1, 0x24, 0x6a, 0x54, 0x57, 0x98, 0x68, 0x97, 0xb4, - 0xa7, 0x27, 0x9d, 0x44, 0xcf, 0xdc, 0x20, 0x4d, 0x9c, 0x79, 0x54, 0xca, - 0xdb, 0x5c, 0xb3, 0x94, 0xb6, 0xc8, 0x99, 0xf7, 0xc4, 0xcd, 0x7e, 0x81, - 0x36, 0x6a, 0x2a, 0x8c, 0xd5, 0x93, 0xb5, 0x2b, 0x40, 0xb3, 0x72, 0xf6, - 0x36, 0xef, 0x9c, 0xab, 0x4d, 0xc6, 0x55, 0x3c, 0xf3, 0x3d, 0xf4, 0x2f, - 0x81, 0x5f, 0xee, 0x25, 0x55, 0x5e, 0x01, 0x5a, 0x26, 0x44, 0x10, 0xc3, - 0xcc, 0x5e, 0x80, 0xde, 0x7e, 0xe6, 0x0c, 0x38, 0x81, 0xb9, 0x26, 0x85, - 0x3e, 0x0b, 0x2a, 0x42, 0xe9, 0xb3, 0x27, 0x68, 0x8e, 0x31, 0xae, 0x99, - 0x96, 0x7b, 0xc1, 0x39, 0xd4, 0xc1, 0xfb, 0x22, 0xc0, 0x44, 0x2a, 0xd2, - 0x5c, 0x5b, 0x8d, 0x91, 0x2e, 0xfe, 0x7f, 0xab, 0x39, 0x02, 0x52, 0x08, - 0xb8, 0x7e, 0x0f, 0x5e, 0x3d, 0xa4, 0x7c, 0xb5, 0x2b, 0x7c, 0xc0, 0xa9, - 0x06, 0x78, 0x8c, 0xaf, 0x5e, 0x0c, 0x7e, 0x46, 0x86, 0x1c, 0x98, 0xb1, - 0xba, 0x13, 0xde, 0xbc, 0x63, 0x43, 0xdd, 0x19, 0x6f, 0x5e, 0xb1, 0x36, - 0xd7, 0xc0, 0x53, 0x14, 0xbb, 0x44, 0x15, 0xf3, 0xf7, 0x2a, 0xea, 0x36, - 0x78, 0x6b, 0xf9, 0x0e, 0xeb, 0xed, 0xbc, 0x47, 0xbe, 0x3e, 0xfa, 0x15, - 0xc7, 0xca, 0x06, 0x1f, 0xfd, 0x7f, 0x79, 0x6f, 0x77, 0x17, 0xd5, 0x8d, - 0xf9, 0x8f, 0xf5, 0x22, 0x12, 0x3d, 0x7a, 0x86, 0xad, 0xec, 0xff, 0xbc, - 0x7a, 0x11, 0x4a, 0xfd, 0x47, 0xbd, 0x08, 0x64, 0x53, 0x4f, 0x7b, 0xfe, - 0x69, 0xf5, 0x22, 0xe6, 0xbf, 0x0d, 0xda, 0x82, 0xc6, 0x0a, 0xfe, 0x68, - 0x9f, 0x50, 0x47, 0x40, 0x3c, 0x22, 0xe7, 0x4f, 0x6a, 0x7f, 0x2f, 0xd3, - 0x7e, 0xf3, 0x0f, 0x7b, 0xab, 0x6f, 0xd4, 0x51, 0x6f, 0xe0, 0xc1, 0x3f, - 0x6b, 0xfc, 0x9d, 0xa2, 0x23, 0x7f, 0xaf, 0xd5, 0x12, 0x81, 0x7e, 0xa5, - 0x9b, 0x55, 0x15, 0x69, 0xc3, 0x9f, 0x55, 0x2f, 0x04, 0x3c, 0x3c, 0xa9, - 0xa3, 0xbf, 0xc7, 0xad, 0x7b, 0xcb, 0xea, 0xd3, 0x5b, 0xfc, 0x69, 0xb5, - 0x6a, 0xd0, 0x14, 0x71, 0xbc, 0x8d, 0xb8, 0xfc, 0xbd, 0xfd, 0xc6, 0x7d, - 0x96, 0xf1, 0x70, 0x28, 0xfe, 0xa4, 0xfe, 0x17, 0xa6, 0x6b, 0x26, 0x54, - 0xfe, 0x47, 0x5d, 0x03, 0xdd, 0x7d, 0x86, 0x1d, 0xbe, 0x96, 0xf4, 0x4f, - 0x1a, 0x7f, 0x77, 0x50, 0xe1, 0xbc, 0xaf, 0xfd, 0xf7, 0xfe, 0x3b, 0xc4, - 0xfb, 0x7a, 0xee, 0xcc, 0x68, 0x7e, 0x66, 0xf1, 0xfc, 0xbf, 0xb3, 0x7e, - 0x04, 0x77, 0x11, 0x2d, 0x5d, 0xf1, 0x8d, 0x93, 0x40, 0xe5, 0x06, 0xca, - 0xe8, 0xdf, 0xc7, 0xbb, 0x8f, 0x59, 0xc2, 0x50, 0xd9, 0x0e, 0x3b, 0x01, - 0xce, 0xfc, 0x3b, 0xd1, 0xce, 0xfb, 0xf5, 0xe5, 0x8f, 0x1a, 0x23, 0xeb, - 0xb3, 0xf4, 0xe7, 0xfb, 0x6a, 0xbf, 0xea, 0x85, 0xf4, 0x05, 0x47, 0x9d, - 0x88, 0x57, 0xaf, 0xa2, 0x2d, 0xff, 0xd3, 0x31, 0xe5, 0x5c, 0xa3, 0x2b, - 0x0d, 0x7f, 0xd5, 0x34, 0xf9, 0x55, 0xa7, 0xc4, 0x07, 0xbd, 0x0c, 0xde, - 0xe8, 0x3f, 0xd7, 0x34, 0xb1, 0xf5, 0xb2, 0xb3, 0x9f, 0xa5, 0xf1, 0x7b, - 0xed, 0x93, 0x8c, 0x5b, 0xd6, 0xdf, 0xeb, 0x94, 0x44, 0xf0, 0x13, 0x69, - 0x3b, 0xf8, 0xf9, 0xef, 0x7f, 0xf9, 0xed, 0xe3, 0xbf, 0xff, 0xd3, 0x6f, - 0xf0, 0xdf, 0xbf, 0xdd, 0x87, 0xb7, 0x3a, 0xfe, 0xfe, 0xfb, 0x6f, 0xbf, - 0x7d, 0xfc, 0xb7, 0xff, 0xf6, 0xdb, 0x33, 0xbf, 0x9d, 0xf3, 0x42, 0x1d, - 0xef, 0xbf, 0xfd, 0xb7, 0x8f, 0x7f, 0xfa, 0x97, 0xdb, 0xe5, 0x32, 0xfc, - 0xf6, 0xbf, 0xc3, 0xdb, 0x7f, 0xfd, 0x6b, 0x79, 0x51, 0x97, 0xdb, 0x5f, - 0x0b, 0x95, 0x97, 0xcd, 0xbf, 0xfc, 0xf6, 0xeb, 0xc7, 0xbf, 0xfe, 0xc3, - 0xeb, 0xe5, 0x45, 0xfe, 0xf5, 0x74, 0xcb, 0xdf, 0x7f, 0x55, 0xe7, 0x53, - 0x35, 0xfc, 0xcb, 0x6f, 0xff, 0x9b, 0xfe, 0x35, 0xff, 0xf9, 0xaf, 0x0e, - 0x99, 0xdf, 0xd4, 0xe6, 0x3f, 0xff, 0xf8, 0x66, 0x7b, 0xee, 0x8e, 0x7f, - 0xbd, 0x57, 0xf9, 0xcf, 0xe1, 0xef, 0x67, 0x30, 0xb5, 0xf9, 0xcf, 0x7f, - 0x7d, 0x10, 0xbc, 0x6d, 0x68, 0xf3, 0x9f, 0x7f, 0x7c, 0xbb, 0xbf, 0x9d, - 0xdb, 0xfc, 0xf6, 0xfe, 0xeb, 0xed, 0x54, 0xe4, 0xff, 0xf2, 0x9b, 0xf6, - 0xcf, 0xbf, 0xe9, 0x2b, 0xe3, 0x9f, 0x7f, 0x33, 0x2c, 0xfd, 0xbf, 0x38, - 0x08, 0x4e, 0xa0, 0x69, 0xa5, 0xf6, 0xb3, 0xf8, 0xc7, 0xf7, 0xee, 0xe5, - 0xe5, 0xd6, 0x9f, 0x2f, 0x1d, 0xbc, 0xf9, 0xa5, 0xcd, 0x7f, 0xfe, 0xd3, - 0x9b, 0xc7, 0xf2, 0xd2, 0xc9, 0xff, 0x38, 0xbf, 0x61, 0x2e, 0xa0, 0x85, - 0x2f, 0x68, 0xc1, 0x5a, 0xfe, 0x97, 0xc7, 0xc1, 0x59, 0x8e, 0x79, 0xb1, - 0x34, 0xff, 0xd3, 0x20, 0xdc, 0xcf, 0xea, 0x79, 0x84, 0xb1, 0xa8, 0x72, - 0x75, 0x2e, 0x8f, 0x70, 0x48, 0x9e, 0xe7, 0xff, 0xf8, 0xfe, 0x2b, 0xbf, - 0x75, 0xe7, 0xee, 0xf4, 0x2f, 0xbf, 0xdd, 0x8e, 0xf2, 0x3f, 0xbd, 0x5e, - 0x9d, 0x07, 0x38, 0xfc, 0xd7, 0x8f, 0xdf, 0x5f, 0x7f, 0x9e, 0x8f, 0xaf, - 0xfe, 0x72, 0x1b, 0xfe, 0x5a, 0x1d, 0x7f, 0x1f, 0x30, 0x5d, 0xd3, 0xfe, - 0x9f, 0xff, 0xfa, 0x4f, 0xff, 0x34, 0x4f, 0xa3, 0x67, 0x6f, 0xfe, 0x17, - 0x73, 0xf6, 0x7f, 0x6a, 0xd6, 0xfe, 0x0f, 0xe6, 0xed, 0x7f, 0x39, 0x73, - 0xda, 0x4f, 0xf3, 0x4b, 0xfb, 0xf9, 0x3f, 0x3b, 0xec, 0xd7, 0xd4, 0x2e, - 0x0d, 0xf3, 0x7f, 0x38, 0xcf, 0x7f, 0x9e, 0x3d, 0xdd, 0xb2, 0xfe, 0x59, - 0xff, 0xfa, 0xfa, 0x67, 0xdd, 0xfa, 0x2f, 0x8f, 0x82, 0x73, 0xac, 0x8a, - 0xa2, 0xfc, 0x1f, 0x1b, 0xf9, 0x2f, 0x27, 0xf0, 0x7f, 0x3e, 0x85, 0xff, - 0xb3, 0x46, 0xfe, 0x71, 0x0a, 0xff, 0xcb, 0x66, 0xfe, 0x87, 0x49, 0xfc, - 0x2f, 0x46, 0xf6, 0xef, 0xf3, 0xf8, 0x5f, 0xbd, 0xf7, 0x3f, 0xcc, 0x25, - 0x24, 0xda, 0xff, 0xe7, 0x9f, 0xfe, 0xe9, 0xe3, 0xbf, 0xfd, 0xa6, 0xf2, - 0xe1, 0xdc, 0xcd, 0xff, 0xfc, 0x7f, 0xff, 0xbc, 0x74, 0xc3, 0x5f, 0x7f, - 0xe6, 0xe5, 0xf1, 0x57, 0xf2, 0xfd, 0xf1, 0xaf, 0xf6, 0xac, 0xe0, 0x8a, - 0xfe, 0x72, 0xb8, 0xcf, 0xb5, 0x23, 0xfe, 0xf2, 0xaf, 0x7f, 0x7b, 0xe3, - 0x57, 0x0a, 0xff, 0xcb, 0x6f, 0xdd, 0xe5, 0xd6, 0xe6, 0xea, 0xef, 0xaf, - 0xbe, 0xfe, 0x88, 0x0a, 0x53, 0xd3, 0xfe, 0xfe, 0x9a, 0x3c, 0xdf, 0x7b, - 0x35, 0x4f, 0x24, 0x9c, 0xa1, 0x9f, 0x5f, 0xbd, 0xdf, 0xca, 0x7f, 0xf9, - 0xed, 0x71, 0x53, 0xff, 0x2f, 0x99, 0x0f, 0xf9, 0xbf, 0xcc, 0xc7, 0x7c, - 0xbc, 0x2e, 0x3f, 0x7f, 0x1a, 0xff, 0x5a, 0xe4, 0xf7, 0xe3, 0x72, 0xf1, - 0xcf, 0x52, 0x5b, 0x79, 0xe1, 0x69, 0x6d, 0xaf, 0xe7, 0xff, 0xdc, 0x98, - 0xae, 0xed, 0xf0, 0xd7, 0xaf, 0xe7, 0x7d, 0x04, 0xff, 0x8e, 0x3a, 0xf8, - 0xdf, 0xfa, 0x7f, 0xf5, 0x9f, 0x77, 0x71, 0xef, 0x9e, 0xb5, 0x7a, 0xf9, - 0x5b, 0xac, 0x7d, 0x6b, 0x15, 0x8f, 0xd8, 0x0e, 0xd9, 0x6b, 0x71, 0xfa, - 0xd6, 0x31, 0x8d, 0x18, 0xf1, 0x82, 0xf1, 0xb2, 0xae, 0xbc, 0xc5, 0xf3, - 0xdb, 0x76, 0xb7, 0x9b, 0xe7, 0x7a, 0x61, 0xb8, 0x5f, 0xfb, 0x93, 0x7e, - 0x59, 0x87, 0xf8, 0x45, 0xd7, 0x49, 0xb6, 0x09, 0xd6, 0x07, 0x3f, 0x5c, - 0x47, 0x27, 0x3b, 0x23, 0x0b, 0xfb, 0xbd, 0x2e, 0xae, 0x5d, 0xa3, 0x17, - 0x7e, 0x79, 0x7c, 0xd8, 0x46, 0xf6, 0xb4, 0xf7, 0x1f, 0x48, 0xa3, 0xa4, - 0xb0, 0xdf, 0xd1, 0x71, 0x9d, 0x27, 0xbb, 0xf0, 0x72, 0xb9, 0x26, 0xdf, - 0xd6, 0x87, 0xb6, 0x0a, 0x92, 0x36, 0xba, 0x9c, 0x13, 0xb0, 0x31, 0x68, - 0x60, 0xc3, 0xab, 0x8c, 0x37, 0xf7, 0xcf, 0x5b, 0xf9, 0x65, 0xe2, 0xe9, - 0xfb, 0xd8, 0xe2, 0xed, 0x42, 0x38, 0x91, 0xba, 0x4f, 0xeb, 0xcb, 0x3e, - 0xe5, 0xe9, 0x76, 0x7b, 0xbe, 0x44, 0x96, 0x56, 0xdd, 0x22, 0x6f, 0x1d, - 0x1d, 0xa4, 0xf3, 0xea, 0xba, 0x6d, 0x30, 0xa6, 0xeb, 0x0c, 0xb9, 0x2e, - 0xca, 0x75, 0xe3, 0x42, 0x71, 0xf5, 0x94, 0x07, 0xbf, 0x5f, 0x17, 0x1f, - 0x71, 0xe2, 0xbd, 0x4a, 0x30, 0x9e, 0xf5, 0x0f, 0xb1, 0x5f, 0xd8, 0x47, - 0xd1, 0x86, 0x76, 0xf8, 0xfe, 0x41, 0x99, 0xb2, 0x9d, 0x1f, 0x53, 0x88, - 0x17, 0x3b, 0x73, 0xe5, 0x89, 0xca, 0x19, 0xc6, 0x8b, 0xbd, 0x57, 0x66, - 0xf8, 0xd9, 0xbd, 0xcb, 0xbc, 0x9d, 0x6e, 0xb5, 0xfd, 0x73, 0x91, 0x4e, - 0xe4, 0xe2, 0x9e, 0xe6, 0xaf, 0xe8, 0x0d, 0xdf, 0xfa, 0xe3, 0xbb, 0x74, - 0xc2, 0x30, 0x48, 0x46, 0x55, 0x7e, 0x2d, 0x2c, 0xe2, 0xeb, 0xda, 0xed, - 0xd3, 0x70, 0x9e, 0xab, 0xd4, 0x47, 0x27, 0xe3, 0x47, 0x6d, 0x8d, 0xab, - 0xeb, 0x8a, 0xff, 0xf4, 0xf2, 0xc5, 0x67, 0x5d, 0xc7, 0xa1, 0xb9, 0x29, - 0x6b, 0xeb, 0xf6, 0xf9, 0xf5, 0x31, 0x95, 0x1f, 0xc3, 0x2b, 0xbd, 0x2e, - 0x73, 0xf3, 0x9e, 0xa0, 0xf7, 0x56, 0x3b, 0x62, 0x97, 0x6b, 0xb6, 0x71, - 0xaf, 0x7c, 0xe5, 0x2e, 0x6b, 0x1b, 0xf4, 0xba, 0x55, 0xca, 0x8b, 0xb6, - 0xce, 0xef, 0xbb, 0xb6, 0x1a, 0x96, 0x7b, 0xad, 0x6a, 0x6f, 0x87, 0x76, - 0x75, 0x6a, 0xe2, 0x75, 0x74, 0xa9, 0xb2, 0x7b, 0x64, 0xe6, 0x97, 0x64, - 0x4b, 0x2e, 0x34, 0x13, 0x67, 0x26, 0xbc, 0x3b, 0xd9, 0xaf, 0xb2, 0x27, - 0xfd, 0x14, 0x60, 0xeb, 0xe3, 0xdb, 0x6e, 0x25, 0xa3, 0x45, 0x79, 0xc4, - 0xa1, 0xfd, 0x4c, 0x97, 0x9f, 0xd3, 0xe6, 0x3b, 0xf9, 0x58, 0x7c, 0x5d, - 0xc9, 0x26, 0x59, 0x5d, 0xce, 0xeb, 0xd8, 0x3e, 0xd5, 0xad, 0xa6, 0xed, - 0x3e, 0x91, 0xa3, 0x33, 0x64, 0xe0, 0x0c, 0xed, 0xbf, 0x36, 0xbb, 0xd7, - 0xfd, 0xf0, 0x12, 0xd5, 0x99, 0xbf, 0x92, 0x35, 0x3a, 0x2e, 0x25, 0xfe, - 0xf9, 0xf3, 0xb3, 0xd4, 0xd3, 0x35, 0x7a, 0x2d, 0x4f, 0xdf, 0x76, 0x47, - 0xc3, 0x40, 0x5d, 0xbb, 0x58, 0xb0, 0x4d, 0x76, 0xfa, 0x26, 0x4d, 0x26, - 0xa8, 0x79, 0xbd, 0x79, 0x51, 0xd8, 0x7a, 0x3c, 0xda, 0x67, 0x21, 0x5d, - 0x7f, 0xb1, 0xc3, 0x8f, 0xad, 0x77, 0xda, 0x7d, 0x7e, 0x14, 0xbe, 0xfb, - 0xf9, 0x91, 0xfc, 0x5c, 0xa1, 0xf3, 0x0f, 0x8d, 0x64, 0xcf, 0x9d, 0xf3, - 0xad, 0x97, 0x2b, 0xb7, 0x23, 0x6e, 0x23, 0x3a, 0xf1, 0xfd, 0x53, 0xbe, - 0xaf, 0x1f, 0xd7, 0x66, 0x77, 0x9a, 0x0e, 0xfc, 0xc6, 0xcf, 0x3c, 0x29, - 0x35, 0x2b, 0x18, 0x16, 0xb5, 0xbd, 0x6a, 0xa8, 0x57, 0xb6, 0xef, 0x6c, - 0x21, 0xbf, 0xef, 0xdb, 0x4d, 0x61, 0x9a, 0xf9, 0x91, 0x68, 0x96, 0xb2, - 0x56, 0x3f, 0xbc, 0xd4, 0xca, 0x37, 0x8b, 0x8d, 0x15, 0x5d, 0x6c, 0xf0, - 0xaf, 0xc3, 0x7d, 0x99, 0x2c, 0x8b, 0x15, 0xf8, 0x5d, 0x36, 0x95, 0xdf, - 0xf1, 0x19, 0x67, 0xfa, 0xf7, 0xf0, 0xd3, 0x5f, 0xac, 0x71, 0xbc, 0x6f, - 0x1d, 0xd3, 0xfb, 0xe8, 0x76, 0xee, 0xa9, 0x3c, 0x5c, 0x5a, 0x3b, 0x76, - 0x16, 0x27, 0xf4, 0x18, 0x83, 0xd3, 0xb8, 0xfe, 0x1e, 0x3f, 0xde, 0xe6, - 0x7a, 0x7b, 0x7d, 0x67, 0x7c, 0xa7, 0x12, 0xb3, 0x3e, 0x3f, 0x46, 0xba, - 0x4d, 0xd6, 0x87, 0xfa, 0xe7, 0x23, 0x22, 0xd6, 0xc1, 0xb2, 0x7f, 0x1c, - 0x4d, 0x63, 0xfb, 0x6d, 0x17, 0x23, 0x98, 0xe4, 0xdd, 0x17, 0xfa, 0xdc, - 0x3e, 0x36, 0xb7, 0xe7, 0xa8, 0xad, 0x03, 0xbb, 0xb7, 0x92, 0x63, 0x18, - 0xa0, 0x36, 0x7d, 0x1b, 0x83, 0xf1, 0x69, 0x8e, 0x6b, 0xe2, 0x7c, 0xee, - 0x84, 0x73, 0xcf, 0x87, 0xf8, 0xe3, 0xaa, 0x6e, 0x3f, 0xa7, 0x87, 0x46, - 0x6d, 0xf6, 0xd4, 0xef, 0x89, 0xbd, 0x6d, 0xa6, 0x83, 0xb9, 0xb5, 0xe2, - 0x75, 0x83, 0xca, 0xe5, 0xb7, 0x5e, 0x9f, 0xba, 0xfa, 0xa4, 0x35, 0x4d, - 0x65, 0xed, 0xec, 0x65, 0xfa, 0xad, 0x9c, 0x75, 0x73, 0x59, 0xaf, 0x37, - 0x3c, 0x7d, 0xbe, 0x7f, 0xdc, 0xf2, 0xcd, 0x21, 0x4f, 0x57, 0xcf, 0xeb, - 0xd0, 0xfe, 0x20, 0xe3, 0x9a, 0x1f, 0x6d, 0x57, 0xdb, 0xbf, 0x5f, 0x92, - 0x7d, 0x28, 0x27, 0x1c, 0xa7, 0x67, 0x75, 0x6c, 0xf5, 0xc1, 0xc7, 0xe8, - 0x6d, 0xa2, 0x25, 0x7b, 0x23, 0xdd, 0x37, 0x57, 0xe6, 0x50, 0xdc, 0xd7, - 0xdb, 0x08, 0xed, 0xb5, 0x5b, 0xe9, 0xa2, 0xc8, 0xde, 0xfa, 0x27, 0x4c, - 0x79, 0x63, 0xf7, 0x6d, 0x29, 0xca, 0xe8, 0xd2, 0x7c, 0xa5, 0x97, 0xb3, - 0x08, 0x96, 0xc7, 0xcf, 0xe7, 0x6e, 0x73, 0x79, 0x2c, 0xe9, 0x23, 0x92, - 0x11, 0x7a, 0x9f, 0x5b, 0x77, 0xb3, 0x54, 0xef, 0xc9, 0x35, 0xbb, 0x49, - 0x1d, 0x97, 0xcb, 0x61, 0xa2, 0x37, 0xf5, 0xf6, 0xb9, 0x1f, 0xab, 0xf1, - 0xc3, 0xd1, 0x3e, 0x53, 0xbd, 0xfb, 0xf8, 0xd2, 0x1a, 0xe4, 0x28, 0x8d, - 0xaf, 0xee, 0xc9, 0x67, 0x65, 0xb8, 0xdb, 0xaf, 0xe0, 0x3c, 0x7d, 0x7f, - 0xfe, 0xb4, 0x34, 0x33, 0xd6, 0x8b, 0x40, 0x1b, 0xac, 0x24, 0xaf, 0xd6, - 0xfb, 0x2a, 0x8c, 0x03, 0xa4, 0xdd, 0x6e, 0xee, 0x6e, 0x33, 0x6d, 0x2e, - 0xb7, 0xc7, 0x18, 0x6d, 0xb4, 0x31, 0x1f, 0x6f, 0xd6, 0xe3, 0xe7, 0x73, - 0xdc, 0x35, 0x51, 0x15, 0x2a, 0x7f, 0xc0, 0xd7, 0xab, 0xb5, 0x2e, 0x56, - 0xdd, 0x8d, 0x6d, 0xf3, 0x1d, 0x4d, 0xc3, 0x5e, 0x20, 0xc7, 0xf2, 0x37, - 0xdf, 0x17, 0xf9, 0x7c, 0x72, 0x93, 0x4c, 0x21, 0x1d, 0xb9, 0x2d, 0x02, - 0xe3, 0xc7, 0x87, 0x96, 0xb5, 0x6f, 0x5d, 0xfb, 0x62, 0x7c, 0xb1, 0xdd, - 0xa5, 0x7e, 0xf4, 0xf3, 0xc7, 0xf5, 0x74, 0xb0, 0xdd, 0x2f, 0xe3, 0x67, - 0x1a, 0x6f, 0xd7, 0xd4, 0x59, 0x3f, 0x37, 0xa7, 0x9f, 0xeb, 0xc5, 0x3e, - 0x0f, 0xc6, 0xed, 0xfa, 0xdb, 0xdf, 0x7a, 0xdf, 0x49, 0xb3, 0x7d, 0xdd, - 0x03, 0xaf, 0x8c, 0xc3, 0xae, 0x79, 0x8b, 0x47, 0x4f, 0xa7, 0xef, 0x8f, - 0x8f, 0xed, 0xeb, 0xe4, 0x9d, 0xd6, 0xa1, 0xbe, 0x71, 0x23, 0x74, 0x40, - 0xd7, 0x73, 0x56, 0x75, 0xcb, 0xf5, 0x76, 0x33, 0x79, 0xf7, 0xb5, 0xa7, - 0x6d, 0x7e, 0x7e, 0x2d, 0xaa, 0x7e, 0x6c, 0x2b, 0xa6, 0xcc, 0xb4, 0x58, - 0x85, 0xee, 0xe7, 0x74, 0xbf, 0x2f, 0xf7, 0x4d, 0xbd, 0xae, 0x58, 0x4e, - 0x49, 0xcc, 0xf5, 0x7a, 0xe9, 0x38, 0xfe, 0x7a, 0xbd, 0x5f, 0x67, 0xcd, - 0x7d, 0x6f, 0x7c, 0xba, 0xb7, 0x63, 0x9d, 0xbc, 0x6e, 0xb7, 0xf6, 0x75, - 0x5b, 0xdb, 0x8b, 0xcd, 0xda, 0x89, 0xde, 0xe1, 0xfb, 0xb6, 0x7f, 0xeb, - 0x95, 0x7f, 0x0a, 0x4f, 0x43, 0x54, 0x67, 0x64, 0x3d, 0xde, 0x9a, 0x24, - 0x5e, 0xbe, 0xcd, 0x55, 0x95, 0x78, 0x91, 0xf9, 0x78, 0xa4, 0xe2, 0x71, - 0x66, 0xce, 0x6b, 0xff, 0xd4, 0x17, 0xf1, 0xe1, 0x67, 0x93, 0xb9, 0x65, - 0xb9, 0xd8, 0xfd, 0xf0, 0xb7, 0xc2, 0xbc, 0xb9, 0xd6, 0xb0, 0xcf, 0x47, - 0x5d, 0x4a, 0xe9, 0xde, 0x16, 0xad, 0x51, 0xa4, 0x6c, 0xd5, 0x23, 0xcf, - 0x63, 0xba, 0x8b, 0x75, 0x99, 0x9f, 0x57, 0x6d, 0xf0, 0x23, 0x23, 0x8f, - 0xef, 0xe7, 0x39, 0x5c, 0x1a, 0x98, 0xad, 0x8e, 0xe3, 0x47, 0x6f, 0xd4, - 0x9f, 0x85, 0xfe, 0x31, 0x3c, 0x9e, 0x3f, 0x7e, 0x3c, 0x4d, 0xb9, 0xfd, - 0x28, 0x48, 0x94, 0x85, 0x59, 0x74, 0x00, 0x31, 0xb8, 0x5f, 0xd5, 0x25, - 0x69, 0x7e, 0x6c, 0xa2, 0xe6, 0x81, 0x49, 0x79, 0x76, 0x9a, 0x31, 0x38, - 0x16, 0x9a, 0x69, 0xab, 0x57, 0xf6, 0x38, 0xd4, 0x68, 0xe1, 0x7a, 0xaf, - 0x6f, 0x54, 0x06, 0xee, 0xa9, 0x13, 0x32, 0x44, 0x90, 0x93, 0x3b, 0x82, - 0xee, 0xf7, 0x4b, 0x2e, 0xfa, 0xa3, 0x1b, 0x8e, 0xd1, 0x89, 0xa1, 0x4b, - 0x45, 0x2f, 0xba, 0x7b, 0x78, 0xea, 0x8d, 0xd6, 0xb4, 0x99, 0x76, 0xb3, - 0x9a, 0xde, 0x7b, 0x14, 0x51, 0x6d, 0x6b, 0xd6, 0xf6, 0xa5, 0x7d, 0x3e, - 0x72, 0x6d, 0xda, 0x4e, 0xd6, 0xe9, 0x8b, 0x3e, 0x36, 0x6b, 0x97, 0x84, - 0x5b, 0xaf, 0x3b, 0x5e, 0xc7, 0x89, 0xbf, 0x1f, 0x7e, 0x85, 0x77, 0xa1, - 0xbb, 0x23, 0xa5, 0x7d, 0x09, 0xda, 0xbd, 0xe7, 0x79, 0x92, 0x26, 0xa3, - 0x1e, 0xde, 0xbe, 0x73, 0xff, 0xda, 0x37, 0x95, 0xcb, 0x8e, 0x8f, 0x67, - 0x34, 0x8c, 0xeb, 0xfb, 0x5a, 0xd4, 0x49, 0xad, 0x7f, 0x3a, 0xe3, 0x99, - 0x0e, 0x1e, 0x6d, 0xbe, 0x7f, 0x66, 0xe8, 0xe4, 0x57, 0x8b, 0x8d, 0x6b, - 0x77, 0x9a, 0x95, 0x7f, 0x5e, 0x5f, 0x4d, 0x0c, 0x79, 0x78, 0x5e, 0x9b, - 0x16, 0x3f, 0x19, 0x97, 0x70, 0xcb, 0x0f, 0x3f, 0xc6, 0xf1, 0x65, 0x23, - 0xac, 0x45, 0x7c, 0xfd, 0xf3, 0x44, 0x3e, 0xd6, 0xa7, 0x53, 0x73, 0x06, - 0xc1, 0xb3, 0x41, 0xda, 0xf1, 0xbb, 0x89, 0xdc, 0x26, 0x1a, 0x1b, 0x77, - 0x1b, 0x8a, 0x48, 0xc5, 0x07, 0x2f, 0xce, 0xec, 0x71, 0xb8, 0xbb, 0xf1, - 0x26, 0x0e, 0x04, 0x0a, 0xb6, 0x41, 0x8c, 0xbb, 0x84, 0xdb, 0xf1, 0xcf, - 0xb4, 0x53, 0x29, 0xea, 0xc5, 0x22, 0x03, 0xca, 0x19, 0x6e, 0xcb, 0x74, - 0xf3, 0x5a, 0x17, 0x9b, 0xe8, 0x72, 0xa7, 0x1e, 0xda, 0xa7, 0x45, 0xb6, - 0x58, 0xac, 0x6b, 0x4f, 0xbd, 0xf2, 0x32, 0xab, 0xb6, 0xeb, 0xc5, 0x67, - 0x6c, 0x52, 0x5c, 0x6b, 0x9f, 0x9b, 0xf8, 0x9a, 0x1c, 0xa6, 0x66, 0x83, - 0xbd, 0xf3, 0xf1, 0x1a, 0xde, 0xf3, 0xe8, 0x7e, 0xc3, 0x6b, 0x6f, 0x5f, - 0x7f, 0xb9, 0x8b, 0x75, 0x65, 0x56, 0xde, 0x3b, 0xae, 0xaf, 0xd1, 0xe6, - 0xbd, 0xad, 0xa3, 0xf7, 0x1d, 0x38, 0x73, 0x43, 0x17, 0x61, 0x15, 0x27, - 0xfa, 0xf7, 0x5a, 0x8c, 0xb7, 0x73, 0x97, 0x6b, 0x67, 0xeb, 0xbc, 0xb9, - 0xfa, 0xeb, 0x45, 0x7d, 0x21, 0xce, 0x2e, 0x8a, 0xa2, 0xb1, 0xdd, 0x20, - 0xb7, 0x09, 0x83, 0x45, 0x00, 0xff, 0xb9, 0xe5, 0xd9, 0x50, 0xf1, 0x87, - 0x75, 0x39, 0x3d, 0x7c, 0xf5, 0xde, 0xbf, 0x45, 0x14, 0x5f, 0x1e, 0x7a, - 0xaf, 0xe1, 0xcc, 0xb6, 0x2e, 0x5e, 0x63, 0x9d, 0x5e, 0x2f, 0xf1, 0xa5, - 0xbf, 0xf6, 0xa7, 0xc3, 0xd4, 0x4e, 0xa1, 0xf7, 0x23, 0x3c, 0x9b, 0x61, - 0x98, 0x7b, 0x9f, 0x1b, 0xa7, 0x5b, 0x6f, 0x63, 0xaf, 0x8e, 0x82, 0xe8, - 0x22, 0xca, 0x57, 0x50, 0xf8, 0xf7, 0xfd, 0xea, 0x5a, 0xe3, 0x9f, 0xbc, - 0x47, 0xeb, 0xf7, 0x9d, 0x7c, 0x59, 0x87, 0xb1, 0x0b, 0x77, 0xb9, 0xbc, - 0x04, 0xd5, 0xc7, 0xf2, 0x3b, 0x14, 0xd7, 0xdd, 0xe7, 0x6e, 0x17, 0xac, - 0xb6, 0xab, 0x9c, 0xe9, 0x0f, 0xf7, 0x33, 0xa2, 0x27, 0x74, 0xa8, 0x6d, - 0xe3, 0xfb, 0x87, 0x52, 0xe1, 0x3d, 0xa9, 0xcf, 0x3d, 0x79, 0xfc, 0x0c, - 0x3e, 0x53, 0x07, 0xe6, 0xb9, 0xd7, 0xf1, 0x57, 0x98, 0x5e, 0x9c, 0x3b, - 0xfe, 0x74, 0xe8, 0xca, 0x0f, 0x8d, 0xf3, 0xb2, 0xf7, 0x89, 0xbb, 0x30, - 0xbf, 0xd7, 0xe6, 0x5e, 0xe8, 0xc3, 0xb1, 0xcd, 0x5b, 0xdd, 0x14, 0xfe, - 0x8d, 0xe9, 0xe1, 0xca, 0x4a, 0x9d, 0xe6, 0x73, 0xd3, 0xb3, 0x7e, 0xe8, - 0x7f, 0xe0, 0xe1, 0x47, 0x88, 0x45, 0x1a, 0xe4, 0x72, 0x49, 0x22, 0xb1, - 0x9a, 0x96, 0xdd, 0x91, 0x3f, 0xaf, 0xf2, 0x10, 0xad, 0xbe, 0xcf, 0x9d, - 0xc2, 0xb5, 0xe3, 0xd6, 0xfe, 0x71, 0xf8, 0x79, 0xfb, 0x71, 0x67, 0xe4, - 0xfd, 0xc1, 0x70, 0xe5, 0x9b, 0xe9, 0xe8, 0x36, 0x97, 0x76, 0xd9, 0xf0, - 0x65, 0x59, 0x1e, 0x57, 0x89, 0x91, 0xee, 0x51, 0xe9, 0xec, 0x70, 0x3c, - 0xbe, 0xf0, 0x67, 0xc8, 0xf2, 0x3e, 0xd5, 0x7e, 0xc2, 0xaf, 0xcf, 0x2a, - 0x63, 0xc5, 0x74, 0xaf, 0xbf, 0xaa, 0x1f, 0xbb, 0xa3, 0x75, 0x3a, 0x0e, - 0xb7, 0xed, 0xdd, 0x5c, 0xe1, 0xc1, 0x10, 0xb9, 0xe6, 0x57, 0x48, 0xf7, - 0x04, 0x29, 0x3f, 0x0c, 0x75, 0xf0, 0xb4, 0x36, 0x4f, 0xcd, 0xfd, 0xcf, - 0xd6, 0xff, 0x59, 0xd5, 0x13, 0xfe, 0xba, 0x45, 0x15, 0xd1, 0x76, 0xfa, - 0x9b, 0x05, 0xf7, 0xaf, 0xaf, 0xfa, 0xa2, 0xd2, 0x14, 0x7f, 0x70, 0xe7, - 0x67, 0x7e, 0x68, 0x9c, 0xef, 0xa3, 0x78, 0xa6, 0xf5, 0xf1, 0x5a, 0xc8, - 0x38, 0x96, 0xa0, 0x1c, 0xaa, 0xf6, 0xea, 0xdc, 0xe5, 0x39, 0x7f, 0x2e, - 0xcf, 0xae, 0x96, 0xf3, 0xcb, 0xe9, 0x53, 0x3b, 0x2b, 0xfa, 0xfe, 0x91, - 0x9d, 0xac, 0x6c, 0xbd, 0x6d, 0x85, 0x3c, 0x7a, 0xe7, 0x7b, 0xd3, 0x15, - 0xe1, 0x61, 0xe1, 0x35, 0x79, 0xea, 0xe9, 0xc9, 0x93, 0x2b, 0xa7, 0xd8, - 0x14, 0xf5, 0xcf, 0x92, 0x5e, 0xeb, 0xc5, 0x37, 0xd9, 0xb2, 0xeb, 0xf8, - 0x24, 0xd7, 0x93, 0xce, 0x1e, 0xe6, 0x0a, 0xf0, 0x29, 0xc5, 0xd6, 0xed, - 0x52, 0x1d, 0xf2, 0xd5, 0xc7, 0xdb, 0xf7, 0xbf, 0x7f, 0x9e, 0x42, 0x9e, - 0xdd, 0x4e, 0xce, 0xfb, 0x4d, 0x9b, 0x9a, 0xb9, 0xe8, 0x2b, 0x25, 0x87, - 0xc4, 0x53, 0x8b, 0xfb, 0x43, 0xac, 0xba, 0xe3, 0x6d, 0xcb, 0xde, 0x71, - 0xb7, 0x3d, 0xd2, 0x75, 0x57, 0xa0, 0xc5, 0x3d, 0xc8, 0xe7, 0xef, 0x3b, - 0x1b, 0xfd, 0x13, 0xf7, 0x2f, 0x86, 0x47, 0x69, 0xe9, 0x6d, 0x44, 0x92, - 0x71, 0xd9, 0x6d, 0xdf, 0xf5, 0xab, 0x0a, 0x6a, 0x3f, 0xd8, 0x2a, 0xf7, - 0x71, 0xfd, 0x76, 0xf6, 0xaa, 0x59, 0x3e, 0xd6, 0x17, 0x6b, 0x57, 0xb2, - 0xb0, 0x12, 0x84, 0x8d, 0x80, 0x75, 0x8c, 0x6e, 0x92, 0xe3, 0x31, 0xdf, - 0x4e, 0x6d, 0xf8, 0xd5, 0x2c, 0x1d, 0x7f, 0x41, 0x93, 0x63, 0x8b, 0x5e, - 0x5b, 0x7a, 0xdd, 0xe6, 0xef, 0x6d, 0xb5, 0x7d, 0xae, 0x11, 0x6a, 0xb4, - 0x50, 0x5f, 0xd3, 0xe8, 0x16, 0xbf, 0x47, 0x94, 0xb4, 0xeb, 0x47, 0x3e, - 0xbd, 0x37, 0x6d, 0xc4, 0xdc, 0x45, 0xd7, 0xbb, 0xad, 0x3f, 0x6e, 0xcf, - 0x8a, 0x87, 0x6e, 0xbc, 0x7b, 0xcb, 0x86, 0xd9, 0xb5, 0x19, 0xf4, 0xcb, - 0x7b, 0x88, 0x9a, 0xdb, 0x79, 0x0a, 0xce, 0x38, 0x90, 0xf5, 0xcf, 0x2d, - 0x93, 0x56, 0x1f, 0x5b, 0x5f, 0xeb, 0xd3, 0xca, 0xdf, 0x2c, 0xe2, 0xec, - 0x2c, 0xb7, 0xef, 0xef, 0xd4, 0xca, 0xee, 0x34, 0x6e, 0xbc, 0x8b, 0xe8, - 0x9b, 0x33, 0xdf, 0x3c, 0x78, 0xb9, 0xef, 0x77, 0x37, 0x37, 0xd0, 0x6b, - 0x14, 0x0c, 0xae, 0xea, 0xab, 0xfb, 0x8f, 0xae, 0xf7, 0xbc, 0xf5, 0xd7, - 0x76, 0x5b, 0xad, 0x93, 0x45, 0x56, 0x95, 0x93, 0x0b, 0x30, 0xd3, 0x6e, - 0xd5, 0xd6, 0x3d, 0x67, 0xd9, 0xf9, 0xda, 0xf0, 0xf5, 0xa5, 0xc5, 0x07, - 0x77, 0x97, 0x2e, 0xa3, 0xb3, 0x4b, 0x3a, 0x78, 0xf1, 0x74, 0x13, 0xea, - 0xac, 0x91, 0xe7, 0x42, 0xea, 0x3f, 0x54, 0xec, 0x1e, 0xcb, 0xde, 0x97, - 0x9e, 0xd1, 0x5d, 0x46, 0x7a, 0xf2, 0xf3, 0x4f, 0x59, 0x90, 0x5e, 0xfb, - 0x2e, 0x2e, 0xf7, 0xb3, 0xff, 0x19, 0xfd, 0x08, 0xbb, 0xac, 0xf9, 0x71, - 0x7a, 0xeb, 0xc1, 0xa1, 0xde, 0x4e, 0xef, 0xd3, 0x8d, 0xdb, 0xdf, 0xc3, - 0xbc, 0x7a, 0xe6, 0x12, 0xdd, 0xbf, 0x86, 0x45, 0x1b, 0x9f, 0x13, 0x21, - 0x6f, 0xb5, 0xdc, 0x4e, 0x1f, 0x87, 0x63, 0x23, 0x2e, 0x7b, 0xad, 0x6d, - 0xac, 0x26, 0x7c, 0xb4, 0xc0, 0x80, 0x1f, 0xe1, 0xe9, 0x1d, 0xac, 0xb7, - 0x5e, 0xbc, 0x77, 0x02, 0x99, 0x25, 0x51, 0xaf, 0xd9, 0xaf, 0x2a, 0x5e, - 0x9e, 0xb0, 0x93, 0xfb, 0xf8, 0xd6, 0xb4, 0x65, 0x4a, 0x97, 0xde, 0xf0, - 0x60, 0xfd, 0xb5, 0x32, 0x9f, 0x03, 0x75, 0xb6, 0xf7, 0xe1, 0x7b, 0x8b, - 0xf4, 0xea, 0x8e, 0x43, 0x80, 0xfe, 0xdc, 0xb2, 0xa6, 0xdb, 0x0e, 0x9f, - 0x5f, 0x93, 0x0d, 0x11, 0x18, 0x7f, 0x46, 0xaf, 0x71, 0x18, 0xb7, 0xa2, - 0x3c, 0x44, 0x9f, 0xa7, 0x69, 0x51, 0x84, 0x2c, 0x74, 0x92, 0x38, 0x5f, - 0x23, 0x99, 0xd9, 0x89, 0x14, 0x5f, 0x8b, 0xb7, 0xa5, 0x69, 0xdf, 0xf5, - 0xb6, 0x7c, 0xe6, 0x8f, 0xd2, 0xfe, 0x2c, 0xdd, 0xec, 0xb3, 0x1a, 0xc2, - 0xdb, 0xfb, 0x66, 0x70, 0x9e, 0x77, 0x1f, 0xe3, 0x57, 0x6f, 0x34, 0xd9, - 0x67, 0x1e, 0x2d, 0xf9, 0x30, 0x11, 0xa7, 0x02, 0x1b, 0xf2, 0xe8, 0x0f, - 0x5e, 0xb3, 0xb9, 0x24, 0x9f, 0x86, 0x77, 0xce, 0xc4, 0x09, 0xc0, 0x09, - 0x34, 0xe5, 0x7a, 0x77, 0x7f, 0xd8, 0x3f, 0xe4, 0x60, 0xed, 0x69, 0xf7, - 0xf1, 0xf9, 0x73, 0x4a, 0x2f, 0xd7, 0xfd, 0xee, 0x7a, 0x2f, 0x78, 0xfd, - 0x5c, 0x6e, 0x2f, 0xaa, 0x69, 0xbf, 0xeb, 0xbb, 0xf9, 0x3d, 0x6d, 0xb4, - 0xe7, 0x7e, 0xb7, 0x04, 0xb0, 0x1b, 0x87, 0xc2, 0x98, 0x9e, 0xde, 0x36, - 0xae, 0xbc, 0xc6, 0x4e, 0xf0, 0xdd, 0x7e, 0x3d, 0xcf, 0xc1, 0xee, 0x9e, - 0xdf, 0xfa, 0xca, 0xc8, 0x3e, 0x6f, 0x95, 0xee, 0x95, 0xfd, 0xbc, 0x04, - 0xb2, 0xe3, 0x1c, 0xbd, 0x69, 0xab, 0x7c, 0xb7, 0x52, 0x91, 0x4b, 0x8d, - 0xdb, 0xf5, 0xc0, 0x16, 0x63, 0xbd, 0x25, 0xef, 0x6a, 0x74, 0x36, 0xb9, - 0xe9, 0x7d, 0x1e, 0xdd, 0x95, 0x76, 0x4f, 0xad, 0xc7, 0x66, 0x48, 0xc3, - 0x70, 0x50, 0x4b, 0x2f, 0x6c, 0x6e, 0x44, 0x6c, 0xbb, 0xc5, 0x02, 0x4f, - 0xd9, 0xf9, 0x89, 0x59, 0x51, 0x4a, 0xe7, 0xd6, 0x74, 0x83, 0xf5, 0x69, - 0xff, 0xd8, 0x1d, 0x8a, 0xc0, 0x3e, 0x3f, 0xc7, 0x43, 0x7b, 0xf0, 0x7e, - 0xec, 0xec, 0x5d, 0x79, 0xed, 0x67, 0x36, 0x10, 0x29, 0x33, 0xb5, 0x0d, - 0x8f, 0x9c, 0x14, 0xff, 0x24, 0xce, 0x3e, 0xf9, 0xb1, 0xf2, 0x07, 0xf1, - 0x8d, 0xcc, 0x43, 0x70, 0xbc, 0xe2, 0x9f, 0x91, 0x8a, 0x92, 0xe0, 0x63, - 0x51, 0x1c, 0x47, 0x31, 0xbe, 0x57, 0x89, 0xc7, 0xf1, 0x4f, 0xcb, 0xdc, - 0x2e, 0x3f, 0xf5, 0xd2, 0x1c, 0xaf, 0xf2, 0xfb, 0x79, 0xd3, 0x3f, 0x5f, - 0x79, 0xb1, 0xa9, 0xc0, 0xb4, 0xfa, 0x32, 0x89, 0xb9, 0x77, 0x43, 0xcb, - 0xf1, 0x81, 0x92, 0x9f, 0xcf, 0xb7, 0xb3, 0xf8, 0xc4, 0xa9, 0xf5, 0x63, - 0x89, 0xf7, 0xd7, 0xb8, 0xf9, 0x99, 0x1b, 0x0d, 0x2d, 0xbf, 0xfd, 0x93, - 0xe1, 0x1b, 0x51, 0xfa, 0x41, 0xbf, 0x89, 0x4a, 0xd6, 0xb8, 0x50, 0x9b, - 0xe7, 0x70, 0x40, 0xa7, 0x55, 0x52, 0x97, 0x6a, 0xc1, 0xc8, 0x39, 0x60, - 0xfe, 0xeb, 0xf9, 0xb1, 0x49, 0x7e, 0xee, 0xc3, 0xa4, 0x5e, 0x3d, 0x79, - 0x78, 0x2f, 0x8a, 0xe3, 0x46, 0xfb, 0xf8, 0x54, 0x6a, 0x97, 0x7d, 0x7d, - 0x68, 0xd3, 0x8f, 0xc7, 0xee, 0xc7, 0xcf, 0xc5, 0xe9, 0xf1, 0x81, 0x56, - 0x9e, 0xa7, 0x82, 0x6d, 0x27, 0xe3, 0x73, 0x94, 0x64, 0x74, 0xa4, 0xfe, - 0x36, 0xec, 0x4b, 0xdb, 0x32, 0xd4, 0x54, 0xd4, 0x0f, 0xd3, 0xaf, 0xd6, - 0xfe, 0x41, 0xb8, 0x1f, 0x40, 0xab, 0x4a, 0x5b, 0x3c, 0x4e, 0x8b, 0xe7, - 0x5a, 0x9c, 0x8d, 0x8f, 0x8f, 0x8f, 0xd1, 0x8a, 0xbc, 0xcf, 0x40, 0x5f, - 0xb3, 0xf5, 0xed, 0x15, 0xae, 0x0b, 0x34, 0x38, 0x6b, 0x9b, 0xbc, 0x36, - 0xe1, 0xf6, 0xf2, 0x79, 0x90, 0xfb, 0xac, 0x90, 0x3f, 0x3b, 0xc5, 0xbd, - 0x35, 0x04, 0xd3, 0x39, 0x3c, 0x7f, 0x4f, 0xcd, 0xce, 0x6e, 0xbf, 0xec, - 0x23, 0xbf, 0x57, 0x56, 0x9c, 0x7f, 0xef, 0x4e, 0x8b, 0x75, 0x34, 0x7d, - 0x26, 0x9a, 0x56, 0x0e, 0xb7, 0xcd, 0xa7, 0xba, 0x96, 0xeb, 0xc8, 0x01, - 0xf8, 0xd6, 0xae, 0x85, 0x85, 0x2e, 0x8f, 0xad, 0x7d, 0x44, 0xee, 0x29, - 0x5e, 0xdb, 0xaf, 0xc7, 0x4f, 0x77, 0xda, 0x2c, 0x78, 0xeb, 0xb1, 0xd4, - 0xd4, 0x9f, 0x6c, 0x99, 0xf2, 0xaf, 0x74, 0xbf, 0xed, 0x7b, 0xe2, 0x1d, - 0x80, 0xb1, 0xbb, 0xd5, 0xc9, 0xff, 0x44, 0x3b, 0x0f, 0xd3, 0xf0, 0x47, - 0x98, 0x8d, 0xcf, 0x62, 0x6e, 0xef, 0x44, 0xbb, 0x4d, 0xc7, 0x46, 0xfe, - 0x5d, 0xaf, 0xc7, 0x32, 0x67, 0xbb, 0xd4, 0xbe, 0x7c, 0xe3, 0xe5, 0xf7, - 0xe3, 0xf0, 0xf9, 0x71, 0xff, 0x60, 0x6b, 0xfd, 0xb4, 0x5b, 0x6f, 0x4e, - 0xb7, 0x2d, 0x22, 0xc5, 0x99, 0x78, 0xd0, 0xc7, 0x76, 0xb1, 0xbc, 0xa3, - 0xb5, 0xfd, 0xf1, 0x6c, 0xfc, 0xc3, 0x57, 0x6f, 0xba, 0x75, 0x7a, 0xa8, - 0xbf, 0x7e, 0x96, 0x91, 0xdf, 0xa7, 0x4c, 0xb7, 0x47, 0x67, 0xd8, 0x89, - 0xcd, 0x6d, 0xda, 0x7c, 0x6d, 0x8e, 0xe7, 0x60, 0xff, 0x71, 0x7c, 0xb4, - 0x93, 0xba, 0x74, 0x45, 0xea, 0xf3, 0xef, 0xe8, 0x83, 0x5e, 0x6f, 0x7b, - 0x09, 0x22, 0xe3, 0x3e, 0xb8, 0x47, 0x75, 0x63, 0x42, 0x7c, 0x66, 0xe2, - 0x76, 0x53, 0xcf, 0xe7, 0xf7, 0x25, 0x0e, 0xaa, 0x0c, 0xfb, 0x49, 0xb8, - 0x73, 0x77, 0xf1, 0x00, 0xba, 0x6d, 0xcf, 0x15, 0x98, 0xc4, 0x83, 0xff, - 0x5d, 0xbd, 0x2f, 0x5a, 0x5a, 0x4c, 0xd6, 0xd7, 0x0f, 0xa9, 0x54, 0xbb, - 0x32, 0x1f, 0x87, 0xdd, 0x86, 0xa4, 0x7d, 0xf5, 0x6a, 0xa2, 0x7c, 0x87, - 0xda, 0xc3, 0x05, 0x74, 0x3a, 0x46, 0xc7, 0xf2, 0xe3, 0x8b, 0xec, 0x40, - 0xec, 0xad, 0xfb, 0x78, 0x61, 0x95, 0x24, 0xbb, 0xb2, 0x9d, 0x93, 0x06, - 0xce, 0xf9, 0x63, 0x90, 0xee, 0x63, 0x25, 0xe9, 0xe2, 0xf3, 0x73, 0xf1, - 0xda, 0xa7, 0x5d, 0xdb, 0xbc, 0x78, 0x38, 0xf9, 0x7e, 0x5a, 0xa4, 0xcd, - 0x97, 0x06, 0x28, 0xd9, 0x12, 0x52, 0x7c, 0x2e, 0xae, 0x4b, 0x1f, 0x3f, - 0xfb, 0xeb, 0x45, 0xb4, 0x07, 0xce, 0x97, 0x02, 0x25, 0xd9, 0x29, 0x4b, - 0x6d, 0xcd, 0xb6, 0x2f, 0x1e, 0xae, 0xdc, 0x1f, 0xeb, 0x18, 0xed, 0xc5, - 0x7d, 0x14, 0x0b, 0xb4, 0x7b, 0x65, 0xda, 0x37, 0x3a, 0xe5, 0xe0, 0xdc, - 0x80, 0xae, 0x2d, 0x0d, 0xed, 0xc9, 0x5b, 0x2f, 0x5c, 0xff, 0xcb, 0x8e, - 0x4e, 0xd1, 0x0e, 0x9d, 0xfb, 0x8d, 0x72, 0x5d, 0xcf, 0x33, 0x40, 0x04, - 0xd1, 0x2c, 0x17, 0x20, 0x43, 0x9a, 0xcb, 0xcb, 0x8c, 0xb2, 0xde, 0x65, - 0x6f, 0x90, 0xd3, 0x1b, 0xf9, 0xf3, 0x94, 0xec, 0xfb, 0xa0, 0xdb, 0xd1, - 0xe5, 0x6d, 0x5d, 0x3b, 0xd7, 0x7e, 0x8c, 0xbf, 0x69, 0xfe, 0x73, 0x15, - 0x45, 0xcc, 0x5f, 0x13, 0x52, 0xbb, 0x45, 0xb6, 0x91, 0xe6, 0x57, 0xab, - 0xc5, 0x6b, 0x57, 0xa0, 0x35, 0x3d, 0xba, 0xfd, 0xcb, 0xf0, 0x1e, 0x3f, - 0xb8, 0x43, 0x72, 0xcd, 0x06, 0x58, 0x38, 0x7e, 0x71, 0x99, 0x7e, 0x7c, - 0x87, 0x6b, 0xe3, 0xb4, 0xf2, 0xee, 0xb7, 0x05, 0x48, 0xfb, 0xa7, 0x7f, - 0xf2, 0xb5, 0x72, 0x0a, 0x3f, 0xb6, 0x83, 0x02, 0x57, 0x7b, 0xaf, 0xdc, - 0x04, 0xb9, 0xde, 0xc9, 0x0d, 0xbb, 0xbe, 0xfa, 0x34, 0xcf, 0x37, 0x77, - 0xbf, 0xd8, 0x5d, 0x1e, 0xfe, 0x3d, 0xbe, 0x3f, 0x9b, 0xda, 0xb4, 0xa2, - 0x77, 0xe1, 0x45, 0xdf, 0xe5, 0x2b, 0x03, 0x7a, 0x22, 0xc3, 0xf8, 0x6d, - 0x5a, 0xf4, 0x03, 0xed, 0xde, 0x2a, 0x39, 0xaf, 0x0f, 0x34, 0xa0, 0x4f, - 0x7b, 0xf5, 0xa3, 0x0f, 0xf3, 0xe8, 0xe3, 0xf8, 0xf3, 0xe4, 0xfb, 0x83, - 0x85, 0x8a, 0x15, 0x61, 0xf6, 0x17, 0xd1, 0x37, 0x76, 0xbf, 0xbf, 0xf6, - 0xf4, 0x38, 0x80, 0xc2, 0x00, 0x4a, 0xda, 0xb1, 0xf1, 0x4d, 0x87, 0x6e, - 0x1f, 0x0d, 0x64, 0x8f, 0x0b, 0x7a, 0xb8, 0xde, 0xbf, 0x8e, 0x13, 0x3f, - 0x1c, 0xf9, 0xcf, 0xe3, 0x62, 0x65, 0xfa, 0xf7, 0x4f, 0x76, 0x38, 0x46, - 0xe7, 0x2f, 0xa7, 0x5d, 0xe6, 0xb4, 0x57, 0x80, 0x61, 0xb8, 0xba, 0xf7, - 0x05, 0x5a, 0xb1, 0x27, 0xcc, 0xc6, 0x56, 0x5f, 0x61, 0xff, 0x74, 0x5b, - 0xa1, 0xee, 0x8b, 0x6f, 0xe4, 0xb2, 0xdf, 0x3f, 0x55, 0xd5, 0xae, 0x5c, - 0x33, 0x7b, 0x6f, 0xdd, 0xe7, 0x5e, 0xe3, 0xdf, 0xe0, 0x69, 0xd5, 0xa1, - 0x7f, 0x68, 0xf8, 0x1b, 0x74, 0x73, 0xdc, 0x5b, 0x5f, 0xe0, 0xba, 0x87, - 0x87, 0xff, 0xf3, 0xfe, 0xf5, 0x2c, 0xaa, 0x83, 0xa1, 0xdf, 0x1f, 0xc3, - 0xcd, 0x6b, 0xb5, 0x9f, 0x45, 0x51, 0xd7, 0x5f, 0xcb, 0x64, 0x88, 0x40, - 0xad, 0x1c, 0x47, 0xa3, 0xab, 0x79, 0x19, 0xef, 0x4d, 0xd2, 0xb7, 0xfa, - 0x5e, 0x04, 0xe3, 0xe0, 0x79, 0xc8, 0x59, 0x8b, 0xef, 0xef, 0x9d, 0xab, - 0xf7, 0xb1, 0xb6, 0x55, 0xeb, 0xe2, 0xfa, 0x23, 0x7c, 0x2d, 0x7e, 0x3e, - 0x52, 0xbd, 0x14, 0x1f, 0x5f, 0xd3, 0x79, 0xf3, 0x60, 0xfb, 0xe8, 0xd0, - 0x1f, 0x20, 0x45, 0x82, 0x67, 0xd1, 0xbf, 0x85, 0x1e, 0xfd, 0x24, 0x1c, - 0xd0, 0xe2, 0x9c, 0x7f, 0x76, 0x5b, 0xdb, 0xe9, 0x8f, 0xe9, 0x55, 0x3d, - 0x56, 0xcb, 0xc3, 0x97, 0xff, 0x1a, 0xb7, 0x2e, 0xd5, 0x0d, 0x81, 0xeb, - 0x4f, 0x3b, 0x2a, 0xc2, 0x33, 0x49, 0x87, 0xf9, 0x8b, 0xbb, 0xb6, 0xe7, - 0xee, 0x55, 0xd0, 0x69, 0xfc, 0x6a, 0xb4, 0x0b, 0x0e, 0xeb, 0x05, 0x5b, - 0xef, 0x2f, 0xdb, 0xef, 0x14, 0xfc, 0xdf, 0xa2, 0x43, 0x46, 0x4c, 0x76, - 0x54, 0xbc, 0x41, 0x21, 0x53, 0x73, 0xa1, 0xef, 0x2f, 0xfb, 0xcf, 0xfb, - 0x71, 0xb3, 0x21, 0xb1, 0x1e, 0x93, 0x77, 0xc3, 0xfa, 0x4d, 0xbc, 0x63, - 0xef, 0x71, 0xa7, 0x3e, 0xd6, 0xdb, 0xc3, 0xd1, 0xce, 0xb5, 0xb8, 0xda, - 0x85, 0x44, 0x8b, 0x9e, 0x8f, 0x75, 0x06, 0x68, 0xb0, 0x6b, 0xbb, 0x38, - 0xbe, 0x5a, 0x27, 0x42, 0xbf, 0x5f, 0x95, 0xde, 0x2e, 0x95, 0x7e, 0x70, - 0xa2, 0x78, 0xd5, 0x6c, 0xfd, 0x5c, 0xcf, 0x1f, 0x69, 0xf8, 0x4a, 0xc9, - 0xd9, 0x37, 0xd2, 0x66, 0xe5, 0xb8, 0xa7, 0xab, 0xbe, 0xdb, 0xa2, 0xb6, - 0xc5, 0xbc, 0xbc, 0xe8, 0xa7, 0x27, 0x3b, 0x57, 0x28, 0xbc, 0xbc, 0xc4, - 0xb7, 0xec, 0xfb, 0x65, 0x9a, 0xf4, 0xee, 0x25, 0xb2, 0x7f, 0x98, 0xb7, - 0xf0, 0xcd, 0xc9, 0x57, 0xbd, 0xfc, 0x0e, 0xec, 0xcd, 0x93, 0x7e, 0xd0, - 0x21, 0x09, 0xd2, 0xa6, 0x4e, 0x51, 0xf4, 0x11, 0xfc, 0x7c, 0xc7, 0xa4, - 0xce, 0x42, 0x66, 0x88, 0xd1, 0x7a, 0xdf, 0xc6, 0x63, 0xaf, 0x3a, 0xbf, - 0x21, 0xea, 0xeb, 0xa8, 0xd7, 0xd5, 0x0f, 0xeb, 0xac, 0x4d, 0xaf, 0x5e, - 0xed, 0xef, 0xce, 0xa7, 0xfa, 0x5c, 0xec, 0x1a, 0xe1, 0x7f, 0xd0, 0x38, - 0x1a, 0xec, 0x67, 0x69, 0xb2, 0x63, 0xbc, 0x7e, 0xff, 0x78, 0xe4, 0x5f, - 0xe8, 0xe6, 0x7f, 0x26, 0x3f, 0x08, 0x7b, 0x7f, 0x14, 0x97, 0x53, 0xbe, - 0x63, 0x51, 0xf5, 0xd6, 0x65, 0xdc, 0x2f, 0x9b, 0xcf, 0xd0, 0xf8, 0x0c, - 0x1f, 0xf5, 0x68, 0xae, 0x3e, 0xfc, 0xab, 0xaa, 0xae, 0xa1, 0xb5, 0xb3, - 0xe4, 0xb6, 0xaa, 0xfa, 0x68, 0x1f, 0x59, 0x72, 0x5d, 0x16, 0xe0, 0x40, - 0xc3, 0xc8, 0x23, 0x64, 0xec, 0x99, 0x08, 0x92, 0xd7, 0xf9, 0x2e, 0x9c, - 0x86, 0x6d, 0x1b, 0x23, 0x50, 0xcf, 0x2c, 0xfb, 0xfe, 0x3e, 0xd4, 0xe1, - 0xe7, 0x0f, 0x15, 0x7e, 0x86, 0xd7, 0xcb, 0xb0, 0xaa, 0x8c, 0xf6, 0x26, - 0xf4, 0xeb, 0x65, 0x23, 0x2f, 0x3f, 0xf6, 0xf7, 0xf5, 0xea, 0x36, 0x79, - 0xdf, 0x51, 0x9c, 0xc9, 0x71, 0x72, 0xe2, 0xf2, 0xa3, 0xe1, 0xa3, 0xe9, - 0xcd, 0x5f, 0x79, 0xe6, 0x8d, 0xae, 0x7e, 0x6e, 0x4c, 0x93, 0x17, 0xd7, - 0x75, 0x71, 0xdb, 0xfb, 0x83, 0xb9, 0xef, 0x7b, 0x18, 0xd8, 0x1f, 0x67, - 0xe3, 0xe7, 0xd9, 0xdd, 0xbe, 0xde, 0xfd, 0x83, 0xec, 0xbe, 0x6a, 0xee, - 0x6b, 0xa9, 0x11, 0xbc, 0x11, 0x79, 0xdd, 0xcb, 0x5a, 0xe6, 0xfd, 0x97, - 0x61, 0xeb, 0xef, 0x26, 0xbf, 0x3e, 0x3d, 0xa5, 0x4e, 0x9d, 0xbf, 0x1f, - 0x62, 0xe3, 0x62, 0x09, 0xe3, 0x6b, 0x7d, 0x48, 0xa7, 0x82, 0x7f, 0xff, - 0xf8, 0x66, 0x32, 0x8e, 0x76, 0xde, 0x27, 0xa4, 0x47, 0xd0, 0x7f, 0x0d, - 0xeb, 0x43, 0xfb, 0xb1, 0xb1, 0xc9, 0xe9, 0xc7, 0x76, 0x20, 0x6b, 0xab, - 0x0a, 0xba, 0x26, 0xd9, 0xbb, 0x97, 0xe5, 0x4e, 0x1b, 0xce, 0xb2, 0xbc, - 0xe9, 0x5b, 0xdb, 0x46, 0xfb, 0xb0, 0xc1, 0x69, 0xf6, 0xf3, 0xbb, 0x54, - 0x59, 0x98, 0x5b, 0x69, 0x10, 0xaf, 0x83, 0x48, 0x1e, 0x50, 0x1a, 0x96, - 0x3f, 0x48, 0x02, 0xd8, 0xb9, 0xc7, 0x90, 0xf3, 0x9f, 0xeb, 0xe3, 0xb2, - 0x33, 0x7f, 0xae, 0xa9, 0xe6, 0x87, 0xbc, 0xd7, 0x8a, 0x57, 0x65, 0x7e, - 0xfc, 0x08, 0x3f, 0x9d, 0x27, 0xf9, 0xb4, 0x59, 0xff, 0x19, 0x72, 0x6b, - 0x38, 0x6e, 0xbe, 0x75, 0xd1, 0xd7, 0x9f, 0x6c, 0xbb, 0xef, 0xb5, 0xf6, - 0xa9, 0xf7, 0xa2, 0x3b, 0xbd, 0x37, 0x17, 0x15, 0xb0, 0x3e, 0x73, 0x4a, - 0x29, 0x5e, 0x51, 0x88, 0xb7, 0x17, 0xef, 0x41, 0x82, 0x83, 0x61, 0x6f, - 0xb0, 0xf8, 0xfa, 0x5c, 0xd8, 0xae, 0x11, 0xb2, 0xf6, 0x1c, 0x96, 0x64, - 0xb5, 0xc8, 0x0a, 0x95, 0xfd, 0xe8, 0xf2, 0x6e, 0x0a, 0x56, 0x09, 0x0e, - 0x3f, 0x07, 0x41, 0x3c, 0x5d, 0xa2, 0xaf, 0x6d, 0x62, 0x35, 0xb4, 0xd9, - 0xa3, 0x6f, 0xdf, 0x2f, 0x8b, 0x1f, 0x2a, 0xf8, 0x99, 0xbe, 0xf9, 0x4f, - 0xe9, 0xbe, 0xd1, 0xad, 0x13, 0x5a, 0xc6, 0xcb, 0x2f, 0x26, 0x1b, 0x37, - 0x1b, 0xb2, 0x67, 0x58, 0xd1, 0xf5, 0xfe, 0x6c, 0x2c, 0x2e, 0xc4, 0x4d, - 0x0b, 0xe7, 0x88, 0x0f, 0x51, 0xc6, 0xde, 0xaf, 0xab, 0xf3, 0x13, 0xf7, - 0xd8, 0xdd, 0xb3, 0x45, 0xca, 0x7d, 0xbd, 0xce, 0x57, 0x75, 0xf3, 0x51, - 0xe3, 0x4b, 0x66, 0xa4, 0x71, 0x14, 0x97, 0xaa, 0x51, 0xcb, 0x9b, 0xf3, - 0xf3, 0x72, 0x61, 0x5f, 0xc9, 0xfb, 0xfa, 0x6e, 0x84, 0x95, 0xfd, 0xbc, - 0x7e, 0xfd, 0x1c, 0x85, 0x7c, 0xd7, 0xf5, 0x77, 0xb2, 0x0e, 0xe4, 0xbe, - 0xdf, 0xca, 0x3c, 0x79, 0x7b, 0x9b, 0xc3, 0x72, 0x58, 0x2d, 0xb3, 0xbb, - 0x46, 0x9a, 0x29, 0x6f, 0x6e, 0x99, 0xfe, 0x9e, 0xbf, 0x49, 0x2d, 0xf4, - 0xd4, 0x75, 0x2a, 0x8a, 0xd2, 0xff, 0xf2, 0xce, 0x35, 0x96, 0xde, 0xee, - 0xfe, 0x76, 0x6c, 0x6e, 0xde, 0x3d, 0xfb, 0xa5, 0xb2, 0xc3, 0x05, 0xf7, - 0x51, 0xe8, 0xe4, 0x89, 0xdb, 0xf7, 0xee, 0x36, 0x79, 0x5d, 0xee, 0xd7, - 0xee, 0x56, 0xd7, 0x1f, 0x89, 0xb9, 0x60, 0xda, 0xfb, 0x79, 0x5a, 0x16, - 0xf7, 0x72, 0x99, 0xed, 0xf6, 0x3c, 0x2e, 0x5e, 0x63, 0xd9, 0x2d, 0x74, - 0x67, 0x34, 0x1e, 0xed, 0x7a, 0x91, 0x84, 0xa2, 0xde, 0xf9, 0x69, 0x97, - 0xaf, 0x85, 0x35, 0x84, 0x45, 0xe6, 0x05, 0x96, 0xb6, 0xb4, 0x8b, 0x0f, - 0x29, 0x69, 0xb5, 0x72, 0x22, 0x72, 0x27, 0x27, 0x6c, 0x9e, 0x93, 0xce, - 0x3f, 0xbe, 0xde, 0x9f, 0x15, 0x1a, 0xfd, 0x2b, 0x0a, 0x8f, 0x39, 0x5f, - 0x6c, 0xb4, 0x6b, 0x5f, 0xed, 0x77, 0x9d, 0x7a, 0xc8, 0x9f, 0x2c, 0x3a, - 0xf5, 0xc7, 0x2b, 0x5b, 0x9f, 0x5f, 0x41, 0xbe, 0xba, 0x6e, 0x5e, 0xfb, - 0x43, 0x7b, 0x9a, 0xa6, 0x2f, 0xac, 0x1c, 0xcd, 0x3b, 0x9f, 0x4f, 0xe5, - 0xf6, 0x67, 0xd8, 0xd3, 0xf5, 0xf5, 0x23, 0x3a, 0x4f, 0x4b, 0x4b, 0x7c, - 0xdc, 0xfd, 0xef, 0x45, 0x7d, 0x3f, 0xec, 0x5e, 0x67, 0x13, 0x05, 0x57, - 0xcd, 0x10, 0xe9, 0x65, 0x47, 0x06, 0x2e, 0xce, 0x08, 0x2f, 0x1c, 0xf4, - 0x4a, 0x0c, 0x11, 0xed, 0x73, 0xb3, 0x73, 0x8e, 0xe1, 0xca, 0xd1, 0x9e, - 0xe4, 0xd4, 0xdf, 0xa7, 0xcf, 0x4f, 0xf3, 0xb9, 0xed, 0xed, 0x93, 0x26, - 0xbe, 0x97, 0xad, 0x3a, 0x9e, 0xdd, 0x7c, 0x1b, 0x37, 0xbd, 0xc9, 0x42, - 0x0d, 0x0f, 0xf5, 0xd9, 0x95, 0x85, 0xea, 0x0f, 0xed, 0xbe, 0x4c, 0xbf, - 0xbf, 0x9b, 0x73, 0x65, 0x1e, 0x56, 0x8d, 0x59, 0x15, 0x8f, 0x5a, 0xdb, - 0x95, 0xb7, 0xf1, 0x21, 0xb2, 0xe7, 0x2d, 0x0b, 0x5a, 0xab, 0xd9, 0x39, - 0xd5, 0xf6, 0xee, 0x04, 0x9e, 0x31, 0x6d, 0x63, 0x54, 0x7d, 0x6e, 0x37, - 0xfb, 0xf0, 0x76, 0xb3, 0xf7, 0xa6, 0x7e, 0xab, 0x2d, 0x75, 0x3f, 0x5e, - 0xf3, 0xe7, 0x84, 0xec, 0x0f, 0x67, 0x07, 0x51, 0x71, 0x1c, 0xbd, 0xc7, - 0xeb, 0x03, 0xdf, 0xae, 0x2d, 0xb7, 0x57, 0xf9, 0xb6, 0xdb, 0x4c, 0xaf, - 0x1f, 0xc1, 0xeb, 0xfa, 0x8e, 0x5e, 0x52, 0x3b, 0x2c, 0x4e, 0x1f, 0x8f, - 0x89, 0xfc, 0x14, 0xaf, 0xe1, 0xc3, 0xd1, 0xc6, 0x93, 0x1c, 0x3f, 0xda, - 0xe8, 0xa3, 0x7b, 0xde, 0x97, 0xf5, 0xe3, 0xe5, 0x29, 0x51, 0xe0, 0x3a, - 0xfb, 0xb1, 0x4a, 0xd3, 0x73, 0x25, 0x3c, 0xef, 0x7b, 0xb8, 0xf1, 0xed, - 0xe1, 0x5c, 0x3d, 0xa8, 0x24, 0x32, 0xf7, 0x62, 0x75, 0xf3, 0xfb, 0x78, - 0x3b, 0xee, 0x57, 0xa0, 0xff, 0xa8, 0xf4, 0xc3, 0xfc, 0x2e, 0x5f, 0x84, - 0x9f, 0x9d, 0xdd, 0xc4, 0x8d, 0xd5, 0xdd, 0xf2, 0xf7, 0xee, 0xed, 0x73, - 0xf7, 0xc3, 0xc5, 0xd7, 0xc5, 0xe6, 0x96, 0xda, 0xbc, 0x65, 0x97, 0x38, - 0x34, 0x9f, 0x87, 0x77, 0xb1, 0x9d, 0x76, 0xf2, 0xe3, 0xe3, 0x36, 0x6d, - 0x07, 0x84, 0x0f, 0xc6, 0xb1, 0xdf, 0x81, 0xa8, 0x79, 0x5e, 0xd5, 0xb2, - 0xe6, 0x27, 0xe7, 0x3e, 0xee, 0xac, 0x7b, 0xfd, 0x7d, 0xdc, 0xbe, 0xb6, - 0xda, 0x90, 0xe9, 0xcf, 0x9b, 0x7c, 0x34, 0xd9, 0x6a, 0xfb, 0x4e, 0xa6, - 0x52, 0x2f, 0x8b, 0x36, 0x60, 0x14, 0xf5, 0xf2, 0x7c, 0xfa, 0x7a, 0x7c, - 0x4a, 0x26, 0xb4, 0xe7, 0x45, 0x4c, 0xf7, 0x71, 0xa5, 0x2f, 0x9d, 0x8f, - 0xf5, 0xfd, 0xd9, 0xa7, 0xef, 0xba, 0xa1, 0x7d, 0xcc, 0xc6, 0x84, 0x7d, - 0xad, 0x35, 0x29, 0xba, 0xb6, 0xb0, 0x1f, 0x9f, 0x1d, 0x91, 0xb4, 0x3d, - 0x0d, 0xda, 0x92, 0xa3, 0x93, 0x08, 0xb7, 0xc3, 0x52, 0x5b, 0x8e, 0x9f, - 0xef, 0xa3, 0xfb, 0xb8, 0x61, 0x8e, 0xb2, 0xad, 0x6d, 0x78, 0x09, 0x1e, - 0x7b, 0xf7, 0xcb, 0x22, 0xfb, 0x47, 0x91, 0xed, 0xa6, 0xe7, 0xfb, 0x23, - 0xc9, 0xf0, 0x67, 0x4b, 0x17, 0xc9, 0x4a, 0x3d, 0xf8, 0xa5, 0xd8, 0xd1, - 0x8f, 0xdc, 0x12, 0x5f, 0xc5, 0x58, 0xd5, 0xab, 0x62, 0xff, 0x6a, 0xc1, - 0x24, 0x4e, 0xd7, 0xdb, 0x5a, 0xbf, 0x7c, 0xfe, 0xfc, 0x79, 0xf4, 0x74, - 0x6f, 0x2b, 0x4f, 0x9f, 0xaf, 0x93, 0xd5, 0x75, 0x85, 0x1f, 0x75, 0xd7, - 0xec, 0xd3, 0x03, 0xc4, 0x0c, 0xf1, 0x58, 0x2e, 0xe6, 0xaf, 0x60, 0xfb, - 0x51, 0x9d, 0x76, 0xfa, 0xa7, 0xd9, 0x6b, 0x5a, 0xb6, 0xeb, 0xaa, 0xa6, - 0x56, 0xe6, 0xed, 0x44, 0x3e, 0xb6, 0xec, 0x62, 0x90, 0xf2, 0xf2, 0xfe, - 0x41, 0x5c, 0x6f, 0xfd, 0x23, 0xbe, 0x7b, 0xcf, 0x25, 0xb2, 0xeb, 0x6d, - 0xfc, 0xf9, 0xae, 0x3a, 0xf0, 0xb7, 0xc7, 0x69, 0x38, 0x93, 0x78, 0xf3, - 0xd5, 0x8f, 0x7a, 0x77, 0x1d, 0xb9, 0xfa, 0x68, 0x83, 0x4c, 0x3d, 0x97, - 0xa7, 0x7d, 0x47, 0xbc, 0xcd, 0xba, 0xb7, 0x6e, 0x9f, 0xad, 0x74, 0x33, - 0xfa, 0x78, 0x94, 0x79, 0xfa, 0x7a, 0xe6, 0xd7, 0xc0, 0x7d, 0x2f, 0xd6, - 0xcd, 0x57, 0xbe, 0xd3, 0x34, 0x8d, 0x47, 0xbc, 0xbd, 0xc4, 0x7b, 0x10, - 0x24, 0xc9, 0xed, 0x49, 0xb7, 0x21, 0xbe, 0x8c, 0x6b, 0x76, 0xad, 0xad, - 0xa8, 0x1d, 0x97, 0x87, 0xd7, 0xb1, 0xf6, 0xed, 0xfa, 0x99, 0x8c, 0xfe, - 0x19, 0xaf, 0x86, 0x67, 0x2e, 0x9c, 0x1c, 0xa8, 0x83, 0xde, 0xbf, 0xed, - 0xe3, 0x15, 0xad, 0x7f, 0x1a, 0xc6, 0xa7, 0x5b, 0x4d, 0xcb, 0xe3, 0xd1, - 0x96, 0xb7, 0xdd, 0x54, 0x84, 0x27, 0xed, 0x71, 0x06, 0x0a, 0x1d, 0xca, - 0x09, 0xdb, 0xd3, 0xe7, 0xb3, 0xac, 0x5f, 0x8e, 0x51, 0x8e, 0xc7, 0xa7, - 0xff, 0xdd, 0x4d, 0xde, 0x45, 0x23, 0x65, 0xf4, 0x20, 0xf4, 0xb1, 0xbc, - 0x26, 0x46, 0x83, 0xb9, 0x68, 0xdd, 0x9f, 0xf9, 0x5a, 0x5b, 0xd6, 0x44, - 0x1c, 0xc3, 0xa5, 0x23, 0xaf, 0x87, 0x45, 0xfc, 0xf8, 0xd9, 0xb4, 0x9b, - 0x7e, 0x20, 0xe7, 0x49, 0xc4, 0xf7, 0x38, 0x78, 0xfc, 0x38, 0x9e, 0x17, - 0x35, 0xbf, 0xac, 0xd6, 0xd7, 0x65, 0x36, 0x2e, 0x77, 0x4f, 0x9c, 0x0f, - 0x3f, 0x74, 0xfe, 0x03, 0x28, 0xec, 0x07, 0x98, 0xf5, 0xbb, 0x74, 0x5b, - 0xd2, 0x74, 0x3f, 0xc9, 0xcf, 0x5b, 0x65, 0xff, 0x44, 0xf1, 0x5e, 0xac, - 0x56, 0x47, 0x77, 0x78, 0xee, 0xd9, 0x6b, 0x47, 0xda, 0xa0, 0x2f, 0xda, - 0xb8, 0xd0, 0x6f, 0x9a, 0xe6, 0xfd, 0xfc, 0xb6, 0xce, 0xa6, 0x99, 0xdf, - 0x0e, 0xe2, 0x9e, 0xae, 0x17, 0x6f, 0xdf, 0x3b, 0xf8, 0x96, 0xf6, 0x55, - 0x7f, 0xd5, 0x43, 0x99, 0xe6, 0xcf, 0xb2, 0x78, 0xe8, 0x60, 0xb6, 0xbe, - 0x83, 0x83, 0x5d, 0x8d, 0xba, 0xbd, 0xfa, 0xd6, 0xae, 0x7c, 0xa8, 0x96, - 0xa7, 0xe8, 0xf5, 0xd3, 0x72, 0x71, 0x53, 0xfa, 0xc8, 0xee, 0xea, 0x6b, - 0x3a, 0xa4, 0xfd, 0xf3, 0xb1, 0xda, 0x6f, 0xc6, 0xb6, 0x95, 0xd6, 0x7d, - 0x75, 0x3f, 0x6d, 0xaa, 0x0f, 0x6a, 0x25, 0x87, 0x8f, 0x63, 0x79, 0xbd, - 0xa1, 0x1d, 0xe1, 0x61, 0xb8, 0x69, 0x8e, 0xc3, 0x26, 0x2e, 0x96, 0x87, - 0x03, 0xc8, 0x55, 0xdc, 0x1e, 0xf4, 0xf8, 0xb3, 0x8f, 0x3f, 0x0f, 0x49, - 0xb6, 0xf1, 0xea, 0xfc, 0xcb, 0x79, 0x2e, 0x9e, 0xf6, 0xf3, 0x4d, 0x5f, - 0x56, 0xbb, 0xd2, 0x34, 0xf3, 0xf3, 0xdb, 0xed, 0x99, 0xbc, 0x1a, 0xcd, - 0x3d, 0x6a, 0x9b, 0x9f, 0xdd, 0xcf, 0x64, 0xff, 0x24, 0xb7, 0xc4, 0xab, - 0x9e, 0x52, 0x0c, 0xb5, 0x6a, 0x2d, 0x9c, 0x7c, 0xb5, 0x4e, 0x63, 0x1c, - 0x97, 0x94, 0xf4, 0x3f, 0x86, 0xa3, 0x36, 0x79, 0xef, 0x7a, 0x12, 0x47, - 0xfc, 0x76, 0x8e, 0x46, 0x51, 0xef, 0x8d, 0xf2, 0xfe, 0x65, 0xad, 0x4d, - 0x53, 0x3b, 0xb9, 0x0b, 0xfa, 0xa5, 0x7d, 0xdd, 0xf4, 0xb6, 0xaf, 0xef, - 0xcd, 0xf7, 0x6a, 0xf9, 0x3a, 0x57, 0x2b, 0x6d, 0x3b, 0x68, 0x6f, 0x32, - 0xf8, 0xdf, 0xc1, 0x0a, 0xe8, 0xb1, 0xce, 0x5d, 0xbc, 0xdc, 0x6c, 0xf5, - 0xdd, 0xf5, 0x9a, 0x71, 0xf5, 0xa0, 0x97, 0xaf, 0x8d, 0xb2, 0xf7, 0xdb, - 0x29, 0xed, 0x68, 0x6e, 0x3c, 0x0c, 0x51, 0xa9, 0x43, 0x12, 0xea, 0xab, - 0x2b, 0x3e, 0x7e, 0x77, 0x3f, 0xd9, 0xb4, 0xff, 0x30, 0xac, 0xe1, 0xb6, - 0x5e, 0x58, 0x01, 0x5a, 0x3f, 0xb2, 0x72, 0xec, 0x2f, 0x97, 0x8e, 0xe7, - 0xe3, 0x21, 0x72, 0x3e, 0xf2, 0xe9, 0xe4, 0xc9, 0xae, 0xef, 0x17, 0xcc, - 0x4c, 0x7e, 0x7c, 0xe6, 0xcf, 0xc5, 0xe9, 0xdd, 0x84, 0xc5, 0x62, 0x83, - 0xfd, 0xc5, 0xd7, 0x75, 0xcf, 0x8e, 0xab, 0xe7, 0x7a, 0x2a, 0xf9, 0xe7, - 0xb2, 0x0b, 0xbe, 0xe5, 0x32, 0xbb, 0x9d, 0x93, 0xed, 0xb3, 0xc2, 0xcf, - 0xef, 0x9d, 0x5f, 0xdd, 0x4e, 0xc1, 0x6d, 0xff, 0x91, 0x5e, 0x37, 0x1b, - 0xad, 0x3e, 0xb7, 0xd1, 0x55, 0x4f, 0xb6, 0xf9, 0x95, 0xdd, 0xfa, 0xd3, - 0xe6, 0x8a, 0x88, 0xed, 0x47, 0x56, 0x93, 0xec, 0x30, 0x3e, 0xfc, 0xb8, - 0xbb, 0xeb, 0xef, 0xe9, 0x71, 0xd9, 0x7f, 0x91, 0x1f, 0x13, 0x75, 0xf2, - 0xeb, 0x2a, 0xaa, 0x3d, 0xbc, 0x1a, 0x2f, 0x63, 0x38, 0xb4, 0xcd, 0x3e, - 0xfc, 0xf4, 0xdc, 0x8b, 0x34, 0xb6, 0x3a, 0xa3, 0x9f, 0x90, 0xa9, 0xf5, - 0x8f, 0x68, 0x7f, 0xf0, 0xcd, 0x50, 0x0f, 0x3f, 0xd7, 0xd1, 0xe9, 0xb9, - 0x5d, 0xf5, 0x29, 0xde, 0x92, 0xf3, 0xd6, 0xfc, 0x5e, 0x09, 0x32, 0x2c, - 0xa8, 0xbd, 0x6d, 0xde, 0x3e, 0x68, 0x32, 0xcd, 0xb9, 0x8a, 0x65, 0x7f, - 0xfa, 0xf0, 0x53, 0xea, 0x58, 0xeb, 0xef, 0xad, 0xfc, 0x4a, 0xf6, 0x85, - 0x11, 0x0f, 0xed, 0xf1, 0xf4, 0x70, 0x9c, 0x6b, 0x96, 0xd2, 0x0f, 0xaf, - 0x5b, 0x36, 0xb9, 0x69, 0xbc, 0x23, 0xe3, 0xf3, 0xdd, 0xc9, 0xc9, 0xbb, - 0xb5, 0x1f, 0x1f, 0x87, 0x9f, 0x54, 0x7a, 0xe6, 0x2b, 0xf9, 0xd6, 0x8a, - 0x8f, 0x0d, 0xfd, 0xa1, 0xff, 0xb4, 0x1f, 0x26, 0x58, 0xcc, 0x89, 0xa9, - 0xcd, 0x63, 0xb1, 0xe9, 0xce, 0xd9, 0xf8, 0xb6, 0xcf, 0x72, 0xbf, 0x7a, - 0xc1, 0xb9, 0x1e, 0x59, 0xfd, 0xe3, 0xd6, 0xad, 0xbe, 0x8e, 0x3f, 0x3f, - 0xf3, 0xf2, 0xd0, 0x6a, 0xde, 0xeb, 0x47, 0x65, 0x0d, 0xad, 0xbd, 0xae, - 0x7e, 0x28, 0x0e, 0x68, 0x2c, 0x4f, 0xe1, 0xf7, 0xd7, 0x35, 0xe0, 0x7d, - 0xe4, 0x1e, 0xf7, 0x9b, 0xad, 0xfb, 0x9d, 0xb8, 0x3f, 0x8b, 0x4f, 0x54, - 0x2e, 0xa3, 0xa6, 0x8d, 0x3f, 0xf8, 0xcb, 0xed, 0x32, 0xa4, 0xf0, 0x8d, - 0x8e, 0xa9, 0xb5, 0xb9, 0x68, 0xcd, 0xda, 0x4d, 0x7c, 0xf9, 0x3c, 0x65, - 0x97, 0x8f, 0x65, 0x8e, 0x7c, 0x23, 0xdf, 0x86, 0xd0, 0x9d, 0x55, 0xff, - 0x88, 0xef, 0x5f, 0xa8, 0x89, 0x9e, 0x64, 0xb8, 0xfb, 0x7d, 0xb1, 0x2b, - 0x2a, 0xb6, 0x44, 0x3a, 0x4b, 0xce, 0x3f, 0x83, 0xb2, 0xf3, 0x4a, 0x35, - 0xbd, 0xe3, 0x2b, 0x89, 0xcf, 0x3f, 0x6e, 0x81, 0xde, 0xa0, 0xd3, 0x40, - 0xd3, 0x7c, 0xba, 0xe8, 0x97, 0x9e, 0x91, 0xdd, 0xc6, 0xcd, 0x8b, 0xdd, - 0x23, 0x7c, 0x7c, 0xed, 0xf8, 0xae, 0xc3, 0x3f, 0x6e, 0x84, 0xa9, 0xf1, - 0xc4, 0xce, 0x76, 0x15, 0x6e, 0xbb, 0xf3, 0xc3, 0x7c, 0x0f, 0xcf, 0x91, - 0x5f, 0x86, 0x90, 0x3d, 0x86, 0x74, 0xa6, 0xd3, 0x0f, 0x96, 0x54, 0xd2, - 0xaf, 0xf2, 0x2f, 0xf7, 0xe5, 0xda, 0xbb, 0xa7, 0xde, 0xc4, 0xc7, 0x91, - 0x7c, 0x61, 0x7f, 0x7c, 0xd9, 0xea, 0xc3, 0xa1, 0xfc, 0x43, 0xfd, 0x7f, - 0x29, 0x3b, 0x8f, 0xed, 0x06, 0xd9, 0x2e, 0xcd, 0xde, 0x4a, 0xad, 0x1a, - 0x75, 0x2d, 0xba, 0x16, 0x39, 0x75, 0x8f, 0xc8, 0x39, 0x67, 0x66, 0x20, - 0x44, 0x46, 0xe4, 0x78, 0xf5, 0x8d, 0xff, 0xaf, 0x7a, 0x5c, 0xdd, 0x1e, - 0x48, 0x96, 0xbd, 0x8c, 0x11, 0x9c, 0xf3, 0x9c, 0xbd, 0x6d, 0xf4, 0xaa, - 0xf2, 0x7a, 0x24, 0x3b, 0xf2, 0x85, 0x97, 0xc0, 0x38, 0xd0, 0x9c, 0xe8, - 0x9b, 0xf4, 0x4d, 0x34, 0xbf, 0x63, 0x94, 0x54, 0x93, 0x05, 0x07, 0x35, - 0x96, 0x4b, 0x0d, 0x46, 0x2e, 0x6b, 0x49, 0x05, 0x9b, 0x46, 0x1b, 0x64, - 0x67, 0x39, 0x0f, 0x8b, 0x8c, 0xcb, 0x1e, 0x2e, 0x29, 0x93, 0x10, 0xb4, - 0x67, 0xcf, 0xdf, 0x39, 0x31, 0xba, 0xe5, 0x2c, 0xc7, 0x5b, 0xcd, 0x0b, - 0x2e, 0x87, 0xba, 0xac, 0xd2, 0xc4, 0xfc, 0x17, 0xd5, 0x6f, 0x1d, 0xa1, - 0x0f, 0x9f, 0x24, 0xbc, 0xa1, 0x54, 0xf9, 0x27, 0x73, 0xb7, 0x05, 0xa7, - 0xd3, 0x8e, 0x1c, 0x9a, 0xfc, 0xfb, 0xb8, 0x68, 0x2a, 0x5c, 0xa9, 0x4f, - 0x6e, 0x63, 0xf9, 0xb6, 0x35, 0xc7, 0x34, 0x82, 0x0d, 0x45, 0xb8, 0x9c, - 0x6f, 0x08, 0xb9, 0x4e, 0xe2, 0xd6, 0xcf, 0x50, 0x8e, 0xdb, 0xb6, 0xb1, - 0x87, 0xef, 0xef, 0x6b, 0x6a, 0x2e, 0xbe, 0x34, 0x95, 0x0f, 0x19, 0xb2, - 0x01, 0x31, 0x66, 0x65, 0xc5, 0x16, 0x39, 0x11, 0x0e, 0xcb, 0xb9, 0xbb, - 0xe5, 0x03, 0x18, 0x76, 0xd2, 0xd6, 0xcf, 0xb2, 0xd1, 0x24, 0x4e, 0xad, - 0x72, 0x4c, 0xb3, 0x1f, 0x1b, 0xad, 0x14, 0x16, 0x4b, 0xdd, 0xb1, 0x30, - 0xb9, 0x9f, 0x83, 0x73, 0xa2, 0xf2, 0xf2, 0xce, 0x03, 0xfc, 0x82, 0x5b, - 0x07, 0x32, 0xb2, 0x8b, 0x09, 0x34, 0xd5, 0xae, 0x9a, 0x3c, 0xd7, 0x03, - 0x79, 0xbb, 0x58, 0xe0, 0x04, 0xe5, 0xee, 0x67, 0x6d, 0x29, 0xd5, 0xc4, - 0xfa, 0xd1, 0xc8, 0xf1, 0xf9, 0x68, 0x71, 0xd5, 0xac, 0xad, 0xf6, 0x46, - 0x04, 0x97, 0x56, 0x55, 0x00, 0x6f, 0xbf, 0xd3, 0xd7, 0x6b, 0x86, 0x3f, - 0xbf, 0xf3, 0xcf, 0x66, 0xba, 0x70, 0xa1, 0xc3, 0x5e, 0x28, 0x82, 0x9f, - 0x98, 0xe7, 0x10, 0x61, 0x1a, 0x33, 0xf0, 0xe5, 0x9c, 0x73, 0x64, 0x55, - 0x62, 0x0b, 0x08, 0xb0, 0x23, 0x15, 0x7e, 0x9b, 0x17, 0x3a, 0xbf, 0x0d, - 0x0f, 0xa2, 0x0d, 0xa9, 0x33, 0x20, 0xff, 0xb3, 0xc7, 0x45, 0x53, 0x52, - 0x85, 0xff, 0x24, 0x89, 0x42, 0xb0, 0x09, 0x6d, 0xff, 0xb0, 0x08, 0x10, - 0xd7, 0xe3, 0xea, 0x85, 0x63, 0xce, 0xf2, 0xed, 0x52, 0x32, 0x51, 0xcf, - 0x48, 0x72, 0x01, 0xb1, 0x19, 0xc9, 0x61, 0x8c, 0x56, 0xe2, 0x21, 0x8b, - 0x40, 0xf6, 0x25, 0x15, 0x1f, 0x2a, 0xee, 0x80, 0xd3, 0xea, 0x91, 0x83, - 0x2e, 0x19, 0x0c, 0x11, 0xbd, 0x00, 0xd3, 0x28, 0x59, 0xdf, 0x20, 0xfb, - 0x6a, 0xfa, 0x7a, 0x4d, 0xa8, 0x1a, 0xb2, 0xae, 0x57, 0xc9, 0x00, 0xb2, - 0x1a, 0xd0, 0xf8, 0x78, 0xd7, 0xbd, 0xa9, 0x52, 0x8d, 0x13, 0xdc, 0xb7, - 0x26, 0x04, 0x49, 0x0d, 0x07, 0x42, 0xf7, 0xdf, 0x84, 0xf9, 0x64, 0xda, - 0x50, 0xc8, 0xdb, 0xf3, 0x96, 0xf8, 0x1e, 0x43, 0x8a, 0x8a, 0xd4, 0xbb, - 0x7a, 0x70, 0x7a, 0xde, 0x5d, 0x3c, 0xd4, 0x26, 0xcd, 0x43, 0x01, 0xd9, - 0x80, 0x15, 0x9f, 0xc2, 0x8a, 0x81, 0xde, 0x56, 0x05, 0xa7, 0x3a, 0x91, - 0x23, 0xcf, 0xf0, 0x6f, 0xf8, 0xa0, 0x97, 0xb4, 0x72, 0x35, 0x06, 0x8c, - 0xc5, 0xa3, 0x87, 0x57, 0x52, 0x17, 0x66, 0x9d, 0xf4, 0xa0, 0xa6, 0x46, - 0x74, 0xa3, 0x0c, 0x4b, 0xc6, 0x54, 0xd7, 0xd3, 0x5f, 0x39, 0x7e, 0xb2, - 0x28, 0x87, 0xbc, 0x2c, 0xdc, 0xa3, 0x70, 0x66, 0x47, 0x1a, 0xf3, 0xf7, - 0x8a, 0xf2, 0x59, 0xac, 0x67, 0x4e, 0xae, 0x09, 0x5d, 0x13, 0xc3, 0x67, - 0x9e, 0xd1, 0x38, 0x1c, 0xc5, 0xda, 0xdf, 0xbc, 0x32, 0x19, 0x98, 0xb2, - 0x84, 0x66, 0xd7, 0xc8, 0x8d, 0x79, 0x1f, 0xd1, 0xc2, 0x37, 0x1e, 0x35, - 0xd5, 0x37, 0xe4, 0x83, 0xbc, 0xa4, 0xd8, 0x63, 0xcc, 0xb5, 0x6d, 0x0d, - 0xf3, 0x98, 0x6d, 0x47, 0x0c, 0x3e, 0x5c, 0x3a, 0x8c, 0x8d, 0x28, 0x24, - 0x51, 0x7c, 0x5b, 0xc0, 0xeb, 0x6d, 0x1a, 0x27, 0x66, 0x4a, 0x41, 0x94, - 0x79, 0x86, 0xf4, 0xcb, 0x1f, 0x23, 0x11, 0xb7, 0xc7, 0xe9, 0x8e, 0x6b, - 0xef, 0x84, 0xbb, 0xd3, 0xbb, 0x89, 0xec, 0x10, 0xe6, 0x21, 0x55, 0x93, - 0xd5, 0x4b, 0x9e, 0x68, 0xaa, 0xb5, 0x15, 0x68, 0xdf, 0xcf, 0x8e, 0x4f, - 0xb0, 0x41, 0x47, 0xd0, 0xef, 0xe4, 0xb7, 0xca, 0x0e, 0x29, 0x16, 0xa6, - 0xa5, 0x45, 0x10, 0xfa, 0x05, 0x1b, 0x3f, 0x72, 0x62, 0x46, 0xc4, 0x13, - 0x9f, 0xfe, 0xb6, 0x71, 0x8e, 0xb9, 0x2c, 0x20, 0xc0, 0xed, 0xde, 0x11, - 0x4f, 0x25, 0x0c, 0xe4, 0xc7, 0xa1, 0x06, 0x0e, 0x7b, 0xdb, 0x72, 0xb5, - 0xe6, 0x89, 0x37, 0xc8, 0x98, 0x76, 0xf3, 0x18, 0x8f, 0xb9, 0xb4, 0xb0, - 0xca, 0xad, 0x17, 0xb0, 0x5f, 0x51, 0xc3, 0x2d, 0x9f, 0x6c, 0x18, 0xc0, - 0x36, 0x62, 0xa3, 0x3a, 0x39, 0xc1, 0x8a, 0xc9, 0xa4, 0x0a, 0x9f, 0xef, - 0x1d, 0x67, 0x1b, 0x7d, 0x95, 0x02, 0x17, 0x50, 0x40, 0x1d, 0xb5, 0x58, - 0x0e, 0x4d, 0xc9, 0x35, 0x4c, 0xa4, 0xa5, 0x7d, 0x6b, 0x9a, 0x2d, 0x0e, - 0x56, 0xf9, 0x66, 0x2e, 0xe0, 0x5b, 0xf2, 0xe7, 0x90, 0x5d, 0x66, 0xcc, - 0x90, 0xf3, 0xaa, 0x05, 0x56, 0x91, 0xbc, 0x52, 0x10, 0x9c, 0xaf, 0xea, - 0x4f, 0x5e, 0xbe, 0x19, 0xb0, 0x40, 0xf0, 0x7a, 0x5a, 0xb5, 0xb2, 0x76, - 0xf3, 0x8a, 0xbc, 0x29, 0x08, 0xfd, 0x6d, 0x80, 0x1e, 0xb6, 0xa7, 0x08, - 0x84, 0x57, 0x9c, 0x62, 0xfc, 0xfe, 0xb3, 0x1f, 0x5a, 0xf8, 0x54, 0x83, - 0x6d, 0x38, 0xd6, 0x46, 0xa5, 0xd3, 0x76, 0x58, 0x2a, 0xf6, 0x99, 0xb5, - 0xb4, 0xce, 0x51, 0xc2, 0xc4, 0x6f, 0x68, 0x84, 0x4d, 0x6a, 0x3f, 0xbe, - 0x1e, 0xf2, 0xdc, 0xd3, 0x14, 0x06, 0x99, 0x6f, 0x97, 0x8e, 0xb2, 0xa4, - 0xf5, 0x97, 0x31, 0xee, 0xdd, 0xd6, 0x96, 0x1d, 0xb8, 0xfa, 0x32, 0x0d, - 0xce, 0x2e, 0x9f, 0xe5, 0x2b, 0x48, 0x58, 0x41, 0xc1, 0x16, 0xee, 0x13, - 0x5f, 0x31, 0xd7, 0x81, 0xba, 0x80, 0x66, 0x9f, 0x15, 0x77, 0xb5, 0xa2, - 0x19, 0x46, 0x00, 0x89, 0x99, 0xb8, 0x1c, 0xb5, 0xbd, 0xb1, 0x7a, 0xe2, - 0x27, 0x81, 0x89, 0x53, 0x0f, 0xd0, 0x2e, 0x01, 0x47, 0x5c, 0x3c, 0x13, - 0x46, 0x13, 0x1b, 0x9f, 0x0b, 0x48, 0x46, 0xc8, 0x8a, 0xff, 0x4b, 0xd8, - 0xd3, 0x54, 0xc4, 0x97, 0x72, 0x89, 0x72, 0x0e, 0x3a, 0x97, 0xd9, 0x1d, - 0xe2, 0x0d, 0xca, 0xd0, 0x6c, 0xa8, 0x47, 0x24, 0x6e, 0x28, 0xec, 0x0d, - 0xf0, 0x68, 0x98, 0x2e, 0x23, 0x9d, 0x8c, 0x6a, 0x8d, 0x99, 0x19, 0x61, - 0x47, 0xe2, 0xe5, 0x1c, 0x8a, 0xc3, 0x44, 0xd1, 0xe4, 0x55, 0xae, 0xa3, - 0xfe, 0x7c, 0x3e, 0xdf, 0x51, 0x4f, 0xc9, 0xde, 0xcf, 0x6c, 0x34, 0x7c, - 0x67, 0x1f, 0xae, 0x02, 0xc6, 0xca, 0x12, 0x78, 0x2f, 0x72, 0xc0, 0xd7, - 0x89, 0xb4, 0x79, 0x7f, 0x74, 0xab, 0x9f, 0xec, 0xc2, 0x81, 0xa6, 0x41, - 0x47, 0x73, 0x4e, 0xf3, 0xfd, 0x1a, 0xf6, 0x2a, 0xbd, 0x12, 0x5d, 0xaa, - 0x66, 0x21, 0x80, 0xa7, 0xb3, 0x0f, 0x7a, 0xb7, 0x70, 0xcb, 0xf2, 0x85, - 0x40, 0x59, 0xcb, 0xc4, 0xf5, 0xd5, 0xdc, 0x8b, 0x2b, 0x57, 0xdc, 0xc4, - 0x94, 0x10, 0x31, 0x40, 0x25, 0xba, 0xcf, 0x7e, 0x00, 0xf3, 0xe6, 0x12, - 0x9b, 0x10, 0xa7, 0x31, 0xfd, 0x98, 0x6d, 0x6a, 0x46, 0x84, 0x1a, 0x2d, - 0xcb, 0xf3, 0xa5, 0x4b, 0x38, 0x45, 0xa9, 0x1e, 0x71, 0x81, 0xec, 0xc5, - 0x9a, 0x5c, 0xaf, 0x39, 0x13, 0xd6, 0xdd, 0x22, 0xf9, 0x68, 0x54, 0xc9, - 0xff, 0x60, 0x57, 0x10, 0x59, 0x74, 0x4c, 0x20, 0xae, 0xc7, 0x87, 0x22, - 0x6c, 0x7a, 0xa7, 0xdb, 0xb5, 0x7c, 0x7c, 0xa6, 0x0c, 0x69, 0x45, 0x1f, - 0x66, 0xc1, 0xb9, 0x93, 0x8a, 0xa0, 0x00, 0x85, 0x6e, 0x4f, 0x03, 0x33, - 0x71, 0xc8, 0xf8, 0x6c, 0xdd, 0x4c, 0xcd, 0x64, 0xf2, 0xd6, 0x02, 0xbb, - 0x74, 0xb9, 0x41, 0x10, 0xac, 0xf2, 0x57, 0x89, 0x84, 0x71, 0xbc, 0x2c, - 0x64, 0x37, 0x8d, 0xb7, 0x54, 0xfe, 0x3d, 0x1c, 0x8a, 0x59, 0x8e, 0x6e, - 0xea, 0x79, 0x5c, 0x39, 0xea, 0x27, 0xeb, 0x49, 0x88, 0xae, 0xc8, 0x5f, - 0x9c, 0xf9, 0xe2, 0xb6, 0x61, 0xcf, 0x62, 0xda, 0xd8, 0xd3, 0x68, 0x45, - 0xca, 0x1c, 0x09, 0x71, 0x5a, 0x46, 0x12, 0xce, 0xa1, 0x72, 0x76, 0x64, - 0xa0, 0xe0, 0x15, 0x01, 0x1d, 0xf3, 0x77, 0xc3, 0x75, 0x0a, 0x60, 0x83, - 0x9b, 0xf0, 0xd0, 0x5f, 0x59, 0x72, 0x2b, 0xbf, 0x7e, 0x21, 0xfa, 0x60, - 0xaa, 0x5d, 0x70, 0x0c, 0xe6, 0xb7, 0x88, 0x31, 0x39, 0x2a, 0xb6, 0x95, - 0x04, 0xb5, 0x5d, 0x02, 0xf3, 0x8e, 0x89, 0xf6, 0x77, 0xef, 0x4a, 0xe4, - 0x6b, 0xac, 0x3c, 0xc4, 0xf7, 0x1c, 0xf2, 0x05, 0xe7, 0x29, 0xaa, 0xbc, - 0xbc, 0x44, 0x39, 0x2a, 0x9f, 0xf0, 0x3c, 0xf0, 0xc1, 0x4d, 0x31, 0xf8, - 0x35, 0xf3, 0x4f, 0x6d, 0x20, 0xda, 0xc3, 0x71, 0xbf, 0x4e, 0xd8, 0x51, - 0x5e, 0x3f, 0xbf, 0x50, 0xec, 0x87, 0x23, 0x2d, 0x70, 0x0d, 0x15, 0xd1, - 0xce, 0xeb, 0xbf, 0xd6, 0xcf, 0x72, 0x8e, 0x4d, 0xd6, 0x77, 0x23, 0x87, - 0x5a, 0xd3, 0x9e, 0x80, 0xe7, 0x31, 0xb2, 0xf3, 0x39, 0xe2, 0x8d, 0x4f, - 0x28, 0xa9, 0xfc, 0xd2, 0x24, 0xc9, 0xb3, 0xe7, 0xaf, 0x95, 0x09, 0x55, - 0xb3, 0xb7, 0x53, 0x8b, 0x46, 0x1b, 0xfe, 0xa9, 0x61, 0x46, 0xc2, 0x6a, - 0x64, 0xf8, 0x24, 0x43, 0xb6, 0x90, 0x6b, 0x98, 0xd6, 0x16, 0xf6, 0x68, - 0x7a, 0x4f, 0x3c, 0xc5, 0x91, 0x79, 0x57, 0x12, 0x42, 0x2c, 0xe9, 0x4e, - 0x6b, 0xb3, 0x24, 0xe7, 0xc7, 0x6b, 0xc3, 0x64, 0x51, 0x58, 0xa1, 0xdb, - 0x11, 0x4c, 0x77, 0x47, 0x42, 0xdd, 0xfd, 0xb4, 0xa2, 0xf7, 0x05, 0x1a, - 0xc8, 0xf6, 0x7e, 0x86, 0x7a, 0x7c, 0xa8, 0x2a, 0x24, 0x7c, 0x7b, 0xf2, - 0x83, 0xb8, 0x5e, 0x7a, 0x72, 0x10, 0x24, 0x8a, 0xc7, 0x64, 0x81, 0x19, - 0x7e, 0xc6, 0xc7, 0x3b, 0x76, 0x63, 0x1e, 0x26, 0x10, 0xd4, 0x81, 0x4d, - 0x2b, 0x59, 0xd0, 0x24, 0x3d, 0xc0, 0xdf, 0x8e, 0x99, 0xca, 0x2a, 0x03, - 0xc0, 0x75, 0x9c, 0xb9, 0xab, 0x0d, 0x55, 0x06, 0x84, 0xcf, 0x52, 0x1a, - 0xfa, 0xfb, 0x7f, 0x5c, 0xb9, 0xe2, 0xc4, 0xdb, 0x11, 0x14, 0xc7, 0x9e, - 0x72, 0xf8, 0xf5, 0x5b, 0xf8, 0x77, 0xf1, 0x20, 0x45, 0x7c, 0x6c, 0x87, - 0x50, 0x40, 0x9d, 0xe6, 0xfa, 0xd9, 0x12, 0xf9, 0xf0, 0x01, 0x79, 0xe1, - 0x2e, 0x7a, 0x95, 0x12, 0xb6, 0x17, 0x26, 0xbe, 0xd1, 0x9e, 0x5a, 0x5d, - 0x92, 0x78, 0xb2, 0x35, 0xea, 0xa2, 0xa4, 0xde, 0x87, 0x16, 0x13, 0x4f, - 0x0a, 0x6b, 0x5e, 0xc1, 0x4b, 0x02, 0x7f, 0x7c, 0xe6, 0x8c, 0xd3, 0x53, - 0x7b, 0x21, 0xd5, 0x51, 0x86, 0x02, 0xff, 0xb7, 0x23, 0x31, 0x98, 0x11, - 0x08, 0x02, 0x24, 0x09, 0xf1, 0x49, 0xd1, 0xe0, 0x3a, 0xe5, 0x0d, 0x8a, - 0x56, 0x86, 0xf8, 0xa6, 0xa3, 0x89, 0x86, 0x82, 0x39, 0x15, 0xc3, 0x42, - 0xf1, 0x6c, 0xee, 0x26, 0x41, 0x58, 0xd8, 0x5a, 0xfb, 0x93, 0xb3, 0xee, - 0xf9, 0xdc, 0x07, 0x77, 0xaf, 0xb3, 0x04, 0xec, 0x37, 0xe9, 0xe1, 0xb8, - 0x6d, 0x81, 0x0a, 0xcb, 0x47, 0x1d, 0xac, 0xda, 0x5e, 0x46, 0xab, 0x10, - 0xc5, 0x30, 0x7d, 0xbe, 0x61, 0x56, 0x9b, 0x4e, 0x9f, 0xa9, 0xee, 0xbb, - 0x69, 0xc3, 0x43, 0x14, 0x2e, 0x5c, 0x17, 0x2a, 0xf2, 0x02, 0x0b, 0x82, - 0x2b, 0x62, 0xea, 0xb9, 0xd1, 0x07, 0x12, 0x7f, 0x67, 0x94, 0xa5, 0x97, - 0x2d, 0x56, 0x99, 0x50, 0x01, 0xb6, 0xb8, 0xc2, 0xdf, 0xf1, 0xb0, 0xc7, - 0xd4, 0x19, 0xc7, 0x1c, 0x0e, 0x2d, 0x4b, 0xc4, 0xce, 0x3f, 0x3f, 0xec, - 0x7f, 0xb6, 0x6c, 0xbb, 0x36, 0xf2, 0x6b, 0xb5, 0xc2, 0x6b, 0x8b, 0x2c, - 0xc3, 0x0c, 0x99, 0x71, 0x52, 0x0e, 0x75, 0xf2, 0x19, 0x99, 0x35, 0x9b, - 0xd8, 0x8f, 0x82, 0x48, 0x1b, 0x73, 0x1b, 0x67, 0xad, 0xc5, 0x27, 0x99, - 0x51, 0x20, 0x36, 0x90, 0xbe, 0x11, 0x3d, 0x35, 0xad, 0xf6, 0x25, 0xbf, - 0x07, 0x08, 0xec, 0xfb, 0xc9, 0xc4, 0x47, 0x9d, 0x91, 0xe6, 0x93, 0x6e, - 0x20, 0xa5, 0x66, 0x73, 0x15, 0xe9, 0xce, 0xf5, 0xa2, 0xc0, 0xb9, 0x46, - 0x92, 0x47, 0xff, 0xfd, 0x07, 0x6c, 0x40, 0x5d, 0x50, 0xe4, 0x72, 0x5b, - 0x6f, 0x6a, 0x23, 0x10, 0x6d, 0xba, 0xb9, 0x39, 0xdc, 0xd0, 0x51, 0x5a, - 0x66, 0x25, 0xb6, 0xe1, 0x8d, 0x29, 0x56, 0x97, 0xe6, 0x97, 0xd4, 0x5d, - 0x3e, 0x34, 0x30, 0x29, 0x78, 0x46, 0x4a, 0x0c, 0xc9, 0x09, 0x99, 0xa9, - 0x24, 0x2a, 0x74, 0x93, 0x13, 0x17, 0x06, 0xf6, 0xe5, 0xdf, 0x3a, 0xd3, - 0x56, 0x95, 0xcb, 0x1d, 0xd0, 0x6f, 0x1c, 0x7a, 0x85, 0xfc, 0xbe, 0x13, - 0x39, 0x67, 0xdb, 0x6e, 0xfb, 0xe5, 0x3f, 0xbe, 0x9f, 0x96, 0x4f, 0x5a, - 0x80, 0x49, 0xa7, 0x04, 0x26, 0x07, 0xaf, 0x16, 0xbd, 0xf8, 0x50, 0xc2, - 0x75, 0x1d, 0x43, 0x57, 0xa2, 0x5a, 0x88, 0x18, 0x6d, 0x4b, 0x07, 0x6a, - 0x71, 0xa3, 0x9b, 0xbb, 0xfc, 0xd5, 0x00, 0xf9, 0x47, 0x55, 0xe9, 0x6c, - 0x25, 0x6c, 0x5c, 0x55, 0x42, 0x16, 0x6b, 0x26, 0xd7, 0xc5, 0x63, 0x3e, - 0x3b, 0xe9, 0xf8, 0x9a, 0x0f, 0xa1, 0xf9, 0xac, 0x28, 0xea, 0xbd, 0x34, - 0x16, 0x05, 0xe8, 0x86, 0x3f, 0x28, 0x79, 0x49, 0x4a, 0x96, 0xb3, 0x16, - 0x69, 0xb8, 0xe2, 0x24, 0xb6, 0xfb, 0x21, 0x61, 0x8b, 0x1f, 0x84, 0x9f, - 0x3f, 0xca, 0x79, 0x22, 0x68, 0x10, 0x90, 0x86, 0xa7, 0xf9, 0x58, 0x05, - 0xea, 0xa2, 0xb5, 0x16, 0xb8, 0x30, 0xe7, 0x22, 0x4f, 0xce, 0xfd, 0x7b, - 0x6c, 0x45, 0xc2, 0x0b, 0x84, 0x31, 0x44, 0x9c, 0x20, 0x7c, 0x69, 0x0f, - 0x67, 0x4d, 0x29, 0x45, 0xad, 0x49, 0x94, 0x9c, 0xa2, 0x08, 0x48, 0xc5, - 0x73, 0xd3, 0x2c, 0xa0, 0x6f, 0x21, 0xbb, 0x8b, 0xd7, 0x74, 0x78, 0x84, - 0x37, 0x28, 0xb4, 0x69, 0xa5, 0x67, 0x38, 0xba, 0xc4, 0x82, 0xf3, 0xb3, - 0xf8, 0xe5, 0x67, 0xf0, 0x10, 0x98, 0xa6, 0x2b, 0xdd, 0x31, 0xd8, 0x0f, - 0x4a, 0x7d, 0xaa, 0x84, 0xf5, 0x69, 0xfd, 0xee, 0x8b, 0x28, 0xc2, 0xe3, - 0xb7, 0x01, 0x1b, 0x72, 0x90, 0x3f, 0x3e, 0x67, 0xb7, 0x22, 0x43, 0xa1, - 0x06, 0x21, 0xa0, 0x1b, 0xea, 0x0d, 0xd2, 0xe6, 0xf6, 0x4e, 0x81, 0x7d, - 0x6c, 0xea, 0x23, 0x7d, 0x3c, 0xbe, 0x58, 0x9c, 0x4d, 0x73, 0xcb, 0x28, - 0xa2, 0xde, 0xaa, 0x89, 0xbb, 0x0e, 0xdd, 0x1e, 0x03, 0x73, 0xe0, 0x2a, - 0x51, 0x45, 0x51, 0x98, 0xf0, 0xe1, 0x4d, 0x19, 0x35, 0x4e, 0x74, 0xe9, - 0x3e, 0xfb, 0x48, 0x2f, 0xf6, 0x19, 0xce, 0xf5, 0x0f, 0x1e, 0x1c, 0x4f, - 0xc3, 0xde, 0x77, 0x18, 0x36, 0x79, 0xb7, 0x1d, 0xd5, 0x24, 0x5e, 0x49, - 0x0a, 0x86, 0x81, 0x1a, 0x98, 0x5f, 0xbe, 0x1d, 0xe6, 0xa2, 0xb4, 0x6e, - 0xcf, 0x31, 0x9c, 0x03, 0x9c, 0x09, 0x9c, 0x08, 0x6c, 0xf8, 0xc0, 0x03, - 0x04, 0x6e, 0x49, 0x7c, 0x2a, 0x33, 0xca, 0x25, 0x4f, 0x09, 0x88, 0xd4, - 0x8c, 0xee, 0x52, 0x9e, 0x52, 0xf6, 0x55, 0x2e, 0x2f, 0xb7, 0x90, 0xa8, - 0x5a, 0x4c, 0x73, 0x4c, 0xa0, 0xd4, 0x41, 0x02, 0x0d, 0x58, 0x24, 0x76, - 0x17, 0x24, 0x01, 0x14, 0xdc, 0xe7, 0x00, 0xbe, 0x73, 0x18, 0x72, 0xf9, - 0x9f, 0x18, 0x8a, 0x51, 0x28, 0x9c, 0x0a, 0xe3, 0x55, 0xbf, 0xe0, 0x75, - 0x46, 0xca, 0xcd, 0xdf, 0x3e, 0xdb, 0x3c, 0xc6, 0xa7, 0xf0, 0xd1, 0x4d, - 0x5e, 0x09, 0xdb, 0xa7, 0x5d, 0xc4, 0xaf, 0xdf, 0x08, 0x17, 0x05, 0x7d, - 0xc7, 0x40, 0x9c, 0x90, 0xa4, 0xc9, 0x21, 0xda, 0xf7, 0x57, 0x90, 0x23, - 0x75, 0x58, 0x52, 0x07, 0xe1, 0x70, 0xd3, 0x02, 0x6c, 0x7d, 0x54, 0x67, - 0xc1, 0x05, 0x87, 0xf6, 0x28, 0x65, 0xd4, 0x32, 0xcb, 0xd9, 0xd6, 0xc2, - 0x59, 0x1e, 0xdf, 0x25, 0x87, 0xf3, 0x3c, 0x2c, 0x37, 0x90, 0x29, 0xe0, - 0xd1, 0x87, 0x75, 0xfb, 0xc9, 0x47, 0x91, 0xa4, 0xc8, 0x8c, 0xe8, 0x4b, - 0x55, 0x20, 0x39, 0x31, 0x84, 0x81, 0x6d, 0x15, 0xe7, 0x96, 0xeb, 0x09, - 0xfa, 0xf2, 0x08, 0x3d, 0x27, 0x06, 0xf4, 0x89, 0xb1, 0xe5, 0x23, 0x5b, - 0x0f, 0x97, 0x23, 0xe4, 0xf0, 0xfb, 0x38, 0x1c, 0x64, 0x7e, 0x0e, 0x0b, - 0x52, 0xea, 0xc7, 0xf4, 0x53, 0xcb, 0x64, 0x2d, 0xbb, 0x0a, 0x8a, 0xfb, - 0xfb, 0xa5, 0x61, 0x42, 0xac, 0xf6, 0xc8, 0xf1, 0xda, 0xce, 0x72, 0x3f, - 0x21, 0xa9, 0x1f, 0x4c, 0x9c, 0x07, 0xb8, 0x7a, 0x49, 0xbf, 0x4f, 0x52, - 0xeb, 0xba, 0xe9, 0xbb, 0x63, 0xe6, 0x18, 0x7d, 0xb9, 0xdb, 0x89, 0x48, - 0x1a, 0x0d, 0x22, 0x7d, 0xab, 0xc2, 0x9f, 0xe9, 0x43, 0x93, 0x82, 0x13, - 0x41, 0xa5, 0x48, 0xf9, 0xd2, 0x00, 0xc7, 0x2e, 0xc9, 0xf3, 0x8c, 0x36, - 0x75, 0x13, 0xa5, 0x1c, 0x08, 0xe7, 0xd6, 0xcb, 0x91, 0xf6, 0x98, 0x5f, - 0x75, 0xa7, 0x62, 0x3a, 0x35, 0x31, 0x8b, 0xff, 0xe3, 0xe7, 0x08, 0x03, - 0xe9, 0x08, 0xad, 0x6d, 0xa6, 0xa4, 0x05, 0xc8, 0x3c, 0x06, 0x80, 0xb0, - 0xcc, 0x06, 0xe9, 0x82, 0x99, 0x3e, 0xcd, 0x89, 0xe3, 0xde, 0x19, 0xde, - 0x40, 0xdc, 0x56, 0xc4, 0xed, 0x22, 0xaa, 0xca, 0x61, 0xc4, 0x2e, 0xa0, - 0x9e, 0xfe, 0xc1, 0x0f, 0x13, 0x60, 0xd5, 0xa9, 0xdd, 0x12, 0x50, 0xaf, - 0xdb, 0xcc, 0x64, 0xe2, 0x62, 0x8a, 0x5c, 0x55, 0x27, 0x9d, 0x02, 0x74, - 0x98, 0xc6, 0x5d, 0x63, 0x33, 0x75, 0xa6, 0x4f, 0xe6, 0x54, 0x36, 0x00, - 0xa0, 0xaf, 0x83, 0x7c, 0xc3, 0xa0, 0x38, 0xf1, 0x0f, 0x38, 0xb2, 0x5b, - 0x11, 0x1e, 0x6c, 0x01, 0xc5, 0x5d, 0x6c, 0x4b, 0x2f, 0x51, 0x48, 0xfb, - 0x5a, 0x75, 0xce, 0x4a, 0x7c, 0xe6, 0xea, 0xb3, 0x9c, 0x29, 0x24, 0xa8, - 0xa1, 0xff, 0x2b, 0x2a, 0x15, 0xf3, 0x85, 0x4c, 0xaa, 0x32, 0x8c, 0x7b, - 0x7f, 0x26, 0xdf, 0x17, 0x0c, 0x84, 0x89, 0x0d, 0x78, 0x1b, 0x0e, 0xa5, - 0xe3, 0x18, 0x56, 0xc2, 0xb8, 0xe1, 0x33, 0x5d, 0xd8, 0x18, 0xf0, 0x98, - 0xf6, 0x1f, 0xb9, 0xff, 0x8e, 0xe0, 0x02, 0xae, 0x77, 0xdc, 0x7e, 0x53, - 0x3a, 0x41, 0xaa, 0x03, 0x7a, 0x47, 0x36, 0xf3, 0x35, 0xac, 0xb5, 0xf8, - 0xa0, 0x9f, 0x77, 0x76, 0xf8, 0x73, 0x4c, 0x50, 0x23, 0xdb, 0x12, 0x46, - 0x98, 0xc0, 0x27, 0xd2, 0x89, 0xab, 0x4e, 0x02, 0xf2, 0xe6, 0x13, 0xd4, - 0x50, 0xe3, 0xb6, 0x97, 0x8e, 0x46, 0xa0, 0x00, 0x21, 0x78, 0x53, 0xe9, - 0x78, 0x69, 0xa8, 0x78, 0xfa, 0xcc, 0x8e, 0x9a, 0x53, 0x84, 0xe0, 0xad, - 0xba, 0xad, 0xec, 0xad, 0x8a, 0xe4, 0x92, 0x23, 0x38, 0x6d, 0x8d, 0x65, - 0xf7, 0x1a, 0x6c, 0x40, 0x74, 0x26, 0xc9, 0xac, 0xdf, 0xe1, 0x27, 0x71, - 0xd7, 0x74, 0xf7, 0x2b, 0xbf, 0x07, 0x58, 0x83, 0x22, 0x1f, 0xa6, 0xcf, - 0x68, 0x6a, 0xe8, 0x4e, 0xf3, 0xae, 0x9a, 0xb3, 0x45, 0xa5, 0x6a, 0x45, - 0xdc, 0x73, 0x45, 0xe8, 0xeb, 0xa7, 0xbe, 0x76, 0x7a, 0x65, 0xd9, 0x57, - 0x4a, 0xc2, 0xd3, 0xc8, 0x5d, 0x22, 0x39, 0x17, 0x23, 0x80, 0xce, 0x54, - 0xa8, 0xd2, 0x6b, 0xe0, 0x02, 0xc6, 0x4c, 0x4d, 0x48, 0x14, 0xea, 0x08, - 0xb9, 0x6b, 0x19, 0xe2, 0xd4, 0x9f, 0xee, 0x43, 0xcb, 0x5c, 0xad, 0xcb, - 0x77, 0x48, 0xd9, 0x45, 0xd9, 0x4d, 0xd3, 0xb1, 0xbf, 0x89, 0xc6, 0xf2, - 0x63, 0xbb, 0x70, 0x6b, 0xbe, 0xbf, 0xd4, 0x5f, 0xb5, 0x3f, 0xa6, 0x1c, - 0x1a, 0x3a, 0xba, 0x8b, 0x51, 0x0f, 0x09, 0x34, 0xd5, 0x4b, 0x79, 0x47, - 0xdc, 0x98, 0x2a, 0x97, 0x00, 0xcd, 0xd0, 0x78, 0xbf, 0xba, 0x8f, 0x8d, - 0x90, 0x26, 0xd6, 0x59, 0xec, 0xa8, 0x99, 0xb5, 0x88, 0x11, 0x36, 0x93, - 0x79, 0x31, 0xaa, 0xeb, 0xfa, 0xb1, 0x5a, 0xe7, 0xde, 0xa1, 0x83, 0xd1, - 0x33, 0x60, 0x7a, 0x20, 0xde, 0x2f, 0x24, 0x3f, 0x06, 0x83, 0x15, 0x9d, - 0x7a, 0xa2, 0xfb, 0xb9, 0xe0, 0x04, 0xcb, 0x51, 0xb1, 0xbf, 0x03, 0xc7, - 0x76, 0xe5, 0xc7, 0x20, 0x72, 0xeb, 0x09, 0x4b, 0x35, 0x58, 0xb7, 0xfb, - 0x37, 0x71, 0xa8, 0x4f, 0x62, 0x1e, 0x16, 0x97, 0x3c, 0xe0, 0x43, 0x64, - 0x48, 0x5e, 0xbe, 0x31, 0x08, 0x5c, 0xbf, 0xa0, 0x81, 0xd4, 0x33, 0xde, - 0x59, 0x82, 0xc9, 0xab, 0x8d, 0xa2, 0x7f, 0xbf, 0x6a, 0x90, 0x78, 0x80, - 0x8f, 0x34, 0xc5, 0xff, 0x42, 0xc8, 0xf3, 0xf1, 0xa4, 0x8b, 0x80, 0x4a, - 0x18, 0xc1, 0x51, 0x16, 0x2d, 0x17, 0xfb, 0x37, 0xc9, 0xc8, 0x73, 0x38, - 0xf3, 0xf9, 0xf7, 0xaa, 0x43, 0xf1, 0x57, 0x12, 0xe0, 0x8e, 0x26, 0x00, - 0xd3, 0x2a, 0x0d, 0x25, 0x9f, 0x22, 0xd0, 0xde, 0x56, 0x69, 0x3a, 0x39, - 0x2d, 0x95, 0x7e, 0xe1, 0x34, 0xd4, 0xe7, 0xdb, 0x42, 0x0a, 0xde, 0x15, - 0x9e, 0xe0, 0x31, 0xb6, 0x86, 0x7f, 0x63, 0x16, 0xf3, 0xd5, 0x74, 0x7f, - 0x35, 0x30, 0x9e, 0x60, 0x1e, 0xab, 0x6b, 0x8a, 0xc7, 0x57, 0x98, 0xe8, - 0x49, 0x96, 0x02, 0x57, 0x27, 0x12, 0xb8, 0xc7, 0x0a, 0xed, 0x92, 0xb8, - 0x89, 0x80, 0xdc, 0x7a, 0x8b, 0xd7, 0x6f, 0xca, 0x6e, 0x8b, 0x50, 0x1e, - 0x50, 0xd9, 0xbb, 0x3f, 0x33, 0x3b, 0x4c, 0x52, 0x8a, 0x51, 0x05, 0x5d, - 0x7f, 0x80, 0x43, 0xf0, 0x7f, 0x02, 0xc2, 0xc6, 0xe0, 0x23, 0x33, 0x00, - 0x7c, 0xc5, 0x31, 0x5b, 0x7d, 0x0d, 0x1e, 0xf2, 0xf1, 0x46, 0xc8, 0x9d, - 0xd3, 0xf0, 0x7d, 0x14, 0x59, 0xdd, 0x59, 0xb1, 0x63, 0xfc, 0xc0, 0x0f, - 0x2c, 0x1a, 0x5c, 0x1f, 0x62, 0x9f, 0x00, 0x93, 0x0e, 0xc7, 0xf8, 0x79, - 0xf0, 0x64, 0xbe, 0x9e, 0x38, 0x7d, 0xa0, 0x87, 0xfc, 0x62, 0xda, 0x74, - 0x75, 0xd1, 0x8b, 0x6a, 0xed, 0x18, 0xef, 0x21, 0x87, 0x36, 0x05, 0xd0, - 0x60, 0x01, 0x2a, 0x2c, 0x30, 0xc7, 0xb8, 0x16, 0x82, 0x2f, 0xc9, 0x51, - 0xfd, 0x5d, 0x16, 0x7b, 0x05, 0x9c, 0xa2, 0x0b, 0xb1, 0xcc, 0xf5, 0x47, - 0xab, 0x8a, 0xc6, 0x12, 0x27, 0x81, 0xcf, 0x4e, 0x3b, 0x9a, 0xd7, 0xc6, - 0xf2, 0x6d, 0x03, 0x6b, 0x0c, 0xb9, 0xd3, 0xf4, 0xe6, 0xa8, 0xa2, 0x7e, - 0xa2, 0xdb, 0xa0, 0x18, 0x52, 0x9d, 0x00, 0x38, 0x46, 0xa6, 0x47, 0x24, - 0xd1, 0x4f, 0x1e, 0x78, 0x4e, 0xaa, 0xee, 0x73, 0xb5, 0xe9, 0xdf, 0x47, - 0x14, 0x57, 0x63, 0x05, 0x18, 0x1a, 0x85, 0xee, 0xf8, 0x0b, 0x44, 0xbf, - 0xc3, 0x46, 0x26, 0x3b, 0xde, 0x01, 0xde, 0xba, 0x93, 0x1d, 0x94, 0xd0, - 0x90, 0x4f, 0x25, 0x57, 0xeb, 0x42, 0x57, 0x47, 0x3d, 0xfc, 0x83, 0x5f, - 0xf4, 0x3a, 0x0a, 0xec, 0x6c, 0xd5, 0x4f, 0xc8, 0x4e, 0x8a, 0x82, 0xc0, - 0xfc, 0x3b, 0x96, 0x7a, 0x57, 0x43, 0xc2, 0x57, 0xde, 0xd2, 0xed, 0x22, - 0xdb, 0xfc, 0x03, 0xc7, 0x8a, 0x4f, 0x62, 0x4e, 0x96, 0xa4, 0x73, 0x9e, - 0x48, 0x7c, 0x1e, 0x49, 0xa5, 0x19, 0x19, 0x9c, 0x75, 0x46, 0x1a, 0x4d, - 0x0c, 0xd7, 0xe5, 0xe0, 0xd3, 0x67, 0xe3, 0x36, 0x43, 0xa2, 0x61, 0x66, - 0x64, 0xa9, 0xe2, 0xbc, 0xa0, 0x92, 0x53, 0xa0, 0xd8, 0x76, 0x57, 0x6e, - 0x02, 0x17, 0xe7, 0xc9, 0x03, 0x88, 0xac, 0x36, 0xb3, 0x4c, 0xc3, 0xf4, - 0x55, 0x32, 0xac, 0x29, 0x50, 0x2a, 0xfc, 0xe8, 0x77, 0x97, 0x3f, 0xf9, - 0xa4, 0x03, 0xf1, 0x86, 0x1e, 0xf1, 0x4d, 0xeb, 0xb9, 0xb2, 0xed, 0xbf, - 0x93, 0xb6, 0x48, 0x85, 0x1c, 0xba, 0x4a, 0x5b, 0x18, 0x45, 0xf7, 0xf8, - 0xf6, 0x87, 0xb6, 0x5a, 0x1b, 0xb7, 0xb7, 0x3f, 0x44, 0xb3, 0xc9, 0x72, - 0x21, 0xbb, 0xc5, 0xec, 0x85, 0x93, 0x63, 0xfb, 0x2b, 0xe2, 0x0d, 0x69, - 0xa9, 0xd3, 0xde, 0xa4, 0x90, 0xed, 0xc3, 0x58, 0x39, 0x47, 0x05, 0x61, - 0x60, 0x63, 0xa1, 0xc1, 0x72, 0xa0, 0x62, 0x32, 0xea, 0x04, 0x42, 0x8c, - 0x83, 0xe9, 0xe2, 0x67, 0x03, 0x46, 0x6d, 0x72, 0x39, 0x22, 0x86, 0xdf, - 0x7e, 0x1d, 0xf5, 0x1b, 0x93, 0xef, 0x02, 0xe5, 0xac, 0x7f, 0x2e, 0x3f, - 0x5d, 0x51, 0xca, 0x45, 0x4d, 0xd3, 0x5a, 0xf5, 0x4a, 0x8f, 0xde, 0x71, - 0x6c, 0x54, 0xaa, 0x71, 0x4a, 0xfd, 0x26, 0xb6, 0xca, 0xe7, 0x73, 0xd5, - 0x5d, 0x35, 0xa2, 0x93, 0x71, 0xd9, 0x8a, 0x93, 0xf0, 0xa9, 0x81, 0xe8, - 0x0b, 0x66, 0xb6, 0x47, 0x63, 0xdf, 0x21, 0xc0, 0x6c, 0x13, 0x8f, 0x29, - 0xe5, 0x17, 0x0b, 0xad, 0x0a, 0x30, 0xd3, 0xe0, 0xf3, 0xc8, 0xb3, 0x2c, - 0xb1, 0xb7, 0x88, 0xb9, 0xf0, 0xa0, 0x00, 0x22, 0x8d, 0x91, 0xa2, 0x6d, - 0x41, 0xea, 0x87, 0x5e, 0x42, 0x49, 0x01, 0xc8, 0xac, 0xb7, 0xf6, 0x49, - 0x5f, 0x71, 0xb1, 0x49, 0x37, 0x04, 0xea, 0x11, 0xce, 0x3f, 0xa9, 0x5f, - 0x27, 0x57, 0xca, 0x0e, 0x26, 0xe1, 0xe1, 0x36, 0x8f, 0x89, 0x44, 0xa6, - 0xf6, 0xfd, 0xf8, 0xa5, 0x24, 0xac, 0x00, 0x71, 0x99, 0xdf, 0x70, 0x9f, - 0x17, 0xd4, 0x59, 0xe3, 0xbf, 0x77, 0x57, 0x07, 0x30, 0xcc, 0x8c, 0x54, - 0x5c, 0xc6, 0xf1, 0x02, 0x2b, 0xa7, 0x48, 0xce, 0x35, 0xfa, 0x68, 0x95, - 0x7a, 0xb7, 0x07, 0x78, 0x9b, 0xae, 0xcf, 0xf3, 0xc8, 0xe8, 0xa9, 0x51, - 0xe6, 0x9e, 0x31, 0x56, 0xfa, 0x3a, 0x1a, 0xd7, 0xc6, 0x7c, 0x5d, 0x76, - 0x79, 0x7f, 0xee, 0xeb, 0xa7, 0x4b, 0xde, 0x13, 0x58, 0xac, 0x14, 0xf8, - 0x19, 0x4c, 0x6e, 0xe1, 0xc6, 0x74, 0x66, 0xd1, 0x8f, 0x58, 0xe4, 0x7d, - 0xf3, 0x8a, 0xed, 0xb7, 0xfb, 0x32, 0xe4, 0x3d, 0x4c, 0x61, 0x24, 0xcf, - 0x87, 0x9e, 0x0e, 0xe1, 0x17, 0xb3, 0x17, 0x6d, 0x38, 0x48, 0x5c, 0xfe, - 0xa2, 0x16, 0x51, 0x17, 0x7b, 0xcf, 0x2a, 0x70, 0xa0, 0xff, 0xad, 0x97, - 0x43, 0x81, 0x41, 0x78, 0x8d, 0xfc, 0xce, 0x7f, 0xae, 0x29, 0xd7, 0x81, - 0x37, 0x78, 0x35, 0x1d, 0x57, 0x5d, 0xbf, 0xcc, 0x5c, 0x13, 0x41, 0x88, - 0x5f, 0x09, 0x3a, 0x59, 0x06, 0x99, 0x73, 0x55, 0xb3, 0xf4, 0x6b, 0xc1, - 0x27, 0xcd, 0x7a, 0x21, 0x65, 0xde, 0xc1, 0x08, 0x33, 0x35, 0xc7, 0xa4, - 0x62, 0x46, 0x0e, 0x5f, 0x35, 0x0f, 0x35, 0x78, 0x31, 0x3a, 0xf7, 0x4a, - 0x20, 0xe0, 0x63, 0xdf, 0xfe, 0x4a, 0x29, 0xeb, 0x72, 0x3f, 0x16, 0xd5, - 0xd9, 0xb6, 0x7c, 0x2f, 0xb6, 0xfe, 0xd2, 0xb7, 0x48, 0x03, 0xcc, 0x27, - 0xfe, 0xf4, 0xee, 0xdf, 0x0a, 0x1d, 0x54, 0x50, 0xec, 0x28, 0xb5, 0xa9, - 0xde, 0xd8, 0xa0, 0xb6, 0x11, 0x7d, 0xa9, 0xc7, 0xac, 0xab, 0x1e, 0xe0, - 0xfb, 0x50, 0x4a, 0x73, 0xd0, 0xea, 0x36, 0x76, 0x3e, 0xed, 0x58, 0x0a, - 0x3b, 0xe0, 0x1d, 0x8f, 0x50, 0x10, 0xcd, 0x2a, 0x84, 0x46, 0x5b, 0xce, - 0xac, 0x3d, 0x23, 0xb4, 0x17, 0xaf, 0x7d, 0x4f, 0xae, 0xfa, 0x9a, 0xce, - 0x60, 0x7a, 0x99, 0xe8, 0x4a, 0x53, 0x59, 0x4d, 0x5b, 0x9f, 0x71, 0xd5, - 0x03, 0xef, 0xd9, 0x02, 0xbb, 0xca, 0x92, 0x49, 0xb1, 0x1f, 0xe8, 0x75, - 0xe4, 0xd2, 0xc5, 0x98, 0x30, 0x61, 0xa5, 0x7d, 0x80, 0x90, 0x83, 0x26, - 0x6d, 0x1c, 0xb8, 0xf1, 0xca, 0x77, 0xe6, 0x3d, 0x1e, 0x09, 0x11, 0xae, - 0x2e, 0x21, 0x76, 0xd7, 0x7b, 0xca, 0x52, 0xcc, 0xff, 0x7e, 0x27, 0xd0, - 0x68, 0xc1, 0xd9, 0xe5, 0xa4, 0x66, 0x70, 0x4a, 0xff, 0xa7, 0xf2, 0xcf, - 0x26, 0xaa, 0xad, 0xe9, 0x9e, 0x38, 0x31, 0x74, 0xb9, 0xc8, 0x82, 0x17, - 0x40, 0x95, 0xb8, 0x72, 0x41, 0x89, 0x50, 0x81, 0x10, 0xfb, 0xde, 0xd9, - 0xa0, 0x27, 0xda, 0xe9, 0xa6, 0xbf, 0xb5, 0x97, 0x9d, 0x9a, 0x83, 0x36, - 0xd3, 0xcd, 0xd6, 0xf1, 0x87, 0x9f, 0x04, 0x98, 0x6d, 0xd2, 0x9f, 0x26, - 0x3d, 0x32, 0xb8, 0x0b, 0xae, 0xbe, 0xd1, 0xf0, 0xa1, 0x21, 0x70, 0x54, - 0x82, 0xd0, 0x3d, 0xd8, 0x79, 0xc4, 0x3f, 0x6b, 0xe5, 0xf8, 0x6f, 0xc4, - 0xf9, 0xc8, 0xbd, 0xcc, 0xee, 0x8a, 0x5e, 0x97, 0xcc, 0xf6, 0xc6, 0xba, - 0x0d, 0xbc, 0xdb, 0x1c, 0xaf, 0xc4, 0xe6, 0xb3, 0xa6, 0x61, 0x02, 0x40, - 0xc4, 0xe5, 0x39, 0x3d, 0x67, 0xf7, 0x58, 0xa2, 0x95, 0xd8, 0x5f, 0x76, - 0x97, 0x59, 0x79, 0xa3, 0xc0, 0x5e, 0xfc, 0x42, 0xd1, 0x66, 0x64, 0xfb, - 0x0b, 0x01, 0xe3, 0x22, 0xf5, 0x4f, 0x47, 0xc4, 0xd1, 0x90, 0x29, 0x39, - 0x5a, 0x62, 0xdf, 0x16, 0x21, 0xb4, 0x82, 0xb8, 0x17, 0x9f, 0x28, 0xa3, - 0xd0, 0x0f, 0xa5, 0x52, 0x9b, 0x7e, 0xf0, 0x34, 0x4f, 0x2b, 0xe5, 0x4b, - 0x6d, 0x0f, 0x07, 0xac, 0x76, 0xf9, 0x87, 0xc9, 0xc7, 0x00, 0xdc, 0x3f, - 0x74, 0xf3, 0xed, 0x7d, 0x66, 0x31, 0xe7, 0x19, 0x4e, 0xc6, 0x2e, 0x6a, - 0x59, 0x42, 0xc5, 0xf0, 0x1c, 0xb3, 0x1a, 0xe7, 0x94, 0xed, 0xf0, 0x2b, - 0xfa, 0x96, 0x94, 0x6c, 0xe2, 0xfa, 0x4d, 0x45, 0x45, 0x02, 0xeb, 0xf2, - 0x8d, 0x5f, 0xd3, 0x90, 0xbd, 0x1a, 0xb0, 0x49, 0xd8, 0x5a, 0x00, 0x17, - 0x5b, 0xbd, 0x29, 0x8a, 0x55, 0x90, 0x33, 0x9c, 0x44, 0xb6, 0x23, 0x3c, - 0xd5, 0x29, 0x6d, 0x72, 0x68, 0x65, 0x62, 0x28, 0x65, 0x52, 0x00, 0xee, - 0xad, 0x99, 0x41, 0x01, 0x73, 0x38, 0x05, 0xfd, 0x1f, 0x63, 0xd0, 0x7b, - 0x34, 0xf4, 0xc0, 0x6e, 0x17, 0x95, 0x9e, 0xd0, 0x98, 0xe6, 0x51, 0x04, - 0x8a, 0x56, 0xc4, 0x18, 0xba, 0x97, 0x2a, 0x63, 0xc7, 0xc3, 0x37, 0x1f, - 0x8b, 0x29, 0x97, 0x99, 0x9c, 0xc9, 0x83, 0xf2, 0x18, 0xfd, 0xc8, 0x9d, - 0xbd, 0x1b, 0xd0, 0xfe, 0x0d, 0x2b, 0x51, 0xa0, 0xaf, 0xaa, 0x12, 0xaf, - 0x35, 0x2b, 0xd4, 0x2f, 0x9e, 0x87, 0x21, 0x55, 0x0c, 0x61, 0x63, 0xf6, - 0x0a, 0x9e, 0xd4, 0x27, 0x3b, 0x5e, 0xf1, 0xa1, 0xa9, 0xe1, 0xa1, 0x5d, - 0xee, 0xb1, 0x51, 0x80, 0x5a, 0x40, 0x93, 0x0a, 0xe2, 0xca, 0x04, 0xe2, - 0xbc, 0x82, 0xc2, 0xba, 0x82, 0x9e, 0x72, 0xa9, 0x7f, 0x96, 0x29, 0x15, - 0x7f, 0xae, 0x32, 0x6a, 0x2a, 0x3d, 0x4a, 0x8a, 0x3b, 0x9d, 0x99, 0xde, - 0xa0, 0xc4, 0x9a, 0xdf, 0x5e, 0xf1, 0xca, 0xee, 0x69, 0x77, 0x5a, 0x4c, - 0x4e, 0x02, 0x45, 0x35, 0x5f, 0xa7, 0xd6, 0xde, 0x13, 0x5f, 0x87, 0xe6, - 0x85, 0xfa, 0x04, 0xeb, 0x3f, 0x25, 0x93, 0x12, 0x0a, 0xcd, 0x0d, 0xdd, - 0x8f, 0x83, 0x40, 0xbb, 0xda, 0x76, 0x33, 0x00, 0x92, 0xf4, 0x64, 0x7e, - 0x08, 0xec, 0x75, 0x26, 0x67, 0x6e, 0x16, 0x3c, 0xc5, 0x79, 0x77, 0xd9, - 0x1f, 0xd7, 0x84, 0xab, 0xef, 0x36, 0xf2, 0x3a, 0x02, 0xd8, 0x8c, 0x61, - 0x33, 0x47, 0x09, 0xe4, 0x54, 0xd8, 0xab, 0xd8, 0x04, 0x02, 0x90, 0x03, - 0xae, 0xb2, 0x3e, 0x39, 0x35, 0xaf, 0x0e, 0xcc, 0xa8, 0xe2, 0x17, 0xb5, - 0xb2, 0x9c, 0x4b, 0x96, 0xdb, 0x76, 0x3c, 0xd5, 0x8a, 0x56, 0x6f, 0xec, - 0x66, 0x79, 0xc2, 0x4b, 0xaa, 0x20, 0xf3, 0x62, 0xd3, 0x14, 0x2b, 0x78, - 0x1c, 0xb7, 0xaa, 0x5d, 0xcd, 0x28, 0xa9, 0x89, 0x90, 0xb3, 0xf1, 0xab, - 0x02, 0x56, 0xbc, 0x10, 0x77, 0x0d, 0x86, 0xe7, 0xc7, 0x88, 0x49, 0x9c, - 0xe0, 0x03, 0xbf, 0x1e, 0xc1, 0x14, 0xb2, 0x24, 0x55, 0x81, 0x92, 0x15, - 0x04, 0x9b, 0x8e, 0x77, 0x11, 0xd6, 0x92, 0x74, 0xaa, 0x19, 0xfa, 0x1e, - 0x50, 0xe7, 0x84, 0x29, 0xf3, 0xb0, 0xe2, 0xeb, 0xe6, 0x62, 0x35, 0xb4, - 0x44, 0xaf, 0xf3, 0x09, 0x74, 0x29, 0x96, 0x27, 0x9f, 0x5f, 0x1d, 0x17, - 0xbb, 0xbe, 0x92, 0x7f, 0x97, 0x78, 0xfa, 0x3b, 0x86, 0xc7, 0x78, 0x8c, - 0x03, 0x02, 0x2e, 0xa9, 0xc3, 0x00, 0x3b, 0xcc, 0xe5, 0xa4, 0x37, 0xd9, - 0xe6, 0x36, 0x25, 0xdd, 0x06, 0xb1, 0x4e, 0xc9, 0x86, 0xe6, 0xb6, 0x25, - 0x1d, 0xa6, 0x41, 0xe7, 0xd9, 0x37, 0x46, 0x6d, 0xed, 0x98, 0xb4, 0x4c, - 0x52, 0x5f, 0xa6, 0xfd, 0x58, 0x61, 0x04, 0xe1, 0xa0, 0x84, 0x56, 0x54, - 0x12, 0x05, 0x46, 0xe8, 0x58, 0x07, 0x18, 0xbe, 0xce, 0x55, 0xca, 0xf5, - 0xfc, 0xb3, 0x95, 0x75, 0x00, 0xca, 0xd3, 0xf2, 0xab, 0x65, 0x3c, 0xa3, - 0xcf, 0x50, 0x3f, 0x8d, 0xb9, 0x7a, 0x9c, 0xaf, 0xb4, 0xf6, 0x11, 0x73, - 0x1b, 0x93, 0x3e, 0xd6, 0x09, 0x3f, 0x56, 0xd0, 0xa7, 0x34, 0x43, 0x5e, - 0x8d, 0x17, 0xe1, 0xf8, 0x80, 0x3c, 0x49, 0xd3, 0x1b, 0x09, 0x12, 0x52, - 0x43, 0xb6, 0xcf, 0x2c, 0x65, 0xf5, 0x4c, 0x7d, 0x14, 0x71, 0xe4, 0x2d, - 0x87, 0x39, 0x59, 0x47, 0x67, 0x0c, 0x46, 0x60, 0x6c, 0x88, 0xba, 0x35, - 0x31, 0x4a, 0x41, 0x65, 0x01, 0xd9, 0xfc, 0x9b, 0xf6, 0xcf, 0x0f, 0x87, - 0xa8, 0xfc, 0x04, 0x59, 0xc6, 0x84, 0x8b, 0x20, 0x60, 0x3f, 0x8f, 0x78, - 0x26, 0xb3, 0x87, 0xd4, 0x59, 0xad, 0x6e, 0x56, 0x18, 0xf9, 0xc4, 0xba, - 0x33, 0x6b, 0x15, 0x5a, 0xb5, 0x90, 0x81, 0xcd, 0xf0, 0xf3, 0xb6, 0x28, - 0xd3, 0x96, 0x0e, 0xec, 0x42, 0xd8, 0xcb, 0x21, 0x60, 0x30, 0x6f, 0x91, - 0x2b, 0x35, 0xd1, 0x63, 0x19, 0x9a, 0x47, 0x8b, 0x22, 0xe6, 0x5f, 0x15, - 0x83, 0x95, 0x5f, 0x78, 0xf4, 0x34, 0xe8, 0x93, 0x1d, 0xf6, 0x58, 0x77, - 0x37, 0xe9, 0x88, 0x0c, 0x65, 0x6e, 0x98, 0xc2, 0xce, 0xd7, 0xb5, 0x46, - 0x81, 0x01, 0x2a, 0xeb, 0x69, 0xde, 0xd2, 0x5f, 0x4f, 0x97, 0xf1, 0xfc, - 0x19, 0x3d, 0x20, 0xe8, 0xc7, 0xda, 0x69, 0x48, 0x7d, 0x3a, 0x1a, 0xd9, - 0x89, 0x4f, 0x88, 0x4a, 0x43, 0xae, 0xcc, 0x15, 0xba, 0x4c, 0x99, 0x3b, - 0xef, 0xf1, 0x40, 0x3c, 0x42, 0x36, 0xa7, 0xc6, 0x53, 0x7b, 0xd9, 0x3c, - 0x37, 0xa1, 0x58, 0x99, 0xeb, 0x98, 0xff, 0x2a, 0x16, 0x64, 0xf9, 0x21, - 0xc5, 0xab, 0x9d, 0xf9, 0xd1, 0x68, 0x99, 0x41, 0x3f, 0x0b, 0xa4, 0xfa, - 0xea, 0x3b, 0xb7, 0x8a, 0x8e, 0xa3, 0xa1, 0xf8, 0x8c, 0xde, 0x62, 0x7e, - 0xbe, 0x7b, 0xc6, 0xba, 0xe8, 0xd6, 0xe0, 0xa5, 0x77, 0x36, 0x2b, 0xee, - 0x45, 0xbd, 0x99, 0x4b, 0xab, 0xfd, 0x3e, 0x6f, 0xe5, 0xb4, 0x4b, 0x11, - 0x67, 0x6c, 0xc2, 0xb9, 0xf6, 0x0a, 0x68, 0xc0, 0xb3, 0x80, 0xd7, 0x9a, - 0x7b, 0xa7, 0xf3, 0x66, 0xfb, 0x5c, 0xab, 0xdb, 0x82, 0x14, 0x16, 0x14, - 0x57, 0x59, 0xa9, 0xfb, 0x0a, 0xc5, 0xf7, 0x55, 0xaf, 0xea, 0xd1, 0xa2, - 0x25, 0x1c, 0x7c, 0xbd, 0x18, 0x8a, 0x61, 0x7a, 0x8c, 0x5f, 0xd8, 0xee, - 0x37, 0x36, 0x83, 0xca, 0x24, 0xf3, 0xfc, 0xb1, 0x7e, 0x01, 0x58, 0xf8, - 0xb4, 0x3f, 0x29, 0xa9, 0xd5, 0x08, 0x63, 0x3c, 0xb0, 0xda, 0x21, 0xb1, - 0x3f, 0x3e, 0x2a, 0x3d, 0x78, 0x60, 0x2d, 0xa1, 0xd5, 0x66, 0x53, 0xf4, - 0xc1, 0x8b, 0x94, 0x61, 0x9f, 0xf7, 0xcf, 0x41, 0xae, 0x45, 0x3a, 0x98, - 0x16, 0xfc, 0xfd, 0x00, 0x00, 0x76, 0x35, 0x03, 0xa9, 0x76, 0x3d, 0x0b, - 0xe0, 0x4d, 0x89, 0x88, 0x6c, 0xb0, 0xeb, 0x06, 0xd1, 0x3e, 0x03, 0xb7, - 0xef, 0xcb, 0x3b, 0x27, 0xb0, 0xbb, 0x4a, 0xef, 0x9c, 0xc4, 0x86, 0xa3, - 0x6a, 0x23, 0x6f, 0x3f, 0x16, 0x9e, 0x2e, 0x4a, 0xf2, 0x00, 0xd2, 0x18, - 0x01, 0x8e, 0x7e, 0x91, 0xf3, 0x6d, 0xc2, 0x37, 0xdb, 0xfc, 0xe0, 0xf8, - 0x36, 0x77, 0xd3, 0xdc, 0xf3, 0x73, 0xdd, 0x12, 0xe3, 0x4d, 0xac, 0x87, - 0xd8, 0x39, 0x74, 0x86, 0x83, 0xa3, 0xf6, 0x9d, 0x1c, 0xf0, 0xed, 0x9d, - 0xa3, 0x86, 0x97, 0xdf, 0x57, 0x84, 0x90, 0x74, 0xf6, 0x9d, 0xfc, 0x91, - 0xb3, 0xe7, 0x2d, 0x6d, 0x18, 0xa7, 0x6e, 0x7e, 0xf9, 0xf4, 0x11, 0xec, - 0x3a, 0xc8, 0xaa, 0x1e, 0xb4, 0x0b, 0x2e, 0xe5, 0x8a, 0x1f, 0xeb, 0x15, - 0xee, 0xba, 0x8a, 0x0f, 0x69, 0x2a, 0xa2, 0xdf, 0x7b, 0x29, 0xd0, 0x25, - 0xb3, 0xf6, 0x3e, 0x37, 0xd0, 0x97, 0x93, 0x8a, 0x02, 0x62, 0x7d, 0x6d, - 0x8e, 0x2c, 0x67, 0x4e, 0x9d, 0xb7, 0x3e, 0xa3, 0xe0, 0x13, 0x5e, 0xfa, - 0x21, 0x79, 0x6a, 0x3b, 0xf1, 0x7b, 0x3b, 0xb9, 0x74, 0xb6, 0x14, 0xac, - 0x70, 0x14, 0x24, 0x87, 0x2f, 0x8b, 0xfd, 0xed, 0xe3, 0x54, 0xe2, 0xfb, - 0xa6, 0xd9, 0xba, 0x21, 0x43, 0x66, 0x3e, 0x0c, 0x8b, 0xfc, 0x65, 0x99, - 0x6f, 0xaf, 0x15, 0xe0, 0xcb, 0x7c, 0x4f, 0x4b, 0x31, 0x1c, 0xc8, 0x0f, - 0xa0, 0x50, 0x63, 0x84, 0xaf, 0x84, 0x83, 0x87, 0x06, 0xe8, 0x57, 0x2b, - 0x87, 0xe9, 0xce, 0xae, 0xed, 0xd7, 0xc7, 0xb9, 0x31, 0x77, 0x6d, 0x99, - 0xa3, 0x48, 0x4e, 0xbe, 0x40, 0xf6, 0xa3, 0x98, 0x32, 0x61, 0x47, 0xeb, - 0x74, 0x3f, 0xe5, 0x17, 0xef, 0x48, 0x6b, 0x5a, 0x89, 0xbc, 0x58, 0xbf, - 0x70, 0x0d, 0x46, 0xc7, 0x80, 0xd3, 0x34, 0xb0, 0x20, 0x10, 0x00, 0xd9, - 0x08, 0x80, 0xe6, 0x25, 0x5a, 0x32, 0xf9, 0xe0, 0x0d, 0x72, 0x31, 0xb6, - 0xc0, 0xfd, 0xc9, 0xd7, 0xbc, 0xe8, 0x08, 0x52, 0xdd, 0xa2, 0x00, 0x46, - 0xd4, 0x65, 0xbf, 0x28, 0xb4, 0xfd, 0xc1, 0x04, 0xa9, 0x54, 0x25, 0xc8, - 0x94, 0x95, 0x92, 0x3c, 0xec, 0xc9, 0x28, 0x4c, 0xb9, 0x6f, 0x72, 0x06, - 0x7e, 0xc3, 0xd1, 0x95, 0x41, 0x48, 0xfc, 0x2d, 0x43, 0x77, 0x31, 0x1a, - 0x4a, 0x42, 0x60, 0x14, 0x77, 0x15, 0xba, 0x4d, 0x3a, 0xea, 0xee, 0x45, - 0x2d, 0xbe, 0xdd, 0x62, 0x5c, 0x2f, 0x75, 0xf5, 0x01, 0x0d, 0xf1, 0x20, - 0xbc, 0xd9, 0x9d, 0x1e, 0x76, 0x6b, 0xf0, 0x5c, 0xbc, 0xc5, 0x48, 0x94, - 0x3f, 0xd6, 0x20, 0x2a, 0xaf, 0x77, 0x86, 0xc4, 0xcf, 0x21, 0xc3, 0xc7, - 0x4e, 0x1f, 0xde, 0xfa, 0x7c, 0xec, 0xa2, 0x00, 0x59, 0x8c, 0xa3, 0x2f, - 0x3d, 0x6e, 0xdb, 0xc8, 0x1c, 0x1e, 0xb2, 0x7f, 0xab, 0xc6, 0xea, 0xfc, - 0x24, 0x55, 0xba, 0x83, 0x23, 0xef, 0x4c, 0xcc, 0x28, 0x24, 0x9a, 0xa4, - 0xb3, 0xa2, 0x6f, 0xfe, 0x51, 0x71, 0xa1, 0xf8, 0xda, 0x53, 0x80, 0x9e, - 0x4e, 0x21, 0x9b, 0x18, 0xea, 0x44, 0xa2, 0x1c, 0x5a, 0x8c, 0x3a, 0xff, - 0xa2, 0x68, 0x94, 0x8d, 0x9d, 0x00, 0x45, 0xf3, 0x49, 0xa4, 0x0c, 0xe5, - 0xca, 0x5d, 0x4e, 0xeb, 0x0d, 0x84, 0xff, 0x5e, 0xf4, 0x23, 0x5e, 0x56, - 0xc6, 0x72, 0xeb, 0x9e, 0xd5, 0x21, 0x63, 0xfa, 0xd3, 0x67, 0xb7, 0x19, - 0xe4, 0x85, 0x2a, 0xcd, 0xd1, 0x12, 0xfd, 0x51, 0xe7, 0x91, 0xac, 0x85, - 0xbd, 0xad, 0xbd, 0x48, 0x90, 0x95, 0x3b, 0x5b, 0x12, 0xdd, 0x6e, 0x82, - 0x28, 0xa8, 0xb4, 0x7d, 0xf3, 0x44, 0xe8, 0x88, 0x5a, 0x1d, 0x5d, 0xca, - 0x03, 0xae, 0x75, 0xf8, 0xbe, 0x03, 0xd8, 0x58, 0x89, 0x50, 0x9b, 0xd0, - 0xf8, 0x45, 0x67, 0x8e, 0xfd, 0x1d, 0xfd, 0x17, 0x39, 0xbf, 0x50, 0x63, - 0xb6, 0x36, 0xcc, 0x6b, 0xfe, 0x17, 0xdf, 0xdc, 0xc0, 0x49, 0xae, 0xcd, - 0xf9, 0x19, 0x88, 0xb0, 0x21, 0x21, 0x0d, 0x2f, 0xe2, 0x5d, 0xa3, 0x0b, - 0x19, 0x45, 0xc4, 0xdd, 0xdb, 0x2a, 0x27, 0x96, 0xad, 0x7e, 0x25, 0x15, - 0x99, 0x1c, 0x69, 0x72, 0xe5, 0x49, 0xb1, 0x50, 0x62, 0x7c, 0x2f, 0x1b, - 0x66, 0xea, 0x0b, 0x5b, 0xae, 0xaa, 0x3a, 0x8e, 0x63, 0x6b, 0x10, 0xfd, - 0x6d, 0x70, 0x07, 0x11, 0xb4, 0x1b, 0xf5, 0xe5, 0xfb, 0x2f, 0x46, 0x08, - 0x8f, 0x38, 0xbd, 0xc8, 0x84, 0x1e, 0x3a, 0xf8, 0x00, 0x23, 0x4f, 0x37, - 0xb1, 0xc7, 0x1f, 0x1c, 0x57, 0x85, 0xe5, 0x4d, 0xc6, 0x27, 0x38, 0xf0, - 0x8c, 0xba, 0xaf, 0x77, 0xad, 0xac, 0xab, 0xfe, 0xd6, 0x42, 0x12, 0xeb, - 0xc1, 0x8d, 0x1c, 0x64, 0x51, 0x3c, 0x8d, 0xa2, 0xde, 0x31, 0x00, 0x75, - 0x6b, 0xd5, 0x64, 0xb8, 0x6e, 0xfa, 0x49, 0xb9, 0x75, 0x32, 0x9e, 0xd6, - 0xcd, 0x64, 0x7a, 0x82, 0xb4, 0xc4, 0x3a, 0x5d, 0x40, 0xe8, 0x5d, 0xc5, - 0x8c, 0x94, 0xac, 0x50, 0x8a, 0xf4, 0x62, 0x80, 0x80, 0x73, 0x8a, 0xe3, - 0x08, 0x20, 0x47, 0xcb, 0x21, 0xb9, 0x3a, 0x0c, 0xf1, 0x44, 0xdf, 0x82, - 0xf0, 0x5c, 0xed, 0xd8, 0x3c, 0x1f, 0x52, 0x89, 0x18, 0xd6, 0x5e, 0x07, - 0xe9, 0x50, 0x5e, 0x89, 0x9f, 0xa9, 0xef, 0x74, 0x04, 0xd5, 0x5e, 0xbe, - 0x7c, 0xf2, 0xf3, 0x7a, 0xdd, 0x50, 0x19, 0xe7, 0x22, 0x4e, 0x3e, 0xc1, - 0x9f, 0x43, 0xc3, 0x06, 0x3a, 0x04, 0xaf, 0xe7, 0x24, 0x7f, 0xf5, 0x06, - 0x07, 0xd1, 0xec, 0x64, 0x07, 0xc1, 0xdc, 0xa1, 0xac, 0x62, 0x3a, 0x3d, - 0xc0, 0x37, 0x6c, 0xbe, 0x52, 0xa1, 0x44, 0x00, 0x15, 0xfe, 0xb1, 0xd8, - 0x97, 0x7f, 0x86, 0x96, 0xb1, 0x9b, 0xfe, 0x3b, 0x88, 0x4a, 0xf0, 0x3d, - 0x8d, 0x91, 0x6f, 0x32, 0x77, 0xa0, 0x2c, 0x3e, 0x44, 0x4b, 0xaa, 0xc8, - 0x99, 0xc0, 0x10, 0xe1, 0xb7, 0x88, 0x64, 0xf6, 0x3a, 0x40, 0x3c, 0x13, - 0xcf, 0xd8, 0x78, 0x03, 0xd2, 0xa7, 0x53, 0x8b, 0xdc, 0x4e, 0xe4, 0xa8, - 0x47, 0x62, 0x0c, 0x64, 0x6d, 0x26, 0x2f, 0xe0, 0x24, 0x29, 0x5b, 0x0f, - 0x5d, 0x46, 0x05, 0x63, 0x32, 0x44, 0xf8, 0xaf, 0xc5, 0x7c, 0x19, 0xee, - 0x21, 0x9f, 0xd9, 0x39, 0x74, 0xe0, 0x4a, 0xd1, 0xe4, 0x89, 0x4a, 0x60, - 0x75, 0xa8, 0xef, 0x57, 0x90, 0x4d, 0xd2, 0xb9, 0xd5, 0xa3, 0x83, 0x0a, - 0xb0, 0x0a, 0xec, 0x7c, 0x9d, 0xd4, 0x41, 0x1d, 0x81, 0xe3, 0x6e, 0x3c, - 0xc8, 0xe6, 0xdc, 0xdd, 0x9b, 0xda, 0x46, 0x30, 0x5a, 0xab, 0xbf, 0xf4, - 0x5e, 0x0d, 0x22, 0x27, 0x60, 0x7b, 0x38, 0x8c, 0x6b, 0x52, 0x56, 0xb0, - 0xac, 0x8d, 0x1f, 0xd0, 0x9d, 0x0f, 0x28, 0x83, 0x73, 0x7d, 0x3a, 0x02, - 0x28, 0x29, 0x0d, 0x0f, 0x11, 0x11, 0x41, 0xda, 0xb6, 0x2f, 0x71, 0x94, - 0x4b, 0x46, 0x90, 0xb6, 0x0b, 0x03, 0x1b, 0xfc, 0x33, 0x80, 0x65, 0xc7, - 0xf8, 0xba, 0x5f, 0xc4, 0x6f, 0x11, 0x64, 0xb6, 0xcb, 0x3d, 0x97, 0x52, - 0xe3, 0x15, 0xca, 0x72, 0x29, 0xbc, 0x0f, 0x26, 0x8a, 0x93, 0x54, 0xc9, - 0x43, 0x9b, 0x5c, 0x52, 0xb8, 0x7c, 0x3d, 0x3a, 0xa5, 0x0a, 0x2f, 0x6c, - 0xfc, 0x70, 0x96, 0xb3, 0x7a, 0xd5, 0xec, 0x24, 0x14, 0xb0, 0x58, 0x74, - 0x27, 0xf8, 0x35, 0x6a, 0x4b, 0x13, 0xa4, 0x5a, 0x86, 0x9c, 0x01, 0x5d, - 0xdb, 0x27, 0x75, 0xfa, 0x36, 0xed, 0x03, 0x9b, 0x30, 0x4f, 0x6a, 0x09, - 0xa3, 0x9d, 0x90, 0x20, 0xbe, 0x98, 0x97, 0xe2, 0x19, 0x03, 0x39, 0xd7, - 0xca, 0x67, 0x70, 0xf6, 0xe2, 0x25, 0x21, 0x15, 0x13, 0xc5, 0x00, 0x90, - 0x1a, 0x9c, 0x68, 0x10, 0x88, 0x8f, 0x56, 0xf1, 0x08, 0x47, 0xf4, 0xea, - 0x78, 0x76, 0xf5, 0x7a, 0xe4, 0x09, 0xe2, 0x63, 0x1a, 0x41, 0x89, 0xd6, - 0xa2, 0xb1, 0x4c, 0x8e, 0xcb, 0xb5, 0x65, 0xe4, 0xd6, 0x85, 0x05, 0x8a, - 0x2b, 0x31, 0xe2, 0xd3, 0xb2, 0x1b, 0xba, 0xcd, 0x81, 0x66, 0x4b, 0x5e, - 0xf4, 0x63, 0xea, 0x41, 0x5c, 0x32, 0x9e, 0xdb, 0xd6, 0xb3, 0xca, 0xa6, - 0x51, 0x76, 0x9c, 0x3e, 0x0f, 0xb7, 0x9b, 0x1a, 0xc4, 0x95, 0x9e, 0x6b, - 0x4e, 0x2e, 0x2f, 0x66, 0x84, 0x4d, 0xe4, 0x37, 0x89, 0xec, 0x9d, 0xc0, - 0xbc, 0xea, 0x67, 0x7b, 0x79, 0x4b, 0xeb, 0xfa, 0x44, 0xdb, 0x07, 0xd0, - 0xb3, 0xc2, 0xb7, 0x3d, 0x18, 0x18, 0x50, 0xd0, 0x37, 0x67, 0x3c, 0x47, - 0x9c, 0xef, 0xb0, 0x46, 0x31, 0xeb, 0x7c, 0x71, 0x19, 0x9c, 0x8c, 0xd7, - 0x2c, 0x66, 0xa0, 0x61, 0x0d, 0x24, 0x38, 0x16, 0x41, 0xda, 0xd5, 0x45, - 0x46, 0xf7, 0xc9, 0x11, 0x31, 0x6d, 0xc3, 0xad, 0xcd, 0xbb, 0x63, 0x35, - 0xb2, 0x34, 0xe0, 0x69, 0x52, 0x69, 0xd7, 0xc1, 0xa4, 0x88, 0x4e, 0xf6, - 0x38, 0xce, 0x74, 0x2e, 0xdf, 0x83, 0xd9, 0x44, 0xaa, 0x2c, 0x7c, 0x5e, - 0x36, 0x30, 0x26, 0x25, 0x91, 0x62, 0xd5, 0xe2, 0x08, 0xdf, 0xfd, 0xb5, - 0xe7, 0x79, 0xbf, 0x80, 0x04, 0xf1, 0xac, 0xa7, 0x61, 0xd2, 0xa9, 0xe3, - 0xf3, 0x05, 0xad, 0xeb, 0x40, 0x39, 0xdf, 0x37, 0xa8, 0xde, 0x72, 0x3b, - 0xf0, 0x1b, 0x41, 0x45, 0x6e, 0xb5, 0x1e, 0x0d, 0x24, 0x9c, 0x10, 0x36, - 0x06, 0xca, 0x3d, 0x4d, 0x3c, 0x1c, 0x59, 0x71, 0xf4, 0x88, 0x66, 0xd0, - 0x80, 0xfa, 0x0a, 0xf8, 0x44, 0x86, 0xa5, 0xcc, 0xdd, 0x34, 0xe8, 0x12, - 0xdb, 0x30, 0xf7, 0x70, 0xa7, 0x3f, 0x45, 0xf4, 0x78, 0x25, 0x38, 0x4d, - 0x4d, 0x67, 0xc1, 0xad, 0xf0, 0xbe, 0x36, 0xa9, 0x44, 0x11, 0x17, 0x16, - 0x53, 0x1e, 0x6d, 0xf1, 0xbc, 0x35, 0x63, 0xea, 0x90, 0x0e, 0x40, 0xa5, - 0x19, 0xd5, 0xa3, 0x4c, 0x66, 0x27, 0xeb, 0x66, 0xe4, 0xf1, 0xc3, 0x79, - 0x47, 0xa9, 0x0c, 0x61, 0x48, 0x5a, 0x42, 0x20, 0x2a, 0x21, 0xb7, 0x12, - 0x1a, 0x7c, 0x13, 0x17, 0x08, 0x39, 0xef, 0xe9, 0x1b, 0xe5, 0x3b, 0xb0, - 0xfe, 0x28, 0xf2, 0x48, 0x3e, 0x7a, 0x27, 0xfb, 0xbc, 0x48, 0xbf, 0xf5, - 0xbd, 0xad, 0x3a, 0x90, 0x70, 0xf7, 0x0f, 0x6b, 0xb8, 0x76, 0x83, 0x09, - 0x9f, 0x24, 0xd4, 0x67, 0x25, 0x0f, 0x11, 0x60, 0x6e, 0x87, 0x05, 0x57, - 0x6d, 0x6f, 0x64, 0xc0, 0xff, 0xca, 0xdd, 0x81, 0xec, 0xb0, 0x8f, 0x66, - 0x24, 0x0a, 0x3d, 0xbe, 0xd7, 0xee, 0xa7, 0x5f, 0x26, 0xe8, 0x4e, 0xe5, - 0xa1, 0xfc, 0x65, 0xc2, 0x8c, 0x7e, 0x05, 0x85, 0x39, 0xa9, 0x7d, 0x24, - 0x3e, 0x25, 0x0d, 0x0c, 0xf4, 0xf8, 0x3b, 0xaa, 0x25, 0x6b, 0x9c, 0xdf, - 0xab, 0x0c, 0x6b, 0x3f, 0xc5, 0xca, 0x6e, 0x5a, 0x66, 0x38, 0x36, 0x64, - 0x73, 0xbe, 0xaa, 0x02, 0xcf, 0xf7, 0xb4, 0xe0, 0xc6, 0x60, 0xb7, 0xd8, - 0xf1, 0x65, 0xeb, 0xe8, 0x38, 0xc1, 0xb6, 0xc9, 0xf3, 0x49, 0xfa, 0x09, - 0xc8, 0x58, 0x9f, 0x85, 0x24, 0xab, 0x5a, 0xb8, 0x29, 0xa2, 0x0b, 0x6f, - 0x30, 0x52, 0xe3, 0xb1, 0xb2, 0x6d, 0x02, 0x1a, 0x33, 0x3d, 0xc0, 0xfd, - 0xee, 0x2b, 0xfa, 0xb9, 0xe2, 0x82, 0x08, 0x17, 0x17, 0x5c, 0x20, 0x11, - 0x62, 0x1b, 0x82, 0x47, 0x99, 0xdb, 0x24, 0xac, 0x1a, 0xaf, 0x91, 0xef, - 0xb0, 0x0c, 0x2c, 0x5f, 0x23, 0x26, 0x65, 0x2f, 0x75, 0x9b, 0xc2, 0x85, - 0x5b, 0x45, 0x86, 0xad, 0x6f, 0x43, 0x95, 0x5f, 0xdb, 0xf2, 0x45, 0x7a, - 0xa7, 0x1c, 0x2e, 0x52, 0xc2, 0x68, 0x25, 0xda, 0x43, 0xab, 0x1a, 0xcb, - 0x56, 0x82, 0xb0, 0xbf, 0xf2, 0x7e, 0xa5, 0xb0, 0x0f, 0xd4, 0x0c, 0x45, - 0x51, 0x07, 0x23, 0xfe, 0x56, 0x4b, 0x90, 0xe2, 0xc9, 0xb0, 0x7b, 0xd2, - 0x02, 0x67, 0xb8, 0x79, 0x10, 0x5a, 0x19, 0x9b, 0xaa, 0xe8, 0xae, 0x05, - 0xae, 0x2d, 0x61, 0xe6, 0xd2, 0x8a, 0xf0, 0x33, 0x14, 0x65, 0x92, 0x52, - 0x24, 0xf7, 0xb2, 0xf2, 0xa3, 0x22, 0xb3, 0xf2, 0xf9, 0x86, 0x4d, 0x7d, - 0x4b, 0x91, 0x82, 0x6e, 0x7b, 0x85, 0x6d, 0xda, 0x8a, 0xf4, 0xf9, 0xf9, - 0x8e, 0x31, 0x8a, 0x55, 0x9a, 0xc2, 0xcc, 0xf4, 0x97, 0xdc, 0x8c, 0x9d, - 0x6b, 0x23, 0xd5, 0x97, 0x64, 0x36, 0x2a, 0xe9, 0x7d, 0x0c, 0x89, 0xe2, - 0x3b, 0x8a, 0x5c, 0xb3, 0xae, 0xe6, 0x0d, 0xa9, 0x4d, 0x50, 0x10, 0x79, - 0x64, 0x00, 0x64, 0x5b, 0x3c, 0xd1, 0x0b, 0x92, 0x0e, 0xcf, 0xae, 0x6c, - 0x99, 0x53, 0x46, 0x30, 0x1b, 0xee, 0x59, 0xef, 0x8a, 0xdb, 0x4e, 0x69, - 0xfd, 0x39, 0x23, 0x24, 0xd4, 0x7f, 0x69, 0x03, 0x80, 0x50, 0x15, 0x7a, - 0x6f, 0xa7, 0xcb, 0x7a, 0x8f, 0x8e, 0x30, 0xcd, 0x56, 0x5a, 0x5b, 0x1e, - 0x79, 0x24, 0x7a, 0xa8, 0xa5, 0x88, 0x2f, 0xe7, 0x12, 0x16, 0x01, 0x4f, - 0x43, 0x47, 0x51, 0x30, 0xc9, 0x64, 0xd7, 0x53, 0xc4, 0x5d, 0xba, 0xa5, - 0xde, 0xf0, 0x96, 0xbe, 0x2a, 0x57, 0x2f, 0x6b, 0x19, 0xcc, 0x66, 0xf6, - 0x3b, 0x2f, 0xe6, 0x22, 0xf1, 0x7c, 0x74, 0xad, 0x8b, 0x31, 0xde, 0xfa, - 0x6d, 0x1a, 0x17, 0x6c, 0x40, 0xc3, 0x89, 0x45, 0xb2, 0x67, 0xd3, 0x27, - 0xc4, 0x23, 0xe1, 0xa1, 0x09, 0x5c, 0x7d, 0xf0, 0xef, 0x9e, 0xdb, 0x1f, - 0x03, 0x18, 0xcd, 0x24, 0x03, 0x4d, 0xa2, 0x20, 0x4b, 0xe7, 0x53, 0xb0, - 0x43, 0xe0, 0x9c, 0x1c, 0xac, 0xad, 0xea, 0x3d, 0xbc, 0x8e, 0x05, 0x0a, - 0x90, 0xaa, 0xad, 0x58, 0x5e, 0x3c, 0x03, 0x47, 0x88, 0xd7, 0x05, 0xfd, - 0xd2, 0x53, 0xe3, 0xdf, 0x16, 0x89, 0x9d, 0x59, 0x61, 0x1c, 0x43, 0x26, - 0xb9, 0x10, 0x41, 0x73, 0x70, 0x18, 0xbf, 0xc3, 0xe3, 0x22, 0xb2, 0x0a, - 0xe1, 0x31, 0x86, 0x74, 0x0a, 0xeb, 0x67, 0x2d, 0xa5, 0x34, 0x3f, 0xec, - 0xa7, 0x29, 0x23, 0x4a, 0x9e, 0x77, 0x52, 0x92, 0x1c, 0xb0, 0x8c, 0x99, - 0x71, 0xaa, 0x9b, 0xfb, 0x91, 0xcf, 0x15, 0xbb, 0x2a, 0x7d, 0x74, 0x7c, - 0x1c, 0x5a, 0x82, 0x7d, 0x18, 0x59, 0x18, 0x85, 0xcd, 0xf2, 0xf4, 0xa3, - 0x76, 0x18, 0x55, 0x21, 0x05, 0xbc, 0xcc, 0x41, 0xec, 0xa7, 0x8a, 0x03, - 0x38, 0x2a, 0xca, 0x02, 0x94, 0xd0, 0xe4, 0xad, 0xd3, 0x74, 0xda, 0x2c, - 0x11, 0xad, 0xcb, 0x02, 0x1f, 0x5e, 0x6a, 0x59, 0xc0, 0x1e, 0x75, 0x3e, - 0x35, 0x49, 0x6f, 0x20, 0x4f, 0x34, 0x61, 0x5e, 0xec, 0x03, 0x36, 0x84, - 0x45, 0xa2, 0x88, 0x57, 0xcc, 0x22, 0xbb, 0xc9, 0x35, 0x42, 0x15, 0xae, - 0x9a, 0xf6, 0x28, 0x75, 0xe4, 0xef, 0xa6, 0xd8, 0xa0, 0x55, 0x66, 0x32, - 0xbf, 0x7c, 0x28, 0xe0, 0x3d, 0x99, 0xbb, 0x02, 0xc0, 0xaa, 0xcf, 0xec, - 0x1a, 0xdd, 0xaf, 0xff, 0xa1, 0x91, 0xe3, 0xb8, 0xfb, 0xa6, 0x34, 0x17, - 0xe6, 0xeb, 0xeb, 0xf8, 0xed, 0xcd, 0x53, 0x13, 0x3e, 0x8f, 0xc9, 0xac, - 0x65, 0x0c, 0x60, 0x24, 0x11, 0x50, 0xf5, 0x5a, 0x34, 0x2f, 0x58, 0xd1, - 0x7c, 0x5c, 0xf5, 0x68, 0x98, 0xb1, 0x45, 0x3c, 0xc8, 0x83, 0xa5, 0x05, - 0x43, 0xa3, 0xe8, 0x9c, 0x81, 0xcd, 0x0b, 0xf1, 0x41, 0xeb, 0x53, 0x52, - 0x39, 0x22, 0x1e, 0xe3, 0xdd, 0x55, 0x45, 0x87, 0x8e, 0xfd, 0x1c, 0x99, - 0xf8, 0x50, 0x22, 0x07, 0x16, 0x53, 0xa2, 0x15, 0xae, 0x99, 0x46, 0x4f, - 0xcc, 0x8f, 0xca, 0x1c, 0xd9, 0x4d, 0x3a, 0x3f, 0x12, 0x0c, 0xd4, 0x3c, - 0x38, 0xfa, 0xc3, 0xd5, 0x96, 0x91, 0x0e, 0xe7, 0xd6, 0x42, 0x8e, 0x60, - 0xe6, 0xdf, 0x13, 0x23, 0x78, 0xa6, 0x75, 0x6b, 0x2d, 0xa8, 0xa4, 0xc8, - 0x9d, 0x87, 0x49, 0x95, 0xd3, 0x95, 0xa7, 0xde, 0xbb, 0x5e, 0x14, 0xa1, - 0xa1, 0x18, 0x34, 0x7e, 0x0c, 0x60, 0xf2, 0x13, 0xb8, 0xdb, 0x23, 0x99, - 0x44, 0x47, 0xcb, 0xdf, 0xa3, 0x89, 0xb1, 0x9c, 0x85, 0x0e, 0x1b, 0xce, - 0x8a, 0x54, 0xbd, 0x13, 0x03, 0xe7, 0x1c, 0x79, 0xef, 0x5f, 0xed, 0x58, - 0xa3, 0x0f, 0x07, 0x50, 0xf5, 0x49, 0x10, 0xb0, 0x77, 0xf7, 0x2d, 0x82, - 0x91, 0x4d, 0xf4, 0xec, 0x52, 0x83, 0x7b, 0x7e, 0x98, 0x19, 0x0e, 0x5e, - 0x6e, 0x3f, 0x70, 0xc5, 0x52, 0x1f, 0xcb, 0x7e, 0xdd, 0x6d, 0x5b, 0x44, - 0x34, 0xd7, 0x2c, 0x1d, 0xaa, 0xf0, 0x8a, 0x37, 0xaf, 0xfa, 0xca, 0xdf, - 0x4d, 0xd5, 0x1d, 0x24, 0x8a, 0xc2, 0x1d, 0x83, 0x1a, 0xfc, 0xfe, 0x94, - 0xf1, 0x52, 0xa9, 0xb1, 0x16, 0x79, 0xda, 0xc0, 0x96, 0x48, 0xc5, 0xfa, - 0x4e, 0xf6, 0x59, 0x1d, 0x8b, 0x2f, 0xe6, 0xa6, 0x10, 0xd3, 0xd8, 0x6e, - 0x58, 0x0b, 0x4f, 0x22, 0x4b, 0x87, 0x50, 0x64, 0x55, 0x00, 0x87, 0x27, - 0x5f, 0xf5, 0xa4, 0x71, 0xd2, 0x18, 0xe6, 0xe5, 0x8b, 0xa3, 0x7d, 0x4d, - 0xbf, 0xcf, 0x7f, 0xb9, 0x36, 0xbe, 0x80, 0x9d, 0x8e, 0xc8, 0x62, 0x49, - 0xda, 0x32, 0x38, 0x29, 0xda, 0xa6, 0xb1, 0x3e, 0x32, 0xbd, 0x32, 0x0c, - 0x50, 0x34, 0xa5, 0x08, 0x04, 0x7b, 0x96, 0x66, 0xfb, 0x8c, 0x5d, 0xa4, - 0x13, 0xed, 0x0a, 0x3e, 0xe4, 0xcd, 0x03, 0x75, 0x22, 0xee, 0x9a, 0x7d, - 0x1f, 0x99, 0x69, 0x59, 0xca, 0xa3, 0x0c, 0x0d, 0x15, 0xb3, 0xa3, 0x07, - 0x16, 0xae, 0xa8, 0xcf, 0xdc, 0xec, 0xd3, 0xeb, 0x10, 0xf2, 0xc5, 0xa2, - 0xb3, 0x47, 0x0c, 0x9d, 0x53, 0x58, 0xde, 0xbd, 0xa1, 0x0d, 0xfc, 0x01, - 0x51, 0x12, 0x36, 0x9a, 0xf2, 0x13, 0x0c, 0xeb, 0xa1, 0x9f, 0x41, 0x65, - 0xeb, 0x9c, 0x17, 0xc6, 0x7a, 0x35, 0xee, 0xde, 0xfb, 0xba, 0xa5, 0x46, - 0x51, 0x96, 0xf8, 0x65, 0xbf, 0x83, 0x53, 0x02, 0xbb, 0xa3, 0x76, 0xe3, - 0x2b, 0x87, 0x2d, 0xd2, 0x4d, 0xdc, 0xa3, 0x36, 0x8b, 0xe8, 0x5d, 0xbb, - 0xdb, 0x55, 0xe3, 0xca, 0xca, 0xbc, 0xa2, 0xd7, 0x8d, 0x24, 0x4f, 0x90, - 0xc7, 0x27, 0xd1, 0xf4, 0x05, 0x56, 0xdd, 0xc7, 0x1d, 0x6b, 0xab, 0x36, - 0x4c, 0xdf, 0x56, 0x45, 0x7d, 0x67, 0xad, 0x2c, 0x01, 0xb4, 0x5c, 0x90, - 0xf9, 0x34, 0x8a, 0xb2, 0xe2, 0x10, 0xe3, 0x4a, 0x89, 0x01, 0xe0, 0xda, - 0xb1, 0x3f, 0x47, 0x30, 0x9f, 0xb1, 0x62, 0xf2, 0x42, 0x7f, 0xa3, 0xbb, - 0xcc, 0x34, 0x69, 0xb7, 0xa1, 0x5b, 0x3c, 0xe2, 0xc7, 0xc6, 0xfa, 0x33, - 0x5c, 0xc0, 0xd7, 0x93, 0xe1, 0xd5, 0x00, 0xcb, 0x41, 0x42, 0x92, 0xc2, - 0x80, 0x10, 0x2d, 0x52, 0x4a, 0x33, 0xbf, 0x19, 0xb2, 0x0d, 0x5f, 0x8a, - 0xac, 0x6d, 0xf7, 0x3c, 0xe1, 0xa6, 0x34, 0xb5, 0x76, 0xa5, 0x70, 0x5d, - 0x16, 0xb7, 0xa5, 0x46, 0x65, 0x39, 0xfe, 0xde, 0xbc, 0x61, 0x8c, 0x4d, - 0xfc, 0x7c, 0xe1, 0x61, 0xf8, 0xb0, 0x93, 0x17, 0x57, 0x4b, 0xfd, 0x60, - 0x32, 0x35, 0xc5, 0x0e, 0xf8, 0x11, 0xef, 0x80, 0x9f, 0x80, 0x96, 0x04, - 0x53, 0x22, 0x54, 0xb0, 0xcb, 0xc6, 0x8c, 0x84, 0xdb, 0x27, 0x52, 0x44, - 0x3d, 0xc6, 0x21, 0xce, 0xcc, 0x88, 0xd7, 0x38, 0xd3, 0x00, 0x6e, 0x67, - 0xd4, 0xed, 0xd3, 0x66, 0xc6, 0xd7, 0x8d, 0x0f, 0xc7, 0x44, 0x42, 0x90, - 0x6f, 0xfb, 0xf6, 0x27, 0x7a, 0x83, 0x33, 0x70, 0xa4, 0x1f, 0x1e, 0xb4, - 0x7f, 0x1c, 0x5a, 0xb0, 0xec, 0x0b, 0x9f, 0x7c, 0x5c, 0x7a, 0x55, 0x31, - 0xa2, 0xc0, 0x72, 0x43, 0xb4, 0xa9, 0x81, 0x69, 0x65, 0xa4, 0x94, 0x7e, - 0x50, 0xbc, 0xa4, 0x5d, 0x6b, 0x5b, 0xdd, 0xa7, 0xc2, 0xbd, 0x16, 0x31, - 0xa1, 0x53, 0x87, 0x7b, 0x3b, 0x7f, 0xa6, 0x20, 0x42, 0x6e, 0x1f, 0xe1, - 0xbd, 0x86, 0x28, 0x8d, 0x91, 0x0d, 0xc7, 0xf8, 0x31, 0xc7, 0x5f, 0xc2, - 0xb9, 0x24, 0xdb, 0xdf, 0x08, 0x85, 0x27, 0xfd, 0xb7, 0xa2, 0x86, 0xad, - 0xfe, 0x59, 0x5a, 0x39, 0x67, 0x11, 0x7d, 0x08, 0xdf, 0xef, 0x7c, 0x1e, - 0xa5, 0x22, 0x0f, 0x00, 0x11, 0xf0, 0x35, 0xc6, 0xe0, 0xaa, 0x1f, 0x55, - 0xeb, 0xfe, 0x81, 0xac, 0xbf, 0xd7, 0xfd, 0xeb, 0x1f, 0x17, 0x9c, 0xe3, - 0x7a, 0xe0, 0x3e, 0xe2, 0xef, 0xb7, 0x35, 0xbf, 0x78, 0x12, 0x4c, 0x9e, - 0xb1, 0xec, 0x65, 0xdb, 0x44, 0x6d, 0x81, 0x1b, 0x15, 0x90, 0xec, 0x94, - 0x38, 0xd1, 0xc9, 0x31, 0x21, 0x8a, 0x4f, 0x0b, 0xf3, 0x6f, 0x1d, 0xee, - 0x34, 0x14, 0xdb, 0xcd, 0xd2, 0xea, 0x0f, 0xd5, 0xff, 0x02, 0x36, 0x3c, - 0xbd, 0x40, 0x33, 0xce, 0x02, 0x94, 0x39, 0x22, 0xa7, 0x08, 0x3f, 0xd1, - 0xee, 0x0c, 0x33, 0x65, 0xb1, 0xf5, 0xe7, 0x43, 0x74, 0x63, 0xc8, 0x3c, - 0x5a, 0xbb, 0x9c, 0x86, 0x0d, 0x7d, 0x9d, 0x68, 0xaf, 0xaf, 0xcd, 0x3c, - 0x56, 0x0f, 0x50, 0x1a, 0x2d, 0x39, 0xe8, 0x92, 0xab, 0x86, 0xb3, 0x6f, - 0xa4, 0x6e, 0xe4, 0x57, 0xe8, 0xb7, 0x0e, 0x1b, 0x95, 0x14, 0xf9, 0x4c, - 0xb4, 0xdc, 0x19, 0x32, 0x42, 0x63, 0x72, 0x19, 0xa4, 0x6d, 0xb0, 0xef, - 0xe2, 0xb5, 0x59, 0xcf, 0xfc, 0x4f, 0xcf, 0xe2, 0x6c, 0x14, 0xd5, 0xb7, - 0x6f, 0x8b, 0x64, 0x93, 0x03, 0xca, 0x50, 0xf5, 0x31, 0x27, 0xbd, 0x3c, - 0xb2, 0x9f, 0xdc, 0xe6, 0x93, 0x31, 0xb2, 0xac, 0x4b, 0xe7, 0x3e, 0x11, - 0xf9, 0x4c, 0xb8, 0x9c, 0xa6, 0xe5, 0x75, 0x25, 0x98, 0xaf, 0x20, 0x47, - 0x14, 0x81, 0x35, 0xc7, 0xd3, 0x00, 0x0d, 0xa3, 0x2a, 0xe0, 0x36, 0x26, - 0x3a, 0xd9, 0x67, 0x85, 0xfa, 0x85, 0x87, 0x41, 0x64, 0x7a, 0x20, 0x5b, - 0x4a, 0x35, 0x6c, 0x95, 0x51, 0x2a, 0x1a, 0xc7, 0x04, 0x9f, 0x31, 0x7b, - 0x43, 0xa2, 0xcd, 0x3a, 0x8a, 0x6e, 0x63, 0x91, 0x79, 0x2f, 0x05, 0x56, - 0x3b, 0xab, 0xe9, 0x51, 0x3f, 0x05, 0x5b, 0x61, 0xa6, 0x43, 0xbf, 0x54, - 0x88, 0xdc, 0x24, 0x33, 0x4a, 0xc0, 0x67, 0x7b, 0xe5, 0x58, 0x0c, 0xd4, - 0xec, 0x98, 0x98, 0x26, 0xd1, 0xf6, 0xec, 0xf3, 0x51, 0xe3, 0x6c, 0xa1, - 0x6f, 0xcc, 0xcb, 0xc4, 0x8d, 0x1a, 0x69, 0x9f, 0x7e, 0x5d, 0xbd, 0x2c, - 0x21, 0x75, 0xa8, 0x7c, 0xe5, 0x57, 0xc4, 0x7a, 0x72, 0xa8, 0xea, 0xea, - 0x3e, 0xc7, 0xa2, 0xe0, 0x1b, 0x2a, 0x37, 0xb9, 0xc3, 0x84, 0x14, 0xed, - 0xe8, 0x31, 0x76, 0x07, 0xdc, 0x31, 0x64, 0xb0, 0x4c, 0xd2, 0x07, 0x8a, - 0x00, 0x25, 0x0d, 0x59, 0x17, 0x35, 0x51, 0x42, 0x64, 0xdb, 0x1f, 0x6f, - 0x42, 0x96, 0x4e, 0xa2, 0x09, 0xea, 0xcd, 0xd4, 0x2a, 0x08, 0x0e, 0xe9, - 0x94, 0xe8, 0x8a, 0xfe, 0x00, 0xe3, 0xb8, 0x0c, 0xc5, 0x27, 0xb6, 0x4e, - 0xd4, 0xb2, 0x84, 0x27, 0x7b, 0x93, 0x69, 0x64, 0xa9, 0x2f, 0x03, 0x0f, - 0x93, 0x1b, 0x7d, 0xf5, 0x2b, 0xac, 0x9e, 0xae, 0x44, 0x50, 0x23, 0xc9, - 0xef, 0xf1, 0x13, 0xbb, 0x21, 0xf5, 0x59, 0x7a, 0x9c, 0xa7, 0x4f, 0x81, - 0xf9, 0xc1, 0x3a, 0xcf, 0x2b, 0x3c, 0x54, 0x38, 0x6c, 0x2c, 0xe8, 0xa7, - 0x50, 0x35, 0xfc, 0x7e, 0xe9, 0x13, 0xb7, 0xc2, 0xee, 0xf5, 0x81, 0x36, - 0x08, 0x44, 0x58, 0xa4, 0xc6, 0x38, 0xc0, 0x02, 0xe5, 0x97, 0x90, 0xf9, - 0x90, 0x91, 0x4f, 0x9a, 0xa3, 0x7f, 0x98, 0x28, 0x43, 0xfc, 0x17, 0xfb, - 0x48, 0xb7, 0x8d, 0x37, 0x55, 0xe6, 0x97, 0xfb, 0x5d, 0xa9, 0x39, 0xf6, - 0xf7, 0xe7, 0xc8, 0xae, 0x33, 0xc2, 0xef, 0x72, 0x7e, 0x94, 0x89, 0x07, - 0xb5, 0x94, 0xf6, 0x01, 0x2b, 0x45, 0x8f, 0x6a, 0x43, 0x4d, 0x1c, 0xa5, - 0xf8, 0x90, 0x3e, 0x1e, 0xeb, 0x46, 0x43, 0xcb, 0x2f, 0x43, 0xeb, 0xb4, - 0x25, 0xc9, 0xba, 0xc0, 0x47, 0x6a, 0xc9, 0xcf, 0xcb, 0x0c, 0xfa, 0x44, - 0x58, 0x76, 0x86, 0x41, 0xc5, 0x7b, 0x76, 0x17, 0xea, 0x62, 0x3a, 0x12, - 0xf4, 0xbe, 0x72, 0xe2, 0xa7, 0x63, 0x35, 0x0b, 0x24, 0x3e, 0x44, 0x0e, - 0xc5, 0x96, 0x67, 0x3c, 0x74, 0x63, 0x48, 0x4d, 0xec, 0x22, 0xb9, 0x1e, - 0x6f, 0x17, 0x81, 0x2a, 0xc2, 0xd4, 0x07, 0x4e, 0x5a, 0xfa, 0xd2, 0x54, - 0xd5, 0x43, 0xa4, 0xeb, 0x5b, 0xb5, 0x30, 0x9b, 0x7d, 0xd3, 0xc2, 0xd5, - 0x6c, 0x61, 0xef, 0xd1, 0x19, 0x5e, 0x74, 0x4a, 0xc9, 0x92, 0xb2, 0xb6, - 0xf4, 0xf0, 0x01, 0x6e, 0xe5, 0xb5, 0xe1, 0xc5, 0x19, 0xcf, 0xa4, 0x0f, - 0x53, 0x7d, 0x17, 0xfc, 0x8f, 0xdd, 0x7e, 0xbd, 0x0e, 0xf8, 0x21, 0x87, - 0xbc, 0x5c, 0xf4, 0xd6, 0xf2, 0x57, 0x21, 0xe4, 0x5d, 0xb9, 0xa2, 0xfb, - 0x72, 0x1f, 0xdf, 0xf6, 0xdb, 0xbd, 0x76, 0x1b, 0x03, 0x81, 0x55, 0x5c, - 0x06, 0x49, 0x32, 0xa7, 0xde, 0x87, 0xba, 0x3e, 0x3d, 0x0f, 0x1d, 0xf3, - 0x62, 0xf9, 0x4d, 0x45, 0x6e, 0xc4, 0x8e, 0x88, 0x55, 0x52, 0x9b, 0xdb, - 0xe2, 0xdd, 0x3e, 0xe3, 0x0e, 0x55, 0x54, 0xec, 0x73, 0xe2, 0xca, 0x40, - 0xf9, 0x9c, 0x42, 0xde, 0xb7, 0x92, 0x15, 0x62, 0x6e, 0x78, 0x45, 0x7f, - 0x6b, 0x83, 0x41, 0xde, 0xb6, 0xd8, 0x96, 0x5d, 0x90, 0x97, 0x2a, 0xe5, - 0xf3, 0xd0, 0xc7, 0x34, 0x22, 0xee, 0x2d, 0x29, 0x84, 0x8b, 0x8c, 0x4f, - 0x52, 0xef, 0x91, 0xe7, 0x3e, 0xf7, 0x36, 0x53, 0x58, 0x28, 0xea, 0x70, - 0x44, 0x69, 0x16, 0x88, 0x82, 0xa6, 0xe5, 0x6a, 0x97, 0x8a, 0x71, 0x1c, - 0xe6, 0xf4, 0x66, 0x22, 0x70, 0x9f, 0x75, 0x39, 0x97, 0x88, 0xda, 0x76, - 0xf8, 0x8b, 0xf0, 0xe8, 0xad, 0x29, 0xc0, 0x83, 0x1d, 0xeb, 0xb7, 0x83, - 0xf2, 0x7a, 0x34, 0xa1, 0x22, 0x41, 0xd0, 0x4f, 0xb3, 0x37, 0x10, 0x90, - 0x64, 0x40, 0x1d, 0xb2, 0xed, 0xc8, 0x4d, 0x7c, 0x2b, 0x55, 0xe4, 0x78, - 0xcf, 0xc2, 0x2d, 0xbd, 0x7c, 0xdc, 0x94, 0xa9, 0x5f, 0xd2, 0x75, 0x42, - 0xb9, 0x44, 0x38, 0x26, 0x24, 0x71, 0x85, 0x05, 0xcd, 0xec, 0x1a, 0x8d, - 0x94, 0xe6, 0x16, 0x2f, 0x1e, 0x3c, 0xd7, 0x57, 0x89, 0x96, 0x12, 0x8f, - 0x49, 0x23, 0x68, 0xfc, 0xa6, 0xa0, 0x4e, 0x09, 0xf4, 0x33, 0xdf, 0x85, - 0x8d, 0xb3, 0xbd, 0x72, 0x49, 0x27, 0xaf, 0x9d, 0x67, 0x0f, 0xf0, 0x42, - 0xad, 0x01, 0x42, 0xb5, 0x34, 0x95, 0x77, 0x75, 0xd6, 0x2a, 0x8c, 0x64, - 0x53, 0x6f, 0x59, 0xbd, 0x4e, 0xba, 0x61, 0xae, 0xe6, 0x86, 0x8d, 0xb1, - 0x95, 0x21, 0xa1, 0xeb, 0x37, 0xc1, 0x79, 0x65, 0x70, 0xf7, 0x23, 0xb6, - 0xa6, 0x87, 0x14, 0xfa, 0xf9, 0xf4, 0x55, 0x04, 0xac, 0x3b, 0xbe, 0xdc, - 0x0e, 0xd1, 0x0f, 0x30, 0x67, 0x85, 0x6f, 0x24, 0x4e, 0x28, 0x1b, 0x15, - 0xc3, 0x26, 0xbc, 0xa1, 0x1e, 0xc7, 0x9c, 0xa4, 0xa9, 0x3e, 0x9f, 0x66, - 0x63, 0xef, 0xd4, 0x84, 0x1e, 0xad, 0x83, 0xe5, 0x88, 0x57, 0x1f, 0x57, - 0xe3, 0x71, 0x08, 0x39, 0x3e, 0x55, 0x3e, 0xb4, 0xdc, 0x8b, 0x7e, 0x49, - 0xce, 0x7b, 0x6c, 0xf3, 0xec, 0x1d, 0xf1, 0x31, 0xa5, 0x67, 0x66, 0x74, - 0x7d, 0xa6, 0xab, 0x34, 0x77, 0xff, 0x87, 0x38, 0x8b, 0xb6, 0xe4, 0x11, - 0xa4, 0xcb, 0x6c, 0x47, 0x3e, 0xc1, 0x56, 0x25, 0x6d, 0x0f, 0x85, 0x4a, - 0xe6, 0x5e, 0xf9, 0xda, 0xf1, 0x2f, 0xb3, 0x1c, 0x1f, 0xa3, 0x89, 0xee, - 0xba, 0x35, 0xbf, 0x5b, 0x70, 0x3b, 0x8f, 0x45, 0x4f, 0x5f, 0x5d, 0xdd, - 0x65, 0x60, 0xda, 0xca, 0xd8, 0x3b, 0x9a, 0x14, 0xb5, 0xd7, 0xd2, 0x1f, - 0x8d, 0xc5, 0x09, 0xbf, 0xa6, 0xc7, 0x09, 0xd7, 0x1b, 0xb3, 0xa1, 0x6f, - 0xf2, 0x9a, 0xa0, 0x17, 0x0b, 0x19, 0xfc, 0x11, 0x9e, 0x4f, 0x53, 0x8a, - 0x48, 0x1d, 0x41, 0xfe, 0xeb, 0x2f, 0x41, 0x2e, 0x58, 0xc9, 0x32, 0x52, - 0x96, 0x8f, 0x98, 0x6f, 0x90, 0xa9, 0xf6, 0x87, 0x6a, 0x83, 0x10, 0x13, - 0xb4, 0x2c, 0xcb, 0x6b, 0xaa, 0xea, 0x8b, 0xe9, 0x0a, 0x05, 0xbb, 0xbd, - 0xd4, 0x1c, 0x8c, 0xa4, 0x21, 0x6e, 0x08, 0x99, 0xcc, 0x6d, 0x5d, 0x18, - 0xe9, 0x13, 0x43, 0x91, 0xdd, 0x28, 0x1a, 0x2e, 0xb0, 0x72, 0x63, 0xbd, - 0x1f, 0x1f, 0x7a, 0xc6, 0x8f, 0xf2, 0x04, 0xae, 0x1d, 0x9a, 0x02, 0xec, - 0x8d, 0x53, 0x7d, 0xae, 0xf2, 0xf0, 0x2d, 0xec, 0x2a, 0xa4, 0xdd, 0xd8, - 0xbd, 0x01, 0x88, 0xc1, 0x91, 0xa8, 0xf5, 0x8f, 0x67, 0x65, 0x3d, 0xc0, - 0xee, 0x43, 0x5e, 0x66, 0xf7, 0x2b, 0x03, 0xc0, 0x46, 0x89, 0xde, 0xac, - 0x7d, 0x75, 0xae, 0x59, 0xbf, 0xae, 0x3f, 0x91, 0x13, 0xf0, 0x24, 0x84, - 0x88, 0xa4, 0xb9, 0x01, 0xd7, 0xe3, 0xe8, 0x2b, 0xde, 0x03, 0x48, 0xa3, - 0xdf, 0x6c, 0x08, 0xd1, 0xa2, 0x2f, 0x49, 0x88, 0xba, 0x75, 0x06, 0xc2, - 0x11, 0x03, 0x53, 0xb2, 0x4c, 0xb5, 0xd8, 0x37, 0xa3, 0xf9, 0x71, 0x29, - 0x38, 0x99, 0x2a, 0xb8, 0xf7, 0x28, 0x17, 0x66, 0xd8, 0x20, 0x89, 0x94, - 0x9d, 0x43, 0x97, 0x40, 0xd0, 0x02, 0xc6, 0x10, 0x60, 0x43, 0xe7, 0x5f, - 0xd9, 0x51, 0xda, 0xbb, 0xae, 0x5e, 0x66, 0xdc, 0x6c, 0x16, 0x0c, 0xc8, - 0x3c, 0x2e, 0x81, 0xc2, 0x6c, 0x2e, 0x8b, 0xdd, 0xd7, 0x79, 0x41, 0xed, - 0x14, 0x1b, 0x2e, 0x9d, 0x67, 0x0a, 0x38, 0x08, 0xdd, 0x48, 0xd2, 0xdf, - 0x58, 0xc5, 0xec, 0x6f, 0x24, 0x34, 0xfd, 0xe6, 0xda, 0x72, 0x81, 0xba, - 0xbb, 0xd5, 0xb0, 0xb8, 0x8e, 0x55, 0x3f, 0xf8, 0x95, 0x18, 0xdd, 0x92, - 0x87, 0x78, 0x65, 0x02, 0x0e, 0xd4, 0xa2, 0x25, 0x66, 0xb0, 0x86, 0x47, - 0xa1, 0xf0, 0xb7, 0xbc, 0x78, 0xfd, 0x33, 0x83, 0xf3, 0x53, 0x5b, 0x94, - 0x1b, 0x98, 0x1c, 0xa6, 0x8f, 0x9b, 0xbb, 0xab, 0x04, 0xa0, 0x7a, 0xa6, - 0x79, 0x5e, 0x60, 0x6a, 0xf5, 0x2b, 0x7f, 0x76, 0xbd, 0xec, 0xab, 0x06, - 0x3d, 0x48, 0x3a, 0xfd, 0x73, 0x35, 0x46, 0x31, 0xe1, 0x5b, 0xe7, 0x02, - 0x7c, 0x77, 0xdb, 0x91, 0x2c, 0x59, 0x35, 0x01, 0x09, 0xbb, 0x2e, 0x52, - 0x96, 0x88, 0x7e, 0x34, 0x00, 0x6b, 0xf7, 0xa3, 0xcb, 0x33, 0x8a, 0xb2, - 0x8e, 0xd8, 0x7c, 0x89, 0x72, 0xd5, 0x6f, 0xe2, 0x73, 0x7f, 0x5f, 0x92, - 0x00, 0x7e, 0x6a, 0xbe, 0x17, 0x12, 0xcb, 0xd8, 0x31, 0xdc, 0x3b, 0xb0, - 0x80, 0x70, 0x36, 0x8a, 0x1e, 0x94, 0x25, 0xfd, 0x6c, 0xe1, 0x6b, 0xd8, - 0x33, 0xb4, 0x8d, 0x24, 0x0e, 0xdc, 0x54, 0xc8, 0x7f, 0x19, 0x83, 0x3f, - 0x9e, 0x6e, 0x9e, 0xba, 0xa4, 0x6f, 0xfc, 0x91, 0xec, 0x76, 0x43, 0xf9, - 0xde, 0x1e, 0x92, 0xd3, 0xe6, 0x7d, 0x7e, 0x51, 0xfb, 0x13, 0x5f, 0x08, - 0xa8, 0xf0, 0x6f, 0xf0, 0x19, 0xf1, 0x5e, 0x2e, 0xcb, 0x22, 0xac, 0x9e, - 0x4c, 0x63, 0x18, 0x08, 0x72, 0xc0, 0x4d, 0xca, 0x0a, 0x40, 0xc7, 0x67, - 0x63, 0xbc, 0xf2, 0xf4, 0xe0, 0xe3, 0x92, 0x01, 0x1b, 0x7f, 0x63, 0xf1, - 0xa8, 0x4c, 0xf7, 0x1c, 0x0a, 0xbc, 0xd3, 0x30, 0x2f, 0x6b, 0x3e, 0x7e, - 0x9c, 0xd6, 0xcf, 0x68, 0x9a, 0x36, 0xf3, 0x4b, 0xc1, 0x49, 0x46, 0x93, - 0x11, 0x42, 0x2d, 0x2d, 0x9c, 0xd2, 0x3d, 0xb9, 0x5f, 0x4e, 0xbe, 0x12, - 0xdd, 0x63, 0x65, 0x30, 0x06, 0x91, 0x25, 0x87, 0x83, 0xb2, 0x6c, 0x6b, - 0xf4, 0x84, 0xab, 0xcf, 0xaa, 0x9a, 0x0e, 0xbf, 0x07, 0xb0, 0x09, 0x6b, - 0x06, 0x06, 0x3c, 0x0e, 0x27, 0x2f, 0x11, 0x20, 0xec, 0x20, 0x22, 0xa8, - 0xb5, 0xd2, 0xfe, 0x18, 0x8b, 0x0f, 0x29, 0x90, 0x06, 0x95, 0x53, 0x41, - 0xcf, 0x01, 0x04, 0xf0, 0xb7, 0x64, 0x79, 0x73, 0x07, 0x33, 0x63, 0x24, - 0x47, 0x35, 0xf2, 0x1a, 0xd8, 0x72, 0xc6, 0x80, 0x9f, 0x99, 0x97, 0xc9, - 0xea, 0x0c, 0x4d, 0x9f, 0x1e, 0x7e, 0xe8, 0x7d, 0x20, 0x97, 0x58, 0x7d, - 0xae, 0x4e, 0xb4, 0xe4, 0xcc, 0x71, 0x01, 0xe4, 0x57, 0xd6, 0xbc, 0x4d, - 0x5d, 0x99, 0xf1, 0xc0, 0xc4, 0x4c, 0xb7, 0x1f, 0x09, 0x97, 0x39, 0xd2, - 0x85, 0x67, 0x32, 0x6e, 0xc5, 0xf6, 0x2a, 0x3e, 0x82, 0x08, 0x93, 0x4b, - 0xf5, 0xd9, 0x08, 0x4e, 0x0b, 0x94, 0xa1, 0x60, 0x90, 0x1d, 0xed, 0xa6, - 0xec, 0x9d, 0x1c, 0xba, 0x0d, 0xf7, 0x14, 0x95, 0xe9, 0x41, 0xfb, 0x6b, - 0xb1, 0xcd, 0xfe, 0x59, 0x29, 0x62, 0xc0, 0x0c, 0xfe, 0x31, 0x32, 0x59, - 0x23, 0xbf, 0xb3, 0xfa, 0xec, 0x05, 0x14, 0xc4, 0xb1, 0x5a, 0x73, 0x9d, - 0x81, 0xbb, 0xc0, 0xb3, 0x79, 0xf5, 0x9d, 0x04, 0x8b, 0x32, 0x95, 0x28, - 0x78, 0xef, 0x9a, 0x4b, 0xd6, 0x89, 0x3b, 0x17, 0x36, 0x8a, 0x10, 0xdf, - 0xfa, 0x4b, 0x14, 0x8f, 0x11, 0x2c, 0xc5, 0x85, 0x59, 0x92, 0x8a, 0xd7, - 0x7d, 0x7d, 0x5f, 0xc2, 0xe7, 0x77, 0x93, 0x9f, 0xaf, 0xaa, 0xd3, 0xb4, - 0x79, 0xc2, 0x76, 0x44, 0xb3, 0xee, 0x26, 0x1d, 0x5a, 0x6f, 0x3f, 0x14, - 0x80, 0x19, 0xdd, 0xb3, 0x23, 0x63, 0x94, 0x24, 0x2e, 0x45, 0x9c, 0x50, - 0x0f, 0x47, 0x81, 0x35, 0x66, 0xa5, 0x3a, 0x77, 0xb7, 0xd0, 0x9c, 0x25, - 0x78, 0x8f, 0xac, 0x3b, 0x8d, 0x78, 0xcb, 0x78, 0xfb, 0x77, 0x7c, 0x74, - 0x32, 0x3b, 0x77, 0x0c, 0x64, 0x98, 0x32, 0x89, 0x12, 0xfd, 0x71, 0xd6, - 0xb9, 0xf3, 0xc7, 0x20, 0x2b, 0x0e, 0xfd, 0x57, 0x62, 0x60, 0x15, 0x02, - 0x3c, 0x4d, 0x5d, 0xb8, 0x32, 0xe7, 0xfe, 0x1c, 0x98, 0xba, 0x1f, 0x0e, - 0x32, 0x1b, 0xe4, 0x1d, 0xf0, 0xa1, 0x89, 0xed, 0x1e, 0x3e, 0xf8, 0x4c, - 0xf5, 0xca, 0x69, 0x05, 0x5e, 0xe2, 0x0b, 0x4c, 0x90, 0x14, 0x99, 0x0a, - 0xf9, 0xa6, 0xb7, 0x61, 0xf6, 0xca, 0x25, 0x01, 0x50, 0x57, 0xf2, 0x51, - 0xb6, 0x0c, 0x36, 0x20, 0xad, 0x0b, 0x4f, 0x9c, 0x73, 0xc8, 0xdd, 0x27, - 0x26, 0x54, 0xf0, 0xc7, 0x8c, 0x1c, 0x70, 0x48, 0xf0, 0x0a, 0x58, 0xb6, - 0x85, 0xa7, 0xb5, 0x20, 0x90, 0x8e, 0xc8, 0x9c, 0x29, 0xc1, 0x56, 0xdf, - 0xf0, 0x21, 0xfe, 0xde, 0x33, 0x89, 0x80, 0x04, 0xd9, 0xed, 0xa2, 0xd4, - 0x64, 0x68, 0xb7, 0x5d, 0x7f, 0x6b, 0x71, 0x22, 0xa4, 0xf2, 0x82, 0x6c, - 0xc4, 0xc2, 0xbd, 0xf8, 0x03, 0x9a, 0xd8, 0xbf, 0xe1, 0x30, 0x1b, 0x4d, - 0x1d, 0xbf, 0x81, 0xa6, 0xa5, 0x83, 0x3c, 0x5d, 0x90, 0xad, 0xfd, 0xd2, - 0x65, 0x70, 0x89, 0x59, 0xdf, 0x10, 0xba, 0x8d, 0x8a, 0xe9, 0x4a, 0xb1, - 0x03, 0xde, 0xa6, 0x8b, 0xd2, 0xdb, 0x4b, 0xed, 0x08, 0x81, 0xf6, 0x43, - 0xad, 0xac, 0xe7, 0x06, 0xbf, 0xa3, 0x84, 0x39, 0x1f, 0x51, 0xb7, 0xdd, - 0x38, 0xa8, 0xce, 0x84, 0xa1, 0x66, 0x62, 0x0e, 0xb2, 0x5c, 0xea, 0x72, - 0xde, 0xc2, 0xd1, 0x55, 0x39, 0x0c, 0xbc, 0x26, 0x74, 0x22, 0xfc, 0xfc, - 0x5b, 0x9b, 0x3b, 0xf8, 0x39, 0x11, 0xbb, 0x64, 0x85, 0x6f, 0xa8, 0xf5, - 0x55, 0x04, 0x26, 0xe5, 0x51, 0xe3, 0xaa, 0x29, 0xc7, 0x9c, 0x9c, 0xae, - 0x89, 0xa9, 0xec, 0xb9, 0x29, 0xcc, 0x7b, 0x36, 0xe2, 0x07, 0xe3, 0x74, - 0x82, 0x90, 0x07, 0xf5, 0x89, 0xd3, 0xf7, 0xe0, 0xa5, 0x9b, 0xf0, 0x41, - 0xca, 0xb9, 0x12, 0x7a, 0x98, 0xb2, 0xcb, 0xd7, 0xe5, 0xc9, 0x76, 0x1c, - 0x84, 0x8a, 0xf3, 0x34, 0xce, 0xca, 0x04, 0xce, 0x23, 0x63, 0x5b, 0x63, - 0x01, 0xa0, 0x70, 0x7c, 0xed, 0xdd, 0x57, 0xb7, 0x9e, 0x3e, 0xee, 0x8c, - 0x76, 0x5e, 0x3e, 0x58, 0x4a, 0x6c, 0x94, 0xe2, 0xf2, 0x77, 0x85, 0x0f, - 0x16, 0x37, 0x16, 0x65, 0xb3, 0xc9, 0xe1, 0x6f, 0xe3, 0x6b, 0x15, 0xad, - 0x8d, 0x57, 0x44, 0x37, 0x13, 0x3b, 0x0d, 0x95, 0x97, 0xf5, 0x32, 0x44, - 0xf1, 0x04, 0x9a, 0xc2, 0x93, 0xe4, 0x3e, 0x3d, 0x60, 0x8e, 0xde, 0x44, - 0x95, 0x70, 0xea, 0x0b, 0xc3, 0xd6, 0xb2, 0x3d, 0x45, 0xce, 0x3f, 0xa7, - 0x7b, 0x47, 0x18, 0x31, 0xc3, 0xd6, 0x5b, 0x8c, 0x01, 0x10, 0x36, 0x2a, - 0xc1, 0xbf, 0xf0, 0x01, 0x14, 0xb2, 0xdc, 0xa0, 0xa0, 0x75, 0x93, 0x55, - 0xfc, 0xa3, 0xd7, 0x05, 0x3b, 0xdb, 0x3b, 0x05, 0x8b, 0x58, 0x9b, 0xf7, - 0xd3, 0xde, 0xae, 0x0f, 0x4b, 0x4b, 0x7b, 0x73, 0x30, 0x70, 0x7a, 0x71, - 0xe4, 0xb9, 0x91, 0x8a, 0x5e, 0xe5, 0x08, 0x5b, 0x1f, 0x28, 0xd4, 0x88, - 0x74, 0xc5, 0x05, 0x32, 0xec, 0x24, 0x59, 0x85, 0xb5, 0xe0, 0x80, 0xe8, - 0x5a, 0xb3, 0x7b, 0xb8, 0x72, 0x5e, 0x9b, 0x84, 0x54, 0x18, 0x07, 0xae, - 0xdf, 0xea, 0x86, 0xbb, 0xcc, 0x09, 0xe8, 0x88, 0x84, 0x40, 0xa8, 0xe1, - 0x3e, 0x56, 0x5f, 0x6a, 0xfc, 0x5e, 0x31, 0x82, 0x12, 0x4c, 0xa0, 0xc5, - 0x61, 0x6e, 0xe4, 0x1a, 0x39, 0x42, 0xf0, 0x1b, 0x33, 0x90, 0x05, 0xf7, - 0xee, 0x8c, 0x5e, 0x1f, 0xf2, 0xbe, 0x83, 0x9b, 0x29, 0x41, 0x71, 0x4c, - 0x62, 0xb6, 0xbc, 0x2b, 0xe6, 0x57, 0x1f, 0x02, 0x80, 0x62, 0x5a, 0x82, - 0xac, 0x85, 0xaf, 0x1b, 0x02, 0xd9, 0xe4, 0x3f, 0x14, 0x36, 0x86, 0x58, - 0x6d, 0xf8, 0x13, 0xe5, 0x56, 0xc0, 0x99, 0xa9, 0xdb, 0x81, 0xb0, 0x86, - 0x38, 0xc3, 0xdc, 0xe4, 0xb0, 0xda, 0xb6, 0x2d, 0x34, 0xf5, 0xaa, 0xa1, - 0xcc, 0x10, 0x34, 0x83, 0xde, 0x0c, 0x3d, 0xbf, 0xdd, 0x8f, 0x08, 0xa5, - 0xea, 0xd4, 0xd7, 0x8f, 0x1f, 0x84, 0xb9, 0xc1, 0x8b, 0x1f, 0xfa, 0x5a, - 0x7d, 0x58, 0xe4, 0xc1, 0xbc, 0xb8, 0x39, 0x8e, 0xb4, 0xb0, 0x7c, 0xc4, - 0x98, 0x1b, 0x32, 0x30, 0x63, 0xb8, 0xa5, 0xe8, 0x04, 0x54, 0xa3, 0x71, - 0x0f, 0xd0, 0xb1, 0xac, 0x87, 0x75, 0x3a, 0xdd, 0x47, 0x07, 0xef, 0xc8, - 0x67, 0xe6, 0xfd, 0x61, 0xe7, 0xe7, 0xa3, 0x83, 0x12, 0x67, 0xed, 0x1a, - 0xb4, 0xba, 0xef, 0x76, 0x12, 0x7b, 0x68, 0x4f, 0xb9, 0xd7, 0x3e, 0x60, - 0xcc, 0x1d, 0x3e, 0xb8, 0xdc, 0x71, 0xc1, 0xe9, 0xaa, 0x8b, 0xbb, 0x93, - 0x27, 0x4b, 0x84, 0xcf, 0xb9, 0xac, 0xf5, 0x3c, 0xd2, 0x6c, 0x3a, 0xf7, - 0xb2, 0xce, 0x87, 0x27, 0x47, 0x6b, 0x7f, 0xad, 0xfc, 0x54, 0x0f, 0x33, - 0x62, 0x3d, 0x9f, 0x5c, 0xef, 0xef, 0x6a, 0x2f, 0x2e, 0x62, 0xeb, 0xbf, - 0x71, 0x35, 0xcf, 0xbf, 0xf2, 0x2a, 0xa5, 0x50, 0x66, 0xb6, 0x59, 0x92, - 0xd6, 0xd5, 0x27, 0xd0, 0xc5, 0x04, 0x64, 0x34, 0x96, 0x74, 0xd6, 0xb6, - 0x7a, 0x12, 0xf2, 0xb8, 0xfd, 0x8a, 0x23, 0x29, 0x4d, 0x7b, 0xa3, 0x60, - 0xbf, 0xe2, 0xa4, 0x46, 0x30, 0x04, 0xde, 0xf1, 0xab, 0x71, 0x57, 0x0f, - 0xc6, 0xd6, 0x81, 0x7d, 0x8f, 0x76, 0x52, 0x05, 0x43, 0x3b, 0xa5, 0x5c, - 0x19, 0x19, 0x0c, 0x60, 0xe1, 0x84, 0x94, 0x97, 0xb4, 0xed, 0x8c, 0xc7, - 0x69, 0xc0, 0x32, 0x7e, 0xb8, 0xf9, 0xed, 0xca, 0xb7, 0x4e, 0xe4, 0xd3, - 0x77, 0x39, 0x4d, 0xb6, 0xc7, 0xfa, 0x77, 0xd4, 0x3f, 0x8e, 0x60, 0x62, - 0x08, 0x0c, 0x20, 0xd7, 0xf4, 0xa3, 0x23, 0xca, 0x93, 0xac, 0xa0, 0x16, - 0xfb, 0xfe, 0x95, 0xf0, 0x70, 0xdb, 0xc8, 0xeb, 0x7c, 0x58, 0x03, 0x9b, - 0xd9, 0xc8, 0xc5, 0xef, 0x63, 0xef, 0xbb, 0x7a, 0xd5, 0xa9, 0x4e, 0x05, - 0x7c, 0x52, 0xfe, 0x08, 0x4b, 0x65, 0x90, 0x86, 0x84, 0x56, 0x70, 0x12, - 0x86, 0x90, 0xa2, 0xc3, 0xea, 0x63, 0xb4, 0xc0, 0x16, 0x42, 0x96, 0x7b, - 0x65, 0x78, 0x0d, 0xe8, 0x85, 0xf4, 0x13, 0x59, 0xab, 0xee, 0x75, 0x60, - 0xc6, 0x15, 0xb5, 0x39, 0x28, 0x11, 0x80, 0xde, 0xd8, 0x2f, 0xad, 0x73, - 0x0f, 0x75, 0x87, 0x42, 0x7f, 0xaa, 0x01, 0xfc, 0x25, 0x67, 0x66, 0xea, - 0xb1, 0x35, 0x98, 0xf8, 0xd2, 0x31, 0xcf, 0xb8, 0x75, 0x7b, 0xa1, 0x7e, - 0xec, 0x75, 0x85, 0xd1, 0x41, 0xe8, 0xc2, 0x6c, 0x3e, 0x56, 0xb0, 0x0c, - 0x62, 0xec, 0xdc, 0xca, 0xfc, 0xe6, 0x29, 0xb4, 0x8c, 0x49, 0x37, 0x03, - 0x37, 0xfa, 0x32, 0x29, 0x85, 0x92, 0xf9, 0x48, 0x8c, 0x67, 0xd9, 0x0b, - 0x1c, 0xe2, 0xd9, 0xd0, 0x9f, 0x7c, 0xc9, 0xc8, 0xef, 0x96, 0xe2, 0xea, - 0xc1, 0xcf, 0x9c, 0x91, 0x33, 0x62, 0x3a, 0x60, 0x50, 0xb0, 0x9e, 0x2a, - 0x57, 0x41, 0x6e, 0xeb, 0x9f, 0x1f, 0x52, 0xad, 0xb9, 0xbc, 0x70, 0xe0, - 0x37, 0x1a, 0x22, 0xea, 0x2c, 0x49, 0xe6, 0xb2, 0xbc, 0xde, 0x23, 0x0f, - 0x7d, 0xc3, 0xe3, 0x00, 0x96, 0x86, 0xef, 0xe5, 0xa3, 0x07, 0x74, 0xf5, - 0x79, 0xdb, 0xe0, 0x9f, 0xa5, 0xee, 0xf0, 0x08, 0xbd, 0xd1, 0x5f, 0x44, - 0xf0, 0x44, 0xad, 0xa1, 0x29, 0xf4, 0x38, 0x62, 0x16, 0x22, 0xbf, 0x17, - 0xe2, 0xb3, 0xad, 0x3c, 0x59, 0x35, 0x44, 0x19, 0x87, 0xf2, 0x8e, 0xdc, - 0x64, 0xb1, 0x9a, 0x77, 0x6d, 0x5a, 0xfe, 0x72, 0x29, 0x32, 0xcb, 0x6a, - 0x6a, 0x3c, 0x00, 0x43, 0x06, 0x8b, 0xbd, 0xac, 0x84, 0xb2, 0x5e, 0x3b, - 0x4d, 0xe0, 0x51, 0x14, 0xa2, 0x04, 0xf2, 0x36, 0xc1, 0x6c, 0x5e, 0x3c, - 0x77, 0x1e, 0x8f, 0xb6, 0xe1, 0x58, 0x56, 0x35, 0x2d, 0x7b, 0xe9, 0xf8, - 0xd3, 0x05, 0x20, 0xc1, 0x03, 0x5a, 0xf5, 0x2d, 0xb5, 0x26, 0xe2, 0xea, - 0x9d, 0x10, 0xa6, 0xe0, 0xba, 0x70, 0x26, 0xa3, 0x12, 0x3e, 0xd6, 0x89, - 0x24, 0xf2, 0xcf, 0xfe, 0x89, 0xcc, 0x47, 0xfc, 0x60, 0x65, 0x14, 0xf2, - 0xc0, 0x72, 0x02, 0x76, 0x77, 0x01, 0x98, 0xfa, 0x77, 0x4d, 0xe4, 0xef, - 0xc0, 0x63, 0xfa, 0xf9, 0xfb, 0xd3, 0x3c, 0x60, 0x23, 0x80, 0x57, 0xc9, - 0x05, 0x4f, 0x79, 0xac, 0x58, 0xdc, 0xc7, 0x1c, 0x47, 0xd0, 0xe9, 0x78, - 0xee, 0x47, 0xe0, 0x00, 0x49, 0xb4, 0xaf, 0x37, 0x77, 0x5e, 0x6d, 0xb3, - 0x58, 0xc4, 0x82, 0x71, 0xdf, 0x96, 0x31, 0xab, 0x05, 0x3a, 0x66, 0x3b, - 0x8e, 0xd7, 0x71, 0xbe, 0x00, 0xb4, 0x01, 0x2b, 0x64, 0x0a, 0x10, 0x05, - 0xb8, 0x46, 0xa1, 0x90, 0x7e, 0xb7, 0x71, 0x0f, 0x2c, 0x62, 0x9f, 0xcf, - 0xfc, 0xd3, 0xbf, 0x45, 0x8d, 0x8e, 0xe7, 0x90, 0x96, 0x64, 0x8f, 0x33, - 0x27, 0x83, 0x27, 0xf0, 0x52, 0x74, 0xcc, 0x51, 0xa6, 0x28, 0xb8, 0x32, - 0x7b, 0xa6, 0xa3, 0xfe, 0x17, 0xec, 0x00, 0x11, 0x08, 0x48, 0x27, 0x78, - 0x78, 0x52, 0xc3, 0x46, 0x08, 0xa6, 0xbd, 0x45, 0xdf, 0x6d, 0xfb, 0x47, - 0xdc, 0xf9, 0x52, 0x46, 0xba, 0xb1, 0x81, 0xbc, 0xb8, 0x68, 0x60, 0x6a, - 0xda, 0x32, 0x50, 0x18, 0x03, 0xfa, 0xf2, 0xa1, 0x6f, 0xec, 0x61, 0xac, - 0xe1, 0xc5, 0x0d, 0xd0, 0x96, 0x37, 0x5e, 0x9a, 0x8e, 0xbf, 0x21, 0x24, - 0xce, 0x0c, 0xfa, 0xb1, 0xaf, 0xae, 0x35, 0xa8, 0xef, 0x89, 0x21, 0x9f, - 0x23, 0x5c, 0x0f, 0xfa, 0xdb, 0x63, 0x5f, 0xba, 0xc8, 0xae, 0x01, 0x24, - 0x88, 0xf9, 0x25, 0x61, 0x44, 0x96, 0x81, 0x75, 0xe8, 0x88, 0x0a, 0x23, - 0xeb, 0x8e, 0xd0, 0x53, 0xff, 0x85, 0xb1, 0x73, 0x9c, 0xdd, 0xf1, 0x9e, - 0x8e, 0xdf, 0x03, 0x43, 0x9f, 0x00, 0x2b, 0x0e, 0x18, 0x46, 0x30, 0x9b, - 0x9f, 0x08, 0x92, 0xf2, 0x27, 0xed, 0xa9, 0xb6, 0xfd, 0x4a, 0xc3, 0xc1, - 0x8d, 0x42, 0x8b, 0x82, 0x51, 0x34, 0x42, 0x49, 0x8c, 0xde, 0x67, 0x11, - 0x6e, 0x03, 0xc2, 0xf2, 0x8b, 0x6c, 0x4d, 0xdd, 0xe2, 0x92, 0x01, 0x97, - 0x64, 0x66, 0x2a, 0x62, 0xb0, 0xfb, 0xbc, 0x6b, 0xe3, 0x73, 0xa1, 0xbb, - 0xb6, 0x73, 0x06, 0x79, 0x56, 0x3c, 0x34, 0x35, 0xad, 0x7e, 0x32, 0x5e, - 0x0d, 0x65, 0x99, 0xc7, 0xd4, 0x9f, 0x86, 0xc9, 0x00, 0x7c, 0xdc, 0xb2, - 0x47, 0x0e, 0x6e, 0xe0, 0xc3, 0xa3, 0x33, 0xb0, 0xac, 0xd3, 0xcf, 0xba, - 0x80, 0x25, 0x63, 0x48, 0x70, 0xf8, 0x4c, 0x5f, 0xee, 0xd7, 0x07, 0x3d, - 0x0f, 0x27, 0x31, 0xd6, 0x71, 0x69, 0x46, 0x06, 0x84, 0x51, 0xd0, 0x5d, - 0xed, 0xb2, 0x9f, 0x1e, 0x84, 0xa1, 0x91, 0x32, 0x46, 0x75, 0x4a, 0xf2, - 0x59, 0x16, 0x31, 0xc7, 0x55, 0xb4, 0x31, 0xec, 0x29, 0x34, 0xcc, 0x0d, - 0x1b, 0x24, 0x18, 0x2d, 0xb7, 0x94, 0xe5, 0xe6, 0x7f, 0x2f, 0x9a, 0xea, - 0x40, 0xcb, 0x28, 0x42, 0xb3, 0x17, 0xc7, 0x05, 0x55, 0xca, 0xee, 0xe2, - 0x4d, 0x97, 0xfb, 0xa9, 0x5c, 0x32, 0xdb, 0x32, 0xd9, 0xa2, 0xdb, 0xed, - 0xdf, 0x57, 0x78, 0xf5, 0x64, 0x40, 0x9b, 0xe5, 0xf8, 0x19, 0x84, 0x2b, - 0xb2, 0xb5, 0xa8, 0xee, 0x28, 0x96, 0xdd, 0x2d, 0x88, 0xd3, 0xc9, 0x0a, - 0xdd, 0xc0, 0xf2, 0x6a, 0x28, 0xf9, 0xf6, 0xc0, 0xab, 0xa3, 0x88, 0x47, - 0x27, 0x87, 0x95, 0xa9, 0x79, 0x50, 0x36, 0x8e, 0x9b, 0xf8, 0x5b, 0x6b, - 0x69, 0xec, 0xb6, 0x36, 0x1f, 0xca, 0x51, 0xf4, 0x85, 0x13, 0xc2, 0x30, - 0x95, 0x23, 0xa1, 0xfe, 0x86, 0xc7, 0x3d, 0xdb, 0x72, 0xb3, 0xe3, 0xd0, - 0xa3, 0x76, 0xb7, 0x83, 0x30, 0x4c, 0x2a, 0xec, 0x5b, 0x29, 0x24, 0xa9, - 0x5b, 0x2b, 0x50, 0x6a, 0xe2, 0xb1, 0x8c, 0x4e, 0xc3, 0x88, 0xfe, 0xd6, - 0x43, 0xf4, 0xf7, 0xad, 0xff, 0x05, 0x7d, 0x16, 0xa7, 0x33, 0xdb, 0x22, - 0x9f, 0x2b, 0xa9, 0xcf, 0x88, 0xc7, 0x74, 0x3b, 0x95, 0xba, 0x74, 0xf6, - 0x14, 0x08, 0x95, 0x51, 0x3d, 0xcf, 0x34, 0xc0, 0xfd, 0x90, 0xb4, 0x74, - 0xa5, 0x18, 0x32, 0x48, 0x1f, 0x3a, 0xc9, 0xe2, 0xe2, 0x1b, 0xdf, 0x18, - 0x38, 0xbe, 0x8a, 0xbb, 0x8d, 0x88, 0x21, 0xd4, 0x62, 0xf8, 0x68, 0x90, - 0x97, 0xe8, 0x91, 0x2f, 0x6d, 0xab, 0x6d, 0xae, 0x4b, 0x4e, 0xe3, 0x66, - 0x59, 0x46, 0x9e, 0xb4, 0xb7, 0xa7, 0x1a, 0x07, 0x37, 0x77, 0xbb, 0x71, - 0x5e, 0xe1, 0x00, 0x44, 0xfe, 0xe4, 0x2e, 0xb2, 0x61, 0x48, 0x1a, 0x9a, - 0x49, 0x49, 0xdc, 0xbb, 0x87, 0x0b, 0x9d, 0x62, 0x90, 0xaf, 0xf0, 0x51, - 0x0d, 0x24, 0x9e, 0x96, 0x37, 0x93, 0x97, 0xe5, 0xbb, 0x89, 0x0e, 0x60, - 0x95, 0xa3, 0x79, 0x46, 0x3b, 0x73, 0x11, 0x83, 0x17, 0xf1, 0x0c, 0x86, - 0xb3, 0x40, 0x17, 0xe0, 0x62, 0xbd, 0xf3, 0xc5, 0x55, 0x39, 0x85, 0x25, - 0xac, 0x83, 0x80, 0x21, 0x41, 0xe1, 0x68, 0xcb, 0xca, 0x0a, 0x9d, 0xff, - 0xc0, 0x8f, 0x72, 0x8c, 0x20, 0x6f, 0xd5, 0xbe, 0x34, 0xd5, 0x65, 0x01, - 0xb0, 0xd3, 0xbc, 0xe5, 0x1e, 0xeb, 0xd2, 0xdf, 0x43, 0xb0, 0x23, 0x64, - 0xc7, 0x88, 0xe2, 0xeb, 0xe0, 0x7b, 0x88, 0xff, 0xf6, 0x6b, 0x5f, 0xa9, - 0xe5, 0xe9, 0xc4, 0xaf, 0x9f, 0xd5, 0xe1, 0xe2, 0x67, 0x0e, 0x06, 0xeb, - 0x74, 0x81, 0x7d, 0x04, 0x79, 0x0f, 0xa0, 0xe9, 0x6c, 0x4a, 0x4f, 0x3f, - 0xf7, 0x9f, 0x25, 0x1a, 0xdd, 0xb8, 0x44, 0xe3, 0x2e, 0xf0, 0xb5, 0x0b, - 0x51, 0x0f, 0x2a, 0x6b, 0x52, 0x6c, 0x72, 0x68, 0x6c, 0x92, 0x9d, 0x5c, - 0x33, 0x77, 0x46, 0x01, 0xea, 0x73, 0x46, 0x14, 0x29, 0xe2, 0xb0, 0x57, - 0x4a, 0x58, 0x89, 0x54, 0x01, 0xc8, 0xd3, 0x9b, 0xfa, 0x42, 0x64, 0x3d, - 0x2a, 0x0e, 0xe9, 0x92, 0x4d, 0x2c, 0xd6, 0xa7, 0x36, 0xdc, 0x6a, 0x29, - 0xbb, 0xfc, 0xca, 0xc1, 0x55, 0x48, 0x64, 0x5a, 0x7f, 0xa7, 0x2a, 0x92, - 0xa9, 0x70, 0x4a, 0x11, 0x07, 0x82, 0x93, 0x99, 0x39, 0x63, 0xe5, 0x51, - 0xfa, 0xe6, 0x9b, 0xa6, 0xe6, 0xd7, 0x73, 0xa0, 0x84, 0x5d, 0x18, 0xc7, - 0xb5, 0x5b, 0x35, 0xfa, 0xbb, 0x2e, 0x16, 0x77, 0x1b, 0xbb, 0xb1, 0x60, - 0x8c, 0x9a, 0xc3, 0x17, 0x38, 0xf6, 0xe7, 0x4b, 0x4a, 0x44, 0xfd, 0x55, - 0x00, 0xdb, 0x91, 0x38, 0xe9, 0xfc, 0xbb, 0xc8, 0x3e, 0x12, 0x14, 0x8c, - 0xbc, 0x55, 0x84, 0x41, 0xd2, 0x8a, 0x02, 0x46, 0x0f, 0x74, 0xf9, 0x29, - 0x3b, 0xb5, 0x1e, 0x49, 0x95, 0xf3, 0x57, 0x75, 0x66, 0xd4, 0x85, 0xe0, - 0x02, 0x08, 0x43, 0xc7, 0x74, 0x1c, 0xd6, 0xa7, 0xfe, 0x51, 0xba, 0x70, - 0xfc, 0xb5, 0x85, 0xb3, 0xf7, 0x09, 0xa3, 0x9d, 0x09, 0x69, 0x37, 0x03, - 0x6a, 0xb4, 0x58, 0xf3, 0xb4, 0xa7, 0x1a, 0x75, 0xd9, 0x27, 0xf2, 0x09, - 0x00, 0x34, 0xa8, 0x79, 0x60, 0xb6, 0xca, 0xf8, 0x3c, 0xf2, 0x9e, 0x36, - 0x94, 0x7c, 0xcc, 0xca, 0x9a, 0x80, 0xa3, 0x07, 0xf1, 0x9f, 0x98, 0xc4, - 0xa3, 0x19, 0x04, 0xeb, 0x5f, 0xd0, 0x31, 0x9e, 0x48, 0x26, 0x5a, 0xf5, - 0x18, 0x7f, 0x6b, 0x20, 0x90, 0x22, 0x89, 0x95, 0xd6, 0x0a, 0x4c, 0x95, - 0xaa, 0x0a, 0x18, 0x44, 0xcb, 0xd1, 0xc1, 0x60, 0x46, 0xa2, 0xbd, 0x51, - 0x46, 0xa2, 0x97, 0x5e, 0x91, 0x96, 0x65, 0x43, 0x20, 0x66, 0x11, 0xbd, - 0x0d, 0x62, 0x0d, 0xf5, 0x29, 0x3e, 0xb4, 0x0d, 0x79, 0x6f, 0x00, 0x7d, - 0xbc, 0x76, 0x18, 0xc4, 0xc1, 0x7d, 0xfc, 0xe8, 0xc2, 0x4f, 0x98, 0x96, - 0xf1, 0x79, 0x2b, 0x87, 0xd1, 0xa4, 0x7f, 0xd5, 0xe0, 0x84, 0x39, 0xeb, - 0x8b, 0xc8, 0x53, 0xf9, 0xa8, 0xd9, 0x17, 0x1c, 0x88, 0x18, 0xca, 0x6a, - 0xa3, 0x5a, 0xf0, 0x3b, 0xd4, 0x2f, 0x34, 0x5c, 0x9b, 0x87, 0xbc, 0x85, - 0x37, 0x1b, 0x4a, 0xfd, 0x91, 0x1b, 0x23, 0x60, 0x8b, 0xd9, 0x3c, 0x69, - 0x5d, 0x69, 0x16, 0xfc, 0x9a, 0x22, 0x58, 0x1e, 0x1a, 0x49, 0xe5, 0xf9, - 0xd8, 0x59, 0x2c, 0xf6, 0xd3, 0x22, 0x18, 0x0d, 0x26, 0x60, 0xf6, 0xbb, - 0x79, 0xc3, 0xf5, 0xc2, 0x82, 0x7a, 0x93, 0xa7, 0x5b, 0x20, 0x2e, 0x98, - 0x64, 0xd7, 0xa3, 0xcd, 0xa1, 0xf7, 0x9e, 0x66, 0x52, 0xa1, 0x0c, 0xd4, - 0xb9, 0x5d, 0x65, 0x4c, 0x8f, 0xfe, 0x5d, 0x81, 0x4b, 0x22, 0xd9, 0x70, - 0x00, 0x22, 0xee, 0xab, 0x9b, 0x66, 0x22, 0x10, 0x2d, 0x5a, 0x6e, 0x36, - 0x0d, 0xc3, 0xaa, 0x8a, 0xb6, 0x58, 0x6e, 0x93, 0x45, 0x41, 0xae, 0x81, - 0xb8, 0x90, 0x88, 0x56, 0x25, 0xe7, 0xdf, 0xec, 0xe6, 0xd9, 0xc9, 0xfe, - 0x53, 0x1b, 0x32, 0x64, 0x06, 0xd3, 0xca, 0xcc, 0xa3, 0xe7, 0x4c, 0xa5, - 0xb2, 0x18, 0x25, 0xda, 0x4b, 0xf2, 0x61, 0x00, 0x1b, 0x24, 0x7b, 0x94, - 0x98, 0xe8, 0x2f, 0xeb, 0xaa, 0x0c, 0xd5, 0x78, 0x3f, 0x7d, 0xc7, 0xde, - 0xa4, 0x2c, 0x2d, 0x9f, 0xf9, 0x96, 0x6e, 0x0f, 0x12, 0x6f, 0xf4, 0x14, - 0x6c, 0x4a, 0xaa, 0xbd, 0x8a, 0xf0, 0x03, 0x6a, 0x2b, 0xa2, 0xff, 0x79, - 0xc9, 0x44, 0x68, 0x09, 0xf7, 0x52, 0xdc, 0x49, 0x34, 0x60, 0x19, 0xda, - 0x8a, 0x03, 0xb7, 0x10, 0x38, 0x8a, 0xdf, 0xa7, 0xcd, 0x3b, 0xfe, 0x5b, - 0xf2, 0x66, 0xaa, 0xfe, 0xc4, 0x08, 0x1e, 0x09, 0xc3, 0xe5, 0x9a, 0x52, - 0x30, 0x76, 0x8d, 0x8c, 0xeb, 0x4a, 0xa8, 0x3e, 0xb7, 0x01, 0xe2, 0xca, - 0x12, 0x07, 0xbf, 0xc2, 0xc1, 0x25, 0x7b, 0xa3, 0xed, 0xcf, 0xdf, 0x6a, - 0xb9, 0xc9, 0x6e, 0xe6, 0x5f, 0x50, 0xa9, 0xc6, 0x54, 0x2c, 0x81, 0x18, - 0x88, 0xdb, 0xe7, 0xc3, 0x56, 0xd2, 0x17, 0x0c, 0x2d, 0x88, 0xa1, 0x6c, - 0xc5, 0xbe, 0xb6, 0x10, 0xc7, 0xca, 0x47, 0x74, 0xfd, 0x4f, 0xc4, 0x9d, - 0xb2, 0x93, 0xfc, 0x2d, 0xaf, 0x6b, 0xd7, 0x38, 0x59, 0xfd, 0x9a, 0xed, - 0xd4, 0xdf, 0x80, 0x97, 0x5e, 0x6c, 0xce, 0x33, 0x62, 0xe4, 0xb1, 0x52, - 0x30, 0xa9, 0x7d, 0x8d, 0x32, 0xfb, 0x95, 0x00, 0x86, 0x92, 0xc4, 0x0a, - 0xdc, 0x3b, 0x8a, 0x2a, 0xcd, 0xe9, 0x14, 0x0e, 0xe2, 0x0c, 0x78, 0x5d, - 0x68, 0x82, 0xc8, 0x81, 0x28, 0x71, 0xdf, 0x5f, 0x64, 0x6e, 0x1a, 0xa1, - 0x7b, 0x9e, 0x9b, 0x1c, 0x2a, 0x1c, 0xfa, 0x84, 0x3d, 0x28, 0x2e, 0xac, - 0x9a, 0x32, 0x55, 0xdf, 0xe7, 0x9f, 0x84, 0x56, 0x7d, 0xbf, 0x49, 0x6e, - 0xe3, 0x03, 0x93, 0xa6, 0xdb, 0xfb, 0xd9, 0xd7, 0x2e, 0x80, 0xcf, 0xc2, - 0x6f, 0x83, 0x16, 0xd3, 0x29, 0xb4, 0x3d, 0xdf, 0x34, 0x1f, 0x72, 0xb8, - 0x19, 0x20, 0x00, 0x03, 0x12, 0xff, 0x39, 0x7c, 0x0f, 0x59, 0x5f, 0x4e, - 0x22, 0x2a, 0x7f, 0x73, 0x7c, 0xfa, 0xfc, 0x2d, 0x79, 0x5a, 0xcf, 0xe2, - 0x04, 0x83, 0x94, 0x48, 0xde, 0xf7, 0x00, 0xe4, 0xd1, 0x92, 0xbc, 0xd8, - 0xc0, 0xf9, 0xbf, 0x77, 0xde, 0x0e, 0x90, 0xf1, 0x9d, 0xb2, 0x55, 0x4d, - 0x26, 0x0b, 0x57, 0xa6, 0x41, 0xd2, 0xe0, 0x82, 0xc7, 0xd5, 0xd9, 0x7d, - 0xcf, 0x5f, 0x57, 0x3c, 0xf2, 0x08, 0xe2, 0x54, 0x4a, 0x77, 0xe2, 0x07, - 0x06, 0x65, 0x0d, 0x30, 0x0f, 0x81, 0x43, 0xf1, 0xc7, 0x75, 0x48, 0x4b, - 0xfe, 0xbe, 0x93, 0xed, 0x5c, 0x05, 0x30, 0xee, 0x2e, 0xdf, 0x27, 0xb6, - 0x63, 0xbe, 0x6e, 0x70, 0xec, 0xba, 0x87, 0x7f, 0x0c, 0xfd, 0xe3, 0xe5, - 0xb5, 0xa5, 0xcc, 0xb7, 0x9a, 0x11, 0x76, 0x15, 0x25, 0xdd, 0x6b, 0xdb, - 0x8c, 0x0f, 0x7c, 0x0d, 0x49, 0x4f, 0xde, 0xea, 0xcc, 0x58, 0xbb, 0x3b, - 0x54, 0x0a, 0xc7, 0xfd, 0x17, 0x6e, 0x0c, 0x11, 0x88, 0xbf, 0x9f, 0xee, - 0xf8, 0x2d, 0xf6, 0xa9, 0x4d, 0x47, 0xcf, 0x0f, 0x27, 0x69, 0x49, 0x11, - 0x8c, 0xf9, 0xe3, 0x62, 0x49, 0x81, 0xf9, 0x0c, 0x25, 0x32, 0x0e, 0x38, - 0x08, 0xab, 0x7f, 0x0b, 0x96, 0xa5, 0x68, 0x4f, 0xde, 0xa7, 0x9d, 0xd2, - 0x89, 0x0a, 0x9f, 0x2e, 0xe6, 0xa4, 0x8e, 0xff, 0x3d, 0xa9, 0x14, 0xd6, - 0x32, 0xf7, 0xa1, 0x6b, 0x4a, 0x8e, 0xa4, 0x3c, 0x66, 0xe5, 0xf4, 0xf4, - 0x02, 0x53, 0xe4, 0xba, 0x61, 0x80, 0x46, 0xec, 0xe2, 0xe1, 0xb9, 0x22, - 0x0d, 0x28, 0x02, 0xf4, 0xbf, 0x85, 0x17, 0x83, 0xfd, 0xcb, 0x63, 0xeb, - 0xcb, 0x27, 0xaf, 0xe3, 0x5b, 0xf6, 0x46, 0x5d, 0x40, 0x3d, 0x4b, 0xbe, - 0xc2, 0xc9, 0xa6, 0x11, 0x9e, 0x12, 0x29, 0x20, 0xcc, 0x85, 0x6b, 0xbb, - 0x8c, 0xb5, 0x12, 0x08, 0xf9, 0x07, 0x56, 0x4f, 0x49, 0xb3, 0x56, 0xba, - 0xca, 0x25, 0x68, 0x99, 0xe3, 0xec, 0x2f, 0x49, 0xec, 0x40, 0xf5, 0xe9, - 0xfd, 0xf1, 0xef, 0x46, 0x02, 0xeb, 0xe1, 0xc4, 0x75, 0xfd, 0x7b, 0x02, - 0xca, 0x83, 0xd8, 0xd8, 0x61, 0x60, 0xb8, 0x9e, 0xda, 0xac, 0x6a, 0xe7, - 0xfc, 0x50, 0xfa, 0x9a, 0x87, 0x82, 0x68, 0xac, 0x06, 0xab, 0x73, 0x88, - 0x44, 0x75, 0xd7, 0x88, 0x6d, 0xad, 0x46, 0x37, 0x21, 0x13, 0x69, 0x6d, - 0x75, 0x79, 0x2f, 0xe7, 0xef, 0x1d, 0xba, 0xb6, 0xe2, 0x7c, 0xe7, 0xaf, - 0x63, 0xa6, 0xfe, 0x6e, 0x26, 0xf2, 0xb1, 0xf4, 0xd2, 0x82, 0x8f, 0x14, - 0xf6, 0x75, 0x81, 0xc6, 0x76, 0x83, 0x0f, 0x33, 0x29, 0x8c, 0x18, 0xbc, - 0xac, 0xbd, 0x33, 0x43, 0xa5, 0x8d, 0x0b, 0xc6, 0xcc, 0x6c, 0xe8, 0xf4, - 0x01, 0x3f, 0x30, 0x7b, 0x0b, 0xf9, 0x7b, 0xe3, 0xa4, 0xbf, 0xc6, 0x5f, - 0x42, 0x66, 0x56, 0xb4, 0x9c, 0x56, 0xf6, 0x20, 0x55, 0x87, 0x18, 0xe1, - 0xde, 0xb2, 0xac, 0x18, 0x09, 0xf1, 0x20, 0x2b, 0xa8, 0x32, 0x70, 0xb6, - 0x84, 0x98, 0x61, 0x64, 0xeb, 0xa8, 0x20, 0x4e, 0x19, 0x18, 0xf6, 0x64, - 0xb6, 0x11, 0x1f, 0xc0, 0xca, 0xf4, 0x8d, 0x57, 0x32, 0x03, 0xf4, 0xc5, - 0x3f, 0xe2, 0xe3, 0x4d, 0xfc, 0x3c, 0x74, 0x83, 0xea, 0xf3, 0xba, 0x5f, - 0x74, 0x4f, 0x24, 0x5e, 0xf7, 0xf6, 0x84, 0x90, 0xc1, 0xfc, 0x4c, 0x9f, - 0x0f, 0x19, 0xcf, 0x8b, 0x55, 0x44, 0x63, 0xbc, 0xf5, 0x98, 0x31, 0xd2, - 0x2f, 0xa3, 0x9f, 0x5b, 0xd7, 0x9f, 0xc8, 0xf7, 0x50, 0xf5, 0x59, 0xcf, - 0x39, 0xb8, 0xeb, 0xee, 0x53, 0x21, 0xad, 0xd5, 0x84, 0xf4, 0xde, 0xf3, - 0x13, 0x6e, 0x79, 0xd4, 0x66, 0xf8, 0x1c, 0x47, 0x0a, 0x67, 0x0a, 0xcc, - 0x53, 0x4f, 0x0b, 0x84, 0x11, 0x4e, 0x51, 0xde, 0xc4, 0xe1, 0x64, 0xf1, - 0x32, 0x37, 0x7f, 0x42, 0x35, 0x14, 0x8e, 0xa3, 0xd0, 0xb4, 0x5c, 0xa3, - 0x9d, 0xc7, 0x1b, 0xf6, 0x25, 0x2b, 0x7f, 0x16, 0xa4, 0x41, 0x67, 0x63, - 0xff, 0xa6, 0xa8, 0xa4, 0xb6, 0x44, 0xcf, 0x3a, 0x22, 0xdc, 0x6b, 0xc3, - 0xe0, 0x63, 0x86, 0x22, 0xe5, 0x4f, 0xe4, 0x12, 0xd9, 0x8a, 0x7c, 0xca, - 0xe7, 0xba, 0xbd, 0xf0, 0x2b, 0x2c, 0xbd, 0x91, 0xae, 0x77, 0xef, 0xdf, - 0xe4, 0xc3, 0xbf, 0x54, 0x7d, 0x83, 0xb2, 0x49, 0xee, 0xd0, 0xa4, 0xf3, - 0xe9, 0xe4, 0xd9, 0xe2, 0x4a, 0x8d, 0x9f, 0x90, 0x35, 0x08, 0xa7, 0x6f, - 0x35, 0xcf, 0x0d, 0x8f, 0x3a, 0x8a, 0x82, 0x27, 0x57, 0x14, 0x53, 0x4c, - 0x4d, 0x41, 0x44, 0x38, 0xef, 0xfa, 0x86, 0xda, 0xe7, 0xf3, 0x8a, 0x27, - 0x38, 0xaa, 0x92, 0x1e, 0xf8, 0x70, 0x8b, 0x6b, 0x60, 0xd6, 0xa5, 0x54, - 0xa6, 0x09, 0x3b, 0xb7, 0xbf, 0x9a, 0x5a, 0x66, 0x9a, 0xd4, 0x75, 0x84, - 0x7d, 0xb2, 0x50, 0x64, 0xfb, 0xeb, 0x95, 0xb4, 0x13, 0xe6, 0xb6, 0xea, - 0xe7, 0xe7, 0x02, 0x0a, 0x1a, 0xa9, 0x12, 0xf9, 0x95, 0x8a, 0x68, 0x60, - 0x1d, 0x86, 0xf9, 0x8f, 0x7f, 0x2b, 0xff, 0x56, 0xf1, 0xde, 0xfe, 0xc7, - 0xbf, 0xff, 0x6b, 0x19, 0xee, 0x7f, 0xff, 0x8f, 0xbf, 0x45, 0xba, 0xf7, - 0x5f, 0xf3, 0x19, 0x8b, 0xef, 0x7f, 0x2e, 0xd9, 0xaf, 0xfa, 0xfe, 0xaf, - 0x7f, 0x0b, 0x00, 0xe8, 0xfd, 0xf8, 0x4f, 0x08, 0x12, 0xc5, 0xff, 0xf9, - 0xf7, 0x00, 0x46, 0xe1, 0x7f, 0xee, 0x71, 0xe4, 0x3f, 0xdf, 0x1b, 0xf4, - 0x5f, 0x0f, 0x10, 0x96, 0xfd, 0xcf, 0xf7, 0x86, 0xfb, 0xe7, 0x01, 0x47, - 0xfc, 0x73, 0xcf, 0x33, 0xff, 0xf3, 0x5f, 0x0b, 0x91, 0xff, 0xeb, 0xf3, - 0x7f, 0x7d, 0x0f, 0xf9, 0xdb, 0x14, 0x02, 0x11, 0xe2, 0x3f, 0x0f, 0x48, - 0xec, 0x9f, 0x7b, 0xe6, 0x9f, 0x6f, 0xc2, 0x08, 0xf2, 0xcf, 0x3d, 0x0d, - 0xff, 0xd7, 0xfd, 0xbf, 0xb6, 0x8e, 0xbc, 0xdf, 0xf8, 0xaf, 0x7b, 0xfc, - 0xff, 0x6e, 0x50, 0x14, 0xfe, 0xd9, 0x1d, 0x51, 0x14, 0xf9, 0xff, 0xfd, - 0x5f, 0xcb, 0x99, 0x97, 0xd9, 0x1b, 0x3b, 0xd9, 0xa7, 0xfb, 0x6f, 0x57, - 0x34, 0x37, 0xb2, 0xed, 0xbb, 0x34, 0x59, 0xff, 0x6f, 0xca, 0x67, 0xfc, - 0xad, 0xff, 0xaf, 0x2b, 0x9b, 0x63, 0xff, 0xac, 0x6c, 0xfe, 0xff, 0xb5, - 0x86, 0x79, 0x22, 0x53, 0x0c, 0x83, 0xfd, 0x6b, 0x35, 0x73, 0x27, 0xab, - 0xde, 0xc7, 0x52, 0xf3, 0xdf, 0xae, 0x61, 0x5e, 0x9f, 0xb9, 0xc0, 0xde, - 0x7c, 0xc3, 0x57, 0x52, 0xc2, 0x70, 0x94, 0x51, 0x0b, 0x0a, 0x37, 0x3e, - 0x8d, 0xa5, 0xfc, 0x62, 0xae, 0xda, 0x31, 0x97, 0x61, 0x58, 0xb3, 0x52, - 0x3a, 0x06, 0x3f, 0x07, 0x96, 0x63, 0xc4, 0xea, 0x37, 0xca, 0x8a, 0x78, - 0xb0, 0xf1, 0x64, 0x32, 0x04, 0xe7, 0x22, 0xb7, 0x33, 0x95, 0x68, 0x33, - 0x54, 0x4f, 0x23, 0x0c, 0x6f, 0x74, 0xad, 0xa2, 0xe8, 0x8d, 0x00, 0x2a, - 0xf4, 0x4d, 0x8f, 0xa3, 0x9f, 0xd8, 0xc9, 0x83, 0xb5, 0x3f, 0x32, 0x58, - 0xdb, 0x05, 0x51, 0xe6, 0x69, 0x69, 0xba, 0xf9, 0xa5, 0xd3, 0x3b, 0xd3, - 0xb5, 0x97, 0x1f, 0x84, 0xad, 0x07, 0xf8, 0xf7, 0x11, 0xab, 0xaa, 0x91, - 0x40, 0xd0, 0xc1, 0xec, 0xb7, 0x63, 0x57, 0x8a, 0xf6, 0x9e, 0xa8, 0x29, - 0xc2, 0x97, 0xdc, 0xaa, 0x52, 0xce, 0x74, 0xd4, 0x69, 0x3e, 0xa9, 0xe6, - 0x32, 0x0c, 0x58, 0xe1, 0x8c, 0xc3, 0x65, 0x75, 0xdd, 0xd3, 0x7e, 0x0d, - 0x17, 0x8e, 0xde, 0x69, 0x25, 0xee, 0x69, 0x0e, 0x08, 0xb1, 0xdb, 0xfe, - 0x57, 0x33, 0x66, 0xaf, 0x6b, 0xce, 0xc9, 0x49, 0xb2, 0x20, 0xb5, 0xbb, - 0xbd, 0x4b, 0xd2, 0xd6, 0x9d, 0x9a, 0x4f, 0x23, 0xc6, 0x39, 0x8f, 0x8f, - 0x2a, 0x4c, 0x5d, 0xc6, 0x07, 0xd8, 0xa8, 0x31, 0xd8, 0x09, 0x59, 0x9f, - 0x40, 0x54, 0x10, 0x73, 0x81, 0x78, 0x7b, 0xa0, 0xb7, 0x0a, 0x1d, 0xb8, - 0x4a, 0x7d, 0xeb, 0xb3, 0x0c, 0xe9, 0x81, 0xb0, 0x0f, 0x96, 0x00, 0xa7, - 0x76, 0x22, 0x55, 0xf6, 0x1d, 0x05, 0x70, 0x8d, 0xfc, 0xe6, 0x79, 0xd2, - 0xf0, 0x3b, 0x0e, 0xee, 0x53, 0x02, 0x39, 0x27, 0xe0, 0x84, 0x0c, 0xa2, - 0x6e, 0xe1, 0x97, 0x6b, 0x3f, 0xeb, 0x7e, 0x0f, 0x49, 0x83, 0xb9, 0x2e, - 0x21, 0xce, 0xdb, 0x82, 0x3e, 0xe8, 0x4f, 0x39, 0xd3, 0x53, 0x5a, 0x31, - 0xfe, 0xbb, 0x9c, 0xb8, 0xdd, 0xa3, 0xae, 0x4a, 0x3f, 0xc5, 0x85, 0x90, - 0x69, 0x9f, 0x13, 0xeb, 0x94, 0xee, 0xf9, 0x17, 0x4f, 0x28, 0xfa, 0x5b, - 0xfa, 0xb7, 0x47, 0xf3, 0x65, 0xbb, 0x2f, 0x24, 0x00, 0xd4, 0x40, 0xa6, - 0x9e, 0xb2, 0xbe, 0xe7, 0x53, 0x0f, 0x01, 0xe5, 0x11, 0xa2, 0x1f, 0xd0, - 0xbf, 0x33, 0x16, 0x6c, 0x0e, 0x51, 0xcd, 0x02, 0x5c, 0xf8, 0xdd, 0xaa, - 0x3a, 0x04, 0x4e, 0x2d, 0x65, 0xca, 0xa4, 0x45, 0x98, 0x8c, 0x5f, 0xcd, - 0x59, 0xf2, 0x72, 0x4f, 0xec, 0x71, 0x43, 0xa8, 0x2f, 0x28, 0xa8, 0xdf, - 0xfd, 0x61, 0x1c, 0xfc, 0xb7, 0x41, 0xb4, 0x02, 0x90, 0x32, 0xe8, 0x8e, - 0x28, 0x08, 0x57, 0x24, 0xaa, 0x4e, 0x4d, 0xe4, 0x65, 0xdf, 0x40, 0x9f, - 0x6c, 0x73, 0x8f, 0x5f, 0x3b, 0x8b, 0x5a, 0xfa, 0xb7, 0x68, 0x89, 0xcb, - 0x01, 0xe9, 0xf1, 0x53, 0x22, 0x4c, 0xdc, 0x3d, 0xd1, 0xbd, 0x56, 0x1d, - 0x37, 0x71, 0x06, 0xb2, 0x1e, 0x65, 0xf7, 0x7f, 0x9c, 0x73, 0xb2, 0x87, - 0xa5, 0xd5, 0x80, 0xf1, 0xc9, 0xa7, 0x45, 0xbb, 0x21, 0x17, 0x7c, 0x21, - 0xf0, 0xce, 0x04, 0x95, 0xd4, 0xc9, 0xef, 0x16, 0xfb, 0x01, 0x69, 0x47, - 0xb7, 0x53, 0x79, 0x8e, 0x3b, 0x24, 0x46, 0x7e, 0x19, 0xd7, 0x42, 0xe7, - 0x1e, 0x0f, 0xf2, 0x48, 0x58, 0x0c, 0xe3, 0x80, 0xf0, 0x76, 0xe6, 0xb0, - 0xe7, 0xc1, 0xbe, 0x3b, 0x62, 0x34, 0xd3, 0xf0, 0xbd, 0xd5, 0xe1, 0xdb, - 0x7c, 0xef, 0xe5, 0x2e, 0x91, 0x03, 0xb4, 0x7e, 0x3d, 0x99, 0x02, 0x79, - 0x83, 0x59, 0x64, 0xce, 0xe7, 0xac, 0x15, 0xf5, 0x5b, 0x3d, 0x42, 0xe3, - 0x8d, 0x03, 0xfb, 0xad, 0xf4, 0x0e, 0x1e, 0xe3, 0x61, 0xc2, 0x24, 0x0a, - 0xc7, 0xf4, 0x61, 0x74, 0x9a, 0xe9, 0x72, 0xec, 0x01, 0x39, 0x16, 0xec, - 0x68, 0x4a, 0xe3, 0x69, 0xbb, 0x8d, 0x01, 0x60, 0x44, 0x89, 0xab, 0x2f, - 0x9b, 0x2c, 0x27, 0x19, 0xb9, 0x00, 0xae, 0x88, 0x8e, 0xa7, 0x29, 0x23, - 0xcc, 0x58, 0xdf, 0x95, 0xfd, 0xca, 0xee, 0x57, 0xcd, 0xa2, 0x96, 0xac, - 0x14, 0x00, 0x50, 0x01, 0x12, 0x28, 0x5c, 0x16, 0x7b, 0x2b, 0x76, 0xe2, - 0xae, 0x00, 0x55, 0x32, 0xc8, 0x6a, 0xd3, 0x3b, 0xec, 0x18, 0x7b, 0xe8, - 0x8f, 0xcf, 0x63, 0x0b, 0x3c, 0x79, 0xc0, 0x47, 0xa3, 0x37, 0x28, 0x8e, - 0x92, 0x88, 0x71, 0x4c, 0xb6, 0xfa, 0x55, 0x6e, 0xc1, 0x5a, 0x1b, 0xc6, - 0x51, 0x95, 0x98, 0x0e, 0x70, 0xfb, 0x07, 0x1e, 0x27, 0x58, 0xe0, 0xe4, - 0x0d, 0x92, 0x2b, 0x05, 0x45, 0xbc, 0xc7, 0x70, 0x61, 0xd5, 0x58, 0xba, - 0x0f, 0x47, 0xc2, 0x5b, 0x41, 0xb1, 0x3a, 0x31, 0xfb, 0x30, 0xc3, 0xb3, - 0x1b, 0x54, 0x4e, 0x0e, 0xd8, 0x2f, 0x84, 0xbd, 0x4e, 0x90, 0x83, 0x75, - 0x32, 0xf7, 0xfe, 0x92, 0x34, 0x4b, 0xb4, 0x73, 0x2f, 0x51, 0xb9, 0x81, - 0xe1, 0xf2, 0x9f, 0x14, 0xb5, 0x4d, 0x97, 0x45, 0x7e, 0x15, 0xb7, 0x1b, - 0x56, 0x9b, 0x1f, 0xb0, 0x3e, 0x90, 0x4e, 0x9a, 0x17, 0x73, 0xe7, 0x27, - 0x7c, 0xd6, 0x2f, 0xfe, 0xca, 0xaa, 0xf2, 0xe6, 0x68, 0x91, 0x41, 0x46, - 0x0c, 0x94, 0xba, 0xb8, 0x5e, 0x8f, 0xec, 0x5e, 0x4f, 0x3b, 0x71, 0xc6, - 0x92, 0xac, 0xa2, 0x9c, 0x82, 0xae, 0xac, 0xb9, 0x67, 0x71, 0xc3, 0xf2, - 0x14, 0xa6, 0x6e, 0xa7, 0x94, 0xef, 0x6a, 0x06, 0x12, 0x0f, 0x79, 0x55, - 0x0a, 0x37, 0x6c, 0x36, 0x59, 0x2b, 0x2b, 0x13, 0x0d, 0xa7, 0xef, 0x75, - 0x68, 0xa2, 0xcc, 0xc4, 0x22, 0x16, 0x0a, 0x9e, 0x24, 0x7b, 0xa7, 0x38, - 0xe8, 0x24, 0x35, 0x6b, 0xf3, 0x03, 0x4b, 0xb2, 0x66, 0xc6, 0x73, 0x17, - 0x9d, 0x6d, 0xf5, 0x30, 0x76, 0x87, 0xb7, 0x4a, 0x2b, 0x64, 0x6b, 0x3c, - 0x1c, 0xbc, 0x48, 0x30, 0xd5, 0xf1, 0x3e, 0x88, 0xb5, 0x8b, 0x03, 0xa2, - 0xfb, 0x07, 0xbc, 0x51, 0x33, 0x75, 0xe3, 0x7e, 0x97, 0xd2, 0x1e, 0xa0, - 0x97, 0xd0, 0x51, 0x80, 0xbf, 0xb7, 0xf1, 0x81, 0x35, 0x70, 0x05, 0x57, - 0x70, 0xba, 0x46, 0x3f, 0x0d, 0x55, 0x8d, 0x6c, 0x40, 0x28, 0xf3, 0x42, - 0x81, 0x7d, 0x1f, 0x08, 0x4a, 0xaa, 0xcd, 0x3f, 0x40, 0x9c, 0xc4, 0x6e, - 0x03, 0x31, 0xbc, 0xeb, 0x97, 0x2c, 0xd2, 0x2b, 0x13, 0xda, 0x67, 0x53, - 0x1a, 0x18, 0x20, 0x15, 0x30, 0x62, 0xdc, 0x27, 0x15, 0x73, 0x89, 0x91, - 0xf8, 0x7e, 0x29, 0x3f, 0xfa, 0x8e, 0xae, 0x11, 0x47, 0x71, 0x24, 0x5e, - 0x11, 0xfc, 0xbc, 0xc7, 0x4f, 0xd6, 0x38, 0x52, 0xf6, 0x38, 0x39, 0xf9, - 0x54, 0x72, 0x6f, 0x61, 0x19, 0xb3, 0xe8, 0x17, 0x3b, 0xa9, 0x5f, 0x77, - 0x5a, 0x95, 0xbd, 0x2e, 0xcf, 0x44, 0x11, 0x07, 0x06, 0x7f, 0xeb, 0xd4, - 0x18, 0x5a, 0x22, 0x8c, 0x18, 0xa3, 0x72, 0x28, 0x31, 0x51, 0x8c, 0x40, - 0x93, 0x64, 0x82, 0xd3, 0x32, 0x69, 0xd1, 0x3a, 0xa9, 0x57, 0xae, 0xad, - 0x75, 0x83, 0xd9, 0xaa, 0xac, 0x2e, 0xc2, 0xbf, 0x12, 0xb7, 0xaa, 0x2a, - 0x27, 0x83, 0xaa, 0xbd, 0x3f, 0x95, 0x7d, 0xcb, 0x46, 0x14, 0x4e, 0x76, - 0xcd, 0x46, 0x4c, 0xbb, 0x96, 0x70, 0x85, 0xf5, 0x1f, 0x8f, 0x69, 0x76, - 0xd5, 0x22, 0x1c, 0x0b, 0x3e, 0x05, 0xf1, 0x6e, 0xb7, 0x60, 0xf1, 0xf4, - 0xe8, 0x55, 0xb6, 0x85, 0xb3, 0xf8, 0xd9, 0x8c, 0x3c, 0x94, 0x01, 0xe0, - 0x08, 0x9f, 0x9a, 0x0c, 0xd9, 0xb6, 0x3c, 0xda, 0x80, 0xb8, 0x03, 0x4c, - 0x70, 0xe7, 0x2d, 0x82, 0x65, 0x9c, 0x1e, 0xaf, 0xfc, 0xf3, 0x54, 0x70, - 0x93, 0x60, 0x14, 0xc3, 0x11, 0x3b, 0xf1, 0x7c, 0xcf, 0x84, 0x33, 0x8e, - 0x16, 0x05, 0x88, 0xd3, 0xb7, 0x62, 0xa6, 0x31, 0x86, 0xef, 0x99, 0x23, - 0xc8, 0x1d, 0xdc, 0x9c, 0xf9, 0x25, 0xff, 0x11, 0x49, 0x12, 0x0f, 0x49, - 0x5e, 0x57, 0x9f, 0xb6, 0xc3, 0x20, 0x74, 0xa7, 0xf5, 0x3b, 0x7b, 0x33, - 0x7a, 0xab, 0x87, 0x40, 0x22, 0x55, 0x75, 0x9b, 0x9a, 0x96, 0xec, 0x61, - 0x68, 0x0a, 0xbb, 0xe9, 0xdc, 0x6a, 0x25, 0xea, 0x1d, 0x5c, 0x79, 0x0f, - 0x7c, 0x07, 0x39, 0x8f, 0x48, 0xd3, 0x64, 0x05, 0xdc, 0xe7, 0x4d, 0xf3, - 0x3d, 0x03, 0x86, 0x70, 0xbd, 0x37, 0xdf, 0x98, 0x86, 0xd6, 0x11, 0x0f, - 0x9e, 0xf2, 0xab, 0x65, 0x71, 0xdd, 0xd6, 0x1b, 0xa7, 0x62, 0xee, 0x79, - 0x80, 0xac, 0xc8, 0xe9, 0xf0, 0xa9, 0x90, 0xb1, 0x31, 0xe4, 0xfa, 0xc6, - 0x15, 0x57, 0x92, 0xd0, 0x15, 0x16, 0xf1, 0xb1, 0x80, 0x80, 0x0a, 0x5a, - 0x02, 0x61, 0xfe, 0xe1, 0x11, 0x20, 0x4b, 0x5c, 0xde, 0x53, 0xf5, 0xc2, - 0x42, 0xc6, 0xab, 0xe8, 0x48, 0x0c, 0x38, 0xf1, 0x6e, 0x2e, 0x45, 0xa5, - 0xd6, 0x28, 0xf3, 0xc7, 0xb7, 0xb0, 0xa7, 0xb1, 0x31, 0x55, 0x89, 0x2c, - 0x55, 0xc2, 0x26, 0xda, 0xe3, 0x2c, 0x86, 0x74, 0x5f, 0x49, 0xf2, 0x3c, - 0xa0, 0xa2, 0xc6, 0x19, 0xf5, 0xfb, 0xa7, 0xd9, 0x73, 0x28, 0x49, 0x07, - 0x9f, 0x15, 0x66, 0x13, 0xda, 0xb2, 0x98, 0xea, 0xa1, 0x03, 0x8d, 0x5e, - 0x91, 0x5d, 0xda, 0x95, 0x5f, 0x61, 0x43, 0xf0, 0x55, 0x1b, 0x2a, 0x87, - 0x13, 0x59, 0x7f, 0x26, 0x2f, 0x7f, 0x53, 0xc8, 0x5b, 0xa6, 0x57, 0x0b, - 0x79, 0xb4, 0x6a, 0xee, 0x76, 0x90, 0xa6, 0x1d, 0x67, 0xf7, 0x8b, 0xbf, - 0x87, 0x1d, 0x0f, 0xcf, 0xad, 0x11, 0xb3, 0x78, 0xca, 0x75, 0xe4, 0xc2, - 0x29, 0x22, 0xde, 0xf3, 0x57, 0x07, 0x0c, 0xf8, 0x13, 0x8a, 0xd0, 0x72, - 0xc3, 0x54, 0x76, 0xfb, 0x41, 0xc7, 0xfa, 0x02, 0x45, 0xd8, 0x44, 0x6c, - 0x67, 0x0c, 0x5b, 0xbc, 0xcc, 0xd6, 0xdc, 0x70, 0x44, 0x78, 0x0d, 0x85, - 0x26, 0x28, 0xc8, 0xe5, 0x63, 0x29, 0xb0, 0xf1, 0xe2, 0xe5, 0xa1, 0x09, - 0x70, 0x3f, 0x27, 0x9f, 0x86, 0x67, 0xca, 0x2d, 0xa1, 0x4c, 0xed, 0xa2, - 0xb4, 0xcc, 0x02, 0x55, 0xdf, 0xd0, 0x37, 0x44, 0xf3, 0xfb, 0x3d, 0xcb, - 0x03, 0xb6, 0x71, 0xf0, 0x5a, 0xc8, 0x13, 0x1d, 0x1f, 0x68, 0x15, 0xa0, - 0xd8, 0x49, 0xd3, 0x0c, 0xdd, 0xe3, 0x44, 0xef, 0xaf, 0x11, 0xc9, 0x05, - 0xb9, 0xdb, 0xab, 0x5f, 0xbb, 0xe4, 0xe1, 0x43, 0x80, 0x90, 0x06, 0xd2, - 0x1e, 0xf4, 0xf3, 0xf3, 0x3a, 0xe0, 0x6b, 0x99, 0xc3, 0xb6, 0x18, 0x18, - 0xbf, 0x63, 0xe3, 0x01, 0xa7, 0x8c, 0x56, 0x53, 0x5f, 0xb3, 0x4c, 0x1e, - 0x2f, 0xdf, 0x1f, 0x7d, 0x83, 0x70, 0xe1, 0x1f, 0x04, 0xad, 0x15, 0x7d, - 0xac, 0xfa, 0x03, 0xab, 0x20, 0x26, 0x1f, 0xe6, 0x41, 0x9b, 0x40, 0x26, - 0x92, 0x61, 0x1f, 0x8e, 0x92, 0x05, 0xb9, 0x88, 0xa8, 0xc2, 0x76, 0x70, - 0xb1, 0xc9, 0x48, 0x2b, 0xdc, 0x8e, 0x0c, 0x71, 0x44, 0x0d, 0xbc, 0x2e, - 0x45, 0x66, 0x07, 0x45, 0xce, 0xd8, 0xca, 0x60, 0x70, 0xb0, 0xca, 0x16, - 0x3a, 0x06, 0x9e, 0x24, 0x77, 0xa7, 0xe2, 0x61, 0xdc, 0x64, 0x06, 0x9f, - 0x2e, 0x54, 0x3c, 0xf0, 0xa8, 0x31, 0x0c, 0xb8, 0x6b, 0xae, 0x51, 0x6a, - 0x65, 0xb6, 0x26, 0xe2, 0x7c, 0xb4, 0xc9, 0x1f, 0x83, 0x3a, 0x0c, 0xe9, - 0x68, 0xd6, 0xfa, 0xbe, 0xb5, 0xf0, 0x28, 0x5c, 0xbe, 0x2f, 0x46, 0x13, - 0xc5, 0x9c, 0x97, 0xc2, 0x04, 0xdd, 0xf2, 0x16, 0x2a, 0xa1, 0xe5, 0x67, - 0xe3, 0xb7, 0x77, 0xc9, 0x5e, 0xda, 0x91, 0x2f, 0x3c, 0xe2, 0xa4, 0x2c, - 0x7e, 0x61, 0xf2, 0x13, 0xde, 0xa0, 0x0d, 0x00, 0x34, 0x0d, 0xf2, 0x25, - 0x40, 0x81, 0x95, 0x5c, 0x95, 0xf2, 0xe9, 0x83, 0x2a, 0xe4, 0x38, 0x0a, - 0xd7, 0x79, 0x02, 0x17, 0x70, 0x0a, 0x17, 0x68, 0x3d, 0xfb, 0x50, 0x55, - 0xe1, 0xc8, 0x9e, 0xbe, 0x8e, 0xde, 0xa2, 0x4c, 0x77, 0x1f, 0xca, 0xdd, - 0x64, 0xdf, 0x83, 0x84, 0x67, 0xfe, 0x3e, 0x8e, 0xc6, 0x19, 0x65, 0x6d, - 0xe7, 0xa7, 0xf9, 0x38, 0xa4, 0xb8, 0xe7, 0x15, 0x37, 0x0f, 0x1b, 0x15, - 0x80, 0x60, 0xf5, 0xf0, 0xcb, 0xc2, 0x0c, 0x25, 0x69, 0x9d, 0x88, 0xe0, - 0x7c, 0xcb, 0xe8, 0x41, 0x4f, 0x67, 0x34, 0x3c, 0x42, 0x00, 0x06, 0x17, - 0x7c, 0xa2, 0xb3, 0x1c, 0xb8, 0x60, 0x91, 0xfa, 0xb5, 0xa5, 0x45, 0xa3, - 0x6b, 0xd8, 0x52, 0xb0, 0x64, 0xc3, 0x5b, 0xd7, 0x09, 0x0d, 0x78, 0x7e, - 0xd4, 0xf4, 0xb5, 0x03, 0x4e, 0x8b, 0xb4, 0x7a, 0x19, 0x2a, 0xa4, 0x81, - 0x39, 0x4f, 0x91, 0x96, 0xf0, 0xcd, 0xc4, 0x7a, 0x68, 0xbf, 0x01, 0x3f, - 0x73, 0x9d, 0x83, 0xc6, 0xc0, 0x82, 0x14, 0x6a, 0xd0, 0x79, 0x0c, 0xcc, - 0x26, 0x7a, 0x70, 0xcb, 0x44, 0x99, 0x7f, 0xdd, 0x4f, 0xaa, 0xd9, 0x6a, - 0xb9, 0x24, 0x3b, 0x70, 0xfc, 0xbd, 0x8b, 0xeb, 0x70, 0x3a, 0x79, 0x7e, - 0xb1, 0x9b, 0x30, 0x40, 0x59, 0xae, 0xb6, 0x0f, 0xc8, 0xe6, 0xb6, 0x56, - 0xa2, 0xb1, 0xbc, 0x99, 0x08, 0xd9, 0x7b, 0x17, 0xcf, 0x41, 0xc6, 0xaa, - 0x72, 0x4c, 0x3e, 0xae, 0x74, 0x14, 0x5b, 0x52, 0xb1, 0x6f, 0xcb, 0x8e, - 0x5c, 0xee, 0xc7, 0x49, 0x87, 0x30, 0x7c, 0x69, 0x1a, 0x25, 0x7e, 0xa1, - 0xfb, 0x90, 0x6e, 0xf6, 0x4e, 0x81, 0xce, 0x7d, 0x07, 0xf3, 0x7c, 0x7e, - 0x2b, 0xdb, 0x61, 0x2e, 0xa7, 0x60, 0x07, 0xe4, 0xd1, 0xea, 0x37, 0x80, - 0xe1, 0xcf, 0x9b, 0xd3, 0x52, 0x6b, 0xe7, 0xeb, 0x05, 0x58, 0x1d, 0x6a, - 0x03, 0xcf, 0xb7, 0x07, 0xf5, 0x4f, 0xf5, 0x3b, 0x28, 0xbf, 0xec, 0x04, - 0xab, 0x74, 0x68, 0x7b, 0x13, 0xb7, 0xd8, 0x48, 0x13, 0x2e, 0xb5, 0xb0, - 0x53, 0x28, 0xde, 0xd9, 0xc4, 0x36, 0x46, 0x2b, 0xf0, 0x59, 0x85, 0x31, - 0x83, 0xd7, 0x06, 0xec, 0xad, 0xc8, 0xa8, 0x30, 0xd5, 0x92, 0x57, 0xc6, - 0x6d, 0x4a, 0x7c, 0x9f, 0x8b, 0xba, 0xd3, 0xd4, 0x26, 0xc2, 0xda, 0xb0, - 0x09, 0x66, 0xb2, 0x3f, 0x6c, 0xe4, 0x90, 0xd3, 0xad, 0x2b, 0x68, 0xad, - 0x3d, 0xbf, 0x09, 0xa7, 0x6f, 0x4d, 0x06, 0xf0, 0x38, 0xa7, 0xc5, 0x23, - 0x42, 0x40, 0x37, 0xff, 0x9d, 0xf9, 0xeb, 0x6d, 0x28, 0x34, 0x40, 0x1a, - 0x30, 0x38, 0xca, 0x2e, 0x8c, 0x35, 0x56, 0x17, 0x14, 0x7a, 0x1c, 0x5e, - 0x01, 0x82, 0xc4, 0x79, 0x3f, 0xc6, 0x9b, 0xab, 0xc0, 0x9b, 0x8a, 0xa1, - 0x10, 0x8a, 0x61, 0x10, 0x8a, 0xae, 0xe0, 0xc3, 0x4b, 0x1e, 0xa3, 0x20, - 0x4d, 0xe6, 0x04, 0x10, 0xb4, 0xd4, 0x45, 0x90, 0x36, 0x80, 0xa2, 0x68, - 0x81, 0xcc, 0x82, 0x2b, 0xbe, 0x4f, 0x3e, 0x80, 0xb3, 0xf1, 0x4c, 0xde, - 0xa0, 0xbf, 0xf6, 0xf1, 0x4a, 0xcd, 0xb5, 0xc6, 0x22, 0x10, 0x1e, 0x6e, - 0x51, 0x71, 0x85, 0xfc, 0xf7, 0xfc, 0x40, 0x28, 0x2b, 0x35, 0x99, 0x79, - 0x25, 0x81, 0xe3, 0x31, 0x47, 0x53, 0x39, 0x7e, 0x8c, 0xc0, 0xec, 0xc8, - 0xd3, 0x15, 0x07, 0x0d, 0x98, 0x20, 0xd5, 0x14, 0xe9, 0xfd, 0x50, 0xc4, - 0x26, 0x9e, 0xa9, 0xf9, 0xfa, 0x43, 0x52, 0xfb, 0x17, 0x1c, 0xe1, 0x89, - 0x8a, 0x6c, 0x6d, 0x73, 0x55, 0xf4, 0x01, 0x9e, 0x3e, 0x96, 0x8c, 0xc0, - 0xc3, 0x76, 0x45, 0x63, 0x1a, 0x5b, 0x39, 0x16, 0x5d, 0x49, 0x49, 0xf0, - 0x32, 0xbe, 0xce, 0x59, 0xc4, 0x8e, 0xed, 0x86, 0x5a, 0xa9, 0x16, 0x79, - 0x09, 0x69, 0x28, 0x78, 0x00, 0x17, 0x87, 0xe7, 0x5b, 0x08, 0x27, 0x7c, - 0x03, 0xb5, 0x13, 0x37, 0xa9, 0xcc, 0xdd, 0x9d, 0xf7, 0x94, 0x42, 0x93, - 0x56, 0x4e, 0xa0, 0xae, 0x78, 0x86, 0xa2, 0x30, 0xa9, 0xed, 0x4d, 0x3f, - 0x3b, 0x4c, 0x13, 0xfb, 0xa6, 0x23, 0x83, 0x59, 0xcf, 0x49, 0x59, 0x30, - 0x7c, 0xd8, 0xd6, 0xc7, 0x58, 0x1a, 0x9e, 0x0e, 0x74, 0x46, 0xd4, 0x9c, - 0x2a, 0xfe, 0x06, 0xcb, 0xef, 0xde, 0x34, 0x91, 0xee, 0xb7, 0xa9, 0xf0, - 0x03, 0xe9, 0xca, 0x28, 0x7c, 0xa3, 0x00, 0xb3, 0xf8, 0xd2, 0x15, 0xd0, - 0x3d, 0x1c, 0x9a, 0x10, 0xbb, 0x3e, 0xe8, 0x23, 0xef, 0x7f, 0x9b, 0xe1, - 0x9d, 0xc5, 0x3b, 0xac, 0x0d, 0xd2, 0x77, 0x6e, 0xb3, 0x2d, 0x04, 0x51, - 0xed, 0x61, 0x40, 0xdd, 0x18, 0xcf, 0x3c, 0x23, 0x63, 0xb8, 0x4d, 0x11, - 0x8e, 0x9c, 0x65, 0x80, 0xb0, 0x02, 0xb6, 0x4d, 0x00, 0x44, 0x92, 0x93, - 0x17, 0xb7, 0x60, 0xf2, 0xbb, 0xd2, 0xf2, 0xf6, 0xd0, 0xd3, 0xf1, 0x2a, - 0xc9, 0x87, 0x69, 0x29, 0xfe, 0x71, 0x7f, 0x64, 0x38, 0x28, 0x7c, 0xe4, - 0xb4, 0x88, 0xe0, 0x20, 0xed, 0x37, 0x7a, 0xd4, 0xef, 0x89, 0x87, 0xab, - 0xfb, 0x4d, 0x06, 0xd7, 0x97, 0x6b, 0x6a, 0xad, 0xe5, 0xc0, 0x91, 0x79, - 0xc8, 0xa8, 0xce, 0xc0, 0x09, 0x58, 0x3d, 0xd8, 0xfa, 0xd2, 0x77, 0x9c, - 0x3a, 0x61, 0x5b, 0x1e, 0x0a, 0xf7, 0x9e, 0x9b, 0x08, 0x5e, 0x14, 0x02, - 0x6d, 0x49, 0xf4, 0x84, 0xe5, 0x03, 0x82, 0x95, 0x9a, 0x82, 0xa9, 0x1d, - 0xd8, 0x49, 0x2a, 0x28, 0x88, 0x18, 0x01, 0xef, 0x3b, 0x4e, 0x62, 0x53, - 0xb6, 0x91, 0x3b, 0xa7, 0x01, 0x49, 0x8c, 0x90, 0x46, 0x8e, 0x6d, 0x8b, - 0x21, 0x42, 0x5d, 0xf8, 0x1e, 0xd7, 0xbf, 0x4b, 0xe3, 0xa1, 0x25, 0x83, - 0xff, 0x16, 0x73, 0xa6, 0x07, 0xfe, 0x4e, 0x6c, 0x77, 0x0d, 0xaf, 0x8f, - 0x9e, 0x5a, 0xde, 0x34, 0x54, 0xb4, 0x21, 0x48, 0xdb, 0xe0, 0x92, 0xed, - 0x2f, 0xcb, 0x0c, 0x18, 0x42, 0xbe, 0x62, 0xa2, 0x62, 0x9f, 0xdc, 0xb8, - 0x8a, 0xc8, 0xf8, 0xe0, 0xf9, 0xa9, 0x3a, 0x7f, 0xaf, 0x08, 0x09, 0xef, - 0x68, 0xaa, 0xea, 0xc8, 0xb8, 0xc4, 0xf7, 0x30, 0xa7, 0xf6, 0x1b, 0x83, - 0xed, 0x28, 0xa8, 0xfb, 0x27, 0x9d, 0xef, 0x54, 0x10, 0x04, 0x46, 0xe1, - 0xea, 0x02, 0xc2, 0xb3, 0xe2, 0x9d, 0x1c, 0x96, 0xe7, 0x89, 0x6b, 0xe4, - 0xf1, 0x7e, 0x4f, 0x61, 0x44, 0x54, 0x9f, 0x80, 0xcd, 0xeb, 0x81, 0x20, - 0x28, 0xec, 0x37, 0x61, 0x34, 0xb1, 0xcf, 0x2a, 0x35, 0x75, 0x9e, 0xea, - 0xb9, 0xb1, 0x78, 0x71, 0x09, 0x4e, 0xe5, 0x17, 0x1a, 0x05, 0x34, 0xfd, - 0xce, 0x7e, 0x51, 0xcb, 0x8d, 0x53, 0x9d, 0x4a, 0x36, 0x52, 0xc8, 0x95, - 0xef, 0xee, 0xab, 0xba, 0x3b, 0x4d, 0x44, 0x57, 0xd9, 0x81, 0xe2, 0x58, - 0xe7, 0x64, 0x8c, 0xa0, 0xa9, 0x02, 0x34, 0xee, 0xa4, 0x2f, 0x44, 0xa9, - 0x94, 0x08, 0x16, 0x1a, 0x19, 0x69, 0x1f, 0x8b, 0x6f, 0x9f, 0x3c, 0xc4, - 0xfc, 0x7b, 0x21, 0xc6, 0x40, 0x88, 0x8b, 0xc8, 0xc3, 0x2f, 0x31, 0xa5, - 0xf5, 0x4b, 0x2f, 0x55, 0x54, 0x23, 0xa5, 0x94, 0xf6, 0xaf, 0x79, 0x6e, - 0x35, 0x97, 0x09, 0xf0, 0xaf, 0x1d, 0xac, 0xb7, 0x95, 0x12, 0x9b, 0xdb, - 0xfd, 0x0b, 0x19, 0x41, 0x32, 0x71, 0x09, 0x23, 0xbd, 0x56, 0xb4, 0x3d, - 0xe3, 0x59, 0x95, 0xf7, 0x4d, 0x8c, 0x7d, 0x8d, 0xfc, 0x94, 0x28, 0x09, - 0x92, 0xb4, 0xc5, 0xb1, 0xaf, 0x65, 0x60, 0x6e, 0x21, 0xba, 0x75, 0x6b, - 0x37, 0x7c, 0xaa, 0xf7, 0xda, 0x04, 0xff, 0x8c, 0x05, 0xcd, 0x9d, 0xe9, - 0xc7, 0x76, 0x4d, 0x1b, 0xe6, 0xa6, 0x87, 0xf5, 0x16, 0xf9, 0xa8, 0x14, - 0x0d, 0xd0, 0x87, 0x6c, 0x62, 0x94, 0xdc, 0x83, 0x81, 0xe5, 0x1a, 0x68, - 0x79, 0x1c, 0x46, 0x2a, 0xe2, 0xea, 0x96, 0xc7, 0x7f, 0xef, 0x53, 0x0b, - 0x88, 0x59, 0x3e, 0xe7, 0xce, 0x1e, 0xc1, 0xba, 0x8a, 0xfa, 0xeb, 0xbb, - 0x07, 0xc4, 0x33, 0x6d, 0xda, 0xf0, 0x0a, 0x4e, 0xbf, 0x95, 0x9f, 0xc2, - 0xb4, 0xd3, 0x2b, 0x95, 0xd4, 0xba, 0x1c, 0x36, 0x7f, 0x8d, 0x1a, 0xd9, - 0x7c, 0x20, 0x7c, 0xf9, 0xd0, 0x9f, 0xa2, 0x90, 0x63, 0x7a, 0x10, 0x9e, - 0x78, 0x75, 0xbd, 0x34, 0x62, 0xaa, 0xc7, 0x59, 0x5f, 0xbe, 0x30, 0xf8, - 0x86, 0xcb, 0x1e, 0xcc, 0x63, 0x5d, 0x81, 0x12, 0x28, 0xe6, 0x3d, 0xbc, - 0x99, 0x3a, 0x4d, 0x1d, 0x3b, 0xb9, 0xd8, 0xdc, 0x3f, 0x0e, 0x27, 0x34, - 0xe7, 0xdd, 0xb2, 0x28, 0xf7, 0x93, 0x64, 0x27, 0x0c, 0xbc, 0x6e, 0x29, - 0x7c, 0xe9, 0x5a, 0x56, 0x1f, 0x13, 0x45, 0x97, 0x4e, 0xfa, 0xce, 0xe0, - 0x2d, 0x0f, 0xe8, 0x77, 0x71, 0xa7, 0x29, 0x0f, 0x21, 0x8c, 0x7a, 0x20, - 0xf8, 0x3a, 0x18, 0x93, 0x6d, 0xd8, 0xaa, 0x9a, 0x25, 0xad, 0xf5, 0x37, - 0x6a, 0x4d, 0xe7, 0xc0, 0xbd, 0x97, 0x75, 0x91, 0x7e, 0x74, 0xf4, 0x24, - 0x45, 0xbf, 0x86, 0x86, 0x8d, 0xa0, 0x15, 0xd4, 0x07, 0x65, 0x82, 0xc3, - 0x18, 0xd0, 0x73, 0x99, 0x4d, 0x5f, 0x8d, 0xe6, 0x49, 0x94, 0xb1, 0x67, - 0xba, 0x76, 0x51, 0xf2, 0xfa, 0x01, 0xc2, 0x7f, 0xee, 0x3c, 0x85, 0x2a, - 0xc7, 0x36, 0x78, 0x79, 0x1e, 0x67, 0x6c, 0x4b, 0x74, 0x16, 0xa2, 0x6d, - 0xa5, 0x02, 0x61, 0xdb, 0x09, 0xcb, 0x9d, 0x32, 0xeb, 0x86, 0xe1, 0x72, - 0x7e, 0x26, 0xc8, 0xe4, 0x7c, 0x3e, 0x61, 0xe3, 0x41, 0xcc, 0x41, 0x00, - 0xd3, 0x47, 0x98, 0x4f, 0x90, 0x95, 0x77, 0x64, 0x8f, 0x1d, 0x97, 0xe1, - 0x93, 0xb9, 0x11, 0x13, 0x8f, 0xeb, 0xe7, 0x02, 0x98, 0x5a, 0x6c, 0xbc, - 0x60, 0x90, 0x25, 0xb7, 0x2f, 0x93, 0xf3, 0x4b, 0xb5, 0xde, 0xed, 0xac, - 0x45, 0x22, 0x7b, 0x75, 0x69, 0x55, 0xd2, 0xf4, 0xf2, 0x9e, 0x8a, 0x2e, - 0x2f, 0x58, 0x0f, 0x08, 0x21, 0xcb, 0x24, 0x13, 0x39, 0x41, 0x01, 0x2a, - 0x12, 0x98, 0xe7, 0x6b, 0x6b, 0xbb, 0x35, 0xf6, 0x30, 0x1f, 0x4f, 0x5f, - 0x9c, 0xfb, 0x5c, 0xf7, 0x07, 0x91, 0xf1, 0xe4, 0x4a, 0x89, 0xf4, 0x61, - 0x7e, 0xc3, 0xb0, 0x27, 0xbb, 0x62, 0x9c, 0x35, 0xf0, 0xdb, 0x87, 0x0b, - 0x39, 0x93, 0xe0, 0x83, 0x5d, 0x73, 0x12, 0x56, 0x7e, 0xc7, 0xde, 0x45, - 0xd7, 0xbb, 0x99, 0x33, 0xc4, 0xe3, 0xb8, 0x6c, 0x31, 0xe4, 0x36, 0xad, - 0x29, 0x58, 0xe9, 0x77, 0xfc, 0xb9, 0x8a, 0xdc, 0xf6, 0xcb, 0x7c, 0xd4, - 0x70, 0xf2, 0xdd, 0x51, 0x53, 0xd9, 0xab, 0x04, 0x51, 0x4e, 0xa9, 0x93, - 0xdf, 0x74, 0x0b, 0x67, 0x0f, 0x9c, 0xc4, 0x4f, 0x14, 0x53, 0x97, 0xcb, - 0x41, 0x39, 0x75, 0xf8, 0xb0, 0x9d, 0xcd, 0x5e, 0x31, 0x99, 0x66, 0xab, - 0xe0, 0xe8, 0x17, 0x66, 0xc2, 0x2f, 0x3a, 0x01, 0xb1, 0x15, 0x9d, 0xc2, - 0x51, 0x0c, 0x8a, 0xbe, 0x7d, 0xd2, 0x22, 0xd3, 0x85, 0xee, 0xc7, 0xf3, - 0x54, 0xf4, 0xbc, 0xa3, 0x7f, 0x99, 0x61, 0x57, 0xba, 0xf6, 0xd9, 0xfb, - 0x54, 0xcc, 0xca, 0x55, 0x5f, 0x3d, 0xd0, 0xda, 0xd8, 0x94, 0x86, 0x35, - 0xf8, 0xd5, 0x02, 0xff, 0x8b, 0x35, 0xe5, 0x2c, 0xf0, 0x62, 0xb2, 0x54, - 0x87, 0xad, 0x15, 0x07, 0xbc, 0x4f, 0x0f, 0xa4, 0x79, 0xa5, 0xc6, 0x55, - 0xd5, 0x6f, 0x79, 0xfb, 0x76, 0x10, 0x1c, 0xc5, 0xe1, 0x97, 0x42, 0x47, - 0x59, 0x82, 0xd6, 0xae, 0x9d, 0x83, 0xd1, 0x9d, 0x02, 0x9e, 0xa9, 0x80, - 0x08, 0x3b, 0x3d, 0x5b, 0x13, 0xac, 0xf8, 0x69, 0x2a, 0xe6, 0xdc, 0xec, - 0x82, 0x29, 0x07, 0xcf, 0x47, 0x3f, 0x12, 0xd4, 0xc4, 0x47, 0x46, 0x9d, - 0x91, 0x17, 0x68, 0x69, 0x1e, 0x2a, 0xa6, 0xb4, 0x86, 0xab, 0xd6, 0x3a, - 0x9b, 0xb0, 0xf3, 0x5b, 0x18, 0xda, 0xef, 0x78, 0x3b, 0xa7, 0x9e, 0xef, - 0x10, 0x27, 0xf2, 0xed, 0xd6, 0x8f, 0x74, 0xf7, 0xaf, 0x97, 0x06, 0x6a, - 0xbb, 0x49, 0x63, 0x6e, 0xc2, 0x38, 0xaf, 0xae, 0xf8, 0x6f, 0x5d, 0x4b, - 0x32, 0x20, 0xd4, 0x7b, 0xa4, 0xdc, 0x8d, 0xef, 0xfb, 0x7e, 0x15, 0xbf, - 0x97, 0xb0, 0x9a, 0x63, 0xcd, 0x06, 0x6c, 0x9e, 0x46, 0x2d, 0xfc, 0x61, - 0x86, 0xa6, 0x7d, 0x32, 0xc5, 0xdc, 0x7c, 0x8b, 0xa4, 0x06, 0xbf, 0xd6, - 0x6c, 0x13, 0x37, 0x7a, 0xb1, 0xb9, 0x15, 0x1c, 0xb7, 0x9e, 0x22, 0x44, - 0xb8, 0x15, 0xeb, 0x54, 0xe4, 0x03, 0x7d, 0xcf, 0xfa, 0x77, 0x70, 0xd1, - 0x7e, 0xd6, 0x53, 0xde, 0x73, 0x16, 0x12, 0x64, 0xa0, 0x91, 0xde, 0x1b, - 0xdf, 0xfc, 0x94, 0x40, 0x28, 0xae, 0x8a, 0x2c, 0x32, 0xa2, 0xf8, 0xe4, - 0x11, 0xce, 0xa7, 0xec, 0xa9, 0x11, 0xda, 0x38, 0xb6, 0x19, 0x9a, 0x7c, - 0xeb, 0xd1, 0xfc, 0x0c, 0x7f, 0xff, 0x48, 0xa5, 0x1f, 0xb3, 0x93, 0xf5, - 0x30, 0x98, 0xbf, 0xb9, 0x5d, 0x74, 0x36, 0xb7, 0x5a, 0x29, 0xbb, 0x7c, - 0x4b, 0xea, 0xa7, 0x73, 0x27, 0x5d, 0x06, 0x86, 0x90, 0xa3, 0x3c, 0xf9, - 0x7e, 0xb5, 0x2a, 0x87, 0xaf, 0x73, 0xd4, 0xaa, 0x39, 0x4b, 0x1d, 0xf6, - 0xb2, 0xdb, 0xa3, 0x5d, 0x97, 0xe7, 0x2e, 0x6a, 0xb3, 0x56, 0xb9, 0x31, - 0x75, 0xdd, 0x67, 0xe2, 0xec, 0x01, 0x94, 0x81, 0xea, 0xee, 0xb8, 0xc4, - 0x49, 0x7b, 0x13, 0xfb, 0xde, 0x74, 0xa2, 0x32, 0x24, 0xda, 0x6f, 0xee, - 0x2b, 0x7b, 0xc2, 0x2a, 0x57, 0x05, 0x2f, 0xca, 0x84, 0x86, 0xb8, 0x07, - 0x02, 0x28, 0xc8, 0x85, 0x25, 0x95, 0xa0, 0x24, 0x64, 0x58, 0x76, 0x39, - 0xee, 0x7c, 0xba, 0xac, 0x3f, 0x62, 0x3a, 0x14, 0x92, 0xc1, 0x50, 0xba, - 0xeb, 0x7a, 0xc0, 0x14, 0xb1, 0xa0, 0x87, 0x93, 0x5b, 0xdc, 0x71, 0x84, - 0x97, 0xc9, 0x9e, 0xa9, 0x22, 0xad, 0x25, 0xa5, 0xe7, 0xef, 0x4e, 0x5f, - 0xad, 0xb7, 0x8e, 0x56, 0x3e, 0x7f, 0x7a, 0xae, 0xfc, 0x40, 0xe4, 0xa4, - 0x99, 0x84, 0xdf, 0x0d, 0x70, 0xf5, 0xcb, 0xc3, 0xd8, 0xb8, 0x7b, 0x84, - 0x34, 0x94, 0x39, 0x4d, 0xe6, 0xea, 0x82, 0x03, 0x4c, 0xbb, 0xda, 0xea, - 0xc2, 0xbe, 0x0d, 0x43, 0xef, 0x7a, 0xa1, 0x4c, 0x0d, 0x08, 0xaa, 0xa8, - 0x9d, 0x3f, 0x97, 0xfd, 0xac, 0x57, 0x5c, 0xc1, 0x43, 0x1e, 0x98, 0x26, - 0x71, 0xb0, 0x4b, 0xe7, 0x48, 0xcf, 0xf0, 0x4b, 0xb6, 0x34, 0x91, 0x85, - 0xdf, 0xb8, 0x10, 0x63, 0xae, 0xd2, 0x71, 0x61, 0x59, 0xcd, 0x86, 0xa5, - 0x8d, 0xff, 0x94, 0x7a, 0x58, 0x45, 0x9e, 0x5a, 0x0a, 0xc4, 0x79, 0x25, - 0xe6, 0x43, 0x84, 0x3f, 0xc8, 0x53, 0xed, 0xb5, 0x9b, 0x65, 0xc9, 0xff, - 0x9e, 0xcf, 0x72, 0x0e, 0xd1, 0x1a, 0x46, 0xc3, 0xb2, 0x6b, 0xd1, 0xcb, - 0xb3, 0xb3, 0x3c, 0xdf, 0xdf, 0xbd, 0xeb, 0xc8, 0xdc, 0x1e, 0xcf, 0xc1, - 0xe7, 0x4a, 0x7d, 0x94, 0x2a, 0x93, 0x8e, 0xdb, 0xb3, 0x62, 0x1e, 0x49, - 0x2e, 0x83, 0xfc, 0x9c, 0x0d, 0xae, 0x10, 0x7f, 0x29, 0x8d, 0xa8, 0xe7, - 0x07, 0x29, 0xbd, 0xb3, 0x34, 0x03, 0x93, 0x95, 0x65, 0xa3, 0x56, 0xa9, - 0x13, 0x12, 0x1f, 0x9f, 0xec, 0xce, 0x72, 0x25, 0x99, 0x0f, 0x1f, 0x56, - 0x16, 0xad, 0x7f, 0xd4, 0x9f, 0x96, 0xe5, 0x4c, 0x67, 0x33, 0x31, 0x04, - 0xb9, 0x00, 0x11, 0x9a, 0xee, 0xc0, 0xee, 0x6d, 0xe6, 0x75, 0x15, 0xc1, - 0x1a, 0x42, 0xe3, 0x11, 0xf4, 0xb7, 0x1b, 0x8b, 0x37, 0xe9, 0x9a, 0xa0, - 0xad, 0x11, 0x2a, 0xa4, 0x34, 0xb5, 0xe2, 0xdf, 0xc8, 0x13, 0x0c, 0x0a, - 0xa2, 0x0c, 0xdf, 0x5f, 0x40, 0x45, 0x1a, 0x7a, 0xbb, 0xa6, 0x44, 0xb4, - 0xf3, 0x3c, 0xa1, 0x1a, 0xc8, 0x7a, 0xc9, 0x56, 0xcc, 0x5c, 0x9f, 0x86, - 0x1d, 0x2c, 0x10, 0xab, 0x0e, 0x70, 0x0a, 0x12, 0x06, 0x32, 0x35, 0xa9, - 0x94, 0xd8, 0x87, 0x6b, 0xe4, 0xa7, 0x13, 0x1c, 0xc9, 0x05, 0xb4, 0xab, - 0x83, 0xd0, 0xcf, 0x49, 0x7e, 0xa2, 0xa4, 0xad, 0x41, 0x64, 0x95, 0xf4, - 0xab, 0x8c, 0x95, 0xab, 0xef, 0x30, 0x78, 0x66, 0x5d, 0x8f, 0x6c, 0x41, - 0x0c, 0x16, 0x4b, 0x2f, 0xff, 0x49, 0x9e, 0x7a, 0x1d, 0x4b, 0x04, 0x9c, - 0xf7, 0x32, 0xd1, 0x78, 0xdb, 0xd3, 0xbd, 0xb6, 0x9b, 0xd6, 0xa9, 0x56, - 0x5b, 0xd1, 0x4c, 0x52, 0x4f, 0x59, 0x64, 0x91, 0x14, 0x18, 0x62, 0xea, - 0xee, 0x68, 0xd5, 0x7e, 0xb0, 0xc3, 0xe7, 0xb9, 0x84, 0x3f, 0x49, 0xe9, - 0xb7, 0x4d, 0xaa, 0xd2, 0x86, 0x18, 0x1b, 0x0d, 0xc5, 0x27, 0x9d, 0x6d, - 0x9a, 0x35, 0x97, 0x46, 0x03, 0x71, 0xa0, 0xa0, 0x93, 0xac, 0x64, 0xad, - 0x5f, 0xb1, 0x4c, 0x47, 0xbc, 0x07, 0x2b, 0x45, 0xb9, 0x17, 0x6a, 0x72, - 0xd4, 0xbb, 0x92, 0x13, 0x0f, 0x03, 0xae, 0x01, 0xb8, 0xce, 0xc1, 0x7e, - 0xc8, 0x66, 0x3b, 0xb8, 0x1d, 0x71, 0x87, 0x76, 0x7d, 0x94, 0xbe, 0xdf, - 0x7a, 0xd0, 0x71, 0xaa, 0xb6, 0xa4, 0xf1, 0x60, 0x27, 0x4a, 0x62, 0xb0, - 0x4c, 0x5b, 0xb3, 0xaf, 0xe9, 0x73, 0xf3, 0x1c, 0x09, 0x64, 0xad, 0x0c, - 0x6c, 0x2c, 0x09, 0x32, 0x45, 0x89, 0xb5, 0x13, 0x62, 0xb5, 0x38, 0xa0, - 0xfe, 0x2d, 0xa3, 0x7c, 0xc8, 0xe2, 0x58, 0x68, 0x1f, 0x5b, 0x6e, 0xda, - 0xd3, 0x9a, 0x39, 0x2b, 0x09, 0xb6, 0xa4, 0xc5, 0x4a, 0xf8, 0x33, 0x44, - 0x62, 0x80, 0x99, 0x44, 0xf1, 0xfe, 0xca, 0xdc, 0xbb, 0x42, 0x6e, 0x10, - 0xf8, 0x77, 0x60, 0x97, 0x7e, 0x83, 0xef, 0x2d, 0xb1, 0x5c, 0x14, 0xcd, - 0xae, 0x63, 0x94, 0x25, 0xe6, 0x47, 0xe1, 0x1a, 0x35, 0x64, 0x85, 0xe4, - 0x18, 0x9b, 0x99, 0x10, 0x95, 0xad, 0x59, 0xdc, 0x61, 0x47, 0xc7, 0xbf, - 0x2b, 0x9b, 0x45, 0x7c, 0xef, 0x6f, 0x43, 0xfd, 0xe9, 0xec, 0xb1, 0x2e, - 0xb8, 0xe7, 0x0f, 0x81, 0xc6, 0x9d, 0x72, 0xda, 0x22, 0x35, 0xd7, 0xba, - 0xde, 0xb6, 0xfb, 0xce, 0xf1, 0x7d, 0x45, 0xdd, 0xe4, 0xd3, 0x6f, 0x13, - 0xb9, 0xe2, 0x81, 0x7e, 0x00, 0xf8, 0x21, 0xe0, 0x5d, 0x60, 0x1f, 0x48, - 0x5f, 0x10, 0x33, 0xec, 0x6e, 0xaf, 0xa4, 0x6c, 0xff, 0xfa, 0x84, 0xbf, - 0x1a, 0x13, 0x87, 0xef, 0xbe, 0x4a, 0x35, 0xb6, 0xe3, 0xb9, 0xf5, 0x5b, - 0xc5, 0x6e, 0xfd, 0xde, 0x64, 0xbf, 0xa4, 0x1f, 0x40, 0xae, 0x44, 0x0a, - 0xad, 0x73, 0xcf, 0x19, 0xa5, 0x0b, 0xf8, 0xa5, 0xbb, 0x27, 0xc4, 0x41, - 0x65, 0xa2, 0xee, 0x5e, 0x99, 0x66, 0x54, 0x0c, 0x55, 0x27, 0x83, 0x3f, - 0x47, 0xb3, 0x84, 0x4a, 0x70, 0xaf, 0x9d, 0x92, 0x77, 0x79, 0x6e, 0x21, - 0xc7, 0x87, 0x4b, 0x8d, 0xaf, 0x2c, 0x0d, 0xc9, 0xf3, 0xe7, 0x1d, 0x89, - 0xdc, 0xeb, 0xb1, 0xd6, 0x62, 0xd9, 0x7c, 0x2a, 0x0c, 0x48, 0x14, 0x3f, - 0xb4, 0x49, 0x41, 0x4f, 0x2f, 0xff, 0xaa, 0x46, 0x20, 0x7b, 0x52, 0x19, - 0xd1, 0x8f, 0x95, 0xbe, 0x33, 0x79, 0xa2, 0x15, 0x35, 0x2f, 0xac, 0x49, - 0xf5, 0x72, 0x27, 0x92, 0xcb, 0x4d, 0x0f, 0x0b, 0x6f, 0x2c, 0xd6, 0xc8, - 0xff, 0x4d, 0xf9, 0xef, 0xde, 0x73, 0x17, 0x5d, 0x99, 0x30, 0x81, 0xaf, - 0xe6, 0xc4, 0xf1, 0x8c, 0x78, 0x5e, 0x9e, 0xb2, 0xcb, 0xaf, 0x9e, 0x64, - 0xaa, 0x92, 0x16, 0xc0, 0x80, 0xf9, 0xbe, 0xa4, 0x43, 0x1e, 0xf5, 0xed, - 0xaf, 0xac, 0xba, 0x8e, 0x6c, 0x1c, 0x57, 0xcb, 0x12, 0x28, 0x9f, 0xe5, - 0x9f, 0xc1, 0x4a, 0xed, 0xa0, 0xfa, 0xe1, 0x29, 0x46, 0x4a, 0xc9, 0xab, - 0xf5, 0xf7, 0x99, 0xdc, 0xa6, 0xcf, 0x52, 0xf3, 0x0f, 0x83, 0xdf, 0xe3, - 0xab, 0x24, 0x40, 0xd1, 0x9c, 0x4b, 0xea, 0x5b, 0x4f, 0x1e, 0xeb, 0x98, - 0x91, 0xd8, 0x8b, 0x38, 0x32, 0xdf, 0x0b, 0x73, 0xdf, 0x3d, 0x4b, 0xea, - 0x0b, 0xad, 0xd4, 0x75, 0x88, 0xe0, 0xd0, 0x95, 0xf8, 0x0f, 0xb9, 0xe8, - 0x20, 0x77, 0x31, 0x1c, 0x20, 0xe2, 0xc9, 0x64, 0xad, 0xfd, 0x0d, 0xea, - 0x1b, 0xbf, 0x8f, 0xab, 0xc6, 0x0e, 0xcd, 0x6f, 0x7a, 0x79, 0xd4, 0xb6, - 0x13, 0xdc, 0x94, 0x59, 0xd6, 0xfd, 0x06, 0x07, 0xf8, 0xda, 0x96, 0x4f, - 0x42, 0x74, 0x7c, 0x7d, 0x0c, 0xf9, 0x07, 0xc6, 0x31, 0x3f, 0x7d, 0x7d, - 0x82, 0x8a, 0x23, 0x17, 0x29, 0x6a, 0xe1, 0xd7, 0xc3, 0x50, 0x34, 0xf1, - 0x95, 0x2c, 0x77, 0xdf, 0xd3, 0x01, 0xf8, 0x34, 0x15, 0xb4, 0x65, 0x54, - 0xb0, 0x8f, 0x1f, 0xc6, 0xbd, 0x0c, 0x11, 0x5a, 0xf4, 0xa4, 0x03, 0xcf, - 0xbc, 0xf5, 0x9e, 0xde, 0xe0, 0x4c, 0xd7, 0xf7, 0xd8, 0x28, 0x8f, 0xb9, - 0xc8, 0xbf, 0x77, 0xbb, 0x8d, 0xdf, 0x84, 0xaf, 0x2f, 0x76, 0xe1, 0x37, - 0xd6, 0x88, 0x63, 0x27, 0x42, 0x69, 0x5c, 0x41, 0x0e, 0x08, 0x60, 0x79, - 0x3c, 0x12, 0x42, 0x14, 0xee, 0x8c, 0x10, 0x1f, 0x57, 0x7d, 0xd4, 0x1d, - 0xc7, 0x96, 0x47, 0x87, 0x1b, 0xa4, 0x71, 0x24, 0x68, 0xc6, 0xac, 0x33, - 0x87, 0xb1, 0x74, 0x01, 0xfa, 0xe5, 0xf4, 0xe8, 0x48, 0xfe, 0x70, 0x97, - 0x7b, 0x10, 0xae, 0x3a, 0x7f, 0xfc, 0x37, 0x63, 0xca, 0xcf, 0xeb, 0x24, - 0x5c, 0xb5, 0xd8, 0x43, 0xfc, 0xb6, 0x99, 0x78, 0x1a, 0x7a, 0x44, 0x99, - 0x3b, 0x83, 0xcd, 0x47, 0x1e, 0x49, 0xc8, 0x6d, 0xa1, 0x13, 0xd4, 0x94, - 0x24, 0xd3, 0xb3, 0x7b, 0x07, 0x8b, 0x2c, 0x53, 0xdf, 0x7c, 0x00, 0xcf, - 0x0f, 0x1c, 0x66, 0x76, 0x78, 0x8e, 0x53, 0x41, 0x14, 0xfd, 0xf5, 0x76, - 0x05, 0xdd, 0x7f, 0x8d, 0x75, 0x32, 0xa8, 0x35, 0xcf, 0x7f, 0xb3, 0xfd, - 0xb8, 0x16, 0x9d, 0xc8, 0x72, 0x5d, 0x6f, 0xd0, 0x97, 0x13, 0x27, 0x62, - 0xa3, 0x14, 0xb5, 0x7e, 0x4d, 0xe7, 0x13, 0x8d, 0x42, 0x52, 0x4f, 0x72, - 0x26, 0x4d, 0x7a, 0x25, 0x46, 0xeb, 0x0b, 0x2d, 0x09, 0xd8, 0xfd, 0x20, - 0xcc, 0x91, 0x70, 0xad, 0x9e, 0xd9, 0x70, 0x01, 0xec, 0x27, 0x95, 0x13, - 0xe0, 0x1e, 0x62, 0xe8, 0xd2, 0xe8, 0xdb, 0xfe, 0x0d, 0x79, 0x1e, 0xe8, - 0x56, 0x8c, 0x83, 0x5f, 0xf5, 0x4a, 0x4a, 0x0b, 0x92, 0xf5, 0x99, 0x5c, - 0x58, 0xb1, 0xac, 0x7d, 0x03, 0x86, 0xdd, 0x7a, 0xa6, 0xb8, 0x95, 0x53, - 0xe1, 0x63, 0x39, 0x82, 0x67, 0xbb, 0x68, 0xf4, 0xfb, 0x9d, 0xd0, 0x2d, - 0x1d, 0xed, 0x03, 0x2b, 0x80, 0xad, 0xb2, 0xd4, 0x99, 0xf5, 0xa0, 0xac, - 0x12, 0x52, 0x59, 0x49, 0x7f, 0xb1, 0xaa, 0x53, 0x1a, 0xcf, 0x63, 0x86, - 0xee, 0xf8, 0x5e, 0x79, 0xa8, 0x48, 0x0b, 0xb0, 0x63, 0xaa, 0xe7, 0x5f, - 0x31, 0x3d, 0xac, 0x75, 0xdc, 0xf0, 0xd5, 0xa5, 0xd9, 0xe3, 0x8b, 0xea, - 0xf1, 0xfa, 0x0a, 0xd6, 0x3a, 0x55, 0xf9, 0x66, 0xb3, 0x90, 0xdd, 0x7e, - 0x1e, 0x63, 0x26, 0x1a, 0xd1, 0xe8, 0x98, 0x20, 0xe1, 0x94, 0xb5, 0x61, - 0xa0, 0x21, 0x33, 0xeb, 0xec, 0x1d, 0xdd, 0x8b, 0x01, 0xb3, 0x8d, 0x5b, - 0x34, 0x6c, 0xc9, 0x11, 0x39, 0x0e, 0x16, 0x72, 0x48, 0x16, 0x7c, 0x4d, - 0x80, 0xb8, 0x9d, 0xf7, 0x48, 0xb1, 0xab, 0xcf, 0xab, 0x13, 0x5c, 0x9f, - 0x32, 0x03, 0x23, 0xd8, 0x26, 0xbc, 0x46, 0x00, 0xb2, 0x78, 0x44, 0xaf, - 0x66, 0x7f, 0x2f, 0xad, 0x5f, 0x17, 0x61, 0x5d, 0x20, 0x94, 0x98, 0xd7, - 0x13, 0xfb, 0xd8, 0x07, 0xb0, 0x9f, 0xf9, 0x71, 0x3c, 0x6f, 0x55, 0x82, - 0x37, 0x14, 0xed, 0x93, 0xf4, 0x75, 0x00, 0x9d, 0xcb, 0xed, 0xd5, 0x17, - 0xd9, 0x51, 0x2f, 0x05, 0x23, 0x28, 0x9b, 0xc8, 0xf9, 0xd4, 0x56, 0xf2, - 0x46, 0xbd, 0x35, 0x07, 0xdf, 0xdf, 0xb7, 0x8f, 0x26, 0x64, 0x9b, 0x32, - 0x0d, 0xc0, 0xa8, 0x79, 0xe8, 0xa6, 0x85, 0x2b, 0x5e, 0xa9, 0xe5, 0xc9, - 0x0f, 0xba, 0x26, 0xe5, 0x14, 0x67, 0xe4, 0x8e, 0xd3, 0x93, 0x9f, 0x80, - 0xbd, 0x7a, 0x89, 0x9a, 0x18, 0x67, 0xf1, 0xd5, 0x09, 0xaf, 0x27, 0x6f, - 0x3a, 0x7c, 0x9f, 0xdb, 0x49, 0xdc, 0x37, 0xfb, 0xb6, 0xcc, 0x38, 0x09, - 0xc8, 0x10, 0x61, 0xe6, 0x94, 0xa0, 0x46, 0x6e, 0xca, 0x3c, 0x17, 0x7e, - 0x7f, 0xfa, 0x76, 0x08, 0xb3, 0xfe, 0x66, 0xb3, 0x9c, 0xb0, 0xf9, 0x2b, - 0x38, 0x5b, 0x44, 0x97, 0xb1, 0x8b, 0x67, 0x75, 0x18, 0x60, 0x72, 0x8e, - 0xf4, 0x5e, 0x00, 0x65, 0x2e, 0x98, 0xbe, 0xe4, 0x0b, 0x4e, 0x99, 0x3d, - 0xd6, 0xf3, 0x3a, 0xf9, 0x28, 0x42, 0xe2, 0xa9, 0x61, 0xf6, 0x40, 0xe9, - 0xad, 0xa5, 0xe3, 0x5f, 0x40, 0xfe, 0x11, 0xc8, 0xd9, 0xc3, 0xdd, 0x75, - 0xa9, 0x75, 0x29, 0x72, 0xf6, 0x5c, 0xdc, 0x38, 0x31, 0x97, 0xfc, 0xfa, - 0x17, 0x1c, 0x9e, 0x12, 0x19, 0x33, 0xa9, 0x10, 0xec, 0xab, 0x42, 0xab, - 0x84, 0x38, 0x02, 0x4e, 0x55, 0x98, 0x2c, 0xa5, 0x0f, 0x3f, 0x66, 0x77, - 0x5d, 0x51, 0x58, 0xad, 0x9d, 0xad, 0xd5, 0x1c, 0x9f, 0x4f, 0xfc, 0x62, - 0x68, 0x7f, 0xe0, 0x50, 0x55, 0x92, 0x36, 0x26, 0x15, 0x9f, 0xb0, 0x9a, - 0x7a, 0xf8, 0x18, 0xc9, 0x38, 0x0d, 0xbe, 0x8a, 0x0e, 0xf0, 0x1e, 0x9e, - 0x1b, 0xa8, 0xfb, 0xa4, 0x0b, 0xce, 0xb0, 0xd1, 0x73, 0x04, 0xbf, 0x78, - 0xe6, 0xd9, 0xce, 0x39, 0x54, 0x1c, 0xff, 0x7d, 0xf6, 0x74, 0xcc, 0x1a, - 0x71, 0x83, 0x86, 0x33, 0xf4, 0x9d, 0x82, 0x7d, 0x67, 0xc9, 0xd6, 0x0d, - 0xcc, 0x6b, 0x80, 0xcc, 0xfd, 0xc9, 0x3b, 0xb3, 0x1d, 0xbe, 0xa7, 0xce, - 0x37, 0x0f, 0x61, 0x9d, 0xca, 0xf2, 0xd4, 0x1f, 0xcd, 0x1e, 0x53, 0x86, - 0x8a, 0x41, 0xc6, 0xb0, 0xd4, 0x8d, 0x3b, 0x09, 0x24, 0x91, 0x53, 0xed, - 0x22, 0xbd, 0x72, 0x2c, 0x3c, 0xa4, 0x32, 0x65, 0x0c, 0xa0, 0xdd, 0x57, - 0x06, 0xb9, 0xe3, 0xf8, 0x6a, 0xcc, 0xe1, 0xa7, 0x6a, 0xd5, 0xbd, 0x9e, - 0x72, 0xef, 0x86, 0x3f, 0xbd, 0x50, 0xe6, 0x69, 0xd9, 0xf9, 0xab, 0xfb, - 0x79, 0x61, 0x81, 0x8d, 0xa7, 0x67, 0x54, 0x14, 0xe1, 0x3d, 0x2e, 0xfd, - 0x2f, 0xa8, 0x89, 0x6a, 0xe8, 0x36, 0xcd, 0x69, 0xbc, 0x30, 0x44, 0x5b, - 0x96, 0x7f, 0xb8, 0x09, 0x37, 0x49, 0xad, 0x5f, 0xdd, 0x17, 0xe8, 0xdb, - 0xbc, 0xf0, 0x70, 0x15, 0xfa, 0xeb, 0xcc, 0x2b, 0x3f, 0x1c, 0x0d, 0x38, - 0x31, 0xa6, 0x3e, 0x0a, 0x5e, 0x92, 0xa3, 0x56, 0xfd, 0xc4, 0x73, 0xc8, - 0xda, 0xe6, 0x06, 0x55, 0xd1, 0xcb, 0x6f, 0x1f, 0x9d, 0x2d, 0x48, 0xe9, - 0x65, 0xcf, 0x21, 0x4c, 0xc7, 0xd1, 0xff, 0x54, 0xed, 0x67, 0x53, 0x7e, - 0xa4, 0xd3, 0x77, 0x08, 0x9a, 0xc1, 0x2e, 0x91, 0xbf, 0xd0, 0x84, 0x42, - 0x20, 0x5f, 0x00, 0xcb, 0xa4, 0xec, 0x6d, 0x01, 0x5b, 0xe2, 0xe7, 0x46, - 0xbb, 0xe3, 0xec, 0xd0, 0xa6, 0x65, 0x3a, 0xf0, 0x9d, 0x7e, 0xde, 0xab, - 0x4a, 0x41, 0x06, 0x2d, 0xf3, 0xe8, 0xf2, 0xc8, 0x5e, 0x3a, 0x03, 0xc7, - 0x75, 0xd9, 0x42, 0xa6, 0xa7, 0x54, 0xba, 0x5f, 0xc4, 0x61, 0x75, 0x0c, - 0x96, 0x58, 0xd1, 0xdf, 0xe5, 0xea, 0xa7, 0xdb, 0x41, 0xc3, 0x2f, 0xbf, - 0x8a, 0xa2, 0x45, 0x86, 0x7a, 0x77, 0x7e, 0xd6, 0x4d, 0x77, 0x2e, 0xcd, - 0x53, 0x80, 0xd7, 0x0c, 0x6c, 0x6b, 0x2f, 0x39, 0xe1, 0x8d, 0xf5, 0xef, - 0x59, 0x54, 0x92, 0xd4, 0x68, 0x78, 0xec, 0x84, 0x40, 0xe9, 0x17, 0x95, - 0xe1, 0x97, 0xb6, 0x09, 0xa2, 0x18, 0xf0, 0x88, 0x80, 0x0a, 0x0f, 0x68, - 0xb5, 0x70, 0x84, 0xa5, 0x65, 0x01, 0x45, 0xbe, 0xc2, 0x09, 0xe7, 0x51, - 0x09, 0xff, 0x82, 0x9f, 0x0e, 0xad, 0x60, 0xbd, 0x85, 0x76, 0x45, 0xb1, - 0x14, 0x6c, 0x08, 0xa9, 0x6c, 0xc6, 0x5f, 0xd9, 0xcc, 0xb2, 0x9a, 0x77, - 0x0a, 0xd0, 0xc5, 0x09, 0x1b, 0xb3, 0xb9, 0xd1, 0xa4, 0xd2, 0x12, 0x7e, - 0x24, 0xa6, 0x68, 0xb8, 0xd3, 0xc8, 0xeb, 0x12, 0x6d, 0x77, 0xa6, 0xa8, - 0x06, 0xdc, 0x38, 0x9a, 0x10, 0x66, 0x51, 0x4d, 0xe5, 0x1c, 0xb4, 0xa5, - 0x33, 0xae, 0x0c, 0x81, 0xbc, 0x4e, 0xed, 0x9f, 0xfd, 0x84, 0xf5, 0xdc, - 0x17, 0x95, 0xe3, 0x49, 0xef, 0x99, 0x44, 0x3d, 0x06, 0x94, 0x3a, 0x84, - 0x51, 0xaa, 0x10, 0xbd, 0xc9, 0x9f, 0xd0, 0x8f, 0x88, 0xfd, 0x24, 0x14, - 0xb0, 0x99, 0xf9, 0x35, 0x5d, 0x75, 0x2d, 0xf7, 0x4f, 0xd8, 0xc6, 0x32, - 0xaf, 0xb0, 0x22, 0x58, 0x94, 0x10, 0xb2, 0xf7, 0x33, 0x37, 0x9b, 0x07, - 0xa9, 0xe6, 0x5a, 0x6a, 0x4d, 0xa7, 0x55, 0x25, 0x09, 0x40, 0xef, 0x09, - 0x7f, 0xd3, 0xcd, 0x32, 0xb0, 0x97, 0xb7, 0x2f, 0x64, 0xff, 0x74, 0x8a, - 0xe1, 0xbf, 0x8e, 0xe7, 0x08, 0x30, 0x99, 0x5a, 0x9b, 0xa9, 0x0b, 0xaa, - 0x19, 0x26, 0xe1, 0xef, 0xfc, 0xd8, 0x84, 0x73, 0x27, 0x46, 0xcd, 0xb6, - 0xdd, 0xf2, 0xcd, 0x41, 0x8f, 0xab, 0x73, 0x9e, 0x0a, 0x1d, 0x19, 0x9b, - 0xf6, 0xaf, 0xb4, 0x34, 0x8b, 0x2c, 0xaa, 0x76, 0xae, 0x28, 0x0a, 0x9e, - 0x48, 0xbb, 0x6e, 0x62, 0x64, 0xe5, 0xba, 0x3c, 0x7d, 0x15, 0xf0, 0x39, - 0x74, 0xc8, 0xaa, 0x91, 0x48, 0x95, 0x4d, 0x78, 0x54, 0xee, 0x3f, 0xa1, - 0x4a, 0xa9, 0x1f, 0xf2, 0xc0, 0x0f, 0x93, 0x35, 0x98, 0xd8, 0x6c, 0xe1, - 0xee, 0x1b, 0x9f, 0x14, 0xb9, 0xbb, 0x0d, 0xa7, 0x01, 0x95, 0xd1, 0xa2, - 0x6b, 0xf7, 0x6e, 0x22, 0xdf, 0x52, 0xe5, 0x1e, 0x45, 0x8d, 0xb8, 0x77, - 0x1f, 0x8f, 0x28, 0x9e, 0xa8, 0x1c, 0xb9, 0x98, 0xd2, 0x93, 0x71, 0x2f, - 0x41, 0xa5, 0x57, 0x11, 0xce, 0x4c, 0xc7, 0xa0, 0x9a, 0x5e, 0xdf, 0x44, - 0x62, 0x7d, 0x51, 0x49, 0x71, 0x95, 0x7a, 0xff, 0xda, 0x6b, 0xec, 0xb3, - 0xcc, 0xde, 0x76, 0x21, 0x38, 0x1b, 0xc8, 0x8e, 0xa2, 0x01, 0xe0, 0x04, - 0x69, 0xfb, 0x19, 0xc8, 0x26, 0x78, 0xe3, 0xe7, 0x7b, 0xa9, 0xe7, 0x7c, - 0x19, 0xfa, 0xd0, 0x1d, 0xdf, 0x79, 0xc2, 0x99, 0x9e, 0x97, 0x99, 0x08, - 0xd5, 0x19, 0x88, 0x3e, 0x4d, 0xb9, 0xfa, 0x0c, 0xa2, 0x1e, 0x63, 0x9e, - 0x63, 0x6d, 0x93, 0x99, 0x96, 0x82, 0x9e, 0x19, 0x08, 0xde, 0xea, 0xbc, - 0xc5, 0xa8, 0xc9, 0xcb, 0xb0, 0x7e, 0xa0, 0x3d, 0xc3, 0x99, 0x2a, 0xd6, - 0xee, 0x0f, 0x67, 0x2c, 0x03, 0xac, 0xf7, 0x43, 0xe7, 0xcc, 0x87, 0x18, - 0xbf, 0x37, 0x97, 0x96, 0x6a, 0x82, 0x99, 0x85, 0x9a, 0x39, 0x15, 0x75, - 0x0d, 0x96, 0xde, 0x8d, 0x1f, 0xee, 0x07, 0xc0, 0x84, 0xcf, 0x16, 0x08, - 0xcf, 0x93, 0xae, 0x23, 0xea, 0x75, 0xcc, 0x50, 0x6a, 0x8b, 0x83, 0xae, - 0x75, 0x17, 0x2e, 0xa5, 0x87, 0x98, 0x92, 0x30, 0x21, 0x82, 0x1e, 0xd1, - 0x5f, 0x1d, 0xa3, 0x2b, 0xa7, 0x5b, 0xb5, 0xac, 0xdc, 0x4f, 0x33, 0xc0, - 0xd3, 0x3e, 0x9c, 0x18, 0x6a, 0xc7, 0xd1, 0xf5, 0xda, 0xc3, 0xd4, 0x6b, - 0xbf, 0x82, 0x0d, 0xe7, 0x6a, 0x7f, 0x52, 0x1d, 0x63, 0x29, 0xc4, 0x78, - 0xa9, 0x7c, 0x58, 0x28, 0x86, 0x07, 0x88, 0xbe, 0x61, 0xe8, 0x8a, 0xd1, - 0xee, 0xaa, 0x0a, 0x17, 0xc7, 0xac, 0x06, 0xdc, 0x65, 0x69, 0x0d, 0xa6, - 0xc0, 0xd2, 0x6e, 0x89, 0x55, 0xce, 0x3e, 0x51, 0x94, 0x04, 0xb7, 0x87, - 0x2e, 0x48, 0x77, 0x56, 0xd3, 0x07, 0x2c, 0x00, 0x6a, 0x64, 0x3b, 0x3c, - 0x19, 0x48, 0x81, 0xe3, 0x16, 0x63, 0x7d, 0x19, 0x77, 0xfa, 0xa0, 0xc7, - 0x0f, 0x92, 0x07, 0x69, 0x6a, 0xa7, 0xd0, 0xe4, 0x7c, 0x29, 0x64, 0xcd, - 0xe3, 0xfa, 0xea, 0xe9, 0xe1, 0xa3, 0x71, 0xda, 0x2a, 0xce, 0x6f, 0xdd, - 0xcd, 0xa5, 0x20, 0x56, 0xa6, 0x4a, 0xbb, 0x29, 0x4b, 0xae, 0x36, 0xfc, - 0xc4, 0x43, 0xca, 0xee, 0x5a, 0x4c, 0x5b, 0x4d, 0x24, 0x0a, 0xf1, 0x61, - 0x2d, 0x5f, 0x90, 0x71, 0xe8, 0x29, 0x0a, 0x1d, 0x6b, 0xc6, 0x9e, 0xd6, - 0xf0, 0xd6, 0x9c, 0x52, 0x3f, 0x28, 0x8e, 0xce, 0xf2, 0x1a, 0x00, 0x5d, - 0x31, 0x2d, 0x91, 0x6c, 0x5d, 0xd7, 0x8d, 0xa1, 0x83, 0x7b, 0x2b, 0x09, - 0x37, 0xd2, 0x35, 0xff, 0x11, 0x2e, 0x87, 0xc1, 0x91, 0x65, 0x53, 0x48, - 0x38, 0xdf, 0x96, 0x30, 0xda, 0x03, 0x54, 0xd4, 0x1b, 0x30, 0x7d, 0x6d, - 0xb1, 0x48, 0x96, 0xf0, 0x04, 0x5e, 0x7c, 0x00, 0x40, 0xaa, 0xec, 0x78, - 0x4f, 0xb9, 0xd4, 0x16, 0xfd, 0x30, 0xcf, 0x5b, 0x75, 0x34, 0x44, 0xf6, - 0xea, 0x12, 0xc5, 0xad, 0xb3, 0x87, 0xf8, 0x4b, 0x27, 0x6d, 0x74, 0xbe, - 0xf3, 0x31, 0xff, 0x85, 0x08, 0x06, 0x94, 0xe5, 0x0f, 0xc0, 0x77, 0x29, - 0xc0, 0xbe, 0x0e, 0x44, 0x5d, 0x4d, 0x2e, 0xab, 0x69, 0x5f, 0xc9, 0xfd, - 0xd1, 0xdc, 0x7a, 0xdd, 0xf0, 0x52, 0xa4, 0xa7, 0xd7, 0x02, 0xb1, 0xa9, - 0xb4, 0x93, 0x08, 0xd4, 0xca, 0xd5, 0xf8, 0x02, 0xdc, 0x11, 0x2f, 0xe6, - 0xe7, 0x3d, 0xaa, 0x62, 0x11, 0x8d, 0x7a, 0xff, 0x3b, 0xa1, 0xdf, 0x38, - 0xd5, 0xa0, 0x35, 0xb3, 0xf6, 0x61, 0x06, 0x99, 0x29, 0xa7, 0x67, 0x47, - 0xe0, 0xb8, 0xc4, 0x7c, 0x18, 0x18, 0x19, 0x21, 0x74, 0xc7, 0x59, 0x93, - 0x40, 0x24, 0x19, 0xce, 0xb5, 0x8f, 0xfe, 0xc2, 0x2a, 0x65, 0x77, 0xc5, - 0xc3, 0xf5, 0x5d, 0x69, 0xfb, 0xdc, 0xb7, 0x20, 0x75, 0xa9, 0x02, 0x67, - 0x5f, 0x6f, 0xd2, 0x40, 0x74, 0xa6, 0x8a, 0x93, 0xc8, 0x32, 0x65, 0xb8, - 0xcf, 0xe4, 0x35, 0x34, 0xba, 0x2b, 0x4b, 0x66, 0x3f, 0x16, 0x57, 0xd9, - 0xb4, 0x73, 0x94, 0xc9, 0x8f, 0x4b, 0x99, 0xed, 0x47, 0x68, 0x96, 0x2f, - 0xc6, 0xbf, 0xbe, 0xd7, 0x13, 0x5d, 0x64, 0xae, 0xf2, 0x27, 0xd3, 0x5d, - 0x23, 0x66, 0x35, 0x41, 0x7c, 0x8d, 0xc6, 0x50, 0x9d, 0x92, 0x91, 0xbc, - 0x96, 0xcf, 0xda, 0xf4, 0x16, 0xa5, 0xde, 0xd8, 0xaa, 0x0a, 0x6b, 0xf5, - 0x25, 0x96, 0x89, 0x2c, 0x50, 0xa6, 0xdf, 0x27, 0x00, 0x6b, 0xb7, 0x4f, - 0xea, 0x38, 0x67, 0x8b, 0x0e, 0x09, 0x34, 0x26, 0xed, 0x9d, 0x6d, 0x91, - 0xfd, 0x3b, 0xb8, 0x6e, 0x66, 0x4e, 0x78, 0x07, 0x67, 0x0d, 0xce, 0xc0, - 0xcb, 0x7d, 0x6d, 0x00, 0xaf, 0x0e, 0x90, 0x9b, 0x18, 0xda, 0xbf, 0x95, - 0x34, 0xab, 0x0d, 0x3e, 0xab, 0x2a, 0xe1, 0xe1, 0x82, 0x1b, 0xa9, 0x26, - 0xab, 0xb5, 0x80, 0x20, 0x3f, 0xa1, 0x63, 0x26, 0x33, 0x8b, 0x00, 0x77, - 0x82, 0xf9, 0x85, 0x8a, 0xc1, 0x53, 0xbd, 0x03, 0xae, 0x16, 0x75, 0xeb, - 0x4e, 0x38, 0x65, 0xf5, 0xeb, 0xe2, 0xdd, 0x8f, 0x68, 0x4b, 0xb4, 0x57, - 0x16, 0x7b, 0x1d, 0xb1, 0xb8, 0x01, 0xa9, 0xf1, 0xb3, 0xcc, 0x4f, 0x9e, - 0xc0, 0x12, 0xa1, 0x00, 0x6f, 0x56, 0xd4, 0x35, 0x11, 0x23, 0x82, 0xac, - 0x87, 0x9f, 0xba, 0xe4, 0x3c, 0x92, 0x8a, 0x6d, 0x75, 0x28, 0xaa, 0x62, - 0x98, 0x08, 0xe4, 0xe2, 0x8b, 0x68, 0xfb, 0x56, 0x9c, 0x33, 0xe6, 0xed, - 0x51, 0x65, 0x3c, 0xa2, 0x4d, 0xe1, 0x2c, 0x11, 0x77, 0xc4, 0xb7, 0x31, - 0xa1, 0x0a, 0xac, 0x7c, 0x74, 0x0a, 0x81, 0x15, 0x8f, 0x7f, 0xac, 0xc3, - 0xa1, 0x6d, 0xc1, 0x0b, 0xaf, 0xac, 0x1a, 0x14, 0xe9, 0xe4, 0x64, 0x22, - 0xf7, 0xcc, 0x37, 0xcc, 0xd4, 0xb0, 0x23, 0x79, 0x3e, 0xda, 0xca, 0xd9, - 0x75, 0x64, 0x87, 0x2e, 0x7a, 0x10, 0x51, 0x41, 0xd7, 0xf2, 0x39, 0xd7, - 0x56, 0xcb, 0x86, 0x1a, 0x27, 0x1f, 0x0e, 0xc5, 0xd4, 0x6f, 0x7f, 0x33, - 0x0c, 0x7f, 0xad, 0xfb, 0xb7, 0x89, 0xca, 0x8f, 0xe0, 0x66, 0x94, 0x90, - 0xf2, 0x5a, 0x83, 0x12, 0x89, 0xad, 0x8b, 0x73, 0xaf, 0x32, 0xfa, 0x17, - 0x6a, 0x21, 0x61, 0x1d, 0x1a, 0x8b, 0x88, 0x8e, 0x38, 0x7d, 0xec, 0x9f, - 0xa0, 0xcf, 0x07, 0x33, 0x09, 0xe4, 0x40, 0x7d, 0x8a, 0x62, 0x81, 0xfa, - 0x5c, 0xf5, 0x2e, 0x67, 0xf3, 0xd3, 0x34, 0xfa, 0x5e, 0x81, 0x6f, 0x11, - 0x2b, 0xf5, 0x6c, 0x38, 0xe2, 0xd2, 0x39, 0xce, 0x0b, 0x00, 0x98, 0xf4, - 0x3f, 0xc4, 0x35, 0xe4, 0xdd, 0x05, 0xd6, 0x26, 0x32, 0x27, 0x89, 0x7c, - 0x58, 0x0b, 0x56, 0x7d, 0x87, 0xb8, 0x83, 0x4f, 0xda, 0xe1, 0x66, 0x13, - 0xe7, 0x62, 0x13, 0x9d, 0x1c, 0x05, 0xd5, 0x9c, 0x50, 0x2f, 0xfc, 0x3b, - 0x23, 0x52, 0x43, 0xb5, 0xb4, 0x2f, 0x52, 0xab, 0x8f, 0x06, 0xf5, 0x02, - 0x41, 0x6b, 0xc4, 0xd4, 0x4c, 0x5c, 0x83, 0xb8, 0x52, 0x87, 0xb7, 0x43, - 0x68, 0xa0, 0x02, 0xe9, 0x89, 0xd0, 0xe8, 0x06, 0xcd, 0x5d, 0xe0, 0x7d, - 0xd7, 0x64, 0xe1, 0x2c, 0xf5, 0xac, 0x01, 0x0a, 0x1e, 0x6a, 0x85, 0xa7, - 0x9c, 0x61, 0x57, 0x9f, 0x29, 0xcf, 0x06, 0xc8, 0x9a, 0x64, 0xc3, 0xdf, - 0x5d, 0xac, 0x66, 0x4b, 0xf4, 0xe1, 0xfb, 0x4a, 0xd4, 0x66, 0x04, 0x38, - 0xa8, 0x30, 0x15, 0x33, 0x91, 0x4c, 0x99, 0xd8, 0xc8, 0x9f, 0x7e, 0x11, - 0xad, 0xb8, 0x67, 0x78, 0x4c, 0x8c, 0xfd, 0x9e, 0x9d, 0xdd, 0x64, 0x09, - 0x6f, 0x90, 0x92, 0xe1, 0x24, 0xb3, 0xa6, 0x2d, 0xe2, 0x78, 0x70, 0x38, - 0x73, 0x8a, 0x6d, 0x68, 0xe0, 0xf9, 0x55, 0x48, 0x08, 0x75, 0x68, 0x4d, - 0x1f, 0x59, 0xf5, 0x9c, 0xe5, 0xa7, 0x3a, 0x9f, 0x93, 0xcd, 0x9b, 0xc6, - 0x50, 0x74, 0x17, 0xd2, 0x9b, 0xd0, 0xa5, 0x3f, 0x06, 0x91, 0x4f, 0x89, - 0xb7, 0xda, 0xd7, 0x4d, 0xde, 0x32, 0xf4, 0x8d, 0x3a, 0x8f, 0x43, 0x00, - 0xdc, 0x27, 0xb4, 0xed, 0xb1, 0x14, 0xbb, 0x81, 0xfb, 0x1e, 0x6a, 0x71, - 0xff, 0x5a, 0xc6, 0x4d, 0xb7, 0x31, 0x24, 0x42, 0x1b, 0xd3, 0x94, 0x3a, - 0x2d, 0x80, 0xfa, 0x72, 0x54, 0x89, 0x37, 0x82, 0x7a, 0xdc, 0x52, 0xe2, - 0x0a, 0xa5, 0x03, 0x43, 0x0b, 0xde, 0xde, 0x3d, 0x9b, 0xd9, 0xb8, 0x4c, - 0x44, 0x13, 0xbb, 0xe8, 0x2b, 0xb7, 0xe8, 0x37, 0x6f, 0x58, 0x07, 0xee, - 0x0f, 0xef, 0xf3, 0x30, 0x52, 0x35, 0x70, 0x02, 0x70, 0x5a, 0x16, 0x2d, - 0x8c, 0x1f, 0x06, 0xd4, 0x04, 0xd6, 0xf9, 0x02, 0x9c, 0x7c, 0x1e, 0x86, - 0xef, 0x6a, 0x8c, 0x78, 0xaf, 0x49, 0xcb, 0x9a, 0x6a, 0xcd, 0xfd, 0x70, - 0x88, 0x64, 0xce, 0x76, 0xaf, 0xb9, 0x2e, 0x90, 0x98, 0x91, 0xca, 0xf2, - 0x4f, 0x14, 0x75, 0xa9, 0x6b, 0x8b, 0x28, 0x1c, 0x9b, 0x3f, 0x8b, 0x1a, - 0xa6, 0x11, 0x43, 0x2c, 0xed, 0x83, 0xda, 0x31, 0x3c, 0x3b, 0xb6, 0x0b, - 0x5f, 0xf3, 0x5d, 0xd0, 0x27, 0x5f, 0xd5, 0xef, 0x68, 0x00, 0x8e, 0xd6, - 0xa1, 0x36, 0x9f, 0x41, 0xc3, 0x96, 0xe1, 0x19, 0x61, 0x67, 0x93, 0x0a, - 0xe6, 0x3a, 0x9e, 0x85, 0x3a, 0x04, 0x81, 0xf7, 0xcf, 0x74, 0x6c, 0x19, - 0x35, 0x49, 0x5a, 0x94, 0xa7, 0xd4, 0xe1, 0x3a, 0x2d, 0xd8, 0x93, 0x17, - 0x0c, 0x7c, 0xc1, 0xb8, 0x8f, 0xe0, 0x02, 0xdd, 0xb0, 0x37, 0x58, 0x1e, - 0x56, 0xbf, 0x71, 0x96, 0xac, 0xbe, 0x31, 0xaa, 0xc3, 0xbc, 0x1f, 0x97, - 0x65, 0x11, 0xa7, 0xc5, 0x6f, 0x51, 0x6d, 0xf8, 0x03, 0xb3, 0xf3, 0xa2, - 0x3b, 0x73, 0xb5, 0x40, 0xe4, 0x64, 0x2e, 0x6c, 0xc1, 0x35, 0x19, 0xfe, - 0x1b, 0x7f, 0xf3, 0x52, 0xf1, 0x52, 0x91, 0xd0, 0x9f, 0xc3, 0x8a, 0xa9, - 0x1a, 0x24, 0x01, 0xe7, 0xc0, 0x55, 0xb8, 0xff, 0xee, 0x68, 0xaf, 0x53, - 0x01, 0x1c, 0xd0, 0x8b, 0x2e, 0x6e, 0x8a, 0xd9, 0xe0, 0x28, 0x8a, 0x07, - 0xc6, 0x99, 0x83, 0x4a, 0x5c, 0x48, 0xaa, 0x64, 0xe4, 0xaf, 0x2b, 0xf6, - 0x8f, 0xb6, 0x29, 0x9d, 0x8e, 0x88, 0x5d, 0xe8, 0x7c, 0x8a, 0xcc, 0x58, - 0xc0, 0x45, 0xe8, 0x95, 0xf8, 0x43, 0x9c, 0x13, 0x53, 0xb8, 0x7c, 0xd0, - 0x39, 0x7d, 0x13, 0x96, 0xda, 0xea, 0xcb, 0x8c, 0x11, 0xe3, 0xee, 0xf7, - 0xf8, 0x7d, 0x64, 0xfd, 0xed, 0x40, 0xaa, 0x2a, 0xd6, 0xb5, 0xfa, 0x40, - 0xcc, 0xc8, 0x89, 0x7f, 0x6f, 0x95, 0x23, 0xd0, 0x8b, 0xeb, 0x67, 0x96, - 0x84, 0x0b, 0x5e, 0x66, 0xde, 0xeb, 0xdb, 0xc4, 0x92, 0x25, 0x8c, 0x00, - 0xdc, 0x8b, 0xde, 0x47, 0xb7, 0xb8, 0x49, 0xbc, 0xc1, 0xd8, 0x4e, 0xa5, - 0x59, 0xfe, 0x48, 0xf4, 0x4a, 0x7d, 0x06, 0x19, 0xe2, 0x72, 0xb1, 0xf8, - 0xe4, 0x72, 0x71, 0x5c, 0x1e, 0x9b, 0x77, 0x57, 0x4b, 0x1c, 0x11, 0xf3, - 0xd4, 0x64, 0x95, 0x00, 0x7d, 0x79, 0x8e, 0x76, 0x92, 0x2f, 0x01, 0xa5, - 0xb3, 0x78, 0xf7, 0x04, 0x01, 0x39, 0xe6, 0x75, 0x54, 0xea, 0xd7, 0x2d, - 0xe5, 0x9e, 0x95, 0x0d, 0x98, 0x02, 0x50, 0xf7, 0x09, 0xc9, 0x13, 0x5a, - 0x5c, 0x52, 0x17, 0x3c, 0x69, 0x34, 0xaf, 0xcd, 0x0c, 0x7f, 0x35, 0xc1, - 0xd9, 0xb6, 0x62, 0x97, 0x76, 0xe0, 0x16, 0x91, 0x29, 0x96, 0x00, 0xfc, - 0xce, 0x12, 0x3a, 0x65, 0x9e, 0x8f, 0x1a, 0x5e, 0x59, 0x5f, 0xa9, 0x32, - 0x0a, 0x6c, 0x12, 0xaf, 0xbd, 0x58, 0xc9, 0x21, 0x70, 0xce, 0xae, 0xfc, - 0x94, 0x6d, 0x84, 0xee, 0xb6, 0x08, 0x63, 0x69, 0xd2, 0xdd, 0xa6, 0x29, - 0xe8, 0x38, 0x08, 0xea, 0x74, 0x44, 0x48, 0x24, 0xef, 0xdc, 0xfe, 0x04, - 0xbf, 0xc5, 0xf8, 0x2d, 0xd6, 0x77, 0x2f, 0x31, 0x61, 0x56, 0x56, 0x53, - 0x89, 0x26, 0x34, 0xf4, 0xbd, 0xbe, 0xa0, 0x8f, 0xb9, 0x4b, 0x38, 0xc2, - 0x5d, 0x3a, 0xf1, 0x2b, 0x3d, 0xdf, 0x02, 0xde, 0xc2, 0xd3, 0x6d, 0x60, - 0xaa, 0x23, 0x5b, 0x6f, 0x33, 0xb4, 0x76, 0xb2, 0x4c, 0x39, 0xea, 0x33, - 0xc7, 0x10, 0x9d, 0xb6, 0xea, 0x91, 0x1c, 0xf7, 0x34, 0xa1, 0xa9, 0x0a, - 0xa1, 0xe2, 0x2b, 0x9a, 0xdb, 0xd2, 0x10, 0xa2, 0x85, 0xa8, 0x8c, 0xd7, - 0x7e, 0x6f, 0x48, 0x82, 0x85, 0x2f, 0x49, 0xbd, 0xc3, 0x6f, 0xc8, 0x3b, - 0x3a, 0xd7, 0xef, 0x0a, 0xd0, 0x80, 0x36, 0xb3, 0xe8, 0x99, 0xf9, 0x03, - 0xf4, 0x5d, 0xb9, 0x87, 0xbd, 0xf1, 0x28, 0x4b, 0x3a, 0xdc, 0x74, 0xff, - 0xcc, 0x7b, 0xfc, 0x89, 0xc0, 0x90, 0x40, 0x64, 0xb8, 0x95, 0xdb, 0x4c, - 0x1b, 0x84, 0xb1, 0x01, 0xc3, 0xcf, 0x1a, 0xdd, 0x5a, 0xef, 0x1d, 0xfc, - 0xb7, 0xf0, 0x53, 0x8f, 0xb7, 0x23, 0xba, 0xcd, 0x5f, 0x56, 0xeb, 0x53, - 0xd7, 0x3b, 0x71, 0x38, 0xc8, 0x5c, 0x9d, 0xdf, 0xda, 0x3c, 0x9d, 0x26, - 0xce, 0x54, 0x2d, 0xb0, 0x1e, 0x3b, 0x2b, 0x7c, 0x15, 0xb2, 0x98, 0xcb, - 0xfa, 0x57, 0xbf, 0x35, 0xe0, 0x8d, 0x53, 0x3e, 0xab, 0x29, 0x22, 0xcf, - 0xca, 0x92, 0x6b, 0xb0, 0x56, 0xa1, 0xdf, 0xe3, 0x13, 0x31, 0xc8, 0xed, - 0x4d, 0x65, 0xa6, 0x7f, 0xfc, 0xe6, 0x29, 0x37, 0x34, 0x45, 0xd2, 0x68, - 0x33, 0x25, 0x9e, 0xd1, 0x51, 0xe0, 0x13, 0x8c, 0x30, 0x42, 0x04, 0x75, - 0xbd, 0x5c, 0x51, 0x76, 0x2e, 0xc7, 0xe1, 0x6c, 0x48, 0x74, 0xc6, 0x11, - 0x7a, 0x90, 0x20, 0x0e, 0x80, 0x3f, 0x5b, 0x3e, 0x5d, 0xbf, 0x13, 0xee, - 0x74, 0x3c, 0xfb, 0xa1, 0xcb, 0x69, 0x3c, 0xe8, 0xd2, 0x80, 0xc0, 0x7f, - 0x1c, 0xa6, 0x09, 0xe6, 0x12, 0xc8, 0x56, 0x94, 0x99, 0x53, 0x8f, 0xa8, - 0xe2, 0xbc, 0xe2, 0x1c, 0x70, 0x81, 0x9b, 0xf5, 0xc3, 0x88, 0x2f, 0x9a, - 0x12, 0x96, 0x4e, 0x12, 0x20, 0x2f, 0xf1, 0xad, 0x09, 0xe1, 0xdf, 0x24, - 0xbd, 0x10, 0x07, 0xb3, 0x5a, 0x6c, 0x53, 0x3d, 0xaf, 0x60, 0xb1, 0xc8, - 0x71, 0xb2, 0x7e, 0xc4, 0xfe, 0x2e, 0x8a, 0xc5, 0x37, 0xef, 0x8a, 0x7e, - 0x6c, 0x39, 0xdb, 0xd9, 0x85, 0x34, 0xc0, 0x92, 0x75, 0xdb, 0x8c, 0x90, - 0x2f, 0x74, 0x92, 0x9a, 0x4e, 0x0f, 0x52, 0xd0, 0x15, 0x42, 0x88, 0xe7, - 0xac, 0xd0, 0xe6, 0xca, 0xae, 0x82, 0x50, 0x66, 0x4a, 0xee, 0xf0, 0xee, - 0xbb, 0xf1, 0x10, 0x31, 0xe2, 0x91, 0xc5, 0x27, 0xdd, 0x34, 0xe3, 0x05, - 0x76, 0x53, 0x10, 0x7f, 0xb5, 0x75, 0x6f, 0x5e, 0xa8, 0xdf, 0xa2, 0x52, - 0xa1, 0xc4, 0x92, 0x8d, 0x18, 0x47, 0x48, 0x68, 0xf6, 0x54, 0x3e, 0x4e, - 0x7e, 0x8f, 0x9b, 0xff, 0xb5, 0xe1, 0xe5, 0xcb, 0x25, 0x96, 0x27, 0x65, - 0x45, 0x80, 0x13, 0x5f, 0x56, 0x2e, 0x1e, 0x06, 0xb3, 0x65, 0x1a, 0xfc, - 0x94, 0x88, 0x29, 0x54, 0xf3, 0xb0, 0x06, 0xd4, 0xba, 0x4a, 0x34, 0xa4, - 0x0f, 0x7c, 0x4a, 0x0e, 0x55, 0x0f, 0xef, 0x7c, 0xbb, 0xaa, 0x24, 0x47, - 0xeb, 0x9c, 0x16, 0xf9, 0xe7, 0x80, 0xf3, 0x85, 0x51, 0x5d, 0x36, 0x7a, - 0x42, 0x2e, 0x56, 0x76, 0xaf, 0xf3, 0x6e, 0x5e, 0x31, 0x6d, 0xcf, 0x75, - 0xd3, 0x84, 0x77, 0xfe, 0xc0, 0xf7, 0x12, 0x09, 0xa5, 0x66, 0x30, 0x45, - 0xce, 0xe2, 0x9f, 0xbc, 0xbd, 0x60, 0x92, 0xf0, 0x63, 0x50, 0xcd, 0x99, - 0x22, 0xdc, 0x4c, 0x11, 0x5a, 0xcd, 0xad, 0xc0, 0x45, 0x53, 0xa6, 0x1a, - 0x08, 0xa3, 0xa8, 0x81, 0x5d, 0xfe, 0x98, 0xaa, 0x44, 0xf5, 0x51, 0x21, - 0x32, 0xbf, 0xfe, 0xce, 0x58, 0x4b, 0x0c, 0x96, 0x59, 0x26, 0x6b, 0xd2, - 0x15, 0x59, 0x2a, 0xca, 0x5c, 0x0b, 0xdb, 0xdd, 0x55, 0xd5, 0x10, 0x94, - 0xb7, 0x1f, 0xc1, 0x4f, 0xca, 0xde, 0xf7, 0x37, 0x80, 0x29, 0x8f, 0x2b, - 0xf6, 0xcc, 0x33, 0xe9, 0x1c, 0x82, 0x8e, 0x3d, 0x6a, 0x66, 0xa6, 0x96, - 0x5c, 0x39, 0x7a, 0x41, 0x9d, 0x46, 0xaa, 0xb0, 0x3e, 0x5b, 0x70, 0xe8, - 0x9c, 0xf6, 0x2a, 0xb9, 0x28, 0x72, 0x4c, 0x0f, 0xef, 0xc9, 0x31, 0xbc, - 0xaa, 0x82, 0x3a, 0x0a, 0x24, 0xd7, 0x52, 0x44, 0x3a, 0xfe, 0x8e, 0x32, - 0x6c, 0x3d, 0xc6, 0x63, 0xd3, 0xaa, 0x42, 0xf1, 0x8c, 0xcd, 0xfe, 0xad, - 0xeb, 0xd8, 0x01, 0x9a, 0x66, 0x98, 0xe8, 0x07, 0xc6, 0x0e, 0xce, 0x55, - 0xe9, 0xf3, 0xc0, 0xc2, 0x94, 0x9d, 0xc9, 0xab, 0x58, 0xc0, 0xc3, 0xf9, - 0xb6, 0xc2, 0x67, 0x9a, 0xaa, 0xaa, 0xa3, 0x4a, 0xb8, 0xfe, 0xe8, 0xb4, - 0x1d, 0x22, 0x19, 0x24, 0xbf, 0xa8, 0xa7, 0xef, 0xfd, 0x9a, 0x43, 0x92, - 0xe9, 0x35, 0x23, 0x53, 0x9a, 0xbb, 0x44, 0x88, 0x2c, 0x5c, 0x39, 0xa7, - 0x6a, 0xea, 0x6e, 0x35, 0x9d, 0xba, 0xa2, 0xca, 0x3f, 0xc6, 0x2f, 0x49, - 0x8a, 0xfd, 0xd6, 0x85, 0x81, 0x25, 0x58, 0xf1, 0xde, 0x46, 0xbe, 0xd3, - 0x1a, 0xa1, 0x69, 0xc8, 0xfd, 0xe7, 0x77, 0x18, 0xf2, 0xe9, 0x08, 0xca, - 0xd7, 0xf0, 0x67, 0x10, 0x7a, 0x0c, 0xa8, 0x33, 0x1a, 0xaf, 0x63, 0xcb, - 0x3e, 0x22, 0xcb, 0xd1, 0x0a, 0x1d, 0xdd, 0x2f, 0xbf, 0x39, 0x3c, 0x0b, - 0x67, 0x6a, 0x51, 0xa3, 0x5d, 0x6a, 0xdd, 0x40, 0xae, 0x2b, 0x08, 0x2a, - 0x33, 0x90, 0xd1, 0xad, 0x42, 0xfb, 0x3a, 0x42, 0x6e, 0xb6, 0x63, 0xfe, - 0x20, 0xa2, 0x45, 0xee, 0x65, 0xb8, 0xa5, 0xb4, 0x09, 0xc8, 0xe1, 0xd3, - 0x85, 0xd5, 0xca, 0xdc, 0x91, 0xaa, 0x01, 0x8c, 0xdd, 0x3d, 0x94, 0x1a, - 0xde, 0xf3, 0x76, 0xb2, 0xbe, 0x4a, 0x4b, 0xb6, 0x62, 0x34, 0x5f, 0x64, - 0xaf, 0xfb, 0x13, 0xf7, 0x1b, 0x8b, 0xe2, 0x9f, 0x2a, 0x87, 0x81, 0x78, - 0x93, 0xc5, 0x5d, 0x84, 0xf3, 0xab, 0xfe, 0x72, 0x65, 0x19, 0x4e, 0xee, - 0xc4, 0xe0, 0x25, 0xf0, 0xfa, 0x79, 0xa9, 0x4c, 0x98, 0xb8, 0xf5, 0xce, - 0xae, 0xe3, 0x2c, 0xbb, 0xf7, 0x77, 0x9d, 0x0e, 0x2c, 0x3c, 0x99, 0x75, - 0xf9, 0x3e, 0x6b, 0x53, 0x82, 0xc4, 0x27, 0xba, 0x77, 0x66, 0x49, 0xe6, - 0x7e, 0x5a, 0xc9, 0x58, 0x66, 0x7f, 0x0a, 0x34, 0xc1, 0xdd, 0x28, 0xb1, - 0x12, 0x65, 0x43, 0x77, 0x98, 0xbb, 0xae, 0x94, 0x60, 0x6f, 0xee, 0x31, - 0x50, 0x18, 0x0c, 0x03, 0xab, 0xd0, 0x55, 0xed, 0xd8, 0x48, 0x36, 0x46, - 0xd5, 0x12, 0x9c, 0x35, 0x37, 0x40, 0x10, 0x38, 0x5b, 0x34, 0x0c, 0x89, - 0x63, 0x25, 0xfb, 0x4d, 0x52, 0xde, 0x34, 0x3d, 0xc0, 0x91, 0xf2, 0x7c, - 0x02, 0x44, 0x68, 0x7f, 0x40, 0xf4, 0x8d, 0x20, 0x43, 0x05, 0x44, 0xe3, - 0x17, 0xd6, 0xc0, 0xf8, 0xab, 0xfc, 0x0c, 0x50, 0x7b, 0xe1, 0x4d, 0xc5, - 0x78, 0x36, 0x43, 0xd4, 0xcb, 0x00, 0xaf, 0x13, 0x22, 0xf2, 0x92, 0x41, - 0x3d, 0x80, 0x0d, 0x30, 0xa7, 0xef, 0x3a, 0x60, 0xa2, 0x12, 0x97, 0xce, - 0x14, 0x0b, 0x3e, 0xfe, 0x44, 0x1d, 0x64, 0x13, 0x7a, 0xb3, 0x0c, 0xac, - 0x27, 0xbd, 0xa3, 0x7c, 0xbb, 0xe6, 0x0d, 0xc8, 0xa4, 0x01, 0x58, 0x89, - 0xab, 0x76, 0x1b, 0xe3, 0x97, 0x2d, 0x27, 0x1c, 0xed, 0xde, 0x79, 0xc1, - 0x89, 0xe2, 0x05, 0x5f, 0x0c, 0xe0, 0xcb, 0xda, 0xd3, 0x46, 0x99, 0xb7, - 0xd2, 0x62, 0xb0, 0xb6, 0xdf, 0xcc, 0x33, 0x53, 0xa9, 0x8d, 0xdc, 0x3d, - 0x14, 0x0e, 0xc2, 0x9d, 0xa2, 0x2e, 0x0f, 0x5d, 0xed, 0x45, 0x9b, 0x59, - 0x15, 0xec, 0xf3, 0x01, 0xa8, 0xef, 0xcb, 0xbf, 0x29, 0xef, 0x1b, 0xe3, - 0xc4, 0xae, 0x3f, 0x6c, 0x43, 0x16, 0xea, 0x61, 0xe1, 0xef, 0x1a, 0x24, - 0xd9, 0xd3, 0x18, 0x79, 0x69, 0xe3, 0xeb, 0xf2, 0x7b, 0xb2, 0xb3, 0x91, - 0xa2, 0xd0, 0x2d, 0xd6, 0x59, 0xd6, 0x89, 0xc3, 0xa2, 0xf9, 0x19, 0x9f, - 0x08, 0x9f, 0x48, 0x77, 0x26, 0x71, 0x27, 0x8b, 0x82, 0x3f, 0x90, 0x60, - 0x0d, 0x04, 0x80, 0x49, 0xc6, 0x2f, 0xa9, 0x17, 0xa8, 0xea, 0x74, 0x3e, - 0xf4, 0x28, 0x3a, 0x76, 0xc6, 0x0e, 0x38, 0xce, 0x81, 0xdd, 0x86, 0x8f, - 0x64, 0x92, 0x1c, 0x64, 0x62, 0x7f, 0x6f, 0x96, 0xb4, 0xa8, 0x42, 0x19, - 0x60, 0x43, 0x43, 0x2a, 0x17, 0x03, 0xa5, 0x84, 0x5e, 0xd0, 0x97, 0x66, - 0xfa, 0xe3, 0x94, 0x44, 0xf1, 0x4c, 0xd5, 0x94, 0xd1, 0xb6, 0x4d, 0xdc, - 0x46, 0xb3, 0x39, 0x50, 0x86, 0x40, 0x0c, 0x77, 0xe6, 0xc3, 0xd4, 0x10, - 0x3d, 0xe4, 0x8a, 0xb9, 0xc4, 0xb1, 0x04, 0xc1, 0x0f, 0xe7, 0xfa, 0x42, - 0x7e, 0xf7, 0x72, 0xbd, 0x80, 0xab, 0x8e, 0x19, 0x47, 0x20, 0x50, 0x55, - 0x89, 0xa0, 0x2d, 0xb8, 0x16, 0x58, 0x21, 0xb5, 0x5f, 0xf1, 0xb3, 0x35, - 0xac, 0x6a, 0xad, 0xb0, 0xe6, 0xb8, 0xe8, 0x7a, 0x8a, 0xbc, 0xa6, 0x5b, - 0x09, 0xb4, 0x31, 0x8c, 0x65, 0x81, 0xfb, 0x93, 0x6d, 0xca, 0xa4, 0xc6, - 0x0a, 0x6d, 0x0a, 0xc0, 0xbb, 0x4d, 0xd9, 0xd0, 0x38, 0x67, 0xaf, 0x4e, - 0xb5, 0xae, 0x00, 0x4f, 0x5d, 0x98, 0x6c, 0x04, 0x69, 0x4f, 0x3d, 0x5c, - 0xf4, 0x50, 0xd9, 0x32, 0x2b, 0x94, 0x83, 0x3c, 0xbe, 0x15, 0x59, 0xd6, - 0xa6, 0x76, 0x76, 0x4a, 0xb8, 0x8d, 0xb5, 0xa8, 0xdc, 0xe9, 0xe5, 0xff, - 0x6e, 0x0d, 0xc2, 0xf3, 0x5a, 0xb6, 0x82, 0x0b, 0xbd, 0xa2, 0x25, 0xf1, - 0x82, 0xc9, 0x01, 0xbb, 0x99, 0x4e, 0x56, 0x05, 0x4a, 0xd8, 0xfe, 0x5e, - 0x61, 0xb0, 0x70, 0xd8, 0xad, 0x62, 0xcb, 0xa5, 0xe6, 0x62, 0xba, 0xfe, - 0x90, 0x95, 0xcf, 0xf0, 0x82, 0xca, 0x54, 0xa7, 0x55, 0x76, 0x17, 0x5c, - 0x62, 0xcf, 0xd9, 0x9d, 0x1e, 0x77, 0x3f, 0xcf, 0xdf, 0xff, 0xbb, 0xaa, - 0x1a, 0x20, 0x7a, 0xd1, 0xa0, 0x34, 0x24, 0x44, 0xc4, 0x12, 0x54, 0xbe, - 0xe2, 0x91, 0x9e, 0xe1, 0xcf, 0x23, 0xfc, 0xb8, 0x4d, 0x35, 0xf8, 0x31, - 0x7a, 0x69, 0x0b, 0x01, 0xbc, 0x43, 0x17, 0xd6, 0xa0, 0x2b, 0x20, 0xcd, - 0x12, 0xcf, 0xef, 0x39, 0xd4, 0x62, 0x90, 0x03, 0x6d, 0xbf, 0x58, 0x56, - 0xaa, 0x81, 0xcd, 0xb2, 0x26, 0x5b, 0x8a, 0xf4, 0x99, 0xf9, 0x4a, 0x08, - 0x37, 0xdf, 0x9d, 0x03, 0x18, 0xc7, 0xe8, 0x44, 0x9f, 0xb8, 0x20, 0x0a, - 0x67, 0xf6, 0x30, 0x84, 0x1a, 0xb8, 0xed, 0x57, 0xf1, 0x55, 0xaf, 0x0a, - 0x67, 0xc1, 0x3c, 0x07, 0x5e, 0x26, 0x1e, 0x1a, 0x0a, 0x5d, 0x9f, 0x9a, - 0x05, 0x2e, 0x6d, 0x30, 0x85, 0xbd, 0xc3, 0xa9, 0xa5, 0x5f, 0xb3, 0x3b, - 0x9e, 0x6a, 0x00, 0x42, 0x2d, 0x47, 0x24, 0xd8, 0xbf, 0x65, 0x38, 0x61, - 0xe7, 0xe6, 0xb6, 0x89, 0x2c, 0x94, 0xa0, 0xf0, 0xdb, 0x15, 0x5a, 0xe5, - 0x1f, 0xfc, 0x94, 0x3b, 0x79, 0x5f, 0xe4, 0x77, 0x48, 0xb9, 0x39, 0xad, - 0x6d, 0xf3, 0xce, 0xd6, 0x43, 0x10, 0x82, 0xaf, 0x56, 0x8e, 0x91, 0xb2, - 0xd1, 0xde, 0xea, 0x32, 0x1a, 0xbd, 0xab, 0x9d, 0x26, 0x22, 0xaf, 0xbc, - 0x91, 0x18, 0x40, 0x9e, 0x19, 0xf2, 0xa5, 0x5d, 0x0c, 0x34, 0xde, 0x83, - 0x84, 0x11, 0x20, 0x39, 0x47, 0x68, 0x99, 0x1a, 0x07, 0xd1, 0x3e, 0xbd, - 0x48, 0x8d, 0x27, 0xa3, 0x89, 0x86, 0xc3, 0xa9, 0x9c, 0xf9, 0xf3, 0x57, - 0xef, 0x76, 0xa0, 0xa6, 0x76, 0xad, 0x0d, 0x67, 0x33, 0x21, 0xc1, 0xec, - 0xaf, 0x80, 0x85, 0x0e, 0xf8, 0x85, 0x4b, 0xbe, 0x2e, 0x7b, 0x18, 0xc1, - 0x81, 0xcf, 0x0f, 0x47, 0x93, 0x81, 0x42, 0x69, 0xaa, 0x64, 0x7f, 0x4f, - 0xbb, 0x80, 0xfd, 0xaf, 0x70, 0xca, 0x80, 0xb8, 0x06, 0xd8, 0xfa, 0xdc, - 0x2f, 0xfc, 0x86, 0x15, 0x57, 0x02, 0x29, 0xbc, 0x77, 0xbb, 0x74, 0x3b, - 0x6b, 0x9d, 0x7f, 0x15, 0xd4, 0x90, 0x5e, 0xd6, 0x2e, 0x2b, 0x78, 0x93, - 0x1b, 0xec, 0xd6, 0xaf, 0x7e, 0x2e, 0x1d, 0x1e, 0x5b, 0xa5, 0x91, 0xdd, - 0xaf, 0x41, 0x96, 0xe2, 0x6c, 0x8b, 0xef, 0x14, 0xf6, 0x5f, 0xab, 0xe1, - 0xda, 0xb5, 0xf7, 0xb3, 0x30, 0xbd, 0xbb, 0xbe, 0xf9, 0x71, 0xf9, 0x5a, - 0x2e, 0xd9, 0x4f, 0xc3, 0x09, 0xf1, 0xbb, 0x4e, 0xac, 0x09, 0x4d, 0xd2, - 0x67, 0x60, 0x6c, 0xc0, 0x8a, 0x9e, 0x32, 0xd0, 0x59, 0xca, 0x8d, 0xd0, - 0xf4, 0x97, 0x4a, 0xfc, 0xe5, 0xb0, 0xdf, 0x0c, 0xc3, 0x8b, 0x28, 0x84, - 0xa2, 0x0c, 0xd2, 0x38, 0xec, 0x6d, 0x3a, 0xb4, 0x6e, 0xf4, 0xa5, 0x12, - 0x9b, 0x20, 0x95, 0x52, 0xd5, 0x0d, 0xbe, 0x17, 0x31, 0x52, 0x27, 0x7c, - 0x22, 0x5e, 0x23, 0xcb, 0x13, 0xf1, 0xdb, 0xf7, 0x2a, 0xa0, 0xaf, 0x15, - 0xaf, 0xe4, 0x27, 0xfe, 0xcc, 0xc4, 0x60, 0xd2, 0xfb, 0x5a, 0x7d, 0x81, - 0xf4, 0x32, 0x18, 0x3d, 0x74, 0xf3, 0x95, 0xfe, 0xbd, 0xee, 0xa0, 0x84, - 0x67, 0x24, 0x86, 0x58, 0xd3, 0x6d, 0xce, 0xc2, 0xac, 0xb3, 0xb3, 0x22, - 0xe2, 0x2c, 0x47, 0xf2, 0xf0, 0xb1, 0x35, 0x5c, 0x57, 0x56, 0x58, 0x06, - 0xcd, 0x4c, 0xc1, 0x8e, 0xf6, 0x76, 0x37, 0xa1, 0x0c, 0x6f, 0xfc, 0x03, - 0x93, 0xfa, 0x57, 0x56, 0xab, 0x5b, 0x0a, 0x8f, 0x33, 0x9f, 0x22, 0x36, - 0x47, 0x5a, 0x6a, 0xa0, 0x16, 0x2a, 0xe4, 0x08, 0xfe, 0xc3, 0x53, 0x44, - 0x93, 0x1a, 0x28, 0xa7, 0xd8, 0x38, 0x67, 0x9e, 0x0f, 0x4b, 0xd1, 0x48, - 0xa1, 0xe1, 0xdc, 0x8f, 0x01, 0x30, 0x5c, 0xf5, 0x0d, 0x74, 0x33, 0x01, - 0x78, 0x1d, 0x19, 0x82, 0x02, 0x9e, 0x54, 0x10, 0x2e, 0x7b, 0x12, 0xb8, - 0x17, 0xba, 0xc3, 0xf0, 0xf7, 0x65, 0x9d, 0xd2, 0xe3, 0xcd, 0x96, 0x07, - 0x5e, 0xfa, 0x0d, 0x89, 0x94, 0xc3, 0x8c, 0x92, 0x9f, 0x17, 0xcb, 0x3b, - 0xea, 0xed, 0xf6, 0x9d, 0xee, 0x06, 0xc6, 0x42, 0xa5, 0x69, 0xa0, 0x9f, - 0x94, 0x00, 0xaa, 0xec, 0xd9, 0x20, 0x70, 0x23, 0x65, 0xa7, 0xb3, 0xdf, - 0xb1, 0x8c, 0x17, 0xc5, 0x0f, 0x9d, 0x45, 0x94, 0xf9, 0xed, 0xbc, 0x3c, - 0x78, 0x7e, 0x3c, 0xf7, 0x6a, 0x59, 0x95, 0x15, 0x15, 0xce, 0x17, 0xe1, - 0xc7, 0xf1, 0x79, 0xbb, 0xb0, 0x77, 0xd4, 0xee, 0x1c, 0x55, 0x92, 0x3f, - 0x08, 0xab, 0x7e, 0x96, 0x59, 0x48, 0x82, 0x9e, 0xc9, 0xea, 0x2a, 0x07, - 0x13, 0xd2, 0x19, 0x0b, 0x73, 0xec, 0x10, 0x36, 0xb8, 0x4d, 0x17, 0x2e, - 0x1d, 0x9c, 0x27, 0x9d, 0xb2, 0xfc, 0xa0, 0xfe, 0x8a, 0xdb, 0xae, 0x73, - 0xa7, 0xb5, 0x44, 0xff, 0x38, 0x14, 0x9d, 0x67, 0xd1, 0x53, 0xf4, 0x8e, - 0x2d, 0x52, 0x39, 0xa3, 0x63, 0x38, 0x78, 0x30, 0x7c, 0x7d, 0x99, 0xe9, - 0x11, 0x78, 0xf0, 0x53, 0xc2, 0xcf, 0x6b, 0xf3, 0x6c, 0x81, 0x96, 0x20, - 0x9f, 0x72, 0x24, 0x66, 0x83, 0x80, 0x60, 0x20, 0xb1, 0x35, 0x21, 0x3a, - 0x68, 0xa4, 0x07, 0x96, 0xb6, 0xdc, 0x32, 0xa0, 0x4a, 0x6f, 0xa5, 0x9f, - 0xf2, 0xa5, 0xc2, 0xf4, 0x3b, 0x95, 0x66, 0x34, 0x06, 0xae, 0x95, 0x23, - 0x38, 0xb1, 0xd3, 0x68, 0x59, 0x10, 0x2c, 0xdd, 0x6f, 0xb3, 0x1a, 0x03, - 0xf3, 0xb8, 0xea, 0xfa, 0x6f, 0x3f, 0xd2, 0x25, 0x6c, 0x59, 0x29, 0x70, - 0xa4, 0xc7, 0x96, 0x80, 0x33, 0x1c, 0x19, 0x4f, 0x6d, 0x0e, 0x51, 0xc2, - 0x17, 0x5a, 0x76, 0xbf, 0x1d, 0x7c, 0x86, 0x57, 0x94, 0x2b, 0xe4, 0xe0, - 0x7e, 0xb9, 0x75, 0xb9, 0x00, 0x54, 0x2f, 0xbb, 0x96, 0xb5, 0xd0, 0x00, - 0x66, 0x75, 0x95, 0xe3, 0x54, 0x13, 0x2b, 0x5a, 0xff, 0xab, 0xe7, 0x5f, - 0x76, 0x4b, 0x04, 0x79, 0xae, 0xb8, 0x14, 0x94, 0xa0, 0x4c, 0x51, 0x5b, - 0xc7, 0xf8, 0xbb, 0x64, 0x28, 0x61, 0x05, 0x7f, 0x78, 0xbe, 0xec, 0x32, - 0x4f, 0xc6, 0xed, 0xba, 0xe3, 0x15, 0xa5, 0x34, 0x65, 0x3f, 0x15, 0x1f, - 0x17, 0x1e, 0x29, 0xae, 0xfe, 0x0d, 0xd3, 0xf1, 0xaa, 0x64, 0x40, 0xdb, - 0xcc, 0xc1, 0xa4, 0xf2, 0xa4, 0x9a, 0xda, 0x5c, 0xe9, 0xb3, 0x7a, 0x71, - 0xac, 0xbb, 0x8a, 0x8b, 0x80, 0x1a, 0x68, 0x16, 0x54, 0x6c, 0xbb, 0x7f, - 0x95, 0x8b, 0x14, 0xe9, 0x2e, 0x03, 0xf9, 0x93, 0x4a, 0x36, 0x16, 0x5a, - 0x32, 0xd6, 0x85, 0x9f, 0xf7, 0x2d, 0x29, 0xbf, 0xb3, 0xce, 0x10, 0x3d, - 0xa3, 0x96, 0xa1, 0x75, 0x65, 0x78, 0xcf, 0x00, 0xdb, 0xa6, 0x20, 0x09, - 0x13, 0x7e, 0xae, 0x79, 0xcb, 0xdf, 0x6c, 0xcb, 0xca, 0x2b, 0x66, 0xcc, - 0xbd, 0xa9, 0xe9, 0xc4, 0xd7, 0xe9, 0xa8, 0x3e, 0x2c, 0x2c, 0x25, 0xf9, - 0x27, 0x22, 0x0e, 0x6d, 0x9f, 0xd6, 0x97, 0x51, 0x2f, 0x1e, 0x3d, 0x91, - 0x50, 0x8b, 0x24, 0x01, 0x34, 0x12, 0x18, 0x5e, 0xc5, 0x5a, 0x81, 0x78, - 0xad, 0xaa, 0x04, 0x00, 0x20, 0x78, 0xb7, 0x45, 0x61, 0x36, 0x80, 0x88, - 0xd2, 0xec, 0x57, 0x47, 0xaf, 0x77, 0x14, 0x15, 0x89, 0xd8, 0x30, 0xe9, - 0xa2, 0x50, 0x73, 0xc6, 0x79, 0xa3, 0x60, 0x40, 0xcb, 0x21, 0x61, 0xd7, - 0xbd, 0x50, 0x91, 0x1e, 0xbb, 0x40, 0xa4, 0x7e, 0x1a, 0xf5, 0x75, 0x20, - 0xef, 0x47, 0xa6, 0x2b, 0xbe, 0x98, 0xad, 0xee, 0x7d, 0x8b, 0x9f, 0xd4, - 0xed, 0x89, 0x31, 0x2c, 0x56, 0xfb, 0x6d, 0x54, 0x4a, 0x74, 0xf2, 0x51, - 0xa9, 0x77, 0x4e, 0x78, 0x7d, 0x99, 0xd5, 0xc8, 0xa7, 0x29, 0xa0, 0x48, - 0x79, 0x29, 0xc1, 0x02, 0x01, 0x65, 0xd2, 0x47, 0xac, 0xed, 0x81, 0x8c, - 0xf0, 0xce, 0x47, 0x1b, 0xdd, 0xbf, 0x17, 0x9a, 0x9d, 0x0b, 0x3f, 0x2c, - 0x53, 0x18, 0xce, 0x5b, 0x5a, 0x05, 0x5f, 0x0c, 0x40, 0xfd, 0x54, 0xcd, - 0xf6, 0xd1, 0xcf, 0x0a, 0x5b, 0x23, 0xee, 0x0a, 0x98, 0x14, 0xc8, 0x56, - 0xbf, 0xf8, 0x33, 0xd3, 0x50, 0x93, 0x1e, 0x1d, 0x24, 0xf3, 0xa6, 0xe8, - 0x81, 0x2c, 0x60, 0x06, 0x3d, 0x95, 0xff, 0xda, 0xc2, 0x55, 0x3b, 0x2a, - 0xa1, 0xda, 0xbc, 0xd3, 0xc7, 0x54, 0x23, 0x51, 0x38, 0xd1, 0x4a, 0xd1, - 0xf0, 0xb9, 0x42, 0x5a, 0xec, 0x86, 0x60, 0xac, 0x34, 0xf8, 0x96, 0x2e, - 0x45, 0xa2, 0x4c, 0x0e, 0x72, 0x9b, 0xda, 0xd9, 0xc5, 0xa3, 0x10, 0x76, - 0x0e, 0xd2, 0xa6, 0x97, 0xff, 0x52, 0x3c, 0x97, 0x99, 0xc9, 0xac, 0x78, - 0xf1, 0x29, 0x38, 0x06, 0x25, 0x60, 0x20, 0xe8, 0x20, 0xed, 0x3c, 0x3f, - 0xc4, 0x7d, 0x85, 0xe8, 0x50, 0xd4, 0x82, 0xd0, 0xbc, 0xb0, 0x18, 0xb6, - 0x75, 0xa0, 0x8b, 0x6f, 0x71, 0xfd, 0xf8, 0xfb, 0x83, 0xb6, 0xb4, 0xa2, - 0x4e, 0x6c, 0x46, 0xd8, 0x62, 0xc9, 0x4e, 0xbf, 0x93, 0x4d, 0x47, 0x6a, - 0xbb, 0xd1, 0x59, 0xc6, 0xee, 0x7e, 0xab, 0xb4, 0x0b, 0xe9, 0xee, 0x02, - 0x84, 0x90, 0x00, 0x6a, 0x22, 0xf7, 0xde, 0x08, 0xff, 0x8a, 0x89, 0xe6, - 0xa6, 0x62, 0x13, 0x2a, 0xe2, 0x1a, 0xb9, 0xe9, 0x3d, 0xdf, 0xf0, 0xbc, - 0x22, 0x4c, 0xdc, 0x31, 0x8c, 0x76, 0x6b, 0xac, 0x5e, 0x21, 0xad, 0x16, - 0xe6, 0xec, 0x6a, 0xeb, 0x1c, 0xfe, 0x9b, 0x8f, 0xfc, 0x44, 0x67, 0x44, - 0x24, 0x0b, 0xab, 0x85, 0xf1, 0x2d, 0x7d, 0x7e, 0x20, 0xd7, 0xc4, 0x3f, - 0x75, 0xa1, 0xb8, 0x0f, 0xfc, 0xb3, 0xd0, 0xe9, 0x68, 0x8b, 0xe2, 0xd3, - 0x02, 0x5c, 0x4f, 0xbc, 0x67, 0x19, 0xe3, 0x2a, 0xa1, 0x93, 0x94, 0x38, - 0x1d, 0xb3, 0x53, 0xfc, 0x01, 0x70, 0xe3, 0x7d, 0x94, 0xaa, 0x55, 0x98, - 0x60, 0x85, 0xbe, 0x78, 0x1a, 0x74, 0x07, 0x6d, 0x5e, 0x9d, 0x89, 0x44, - 0xf5, 0x5c, 0xd8, 0xd0, 0xa5, 0x38, 0x5b, 0x8b, 0xd0, 0x06, 0x61, 0x4b, - 0x30, 0x57, 0x92, 0xd2, 0x3d, 0xba, 0x0e, 0x3c, 0xa8, 0x22, 0x45, 0x86, - 0x69, 0x03, 0xef, 0x30, 0xdb, 0x41, 0x7a, 0x13, 0x7d, 0x7f, 0x15, 0x00, - 0x8a, 0x0a, 0xdc, 0x71, 0x2e, 0xe8, 0x89, 0x4e, 0x2d, 0xc7, 0xdc, 0xfe, - 0xb1, 0x4a, 0x98, 0x73, 0xe5, 0x0f, 0xef, 0x0b, 0xdd, 0x7b, 0x44, 0x3d, - 0x06, 0x16, 0xb4, 0xa8, 0xe9, 0x27, 0x87, 0x09, 0x32, 0x14, 0x2b, 0x2b, - 0xdd, 0x83, 0xe9, 0x87, 0xbc, 0x75, 0x3e, 0xe6, 0x7e, 0x14, 0xad, 0x96, - 0x0b, 0xa6, 0x55, 0x98, 0x5b, 0x65, 0xf9, 0x89, 0x49, 0x23, 0xaf, 0xbc, - 0x20, 0x2d, 0x3d, 0xcf, 0x50, 0x5f, 0x72, 0x93, 0xa5, 0x0d, 0xa0, 0xd7, - 0x2d, 0xee, 0x55, 0x8c, 0x90, 0x1b, 0x7e, 0xa3, 0x7f, 0x46, 0x59, 0xc9, - 0xa9, 0x8c, 0x91, 0xbb, 0xc5, 0x4a, 0x9c, 0x75, 0xd8, 0xb1, 0x75, 0xcf, - 0xb1, 0x55, 0xbf, 0x06, 0x51, 0x94, 0x00, 0x91, 0xdc, 0xa2, 0x25, 0xbc, - 0xb1, 0x1d, 0x70, 0xc9, 0x63, 0x2e, 0x74, 0x83, 0x0d, 0xd2, 0x1d, 0xde, - 0xd3, 0x4c, 0x4f, 0xf5, 0x73, 0xaa, 0xa2, 0xb2, 0x3f, 0xbf, 0x92, 0xa7, - 0x57, 0x55, 0x71, 0xea, 0x8e, 0x81, 0xe4, 0x45, 0x33, 0xd7, 0x29, 0x9b, - 0x0b, 0x3b, 0xe2, 0xa9, 0xb1, 0xe6, 0xcb, 0x21, 0x25, 0x10, 0xbb, 0xfb, - 0x1e, 0x0b, 0x82, 0xa9, 0x37, 0x54, 0x84, 0x93, 0xeb, 0xd7, 0x3d, 0xb2, - 0x5a, 0x4a, 0xa4, 0xd6, 0xfa, 0xaa, 0x7a, 0x25, 0x90, 0x7d, 0x82, 0xd8, - 0x54, 0xad, 0x3e, 0x95, 0x61, 0xb2, 0x9e, 0xc9, 0x2a, 0x8e, 0x04, 0x2b, - 0x57, 0x93, 0x02, 0x75, 0x05, 0x2b, 0x01, 0xf8, 0x88, 0x85, 0x58, 0x37, - 0x80, 0x8d, 0xed, 0x4e, 0x96, 0x1a, 0xe2, 0x2c, 0x8e, 0xef, 0x20, 0xba, - 0x16, 0x61, 0x2a, 0xbb, 0x16, 0x5d, 0x26, 0xbd, 0xe0, 0x78, 0x7e, 0xdd, - 0x7a, 0x39, 0xdc, 0x19, 0x3d, 0x88, 0xac, 0xe1, 0xd4, 0x7e, 0xc9, 0xaf, - 0x21, 0x84, 0xb9, 0xae, 0x24, 0x90, 0xb3, 0xbb, 0xd0, 0x8d, 0x7a, 0x83, - 0x7e, 0xa4, 0x6b, 0x47, 0x53, 0xb0, 0x0b, 0x89, 0xf1, 0xa4, 0x10, 0xa1, - 0xe0, 0x42, 0xa8, 0x05, 0x0f, 0x8e, 0x88, 0x94, 0xd6, 0x96, 0xf9, 0x8d, - 0xd4, 0xc0, 0x19, 0xfe, 0x26, 0xf5, 0x66, 0x6a, 0x1b, 0x87, 0x4e, 0x5a, - 0x03, 0x5b, 0xe0, 0x44, 0x04, 0x8e, 0x9f, 0xea, 0xa3, 0x9c, 0x68, 0x2a, - 0x3f, 0x21, 0xa9, 0xf0, 0x89, 0x8e, 0x3d, 0xaa, 0xf9, 0xa5, 0xf9, 0x8a, - 0xba, 0xe7, 0x54, 0xb1, 0x9d, 0x48, 0x45, 0x5e, 0x0d, 0x44, 0xa4, 0x0b, - 0x7b, 0x14, 0x5a, 0x64, 0xd4, 0xf4, 0x49, 0xbe, 0xb4, 0x59, 0x61, 0x3a, - 0xd1, 0x56, 0x94, 0x98, 0xf7, 0x8f, 0x02, 0x85, 0x98, 0x0e, 0xcf, 0x37, - 0xb9, 0x40, 0x3a, 0x5a, 0xa1, 0xe1, 0x84, 0x93, 0x9b, 0x53, 0xe4, 0x5a, - 0xd2, 0x84, 0x53, 0x53, 0x35, 0x4d, 0xca, 0x56, 0x74, 0x01, 0x22, 0xe5, - 0x34, 0x42, 0x92, 0x7d, 0x16, 0xf5, 0x4c, 0x35, 0xa8, 0x7d, 0xd2, 0x1d, - 0xd8, 0x77, 0x63, 0x6e, 0xea, 0x05, 0xdf, 0x1f, 0xcd, 0xb7, 0x64, 0x44, - 0x26, 0xe9, 0xe3, 0xc2, 0x9e, 0xaf, 0xe7, 0x91, 0x04, 0x42, 0x97, 0x00, - 0x1a, 0x76, 0x03, 0xa4, 0x11, 0xef, 0x28, 0x89, 0x0e, 0xaa, 0xc0, 0x05, - 0xdb, 0x4c, 0xb4, 0x77, 0x28, 0x25, 0x10, 0x64, 0x96, 0xe5, 0x44, 0x66, - 0x62, 0xa9, 0x55, 0x1c, 0x27, 0xf2, 0xef, 0x61, 0xc3, 0x77, 0x8a, 0xd9, - 0x33, 0x48, 0xf4, 0xfb, 0x61, 0xbe, 0x59, 0xe9, 0x2e, 0xc8, 0xbf, 0xf7, - 0xe4, 0x70, 0xfb, 0xfd, 0x81, 0xe8, 0xe2, 0xc3, 0x60, 0xc9, 0x18, 0x9e, - 0xb4, 0x12, 0xea, 0x5d, 0xbc, 0xc2, 0xf8, 0x08, 0x6b, 0xba, 0xcc, 0x09, - 0x3f, 0x20, 0x86, 0x22, 0xc9, 0x38, 0xc9, 0x9c, 0x57, 0x97, 0xd1, 0x3b, - 0xf3, 0x4b, 0xb3, 0x09, 0x67, 0x62, 0x96, 0x4f, 0x3b, 0x5f, 0x1a, 0xfb, - 0xda, 0x93, 0xe7, 0xd8, 0x6f, 0x4c, 0xc0, 0x9f, 0xd2, 0xe2, 0x33, 0x1f, - 0xda, 0x14, 0x68, 0x61, 0x38, 0x75, 0x9c, 0xbd, 0x56, 0x09, 0x4e, 0x35, - 0xdf, 0x94, 0x71, 0x3f, 0x00, 0x7b, 0x6a, 0x91, 0x0f, 0x36, 0xa8, 0x61, - 0xd8, 0x3d, 0x2f, 0xd1, 0x17, 0x07, 0x74, 0x72, 0xb7, 0x95, 0x88, 0x0d, - 0xed, 0xb3, 0xbe, 0x42, 0x95, 0x2b, 0x47, 0x80, 0xa6, 0xda, 0x73, 0x7a, - 0x7d, 0x44, 0x80, 0x58, 0x45, 0x8f, 0xbc, 0x46, 0x5e, 0x87, 0xa9, 0xb5, - 0x40, 0xbf, 0xd1, 0x0c, 0xe9, 0x0c, 0x8a, 0x79, 0x49, 0xe8, 0x37, 0x58, - 0x20, 0x3a, 0xc4, 0x90, 0x5f, 0xbc, 0x6c, 0x7f, 0x20, 0xa4, 0xec, 0xdf, - 0x01, 0x91, 0xf7, 0x55, 0xb2, 0x7d, 0x85, 0x43, 0x5b, 0x79, 0x20, 0x6f, - 0x0a, 0x1c, 0xf9, 0xad, 0x86, 0x64, 0xbd, 0xa7, 0xe3, 0x1d, 0xe5, 0x40, - 0x24, 0x83, 0x59, 0x63, 0x67, 0x6b, 0xc4, 0x23, 0xd9, 0x80, 0x3b, 0x39, - 0xf9, 0x78, 0xb7, 0xad, 0xc5, 0x28, 0x05, 0x0b, 0xdc, 0x8c, 0x6c, 0xce, - 0x8b, 0xfb, 0x1c, 0x5e, 0xf2, 0x6b, 0xe4, 0xd4, 0x91, 0xf3, 0xfc, 0xd6, - 0x9f, 0x18, 0xba, 0x10, 0x60, 0xe5, 0x15, 0xf5, 0x7b, 0x4e, 0x6a, 0x7e, - 0xcf, 0x79, 0x6d, 0xfa, 0x3e, 0x1a, 0x31, 0x1c, 0xa7, 0xb4, 0x3c, 0xb3, - 0x0f, 0x75, 0x9c, 0xad, 0xc0, 0x04, 0xf5, 0xe9, 0x6c, 0x76, 0xbd, 0x8a, - 0x9a, 0x3f, 0x02, 0x45, 0xa8, 0x22, 0xc3, 0x31, 0xfb, 0x87, 0xe2, 0x18, - 0x60, 0xdf, 0xeb, 0x85, 0x8c, 0x55, 0x92, 0xbb, 0x0e, 0xbb, 0x1c, 0xdc, - 0xf8, 0x15, 0xbe, 0xc2, 0xc6, 0xd6, 0xbf, 0xde, 0x36, 0x9e, 0x8d, 0x0b, - 0xa8, 0xb9, 0x22, 0x7a, 0x5c, 0xdd, 0x4c, 0x11, 0x3a, 0xfb, 0x6a, 0xe6, - 0x70, 0x0d, 0xd9, 0xee, 0x14, 0x1d, 0x56, 0x09, 0x46, 0x29, 0x08, 0x78, - 0x05, 0xfc, 0xc5, 0x77, 0xcb, 0x3b, 0x31, 0xec, 0x4c, 0xed, 0x99, 0x11, - 0x1f, 0x23, 0x86, 0x53, 0xa0, 0xee, 0x4e, 0x3d, 0x53, 0x1a, 0x48, 0x2a, - 0x8d, 0xe6, 0x39, 0xe2, 0xc9, 0x70, 0xca, 0xce, 0x5e, 0x17, 0xa6, 0x26, - 0x07, 0xd8, 0x75, 0xdb, 0xd3, 0xc0, 0xf7, 0xb9, 0x3e, 0x4c, 0x07, 0x01, - 0x54, 0xe9, 0x0c, 0x36, 0x7e, 0x6a, 0x62, 0x69, 0xc7, 0x84, 0x3b, 0xba, - 0x41, 0xc7, 0x7e, 0x87, 0x5d, 0x91, 0x70, 0x0c, 0xfd, 0x59, 0x46, 0xa2, - 0x5a, 0x04, 0x59, 0x79, 0x1b, 0xe5, 0xc3, 0xa1, 0xd8, 0x03, 0x1b, 0xf4, - 0xa8, 0x6f, 0x39, 0xdf, 0xaf, 0xe8, 0x4f, 0x9b, 0xc1, 0x41, 0xb8, 0x12, - 0x5e, 0x11, 0xba, 0x05, 0xee, 0x4b, 0x7c, 0x8c, 0xbd, 0x1e, 0x98, 0xab, - 0x31, 0xd4, 0x0f, 0x1c, 0x5b, 0x9c, 0x74, 0x9d, 0xa5, 0x43, 0x1c, 0xb7, - 0x8e, 0x5d, 0x95, 0xd5, 0x04, 0xf6, 0x42, 0xc1, 0xde, 0x01, 0xd6, 0x9a, - 0x56, 0xc0, 0x9a, 0x84, 0x54, 0x15, 0xcf, 0x01, 0x13, 0x54, 0x16, 0xff, - 0xd8, 0x8e, 0xf7, 0xa4, 0x19, 0x5c, 0x6e, 0x8e, 0xf1, 0x44, 0xfd, 0x3e, - 0xe1, 0x72, 0xf1, 0x0e, 0xfb, 0x58, 0xd8, 0xb6, 0xb9, 0x23, 0x6a, 0xb8, - 0xf7, 0x28, 0xa2, 0x3b, 0x0e, 0x0c, 0x82, 0xae, 0xc4, 0x1b, 0x9c, 0x13, - 0x86, 0xea, 0x56, 0xd7, 0x53, 0x10, 0xc8, 0x30, 0x13, 0xa6, 0xf3, 0x18, - 0x67, 0xec, 0xb0, 0xcd, 0xb7, 0xf4, 0x96, 0xe9, 0x3d, 0xdd, 0x16, 0xb6, - 0x45, 0x76, 0xf2, 0x16, 0x91, 0xcf, 0x9f, 0x5a, 0xa6, 0xf1, 0xbc, 0xf6, - 0xaa, 0xe8, 0xa4, 0xd6, 0xaa, 0xb0, 0x08, 0x2c, 0x96, 0xba, 0x92, 0xec, - 0xd1, 0xba, 0x37, 0x18, 0x21, 0x23, 0x26, 0x0b, 0x6b, 0xcf, 0xf1, 0x37, - 0x9e, 0x94, 0xe3, 0xa9, 0x88, 0xef, 0x5d, 0xdf, 0xa8, 0x45, 0xbb, 0x09, - 0x07, 0xa5, 0x96, 0xe8, 0x99, 0xd8, 0xb2, 0x64, 0xfa, 0x23, 0x56, 0x9e, - 0x9f, 0x34, 0xbe, 0x5f, 0x6f, 0xb1, 0x07, 0x4d, 0xb5, 0xbb, 0xe0, 0x09, - 0x85, 0x4b, 0xcd, 0x79, 0xb5, 0x5a, 0xb6, 0x18, 0xef, 0x00, 0x35, 0x0a, - 0x30, 0xb3, 0xbe, 0x51, 0x0b, 0x3b, 0x7c, 0x0d, 0x17, 0x08, 0x11, 0x01, - 0x16, 0x67, 0x3d, 0xf9, 0x1e, 0xb7, 0xc4, 0x99, 0xaa, 0x3b, 0x2d, 0x9f, - 0x8c, 0xfd, 0x19, 0xdf, 0xea, 0xc9, 0xb0, 0x9c, 0x83, 0x87, 0x68, 0x73, - 0x6e, 0xb6, 0xeb, 0xf7, 0x3d, 0xe3, 0x3f, 0xbd, 0x50, 0xfc, 0x9c, 0x09, - 0xcd, 0xba, 0x65, 0x50, 0x8b, 0x62, 0x66, 0xd3, 0xb3, 0xe3, 0x21, 0x31, - 0x0e, 0xaf, 0x9d, 0x15, 0x34, 0xe3, 0x6b, 0xae, 0x24, 0x4a, 0x59, 0xe9, - 0x19, 0xf3, 0x45, 0x45, 0x1f, 0x3e, 0x81, 0x7d, 0xad, 0xb9, 0xbf, 0x8a, - 0xad, 0x19, 0x82, 0x55, 0x9d, 0xa8, 0xaa, 0xb3, 0xe5, 0x9a, 0x7d, 0x56, - 0x12, 0x91, 0x91, 0xb6, 0x31, 0x5e, 0x5d, 0xbc, 0x06, 0x14, 0x5f, 0xa5, - 0x00, 0x1f, 0x08, 0xbd, 0x42, 0x03, 0xfc, 0x6e, 0xf1, 0xa3, 0x0c, 0x58, - 0x51, 0x3f, 0x3e, 0x95, 0x37, 0x38, 0xe3, 0x1e, 0xa7, 0x88, 0xac, 0xb0, - 0xae, 0xec, 0x28, 0x61, 0xa6, 0x22, 0xab, 0xe2, 0x50, 0x6d, 0x5d, 0xad, - 0x6e, 0x6a, 0x31, 0xa6, 0x5a, 0x08, 0x8a, 0xd0, 0x3a, 0x8b, 0xd0, 0xc4, - 0x73, 0x13, 0x91, 0x10, 0xc4, 0xb9, 0x67, 0x7f, 0x9d, 0x8d, 0x40, 0x20, - 0x86, 0x72, 0x7d, 0xd4, 0x65, 0xdd, 0x97, 0xe3, 0xd7, 0xd3, 0x4d, 0xb2, - 0x79, 0xc4, 0xdd, 0xd0, 0x49, 0xdd, 0xac, 0x92, 0x16, 0x04, 0x1a, 0x34, - 0xd4, 0x9e, 0x9c, 0xa2, 0xa7, 0xab, 0x1e, 0xfe, 0x3c, 0x32, 0x2f, 0xdf, - 0x28, 0xf4, 0xc5, 0xd9, 0x84, 0x44, 0xb7, 0xda, 0xe9, 0x02, 0x67, 0x60, - 0x6a, 0x03, 0xb5, 0xe9, 0x4b, 0x12, 0x76, 0xca, 0x25, 0x27, 0xa7, 0xe9, - 0x1c, 0xe8, 0x48, 0x40, 0xf3, 0x25, 0x36, 0x9a, 0x56, 0xce, 0x02, 0x5d, - 0xb9, 0xa7, 0x42, 0x9c, 0x33, 0x90, 0x70, 0x87, 0x0e, 0xe7, 0xcb, 0xd6, - 0x56, 0x8a, 0x21, 0xc5, 0x34, 0x1b, 0xf5, 0x48, 0x26, 0xea, 0xc8, 0xe9, - 0xb0, 0xbd, 0xc5, 0x0d, 0x37, 0xd8, 0xe8, 0xb7, 0xf5, 0x6b, 0xbf, 0xf5, - 0xfb, 0xed, 0x83, 0xb1, 0xd8, 0x72, 0x3b, 0xd7, 0xbf, 0x25, 0xa5, 0xf9, - 0x63, 0xe0, 0xd6, 0x81, 0x5c, 0x84, 0xdb, 0x56, 0x4b, 0xf7, 0xef, 0x0f, - 0x9d, 0xee, 0x5e, 0x27, 0xc5, 0xf8, 0x7a, 0xdf, 0xc0, 0x5d, 0x93, 0x11, - 0xe8, 0x7d, 0x02, 0xf1, 0x55, 0x8c, 0xe6, 0xd9, 0x60, 0x64, 0x69, 0x35, - 0x78, 0x94, 0x36, 0x25, 0x1b, 0xbc, 0xaa, 0x1d, 0xb6, 0x1c, 0xa5, 0xee, - 0xe6, 0x04, 0x51, 0xfa, 0x08, 0xb8, 0xcb, 0x92, 0x35, 0x72, 0xf5, 0x3e, - 0x0b, 0xee, 0xfe, 0x70, 0xe9, 0x83, 0x25, 0x66, 0x25, 0x56, 0x6f, 0x47, - 0xb0, 0x81, 0x7a, 0x44, 0x44, 0xf5, 0xaa, 0xec, 0x7e, 0x7e, 0x19, 0x0c, - 0xa1, 0xf3, 0x5d, 0xa9, 0x3b, 0x13, 0x8f, 0x6a, 0x2d, 0xa7, 0x93, 0x59, - 0xaa, 0x53, 0x7b, 0x8c, 0x8c, 0xee, 0xe4, 0x58, 0x67, 0x86, 0xe5, 0xc7, - 0x39, 0x95, 0x87, 0xf8, 0x80, 0x91, 0x64, 0xbb, 0x1c, 0x01, 0xfd, 0x96, - 0xe5, 0xd2, 0x98, 0xea, 0x83, 0xdc, 0x46, 0x15, 0x5a, 0x29, 0x05, 0xc7, - 0x1b, 0x20, 0x9d, 0x91, 0x45, 0x9f, 0x94, 0x88, 0xd8, 0x9c, 0x15, 0x9e, - 0x1a, 0x28, 0x98, 0xa5, 0x05, 0xcc, 0x59, 0x19, 0xef, 0x2c, 0x26, 0xe4, - 0x4e, 0xee, 0xe9, 0xb8, 0x4f, 0xa6, 0xc2, 0xcc, 0xce, 0x9f, 0x2b, 0x61, - 0x2b, 0xfd, 0xfd, 0xd1, 0xb6, 0xec, 0xa4, 0x1d, 0x5a, 0x03, 0xf8, 0xaa, - 0x26, 0x39, 0x63, 0x77, 0xb3, 0x92, 0xd3, 0xea, 0xcc, 0x51, 0x00, 0x83, - 0x7f, 0xda, 0x90, 0x98, 0x99, 0x47, 0xc6, 0x2d, 0xff, 0xb1, 0xbe, 0x6c, - 0x53, 0xb5, 0x54, 0x7c, 0xa3, 0x39, 0xac, 0xdf, 0x59, 0x8d, 0x68, 0xec, - 0x3a, 0xd9, 0x35, 0x3c, 0xb5, 0x16, 0x41, 0x1a, 0xb4, 0x71, 0x98, 0xee, - 0xdc, 0x78, 0xd3, 0xc8, 0xc1, 0x96, 0x59, 0x63, 0x81, 0xb5, 0x86, 0x4f, - 0xa8, 0x49, 0x6b, 0xc6, 0x06, 0x71, 0x16, 0x1b, 0x56, 0xaa, 0x82, 0xdb, - 0x60, 0xcf, 0x14, 0x9c, 0x6a, 0xca, 0x33, 0x1a, 0xfc, 0x8b, 0xb5, 0xa1, - 0xed, 0x7a, 0x76, 0xfb, 0x46, 0x83, 0x3a, 0x99, 0x83, 0x22, 0xe6, 0x33, - 0xe5, 0x3e, 0x4c, 0xbf, 0x5b, 0x24, 0x58, 0x67, 0xd7, 0x35, 0xc5, 0x65, - 0x16, 0xc5, 0xca, 0x33, 0x95, 0xab, 0x47, 0xec, 0xda, 0x02, 0xec, 0x5f, - 0xf6, 0x34, 0xf9, 0x36, 0xf2, 0x96, 0xa9, 0x47, 0xe1, 0x9c, 0x9f, 0xea, - 0xde, 0x0c, 0xc7, 0x37, 0x71, 0x6a, 0x9c, 0x33, 0x2a, 0x16, 0x14, 0xd8, - 0x6f, 0x72, 0xde, 0x2a, 0x0d, 0x7a, 0x21, 0xeb, 0x85, 0xd1, 0xd4, 0x4b, - 0x52, 0xb3, 0xcc, 0x3a, 0x73, 0x2e, 0x42, 0xcd, 0x8e, 0xc0, 0x87, 0xe6, - 0x8e, 0x18, 0x0d, 0x84, 0x55, 0xc8, 0x0c, 0x3d, 0x0a, 0x12, 0xe6, 0x0e, - 0xa7, 0xd9, 0x10, 0xb7, 0x6d, 0x98, 0xd5, 0x3a, 0x15, 0xc3, 0xf1, 0xbc, - 0x5b, 0xfb, 0x83, 0x62, 0x82, 0xe1, 0x28, 0x82, 0xed, 0xc2, 0x63, 0xa0, - 0x10, 0xac, 0xbd, 0x8a, 0xfb, 0xc6, 0x02, 0x96, 0xb7, 0x10, 0x86, 0x7d, - 0x18, 0x96, 0x18, 0xbb, 0xde, 0xe3, 0x62, 0xca, 0xa7, 0xdd, 0x7b, 0xae, - 0xf4, 0x0e, 0x35, 0xab, 0xf2, 0xfe, 0x86, 0xf7, 0xf7, 0x37, 0x28, 0xaa, - 0xf2, 0xf9, 0xde, 0xbf, 0x0c, 0xc3, 0x1a, 0x86, 0x85, 0x41, 0xcc, 0x48, - 0x28, 0x4b, 0x6f, 0x88, 0x0f, 0x93, 0x1f, 0x29, 0xc4, 0x20, 0x50, 0xb3, - 0x2e, 0x9c, 0x17, 0x40, 0xf0, 0x25, 0x2d, 0x93, 0xe0, 0xc4, 0x0d, 0x16, - 0xc3, 0x36, 0xcc, 0x2a, 0x7c, 0x77, 0x19, 0x89, 0x18, 0x3a, 0x6b, 0x59, - 0x9d, 0x61, 0xab, 0xb9, 0xb0, 0x85, 0x35, 0xc2, 0x10, 0x16, 0x30, 0xf9, - 0xd6, 0xc0, 0x4e, 0xcc, 0x47, 0x46, 0x8e, 0x4f, 0x08, 0xc2, 0x96, 0x41, - 0x5a, 0x7d, 0x32, 0xd1, 0x3d, 0xf4, 0x7b, 0x4d, 0x92, 0xf4, 0x60, 0x40, - 0x8c, 0xc5, 0x49, 0xd2, 0x84, 0xf1, 0xf2, 0x63, 0x75, 0x76, 0x40, 0x85, - 0xc6, 0x1b, 0xce, 0xfe, 0x32, 0x07, 0xe9, 0x87, 0x66, 0xa5, 0xfc, 0xf8, - 0x79, 0xce, 0x6e, 0x87, 0x97, 0xdf, 0x99, 0x46, 0xb5, 0x31, 0xe6, 0x2d, - 0x5e, 0xd0, 0xc7, 0x52, 0x4a, 0xea, 0x9a, 0xbb, 0x27, 0x0e, 0xc5, 0x5a, - 0xe7, 0xd2, 0x9c, 0xf7, 0xc2, 0xf0, 0x7e, 0x8a, 0xba, 0xf0, 0x62, 0xc8, - 0xd8, 0xcf, 0xe1, 0xab, 0x8c, 0xbc, 0xec, 0xdd, 0xfb, 0x20, 0xdd, 0xc4, - 0x1b, 0xe1, 0xa2, 0xfb, 0xf2, 0x97, 0x0b, 0x7d, 0x2f, 0x75, 0x16, 0x0e, - 0xc6, 0xf3, 0x6d, 0x33, 0x57, 0x4d, 0x0a, 0x28, 0x0f, 0x10, 0x7e, 0xb0, - 0x4d, 0x4b, 0xe6, 0x2e, 0x40, 0xfd, 0xdc, 0xd8, 0x98, 0xd3, 0x7d, 0x39, - 0xe0, 0x39, 0xc6, 0x2f, 0x3b, 0xec, 0xcf, 0x73, 0x9c, 0x71, 0xb2, 0x82, - 0xcd, 0xef, 0xe7, 0x2d, 0x17, 0xed, 0x0c, 0x95, 0x87, 0x6c, 0xe9, 0x2d, - 0x38, 0x1b, 0xcb, 0x53, 0x6e, 0x4f, 0x61, 0x4d, 0xbc, 0x26, 0xd1, 0x74, - 0x7c, 0x70, 0xc0, 0xe7, 0xf8, 0xae, 0x44, 0x77, 0x2d, 0xe3, 0x58, 0xbd, - 0x67, 0x99, 0x86, 0x95, 0x42, 0xdd, 0x7c, 0x4b, 0x89, 0xe5, 0xb0, 0x70, - 0x1a, 0x43, 0xa2, 0x7b, 0x6e, 0xbb, 0xe3, 0xbc, 0x32, 0x57, 0x0c, 0xc8, - 0x6f, 0x75, 0xec, 0x53, 0xc6, 0x3c, 0x09, 0x52, 0x56, 0x0e, 0x4b, 0x70, - 0x49, 0x2c, 0xb8, 0xf1, 0x0c, 0x1e, 0xcc, 0x51, 0x5e, 0x75, 0xb3, 0x46, - 0xd6, 0xb2, 0x77, 0xe2, 0x2d, 0x5f, 0x3a, 0x3b, 0xb2, 0xd7, 0xc3, 0x99, - 0x85, 0x47, 0xca, 0x99, 0x00, 0x02, 0xf5, 0x1d, 0x04, 0x3f, 0xef, 0x64, - 0xc1, 0x12, 0xd8, 0xc3, 0x58, 0x71, 0x66, 0x0c, 0x53, 0xc9, 0x2b, 0x71, - 0x7e, 0x93, 0x7a, 0xe6, 0x38, 0xd1, 0xa0, 0x13, 0x15, 0x74, 0xa6, 0xbb, - 0x6b, 0x8a, 0x56, 0x7b, 0x3d, 0x4a, 0x66, 0x88, 0x2d, 0x87, 0xfe, 0x1c, - 0x4d, 0xdf, 0xd0, 0xdc, 0xf7, 0x59, 0xbb, 0x87, 0xaf, 0x53, 0x2e, 0x7a, - 0x72, 0x19, 0x3c, 0x93, 0x49, 0x13, 0x98, 0x82, 0x9f, 0x9d, 0xc4, 0xc0, - 0x97, 0x52, 0x32, 0xd0, 0x2e, 0x7f, 0xda, 0x18, 0x99, 0x6a, 0xbd, 0xe9, - 0x28, 0xb2, 0x3c, 0x23, 0xad, 0x7d, 0x4a, 0x37, 0xfc, 0xd5, 0x9d, 0xc1, - 0x0e, 0xc9, 0x46, 0xc3, 0x84, 0xc9, 0x6c, 0x06, 0x0f, 0x51, 0x83, 0x3b, - 0x1d, 0xae, 0x90, 0x6c, 0x27, 0x71, 0xc8, 0xee, 0x4b, 0x8f, 0x70, 0x35, - 0x2b, 0xec, 0x9e, 0x91, 0xe2, 0x0f, 0x94, 0x24, 0x6b, 0x3a, 0x24, 0xe4, - 0x6d, 0x21, 0x65, 0x7b, 0xa7, 0xa2, 0xe0, 0x26, 0xa9, 0x64, 0xe9, 0xef, - 0x94, 0x88, 0x22, 0x47, 0x8b, 0x3f, 0x58, 0x7b, 0x23, 0x75, 0x5f, 0x87, - 0x03, 0x33, 0x7d, 0x94, 0x0d, 0x1a, 0x08, 0x55, 0x9a, 0x66, 0xc5, 0xb4, - 0x62, 0xba, 0x2c, 0x16, 0x3d, 0x8d, 0xa1, 0x83, 0x21, 0x12, 0xff, 0x69, - 0x16, 0x94, 0x6f, 0x65, 0x09, 0xfb, 0x45, 0xe1, 0xc9, 0xd6, 0x31, 0x93, - 0xc6, 0xf3, 0x6a, 0xde, 0x1e, 0x26, 0x50, 0x7e, 0xf8, 0x1d, 0x41, 0x66, - 0x22, 0x4c, 0x41, 0x4e, 0x39, 0x02, 0x70, 0xdc, 0x49, 0x1b, 0x3e, 0x78, - 0x93, 0xf9, 0xb7, 0x9e, 0xd9, 0xfd, 0x70, 0x93, 0xf4, 0x92, 0x34, 0xcf, - 0x2b, 0xac, 0xec, 0x50, 0x68, 0x56, 0xe6, 0x15, 0x76, 0x13, 0xce, 0xf5, - 0xe0, 0x9b, 0x93, 0xc7, 0x8e, 0x61, 0xdd, 0x4b, 0xfe, 0xef, 0xa5, 0x7a, - 0x67, 0x85, 0x28, 0xa4, 0x33, 0xcf, 0x4b, 0x9c, 0x6e, 0x40, 0xff, 0x55, - 0xa3, 0x57, 0xc7, 0x01, 0xe3, 0x45, 0xfc, 0x7c, 0x71, 0xb0, 0xba, 0x7a, - 0xf4, 0x45, 0x98, 0x73, 0x3d, 0x6f, 0x42, 0x05, 0x69, 0xf1, 0xb5, 0x7c, - 0xb8, 0xd7, 0x43, 0x16, 0xc1, 0x96, 0x4f, 0x29, 0xf9, 0xb0, 0x1a, 0xea, - 0x9e, 0xcf, 0x27, 0x99, 0x44, 0xdb, 0x17, 0x96, 0x5c, 0x0c, 0xd3, 0xbc, - 0x5a, 0xc8, 0x1d, 0x7e, 0x68, 0x98, 0x05, 0xbf, 0x8e, 0xac, 0x3e, 0x5a, - 0x7c, 0x30, 0x0a, 0x84, 0x0c, 0x8c, 0xa1, 0xed, 0x26, 0xf8, 0x07, 0x78, - 0x67, 0x73, 0x31, 0xf1, 0x70, 0x60, 0x22, 0xe0, 0xdb, 0x63, 0xc6, 0xbd, - 0xbd, 0xa2, 0xd8, 0x3e, 0x9c, 0x04, 0x38, 0x3d, 0x5b, 0x42, 0xa6, 0x77, - 0x82, 0xcb, 0x72, 0xd2, 0x59, 0x82, 0xc5, 0x56, 0x42, 0x4e, 0x5e, 0x95, - 0xcb, 0x22, 0xae, 0xec, 0x44, 0x57, 0xcb, 0x89, 0xa2, 0xb0, 0x69, 0x7b, - 0xd5, 0x6a, 0xfe, 0xc8, 0x8c, 0xf5, 0x0b, 0xbb, 0x5f, 0xc1, 0xd2, 0x81, - 0x7b, 0x20, 0x56, 0x14, 0x69, 0x27, 0x4c, 0xa5, 0xa8, 0x55, 0xf0, 0xd5, - 0x6b, 0xfe, 0x5e, 0x0d, 0x28, 0x27, 0x2b, 0xd1, 0x50, 0xc9, 0xa3, 0xbc, - 0xb1, 0xb6, 0xf8, 0x3e, 0x8f, 0x31, 0x91, 0x90, 0x2d, 0x2a, 0xc7, 0xa8, - 0x89, 0x12, 0x76, 0xbd, 0x34, 0x3c, 0x20, 0xca, 0xf7, 0x37, 0xc7, 0xf1, - 0x26, 0x9c, 0xd7, 0xa1, 0x2d, 0xc3, 0x96, 0x6a, 0xb3, 0xe8, 0xe5, 0x40, - 0x2b, 0x53, 0x24, 0x41, 0xd5, 0x82, 0x34, 0x32, 0x08, 0x06, 0xf1, 0xc1, - 0x3b, 0x83, 0x31, 0x94, 0x95, 0x16, 0x61, 0x98, 0x57, 0x2f, 0x5c, 0xfb, - 0xe3, 0x23, 0x7e, 0x5a, 0x5a, 0x36, 0xb8, 0xa1, 0x7b, 0x8c, 0x24, 0xfc, - 0x7e, 0xf3, 0x07, 0x31, 0xd5, 0x41, 0xec, 0x40, 0xd0, 0xf4, 0x88, 0x25, - 0xb4, 0x6c, 0xfe, 0xf7, 0x80, 0xc2, 0xfc, 0x69, 0x82, 0xf7, 0xfc, 0xa9, - 0x51, 0xaa, 0xce, 0xdc, 0x02, 0xc9, 0xed, 0xdc, 0xb9, 0x46, 0xa3, 0x6a, - 0xef, 0xf1, 0xf5, 0x11, 0xb1, 0x08, 0x9a, 0xd7, 0x72, 0xd5, 0x03, 0x39, - 0x33, 0xb3, 0x09, 0x91, 0x7d, 0xf2, 0x06, 0x06, 0xe9, 0xc5, 0xda, 0x99, - 0x84, 0x37, 0x04, 0xa8, 0x17, 0x0d, 0xac, 0x96, 0x81, 0xc4, 0xba, 0xbb, - 0x9b, 0x9e, 0xda, 0xa2, 0x07, 0xee, 0x93, 0x54, 0x85, 0x85, 0x98, 0xa8, - 0xd2, 0x31, 0x5d, 0x70, 0xe5, 0x9c, 0xf1, 0x29, 0x8a, 0x1b, 0x29, 0x57, - 0x2c, 0x7b, 0x03, 0x3e, 0x53, 0x98, 0x98, 0x30, 0x79, 0x0c, 0xaa, 0xcd, - 0xda, 0xf9, 0x57, 0x9c, 0x31, 0x66, 0x0a, 0xeb, 0xc7, 0x34, 0xcb, 0x77, - 0x8b, 0x56, 0xc6, 0xba, 0xa2, 0x91, 0x11, 0x49, 0xfc, 0x00, 0xcd, 0xa7, - 0x04, 0x9f, 0x3b, 0xa0, 0x93, 0x44, 0x7b, 0x74, 0x5f, 0x85, 0x74, 0xdc, - 0xec, 0x6d, 0xf0, 0xdb, 0xb1, 0xbe, 0x0b, 0xe1, 0x50, 0xd0, 0xcb, 0x22, - 0x95, 0x37, 0xbb, 0x80, 0x31, 0x73, 0xe1, 0x8f, 0x7b, 0x8f, 0xcb, 0x16, - 0x98, 0x5b, 0x07, 0xc7, 0xb8, 0x5f, 0x54, 0x66, 0xb0, 0xac, 0x24, 0x3a, - 0x2f, 0x7e, 0x4e, 0x77, 0xdd, 0x13, 0xd0, 0x96, 0x75, 0x0b, 0xd3, 0x77, - 0xe1, 0x4b, 0x3e, 0x9c, 0x4a, 0x13, 0x47, 0x95, 0xdc, 0x3e, 0x41, 0xf5, - 0xdf, 0xdf, 0xb7, 0xcc, 0xec, 0xc6, 0x97, 0x53, 0x10, 0x82, 0x33, 0xd0, - 0x49, 0xba, 0x59, 0x2d, 0x38, 0x7c, 0x5a, 0x07, 0xec, 0x20, 0x12, 0x0d, - 0x95, 0x87, 0xce, 0xed, 0x38, 0x67, 0x99, 0xee, 0x56, 0x98, 0xde, 0x4d, - 0xcf, 0x6f, 0x35, 0xed, 0xda, 0xc1, 0xd9, 0x1f, 0x61, 0x2c, 0x3f, 0xd1, - 0x62, 0x70, 0x93, 0x85, 0xb5, 0xed, 0x22, 0x95, 0x58, 0x22, 0x3f, 0xf6, - 0x7b, 0xd0, 0xcc, 0x05, 0xdb, 0x1a, 0x80, 0x90, 0x5a, 0x47, 0xa1, 0x08, - 0xd9, 0x2d, 0x4d, 0xfd, 0x93, 0x21, 0x0a, 0xc8, 0x7a, 0x5a, 0x31, 0x61, - 0x78, 0x0b, 0xfd, 0x46, 0x61, 0x36, 0x4e, 0x37, 0x98, 0xa4, 0xa9, 0x52, - 0x29, 0x96, 0x80, 0x91, 0x5f, 0x12, 0xd4, 0xd8, 0xf3, 0x13, 0x1d, 0xe7, - 0xd3, 0x8c, 0x80, 0xc4, 0x82, 0xd2, 0x24, 0x58, 0x0e, 0xf3, 0xbb, 0xb0, - 0x9f, 0xb2, 0xe6, 0x56, 0xca, 0x7c, 0xf3, 0xa2, 0x0a, 0x8f, 0x97, 0x33, - 0x6c, 0x9e, 0x73, 0x45, 0x3a, 0xb7, 0x1e, 0x05, 0x58, 0x39, 0xfd, 0x7b, - 0x7c, 0xe0, 0xde, 0x6c, 0x00, 0xad, 0x9a, 0x37, 0x35, 0x91, 0xf2, 0xab, - 0x4c, 0x2e, 0x2c, 0x9f, 0x5d, 0x44, 0x6c, 0x67, 0xe1, 0x43, 0xc2, 0x2f, - 0x35, 0x8f, 0x69, 0x7c, 0xe8, 0x9a, 0x36, 0xf7, 0x78, 0x0a, 0x9c, 0x8f, - 0x2f, 0x13, 0xd8, 0xea, 0x36, 0x96, 0xaa, 0xce, 0x8a, 0xde, 0xf4, 0x5c, - 0xe0, 0xcc, 0xa3, 0x19, 0x7f, 0x88, 0x63, 0x4c, 0x0e, 0x51, 0x9c, 0x73, - 0x15, 0xd4, 0x04, 0x5f, 0x02, 0x91, 0x6c, 0x64, 0x61, 0x77, 0xf8, 0xbb, - 0xb0, 0x6c, 0x8d, 0x88, 0x5f, 0xab, 0x4c, 0x5d, 0x44, 0x7a, 0xe1, 0x80, - 0x15, 0x3b, 0x2c, 0xb5, 0xf5, 0x27, 0x91, 0x17, 0x23, 0xee, 0x72, 0x2e, - 0xf5, 0xb9, 0xee, 0x23, 0x00, 0x85, 0x69, 0xdd, 0xd4, 0xdd, 0xea, 0x13, - 0x6c, 0x0e, 0x3c, 0x4b, 0x1d, 0xba, 0xc0, 0x42, 0x43, 0x15, 0x02, 0x44, - 0x8c, 0x47, 0x2e, 0x9c, 0x42, 0xb1, 0x3b, 0xf0, 0x9a, 0x9b, 0xab, 0x6d, - 0x21, 0xe2, 0x24, 0xeb, 0x30, 0xf1, 0xfe, 0x83, 0x3c, 0x19, 0xa7, 0x22, - 0x6d, 0x3f, 0xd1, 0x0e, 0x30, 0xc8, 0x23, 0xfe, 0x7c, 0xd6, 0x23, 0x50, - 0x5a, 0x76, 0xb3, 0x3e, 0x93, 0xfa, 0x31, 0xee, 0x01, 0x1f, 0x67, 0x25, - 0x15, 0xbb, 0x65, 0xce, 0x64, 0x96, 0x86, 0x90, 0xb5, 0x51, 0x3e, 0x75, - 0xf8, 0xc9, 0x95, 0x02, 0xa6, 0xc3, 0xec, 0x75, 0x0c, 0xd3, 0xb6, 0x39, - 0x59, 0x10, 0xca, 0x76, 0x68, 0x56, 0x18, 0x0c, 0x74, 0x2f, 0x8e, 0x36, - 0x42, 0x58, 0xa8, 0xbd, 0x80, 0x22, 0xb8, 0xb1, 0xe5, 0xee, 0xae, 0x48, - 0xec, 0x71, 0x85, 0x31, 0xc6, 0xe1, 0x8a, 0x5a, 0x56, 0xb6, 0xfb, 0xa4, - 0xe8, 0xdd, 0x6a, 0x0f, 0x49, 0x18, 0xb5, 0x50, 0x73, 0xf3, 0x8f, 0x34, - 0x5d, 0xf3, 0x20, 0x3d, 0x51, 0xd5, 0x90, 0x95, 0xfb, 0x6c, 0x23, 0xb9, - 0xc8, 0xb7, 0xcd, 0x05, 0x91, 0x7b, 0xb4, 0x2b, 0x97, 0x2c, 0x72, 0xfd, - 0xd0, 0x8c, 0x2d, 0xff, 0x12, 0xa4, 0xb4, 0x8a, 0x31, 0x92, 0x8f, 0x4f, - 0x2a, 0x83, 0x9c, 0x3c, 0x40, 0xed, 0x78, 0x1b, 0x69, 0xdd, 0x9c, 0x0a, - 0x5b, 0x1f, 0x7e, 0x5e, 0x77, 0x50, 0xb2, 0x26, 0x75, 0xb5, 0xb7, 0xed, - 0xbd, 0x33, 0xd4, 0x6f, 0xaf, 0x03, 0xb1, 0xc8, 0x6d, 0x52, 0xf6, 0x55, - 0x6f, 0x7d, 0x47, 0x67, 0xbf, 0x11, 0xe6, 0x8d, 0x18, 0x57, 0x65, 0x9e, - 0xf1, 0xa5, 0xef, 0x09, 0x53, 0x0d, 0xbf, 0xa1, 0x37, 0x48, 0xc0, 0xb6, - 0x1c, 0x32, 0xf9, 0x41, 0x12, 0x80, 0x52, 0xd3, 0x58, 0x00, 0x4f, 0xce, - 0xa3, 0x8c, 0xb8, 0x41, 0xd2, 0x1c, 0xb5, 0x6f, 0xbe, 0x5e, 0x3f, 0x41, - 0x43, 0xac, 0x26, 0x90, 0x54, 0xe4, 0x6e, 0xec, 0x99, 0x70, 0xbb, 0x51, - 0x89, 0x93, 0x72, 0xee, 0xde, 0x69, 0xf2, 0xc2, 0x22, 0x30, 0x7c, 0xc5, - 0xc3, 0x04, 0x2d, 0xec, 0x8b, 0x5d, 0x1f, 0x03, 0x48, 0xc8, 0x9b, 0x85, - 0x87, 0x41, 0x1e, 0x31, 0xbb, 0x6e, 0xd7, 0x3c, 0xe2, 0x1b, 0x6c, 0x35, - 0xda, 0x44, 0x78, 0x71, 0x97, 0x87, 0xfc, 0x8b, 0x6f, 0x1c, 0x2f, 0xab, - 0x68, 0x78, 0x56, 0xa5, 0xa5, 0x24, 0xa3, 0x89, 0xfa, 0xb8, 0xd6, 0x9b, - 0x16, 0x7e, 0x9d, 0x4a, 0x28, 0x29, 0x66, 0x71, 0x65, 0x61, 0x1f, 0x92, - 0xfd, 0xae, 0xb6, 0x83, 0x97, 0xe8, 0x4b, 0x74, 0x69, 0x80, 0x8e, 0x6f, - 0x82, 0x80, 0x7b, 0x2e, 0x2f, 0xde, 0x84, 0x7a, 0x8c, 0xf1, 0x90, 0xac, - 0x7f, 0x4c, 0xb2, 0x66, 0xa1, 0xd6, 0x17, 0xc0, 0xbf, 0xbb, 0x63, 0x93, - 0x37, 0xd4, 0x50, 0x9a, 0x55, 0x0f, 0xf6, 0xb9, 0xd8, 0x5f, 0x8c, 0x2f, - 0x97, 0xaf, 0xbd, 0xb1, 0xf8, 0x44, 0x19, 0x77, 0xab, 0x6c, 0xa4, 0x58, - 0xd4, 0xa9, 0x2c, 0x28, 0xcb, 0x85, 0xc4, 0x3f, 0x6e, 0xe7, 0xb3, 0xe3, - 0xd8, 0x1c, 0x93, 0x89, 0xbb, 0xeb, 0x5b, 0x2c, 0xd2, 0x37, 0xac, 0x8c, - 0x3d, 0x76, 0x5f, 0x04, 0x24, 0x2e, 0xb2, 0x31, 0x7e, 0x68, 0x69, 0x82, - 0x3c, 0x85, 0xbf, 0x45, 0x49, 0x28, 0x22, 0x8f, 0x91, 0xfc, 0x33, 0x41, - 0x5d, 0xfe, 0xd1, 0x23, 0x4f, 0xf2, 0x8c, 0xf7, 0xf9, 0xab, 0x71, 0xbb, - 0x62, 0x7e, 0x4d, 0xdb, 0x06, 0xd4, 0xff, 0xd8, 0x41, 0xcd, 0x44, 0x0e, - 0xa2, 0x59, 0x0f, 0xc6, 0x0d, 0x24, 0xed, 0xe3, 0x81, 0xf9, 0xf4, 0xee, - 0xb9, 0x7e, 0xae, 0x72, 0xf8, 0xed, 0x1b, 0x44, 0xf4, 0x64, 0x2e, 0xba, - 0x9c, 0xe9, 0x76, 0x15, 0x81, 0x30, 0xa5, 0xf3, 0x99, 0x2f, 0x88, 0xca, - 0xd9, 0x65, 0xa0, 0x0d, 0x32, 0x1e, 0xb4, 0xaf, 0x4b, 0xe0, 0xa9, 0xee, - 0xe3, 0xf3, 0x47, 0x9b, 0xee, 0x99, 0x96, 0x99, 0xae, 0x09, 0x40, 0xd0, - 0xd5, 0xc8, 0xac, 0x17, 0xaa, 0xa8, 0xfb, 0x82, 0x01, 0x5d, 0x57, 0x2c, - 0x60, 0x66, 0xd3, 0xce, 0x30, 0x82, 0x8e, 0xf8, 0x04, 0xe8, 0xf5, 0x0f, - 0xe6, 0x8e, 0xd7, 0x0b, 0x42, 0xaa, 0x33, 0xfb, 0xed, 0x57, 0x00, 0x26, - 0x2d, 0xfe, 0x26, 0x21, 0xd3, 0x5c, 0xbb, 0x1a, 0x0a, 0x1e, 0xe3, 0xb7, - 0xd9, 0x8f, 0x06, 0x0c, 0x73, 0xd4, 0xf8, 0x3e, 0x59, 0x98, 0x1e, 0xc2, - 0xe0, 0xdd, 0x0e, 0x95, 0xe3, 0x9a, 0x2b, 0x38, 0xaa, 0x51, 0xc9, 0x0a, - 0x30, 0xcc, 0x6a, 0x85, 0x3d, 0x7a, 0x93, 0x91, 0xde, 0xd7, 0xdf, 0xc5, - 0x5d, 0x35, 0x9b, 0x3e, 0x97, 0x9b, 0x39, 0x9e, 0x04, 0x4f, 0xb1, 0x56, - 0x2a, 0x26, 0x43, 0xfc, 0xce, 0x62, 0xfe, 0x19, 0x09, 0x5f, 0xe8, 0xb8, - 0xd4, 0x92, 0x28, 0x46, 0x96, 0x7d, 0xfa, 0x7f, 0x38, 0x3a, 0x8f, 0xe5, - 0x46, 0x81, 0x00, 0x88, 0x7e, 0x10, 0x07, 0x72, 0x3a, 0x92, 0x33, 0x88, - 0x28, 0xd0, 0x8d, 0x9c, 0x73, 0xe6, 0xeb, 0x17, 0xef, 0xde, 0xd6, 0x25, - 0x97, 0xad, 0x09, 0xdd, 0xef, 0x19, 0xc4, 0xa4, 0x63, 0x07, 0x01, 0x19, - 0x07, 0xcd, 0x90, 0x89, 0x13, 0xfc, 0x9a, 0x55, 0x3e, 0xfe, 0x03, 0x01, - 0xed, 0x6d, 0x56, 0x99, 0xdb, 0x50, 0x6c, 0x1d, 0x7d, 0x46, 0x3d, 0x3b, - 0x8f, 0x9a, 0xa8, 0x5f, 0x85, 0x70, 0x7f, 0x17, 0xce, 0x95, 0x9e, 0xaf, - 0x22, 0x40, 0xea, 0xf0, 0x77, 0xdb, 0xb3, 0x9c, 0x82, 0xa8, 0x26, 0x62, - 0x81, 0xc6, 0xc7, 0x3d, 0x41, 0x3b, 0x74, 0x46, 0xce, 0xc1, 0x8b, 0x44, - 0x63, 0x91, 0xa2, 0xed, 0x98, 0x9b, 0x9b, 0x4e, 0xd0, 0x6c, 0x96, 0xce, - 0x73, 0x2a, 0x45, 0x17, 0x4e, 0x5d, 0x82, 0x1b, 0x66, 0xb1, 0xb0, 0xe5, - 0xa9, 0x02, 0xfc, 0xd5, 0x4e, 0x44, 0x5d, 0x28, 0x14, 0x12, 0x47, 0x08, - 0xa6, 0x7a, 0x9b, 0x25, 0x67, 0xba, 0x54, 0x47, 0x94, 0x28, 0x8d, 0x7a, - 0x28, 0x69, 0xbb, 0x9e, 0x6c, 0x95, 0x40, 0xc2, 0xc7, 0x74, 0xa3, 0xe9, - 0x47, 0xcf, 0xda, 0xaf, 0xca, 0x3e, 0xad, 0x5b, 0x4a, 0x28, 0xdc, 0xcc, - 0x93, 0xf9, 0xc9, 0x74, 0x93, 0x46, 0xd0, 0xf2, 0xdb, 0x93, 0x47, 0x10, - 0x19, 0xd3, 0xca, 0xa2, 0x4d, 0x1e, 0xbc, 0x88, 0xf1, 0x9d, 0xc2, 0x94, - 0xe5, 0x75, 0x2d, 0xd2, 0x4e, 0xa5, 0xde, 0x0e, 0x48, 0xd0, 0x2b, 0x88, - 0xe5, 0x6b, 0x1d, 0xe8, 0xa6, 0x88, 0x7b, 0x3b, 0x5e, 0x87, 0x90, 0xe4, - 0x99, 0xb8, 0x12, 0xcd, 0xe9, 0xce, 0xdd, 0xe2, 0xe3, 0x8d, 0xfc, 0x44, - 0xfd, 0xaa, 0x42, 0x7c, 0x2d, 0x2d, 0x21, 0xb5, 0xd9, 0xac, 0xbb, 0x89, - 0xf4, 0x83, 0x33, 0x01, 0xc8, 0x65, 0xb2, 0x8b, 0x71, 0x43, 0xaa, 0x49, - 0x5e, 0xb0, 0xe9, 0xb2, 0xf7, 0x0c, 0xc5, 0xf5, 0x91, 0x79, 0x75, 0x24, - 0xf7, 0x97, 0xac, 0x57, 0x59, 0xd6, 0xd7, 0x14, 0x14, 0x0f, 0xee, 0x36, - 0x42, 0xf5, 0xf1, 0x14, 0xa5, 0x95, 0x23, 0x33, 0x37, 0x58, 0x6a, 0x32, - 0xf3, 0x83, 0xfc, 0x18, 0x39, 0x7b, 0xf0, 0x00, 0x03, 0x3e, 0x20, 0xe1, - 0x83, 0x09, 0x09, 0xa0, 0x46, 0xf7, 0x10, 0x7c, 0x0b, 0x3e, 0xcf, 0xf0, - 0x90, 0xa3, 0x90, 0xda, 0x75, 0x2e, 0x3a, 0x64, 0x14, 0x34, 0x7d, 0xc0, - 0xb5, 0x1a, 0x1c, 0x36, 0x3a, 0x0a, 0x6f, 0xa0, 0x54, 0x6e, 0x9c, 0xa6, - 0x62, 0x08, 0x3e, 0x03, 0x38, 0x91, 0xbf, 0x3b, 0x85, 0xde, 0xbf, 0x7a, - 0x45, 0xef, 0x25, 0xc2, 0x29, 0xbc, 0x6e, 0x35, 0x90, 0x7d, 0xa7, 0xe5, - 0xc0, 0xb4, 0xe0, 0xdd, 0x97, 0xb4, 0x55, 0xe5, 0x74, 0x1a, 0xd7, 0x0f, - 0x1e, 0xf6, 0xc4, 0xcb, 0x13, 0x84, 0x4b, 0x3b, 0x81, 0xfa, 0xf7, 0x48, - 0x58, 0x64, 0x9b, 0x40, 0x12, 0x01, 0xc3, 0x05, 0x00, 0x73, 0xe3, 0xfe, - 0x32, 0xbf, 0x9b, 0x6e, 0x1e, 0xa1, 0xd2, 0x0a, 0x6b, 0x4d, 0x6e, 0x4d, - 0x56, 0x38, 0x9b, 0xad, 0x6b, 0x91, 0x8d, 0x38, 0x4f, 0xf9, 0x99, 0x56, - 0x8e, 0xd6, 0xfb, 0x6f, 0xdb, 0x6e, 0x68, 0xde, 0x9c, 0x52, 0xc4, 0x6c, - 0x43, 0xeb, 0x8f, 0x3b, 0xcb, 0xd0, 0x63, 0xc0, 0xe7, 0x97, 0x03, 0xc1, - 0xef, 0x60, 0xd2, 0x67, 0xdc, 0x0f, 0xa2, 0xba, 0xec, 0xc9, 0x07, 0xa3, - 0xfd, 0xd5, 0x98, 0x57, 0xae, 0x0b, 0x82, 0xb9, 0x26, 0x16, 0xb0, 0x33, - 0x12, 0xe9, 0x1d, 0x31, 0xe7, 0xf8, 0x8e, 0x40, 0x93, 0x34, 0x1f, 0x22, - 0x1a, 0x56, 0xcc, 0xc5, 0xeb, 0xbd, 0x2f, 0x8b, 0xbc, 0x7c, 0xcb, 0x63, - 0x21, 0xc2, 0x62, 0xdc, 0xe3, 0xcb, 0x10, 0x30, 0xd7, 0xf9, 0x35, 0x83, - 0xba, 0xe4, 0x31, 0x2b, 0xf8, 0x6b, 0x39, 0x4a, 0x40, 0x30, 0x02, 0x62, - 0x8f, 0x55, 0x0b, 0x48, 0x54, 0xd5, 0x3c, 0x1d, 0xd9, 0xd7, 0x89, 0xf6, - 0x29, 0xe0, 0x13, 0x66, 0x73, 0xe4, 0xb9, 0xa5, 0x69, 0xc7, 0x58, 0x40, - 0x7f, 0xa4, 0xd9, 0x0d, 0x7b, 0x52, 0x49, 0xea, 0xbf, 0x1c, 0xf3, 0x6b, - 0xfc, 0x3a, 0x0f, 0x89, 0x62, 0x78, 0xfa, 0x90, 0x42, 0x97, 0xdc, 0x4c, - 0x28, 0x13, 0xcd, 0x50, 0x40, 0xce, 0xa1, 0xdc, 0xea, 0x19, 0xf4, 0xd4, - 0x87, 0xba, 0x50, 0xe2, 0x10, 0xcd, 0x92, 0x3d, 0x19, 0xd2, 0x75, 0xcb, - 0x88, 0x1e, 0x29, 0xe5, 0xfd, 0xe3, 0x82, 0xd9, 0xdf, 0xf1, 0x3e, 0x49, - 0x4b, 0xa3, 0x78, 0x6c, 0xf3, 0x22, 0xb0, 0xbf, 0x98, 0x46, 0xa3, 0x0f, - 0x5f, 0x00, 0xa4, 0x00, 0x42, 0x9b, 0x0f, 0xc2, 0x53, 0x42, 0xfe, 0x68, - 0xb0, 0x82, 0xc1, 0x05, 0x65, 0x68, 0xf3, 0x7e, 0x21, 0x80, 0xa4, 0xdd, - 0x88, 0x26, 0xd0, 0xd6, 0x2a, 0xc2, 0x16, 0x71, 0x08, 0xd4, 0x2e, 0x6d, - 0x0d, 0xcc, 0xcd, 0x9d, 0x4b, 0xbb, 0x43, 0xcf, 0x27, 0xd7, 0x6a, 0xc2, - 0x85, 0x98, 0xeb, 0x8e, 0x8d, 0x57, 0x2f, 0x31, 0x0e, 0xbd, 0x9c, 0x76, - 0x84, 0xfb, 0x7b, 0x94, 0x85, 0xe5, 0x4e, 0xa6, 0xe5, 0x31, 0xb7, 0x06, - 0x6e, 0x0c, 0x12, 0x17, 0x9b, 0xe6, 0x18, 0x1b, 0x65, 0xb3, 0x9f, 0x6f, - 0x8c, 0xde, 0x5b, 0x53, 0x83, 0x1a, 0xee, 0x43, 0x08, 0x5c, 0x8e, 0x7c, - 0x4b, 0xb9, 0x69, 0x38, 0x2e, 0x65, 0xc3, 0x1d, 0x51, 0x58, 0xfe, 0x7e, - 0xae, 0xfb, 0xc4, 0xd1, 0xd7, 0x22, 0x28, 0xf5, 0x8b, 0x32, 0xa3, 0xb6, - 0xc0, 0xc9, 0xbc, 0xaa, 0xb1, 0xa3, 0xfe, 0x7a, 0xcf, 0x55, 0x5f, 0xa4, - 0xdc, 0xe1, 0x9d, 0xcb, 0x7c, 0x53, 0x36, 0x11, 0x99, 0xf2, 0x74, 0xda, - 0xa7, 0xa4, 0x78, 0x4b, 0xed, 0x39, 0x46, 0x16, 0xa4, 0xf6, 0x9c, 0xba, - 0x7d, 0xdd, 0x4c, 0x25, 0x94, 0x08, 0xd6, 0x18, 0xac, 0x55, 0x5b, 0xf0, - 0x30, 0x8e, 0x30, 0x58, 0x89, 0xf1, 0x32, 0x0a, 0xc3, 0x65, 0x54, 0x75, - 0x28, 0xd9, 0x87, 0xdf, 0x5f, 0xae, 0x52, 0xdc, 0x7e, 0x3b, 0x30, 0x5f, - 0x56, 0x96, 0x6f, 0x82, 0xec, 0xa0, 0x7b, 0xd8, 0xf8, 0x39, 0x2a, 0x5c, - 0x7d, 0x19, 0xf3, 0xe4, 0x38, 0x72, 0xfe, 0x26, 0xf4, 0xb7, 0xa4, 0x8d, - 0xf9, 0xd5, 0xbc, 0x63, 0x65, 0x98, 0xdc, 0xc6, 0xb9, 0x6d, 0x38, 0x53, - 0x64, 0x30, 0x19, 0xbd, 0x66, 0x02, 0x15, 0x56, 0xa2, 0x23, 0x67, 0x77, - 0x14, 0xa4, 0xad, 0x28, 0x42, 0x17, 0x57, 0xdc, 0x4b, 0x59, 0xf2, 0x58, - 0x77, 0xca, 0x36, 0x7c, 0xab, 0x59, 0x15, 0xff, 0xb0, 0xe9, 0x6d, 0x15, - 0xa2, 0x73, 0x5b, 0x91, 0x4e, 0x98, 0x75, 0x05, 0x89, 0xec, 0x1c, 0x32, - 0x56, 0xe1, 0xc1, 0xe1, 0x50, 0x5d, 0x0e, 0xd6, 0xc1, 0xf0, 0x77, 0x8a, - 0x94, 0x3d, 0xf1, 0xd3, 0x41, 0x30, 0xf0, 0x99, 0xa0, 0x13, 0xf9, 0x1b, - 0xdd, 0xf5, 0xf2, 0x7a, 0xee, 0xc7, 0x91, 0x82, 0xd0, 0xfe, 0x7e, 0x97, - 0xee, 0x6b, 0x95, 0x06, 0xae, 0x4f, 0x85, 0x40, 0xba, 0xe3, 0x2f, 0x7a, - 0x7e, 0x6b, 0x6c, 0x64, 0xec, 0xfc, 0x77, 0x53, 0xea, 0x53, 0x5e, 0x58, - 0x89, 0xd1, 0xf2, 0xd8, 0xa6, 0x49, 0x74, 0x82, 0xb0, 0xf0, 0x0d, 0x65, - 0xf3, 0x34, 0x6d, 0x61, 0x57, 0xc5, 0xaf, 0x20, 0x60, 0x92, 0x45, 0x31, - 0xfb, 0x4b, 0x40, 0x30, 0x72, 0x3d, 0x49, 0xca, 0x37, 0xed, 0xb9, 0xdd, - 0xc4, 0x40, 0xb3, 0xc3, 0x17, 0x7f, 0x10, 0x9e, 0x6e, 0x5e, 0x0d, 0x4f, - 0x15, 0xc4, 0x4c, 0x1c, 0x4a, 0x1c, 0x19, 0x2b, 0x2b, 0xa6, 0xdd, 0x40, - 0x0a, 0x90, 0x07, 0x87, 0x7c, 0xc7, 0x0d, 0xbf, 0xe7, 0xae, 0x84, 0x9a, - 0xa0, 0x64, 0xba, 0xa5, 0x2f, 0x37, 0x34, 0x8f, 0x5c, 0x13, 0xd7, 0x34, - 0xa7, 0x1f, 0x86, 0x07, 0x79, 0xce, 0x4b, 0x91, 0xb9, 0x16, 0x25, 0x53, - 0x73, 0xc0, 0xab, 0x1c, 0x9c, 0x38, 0x1e, 0x96, 0x18, 0xf7, 0x2e, 0x33, - 0x31, 0x04, 0x1f, 0x58, 0x8c, 0x5a, 0xac, 0x49, 0xce, 0x99, 0xff, 0x4e, - 0xf5, 0xfd, 0xb6, 0xd9, 0x67, 0x49, 0x24, 0x54, 0xbd, 0x27, 0xb2, 0xfd, - 0xba, 0xf6, 0xd3, 0x22, 0x59, 0xda, 0xe6, 0x26, 0xdf, 0x5a, 0x67, 0xf3, - 0xe7, 0xb4, 0xb7, 0x72, 0x47, 0x9b, 0xd5, 0x03, 0x18, 0x58, 0xc4, 0x29, - 0x14, 0x8e, 0xbd, 0x0f, 0x3d, 0x99, 0x57, 0x36, 0x60, 0x1b, 0x3a, 0x72, - 0x1a, 0x32, 0x7e, 0x19, 0x7c, 0x36, 0x2f, 0x39, 0x61, 0xc7, 0x15, 0x66, - 0xdb, 0x13, 0xed, 0xfe, 0x4e, 0xa4, 0x9b, 0xaf, 0xb0, 0x2f, 0x53, 0x1e, - 0xd3, 0xe0, 0xce, 0x26, 0xc0, 0xd6, 0x15, 0x75, 0x22, 0x89, 0xc1, 0x8c, - 0xb0, 0x12, 0x40, 0x46, 0x70, 0x5b, 0x44, 0xc5, 0x01, 0x9c, 0x69, 0x58, - 0x1a, 0xed, 0x12, 0xaf, 0x82, 0x7e, 0x4d, 0xec, 0x6e, 0xf9, 0xaf, 0x01, - 0xea, 0x12, 0xe2, 0xc9, 0x11, 0xac, 0x7c, 0xc8, 0xeb, 0xeb, 0x12, 0x07, - 0x90, 0xfe, 0xe0, 0x45, 0xc5, 0x4c, 0x2f, 0x88, 0xb8, 0x88, 0x52, 0xdb, - 0x0c, 0x36, 0x09, 0x5b, 0xdd, 0xbe, 0xb0, 0x77, 0x0f, 0x86, 0xfc, 0x8b, - 0xbf, 0x36, 0x4d, 0x2c, 0x4e, 0x91, 0x3f, 0x17, 0xea, 0xe9, 0x92, 0x5a, - 0xcb, 0xd0, 0x05, 0x16, 0x9e, 0x3a, 0xce, 0x9f, 0x1e, 0xa3, 0xbc, 0xef, - 0x76, 0x8e, 0x7e, 0x85, 0x37, 0x51, 0xfa, 0xab, 0x9c, 0x4f, 0x6b, 0xba, - 0x6c, 0x1b, 0x27, 0x67, 0x4a, 0xe8, 0xbc, 0x8f, 0x9e, 0x4b, 0x10, 0xdf, - 0x9a, 0xf1, 0x10, 0xa7, 0x2a, 0x85, 0x29, 0x03, 0x80, 0x02, 0xd9, 0xf4, - 0x80, 0x46, 0x38, 0x1c, 0x03, 0x8e, 0x3f, 0x45, 0x51, 0xbb, 0x6f, 0x00, - 0x8f, 0xbb, 0x86, 0x1b, 0x3b, 0xff, 0xf0, 0x64, 0x32, 0xaa, 0xf8, 0xc8, - 0x88, 0xc6, 0xe7, 0x07, 0x4c, 0x05, 0xbe, 0xb8, 0x2b, 0x50, 0x7e, 0x44, - 0x3f, 0xee, 0xa4, 0xc4, 0xf9, 0xce, 0xb4, 0x32, 0xc9, 0x1e, 0x48, 0x69, - 0x3d, 0x2b, 0x57, 0xae, 0xb0, 0x87, 0x7a, 0x1f, 0x01, 0x73, 0xfe, 0x61, - 0x1a, 0xfc, 0x3c, 0x66, 0x58, 0xb6, 0x81, 0x99, 0x7c, 0xa5, 0x79, 0x14, - 0xa8, 0x47, 0x50, 0x08, 0x83, 0x69, 0xab, 0xda, 0x99, 0xb3, 0xb7, 0x6e, - 0xb2, 0x73, 0xc1, 0x1b, 0xef, 0x8b, 0xb1, 0xe8, 0xb7, 0xf4, 0x5b, 0x19, - 0xfc, 0xfc, 0xd0, 0x52, 0xa1, 0xc0, 0xd6, 0x58, 0xc1, 0x8b, 0x72, 0x5f, - 0xdb, 0x14, 0x9d, 0x62, 0x2c, 0x6a, 0x36, 0x05, 0x64, 0xf6, 0xd4, 0x9e, - 0x35, 0xb0, 0x7a, 0xc1, 0xe4, 0x84, 0x81, 0xc6, 0xf8, 0xa1, 0xee, 0x5b, - 0xda, 0x2f, 0x1c, 0x06, 0xc3, 0x91, 0xb2, 0xfe, 0x04, 0x13, 0x4f, 0x9a, - 0x6d, 0xa4, 0xcf, 0x87, 0xf3, 0xc6, 0x3f, 0xd3, 0xe5, 0x99, 0x2a, 0x79, - 0xaa, 0xa1, 0xa2, 0x31, 0x33, 0x34, 0x5c, 0xe5, 0x70, 0x4f, 0x92, 0xd8, - 0xe3, 0x51, 0xc8, 0x0f, 0x65, 0x3c, 0x37, 0x70, 0x18, 0xf7, 0x69, 0x83, - 0xf9, 0x08, 0x3c, 0x94, 0xa6, 0xf0, 0xd0, 0x18, 0x05, 0x8b, 0x32, 0x92, - 0xcd, 0x93, 0x2b, 0x8c, 0x68, 0x46, 0xc7, 0x53, 0xed, 0xa5, 0x80, 0x13, - 0x04, 0x30, 0x1f, 0x03, 0x26, 0x61, 0x5a, 0x3d, 0xe8, 0x8d, 0x1c, 0x9c, - 0x55, 0x86, 0x4f, 0x55, 0x97, 0x4f, 0x4c, 0x46, 0xc6, 0x25, 0xcb, 0x9b, - 0xac, 0xdb, 0x46, 0x08, 0x47, 0x1a, 0x04, 0x0d, 0x67, 0x9f, 0x9e, 0x9d, - 0x8e, 0xd2, 0xe4, 0x8a, 0xdc, 0x50, 0xb0, 0x9b, 0xac, 0x91, 0x72, 0xc8, - 0x76, 0xd9, 0x7e, 0xd8, 0x28, 0x6d, 0x24, 0x41, 0xc5, 0x89, 0x53, 0xe2, - 0x4d, 0x67, 0xd3, 0xb1, 0x06, 0x5d, 0x17, 0x03, 0x60, 0x36, 0xcd, 0x7a, - 0xfd, 0x50, 0xe2, 0x58, 0x69, 0xd7, 0xe9, 0x40, 0x4d, 0x55, 0xd0, 0x6d, - 0x9b, 0x30, 0x3e, 0xe0, 0x51, 0x13, 0x46, 0xda, 0x3a, 0x76, 0x51, 0x53, - 0x1c, 0x6b, 0xbf, 0xf4, 0xe4, 0x47, 0x55, 0x0a, 0xe1, 0xc8, 0x13, 0x5f, - 0xcc, 0x76, 0x0e, 0x95, 0x71, 0x8c, 0x36, 0x28, 0x36, 0x02, 0x00, 0xc8, - 0xd4, 0x9b, 0x5b, 0x41, 0x1f, 0xed, 0x0d, 0xb6, 0x1f, 0x40, 0x8f, 0x21, - 0x72, 0xc7, 0x0b, 0xdc, 0xed, 0xe8, 0x6b, 0x3e, 0x01, 0xbf, 0xa5, 0xa0, - 0x09, 0x6d, 0x3f, 0x26, 0x51, 0x1f, 0x1c, 0x46, 0xc9, 0xf5, 0xf0, 0xd0, - 0xf8, 0xe8, 0xc9, 0x35, 0x4a, 0x62, 0x05, 0x99, 0x04, 0xa3, 0x45, 0x79, - 0x83, 0xf1, 0x36, 0x99, 0x0c, 0xf1, 0x4c, 0x3c, 0xe4, 0xd9, 0x1a, 0x19, - 0xb0, 0xd5, 0x73, 0xeb, 0x25, 0x42, 0x0e, 0xc9, 0x36, 0xa2, 0x3d, 0x97, - 0xb5, 0x34, 0x33, 0xc6, 0x11, 0xc5, 0xf3, 0x78, 0x41, 0x46, 0xdf, 0x8f, - 0x90, 0xf8, 0x7e, 0x43, 0xfa, 0xde, 0x54, 0x47, 0x2e, 0xab, 0xa0, 0xc1, - 0x38, 0x89, 0x08, 0x51, 0xea, 0x9d, 0x63, 0xb7, 0xa0, 0x3f, 0xf0, 0xf2, - 0xed, 0x8a, 0x45, 0x3a, 0x4a, 0x1b, 0x73, 0x5c, 0xf4, 0xd3, 0x40, 0x50, - 0x0f, 0x42, 0x11, 0x70, 0x0c, 0xe0, 0xaf, 0x2c, 0xf6, 0x93, 0x87, 0x18, - 0xd0, 0x93, 0xc5, 0xa0, 0xcd, 0x17, 0x0e, 0x2c, 0x11, 0x04, 0xea, 0x6f, - 0xc6, 0x90, 0xf0, 0xdf, 0x74, 0x1b, 0xb4, 0x57, 0x61, 0x1d, 0x93, 0xe0, - 0x30, 0x27, 0x7b, 0xd6, 0xbc, 0x17, 0xe5, 0x2d, 0x56, 0x8b, 0x8e, 0xc0, - 0xad, 0xcc, 0x5a, 0xe5, 0x8d, 0xc2, 0x91, 0x33, 0xdc, 0xa1, 0xf5, 0x2e, - 0xf6, 0x5a, 0xfd, 0xa5, 0xa7, 0x90, 0x2c, 0xda, 0xe5, 0x69, 0x6b, 0x8a, - 0x81, 0x1d, 0x19, 0x7f, 0xa2, 0x3c, 0xf7, 0x6b, 0xce, 0x18, 0x99, 0x49, - 0x6e, 0x36, 0x7b, 0x88, 0xf7, 0x4c, 0x20, 0xb8, 0x05, 0xcf, 0x18, 0x57, - 0xed, 0xf4, 0xfd, 0xe6, 0xbf, 0xea, 0xe0, 0x5f, 0x5a, 0x48, 0xd4, 0x50, - 0x69, 0xc4, 0xb6, 0x55, 0x33, 0xbb, 0x57, 0x35, 0x45, 0x8a, 0xd3, 0xd1, - 0xdd, 0xaa, 0x0e, 0x7c, 0x97, 0x12, 0x82, 0xc2, 0x8a, 0x6e, 0xd6, 0x1f, - 0x16, 0xba, 0xeb, 0x4a, 0xb3, 0x84, 0x0a, 0x51, 0x34, 0x40, 0x8f, 0x7e, - 0x8b, 0x3d, 0xff, 0xac, 0xc1, 0x32, 0x8a, 0x4a, 0x98, 0x0a, 0xb3, 0x13, - 0x85, 0xb8, 0xda, 0x42, 0xbb, 0xc3, 0x2f, 0x54, 0xe2, 0x8a, 0x0c, 0x73, - 0xf2, 0xb4, 0x8e, 0x44, 0xa5, 0x56, 0x6f, 0x91, 0x45, 0x96, 0x08, 0x82, - 0x90, 0x69, 0xe8, 0x51, 0x36, 0xaa, 0x46, 0x84, 0x1f, 0x1b, 0x69, 0x27, - 0xeb, 0x3b, 0x83, 0x37, 0xe7, 0x90, 0x83, 0xe3, 0xd7, 0x3b, 0xb1, 0xa6, - 0xc5, 0x8d, 0x6e, 0x70, 0x6a, 0xe7, 0x1d, 0x15, 0xd9, 0x42, 0x62, 0x2f, - 0x9f, 0x29, 0x9d, 0x91, 0x13, 0x3c, 0x2e, 0xa4, 0x9d, 0xa4, 0x77, 0xf9, - 0x4c, 0xa2, 0xde, 0x7e, 0x20, 0x4a, 0x3e, 0x88, 0x60, 0x90, 0xa7, 0x8f, - 0x35, 0x03, 0x63, 0x5a, 0x4e, 0x7a, 0xae, 0x93, 0xf0, 0x97, 0xc4, 0x57, - 0x0f, 0x85, 0x13, 0x1f, 0xfb, 0x7a, 0xa6, 0x3f, 0xcf, 0xf6, 0x97, 0x50, - 0x5b, 0xea, 0xf6, 0xc0, 0x41, 0x8b, 0xdb, 0xb8, 0xb4, 0xe5, 0x7d, 0x11, - 0x24, 0xc8, 0x83, 0x32, 0x1d, 0xcb, 0xb0, 0xc7, 0xe7, 0x63, 0x01, 0x4a, - 0x88, 0x2e, 0x48, 0x44, 0x9f, 0x60, 0x56, 0x1a, 0xcc, 0x79, 0x83, 0x78, - 0x10, 0xc6, 0x26, 0xa0, 0x2b, 0xc8, 0xf1, 0x47, 0xc0, 0x86, 0xc9, 0xbc, - 0x12, 0x2c, 0x7c, 0x9d, 0x11, 0x1b, 0x1f, 0x65, 0xf8, 0xb4, 0xa8, 0xdc, - 0xdd, 0x7f, 0x8f, 0x81, 0x32, 0xf1, 0xce, 0xdb, 0xa0, 0xd8, 0x9c, 0xb3, - 0xe5, 0xaa, 0xad, 0xe9, 0xc6, 0x2e, 0xdd, 0x57, 0xea, 0x5c, 0x32, 0x2e, - 0x8c, 0x86, 0x94, 0x94, 0xad, 0xc0, 0xbb, 0x15, 0x28, 0x70, 0x54, 0x9b, - 0x2e, 0x12, 0xbc, 0xe9, 0x7c, 0x2b, 0x54, 0xaa, 0x67, 0xb4, 0xfa, 0x9b, - 0x25, 0x35, 0x17, 0xc1, 0x3a, 0x3f, 0x71, 0xef, 0x17, 0x93, 0xfa, 0xea, - 0xc7, 0xc4, 0x67, 0x51, 0x06, 0xd9, 0x15, 0x0d, 0xb7, 0x02, 0x91, 0xf2, - 0x70, 0xad, 0xe7, 0x4a, 0x6c, 0x1e, 0x86, 0x0f, 0xa5, 0xf8, 0xe4, 0xe0, - 0x75, 0xdc, 0x2a, 0x32, 0x7d, 0x77, 0x3f, 0xc2, 0x91, 0xf3, 0x69, 0x06, - 0x58, 0xcf, 0xaa, 0xaf, 0xfe, 0xd9, 0x94, 0x2a, 0xa4, 0xbe, 0xce, 0x25, - 0x00, 0x07, 0xff, 0x7d, 0x3d, 0xd6, 0xf8, 0x8c, 0x6b, 0x3b, 0x76, 0xb4, - 0xf5, 0x29, 0xec, 0x4b, 0x9f, 0x97, 0xd2, 0xad, 0x25, 0x14, 0x79, 0x91, - 0x69, 0x33, 0x22, 0x3c, 0x4f, 0xef, 0x88, 0x39, 0x52, 0x03, 0x16, 0xbf, - 0x2b, 0x0c, 0xa5, 0x57, 0x72, 0x42, 0xdf, 0x61, 0x05, 0x5a, 0xf1, 0x89, - 0xf6, 0x73, 0x28, 0x68, 0x92, 0xa0, 0xe0, 0x9a, 0x0e, 0x5e, 0x4f, 0x25, - 0xed, 0xe3, 0xf9, 0x98, 0x84, 0xb6, 0xb4, 0x01, 0xc8, 0x4b, 0x2c, 0x50, - 0x8b, 0xf2, 0xa5, 0x35, 0x19, 0xb4, 0x8b, 0xe5, 0xa6, 0x7a, 0xe8, 0xa5, - 0x46, 0x9f, 0x9e, 0xd2, 0x19, 0x63, 0x33, 0x95, 0xe5, 0x54, 0x16, 0xd2, - 0x81, 0x40, 0xe3, 0x91, 0xa7, 0x8e, 0x9b, 0x7b, 0x38, 0x25, 0x9d, 0xb6, - 0x2f, 0xac, 0x4d, 0xdc, 0xd3, 0x9a, 0xf1, 0x16, 0x29, 0xf8, 0x74, 0x7c, - 0xac, 0x25, 0x20, 0xc6, 0x46, 0x1a, 0xcb, 0x66, 0xb7, 0xb0, 0xcb, 0xf9, - 0xd7, 0x14, 0xab, 0xdc, 0x28, 0x49, 0x15, 0xe5, 0xcd, 0x6f, 0x34, 0xb2, - 0xb8, 0xde, 0x38, 0x12, 0x6e, 0x06, 0xf7, 0x19, 0x97, 0xa2, 0x9b, 0x65, - 0xfb, 0xb8, 0xce, 0x9d, 0x8f, 0x22, 0xa1, 0xa3, 0x66, 0x8e, 0xb2, 0x03, - 0xd9, 0xaf, 0x28, 0x3b, 0xbe, 0x21, 0xb7, 0x11, 0x7d, 0xdc, 0xcb, 0xb5, - 0xb8, 0x11, 0xdc, 0xa6, 0xef, 0xc9, 0x87, 0xa8, 0xde, 0x05, 0xa0, 0x82, - 0xfd, 0x48, 0x87, 0x81, 0xf8, 0x4c, 0xfc, 0x1d, 0xa2, 0x6c, 0xfe, 0x34, - 0x26, 0xeb, 0xef, 0x66, 0x16, 0x69, 0xb0, 0xdb, 0x0d, 0xd9, 0xea, 0x2c, - 0x1d, 0x9d, 0x75, 0xfe, 0xaa, 0x0a, 0x45, 0x0e, 0x73, 0xc0, 0x9d, 0x16, - 0xfd, 0xea, 0xf3, 0x2f, 0xda, 0xd5, 0xf9, 0xaf, 0xdd, 0x8c, 0x3b, 0xb0, - 0x6d, 0x5d, 0x5c, 0xed, 0xc4, 0x8e, 0xa8, 0x88, 0x69, 0x20, 0xff, 0xce, - 0xbf, 0xb0, 0x14, 0x59, 0xa2, 0x1b, 0xeb, 0xf9, 0xb5, 0x80, 0xaa, 0xc8, - 0xd9, 0x61, 0x27, 0x66, 0x5e, 0xf3, 0xcb, 0x93, 0x6f, 0x3f, 0x03, 0x59, - 0x0e, 0x0c, 0x94, 0x45, 0x03, 0xfa, 0xf3, 0x11, 0x24, 0x57, 0xad, 0x62, - 0x4e, 0xb1, 0xf9, 0x69, 0x44, 0x19, 0x83, 0x5b, 0xac, 0x81, 0x5b, 0xe0, - 0x28, 0x76, 0x18, 0x9c, 0x98, 0x25, 0xd4, 0xf8, 0xaa, 0xc4, 0x24, 0xf0, - 0x94, 0x81, 0x79, 0x69, 0x38, 0x9c, 0xdf, 0xaf, 0x6c, 0x07, 0x07, 0x4d, - 0xc7, 0xda, 0x95, 0x00, 0x37, 0x8c, 0x67, 0xf1, 0xda, 0x5e, 0x5d, 0x41, - 0xf0, 0x98, 0x19, 0x7f, 0x0b, 0x68, 0x30, 0x0f, 0xf6, 0xfb, 0x58, 0xe1, - 0x51, 0xaf, 0xb7, 0x48, 0x0f, 0x76, 0x4e, 0xac, 0xcf, 0xb6, 0xdf, 0x39, - 0xab, 0x62, 0x8c, 0xfe, 0x09, 0x36, 0x75, 0x69, 0x9b, 0x0b, 0xb5, 0xc9, - 0xa9, 0xeb, 0xc2, 0xbb, 0x44, 0x3a, 0x54, 0x73, 0x08, 0xb0, 0xa4, 0x0b, - 0xbd, 0xe3, 0x35, 0x0a, 0x3f, 0x14, 0x85, 0x8c, 0x22, 0x77, 0x35, 0xab, - 0x48, 0x4c, 0x2e, 0x95, 0x2d, 0x79, 0x3e, 0x81, 0xbb, 0x23, 0x2a, 0xd3, - 0xe8, 0x0e, 0xb8, 0xee, 0x23, 0xff, 0x80, 0x4f, 0x2b, 0xc7, 0x86, 0x43, - 0x3d, 0xe7, 0xb2, 0xc8, 0xc6, 0xcb, 0x00, 0x1d, 0x82, 0x8f, 0x7a, 0x69, - 0x76, 0x7a, 0xd8, 0xaf, 0x40, 0x63, 0x07, 0xeb, 0x74, 0xca, 0x44, 0x25, - 0x7e, 0x66, 0x5f, 0x41, 0x8e, 0x40, 0xb5, 0x03, 0xfa, 0xdb, 0x90, 0x95, - 0xbb, 0x72, 0xfd, 0xa4, 0x51, 0x05, 0x00, 0xc5, 0x11, 0x4f, 0xaf, 0x11, - 0x59, 0x80, 0x00, 0x19, 0xf1, 0x50, 0x94, 0x2b, 0xbe, 0xaa, 0xea, 0x80, - 0x09, 0x69, 0x60, 0xd1, 0x12, 0xcc, 0x95, 0x7d, 0x08, 0x4d, 0x34, 0xce, - 0x2f, 0xfc, 0x14, 0x4e, 0x28, 0x8e, 0x2c, 0x0f, 0x5a, 0x60, 0x25, 0x60, - 0x08, 0x0f, 0x2e, 0xdd, 0x81, 0xf3, 0x10, 0x1c, 0x7e, 0x21, 0x8e, 0xff, - 0xfb, 0xd0, 0xe1, 0xdb, 0x09, 0x8e, 0x32, 0x48, 0x89, 0x29, 0x1e, 0xd0, - 0x8a, 0x4c, 0x37, 0x0b, 0x6a, 0xd4, 0x5d, 0x2b, 0xc4, 0xf5, 0xd6, 0xe3, - 0x7d, 0x4c, 0x6c, 0x58, 0x45, 0x01, 0x6e, 0xda, 0x1c, 0x5f, 0xa2, 0x5f, - 0xf3, 0x41, 0x02, 0x0a, 0x69, 0xdf, 0x30, 0x64, 0x0a, 0x2e, 0x8c, 0x16, - 0x83, 0x50, 0x30, 0x62, 0xdb, 0x64, 0xf3, 0x6a, 0x24, 0xb3, 0x1b, 0x9d, - 0x94, 0x28, 0x52, 0xa6, 0x3f, 0x3e, 0x52, 0xff, 0xe1, 0xed, 0x4e, 0x86, - 0x05, 0xc2, 0x2f, 0x01, 0x5e, 0xb4, 0x5e, 0xaa, 0xf6, 0x6c, 0xcd, 0x11, - 0x99, 0x2f, 0x69, 0xf3, 0x96, 0xf9, 0xa6, 0x51, 0x8f, 0x78, 0x34, 0xbe, - 0xb2, 0xb5, 0xa8, 0x31, 0x1f, 0x45, 0xf2, 0xc2, 0x46, 0xc5, 0x77, 0xcf, - 0xa1, 0x4b, 0xeb, 0xf2, 0xdb, 0x15, 0xa9, 0x49, 0x21, 0x7b, 0xdf, 0x0a, - 0xa3, 0x2f, 0x9f, 0x61, 0x96, 0x82, 0xec, 0xa6, 0xf8, 0x35, 0x09, 0x6b, - 0x1d, 0x24, 0xbc, 0x08, 0xb6, 0x30, 0xe2, 0xc2, 0x43, 0x12, 0xda, 0x43, - 0xd4, 0xb9, 0x9e, 0xc8, 0xf3, 0x97, 0x3b, 0xfe, 0xa9, 0x9d, 0x2c, 0xda, - 0x8c, 0xba, 0x7c, 0xa9, 0x33, 0x17, 0x2b, 0x00, 0x8a, 0x2a, 0x8c, 0x27, - 0x14, 0x54, 0x65, 0x8a, 0xaf, 0x06, 0x98, 0x37, 0x89, 0xf7, 0xaa, 0x15, - 0x41, 0xc9, 0x67, 0x93, 0x6a, 0xad, 0xa6, 0x4f, 0x45, 0xcf, 0x6c, 0x93, - 0x85, 0x84, 0x25, 0xa0, 0x9a, 0x9d, 0xaa, 0xfb, 0xc9, 0xac, 0x48, 0xed, - 0x2c, 0x67, 0xe8, 0x45, 0xce, 0x3e, 0x60, 0xd3, 0xfd, 0xa3, 0x0c, 0x39, - 0x64, 0xca, 0xba, 0xd6, 0x18, 0xce, 0x76, 0x18, 0x14, 0x7a, 0x1a, 0xb1, - 0xbb, 0x24, 0xd9, 0x62, 0x8c, 0x2f, 0x0e, 0xe0, 0xf3, 0x54, 0x38, 0x06, - 0x4c, 0x8a, 0xc5, 0xe9, 0x5e, 0x4b, 0x75, 0x86, 0xd7, 0x52, 0x76, 0xcf, - 0x4e, 0x1d, 0x1a, 0xd5, 0xc1, 0xbb, 0x30, 0x69, 0x37, 0xe9, 0xed, 0x5a, - 0xbe, 0x71, 0x82, 0x11, 0x87, 0xcf, 0x17, 0xd1, 0x97, 0x72, 0xba, 0x16, - 0xd6, 0x31, 0x0b, 0x2e, 0xf9, 0x08, 0xbf, 0x73, 0xec, 0x54, 0x86, 0x1f, - 0x7e, 0x9b, 0xe9, 0x47, 0x79, 0x13, 0xfa, 0xc1, 0x29, 0xef, 0xcd, 0x6f, - 0x1b, 0x5d, 0x90, 0xd0, 0x8f, 0x6a, 0x81, 0x0c, 0x05, 0x77, 0xbe, 0x6f, - 0x11, 0xe3, 0xe1, 0x17, 0xc4, 0xda, 0xb1, 0x05, 0x89, 0xfd, 0xb7, 0x3e, - 0x80, 0x80, 0x0c, 0x96, 0x70, 0x6f, 0x68, 0x63, 0x6b, 0xaf, 0x55, 0x84, - 0x88, 0xaa, 0x63, 0xeb, 0xeb, 0xa0, 0xb0, 0xac, 0x77, 0xe1, 0x5b, 0x7e, - 0xa1, 0x8a, 0x87, 0xba, 0x4a, 0xde, 0x6c, 0x09, 0xe5, 0xde, 0x01, 0xe5, - 0x6d, 0xbc, 0x32, 0x87, 0x46, 0x4c, 0xb0, 0x81, 0xc5, 0x3b, 0xeb, 0xc4, - 0x4e, 0x19, 0xdd, 0x10, 0xfa, 0x58, 0x3e, 0x45, 0x71, 0x5b, 0x4d, 0x6e, - 0xa5, 0xa2, 0xf2, 0xd4, 0xb4, 0x46, 0xc5, 0x6d, 0xb5, 0xb6, 0x15, 0xa3, - 0x1b, 0x5e, 0xea, 0xb6, 0xff, 0xc1, 0xed, 0xf8, 0x93, 0x0b, 0xdb, 0x66, - 0x7f, 0x47, 0x06, 0x19, 0x79, 0x0c, 0xca, 0xa2, 0x8f, 0xff, 0x26, 0x78, - 0xa9, 0x10, 0x62, 0x01, 0x96, 0xf7, 0x17, 0x40, 0xc5, 0x7d, 0x87, 0xb3, - 0xaf, 0x50, 0xa4, 0xd2, 0x87, 0x84, 0x33, 0x1a, 0x70, 0x53, 0x1c, 0x9d, - 0x6a, 0x6b, 0xa5, 0xc8, 0x07, 0x01, 0x7e, 0x14, 0x93, 0x35, 0x37, 0x94, - 0x14, 0x3d, 0x08, 0xeb, 0x54, 0xea, 0xb9, 0xd4, 0x81, 0x5c, 0x81, 0x38, - 0x96, 0x3d, 0x83, 0x31, 0x69, 0x29, 0x30, 0xd7, 0xb1, 0x85, 0x5c, 0x0e, - 0xd3, 0x1b, 0x07, 0xdc, 0x3f, 0x8d, 0xfb, 0xb9, 0x78, 0x2e, 0xfb, 0x15, - 0x94, 0xbf, 0x1c, 0x02, 0xa2, 0x67, 0x43, 0x4a, 0xa7, 0xe6, 0x28, 0x4a, - 0xe2, 0x23, 0x70, 0x51, 0x1b, 0xbf, 0xa6, 0xc4, 0x73, 0xbd, 0x8f, 0x87, - 0x6e, 0x70, 0x6f, 0x5c, 0x0a, 0x51, 0x53, 0x6c, 0x21, 0xf4, 0xe3, 0xf2, - 0xdf, 0x99, 0x07, 0xd9, 0x3b, 0x6a, 0xca, 0xbd, 0x4f, 0xb1, 0xd4, 0xd1, - 0x2d, 0xff, 0xdb, 0x0f, 0xde, 0xdf, 0x91, 0x59, 0xe4, 0x06, 0x3d, 0x65, - 0xfb, 0xc4, 0x3d, 0x38, 0xfc, 0xfc, 0xaa, 0xb7, 0x37, 0x46, 0x30, 0x7e, - 0xc1, 0xea, 0x29, 0xf6, 0x64, 0x98, 0x0f, 0xc7, 0x69, 0x5a, 0xff, 0xad, - 0xb0, 0xc5, 0x05, 0x9e, 0x5a, 0x0f, 0x17, 0x73, 0xbc, 0x3b, 0x45, 0x15, - 0xda, 0xd1, 0x85, 0xc6, 0xc2, 0x26, 0x02, 0x19, 0x52, 0x37, 0x24, 0x2a, - 0x01, 0xef, 0xa3, 0x18, 0xdf, 0xea, 0x45, 0x59, 0xcd, 0x75, 0xf0, 0xa5, - 0x16, 0xab, 0xab, 0x22, 0x39, 0x45, 0x03, 0x7f, 0x80, 0x61, 0xb6, 0x7f, - 0x9f, 0x91, 0xfb, 0x06, 0x03, 0x55, 0x6c, 0x16, 0x0f, 0xdc, 0xc2, 0x4c, - 0xc8, 0x5e, 0x1d, 0x60, 0x66, 0xe8, 0xaf, 0xa8, 0xcc, 0x4e, 0xd5, 0xaa, - 0x6a, 0xa4, 0xfd, 0xd6, 0x06, 0x81, 0x15, 0x1b, 0x6e, 0xd6, 0xc1, 0x69, - 0x1a, 0x95, 0x82, 0x4f, 0xf0, 0xb7, 0xce, 0x28, 0xbf, 0x10, 0x8d, 0x5b, - 0xad, 0xc1, 0x4f, 0xe6, 0xd2, 0xd4, 0x1d, 0x42, 0xc2, 0xe5, 0x23, 0x12, - 0xba, 0xc0, 0x72, 0xbb, 0x41, 0x15, 0xdb, 0xbd, 0xc0, 0x2c, 0x1f, 0x48, - 0xe9, 0xb0, 0x2a, 0x75, 0x62, 0x34, 0x66, 0x9b, 0x4c, 0x64, 0xc1, 0x22, - 0x31, 0xfa, 0x65, 0x09, 0x3a, 0xeb, 0xe5, 0xf1, 0xd4, 0x75, 0xf6, 0x4d, - 0x96, 0x57, 0x26, 0xf5, 0x77, 0x9f, 0x81, 0x5c, 0x6b, 0x68, 0x7a, 0x74, - 0x73, 0x39, 0x5b, 0xef, 0x46, 0x63, 0x93, 0x8c, 0x55, 0x1c, 0xf5, 0x82, - 0x47, 0xbb, 0x70, 0x4d, 0xa8, 0xa5, 0xb8, 0x91, 0xee, 0x5c, 0x49, 0x3f, - 0x09, 0xd3, 0x33, 0x7f, 0x82, 0x0a, 0x11, 0x80, 0x7b, 0x71, 0x8b, 0x2d, - 0x17, 0x30, 0xfd, 0x3b, 0xe4, 0x57, 0xf2, 0xde, 0x89, 0x0b, 0xcd, 0x35, - 0xe6, 0x0c, 0xab, 0x55, 0xdf, 0x36, 0xb0, 0xcf, 0x76, 0xd9, 0xa2, 0x21, - 0x9f, 0xe5, 0xa8, 0xdd, 0xa5, 0x86, 0xa9, 0x63, 0x0b, 0x9d, 0xc7, 0x9f, - 0xaa, 0xec, 0x5d, 0xb3, 0xc5, 0x8b, 0xf5, 0xd5, 0x3e, 0x23, 0x83, 0x6d, - 0x9d, 0xf7, 0x00, 0x47, 0x1b, 0xf5, 0x65, 0x83, 0x06, 0xf1, 0x4e, 0x88, - 0x13, 0x30, 0xd4, 0xd7, 0x7a, 0x00, 0xd7, 0x06, 0xe8, 0xa3, 0xb3, 0x70, - 0x33, 0xd9, 0x7e, 0x30, 0x8f, 0xde, 0xdf, 0x24, 0x44, 0x17, 0xeb, 0xc8, - 0x39, 0x37, 0xa7, 0xa5, 0xc2, 0xdf, 0xf6, 0x8d, 0xfd, 0x90, 0x3d, 0x1d, - 0x25, 0x8f, 0x27, 0x20, 0x76, 0x75, 0xc8, 0x92, 0x42, 0x34, 0x8f, 0x55, - 0x97, 0xd1, 0x17, 0x46, 0x13, 0x26, 0xff, 0x62, 0x5d, 0x04, 0x48, 0x53, - 0xb2, 0x2c, 0xf1, 0x9c, 0x59, 0x67, 0xb5, 0x9d, 0xde, 0xa2, 0x64, 0xce, - 0xf7, 0xb5, 0xb3, 0x62, 0x7e, 0xbf, 0x4c, 0x22, 0x60, 0xcc, 0x6b, 0xaa, - 0x09, 0x7a, 0x94, 0xe5, 0x0a, 0x59, 0xa0, 0x5b, 0x3f, 0x65, 0x72, 0x92, - 0x04, 0x7d, 0x08, 0x7b, 0xb9, 0x4b, 0x2f, 0x3b, 0x7d, 0xa0, 0xb7, 0x42, - 0xfc, 0x1d, 0xef, 0xa2, 0x1a, 0x2d, 0xf3, 0xfa, 0x2d, 0x93, 0x06, 0xb1, - 0x08, 0x6b, 0x9c, 0xe4, 0x25, 0x32, 0x81, 0xc7, 0xdd, 0xce, 0x4e, 0x9f, - 0xb5, 0xc4, 0x56, 0x01, 0x94, 0x9f, 0x53, 0x7b, 0x04, 0x38, 0xc3, 0x1c, - 0xee, 0x58, 0xbf, 0x61, 0x70, 0x2a, 0x3b, 0xba, 0xdc, 0x1d, 0x8a, 0xb8, - 0x36, 0x46, 0x50, 0x46, 0x1f, 0xd0, 0x40, 0x2e, 0xdb, 0x1e, 0xa6, 0x90, - 0x4e, 0xa4, 0x01, 0x53, 0x73, 0xc5, 0xa6, 0x10, 0x50, 0xfe, 0xab, 0xed, - 0x4a, 0x2a, 0x71, 0x6e, 0xd4, 0x58, 0x71, 0xbe, 0xd0, 0x8c, 0x0e, 0x0b, - 0x24, 0xe9, 0x20, 0x92, 0x8b, 0x45, 0x48, 0x48, 0xee, 0xb8, 0x95, 0x0b, - 0x0a, 0x86, 0x76, 0xb0, 0x9f, 0xd4, 0x3f, 0x31, 0x5f, 0x46, 0x8e, 0xa2, - 0xd4, 0x6a, 0x7e, 0x37, 0x4a, 0x7c, 0x9c, 0x79, 0xb8, 0x6a, 0xad, 0x11, - 0xb1, 0xd7, 0xab, 0xa8, 0xd3, 0xf9, 0xbd, 0xd6, 0xa5, 0xea, 0x49, 0xad, - 0x0f, 0xcf, 0x61, 0x11, 0x60, 0x3d, 0xa5, 0x5c, 0x54, 0xd3, 0x72, 0x46, - 0x12, 0x29, 0x80, 0x2a, 0x84, 0xa9, 0x0f, 0xbe, 0x81, 0x05, 0xb0, 0xe9, - 0xd8, 0x91, 0x6b, 0x35, 0xc5, 0x4f, 0xe6, 0x2b, 0x68, 0xb3, 0x88, 0xad, - 0x4e, 0x66, 0xb8, 0xd8, 0xb0, 0x34, 0x40, 0x35, 0x06, 0x6c, 0x0d, 0x6b, - 0xfd, 0x93, 0x96, 0x77, 0x01, 0x97, 0xca, 0x29, 0x00, 0x52, 0xaf, 0xda, - 0x42, 0x02, 0x06, 0x4d, 0xd9, 0x1b, 0xdf, 0x6d, 0xfe, 0xed, 0x99, 0x1e, - 0xd7, 0x48, 0x22, 0xfc, 0x66, 0xde, 0x26, 0xc7, 0x86, 0xfb, 0x1a, 0x67, - 0x8e, 0xb6, 0x0b, 0xe3, 0xad, 0xf3, 0x4f, 0xd1, 0x2b, 0x09, 0x59, 0xc6, - 0x01, 0x73, 0xca, 0xae, 0x84, 0xf4, 0x14, 0xa5, 0xd0, 0xe4, 0x78, 0x99, - 0xb0, 0x95, 0xf7, 0x77, 0xba, 0xf3, 0xa7, 0xe6, 0x9f, 0x22, 0xd6, 0xe5, - 0x80, 0x5d, 0xab, 0xb7, 0xbf, 0xa1, 0xe1, 0x0b, 0xe5, 0x85, 0xa9, 0x7e, - 0x58, 0xee, 0x57, 0xc6, 0xe8, 0xb2, 0x13, 0x47, 0x3d, 0x3a, 0x37, 0x9b, - 0x27, 0xfd, 0xac, 0xdf, 0x09, 0xe4, 0x9f, 0x99, 0x7f, 0x6d, 0xae, 0x00, - 0x87, 0x32, 0x3a, 0xaa, 0xbb, 0x64, 0xd2, 0xb5, 0x1d, 0x33, 0xe0, 0xe9, - 0x85, 0x58, 0xfe, 0x9d, 0x0b, 0xf6, 0xd4, 0x21, 0x4f, 0xff, 0xf1, 0x4f, - 0xd7, 0x7d, 0x6b, 0xb0, 0x84, 0xfd, 0xd9, 0x3c, 0x0a, 0xc8, 0x62, 0xdd, - 0xb8, 0x62, 0x4d, 0xde, 0x38, 0x29, 0x26, 0x79, 0x7e, 0xae, 0x85, 0xfb, - 0xd7, 0x0c, 0x3f, 0x52, 0xbf, 0xbd, 0x45, 0xee, 0x60, 0x90, 0xd6, 0x16, - 0x43, 0xfa, 0x9a, 0x89, 0x63, 0x37, 0x52, 0x58, 0x31, 0x0f, 0x51, 0x65, - 0x2a, 0x08, 0xfb, 0x1a, 0xd7, 0xcd, 0xf7, 0xb9, 0x12, 0x05, 0xc4, 0x4b, - 0x1b, 0x7b, 0xc1, 0xbf, 0x06, 0xaa, 0xaa, 0x2f, 0x3f, 0x28, 0x2d, 0x35, - 0x60, 0x5f, 0x59, 0x33, 0x8c, 0x83, 0x49, 0xc3, 0x74, 0xfa, 0x92, 0x3d, - 0x76, 0x77, 0x0c, 0x6e, 0x5e, 0x95, 0x52, 0x9d, 0x97, 0x8a, 0xee, 0x84, - 0x09, 0x02, 0xd7, 0xa2, 0x8d, 0x42, 0x5a, 0x73, 0xd5, 0xfe, 0xf7, 0x41, - 0x13, 0x6c, 0x7d, 0xc5, 0x02, 0x0d, 0xa9, 0xa1, 0xfe, 0xf9, 0x84, 0x2a, - 0x15, 0x44, 0x76, 0xe9, 0xd4, 0xf4, 0xfa, 0xb4, 0x29, 0x71, 0xbf, 0x8b, - 0xb0, 0x2c, 0xcc, 0xb3, 0x93, 0xbb, 0xca, 0x6d, 0x85, 0xe5, 0x98, 0x53, - 0xf1, 0x85, 0x74, 0xae, 0xed, 0x52, 0x76, 0xfc, 0xb3, 0x42, 0x72, 0x40, - 0xc9, 0xf2, 0xf2, 0xef, 0x43, 0x25, 0xea, 0xc3, 0x02, 0xc1, 0xa3, 0x4c, - 0xde, 0xa3, 0xb8, 0xe4, 0xc3, 0xed, 0xe4, 0xf3, 0xa9, 0xde, 0xa8, 0x85, - 0xdb, 0x64, 0xbb, 0x9c, 0x5f, 0x1b, 0x00, 0x88, 0xf4, 0x49, 0xf2, 0xea, - 0x08, 0x0b, 0x75, 0x19, 0x8c, 0x5f, 0xb2, 0x14, 0x49, 0x16, 0xd1, 0x6f, - 0xb7, 0x32, 0x09, 0xc6, 0x92, 0x5c, 0x4c, 0x81, 0x97, 0x30, 0x83, 0xe7, - 0x1c, 0x12, 0x30, 0x8a, 0x9b, 0xb3, 0xe6, 0xd8, 0xbc, 0xe1, 0x04, 0x3a, - 0xf5, 0x63, 0x76, 0xe9, 0xa7, 0xea, 0xbb, 0x13, 0x59, 0x37, 0x64, 0x76, - 0x80, 0x50, 0x36, 0xee, 0xf0, 0xdd, 0xa5, 0x60, 0xde, 0x93, 0x6d, 0xae, - 0x5e, 0x4f, 0xa9, 0xea, 0xae, 0x22, 0xd5, 0xa0, 0x63, 0xec, 0x28, 0x24, - 0xbc, 0x0c, 0x7e, 0x23, 0x3a, 0xb8, 0x58, 0x5d, 0x93, 0x78, 0x67, 0xf6, - 0x9e, 0xec, 0xf3, 0x35, 0x13, 0xbe, 0xb3, 0x35, 0x73, 0x48, 0x24, 0xb9, - 0xc1, 0xac, 0x5b, 0xdb, 0xc0, 0x9a, 0xdc, 0xe5, 0x03, 0xff, 0x70, 0x8e, - 0x4e, 0x64, 0xb6, 0xa6, 0x65, 0x66, 0xf7, 0x28, 0x11, 0x39, 0x80, 0x48, - 0x9c, 0xb6, 0x81, 0x77, 0x1c, 0xf9, 0xd2, 0xf6, 0xf1, 0xef, 0x07, 0x8d, - 0xb9, 0x13, 0x91, 0x38, 0xda, 0x4e, 0x6e, 0xb8, 0x7d, 0x7c, 0xb4, 0x3e, - 0xfa, 0x10, 0xc6, 0x10, 0xb4, 0x60, 0x47, 0x98, 0x5e, 0xcd, 0x0c, 0x38, - 0xb2, 0xb4, 0x28, 0x62, 0xb7, 0xc8, 0x29, 0x47, 0x91, 0x56, 0xca, 0xee, - 0x15, 0x60, 0x08, 0xc4, 0x9d, 0x6b, 0xae, 0xfd, 0x80, 0xe0, 0x67, 0xf7, - 0xee, 0x2b, 0x98, 0x9b, 0xa7, 0x00, 0x6f, 0x9a, 0xfe, 0xb6, 0xfa, 0xd7, - 0x5f, 0x02, 0x62, 0x73, 0x66, 0x44, 0xf6, 0xd0, 0xc7, 0xf4, 0x47, 0x08, - 0x6b, 0x7c, 0x8c, 0x7f, 0xbb, 0xd8, 0x64, 0x4b, 0x7b, 0x05, 0x7e, 0x4a, - 0x25, 0xe9, 0xaa, 0x66, 0x73, 0xb6, 0x92, 0xc7, 0x82, 0xf2, 0x61, 0x17, - 0x59, 0x28, 0xf1, 0x6b, 0x15, 0x3b, 0xdd, 0xf8, 0xd9, 0x0f, 0xb7, 0xc5, - 0xa6, 0x25, 0x7d, 0x6e, 0xb0, 0xb0, 0xae, 0x9f, 0x85, 0xdf, 0x9d, 0x38, - 0x1c, 0x4b, 0xbb, 0x3d, 0xfe, 0x1e, 0x19, 0x3a, 0xaa, 0xe3, 0xe4, 0x1c, - 0xa6, 0xb6, 0x0c, 0x3e, 0xce, 0x63, 0x1c, 0x2c, 0x53, 0x83, 0xa8, 0xe1, - 0x91, 0x59, 0x88, 0xb3, 0xc6, 0x37, 0xb8, 0xb8, 0xc6, 0x08, 0x53, 0x56, - 0xf6, 0x64, 0x2c, 0xb6, 0xfa, 0x39, 0x63, 0x5b, 0x3d, 0xf8, 0xc1, 0x74, - 0xc6, 0xec, 0x43, 0x84, 0xc8, 0x7b, 0xfd, 0xbb, 0xec, 0xef, 0xe0, 0x85, - 0x90, 0x7c, 0x7f, 0x15, 0xcb, 0xa6, 0x15, 0x74, 0x6b, 0x67, 0x82, 0x9d, - 0xb3, 0x35, 0x0f, 0x7b, 0x01, 0xc4, 0xef, 0x42, 0x6c, 0x3c, 0xbd, 0xc4, - 0xb5, 0xe6, 0x85, 0x52, 0xed, 0x77, 0x9d, 0xe5, 0xf7, 0x48, 0xef, 0x60, - 0xb0, 0x8a, 0x37, 0xc7, 0xb1, 0xe7, 0xb9, 0xe7, 0xa3, 0xf8, 0x18, 0xeb, - 0xf7, 0x85, 0x4d, 0x98, 0x56, 0xb4, 0x6f, 0x1f, 0x59, 0xc7, 0x21, 0x85, - 0x34, 0xa7, 0x58, 0x9b, 0x56, 0x84, 0x14, 0x09, 0x72, 0x5a, 0x6b, 0xce, - 0x37, 0x43, 0x7d, 0xea, 0x49, 0x94, 0xf3, 0xf6, 0xbe, 0x5d, 0xd7, 0xf3, - 0xce, 0x53, 0xf0, 0x8b, 0x1b, 0x77, 0xd7, 0xef, 0x54, 0x4e, 0x54, 0x5b, - 0x16, 0x34, 0xec, 0x85, 0xaf, 0xdc, 0x43, 0x43, 0x93, 0x5d, 0xa0, 0x4f, - 0xb9, 0xa5, 0xd3, 0xaa, 0x52, 0xda, 0x4e, 0xb7, 0x3d, 0xa8, 0x46, 0xee, - 0x87, 0xb8, 0xf9, 0xdc, 0x31, 0xf0, 0xbe, 0xc6, 0x96, 0x5b, 0xea, 0x48, - 0x9f, 0xec, 0x34, 0x0f, 0x99, 0xbb, 0x17, 0x53, 0x08, 0x5f, 0xf8, 0x26, - 0x58, 0xbd, 0x79, 0x17, 0xf2, 0xd0, 0xab, 0x44, 0x98, 0x5d, 0x19, 0x3c, - 0x45, 0xed, 0x1f, 0x18, 0x4b, 0x79, 0x6c, 0x20, 0x40, 0x9a, 0xf1, 0xe7, - 0x8f, 0xb0, 0x50, 0x28, 0xdd, 0x5e, 0x56, 0xac, 0xe1, 0x69, 0xfb, 0x95, - 0x5e, 0xfc, 0x5c, 0xba, 0x62, 0xf4, 0x20, 0xf5, 0x63, 0x4b, 0xb2, 0xe0, - 0x28, 0x55, 0x47, 0xb2, 0x18, 0x64, 0x17, 0x01, 0x29, 0x69, 0xba, 0xcf, - 0xbe, 0x13, 0x38, 0xd1, 0x66, 0x42, 0xc5, 0x07, 0xb9, 0x39, 0x06, 0xa8, - 0x36, 0x53, 0x42, 0xb7, 0xae, 0xa2, 0xa2, 0x2a, 0x9c, 0xc8, 0x5f, 0x08, - 0x5d, 0x3a, 0x94, 0xb8, 0x23, 0x2a, 0xb7, 0xd0, 0xa4, 0x85, 0xf4, 0x68, - 0xeb, 0xa1, 0x58, 0x02, 0x86, 0x91, 0x50, 0x66, 0x89, 0xd9, 0x1e, 0x76, - 0x0c, 0xd8, 0xed, 0x6b, 0xba, 0x5d, 0xab, 0x54, 0x98, 0x0c, 0xac, 0x14, - 0x08, 0x1e, 0xda, 0xf0, 0x01, 0x9f, 0xfa, 0x07, 0x77, 0x27, 0x97, 0x80, - 0xbc, 0x5a, 0x9c, 0x5c, 0x68, 0xa8, 0xa8, 0xd5, 0x16, 0xa5, 0xd0, 0x91, - 0xe6, 0x7a, 0x94, 0x60, 0x35, 0x6f, 0x27, 0x14, 0x52, 0x96, 0xaa, 0xab, - 0xf1, 0x37, 0x67, 0x6b, 0x74, 0x96, 0xcb, 0x06, 0x6e, 0x82, 0x60, 0xe5, - 0xc5, 0xc2, 0x98, 0xe6, 0xf6, 0x63, 0xea, 0xa9, 0x84, 0x7c, 0xc0, 0x0a, - 0xcc, 0x41, 0x77, 0xef, 0xaf, 0x64, 0x72, 0x37, 0x70, 0x9d, 0xd3, 0x40, - 0x04, 0xa9, 0x04, 0xad, 0xc7, 0x8d, 0xd4, 0xd6, 0xb9, 0xfc, 0x94, 0x91, - 0x35, 0x1e, 0xe0, 0xee, 0x6e, 0xbc, 0xce, 0x38, 0x05, 0x99, 0x4b, 0x04, - 0xf3, 0xbb, 0x5a, 0xb9, 0x3d, 0x50, 0xfe, 0x93, 0x74, 0xc0, 0xf3, 0x79, - 0x78, 0x6c, 0x02, 0x93, 0x82, 0x34, 0xa3, 0xbe, 0x00, 0x4d, 0xa0, 0xb7, - 0x17, 0xd4, 0x2b, 0xb1, 0xc1, 0x02, 0xdb, 0x78, 0x47, 0x4e, 0x29, 0x51, - 0x61, 0xd0, 0xc2, 0xd4, 0x63, 0x31, 0x8a, 0x9d, 0x0b, 0xee, 0xf8, 0x52, - 0xe9, 0xc2, 0x9b, 0x83, 0xdf, 0x7a, 0x8d, 0xf7, 0x30, 0xba, 0x30, 0x8b, - 0xda, 0x21, 0xe8, 0x81, 0xac, 0xcf, 0xcb, 0x04, 0xec, 0x8d, 0x2e, 0x17, - 0xe6, 0x6b, 0x73, 0x2e, 0xd7, 0x8b, 0x0f, 0x64, 0x36, 0x25, 0x6d, 0x27, - 0x46, 0xc9, 0xdd, 0x5e, 0x4b, 0x93, 0x19, 0x50, 0x60, 0xcb, 0x01, 0xc2, - 0xac, 0x64, 0x50, 0x3b, 0x1e, 0xe8, 0x5a, 0x67, 0x86, 0x05, 0x75, 0x5f, - 0x04, 0x66, 0xd2, 0x60, 0x38, 0x92, 0x2b, 0xc8, 0x3a, 0x18, 0xd6, 0x46, - 0x8f, 0x20, 0xe1, 0x2f, 0x9f, 0x7c, 0x0b, 0x89, 0x01, 0xb8, 0xc2, 0xaa, - 0xd8, 0xed, 0xd1, 0x06, 0xaa, 0xe0, 0xad, 0x5d, 0xbe, 0x2f, 0xdc, 0xcb, - 0xdf, 0xfa, 0x34, 0xfb, 0x5a, 0xb0, 0x92, 0xcd, 0x62, 0xde, 0xfe, 0x24, - 0x19, 0xc4, 0xa4, 0x21, 0xff, 0x84, 0x01, 0x48, 0x5d, 0x9a, 0xff, 0x02, - 0xe9, 0x95, 0xf3, 0xf4, 0x90, 0x95, 0xdf, 0x81, 0x4e, 0xfe, 0x2e, 0xf8, - 0x20, 0xcb, 0xb5, 0x7f, 0xe4, 0x91, 0xb4, 0xf4, 0xf9, 0x8d, 0xdf, 0x0c, - 0xdd, 0xbc, 0x14, 0xd9, 0x23, 0xfd, 0xd0, 0xc4, 0xa1, 0x00, 0xa7, 0x45, - 0x42, 0x5d, 0x9d, 0x87, 0x69, 0x20, 0xc2, 0x32, 0x65, 0x7d, 0xc3, 0x5a, - 0x6c, 0x72, 0x78, 0x9f, 0xe5, 0x5f, 0x0d, 0x13, 0x53, 0x5a, 0x26, 0x50, - 0x2e, 0x98, 0x37, 0x90, 0xe2, 0x05, 0x7c, 0x60, 0xac, 0x71, 0x57, 0x64, - 0xb8, 0x67, 0xdb, 0x67, 0xff, 0x3d, 0xc7, 0x9e, 0xcb, 0x6d, 0x8a, 0xee, - 0xa9, 0xa5, 0x38, 0x02, 0x2b, 0xf2, 0xae, 0x10, 0xa8, 0x2d, 0x77, 0x67, - 0x5d, 0x79, 0xe1, 0x71, 0xe3, 0x4d, 0x06, 0xf8, 0x4d, 0x58, 0x77, 0x45, - 0x06, 0x7d, 0x38, 0x45, 0x8e, 0x55, 0x6a, 0xf6, 0xfd, 0x5a, 0xef, 0x69, - 0x6d, 0x6d, 0x16, 0xa5, 0xaf, 0x75, 0x77, 0xe7, 0x8c, 0x90, 0xe6, 0xfc, - 0xea, 0x1b, 0x07, 0x1f, 0xb5, 0x46, 0x63, 0xc3, 0x42, 0x8a, 0x6f, 0xba, - 0xfb, 0x3f, 0xc7, 0x8d, 0xfb, 0xbe, 0x0b, 0xf0, 0x2a, 0x7d, 0x69, 0xbc, - 0xed, 0x85, 0x79, 0x9e, 0xdf, 0x15, 0xe0, 0x4c, 0xef, 0xbf, 0xc0, 0x8c, - 0x89, 0xef, 0xd7, 0x0f, 0xc2, 0x04, 0x36, 0x33, 0x27, 0xf2, 0x29, 0x04, - 0xce, 0x19, 0x3a, 0x8a, 0x11, 0x18, 0x86, 0xcd, 0xce, 0x3e, 0x31, 0xa6, - 0x6f, 0x9c, 0x16, 0x8d, 0x32, 0xcd, 0x8f, 0x93, 0x4f, 0xff, 0x88, 0xfb, - 0xf9, 0x33, 0x7b, 0xcd, 0xcc, 0x57, 0x24, 0x79, 0xb7, 0x5d, 0x92, 0xe5, - 0x79, 0x61, 0xe7, 0x96, 0xab, 0x2a, 0xb5, 0xf7, 0x4a, 0x19, 0x9e, 0xc9, - 0x42, 0x2d, 0x4a, 0x8b, 0x59, 0xab, 0xce, 0xfc, 0xce, 0x49, 0xbd, 0x43, - 0x78, 0x70, 0x2b, 0x6c, 0xf3, 0x9d, 0x97, 0x8a, 0x85, 0x7d, 0xf7, 0x97, - 0x7a, 0xbf, 0x3d, 0x4c, 0x61, 0xef, 0xc3, 0x61, 0x63, 0x24, 0x22, 0xf3, - 0x12, 0xa5, 0x5f, 0x5e, 0x97, 0x97, 0x48, 0xe1, 0x26, 0xc1, 0x7d, 0x61, - 0x53, 0x69, 0x1d, 0x63, 0x7e, 0x23, 0x41, 0xf1, 0xdd, 0x64, 0xb5, 0xb8, - 0x60, 0x87, 0x89, 0x6b, 0x24, 0x65, 0xec, 0xac, 0x8c, 0x75, 0x00, 0x4b, - 0x8b, 0x7b, 0x45, 0x00, 0xad, 0xa6, 0x83, 0x1d, 0x19, 0x3c, 0xac, 0xba, - 0x30, 0x79, 0xf3, 0xb8, 0xf3, 0x71, 0x08, 0x10, 0x58, 0x02, 0x8a, 0xda, - 0xeb, 0xd7, 0xba, 0x3f, 0x49, 0x15, 0xb6, 0x37, 0xbe, 0xcf, 0xaf, 0x4a, - 0x13, 0x8a, 0xff, 0x35, 0xad, 0x50, 0x6c, 0x42, 0x0d, 0xaf, 0xb9, 0xd4, - 0x76, 0xac, 0xd6, 0xf8, 0x09, 0x53, 0xfb, 0x5a, 0x30, 0x95, 0xa5, 0xf3, - 0xb7, 0x82, 0x08, 0xea, 0xdb, 0xfc, 0x08, 0x30, 0x47, 0xf5, 0xe6, 0xc1, - 0x52, 0xc9, 0x6b, 0x77, 0x56, 0x09, 0xc2, 0x30, 0x08, 0x41, 0xd4, 0xf7, - 0xa9, 0x85, 0x78, 0xab, 0x76, 0xc4, 0xe8, 0xd8, 0x18, 0xeb, 0x2f, 0xff, - 0x72, 0x71, 0xc5, 0x58, 0x76, 0xec, 0x20, 0xe9, 0x0d, 0x4c, 0x7c, 0xd5, - 0xf2, 0x82, 0xc9, 0x29, 0xd1, 0x6f, 0x55, 0x25, 0xa1, 0xfd, 0x0c, 0x76, - 0xc7, 0xb8, 0x90, 0x7a, 0xbc, 0x38, 0xd8, 0xd7, 0xc2, 0x23, 0x65, 0xe6, - 0x68, 0xf5, 0xe9, 0x83, 0xff, 0x98, 0x13, 0xb1, 0x01, 0x8b, 0xce, 0x02, - 0x6b, 0x97, 0xe3, 0xf6, 0x26, 0xb0, 0x60, 0x53, 0xcc, 0x80, 0xb0, 0x3f, - 0xcb, 0x7c, 0x40, 0x27, 0xe8, 0x5f, 0x24, 0xb4, 0x6e, 0xba, 0x76, 0xf3, - 0x84, 0x80, 0xf0, 0x8d, 0x42, 0xdc, 0xe6, 0x99, 0xde, 0x66, 0x1f, 0x35, - 0xfd, 0xba, 0x31, 0x92, 0x17, 0x80, 0x79, 0x22, 0x5a, 0x72, 0xd6, 0x5c, - 0xc4, 0x2a, 0x7e, 0x50, 0x8f, 0x35, 0xc9, 0xf6, 0x87, 0x75, 0x56, 0xce, - 0x8c, 0xf9, 0x00, 0x28, 0x8f, 0x3b, 0x3b, 0x04, 0x35, 0x95, 0x10, 0xdb, - 0xf3, 0xfa, 0x4a, 0xa7, 0xd4, 0xee, 0x16, 0xc3, 0x99, 0x7f, 0x87, 0x13, - 0x07, 0xbe, 0xb6, 0x90, 0x97, 0xdf, 0x54, 0x06, 0xca, 0x24, 0xb5, 0xa4, - 0x98, 0xde, 0xab, 0x3a, 0x6d, 0x26, 0x7f, 0x1c, 0xdd, 0xd0, 0x9f, 0xfd, - 0xbb, 0xcb, 0x60, 0xb6, 0x1c, 0xb0, 0xd8, 0x91, 0x7e, 0x77, 0x3e, 0x96, - 0x3e, 0x32, 0x46, 0x26, 0x82, 0x77, 0x8e, 0x5d, 0x3a, 0xc5, 0xcf, 0x7b, - 0x72, 0x7c, 0x18, 0x4c, 0x56, 0x82, 0x77, 0x14, 0xff, 0xb4, 0x81, 0x74, - 0xcc, 0x4f, 0xa5, 0x38, 0xe5, 0x84, 0x35, 0x06, 0xf4, 0xa5, 0x6d, 0x65, - 0x2a, 0xba, 0xfa, 0xba, 0xd6, 0x70, 0x44, 0xac, 0x46, 0x5f, 0xe1, 0x86, - 0x54, 0xc8, 0x27, 0x3f, 0x4b, 0x4d, 0xd3, 0x1e, 0x6a, 0x03, 0xc6, 0x4f, - 0xfa, 0xa9, 0xb5, 0xad, 0x8a, 0xc0, 0xcb, 0xe8, 0x2b, 0x1b, 0x92, 0x88, - 0xeb, 0x77, 0xe9, 0xe2, 0xfb, 0xbd, 0x44, 0x8a, 0xc9, 0xc9, 0x2e, 0xeb, - 0xad, 0x2e, 0x02, 0x4b, 0xdf, 0xae, 0xc5, 0x79, 0xd8, 0x64, 0x7f, 0x4a, - 0x58, 0x2b, 0x7d, 0xd8, 0xb3, 0x4a, 0x75, 0x59, 0x45, 0x82, 0xfb, 0x2b, - 0x5b, 0x46, 0xb9, 0x2d, 0x26, 0x63, 0xbd, 0x18, 0xed, 0x71, 0xc1, 0x50, - 0x20, 0x1e, 0x36, 0x20, 0x06, 0x45, 0x24, 0x98, 0x99, 0x78, 0xfe, 0xda, - 0xa8, 0x58, 0xb3, 0x10, 0x71, 0xf5, 0xb3, 0x3c, 0x59, 0xca, 0x86, 0xca, - 0xc5, 0xf6, 0x79, 0xcf, 0x34, 0x4a, 0xd0, 0x55, 0xbf, 0xc7, 0xd9, 0x95, - 0xec, 0xfd, 0x1c, 0xd8, 0x68, 0x3a, 0xb2, 0x56, 0xb6, 0xc8, 0x3d, 0x47, - 0x88, 0xc1, 0x9b, 0x79, 0x68, 0x75, 0x0c, 0x1b, 0x8c, 0x30, 0xc7, 0xa3, - 0xf4, 0x4c, 0x0c, 0x56, 0xd4, 0xb0, 0xac, 0x7e, 0x73, 0x59, 0xc5, 0x77, - 0x1c, 0x68, 0x87, 0x4e, 0xfb, 0x96, 0x23, 0x33, 0x91, 0x51, 0xad, 0x2d, - 0xfe, 0xdc, 0xdf, 0xac, 0x0e, 0x52, 0x99, 0x1b, 0xb1, 0xdd, 0x71, 0x4f, - 0x14, 0xa1, 0x95, 0x8f, 0x41, 0x7d, 0x06, 0x82, 0x95, 0x5d, 0x55, 0x74, - 0xd2, 0x4c, 0x69, 0xb3, 0xed, 0xf2, 0xc7, 0x4a, 0x50, 0xed, 0x74, 0x09, - 0xdc, 0xc1, 0x77, 0xe1, 0x34, 0xce, 0x42, 0x2d, 0x28, 0xa9, 0x45, 0xd7, - 0x60, 0x0e, 0x64, 0x70, 0xe6, 0x67, 0x88, 0x5f, 0x4a, 0xb4, 0x59, 0xba, - 0x04, 0x7f, 0x16, 0x65, 0xcf, 0xb7, 0x78, 0x76, 0x44, 0xfb, 0x33, 0xe0, - 0xcf, 0xf9, 0x5b, 0x41, 0xe6, 0x90, 0x2e, 0xd2, 0xf6, 0x0e, 0x4f, 0x93, - 0xd5, 0xd0, 0xce, 0x3f, 0x32, 0x3f, 0x43, 0xab, 0x6f, 0x10, 0x0c, 0xe6, - 0x40, 0x5e, 0x96, 0x6c, 0xc3, 0x13, 0xad, 0xb9, 0xf9, 0xd0, 0xcd, 0x25, - 0x1c, 0xf8, 0x6d, 0x1b, 0x9c, 0x5d, 0x72, 0xdf, 0x16, 0x05, 0x5b, 0xa2, - 0x68, 0x93, 0xf0, 0x48, 0x49, 0x48, 0xfb, 0xec, 0xd8, 0xa7, 0x1e, 0x38, - 0xc7, 0xb5, 0x1f, 0xde, 0xf2, 0x73, 0x2a, 0x27, 0x2b, 0x05, 0xfe, 0xe1, - 0xce, 0xde, 0x4a, 0x14, 0xcf, 0x0b, 0x89, 0x4e, 0xd1, 0xac, 0x66, 0xe3, - 0xe4, 0x03, 0xfe, 0x48, 0x36, 0xe1, 0x65, 0xd2, 0xc2, 0x64, 0x52, 0x16, - 0x82, 0xbf, 0x63, 0x1a, 0xd5, 0x14, 0xff, 0x60, 0x43, 0xf0, 0xfc, 0xd0, - 0x05, 0x3b, 0xcb, 0x8b, 0xf8, 0x46, 0xb6, 0x78, 0x0a, 0x97, 0xae, 0xf3, - 0xa2, 0x3e, 0x7e, 0x0b, 0x83, 0x9e, 0xaf, 0x61, 0x0a, 0xba, 0xae, 0x0b, - 0xed, 0x23, 0xef, 0x04, 0xa9, 0xd2, 0x6e, 0x4d, 0x64, 0xc5, 0x6d, 0x55, - 0x64, 0x53, 0x9d, 0xb6, 0x0e, 0xe9, 0xe7, 0x25, 0xe1, 0x68, 0x32, 0x88, - 0x30, 0x57, 0xcd, 0x88, 0xfb, 0xbe, 0x49, 0x9c, 0xe3, 0xfa, 0xf3, 0x79, - 0x08, 0x11, 0x5d, 0xd8, 0xa2, 0x8d, 0xeb, 0x51, 0x28, 0xd3, 0xcc, 0xdf, - 0xe7, 0x51, 0xa0, 0xe6, 0xec, 0xf5, 0x49, 0xc6, 0xc6, 0x93, 0xcf, 0xd7, - 0x56, 0x53, 0x36, 0x6b, 0x1a, 0xea, 0x3c, 0x3e, 0xe7, 0x1d, 0x1e, 0x3d, - 0x40, 0xcd, 0x33, 0x14, 0xff, 0x1a, 0x92, 0x4c, 0xb4, 0x20, 0xdb, 0xb7, - 0x94, 0xa6, 0x92, 0x11, 0x39, 0x0a, 0x23, 0xdc, 0xa5, 0x77, 0x06, 0x09, - 0xfc, 0x97, 0xc0, 0xcb, 0xb0, 0xb1, 0x7f, 0x5c, 0x94, 0x66, 0xd2, 0x07, - 0x3c, 0x44, 0x75, 0xf9, 0xfb, 0x8b, 0x85, 0x01, 0x82, 0xdf, 0x5e, 0x2f, - 0xc0, 0xab, 0x21, 0xc0, 0xe7, 0xed, 0x40, 0x06, 0x39, 0x55, 0xe2, 0x55, - 0x15, 0x5f, 0x46, 0x4b, 0x32, 0x6a, 0xe9, 0x65, 0x00, 0x2b, 0x00, 0xe3, - 0x12, 0x66, 0xe0, 0x71, 0x1c, 0x61, 0x0a, 0x2c, 0x5a, 0xb9, 0x62, 0x63, - 0x10, 0x85, 0x21, 0x85, 0x5e, 0x76, 0x86, 0x25, 0x6b, 0x7f, 0x0f, 0x95, - 0x65, 0xaa, 0xda, 0x19, 0x18, 0xb1, 0xe2, 0x52, 0x3b, 0x65, 0xea, 0x2e, - 0x53, 0x7c, 0x09, 0x96, 0xad, 0x23, 0x30, 0x59, 0xe9, 0x81, 0xe3, 0x9e, - 0x56, 0x0b, 0x4d, 0x0b, 0xa6, 0xda, 0x21, 0x04, 0x0a, 0x1e, 0xa3, 0xf7, - 0x2b, 0x39, 0x9b, 0xa6, 0x06, 0xc6, 0x78, 0x1e, 0x06, 0x3e, 0x45, 0xd2, - 0xe8, 0x35, 0x07, 0x74, 0xaa, 0x69, 0xd2, 0x1f, 0xd0, 0x14, 0x75, 0x38, - 0x16, 0x95, 0xd5, 0xa0, 0xde, 0x40, 0x9c, 0xda, 0xbb, 0x8f, 0x6e, 0x1a, - 0x89, 0x78, 0xd6, 0x46, 0x12, 0x25, 0xfb, 0x7e, 0xee, 0xaf, 0x65, 0xef, - 0xf8, 0x54, 0x37, 0x17, 0x7c, 0x3d, 0xcf, 0xcf, 0x3f, 0x42, 0x00, 0x34, - 0x30, 0x48, 0x66, 0x00, 0x90, 0xea, 0xbb, 0xc8, 0x9e, 0xda, 0xfa, 0xbb, - 0xb4, 0xb7, 0x2a, 0xf6, 0x27, 0x81, 0xca, 0x08, 0x7f, 0x86, 0x05, 0xf4, - 0xc2, 0x19, 0x88, 0x7c, 0x83, 0x1d, 0x78, 0x00, 0x99, 0xc2, 0xb2, 0x16, - 0x20, 0x1e, 0x9e, 0x5a, 0x5e, 0x66, 0x03, 0xa7, 0xc3, 0x3a, 0xc6, 0x52, - 0xf0, 0xab, 0xf4, 0xee, 0x88, 0x7c, 0x59, 0xfa, 0x9a, 0x20, 0xa2, 0xb8, - 0xd9, 0x01, 0x1c, 0xcb, 0xf7, 0x8a, 0x1d, 0xb5, 0x22, 0x77, 0x3e, 0xcb, - 0x68, 0xdf, 0x63, 0xab, 0x0a, 0x53, 0x51, 0xb8, 0xe1, 0x38, 0xe1, 0x74, - 0x4b, 0x64, 0x5a, 0x47, 0x10, 0x14, 0xb8, 0xd8, 0x82, 0xa4, 0xf1, 0xbc, - 0x6d, 0xcb, 0x33, 0xff, 0x4e, 0xf9, 0xd5, 0x9c, 0x4e, 0x55, 0x73, 0xf2, - 0xac, 0x09, 0xb3, 0xbe, 0x32, 0xcf, 0x56, 0x55, 0xef, 0xb4, 0x3c, 0x3c, - 0x9f, 0xb1, 0xdd, 0x5e, 0x49, 0x58, 0xd3, 0x64, 0xce, 0xd0, 0x89, 0xe2, - 0x57, 0x42, 0x20, 0x68, 0x7e, 0x64, 0x29, 0x17, 0xfb, 0xde, 0x33, 0x77, - 0xc3, 0x4c, 0x25, 0xbb, 0x76, 0x93, 0x58, 0x4f, 0xb7, 0x16, 0x78, 0xce, - 0x0d, 0xb9, 0xa4, 0x38, 0xeb, 0x5c, 0x4b, 0xb6, 0x80, 0x28, 0x9a, 0xde, - 0xfe, 0xe7, 0x8b, 0xcc, 0x41, 0xe2, 0x08, 0x8b, 0xee, 0xdf, 0xeb, 0x8d, - 0xfb, 0xbb, 0xa2, 0xf6, 0xbe, 0x47, 0x10, 0x37, 0xe9, 0x6e, 0xf4, 0x67, - 0x0c, 0x0f, 0x69, 0xe3, 0xf8, 0xc8, 0x11, 0x11, 0x41, 0xe0, 0xf2, 0xba, - 0x87, 0x24, 0x9c, 0xbe, 0x2b, 0xc1, 0x63, 0x76, 0x32, 0x35, 0x0c, 0x76, - 0x68, 0xec, 0x0b, 0x6c, 0x0a, 0x4b, 0x25, 0x87, 0xc1, 0x4a, 0x9c, 0x83, - 0xe5, 0x83, 0x6f, 0xc2, 0xa1, 0xaf, 0xc0, 0x18, 0x69, 0xf7, 0xf2, 0x8a, - 0x5e, 0x25, 0x20, 0xd6, 0x7e, 0x52, 0x90, 0x05, 0x9e, 0x8b, 0x99, 0x5b, - 0x8e, 0x5d, 0x4b, 0x87, 0xff, 0xa9, 0xa6, 0xfd, 0xe5, 0xd4, 0x78, 0xed, - 0x03, 0x17, 0xe3, 0x13, 0xe7, 0xd6, 0xdf, 0x24, 0x9d, 0xc9, 0x57, 0x01, - 0xcc, 0x25, 0xc0, 0xbc, 0x53, 0x88, 0x0d, 0x02, 0xbd, 0xd0, 0x37, 0x0c, - 0xa4, 0x23, 0xbb, 0xea, 0xef, 0x6a, 0x33, 0xb7, 0x16, 0x98, 0x90, 0x21, - 0x59, 0x47, 0x7f, 0x9a, 0xb2, 0x0d, 0x7c, 0xda, 0xf8, 0xd2, 0x2d, 0xdc, - 0x7d, 0xdf, 0xa7, 0x1a, 0x85, 0xbf, 0x63, 0xb8, 0x0d, 0x8a, 0x2e, 0x46, - 0x2e, 0x60, 0xcf, 0x19, 0x51, 0x05, 0x09, 0x0e, 0x1b, 0xb6, 0x92, 0xb1, - 0xfa, 0xeb, 0x74, 0xdc, 0x2d, 0x42, 0x6f, 0x0a, 0xe7, 0x28, 0xe1, 0x39, - 0x61, 0x41, 0xde, 0xb3, 0x78, 0x4f, 0x97, 0x88, 0x53, 0xf3, 0x65, 0x99, - 0xbe, 0x00, 0xce, 0x0f, 0xe9, 0x5f, 0xdf, 0x29, 0x67, 0xae, 0xf2, 0x76, - 0x4c, 0xcd, 0x90, 0x1c, 0xb2, 0x7f, 0x84, 0x16, 0x4a, 0x60, 0x62, 0xf6, - 0x7e, 0xdb, 0x4c, 0x9a, 0x6f, 0xc4, 0x1a, 0x9a, 0xa8, 0xaa, 0xe9, 0xee, - 0x85, 0xc3, 0xcd, 0x1a, 0x00, 0x99, 0x51, 0x3e, 0x50, 0x98, 0xcd, 0x43, - 0x64, 0x16, 0xae, 0xc3, 0xb4, 0x56, 0x7c, 0xf6, 0xaf, 0xc1, 0x53, 0x82, - 0x29, 0x5f, 0xa5, 0x7b, 0x16, 0xe5, 0xa9, 0x41, 0x1c, 0xc3, 0x32, 0xaf, - 0x49, 0x29, 0x44, 0x6c, 0x72, 0xda, 0xa9, 0xb0, 0x0e, 0xe7, 0x44, 0x6b, - 0x18, 0xf2, 0xa5, 0xa5, 0x08, 0x72, 0x73, 0xbd, 0x03, 0xa1, 0x8d, 0xb6, - 0x12, 0x6a, 0x32, 0x2b, 0xb4, 0xf4, 0xcf, 0xa8, 0x8d, 0x51, 0xe0, 0x59, - 0xa6, 0x44, 0x62, 0x2b, 0x6f, 0x6c, 0x3d, 0xe5, 0x04, 0xc2, 0x61, 0x90, - 0xc4, 0x88, 0x14, 0x81, 0x67, 0x42, 0x45, 0xe1, 0x10, 0x5b, 0x91, 0xe6, - 0x8a, 0x29, 0xdf, 0x15, 0x7c, 0x62, 0xa9, 0x28, 0xd5, 0x9a, 0x32, 0x3a, - 0x27, 0x44, 0xac, 0x5f, 0x86, 0xac, 0x2f, 0x5d, 0x08, 0x74, 0x9c, 0xa0, - 0x3f, 0x9f, 0xfe, 0x14, 0xdd, 0x4a, 0x98, 0xfd, 0xd2, 0x31, 0xd7, 0xaf, - 0x56, 0xbb, 0x95, 0x63, 0xb7, 0xf7, 0xe4, 0x77, 0x6f, 0x11, 0xab, 0xa2, - 0xb7, 0xb4, 0xf3, 0x18, 0x6f, 0xdf, 0x1a, 0xd6, 0xca, 0x6b, 0x0c, 0xe2, - 0x4d, 0x0e, 0xc3, 0x79, 0xd0, 0xa6, 0xd0, 0x83, 0x6f, 0x9e, 0x5d, 0xd6, - 0xd8, 0xfc, 0x2d, 0xc1, 0x24, 0xf4, 0xd0, 0x6f, 0x45, 0xa3, 0xed, 0x5b, - 0x5d, 0x2c, 0x53, 0x8d, 0xae, 0xb6, 0x7d, 0x43, 0x73, 0x86, 0x88, 0x4c, - 0xda, 0xd1, 0x17, 0xa2, 0x46, 0x13, 0xee, 0xad, 0xb2, 0x2f, 0x01, 0x7d, - 0x8a, 0x17, 0xf2, 0x50, 0xef, 0x8c, 0x2e, 0x0a, 0x20, 0x9c, 0xa1, 0xef, - 0x3b, 0x79, 0x30, 0x99, 0xc2, 0x55, 0xc2, 0x9b, 0x2c, 0xa3, 0x94, 0x50, - 0xdd, 0x36, 0xaf, 0x6d, 0xbf, 0x6f, 0xd1, 0xa9, 0x1a, 0x21, 0x82, 0x53, - 0xc4, 0x45, 0xd8, 0xdb, 0xf2, 0x0e, 0x37, 0x56, 0x29, 0xff, 0x5b, 0xc6, - 0x9c, 0xe7, 0x8a, 0x8e, 0xac, 0xee, 0x7b, 0xe3, 0x0b, 0xac, 0x3d, 0xff, - 0xd4, 0xc9, 0xd4, 0x1d, 0xc8, 0x6a, 0x23, 0x09, 0x7a, 0xb4, 0x44, 0x8f, - 0x50, 0x5e, 0x48, 0x3f, 0x5d, 0xbd, 0x7b, 0xcf, 0x1d, 0x4d, 0x82, 0x6e, - 0x04, 0x75, 0xc6, 0x2b, 0x3f, 0x79, 0xe9, 0xdc, 0x45, 0x98, 0x1a, 0x47, - 0xdb, 0xe0, 0x71, 0xcb, 0x49, 0x83, 0xad, 0x57, 0x09, 0x83, 0x89, 0xc4, - 0x8b, 0x59, 0x7e, 0x7c, 0x33, 0x21, 0x34, 0x4f, 0xc3, 0x24, 0x1d, 0xc8, - 0x5e, 0x07, 0xf5, 0x45, 0xdb, 0xe7, 0xdd, 0x76, 0x3b, 0xdb, 0x74, 0xc4, - 0x3c, 0x37, 0x3d, 0xbe, 0xf5, 0xd4, 0xad, 0x61, 0x09, 0x59, 0xbe, 0x32, - 0x00, 0x29, 0x76, 0x52, 0x09, 0xca, 0xd4, 0x71, 0x6a, 0xfb, 0xfe, 0x0e, - 0xda, 0xdd, 0xfa, 0x2d, 0xf2, 0xbe, 0xf9, 0xab, 0x8a, 0x70, 0x63, 0xd0, - 0xb4, 0x8a, 0x71, 0x85, 0x1a, 0xaf, 0x95, 0xd2, 0xf5, 0x03, 0xb1, 0x8b, - 0x76, 0x65, 0x56, 0x39, 0xaf, 0x75, 0xa1, 0x71, 0xee, 0x54, 0xd5, 0xd5, - 0x5d, 0x64, 0xfb, 0x0a, 0x3f, 0x69, 0x8e, 0xef, 0x75, 0xac, 0x07, 0x17, - 0x18, 0xe6, 0x77, 0xca, 0xa6, 0x20, 0xd8, 0xe3, 0x79, 0x3e, 0xd4, 0xd0, - 0x07, 0x0c, 0x94, 0xcf, 0xe2, 0xcd, 0xf1, 0x37, 0x3d, 0x0c, 0x0b, 0xa5, - 0xdf, 0xb2, 0xcc, 0xdf, 0x18, 0xda, 0xdf, 0xbc, 0x85, 0xf8, 0xbb, 0x05, - 0xf8, 0x14, 0x68, 0x55, 0xf9, 0x36, 0xfa, 0x9d, 0xb6, 0xa9, 0xb4, 0x63, - 0x63, 0xdf, 0x52, 0x5b, 0xc1, 0x17, 0xe8, 0x28, 0x5b, 0x5d, 0x97, 0x96, - 0xf4, 0x17, 0x04, 0x55, 0x6f, 0xa7, 0x56, 0x03, 0x86, 0x95, 0x08, 0xee, - 0xd2, 0x00, 0x60, 0xf5, 0x02, 0xd7, 0x93, 0x7c, 0x20, 0xab, 0xc2, 0xfa, - 0x69, 0x05, 0x85, 0x81, 0x57, 0x75, 0xdb, 0xa1, 0xa2, 0xa5, 0xfd, 0x7e, - 0xe1, 0xc4, 0xbe, 0x16, 0x8d, 0x00, 0xad, 0x2e, 0xf0, 0xb5, 0xa8, 0x44, - 0xeb, 0x0f, 0x8b, 0x0c, 0x46, 0x92, 0xb0, 0xd2, 0x4d, 0xd1, 0x30, 0x1f, - 0xec, 0xe2, 0xcb, 0x8e, 0x06, 0xa3, 0x83, 0xcb, 0xa5, 0x9f, 0x0e, 0x8e, - 0x4f, 0x52, 0x60, 0x1a, 0xb5, 0x32, 0x20, 0x63, 0xd8, 0x45, 0xb2, 0x8a, - 0xb7, 0xc0, 0xdc, 0x0d, 0x6f, 0x1f, 0xf9, 0xa5, 0x61, 0x28, 0x2d, 0x8f, - 0xb3, 0x37, 0x1c, 0x1b, 0xd2, 0x2d, 0xb6, 0xf6, 0xca, 0xd1, 0x6a, 0x9d, - 0x62, 0x2d, 0xb8, 0x89, 0xb9, 0x2f, 0xca, 0x98, 0x4b, 0x8c, 0x69, 0x43, - 0x8a, 0x68, 0x2c, 0xf5, 0xff, 0x61, 0xe0, 0x71, 0x13, 0x15, 0x12, 0x25, - 0xf2, 0x28, 0xd0, 0x07, 0x6d, 0x2b, 0xd6, 0x3a, 0x12, 0x71, 0x13, 0x70, - 0x71, 0xbe, 0x2f, 0x02, 0x9c, 0x89, 0x8b, 0x6d, 0xe1, 0xcf, 0x44, 0x23, - 0x1a, 0x0c, 0xd5, 0x8e, 0x59, 0x4c, 0xe3, 0x38, 0xff, 0xa5, 0x2c, 0xb2, - 0x13, 0x51, 0x4a, 0xc3, 0x60, 0x75, 0x07, 0x13, 0x34, 0xbf, 0x49, 0xd1, - 0xd4, 0xeb, 0x17, 0xf6, 0x20, 0xa1, 0x2c, 0xbf, 0xc2, 0x0b, 0x32, 0xb8, - 0xc0, 0x98, 0xed, 0x5a, 0xa2, 0x29, 0x11, 0xb8, 0x9c, 0xa2, 0xc8, 0xef, - 0xcc, 0x0b, 0xa4, 0xc3, 0x4a, 0x8d, 0xac, 0x7b, 0xfb, 0xe9, 0x0d, 0x59, - 0xa5, 0xf3, 0x08, 0xee, 0x39, 0x00, 0x1d, 0x57, 0x36, 0xc3, 0xd4, 0x98, - 0xbc, 0x91, 0xea, 0x7a, 0x81, 0x6d, 0x35, 0x3d, 0x9f, 0x11, 0xd2, 0x1b, - 0xdf, 0x0d, 0x50, 0x7e, 0xf0, 0xf3, 0xb7, 0xe2, 0x22, 0x66, 0xc5, 0xe3, - 0xde, 0x58, 0x3f, 0x11, 0x61, 0x76, 0x63, 0xfc, 0x39, 0xb1, 0xee, 0x20, - 0x67, 0x97, 0x9f, 0x94, 0x0c, 0xa0, 0x45, 0xe1, 0x7e, 0x38, 0x18, 0x10, - 0xf2, 0x46, 0x15, 0x8e, 0x2b, 0xab, 0x00, 0x65, 0x11, 0xca, 0x48, 0xbb, - 0x09, 0xfa, 0x4c, 0xe2, 0x76, 0xad, 0xfc, 0x70, 0x04, 0xe4, 0x5f, 0x03, - 0xeb, 0x80, 0x77, 0x67, 0x37, 0x18, 0xda, 0x06, 0x1b, 0xe3, 0x0f, 0x45, - 0xeb, 0xfb, 0x08, 0x09, 0xa3, 0x29, 0x4b, 0x72, 0x66, 0x8f, 0x4e, 0xc6, - 0x88, 0x56, 0xcc, 0x71, 0xe7, 0x53, 0x63, 0xb5, 0x9e, 0x8a, 0x74, 0xd8, - 0xfe, 0x70, 0xbc, 0x39, 0x19, 0x19, 0x49, 0x4e, 0xc3, 0x80, 0xe9, 0x63, - 0x8e, 0x8c, 0xeb, 0x68, 0x6a, 0xcb, 0x22, 0xda, 0x47, 0x1a, 0xf3, 0xfc, - 0xca, 0x5e, 0x7e, 0x16, 0x7e, 0x62, 0x1f, 0x4c, 0x2b, 0x99, 0x81, 0xba, - 0x92, 0x2e, 0x8e, 0xe8, 0xef, 0xe2, 0x6f, 0x25, 0xe4, 0xd1, 0x58, 0x67, - 0xba, 0x94, 0x1e, 0xba, 0xa8, 0xa3, 0x41, 0xc9, 0x2d, 0xbe, 0xfe, 0xd4, - 0xb5, 0x2e, 0x11, 0xc8, 0xfc, 0xa3, 0x7e, 0x3d, 0x61, 0x72, 0x65, 0xb2, - 0x01, 0xad, 0xfb, 0xfc, 0xfd, 0x29, 0x48, 0xfb, 0x76, 0xd9, 0x14, 0xd7, - 0x2d, 0xf3, 0x21, 0xca, 0xab, 0x82, 0xb8, 0x65, 0xbf, 0xe9, 0x14, 0x8a, - 0xd3, 0xbe, 0x42, 0xc7, 0x62, 0xf6, 0x84, 0xd0, 0xc4, 0x00, 0x54, 0xb6, - 0x1b, 0xc4, 0x87, 0x91, 0x26, 0x8d, 0x1a, 0x9e, 0xc6, 0x38, 0x69, 0xb9, - 0xe2, 0x64, 0xfe, 0x3e, 0x12, 0x20, 0xce, 0xbe, 0x30, 0xf9, 0x06, 0xb5, - 0xd6, 0x05, 0x9a, 0x0d, 0xfd, 0x78, 0x4e, 0xd4, 0xf1, 0x7e, 0xbb, 0x2f, - 0x40, 0x20, 0xb1, 0x5e, 0xb2, 0xc0, 0x20, 0xd9, 0xe7, 0x87, 0xb4, 0xdf, - 0x93, 0x53, 0x90, 0xfc, 0x53, 0xc3, 0x5b, 0x3a, 0xb2, 0x72, 0xb1, 0xe1, - 0xf6, 0x9d, 0x9f, 0x2c, 0x1c, 0xba, 0x05, 0xf3, 0xcd, 0x22, 0x6b, 0xf7, - 0x06, 0x35, 0xdb, 0x17, 0xe7, 0xa0, 0x1b, 0xa6, 0x01, 0x4b, 0xca, 0x8c, - 0xcd, 0xaf, 0xd1, 0xfd, 0xfc, 0x7a, 0xe5, 0x5d, 0x1d, 0xcf, 0x88, 0x61, - 0x90, 0x74, 0x71, 0x42, 0xc6, 0x5b, 0x19, 0xa9, 0x3c, 0x5a, 0x10, 0xc3, - 0x47, 0xdb, 0xbe, 0xea, 0x91, 0x2c, 0x08, 0x98, 0x65, 0x7a, 0x8a, 0xc4, - 0xbe, 0xbf, 0x02, 0xd0, 0x4e, 0x0e, 0xaa, 0x1f, 0xb0, 0x92, 0x28, 0xe9, - 0xce, 0x2c, 0x50, 0x4d, 0xa5, 0xbc, 0x30, 0xa6, 0xc4, 0xba, 0xb4, 0x2d, - 0x7b, 0x8f, 0x5d, 0x53, 0x3b, 0x21, 0xb7, 0x0b, 0x75, 0x4a, 0x23, 0x73, - 0xc4, 0x7d, 0x3b, 0x5f, 0xdf, 0x3c, 0xe9, 0x2d, 0x81, 0x32, 0xe3, 0x1d, - 0x59, 0xcb, 0xd7, 0x2e, 0xfb, 0x0a, 0x61, 0x03, 0xca, 0x10, 0xf8, 0xf2, - 0x8b, 0xf2, 0x46, 0xb9, 0x40, 0x1f, 0x38, 0xad, 0xfe, 0x78, 0x00, 0xf1, - 0xb2, 0x77, 0x0c, 0x22, 0xe6, 0xcc, 0x8a, 0xf8, 0x89, 0x0c, 0xd4, 0x6d, - 0xd1, 0x82, 0x25, 0xca, 0x5b, 0xf1, 0x8f, 0x11, 0x3d, 0xdc, 0x7e, 0xfe, - 0x3c, 0x6a, 0x65, 0x37, 0xc7, 0x06, 0x96, 0x65, 0xb3, 0x0a, 0x57, 0x78, - 0x65, 0xc1, 0x65, 0x75, 0xfe, 0xb7, 0xd6, 0xd8, 0xf5, 0x3c, 0x0b, 0x8b, - 0xec, 0x47, 0x0a, 0xb0, 0x0b, 0x1b, 0x26, 0x4b, 0xe0, 0xc3, 0xd8, 0x44, - 0x51, 0xef, 0x9b, 0xb7, 0xe1, 0x79, 0xb6, 0x74, 0xd3, 0x78, 0x29, 0x45, - 0xb5, 0xe1, 0xca, 0xa7, 0x01, 0xea, 0x90, 0x36, 0xd6, 0x8c, 0x38, 0xec, - 0x59, 0xac, 0x03, 0x27, 0xf1, 0xe8, 0x43, 0xb5, 0xdf, 0x52, 0xbe, 0x84, - 0xef, 0x22, 0xb3, 0xb9, 0x45, 0xaf, 0xe7, 0x33, 0x9e, 0x08, 0x5d, 0xbe, - 0x19, 0xe0, 0xb6, 0xce, 0x87, 0xad, 0x7f, 0x38, 0xac, 0x23, 0x26, 0x15, - 0x73, 0x28, 0x56, 0x2c, 0x21, 0xee, 0x03, 0xb5, 0x0f, 0x9c, 0x60, 0x2f, - 0xf9, 0x1d, 0x77, 0xad, 0xd1, 0x05, 0x30, 0x91, 0x68, 0x7d, 0x04, 0x34, - 0xf2, 0xef, 0xe8, 0x82, 0xec, 0x6f, 0x12, 0xe6, 0x33, 0x17, 0x07, 0xfa, - 0x6a, 0xb6, 0x56, 0x79, 0xf0, 0xc3, 0x9c, 0xc7, 0xbd, 0x82, 0x48, 0xbb, - 0x4d, 0x1d, 0x53, 0x36, 0xc4, 0x9b, 0xc9, 0x45, 0xa9, 0x53, 0x6d, 0xd2, - 0x6e, 0x4a, 0x2a, 0x5a, 0x3b, 0x9a, 0xcb, 0x16, 0x12, 0x71, 0xe3, 0xd8, - 0x89, 0x16, 0x66, 0x00, 0x79, 0x1c, 0x57, 0x96, 0xc9, 0x97, 0x0b, 0x5f, - 0x40, 0x36, 0xd3, 0xec, 0x47, 0x67, 0xa7, 0xe7, 0x30, 0x94, 0xeb, 0xfb, - 0xfb, 0x4e, 0x1e, 0x9a, 0xee, 0x5d, 0xb4, 0xf0, 0x91, 0xd1, 0xca, 0xb5, - 0xf2, 0x0a, 0xcf, 0xa8, 0xea, 0x59, 0x5a, 0xf4, 0x92, 0x27, 0x8e, 0x71, - 0x47, 0x7f, 0xb6, 0x77, 0xd6, 0x62, 0xc4, 0x21, 0xe0, 0x0f, 0xdb, 0x88, - 0x03, 0x73, 0xf3, 0x65, 0x9f, 0x7a, 0x7c, 0x83, 0x56, 0xa3, 0x73, 0x42, - 0x18, 0x03, 0xcd, 0x83, 0x74, 0xbe, 0x14, 0x73, 0x41, 0x61, 0x58, 0x54, - 0xf9, 0xd2, 0x73, 0xbc, 0x19, 0x65, 0x09, 0x33, 0x81, 0x58, 0x1e, 0x81, - 0x58, 0xda, 0x23, 0x41, 0x14, 0xe8, 0xe0, 0x0d, 0x68, 0x62, 0x9a, 0xe8, - 0xc1, 0xc1, 0xa9, 0x03, 0xc2, 0xb3, 0x32, 0x76, 0x94, 0x4b, 0x56, 0x18, - 0x88, 0x9a, 0xfb, 0xee, 0x12, 0x5b, 0x7e, 0x20, 0xf7, 0x2c, 0xd1, 0xd1, - 0x53, 0xb5, 0xba, 0xad, 0x8e, 0x51, 0x39, 0x44, 0xfe, 0xd3, 0x39, 0x88, - 0x7f, 0xbf, 0xf8, 0x7e, 0xd1, 0x81, 0x46, 0x4f, 0x82, 0x01, 0xf7, 0x3b, - 0xff, 0xf4, 0x4d, 0xad, 0x0a, 0xdc, 0x4a, 0xfe, 0xf0, 0x21, 0x15, 0xaa, - 0xe6, 0xe2, 0x5f, 0x58, 0xe4, 0xa0, 0xde, 0x75, 0xde, 0xdf, 0xdc, 0x91, - 0x8a, 0x91, 0x9e, 0xae, 0xec, 0x1c, 0x86, 0x6f, 0xe2, 0x7f, 0xd5, 0x7e, - 0x7f, 0x4e, 0x9c, 0x59, 0x2c, 0x69, 0x17, 0x46, 0x81, 0x44, 0x59, 0xb7, - 0xf8, 0x3b, 0xc6, 0x7d, 0xd9, 0x6a, 0x98, 0xcc, 0x1c, 0xb8, 0xba, 0x8b, - 0x8c, 0xb6, 0x81, 0xa9, 0x30, 0x82, 0xa5, 0xd6, 0x30, 0x1a, 0xae, 0x44, - 0x11, 0x2e, 0x5c, 0xf8, 0x18, 0xb3, 0xb0, 0x5c, 0xec, 0xe7, 0x17, 0x49, - 0x71, 0xac, 0x33, 0x3d, 0xe3, 0x13, 0xc6, 0x95, 0xbb, 0x02, 0x32, 0x5e, - 0xe9, 0xc6, 0x93, 0x56, 0xb4, 0xbc, 0x7c, 0x28, 0x0f, 0x39, 0x24, 0x5b, - 0x02, 0xd1, 0x05, 0xf0, 0xe6, 0x57, 0x08, 0xe7, 0xbf, 0xeb, 0x0d, 0x88, - 0x2c, 0x11, 0x41, 0xac, 0xaa, 0xcb, 0x65, 0x5e, 0x16, 0x90, 0x4c, 0xc1, - 0xa8, 0xcf, 0xce, 0x1e, 0x75, 0x67, 0xcb, 0x57, 0x5c, 0xe6, 0x36, 0x8f, - 0xbd, 0x66, 0x2b, 0x4d, 0xcb, 0x77, 0x76, 0x9f, 0x20, 0x9d, 0x2c, 0x20, - 0xdd, 0x8c, 0xd3, 0xe0, 0xc7, 0x77, 0xc9, 0x9a, 0xd1, 0xd1, 0x73, 0x05, - 0xd2, 0x73, 0x8d, 0xee, 0xd4, 0x99, 0xe7, 0xe8, 0x55, 0x08, 0x09, 0x6c, - 0xc1, 0x6b, 0x9f, 0x22, 0x38, 0xdc, 0x8b, 0xe9, 0x68, 0x92, 0x2c, 0x2b, - 0x9c, 0xbb, 0x12, 0x38, 0x49, 0x67, 0xde, 0xca, 0x3b, 0xd6, 0x4e, 0x82, - 0xe3, 0xea, 0x83, 0x6f, 0x7b, 0x96, 0x99, 0x0f, 0xc4, 0x04, 0xb9, 0x37, - 0xdb, 0x1a, 0x6e, 0x5f, 0xe5, 0x68, 0x16, 0x96, 0x3f, 0xf6, 0xe5, 0xbe, - 0xa6, 0xa7, 0x8a, 0x89, 0x73, 0xee, 0x70, 0x58, 0xf5, 0x56, 0x23, 0x09, - 0x9e, 0x2d, 0x34, 0xa8, 0x34, 0x9a, 0xb0, 0x89, 0xd5, 0x08, 0x53, 0x84, - 0x11, 0x1d, 0x93, 0xee, 0x65, 0x21, 0xa7, 0x3b, 0x7c, 0xc2, 0x63, 0xa4, - 0xb6, 0xbc, 0x3c, 0xd8, 0x63, 0x29, 0xa9, 0xa2, 0x2d, 0x68, 0x51, 0xb7, - 0xf4, 0x8f, 0xf9, 0x11, 0xdf, 0x72, 0xe3, 0x46, 0xa8, 0x9d, 0x96, 0xb3, - 0xb5, 0xcd, 0xef, 0xd8, 0x9c, 0xb3, 0xca, 0x24, 0xc2, 0x31, 0xcf, 0x9e, - 0x5c, 0x7d, 0xe2, 0x08, 0x79, 0x5c, 0xce, 0x54, 0x01, 0x95, 0xaf, 0x2f, - 0x67, 0x9e, 0x77, 0x56, 0x4f, 0xcc, 0x30, 0xff, 0x11, 0xec, 0x10, 0x44, - 0xa3, 0x9e, 0xf3, 0x84, 0xa3, 0x0a, 0x80, 0xff, 0xfb, 0x6a, 0xa3, 0xc9, - 0xf0, 0xe0, 0x57, 0x43, 0x63, 0xbc, 0xf6, 0x00, 0x52, 0x4b, 0x5b, 0xf7, - 0xcb, 0xf8, 0x7c, 0x7e, 0x02, 0x7f, 0x77, 0x8e, 0xde, 0xc4, 0x73, 0x2f, - 0x8f, 0x34, 0x2c, 0x38, 0x8d, 0xa9, 0xb9, 0xe8, 0x23, 0xa6, 0x19, 0x4a, - 0xcf, 0x58, 0x8b, 0x0a, 0xae, 0x4a, 0x99, 0x76, 0x9e, 0x18, 0x58, 0x8a, - 0xcd, 0xdc, 0x00, 0x83, 0x69, 0x98, 0xa8, 0x4b, 0x0e, 0x3f, 0xa1, 0x1a, - 0xbb, 0x73, 0xbe, 0xfd, 0xb3, 0x6f, 0x53, 0x13, 0xd1, 0xcc, 0x9b, 0x9d, - 0x07, 0x61, 0x37, 0xad, 0xe1, 0x8e, 0xf8, 0xa4, 0xf5, 0x50, 0xff, 0x31, - 0x62, 0xcc, 0x5b, 0x31, 0xae, 0x0a, 0x28, 0xe2, 0x8e, 0x6d, 0x9c, 0x5a, - 0xf0, 0xb3, 0x83, 0x16, 0x3f, 0xd5, 0x88, 0x99, 0x0e, 0x66, 0x67, 0xcc, - 0x8e, 0x91, 0x14, 0x7c, 0x1a, 0xc6, 0x7f, 0xa8, 0xb9, 0x85, 0xa2, 0x38, - 0x72, 0x24, 0xd2, 0x39, 0xc2, 0xb3, 0xbe, 0x11, 0xef, 0xeb, 0x5e, 0x3d, - 0x72, 0x12, 0xd6, 0xe1, 0xa2, 0x45, 0x29, 0x8b, 0x3a, 0x9a, 0x69, 0x4e, - 0xbd, 0x0e, 0x9e, 0xbe, 0x64, 0x08, 0xa2, 0xc4, 0x97, 0x54, 0x76, 0xeb, - 0x06, 0x70, 0xb5, 0x41, 0x26, 0x11, 0x97, 0xf5, 0xac, 0xb7, 0xe3, 0xbd, - 0xca, 0x47, 0x28, 0x8d, 0x59, 0x0c, 0xc7, 0xfd, 0xe2, 0x2d, 0xf3, 0xb1, - 0x8e, 0x9a, 0x99, 0xad, 0xf9, 0xf1, 0xab, 0xf3, 0x4a, 0xba, 0x26, 0x1e, - 0xf9, 0xf9, 0xc9, 0x07, 0xbc, 0x61, 0x47, 0xfe, 0x1d, 0x6a, 0x96, 0x24, - 0x1c, 0x19, 0x23, 0xbb, 0xa0, 0x9a, 0xb3, 0x86, 0xb1, 0xe5, 0xdd, 0x0c, - 0x4f, 0xa8, 0xe0, 0x8c, 0x6e, 0xff, 0x55, 0xc8, 0xa6, 0x00, 0x0a, 0x85, - 0xf0, 0x93, 0xeb, 0xa8, 0x6a, 0x28, 0x5a, 0x04, 0x47, 0xb1, 0x96, 0x99, - 0x02, 0xde, 0x4f, 0xf5, 0xd2, 0x9e, 0x0d, 0x6a, 0xa0, 0x06, 0x1a, 0xac, - 0x56, 0xc5, 0x73, 0xbd, 0x94, 0xd2, 0xe3, 0xa3, 0x18, 0x6b, 0x3a, 0xec, - 0x74, 0x9c, 0xcd, 0x75, 0x31, 0x9a, 0x24, 0x04, 0xf5, 0xd5, 0x80, 0x59, - 0xe5, 0xc7, 0x74, 0xd2, 0x45, 0x5c, 0x90, 0xa1, 0xd4, 0x54, 0x29, 0x20, - 0xc9, 0x94, 0x84, 0xc0, 0x5e, 0x89, 0x02, 0x60, 0x2d, 0x42, 0x85, 0x10, - 0x62, 0xf4, 0xcf, 0x97, 0xc4, 0x13, 0xe8, 0xc9, 0xdb, 0xfb, 0xfb, 0x4d, - 0x21, 0xe7, 0x6a, 0x3e, 0xc6, 0x2d, 0x49, 0xd8, 0x55, 0x93, 0x8c, 0x66, - 0xa0, 0x4f, 0xf3, 0xe1, 0xed, 0x30, 0xb4, 0x43, 0x82, 0x8e, 0x32, 0xd4, - 0xd1, 0xd4, 0xb7, 0xa2, 0x9e, 0x02, 0x3a, 0xc1, 0x1c, 0x43, 0x7f, 0xb0, - 0x37, 0x32, 0x5f, 0xec, 0x52, 0x97, 0x9b, 0x8b, 0x4d, 0xc0, 0xe7, 0x3e, - 0x12, 0xfa, 0x11, 0xf7, 0x78, 0xb3, 0x85, 0xcc, 0x77, 0x56, 0xd0, 0x89, - 0xf0, 0xa5, 0x62, 0x48, 0xd2, 0xd7, 0x1e, 0x93, 0xf6, 0xb4, 0x12, 0xec, - 0xb4, 0x9f, 0x81, 0x6f, 0xa1, 0xd5, 0x53, 0x44, 0x7a, 0x95, 0x60, 0x60, - 0xe5, 0x11, 0x98, 0x6f, 0x42, 0x6b, 0xe4, 0xb3, 0x60, 0x89, 0xe2, 0x42, - 0x5a, 0xca, 0x0d, 0x75, 0x41, 0x58, 0x4b, 0x1a, 0xda, 0x4e, 0x64, 0x7d, - 0xe4, 0xc0, 0xb2, 0x98, 0x28, 0x9b, 0x02, 0x52, 0x7b, 0x93, 0xcd, 0x01, - 0x0b, 0xfe, 0x4a, 0xe9, 0x5b, 0x56, 0x7e, 0x53, 0x93, 0x00, 0x27, 0x4d, - 0xf3, 0xe3, 0xba, 0x97, 0x31, 0xd7, 0x0f, 0x1f, 0xb7, 0xa6, 0x55, 0x35, - 0xf3, 0x33, 0xdc, 0x9f, 0xad, 0xb5, 0xd6, 0x4c, 0xa9, 0x26, 0xe3, 0x3d, - 0xa0, 0x83, 0x31, 0x40, 0x85, 0x31, 0xae, 0x3e, 0xdb, 0x48, 0xca, 0x70, - 0x2e, 0x84, 0x1e, 0xe3, 0xc3, 0xa8, 0x98, 0xd5, 0xa5, 0x00, 0xea, 0x56, - 0xe6, 0xe7, 0x66, 0x33, 0xce, 0x2d, 0xae, 0xe7, 0x4f, 0xba, 0x28, 0x58, - 0x9d, 0xf7, 0x3e, 0xac, 0x56, 0x08, 0xe4, 0x53, 0x0d, 0x43, 0x9f, 0x51, - 0xec, 0x26, 0x0b, 0x13, 0x42, 0xd8, 0x9c, 0x6f, 0xc7, 0xac, 0x3b, 0x1d, - 0xa1, 0x56, 0x82, 0x99, 0x2f, 0xe4, 0xfc, 0x30, 0x0d, 0x1b, 0x58, 0xbb, - 0xf6, 0xf9, 0x95, 0xd0, 0xe6, 0xf5, 0x02, 0xef, 0xb4, 0xef, 0x5e, 0x74, - 0xa9, 0xaa, 0x42, 0x34, 0x9e, 0x16, 0xcb, 0xc0, 0x7e, 0x21, 0x29, 0x5a, - 0x11, 0x81, 0x8f, 0xb3, 0xf8, 0x28, 0xab, 0x31, 0xf6, 0x78, 0x00, 0x0d, - 0xe4, 0x65, 0x2b, 0xd5, 0xbf, 0x87, 0x55, 0x2e, 0x2e, 0x44, 0x05, 0x72, - 0x88, 0x15, 0x6d, 0x35, 0xc0, 0x16, 0xb5, 0x1f, 0x1f, 0xa2, 0xe0, 0x68, - 0x8c, 0x9d, 0x69, 0x94, 0xe0, 0x5a, 0x40, 0x3f, 0x14, 0xdb, 0xf9, 0x8e, - 0x6e, 0x61, 0x0a, 0x23, 0xb3, 0xee, 0x70, 0x11, 0xa3, 0x9d, 0x13, 0x14, - 0x21, 0xcc, 0xfb, 0x61, 0x98, 0x35, 0x2a, 0x9d, 0x6a, 0x94, 0x5f, 0x44, - 0x08, 0x8c, 0x31, 0xdb, 0xa8, 0x19, 0xc7, 0x30, 0x21, 0xf0, 0xcc, 0x1c, - 0x49, 0x11, 0xfb, 0xe7, 0xd2, 0xf8, 0x5b, 0x78, 0x12, 0x7c, 0x1f, 0x93, - 0xa5, 0x4d, 0x19, 0xb6, 0x04, 0x6b, 0xc0, 0x55, 0x97, 0x31, 0xfa, 0x51, - 0xaf, 0x1d, 0xc6, 0x91, 0x62, 0xa6, 0x2b, 0x31, 0xd8, 0xca, 0x76, 0x86, - 0x50, 0xe5, 0xdc, 0x88, 0x48, 0x44, 0xc8, 0x79, 0xdc, 0x42, 0xc2, 0x1f, - 0x54, 0x85, 0x77, 0xde, 0x70, 0x48, 0xa8, 0x72, 0x1a, 0x2d, 0x4f, 0x38, - 0xc1, 0xb4, 0x1d, 0x46, 0x38, 0x3c, 0x1c, 0xd5, 0xa2, 0x27, 0xf9, 0x55, - 0x0c, 0x9b, 0x7b, 0xb4, 0x25, 0x4c, 0x51, 0xa9, 0xfa, 0xa1, 0xab, 0x30, - 0x5f, 0xbf, 0x72, 0x29, 0x24, 0xcf, 0xcf, 0xe5, 0x78, 0xfc, 0xfb, 0xbc, - 0x2f, 0xa1, 0x90, 0xd4, 0x25, 0x73, 0x83, 0xc2, 0x0d, 0x92, 0x28, 0xb9, - 0xf8, 0x41, 0x9a, 0x8e, 0x10, 0x1c, 0xfd, 0xad, 0x37, 0x98, 0x3d, 0x38, - 0xd3, 0x02, 0x77, 0xbd, 0x17, 0xf6, 0xda, 0x0d, 0x36, 0x75, 0x6f, 0x85, - 0xb3, 0xca, 0x86, 0x4d, 0xe2, 0xad, 0xbe, 0xed, 0x98, 0xd6, 0xd5, 0x0b, - 0x9f, 0xe3, 0x55, 0x70, 0x71, 0x64, 0x26, 0x9c, 0xa1, 0xf7, 0xcc, 0x02, - 0xa3, 0x95, 0xfe, 0xa2, 0xbd, 0xb5, 0xee, 0x17, 0xaa, 0xe6, 0x03, 0xeb, - 0xf1, 0x9c, 0x28, 0x68, 0x60, 0x66, 0xb7, 0xfc, 0xf2, 0xda, 0xf9, 0x24, - 0x1f, 0x62, 0xe8, 0x56, 0x72, 0x9d, 0x89, 0x06, 0x69, 0xaa, 0x03, 0x42, - 0xda, 0x43, 0x33, 0x88, 0x3e, 0xe4, 0x36, 0x40, 0x69, 0x45, 0xbf, 0x01, - 0x64, 0xa3, 0x3d, 0x45, 0xd3, 0x2c, 0xd3, 0x10, 0x96, 0x8e, 0xaa, 0xfe, - 0x5b, 0xcc, 0x5d, 0xe6, 0x77, 0xc2, 0xda, 0xa1, 0x8d, 0xd8, 0x00, 0xb0, - 0x3b, 0x33, 0xeb, 0xbc, 0x35, 0x37, 0x28, 0x38, 0x12, 0x9b, 0xdf, 0xc9, - 0xfe, 0xe5, 0x5a, 0xe3, 0x09, 0x31, 0xdb, 0x0e, 0x24, 0x60, 0x81, 0x39, - 0xbb, 0xba, 0x09, 0xd3, 0x2d, 0x30, 0xf2, 0x03, 0x10, 0x43, 0x06, 0x08, - 0x1c, 0x67, 0xa0, 0xb5, 0x69, 0x30, 0x6c, 0x24, 0x34, 0x80, 0x2c, 0x9c, - 0xe5, 0xfa, 0x36, 0xbe, 0x13, 0xc9, 0x06, 0x43, 0x54, 0x69, 0x6e, 0x2d, - 0xd1, 0x67, 0xeb, 0x9b, 0x51, 0x27, 0x6d, 0x70, 0x84, 0x40, 0xb7, 0xc6, - 0x32, 0x4e, 0xd7, 0xbb, 0xd3, 0x13, 0x36, 0xd7, 0x27, 0xae, 0xa6, 0x7b, - 0x03, 0x10, 0x2c, 0xcd, 0x5f, 0x6c, 0x69, 0x87, 0xc3, 0x93, 0x74, 0x71, - 0x91, 0xbf, 0x0a, 0x45, 0xe4, 0x95, 0x86, 0x0b, 0xf8, 0x26, 0xb8, 0xa1, - 0x6d, 0x67, 0xd5, 0xf9, 0xde, 0xea, 0x34, 0x80, 0x74, 0xd3, 0x48, 0x72, - 0xfb, 0x93, 0x9f, 0xdb, 0x5b, 0x89, 0xad, 0x62, 0x30, 0x3f, 0x1f, 0xf1, - 0x4a, 0x4c, 0x0e, 0xec, 0x94, 0xa5, 0xca, 0x13, 0xf5, 0x51, 0xc1, 0x7c, - 0x2f, 0xb3, 0x51, 0x93, 0xe7, 0x7f, 0xf5, 0x9e, 0x4a, 0x4a, 0xcc, 0x4d, - 0xdf, 0x2d, 0x24, 0x17, 0xf0, 0xc0, 0x4f, 0x9d, 0x4a, 0x25, 0xe4, 0xd5, - 0x32, 0xfb, 0x06, 0xf3, 0x3e, 0xfd, 0xc4, 0xf9, 0xe9, 0x36, 0xfc, 0x0c, - 0xab, 0x9a, 0xb1, 0xf1, 0x79, 0xd1, 0x86, 0xe0, 0xa8, 0x42, 0x28, 0xdb, - 0x40, 0x43, 0xf2, 0x91, 0x06, 0x6a, 0xcf, 0x68, 0xe9, 0x90, 0xc1, 0x0c, - 0x23, 0xfb, 0x69, 0xb2, 0xbe, 0xa3, 0x3e, 0x9b, 0xb4, 0x2b, 0x52, 0xc8, - 0x5e, 0x87, 0x7c, 0x90, 0x6e, 0xba, 0xb9, 0x15, 0xb7, 0xab, 0x66, 0x06, - 0x37, 0xc1, 0x99, 0x6e, 0xbb, 0xb4, 0x31, 0x17, 0x48, 0xa9, 0x7f, 0xa5, - 0x55, 0x85, 0x23, 0x5e, 0x65, 0x4d, 0x49, 0xa7, 0x7f, 0x62, 0x3e, 0x98, - 0x28, 0x53, 0x77, 0x5b, 0xb0, 0x8e, 0xe2, 0x15, 0x4a, 0x7b, 0x52, 0xb7, - 0x48, 0xd4, 0x2a, 0xce, 0x7d, 0x0e, 0xc9, 0x23, 0xcf, 0xde, 0xc7, 0x0e, - 0x7b, 0x59, 0xb6, 0xb5, 0xc3, 0xf6, 0xb2, 0xfa, 0xa9, 0x9c, 0xd2, 0x08, - 0xf5, 0xd3, 0x08, 0x29, 0xd9, 0xd9, 0x7c, 0xab, 0x64, 0x74, 0xdd, 0x88, - 0xfe, 0x0e, 0x75, 0x67, 0x72, 0xc3, 0xc1, 0x9a, 0x2c, 0xe8, 0xbe, 0xd6, - 0xcb, 0xb6, 0x7b, 0x71, 0x8e, 0xd3, 0xbc, 0xa3, 0x9d, 0xd2, 0x4d, 0x88, - 0xf9, 0xbb, 0xed, 0xfa, 0x4b, 0xe4, 0x8c, 0x11, 0xd0, 0xb1, 0xdd, 0x1e, - 0xdf, 0x33, 0xb4, 0x0a, 0x00, 0xfd, 0x2d, 0x9f, 0xc1, 0x84, 0x28, 0xd3, - 0xbe, 0x62, 0x47, 0x38, 0xb6, 0xa2, 0x43, 0x7d, 0x9e, 0xfa, 0x52, 0x35, - 0x84, 0x29, 0x20, 0xb2, 0x04, 0x35, 0xeb, 0xca, 0x15, 0x11, 0xf4, 0xa6, - 0xe0, 0xc5, 0x1c, 0xad, 0x13, 0x33, 0xc8, 0xe8, 0x92, 0x4f, 0x37, 0x22, - 0x05, 0x9b, 0x56, 0x3d, 0x5c, 0xe2, 0x81, 0x84, 0xf8, 0xcb, 0x7b, 0xf3, - 0x60, 0xd0, 0x04, 0x28, 0x3f, 0x6f, 0x7a, 0x40, 0xaa, 0xde, 0x4b, 0xdf, - 0xf0, 0xdd, 0xf8, 0x35, 0xd2, 0xb1, 0xc2, 0xcf, 0x3c, 0x05, 0xd4, 0xfb, - 0x05, 0x1f, 0xa6, 0x35, 0xe2, 0x77, 0x30, 0x45, 0x00, 0xae, 0x52, 0xaa, - 0x0f, 0x76, 0xd7, 0x4b, 0xdd, 0xcc, 0x1b, 0x63, 0x57, 0x39, 0xa4, 0x3d, - 0x9b, 0x49, 0xa8, 0x51, 0x8e, 0x6d, 0x50, 0xeb, 0xdc, 0xed, 0x28, 0xc8, - 0x45, 0xbe, 0xe1, 0xbe, 0x60, 0xdc, 0x4a, 0xd9, 0x86, 0x31, 0xe4, 0x49, - 0xd7, 0xee, 0x81, 0xf1, 0x95, 0xbf, 0x8c, 0x1b, 0x97, 0xac, 0xc9, 0xcf, - 0x9e, 0xf5, 0x77, 0x81, 0xf6, 0xe7, 0x50, 0xb8, 0xf2, 0x7c, 0x64, 0x0a, - 0x3a, 0xe2, 0xa0, 0xfd, 0x0d, 0x49, 0xc0, 0x37, 0x17, 0xee, 0x4e, 0x20, - 0x34, 0xbe, 0xd1, 0x75, 0xa4, 0xea, 0x04, 0x30, 0x7e, 0xda, 0x56, 0x28, - 0x7b, 0x4a, 0x77, 0x70, 0xd3, 0x89, 0x98, 0x1b, 0x20, 0x53, 0x9e, 0xe3, - 0x9c, 0x33, 0xa2, 0x6d, 0xac, 0x62, 0x36, 0xb2, 0x3e, 0x4d, 0xe2, 0x27, - 0x84, 0x7d, 0x9d, 0xc5, 0x5b, 0xba, 0x1f, 0xcc, 0x28, 0xe1, 0x05, 0xe0, - 0x4e, 0x34, 0x79, 0x99, 0x71, 0x04, 0xdf, 0x6d, 0x07, 0x39, 0x3c, 0x3e, - 0xf5, 0x8a, 0xfe, 0x41, 0x32, 0xbf, 0xc1, 0x53, 0x87, 0x0d, 0x07, 0x9d, - 0xb9, 0x50, 0x8f, 0x08, 0xcd, 0x3b, 0xa5, 0x43, 0xbb, 0x4e, 0xc0, 0xb8, - 0xc0, 0xd0, 0x79, 0x0e, 0xad, 0x3f, 0xc0, 0x1b, 0x4c, 0xc9, 0x37, 0xda, - 0x8f, 0x04, 0x3f, 0xb1, 0xaf, 0xa9, 0x92, 0x01, 0x4f, 0x0b, 0x53, 0x22, - 0x43, 0xa7, 0x3b, 0x4a, 0x75, 0x71, 0xa0, 0xab, 0x05, 0x74, 0x67, 0x3b, - 0x1f, 0x12, 0x30, 0x9e, 0xac, 0xf9, 0x9d, 0xf0, 0xa8, 0xd9, 0xcd, 0xa7, - 0xc1, 0x1f, 0x33, 0xb6, 0x1f, 0xd7, 0xed, 0x81, 0x0d, 0x96, 0xab, 0x5c, - 0xd0, 0x87, 0xad, 0x98, 0x50, 0x30, 0x9a, 0xfd, 0xe8, 0xd3, 0x24, 0x47, - 0x45, 0xd7, 0x1e, 0x76, 0x87, 0x23, 0xdf, 0x5b, 0xcb, 0x6c, 0x94, 0xae, - 0x08, 0xa3, 0x05, 0xc9, 0xf7, 0xb7, 0xb9, 0xf2, 0x13, 0xf1, 0xce, 0xce, - 0x83, 0xa1, 0x61, 0xf1, 0xa3, 0xb0, 0x86, 0x18, 0x08, 0xf4, 0x6d, 0xe8, - 0xfd, 0x83, 0x1b, 0xde, 0x90, 0x86, 0xbf, 0xbb, 0xe6, 0x7f, 0xf9, 0x50, - 0x84, 0xec, 0x37, 0x24, 0xfb, 0x78, 0x07, 0x3e, 0x15, 0x09, 0x5e, 0xa6, - 0x82, 0x01, 0x76, 0xe7, 0xc5, 0x06, 0x5c, 0x03, 0xf6, 0xe2, 0x2a, 0x9f, - 0xb7, 0x34, 0x3c, 0xeb, 0xd2, 0xf3, 0x92, 0x75, 0xa3, 0x5f, 0x34, 0x0c, - 0xb9, 0x71, 0xfa, 0xd5, 0x95, 0xc9, 0x39, 0x7d, 0xd7, 0x2f, 0x14, 0xcb, - 0x77, 0x01, 0x41, 0x10, 0x7b, 0x86, 0xb5, 0xcf, 0x07, 0x7d, 0x8a, 0x7c, - 0x61, 0xee, 0x28, 0xe9, 0x6d, 0x4b, 0xdf, 0x2a, 0x26, 0xa5, 0x44, 0x84, - 0xe4, 0xec, 0x88, 0xde, 0x5d, 0x75, 0xc4, 0xb9, 0xf6, 0x7d, 0xb9, 0xbd, - 0x23, 0xc1, 0xbf, 0x67, 0x27, 0x2d, 0x00, 0xee, 0xee, 0x36, 0xb1, 0x3a, - 0x03, 0xfa, 0x45, 0x08, 0xb4, 0x97, 0x7d, 0x58, 0x48, 0x34, 0x50, 0x2e, - 0x9e, 0x95, 0x66, 0xc8, 0x66, 0xfc, 0xe1, 0x74, 0xfc, 0xd3, 0x7d, 0xd4, - 0x4b, 0xf0, 0x0f, 0x1b, 0x0f, 0x1e, 0x15, 0x08, 0x0b, 0x45, 0xb8, 0xae, - 0x1e, 0x0a, 0x8d, 0xa2, 0xa6, 0xc2, 0x44, 0x9f, 0xcc, 0x8c, 0xff, 0x06, - 0x60, 0xa4, 0x90, 0x9f, 0x8c, 0x43, 0x70, 0xf5, 0x96, 0x23, 0xc8, 0x22, - 0xa0, 0xda, 0x83, 0x6d, 0x56, 0x94, 0xdd, 0x6e, 0xa3, 0xbf, 0x20, 0x5b, - 0x1b, 0xfa, 0xc7, 0xb5, 0xba, 0xfa, 0xdb, 0xab, 0x11, 0x05, 0x54, 0x0b, - 0x6e, 0x49, 0x09, 0xff, 0xb8, 0xea, 0xba, 0x7f, 0xbd, 0x1e, 0x89, 0x72, - 0x57, 0x37, 0x89, 0x4c, 0x22, 0xad, 0x02, 0x9d, 0x2b, 0xca, 0x2a, 0xfa, - 0x95, 0x09, 0xf2, 0x4d, 0x6e, 0xfe, 0x96, 0xe8, 0x7d, 0xd3, 0xa8, 0xea, - 0x87, 0x27, 0xa7, 0xea, 0x32, 0x47, 0xb9, 0x2d, 0xaf, 0x6e, 0xe8, 0x77, - 0xf7, 0x4d, 0x3a, 0x90, 0xc7, 0x97, 0xb8, 0x06, 0x0c, 0x03, 0x40, 0x7d, - 0x89, 0x35, 0xe0, 0x9b, 0x7f, 0xb2, 0xdc, 0x5c, 0x6b, 0x00, 0xa8, 0xb3, - 0x87, 0xd2, 0x4f, 0x05, 0x21, 0x9e, 0x18, 0xf8, 0x7b, 0xd1, 0xc5, 0x5e, - 0xe0, 0x49, 0x03, 0xcf, 0x88, 0xe3, 0xe1, 0xc7, 0xfa, 0xb4, 0x3c, 0xe8, - 0x6c, 0x3a, 0x4e, 0xad, 0xaf, 0x2f, 0xc9, 0x1a, 0x67, 0xdf, 0x42, 0xb1, - 0x16, 0x97, 0xfb, 0xf5, 0x3f, 0x6d, 0x6e, 0x65, 0x27, 0xce, 0x4a, 0xc5, - 0xf4, 0x6b, 0xe9, 0x69, 0x94, 0x27, 0x9e, 0x58, 0x75, 0xf6, 0xc8, 0xfb, - 0x38, 0x4a, 0x57, 0xcc, 0x4b, 0x72, 0x4a, 0x31, 0x88, 0x99, 0x48, 0x0b, - 0xa3, 0x5a, 0x7e, 0x13, 0xf9, 0x14, 0x01, 0x71, 0x24, 0xcd, 0xb0, 0x41, - 0xfd, 0xd7, 0xdb, 0xf4, 0xce, 0xdb, 0xb3, 0x28, 0xac, 0x1f, 0xb9, 0xa2, - 0xe8, 0x99, 0xf8, 0x9c, 0x26, 0xb8, 0x22, 0x06, 0xa2, 0x04, 0xfc, 0x60, - 0x6b, 0x4e, 0xec, 0xe6, 0xf2, 0xd7, 0x83, 0x15, 0x07, 0x58, 0x32, 0x46, - 0xc5, 0x81, 0x02, 0x5e, 0x7a, 0xd6, 0x21, 0x3e, 0x3f, 0x1a, 0x7e, 0xe5, - 0x84, 0x50, 0x8b, 0xb4, 0xde, 0x06, 0xee, 0x98, 0x3f, 0xf1, 0x79, 0x89, - 0xc0, 0x11, 0x51, 0x02, 0xc3, 0x4a, 0x21, 0x01, 0x50, 0xe4, 0x4d, 0x68, - 0x90, 0x67, 0x01, 0x6f, 0x1a, 0x43, 0x63, 0xa9, 0xba, 0xcb, 0xe7, 0xe3, - 0x40, 0x18, 0xee, 0xe9, 0x3b, 0x57, 0xcf, 0x32, 0xf6, 0x3d, 0xf1, 0xd8, - 0x3c, 0xb8, 0x78, 0x5f, 0x53, 0x12, 0x35, 0x60, 0xe3, 0x7a, 0x69, 0xb4, - 0xf2, 0x9e, 0xc5, 0x1f, 0xa0, 0x50, 0xd9, 0xf7, 0xfa, 0xad, 0x61, 0xda, - 0x1e, 0x26, 0xa6, 0x67, 0xc7, 0x5f, 0x0c, 0xa2, 0xeb, 0xab, 0x75, 0xee, - 0x9d, 0x1c, 0x69, 0x03, 0x5e, 0x42, 0x58, 0x91, 0x3f, 0x0c, 0x2a, 0x06, - 0xc5, 0xff, 0x35, 0x4f, 0xc1, 0xa4, 0xc5, 0xfa, 0xed, 0x40, 0x25, 0x00, - 0xfb, 0xe7, 0x7a, 0xd0, 0xe9, 0xfb, 0x21, 0x5b, 0x24, 0xd3, 0xb5, 0x6f, - 0xa8, 0x40, 0xc3, 0x52, 0x4d, 0x0f, 0x2c, 0x1c, 0xae, 0x41, 0x36, 0xce, - 0x77, 0xfd, 0x00, 0x9f, 0x89, 0x38, 0xe8, 0x41, 0xca, 0x4c, 0x89, 0xc2, - 0x99, 0x9c, 0x45, 0x69, 0x58, 0x8a, 0x10, 0x79, 0xf9, 0x19, 0xe4, 0xf6, - 0xa0, 0x38, 0x43, 0xd5, 0x22, 0xda, 0xd5, 0x93, 0xe7, 0xe1, 0x51, 0x7a, - 0x0e, 0x60, 0xf1, 0xf7, 0x19, 0x11, 0x33, 0xa6, 0xd0, 0x44, 0x60, 0x35, - 0x58, 0x5b, 0xeb, 0x07, 0x7e, 0xea, 0x55, 0x3a, 0x7c, 0xd3, 0xe5, 0x12, - 0x67, 0x72, 0xad, 0x32, 0xd2, 0x21, 0xfa, 0x9c, 0x16, 0x01, 0x2c, 0x84, - 0x08, 0x94, 0xb6, 0xed, 0x49, 0xde, 0xd1, 0xda, 0x7b, 0x64, 0x25, 0xf8, - 0xcd, 0xae, 0xcd, 0x4f, 0x37, 0x6a, 0x4d, 0x9d, 0x26, 0xae, 0x49, 0x15, - 0x27, 0x22, 0x85, 0xeb, 0xf0, 0xdd, 0x17, 0x7b, 0x81, 0x91, 0x8e, 0xa2, - 0xe4, 0x19, 0x94, 0xec, 0xf1, 0xa8, 0x46, 0xfc, 0xea, 0xb1, 0x72, 0x5e, - 0x4b, 0x12, 0xa7, 0x1f, 0xb7, 0x78, 0xc6, 0xc8, 0xd8, 0x55, 0x07, 0xfe, - 0x05, 0x31, 0x81, 0x03, 0xb9, 0x3b, 0x11, 0x80, 0xce, 0xa4, 0xf7, 0x70, - 0x70, 0xf0, 0x13, 0xd5, 0xbe, 0xba, 0x56, 0x10, 0x3e, 0x78, 0x08, 0x8e, - 0x76, 0x78, 0xed, 0x52, 0x2d, 0xde, 0xd8, 0xa0, 0x7e, 0x2c, 0x72, 0xc1, - 0x17, 0x8b, 0xe9, 0x36, 0xc1, 0xdc, 0x9b, 0x59, 0x8a, 0xa8, 0x70, 0x2d, - 0x25, 0xf2, 0xc6, 0x31, 0x6a, 0x3e, 0x2a, 0x3f, 0x33, 0x1e, 0x9e, 0x04, - 0x84, 0x8f, 0xc0, 0xd5, 0xc0, 0xa5, 0xf5, 0xad, 0x0a, 0xa3, 0x83, 0x55, - 0xd7, 0xc6, 0x0a, 0x3d, 0xbb, 0x09, 0xbc, 0x5e, 0x49, 0x0c, 0x55, 0x54, - 0x68, 0xb0, 0x09, 0xaf, 0x67, 0xa1, 0xc4, 0x53, 0xca, 0x08, 0xf6, 0xa8, - 0x61, 0x3d, 0x38, 0xf3, 0x4f, 0xac, 0x92, 0x43, 0xcb, 0x03, 0x8d, 0x31, - 0xad, 0x83, 0x3d, 0x6c, 0xde, 0xe9, 0xf6, 0x5e, 0x04, 0x01, 0x9e, 0xb4, - 0xa5, 0xfc, 0xfa, 0xfc, 0xa0, 0x96, 0x09, 0x2c, 0x43, 0x95, 0x2c, 0x57, - 0xc1, 0x87, 0x58, 0x50, 0xec, 0xcf, 0xeb, 0xc8, 0x93, 0x85, 0x3a, 0x13, - 0x9c, 0x72, 0xf5, 0x6d, 0x86, 0x2e, 0x43, 0x0c, 0x61, 0x6b, 0x44, 0xaa, - 0xc4, 0xa4, 0x2d, 0xf2, 0x1c, 0xe8, 0x2f, 0x0b, 0xd2, 0x22, 0x9e, 0x24, - 0x97, 0x3d, 0x37, 0x18, 0x59, 0xa2, 0x15, 0xcc, 0x72, 0x67, 0xda, 0x22, - 0xd2, 0xcd, 0x81, 0x19, 0xb4, 0xbf, 0xf5, 0xf6, 0xf7, 0xec, 0xff, 0x0f, - 0x2a, 0xc7, 0x7a, 0xae, 0x2f, 0x20, 0x62, 0x18, 0xdf, 0x4f, 0x74, 0xa3, - 0x13, 0x0c, 0x7a, 0xe4, 0x2d, 0xa7, 0x93, 0x27, 0x87, 0x1b, 0x92, 0x0c, - 0x49, 0xea, 0x75, 0x18, 0xb5, 0x9f, 0xd1, 0xe8, 0xd4, 0x94, 0xf5, 0xd0, - 0x4e, 0x57, 0xd3, 0x71, 0x35, 0xb1, 0xe4, 0xc7, 0xd3, 0xc9, 0xf1, 0x97, - 0x39, 0x84, 0x9b, 0x37, 0xba, 0x5d, 0x7a, 0xfa, 0x94, 0xee, 0x4a, 0x19, - 0x84, 0x30, 0x42, 0xa6, 0xcd, 0xf7, 0xfb, 0x9a, 0x82, 0xef, 0xcf, 0xcf, - 0xdb, 0x51, 0x88, 0x63, 0xf6, 0x3a, 0xbd, 0x06, 0xb6, 0x57, 0xf0, 0x19, - 0x86, 0x91, 0xb8, 0x52, 0xb8, 0xb1, 0x9c, 0xfb, 0x52, 0x10, 0x48, 0xcb, - 0x5b, 0x19, 0x66, 0x8d, 0xc7, 0xb2, 0xc7, 0x41, 0xb5, 0xd0, 0x97, 0xfc, - 0x8d, 0x7a, 0xa8, 0xd2, 0x91, 0x68, 0xe6, 0x50, 0x81, 0x03, 0xa0, 0x78, - 0x0e, 0xe8, 0xfd, 0x8c, 0x2d, 0x74, 0xe7, 0x34, 0x84, 0x9d, 0xef, 0x67, - 0xfa, 0x49, 0x63, 0xef, 0xc9, 0x3f, 0xf9, 0x00, 0x9e, 0xac, 0x98, 0x5c, - 0xcc, 0x1c, 0xf8, 0x79, 0x02, 0xa5, 0xe2, 0x67, 0x49, 0x82, 0xb2, 0x28, - 0x02, 0xd0, 0x40, 0x7e, 0x7a, 0xf7, 0x80, 0x1b, 0x38, 0xfe, 0x8c, 0xe7, - 0x43, 0x81, 0xe1, 0x91, 0xef, 0x78, 0x2d, 0x3a, 0xa3, 0x8e, 0xca, 0xad, - 0x35, 0x76, 0x19, 0x50, 0xcb, 0x79, 0x0f, 0x73, 0x88, 0xf0, 0x05, 0xbe, - 0x5e, 0x91, 0x5a, 0xc9, 0x3b, 0x88, 0x27, 0x38, 0xc5, 0x6d, 0xae, 0x95, - 0x04, 0xe3, 0x20, 0x7f, 0x47, 0xfb, 0x4c, 0x54, 0xc1, 0xe4, 0xbe, 0x29, - 0x37, 0x26, 0x92, 0xe8, 0x84, 0x5d, 0x83, 0xcc, 0xa7, 0xa8, 0xae, 0x63, - 0xf3, 0xb4, 0x6f, 0x05, 0x48, 0x48, 0xd7, 0x8b, 0xb8, 0x02, 0x38, 0xc3, - 0xe9, 0xb2, 0x1f, 0x8c, 0x2e, 0xaa, 0x84, 0xc2, 0xa9, 0x1b, 0xfe, 0xed, - 0x6b, 0x6f, 0x1b, 0xe7, 0xe6, 0xd8, 0x07, 0xa1, 0x97, 0xd2, 0x21, 0x65, - 0xbe, 0x7a, 0x7c, 0x04, 0x83, 0xbb, 0xec, 0x03, 0x54, 0xb0, 0xf0, 0x63, - 0x5f, 0xfd, 0xe8, 0x32, 0xfe, 0x8d, 0x7f, 0xf0, 0xe2, 0xdc, 0x2d, 0xa3, - 0x8c, 0x18, 0xa7, 0x93, 0x71, 0x55, 0x84, 0x23, 0x5d, 0xcb, 0x7f, 0xde, - 0x6f, 0xb3, 0x7b, 0x2e, 0xe1, 0xcc, 0xc9, 0x5d, 0xec, 0xb5, 0xc2, 0x03, - 0x26, 0x02, 0x7a, 0xdb, 0x92, 0x6a, 0x61, 0xfb, 0x45, 0x41, 0x64, 0x35, - 0x91, 0xdc, 0xc5, 0xe9, 0xbc, 0x44, 0x87, 0x93, 0x81, 0x38, 0x36, 0x15, - 0xbc, 0xb0, 0xb2, 0x0d, 0x40, 0x70, 0x08, 0xc9, 0x6f, 0x33, 0x38, 0x6f, - 0x23, 0xfb, 0xe8, 0x81, 0xa2, 0xf7, 0xd0, 0x93, 0x14, 0xe0, 0xaf, 0x2e, - 0x0d, 0xda, 0x56, 0x8e, 0xd3, 0xd5, 0x5c, 0x41, 0x0a, 0x97, 0x53, 0x09, - 0x88, 0x5c, 0xcf, 0x41, 0x1a, 0xd6, 0xdc, 0x77, 0x87, 0xcd, 0xe2, 0xc2, - 0x9a, 0x75, 0xc3, 0xc3, 0x6b, 0x70, 0x1a, 0x8e, 0x83, 0xfe, 0x1c, 0xda, - 0xb7, 0xdd, 0x71, 0x9e, 0x35, 0x7c, 0x5e, 0xb9, 0xe5, 0x6d, 0x1f, 0x47, - 0x3a, 0x19, 0xf6, 0xd0, 0x25, 0x60, 0xd6, 0x2a, 0x74, 0x6c, 0x68, 0xd5, - 0xaa, 0xf2, 0x65, 0x0e, 0x6b, 0xf3, 0xa1, 0x35, 0x84, 0x84, 0xa6, 0x95, - 0xff, 0x4e, 0xcf, 0x22, 0x48, 0x71, 0xf6, 0x72, 0x3a, 0xf8, 0x2e, 0xe1, - 0xec, 0x28, 0x64, 0x1b, 0x9c, 0x51, 0x30, 0x1c, 0xec, 0x68, 0x55, 0x02, - 0x56, 0x0e, 0x16, 0xc7, 0x69, 0xd8, 0xfc, 0xb3, 0x7d, 0xac, 0xc3, 0xb9, - 0x28, 0x5e, 0x84, 0x45, 0x66, 0x75, 0x9f, 0xa2, 0xcb, 0x59, 0x24, 0x4b, - 0xb0, 0x1a, 0xc0, 0x3e, 0x10, 0xf5, 0x13, 0xab, 0x2e, 0x4b, 0xbe, 0xf6, - 0x6e, 0x7c, 0xb8, 0xda, 0xeb, 0x26, 0x42, 0x2d, 0xc5, 0x2d, 0x71, 0xe7, - 0x9a, 0x03, 0xac, 0xb2, 0x10, 0x56, 0x74, 0x89, 0x52, 0x9c, 0x61, 0x3e, - 0x07, 0x8d, 0x73, 0x81, 0x13, 0x8b, 0x79, 0x52, 0x2e, 0x94, 0x51, 0x99, - 0xb4, 0x16, 0xab, 0x15, 0xe1, 0x85, 0x43, 0x54, 0x76, 0x4a, 0xee, 0xb4, - 0x30, 0x23, 0x7c, 0xc1, 0x28, 0xbc, 0x0e, 0xe8, 0xc6, 0xe7, 0x49, 0x57, - 0x02, 0xb1, 0xcd, 0x47, 0x1b, 0x47, 0x35, 0x81, 0xa0, 0x3e, 0x83, 0xb6, - 0x5e, 0xc6, 0x22, 0xca, 0x6e, 0xa9, 0xb5, 0x1d, 0x05, 0x2f, 0x59, 0x1a, - 0xf9, 0x89, 0xf9, 0xd5, 0x35, 0xbc, 0xcd, 0x1e, 0xed, 0x10, 0xb7, 0x9c, - 0x94, 0xa6, 0x2a, 0x64, 0x3c, 0x2b, 0x0c, 0x5f, 0xb8, 0xba, 0x35, 0x47, - 0x1e, 0x61, 0xe0, 0x28, 0xd0, 0x62, 0xbc, 0x6c, 0x2a, 0xde, 0x1c, 0xb9, - 0x50, 0x94, 0xbf, 0x3f, 0x3d, 0x19, 0xf4, 0xcf, 0x11, 0x62, 0x8b, 0xec, - 0xe5, 0x8c, 0xc4, 0x67, 0x4c, 0xec, 0xf2, 0x33, 0x39, 0x32, 0xaf, 0x36, - 0x75, 0xff, 0xda, 0x8d, 0x2a, 0x12, 0x64, 0x19, 0xb5, 0x46, 0x7a, 0x71, - 0xe4, 0xef, 0x6e, 0xb8, 0x93, 0x00, 0xf4, 0x2f, 0x21, 0xf4, 0x88, 0x5c, - 0xb6, 0x12, 0x2a, 0xe2, 0xf3, 0xbc, 0x9b, 0xdb, 0xbe, 0x8a, 0x6c, 0xeb, - 0x0e, 0x30, 0x13, 0xae, 0x1f, 0xb5, 0xaa, 0x97, 0xbf, 0x0b, 0x1b, 0xe2, - 0xc7, 0x2a, 0xb9, 0xd9, 0x1c, 0xfd, 0x26, 0x61, 0x02, 0x59, 0xd2, 0x67, - 0x14, 0xf8, 0x36, 0x9f, 0x9c, 0x05, 0x3e, 0x86, 0xc1, 0x9c, 0x47, 0x13, - 0x80, 0xcf, 0xfa, 0x29, 0xe1, 0x24, 0xa2, 0x5e, 0x46, 0xff, 0xdd, 0xe1, - 0xd3, 0x72, 0xa4, 0x66, 0xd8, 0x5c, 0x54, 0x56, 0xc6, 0x67, 0xd3, 0xb5, - 0x5a, 0x54, 0x43, 0x17, 0xe7, 0x95, 0x1c, 0x4e, 0xfa, 0xaf, 0x31, 0x9b, - 0xe2, 0x66, 0x0f, 0x8c, 0xcc, 0x32, 0x8a, 0x7d, 0x67, 0x75, 0xff, 0xbb, - 0x97, 0x83, 0x02, 0xe3, 0x3a, 0x7e, 0xde, 0xd9, 0x95, 0x92, 0xc8, 0x28, - 0x62, 0x67, 0xfe, 0x5b, 0x6d, 0xf0, 0x53, 0x6d, 0x31, 0xbf, 0x73, 0x91, - 0xa3, 0x1e, 0x6c, 0xb5, 0x3c, 0xec, 0xaa, 0xc5, 0xa1, 0xa2, 0xa8, 0x44, - 0x98, 0x5a, 0x25, 0x01, 0xc7, 0xc9, 0x5e, 0xb4, 0x77, 0x7b, 0x71, 0xe3, - 0x1b, 0xce, 0xa2, 0xa6, 0x24, 0x65, 0x68, 0xf7, 0xe8, 0x59, 0xb9, 0x9c, - 0x06, 0xd3, 0x6e, 0x5f, 0x60, 0xac, 0x7b, 0x4f, 0xcf, 0x4b, 0xd1, 0x15, - 0x2c, 0x71, 0x19, 0x31, 0xa0, 0x15, 0x89, 0x16, 0x7d, 0x0a, 0xde, 0xf9, - 0x39, 0xaf, 0xcd, 0xb7, 0xdc, 0x95, 0x16, 0x8d, 0x98, 0x2c, 0xf5, 0x18, - 0xc6, 0xc6, 0x45, 0x4e, 0xd6, 0x4e, 0x46, 0x42, 0xe8, 0x31, 0x08, 0x6a, - 0x94, 0xa7, 0xe2, 0xe9, 0x77, 0x67, 0xdd, 0x72, 0x75, 0xdd, 0xe5, 0x7f, - 0x52, 0x44, 0x3e, 0x8a, 0xa2, 0x1c, 0xb7, 0x83, 0x7d, 0xc4, 0x07, 0x2b, - 0xa6, 0xa0, 0x22, 0x59, 0xce, 0x1c, 0x88, 0xc9, 0xb9, 0x3b, 0x0b, 0x11, - 0xc3, 0xf5, 0xe7, 0x52, 0x61, 0xdf, 0x88, 0xdb, 0x52, 0xa1, 0xcb, 0xc1, - 0xe0, 0xa7, 0x9d, 0xce, 0x4f, 0x24, 0x5e, 0xd7, 0xa3, 0xac, 0x81, 0x27, - 0x8a, 0x45, 0xf6, 0x15, 0xe1, 0x1f, 0x23, 0x31, 0x4e, 0xed, 0x39, 0xb1, - 0x65, 0xe3, 0x70, 0x3f, 0xb0, 0x7d, 0x50, 0x14, 0xca, 0xb0, 0x29, 0x62, - 0x4a, 0xb8, 0x63, 0xa6, 0xee, 0xbf, 0x37, 0xb9, 0x89, 0x0f, 0x42, 0xcc, - 0x94, 0xbc, 0x39, 0x51, 0x06, 0x82, 0xa3, 0xbc, 0x74, 0x3d, 0x1b, 0x7f, - 0xa3, 0xec, 0xef, 0xe6, 0x71, 0x7b, 0x63, 0x5d, 0xa9, 0xe1, 0xe2, 0x45, - 0x5f, 0xfd, 0xb3, 0xb3, 0xcf, 0xc4, 0xe8, 0xa2, 0x5d, 0x8f, 0x93, 0x73, - 0xbf, 0x88, 0xec, 0x6b, 0x06, 0x6d, 0xcc, 0x53, 0x55, 0xf4, 0xce, 0x02, - 0x69, 0xf9, 0x5c, 0x9b, 0xc6, 0x4f, 0x67, 0xec, 0x2b, 0x1c, 0xa4, 0xad, - 0x1e, 0x0e, 0x0a, 0x4f, 0x60, 0x6d, 0x23, 0x33, 0x87, 0x0d, 0xba, 0x91, - 0x5d, 0x97, 0xeb, 0xb2, 0x5a, 0x06, 0x63, 0xd7, 0xb1, 0x51, 0x3d, 0x70, - 0xe8, 0x38, 0xd7, 0xde, 0x4a, 0xca, 0x05, 0x26, 0xd5, 0x0b, 0x7f, 0x84, - 0x60, 0x9c, 0xd7, 0x84, 0x0f, 0x23, 0x97, 0x4a, 0x90, 0x71, 0xd8, 0x80, - 0xa9, 0x3e, 0x79, 0xcd, 0xce, 0x59, 0x8a, 0x1a, 0xba, 0xe9, 0xa8, 0xc5, - 0xfa, 0x30, 0xdf, 0xb4, 0xa1, 0x4b, 0x6c, 0x72, 0xe9, 0x82, 0x42, 0x04, - 0x65, 0x62, 0x4c, 0x5f, 0xe7, 0x05, 0x02, 0x7f, 0x49, 0xa8, 0x12, 0xa8, - 0xa1, 0xfa, 0x32, 0x33, 0x24, 0x9b, 0xdf, 0xcd, 0xe3, 0xf6, 0xb1, 0xda, - 0x11, 0xc3, 0xb9, 0xaf, 0xf9, 0x46, 0x20, 0xe8, 0x43, 0x19, 0xc2, 0x86, - 0xd5, 0x8e, 0x14, 0x57, 0xc8, 0xc2, 0xe7, 0xf3, 0xae, 0xbb, 0xfb, 0x76, - 0x0b, 0xd8, 0xc6, 0x9a, 0xe8, 0x2b, 0x99, 0xd3, 0x9c, 0x50, 0x92, 0x94, - 0xbf, 0x9d, 0xf5, 0xf3, 0xc2, 0x87, 0xf5, 0x0b, 0xb1, 0x69, 0x8d, 0x8a, - 0x55, 0x58, 0xed, 0xf3, 0xbc, 0x1d, 0x7e, 0xce, 0x5a, 0x5d, 0x8f, 0xee, - 0x46, 0xa7, 0xbb, 0xe3, 0xe3, 0x9d, 0x8f, 0xbb, 0xf6, 0x04, 0x09, 0xa9, - 0x3b, 0xf4, 0x9f, 0xe5, 0xd3, 0xdf, 0x15, 0xb6, 0x80, 0xb1, 0x6c, 0x05, - 0xef, 0x12, 0x35, 0x8f, 0xaf, 0x83, 0xa0, 0x63, 0xbb, 0x32, 0x14, 0x91, - 0x65, 0xee, 0xc5, 0x7d, 0x37, 0x60, 0x95, 0x11, 0x2e, 0x32, 0x09, 0xbb, - 0x5b, 0xd9, 0x7b, 0x79, 0xab, 0xc9, 0xac, 0xfd, 0x23, 0x63, 0x3f, 0x29, - 0xc3, 0x49, 0x1f, 0x73, 0xb8, 0x0e, 0xdf, 0x1e, 0x59, 0x3d, 0xc2, 0x8e, - 0xc9, 0xa6, 0x06, 0xe0, 0xba, 0xe4, 0x4e, 0x7d, 0x0a, 0x40, 0xdb, 0x49, - 0x43, 0x75, 0x69, 0xe9, 0xd6, 0x62, 0xe8, 0x73, 0x3d, 0x67, 0x71, 0xa8, - 0x4c, 0x11, 0xbf, 0x8d, 0x14, 0xf7, 0xed, 0xde, 0x1c, 0x3d, 0x88, 0x8a, - 0x5f, 0x1d, 0xbc, 0x5d, 0x92, 0x79, 0x80, 0xb9, 0xd3, 0xb2, 0xd2, 0x27, - 0x54, 0xc6, 0xbe, 0xdb, 0x1c, 0x09, 0x89, 0x5f, 0xbc, 0x43, 0x3a, 0xcc, - 0x95, 0xc4, 0x47, 0xf4, 0xd8, 0xe1, 0x77, 0x20, 0xbe, 0x32, 0x59, 0x1d, - 0xc1, 0x08, 0x58, 0x49, 0xea, 0x4f, 0x26, 0x62, 0x7a, 0x6d, 0xa7, 0x80, - 0x5e, 0xea, 0x93, 0x63, 0x0d, 0xb3, 0xfa, 0xfb, 0x68, 0xaf, 0x83, 0x74, - 0x61, 0xe9, 0xa0, 0x00, 0x12, 0x62, 0x77, 0x67, 0x04, 0x6a, 0xb9, 0xe7, - 0xd7, 0x2f, 0x7a, 0x0d, 0xc0, 0x84, 0x34, 0x52, 0xca, 0x5e, 0xf2, 0x94, - 0x63, 0xc8, 0x47, 0xc7, 0x65, 0xbb, 0xcc, 0xd5, 0x9c, 0xa2, 0x39, 0x22, - 0xd6, 0x78, 0x67, 0x23, 0x53, 0xde, 0xc3, 0x2f, 0xfc, 0x31, 0xcc, 0xe0, - 0x39, 0xc2, 0xb2, 0x99, 0x86, 0x1a, 0xf3, 0x57, 0x81, 0x75, 0xf4, 0xa8, - 0x30, 0xe1, 0xac, 0x5a, 0xb7, 0x8f, 0xc6, 0x6f, 0x7b, 0xb2, 0x3d, 0x30, - 0xd1, 0x4b, 0x0b, 0x71, 0xc1, 0x3a, 0x0b, 0xc5, 0x57, 0x28, 0x96, 0xf2, - 0x00, 0x1b, 0x0e, 0x49, 0x7c, 0x0b, 0xd0, 0xb5, 0xd4, 0x9d, 0xd3, 0xa8, - 0x19, 0xe5, 0x6d, 0xae, 0xbe, 0xc6, 0xcd, 0x0d, 0x22, 0x8e, 0xac, 0xca, - 0x3a, 0x60, 0x5c, 0xb8, 0x02, 0x82, 0x30, 0xd3, 0x01, 0xde, 0x6b, 0x63, - 0xbf, 0xc0, 0xe1, 0xf8, 0xe6, 0x1f, 0x93, 0xdf, 0x2e, 0xcd, 0x4f, 0x19, - 0x98, 0x67, 0xf3, 0x08, 0x78, 0x2d, 0x96, 0x49, 0xc5, 0x56, 0x29, 0x25, - 0x45, 0x61, 0x95, 0xbc, 0xca, 0xf5, 0x79, 0xfd, 0x0d, 0x23, 0xbb, 0x33, - 0x88, 0x2d, 0x0e, 0x24, 0x06, 0x5d, 0x2d, 0x66, 0x81, 0x8f, 0x20, 0x00, - 0x92, 0x4b, 0xe5, 0x56, 0xd2, 0x19, 0x0f, 0xf6, 0xf9, 0xb0, 0x7a, 0xf3, - 0xbb, 0x19, 0xe2, 0xf3, 0x34, 0xda, 0xcf, 0x29, 0xac, 0xd9, 0x80, 0x0c, - 0x60, 0x12, 0x56, 0x4c, 0x50, 0x84, 0x25, 0xb0, 0x31, 0x25, 0x37, 0xa0, - 0xd2, 0xbc, 0x53, 0xc0, 0x2a, 0x1c, 0x1d, 0x68, 0x28, 0xe8, 0x0c, 0x48, - 0x8d, 0x89, 0x09, 0x45, 0xc0, 0x96, 0xba, 0xad, 0xbb, 0xcf, 0xea, 0xae, - 0xcc, 0x44, 0xf8, 0xad, 0x7b, 0xa9, 0x35, 0xdb, 0x79, 0x25, 0xb5, 0xf7, - 0xe2, 0xc7, 0xb8, 0xa7, 0x3c, 0x6b, 0xa6, 0x00, 0x50, 0x8b, 0xd2, 0x85, - 0xc8, 0x93, 0x47, 0x69, 0x3e, 0x83, 0x16, 0xb8, 0xa0, 0x84, 0x56, 0x42, - 0xd4, 0x8f, 0xcb, 0xff, 0x78, 0x19, 0x0f, 0x01, 0xca, 0x62, 0xad, 0x88, - 0xda, 0x90, 0x40, 0xa1, 0xce, 0x5f, 0x19, 0xfe, 0xe6, 0x90, 0x42, 0x54, - 0xdf, 0x82, 0x91, 0x98, 0xad, 0xc1, 0x83, 0x1f, 0xe1, 0x73, 0x8a, 0xa5, - 0x2e, 0x11, 0x60, 0x8d, 0xf3, 0x10, 0x95, 0x0b, 0xcb, 0xe0, 0x7c, 0xd6, - 0xb0, 0x67, 0x54, 0x25, 0x61, 0x36, 0x82, 0x74, 0x69, 0xe7, 0x13, 0xd7, - 0xa2, 0x18, 0x00, 0x37, 0xf4, 0x12, 0xaf, 0xa8, 0x6e, 0x0c, 0xcd, 0xea, - 0xa2, 0x4b, 0x2e, 0xbd, 0x30, 0xcc, 0x5c, 0xc8, 0xd0, 0x33, 0x59, 0x14, - 0x24, 0xb0, 0x6e, 0xce, 0xc2, 0x0e, 0x69, 0xce, 0xa7, 0x3c, 0x71, 0x89, - 0x4f, 0x2c, 0x20, 0xf0, 0x52, 0x88, 0xcc, 0x19, 0xf7, 0x28, 0x2a, 0x37, - 0x59, 0x43, 0xba, 0xf2, 0x06, 0x83, 0xaf, 0x71, 0xea, 0xb2, 0x08, 0x45, - 0x03, 0xf4, 0xb1, 0x00, 0x5e, 0x3b, 0xf3, 0x97, 0xad, 0x1c, 0x1f, 0xc6, - 0x67, 0xdb, 0x0b, 0x7b, 0x93, 0x1c, 0x06, 0xad, 0x00, 0xd5, 0x6a, 0xd2, - 0x10, 0xf9, 0xe3, 0x24, 0x2c, 0x87, 0xee, 0x17, 0xf8, 0x6c, 0x68, 0xbc, - 0xb1, 0x6d, 0x45, 0xcf, 0x59, 0x84, 0x03, 0x44, 0x01, 0xce, 0x96, 0x0a, - 0x27, 0xed, 0xe4, 0x3d, 0xdd, 0x98, 0x14, 0x0d, 0x83, 0xf1, 0x92, 0x01, - 0xd2, 0x65, 0xee, 0x9a, 0xd5, 0x9e, 0x1e, 0xd8, 0x18, 0xe8, 0x44, 0x8c, - 0x39, 0xa7, 0x66, 0x27, 0x9d, 0x58, 0x99, 0xbc, 0xf6, 0x3d, 0xe0, 0x02, - 0x9e, 0x30, 0x84, 0xd3, 0x94, 0xd1, 0x07, 0x07, 0xa2, 0xf5, 0x24, 0xcc, - 0x3b, 0x1c, 0x3c, 0x84, 0xc1, 0x4a, 0x03, 0xa4, 0x0b, 0x70, 0x12, 0x42, - 0x9d, 0x92, 0xcb, 0x89, 0x37, 0x9b, 0xe7, 0x7e, 0xf6, 0xf4, 0x61, 0x24, - 0x82, 0x36, 0xe9, 0x7c, 0x72, 0x1a, 0x92, 0x86, 0xc0, 0xbb, 0x84, 0xb9, - 0x8d, 0x85, 0x6c, 0xfc, 0x18, 0xed, 0xbb, 0x61, 0x63, 0x6e, 0xd4, 0xf2, - 0x20, 0x83, 0x19, 0x69, 0x54, 0xfc, 0x75, 0x14, 0x61, 0x1c, 0x60, 0xee, - 0x0e, 0xb0, 0xd1, 0x90, 0x65, 0xd0, 0xe8, 0x88, 0x39, 0x77, 0xa6, 0xed, - 0x08, 0x7e, 0x51, 0x73, 0xa4, 0xb2, 0xd5, 0x86, 0xce, 0xcc, 0x91, 0x8a, - 0xf9, 0x48, 0x13, 0x5b, 0x7e, 0xae, 0x05, 0xfe, 0x8e, 0x12, 0xe4, 0x3f, - 0x25, 0xb7, 0x11, 0xd8, 0xb7, 0x09, 0xd8, 0xda, 0xf9, 0xc2, 0xf2, 0x24, - 0xbe, 0x30, 0x33, 0x63, 0xfc, 0x2d, 0x11, 0xeb, 0x06, 0x8a, 0x9f, 0x54, - 0xd3, 0x35, 0x1f, 0x6c, 0x77, 0xa0, 0x8c, 0xa1, 0xdd, 0xb6, 0x8a, 0x34, - 0x41, 0x2b, 0x3d, 0x03, 0xef, 0xeb, 0x19, 0xe0, 0xee, 0x55, 0x3b, 0xaf, - 0x5e, 0x94, 0xe0, 0x77, 0x47, 0x49, 0xfe, 0xc2, 0xfa, 0x55, 0x6d, 0xb6, - 0xb3, 0x3d, 0xdf, 0x69, 0x1f, 0x15, 0x02, 0x2d, 0xa9, 0x45, 0xb8, 0x46, - 0x0c, 0xea, 0xbe, 0x4f, 0xcc, 0x3b, 0x75, 0x3b, 0x9e, 0x00, 0xdc, 0xa4, - 0xf4, 0x30, 0xad, 0x14, 0x91, 0xe2, 0x63, 0x0b, 0x42, 0xab, 0x04, 0x41, - 0x79, 0x9e, 0x1d, 0x7d, 0xad, 0xf5, 0x5d, 0x56, 0x50, 0xd1, 0x6e, 0x84, - 0x4c, 0xa7, 0xbc, 0x3f, 0x5b, 0xa4, 0x2f, 0x21, 0x3f, 0x6b, 0xc0, 0xe0, - 0xb0, 0xcf, 0x15, 0x41, 0x81, 0x93, 0xc3, 0x3f, 0x31, 0x4f, 0x1b, 0x29, - 0x32, 0xe8, 0x88, 0x0b, 0x7e, 0x05, 0x66, 0x1e, 0xae, 0x46, 0xe5, 0xfc, - 0xa7, 0x29, 0xce, 0x07, 0x5e, 0x3a, 0x76, 0x3b, 0x4c, 0xf4, 0xc6, 0x27, - 0x72, 0xa0, 0x79, 0x71, 0x73, 0xfd, 0x43, 0xdd, 0x4f, 0x92, 0x02, 0x10, - 0xf6, 0x48, 0xba, 0x99, 0x6d, 0x84, 0xad, 0x29, 0x9a, 0xc7, 0xd5, 0x44, - 0xf2, 0x36, 0x0c, 0xfb, 0x84, 0x3d, 0x46, 0xa3, 0x32, 0xaf, 0x32, 0x4f, - 0x02, 0x13, 0xba, 0x39, 0x89, 0xf3, 0x16, 0x2a, 0x39, 0xe3, 0x6e, 0x30, - 0xe5, 0x2c, 0x61, 0x27, 0xbd, 0xa3, 0x87, 0xb1, 0xb4, 0x6b, 0x98, 0xac, - 0xa4, 0xe2, 0x73, 0xbf, 0x74, 0xdc, 0x42, 0x26, 0x92, 0x93, 0x49, 0xda, - 0x40, 0x34, 0x65, 0xed, 0xd8, 0xb8, 0x7a, 0xb0, 0x8e, 0x90, 0xf5, 0xa9, - 0x9c, 0x82, 0xcf, 0x78, 0xca, 0x29, 0x67, 0xc0, 0xf6, 0xe8, 0xb8, 0x97, - 0x6c, 0xfa, 0x70, 0x9e, 0xa4, 0x35, 0x61, 0x7d, 0x9e, 0xad, 0xee, 0xd3, - 0x9a, 0x89, 0x6b, 0x43, 0x68, 0x20, 0x82, 0x4b, 0xb6, 0xea, 0xa2, 0x72, - 0xab, 0xea, 0x77, 0x6f, 0x5a, 0x87, 0xd7, 0x32, 0x7d, 0x31, 0xe1, 0xdc, - 0xc7, 0xc6, 0xa4, 0xd9, 0xc5, 0x77, 0x22, 0xea, 0x5a, 0x6b, 0x19, 0x50, - 0xd0, 0x69, 0xfb, 0x2d, 0x00, 0xda, 0x29, 0x32, 0x95, 0x86, 0x47, 0x71, - 0x92, 0xd0, 0x8f, 0x07, 0xd5, 0xc9, 0xd5, 0x19, 0xef, 0x51, 0x4b, 0xc9, - 0x88, 0x46, 0x11, 0x08, 0x24, 0x0a, 0x20, 0xf6, 0x32, 0xe4, 0x18, 0x80, - 0xff, 0xee, 0x4d, 0x3a, 0xbe, 0x68, 0x74, 0x57, 0x89, 0x8a, 0xd1, 0x4e, - 0x02, 0xc6, 0xf9, 0x54, 0x72, 0x18, 0x0f, 0x5f, 0x33, 0xf4, 0xcd, 0x15, - 0xd0, 0xfb, 0x0d, 0x6d, 0x8f, 0x1b, 0x20, 0xd8, 0xef, 0x61, 0x0f, 0x15, - 0x80, 0x09, 0xe8, 0x35, 0xc5, 0xd9, 0x38, 0x44, 0x7e, 0x69, 0x2a, 0x96, - 0x7d, 0x80, 0xf3, 0x0d, 0x55, 0xcf, 0x63, 0x53, 0xb9, 0x79, 0xd6, 0xcf, - 0x8a, 0x7e, 0x84, 0xb5, 0x36, 0x4f, 0xee, 0x72, 0xff, 0x8c, 0xc1, 0xab, - 0x66, 0xf0, 0x58, 0x31, 0x52, 0xbb, 0x90, 0x87, 0x3b, 0xb3, 0xc7, 0x18, - 0x7b, 0x63, 0x3e, 0xe3, 0xf4, 0xf5, 0xb9, 0x35, 0xf2, 0x88, 0x6a, 0x62, - 0x3f, 0x84, 0xa4, 0xec, 0xe5, 0xcf, 0xb7, 0x4f, 0x00, 0x56, 0x18, 0x84, - 0xd2, 0x86, 0x8d, 0x12, 0x32, 0x03, 0x38, 0x06, 0x60, 0xc1, 0xa6, 0x9a, - 0x4e, 0xfe, 0x0a, 0xfe, 0x4b, 0xdb, 0x57, 0xfc, 0xa3, 0xdc, 0x6f, 0x53, - 0x92, 0x2f, 0xd0, 0x05, 0x6e, 0x86, 0x35, 0xd2, 0x40, 0xf8, 0xa4, 0x4f, - 0xd3, 0xe4, 0x7c, 0xc0, 0xde, 0xf7, 0xe3, 0x84, 0x63, 0xa3, 0x37, 0x4f, - 0x36, 0xc5, 0x47, 0xb1, 0xb0, 0x75, 0x96, 0xf5, 0x6b, 0x0e, 0xd5, 0x87, - 0xc7, 0xdf, 0x22, 0x8c, 0x88, 0xa8, 0x80, 0x12, 0x94, 0x9c, 0xe8, 0x8d, - 0xa9, 0x98, 0x55, 0x2d, 0xac, 0xd5, 0xc5, 0x8c, 0xc6, 0x78, 0x6f, 0xcb, - 0x5e, 0x28, 0x73, 0x68, 0xcd, 0x9f, 0x0d, 0xa6, 0xce, 0xfe, 0x3e, 0x21, - 0xfa, 0xf8, 0xb1, 0x1a, 0x19, 0xe9, 0xdf, 0xdc, 0x32, 0x12, 0x8a, 0xa5, - 0x1b, 0x70, 0x8d, 0x67, 0xbc, 0x56, 0xd7, 0x8c, 0xff, 0x50, 0x3e, 0x45, - 0xee, 0x3f, 0x06, 0x41, 0x10, 0x41, 0x1c, 0x6c, 0xd8, 0x02, 0x09, 0x38, - 0xb1, 0x9d, 0x7b, 0x85, 0x1b, 0x67, 0xe8, 0x70, 0x1e, 0xa4, 0x50, 0x0b, - 0x99, 0x46, 0xdc, 0x9c, 0x6f, 0x9d, 0x49, 0xd8, 0x93, 0xd3, 0x39, 0x44, - 0xb4, 0xa3, 0xec, 0x20, 0x50, 0xeb, 0x6c, 0x3c, 0x0f, 0x55, 0xcb, 0xf2, - 0x44, 0x29, 0xeb, 0x0c, 0x5d, 0x4e, 0x39, 0x27, 0xce, 0x65, 0x9c, 0x2a, - 0xea, 0x4e, 0x59, 0x1a, 0x79, 0x42, 0x25, 0x31, 0x24, 0xf8, 0x55, 0x7b, - 0xf9, 0xd1, 0x47, 0x37, 0x95, 0xfd, 0xb6, 0xfc, 0x78, 0xb1, 0xc4, 0xca, - 0xbe, 0x89, 0xc8, 0xe1, 0x67, 0x13, 0x61, 0x41, 0xc9, 0x7f, 0x58, 0x06, - 0x6f, 0xcd, 0xc1, 0x67, 0x97, 0x2b, 0xf0, 0x2a, 0x55, 0xd5, 0x4d, 0xcf, - 0x5d, 0xcb, 0xfd, 0x46, 0xb5, 0xba, 0xef, 0x92, 0x68, 0xe3, 0x63, 0x58, - 0x44, 0xb3, 0x62, 0x11, 0x66, 0xfa, 0xce, 0xb5, 0x5e, 0x31, 0xa7, 0x61, - 0x29, 0x4c, 0x57, 0x2a, 0xcc, 0x9d, 0x07, 0x48, 0x13, 0x67, 0x5d, 0xf2, - 0x4d, 0xbd, 0x5a, 0x44, 0x3c, 0x1d, 0x71, 0x63, 0x2d, 0x62, 0xa6, 0xcc, - 0xa8, 0xbe, 0x3e, 0x98, 0xc2, 0x11, 0xa1, 0xa9, 0xaf, 0xd2, 0x7c, 0x2c, - 0x76, 0x94, 0x41, 0x44, 0xc1, 0xda, 0x93, 0x8d, 0x3c, 0x82, 0xc5, 0xd3, - 0x30, 0xfe, 0x11, 0x1f, 0xc3, 0x37, 0xc6, 0x6d, 0x26, 0xf0, 0x44, 0x76, - 0xee, 0x51, 0x87, 0x3e, 0x23, 0x8d, 0xbb, 0xab, 0x1f, 0xed, 0xb8, 0x48, - 0x74, 0xe9, 0xb8, 0xbe, 0x6b, 0x73, 0x51, 0x4f, 0x5e, 0xe0, 0x6b, 0x98, - 0xab, 0xf3, 0xb2, 0x15, 0x8c, 0xc9, 0x8c, 0x96, 0x93, 0xe3, 0xec, 0x2d, - 0x21, 0x94, 0x1a, 0x06, 0xa6, 0x51, 0xe4, 0x3f, 0xca, 0x05, 0xcb, 0xa5, - 0xa7, 0x70, 0x5e, 0x9e, 0xcb, 0x2d, 0xc5, 0x9e, 0xad, 0xe0, 0xa7, 0x5a, - 0xce, 0x2a, 0x87, 0xbb, 0xc4, 0xc5, 0x9a, 0x25, 0x7c, 0x13, 0xda, 0xf1, - 0x18, 0x3d, 0x16, 0xe0, 0x28, 0x0e, 0xd4, 0x62, 0xcc, 0xa7, 0xb7, 0xf3, - 0xa9, 0xe5, 0xb2, 0x4b, 0xc5, 0xd2, 0xc1, 0x8d, 0xa5, 0x9d, 0x66, 0xfc, - 0x9f, 0xf1, 0x29, 0x3c, 0x59, 0xb2, 0xd9, 0x19, 0xf8, 0x3b, 0x0f, 0x07, - 0x7b, 0x48, 0x0b, 0x65, 0xfd, 0xda, 0x6d, 0x9d, 0x03, 0x57, 0x25, 0x4b, - 0xdf, 0x02, 0xe4, 0x52, 0x18, 0x97, 0xac, 0xb8, 0x4a, 0x6d, 0x60, 0x53, - 0x5f, 0x79, 0xf6, 0xeb, 0x75, 0x62, 0xb3, 0x1a, 0x51, 0xf6, 0x6d, 0x04, - 0xd7, 0x10, 0xef, 0x74, 0x3f, 0xa5, 0xdd, 0xfc, 0x20, 0xfa, 0xbc, 0x3c, - 0x7a, 0x5d, 0x9e, 0x42, 0x4b, 0x9b, 0xc1, 0xea, 0xce, 0x69, 0x52, 0x25, - 0x1c, 0x8a, 0xff, 0x14, 0xdc, 0x46, 0x85, 0x9d, 0x66, 0xe7, 0x8a, 0xe5, - 0x3a, 0xbd, 0xad, 0x28, 0xf1, 0x8a, 0xb8, 0xd1, 0x83, 0x93, 0x8e, 0xf8, - 0x50, 0x51, 0x6e, 0x22, 0x2d, 0x92, 0x88, 0x32, 0x09, 0x42, 0x45, 0x13, - 0x3a, 0xf7, 0x5c, 0x3b, 0x38, 0x47, 0x1c, 0x7d, 0x91, 0xba, 0x2e, 0xff, - 0x68, 0x7b, 0x4a, 0x54, 0xf9, 0x80, 0xad, 0x62, 0xf2, 0x31, 0x00, 0x14, - 0x50, 0x0c, 0xc1, 0xd7, 0xd5, 0x6f, 0xf2, 0x77, 0xe2, 0x6a, 0xff, 0xf8, - 0xbf, 0x5f, 0x0c, 0x08, 0xb8, 0x7d, 0x44, 0x61, 0x9d, 0xb2, 0x17, 0x72, - 0x4a, 0x97, 0x06, 0x57, 0xc5, 0x3a, 0xba, 0x5a, 0x04, 0x50, 0x10, 0xa2, - 0xc5, 0x5e, 0xd0, 0x18, 0xf3, 0xd5, 0x8e, 0x02, 0x55, 0x4a, 0x0d, 0xec, - 0x16, 0x0f, 0xd5, 0x73, 0x3f, 0xc8, 0xe9, 0x39, 0xc1, 0xf9, 0xce, 0x3b, - 0x38, 0x50, 0xa6, 0xb3, 0xc0, 0x61, 0xc5, 0xab, 0xea, 0x1b, 0x3d, 0x94, - 0x4e, 0x5e, 0x8a, 0x57, 0xb0, 0x94, 0x88, 0x3a, 0xa1, 0xa1, 0xe9, 0xe6, - 0xa4, 0x9f, 0x04, 0xb8, 0xc1, 0x7c, 0xa3, 0xbe, 0x82, 0xc8, 0xc8, 0xfc, - 0xe5, 0xa1, 0x54, 0xd9, 0xd2, 0xd0, 0xeb, 0xfa, 0x6a, 0xd5, 0xa0, 0x50, - 0x49, 0xcd, 0xb5, 0xe7, 0xb9, 0x8c, 0x1c, 0x67, 0x2c, 0x4b, 0x70, 0xed, - 0x89, 0x27, 0x16, 0xec, 0xb2, 0x68, 0x1c, 0x8a, 0xb6, 0x22, 0xe2, 0xe6, - 0x50, 0x4d, 0x27, 0x7a, 0xc2, 0x8d, 0x74, 0xf9, 0x7e, 0x98, 0xbe, 0x43, - 0xc9, 0xcb, 0x24, 0xd4, 0x6b, 0x17, 0xe7, 0x82, 0xdf, 0xf1, 0x12, 0xc4, - 0x29, 0x81, 0x1c, 0x90, 0x93, 0x4f, 0xa0, 0xa8, 0x14, 0xe3, 0xde, 0xb0, - 0xd9, 0x10, 0x7f, 0x9d, 0x02, 0xc8, 0x03, 0x12, 0x84, 0xcc, 0xd2, 0x58, - 0x02, 0x5e, 0x35, 0xfe, 0xba, 0x34, 0x80, 0x4f, 0xdb, 0x8e, 0xed, 0xeb, - 0xe5, 0x36, 0x86, 0x64, 0xcf, 0x6a, 0x50, 0xee, 0x0e, 0x12, 0x53, 0x7c, - 0x3f, 0x2a, 0xc4, 0x6d, 0x38, 0x90, 0x14, 0x08, 0x1e, 0x33, 0xee, 0xb8, - 0xb0, 0x28, 0x84, 0xec, 0xa9, 0xec, 0xad, 0x99, 0x79, 0x35, 0x0b, 0x3c, - 0xe9, 0x12, 0xe1, 0xb9, 0xdf, 0x11, 0xfc, 0xbb, 0xa6, 0x92, 0x68, 0x78, - 0x5c, 0x19, 0x5e, 0x0c, 0xb1, 0xda, 0xa8, 0x3d, 0x4d, 0x79, 0x76, 0x90, - 0x7c, 0x5e, 0xe7, 0x2f, 0x04, 0x04, 0x1f, 0xe4, 0x24, 0x4b, 0x1c, 0x5d, - 0x48, 0x76, 0xf1, 0x10, 0x8b, 0x3f, 0x7e, 0x0b, 0xf6, 0x7c, 0x72, 0xff, - 0x80, 0x19, 0x71, 0x44, 0xcc, 0xe4, 0xbe, 0x45, 0x21, 0x60, 0xa3, 0x9a, - 0x65, 0xdf, 0x6c, 0x14, 0x9a, 0x5f, 0x8c, 0xe8, 0x0d, 0xae, 0x9b, 0x9a, - 0x4c, 0x64, 0x84, 0x76, 0x66, 0xaa, 0x24, 0x5a, 0x40, 0xf7, 0x4a, 0xe6, - 0x5b, 0x19, 0x5c, 0xa0, 0x02, 0x07, 0xce, 0x02, 0x5e, 0x0d, 0x31, 0x42, - 0x40, 0xd8, 0xd6, 0x96, 0x1b, 0x41, 0x14, 0x11, 0x27, 0xc9, 0x8a, 0xe2, - 0xee, 0xe1, 0x61, 0xdf, 0x77, 0x75, 0x66, 0x29, 0x78, 0x1d, 0x99, 0xfc, - 0x1e, 0xa1, 0xec, 0x13, 0x33, 0x68, 0x87, 0x30, 0xc3, 0x2c, 0x7d, 0x71, - 0x8e, 0x2b, 0xc3, 0xf6, 0x61, 0x6c, 0xc6, 0x73, 0x54, 0xa8, 0x8c, 0x7d, - 0xea, 0x1a, 0xb8, 0xb0, 0xb0, 0x38, 0xe6, 0xb2, 0x94, 0x70, 0xd2, 0x4a, - 0x2a, 0xa8, 0x34, 0xe7, 0x68, 0xb5, 0x8d, 0xbe, 0xd9, 0xc5, 0xf6, 0xcf, - 0x4d, 0x51, 0x66, 0x08, 0xe0, 0x5a, 0x21, 0x2f, 0x22, 0x7e, 0x71, 0x6a, - 0xf9, 0x67, 0xe4, 0xfe, 0x5b, 0xac, 0xdf, 0xf0, 0x4a, 0xec, 0x6e, 0x67, - 0x82, 0x24, 0xb3, 0x6b, 0x87, 0xda, 0x8d, 0x55, 0x25, 0xcd, 0xfe, 0x6b, - 0x0e, 0xd4, 0x1a, 0x6a, 0xf8, 0x62, 0x33, 0x92, 0x0b, 0x65, 0x9b, 0xb0, - 0x06, 0xce, 0xc1, 0xe6, 0xcb, 0x65, 0x5a, 0x63, 0x5f, 0x54, 0x43, 0xd7, - 0xcd, 0xa8, 0xda, 0xf3, 0x1e, 0x57, 0x78, 0xc7, 0x06, 0x01, 0xa5, 0x37, - 0xdb, 0x1d, 0x51, 0x59, 0xfd, 0xaf, 0xed, 0x73, 0x2c, 0x3a, 0xcd, 0xd2, - 0xfc, 0xac, 0xe7, 0x49, 0x02, 0x1f, 0x24, 0xba, 0x9e, 0xcb, 0x55, 0x49, - 0x55, 0x03, 0x2f, 0x4e, 0xe4, 0x4c, 0x27, 0x24, 0xec, 0x75, 0xa6, 0x11, - 0x0e, 0x92, 0x01, 0x3b, 0x6c, 0xd0, 0x6f, 0x4b, 0x60, 0x7f, 0xcc, 0x7e, - 0x7d, 0x3b, 0xc1, 0xc0, 0x79, 0xb1, 0x88, 0x49, 0x4a, 0x4a, 0x63, 0x80, - 0x18, 0x67, 0xa0, 0x96, 0xd0, 0x34, 0x83, 0x82, 0x4f, 0x81, 0x48, 0x06, - 0xa4, 0xc5, 0x9a, 0x86, 0x43, 0xba, 0x5c, 0x9d, 0x58, 0x4c, 0x7c, 0xc0, - 0x7b, 0x56, 0x12, 0x5d, 0xc6, 0x2e, 0x29, 0xa3, 0xc2, 0x1c, 0x63, 0xd4, - 0xa0, 0xe4, 0x11, 0xf1, 0xc7, 0x97, 0xea, 0xc7, 0xf3, 0x4e, 0xba, 0xc4, - 0xb3, 0xe0, 0x14, 0x1b, 0x7b, 0xb2, 0x1a, 0x76, 0x0d, 0xfd, 0xe6, 0x27, - 0x4a, 0xa6, 0x4f, 0x08, 0xf2, 0x51, 0x11, 0xd7, 0xb6, 0xcc, 0xcd, 0x8f, - 0xe9, 0x88, 0xb4, 0xf0, 0xaf, 0x96, 0x07, 0x1a, 0x15, 0xcc, 0x3f, 0x5c, - 0xe0, 0x4f, 0xfd, 0xf8, 0xf7, 0xf7, 0xad, 0x80, 0xbd, 0x7e, 0x26, 0x55, - 0x96, 0xe3, 0xb5, 0x6e, 0xb6, 0x94, 0x7e, 0x5f, 0x09, 0x14, 0xfa, 0xac, - 0x35, 0xf2, 0x3a, 0x37, 0xfa, 0x69, 0x59, 0xf5, 0xb4, 0x36, 0x66, 0x57, - 0x35, 0x3f, 0xf4, 0xa7, 0x82, 0x1e, 0x02, 0x2f, 0xea, 0x2e, 0x09, 0xe9, - 0x28, 0xf4, 0x29, 0x38, 0x0a, 0xe2, 0x9a, 0xac, 0x76, 0x98, 0x9d, 0xdd, - 0x60, 0xad, 0x06, 0x9a, 0x9e, 0x24, 0x7f, 0x0d, 0x12, 0x1d, 0x49, 0x23, - 0xf8, 0xde, 0x26, 0xeb, 0x55, 0x16, 0xea, 0xd1, 0x20, 0x9f, 0xc1, 0xcc, - 0xd8, 0x64, 0xbd, 0x3c, 0xaa, 0x5b, 0x1c, 0x62, 0xc1, 0xdd, 0x6c, 0xbe, - 0x63, 0x80, 0xb0, 0x65, 0x5f, 0x7d, 0xb2, 0xe4, 0x53, 0x5c, 0xfc, 0xc3, - 0x2f, 0x50, 0x80, 0xa6, 0x72, 0x51, 0x67, 0xdd, 0x6e, 0x16, 0x9f, 0x65, - 0xfe, 0x48, 0x78, 0xe1, 0xf8, 0x63, 0xaa, 0xd6, 0x5f, 0x66, 0x8d, 0x04, - 0xcc, 0xaa, 0x6c, 0xf6, 0x32, 0x8d, 0xce, 0x33, 0xba, 0xa9, 0x0c, 0x98, - 0x28, 0x24, 0x62, 0xde, 0xf0, 0x87, 0xec, 0xa7, 0x31, 0xb8, 0xc8, 0x7b, - 0x1f, 0x5e, 0x1c, 0x47, 0xc3, 0x4d, 0x46, 0xad, 0x71, 0xed, 0x63, 0x3c, - 0xf3, 0xf5, 0xb8, 0x8c, 0x6e, 0xc0, 0x42, 0x40, 0x06, 0x89, 0xf7, 0xbd, - 0x2b, 0xa5, 0x9d, 0x6f, 0x86, 0xf0, 0xf1, 0x27, 0xcc, 0x80, 0xd2, 0x93, - 0x65, 0x7a, 0xfd, 0xca, 0xa3, 0x51, 0x5f, 0xab, 0x8f, 0xce, 0xba, 0x1d, - 0x1d, 0xdf, 0xc8, 0x20, 0x8a, 0x78, 0xcf, 0x4c, 0x5b, 0xc7, 0x9c, 0x58, - 0x03, 0xa9, 0x21, 0x9b, 0x1e, 0x3a, 0x73, 0x18, 0x8b, 0xa3, 0xcf, 0xe3, - 0xac, 0x73, 0xc4, 0xe8, 0x3d, 0xf5, 0xe7, 0x4b, 0x4c, 0x4f, 0xf3, 0x95, - 0x31, 0x5f, 0xce, 0xc4, 0xef, 0xf0, 0x22, 0xb3, 0xc2, 0x16, 0x31, 0xdd, - 0xbe, 0x1b, 0x2f, 0xf1, 0x32, 0x49, 0xc0, 0xcf, 0x34, 0x56, 0x44, 0xf1, - 0x33, 0x4a, 0xf5, 0xdf, 0xcd, 0xee, 0x8a, 0xae, 0xdb, 0x1f, 0x93, 0x5b, - 0xe0, 0x9a, 0xc2, 0x0d, 0x57, 0xd1, 0x4b, 0x45, 0x9d, 0xe1, 0xb0, 0xaf, - 0x76, 0x0c, 0x9a, 0x9e, 0x19, 0x25, 0x27, 0x3d, 0xb6, 0xfb, 0x6f, 0x6b, - 0x79, 0x91, 0xca, 0x0b, 0x31, 0x7c, 0x33, 0xea, 0x59, 0xf2, 0xcb, 0x2f, - 0x79, 0xd4, 0xab, 0xcb, 0xae, 0x53, 0x37, 0x80, 0x27, 0x7d, 0x04, 0x96, - 0x79, 0x75, 0x6b, 0x13, 0xd8, 0xc8, 0x55, 0xf9, 0x33, 0xef, 0xa6, 0xfa, - 0xf6, 0xe8, 0x2f, 0xe1, 0x7b, 0x10, 0x55, 0xe7, 0x41, 0xdf, 0xef, 0xb2, - 0x06, 0x61, 0xe3, 0x91, 0x47, 0xfc, 0x7c, 0x57, 0x87, 0x45, 0x17, 0x34, - 0x7f, 0x7d, 0x09, 0x5a, 0x82, 0x9a, 0x45, 0xdf, 0x5f, 0x3d, 0xcb, 0x1e, - 0x93, 0x53, 0x92, 0xfc, 0x52, 0x13, 0xbc, 0x36, 0x8e, 0x0d, 0x79, 0x98, - 0x39, 0x09, 0xd4, 0x8b, 0x39, 0xf8, 0x21, 0xf1, 0xd2, 0xe5, 0x58, 0x2c, - 0x95, 0x6f, 0x65, 0x3e, 0xf8, 0x91, 0xef, 0x52, 0xb4, 0xea, 0x26, 0xa2, - 0xe4, 0xa8, 0x39, 0x14, 0xf1, 0x02, 0xea, 0x11, 0xfc, 0x3b, 0x75, 0x0a, - 0x7f, 0xc7, 0x48, 0x7f, 0xb9, 0xb8, 0x80, 0x55, 0xf2, 0x11, 0xcc, 0xbb, - 0x9e, 0x19, 0x25, 0x44, 0xab, 0xcb, 0x1d, 0x06, 0x5c, 0x83, 0x10, 0x71, - 0xdd, 0xd3, 0x44, 0x26, 0x19, 0xf8, 0x79, 0x3e, 0xfa, 0x41, 0x78, 0x7c, - 0x31, 0xc4, 0xbb, 0x1d, 0xe8, 0xcc, 0xa0, 0x4c, 0x67, 0xff, 0xd3, 0x25, - 0xa4, 0x2d, 0xa6, 0xdc, 0x9b, 0x64, 0xa5, 0x6d, 0x74, 0x3a, 0xfc, 0x29, - 0xcb, 0x83, 0x86, 0x27, 0x58, 0x35, 0xfd, 0xe3, 0xca, 0x48, 0xb9, 0x8f, - 0xab, 0x3c, 0x29, 0x01, 0x67, 0x12, 0xb3, 0xfb, 0x1b, 0x81, 0x96, 0x7d, - 0x32, 0xe0, 0xc7, 0xd9, 0x11, 0xd2, 0x6f, 0xee, 0xe6, 0xdd, 0xa8, 0x6e, - 0xe3, 0x05, 0xc0, 0x54, 0x64, 0xe3, 0xb5, 0x1f, 0x75, 0x82, 0xf8, 0xa3, - 0x44, 0xb8, 0x90, 0x25, 0x9c, 0x5b, 0x11, 0x18, 0x34, 0x33, 0x4a, 0xd1, - 0x8a, 0x42, 0x8a, 0xcf, 0x32, 0xb5, 0xa6, 0xd1, 0xcf, 0x6f, 0xbe, 0xe5, - 0xaf, 0x42, 0xad, 0xce, 0xba, 0x65, 0x2d, 0x1d, 0x55, 0x21, 0xb0, 0x3a, - 0xef, 0xd6, 0x19, 0xdc, 0x6b, 0xc0, 0x04, 0x52, 0xaf, 0x33, 0x6e, 0x30, - 0x10, 0x7b, 0x3c, 0x2b, 0xbf, 0x1b, 0xc7, 0xa6, 0x9f, 0xc4, 0x3d, 0x69, - 0xfc, 0x43, 0x78, 0x5f, 0x72, 0x9a, 0x32, 0x52, 0x9b, 0xa5, 0x3a, 0x20, - 0x8d, 0xe5, 0xf0, 0x5c, 0x2c, 0xf2, 0xf9, 0xa5, 0x43, 0xfe, 0x46, 0x23, - 0x6e, 0x40, 0xc7, 0x86, 0x6d, 0xcf, 0xc1, 0x61, 0x7f, 0x5b, 0xed, 0xd1, - 0xc9, 0x9c, 0x84, 0x8f, 0xc8, 0x9d, 0x1c, 0xa5, 0x9a, 0x46, 0x09, 0x87, - 0x82, 0x29, 0x29, 0xb3, 0xbc, 0xc2, 0x4b, 0xbc, 0x4d, 0x99, 0xe5, 0x8e, - 0x97, 0xae, 0x92, 0xa1, 0x05, 0xec, 0x0b, 0xab, 0xd3, 0xee, 0xcd, 0x6d, - 0xc2, 0x74, 0x62, 0xb7, 0x27, 0x0d, 0xa8, 0x26, 0xe8, 0x15, 0x4d, 0xe9, - 0xc9, 0xd9, 0xe0, 0x8d, 0x4c, 0xe8, 0xeb, 0x64, 0x3f, 0x21, 0xe8, 0x1d, - 0x8c, 0x34, 0xb7, 0x78, 0x97, 0xa1, 0x4e, 0x4c, 0xe0, 0xf0, 0xf3, 0x47, - 0x3a, 0xc7, 0x10, 0xfa, 0x82, 0x1a, 0xdb, 0x8a, 0xfe, 0xc0, 0x3a, 0x26, - 0x36, 0x8d, 0xd5, 0x78, 0xf3, 0x03, 0xf2, 0x20, 0xbe, 0x1b, 0xa0, 0xf6, - 0x1b, 0x41, 0x0b, 0xe1, 0xb8, 0x4d, 0x7d, 0x09, 0x75, 0x7a, 0xbc, 0xd5, - 0xb4, 0xd7, 0x9f, 0xa9, 0x52, 0xe2, 0xb7, 0x50, 0x62, 0x25, 0x48, 0x35, - 0x83, 0x7a, 0x82, 0x8f, 0x21, 0xa6, 0x8b, 0xf1, 0xfe, 0x47, 0xc2, 0xc2, - 0x00, 0x71, 0x5c, 0x02, 0x74, 0x61, 0x61, 0xde, 0xc9, 0x7e, 0x20, 0x6f, - 0x8d, 0x65, 0x66, 0xd4, 0xbe, 0x00, 0xd6, 0x2f, 0xc9, 0x39, 0x72, 0x68, - 0x0f, 0x13, 0x21, 0xd8, 0x8d, 0xb2, 0x5d, 0xf8, 0x3a, 0xc2, 0x56, 0x0a, - 0xb9, 0xab, 0x46, 0x91, 0x55, 0x6a, 0x32, 0xd5, 0x13, 0x3e, 0x65, 0x13, - 0x51, 0x2a, 0xfe, 0x08, 0xe7, 0x07, 0x7d, 0xaa, 0x69, 0xf2, 0xb0, 0x43, - 0x8c, 0x07, 0xb0, 0x7a, 0x20, 0x63, 0x38, 0x08, 0x42, 0x8b, 0x4a, 0x6d, - 0x67, 0x99, 0x2a, 0x20, 0x30, 0x56, 0xa1, 0xca, 0xcb, 0xa4, 0xa8, 0xca, - 0xce, 0xb6, 0x07, 0x13, 0xbf, 0x81, 0x64, 0x92, 0xca, 0x69, 0xcb, 0x80, - 0xb3, 0x64, 0xb8, 0xb8, 0xf0, 0xee, 0xaf, 0x37, 0x4a, 0x23, 0x5d, 0xbb, - 0x6f, 0x59, 0xa6, 0x5f, 0xac, 0x7c, 0x0b, 0xe9, 0x53, 0xc7, 0xc7, 0x56, - 0x09, 0xe6, 0x5c, 0xfd, 0x9d, 0xe4, 0x1b, 0x30, 0x7d, 0x96, 0x12, 0x4d, - 0x17, 0x60, 0xd8, 0xf6, 0x30, 0x2c, 0xca, 0x91, 0x96, 0x02, 0x47, 0xec, - 0x38, 0x20, 0xd2, 0x16, 0xbf, 0xd8, 0x33, 0xd7, 0x23, 0x8e, 0x11, 0x65, - 0x38, 0xaf, 0xa9, 0x76, 0x76, 0xae, 0x84, 0x96, 0xa4, 0x46, 0xa4, 0x64, - 0x9c, 0x5d, 0x17, 0x78, 0x85, 0x41, 0x49, 0x67, 0x71, 0xce, 0x1d, 0x71, - 0x0b, 0xe5, 0xce, 0xa6, 0x85, 0xe1, 0xaf, 0xe5, 0x34, 0x5c, 0x5d, 0xaf, - 0x99, 0x29, 0x79, 0x28, 0xa1, 0xf4, 0xa0, 0x97, 0xa3, 0x6b, 0xb0, 0xbd, - 0x69, 0xed, 0x95, 0x1c, 0x88, 0xd3, 0x79, 0x5d, 0xdf, 0x05, 0x66, 0x66, - 0xe8, 0x0f, 0x97, 0x27, 0x82, 0x50, 0x4a, 0xc3, 0xfd, 0xb8, 0x1f, 0xee, - 0x83, 0x09, 0x11, 0x11, 0xa6, 0x02, 0x46, 0x27, 0x62, 0xbf, 0x61, 0x99, - 0xe1, 0xcd, 0x25, 0x87, 0x96, 0x47, 0xdf, 0x3f, 0x87, 0x62, 0x7f, 0x68, - 0x57, 0x27, 0xac, 0xf6, 0x38, 0x54, 0xbf, 0xac, 0xaf, 0x6d, 0x9c, 0x19, - 0xeb, 0xfd, 0x31, 0x86, 0x8f, 0xa7, 0x02, 0x91, 0xf9, 0x02, 0x03, 0x50, - 0xdb, 0xf5, 0x1d, 0xfd, 0x88, 0x1a, 0x5a, 0x51, 0xc2, 0xf2, 0xbf, 0xdb, - 0xa8, 0xe6, 0x7a, 0x41, 0x22, 0xfa, 0x90, 0xed, 0x94, 0xc4, 0xf9, 0x35, - 0x90, 0x84, 0xcf, 0x09, 0xb7, 0x9f, 0x8c, 0xb5, 0x45, 0x18, 0x0b, 0x7c, - 0x94, 0x8c, 0x3a, 0x84, 0x42, 0xbb, 0x9a, 0xb9, 0x54, 0x06, 0xee, 0x1c, - 0xab, 0xd6, 0x5e, 0x1e, 0x5c, 0xd5, 0xdd, 0xe0, 0x76, 0xa3, 0xbd, 0x58, - 0x99, 0x69, 0x81, 0x42, 0xbb, 0x55, 0x92, 0x4d, 0x29, 0xca, 0x27, 0x89, - 0xdf, 0x00, 0x3b, 0x2f, 0x6f, 0x54, 0x53, 0xc5, 0xb7, 0x42, 0xca, 0x64, - 0x2d, 0xe3, 0xfe, 0x9c, 0xad, 0x78, 0x97, 0x40, 0x96, 0xbb, 0x5a, 0x70, - 0xa6, 0x1c, 0x98, 0xc7, 0xb6, 0xe7, 0xdf, 0xc1, 0x92, 0x24, 0x2b, 0xbb, - 0x66, 0x36, 0x6e, 0x98, 0xc4, 0x1e, 0x54, 0xc5, 0x6b, 0x07, 0xde, 0x6c, - 0xdd, 0xbf, 0x9e, 0x7f, 0xe1, 0xa9, 0x22, 0xaa, 0x90, 0x1c, 0xf9, 0xfc, - 0x0b, 0x9d, 0xfc, 0x27, 0x36, 0x7f, 0xb2, 0xe1, 0x0a, 0x85, 0xa8, 0xba, - 0xbc, 0x8d, 0x6e, 0xb1, 0x28, 0x7d, 0x6a, 0x65, 0x52, 0xc6, 0x52, 0x12, - 0x5b, 0x3d, 0xd0, 0x46, 0x9c, 0xd7, 0xbf, 0x72, 0x7b, 0x98, 0x4a, 0x29, - 0xb2, 0xf3, 0xea, 0xc3, 0x6a, 0xec, 0x8e, 0xe6, 0xe4, 0xfa, 0x9f, 0xf4, - 0xf7, 0x44, 0x46, 0xb1, 0x90, 0xfe, 0xfa, 0x49, 0x3d, 0xf6, 0x56, 0x41, - 0x45, 0x5e, 0xd7, 0xae, 0xb1, 0x5b, 0x6c, 0x0a, 0xb3, 0x03, 0x23, 0x0f, - 0x7b, 0x94, 0x06, 0x8a, 0xc0, 0x65, 0xd2, 0xe1, 0xa2, 0x1c, 0x58, 0x12, - 0xcd, 0xf8, 0x1d, 0x01, 0x06, 0xd9, 0x0b, 0x4f, 0x19, 0x79, 0xb4, 0x84, - 0x44, 0x9e, 0x6b, 0x05, 0x9d, 0xfd, 0x96, 0x59, 0x03, 0xd6, 0xfc, 0x13, - 0x2c, 0xb9, 0x75, 0x53, 0xc0, 0x8b, 0x46, 0x93, 0x95, 0xd5, 0xbe, 0x5f, - 0xfd, 0x5d, 0x01, 0x30, 0x8c, 0xa8, 0xf8, 0x98, 0x30, 0xcd, 0xbd, 0x79, - 0xea, 0x14, 0x52, 0x11, 0x03, 0x0f, 0x1f, 0x78, 0x6b, 0xfd, 0xdd, 0xb4, - 0x9a, 0x41, 0x98, 0x47, 0x12, 0x9c, 0x5a, 0xcd, 0x91, 0xa8, 0xad, 0xd5, - 0x62, 0xcf, 0x13, 0xc4, 0xec, 0x75, 0xed, 0x22, 0xba, 0x03, 0x0e, 0x9d, - 0x96, 0xa6, 0xd7, 0xc0, 0x9f, 0xdb, 0x66, 0x98, 0x54, 0x4a, 0x49, 0x5e, - 0xb3, 0x35, 0x67, 0x36, 0x95, 0xc9, 0xe9, 0xc7, 0x27, 0x5d, 0x99, 0x86, - 0x3a, 0x9e, 0x7e, 0x6a, 0xba, 0x7f, 0x34, 0xbd, 0xd5, 0x8f, 0xa3, 0x8a, - 0x3c, 0x7b, 0xdb, 0x5d, 0x4f, 0xdf, 0xc9, 0x37, 0x36, 0x93, 0x0f, 0xf7, - 0x78, 0x9a, 0xf7, 0x61, 0xb2, 0x7b, 0x6d, 0x72, 0xb7, 0xee, 0x1c, 0xef, - 0xb7, 0x69, 0x03, 0xc9, 0x88, 0x0c, 0x57, 0xe1, 0x37, 0x56, 0x91, 0xc4, - 0xc3, 0x4b, 0x18, 0xab, 0xfb, 0x2a, 0x26, 0xa1, 0x73, 0x8e, 0xf4, 0x09, - 0x13, 0x2a, 0x9e, 0x7c, 0xdb, 0xf6, 0x06, 0x34, 0xd3, 0x87, 0x76, 0xe0, - 0x3b, 0x12, 0xd5, 0x75, 0x03, 0xf0, 0x55, 0xa2, 0xbc, 0x1f, 0x10, 0x9f, - 0x56, 0x9b, 0xf8, 0x70, 0xca, 0xc0, 0xde, 0x06, 0x73, 0xab, 0xad, 0x1f, - 0xea, 0xd7, 0xb2, 0x6d, 0xb2, 0x5e, 0x46, 0x40, 0x32, 0xc0, 0x6b, 0x78, - 0xf6, 0x2f, 0xc2, 0x9b, 0x20, 0x09, 0xd2, 0xdb, 0xbb, 0xfb, 0x05, 0x15, - 0xf8, 0xf5, 0x58, 0x3f, 0x26, 0xab, 0x33, 0x66, 0xaf, 0x3a, 0xa5, 0xfc, - 0x76, 0x2e, 0x11, 0x94, 0x46, 0x43, 0x42, 0x1c, 0x68, 0xfe, 0xbb, 0x89, - 0x0c, 0x35, 0xf7, 0x72, 0xe5, 0x48, 0x98, 0x59, 0x1d, 0x7b, 0x88, 0x25, - 0x3e, 0x32, 0x74, 0x26, 0xec, 0xde, 0x8e, 0x22, 0x43, 0x56, 0x2f, 0x67, - 0x95, 0xb4, 0x87, 0x8a, 0x63, 0xd3, 0x88, 0x6e, 0x74, 0xf5, 0x50, 0x23, - 0x8b, 0x8f, 0xd9, 0xa0, 0x04, 0xea, 0x2f, 0xdf, 0x71, 0x3c, 0xe1, 0x50, - 0x82, 0x97, 0xd9, 0xfd, 0x8f, 0x5d, 0x19, 0x9f, 0x56, 0x4f, 0x68, 0xff, - 0x19, 0x09, 0xd1, 0x9e, 0x6f, 0x1f, 0xfb, 0xc0, 0xc7, 0x41, 0x31, 0x4e, - 0x91, 0x0c, 0xea, 0xd8, 0x6c, 0xfc, 0x76, 0x92, 0x55, 0x82, 0x13, 0x05, - 0x64, 0xcc, 0xa0, 0xca, 0x53, 0x6c, 0xe0, 0x68, 0x14, 0x4c, 0x88, 0xbe, - 0xeb, 0x0d, 0xc3, 0x49, 0x03, 0xa8, 0x50, 0x0e, 0xb8, 0xe8, 0xe0, 0xb1, - 0x8b, 0x05, 0x88, 0xfb, 0xd8, 0x99, 0x12, 0x36, 0xf0, 0xd9, 0xde, 0x7a, - 0xd5, 0x41, 0x41, 0xf0, 0x18, 0x8a, 0xee, 0x11, 0xc7, 0xa3, 0x0a, 0x52, - 0x2d, 0xfa, 0x92, 0x19, 0xf0, 0xf9, 0x79, 0xa1, 0x53, 0x68, 0x11, 0x95, - 0x5d, 0x8e, 0xcc, 0x06, 0xad, 0x93, 0x5a, 0x7c, 0x06, 0xa2, 0xc5, 0xad, - 0x2d, 0xbb, 0x86, 0x5a, 0x37, 0x0f, 0x35, 0xac, 0xf5, 0xbb, 0x18, 0xea, - 0x68, 0xff, 0x69, 0xbf, 0x6c, 0xe5, 0x25, 0xcf, 0x22, 0x2e, 0x9e, 0xbb, - 0x24, 0xf0, 0xa0, 0xf7, 0xad, 0xa8, 0xf4, 0x85, 0x6c, 0x36, 0x1d, 0xe9, - 0x66, 0x99, 0xb0, 0x4f, 0x64, 0x42, 0xbf, 0x1f, 0x30, 0xd6, 0x1b, 0xfd, - 0x31, 0xb7, 0xc7, 0xc0, 0x7f, 0x72, 0xda, 0x67, 0x1f, 0xf8, 0x77, 0x2f, - 0x36, 0x9a, 0x82, 0xfb, 0xcb, 0xbe, 0xac, 0xe3, 0x95, 0x81, 0x99, 0xfd, - 0x3d, 0xa9, 0xad, 0xc7, 0xdf, 0x58, 0x7f, 0x18, 0x12, 0x04, 0xa8, 0xb6, - 0x8f, 0xcb, 0x6a, 0x4f, 0x4b, 0x37, 0xc1, 0xc3, 0x8f, 0xda, 0x69, 0x38, - 0x17, 0x40, 0xfb, 0x62, 0x4b, 0x64, 0xd5, 0x70, 0x3a, 0xe8, 0xa9, 0x0c, - 0x9d, 0x0b, 0xd9, 0x1b, 0xee, 0x14, 0x46, 0x7c, 0xf4, 0x34, 0xd0, 0x0b, - 0x81, 0x6f, 0x6b, 0x44, 0x96, 0xd8, 0x94, 0x2e, 0x99, 0x42, 0x3a, 0xc6, - 0x22, 0xa9, 0xb0, 0xc8, 0xa6, 0x6d, 0x0c, 0x43, 0x32, 0x63, 0x92, 0x9e, - 0xf6, 0xa7, 0x8d, 0xeb, 0xe4, 0x89, 0x98, 0x3f, 0xed, 0xdf, 0xf0, 0xe4, - 0xa4, 0x16, 0x8a, 0xbe, 0xed, 0x62, 0xd3, 0xbf, 0x85, 0x31, 0x00, 0x73, - 0xf7, 0x04, 0x44, 0xe5, 0xbc, 0xb1, 0x31, 0xbf, 0xfe, 0x7d, 0xb9, 0xe2, - 0x53, 0xab, 0xf2, 0x05, 0xc6, 0x1e, 0x46, 0xfe, 0x42, 0xcc, 0x9b, 0xf9, - 0xca, 0xd5, 0xb7, 0x76, 0xfa, 0x82, 0x02, 0x93, 0x24, 0x31, 0x8c, 0xac, - 0x55, 0x7d, 0xc1, 0xc9, 0xf2, 0xfe, 0xa7, 0x68, 0x86, 0x4e, 0xff, 0xd5, - 0xa6, 0x69, 0x36, 0x68, 0x21, 0x5a, 0x89, 0x60, 0x7b, 0x8e, 0xc2, 0x7b, - 0xda, 0x00, 0xeb, 0x33, 0x4d, 0x34, 0x92, 0xab, 0x6c, 0xf9, 0xb7, 0xcc, - 0x18, 0x92, 0x87, 0x47, 0x3a, 0x9c, 0x81, 0xd8, 0x61, 0xc6, 0xcb, 0x1e, - 0xb0, 0x5c, 0x26, 0x8a, 0xbc, 0x54, 0x8a, 0x14, 0x4b, 0x7e, 0xe5, 0xaf, - 0xb6, 0x3f, 0x9b, 0x19, 0x15, 0x32, 0xf6, 0x6e, 0x83, 0x61, 0xa8, 0xde, - 0x02, 0xd4, 0x1e, 0x1e, 0x3a, 0x54, 0x37, 0xd2, 0xaa, 0xca, 0xd0, 0x2d, - 0x01, 0x88, 0x2a, 0x14, 0x48, 0xfb, 0x88, 0xd7, 0xf2, 0xaf, 0xdd, 0x7d, - 0x48, 0x41, 0xd4, 0x84, 0x9a, 0xb2, 0xb5, 0x10, 0xed, 0x2a, 0x15, 0xf6, - 0x15, 0xd1, 0xb5, 0x2a, 0x6a, 0x9f, 0xd7, 0x23, 0xf5, 0x48, 0x21, 0x44, - 0x22, 0xcc, 0xe6, 0xb7, 0xdd, 0xf4, 0x8e, 0x9a, 0x2d, 0x88, 0xb6, 0xff, - 0x28, 0xa8, 0xe5, 0x22, 0xe6, 0xaf, 0xa4, 0xd5, 0xa3, 0x41, 0xb1, 0x81, - 0x88, 0xdf, 0xdf, 0xdc, 0xb6, 0xed, 0x7c, 0x81, 0x67, 0xc4, 0xe0, 0x10, - 0xe2, 0x27, 0xf5, 0xe6, 0xdb, 0x00, 0xe6, 0xda, 0x7e, 0xdb, 0xf4, 0x97, - 0x04, 0xfa, 0x47, 0x5a, 0x4c, 0x0f, 0xba, 0xf0, 0xf3, 0x01, 0x2e, 0xba, - 0x59, 0xfd, 0xee, 0xd5, 0x7d, 0x5f, 0x05, 0x08, 0xfe, 0x92, 0x68, 0x29, - 0x2e, 0x39, 0x75, 0x33, 0x54, 0x43, 0x15, 0xb9, 0xf6, 0x1a, 0x10, 0x8c, - 0x7d, 0xd9, 0x0b, 0x9a, 0x9a, 0x5c, 0x1b, 0x90, 0x52, 0x48, 0x23, 0x48, - 0xd6, 0x99, 0x8f, 0x8e, 0x75, 0x6a, 0x9b, 0x09, 0x88, 0x24, 0xa4, 0x92, - 0x71, 0xf2, 0xb8, 0x69, 0xae, 0xd5, 0x58, 0x5a, 0x9c, 0xae, 0x62, 0x1f, - 0x64, 0xb2, 0xfc, 0x0d, 0xe1, 0x32, 0x85, 0xe0, 0x80, 0xbf, 0x33, 0x69, - 0x6c, 0xde, 0x09, 0xd3, 0xaf, 0x09, 0xcc, 0x39, 0xc6, 0x96, 0xfa, 0xf0, - 0xe5, 0x08, 0x2a, 0xb2, 0x3d, 0xa0, 0x56, 0x36, 0xd9, 0xb7, 0xd0, 0xd4, - 0x40, 0x56, 0x90, 0x57, 0x7d, 0xa9, 0xf1, 0xb9, 0x2d, 0x01, 0x5b, 0x95, - 0x7e, 0x96, 0x5a, 0xfb, 0x2d, 0x88, 0xb7, 0xa0, 0x99, 0xfc, 0x3c, 0x77, - 0xc8, 0x7f, 0x7d, 0x61, 0xbb, 0x4c, 0x58, 0x63, 0xbc, 0xfd, 0x0e, 0x6e, - 0x76, 0x8a, 0x12, 0x87, 0xbd, 0xe3, 0x5f, 0xa3, 0x12, 0x95, 0x57, 0x4d, - 0xcf, 0xf9, 0xc1, 0xe4, 0xd6, 0x4a, 0x0c, 0xa0, 0x21, 0xf1, 0xc3, 0xcb, - 0x91, 0xf9, 0xd0, 0x44, 0xa8, 0xd8, 0xca, 0x31, 0x4f, 0x65, 0xd3, 0x9a, - 0x3a, 0x3b, 0x83, 0xc9, 0x01, 0x9f, 0xa6, 0x05, 0xfb, 0x8c, 0x40, 0x53, - 0x3e, 0xde, 0x46, 0x00, 0x20, 0x23, 0xaf, 0xa7, 0x16, 0x92, 0xe8, 0x3a, - 0x00, 0x60, 0x47, 0x80, 0x27, 0xc2, 0xc9, 0x4a, 0xfc, 0xe6, 0x3c, 0x32, - 0xd3, 0x37, 0x08, 0x4e, 0x25, 0x65, 0x19, 0x83, 0x11, 0x8e, 0xb8, 0xdb, - 0xa4, 0x02, 0x92, 0xb3, 0x96, 0x38, 0xaf, 0x04, 0x5d, 0x06, 0xfd, 0x36, - 0x10, 0x3e, 0xb0, 0x53, 0x5f, 0xb8, 0x31, 0x09, 0xfa, 0xaa, 0x52, 0x45, - 0x38, 0x23, 0x9f, 0x17, 0x97, 0x30, 0x2f, 0x1b, 0x13, 0xa7, 0x1a, 0x9c, - 0x9d, 0x67, 0xc3, 0x4c, 0xc9, 0xf2, 0x4b, 0x9d, 0xd7, 0x8d, 0x42, 0x17, - 0xf8, 0xce, 0x77, 0xc6, 0x1b, 0x39, 0x0e, 0x20, 0x9c, 0xe8, 0xbb, 0x79, - 0xf4, 0x9a, 0x83, 0xf3, 0x56, 0x4e, 0x7c, 0x17, 0xf6, 0xcd, 0xf9, 0x1a, - 0x43, 0x00, 0x41, 0x9e, 0xad, 0x15, 0xc6, 0xe5, 0x06, 0xe1, 0x6d, 0x5c, - 0x57, 0x45, 0xf3, 0xf1, 0x69, 0xde, 0x15, 0xd8, 0xd7, 0xe7, 0xcf, 0xeb, - 0xf0, 0x41, 0xaa, 0xa5, 0xe7, 0xc3, 0x37, 0x5f, 0x7c, 0x87, 0xd5, 0x61, - 0xe8, 0x1d, 0x11, 0xd2, 0xb7, 0x63, 0x62, 0xe7, 0xeb, 0x18, 0xad, 0xad, - 0xfb, 0x88, 0x47, 0x53, 0xd1, 0x1f, 0x71, 0x95, 0xf6, 0x7a, 0x9b, 0x85, - 0xe4, 0x2d, 0x9f, 0x40, 0x2a, 0x46, 0xd8, 0xae, 0x5a, 0x28, 0x10, 0xf8, - 0xf5, 0x02, 0x48, 0x19, 0x81, 0x7c, 0x33, 0x82, 0x5f, 0x75, 0xd4, 0x29, - 0x7e, 0x82, 0xa7, 0x8c, 0x42, 0x7e, 0x39, 0xdc, 0xcb, 0x27, 0xa9, 0x8a, - 0xd2, 0xad, 0xa4, 0x08, 0xb2, 0xc0, 0x0d, 0xa5, 0x26, 0x80, 0xfa, 0xad, - 0xc4, 0x4e, 0xd5, 0x55, 0x45, 0x80, 0x61, 0x84, 0x3f, 0xcf, 0xc2, 0x60, - 0xe6, 0x92, 0x2f, 0xce, 0x9c, 0x69, 0xb1, 0x9a, 0xae, 0x98, 0x2a, 0x4e, - 0x2e, 0x24, 0xd0, 0xd9, 0xb8, 0xba, 0xcd, 0xb7, 0x88, 0x1e, 0xda, 0xea, - 0xc5, 0xad, 0x63, 0xef, 0x79, 0x71, 0x30, 0x79, 0x68, 0x1d, 0x21, 0x29, - 0x7a, 0xe7, 0xe1, 0xaa, 0x57, 0x65, 0x37, 0xd2, 0x08, 0x69, 0x1c, 0x6e, - 0x66, 0x74, 0xff, 0xf8, 0x9d, 0x21, 0x95, 0xf9, 0x54, 0xde, 0x97, 0x6d, - 0xa8, 0x64, 0x23, 0xe8, 0xc8, 0x62, 0xf4, 0x46, 0x85, 0x92, 0xad, 0x3b, - 0x96, 0x2f, 0x73, 0xa5, 0x5a, 0xb9, 0x58, 0x0c, 0x64, 0x3d, 0x63, 0xcb, - 0x0b, 0xef, 0xb0, 0xb1, 0x6c, 0x02, 0xc6, 0xd2, 0x9e, 0xf8, 0xd7, 0x13, - 0x2b, 0xaf, 0x11, 0x61, 0xc9, 0x5d, 0xb6, 0x16, 0x65, 0xce, 0xfe, 0x5d, - 0x3a, 0xb5, 0x02, 0xe5, 0x87, 0x60, 0xb3, 0xf0, 0x74, 0x5a, 0x62, 0x1d, - 0x68, 0xd8, 0xce, 0x5b, 0x48, 0xb5, 0x76, 0x98, 0x1a, 0x9b, 0xa2, 0x8e, - 0x27, 0xa0, 0xca, 0x47, 0x34, 0x3f, 0xa3, 0x74, 0xc9, 0x45, 0xb3, 0xa1, - 0x99, 0x6b, 0xd7, 0x07, 0xa2, 0xe7, 0x73, 0x65, 0xa6, 0x82, 0x50, 0x7a, - 0x2d, 0xe1, 0x79, 0xcd, 0xeb, 0x43, 0xba, 0x2a, 0xc1, 0x53, 0xc4, 0xac, - 0x5c, 0x36, 0xf6, 0x32, 0x9a, 0x8b, 0x28, 0x08, 0x5f, 0xf2, 0xd6, 0x74, - 0xea, 0x11, 0x33, 0x8e, 0x5d, 0x90, 0x28, 0x1f, 0x47, 0x6e, 0x63, 0xee, - 0x8e, 0xa7, 0x28, 0x62, 0x9c, 0x5f, 0xfd, 0xbe, 0xc1, 0x0f, 0x16, 0xe9, - 0x54, 0x5c, 0xf5, 0x9a, 0x87, 0x50, 0x83, 0xe3, 0xf8, 0xb2, 0x42, 0x67, - 0x12, 0xa5, 0x89, 0xd3, 0xbe, 0x09, 0xb9, 0x2f, 0x15, 0xb5, 0x9b, 0x58, - 0x60, 0xaa, 0x7c, 0xf5, 0xee, 0x07, 0x30, 0xac, 0x0d, 0x4d, 0xd0, 0xf6, - 0xbb, 0x95, 0x80, 0xbc, 0x21, 0xae, 0xba, 0x63, 0xbb, 0xa1, 0x1b, 0xf0, - 0x87, 0x7c, 0x7f, 0x7b, 0x12, 0xce, 0x74, 0x44, 0x27, 0xae, 0x4e, 0x8f, - 0xaf, 0xd8, 0xf6, 0x7c, 0xb4, 0x61, 0xd0, 0xb8, 0x0e, 0x9c, 0x7e, 0xc0, - 0xce, 0x07, 0xef, 0xe7, 0x2d, 0x7a, 0x11, 0x70, 0x37, 0x5f, 0xc3, 0xed, - 0x18, 0x45, 0xda, 0x27, 0x6c, 0x5e, 0xc1, 0xe7, 0xc1, 0x0c, 0x49, 0x84, - 0xb6, 0x42, 0x1e, 0x2c, 0xc9, 0x3c, 0xb9, 0xc9, 0xe6, 0xd9, 0x59, 0xb3, - 0xaa, 0xf8, 0xf1, 0x2f, 0x03, 0x74, 0xd9, 0xba, 0x25, 0x0a, 0xa4, 0xbe, - 0xb0, 0x64, 0xea, 0x86, 0x19, 0x94, 0xb3, 0xc5, 0x69, 0x0e, 0x66, 0x72, - 0x04, 0x1b, 0x76, 0x02, 0x88, 0xba, 0xeb, 0x91, 0xed, 0x7c, 0x8c, 0x1f, - 0xf9, 0xb8, 0x58, 0x74, 0x08, 0x4e, 0x5b, 0xdc, 0xc5, 0x89, 0xa8, 0x2f, - 0x8e, 0x0d, 0x26, 0xa2, 0x78, 0x85, 0xc0, 0x8f, 0x7c, 0x3f, 0x07, 0x00, - 0x15, 0x40, 0x7b, 0xa6, 0x0e, 0xf0, 0x38, 0x58, 0xca, 0xe0, 0xd2, 0x8e, - 0xa2, 0x75, 0x7b, 0x26, 0xc3, 0xd3, 0x7b, 0x27, 0xaa, 0x7e, 0x5d, 0x8a, - 0x3d, 0xc9, 0x5d, 0x0c, 0x26, 0x1a, 0xab, 0xb2, 0xe2, 0x55, 0xfb, 0xaf, - 0xae, 0x37, 0xd5, 0x95, 0xc4, 0xe2, 0x3d, 0x45, 0x19, 0x2f, 0xbf, 0xd6, - 0xfa, 0x69, 0xd3, 0x4d, 0xe7, 0x9c, 0xd6, 0x6e, 0x5a, 0x42, 0x4f, 0xb0, - 0x29, 0x57, 0x3e, 0x05, 0x0c, 0xfa, 0x60, 0x93, 0x02, 0xd5, 0x87, 0x73, - 0x4c, 0x5e, 0x3c, 0xf8, 0x92, 0xe2, 0x3e, 0xbf, 0x27, 0x81, 0x85, 0x93, - 0xbd, 0x30, 0x3b, 0xf3, 0x8d, 0x80, 0x7a, 0x48, 0x6f, 0x6d, 0xb2, 0xe3, - 0x53, 0xf5, 0xfd, 0x1d, 0xc2, 0xa4, 0x99, 0x63, 0x34, 0xd9, 0x09, 0x68, - 0x04, 0x3c, 0x92, 0xff, 0x09, 0xac, 0xb6, 0x03, 0x97, 0x0e, 0xde, 0x70, - 0x2a, 0xbc, 0x22, 0x28, 0x0b, 0x52, 0xca, 0x28, 0xbf, 0x87, 0xb1, 0xe3, - 0xc5, 0x1e, 0x26, 0x02, 0x45, 0xd7, 0x7c, 0x66, 0x0d, 0xd1, 0x72, 0xea, - 0x31, 0xe5, 0x7a, 0x9c, 0x2d, 0xbf, 0x18, 0x7c, 0xaa, 0xc7, 0xdd, 0x81, - 0xb0, 0xf1, 0xa8, 0x1e, 0x06, 0x2f, 0xc7, 0xf8, 0x6b, 0xa4, 0xec, 0xb0, - 0x65, 0xec, 0x04, 0x6f, 0x17, 0x6f, 0xd1, 0x46, 0x00, 0x5e, 0x5c, 0x21, - 0xc1, 0x9e, 0x32, 0x88, 0x8f, 0x15, 0x6f, 0x70, 0x30, 0x98, 0x36, 0xfd, - 0x3d, 0x2e, 0xf5, 0x11, 0x38, 0x40, 0x77, 0x12, 0x90, 0x53, 0xa6, 0x9a, - 0xea, 0x30, 0xfd, 0xe7, 0x1c, 0x0f, 0xfb, 0x9b, 0xb5, 0x28, 0x19, 0xba, - 0x02, 0x2d, 0x4c, 0x74, 0xcb, 0x8a, 0xaa, 0x31, 0x34, 0xb6, 0x46, 0x02, - 0x6e, 0x54, 0xa3, 0x2c, 0x92, 0xfb, 0x25, 0x8c, 0x60, 0x63, 0x43, 0xe2, - 0xd0, 0xa3, 0xca, 0x54, 0x41, 0x3f, 0xa2, 0x0b, 0x1d, 0x19, 0xaf, 0xf0, - 0xfd, 0x97, 0x5d, 0xbe, 0x9c, 0xf2, 0x81, 0x9c, 0x85, 0xac, 0xee, 0xee, - 0xb3, 0x21, 0x6a, 0x2e, 0x99, 0x6f, 0xa6, 0x04, 0x21, 0xbf, 0x65, 0x01, - 0x64, 0xff, 0x7e, 0x74, 0x96, 0x75, 0xfd, 0x9a, 0xf1, 0xf3, 0x01, 0xb7, - 0xd2, 0x0d, 0x57, 0x1b, 0xba, 0xc1, 0x5e, 0x35, 0xfa, 0x61, 0x41, 0xbf, - 0xc8, 0x27, 0x6f, 0x4c, 0x5c, 0x69, 0x88, 0xb6, 0xf6, 0xd8, 0xc9, 0x5c, - 0x6b, 0x97, 0x7e, 0x90, 0x99, 0x8c, 0x1a, 0x51, 0x05, 0xa0, 0xb2, 0x7f, - 0xb0, 0xb2, 0xa6, 0x91, 0x99, 0x09, 0x9d, 0xf9, 0x42, 0x4a, 0xc4, 0x90, - 0xa5, 0xb5, 0xfc, 0xd3, 0x98, 0x1f, 0xd5, 0xaa, 0x1d, 0x7f, 0x5c, 0x2d, - 0x2d, 0xd3, 0x0a, 0xa7, 0x2d, 0x5d, 0x12, 0x4d, 0x36, 0x7a, 0x5c, 0x14, - 0x1f, 0x37, 0x8e, 0xf8, 0xb0, 0x9c, 0x3e, 0xcb, 0x6a, 0xbc, 0x79, 0xed, - 0x29, 0xed, 0x7d, 0xb4, 0x33, 0xc1, 0xfa, 0xab, 0x56, 0xb6, 0x61, 0x30, - 0xc4, 0xcd, 0x8d, 0xa7, 0x0f, 0x3f, 0xe8, 0x61, 0x19, 0xdf, 0xcc, 0x22, - 0xa0, 0x4e, 0x96, 0x1c, 0x93, 0xd9, 0x71, 0xe8, 0xeb, 0xad, 0xf4, 0xe2, - 0x65, 0xf2, 0xe6, 0xb1, 0x61, 0xc3, 0x3c, 0xb4, 0xc7, 0xd1, 0x4f, 0x7a, - 0x56, 0x0f, 0x9b, 0x3a, 0x75, 0x7d, 0xb3, 0x37, 0x29, 0x70, 0x02, 0x5b, - 0x79, 0x99, 0xe0, 0x7e, 0x5b, 0xfb, 0x4e, 0x1d, 0xf8, 0xa1, 0xf4, 0x71, - 0xaf, 0x4f, 0xdb, 0xcd, 0x1a, 0xc1, 0xa1, 0x1e, 0x83, 0x06, 0xaa, 0x0d, - 0x76, 0x81, 0x0b, 0x98, 0xd7, 0x9b, 0x4c, 0x4b, 0x13, 0xff, 0xec, 0x9d, - 0xfc, 0x62, 0xd8, 0x21, 0x7f, 0xd8, 0xe4, 0x4e, 0x6d, 0xb8, 0x07, 0x18, - 0x79, 0x08, 0x19, 0xf9, 0x73, 0x4b, 0xbe, 0x58, 0x19, 0x80, 0x23, 0x8c, - 0xeb, 0x13, 0x9c, 0x49, 0x31, 0x3b, 0xb2, 0x68, 0x6b, 0xd5, 0x0f, 0x7d, - 0x36, 0x5b, 0xc9, 0x02, 0x79, 0xd1, 0xa7, 0xee, 0x92, 0xf1, 0x1d, 0x32, - 0x78, 0xde, 0xa9, 0x11, 0xb3, 0x64, 0x78, 0x1f, 0x18, 0x14, 0x88, 0xe8, - 0xb8, 0xaf, 0x52, 0x86, 0xd8, 0xf7, 0xf2, 0x39, 0xfe, 0xc9, 0x9d, 0x98, - 0xf9, 0x61, 0x00, 0x71, 0x67, 0x72, 0x9a, 0x38, 0xb9, 0x9b, 0xfa, 0x94, - 0x68, 0x64, 0xe9, 0xc9, 0x94, 0x55, 0x19, 0x08, 0x10, 0x0c, 0x8b, 0x35, - 0x16, 0x9c, 0x9c, 0xee, 0xde, 0xc0, 0x1c, 0xcf, 0x7a, 0x0a, 0xe8, 0xb4, - 0xfa, 0x51, 0x10, 0x2b, 0x8b, 0x1b, 0x8e, 0xef, 0xb6, 0x8a, 0x27, 0x88, - 0xe4, 0x40, 0x3b, 0xa0, 0x3b, 0x82, 0xd0, 0x70, 0xbb, 0x4f, 0x76, 0x2c, - 0x82, 0x4d, 0x6a, 0xe9, 0xd9, 0xf9, 0x8e, 0xed, 0xb4, 0xe5, 0x99, 0xb4, - 0xa3, 0x78, 0x23, 0xfe, 0xdf, 0xdd, 0x83, 0xc3, 0xf8, 0xab, 0xea, 0x31, - 0xaf, 0x10, 0x32, 0xbe, 0xba, 0x5f, 0x0e, 0xea, 0xf2, 0xe5, 0xf8, 0xde, - 0x2f, 0x60, 0x8d, 0x15, 0x9b, 0x52, 0xb5, 0x97, 0xa1, 0x36, 0x41, 0x91, - 0x6d, 0x76, 0x1d, 0x74, 0xc9, 0x28, 0x1a, 0x28, 0xb6, 0xc5, 0x3d, 0xd7, - 0x65, 0xc6, 0x8e, 0x1b, 0x35, 0xfb, 0xa6, 0x43, 0x88, 0xcc, 0x0a, 0xf4, - 0xdd, 0x92, 0x8d, 0x01, 0xb0, 0xbc, 0x72, 0xbf, 0x53, 0x30, 0x05, 0x97, - 0xb3, 0xf3, 0x8e, 0xa1, 0x59, 0x65, 0x76, 0x2b, 0xc2, 0xee, 0xca, 0xbe, - 0xc1, 0xe5, 0x19, 0x13, 0xb3, 0x85, 0x5c, 0x48, 0x7d, 0xd1, 0x1f, 0x66, - 0xa1, 0x9a, 0x99, 0x8d, 0xab, 0x87, 0x85, 0xc0, 0xa9, 0x79, 0xd2, 0x74, - 0x08, 0x19, 0x40, 0xc6, 0x6e, 0x43, 0xc5, 0xc0, 0xeb, 0x35, 0x45, 0xd4, - 0x30, 0x37, 0x9f, 0xc7, 0x0e, 0xff, 0x4b, 0xea, 0xc8, 0x9c, 0x39, 0x9e, - 0x02, 0x89, 0x29, 0xa1, 0x8e, 0x51, 0x08, 0x4e, 0x2b, 0x53, 0x54, 0x67, - 0xc0, 0x40, 0x1a, 0x0b, 0xf3, 0x27, 0xe4, 0xb2, 0x44, 0x17, 0xa1, 0xeb, - 0x73, 0x0b, 0x00, 0x69, 0xaa, 0xb2, 0xd2, 0x05, 0x33, 0xd6, 0x6e, 0xa2, - 0x93, 0x9f, 0xec, 0xcf, 0x1b, 0x56, 0xee, 0xad, 0x1f, 0xdb, 0x19, 0x34, - 0x98, 0xf4, 0x69, 0x05, 0x01, 0x7f, 0x71, 0xc9, 0x5f, 0x8c, 0xb0, 0xcd, - 0x69, 0xe9, 0xc8, 0xf7, 0xd0, 0x52, 0xe5, 0x38, 0x51, 0xdb, 0x5a, 0xdd, - 0x86, 0xeb, 0x8a, 0xbd, 0x2a, 0xa1, 0xc8, 0x31, 0xd6, 0x82, 0x05, 0x47, - 0x0f, 0xb8, 0x9d, 0x4d, 0x7d, 0xac, 0xad, 0xf8, 0x5a, 0x66, 0xd0, 0xac, - 0x55, 0xd9, 0x1c, 0x4a, 0x53, 0x5e, 0xee, 0xf7, 0xcd, 0x2a, 0x15, 0xba, - 0x73, 0x8a, 0x8c, 0x1c, 0xa9, 0x2d, 0xb6, 0x94, 0xf7, 0x47, 0xc9, 0xa4, - 0x4e, 0x27, 0x6d, 0x7c, 0x6b, 0xb7, 0x14, 0x39, 0xf6, 0x85, 0xd1, 0xcf, - 0x97, 0xde, 0xda, 0x9f, 0x20, 0x69, 0x2f, 0xd7, 0x2c, 0xcc, 0x97, 0x70, - 0x2a, 0xac, 0xc5, 0x27, 0xec, 0xe9, 0xf8, 0xa7, 0x57, 0x27, 0xea, 0xb4, - 0x23, 0x7a, 0x12, 0x1d, 0x91, 0xf4, 0xfa, 0xeb, 0x2b, 0xe0, 0x6b, 0x79, - 0x32, 0x9e, 0x86, 0xf8, 0x6d, 0x2d, 0x78, 0xae, 0x17, 0x16, 0x16, 0x74, - 0x4b, 0x48, 0xb6, 0x27, 0x2f, 0xbf, 0xbb, 0x17, 0x5d, 0x68, 0x9f, 0x35, - 0xf0, 0x3e, 0xba, 0x1e, 0xaa, 0xf4, 0x67, 0x4d, 0x22, 0xf9, 0x4a, 0xb2, - 0x72, 0x92, 0x72, 0xd2, 0x48, 0x91, 0x3c, 0x7d, 0x93, 0x33, 0x2c, 0x7e, - 0xd9, 0xf5, 0xfd, 0x26, 0xd9, 0x0a, 0xf4, 0xe7, 0xaa, 0xe2, 0x36, 0x80, - 0x0b, 0xc0, 0x98, 0x11, 0x5f, 0x1a, 0xc5, 0x73, 0x81, 0xae, 0x09, 0xe6, - 0x02, 0x24, 0x44, 0x7f, 0x09, 0x2f, 0x21, 0xf1, 0x77, 0xf5, 0x25, 0xb5, - 0x6d, 0x9d, 0xc7, 0xf0, 0xf7, 0x8c, 0xa8, 0x18, 0x4b, 0xc7, 0x45, 0xaa, - 0x09, 0xa3, 0x65, 0x6f, 0xe3, 0xe4, 0xa8, 0xaa, 0xb9, 0xe6, 0x80, 0xea, - 0x14, 0x8c, 0x9f, 0x5e, 0xc6, 0x90, 0x42, 0x55, 0xf7, 0x34, 0xac, 0x48, - 0x6c, 0xb7, 0x4e, 0x27, 0xc4, 0x88, 0xde, 0x37, 0x48, 0x5b, 0xe5, 0xb8, - 0xea, 0x32, 0xa9, 0xa3, 0xbe, 0x7e, 0xe9, 0x7c, 0xdc, 0x5d, 0x31, 0xb3, - 0x00, 0xc8, 0x4b, 0x81, 0xdf, 0xdd, 0x66, 0x92, 0xda, 0x5c, 0xd9, 0x14, - 0x24, 0xba, 0xda, 0x49, 0xe2, 0x28, 0x3f, 0xe9, 0x93, 0x47, 0xa3, 0xd6, - 0xd2, 0xde, 0x02, 0x9b, 0xc0, 0x98, 0xe5, 0x00, 0x81, 0x9a, 0xb6, 0x77, - 0x1e, 0x36, 0x70, 0x0f, 0x6f, 0xa7, 0x9b, 0xca, 0xb4, 0x11, 0x8a, 0x19, - 0xfd, 0x09, 0xd0, 0x39, 0x4f, 0x0e, 0x7a, 0x05, 0x53, 0x75, 0x72, 0xbb, - 0x19, 0x25, 0x30, 0xaf, 0xd1, 0xed, 0xe8, 0xe5, 0xab, 0x3f, 0xec, 0x3c, - 0x28, 0xbe, 0xc0, 0x98, 0xfa, 0xb6, 0x26, 0x30, 0xa2, 0xe5, 0x9c, 0x27, - 0x1e, 0x33, 0x8d, 0x2b, 0x47, 0x18, 0xce, 0x87, 0x63, 0xc5, 0x1f, 0x78, - 0xa2, 0x85, 0x11, 0x80, 0x95, 0x46, 0xea, 0xa2, 0x2b, 0xbc, 0x47, 0x2a, - 0x04, 0xbe, 0x9e, 0x6f, 0x96, 0x15, 0xd2, 0xe0, 0x53, 0xd8, 0xc6, 0x8d, - 0x3c, 0x16, 0xa8, 0x7a, 0x56, 0xb6, 0x31, 0x57, 0x21, 0x08, 0x2f, 0x83, - 0x76, 0x15, 0x57, 0x5b, 0x03, 0xbe, 0x01, 0xb2, 0xbf, 0x5a, 0xf8, 0x80, - 0x45, 0x55, 0x09, 0xb9, 0x0e, 0x05, 0xc8, 0x82, 0x45, 0xf5, 0xd4, 0xbb, - 0x3d, 0x3c, 0xc8, 0x1d, 0x6f, 0x72, 0xae, 0xdf, 0x0b, 0x0a, 0x1d, 0x79, - 0xf5, 0x0d, 0xf9, 0x31, 0xf1, 0x30, 0x7e, 0x96, 0x0b, 0x7c, 0xea, 0x67, - 0x96, 0xde, 0x0b, 0x61, 0x98, 0xb0, 0x2d, 0xf1, 0x04, 0xa5, 0x3c, 0xe4, - 0x01, 0x4b, 0x3c, 0xc7, 0x27, 0xa3, 0x58, 0x41, 0xf9, 0x8a, 0x47, 0x81, - 0x54, 0xc3, 0x25, 0x92, 0x11, 0xa5, 0x05, 0x3b, 0xad, 0x1d, 0xcd, 0x41, - 0xf5, 0x83, 0xe0, 0x40, 0x45, 0x23, 0x67, 0xd5, 0xa0, 0xf7, 0x56, 0xb5, - 0x72, 0xa0, 0x02, 0xea, 0x37, 0x7c, 0xd3, 0xc9, 0xa5, 0x2f, 0x22, 0x0f, - 0xa6, 0x86, 0x6b, 0xfe, 0x3d, 0x45, 0xdd, 0x0b, 0xde, 0x78, 0x8f, 0xe8, - 0xb0, 0x85, 0x77, 0x96, 0x8c, 0x96, 0x9c, 0xff, 0xe8, 0x8c, 0x5b, 0xe9, - 0x01, 0xc1, 0x73, 0x9f, 0xb2, 0x80, 0x40, 0x5a, 0x35, 0x64, 0x47, 0xa1, - 0xe3, 0xea, 0xb9, 0x52, 0x02, 0x56, 0xc5, 0x22, 0xb4, 0xfa, 0x86, 0xea, - 0xa1, 0x1f, 0xb5, 0x35, 0xa7, 0x7e, 0x92, 0xf6, 0x54, 0xbe, 0xba, 0x05, - 0x91, 0xe1, 0xa6, 0x0f, 0xed, 0xd8, 0xca, 0x5a, 0x81, 0xfb, 0x50, 0x9c, - 0xe8, 0x03, 0xd9, 0x1d, 0x42, 0x60, 0xcd, 0x16, 0xdb, 0x85, 0xd6, 0x59, - 0x11, 0x7e, 0xef, 0xeb, 0xa6, 0x8f, 0x64, 0x9e, 0xa5, 0x7e, 0xa7, 0xcd, - 0xe2, 0x69, 0x0e, 0x8c, 0x85, 0xd2, 0xbe, 0x86, 0xbc, 0x20, 0xe7, 0x30, - 0x76, 0x7e, 0xd1, 0x44, 0x45, 0x6b, 0x16, 0xb6, 0x8a, 0x78, 0xd6, 0xca, - 0x31, 0x2b, 0x3d, 0xc1, 0x54, 0x70, 0xf5, 0x2b, 0xb5, 0x3c, 0x39, 0x40, - 0x4c, 0x3e, 0x65, 0x91, 0x13, 0xbd, 0xb9, 0x62, 0x4b, 0x5e, 0x31, 0xd2, - 0xea, 0x9c, 0xf6, 0xfd, 0xbb, 0x7e, 0xe6, 0x58, 0xa2, 0xdf, 0x69, 0xf4, - 0x37, 0x51, 0x11, 0xbc, 0x08, 0x02, 0xc2, 0x11, 0xf9, 0xe2, 0x3c, 0xe2, - 0x1a, 0x0b, 0x37, 0x23, 0x47, 0x3a, 0x94, 0x19, 0x58, 0x22, 0x9c, 0xd5, - 0x3d, 0x26, 0xfc, 0x77, 0x85, 0x13, 0x83, 0x39, 0x1a, 0x60, 0x14, 0xb1, - 0xfb, 0x36, 0x55, 0x82, 0x01, 0xae, 0x95, 0xf2, 0x37, 0x3a, 0x41, 0xd1, - 0xd1, 0xe5, 0x5f, 0xee, 0x2a, 0xdc, 0xe8, 0x1c, 0xbc, 0x20, 0xf9, 0x0c, - 0xb7, 0x7d, 0xd1, 0xa9, 0x2a, 0x40, 0xae, 0xbe, 0xc0, 0x66, 0xcd, 0x7c, - 0xd5, 0x1f, 0xd3, 0x25, 0xd5, 0x5a, 0x0d, 0xd6, 0x0a, 0x53, 0xe3, 0x6f, - 0x1d, 0xdc, 0x95, 0xb2, 0x14, 0x33, 0x98, 0xa7, 0x7b, 0xf8, 0x05, 0xe7, - 0xd8, 0xac, 0x0f, 0x06, 0x30, 0x2d, 0xed, 0x58, 0x08, 0xcf, 0x31, 0x1f, - 0xe4, 0xd4, 0xef, 0xbf, 0x73, 0x9a, 0x82, 0x9a, 0x44, 0xde, 0x34, 0x32, - 0xbe, 0x4b, 0xd9, 0xec, 0xc6, 0x2a, 0x00, 0x54, 0x75, 0x18, 0x9b, 0x76, - 0x1a, 0x6c, 0xc4, 0xd6, 0xf1, 0x87, 0xff, 0x89, 0x2d, 0x42, 0x89, 0x5e, - 0x53, 0xb1, 0xbd, 0x41, 0x59, 0xe2, 0x8d, 0xa9, 0x10, 0xa3, 0x11, 0xb3, - 0x3f, 0x1f, 0xca, 0xa8, 0x30, 0x28, 0xba, 0x46, 0x27, 0x2c, 0x9b, 0x9f, - 0x9d, 0x4f, 0xbf, 0x9b, 0xaf, 0xad, 0x18, 0x6a, 0xb1, 0x1f, 0x7f, 0xec, - 0xfa, 0xf9, 0x63, 0x80, 0x39, 0x90, 0xb7, 0x43, 0x86, 0xa1, 0xf4, 0x62, - 0x56, 0xc2, 0x76, 0x68, 0x16, 0xbd, 0xc7, 0xc8, 0x8c, 0x44, 0x1e, 0x74, - 0xa4, 0x94, 0xf7, 0x9c, 0xee, 0xa8, 0xcd, 0x01, 0x8e, 0x75, 0xec, 0x4a, - 0x27, 0x0d, 0x45, 0xe1, 0x14, 0x37, 0x2a, 0x3f, 0x95, 0xd1, 0x66, 0x5f, - 0xb1, 0x45, 0x14, 0x60, 0xdb, 0xaf, 0x44, 0xb1, 0x83, 0x2b, 0xf4, 0x8b, - 0xce, 0x01, 0xbd, 0xf1, 0x63, 0x8b, 0x56, 0x98, 0xbe, 0xd7, 0xbe, 0x4d, - 0xeb, 0xc2, 0xdc, 0xc3, 0x28, 0x7e, 0x4d, 0x8f, 0x90, 0x6f, 0x7a, 0xe7, - 0xe1, 0x0b, 0x2b, 0x87, 0x3a, 0x1f, 0x1f, 0x8f, 0xd7, 0x64, 0xca, 0xcc, - 0xd2, 0xb7, 0xc8, 0x9c, 0xe2, 0x31, 0xfa, 0x50, 0x18, 0xe3, 0x30, 0x3f, - 0x99, 0x38, 0x4f, 0x83, 0x25, 0x02, 0x3c, 0x05, 0x00, 0x0c, 0x12, 0x0b, - 0x26, 0x17, 0x60, 0x3b, 0xc2, 0x44, 0x8c, 0x84, 0x8b, 0x69, 0xfb, 0x1e, - 0x70, 0x69, 0x0b, 0xc4, 0x6f, 0x5f, 0x69, 0x82, 0xf2, 0xe1, 0x4d, 0x23, - 0xe9, 0x8c, 0xdb, 0xb7, 0xc8, 0x71, 0x14, 0x1d, 0xad, 0x16, 0x7c, 0x43, - 0xca, 0x8b, 0x58, 0x75, 0x9f, 0xe2, 0x00, 0x51, 0xc2, 0x45, 0x4b, 0x5e, - 0x6b, 0x5d, 0x8e, 0x75, 0xd4, 0xd4, 0x08, 0x90, 0xd1, 0xab, 0xff, 0x9e, - 0xbe, 0xea, 0xb5, 0x31, 0x4a, 0x4a, 0x0f, 0x7e, 0x8b, 0x74, 0xcc, 0x04, - 0xf0, 0xc8, 0x94, 0xdc, 0xf3, 0x7d, 0x42, 0x09, 0xea, 0xe6, 0xa4, 0x25, - 0x33, 0x9b, 0x1d, 0x1d, 0x9b, 0x05, 0xe3, 0x05, 0x87, 0x63, 0x63, 0xa9, - 0xbd, 0x65, 0x7f, 0xa5, 0x0f, 0x99, 0x90, 0xe0, 0xeb, 0xed, 0xde, 0xe9, - 0xe1, 0xe5, 0x91, 0xf8, 0x68, 0xd9, 0x06, 0x17, 0xb6, 0xfc, 0x70, 0x12, - 0x38, 0x49, 0xfc, 0xce, 0x0d, 0xbc, 0x8a, 0x06, 0xc2, 0x41, 0x62, 0x88, - 0x67, 0x58, 0x0b, 0x22, 0xf8, 0x38, 0x47, 0x4f, 0xe1, 0x7b, 0xce, 0x86, - 0x9c, 0x9a, 0x28, 0xee, 0xdd, 0x70, 0x20, 0xb0, 0x12, 0x58, 0x73, 0x0a, - 0x07, 0x25, 0x1f, 0x82, 0x75, 0x5f, 0x8d, 0x84, 0xed, 0x03, 0xbc, 0x6b, - 0x8c, 0x99, 0x4c, 0xaf, 0x3d, 0x8c, 0xb7, 0x42, 0xb2, 0x4d, 0xeb, 0x0c, - 0xb8, 0x67, 0xfb, 0xc5, 0x0f, 0x60, 0x37, 0x9a, 0xef, 0xfe, 0x95, 0xce, - 0xe6, 0x26, 0x14, 0x17, 0xd6, 0xa5, 0x76, 0x2f, 0x91, 0xe8, 0x79, 0x13, - 0x21, 0xae, 0x6b, 0x55, 0x6a, 0x1f, 0xf7, 0x1a, 0x94, 0xf3, 0xa2, 0xb7, - 0xa7, 0x4e, 0x89, 0x7a, 0x42, 0x10, 0xbb, 0x9b, 0x55, 0x9d, 0x55, 0xa8, - 0x95, 0xae, 0x77, 0x8c, 0xb8, 0x93, 0x63, 0x53, 0x74, 0x2e, 0x98, 0xec, - 0xdd, 0x74, 0x88, 0xa8, 0xa0, 0xd0, 0x00, 0x74, 0xf1, 0x5b, 0xfd, 0x30, - 0x0f, 0xe8, 0x19, 0xb6, 0x7b, 0x9f, 0x78, 0xda, 0x98, 0x83, 0x01, 0xa2, - 0x3d, 0x11, 0xe2, 0xca, 0x83, 0x16, 0x8f, 0x6b, 0x62, 0x32, 0x9b, 0xc7, - 0x95, 0xda, 0xc3, 0xee, 0xa5, 0x2a, 0x30, 0x2d, 0x8c, 0x80, 0x4c, 0x72, - 0x0c, 0x8d, 0x29, 0x61, 0xa9, 0xbe, 0x5b, 0x32, 0x1c, 0xcb, 0x37, 0x49, - 0xf4, 0x1d, 0xb2, 0xc7, 0x17, 0x7f, 0xb9, 0x50, 0x51, 0xf1, 0xb1, 0x9f, - 0xc7, 0x2a, 0x2a, 0x22, 0x8e, 0x33, 0xc2, 0x24, 0x97, 0x08, 0x6c, 0x05, - 0x03, 0xc9, 0x1f, 0x92, 0xdb, 0x8e, 0x70, 0x5c, 0x50, 0xb1, 0x23, 0x68, - 0xb5, 0xc3, 0x42, 0x50, 0xe5, 0xd7, 0x03, 0x3c, 0xb5, 0xff, 0xfc, 0x21, - 0x2b, 0x98, 0xb0, 0xdb, 0xcd, 0x75, 0xf4, 0x92, 0xd1, 0x82, 0xcf, 0xfb, - 0xf4, 0xf4, 0x91, 0x32, 0xac, 0x9a, 0x27, 0xbb, 0xa5, 0x2e, 0x7e, 0x71, - 0x21, 0xe6, 0x54, 0x06, 0x7c, 0xe8, 0xcf, 0x97, 0xa6, 0x0a, 0xf8, 0x75, - 0xd0, 0xef, 0xc7, 0xfb, 0x31, 0xc1, 0xf8, 0x1b, 0x9b, 0x32, 0xe5, 0xbf, - 0x38, 0x71, 0xc2, 0x3d, 0x21, 0xbc, 0xcb, 0x76, 0xe7, 0xac, 0x76, 0xa9, - 0xc2, 0x99, 0x9f, 0x44, 0xb0, 0x97, 0xf6, 0xf1, 0x8d, 0x8c, 0x16, 0xfe, - 0x24, 0xec, 0x51, 0xb1, 0xf3, 0x87, 0x38, 0x7c, 0x7f, 0xf8, 0xd5, 0x98, - 0xb0, 0x73, 0x43, 0xc7, 0xbd, 0x2f, 0x26, 0xe1, 0xa4, 0x71, 0xa6, 0xb9, - 0x68, 0x28, 0xaf, 0x1f, 0xa4, 0x92, 0x7a, 0xd6, 0xb2, 0x30, 0xc2, 0x85, - 0x42, 0x7b, 0x14, 0x38, 0xe0, 0x59, 0xdc, 0xc9, 0x3b, 0x01, 0x74, 0x54, - 0xb1, 0x92, 0xd2, 0x67, 0xe1, 0x16, 0x98, 0xf5, 0x90, 0x45, 0xfb, 0x2c, - 0xd2, 0x3f, 0x9f, 0xf2, 0x4d, 0x88, 0xaa, 0x0c, 0xdf, 0x35, 0x0d, 0xa6, - 0x62, 0x61, 0x23, 0xd1, 0xc8, 0xe5, 0x9d, 0x1b, 0x8a, 0x79, 0x63, 0xb4, - 0x55, 0x78, 0x35, 0xec, 0x59, 0xcb, 0x88, 0x17, 0x09, 0xdc, 0x1a, 0x35, - 0x25, 0xeb, 0xd8, 0x84, 0xeb, 0x48, 0x80, 0x7e, 0x45, 0xbe, 0xcd, 0xa5, - 0xf8, 0x3c, 0xc8, 0x28, 0x24, 0x0e, 0xdf, 0xbc, 0xb6, 0xe9, 0xfa, 0xc7, - 0x25, 0xbd, 0xa7, 0x46, 0xc2, 0x2a, 0xb8, 0x2d, 0x26, 0x95, 0xc5, 0x86, - 0xa0, 0xd2, 0x90, 0xd5, 0x5f, 0xca, 0xbc, 0xd1, 0x98, 0x82, 0x49, 0xf1, - 0x50, 0x35, 0x27, 0xe8, 0x01, 0x0f, 0x07, 0x28, 0xba, 0x2c, 0x7f, 0x28, - 0xec, 0x19, 0xef, 0xf2, 0x3c, 0x87, 0xb6, 0x8a, 0x30, 0xbd, 0x65, 0x80, - 0x39, 0xf5, 0xf3, 0x8f, 0x29, 0xf5, 0xb6, 0x6d, 0xb4, 0x65, 0xf8, 0x60, - 0xcc, 0x42, 0xee, 0xe6, 0x2f, 0xce, 0xa8, 0x2e, 0xf5, 0x6f, 0xc7, 0xe0, - 0x6d, 0x3c, 0xce, 0x02, 0x26, 0xde, 0xeb, 0xcf, 0x24, 0x85, 0xce, 0xb5, - 0x89, 0x45, 0xc6, 0x01, 0x94, 0xc4, 0xf3, 0xb0, 0x5d, 0x4f, 0x40, 0x13, - 0xb3, 0x76, 0x51, 0xb8, 0x99, 0x67, 0x52, 0xe1, 0x86, 0xce, 0x3d, 0xdc, - 0x63, 0x00, 0x99, 0xcc, 0x5e, 0x77, 0xbc, 0xef, 0xfb, 0x98, 0x4d, 0xb4, - 0x06, 0xe8, 0xfd, 0x20, 0x02, 0x72, 0xc1, 0x83, 0x34, 0xcc, 0x4c, 0x53, - 0xac, 0x8b, 0x80, 0xac, 0xb0, 0x83, 0x31, 0x2a, 0x60, 0xda, 0x5e, 0xc6, - 0xf6, 0x68, 0x36, 0x85, 0x7d, 0x75, 0x97, 0x77, 0x74, 0x8e, 0xc2, 0xee, - 0x8b, 0x75, 0x8f, 0xb5, 0xcf, 0x6e, 0x43, 0x87, 0x50, 0xd6, 0x03, 0x14, - 0x8f, 0xde, 0xdd, 0xf3, 0x7a, 0x3e, 0x36, 0xd6, 0x5c, 0x63, 0x28, 0xc3, - 0x19, 0x99, 0xce, 0x6b, 0x17, 0x07, 0xa5, 0x43, 0xe7, 0x40, 0xb3, 0xaa, - 0x6d, 0x0f, 0x38, 0x67, 0x56, 0x40, 0xc5, 0xb8, 0x50, 0xf9, 0xfe, 0x56, - 0x34, 0xc4, 0x7e, 0x08, 0x99, 0xd0, 0xd1, 0x1f, 0x14, 0x76, 0x58, 0xdc, - 0x86, 0x8d, 0xa6, 0xee, 0x28, 0x91, 0x66, 0x10, 0xdd, 0x30, 0x6d, 0xa1, - 0xc2, 0xcb, 0x29, 0x3a, 0x9e, 0x46, 0x8c, 0x93, 0x22, 0x12, 0x96, 0xbe, - 0x6f, 0xe0, 0xa8, 0xa4, 0xe4, 0x74, 0x8d, 0x85, 0x74, 0xe5, 0x24, 0x92, - 0xbd, 0xfa, 0x02, 0x20, 0x5f, 0x65, 0x38, 0x6a, 0x1e, 0x1b, 0x73, 0xb0, - 0xfc, 0x16, 0x73, 0x49, 0x32, 0x46, 0xf9, 0xf0, 0x98, 0xcb, 0xc3, 0x04, - 0x87, 0xc9, 0xdf, 0x0a, 0x2c, 0x6a, 0x9b, 0x84, 0xe3, 0x6d, 0xca, 0x9d, - 0x87, 0x30, 0x0a, 0x19, 0x42, 0x07, 0xa5, 0xe7, 0xa5, 0xe6, 0x1d, 0xc1, - 0x49, 0xfc, 0x56, 0xaf, 0x5b, 0xe8, 0xf9, 0xcd, 0x69, 0x19, 0x53, 0x39, - 0x5d, 0xcc, 0x16, 0x57, 0x7d, 0x06, 0x4d, 0x06, 0xf6, 0xb1, 0xae, 0xdf, - 0x5f, 0xad, 0xe0, 0x85, 0x87, 0xb0, 0xe4, 0xd6, 0x40, 0xc2, 0x55, 0x66, - 0x26, 0x79, 0x2a, 0x4d, 0x6a, 0x7a, 0x56, 0x9c, 0x14, 0x72, 0x42, 0x5d, - 0x23, 0xd3, 0xf0, 0x04, 0x1e, 0x45, 0xf4, 0xdf, 0xf4, 0x49, 0xb0, 0xdd, - 0x33, 0xcd, 0x99, 0xc0, 0xf3, 0xd6, 0x64, 0xa9, 0xb8, 0x8f, 0xac, 0x17, - 0x09, 0xfa, 0x76, 0x76, 0x14, 0x95, 0x71, 0x7f, 0xe4, 0x4c, 0x7f, 0x0c, - 0x15, 0x72, 0xc1, 0xfe, 0x8b, 0xd2, 0xf1, 0x3b, 0x15, 0x26, 0xda, 0x82, - 0x67, 0x9b, 0xad, 0xf4, 0xc4, 0x42, 0x13, 0xa5, 0x1c, 0x08, 0xa1, 0x85, - 0xbb, 0xc5, 0x7f, 0xf6, 0x75, 0x49, 0x06, 0xd3, 0x41, 0x59, 0xee, 0xbb, - 0x90, 0xe9, 0xc4, 0xec, 0x1e, 0xed, 0x7c, 0x90, 0x9c, 0x3c, 0x86, 0xba, - 0x03, 0x87, 0xd4, 0x00, 0x58, 0x53, 0x0d, 0x94, 0x1e, 0x84, 0x64, 0x8d, - 0x1b, 0x9e, 0x39, 0xc4, 0x3a, 0x5f, 0xd1, 0x3c, 0x4f, 0x6f, 0x49, 0xa0, - 0xa7, 0x8d, 0xbe, 0xac, 0x4c, 0x3e, 0x04, 0x38, 0x92, 0xdb, 0x49, 0xf1, - 0xfb, 0x1c, 0x8c, 0x3d, 0xb3, 0xdf, 0x6f, 0x4a, 0x89, 0x71, 0x4a, 0x4b, - 0x8a, 0x0d, 0x42, 0xe1, 0xe5, 0x31, 0xa0, 0xc7, 0xf9, 0x32, 0xcd, 0xfe, - 0xfa, 0x6b, 0x42, 0xd6, 0xb4, 0x34, 0x1e, 0x19, 0xab, 0xaa, 0x07, 0x14, - 0x08, 0x3a, 0x04, 0xf1, 0xcb, 0x7a, 0x07, 0xc6, 0xde, 0x08, 0x1c, 0x2b, - 0x17, 0x5b, 0x79, 0x95, 0xe2, 0x26, 0x29, 0xf1, 0x3c, 0x56, 0x09, 0x0f, - 0xc3, 0x16, 0xd2, 0xa9, 0x33, 0x0d, 0x52, 0x98, 0x84, 0xd1, 0x6d, 0xea, - 0xed, 0x1a, 0x99, 0x87, 0x0d, 0x83, 0xaf, 0x56, 0xfe, 0x1c, 0x86, 0x34, - 0xca, 0x1f, 0x78, 0x32, 0xe8, 0x61, 0x31, 0xe9, 0x6d, 0x7c, 0x07, 0xce, - 0x2c, 0x13, 0x88, 0x64, 0x69, 0x0b, 0x77, 0xa1, 0xc0, 0x47, 0x77, 0x42, - 0x4e, 0x1f, 0x4c, 0xa5, 0x02, 0x75, 0xed, 0xea, 0x4f, 0x50, 0xf4, 0x6f, - 0x43, 0xba, 0x61, 0x29, 0xa4, 0x1f, 0xe2, 0x04, 0xf9, 0x00, 0x4a, 0x02, - 0x05, 0x01, 0x12, 0x9c, 0x95, 0x5c, 0x60, 0xfd, 0x26, 0x65, 0x87, 0x8e, - 0x47, 0x9d, 0x44, 0x0b, 0x1e, 0x1d, 0x7a, 0xb1, 0xde, 0x59, 0xb9, 0xaa, - 0xb9, 0x39, 0x3d, 0x80, 0xbb, 0xe7, 0x1c, 0xa3, 0x6f, 0x60, 0x1b, 0x7e, - 0xaf, 0xf8, 0xd3, 0x8c, 0x2b, 0xf3, 0xa1, 0xd4, 0xdc, 0x7f, 0x22, 0x54, - 0x23, 0x75, 0x3c, 0x48, 0x48, 0x8c, 0xb2, 0x87, 0xfe, 0xa7, 0x7c, 0xc8, - 0xe5, 0x5a, 0x56, 0x55, 0x86, 0x2b, 0xf0, 0xd6, 0xf6, 0x80, 0x23, 0xad, - 0x8a, 0x1e, 0x1a, 0xfb, 0x0b, 0x06, 0x7b, 0x63, 0x82, 0xe1, 0xe8, 0x6a, - 0x3f, 0xb4, 0x84, 0xc0, 0xb4, 0xb7, 0x62, 0x1f, 0x21, 0xbf, 0xe2, 0xb3, - 0x46, 0x6b, 0xda, 0x4a, 0x3e, 0x13, 0xb0, 0xe8, 0x96, 0xe7, 0x50, 0x48, - 0x4c, 0x6d, 0x4e, 0xb7, 0x5e, 0xea, 0xa1, 0x1b, 0xf7, 0x8b, 0xe6, 0xec, - 0x72, 0x44, 0x98, 0x65, 0xec, 0x95, 0xc3, 0xb2, 0x1a, 0x73, 0xe5, 0x0b, - 0x7e, 0x7c, 0x7a, 0xb9, 0x64, 0xa0, 0x77, 0xc4, 0x3c, 0xd7, 0x5f, 0x52, - 0x67, 0xde, 0x04, 0x17, 0x85, 0xbe, 0x9f, 0x3d, 0x2a, 0x11, 0xc7, 0xaa, - 0xf9, 0x0d, 0x73, 0x32, 0x4c, 0x46, 0xe6, 0x33, 0x2b, 0x84, 0x7e, 0x4f, - 0xb1, 0xfe, 0xa9, 0x28, 0xe4, 0xb1, 0xfd, 0x37, 0xf8, 0x5e, 0xae, 0xb2, - 0x8f, 0xba, 0x8f, 0x5b, 0x85, 0x02, 0x23, 0xca, 0xb2, 0x3c, 0xe1, 0x98, - 0xb7, 0x0b, 0xc5, 0x9b, 0x13, 0x5a, 0x70, 0x0e, 0x87, 0x84, 0xca, 0x1a, - 0x89, 0x43, 0xf1, 0x05, 0x69, 0xdc, 0x0e, 0xd2, 0x85, 0x23, 0xa0, 0x18, - 0xcf, 0x3b, 0x3c, 0x7b, 0xf3, 0x77, 0x6a, 0xc5, 0x77, 0x28, 0x44, 0x1b, - 0xea, 0xe0, 0x6f, 0x0a, 0x98, 0xce, 0x6d, 0xb4, 0xd6, 0xdf, 0x96, 0xed, - 0xad, 0xc4, 0x24, 0x35, 0xa3, 0x94, 0x49, 0x3c, 0x39, 0xaa, 0x02, 0x5d, - 0xab, 0xad, 0x19, 0xd1, 0xd4, 0xc3, 0x90, 0x3e, 0xc0, 0x0e, 0x5f, 0x8e, - 0xd3, 0x22, 0xc3, 0x5a, 0x75, 0xe2, 0x5c, 0x73, 0x87, 0xe6, 0x2f, 0x3b, - 0x4b, 0x4e, 0x31, 0x72, 0xbf, 0xb8, 0x9b, 0xbf, 0xd5, 0xf7, 0x89, 0x0c, - 0xc0, 0x8c, 0x51, 0xd5, 0xf3, 0x2c, 0xbd, 0xe6, 0xee, 0x49, 0xaa, 0x5d, - 0x0a, 0x75, 0x20, 0x81, 0x3b, 0x4c, 0x93, 0x33, 0xe9, 0xa9, 0x6d, 0xb0, - 0x54, 0xdd, 0x49, 0xd4, 0x22, 0xfc, 0xbb, 0x34, 0x98, 0x6b, 0xda, 0xae, - 0x9c, 0xd8, 0x8c, 0x8b, 0xf8, 0xfd, 0xdd, 0x4f, 0xda, 0xcf, 0x97, 0x7b, - 0x6e, 0x3e, 0x64, 0x55, 0x30, 0x25, 0x5b, 0x0e, 0x6b, 0x42, 0xfb, 0x14, - 0x28, 0xbe, 0x17, 0x33, 0x23, 0x11, 0x38, 0x65, 0xfc, 0x77, 0xb6, 0x2d, - 0x32, 0xbb, 0x99, 0xe1, 0x7b, 0x5c, 0xa6, 0x46, 0x4c, 0x93, 0x28, 0x8f, - 0x88, 0x36, 0x4c, 0xf5, 0xd1, 0x2a, 0xc8, 0x14, 0xe6, 0x2d, 0x39, 0xed, - 0xcd, 0x13, 0x1d, 0x15, 0x61, 0xbd, 0x66, 0x87, 0x8f, 0x23, 0x3b, 0xc6, - 0xf2, 0x6a, 0xd4, 0xc1, 0xcd, 0x7f, 0xd2, 0x32, 0x72, 0x3e, 0x2d, 0x7e, - 0x7e, 0xae, 0x50, 0xd3, 0x2c, 0xd4, 0x86, 0xf4, 0xef, 0x31, 0xbc, 0x48, - 0x02, 0x04, 0xd0, 0x84, 0x58, 0x05, 0x50, 0xa9, 0x78, 0x26, 0xb4, 0x0d, - 0x85, 0xe8, 0x94, 0xc3, 0xab, 0x98, 0xc5, 0x48, 0x16, 0xa4, 0xc8, 0x14, - 0xcc, 0x3b, 0x1f, 0x7d, 0xc4, 0x81, 0x06, 0x4b, 0xe3, 0x42, 0x0d, 0xf6, - 0xb5, 0x1a, 0x21, 0x28, 0x52, 0x20, 0x79, 0x0e, 0x20, 0x62, 0x69, 0xd8, - 0x28, 0xe7, 0xad, 0x88, 0xb4, 0x16, 0x14, 0xb2, 0x18, 0x6f, 0x9e, 0x64, - 0x18, 0xce, 0x7d, 0xb7, 0x83, 0x84, 0x2a, 0x87, 0x97, 0x12, 0xbe, 0x66, - 0xd1, 0xe1, 0x96, 0x92, 0x34, 0xed, 0x1c, 0xeb, 0xd6, 0x71, 0xfb, 0x1f, - 0x54, 0xbe, 0x05, 0xb2, 0x8b, 0xba, 0x4c, 0x89, 0x3a, 0x3d, 0xd0, 0x6b, - 0xb4, 0xe6, 0x2a, 0x4e, 0x06, 0x12, 0xc1, 0x1e, 0x23, 0x33, 0x22, 0x2f, - 0x8d, 0x63, 0xcc, 0xe6, 0xf1, 0xd1, 0xeb, 0xe2, 0xe6, 0x4e, 0xfe, 0xcc, - 0xbb, 0x73, 0x57, 0x26, 0x6d, 0x83, 0xea, 0x87, 0x18, 0x0b, 0x9d, 0x30, - 0x94, 0x8c, 0x37, 0x94, 0x43, 0xf4, 0xc0, 0xac, 0x99, 0x4b, 0x16, 0x4e, - 0xe1, 0xa5, 0x91, 0xa3, 0xaa, 0x33, 0x81, 0x17, 0x53, 0x69, 0x4a, 0x4c, - 0x27, 0x23, 0x68, 0xb9, 0x46, 0x61, 0xdf, 0x9f, 0x29, 0x29, 0x38, 0xd9, - 0x10, 0xf2, 0x41, 0xaa, 0xcc, 0x77, 0x34, 0x94, 0x8b, 0x60, 0x06, 0xe5, - 0xba, 0x5a, 0xaf, 0x04, 0x88, 0x6e, 0x68, 0x09, 0xef, 0x7e, 0x33, 0x35, - 0x7e, 0xd7, 0x21, 0xc1, 0x3c, 0xa6, 0x3c, 0x0c, 0x8f, 0xb1, 0x3c, 0x96, - 0x91, 0x3b, 0x97, 0x0e, 0x7f, 0xe3, 0xe5, 0x03, 0xc7, 0x9f, 0x12, 0xab, - 0x45, 0xa0, 0xc5, 0x5f, 0x4f, 0x6e, 0x1a, 0xc3, 0x45, 0xa8, 0xd6, 0xe0, - 0x49, 0x6a, 0x49, 0x5d, 0x06, 0x67, 0x1f, 0x12, 0xb3, 0x91, 0x58, 0x1e, - 0xdf, 0x32, 0xc4, 0x7d, 0x43, 0x5d, 0xcd, 0xb7, 0x14, 0x05, 0xbd, 0x5e, - 0x02, 0x99, 0x79, 0x06, 0xee, 0x2d, 0x1a, 0xd9, 0xae, 0x5c, 0x2e, 0x10, - 0x4c, 0xd7, 0x81, 0xcf, 0x4c, 0x10, 0xfa, 0x8e, 0x76, 0xe5, 0x90, 0x2c, - 0x77, 0x40, 0xfe, 0x3d, 0x99, 0x00, 0xf5, 0x29, 0xd5, 0x44, 0x36, 0x4b, - 0xdb, 0x51, 0x34, 0x2a, 0x6e, 0xee, 0xdb, 0xbc, 0x3c, 0xa3, 0xf9, 0xa5, - 0x13, 0xc8, 0xdf, 0xe9, 0x68, 0x16, 0x89, 0xb2, 0x38, 0x99, 0xc7, 0x73, - 0x0a, 0xe5, 0xbe, 0x02, 0xb3, 0x07, 0x13, 0xed, 0xd1, 0x97, 0xf0, 0xb5, - 0x25, 0xe7, 0xb4, 0xeb, 0xcb, 0xc0, 0xf7, 0x63, 0xde, 0x29, 0x51, 0x88, - 0xa9, 0xb4, 0xce, 0xc6, 0xd7, 0x50, 0xf7, 0xcf, 0x5e, 0xbe, 0x33, 0x93, - 0xb2, 0x77, 0x70, 0x0a, 0x13, 0xac, 0xea, 0x52, 0xf6, 0x69, 0x9e, 0xaa, - 0xa1, 0x2e, 0x5f, 0xfd, 0x3a, 0x52, 0x67, 0xf7, 0xe8, 0x93, 0x61, 0xd7, - 0x1e, 0x84, 0x1f, 0x73, 0xba, 0xc7, 0x0e, 0x45, 0x38, 0xf1, 0x4e, 0x55, - 0xca, 0x60, 0x22, 0xec, 0x0b, 0x3e, 0xb3, 0xdf, 0x8a, 0x82, 0x59, 0x83, - 0xa0, 0xdd, 0x1e, 0xbb, 0x6f, 0x87, 0x0b, 0x21, 0x07, 0x5d, 0x01, 0xdd, - 0xc9, 0xcf, 0xc4, 0x32, 0x74, 0xcc, 0xfa, 0xbd, 0x9e, 0xe9, 0x86, 0xb4, - 0x66, 0x94, 0x63, 0xd0, 0x32, 0x98, 0x53, 0x7c, 0xc8, 0x13, 0xba, 0xa1, - 0xc9, 0xae, 0xf1, 0xd2, 0x06, 0x04, 0xd9, 0x2f, 0x59, 0xb1, 0x5c, 0xdc, - 0x32, 0xdc, 0x67, 0xa4, 0xed, 0xfd, 0x34, 0xab, 0x27, 0xfc, 0xfb, 0x70, - 0xbe, 0x50, 0xbb, 0xb0, 0x89, 0x50, 0xae, 0x4f, 0x3b, 0xe2, 0x9c, 0xe1, - 0x90, 0xae, 0x0d, 0xc1, 0x1e, 0x65, 0x24, 0x4a, 0xf5, 0x1d, 0x02, 0xef, - 0x74, 0x3d, 0x70, 0x87, 0xb1, 0x6a, 0xcf, 0x58, 0x9e, 0x9b, 0x22, 0x29, - 0x68, 0xfe, 0x81, 0x1f, 0x5c, 0xa8, 0xed, 0x5e, 0x1e, 0x89, 0x1f, 0xf7, - 0x2b, 0x6d, 0x47, 0x89, 0xe2, 0x9c, 0xfb, 0x15, 0x28, 0x71, 0x17, 0x3d, - 0xe7, 0x63, 0x3b, 0x7b, 0x60, 0xe8, 0x57, 0x82, 0x49, 0xa8, 0x58, 0xf6, - 0x35, 0xd6, 0xfa, 0x29, 0xa8, 0x97, 0x8b, 0x1e, 0xa1, 0x33, 0xce, 0xd4, - 0x42, 0x49, 0xae, 0xef, 0x75, 0x23, 0xc9, 0x54, 0x8c, 0x7e, 0xcd, 0x3a, - 0x2f, 0x1e, 0x10, 0x22, 0x79, 0xdc, 0x97, 0x25, 0xa6, 0x14, 0x13, 0x1f, - 0x5f, 0x1b, 0xb9, 0x1f, 0x8e, 0x0b, 0x25, 0x21, 0xc0, 0x18, 0x29, 0xf4, - 0x47, 0x61, 0x0f, 0xdd, 0x6f, 0x74, 0xc1, 0x8c, 0xdf, 0x43, 0xa4, 0xac, - 0x18, 0xa7, 0x13, 0x70, 0x98, 0x53, 0xa9, 0x69, 0x1f, 0x8c, 0xbd, 0xf3, - 0xed, 0xf5, 0x11, 0x49, 0xff, 0xce, 0xb3, 0xd9, 0xc7, 0x09, 0xf6, 0x3b, - 0x78, 0x0e, 0x48, 0x97, 0x94, 0x0b, 0xb9, 0x30, 0x25, 0x90, 0x65, 0x69, - 0x6c, 0x59, 0xf4, 0x1a, 0x2c, 0x10, 0x2e, 0xe4, 0x73, 0x2e, 0x91, 0x23, - 0x3d, 0x2c, 0x57, 0x37, 0x31, 0xfd, 0xe1, 0xfb, 0x64, 0x6a, 0xb6, 0xc2, - 0x40, 0x76, 0x40, 0x4b, 0x51, 0xdd, 0x00, 0x4a, 0xad, 0xc0, 0x26, 0x51, - 0x46, 0xe6, 0xe2, 0xcd, 0xef, 0xe3, 0xcf, 0x60, 0x52, 0xca, 0xc0, 0x77, - 0xb6, 0xdf, 0x66, 0x1d, 0x00, 0x08, 0x0b, 0x0f, 0x88, 0x38, 0xc2, 0x23, - 0xa5, 0x89, 0x86, 0x30, 0xe2, 0x5c, 0x7b, 0x72, 0xb0, 0x15, 0x2b, 0x2d, - 0xb2, 0x25, 0x2f, 0x28, 0xe4, 0x26, 0x12, 0x82, 0x5f, 0x1f, 0xe6, 0xca, - 0x3b, 0xd7, 0xa4, 0x1d, 0x65, 0x8d, 0xd9, 0xa8, 0x5f, 0x19, 0xf5, 0x0b, - 0x22, 0xe7, 0x28, 0xda, 0x32, 0x51, 0xa3, 0xb7, 0x7d, 0xf4, 0xf7, 0xfb, - 0x7e, 0xd7, 0x3a, 0x6f, 0x78, 0xf8, 0xad, 0x4a, 0x31, 0x65, 0xd9, 0x77, - 0xa3, 0x54, 0x91, 0xf1, 0xc1, 0x08, 0x45, 0x83, 0x4e, 0x26, 0xcb, 0xfa, - 0x10, 0x95, 0x6a, 0xbd, 0x6a, 0x0a, 0xfb, 0x4c, 0x64, 0x01, 0xe7, 0x2f, - 0x3c, 0xfe, 0xe5, 0x6f, 0x7c, 0x1a, 0xcb, 0x60, 0x75, 0x2d, 0x27, 0x8e, - 0x67, 0x6a, 0x21, 0x6f, 0x9f, 0x5c, 0x49, 0x90, 0x22, 0x8f, 0xc6, 0x97, - 0xe5, 0x40, 0x0b, 0x65, 0x42, 0xfb, 0x6d, 0x7b, 0xe0, 0x6c, 0x46, 0xf8, - 0x35, 0x7f, 0x61, 0xc0, 0xc8, 0xd7, 0x7f, 0x47, 0x55, 0x8f, 0x03, 0x36, - 0x34, 0xad, 0x30, 0x13, 0xf1, 0x4d, 0xa4, 0x4d, 0x83, 0x19, 0xd9, 0xc0, - 0xf4, 0x9f, 0x96, 0xde, 0x65, 0xaf, 0x0f, 0x75, 0xa6, 0xfe, 0xdc, 0x7e, - 0xee, 0xd8, 0x9a, 0xd6, 0x7d, 0x8b, 0x40, 0xca, 0xf1, 0x86, 0x0b, 0x40, - 0x56, 0x46, 0x8d, 0xd6, 0x16, 0x09, 0x99, 0xd9, 0xb7, 0x08, 0xe9, 0x7b, - 0x05, 0xfa, 0xc6, 0x66, 0x5e, 0x53, 0xfe, 0xf9, 0xf8, 0x90, 0xc7, 0xef, - 0x4e, 0x94, 0x3b, 0x77, 0xad, 0xda, 0xb0, 0x4b, 0x61, 0xd3, 0xcf, 0xf2, - 0x95, 0xcc, 0xe5, 0x60, 0x8b, 0x42, 0x74, 0x30, 0x7f, 0x62, 0x75, 0x7c, - 0xac, 0xcf, 0x16, 0x84, 0xe5, 0x85, 0x41, 0xd0, 0xb9, 0xaa, 0x67, 0x9f, - 0xd6, 0x24, 0x06, 0x20, 0xa2, 0xd9, 0x7c, 0x45, 0x70, 0xff, 0xc1, 0xc8, - 0x6c, 0xe2, 0x3a, 0x78, 0xec, 0x6a, 0x24, 0xf3, 0x41, 0x60, 0xd3, 0x12, - 0x64, 0x3f, 0xcb, 0xf5, 0xcc, 0x52, 0x75, 0x87, 0x5b, 0x31, 0x95, 0x17, - 0x7b, 0x7b, 0x6e, 0xa5, 0x1c, 0x34, 0x15, 0x8d, 0x50, 0xa5, 0xc0, 0x99, - 0xf1, 0xa3, 0xe1, 0xa1, 0xd4, 0xe3, 0x31, 0xd8, 0x8e, 0x20, 0x54, 0xd9, - 0xda, 0xb2, 0x60, 0xa2, 0x96, 0x33, 0xc9, 0x63, 0x05, 0xc6, 0xe4, 0x63, - 0xcd, 0x80, 0xa9, 0x5a, 0x06, 0x58, 0x32, 0x5b, 0xbe, 0x90, 0x0e, 0x74, - 0xc8, 0x22, 0xb5, 0x90, 0xe5, 0x79, 0xfb, 0x22, 0x1d, 0xc3, 0x4f, 0xd7, - 0x13, 0xb3, 0x26, 0x21, 0xa0, 0xc7, 0x4c, 0xde, 0xb9, 0x13, 0xcb, 0xd9, - 0xa3, 0xd5, 0x0b, 0x03, 0x47, 0x07, 0xe8, 0x5f, 0x40, 0x50, 0x99, 0xf4, - 0x21, 0x80, 0x2f, 0x49, 0x24, 0x7d, 0xc3, 0x10, 0xd8, 0xfb, 0x1d, 0x27, - 0x60, 0x9c, 0xaf, 0x68, 0x2f, 0x72, 0xf2, 0xe2, 0x66, 0xb1, 0xce, 0x9e, - 0xbc, 0x75, 0xe6, 0x6f, 0xcf, 0x24, 0x68, 0x8f, 0xe3, 0x77, 0x40, 0x34, - 0x9a, 0x7c, 0xb1, 0x7d, 0x97, 0x40, 0xab, 0x87, 0x7c, 0x20, 0x69, 0x91, - 0x4f, 0xff, 0xfd, 0x66, 0x39, 0x49, 0x13, 0xfb, 0x4c, 0x91, 0x67, 0x0d, - 0x7b, 0xb7, 0x0e, 0x80, 0xb8, 0x5c, 0x53, 0x90, 0xd7, 0xea, 0x04, 0x1b, - 0xcf, 0x73, 0xcd, 0x50, 0x7b, 0xf5, 0x17, 0x3c, 0xa7, 0x6f, 0xe6, 0xf6, - 0x7c, 0x82, 0xaf, 0x4c, 0x4a, 0x5c, 0xee, 0xb7, 0x67, 0x2c, 0x57, 0x6d, - 0x3a, 0xd6, 0xab, 0x7c, 0xb9, 0xc4, 0x14, 0xfd, 0x5e, 0x3e, 0xfc, 0x2a, - 0x75, 0xfe, 0xc6, 0x5e, 0x61, 0x27, 0x99, 0x90, 0x72, 0xd5, 0xf8, 0xfd, - 0xfd, 0xfc, 0x62, 0xaf, 0xe3, 0xe9, 0x6b, 0x70, 0x18, 0x7b, 0x7f, 0xfd, - 0x95, 0xd3, 0xd9, 0x88, 0x4a, 0xc7, 0x4f, 0x6c, 0x41, 0x32, 0xe5, 0x92, - 0x1c, 0x85, 0x56, 0x43, 0xb7, 0xaf, 0x54, 0x84, 0x54, 0xca, 0x30, 0x00, - 0x04, 0xc0, 0x31, 0x27, 0x07, 0x88, 0xcd, 0x0d, 0x79, 0x24, 0xeb, 0x9b, - 0x94, 0x74, 0x23, 0x5d, 0x02, 0x02, 0xed, 0x06, 0x26, 0x13, 0xb1, 0x9e, - 0x8d, 0xa4, 0x65, 0x15, 0x4f, 0x45, 0xa5, 0xfd, 0x1a, 0x1f, 0x94, 0x37, - 0x38, 0x05, 0xed, 0x6a, 0x95, 0x59, 0x12, 0x35, 0xb8, 0x2a, 0xe8, 0xe5, - 0xda, 0x27, 0x4a, 0x3f, 0x9f, 0x48, 0x78, 0xb5, 0x36, 0x25, 0x13, 0x2c, - 0x2c, 0x00, 0xa4, 0x25, 0x71, 0x81, 0x2c, 0xc6, 0x4d, 0xce, 0x78, 0x06, - 0x38, 0x8b, 0x75, 0x03, 0xe4, 0xf0, 0xbb, 0x7f, 0xfb, 0xf3, 0x31, 0xc8, - 0xcd, 0x0f, 0x2f, 0x08, 0x91, 0xf9, 0x94, 0xde, 0xe4, 0x09, 0x10, 0x88, - 0x88, 0xfd, 0xcd, 0x29, 0x3f, 0x32, 0x8d, 0x80, 0x00, 0xea, 0x0b, 0x89, - 0x14, 0x9a, 0x95, 0x2a, 0x79, 0xb1, 0x74, 0x7f, 0xf1, 0x96, 0xba, 0xa7, - 0xc4, 0xa1, 0x75, 0x44, 0xb2, 0x2e, 0xf2, 0x61, 0x46, 0x3e, 0xb8, 0xcb, - 0x96, 0x60, 0xee, 0x70, 0x73, 0x3c, 0xbf, 0xc3, 0xeb, 0x62, 0xb8, 0xec, - 0xbc, 0xf2, 0xa2, 0x69, 0x31, 0x8e, 0xc8, 0x31, 0x46, 0x19, 0x82, 0x6e, - 0xe2, 0x2a, 0xfb, 0x95, 0xfc, 0xe4, 0x3c, 0x61, 0x7d, 0xe6, 0xf6, 0x5d, - 0x89, 0xe5, 0x03, 0x71, 0xe6, 0x16, 0xf2, 0x99, 0x06, 0x32, 0x15, 0xd7, - 0x7f, 0x20, 0x58, 0xb0, 0x7b, 0x56, 0xc3, 0x7f, 0x91, 0xba, 0x10, 0x4e, - 0x5b, 0x68, 0x7b, 0x78, 0x88, 0xf7, 0xf2, 0xda, 0x30, 0x50, 0x0a, 0xd7, - 0xb3, 0x12, 0xfa, 0x5b, 0x31, 0x9d, 0xd9, 0x5c, 0xed, 0xf6, 0xe6, 0xa8, - 0xfc, 0x88, 0x19, 0x51, 0x6a, 0xfe, 0xc0, 0x86, 0xcd, 0x12, 0xc5, 0xa3, - 0x27, 0xa3, 0x3d, 0x09, 0x41, 0x08, 0xfd, 0xf8, 0x5f, 0x3e, 0x6d, 0xc4, - 0xcf, 0xbe, 0xab, 0x3f, 0xd2, 0xe1, 0xba, 0xdc, 0x8a, 0xcc, 0x76, 0x8c, - 0x21, 0x9c, 0x1c, 0xd3, 0x3a, 0xf5, 0x35, 0xc3, 0x55, 0xee, 0x74, 0xfb, - 0x9d, 0x7d, 0xec, 0xdf, 0xaa, 0x56, 0xdd, 0x52, 0x46, 0x95, 0x8d, 0x48, - 0xb5, 0xe8, 0x53, 0x91, 0xd8, 0x09, 0xf4, 0x04, 0xf7, 0x64, 0x39, 0x5c, - 0xac, 0x05, 0x71, 0x5c, 0x58, 0xbb, 0xf3, 0x18, 0xe7, 0xff, 0x5d, 0x04, - 0xfe, 0x00, 0xce, 0x2f, 0x56, 0x7e, 0x28, 0xa5, 0x52, 0xb9, 0xfe, 0xcb, - 0xa5, 0xbd, 0xe2, 0xf4, 0x06, 0xb4, 0x71, 0x4e, 0xd6, 0xbf, 0x76, 0x6f, - 0xe1, 0x04, 0x73, 0x3a, 0xb4, 0x2e, 0x8f, 0x7b, 0xae, 0x1b, 0x1a, 0x17, - 0x32, 0x4d, 0x01, 0xa7, 0x34, 0xdf, 0x15, 0xbf, 0x66, 0x0b, 0x4b, 0x3c, - 0x69, 0x56, 0x91, 0x80, 0x52, 0xe0, 0xf0, 0x1f, 0x50, 0x3f, 0x7e, 0xc3, - 0x83, 0x2d, 0x55, 0xdc, 0x65, 0x58, 0x10, 0xcf, 0x48, 0x63, 0x02, 0xfa, - 0x6c, 0xd0, 0x28, 0x82, 0x35, 0x96, 0x6f, 0x86, 0xc2, 0xc5, 0x7d, 0x67, - 0x2a, 0x4a, 0x8b, 0x4e, 0xc5, 0x23, 0xa9, 0x0f, 0x0c, 0xec, 0xde, 0xaa, - 0xcd, 0xa8, 0x4d, 0x1b, 0x1e, 0x58, 0x85, 0xf4, 0x2b, 0xba, 0xba, 0x6c, - 0x95, 0xee, 0x0e, 0x69, 0x09, 0x04, 0x45, 0xcd, 0x14, 0x81, 0x13, 0x59, - 0x3c, 0x72, 0xc2, 0x1f, 0xbe, 0xc7, 0x85, 0x73, 0x68, 0x5c, 0xca, 0x26, - 0x51, 0xf0, 0xa3, 0xd9, 0x68, 0x1e, 0xc9, 0x1d, 0xb9, 0x17, 0x51, 0xd6, - 0xf0, 0x1d, 0x30, 0x4f, 0x78, 0x6a, 0x29, 0x2b, 0x75, 0x27, 0xa8, 0x42, - 0x5a, 0x18, 0xe9, 0x1b, 0xc9, 0x4f, 0xfa, 0x89, 0x94, 0xe5, 0x6d, 0xa9, - 0x18, 0x82, 0x9a, 0x74, 0x14, 0xb1, 0x24, 0x3a, 0xd9, 0x84, 0x45, 0x7c, - 0x40, 0x46, 0x25, 0xce, 0xec, 0x10, 0x26, 0x54, 0xee, 0x27, 0xfe, 0x14, - 0xb4, 0x48, 0xcb, 0xaf, 0xc0, 0x58, 0xe4, 0x96, 0x1e, 0xeb, 0xc4, 0x51, - 0x81, 0x90, 0xa6, 0xa1, 0x1c, 0xce, 0x85, 0xb2, 0x12, 0x24, 0x4c, 0x7c, - 0xce, 0x5a, 0x83, 0x0e, 0xc6, 0x57, 0xdc, 0x62, 0xb1, 0xa5, 0xf4, 0x28, - 0xb9, 0x4b, 0x50, 0x1f, 0x46, 0xfb, 0xd9, 0x48, 0x4e, 0xa5, 0xab, 0x88, - 0x7d, 0x66, 0x94, 0x06, 0xf5, 0x0d, 0xa2, 0x0f, 0xc6, 0xfd, 0xe4, 0xc5, - 0xd8, 0x92, 0x4c, 0xf7, 0x00, 0x3d, 0x2a, 0x76, 0x4c, 0x2a, 0xa5, 0x6c, - 0x47, 0x22, 0x17, 0x10, 0x05, 0x62, 0x32, 0x19, 0x44, 0xaa, 0xfb, 0xe1, - 0x9e, 0x18, 0xc6, 0xb3, 0xe8, 0x4f, 0x67, 0xf2, 0x5a, 0xb8, 0x01, 0x4b, - 0x29, 0x0d, 0xb3, 0x30, 0x2d, 0x06, 0xac, 0x3e, 0x8a, 0xe4, 0x5b, 0xe1, - 0x6a, 0x68, 0x5a, 0x8f, 0x27, 0x1b, 0xd2, 0x83, 0x4e, 0x80, 0x51, 0xcc, - 0x31, 0xb7, 0xc4, 0x77, 0x0b, 0xa1, 0xfd, 0x90, 0x33, 0x41, 0x79, 0x33, - 0x09, 0x9c, 0x14, 0xe4, 0x2e, 0xee, 0x6a, 0xf9, 0x7b, 0x30, 0x49, 0x88, - 0x98, 0x47, 0xf5, 0xca, 0xa6, 0xbd, 0x4f, 0xc3, 0xc4, 0x67, 0xd3, 0xed, - 0x3d, 0x06, 0xae, 0xde, 0x53, 0x57, 0xa5, 0xeb, 0xb5, 0x44, 0x2d, 0x82, - 0xaf, 0x5c, 0xfc, 0x90, 0x2b, 0x72, 0x75, 0x4f, 0xc4, 0xaf, 0x9b, 0xb3, - 0x71, 0x6e, 0xf1, 0x93, 0xa8, 0xa0, 0xd0, 0x05, 0x9f, 0xfa, 0x80, 0x8c, - 0x4d, 0x16, 0x03, 0x30, 0x6b, 0x42, 0x30, 0x1a, 0xbc, 0x59, 0xb5, 0xd3, - 0xd2, 0x0a, 0xf1, 0x24, 0x74, 0xb8, 0xa4, 0x05, 0xc8, 0x91, 0xe6, 0x03, - 0xf0, 0x08, 0xd5, 0xb7, 0x8b, 0xea, 0xe9, 0x4c, 0x7f, 0xc0, 0xba, 0xd0, - 0xbf, 0x32, 0xcb, 0x57, 0xe9, 0xa2, 0x59, 0xef, 0x5c, 0xaa, 0x4c, 0xf0, - 0xc5, 0x50, 0xb7, 0x89, 0x09, 0x4b, 0x1b, 0x67, 0x33, 0x91, 0xbd, 0xa2, - 0x66, 0xe7, 0xde, 0x09, 0xfd, 0xe6, 0x5b, 0x70, 0x67, 0xf1, 0xdf, 0xa8, - 0xfa, 0x57, 0x5d, 0x39, 0x1a, 0xd0, 0x33, 0x4a, 0xf2, 0x6c, 0x32, 0x52, - 0x75, 0x37, 0xf5, 0xe3, 0xbe, 0x52, 0x0a, 0xf4, 0xc5, 0xb5, 0xd1, 0xe6, - 0xf2, 0x61, 0x97, 0xda, 0x5f, 0x22, 0x54, 0x16, 0x6e, 0xb0, 0x43, 0x3e, - 0x26, 0x40, 0x06, 0x89, 0x94, 0x5c, 0x4c, 0xce, 0xf7, 0x32, 0x70, 0x24, - 0xa0, 0xa8, 0xc6, 0xf0, 0x86, 0x9a, 0x92, 0x65, 0xf9, 0x8b, 0xbb, 0xd3, - 0xd7, 0xaf, 0xeb, 0x4e, 0xbb, 0x20, 0x11, 0xfc, 0x28, 0xec, 0x95, 0xe6, - 0xd5, 0x34, 0xbd, 0xd0, 0x12, 0xa4, 0xae, 0x0f, 0xc5, 0xa0, 0x3e, 0xa4, - 0x6d, 0x0a, 0x50, 0xdc, 0x4e, 0x0e, 0xe4, 0x1f, 0x34, 0x37, 0x9b, 0x26, - 0x4e, 0xf0, 0x2a, 0x50, 0x93, 0x58, 0xf2, 0xd2, 0x60, 0x82, 0x50, 0xe6, - 0x7d, 0xfd, 0x84, 0xaf, 0x9d, 0x3a, 0xe8, 0xe5, 0x67, 0xbb, 0xb5, 0xf1, - 0xfc, 0x41, 0xa0, 0x7a, 0x0e, 0x5e, 0xb3, 0x7e, 0x75, 0x3a, 0xca, 0xf3, - 0x73, 0x70, 0x85, 0xd5, 0xe7, 0xbe, 0x19, 0xe8, 0x43, 0xfc, 0x93, 0x64, - 0x68, 0x82, 0x87, 0xbf, 0x85, 0x77, 0xd9, 0xec, 0xe0, 0x19, 0xf9, 0x8c, - 0xef, 0x8f, 0xb9, 0xcd, 0xe4, 0xb9, 0x8a, 0xd7, 0x23, 0x55, 0xa1, 0xcb, - 0x18, 0xbf, 0xd4, 0x16, 0xee, 0x37, 0x01, 0xc3, 0xb5, 0xcc, 0xa7, 0x80, - 0x15, 0x37, 0xe0, 0x48, 0x71, 0xc5, 0x4d, 0x21, 0xd8, 0x25, 0x31, 0xee, - 0xef, 0xa1, 0x69, 0x37, 0x19, 0xbb, 0x14, 0x81, 0x2c, 0x45, 0x81, 0x16, - 0x6b, 0x42, 0x4e, 0x09, 0xf1, 0xbd, 0xd8, 0x5f, 0xc8, 0x89, 0x52, 0x40, - 0x54, 0x50, 0x5f, 0xb0, 0xac, 0xc3, 0x73, 0x7b, 0x9d, 0x02, 0xcc, 0xd1, - 0x12, 0x54, 0x83, 0x76, 0x69, 0x8f, 0x39, 0x48, 0xa9, 0x18, 0x7a, 0x81, - 0x22, 0x73, 0x78, 0x78, 0x9a, 0x09, 0x67, 0xc2, 0xba, 0x7d, 0x83, 0xc6, - 0x1a, 0xe5, 0x47, 0x2d, 0xca, 0x8c, 0xa2, 0xef, 0x28, 0x9c, 0x4a, 0xde, - 0xe9, 0xe0, 0xcf, 0x8f, 0x30, 0x40, 0xa4, 0x26, 0x8e, 0x98, 0xa5, 0xcc, - 0x58, 0x99, 0x11, 0x6c, 0xcd, 0x0a, 0x0f, 0x9d, 0x87, 0x01, 0x8d, 0x05, - 0xfc, 0x69, 0x2a, 0xc3, 0xd3, 0x5a, 0x08, 0x59, 0x91, 0x78, 0x6a, 0x89, - 0xb1, 0x8b, 0x4e, 0x62, 0x0f, 0xf9, 0xc7, 0x10, 0x66, 0xb2, 0xcf, 0xac, - 0xed, 0xe7, 0x82, 0x2b, 0x59, 0x34, 0xc7, 0x36, 0x60, 0xf1, 0xa3, 0xb8, - 0x9f, 0x82, 0xdb, 0xac, 0x17, 0x39, 0x00, 0x73, 0xe2, 0x19, 0xab, 0x4d, - 0x69, 0x45, 0x3a, 0x01, 0x46, 0xab, 0x96, 0xb7, 0x12, 0xba, 0xd5, 0x09, - 0xf1, 0xe5, 0xf6, 0x01, 0xc5, 0x15, 0x4a, 0x74, 0x12, 0x10, 0x47, 0x57, - 0xaf, 0x36, 0xa0, 0x11, 0xc2, 0x14, 0x46, 0xc0, 0xf0, 0x4c, 0xf1, 0xc3, - 0x80, 0xc2, 0xe0, 0xc3, 0xe9, 0x5b, 0xcb, 0x54, 0x41, 0x79, 0x90, 0xd7, - 0xf1, 0x4d, 0xbb, 0x6c, 0x76, 0x62, 0x60, 0x83, 0xa0, 0x58, 0x6f, 0xd0, - 0xc0, 0x47, 0x05, 0x07, 0x1a, 0x74, 0x03, 0x91, 0x49, 0xee, 0x32, 0xce, - 0xba, 0x24, 0xb2, 0xe2, 0x66, 0xd6, 0xc0, 0x34, 0x3e, 0x0d, 0x90, 0x1f, - 0x02, 0x72, 0xe2, 0xd5, 0x68, 0x06, 0x48, 0x24, 0x48, 0x01, 0x80, 0xc5, - 0x59, 0x75, 0xeb, 0x22, 0x7f, 0xd7, 0xac, 0x58, 0xeb, 0x25, 0x48, 0xbc, - 0x67, 0xf6, 0xa6, 0xa7, 0x04, 0x78, 0x85, 0x3c, 0xfb, 0x27, 0xe7, 0x61, - 0x71, 0x86, 0xa6, 0x37, 0xda, 0x3c, 0xd6, 0x30, 0x7e, 0x7e, 0x27, 0x20, - 0xde, 0xb0, 0xb7, 0xff, 0xed, 0x8f, 0x20, 0xb8, 0x9a, 0xc6, 0x86, 0xcc, - 0x62, 0x83, 0xe2, 0x83, 0x5b, 0x7e, 0x69, 0x37, 0x09, 0xe3, 0x16, 0xc8, - 0x14, 0xc4, 0x3a, 0xf2, 0x4c, 0xe5, 0x91, 0xe7, 0x42, 0x85, 0xd0, 0xc2, - 0xb8, 0x9a, 0x4f, 0xb6, 0xc7, 0xcb, 0xa5, 0xd8, 0xc4, 0xec, 0x7d, 0xdb, - 0x93, 0x34, 0x54, 0xf0, 0x84, 0x19, 0x7a, 0xeb, 0x17, 0xa2, 0x8c, 0x95, - 0x35, 0xd8, 0x7e, 0x45, 0x89, 0x7f, 0x76, 0xe1, 0x4b, 0x16, 0xdd, 0x14, - 0xd7, 0xef, 0x97, 0xca, 0x18, 0x41, 0x72, 0x7f, 0xfd, 0x5a, 0xea, 0xb9, - 0x21, 0x89, 0xc2, 0x3f, 0x9d, 0x80, 0xe0, 0xe6, 0xb1, 0x1a, 0x04, 0x24, - 0x86, 0x11, 0x31, 0x05, 0x91, 0xcb, 0x51, 0x5f, 0x9d, 0xf1, 0x17, 0xb3, - 0x57, 0x8d, 0x92, 0xeb, 0xd1, 0xfe, 0x28, 0x54, 0x65, 0xec, 0x15, 0xdc, - 0x2f, 0x57, 0x70, 0x97, 0x3a, 0x29, 0x9a, 0x52, 0xd1, 0xb0, 0xf1, 0x0f, - 0x76, 0x77, 0x95, 0x7a, 0xbe, 0x18, 0xfe, 0xd8, 0x3f, 0x94, 0x96, 0x36, - 0x69, 0xfa, 0xec, 0x9f, 0x63, 0x7e, 0x25, 0xde, 0x79, 0x76, 0x7b, 0x27, - 0x7c, 0xe8, 0xb3, 0x9e, 0x4a, 0x94, 0xe1, 0xe0, 0x4a, 0xd8, 0x45, 0x4f, - 0xac, 0x41, 0x54, 0xe9, 0xf7, 0x75, 0x56, 0xdc, 0x2f, 0x84, 0x4d, 0x51, - 0xfa, 0xe2, 0xbd, 0xb1, 0xfb, 0x65, 0x0a, 0xb0, 0x9e, 0xd7, 0xa0, 0x95, - 0x78, 0x1c, 0xf3, 0xbb, 0xd4, 0xea, 0x1f, 0x8d, 0x11, 0x33, 0x90, 0xa6, - 0x48, 0x34, 0xa9, 0x69, 0x2e, 0xdc, 0x25, 0x76, 0x8e, 0x4c, 0x60, 0x52, - 0x8a, 0xb5, 0x89, 0xc6, 0xdc, 0x0e, 0xb6, 0x80, 0x04, 0x3b, 0x28, 0x94, - 0xfa, 0xc4, 0xfb, 0x9d, 0x5b, 0xaa, 0x16, 0x35, 0x0a, 0x30, 0xcb, 0xf9, - 0x45, 0xcc, 0x49, 0x4e, 0x9b, 0xa4, 0xd3, 0x4f, 0xcc, 0xbc, 0x23, 0xde, - 0xe9, 0x17, 0x57, 0x86, 0x9f, 0x08, 0xba, 0x6f, 0x3c, 0xd5, 0xaa, 0x86, - 0x30, 0x71, 0xd3, 0x3d, 0x61, 0xe7, 0x2f, 0x4e, 0xec, 0x6f, 0xd7, 0x0b, - 0x55, 0x48, 0xd4, 0x1e, 0xfe, 0xbe, 0x95, 0x36, 0xda, 0x7c, 0xa8, 0x66, - 0x28, 0x6d, 0xd2, 0x2d, 0x0e, 0xcd, 0x10, 0xda, 0xb5, 0x3c, 0xbd, 0x0e, - 0x0c, 0xa9, 0x44, 0x07, 0x14, 0xe2, 0x48, 0xc7, 0xaa, 0x5b, 0x24, 0xfd, - 0xb7, 0x62, 0x86, 0xbd, 0xa4, 0x2d, 0x8f, 0x96, 0x98, 0x05, 0xa8, 0xfb, - 0xd7, 0x3d, 0x8e, 0xdc, 0xa6, 0x20, 0x02, 0x8b, 0xec, 0x84, 0xdf, 0xe4, - 0xdb, 0xf8, 0xf1, 0xb0, 0x6b, 0x93, 0xcf, 0x48, 0x50, 0xbc, 0x2d, 0x4e, - 0xc8, 0xb0, 0xe7, 0x2e, 0x48, 0xdb, 0x17, 0xe2, 0xa3, 0xa5, 0xc8, 0x79, - 0x39, 0x33, 0x09, 0x0d, 0xf7, 0x63, 0x85, 0xe9, 0x5b, 0x3a, 0x0d, 0xca, - 0x4c, 0xbb, 0xa2, 0x76, 0x9f, 0x14, 0x41, 0xe7, 0x92, 0x79, 0x2c, 0x16, - 0x14, 0x59, 0x83, 0xf8, 0xed, 0x50, 0x6f, 0xe2, 0xab, 0x54, 0x6a, 0x5c, - 0x40, 0x59, 0x6f, 0x1a, 0xf3, 0x21, 0x9d, 0xb8, 0x0c, 0x15, 0x05, 0xb2, - 0x5e, 0x9d, 0x3f, 0x97, 0x7e, 0xe6, 0xbf, 0xe7, 0xe0, 0x4a, 0x73, 0x85, - 0x1d, 0xdc, 0x27, 0x38, 0xb8, 0xce, 0xe7, 0x98, 0xd7, 0x45, 0x2f, 0x81, - 0xe2, 0x1c, 0x63, 0x36, 0x02, 0x5b, 0xb1, 0xae, 0x31, 0x38, 0x33, 0x18, - 0xda, 0x5d, 0x7b, 0xd1, 0xc6, 0xdf, 0x71, 0x09, 0xe5, 0x2a, 0xcc, 0x5c, - 0x9f, 0x4c, 0x33, 0x3f, 0xb7, 0x47, 0x0c, 0x46, 0xac, 0xe8, 0xbb, 0x87, - 0xa2, 0xd9, 0x6a, 0x55, 0x30, 0x6f, 0x7f, 0xab, 0xab, 0x5b, 0x8c, 0x67, - 0x2c, 0xf4, 0x02, 0x59, 0x1d, 0xf0, 0xb9, 0x89, 0xcb, 0xaf, 0x72, 0xec, - 0xa7, 0xdb, 0x12, 0x8a, 0xa8, 0x41, 0xd4, 0x1f, 0xb7, 0xad, 0x21, 0x21, - 0xaf, 0xbf, 0xf9, 0xe4, 0x03, 0xff, 0xc0, 0x11, 0xae, 0x08, 0xc2, 0x6e, - 0x11, 0x6d, 0xec, 0x92, 0x6f, 0x10, 0x40, 0x87, 0x42, 0x4a, 0xe3, 0x47, - 0x03, 0x31, 0xf2, 0x0a, 0x59, 0xa9, 0x35, 0x3d, 0xd1, 0xc6, 0x3a, 0x36, - 0xf9, 0x7c, 0xac, 0xc5, 0xb2, 0xdb, 0x76, 0x1b, 0x8d, 0x0a, 0xcb, 0x85, - 0x56, 0xfc, 0xb8, 0x3c, 0x50, 0xe5, 0x16, 0x3a, 0xad, 0xdc, 0x0e, 0x80, - 0xce, 0x30, 0x1b, 0xac, 0xc4, 0x4c, 0x9a, 0xb1, 0x5f, 0x82, 0xa3, 0x5c, - 0xf9, 0x2b, 0xfd, 0x70, 0x44, 0xfe, 0xea, 0x11, 0x49, 0xbc, 0x07, 0x67, - 0x49, 0x76, 0x13, 0xb5, 0xb2, 0xfc, 0x15, 0x55, 0x05, 0x37, 0x2a, 0xac, - 0xdc, 0xc5, 0xf3, 0xe1, 0xd2, 0x1a, 0x6c, 0x76, 0x5a, 0xd7, 0xd9, 0xa2, - 0x42, 0x02, 0x56, 0x1b, 0xca, 0xdc, 0x6d, 0x86, 0xda, 0xc5, 0x3e, 0xc0, - 0xac, 0xf3, 0xbf, 0x9c, 0x90, 0xa9, 0x7a, 0x69, 0x81, 0x88, 0x12, 0x10, - 0xf0, 0x81, 0xb3, 0x71, 0xcc, 0x58, 0x36, 0x05, 0x7d, 0xf4, 0xa8, 0x84, - 0x9d, 0x75, 0x59, 0x74, 0x5b, 0x02, 0x56, 0x6e, 0x8f, 0xb9, 0xfe, 0xa4, - 0xeb, 0xcd, 0xfb, 0xd0, 0xf3, 0xca, 0x70, 0xbc, 0x99, 0x8d, 0x6d, 0x5f, - 0x89, 0x6b, 0xd0, 0x6e, 0x60, 0xb7, 0x69, 0x53, 0x09, 0xc7, 0x42, 0xa0, - 0x0d, 0x96, 0xaf, 0x99, 0xec, 0xce, 0x38, 0x5b, 0xba, 0x40, 0x0c, 0x82, - 0x4a, 0x5e, 0x86, 0xd5, 0xcc, 0x5b, 0xa9, 0x04, 0xec, 0xb4, 0x47, 0x70, - 0x17, 0x44, 0xb4, 0xe4, 0x05, 0xbb, 0x8b, 0xce, 0xa7, 0x2a, 0xd6, 0xfd, - 0x1c, 0xa5, 0x34, 0xbf, 0xfe, 0xa5, 0x30, 0x41, 0x15, 0x7a, 0x43, 0xff, - 0xed, 0xc3, 0x5d, 0x40, 0xa8, 0x1f, 0x2a, 0x29, 0x93, 0x7f, 0x23, 0x34, - 0xc9, 0x30, 0xe2, 0x4f, 0x59, 0x3d, 0x32, 0xb1, 0x25, 0x06, 0xa3, 0x45, - 0x96, 0xe1, 0x44, 0x8b, 0x69, 0xfd, 0x2b, 0x49, 0x71, 0xcb, 0x38, 0xf4, - 0xf4, 0x2b, 0x89, 0x6a, 0x72, 0x98, 0x6a, 0xc3, 0xc0, 0x57, 0xac, 0x79, - 0xfe, 0x2f, 0x04, 0xfd, 0xe1, 0xba, 0x18, 0x62, 0xfe, 0x30, 0x03, 0x6f, - 0xed, 0xdf, 0x9f, 0xbe, 0xd0, 0x0a, 0xa4, 0xdb, 0x0c, 0x3a, 0x0e, 0xd4, - 0xf7, 0x41, 0xa7, 0x66, 0x3a, 0x8e, 0xf0, 0xa7, 0xaf, 0x73, 0xa4, 0xc9, - 0xc8, 0xe7, 0xc7, 0x6f, 0x9f, 0x16, 0x71, 0xf9, 0xdf, 0xaf, 0x91, 0xa5, - 0x98, 0x0b, 0xed, 0xc0, 0x4e, 0x59, 0x9b, 0x4e, 0x8c, 0x78, 0x71, 0xdb, - 0x9a, 0x90, 0x65, 0xf4, 0xc7, 0x73, 0xb9, 0xfa, 0xa3, 0x2b, 0x67, 0xcf, - 0x35, 0xb5, 0x0e, 0x28, 0x7c, 0x69, 0xf8, 0x67, 0xbd, 0x52, 0xed, 0x51, - 0xc7, 0x18, 0xe4, 0x6f, 0xe6, 0xdd, 0x63, 0xe0, 0xa9, 0xba, 0x93, 0xca, - 0xa7, 0x26, 0x21, 0xaf, 0x5d, 0x1e, 0x42, 0x77, 0x45, 0x74, 0x84, 0x45, - 0x40, 0xe4, 0x63, 0x35, 0x74, 0x39, 0x89, 0x54, 0x63, 0x9c, 0xc9, 0x00, - 0xf1, 0xe0, 0xe1, 0xd4, 0x4d, 0xa1, 0x41, 0xdf, 0xb1, 0x5b, 0xa9, 0xfd, - 0x96, 0x10, 0x29, 0xe9, 0x69, 0xee, 0x6c, 0x8d, 0x60, 0xb6, 0xbe, 0xd0, - 0x27, 0x69, 0x97, 0xc5, 0xc1, 0x78, 0xe5, 0x91, 0x6c, 0x3b, 0x1e, 0xa4, - 0x16, 0x58, 0xbf, 0x35, 0x40, 0xa7, 0x5e, 0xee, 0x89, 0x1d, 0xe4, 0x6b, - 0x1b, 0xf5, 0x85, 0x79, 0xe6, 0xdc, 0x34, 0x07, 0x19, 0xc4, 0x79, 0x16, - 0xe2, 0xe7, 0x63, 0x61, 0xd5, 0x38, 0x11, 0xef, 0x72, 0xcb, 0x7d, 0x3d, - 0x90, 0x56, 0x3e, 0x82, 0xaa, 0x81, 0x4b, 0xe7, 0x77, 0x87, 0x85, 0xbb, - 0xda, 0x6a, 0x5a, 0x25, 0x11, 0x03, 0xe3, 0xe9, 0x31, 0x26, 0xeb, 0xc9, - 0x1e, 0x07, 0xea, 0xb9, 0x0c, 0x64, 0xdd, 0x3d, 0x7e, 0x61, 0x64, 0x7d, - 0x16, 0xd1, 0x5d, 0xcd, 0x65, 0x80, 0x5d, 0x9d, 0x73, 0xa7, 0x62, 0x86, - 0x87, 0x8b, 0x92, 0xca, 0x59, 0xfa, 0x8e, 0xf7, 0x99, 0x78, 0x73, 0x6d, - 0xcc, 0xc0, 0x81, 0x0d, 0x88, 0xd7, 0xfc, 0x1b, 0x75, 0xc3, 0x82, 0x84, - 0x51, 0x72, 0x7c, 0xb3, 0x90, 0x65, 0x97, 0x05, 0x8c, 0x0c, 0xd1, 0xe5, - 0xa6, 0xa9, 0x30, 0xa1, 0x51, 0xa0, 0x63, 0x6e, 0xcc, 0xdb, 0xe0, 0x7a, - 0xdd, 0x69, 0xdc, 0xd0, 0x27, 0xf6, 0xf7, 0x27, 0x95, 0x3a, 0xf4, 0x6d, - 0x67, 0x59, 0x14, 0x0a, 0x03, 0x96, 0xae, 0xad, 0x17, 0xad, 0xa3, 0xa4, - 0xde, 0x56, 0x8a, 0x37, 0xa7, 0xe8, 0xb4, 0x1f, 0xf3, 0x85, 0xdf, 0x7c, - 0x86, 0x33, 0xea, 0xf5, 0xd2, 0x7c, 0x2f, 0x7f, 0xf4, 0xf2, 0xd4, 0x41, - 0x9f, 0x55, 0xe7, 0x03, 0x3c, 0xf8, 0xeb, 0xab, 0xf9, 0xd4, 0x79, 0x42, - 0xdf, 0x3e, 0x6e, 0x7d, 0xd2, 0x71, 0x1d, 0x7a, 0xcf, 0xc7, 0x0c, 0xc8, - 0x6a, 0x2c, 0xe0, 0x19, 0xc1, 0x6d, 0x04, 0x29, 0x3f, 0xd9, 0xd3, 0xee, - 0x61, 0x1e, 0x01, 0x41, 0x66, 0xe7, 0xf2, 0x56, 0x5a, 0xf7, 0xa4, 0x4a, - 0x69, 0x59, 0xcd, 0xe2, 0x35, 0x3d, 0x6e, 0x7b, 0x0b, 0x74, 0x2f, 0xcc, - 0x7c, 0xc3, 0xd9, 0x26, 0xc4, 0x6c, 0x9f, 0xb5, 0x0b, 0xad, 0x30, 0x06, - 0x5b, 0x54, 0x30, 0x87, 0x39, 0x5c, 0x1e, 0xd1, 0xee, 0x9c, 0x8a, 0x71, - 0xd5, 0xb9, 0x86, 0x47, 0x40, 0x75, 0x66, 0xc7, 0xd2, 0x9d, 0xa5, 0x3d, - 0xd3, 0x94, 0x44, 0xde, 0x08, 0xb5, 0x2d, 0x94, 0xc7, 0xd7, 0xfa, 0x16, - 0x07, 0x6c, 0x3e, 0x15, 0x57, 0x67, 0x07, 0x92, 0xf3, 0xb1, 0x0e, 0x5f, - 0x59, 0xaf, 0xf9, 0x66, 0x74, 0xc3, 0x61, 0x51, 0x39, 0x9a, 0x42, 0xd8, - 0x49, 0xdb, 0x1a, 0x14, 0xa0, 0xa3, 0x8b, 0x18, 0x36, 0x5c, 0xaf, 0xa6, - 0x11, 0x6d, 0x60, 0xd2, 0xdc, 0x44, 0xa2, 0xc2, 0x8e, 0x7b, 0x16, 0x92, - 0x80, 0xac, 0x4a, 0x1b, 0x50, 0x31, 0xb7, 0x25, 0x95, 0xe4, 0xb7, 0xe6, - 0x59, 0xc3, 0x8e, 0x0a, 0x7c, 0x47, 0x03, 0x50, 0x26, 0xa2, 0xa9, 0x5a, - 0xcb, 0x23, 0x55, 0x79, 0x03, 0x29, 0xa0, 0xaf, 0x01, 0x5a, 0xbc, 0x05, - 0xb5, 0xa1, 0x87, 0x16, 0x29, 0x29, 0x4b, 0x3b, 0xaa, 0xa9, 0xcd, 0x37, - 0xb4, 0x50, 0x07, 0x4f, 0x21, 0x17, 0x71, 0x0d, 0x76, 0xd8, 0xdd, 0xbc, - 0x04, 0x70, 0x3e, 0xac, 0x9d, 0xe5, 0x1b, 0xb2, 0x04, 0x6c, 0xd0, 0x6b, - 0x26, 0x95, 0x94, 0xb7, 0x26, 0x5f, 0xd0, 0x6c, 0xdc, 0xd9, 0xec, 0x93, - 0x78, 0x4f, 0x96, 0xfb, 0x36, 0xc3, 0x66, 0xe4, 0x62, 0x29, 0x59, 0x4c, - 0x54, 0x71, 0xab, 0xa4, 0x43, 0xa4, 0xcb, 0x5b, 0x43, 0x49, 0x07, 0xf8, - 0xe6, 0x26, 0xcf, 0xcf, 0x98, 0x88, 0xeb, 0x99, 0x0d, 0xab, 0x40, 0x67, - 0xbc, 0x0c, 0xff, 0x3d, 0xe0, 0xdb, 0x8f, 0x19, 0xf7, 0x80, 0xd3, 0x4e, - 0xc1, 0xd1, 0x0d, 0x47, 0x4f, 0xeb, 0xe7, 0x6c, 0xe8, 0x98, 0xd5, 0x73, - 0xa0, 0xb4, 0x9f, 0xed, 0x21, 0x44, 0x13, 0x93, 0xe5, 0x38, 0x95, 0x1e, - 0xf9, 0xe8, 0x73, 0xe2, 0x06, 0x37, 0xe5, 0xd9, 0x2d, 0xbe, 0xba, 0x87, - 0x93, 0xdb, 0xc7, 0x9e, 0x29, 0xf2, 0x3d, 0x8a, 0xe9, 0xa6, 0xa3, 0x0e, - 0x25, 0xb2, 0x79, 0xe5, 0x8c, 0xdd, 0xb8, 0x16, 0x5e, 0x3f, 0x86, 0x7b, - 0x25, 0x88, 0x3f, 0x77, 0x33, 0x74, 0x72, 0x5e, 0x7e, 0xbf, 0x88, 0xa9, - 0x18, 0x14, 0xb2, 0xea, 0x20, 0x01, 0xcf, 0x2b, 0x19, 0x07, 0xa0, 0xd8, - 0x2b, 0x84, 0x3b, 0x52, 0xdf, 0xf1, 0x87, 0x89, 0x3f, 0x40, 0x95, 0x4e, - 0x8f, 0x91, 0x82, 0xf0, 0x7e, 0x16, 0x88, 0xe7, 0xf5, 0xf9, 0x0b, 0xbc, - 0x25, 0x38, 0xdf, 0x32, 0xbe, 0xc6, 0x62, 0xe4, 0x63, 0xde, 0xdd, 0x9d, - 0x07, 0x93, 0x19, 0xfd, 0x38, 0xee, 0x4c, 0x74, 0x42, 0xd5, 0xb1, 0x4c, - 0x5f, 0xea, 0xa7, 0xb6, 0xa0, 0x84, 0x5f, 0xd7, 0xd7, 0xba, 0x8a, 0x41, - 0x7b, 0xa7, 0x66, 0x5c, 0xd7, 0xb2, 0xeb, 0xad, 0x15, 0x3b, 0x4c, 0x16, - 0x83, 0xe3, 0x16, 0x51, 0x3d, 0x94, 0x42, 0x8d, 0x9f, 0x9c, 0x85, 0x2d, - 0x27, 0x26, 0x55, 0xa6, 0x34, 0xf6, 0x59, 0x2c, 0x46, 0xe6, 0xe1, 0x7b, - 0xde, 0x07, 0x1d, 0x1c, 0x34, 0x70, 0xca, 0xab, 0x24, 0x64, 0x14, 0x8e, - 0xee, 0x93, 0x8c, 0x90, 0x67, 0x35, 0xe1, 0x25, 0x56, 0x97, 0x27, 0x0d, - 0x94, 0xb8, 0x9c, 0xa9, 0xdf, 0xea, 0x56, 0x50, 0xeb, 0x0b, 0x61, 0x75, - 0x4d, 0xad, 0x77, 0xcf, 0xb9, 0xf8, 0x41, 0x95, 0x8f, 0x05, 0x50, 0xaf, - 0x2d, 0x2d, 0xc2, 0x8b, 0x75, 0x5d, 0x2d, 0xa1, 0xca, 0xf8, 0x33, 0xdb, - 0xb0, 0xf0, 0x0e, 0x6b, 0x11, 0x53, 0xd4, 0xd4, 0x56, 0x49, 0x4c, 0x1d, - 0x08, 0x0d, 0x5a, 0x61, 0x36, 0x67, 0x13, 0x57, 0xa0, 0x88, 0xaf, 0x48, - 0xfb, 0x56, 0x17, 0x65, 0x9a, 0xd9, 0xf1, 0xef, 0x16, 0xf7, 0x5e, 0x11, - 0x8e, 0xe2, 0xd4, 0x70, 0x41, 0xfb, 0x49, 0x6a, 0x47, 0x07, 0x8c, 0x67, - 0x4d, 0x34, 0xe6, 0xd9, 0x9f, 0x1a, 0x1a, 0xa8, 0xce, 0x5c, 0x33, 0x41, - 0x18, 0xbd, 0x8e, 0xca, 0xda, 0xb2, 0x58, 0xc1, 0xbc, 0x7d, 0x7c, 0xc8, - 0xef, 0x6d, 0x84, 0xfe, 0x5e, 0x30, 0x10, 0xdd, 0x6d, 0xae, 0x7d, 0x59, - 0x75, 0x7c, 0x37, 0x50, 0x4a, 0x1b, 0x18, 0x1a, 0x0e, 0x61, 0x9e, 0x0f, - 0xae, 0x5d, 0x58, 0x8c, 0x83, 0x44, 0xb3, 0xe0, 0xc0, 0x29, 0x3c, 0xd6, - 0x4a, 0x5a, 0x8b, 0x01, 0x5c, 0x5a, 0x1f, 0xd4, 0xd6, 0xea, 0xcd, 0x91, - 0x7b, 0xbf, 0x0c, 0x7c, 0xbe, 0xe5, 0x8d, 0x4d, 0xd8, 0xad, 0x74, 0x62, - 0xff, 0x9e, 0xa4, 0x61, 0x1f, 0x86, 0x73, 0x2a, 0x8c, 0x07, 0x2c, 0xb3, - 0xfc, 0x5d, 0x1a, 0x69, 0x88, 0x31, 0xe5, 0xe6, 0x15, 0x87, 0x16, 0x4b, - 0xb9, 0x76, 0x6e, 0x23, 0x25, 0x7e, 0x6d, 0x1c, 0x9b, 0xc5, 0xa8, 0x61, - 0x0b, 0x64, 0x43, 0x41, 0xfd, 0xae, 0x3b, 0x8d, 0x9a, 0xaa, 0xc7, 0x2d, - 0x30, 0xfa, 0x93, 0xdb, 0x9f, 0x89, 0x8e, 0x4a, 0x77, 0x2b, 0x3f, 0x53, - 0x82, 0xf0, 0x64, 0xc4, 0x8e, 0x76, 0xd6, 0xbe, 0xe2, 0x28, 0x99, 0x5a, - 0xfb, 0x21, 0x21, 0x32, 0x3d, 0x61, 0xa2, 0xb9, 0xe3, 0xc4, 0x6b, 0xaa, - 0x52, 0x97, 0x69, 0x6e, 0x66, 0x1b, 0x0f, 0xad, 0xbc, 0xa7, 0x69, 0xd2, - 0xa0, 0x11, 0xb4, 0x0f, 0x96, 0xd2, 0x9e, 0x3a, 0xd9, 0x19, 0xad, 0x9b, - 0x00, 0x6c, 0x2e, 0xf1, 0xbc, 0xf8, 0x5e, 0x34, 0x94, 0x6a, 0x78, 0x36, - 0xa3, 0x82, 0x04, 0x9b, 0x40, 0x07, 0xa8, 0x32, 0x7d, 0x1b, 0x18, 0x07, - 0x3a, 0x12, 0x83, 0xf9, 0x2f, 0x62, 0xcf, 0x6a, 0x5d, 0x77, 0x12, 0x27, - 0xa7, 0xe3, 0xad, 0x1d, 0x58, 0x53, 0x3e, 0x39, 0xf6, 0x81, 0xc9, 0x44, - 0x81, 0x0a, 0x8b, 0xd2, 0x0b, 0xcb, 0xd1, 0x96, 0x95, 0x85, 0x82, 0x68, - 0x5e, 0x3f, 0x84, 0xce, 0x95, 0xe6, 0xe6, 0xf0, 0xbb, 0x45, 0xbb, 0xd3, - 0x9b, 0xad, 0xb4, 0x33, 0xfa, 0xc2, 0x98, 0x81, 0x5d, 0xe8, 0xf3, 0xa0, - 0x0d, 0x45, 0x6f, 0xd1, 0xc2, 0x43, 0x28, 0x3f, 0xf6, 0xbd, 0x05, 0x68, - 0xd3, 0x3e, 0x1b, 0xba, 0x6f, 0xd9, 0xe4, 0x2b, 0xb1, 0xe8, 0xaf, 0xe6, - 0xdd, 0xc7, 0x19, 0x03, 0x66, 0xf6, 0x8f, 0xbf, 0x7e, 0xba, 0x25, 0xcc, - 0x63, 0x85, 0xc8, 0xfa, 0x1c, 0xda, 0xcf, 0x81, 0x68, 0xe0, 0x9a, 0x38, - 0x86, 0x2f, 0xf0, 0x0d, 0x68, 0x8d, 0x1c, 0x9f, 0x8d, 0x19, 0x8c, 0x90, - 0xd9, 0x71, 0x12, 0xd4, 0xdc, 0x1f, 0x70, 0x48, 0x5f, 0x0d, 0x93, 0x8f, - 0xb4, 0x86, 0x69, 0xc4, 0x6b, 0xa3, 0x06, 0x6c, 0x9a, 0x2b, 0x25, 0xc5, - 0x89, 0xa6, 0x1a, 0x42, 0x0c, 0xf6, 0x72, 0x2f, 0xaa, 0xd0, 0x93, 0x8d, - 0xf8, 0x2a, 0x97, 0x7a, 0xf2, 0x3d, 0x13, 0x80, 0xa5, 0xd7, 0xa4, 0x8f, - 0x5a, 0x4b, 0x52, 0xeb, 0xf5, 0x3a, 0x34, 0x93, 0x3d, 0xb3, 0xab, 0x64, - 0x34, 0x1f, 0x82, 0xfb, 0x12, 0x01, 0x5c, 0x37, 0x3a, 0x06, 0x93, 0x76, - 0x40, 0xe0, 0x29, 0x5c, 0x35, 0xe1, 0x8a, 0x8b, 0x3d, 0xa4, 0xe0, 0x38, - 0x24, 0x29, 0x59, 0xdd, 0x98, 0x84, 0x29, 0x84, 0xfd, 0x2c, 0x8e, 0xdb, - 0x3e, 0xc9, 0xa4, 0x6b, 0x61, 0x5b, 0xf5, 0x32, 0xb9, 0x91, 0x30, 0x62, - 0xe1, 0x1d, 0x55, 0x11, 0xc3, 0xe7, 0xf7, 0x9a, 0x3e, 0xa6, 0x39, 0x18, - 0xba, 0xf6, 0x6f, 0xa5, 0x3b, 0x86, 0x1a, 0x96, 0x41, 0x84, 0x1a, 0x20, - 0x09, 0x8f, 0xcf, 0x04, 0x64, 0xc4, 0x6d, 0x3b, 0x89, 0x39, 0x4e, 0x1f, - 0x7f, 0x25, 0xbd, 0x9b, 0xad, 0xf7, 0x40, 0xa7, 0x8e, 0xd1, 0xfb, 0xb6, - 0x5d, 0xd5, 0x94, 0x1f, 0xaa, 0xd7, 0x5c, 0xb8, 0x0d, 0x7e, 0xfc, 0x63, - 0x6a, 0x3d, 0xdb, 0xed, 0xa8, 0xf7, 0x95, 0x7e, 0x11, 0xf2, 0xb1, 0x64, - 0x5c, 0xae, 0x7c, 0x28, 0x29, 0xdf, 0x79, 0x1e, 0x2c, 0x38, 0x10, 0xc7, - 0xc0, 0x4e, 0xd6, 0x10, 0xa2, 0x26, 0x79, 0x8a, 0xae, 0x77, 0xa7, 0x3f, - 0xb1, 0xcd, 0xb5, 0x58, 0xf9, 0x13, 0xec, 0xbb, 0x24, 0x20, 0x0b, 0xe6, - 0x22, 0xf2, 0x00, 0x2c, 0xb2, 0x0d, 0xff, 0x1e, 0x2b, 0xaa, 0xd0, 0x98, - 0x4d, 0x84, 0x33, 0xdb, 0x57, 0x6f, 0x2e, 0x1b, 0x2a, 0x69, 0x6a, 0xbb, - 0xa1, 0xd2, 0x22, 0x95, 0x2c, 0xaf, 0xfe, 0xd8, 0xa3, 0xdb, 0x12, 0xae, - 0xc9, 0x6f, 0x96, 0x07, 0x96, 0x57, 0x6f, 0xa0, 0x87, 0x7b, 0xf3, 0xd8, - 0xea, 0xeb, 0xf1, 0xa6, 0xbb, 0x1f, 0x8e, 0x19, 0x18, 0xa6, 0xdf, 0xb4, - 0x23, 0x3e, 0x29, 0x58, 0xaa, 0x0f, 0xbb, 0xac, 0x55, 0x2b, 0x43, 0x8c, - 0x23, 0x1c, 0x85, 0x0b, 0x47, 0xd0, 0xa8, 0x6f, 0x44, 0xc3, 0xc1, 0x5c, - 0xf3, 0xeb, 0xc1, 0x1a, 0x53, 0xb5, 0x33, 0x76, 0x1c, 0x8f, 0x4d, 0x73, - 0xbc, 0x45, 0x4c, 0xa1, 0x14, 0xd2, 0xa5, 0x19, 0x84, 0xfc, 0x47, 0xa2, - 0x7b, 0x7f, 0x4f, 0xc4, 0x1a, 0x14, 0x45, 0x90, 0x44, 0xbc, 0x2b, 0x3f, - 0x41, 0xec, 0xae, 0x64, 0xd2, 0x97, 0x6c, 0xf9, 0x23, 0xbc, 0x46, 0xbe, - 0x6a, 0x33, 0x2f, 0xc9, 0x5c, 0xf3, 0x1b, 0x4c, 0x2e, 0x84, 0x08, 0x98, - 0x47, 0xfa, 0x18, 0xa3, 0x9e, 0x06, 0x27, 0x29, 0x90, 0x76, 0x72, 0xa5, - 0xec, 0x04, 0xe2, 0x03, 0x73, 0x3c, 0x51, 0x63, 0x23, 0xe6, 0x7a, 0x1e, - 0x70, 0xc9, 0x90, 0x97, 0xfd, 0x08, 0xf4, 0x02, 0xb7, 0x48, 0x8a, 0x17, - 0xb5, 0xc4, 0x7d, 0x8c, 0x26, 0xa5, 0x38, 0x86, 0xc7, 0x90, 0xb4, 0x1b, - 0xb3, 0x58, 0x4f, 0x9b, 0x5a, 0x8e, 0x73, 0x8d, 0x69, 0xef, 0xde, 0x11, - 0xfc, 0x89, 0x02, 0x56, 0xa2, 0x01, 0xe4, 0xdd, 0x3d, 0x18, 0xf4, 0x8b, - 0x3a, 0x85, 0x0c, 0xa0, 0xd7, 0xf6, 0xa6, 0x40, 0x30, 0xf3, 0xd9, 0x6f, - 0xca, 0x25, 0x51, 0x54, 0x13, 0x3a, 0x45, 0x51, 0xe9, 0x72, 0x6a, 0x2e, - 0x2f, 0xd8, 0x2c, 0x58, 0x5a, 0x5e, 0x7d, 0xf2, 0xeb, 0x19, 0x7e, 0x8c, - 0xf7, 0xcd, 0x57, 0xc9, 0x90, 0xc3, 0x8f, 0xac, 0xc1, 0x7d, 0x7a, 0x3d, - 0xad, 0x0b, 0x14, 0x17, 0xe6, 0x89, 0x8d, 0x63, 0x23, 0x60, 0xe4, 0x6f, - 0x40, 0x61, 0x57, 0xf2, 0x74, 0x47, 0x05, 0x18, 0xca, 0x30, 0xd8, 0xe8, - 0xf2, 0x1b, 0x18, 0x94, 0xe4, 0xa6, 0xc8, 0xb8, 0x76, 0xe8, 0xb0, 0x71, - 0x44, 0xe6, 0x86, 0x44, 0xdd, 0xbd, 0x39, 0x81, 0x4d, 0xb8, 0x7b, 0xb7, - 0x3e, 0x72, 0x27, 0xa8, 0xa3, 0x52, 0x44, 0x13, 0xc8, 0xb7, 0x82, 0xb4, - 0xf9, 0x4e, 0x64, 0xe7, 0xe2, 0x7e, 0x16, 0xf7, 0xef, 0x63, 0xad, 0xa0, - 0x72, 0x2d, 0xf0, 0xce, 0xc2, 0x4f, 0x45, 0xb8, 0x03, 0x72, 0xa9, 0x9f, - 0xec, 0x16, 0xc8, 0x73, 0xfb, 0x75, 0xc4, 0x2b, 0xde, 0xc3, 0x0d, 0xec, - 0xa1, 0xf4, 0xfc, 0xc8, 0xa5, 0x2c, 0x26, 0x82, 0xfe, 0x6c, 0x04, 0x49, - 0x2e, 0xde, 0xe4, 0x96, 0xb7, 0x5f, 0x64, 0x58, 0xc9, 0x0b, 0x4f, 0xb0, - 0xfd, 0xde, 0x81, 0xc9, 0xeb, 0x01, 0xb5, 0xe5, 0x8d, 0xec, 0x4b, 0xcf, - 0xae, 0x32, 0x0d, 0x71, 0x8b, 0x1b, 0x98, 0x81, 0xe6, 0xf8, 0xa4, 0x42, - 0x41, 0x9d, 0x83, 0x9f, 0x9c, 0x99, 0xf8, 0x66, 0xf2, 0x03, 0x0e, 0xdb, - 0x63, 0xcd, 0x85, 0x85, 0x05, 0x3f, 0xa6, 0x44, 0x31, 0xcb, 0x42, 0x6d, - 0x68, 0xcc, 0x1b, 0x7f, 0x63, 0xe4, 0xdd, 0x62, 0xff, 0x8e, 0x64, 0x27, - 0x86, 0xf9, 0x4b, 0x11, 0x01, 0x26, 0x7e, 0x4c, 0x34, 0xae, 0xd7, 0x8c, - 0x84, 0xc6, 0x6c, 0xcb, 0xda, 0x85, 0x4b, 0xba, 0x2d, 0xb0, 0x6d, 0x58, - 0x4d, 0x1e, 0x92, 0x3c, 0xaf, 0x42, 0xf9, 0x62, 0xdd, 0xf0, 0x8e, 0x28, - 0xa5, 0x6b, 0xa9, 0xa8, 0x5a, 0xc7, 0xfc, 0x96, 0x14, 0xe6, 0x86, 0xc4, - 0xeb, 0x9b, 0xdb, 0x67, 0xb2, 0x1b, 0x99, 0x4e, 0x41, 0x62, 0x21, 0x66, - 0x6a, 0x19, 0xcc, 0x3c, 0x5d, 0x0e, 0x6d, 0x8e, 0xef, 0xdc, 0x4d, 0x2a, - 0x9e, 0x91, 0xea, 0x2c, 0x74, 0x9c, 0xb9, 0x15, 0x12, 0x7c, 0x97, 0xc6, - 0xe9, 0xdb, 0x47, 0xd2, 0xa1, 0xaa, 0xba, 0xa9, 0xa5, 0x67, 0xf6, 0x5c, - 0x62, 0x5f, 0xc0, 0xc9, 0x1b, 0xb2, 0x67, 0xfd, 0x14, 0xde, 0x4f, 0xaf, - 0x24, 0x9a, 0xd6, 0x04, 0x1b, 0x5d, 0xe1, 0x8e, 0xcb, 0xb9, 0x0c, 0x8c, - 0x7e, 0xfc, 0x8c, 0x87, 0x18, 0xbe, 0xf1, 0x67, 0x5e, 0x46, 0x6a, 0x46, - 0x86, 0x77, 0xf3, 0x3b, 0xe8, 0xbb, 0x72, 0x8b, 0xab, 0xab, 0xac, 0x62, - 0xa6, 0x3a, 0x3a, 0x1d, 0x56, 0xd0, 0x92, 0x39, 0xa7, 0x99, 0xfe, 0x51, - 0x74, 0xde, 0x08, 0x8e, 0x02, 0x41, 0x14, 0x3d, 0x10, 0x01, 0x46, 0xd8, - 0x10, 0xef, 0xbd, 0x27, 0x43, 0x80, 0xf0, 0xde, 0x73, 0xfa, 0x61, 0x82, - 0x0d, 0x66, 0x8d, 0x46, 0xea, 0xae, 0xaa, 0xff, 0x9e, 0x56, 0xd3, 0x4d, - 0xb6, 0x80, 0x4a, 0x61, 0xf5, 0x4a, 0x54, 0x76, 0x18, 0x2c, 0xbb, 0x3b, - 0x13, 0x97, 0x94, 0xbc, 0x82, 0x30, 0xe9, 0x46, 0xe6, 0xe9, 0x8e, 0x92, - 0x7e, 0xeb, 0x7b, 0x64, 0x81, 0x8e, 0xb3, 0xf2, 0xe4, 0xfb, 0x4d, 0xef, - 0xc4, 0x9d, 0x36, 0x0d, 0xdb, 0x98, 0x99, 0xe7, 0x38, 0x39, 0x69, 0x3c, - 0xf5, 0x37, 0x47, 0x3e, 0x11, 0x49, 0x76, 0x86, 0x03, 0x84, 0x41, 0x8d, - 0x89, 0xa3, 0x96, 0xe8, 0xb3, 0x7b, 0xe5, 0xf7, 0x8c, 0xa7, 0xc9, 0xcd, - 0x89, 0xc7, 0x36, 0xa6, 0xf9, 0xb3, 0x51, 0xf7, 0x71, 0x92, 0xe0, 0x9a, - 0xc0, 0x8e, 0x0c, 0x55, 0x80, 0x2f, 0x90, 0x1f, 0x4e, 0xf5, 0xe8, 0x0f, - 0xa7, 0xc1, 0x4e, 0x6a, 0x7a, 0x07, 0x73, 0x86, 0x1c, 0x2c, 0x2f, 0xca, - 0x9e, 0x33, 0xa7, 0x57, 0xcd, 0x65, 0x05, 0x6c, 0x45, 0xf6, 0xfd, 0xbf, - 0x76, 0x31, 0x89, 0xc9, 0xa9, 0x19, 0xf6, 0xfe, 0xf1, 0x63, 0x6b, 0x32, - 0x50, 0xd1, 0xf9, 0xde, 0xd9, 0xdd, 0x84, 0xec, 0x76, 0x68, 0x49, 0xb8, - 0x7c, 0x80, 0x08, 0x8a, 0x41, 0x64, 0xad, 0x01, 0x5a, 0x28, 0x0b, 0x22, - 0x4f, 0x04, 0xfd, 0xcd, 0xf2, 0xdd, 0xc6, 0xcc, 0x06, 0xb7, 0x17, 0x2d, - 0x99, 0xa3, 0x95, 0xb9, 0x49, 0xcc, 0x79, 0x6a, 0x73, 0xaf, 0x15, 0x62, - 0xd0, 0x79, 0x08, 0xd8, 0xe8, 0x87, 0x12, 0x4e, 0x3a, 0x30, 0xf9, 0x41, - 0x61, 0x69, 0x2c, 0xeb, 0x1f, 0xef, 0xf3, 0x8e, 0xae, 0x4f, 0x31, 0x1f, - 0x8e, 0x2b, 0xd0, 0xba, 0xb3, 0x6d, 0x0a, 0x67, 0x05, 0x14, 0xf8, 0x72, - 0x79, 0x1b, 0x02, 0xd8, 0x15, 0x7c, 0x11, 0x27, 0x2a, 0xfa, 0x46, 0x9a, - 0x31, 0xf7, 0xb8, 0xd0, 0x70, 0xd6, 0xc1, 0xd4, 0xca, 0xfc, 0xb9, 0x9f, - 0x95, 0xbc, 0x01, 0xe6, 0x8a, 0x86, 0x25, 0x83, 0xdb, 0xb3, 0xb3, 0x6b, - 0xce, 0x38, 0x1b, 0x4c, 0x82, 0xef, 0xc8, 0x4b, 0x8d, 0x60, 0x60, 0x14, - 0xf9, 0x1b, 0xe7, 0x74, 0xcb, 0x16, 0xdd, 0xf6, 0x82, 0x22, 0x91, 0x12, - 0xea, 0xd5, 0xa7, 0x71, 0xbb, 0xfe, 0xed, 0x68, 0x65, 0xe9, 0x4c, 0xd1, - 0x95, 0x48, 0x23, 0xdf, 0x60, 0x1c, 0x0f, 0x12, 0x58, 0x80, 0xea, 0x69, - 0xa3, 0x1f, 0x52, 0xfd, 0x80, 0x14, 0xcb, 0x44, 0x5a, 0xbd, 0x50, 0x02, - 0xc1, 0x3d, 0x03, 0xf1, 0xba, 0x0b, 0x06, 0x3c, 0xca, 0xff, 0x89, 0xae, - 0xfc, 0x83, 0xe6, 0x20, 0xdf, 0x54, 0x49, 0xe1, 0xde, 0x9d, 0x0c, 0x0c, - 0xa6, 0x4e, 0xa2, 0x98, 0x3e, 0xf1, 0xe0, 0x17, 0x5c, 0x2c, 0x00, 0xc9, - 0x6b, 0x46, 0x7c, 0x9c, 0xd2, 0x11, 0x89, 0x3e, 0xd7, 0xd0, 0xe4, 0x9b, - 0xb6, 0x59, 0xf8, 0x01, 0x2c, 0x38, 0x0c, 0x53, 0x7c, 0x15, 0xf2, 0x2d, - 0x74, 0xc3, 0x1d, 0x18, 0x60, 0xf1, 0x8b, 0x18, 0xa3, 0x84, 0x7d, 0x17, - 0x3c, 0xd0, 0x51, 0x67, 0x3e, 0x49, 0xe0, 0x66, 0x01, 0xf6, 0xd6, 0xee, - 0x7e, 0x54, 0xe4, 0x32, 0x2a, 0xc6, 0x00, 0x21, 0x7f, 0xe2, 0xf3, 0x04, - 0xcb, 0x85, 0xfb, 0xe3, 0x02, 0xdf, 0x97, 0x85, 0x6f, 0x2f, 0x9e, 0xd2, - 0xf0, 0x52, 0x77, 0x80, 0xd3, 0xe4, 0x83, 0x9b, 0x07, 0x3c, 0x8b, 0xe4, - 0x11, 0x96, 0xa7, 0x45, 0xc2, 0x86, 0xc5, 0x72, 0xf4, 0x62, 0xa2, 0x31, - 0xa0, 0x1a, 0xb2, 0xf3, 0x28, 0x75, 0x00, 0x79, 0x00, 0xa9, 0xfa, 0x54, - 0x6a, 0xbf, 0x04, 0x6e, 0x4c, 0xd2, 0x42, 0xa3, 0xbd, 0x8f, 0x53, 0xfe, - 0xba, 0x90, 0x5e, 0x0e, 0x0d, 0xda, 0x09, 0x17, 0x57, 0x7e, 0x6b, 0xed, - 0x17, 0x69, 0xe3, 0x2f, 0x12, 0x2c, 0xb3, 0xb6, 0x38, 0x66, 0x40, 0xb3, - 0xd8, 0x5f, 0x36, 0x31, 0xc9, 0x2f, 0x87, 0xa5, 0xfe, 0x5b, 0x3a, 0xe5, - 0xf9, 0x63, 0x1e, 0x39, 0xcd, 0x1a, 0xb4, 0x7e, 0x9b, 0xeb, 0x95, 0x49, - 0xe0, 0xaa, 0x6e, 0x5e, 0x74, 0xdc, 0x6b, 0x4c, 0xcc, 0xda, 0x5c, 0x68, - 0x43, 0xdf, 0x7a, 0x79, 0x74, 0xe8, 0x80, 0xc1, 0x8d, 0xb2, 0xd3, 0xc9, - 0xea, 0x2b, 0x3b, 0x75, 0x72, 0x88, 0x89, 0xa5, 0xf2, 0xd3, 0x59, 0xa3, - 0xe6, 0xb6, 0x10, 0xfc, 0x2f, 0xff, 0xbd, 0xd8, 0x33, 0x36, 0x13, 0x7d, - 0x88, 0xbc, 0xc2, 0xbe, 0x2c, 0xc2, 0x1d, 0x31, 0x42, 0xb3, 0xc0, 0x54, - 0x3f, 0x10, 0x32, 0x4e, 0x1b, 0xd0, 0x73, 0x75, 0x00, 0x56, 0xa9, 0x06, - 0x23, 0xfa, 0xbb, 0xf1, 0x14, 0xc4, 0x3a, 0xb0, 0x4d, 0xe1, 0x37, 0xa1, - 0xf5, 0x0b, 0x1a, 0x8a, 0x4e, 0xae, 0xca, 0x3b, 0x98, 0x97, 0x2c, 0xc5, - 0x80, 0x3d, 0x74, 0xb7, 0x13, 0xda, 0x80, 0x4b, 0x11, 0xac, 0x27, 0xe1, - 0xa8, 0x78, 0x2a, 0xd7, 0x13, 0x91, 0x9f, 0xe5, 0xbd, 0x24, 0xb1, 0xf4, - 0x75, 0xf2, 0x94, 0x5b, 0x20, 0x44, 0xc8, 0x31, 0x26, 0xf1, 0x39, 0x58, - 0xcf, 0xd0, 0x54, 0x63, 0x17, 0xb3, 0xed, 0xc7, 0x9d, 0x90, 0x26, 0x3f, - 0x0c, 0x38, 0x2b, 0x8b, 0x0d, 0x2b, 0xad, 0x9f, 0x73, 0xeb, 0xe0, 0xcd, - 0xac, 0xb0, 0x9a, 0xb9, 0xdf, 0x29, 0x15, 0x1f, 0xba, 0x39, 0x5e, 0x4e, - 0x0f, 0x99, 0x27, 0xef, 0x5f, 0xf9, 0xe9, 0x90, 0x2c, 0x9a, 0x81, 0x1d, - 0xbb, 0x88, 0xbe, 0x46, 0xd7, 0xdf, 0xaf, 0x8c, 0x1c, 0x36, 0x87, 0x2a, - 0x0d, 0x57, 0xcb, 0x55, 0xcb, 0x68, 0x57, 0xc9, 0x50, 0x39, 0x2b, 0x1f, - 0xbf, 0xf9, 0x03, 0xbc, 0xc8, 0x08, 0xf5, 0x8f, 0xc1, 0x98, 0x53, 0xea, - 0xae, 0xdf, 0x39, 0x48, 0x53, 0x32, 0x9c, 0x02, 0xff, 0x37, 0x31, 0xd3, - 0x1b, 0xc7, 0x7e, 0x92, 0xf6, 0x60, 0x23, 0x30, 0x48, 0xc6, 0x9d, 0xd7, - 0x88, 0x7c, 0xea, 0xe8, 0x7d, 0xd8, 0x11, 0x8d, 0x82, 0x56, 0xb4, 0xca, - 0xf2, 0xf8, 0x99, 0xe1, 0x07, 0x4d, 0x7e, 0x06, 0x14, 0x7f, 0x39, 0xbd, - 0x15, 0x3e, 0x75, 0x45, 0xf9, 0xf9, 0x49, 0x2a, 0x00, 0x7c, 0xe8, 0x06, - 0xb5, 0x62, 0x45, 0x60, 0x56, 0x53, 0x8f, 0x57, 0x3b, 0xb1, 0x0b, 0x0b, - 0xeb, 0xb4, 0x73, 0x0c, 0x68, 0x55, 0xcf, 0xe9, 0x6a, 0x16, 0x40, 0xbc, - 0x0d, 0x5f, 0x09, 0x03, 0xa3, 0x90, 0x1a, 0x7e, 0x3e, 0x4b, 0x5d, 0x1c, - 0xad, 0xe9, 0x69, 0x4d, 0x3f, 0xbf, 0x30, 0xbf, 0x0d, 0x3e, 0x0b, 0xf1, - 0x4a, 0xbf, 0x58, 0x3e, 0x58, 0x1d, 0x84, 0xfe, 0x58, 0x3f, 0x6a, 0x42, - 0xf0, 0x93, 0x48, 0xc3, 0xc4, 0x81, 0xd8, 0x85, 0xd2, 0x64, 0x57, 0xbf, - 0xa5, 0xb2, 0x16, 0xfa, 0x09, 0xac, 0x31, 0x65, 0xf0, 0xe2, 0x4b, 0x24, - 0x34, 0x40, 0x0e, 0x68, 0x4d, 0xb8, 0x9d, 0x53, 0x0d, 0x5d, 0xcb, 0x90, - 0xd6, 0x38, 0xd3, 0x71, 0x52, 0x49, 0xfa, 0x52, 0x2b, 0x33, 0x3b, 0xb9, - 0xf2, 0x9e, 0xf8, 0x3f, 0x3b, 0x9f, 0xea, 0x7f, 0x7b, 0x8b, 0x8d, 0xa5, - 0x63, 0xb0, 0xa8, 0x9d, 0xf6, 0x71, 0xbd, 0x6d, 0xf5, 0xe7, 0xb1, 0x3d, - 0x57, 0x96, 0x95, 0xac, 0x66, 0xec, 0x7a, 0x4d, 0x32, 0xbd, 0x30, 0x7f, - 0x6c, 0xdb, 0xe6, 0x4d, 0xce, 0x6e, 0xa5, 0x1d, 0x13, 0x68, 0xac, 0x7f, - 0x26, 0x8e, 0xc6, 0x00, 0x67, 0xc5, 0xe4, 0x15, 0xfb, 0xbf, 0xc3, 0x59, - 0xdf, 0xd8, 0x47, 0x3d, 0xa8, 0x1f, 0x10, 0x33, 0xd1, 0x9c, 0xca, 0xbf, - 0x9a, 0x7d, 0x37, 0x48, 0xfb, 0xbe, 0x24, 0x7d, 0x47, 0xcc, 0xe1, 0xdb, - 0xb1, 0x3a, 0x8e, 0xc1, 0x71, 0x3b, 0x97, 0xc8, 0xe5, 0xa0, 0x20, 0x02, - 0x9d, 0x45, 0x15, 0xd6, 0x70, 0x96, 0x9f, 0xc9, 0xf8, 0x04, 0x00, 0xf8, - 0x49, 0x06, 0x07, 0x90, 0x3e, 0x97, 0x8d, 0x56, 0x2d, 0x4e, 0x4b, 0xd1, - 0xa0, 0x27, 0x8c, 0x38, 0x2b, 0x54, 0xa1, 0x56, 0x6c, 0xb8, 0x5c, 0x9c, - 0x08, 0x9c, 0x8e, 0xb7, 0x16, 0x76, 0x1b, 0x92, 0xb5, 0xac, 0x1d, 0xca, - 0x61, 0xb1, 0x2f, 0x90, 0x23, 0xfc, 0xd5, 0x18, 0xc4, 0x8f, 0xcd, 0x98, - 0x99, 0xa6, 0x3e, 0x22, 0xb1, 0xee, 0x76, 0x7e, 0x42, 0xf8, 0xa5, 0xa9, - 0x78, 0x63, 0x02, 0x98, 0x8a, 0xc2, 0x3e, 0xf6, 0x13, 0x9b, 0x07, 0xdc, - 0x3f, 0xc5, 0x67, 0xde, 0x2a, 0xfa, 0xa3, 0x63, 0x1c, 0xf7, 0x28, 0x16, - 0x28, 0xe1, 0x2a, 0xfc, 0xfd, 0xe4, 0x70, 0xff, 0xb1, 0x1a, 0x90, 0x5a, - 0x19, 0xa5, 0x44, 0x3d, 0xe1, 0x3b, 0xf2, 0xed, 0xe9, 0xa3, 0x67, 0x19, - 0xab, 0xd9, 0xff, 0x51, 0x51, 0xab, 0x51, 0xe5, 0xbc, 0x2e, 0x59, 0x37, - 0x33, 0x57, 0xa4, 0xf5, 0xd8, 0x17, 0x40, 0xa8, 0x0a, 0x4d, 0x90, 0x91, - 0x0c, 0xca, 0xf5, 0x37, 0xf7, 0xe6, 0x26, 0x8f, 0xe7, 0xb8, 0xcb, 0x50, - 0x03, 0x4f, 0x64, 0x52, 0x1b, 0x35, 0x89, 0xc9, 0xa7, 0xc3, 0x22, 0x3f, - 0x7d, 0x9e, 0xab, 0xdf, 0xe4, 0xd0, 0x7e, 0x05, 0x62, 0x90, 0xc7, 0x67, - 0x11, 0xdf, 0x01, 0x0c, 0x64, 0xb5, 0x8e, 0xd4, 0x30, 0x94, 0xd2, 0x3c, - 0x19, 0x13, 0xfb, 0x9c, 0xa3, 0x93, 0x8b, 0x3b, 0xc4, 0x75, 0xff, 0xcc, - 0x42, 0x43, 0xfd, 0xda, 0xaa, 0x41, 0xd6, 0xd5, 0xe1, 0xfe, 0x42, 0x26, - 0xb4, 0x12, 0xdd, 0x33, 0x68, 0xc3, 0x70, 0xd6, 0x90, 0x44, 0x83, 0xce, - 0x29, 0x29, 0xec, 0x1b, 0x95, 0x65, 0x91, 0x92, 0x64, 0xea, 0x73, 0x94, - 0xc8, 0x44, 0x00, 0xbf, 0x6c, 0x6c, 0xec, 0xd8, 0x9c, 0xfa, 0x26, 0x9a, - 0x1d, 0x5d, 0xb6, 0x36, 0x72, 0x17, 0x37, 0x3b, 0x61, 0x83, 0x84, 0x07, - 0xeb, 0x3a, 0x0e, 0x08, 0x3c, 0x35, 0x50, 0x42, 0x20, 0x6a, 0xd2, 0x6e, - 0xc5, 0xcf, 0x4b, 0x1b, 0xbb, 0xe5, 0xae, 0xe9, 0x8d, 0xbc, 0x78, 0x6b, - 0xf4, 0x83, 0xb3, 0x10, 0x4f, 0x7a, 0x9e, 0x13, 0x1b, 0x56, 0xf5, 0xa7, - 0xc2, 0xfb, 0xb3, 0x03, 0x17, 0x0e, 0x24, 0x33, 0x4f, 0x52, 0x07, 0xe0, - 0x34, 0x19, 0xfa, 0xc0, 0xd4, 0x1c, 0xfc, 0x01, 0x07, 0x07, 0xf4, 0xf5, - 0x6d, 0x6d, 0xe6, 0xd7, 0xa4, 0x1e, 0x78, 0xd1, 0x36, 0xce, 0x53, 0x2b, - 0x2e, 0x32, 0xea, 0xb2, 0xb0, 0x84, 0x3b, 0x06, 0xea, 0x34, 0x01, 0x83, - 0x80, 0xd7, 0xf7, 0x12, 0xa3, 0x9a, 0x18, 0x02, 0x9a, 0x9a, 0x0d, 0x60, - 0xcf, 0xff, 0xe8, 0xee, 0xdb, 0x6b, 0xdf, 0x41, 0x51, 0x1c, 0xa1, 0x1d, - 0xa0, 0x35, 0xb4, 0x20, 0xec, 0x60, 0xc9, 0xb8, 0xd8, 0x36, 0xf4, 0xc1, - 0xef, 0xc2, 0x7c, 0xbd, 0xa0, 0xf1, 0x5b, 0x4e, 0x05, 0xd3, 0x07, 0xc1, - 0xbd, 0xae, 0x9f, 0xca, 0x87, 0x88, 0xd5, 0x4d, 0x31, 0xbe, 0x0a, 0x3e, - 0x82, 0x28, 0x77, 0x92, 0xcd, 0x8f, 0x5f, 0x6d, 0x68, 0x87, 0xa9, 0xeb, - 0x2d, 0x9d, 0x00, 0x4c, 0xfb, 0x42, 0x09, 0xa6, 0xee, 0xee, 0xcc, 0xf1, - 0x38, 0x19, 0x19, 0xbf, 0xd5, 0x8b, 0x35, 0xf6, 0xae, 0x8f, 0xcd, 0xf8, - 0xb2, 0x9b, 0x7d, 0x44, 0x9d, 0x9d, 0xac, 0xa6, 0xd5, 0xd6, 0xdc, 0xfa, - 0xe9, 0x83, 0x2a, 0x10, 0x4f, 0x41, 0x7d, 0x04, 0x14, 0xa0, 0x48, 0xdb, - 0x7b, 0xe6, 0xfb, 0x83, 0x8e, 0x5d, 0xc5, 0xcf, 0x36, 0xc4, 0x96, 0x6f, - 0x22, 0xdc, 0xdf, 0xdf, 0xfa, 0x60, 0x65, 0x35, 0xc3, 0x90, 0x0f, 0x1e, - 0x88, 0x8d, 0xa5, 0xa2, 0x44, 0xb7, 0x59, 0x7f, 0xcf, 0x7b, 0x20, 0x38, - 0x8c, 0xa5, 0xa6, 0xc4, 0x62, 0x26, 0x5e, 0xea, 0x94, 0x55, 0xde, 0x65, - 0x5c, 0x13, 0xdc, 0x72, 0xe4, 0x2a, 0xbc, 0x4d, 0x10, 0xd9, 0x47, 0xbd, - 0x80, 0xb3, 0x9d, 0x15, 0xba, 0x75, 0xae, 0x5f, 0xe3, 0xd5, 0xdc, 0x97, - 0xb1, 0x48, 0x54, 0x4c, 0xf0, 0xe2, 0x53, 0xfb, 0x78, 0x00, 0xb9, 0x83, - 0x72, 0xd2, 0xd4, 0x0d, 0x1c, 0x2d, 0x21, 0x2f, 0xbe, 0x69, 0x05, 0xd3, - 0xa6, 0x04, 0xe7, 0x55, 0x33, 0xb4, 0x65, 0xae, 0x01, 0x88, 0x7c, 0xef, - 0x4f, 0x3d, 0x37, 0xb1, 0xa9, 0x7b, 0xf4, 0xdb, 0x5c, 0x78, 0x12, 0x1e, - 0x59, 0xac, 0xd9, 0x13, 0xca, 0x07, 0xd4, 0xf7, 0x60, 0x6c, 0xef, 0xaa, - 0xf9, 0xc1, 0x09, 0xd7, 0x4b, 0x3c, 0x1b, 0x73, 0x6c, 0x2c, 0xf2, 0xf7, - 0x13, 0xbf, 0xc0, 0x78, 0x65, 0x83, 0xbe, 0xe9, 0x94, 0xc0, 0x4e, 0xe6, - 0x34, 0xa7, 0xc5, 0xf2, 0x1a, 0x2b, 0x36, 0x4d, 0xb4, 0x9f, 0xe1, 0x43, - 0xf2, 0x60, 0x64, 0xec, 0x8d, 0x14, 0x94, 0x05, 0x23, 0x24, 0x38, 0x08, - 0xb9, 0x75, 0xff, 0xe7, 0x65, 0x25, 0x8c, 0x24, 0x28, 0xb7, 0x8f, 0x81, - 0xf3, 0x36, 0x6f, 0x83, 0x35, 0x53, 0x75, 0x78, 0x4e, 0xe8, 0x53, 0xdf, - 0xf9, 0x21, 0xf6, 0x7c, 0x02, 0x29, 0x0b, 0x90, 0x1c, 0x61, 0xd9, 0xbf, - 0xfb, 0x45, 0x79, 0xd7, 0x4b, 0x07, 0x61, 0x8b, 0x61, 0xce, 0x7e, 0x5f, - 0x4d, 0xc9, 0x33, 0xd7, 0x24, 0x33, 0xdd, 0xc7, 0xb8, 0x9f, 0xb1, 0x87, - 0xb5, 0x4f, 0xb9, 0xb9, 0x4c, 0x45, 0x66, 0xbf, 0x08, 0xb7, 0x69, 0x47, - 0x34, 0x82, 0xfe, 0x31, 0xbf, 0x57, 0xdc, 0x8f, 0xf1, 0x4e, 0x71, 0x1c, - 0xc1, 0xf6, 0x0b, 0x4b, 0xce, 0xca, 0xd2, 0xe6, 0x64, 0x16, 0xdd, 0x04, - 0xc2, 0x04, 0xda, 0x1a, 0x7d, 0xf9, 0xa3, 0x21, 0x60, 0x8c, 0xd3, 0x83, - 0xfa, 0x6e, 0x9b, 0x9d, 0x2c, 0xf2, 0xf4, 0xb5, 0x1f, 0x88, 0x2b, 0x2e, - 0x03, 0x14, 0x7c, 0x69, 0xa8, 0xca, 0x21, 0x8a, 0x48, 0x32, 0xc0, 0x3e, - 0xdb, 0x03, 0xa7, 0x1a, 0x36, 0x63, 0xf7, 0xf6, 0x3b, 0x5e, 0xed, 0x2d, - 0xb6, 0x91, 0xf8, 0xc1, 0x97, 0x47, 0x88, 0xd0, 0xf3, 0x29, 0x5d, 0x60, - 0xb5, 0x46, 0x66, 0xe7, 0xe6, 0xe4, 0xad, 0xc2, 0x09, 0x30, 0xb2, 0xc7, - 0x9e, 0xc7, 0xec, 0x52, 0xf6, 0xbb, 0x86, 0x31, 0x42, 0x17, 0x12, 0x07, - 0x9e, 0xb0, 0x4c, 0x24, 0x8a, 0xe8, 0xe1, 0x22, 0x0f, 0xaa, 0xb4, 0x48, - 0xc5, 0x5f, 0xb1, 0xc4, 0x8c, 0xfe, 0xdb, 0x54, 0x6a, 0x32, 0xfc, 0x9f, - 0x7a, 0x8b, 0x54, 0xad, 0xfc, 0x8b, 0xeb, 0xd7, 0x62, 0x90, 0x55, 0xda, - 0xd6, 0xb4, 0xe8, 0xa4, 0x52, 0xa4, 0x3f, 0xab, 0x56, 0x38, 0x34, 0x12, - 0x6e, 0xd0, 0x3b, 0x16, 0xa0, 0x2c, 0x4b, 0x5d, 0xff, 0x4a, 0x51, 0x2c, - 0xee, 0xf0, 0x26, 0x86, 0xab, 0x71, 0x79, 0xa1, 0x76, 0x2a, 0xbb, 0x05, - 0xa9, 0x58, 0x4a, 0x54, 0xbe, 0x88, 0x4c, 0x28, 0xe4, 0x61, 0x9b, 0x1c, - 0xb4, 0x9f, 0x50, 0xdf, 0x33, 0xf2, 0x63, 0xd1, 0xee, 0x8a, 0x94, 0xb3, - 0x2b, 0xb3, 0x6f, 0x13, 0x8c, 0xd7, 0x81, 0xad, 0xde, 0x11, 0xc8, 0x4b, - 0x9f, 0x95, 0xe6, 0xb8, 0x1a, 0x07, 0x74, 0x27, 0xb0, 0xad, 0x3e, 0x8f, - 0x35, 0x47, 0xd8, 0x06, 0x08, 0xc7, 0xd2, 0xa5, 0x16, 0x57, 0x6d, 0xce, - 0xfa, 0x9c, 0x78, 0x6b, 0xf2, 0x2b, 0x1c, 0x13, 0xd6, 0x15, 0x16, 0x08, - 0x4a, 0x7c, 0xb7, 0xbe, 0x58, 0xb3, 0xe7, 0x13, 0x0f, 0xbf, 0x3d, 0xc9, - 0xdd, 0x3d, 0x28, 0x6e, 0x8a, 0x70, 0x73, 0xe8, 0xe3, 0x9a, 0x6a, 0x2e, - 0x77, 0x26, 0x55, 0x55, 0xc4, 0x11, 0xd1, 0x63, 0xd4, 0x69, 0x9e, 0xf3, - 0x8e, 0x3f, 0xf8, 0x35, 0xb1, 0xa5, 0xfb, 0x3f, 0x7e, 0x05, 0x99, 0x67, - 0x11, 0x32, 0x60, 0x48, 0x2a, 0xda, 0xec, 0x07, 0xf1, 0xaf, 0x8d, 0x0f, - 0x10, 0xba, 0xde, 0xb2, 0xd5, 0x5f, 0x40, 0x2b, 0xa2, 0x86, 0xa5, 0x65, - 0xc4, 0x2b, 0x08, 0x22, 0x54, 0x20, 0x96, 0x06, 0x85, 0xce, 0xf2, 0x71, - 0xc9, 0xc5, 0x36, 0x66, 0x18, 0x8d, 0x25, 0x3b, 0x62, 0x6e, 0xd7, 0x81, - 0x60, 0x75, 0x49, 0x1a, 0xa3, 0x11, 0xd9, 0x2c, 0xd2, 0xe3, 0xdb, 0xf3, - 0xd3, 0x31, 0x2d, 0x4c, 0x99, 0x83, 0x3f, 0xa9, 0xe3, 0x28, 0x93, 0x17, - 0xc4, 0xb5, 0x8b, 0xfc, 0x7e, 0x48, 0xae, 0x60, 0x75, 0xe3, 0xbf, 0x1b, - 0x32, 0xd6, 0x91, 0x8d, 0x09, 0x04, 0xf6, 0x18, 0xe2, 0xb2, 0x01, 0x68, - 0xb6, 0x47, 0xf6, 0x0b, 0xc0, 0xc8, 0xcf, 0x1a, 0xb0, 0x05, 0xe3, 0xa7, - 0xaf, 0x7e, 0x3e, 0x28, 0x38, 0x33, 0x25, 0x3e, 0xdb, 0xd9, 0x88, 0xce, - 0x77, 0x10, 0x2f, 0xf7, 0xe6, 0x44, 0xb3, 0xd6, 0x06, 0x53, 0x99, 0xa7, - 0xa5, 0x66, 0x17, 0x6d, 0x68, 0xdb, 0xdf, 0x67, 0x8c, 0xf9, 0xf4, 0x54, - 0x81, 0xc8, 0xdc, 0x55, 0x0c, 0xcf, 0xc6, 0x68, 0xba, 0x4a, 0xa9, 0x0f, - 0xad, 0x06, 0x45, 0x1d, 0xae, 0x01, 0xd6, 0xe6, 0x13, 0xc0, 0x8b, 0xf1, - 0x1b, 0x70, 0x05, 0x13, 0xf4, 0xaa, 0xcb, 0x5c, 0xcd, 0x82, 0x98, 0xde, - 0x1f, 0x6d, 0x31, 0x9b, 0x9e, 0x01, 0x5e, 0xca, 0xf3, 0xff, 0xa0, 0x34, - 0x11, 0xa5, 0x34, 0xfe, 0x91, 0xed, 0xd4, 0x0c, 0x62, 0x1f, 0xc6, 0x54, - 0x6d, 0x7a, 0xb7, 0x74, 0x5c, 0xd0, 0xeb, 0x82, 0x61, 0x1d, 0xcd, 0xef, - 0x8a, 0x85, 0x7b, 0x71, 0xdd, 0x66, 0x88, 0x5e, 0xf6, 0xba, 0xd6, 0x2c, - 0x8a, 0xab, 0xcf, 0x82, 0xca, 0xe2, 0x33, 0xfa, 0x7d, 0x2e, 0x79, 0xf2, - 0xbc, 0xad, 0x3c, 0xf3, 0x88, 0xe1, 0x7f, 0x52, 0xaf, 0xab, 0x28, 0x7e, - 0xca, 0xae, 0xf9, 0xb5, 0xe8, 0xab, 0xdd, 0x2d, 0x62, 0xfe, 0x31, 0x20, - 0x0f, 0x03, 0x1a, 0x14, 0x48, 0xc5, 0xb7, 0x3c, 0x1b, 0xe7, 0xfa, 0x7e, - 0x10, 0x75, 0x03, 0xfc, 0xeb, 0x06, 0x7a, 0xf6, 0xe3, 0xaf, 0x2d, 0xb2, - 0x2d, 0x1d, 0x1b, 0x4f, 0x37, 0xb3, 0x3c, 0x79, 0xce, 0x12, 0x97, 0xb1, - 0xe0, 0x26, 0xc1, 0x2d, 0x9f, 0x9b, 0xe5, 0x0e, 0x63, 0x8b, 0x5f, 0x40, - 0x58, 0x77, 0x42, 0x90, 0x22, 0x8b, 0x7b, 0xa6, 0x0e, 0x7c, 0xc4, 0x89, - 0x50, 0xc6, 0x69, 0xd0, 0xd7, 0xcf, 0x82, 0xdb, 0x68, 0xb2, 0xfb, 0xab, - 0xf9, 0x4d, 0x46, 0x77, 0x25, 0xaf, 0x52, 0x4b, 0x6b, 0x73, 0xfb, 0xf1, - 0x91, 0x77, 0x18, 0x4e, 0xbd, 0xa2, 0x28, 0x7d, 0xd8, 0xdb, 0xa6, 0x56, - 0x81, 0xf7, 0xf1, 0x11, 0x1f, 0x96, 0x1a, 0x9c, 0x3e, 0x35, 0x7c, 0xa6, - 0x27, 0x20, 0x1b, 0xbe, 0x10, 0x61, 0xbc, 0xca, 0xea, 0x6f, 0x59, 0x9b, - 0xf4, 0xe1, 0x0e, 0xa7, 0x3b, 0xaf, 0xd5, 0x78, 0x11, 0xff, 0x5f, 0x17, - 0x79, 0xdf, 0x4a, 0x0c, 0xce, 0x0a, 0x2a, 0xe6, 0x64, 0xb0, 0x40, 0x32, - 0xfb, 0x56, 0xcb, 0x60, 0x7c, 0xaf, 0x7d, 0xac, 0x0b, 0x17, 0x50, 0x5a, - 0x98, 0x46, 0xdc, 0x31, 0x75, 0x84, 0x8e, 0x04, 0xb4, 0x56, 0x42, 0x89, - 0x18, 0x4f, 0x0f, 0xe7, 0xa5, 0x65, 0xb9, 0x3e, 0x90, 0x66, 0x11, 0x5b, - 0x3e, 0x36, 0xcb, 0xda, 0x54, 0x4f, 0x8f, 0x8f, 0xeb, 0xdf, 0xe4, 0x50, - 0xe5, 0x24, 0x57, 0x61, 0x7e, 0x39, 0xf0, 0x88, 0x4d, 0xbe, 0x05, 0x10, - 0x8e, 0xfb, 0x76, 0x21, 0x21, 0x54, 0xd3, 0x19, 0x43, 0xdd, 0x14, 0xe7, - 0xa3, 0xf3, 0x52, 0x18, 0xe5, 0xef, 0x6a, 0xb6, 0x79, 0x0f, 0x0c, 0x05, - 0x5a, 0x84, 0x09, 0x0a, 0xaa, 0x02, 0x32, 0xd7, 0xb7, 0x13, 0x34, 0x04, - 0xce, 0x05, 0xcd, 0x24, 0x5e, 0xf1, 0x67, 0xd5, 0xf8, 0xec, 0xf1, 0xaa, - 0x11, 0x1d, 0x82, 0x26, 0xcc, 0xcb, 0x57, 0xbc, 0x74, 0x65, 0x1a, 0x6e, - 0x20, 0x54, 0xf1, 0xf5, 0xb0, 0xcb, 0x3a, 0xbb, 0x8f, 0xa3, 0xca, 0xe1, - 0xa1, 0x75, 0xf2, 0x98, 0xa8, 0x1e, 0x8d, 0x75, 0x09, 0x1e, 0xfa, 0x99, - 0xfa, 0xdd, 0xf4, 0xff, 0x01, 0x1b, 0xd9, 0xbd, 0x8c, 0xbc, 0x07, 0xe5, - 0x2e, 0xe7, 0x19, 0x8a, 0xd0, 0x98, 0x4d, 0x8b, 0x47, 0xff, 0xc7, 0x7b, - 0x6f, 0x8d, 0x9b, 0x43, 0x40, 0xc4, 0x79, 0x97, 0x14, 0x88, 0xa9, 0x76, - 0x80, 0x90, 0xaf, 0x24, 0x56, 0x00, 0x52, 0x2e, 0x09, 0x3c, 0xe0, 0xbd, - 0xaa, 0x73, 0xb6, 0xc9, 0xc2, 0x19, 0x15, 0x53, 0x54, 0x71, 0xc2, 0x42, - 0xb1, 0xb1, 0xf3, 0xaa, 0x87, 0x77, 0x3c, 0x7c, 0x3c, 0x96, 0x82, 0x6a, - 0x9f, 0x3c, 0x68, 0x34, 0xa4, 0xbd, 0x98, 0xaa, 0x3c, 0x45, 0xfe, 0xfe, - 0xd0, 0x78, 0x77, 0x48, 0xe5, 0x48, 0x12, 0x88, 0x6c, 0x12, 0x04, 0x92, - 0xd7, 0x6c, 0x4e, 0x94, 0xb4, 0x27, 0x23, 0x42, 0xc6, 0x35, 0xb4, 0xdf, - 0x5b, 0xbb, 0x69, 0x16, 0x05, 0x78, 0xc0, 0xaf, 0x3e, 0x32, 0xfe, 0xc6, - 0x74, 0xe3, 0xb4, 0x2a, 0xaa, 0x0e, 0x92, 0xb5, 0x01, 0xdd, 0x57, 0x72, - 0x8f, 0xd9, 0xab, 0x7b, 0x0e, 0xfb, 0xe4, 0x3c, 0x79, 0x2f, 0xc8, 0x24, - 0x5c, 0xb3, 0x9a, 0x65, 0x25, 0x9c, 0x19, 0x42, 0xb5, 0x57, 0x56, 0x78, - 0xa6, 0x9f, 0x4f, 0x71, 0x55, 0xcc, 0xc6, 0xf9, 0x46, 0xf3, 0xff, 0x66, - 0x97, 0xd5, 0xc9, 0x79, 0xea, 0x5a, 0xaa, 0xe9, 0xc7, 0xd5, 0x56, 0xad, - 0xfa, 0xd7, 0x32, 0x78, 0x99, 0xe6, 0xbe, 0x7c, 0x50, 0xc8, 0xb8, 0x5d, - 0x06, 0xf6, 0xdd, 0x7c, 0x7c, 0x46, 0x08, 0x18, 0x30, 0xa9, 0x03, 0x96, - 0x3e, 0x61, 0xa1, 0xce, 0xdd, 0x89, 0x21, 0x83, 0x02, 0x85, 0xc5, 0x42, - 0x60, 0x44, 0xdb, 0x3a, 0xe7, 0x09, 0x32, 0xa4, 0x04, 0x94, 0xef, 0x56, - 0xed, 0x8a, 0xb5, 0x83, 0x95, 0xae, 0xdd, 0x53, 0x60, 0x8d, 0x3f, 0xa7, - 0xff, 0x29, 0x0e, 0xb2, 0xe9, 0x31, 0x45, 0x9c, 0x73, 0xa9, 0x74, 0xf7, - 0xd9, 0x4d, 0xa2, 0x9d, 0xca, 0xd6, 0x4b, 0x86, 0x48, 0xdc, 0x59, 0xf9, - 0x6d, 0x4c, 0xba, 0xfe, 0xd9, 0x28, 0x6c, 0x9a, 0x19, 0x33, 0x6d, 0x8c, - 0x28, 0xb1, 0xed, 0x2d, 0xc8, 0x9b, 0x6a, 0x9d, 0x2f, 0x53, 0xf5, 0x07, - 0x22, 0xd9, 0x04, 0x49, 0x10, 0x83, 0x51, 0xd1, 0x8f, 0xf9, 0xbe, 0xc6, - 0xb0, 0x02, 0x09, 0x24, 0x90, 0xe0, 0xa2, 0x11, 0x8c, 0x2a, 0xf9, 0x62, - 0xd3, 0xfa, 0xcd, 0x12, 0xf5, 0x62, 0x64, 0x8a, 0x00, 0x70, 0xf4, 0xa7, - 0x47, 0x50, 0x6b, 0x7c, 0x05, 0xc8, 0x6d, 0x0f, 0xdc, 0x99, 0xa3, 0x50, - 0x2b, 0x5d, 0x3a, 0x36, 0x2f, 0x6b, 0xb4, 0x81, 0x9a, 0xca, 0x2a, 0xb7, - 0x6f, 0xb0, 0x24, 0xb4, 0x38, 0x79, 0x0d, 0xf8, 0xc7, 0x56, 0xa1, 0xc4, - 0xe9, 0x08, 0x79, 0xbe, 0xb1, 0x4d, 0xf7, 0xc3, 0x8b, 0xb6, 0x09, 0xf2, - 0xa0, 0x4e, 0x58, 0xba, 0xfa, 0x40, 0xbf, 0x6f, 0x98, 0x2e, 0x8e, 0x49, - 0x2e, 0xde, 0xc6, 0x27, 0x7b, 0xef, 0xf7, 0x63, 0xd7, 0x49, 0x7e, 0x0c, - 0x5b, 0x9a, 0x3c, 0x2e, 0x1b, 0x58, 0x2e, 0x4b, 0xfb, 0xb5, 0x9c, 0x58, - 0xfe, 0x1b, 0xe6, 0x67, 0x36, 0x3b, 0x32, 0x57, 0x24, 0xb6, 0x03, 0x58, - 0xef, 0xee, 0xd1, 0x69, 0xee, 0x2d, 0x1f, 0xa8, 0x38, 0xed, 0x56, 0x9e, - 0x52, 0x61, 0x66, 0x44, 0x98, 0xed, 0x49, 0x3f, 0xe8, 0x6f, 0x27, 0x23, - 0x05, 0x93, 0x2f, 0x7b, 0x2e, 0x5b, 0x37, 0xc5, 0x1b, 0xf8, 0xef, 0xb6, - 0x1c, 0xf3, 0x1b, 0x55, 0x9f, 0x49, 0xdb, 0x18, 0x22, 0x50, 0xe4, 0x4f, - 0xe5, 0x96, 0xe8, 0x46, 0x54, 0xf5, 0xd8, 0xf1, 0xe3, 0x33, 0xe9, 0x5a, - 0xc3, 0x95, 0xd4, 0x85, 0x44, 0xfe, 0x0b, 0x17, 0xc7, 0x5c, 0x5a, 0x5e, - 0xb7, 0xb3, 0x3b, 0x56, 0x98, 0x35, 0x3c, 0x66, 0xae, 0xa5, 0xf0, 0xfa, - 0x45, 0xf1, 0x9d, 0x3a, 0x77, 0x0a, 0xa4, 0x43, 0x42, 0x82, 0xc1, 0x07, - 0x81, 0xc4, 0x29, 0xb9, 0xac, 0x35, 0x2b, 0x0a, 0xe6, 0x4d, 0xb2, 0xef, - 0x3c, 0x5b, 0x3e, 0x92, 0xbb, 0x96, 0x49, 0x77, 0xad, 0xc7, 0x65, 0x9f, - 0xf8, 0x67, 0xab, 0x42, 0x9a, 0xb6, 0x95, 0x5c, 0x67, 0x42, 0x0a, 0x5a, - 0xa5, 0x85, 0x30, 0xa0, 0xdf, 0x18, 0x51, 0xf7, 0xa7, 0xd2, 0x4b, 0x6b, - 0x0a, 0xf6, 0xf4, 0xb7, 0x47, 0x01, 0x06, 0x71, 0xf0, 0xa5, 0xe1, 0x70, - 0x5a, 0xd7, 0xcb, 0x0a, 0x7f, 0x23, 0x69, 0x8a, 0xd1, 0xc4, 0x60, 0x56, - 0xef, 0xcc, 0xda, 0x03, 0xb5, 0x0f, 0x6e, 0xa8, 0xea, 0xff, 0xcb, 0x19, - 0x16, 0xd8, 0xca, 0x0c, 0x40, 0x44, 0xf4, 0x48, 0x52, 0x26, 0x3c, 0x82, - 0xef, 0x33, 0xaf, 0xe9, 0x09, 0xaa, 0x58, 0x1c, 0x58, 0xd6, 0x8a, 0xe1, - 0xe2, 0x80, 0x2d, 0xa7, 0xc6, 0x48, 0xe6, 0x6f, 0x92, 0x95, 0xd2, 0x1c, - 0x8b, 0x2d, 0xb3, 0x6f, 0xdb, 0x04, 0xcf, 0x5f, 0x3e, 0x8f, 0x96, 0x65, - 0x1a, 0x34, 0x14, 0xbf, 0xf0, 0xcf, 0x2f, 0x3c, 0x86, 0x07, 0x38, 0x14, - 0xf2, 0x44, 0x45, 0x2f, 0x6c, 0x03, 0x33, 0x24, 0xb8, 0x10, 0x82, 0xcd, - 0x73, 0x51, 0x72, 0x39, 0x75, 0x55, 0x1b, 0xd2, 0xc3, 0x1e, 0x10, 0x7d, - 0x6c, 0x8e, 0x3c, 0x0b, 0xfb, 0x2d, 0x6e, 0xb3, 0x06, 0x8e, 0x54, 0x95, - 0x52, 0x78, 0xe9, 0x17, 0xd9, 0x50, 0xc1, 0xa7, 0x64, 0xd1, 0x19, 0xc1, - 0x90, 0x5d, 0x26, 0xdb, 0xd5, 0xfb, 0x90, 0xbf, 0xbb, 0xb1, 0x6d, 0x0e, - 0x37, 0x0f, 0xe9, 0xd6, 0x92, 0xd2, 0x58, 0x5a, 0x77, 0xa1, 0x48, 0xae, - 0xd3, 0xc4, 0xca, 0x0b, 0x19, 0xff, 0x73, 0x84, 0x51, 0xf8, 0x3d, 0x7f, - 0xba, 0xc8, 0x0d, 0x09, 0x0b, 0x6f, 0x2b, 0x06, 0x94, 0xb2, 0xe3, 0x06, - 0xf9, 0x42, 0x0e, 0x6b, 0x61, 0x15, 0x32, 0xf6, 0xff, 0x26, 0xc5, 0x76, - 0xd9, 0x57, 0x73, 0x2d, 0x77, 0x56, 0xaa, 0x9d, 0x85, 0x1a, 0xc1, 0x87, - 0xdc, 0x4c, 0x7e, 0xfb, 0x7f, 0x7b, 0xb9, 0x2c, 0x28, 0xd4, 0xeb, 0xb0, - 0x03, 0x11, 0x27, 0xf2, 0xdd, 0x78, 0x0b, 0x40, 0x0d, 0x3e, 0x55, 0x60, - 0x8b, 0x87, 0xb6, 0x25, 0x47, 0xb0, 0x1d, 0x05, 0x69, 0x12, 0x3f, 0xdc, - 0xa7, 0x47, 0x43, 0xff, 0xa3, 0x7d, 0x36, 0xee, 0x58, 0xb7, 0x8a, 0x92, - 0x8b, 0xe8, 0x57, 0x23, 0xdb, 0x64, 0x54, 0x8c, 0x0c, 0xc7, 0xbd, 0x53, - 0x32, 0xc7, 0xe0, 0x4b, 0x8c, 0x7f, 0x9c, 0x6e, 0x5f, 0x3b, 0x55, 0x8e, - 0x2b, 0xdd, 0xa8, 0x51, 0x66, 0x89, 0x15, 0x12, 0xca, 0x12, 0x3d, 0x97, - 0xe7, 0x93, 0xdc, 0x93, 0x60, 0x4d, 0x57, 0x08, 0x15, 0x7c, 0x4f, 0x98, - 0xdd, 0x69, 0xd0, 0xc3, 0xdd, 0xc2, 0x56, 0xf0, 0x8c, 0xe6, 0xdb, 0xd8, - 0xf5, 0x89, 0xb3, 0x02, 0x54, 0x2f, 0x74, 0xdb, 0x5f, 0xb1, 0x85, 0xba, - 0xa7, 0xcb, 0x59, 0x9a, 0xb5, 0x44, 0x66, 0x5a, 0xfc, 0x52, 0xbe, 0x93, - 0x14, 0x9f, 0x03, 0x03, 0xc6, 0xf9, 0xc7, 0x79, 0x4d, 0x9b, 0xdf, 0x87, - 0xda, 0xeb, 0xc3, 0xdb, 0x27, 0xf8, 0x16, 0x3a, 0x48, 0x90, 0x6e, 0x1e, - 0xb1, 0xc7, 0x8a, 0x53, 0xab, 0x55, 0x07, 0xfb, 0xfc, 0x36, 0x8a, 0x84, - 0x1b, 0xe3, 0xe2, 0xdf, 0x49, 0x00, 0x0c, 0x12, 0xab, 0xf2, 0x89, 0xb2, - 0xcc, 0x5f, 0xe4, 0xfe, 0x61, 0xb9, 0x6b, 0x83, 0x98, 0x68, 0x06, 0xba, - 0x4e, 0xb0, 0x98, 0x2e, 0x7d, 0x1c, 0x5b, 0xe2, 0x50, 0x3f, 0x64, 0xa5, - 0x31, 0x69, 0xd9, 0x55, 0xca, 0xc9, 0xb4, 0x5d, 0x58, 0xc8, 0xbf, 0x8a, - 0x46, 0xde, 0x03, 0x33, 0x8a, 0x0d, 0xa6, 0xa2, 0xdd, 0x81, 0xde, 0x62, - 0x2f, 0xad, 0xf4, 0xc4, 0x46, 0x48, 0xe5, 0x9c, 0xc8, 0xbc, 0x38, 0xd3, - 0x26, 0xeb, 0xd9, 0x3c, 0x02, 0xa2, 0x11, 0xc7, 0xcb, 0x17, 0x3d, 0xbc, - 0x9e, 0x1d, 0xbd, 0x65, 0x37, 0x70, 0x65, 0x2d, 0xbd, 0x7c, 0xca, 0x6e, - 0xf3, 0xf9, 0x5e, 0xcf, 0x4b, 0xe8, 0xe8, 0x57, 0x2e, 0x8c, 0x82, 0xc4, - 0x85, 0x1b, 0x8c, 0x12, 0x68, 0x96, 0x98, 0xd1, 0x42, 0x9c, 0x0e, 0x3a, - 0x14, 0x51, 0xca, 0x19, 0xe7, 0x48, 0x6e, 0xb0, 0xe1, 0xa1, 0x1a, 0x06, - 0xc6, 0x85, 0x12, 0x2b, 0x71, 0x5a, 0xba, 0xb5, 0x85, 0x7e, 0x6b, 0x3e, - 0xd9, 0x70, 0x3c, 0x5d, 0x92, 0x03, 0xda, 0x94, 0xcb, 0x41, 0x6f, 0x98, - 0xa2, 0x5c, 0x7e, 0x93, 0xce, 0xd2, 0xe2, 0xad, 0xc4, 0x77, 0x86, 0x05, - 0x4e, 0x76, 0x8b, 0xe4, 0x1e, 0xfd, 0xe5, 0xaf, 0x6f, 0x83, 0x1e, 0x06, - 0x9e, 0x57, 0xa2, 0x33, 0x7e, 0x49, 0x3f, 0xc5, 0x7f, 0xd1, 0xb6, 0x9c, - 0x42, 0x96, 0xaa, 0x50, 0xd1, 0x0e, 0xb0, 0xad, 0xb4, 0x0c, 0x9c, 0xf3, - 0xa6, 0x61, 0xab, 0xfa, 0x49, 0x00, 0xe9, 0x62, 0x07, 0x4d, 0x89, 0x32, - 0xf3, 0x0b, 0xaa, 0xf1, 0x0c, 0xd9, 0xc6, 0xa5, 0x2b, 0x39, 0xd3, 0x43, - 0x9c, 0xcb, 0x11, 0x1f, 0x99, 0x1a, 0xb3, 0xce, 0xb7, 0xce, 0x3a, 0xb7, - 0x71, 0xb0, 0x73, 0x92, 0xd5, 0xb2, 0x24, 0x9b, 0x24, 0x04, 0x9a, 0x09, - 0x13, 0x5b, 0x37, 0xfc, 0x71, 0x48, 0x7e, 0x7c, 0xfd, 0x69, 0xcb, 0xde, - 0x73, 0xbe, 0xb2, 0xd3, 0x69, 0x9a, 0x27, 0x77, 0x97, 0x56, 0xb7, 0xfd, - 0x3e, 0x11, 0xaf, 0x5e, 0x32, 0x49, 0x60, 0xa6, 0x8b, 0xa0, 0xf6, 0x27, - 0x3f, 0x2a, 0x21, 0x2e, 0x47, 0x6a, 0xd9, 0xf7, 0xc2, 0xa3, 0x0e, 0xba, - 0x48, 0xab, 0xcf, 0x9d, 0xdb, 0x2c, 0x37, 0x1b, 0x85, 0x23, 0x97, 0x4e, - 0xb1, 0xf3, 0xd9, 0x5c, 0x87, 0xed, 0x2e, 0x53, 0x97, 0x9f, 0xda, 0xa2, - 0xaa, 0x2f, 0x23, 0xb6, 0x51, 0xdd, 0x59, 0x43, 0x73, 0x08, 0x30, 0xe3, - 0x6d, 0xf4, 0xcc, 0xb3, 0x99, 0x50, 0x84, 0xf3, 0x16, 0x09, 0x1c, 0x1b, - 0x3e, 0x4b, 0xc5, 0x8a, 0xb8, 0xcd, 0x63, 0x64, 0xaf, 0x81, 0x7e, 0x5c, - 0x70, 0x47, 0x9f, 0xcd, 0xca, 0x9c, 0xcf, 0x04, 0x27, 0x84, 0xf2, 0xfb, - 0x49, 0x37, 0xb4, 0xe5, 0x1c, 0x05, 0x2e, 0x9f, 0x5e, 0x52, 0x60, 0x60, - 0xc5, 0x84, 0xd4, 0x03, 0xb0, 0x96, 0xd4, 0x05, 0xac, 0x48, 0x3f, 0x18, - 0x9a, 0x69, 0xec, 0xd9, 0x4f, 0x5e, 0x21, 0xba, 0xe8, 0x4e, 0xe1, 0x23, - 0xff, 0xa2, 0x66, 0x20, 0x1f, 0x5b, 0xcc, 0x2a, 0x62, 0x46, 0xcb, 0x29, - 0x68, 0xe8, 0xff, 0x6f, 0x72, 0x6e, 0xf2, 0xd7, 0xd7, 0x93, 0x7e, 0x32, - 0x3b, 0x7e, 0x55, 0x07, 0x97, 0xd2, 0x2e, 0xaf, 0x35, 0x1c, 0x50, 0x74, - 0x8c, 0x5f, 0xe5, 0xc0, 0x0a, 0xf6, 0x35, 0x74, 0x57, 0xba, 0x86, 0x91, - 0x36, 0xde, 0x39, 0x3c, 0xf5, 0x48, 0x76, 0xcb, 0xae, 0xb5, 0x54, 0x1f, - 0x55, 0xa7, 0x48, 0x1c, 0x85, 0x15, 0x63, 0x01, 0x75, 0x2b, 0x92, 0xc5, - 0x14, 0xb2, 0xde, 0xc9, 0x97, 0xa8, 0xf0, 0x3c, 0xb9, 0xea, 0x67, 0xaf, - 0x88, 0x57, 0xb1, 0x36, 0x3f, 0x80, 0x12, 0x2b, 0xb2, 0xd5, 0x61, 0xeb, - 0xfa, 0x7d, 0x0c, 0xa5, 0x55, 0x48, 0xbe, 0x56, 0xdf, 0x1d, 0xc8, 0x9e, - 0xda, 0x74, 0x80, 0x4d, 0x67, 0xb0, 0x82, 0x7e, 0xae, 0x86, 0x50, 0x61, - 0x89, 0xea, 0x18, 0x77, 0x76, 0x91, 0x71, 0xc4, 0xc4, 0x8f, 0xc9, 0x3c, - 0x73, 0x82, 0x54, 0x4e, 0x66, 0xbb, 0xa5, 0x52, 0x5f, 0xfd, 0xf2, 0xb7, - 0x61, 0xa8, 0xa2, 0xb0, 0xf4, 0x39, 0x3c, 0xa2, 0x14, 0x39, 0x23, 0x61, - 0x71, 0x49, 0xfa, 0x47, 0x10, 0x5f, 0x97, 0x0e, 0x2a, 0x55, 0x8a, 0x25, - 0x9f, 0x13, 0x5c, 0xc8, 0x0c, 0xfc, 0x34, 0x4d, 0x4d, 0x26, 0x93, 0x7c, - 0xda, 0xea, 0x86, 0x02, 0x5d, 0x20, 0xcb, 0x39, 0x6b, 0xe1, 0x90, 0x51, - 0x15, 0xb5, 0x56, 0x9d, 0xed, 0x9f, 0x60, 0x77, 0x61, 0x16, 0xfd, 0xda, - 0xfb, 0x03, 0x75, 0x45, 0x38, 0x0d, 0xc4, 0xc7, 0x2f, 0xbe, 0x8a, 0xde, - 0x7c, 0x47, 0xa8, 0xeb, 0x54, 0xc2, 0xbb, 0x5a, 0x9d, 0xf1, 0x0a, 0x04, - 0x0e, 0x1b, 0x8a, 0x25, 0x8b, 0x2a, 0x18, 0x78, 0x9b, 0x04, 0x50, 0xfc, - 0x26, 0x6d, 0x38, 0xcd, 0x06, 0xa4, 0x98, 0x6a, 0x6c, 0x68, 0x85, 0x78, - 0x96, 0xf7, 0xbb, 0x73, 0xa8, 0xa2, 0xd9, 0xaf, 0x1e, 0x88, 0x84, 0x61, - 0x09, 0x1b, 0x2f, 0xcb, 0xd5, 0x33, 0xb4, 0xdc, 0x71, 0x9e, 0x70, 0x27, - 0xc1, 0x5a, 0xe1, 0x0a, 0x0a, 0x18, 0xea, 0x42, 0xe1, 0x62, 0x17, 0x0b, - 0x26, 0xba, 0x30, 0x15, 0xa1, 0xa0, 0xe1, 0xab, 0x80, 0x3b, 0xdb, 0x84, - 0xd4, 0x94, 0x70, 0xea, 0xed, 0xc1, 0xe3, 0x52, 0x5e, 0xac, 0x30, 0xa6, - 0xdd, 0xf5, 0xc3, 0xd1, 0xc6, 0xfe, 0xc8, 0x4f, 0xc7, 0x8c, 0xc6, 0xc3, - 0x0f, 0x25, 0x77, 0x89, 0x35, 0xad, 0x45, 0x70, 0x4e, 0xff, 0x12, 0x22, - 0xc2, 0xe3, 0xd8, 0x0f, 0xf8, 0xb4, 0x57, 0x22, 0xb5, 0xde, 0xee, 0xcf, - 0x39, 0x76, 0x8f, 0x90, 0xc8, 0x9d, 0x31, 0xaf, 0x33, 0x2f, 0x32, 0x9f, - 0x4e, 0x51, 0x80, 0x70, 0x5f, 0xfa, 0x93, 0xb1, 0x8c, 0x9f, 0x68, 0xb3, - 0x69, 0x80, 0x28, 0xe4, 0x29, 0x73, 0x95, 0x00, 0x4a, 0xeb, 0xa6, 0x6d, - 0x58, 0x33, 0x23, 0x52, 0x8d, 0xe4, 0x9e, 0xff, 0xfb, 0x19, 0x5d, 0xe1, - 0x3b, 0x14, 0x16, 0x0d, 0x35, 0x33, 0xbf, 0x23, 0xdd, 0x1d, 0xc2, 0x32, - 0x94, 0xa2, 0x10, 0xc8, 0xe9, 0x8d, 0xa9, 0x5d, 0x24, 0xee, 0x7f, 0x37, - 0x99, 0x62, 0xd9, 0x50, 0x81, 0xa4, 0x4e, 0xb9, 0xa6, 0xe9, 0x25, 0xfe, - 0xe2, 0x57, 0x70, 0xb4, 0x02, 0x0a, 0x31, 0x84, 0x3b, 0x62, 0x9c, 0x53, - 0x0b, 0x45, 0x53, 0x78, 0x18, 0xe9, 0x28, 0x79, 0x16, 0x3a, 0x7b, 0xdc, - 0x0d, 0x98, 0x5c, 0x21, 0x1f, 0xff, 0xd0, 0x4d, 0xfa, 0x29, 0xed, 0x73, - 0x9a, 0x3d, 0x7f, 0x1d, 0xd7, 0x91, 0x74, 0x5b, 0x37, 0x88, 0x22, 0x68, - 0x4f, 0x2e, 0x11, 0x8b, 0x06, 0x2f, 0xdd, 0x2f, 0x91, 0x3f, 0x66, 0x5c, - 0x84, 0x1d, 0xed, 0x01, 0x67, 0x22, 0x06, 0x5f, 0x97, 0x2f, 0xdd, 0xba, - 0x41, 0xae, 0xc6, 0x0d, 0xa3, 0xce, 0x32, 0x74, 0x2d, 0x67, 0x3c, 0x5c, - 0xc6, 0x7f, 0x8b, 0x3e, 0x53, 0xb7, 0x26, 0x01, 0x5c, 0x59, 0x88, 0x55, - 0x3c, 0x2f, 0xf4, 0x7a, 0x4b, 0xc2, 0xad, 0xa0, 0xc0, 0x68, 0xce, 0x4b, - 0xfb, 0x3e, 0x3b, 0x08, 0xc1, 0x65, 0x78, 0x94, 0xfa, 0x84, 0x3c, 0xaa, - 0x2a, 0x6d, 0xfc, 0x1d, 0x30, 0xda, 0xa0, 0x34, 0x2b, 0x85, 0xa4, 0x77, - 0x01, 0x8d, 0xce, 0x9d, 0x38, 0x17, 0x07, 0x5d, 0xbf, 0xe2, 0xfd, 0x95, - 0x65, 0x25, 0x6e, 0xe6, 0x85, 0xa5, 0x47, 0x56, 0xdb, 0x22, 0x15, 0xb6, - 0x70, 0x36, 0xfa, 0xaa, 0xcd, 0x3d, 0x05, 0x45, 0x9f, 0xea, 0x24, 0x7b, - 0x8b, 0x23, 0x31, 0x7e, 0x5f, 0x94, 0xa8, 0x14, 0xa6, 0x8c, 0x19, 0x83, - 0x12, 0x54, 0x61, 0x08, 0xfa, 0x08, 0x39, 0x56, 0x69, 0xda, 0x8e, 0xa8, - 0x96, 0x6b, 0xc8, 0x65, 0x11, 0x88, 0xe3, 0xbf, 0x3d, 0x38, 0xdc, 0x8e, - 0x6f, 0x09, 0x3c, 0x67, 0xa3, 0xbf, 0xad, 0xef, 0xf2, 0x8a, 0x26, 0x9c, - 0xa4, 0x6c, 0xef, 0x8a, 0x63, 0x36, 0xdd, 0x41, 0xdc, 0x9d, 0x17, 0xe3, - 0xed, 0x9c, 0xd2, 0xe4, 0x91, 0xc3, 0x25, 0x54, 0x74, 0x90, 0x05, 0x52, - 0xe9, 0x63, 0x53, 0x6d, 0xf8, 0x43, 0x96, 0xf8, 0xc0, 0x34, 0x07, 0x30, - 0x5d, 0xb9, 0xba, 0x0e, 0x79, 0x1b, 0x22, 0x9d, 0xb8, 0xda, 0x53, 0xa8, - 0x2f, 0x09, 0x49, 0x3b, 0x47, 0x6a, 0xbb, 0x6e, 0xe4, 0x97, 0x0a, 0x6e, - 0xc0, 0xea, 0xeb, 0xd6, 0xa3, 0x71, 0x6b, 0xde, 0xea, 0x56, 0xb6, 0x71, - 0xf6, 0x11, 0x87, 0x81, 0xad, 0xbc, 0x51, 0x4f, 0xc4, 0x8e, 0xef, 0xdc, - 0xee, 0x67, 0xc3, 0x4e, 0x35, 0x6f, 0xf1, 0xa5, 0x39, 0x4c, 0xb3, 0x5a, - 0x4b, 0x89, 0xa7, 0xbd, 0xe2, 0x5d, 0x65, 0x0d, 0xc8, 0xc5, 0x58, 0xa4, - 0x97, 0x85, 0x4f, 0x06, 0xe1, 0x8f, 0x1a, 0x95, 0xc3, 0x8b, 0x96, 0x13, - 0xcb, 0x19, 0x1a, 0x98, 0xf1, 0x3b, 0xf6, 0x6d, 0x0c, 0xde, 0x96, 0x17, - 0xe4, 0x46, 0xb8, 0xd9, 0x7e, 0xb1, 0x5b, 0x63, 0xcd, 0x4b, 0x32, 0xbd, - 0x08, 0xd8, 0x78, 0xf4, 0x17, 0x51, 0x79, 0x82, 0x2b, 0xda, 0xb8, 0xf6, - 0x95, 0xd7, 0xca, 0xb3, 0xad, 0xc6, 0xbf, 0xc0, 0x2f, 0x93, 0x50, 0xb8, - 0x6f, 0x17, 0xec, 0xa0, 0xb8, 0xeb, 0x10, 0x8b, 0xc2, 0x58, 0x8c, 0xd2, - 0x8e, 0xa7, 0x36, 0x21, 0x3f, 0x83, 0xbc, 0x48, 0xfe, 0x69, 0xf3, 0x54, - 0xda, 0x46, 0xd6, 0x65, 0x13, 0x5f, 0xf2, 0xfd, 0xaf, 0x4a, 0xe0, 0x77, - 0xca, 0xe3, 0xbd, 0x16, 0xcd, 0xc3, 0x2d, 0x8d, 0xf1, 0xec, 0x62, 0xe1, - 0xdd, 0xbd, 0xff, 0x68, 0x8e, 0xd8, 0xee, 0x13, 0xd2, 0x7b, 0x1b, 0x23, - 0xc3, 0xfa, 0xf4, 0x2e, 0xa4, 0xaf, 0xb5, 0x6f, 0x67, 0x28, 0x60, 0x10, - 0xdf, 0xae, 0xcc, 0x8f, 0xc5, 0xe4, 0xda, 0x63, 0x5f, 0x60, 0x17, 0x22, - 0x0f, 0x64, 0xd9, 0x3e, 0x56, 0x5b, 0xf3, 0xa7, 0x72, 0x7d, 0x7e, 0x02, - 0xb8, 0x7d, 0xfc, 0x25, 0x8e, 0x4e, 0xf3, 0x21, 0x42, 0x59, 0x40, 0x20, - 0xfa, 0xda, 0x05, 0x93, 0x99, 0x42, 0xdb, 0xe3, 0x7c, 0x79, 0x82, 0xaf, - 0xfa, 0x83, 0xf8, 0xb1, 0xc6, 0x55, 0x31, 0xd8, 0x8b, 0xd2, 0x74, 0xfe, - 0x08, 0x5d, 0x6e, 0x2b, 0x25, 0x32, 0x8f, 0xfa, 0x54, 0xe9, 0xd1, 0x96, - 0xdf, 0x24, 0x38, 0xe4, 0x72, 0x81, 0xec, 0xd0, 0xcb, 0x9f, 0x24, 0x31, - 0x6c, 0x48, 0x7b, 0x96, 0xe6, 0x6a, 0xbb, 0x58, 0x93, 0xdc, 0x4f, 0x1a, - 0xf9, 0xea, 0x3a, 0x87, 0x3f, 0xc9, 0x91, 0x8a, 0x2c, 0x8f, 0xbc, 0x1a, - 0x46, 0xec, 0x1e, 0xf8, 0xbf, 0x05, 0xe3, 0x09, 0x56, 0x7a, 0x55, 0xaf, - 0x53, 0x8b, 0x79, 0x05, 0x95, 0x24, 0xeb, 0xeb, 0x42, 0x2d, 0x84, 0x6c, - 0x88, 0x56, 0x33, 0x3c, 0x52, 0x62, 0x3d, 0x94, 0x49, 0xd4, 0x5a, 0x49, - 0x83, 0x94, 0x20, 0x12, 0x76, 0x58, 0x50, 0x6c, 0x57, 0x14, 0xb4, 0xfb, - 0xf0, 0xc4, 0x35, 0xdc, 0xa0, 0xb7, 0x14, 0xe0, 0x33, 0xec, 0x8b, 0xa1, - 0x66, 0xee, 0x0f, 0xb0, 0x37, 0x8b, 0x6c, 0x54, 0x32, 0xfa, 0x8a, 0x71, - 0x72, 0xfc, 0xcb, 0x6e, 0x48, 0xd1, 0x08, 0x79, 0x8b, 0x8b, 0x16, 0xfd, - 0xc6, 0xdd, 0x43, 0xc3, 0xfb, 0xb2, 0x4f, 0xbf, 0x49, 0x14, 0xdc, 0xc3, - 0xa1, 0xc3, 0x5c, 0x40, 0xfc, 0xaf, 0xc7, 0x10, 0x12, 0x7e, 0x45, 0x8e, - 0x3b, 0x89, 0xbf, 0xaf, 0x26, 0x4e, 0x19, 0xbb, 0x11, 0x6b, 0x6d, 0xf2, - 0x45, 0x0d, 0x09, 0x8e, 0xe9, 0xc6, 0xc6, 0x66, 0x5f, 0x4b, 0xbf, 0xb3, - 0x49, 0xc8, 0x5d, 0x42, 0xec, 0x39, 0xa2, 0xfd, 0xb3, 0xa3, 0x47, 0xf6, - 0x1c, 0x5e, 0x18, 0x6e, 0x85, 0x2a, 0xb6, 0x57, 0xbc, 0x02, 0x31, 0xd7, - 0x5b, 0x27, 0x60, 0x88, 0xed, 0x37, 0x43, 0xdc, 0x3a, 0x31, 0x4c, 0x94, - 0xca, 0x71, 0x63, 0xb8, 0x1a, 0x73, 0x39, 0x5b, 0x9c, 0x4d, 0x95, 0xde, - 0x4a, 0x1d, 0x69, 0x18, 0x7e, 0x06, 0x4c, 0x3c, 0x39, 0x7e, 0xd4, 0x25, - 0xe6, 0x77, 0x63, 0xdd, 0xdd, 0x96, 0x17, 0x58, 0xec, 0x13, 0x34, 0x71, - 0x3c, 0x85, 0x44, 0x25, 0x77, 0xb8, 0xba, 0x15, 0x66, 0xef, 0xbb, 0x5f, - 0x64, 0x6c, 0x97, 0x9b, 0x24, 0x66, 0x9d, 0x1f, 0xa5, 0xb6, 0xbd, 0xea, - 0xd3, 0x8c, 0xc9, 0xb9, 0xae, 0xa7, 0xd5, 0xe6, 0xc4, 0xf6, 0x86, 0xe2, - 0x4d, 0x42, 0xe8, 0x0e, 0xb3, 0xf1, 0x78, 0x32, 0x60, 0x1a, 0xab, 0xe3, - 0x2e, 0xa1, 0x18, 0x39, 0x97, 0x7e, 0xe2, 0x3b, 0xfc, 0x4c, 0x29, 0x60, - 0x7d, 0x6b, 0x7b, 0x69, 0xdb, 0xad, 0x9c, 0x30, 0x39, 0x18, 0xfc, 0x0d, - 0x28, 0x3f, 0xf6, 0x41, 0xe2, 0x7a, 0xf8, 0x97, 0xbf, 0x2e, 0x76, 0xa2, - 0xd5, 0xf7, 0xd9, 0x2d, 0x9c, 0xa6, 0x93, 0xe7, 0x58, 0xf9, 0x4a, 0x32, - 0xbf, 0x85, 0xa7, 0x1e, 0x5e, 0xc5, 0x48, 0xf8, 0x39, 0xc9, 0x16, 0xff, - 0x7a, 0xab, 0xcb, 0xdb, 0xf5, 0x69, 0xf1, 0xf7, 0x4f, 0x41, 0x2c, 0xee, - 0x7c, 0x56, 0x1b, 0x08, 0x07, 0xec, 0xc9, 0x7f, 0xd9, 0x07, 0x38, 0x8f, - 0x13, 0x92, 0x02, 0x05, 0x4b, 0x7b, 0xf4, 0xc8, 0x7d, 0x32, 0x1a, 0xb0, - 0xfe, 0xfc, 0x7f, 0x53, 0x14, 0x7e, 0xcc, 0x5f, 0x1e, 0x70, 0xe3, 0x09, - 0xb6, 0x9e, 0xf9, 0x6e, 0x46, 0x9b, 0x4d, 0xdb, 0x74, 0x56, 0x26, 0x57, - 0x51, 0x8c, 0x0f, 0x32, 0x11, 0x31, 0xb4, 0x9d, 0x92, 0x29, 0xc7, 0xad, - 0xd6, 0x28, 0x22, 0xe2, 0x80, 0xf7, 0xa1, 0xdc, 0x57, 0x3a, 0xfa, 0xbc, - 0x96, 0x6c, 0xec, 0xdb, 0x7e, 0x57, 0xc2, 0x71, 0xe4, 0x85, 0xe1, 0xad, - 0xcd, 0x92, 0x33, 0xdf, 0xb7, 0x46, 0xa3, 0xe6, 0x85, 0x45, 0x39, 0xb5, - 0xc1, 0xb8, 0xa8, 0x66, 0xe3, 0x5e, 0xa4, 0x8b, 0x3f, 0xcb, 0x1b, 0xae, - 0xe6, 0x74, 0x7c, 0x30, 0xa4, 0x01, 0xa8, 0x35, 0x84, 0x7a, 0x75, 0xc2, - 0x88, 0xbd, 0x20, 0xbf, 0x66, 0x86, 0x01, 0x7e, 0xfd, 0x6c, 0x2e, 0xdb, - 0xba, 0x9a, 0xfb, 0x65, 0x31, 0xb4, 0xb2, 0x6f, 0xe0, 0x13, 0x5c, 0xea, - 0xe3, 0xcc, 0xb7, 0x0e, 0x78, 0x5d, 0xa8, 0xbf, 0xc0, 0xcc, 0x99, 0xf6, - 0xb5, 0xbf, 0x10, 0x15, 0x1c, 0xa1, 0x3d, 0x0e, 0xbf, 0x69, 0xe2, 0x9e, - 0x13, 0x7b, 0x65, 0xbc, 0xb8, 0x03, 0x77, 0x81, 0x56, 0x91, 0x28, 0xd0, - 0xf5, 0xc3, 0x7c, 0x51, 0xf4, 0x39, 0x6b, 0xad, 0x86, 0x0b, 0x29, 0x97, - 0x2b, 0x9e, 0x50, 0x3e, 0x30, 0xfe, 0xa6, 0x53, 0x15, 0xc2, 0x64, 0xaf, - 0xa5, 0x9f, 0x1d, 0x81, 0x35, 0xbe, 0xff, 0xf0, 0x43, 0x92, 0x6c, 0x52, - 0x6b, 0xfd, 0xdc, 0x8c, 0x38, 0xba, 0x28, 0xcc, 0xdd, 0x4e, 0x87, 0xbd, - 0x37, 0x46, 0x05, 0x68, 0xcd, 0xe2, 0x0b, 0xcc, 0xfa, 0xe6, 0xa7, 0x5e, - 0xc8, 0x74, 0x6d, 0x13, 0x78, 0x8d, 0xfc, 0x3d, 0x4d, 0x3f, 0x04, 0x30, - 0x98, 0xa7, 0x08, 0xdb, 0x4a, 0xeb, 0x39, 0x3b, 0xa5, 0x71, 0xcc, 0x24, - 0x3a, 0xd7, 0x15, 0xd6, 0xc8, 0xa5, 0x4b, 0x85, 0x9d, 0x4d, 0x11, 0x1f, - 0x31, 0xd9, 0xa6, 0x40, 0x57, 0xf5, 0x02, 0x3c, 0x04, 0xce, 0xc7, 0x0d, - 0xee, 0xf2, 0x63, 0xdc, 0x08, 0x5d, 0xd6, 0x93, 0x3a, 0x22, 0xf3, 0x38, - 0x39, 0x0f, 0xbe, 0x4f, 0x2f, 0x0a, 0xf3, 0x46, 0x48, 0x29, 0x9f, 0x79, - 0x6f, 0x24, 0xad, 0x0a, 0x0f, 0x0a, 0x1b, 0x56, 0xbb, 0x02, 0x5c, 0x35, - 0x70, 0x7b, 0x43, 0x0f, 0xb9, 0x69, 0x12, 0x71, 0xf1, 0xb0, 0xa3, 0x85, - 0x98, 0x4d, 0x3e, 0x7a, 0x98, 0x22, 0x16, 0x6c, 0x09, 0xe6, 0x81, 0x46, - 0x5f, 0xbd, 0x9b, 0xf0, 0xf6, 0x42, 0x63, 0xe2, 0x06, 0xf8, 0x01, 0x4b, - 0xd0, 0x1b, 0x87, 0x36, 0xc0, 0x19, 0x69, 0xe2, 0xb3, 0xd8, 0x52, 0x6c, - 0x8f, 0xf4, 0x4d, 0x72, 0x6b, 0x8e, 0x52, 0xf7, 0xa1, 0xfa, 0xad, 0x7f, - 0x42, 0x55, 0xa1, 0x95, 0x9f, 0xb8, 0x43, 0x57, 0xd1, 0xc1, 0x5a, 0x7c, - 0xe8, 0xf8, 0xc7, 0x8b, 0xcf, 0xd9, 0x39, 0xf1, 0xde, 0x0d, 0xcc, 0x5b, - 0x64, 0xff, 0x3f, 0x69, 0xcf, 0x1c, 0x01, 0xb7, 0xd5, 0x0b, 0x2e, 0x3c, - 0xd6, 0x1e, 0xf6, 0x53, 0x26, 0xd6, 0x46, 0xd3, 0x87, 0xa7, 0x26, 0x10, - 0x2e, 0x47, 0x73, 0x96, 0xff, 0xe2, 0xde, 0xcb, 0x9b, 0x2d, 0x78, 0xad, - 0x5d, 0xd5, 0xc4, 0xb5, 0xa8, 0x32, 0x6f, 0x38, 0x24, 0x30, 0x35, 0xc4, - 0xd7, 0xb5, 0xbe, 0x7c, 0x24, 0x57, 0x8a, 0x4e, 0x7e, 0x53, 0x47, 0x3c, - 0x72, 0x6e, 0x15, 0x69, 0xf6, 0xfe, 0xd6, 0x20, 0x0d, 0xd1, 0xe5, 0xe8, - 0xe0, 0xcf, 0x3a, 0x27, 0x43, 0xee, 0x28, 0xba, 0xd7, 0xd6, 0x75, 0x5e, - 0xee, 0x89, 0x08, 0x9b, 0x97, 0x23, 0x38, 0xb1, 0xaf, 0xba, 0xd8, 0x79, - 0x76, 0x56, 0x2f, 0x52, 0x71, 0x3b, 0xc2, 0x5b, 0x7e, 0xf3, 0x60, 0x17, - 0x9a, 0x1a, 0xe4, 0x30, 0xe4, 0x7c, 0x2a, 0xd0, 0xeb, 0x1d, 0xe1, 0x7a, - 0xda, 0xef, 0xc4, 0x30, 0x92, 0xca, 0x8c, 0x3f, 0x59, 0x98, 0x8c, 0x70, - 0x2c, 0xe8, 0xd0, 0x76, 0x55, 0xd0, 0x73, 0xcd, 0xe4, 0x24, 0x11, 0x11, - 0xe2, 0x89, 0x0e, 0xf3, 0x2e, 0x51, 0xdf, 0x36, 0x66, 0xfd, 0xf4, 0x63, - 0xfb, 0x00, 0x8a, 0xaf, 0x25, 0xba, 0xb6, 0x67, 0x8c, 0xf7, 0x59, 0x45, - 0x61, 0xe6, 0x10, 0xee, 0xa0, 0x43, 0xb5, 0xd0, 0x9c, 0x51, 0xc6, 0x0d, - 0x5e, 0x8f, 0xa5, 0x71, 0xc0, 0x45, 0x28, 0x23, 0x5d, 0xf1, 0x2c, 0x27, - 0x84, 0x9f, 0x8c, 0x8e, 0x6a, 0xdb, 0x57, 0x16, 0x6e, 0xaa, 0xd9, 0x0f, - 0xc7, 0x75, 0xe8, 0x96, 0x48, 0x9e, 0xd3, 0x16, 0xed, 0x10, 0x43, 0xc2, - 0x24, 0xc8, 0x8c, 0x9c, 0x6a, 0x96, 0xaf, 0xd2, 0xe9, 0x5d, 0x53, 0xaa, - 0xd7, 0xea, 0xb9, 0x87, 0xbd, 0xb3, 0x2e, 0x02, 0x38, 0x55, 0xc8, 0x64, - 0xbc, 0xf4, 0x31, 0xd7, 0x1d, 0x88, 0x3d, 0x31, 0xee, 0x23, 0x76, 0xf7, - 0xb5, 0x9c, 0xf4, 0xb2, 0x2f, 0x1a, 0x0b, 0x3f, 0xd5, 0xf0, 0x6b, 0x7e, - 0x92, 0x4b, 0x71, 0xf9, 0x0e, 0x55, 0x8e, 0x08, 0x33, 0x7b, 0xcb, 0x1b, - 0x87, 0x67, 0x62, 0x32, 0x62, 0xe7, 0x68, 0x13, 0xb7, 0x68, 0xaf, 0x38, - 0x5a, 0xf0, 0x58, 0xbf, 0xd7, 0x24, 0x50, 0x51, 0xc6, 0x6f, 0xc9, 0x72, - 0xf2, 0x3c, 0xdb, 0x25, 0xa4, 0x12, 0x3a, 0xd1, 0x0d, 0x4e, 0x9b, 0x21, - 0x34, 0x9b, 0x04, 0xdb, 0x86, 0xd8, 0x91, 0x8c, 0xd1, 0x4e, 0xfa, 0xa0, - 0x4d, 0xd8, 0x40, 0xa1, 0x60, 0xa1, 0x04, 0x30, 0x54, 0x19, 0x3b, 0xc6, - 0x64, 0x4f, 0x77, 0xc9, 0x4e, 0xba, 0x45, 0xbb, 0xb2, 0xdf, 0xc7, 0x29, - 0x10, 0xf0, 0x58, 0x7f, 0xe0, 0xb7, 0xd0, 0x93, 0x49, 0xa5, 0xa5, 0x01, - 0xcc, 0xae, 0x80, 0x8f, 0x3c, 0xe2, 0x5d, 0x83, 0xeb, 0x23, 0x9d, 0x27, - 0xd7, 0x4c, 0x8a, 0xdc, 0xf7, 0x9d, 0x77, 0x7f, 0x3c, 0x44, 0x00, 0x0d, - 0xcc, 0x8d, 0x03, 0xe0, 0xea, 0x18, 0xfc, 0x6e, 0x8c, 0x20, 0xf9, 0x8e, - 0x6d, 0xb4, 0x5e, 0xb1, 0x98, 0xbf, 0x24, 0x05, 0xad, 0xb1, 0x9a, 0x6c, - 0x17, 0xe3, 0xb3, 0x07, 0x6b, 0x6d, 0x63, 0xb0, 0x29, 0x0f, 0xe7, 0x6a, - 0xc0, 0x17, 0x93, 0xec, 0x90, 0xaf, 0xfb, 0xa2, 0x17, 0x10, 0x58, 0xd8, - 0x5c, 0xc1, 0x6e, 0x9b, 0xf8, 0x1a, 0xb6, 0x88, 0xd0, 0x7c, 0xf6, 0x99, - 0xd2, 0x62, 0x9e, 0x64, 0xfa, 0x3c, 0x3c, 0x4f, 0xe8, 0x2f, 0x2a, 0x95, - 0xd6, 0x38, 0xb4, 0x8e, 0xbb, 0x88, 0x89, 0x09, 0xbe, 0x53, 0x34, 0xf7, - 0xbb, 0x34, 0x53, 0xc8, 0xc5, 0xfc, 0x06, 0xe2, 0xd8, 0x31, 0x09, 0x74, - 0xcf, 0xa3, 0x7c, 0x3d, 0xcd, 0x6e, 0xad, 0x33, 0xc4, 0xda, 0x5a, 0x9f, - 0x62, 0xaf, 0x1a, 0x3f, 0x3b, 0x9e, 0xd7, 0x00, 0xc8, 0xd5, 0xdc, 0x51, - 0xfc, 0xbc, 0x05, 0xfa, 0x64, 0xb2, 0x52, 0x71, 0xe7, 0x15, 0x41, 0x41, - 0xec, 0x23, 0x6e, 0xd4, 0x1e, 0x60, 0x31, 0x60, 0x7b, 0xda, 0x2b, 0x7d, - 0xde, 0x4d, 0x61, 0xbc, 0xee, 0x03, 0x4a, 0xfd, 0x68, 0xb7, 0x86, 0xc3, - 0x20, 0x17, 0xb3, 0xf1, 0xf4, 0xf3, 0x8d, 0x47, 0x76, 0xc8, 0xe1, 0x18, - 0x2d, 0x43, 0xad, 0xe6, 0x97, 0x5a, 0xf6, 0xe6, 0xea, 0xfd, 0x98, 0xf5, - 0x3b, 0x02, 0xf8, 0xd7, 0x57, 0x43, 0x61, 0x6f, 0x59, 0xde, 0x34, 0x70, - 0xc5, 0xdb, 0x36, 0x6f, 0xcb, 0xee, 0x21, 0xc4, 0x73, 0xbb, 0xa3, 0x36, - 0xc6, 0x0e, 0x5b, 0xcc, 0x8f, 0xaf, 0xe9, 0xb2, 0x5e, 0xb4, 0x5f, 0x49, - 0x8b, 0x60, 0xf9, 0x41, 0x7e, 0x1d, 0xa7, 0x63, 0xeb, 0x49, 0xd4, 0xe5, - 0x11, 0xc0, 0xc6, 0xcf, 0xe6, 0x69, 0x7c, 0xa8, 0x33, 0xd1, 0x57, 0x7b, - 0x9f, 0x1b, 0x48, 0x0a, 0x4a, 0xda, 0x36, 0xda, 0x04, 0x09, 0x76, 0xbd, - 0xab, 0x7f, 0x13, 0xd8, 0xf1, 0x66, 0x83, 0x52, 0x3f, 0xd0, 0x71, 0x6f, - 0xb2, 0x91, 0xd5, 0x75, 0x37, 0xdf, 0x37, 0x52, 0xbe, 0x1a, 0x79, 0x38, - 0x03, 0xdf, 0x52, 0x4c, 0xcc, 0x77, 0x5f, 0x3a, 0x1a, 0x16, 0x39, 0x5d, - 0xae, 0x20, 0x0d, 0x5c, 0xae, 0x34, 0xd3, 0x64, 0x1b, 0xa6, 0x0d, 0x3b, - 0xb7, 0x13, 0xba, 0xe0, 0xb6, 0xb3, 0xb3, 0x8f, 0xf3, 0xfd, 0x21, 0x8f, - 0x79, 0xef, 0x71, 0x9b, 0xbc, 0xca, 0x3a, 0x8a, 0x80, 0x15, 0x33, 0x8b, - 0xe0, 0xb4, 0x26, 0xd7, 0x83, 0x22, 0x96, 0xd0, 0x3b, 0xad, 0x47, 0xf5, - 0x51, 0x7e, 0x77, 0x90, 0x0a, 0xce, 0xf3, 0xc5, 0x8e, 0x62, 0xf8, 0xe2, - 0x78, 0xf4, 0xfe, 0x02, 0x1e, 0xa0, 0xca, 0x06, 0xd0, 0x26, 0x12, 0xc9, - 0x4c, 0x06, 0x6e, 0x40, 0x3f, 0x47, 0xfb, 0x31, 0xa7, 0x30, 0x17, 0x87, - 0xa3, 0xab, 0x88, 0x8d, 0x40, 0xdd, 0x8f, 0x45, 0xd4, 0x4c, 0x67, 0x3a, - 0x78, 0x59, 0xf8, 0x44, 0x3a, 0x5f, 0x42, 0xc3, 0x99, 0xbf, 0x6f, 0xad, - 0x72, 0x9d, 0xa0, 0xe4, 0x71, 0xe1, 0x26, 0x5f, 0xa9, 0x83, 0xc1, 0xeb, - 0xaa, 0x0a, 0x2b, 0x68, 0xd1, 0x20, 0x0a, 0x11, 0x6a, 0xc2, 0x5f, 0x1e, - 0x1b, 0x40, 0x76, 0x87, 0x9f, 0x26, 0x88, 0xae, 0x64, 0x25, 0x04, 0xa2, - 0x3b, 0x79, 0x34, 0x05, 0x28, 0xda, 0xfb, 0xe6, 0xda, 0xab, 0xb9, 0x65, - 0xc6, 0x5e, 0xe5, 0x22, 0x12, 0x78, 0xf5, 0x8d, 0x30, 0x74, 0x4f, 0xb7, - 0xde, 0x5e, 0xe8, 0xaa, 0x93, 0xe4, 0x95, 0x96, 0xd7, 0x0a, 0x81, 0xb4, - 0x78, 0x70, 0xe8, 0x7a, 0x45, 0x3c, 0x4e, 0xd5, 0xc5, 0xb2, 0x1f, 0xf3, - 0x6c, 0x57, 0xf3, 0xc3, 0x72, 0xc0, 0x5f, 0x7d, 0x5f, 0xe5, 0x0b, 0x5c, - 0x7b, 0xc9, 0x1d, 0x0d, 0x45, 0xb6, 0x21, 0xf2, 0x30, 0x00, 0x78, 0x8e, - 0x74, 0x9d, 0x53, 0x48, 0x11, 0x70, 0x35, 0x2b, 0xfa, 0xd4, 0x2b, 0x71, - 0xdd, 0x8f, 0xc6, 0x04, 0x2a, 0xdc, 0xcd, 0x2e, 0x31, 0x73, 0x16, 0xe6, - 0x03, 0xa2, 0x20, 0x65, 0x17, 0x2a, 0xf1, 0x05, 0x61, 0xca, 0x4d, 0x51, - 0x39, 0x73, 0xf2, 0xd9, 0x24, 0x93, 0x3a, 0x19, 0x1b, 0x79, 0xec, 0xb3, - 0xb5, 0xb1, 0xb8, 0xf1, 0xbb, 0xff, 0x2a, 0x48, 0xfb, 0xe5, 0xb6, 0x2e, - 0x76, 0x78, 0xa5, 0x18, 0xd6, 0x70, 0x7d, 0x4b, 0x4b, 0x8d, 0x05, 0xa3, - 0x79, 0x19, 0xb6, 0x42, 0x3b, 0xf4, 0x06, 0x5c, 0xde, 0xd7, 0x7f, 0x29, - 0x37, 0xc4, 0x76, 0xf7, 0xf8, 0x5d, 0xdd, 0x46, 0xde, 0xc4, 0x49, 0xba, - 0xd6, 0xde, 0x8e, 0x56, 0x5e, 0xfc, 0x4e, 0x6d, 0x81, 0x92, 0x1e, 0x4f, - 0xbb, 0xce, 0x0b, 0x52, 0x28, 0x46, 0xc1, 0xaa, 0x76, 0xd4, 0xde, 0xf8, - 0x13, 0x63, 0xb4, 0x56, 0xdc, 0xfa, 0x59, 0xfc, 0x20, 0xa8, 0xd4, 0xa6, - 0xdb, 0x16, 0x60, 0xb7, 0xfe, 0x59, 0x3c, 0xdb, 0x6c, 0xfb, 0x94, 0x63, - 0xf6, 0x97, 0x62, 0x9d, 0x4e, 0x46, 0x70, 0x96, 0x9f, 0x38, 0xb0, 0xd8, - 0x37, 0x4c, 0xff, 0x47, 0x0b, 0x2b, 0x70, 0x4c, 0x96, 0x3e, 0x75, 0x66, - 0xf7, 0xb8, 0x7e, 0xbc, 0x8e, 0xa8, 0x6a, 0xac, 0x77, 0x72, 0x42, 0xb9, - 0x0c, 0xfa, 0x5f, 0x8a, 0x64, 0x76, 0x0a, 0x6e, 0x92, 0xcc, 0x29, 0xa9, - 0x54, 0x81, 0x1d, 0x91, 0xca, 0x14, 0x20, 0x9b, 0xf6, 0xb7, 0x6d, 0xa3, - 0xb0, 0x48, 0x64, 0x93, 0xdb, 0x00, 0xa1, 0x0a, 0x43, 0x01, 0x0b, 0x94, - 0x65, 0xcb, 0x0f, 0xb8, 0xfc, 0x69, 0xa1, 0x0b, 0x18, 0x9d, 0xd0, 0xbc, - 0x71, 0x14, 0x03, 0x32, 0xbe, 0x86, 0xdb, 0xf7, 0x93, 0xc2, 0xa9, 0x84, - 0x7c, 0xe1, 0xb3, 0xab, 0x05, 0x9a, 0x4a, 0x1f, 0xe1, 0xc4, 0x7e, 0x53, - 0xac, 0xe3, 0x8e, 0x74, 0x09, 0x67, 0x6d, 0x95, 0x7e, 0x39, 0xcb, 0x8b, - 0xe2, 0x21, 0xac, 0x54, 0x53, 0x87, 0xea, 0x8b, 0x44, 0x97, 0xed, 0xed, - 0x57, 0x8e, 0xac, 0x03, 0xf8, 0x3d, 0x12, 0x77, 0x70, 0x88, 0x8d, 0xfa, - 0x7e, 0x96, 0x7e, 0x9e, 0x92, 0x31, 0x82, 0x7b, 0x99, 0x4e, 0xf4, 0xff, - 0x03, 0x34, 0xa4, 0x8b, 0x3a, 0x47, 0x67, 0x93, 0x70, 0xe6, 0xf1, 0x38, - 0x6a, 0xca, 0x27, 0xe5, 0xfd, 0xd7, 0x11, 0xa7, 0x4d, 0x85, 0x38, 0x83, - 0xfe, 0x05, 0xab, 0x5f, 0x37, 0x38, 0xd5, 0x25, 0x38, 0xdf, 0x66, 0x52, - 0x72, 0x74, 0x48, 0x5c, 0xb2, 0xc1, 0x9a, 0x9e, 0xb1, 0x2f, 0x50, 0x6e, - 0x12, 0xaf, 0x1c, 0xe4, 0xcc, 0xa5, 0x4d, 0x46, 0x30, 0x7b, 0x4c, 0xec, - 0x83, 0x97, 0xee, 0x92, 0x57, 0x29, 0xfc, 0x06, 0xda, 0x90, 0xde, 0x39, - 0xaa, 0x6f, 0x7d, 0x6c, 0x83, 0xd9, 0x5f, 0x27, 0xa7, 0xb5, 0x56, 0x62, - 0x3d, 0x2b, 0xa6, 0x7b, 0xfa, 0xc7, 0x90, 0x5f, 0x3c, 0xe4, 0xf3, 0x87, - 0x1b, 0x3e, 0xa3, 0xcc, 0x99, 0xfb, 0xf7, 0x4d, 0x2f, 0x95, 0xf1, 0x17, - 0xe2, 0x17, 0xc1, 0x78, 0x0a, 0x2e, 0x78, 0x8f, 0x45, 0x7d, 0x2b, 0xf3, - 0x75, 0xf1, 0x31, 0x24, 0xa3, 0x95, 0x12, 0x66, 0x98, 0xe0, 0x66, 0x5d, - 0x56, 0x6f, 0xe7, 0xed, 0x80, 0x80, 0x4c, 0xcd, 0x93, 0x55, 0xf3, 0xc6, - 0x3f, 0xce, 0xc8, 0x97, 0x5b, 0x9e, 0x07, 0x91, 0xbb, 0x7f, 0xb8, 0xbd, - 0xc6, 0xd6, 0x09, 0x5c, 0xe8, 0x1a, 0xb8, 0xe1, 0x0e, 0xc5, 0x61, 0x07, - 0x48, 0x02, 0x85, 0x13, 0x28, 0x3f, 0xe3, 0x9e, 0x7a, 0x4f, 0xac, 0x72, - 0x0b, 0x50, 0xaa, 0x03, 0xfa, 0x5c, 0x81, 0x9c, 0xaa, 0x11, 0xea, 0x85, - 0x06, 0x1c, 0x05, 0x08, 0x8d, 0x10, 0xc3, 0x41, 0x23, 0x8c, 0x21, 0x7e, - 0xa1, 0x7b, 0x05, 0xa3, 0x21, 0x83, 0x1a, 0x66, 0x8c, 0x80, 0xb6, 0xe6, - 0x27, 0x7c, 0xe6, 0xaf, 0x7d, 0xca, 0x67, 0x0d, 0x35, 0xe6, 0xd6, 0x5d, - 0xbf, 0xac, 0x9f, 0x1e, 0x2e, 0x22, 0x9f, 0xf2, 0xbe, 0xbc, 0xf9, 0xf5, - 0x43, 0xf9, 0x40, 0xb6, 0x8e, 0xbb, 0xbd, 0xf4, 0x44, 0x5d, 0x31, 0xac, - 0xbc, 0xdc, 0x5a, 0xfa, 0x81, 0x14, 0x39, 0x74, 0xda, 0x9d, 0xbb, 0xc0, - 0x99, 0xfd, 0xca, 0xe0, 0xcb, 0xff, 0x59, 0xe1, 0xd5, 0x2b, 0xb6, 0x59, - 0x0f, 0xf7, 0x50, 0x69, 0x69, 0xb6, 0x52, 0x3b, 0x1b, 0x33, 0x31, 0xd7, - 0xf2, 0x91, 0xed, 0xc2, 0x46, 0xd0, 0x4d, 0x2a, 0xbe, 0x25, 0xdf, 0x49, - 0x4e, 0x07, 0xb9, 0x49, 0x91, 0xc5, 0xc3, 0x4f, 0x49, 0x9c, 0x05, 0xdd, - 0x10, 0x50, 0xb6, 0x78, 0x4d, 0xe4, 0x79, 0x51, 0x95, 0x68, 0x59, 0x18, - 0x60, 0x07, 0x77, 0x0f, 0x5d, 0x9e, 0xaf, 0x54, 0x78, 0x1f, 0xea, 0x65, - 0x02, 0x60, 0xb0, 0x71, 0xb5, 0xe0, 0x6d, 0x17, 0x3b, 0xaa, 0xe2, 0xe3, - 0x5b, 0x20, 0x5f, 0x3b, 0xa6, 0x4c, 0x00, 0xe8, 0xae, 0xdb, 0xa7, 0x04, - 0xd3, 0x2d, 0x5c, 0xf8, 0x56, 0x3d, 0x9e, 0x7a, 0xe3, 0x16, 0x51, 0x68, - 0x71, 0xa6, 0xdd, 0x39, 0x43, 0xbe, 0x97, 0xbb, 0xfe, 0xf2, 0x31, 0x42, - 0x9d, 0xda, 0x7b, 0xe5, 0x8b, 0x2e, 0x33, 0x89, 0x1e, 0x2f, 0xa5, 0xe6, - 0x20, 0xf6, 0x4c, 0x30, 0xf3, 0x62, 0x5f, 0x9a, 0xad, 0x10, 0xae, 0xef, - 0x9e, 0xb6, 0x29, 0x9a, 0xcb, 0x4c, 0xe7, 0xb7, 0x33, 0x9a, 0xa2, 0x84, - 0x61, 0x2f, 0xef, 0x19, 0xc9, 0x18, 0x2f, 0xf0, 0x8c, 0xe3, 0x79, 0x7d, - 0x2c, 0x8a, 0xfb, 0xf0, 0xa1, 0x0b, 0x9a, 0x57, 0xa6, 0x51, 0x60, 0x0f, - 0x9d, 0x04, 0x1a, 0xfc, 0x6c, 0x84, 0xd4, 0xcd, 0xc0, 0xbd, 0x2f, 0x05, - 0x54, 0x7a, 0x02, 0x25, 0xf6, 0x5c, 0xb8, 0xfa, 0xfb, 0xdc, 0x61, 0xc5, - 0x03, 0x15, 0x98, 0x58, 0xbf, 0xa1, 0x1a, 0x92, 0xc5, 0x6f, 0x04, 0x5a, - 0x12, 0xc9, 0x81, 0x9b, 0x13, 0xf6, 0x12, 0x09, 0xa6, 0x44, 0x91, 0x55, - 0x43, 0x5b, 0x7c, 0x5f, 0xe2, 0xb8, 0xff, 0x73, 0x79, 0x93, 0xd5, 0x8f, - 0x1d, 0x95, 0xff, 0x95, 0xaa, 0x43, 0xe0, 0x28, 0xdd, 0xdd, 0x60, 0x06, - 0xa5, 0x2f, 0x73, 0x55, 0x8d, 0xfd, 0x86, 0xca, 0xc8, 0xcd, 0xc4, 0x16, - 0x36, 0xad, 0x37, 0x18, 0x4e, 0x6a, 0xe1, 0x50, 0xc4, 0xe0, 0xe6, 0x85, - 0x2c, 0x89, 0xa9, 0x2f, 0xc4, 0x6e, 0x3a, 0x3c, 0x05, 0x90, 0x23, 0x25, - 0xea, 0x5f, 0xe6, 0x77, 0x56, 0x57, 0x3c, 0xa3, 0x11, 0x0c, 0x7c, 0x93, - 0x5a, 0x13, 0x3b, 0x39, 0x2d, 0x33, 0x22, 0x2e, 0xec, 0xd1, 0x06, 0x59, - 0x9f, 0x68, 0xa8, 0xc7, 0xbf, 0x19, 0xb4, 0x35, 0xa0, 0xc9, 0xd8, 0x2b, - 0x21, 0xf2, 0xa8, 0x7d, 0x82, 0x23, 0x9c, 0x46, 0x33, 0x77, 0x3b, 0x80, - 0x19, 0x42, 0x76, 0x0c, 0x12, 0x72, 0x74, 0x65, 0xa8, 0xba, 0x3e, 0xd7, - 0xe6, 0x90, 0xeb, 0x58, 0x57, 0xd4, 0x36, 0xea, 0xca, 0x8f, 0x6c, 0x04, - 0xae, 0xba, 0x32, 0xb6, 0xca, 0x92, 0x0b, 0x4b, 0x00, 0x6a, 0xc7, 0xf2, - 0x25, 0xf9, 0x8d, 0x61, 0x4f, 0xb3, 0x71, 0xb7, 0xb3, 0x47, 0xe3, 0x0a, - 0xf1, 0xd4, 0x61, 0xc7, 0x7c, 0xfa, 0x3a, 0xed, 0x2a, 0x09, 0x44, 0xe0, - 0x0d, 0x5f, 0x86, 0x1e, 0x74, 0x97, 0x74, 0x41, 0x84, 0xd9, 0xf3, 0x71, - 0xe1, 0xd5, 0x37, 0x07, 0xf4, 0x37, 0xf9, 0xee, 0xf5, 0x34, 0x7d, 0x64, - 0x34, 0x8d, 0xb9, 0x4c, 0xc6, 0x2f, 0xf2, 0x04, 0xc7, 0x91, 0x52, 0x31, - 0xe0, 0x36, 0x1e, 0x90, 0x96, 0xcb, 0x49, 0x44, 0xb7, 0x97, 0x89, 0x7d, - 0x25, 0xf6, 0xda, 0x1a, 0x9f, 0x96, 0xfd, 0x36, 0xb6, 0xc9, 0x7a, 0xe3, - 0x40, 0xc1, 0x01, 0x65, 0x95, 0x50, 0x5b, 0xa9, 0x98, 0x33, 0x26, 0xa5, - 0xa2, 0x65, 0x6f, 0x30, 0x34, 0x7b, 0x53, 0x65, 0xc2, 0xa0, 0x00, 0x6b, - 0x6a, 0x28, 0x8d, 0xff, 0x18, 0x1a, 0x9a, 0xc5, 0xf3, 0x9b, 0xc9, 0x66, - 0xa8, 0x5d, 0x9e, 0xe2, 0x63, 0x62, 0xec, 0x4b, 0xcb, 0xdb, 0xae, 0xf2, - 0x3a, 0x69, 0x12, 0x9b, 0x1b, 0xa3, 0x95, 0x37, 0x09, 0x3d, 0xd5, 0x84, - 0xa0, 0x93, 0xc2, 0x2b, 0x28, 0x61, 0x46, 0xbf, 0xd5, 0x50, 0x3a, 0x6b, - 0xe9, 0xc6, 0x0d, 0xa6, 0x02, 0x92, 0xd3, 0xf4, 0x62, 0x55, 0x55, 0xc0, - 0x4f, 0x9a, 0x34, 0x63, 0x74, 0x5b, 0x43, 0xba, 0x7b, 0xad, 0xf9, 0x3d, - 0xe6, 0x54, 0x38, 0x2e, 0x94, 0xb7, 0x59, 0xf2, 0xcf, 0x7e, 0xd9, 0x0f, - 0x3a, 0xfd, 0xa7, 0xfd, 0xc6, 0x81, 0xa0, 0x24, 0x34, 0x10, 0x6c, 0x82, - 0xff, 0xc9, 0x34, 0xd7, 0xe5, 0xa1, 0x61, 0x51, 0xe4, 0x48, 0x4d, 0x75, - 0x04, 0x4a, 0xef, 0x48, 0xb7, 0xec, 0xeb, 0xec, 0xe2, 0x0c, 0x9a, 0x1c, - 0x84, 0x90, 0x4f, 0x03, 0x5d, 0xe7, 0x94, 0x7c, 0xea, 0xb6, 0xd5, 0x20, - 0x9a, 0x5b, 0xe7, 0x69, 0xda, 0x1b, 0x02, 0x8a, 0x61, 0x55, 0x3a, 0x98, - 0xf3, 0xf3, 0x7d, 0x3c, 0x91, 0x0c, 0x90, 0x2b, 0xa0, 0x1f, 0x19, 0x12, - 0x29, 0x0d, 0xe8, 0x16, 0x8d, 0x2c, 0x78, 0xc9, 0x30, 0x94, 0x49, 0xbe, - 0x80, 0x06, 0xcf, 0xe9, 0xb8, 0x1c, 0x66, 0xfe, 0x4a, 0xd8, 0x23, 0x96, - 0x76, 0xd8, 0x29, 0xbc, 0x67, 0x1c, 0xae, 0xaa, 0xc7, 0x32, 0x6b, 0x4d, - 0x1a, 0x12, 0xe4, 0x81, 0x36, 0x8b, 0x09, 0x65, 0xf7, 0x88, 0xf8, 0x30, - 0xdf, 0x08, 0x08, 0x57, 0xed, 0xc7, 0xf3, 0x48, 0x7a, 0x07, 0x17, 0x8f, - 0x3c, 0x65, 0x03, 0xcf, 0x5e, 0x61, 0xa1, 0x19, 0x9b, 0x41, 0x74, 0xfb, - 0x0e, 0x37, 0xdd, 0xeb, 0xd3, 0xc2, 0x50, 0xd7, 0x28, 0x80, 0xba, 0xc2, - 0xb2, 0x58, 0xf6, 0x2b, 0x4f, 0x7a, 0xe3, 0x8a, 0xe4, 0xb3, 0x77, 0x53, - 0x00, 0x2f, 0xe8, 0x51, 0xe1, 0x1a, 0x41, 0x17, 0x12, 0x87, 0x64, 0xb7, - 0x3d, 0x50, 0x95, 0x9a, 0x08, 0xba, 0x55, 0xb1, 0x02, 0xa4, 0x9f, 0x08, - 0xd9, 0xc8, 0x0f, 0x96, 0x7a, 0x0b, 0xba, 0x1f, 0x28, 0x70, 0x9c, 0x79, - 0x64, 0x6c, 0x94, 0xf3, 0x65, 0x5f, 0xa7, 0x83, 0x7b, 0x75, 0xfe, 0x7c, - 0xfd, 0x6e, 0x8c, 0x5f, 0xa5, 0xd0, 0x11, 0x8b, 0xd5, 0x81, 0x89, 0x9b, - 0x1f, 0x59, 0xcb, 0x9a, 0x6b, 0x0e, 0x7b, 0xae, 0x86, 0x3e, 0x4e, 0x3c, - 0x48, 0x0d, 0x82, 0x5a, 0xe3, 0x65, 0xf0, 0xb0, 0xa2, 0x03, 0xf8, 0x2c, - 0xc3, 0xf3, 0xca, 0x41, 0xfa, 0xb7, 0x84, 0x42, 0x70, 0x68, 0x6e, 0xfb, - 0x77, 0x93, 0xf3, 0xcf, 0xdf, 0x62, 0x66, 0xce, 0xfa, 0xed, 0x7c, 0xb3, - 0x4a, 0x09, 0x2d, 0x57, 0x70, 0x8a, 0x83, 0x51, 0x94, 0xa1, 0x38, 0xf9, - 0xbe, 0xa4, 0x02, 0xae, 0x89, 0x15, 0xd8, 0xb6, 0xf7, 0x5f, 0x54, 0xc9, - 0xe9, 0xd4, 0x84, 0x11, 0x03, 0xc8, 0xe6, 0xb6, 0x6c, 0x07, 0x6a, 0xf3, - 0x80, 0x00, 0xd0, 0xfe, 0x07, 0x9c, 0x52, 0x17, 0x3d, 0x1d, 0x9e, 0x89, - 0x40, 0x31, 0xfc, 0xfd, 0x30, 0x91, 0x19, 0x4d, 0x01, 0xe5, 0x47, 0x33, - 0x06, 0x7f, 0xce, 0xda, 0x49, 0x33, 0x43, 0xa6, 0x21, 0xfb, 0x74, 0x21, - 0xd9, 0xa8, 0xa7, 0x0f, 0xd2, 0x42, 0x84, 0x0b, 0xff, 0x37, 0xdc, 0x88, - 0x6b, 0x11, 0x0a, 0xed, 0xfa, 0x45, 0x60, 0x3f, 0x01, 0x51, 0xf1, 0x9c, - 0x61, 0x17, 0xcf, 0x57, 0x1e, 0x21, 0xb4, 0xfe, 0x5d, 0xa0, 0xcb, 0x73, - 0xf3, 0x85, 0x72, 0x60, 0x83, 0xd8, 0x87, 0x9f, 0xb4, 0x1d, 0xfe, 0xaa, - 0x42, 0xb6, 0xfe, 0x9d, 0x3c, 0xf8, 0x74, 0xd2, 0xf2, 0x49, 0x8c, 0xa1, - 0xa9, 0x71, 0x00, 0xa9, 0x63, 0xec, 0xb9, 0x01, 0x1a, 0xd0, 0xd4, 0x6e, - 0xe5, 0x8c, 0xeb, 0xfa, 0xb0, 0x99, 0x1b, 0x2c, 0xa8, 0x73, 0x2e, 0x68, - 0xc4, 0xd2, 0x28, 0x18, 0xce, 0x2d, 0x0b, 0x1d, 0x09, 0xa6, 0xcd, 0x9c, - 0xaa, 0xf2, 0x34, 0xe6, 0xb7, 0xf1, 0x89, 0xc0, 0xbf, 0x5f, 0x84, 0xca, - 0xa9, 0x28, 0x1c, 0x5b, 0xc1, 0xda, 0x80, 0xc8, 0x5f, 0xb2, 0x50, 0x13, - 0xab, 0x89, 0x5e, 0xa3, 0x03, 0x27, 0x7d, 0xcc, 0xf7, 0x4a, 0x53, 0x26, - 0xdf, 0x83, 0x09, 0xaa, 0xbc, 0xfb, 0x15, 0x8b, 0x04, 0x0b, 0x07, 0x2e, - 0x20, 0x78, 0x39, 0xf9, 0x02, 0x67, 0xd0, 0x8e, 0x19, 0x25, 0x39, 0x89, - 0xcb, 0xde, 0x17, 0xba, 0x57, 0x1f, 0x36, 0xc9, 0xee, 0xe3, 0xf0, 0x39, - 0x6e, 0xee, 0xc4, 0xc8, 0x49, 0x69, 0xf6, 0x21, 0xdf, 0xd7, 0x1d, 0x52, - 0x6d, 0xd3, 0xf8, 0x23, 0xe9, 0x5e, 0xe5, 0x34, 0x7f, 0xcf, 0xa6, 0x63, - 0x99, 0xce, 0xf5, 0xd0, 0xc3, 0xbc, 0xa6, 0xef, 0x6f, 0x38, 0xcb, 0x51, - 0x8e, 0xbd, 0xc4, 0x31, 0x19, 0x89, 0xdf, 0x05, 0xf9, 0xfa, 0xbc, 0xfa, - 0x1d, 0x4a, 0x10, 0xcb, 0xd4, 0xba, 0xe5, 0xa6, 0x42, 0xa9, 0xc9, 0x34, - 0x74, 0x13, 0xbd, 0xdc, 0x12, 0x04, 0x6c, 0xa6, 0xe7, 0x42, 0x4b, 0x78, - 0xba, 0x39, 0x19, 0xdb, 0x06, 0xcf, 0xf7, 0xfb, 0x71, 0x6a, 0x26, 0x76, - 0x2d, 0x78, 0xf8, 0xc5, 0x52, 0x58, 0x30, 0x65, 0xea, 0x7f, 0xdd, 0x81, - 0x03, 0xa4, 0x33, 0x1b, 0x1b, 0xc5, 0x98, 0x96, 0xd5, 0xf7, 0x61, 0x8d, - 0x9e, 0x60, 0x93, 0x5e, 0x79, 0x0a, 0x3d, 0xe6, 0x67, 0x37, 0x55, 0x18, - 0x36, 0xb4, 0xfe, 0x79, 0xd5, 0xd3, 0xf0, 0xd7, 0x06, 0x09, 0xcc, 0x03, - 0x2a, 0x2c, 0x3b, 0xf6, 0xec, 0x5f, 0xaa, 0x8e, 0x7b, 0x57, 0x94, 0xac, - 0x60, 0x74, 0xaa, 0x5d, 0x92, 0x33, 0xd0, 0x4d, 0x74, 0xe1, 0x8e, 0x41, - 0x62, 0x13, 0x0d, 0x2c, 0x1e, 0xc5, 0x4d, 0xaa, 0xd8, 0x56, 0x9a, 0x02, - 0x69, 0x9c, 0x72, 0x00, 0x93, 0x25, 0x35, 0x62, 0x8d, 0xc4, 0xfe, 0xaa, - 0x02, 0x5a, 0x95, 0xaa, 0x79, 0x10, 0x54, 0xcd, 0xd9, 0x21, 0xfb, 0x72, - 0x22, 0xa4, 0x7d, 0x18, 0x98, 0x16, 0x66, 0x40, 0x96, 0xd8, 0xe8, 0x77, - 0x79, 0x70, 0x3e, 0x0b, 0x75, 0xec, 0x9c, 0x04, 0xcf, 0x4d, 0x26, 0xa4, - 0xf5, 0x09, 0xf2, 0x88, 0x85, 0xcc, 0x29, 0x6a, 0xe1, 0x0a, 0xc2, 0x54, - 0xef, 0x0b, 0x8c, 0x66, 0x92, 0x85, 0xc7, 0x05, 0x8a, 0xce, 0xb9, 0x36, - 0x6e, 0xcd, 0xd5, 0xee, 0xcb, 0x6d, 0x7a, 0x2b, 0x17, 0xe0, 0x0b, 0xa7, - 0xfe, 0x5c, 0x71, 0xd9, 0xe3, 0x4d, 0x61, 0x41, 0xef, 0x83, 0xd5, 0x55, - 0xda, 0x9a, 0x65, 0xdb, 0xa7, 0x51, 0x80, 0xee, 0xe5, 0x40, 0x0b, 0xd8, - 0x1d, 0x19, 0xab, 0x16, 0xbc, 0xd0, 0x4a, 0x64, 0x60, 0xeb, 0x5d, 0xa2, - 0xf7, 0x10, 0x6b, 0x79, 0xc5, 0x23, 0x78, 0xdd, 0x38, 0xa9, 0x5e, 0x8e, - 0xc8, 0xac, 0x2c, 0xdd, 0x40, 0xc2, 0xef, 0x26, 0x24, 0xa8, 0x80, 0x47, - 0x59, 0xc3, 0x9f, 0x9c, 0xfa, 0x6a, 0xb1, 0xaa, 0x8c, 0xf9, 0x05, 0x44, - 0x11, 0xaf, 0x82, 0xca, 0xb6, 0x47, 0x53, 0x70, 0xd8, 0xa2, 0x55, 0xe1, - 0x9f, 0xb9, 0x6a, 0xbe, 0x6c, 0x6c, 0x2d, 0x52, 0xd0, 0x2d, 0x95, 0x1d, - 0x95, 0x06, 0x0e, 0x61, 0x83, 0x99, 0x28, 0xba, 0x01, 0xff, 0xc6, 0x8f, - 0x98, 0xc5, 0x5f, 0x9a, 0xff, 0x20, 0x29, 0x3f, 0xea, 0x9e, 0x34, 0xa8, - 0x53, 0x98, 0xe6, 0x85, 0x32, 0x0b, 0xd2, 0x57, 0x4b, 0xa4, 0xf0, 0x9b, - 0x40, 0x69, 0x7f, 0xf4, 0xc2, 0xe0, 0xcd, 0x94, 0xf3, 0xb3, 0xa5, 0xb5, - 0xb6, 0xd8, 0xf4, 0x7b, 0x54, 0xbd, 0x79, 0xc4, 0xab, 0x9f, 0xf5, 0x26, - 0x2a, 0x8e, 0xe7, 0xe9, 0x60, 0x35, 0xc4, 0xba, 0x53, 0x1f, 0x17, 0x9c, - 0x35, 0xe8, 0xb2, 0x9d, 0x2b, 0xd7, 0x57, 0x8a, 0x2d, 0x39, 0x37, 0x2c, - 0x00, 0x4c, 0x12, 0x89, 0x6a, 0xe3, 0x77, 0x87, 0x8f, 0xad, 0xc9, 0x51, - 0xcd, 0x27, 0x3f, 0xd7, 0x84, 0xd8, 0x46, 0x00, 0x19, 0x21, 0x90, 0x63, - 0xc7, 0xf3, 0xae, 0xe0, 0xba, 0xb9, 0xb4, 0xa1, 0x5f, 0x2a, 0x83, 0xbe, - 0x21, 0xde, 0xe4, 0x85, 0x48, 0x19, 0x68, 0xad, 0x93, 0xd8, 0xa6, 0x18, - 0x10, 0x11, 0xa2, 0xd1, 0xf9, 0x1d, 0xe8, 0xde, 0x5b, 0x3d, 0x3a, 0x36, - 0x03, 0x61, 0xc8, 0x3c, 0x86, 0x1f, 0xfc, 0xfc, 0xa7, 0xcc, 0xa7, 0xdf, - 0x86, 0xbc, 0xac, 0xcb, 0x8a, 0xc5, 0x40, 0x99, 0xcc, 0xc9, 0x27, 0xe9, - 0xa5, 0xc1, 0x12, 0x16, 0x48, 0xd0, 0x7c, 0x94, 0xb8, 0x2e, 0xe6, 0xbe, - 0x4e, 0xea, 0xca, 0x52, 0xbd, 0x03, 0xe7, 0xde, 0x8c, 0x72, 0x24, 0x09, - 0xe2, 0xd7, 0xa0, 0xe9, 0xc7, 0x10, 0x28, 0xbb, 0x94, 0x65, 0x34, 0x34, - 0x0c, 0x73, 0xe7, 0xe6, 0x7d, 0x81, 0x59, 0xf7, 0xf9, 0xc5, 0xf4, 0x22, - 0xd2, 0x21, 0xf9, 0x77, 0x5f, 0xcc, 0x51, 0x87, 0x59, 0xa0, 0x58, 0x45, - 0x18, 0x70, 0xc6, 0xae, 0x8d, 0x94, 0xe5, 0x04, 0x83, 0x14, 0x2a, 0x00, - 0x5d, 0x7f, 0x63, 0x68, 0x9c, 0xed, 0x5b, 0xc1, 0x54, 0x43, 0xe0, 0x12, - 0xa0, 0x97, 0xb5, 0x9d, 0xcf, 0xc5, 0x85, 0xd6, 0xa0, 0xae, 0x07, 0x8e, - 0x5d, 0x4d, 0x0b, 0xb0, 0x97, 0xbd, 0x2c, 0x9c, 0x2c, 0xf9, 0xb2, 0xd7, - 0x8d, 0x6d, 0xba, 0xf6, 0x27, 0x5a, 0xa8, 0x3e, 0xc9, 0xbb, 0x03, 0xd1, - 0xb1, 0xf1, 0x15, 0x46, 0x57, 0xe7, 0x95, 0xa5, 0x4f, 0x49, 0xb5, 0x01, - 0x96, 0x8c, 0xd9, 0x58, 0x66, 0xd6, 0xfb, 0x82, 0xed, 0x2d, 0xc2, 0x7e, - 0xa6, 0xca, 0x91, 0x29, 0x84, 0xf3, 0xbd, 0xb6, 0x1e, 0xf3, 0x5e, 0xdf, - 0xfa, 0x0f, 0x43, 0x54, 0x37, 0xbc, 0x43, 0x9a, 0xaf, 0x24, 0xa4, 0x18, - 0xdb, 0x3f, 0xe4, 0x64, 0x6c, 0x32, 0x75, 0xc8, 0x6d, 0x38, 0xdc, 0x60, - 0x1b, 0xbe, 0x0d, 0x5b, 0x30, 0x11, 0xda, 0x33, 0xac, 0x84, 0x96, 0x7d, - 0x1d, 0x7a, 0x02, 0x4f, 0x98, 0x5f, 0x8a, 0xa8, 0x26, 0xa0, 0xaa, 0x4b, - 0x8d, 0xdc, 0xbc, 0xf5, 0x63, 0xac, 0xf5, 0x90, 0x5f, 0x17, 0xaa, 0x04, - 0x8d, 0xe2, 0x8e, 0x16, 0x1d, 0xfd, 0x76, 0xfd, 0x64, 0x42, 0xbc, 0x99, - 0x01, 0x7c, 0xb9, 0x28, 0xc9, 0xe1, 0xa5, 0x4c, 0xed, 0x5e, 0x2b, 0xd7, - 0x61, 0x60, 0xa5, 0xdc, 0xf4, 0xb3, 0x9a, 0x9e, 0xbf, 0xa0, 0xbe, 0x16, - 0xb6, 0x15, 0xf5, 0x71, 0xe0, 0x56, 0xd7, 0x15, 0x71, 0x51, 0x4a, 0x6d, - 0x7d, 0x74, 0xea, 0x4b, 0xe7, 0x2b, 0xc5, 0x49, 0x1a, 0x96, 0xbb, 0x66, - 0xc7, 0xfb, 0xcb, 0xb9, 0x2f, 0xcf, 0x5d, 0xad, 0x07, 0x7d, 0xcf, 0x48, - 0x90, 0xde, 0xeb, 0x5a, 0x18, 0x69, 0x65, 0xdd, 0x80, 0xcd, 0x76, 0x28, - 0x4c, 0xce, 0x11, 0x94, 0x46, 0xd4, 0x3e, 0x2a, 0x3c, 0xa8, 0xf2, 0xc1, - 0x49, 0x3c, 0x2a, 0x5a, 0x2f, 0x8f, 0x99, 0x01, 0xb8, 0x2d, 0xdf, 0x42, - 0x7f, 0xc4, 0x1e, 0x7e, 0xdc, 0xd6, 0xb4, 0x60, 0x44, 0xaa, 0x50, 0xfa, - 0xa1, 0x47, 0xa6, 0x90, 0xa7, 0x0f, 0x8a, 0xef, 0xcd, 0x40, 0x7d, 0x14, - 0x08, 0x4f, 0x21, 0x50, 0x47, 0xea, 0x69, 0x5a, 0x36, 0x1c, 0x03, 0x54, - 0xde, 0x66, 0xce, 0x61, 0x02, 0xf7, 0xa5, 0xb1, 0x70, 0x55, 0x4e, 0x04, - 0xba, 0x1e, 0xc3, 0x1e, 0xa2, 0x92, 0x4c, 0xfd, 0x32, 0x96, 0x0e, 0x58, - 0x35, 0x0a, 0x0d, 0xc7, 0xe8, 0x5b, 0x02, 0x73, 0x37, 0xd3, 0x34, 0x85, - 0x72, 0x6b, 0x4f, 0x38, 0x01, 0x86, 0x68, 0xb5, 0xc7, 0x31, 0xc0, 0xa8, - 0xf2, 0x0a, 0x37, 0x63, 0xb5, 0x97, 0x27, 0x4f, 0x53, 0x74, 0x96, 0xc5, - 0xa1, 0x3e, 0xcc, 0x11, 0x72, 0xc7, 0x81, 0x81, 0x17, 0xff, 0x42, 0xbe, - 0x29, 0xdc, 0xe5, 0x37, 0x09, 0xfb, 0xd3, 0x5d, 0x5d, 0x1f, 0x64, 0xcc, - 0xdd, 0x1c, 0xcc, 0x98, 0x00, 0xd9, 0x09, 0x60, 0x79, 0x1c, 0xd4, 0xb7, - 0xa5, 0x44, 0x39, 0xbb, 0x2c, 0xda, 0x5b, 0xf2, 0xb0, 0xbc, 0x32, 0xa9, - 0xed, 0xd9, 0xb4, 0xab, 0x84, 0xf1, 0xb6, 0xab, 0xc3, 0x4d, 0x1a, 0x69, - 0xa4, 0xbd, 0xeb, 0x4b, 0x64, 0x9d, 0xbc, 0x8c, 0xfe, 0xf2, 0xb3, 0x1c, - 0x61, 0x24, 0x7f, 0xc7, 0x87, 0xea, 0x51, 0xcb, 0xfb, 0xe2, 0x67, 0x21, - 0xde, 0x03, 0x66, 0x68, 0xe0, 0x5d, 0x0a, 0x0a, 0xdc, 0x79, 0x4d, 0x72, - 0xa8, 0x34, 0xec, 0xe3, 0x32, 0x2f, 0x9e, 0xcc, 0xec, 0xf8, 0x8b, 0xe6, - 0xd3, 0xe1, 0xcf, 0x02, 0x85, 0x83, 0x8e, 0x82, 0x45, 0xc7, 0x27, 0xe7, - 0xac, 0xb3, 0x54, 0x34, 0x09, 0x97, 0xe5, 0x6f, 0x13, 0x9f, 0x81, 0x97, - 0x66, 0xd6, 0xff, 0x23, 0x53, 0x07, 0x34, 0xbb, 0x1c, 0x00, 0x0c, 0x8b, - 0x67, 0xb1, 0xbe, 0x56, 0x06, 0x51, 0x29, 0x84, 0xf4, 0xd8, 0xc5, 0x43, - 0xcf, 0x21, 0x42, 0x87, 0x40, 0xbd, 0xf3, 0xec, 0x53, 0x2c, 0x3f, 0xc9, - 0x1e, 0xda, 0xe8, 0x93, 0x2b, 0x44, 0xe0, 0x73, 0x63, 0x44, 0x74, 0x68, - 0x46, 0x3a, 0x3f, 0x5f, 0xb7, 0x35, 0xe3, 0x07, 0x5d, 0x78, 0xd6, 0x42, - 0xa3, 0xf6, 0xcd, 0xd0, 0xb9, 0x9c, 0x46, 0x71, 0x88, 0xdf, 0x91, 0x57, - 0x47, 0x59, 0xed, 0x69, 0x5f, 0xb8, 0x91, 0xfb, 0x6c, 0x8e, 0x78, 0x53, - 0x57, 0x69, 0xca, 0xc2, 0xab, 0x0c, 0x19, 0x2e, 0x3a, 0x22, 0x85, 0xce, - 0xc7, 0x69, 0x17, 0x20, 0x37, 0x7f, 0xd8, 0x41, 0x86, 0xcd, 0x0f, 0xf2, - 0x25, 0x5c, 0xeb, 0x49, 0x05, 0x78, 0x4b, 0x63, 0x31, 0x11, 0xbd, 0x9b, - 0xfd, 0xb6, 0x9d, 0x45, 0x91, 0x94, 0xa0, 0x03, 0x47, 0xfe, 0x25, 0x5d, - 0x6d, 0x4f, 0xc7, 0x65, 0xed, 0x89, 0xe0, 0xd5, 0xcd, 0x1b, 0xf7, 0xf5, - 0xc4, 0x94, 0x70, 0x80, 0x2e, 0x05, 0xba, 0xb8, 0xc8, 0x61, 0x71, 0x85, - 0x1a, 0x34, 0xc9, 0xcd, 0x2c, 0x43, 0x05, 0x17, 0x58, 0x9c, 0x9e, 0xc0, - 0x35, 0x81, 0xb4, 0x61, 0xe4, 0x91, 0xa3, 0xf3, 0xee, 0x0c, 0x58, 0xcc, - 0xa2, 0x05, 0xd9, 0xa7, 0x56, 0x12, 0xb6, 0x96, 0x03, 0xca, 0x55, 0xe8, - 0x93, 0xc1, 0xa2, 0x62, 0xf1, 0x65, 0xa4, 0x44, 0x10, 0x4e, 0x3a, 0x2a, - 0xa5, 0x22, 0x1e, 0xcd, 0x9b, 0x69, 0x21, 0xb5, 0x40, 0xc2, 0x53, 0x81, - 0x8d, 0xd6, 0x7a, 0x71, 0x0d, 0x7f, 0x33, 0xb7, 0x4b, 0x7c, 0x94, 0xce, - 0xaa, 0x1c, 0x53, 0xa8, 0x61, 0x7e, 0xe8, 0x97, 0x99, 0x87, 0xbe, 0x08, - 0x82, 0x4c, 0x4a, 0x53, 0xb1, 0xb8, 0xb8, 0x71, 0x45, 0xf1, 0x95, 0xa8, - 0x78, 0x75, 0x60, 0x7e, 0xb7, 0x91, 0xcd, 0x3c, 0xa5, 0x57, 0x0e, 0x53, - 0x06, 0xa3, 0xe6, 0x48, 0x0b, 0xe1, 0xfa, 0x5f, 0x8e, 0x2e, 0xd6, 0x23, - 0x5b, 0xd8, 0x20, 0x55, 0x0c, 0x03, 0xfb, 0x25, 0x55, 0xf2, 0x96, 0x14, - 0x0a, 0xf5, 0xac, 0xbb, 0xf3, 0xc1, 0xec, 0x97, 0xaa, 0xfe, 0x00, 0x90, - 0xbc, 0x3a, 0x4c, 0x3b, 0x8b, 0xa7, 0x8b, 0xba, 0x3f, 0x8a, 0x86, 0x1b, - 0xe8, 0xe0, 0xfd, 0x87, 0x6f, 0x35, 0x51, 0x9d, 0xbd, 0x6c, 0x9c, 0xa7, - 0x3d, 0x55, 0xb1, 0x7a, 0xef, 0x69, 0xe4, 0x9e, 0x0d, 0xd7, 0x09, 0x13, - 0x0c, 0x0e, 0xb9, 0xd5, 0x8a, 0x75, 0x90, 0xaf, 0x62, 0xb1, 0xcc, 0xc7, - 0x14, 0x7c, 0x47, 0x69, 0xfc, 0xfd, 0x75, 0xa5, 0x0a, 0x32, 0xb4, 0x9f, - 0xaa, 0x19, 0x69, 0xf2, 0x2f, 0x5c, 0x0e, 0x7e, 0x2d, 0xd7, 0xab, 0xef, - 0x94, 0xee, 0x49, 0xf8, 0x08, 0x6d, 0xbe, 0xfd, 0x95, 0xbc, 0x4c, 0x99, - 0x92, 0xce, 0xb3, 0x08, 0xf0, 0xf8, 0xf5, 0x03, 0x67, 0xf9, 0x9c, 0x07, - 0x5a, 0x93, 0x1c, 0x27, 0xa8, 0x49, 0x4c, 0x18, 0x40, 0xe1, 0x88, 0x0f, - 0x6b, 0xb8, 0x95, 0xd2, 0xbc, 0x66, 0x6c, 0xa9, 0x17, 0x99, 0x51, 0xa5, - 0x9d, 0x1e, 0x7b, 0xee, 0x61, 0x0a, 0x9e, 0x0b, 0xe9, 0x33, 0xa3, 0x6e, - 0xd1, 0x58, 0xc3, 0xe5, 0xf3, 0xe8, 0x43, 0x46, 0xae, 0x3a, 0x7a, 0x25, - 0x7e, 0x62, 0xba, 0xb6, 0x19, 0x6f, 0x22, 0xb5, 0x2c, 0x28, 0x3c, 0xdd, - 0x59, 0xc0, 0x37, 0x41, 0x3f, 0x44, 0xa9, 0x73, 0x4e, 0x85, 0xd0, 0x53, - 0xf8, 0xc0, 0xd8, 0x13, 0xce, 0xcf, 0x8c, 0x4d, 0xba, 0x96, 0x2f, 0x86, - 0x06, 0xa7, 0x21, 0x5c, 0x10, 0xf8, 0xf9, 0xfc, 0x9f, 0x2a, 0x8e, 0x0f, - 0x9d, 0x7e, 0x61, 0xe0, 0x78, 0x95, 0xd5, 0x4b, 0x67, 0xc0, 0xa3, 0xa6, - 0xef, 0x20, 0x7b, 0xe5, 0x86, 0xa3, 0x47, 0xc8, 0x43, 0xd4, 0x8d, 0xa5, - 0x7a, 0x11, 0xa3, 0x9d, 0x34, 0x31, 0x72, 0xac, 0x4d, 0x1f, 0x4f, 0xbe, - 0xdf, 0xb6, 0xdb, 0x15, 0xd5, 0xdb, 0x70, 0x1f, 0x35, 0x4a, 0xea, 0x1a, - 0x3f, 0x17, 0x91, 0x94, 0xf9, 0x81, 0x14, 0x71, 0x11, 0xf0, 0xf9, 0x0f, - 0x22, 0x60, 0xb4, 0xc8, 0x1f, 0x43, 0xf4, 0x91, 0xd4, 0x54, 0x83, 0xbe, - 0x68, 0x7d, 0x11, 0xd8, 0x86, 0x75, 0x9a, 0x3e, 0x4a, 0xd1, 0x07, 0xcb, - 0x81, 0x01, 0x28, 0x1a, 0x30, 0x82, 0x3c, 0x30, 0x66, 0x33, 0x12, 0x1b, - 0x1c, 0x19, 0xb4, 0xcd, 0xc6, 0xba, 0x15, 0xd8, 0xd4, 0x87, 0xa8, 0x4e, - 0x38, 0x42, 0xb2, 0xee, 0x8a, 0x1c, 0x0a, 0xdb, 0xbd, 0x5d, 0xf7, 0x12, - 0x01, 0xc5, 0x6b, 0xcc, 0xb1, 0x4b, 0x76, 0x78, 0x87, 0x9a, 0x44, 0x35, - 0xe3, 0x2b, 0x72, 0x3c, 0x74, 0x5a, 0xfa, 0xeb, 0x29, 0x6b, 0xb0, 0x19, - 0xf9, 0x48, 0x87, 0xed, 0x7c, 0xcd, 0x6c, 0x5f, 0x85, 0xac, 0xa8, 0x9b, - 0x3e, 0x5b, 0x9e, 0x3d, 0x59, 0x62, 0x28, 0x7e, 0x5a, 0x5f, 0x85, 0xdf, - 0xe7, 0x40, 0x60, 0xf5, 0xf2, 0x41, 0xab, 0x3e, 0xf8, 0x2a, 0x4c, 0x6d, - 0xf8, 0xb4, 0x14, 0xfb, 0xbd, 0x91, 0x4e, 0x1d, 0xba, 0xa1, 0xae, 0xff, - 0xee, 0x95, 0xa7, 0xa7, 0xe2, 0x49, 0x62, 0xac, 0x87, 0x9c, 0xe5, 0xbe, - 0x29, 0xab, 0x01, 0xe8, 0xc8, 0x85, 0x87, 0xd9, 0x02, 0xbb, 0x6a, 0xa3, - 0xfa, 0xd9, 0x72, 0xdf, 0x11, 0x6f, 0xa8, 0x78, 0xb2, 0xbd, 0xdb, 0xa1, - 0x18, 0x5e, 0x9e, 0x85, 0xd7, 0x27, 0x6d, 0xd1, 0x79, 0x4d, 0x6e, 0x17, - 0xa1, 0xd6, 0x92, 0x26, 0x72, 0x37, 0xbd, 0xe5, 0x49, 0x88, 0x94, 0x5c, - 0xc2, 0x60, 0x46, 0x0f, 0x78, 0x24, 0xf1, 0x2a, 0xc1, 0x59, 0xae, 0x5e, - 0x16, 0x62, 0xee, 0xb3, 0x7e, 0x84, 0xf1, 0xab, 0xfb, 0xf5, 0x14, 0x8c, - 0x0f, 0x6b, 0x3e, 0x3d, 0x98, 0xa6, 0xe5, 0xec, 0xcc, 0x37, 0xe5, 0x91, - 0x2c, 0x76, 0x09, 0x62, 0xd4, 0xe8, 0x89, 0x84, 0xbc, 0x73, 0x7c, 0x9d, - 0x28, 0x96, 0x64, 0x57, 0x6c, 0xbf, 0x2c, 0xbf, 0x06, 0x15, 0x2a, 0xa2, - 0x0c, 0xa7, 0xf1, 0x96, 0x4c, 0x95, 0x7a, 0x97, 0x7a, 0xbc, 0xdf, 0xe6, - 0xd0, 0xc9, 0x6c, 0xca, 0xb9, 0x9e, 0x54, 0x6a, 0x4d, 0x25, 0xc3, 0x36, - 0x92, 0x06, 0x2b, 0xe4, 0x93, 0xeb, 0x27, 0x29, 0x3d, 0x05, 0x05, 0x7a, - 0xd4, 0xb0, 0xfd, 0xc0, 0xc9, 0xe1, 0x97, 0xd6, 0x5d, 0x65, 0xbb, 0xa5, - 0x5c, 0xc8, 0x51, 0xaa, 0x3c, 0x88, 0x3f, 0xa2, 0xe9, 0x11, 0x86, 0x9c, - 0x0f, 0x2a, 0x5a, 0xf2, 0x99, 0x9d, 0xcd, 0x9d, 0xc1, 0x79, 0x0a, 0xf9, - 0x7d, 0xd5, 0x36, 0xff, 0x52, 0x27, 0x47, 0x60, 0x2e, 0xa8, 0xb5, 0x58, - 0xc3, 0x47, 0x26, 0x54, 0x63, 0xa3, 0xc4, 0x64, 0x66, 0x79, 0x76, 0x8a, - 0xc1, 0xcc, 0xa3, 0x67, 0x93, 0x5d, 0xc8, 0x0b, 0x05, 0x28, 0x42, 0x51, - 0x95, 0x63, 0x45, 0x70, 0x3b, 0x9c, 0xf2, 0x93, 0xcb, 0xf3, 0xcc, 0xa2, - 0x3a, 0xe9, 0x56, 0x83, 0x1f, 0xdc, 0x56, 0xf8, 0xcc, 0x91, 0x0c, 0x7e, - 0x13, 0xbb, 0x4b, 0xe6, 0x14, 0x0d, 0xdf, 0xe5, 0xbc, 0x46, 0x04, 0x2a, - 0x1a, 0x52, 0xa0, 0xf8, 0x1d, 0xb5, 0x28, 0x78, 0xfb, 0x2d, 0x1f, 0x5e, - 0x36, 0x03, 0xd4, 0x2f, 0x3f, 0xf8, 0xf2, 0xce, 0x8e, 0xc4, 0x90, 0xa1, - 0xaa, 0xda, 0xb3, 0xc9, 0xf4, 0x7a, 0x13, 0x1a, 0x34, 0x2c, 0x54, 0xf6, - 0x19, 0x48, 0x9c, 0xef, 0xb6, 0x44, 0xa1, 0xd0, 0x25, 0xb8, 0x10, 0xd1, - 0xa9, 0x07, 0x0c, 0xb1, 0xa5, 0xb4, 0x98, 0xc8, 0x09, 0x1c, 0x2d, 0x63, - 0x67, 0xf1, 0xe6, 0x19, 0x8f, 0xd6, 0xb4, 0xeb, 0xba, 0x78, 0x96, 0xc6, - 0x5b, 0x2f, 0x3f, 0x26, 0x50, 0xd7, 0x3d, 0x1a, 0x8c, 0xdf, 0x47, 0x0d, - 0xad, 0x72, 0x93, 0xe9, 0xd3, 0x60, 0x54, 0xb4, 0xbb, 0x86, 0x94, 0xad, - 0xeb, 0xe7, 0xe8, 0x5b, 0xbb, 0x3f, 0xf7, 0xfb, 0x5d, 0xf9, 0xa2, 0x9e, - 0xbe, 0x93, 0x0c, 0x50, 0x35, 0x61, 0xce, 0x21, 0xd5, 0xf5, 0xa9, 0xc3, - 0x7c, 0x8f, 0x06, 0x87, 0xf4, 0x9b, 0x58, 0xbe, 0x5c, 0x7e, 0x12, 0xcc, - 0x4b, 0x48, 0x11, 0x4c, 0x59, 0x2a, 0x1e, 0x29, 0xc1, 0x22, 0x36, 0xa0, - 0xa4, 0x75, 0xd5, 0xcd, 0xe4, 0x79, 0xa7, 0x36, 0xe4, 0x2a, 0xe6, 0xf5, - 0x11, 0x54, 0x30, 0xdc, 0x26, 0x2f, 0xf7, 0x70, 0xf3, 0x2a, 0x2a, 0x93, - 0x02, 0x41, 0xa4, 0xa2, 0x41, 0x4c, 0x1a, 0x86, 0x89, 0xfa, 0xe1, 0xa6, - 0xad, 0x32, 0xf1, 0x0e, 0xaa, 0x7c, 0x44, 0x49, 0x9f, 0xd3, 0x75, 0x32, - 0x5c, 0x49, 0xa1, 0xe5, 0x46, 0x86, 0x6e, 0xce, 0xbb, 0x1b, 0x29, 0x1d, - 0x61, 0x25, 0xf9, 0x3e, 0xd4, 0xe9, 0xbc, 0xc5, 0x56, 0xc5, 0xd6, 0xa1, - 0x4d, 0x52, 0xde, 0x92, 0x11, 0x4b, 0xef, 0x16, 0x1d, 0xd6, 0xcb, 0xce, - 0xb4, 0x2a, 0x4e, 0xfa, 0x1c, 0xae, 0xcf, 0x0f, 0xc8, 0x10, 0x61, 0x23, - 0x48, 0xaf, 0x92, 0x79, 0x7c, 0x88, 0xce, 0x12, 0x78, 0x6e, 0x63, 0x45, - 0xbe, 0xed, 0x2c, 0x65, 0xe0, 0x54, 0x7d, 0x84, 0x68, 0x00, 0x07, 0x3e, - 0x6a, 0x99, 0xf9, 0x22, 0x05, 0x30, 0x83, 0x9a, 0x3a, 0xb5, 0x0f, 0x88, - 0x18, 0xb4, 0x9b, 0x4a, 0x6e, 0x26, 0xdd, 0x8e, 0x09, 0xed, 0xc5, 0x24, - 0x83, 0xf9, 0xc9, 0x6e, 0x1b, 0x06, 0xd5, 0x21, 0xd6, 0xdf, 0xec, 0xd7, - 0x8e, 0x35, 0x89, 0x8b, 0x56, 0x77, 0x5d, 0xa9, 0x2c, 0xbf, 0x85, 0x7d, - 0xd1, 0xbc, 0xc1, 0x66, 0x2c, 0xc6, 0x18, 0x2a, 0x3d, 0xae, 0x9a, 0x01, - 0xbe, 0xfb, 0x5c, 0x08, 0x64, 0xa3, 0xf8, 0x12, 0xb3, 0x4b, 0xa0, 0x4b, - 0x3a, 0xf6, 0x40, 0x96, 0x5d, 0x67, 0x36, 0x65, 0x19, 0x58, 0x03, 0x59, - 0x1f, 0xcd, 0xcc, 0x3a, 0xa8, 0x2f, 0x23, 0xb5, 0xcb, 0xef, 0x8e, 0xe1, - 0x57, 0xdc, 0xcb, 0xd5, 0x3f, 0x48, 0xd5, 0x16, 0xc9, 0x56, 0x52, 0xc2, - 0x0c, 0x2a, 0x83, 0xde, 0xe8, 0x03, 0x35, 0x90, 0x69, 0x3e, 0x81, 0xee, - 0x7d, 0xde, 0x28, 0xcd, 0x4e, 0xa5, 0xb9, 0x8b, 0xfc, 0x3a, 0x48, 0xe0, - 0x43, 0x5e, 0xd9, 0x5f, 0x7f, 0xf7, 0x0f, 0x7e, 0x89, 0xce, 0xf3, 0xab, - 0xa3, 0x76, 0xc3, 0x41, 0x73, 0xcf, 0xa3, 0x84, 0xa3, 0xf1, 0xfc, 0xa8, - 0x4c, 0xad, 0x2c, 0x84, 0x6e, 0x9f, 0x8e, 0x0e, 0x78, 0x8e, 0xaa, 0xfc, - 0x71, 0x1f, 0x1d, 0x7a, 0xbf, 0xdc, 0x32, 0xcc, 0x25, 0xe2, 0x0f, 0xd1, - 0x7b, 0xe2, 0x1d, 0x44, 0x21, 0xaf, 0x7e, 0x82, 0xfe, 0xb3, 0xf4, 0xc1, - 0xeb, 0x52, 0xe5, 0xaf, 0x91, 0xe9, 0x69, 0x0f, 0x39, 0xe3, 0xcb, 0x7a, - 0x16, 0x6a, 0xe9, 0x78, 0x29, 0x5f, 0xe1, 0x66, 0x95, 0x6d, 0x30, 0xd0, - 0x50, 0x13, 0x08, 0x62, 0x40, 0x3b, 0xb3, 0xca, 0x7d, 0xa1, 0xb2, 0x51, - 0x9c, 0x29, 0x7b, 0xd3, 0x1a, 0xee, 0x46, 0xfa, 0xec, 0x27, 0x9b, 0x5c, - 0xa3, 0x0f, 0xf1, 0x73, 0x4a, 0x16, 0xdc, 0x0e, 0xd6, 0xb8, 0xc6, 0x50, - 0x29, 0xc2, 0x99, 0x47, 0x37, 0xf7, 0xb4, 0xee, 0x52, 0x9b, 0x0a, 0xe1, - 0xd3, 0xed, 0x94, 0x59, 0xda, 0x1b, 0xeb, 0x80, 0x4d, 0xf7, 0xb4, 0x78, - 0x0a, 0x0b, 0xd9, 0x4c, 0x67, 0x75, 0x2c, 0x05, 0x59, 0x02, 0xeb, 0xff, - 0xf7, 0x71, 0xe0, 0x88, 0x19, 0x61, 0xb9, 0xce, 0x49, 0x75, 0xd7, 0xb4, - 0xa6, 0x7c, 0x35, 0x80, 0x77, 0x5d, 0xfb, 0xb0, 0x2d, 0xb7, 0x58, 0x95, - 0x82, 0xca, 0x95, 0x74, 0x25, 0x60, 0x48, 0x5b, 0x7c, 0x46, 0xec, 0x53, - 0x89, 0xe7, 0x3b, 0x23, 0xb2, 0xcc, 0x1b, 0x0f, 0x47, 0xdb, 0xf5, 0x2a, - 0x25, 0x90, 0x12, 0x9b, 0x3f, 0x1e, 0xfb, 0xe3, 0x3a, 0x55, 0x77, 0xb3, - 0xa4, 0x30, 0x65, 0x43, 0x76, 0x81, 0x4b, 0xa0, 0x21, 0xe0, 0x79, 0x36, - 0xe4, 0x13, 0xef, 0x25, 0x8c, 0xd0, 0x43, 0x4b, 0xa5, 0xeb, 0x8d, 0x4f, - 0x56, 0x53, 0xd2, 0x70, 0xe9, 0xbf, 0x44, 0x31, 0x28, 0x1c, 0x04, 0x77, - 0x19, 0xee, 0x88, 0xd4, 0x1c, 0x32, 0xbb, 0xab, 0xd6, 0xb2, 0x75, 0x27, - 0x93, 0x09, 0xe7, 0x03, 0xee, 0x59, 0x58, 0x36, 0xbd, 0x75, 0xfa, 0x2c, - 0xd4, 0x2f, 0x88, 0xb7, 0xdd, 0x59, 0xe0, 0x14, 0xda, 0x34, 0x31, 0x34, - 0xc0, 0x18, 0x86, 0xa3, 0xcc, 0x9f, 0x28, 0x28, 0xf2, 0x9f, 0xdc, 0x89, - 0x01, 0x7f, 0xac, 0x29, 0x5b, 0x8a, 0x27, 0x27, 0x38, 0x8b, 0x55, 0xf5, - 0x88, 0x74, 0x42, 0x4c, 0xd1, 0xd8, 0xdc, 0xd5, 0xe5, 0x87, 0xaf, 0x25, - 0x17, 0xec, 0x75, 0xe4, 0x0d, 0xd5, 0x75, 0x14, 0x64, 0xad, 0x80, 0x53, - 0x03, 0x5a, 0xf4, 0xf8, 0x1a, 0x28, 0xe4, 0xa2, 0x37, 0x65, 0x06, 0xdb, - 0x59, 0x7e, 0x73, 0xca, 0x65, 0x75, 0x59, 0x8d, 0xe8, 0x2b, 0xce, 0x42, - 0xcf, 0x22, 0xfa, 0x98, 0x38, 0xd7, 0x2c, 0x93, 0x20, 0xf1, 0x1f, 0x62, - 0x7b, 0xa3, 0x8f, 0xad, 0x4b, 0xf5, 0xf3, 0xdb, 0x27, 0x8b, 0xac, 0x25, - 0xef, 0x03, 0x58, 0xa4, 0x8e, 0xc0, 0x06, 0xd5, 0xc7, 0xc0, 0xae, 0x98, - 0xa2, 0xee, 0xab, 0x70, 0x9c, 0x99, 0xad, 0x92, 0x7d, 0xe3, 0x5b, 0x2d, - 0x9f, 0xf0, 0xe3, 0xac, 0xea, 0xe2, 0xdc, 0x48, 0x24, 0x3f, 0x33, 0x6f, - 0xc4, 0xd2, 0x8d, 0x9c, 0xcf, 0xe8, 0xb7, 0x52, 0x32, 0xab, 0xb9, 0x41, - 0x18, 0x0c, 0x0f, 0x13, 0xf2, 0x48, 0x91, 0x68, 0x19, 0x55, 0x22, 0x04, - 0x1d, 0xed, 0xda, 0xa6, 0xaf, 0x29, 0xcb, 0xcb, 0x85, 0x00, 0x00, 0x04, - 0xe6, 0x3d, 0x68, 0xb5, 0x2b, 0xd4, 0x0d, 0x5b, 0xcd, 0x34, 0x6b, 0x15, - 0x36, 0x71, 0x48, 0xf2, 0xd2, 0xcd, 0x46, 0xc5, 0x3b, 0xa5, 0x19, 0xa0, - 0x94, 0x60, 0x36, 0x62, 0x41, 0xe8, 0x4e, 0x10, 0x0d, 0x81, 0x43, 0x68, - 0xc4, 0x7f, 0x89, 0x29, 0x24, 0x9f, 0x6f, 0x69, 0x8f, 0xf2, 0x26, 0x8d, - 0x8b, 0x36, 0x64, 0x4f, 0xde, 0x6f, 0xae, 0xaa, 0xd3, 0x1b, 0xa0, 0x8a, - 0x55, 0x60, 0xa3, 0xe7, 0x67, 0xe8, 0x89, 0xfb, 0xce, 0x66, 0x34, 0x0b, - 0xce, 0xba, 0xe6, 0x80, 0xc2, 0xeb, 0x01, 0xc9, 0xd6, 0xad, 0x59, 0x02, - 0xb7, 0x14, 0x0d, 0x2c, 0xe9, 0xf9, 0xcd, 0x7a, 0x83, 0x72, 0xdf, 0xb5, - 0x25, 0x11, 0x65, 0x1a, 0xee, 0xf0, 0x40, 0xbb, 0xdf, 0x62, 0xb3, 0x03, - 0xd5, 0xbf, 0x18, 0xbc, 0xd1, 0x41, 0x53, 0x84, 0x5e, 0x28, 0x25, 0x54, - 0x14, 0xd1, 0xcf, 0xff, 0x1b, 0xb1, 0x62, 0xc9, 0x5e, 0x05, 0xd6, 0xe7, - 0x92, 0x18, 0xe7, 0xf3, 0x55, 0xd4, 0x9e, 0x3c, 0x0f, 0x0f, 0x77, 0xb8, - 0xd3, 0xd7, 0x7e, 0xb4, 0xb1, 0xe0, 0x36, 0x50, 0x96, 0xeb, 0xd0, 0x7e, - 0x72, 0x22, 0x69, 0x65, 0x35, 0xbb, 0xba, 0xc4, 0x4a, 0xdf, 0xdd, 0x30, - 0xe8, 0xe0, 0x47, 0x30, 0x1c, 0xbb, 0x7b, 0xa2, 0x7f, 0xbf, 0x7c, 0x34, - 0x93, 0x0e, 0x72, 0x38, 0x80, 0x5a, 0x6a, 0xfa, 0x67, 0xa7, 0x70, 0x39, - 0xb8, 0xfd, 0x39, 0x48, 0x67, 0x9a, 0x56, 0x8f, 0x8c, 0xc3, 0xb0, 0x4a, - 0x99, 0x00, 0xde, 0x63, 0x29, 0x9c, 0xae, 0x34, 0xcd, 0x73, 0xd7, 0xf3, - 0xcb, 0x7d, 0xa6, 0xd6, 0xe0, 0x1d, 0xd4, 0x86, 0xa5, 0xaa, 0x1e, 0xf1, - 0x78, 0xad, 0xd5, 0xc6, 0xae, 0xc0, 0xdd, 0x04, 0x23, 0x02, 0x75, 0xc7, - 0xb2, 0xef, 0x99, 0x5d, 0xa7, 0xea, 0xf9, 0x5e, 0x34, 0xe3, 0x5e, 0x0b, - 0x0a, 0x23, 0x21, 0xd7, 0x4b, 0x0a, 0x5e, 0xa3, 0xfd, 0xe8, 0xb7, 0x32, - 0xf8, 0x7e, 0xf4, 0xfd, 0xe8, 0xa9, 0x1b, 0xd6, 0x65, 0x7e, 0xf9, 0xce, - 0xa4, 0x54, 0xe2, 0x73, 0xaf, 0xf1, 0x17, 0x15, 0x28, 0x23, 0x75, 0xfa, - 0x36, 0xbe, 0x39, 0x89, 0xb4, 0xeb, 0xb1, 0x05, 0xff, 0x68, 0xe7, 0xbc, - 0xc1, 0x62, 0x11, 0xc7, 0xb9, 0xcc, 0xe6, 0xde, 0x12, 0x93, 0x7e, 0x0e, - 0x7e, 0x02, 0xb5, 0xfd, 0xb0, 0x5e, 0x11, 0x8b, 0xbf, 0xc8, 0x4d, 0x76, - 0x48, 0xdf, 0x60, 0x2b, 0x47, 0x48, 0x1f, 0xd5, 0x3e, 0x6e, 0x14, 0xe3, - 0xe8, 0xcd, 0x65, 0x8b, 0xf8, 0x7f, 0x40, 0x69, 0x2d, 0x1e, 0x64, 0x85, - 0xe0, 0x37, 0xe6, 0x07, 0x43, 0x02, 0x44, 0xc5, 0x37, 0x23, 0x37, 0x5e, - 0x8a, 0x78, 0xde, 0xdd, 0x96, 0x36, 0xf4, 0x46, 0xe4, 0x19, 0x47, 0xca, - 0xe9, 0x35, 0x31, 0x30, 0xdc, 0x54, 0x83, 0x8f, 0x6f, 0x5e, 0xa0, 0xdd, - 0xa6, 0x9d, 0x6d, 0xdf, 0xb2, 0x53, 0x24, 0x0c, 0xb1, 0xea, 0x45, 0x7e, - 0x65, 0xbd, 0x6d, 0x72, 0xbc, 0xcf, 0xb2, 0x41, 0x0b, 0xc8, 0xcd, 0xec, - 0x9c, 0xea, 0xda, 0x62, 0xc2, 0xf6, 0xdf, 0x22, 0xed, 0xc5, 0x0c, 0xd0, - 0xa3, 0x71, 0x6a, 0x23, 0xf0, 0x80, 0x7a, 0x0c, 0x31, 0x38, 0xb4, 0x70, - 0x52, 0xb3, 0x3a, 0xfd, 0x8f, 0x57, 0x48, 0xb1, 0x86, 0xce, 0x6d, 0x90, - 0xa8, 0x1e, 0xaa, 0xa1, 0xbd, 0x85, 0x49, 0x49, 0x25, 0xbb, 0x03, 0x08, - 0xcf, 0xa8, 0xc4, 0x7d, 0x6c, 0x11, 0x94, 0xb0, 0x17, 0xc9, 0xee, 0xdb, - 0xd5, 0x66, 0x60, 0x1a, 0xc2, 0xda, 0xfb, 0xbb, 0xc4, 0xa2, 0x82, 0x74, - 0x98, 0x5f, 0x89, 0xf5, 0xc7, 0x31, 0xb0, 0xb0, 0x13, 0xf6, 0x88, 0x7e, - 0x02, 0xa6, 0x45, 0xe8, 0x46, 0xc1, 0x1f, 0xbd, 0x61, 0x7e, 0x86, 0x94, - 0xfe, 0xb9, 0x0e, 0xcb, 0xba, 0x94, 0x65, 0xde, 0x79, 0x79, 0xb5, 0x2b, - 0xbb, 0x89, 0xcb, 0x0d, 0xbc, 0x60, 0x72, 0xaf, 0x9b, 0xcf, 0x86, 0xd6, - 0x37, 0xf0, 0x32, 0x11, 0xd5, 0x2d, 0xab, 0xb2, 0xfd, 0x48, 0x9a, 0x08, - 0x46, 0x83, 0xa9, 0x67, 0x02, 0x70, 0x76, 0xca, 0x7b, 0x4c, 0x24, 0xee, - 0x2a, 0x4c, 0x9b, 0x2d, 0xd0, 0x09, 0x2a, 0x78, 0xaa, 0xd1, 0x25, 0xb4, - 0xa1, 0x99, 0x8d, 0xc6, 0x1b, 0x79, 0xd2, 0xd6, 0xd9, 0x04, 0x6e, 0x9e, - 0x4f, 0x8e, 0x51, 0xa9, 0x53, 0x78, 0xe7, 0x00, 0xcf, 0xf8, 0x0f, 0xb6, - 0x20, 0x2c, 0xfc, 0x82, 0xb0, 0xf6, 0x4d, 0x15, 0xc5, 0x40, 0x44, 0x2a, - 0xee, 0x9e, 0xc0, 0x70, 0x72, 0x92, 0xf0, 0x32, 0x8a, 0x4c, 0x72, 0x3e, - 0x19, 0xe1, 0x46, 0xcc, 0xaa, 0x69, 0x46, 0x54, 0xa4, 0x02, 0x12, 0x73, - 0xb2, 0xca, 0x75, 0x67, 0x8d, 0x79, 0x01, 0x52, 0xfd, 0x80, 0x92, 0xe9, - 0x7b, 0x02, 0xfd, 0x4d, 0xd7, 0x85, 0x84, 0x4b, 0xe2, 0xa7, 0x36, 0x74, - 0xb8, 0xed, 0x28, 0x6d, 0xb3, 0x35, 0x37, 0x92, 0x7e, 0xb5, 0x67, 0x00, - 0x87, 0x16, 0xbc, 0x41, 0x08, 0x69, 0x07, 0xdd, 0x45, 0x0e, 0x91, 0xe9, - 0x5d, 0x9c, 0xed, 0x6c, 0xd3, 0x18, 0xd0, 0x8a, 0x0c, 0x45, 0x52, 0x54, - 0x2a, 0xa7, 0x3a, 0x0a, 0xe6, 0xe6, 0x5e, 0x19, 0xb8, 0xb4, 0xb5, 0xd9, - 0x8c, 0x7b, 0x76, 0x2d, 0xf7, 0x04, 0x0f, 0x29, 0x54, 0x29, 0xc3, 0x42, - 0x35, 0x9f, 0x52, 0x0d, 0x64, 0x35, 0xea, 0xb7, 0xfd, 0x4d, 0x63, 0x17, - 0x3f, 0xdc, 0x00, 0xc5, 0x01, 0x28, 0x4c, 0x34, 0xcc, 0x8c, 0xb2, 0x6b, - 0x68, 0xa7, 0x04, 0x2f, 0x36, 0xdd, 0xcd, 0xfa, 0xcd, 0x12, 0xc2, 0x93, - 0xd3, 0xf7, 0xfe, 0x91, 0xda, 0xad, 0x09, 0x2d, 0x93, 0x13, 0xbf, 0x5c, - 0xef, 0x10, 0x46, 0x11, 0x8c, 0x22, 0xb4, 0xcc, 0xf8, 0x01, 0x85, 0x79, - 0x98, 0x4c, 0x8b, 0xa7, 0x30, 0x07, 0x6a, 0x2f, 0x10, 0x5f, 0x1a, 0x72, - 0x7a, 0x69, 0xf6, 0xf6, 0x22, 0x87, 0x98, 0x31, 0x8d, 0xe3, 0x38, 0xf2, - 0xd7, 0x10, 0xfc, 0xe7, 0xa0, 0x2a, 0xdd, 0x5e, 0x4f, 0x30, 0x21, 0x5b, - 0x8c, 0x2d, 0x5f, 0xdb, 0x45, 0x66, 0xc2, 0x59, 0x56, 0x4a, 0x77, 0x13, - 0xef, 0xf3, 0xff, 0x61, 0x43, 0xaf, 0x4e, 0x29, 0xe2, 0xf9, 0x0d, 0xe2, - 0x21, 0x2b, 0x58, 0xea, 0x9e, 0x0d, 0xe1, 0xbc, 0x7b, 0xc2, 0x39, 0xdf, - 0xf5, 0xdb, 0x12, 0xfd, 0xc2, 0x1c, 0xf7, 0x2f, 0xdb, 0x5d, 0x41, 0x50, - 0xdc, 0xcb, 0x2b, 0x7e, 0xd0, 0x86, 0xef, 0x1a, 0xcb, 0x0e, 0x06, 0x2c, - 0x6d, 0x53, 0x09, 0xc7, 0x7b, 0x66, 0xa7, 0x49, 0x2a, 0xa3, 0x94, 0xe5, - 0x27, 0x16, 0x75, 0x8a, 0x9e, 0xec, 0x30, 0x22, 0x67, 0xe4, 0x6c, 0x19, - 0x70, 0xe4, 0x04, 0x7e, 0xbf, 0xe3, 0x45, 0x41, 0x63, 0x2e, 0x94, 0x22, - 0x5b, 0x98, 0xb7, 0xdf, 0x13, 0x67, 0x6a, 0x49, 0x1e, 0xa3, 0xbb, 0xb5, - 0x4d, 0x06, 0x08, 0x2a, 0x0f, 0xd3, 0xce, 0xbf, 0x61, 0x9d, 0x6d, 0xff, - 0x87, 0xcd, 0x3e, 0x6f, 0x1c, 0xd8, 0x77, 0x08, 0xcc, 0xe4, 0xae, 0x2d, - 0x32, 0x85, 0x60, 0xe0, 0xfa, 0xa2, 0x2d, 0x44, 0x14, 0xe8, 0x6b, 0x9f, - 0x73, 0xbd, 0x16, 0x43, 0xf0, 0x82, 0xdd, 0xaf, 0x56, 0xf0, 0x73, 0x87, - 0x4e, 0x39, 0x5a, 0xe7, 0xa5, 0x98, 0xfa, 0xf6, 0xa7, 0x55, 0xdf, 0xc3, - 0xbc, 0xa0, 0x69, 0x65, 0x05, 0xc2, 0xe9, 0x57, 0xba, 0x53, 0x84, 0x29, - 0x88, 0x3c, 0x5f, 0x33, 0x9c, 0xc4, 0xaf, 0xbd, 0x50, 0xcd, 0xf7, 0x25, - 0x9c, 0x6c, 0x53, 0xd7, 0x8f, 0x70, 0x55, 0x77, 0x72, 0xd6, 0xea, 0x0d, - 0x6b, 0x95, 0x55, 0x30, 0x92, 0x8d, 0x01, 0x79, 0xca, 0x3f, 0xe9, 0x87, - 0x7e, 0xd5, 0xcb, 0x0e, 0x30, 0xbd, 0x46, 0x03, 0x60, 0xd2, 0xef, 0x83, - 0x5b, 0x91, 0x20, 0x2d, 0x9c, 0xb9, 0xcf, 0x7e, 0xff, 0xa7, 0x41, 0x5b, - 0x6c, 0xcd, 0x56, 0x87, 0xf9, 0xb6, 0x32, 0x65, 0xf7, 0x19, 0xad, 0x8d, - 0x17, 0xeb, 0x98, 0xa0, 0x65, 0x7c, 0x60, 0xa1, 0x9a, 0x8f, 0x97, 0xc2, - 0x37, 0x9a, 0x43, 0x99, 0x00, 0xa7, 0x64, 0x0b, 0x23, 0x4a, 0x1b, 0xc0, - 0xf4, 0xb4, 0xc4, 0x2d, 0xdb, 0x69, 0xc3, 0x04, 0xbf, 0xb7, 0x70, 0xed, - 0x26, 0x9c, 0xcf, 0xa6, 0x7d, 0x23, 0xf3, 0x80, 0x75, 0x2b, 0x2c, 0xfe, - 0x7e, 0x99, 0x02, 0xf6, 0x87, 0xdc, 0x9a, 0xff, 0x7f, 0x5a, 0xed, 0x3c, - 0xa2, 0x05, 0x02, 0x84, 0x57, 0x4d, 0x52, 0xf1, 0xd2, 0xf5, 0xb2, 0x82, - 0x94, 0x43, 0xde, 0x9c, 0x63, 0x5c, 0x3b, 0xdd, 0x32, 0xe1, 0x8e, 0x6c, - 0x4c, 0xa1, 0x77, 0xbd, 0x60, 0xb5, 0x7f, 0x5c, 0xe8, 0xeb, 0x8a, 0xfb, - 0x04, 0xf9, 0x53, 0x37, 0x81, 0x62, 0xb4, 0xcc, 0x53, 0x29, 0x18, 0x62, - 0x99, 0x0f, 0x57, 0xcd, 0x2c, 0x92, 0x05, 0x39, 0x25, 0xb2, 0xa4, 0x16, - 0x88, 0xd3, 0x9b, 0x17, 0xcc, 0x83, 0xf9, 0xc9, 0xf2, 0xfb, 0xde, 0x98, - 0x59, 0xcd, 0x26, 0x59, 0xe8, 0xf6, 0x30, 0x2a, 0x1b, 0xa7, 0x6e, 0x1f, - 0xb0, 0x11, 0xdb, 0x51, 0xc9, 0xf7, 0xbc, 0x9a, 0x47, 0x50, 0x82, 0x3a, - 0xed, 0x1a, 0x37, 0x59, 0x22, 0x29, 0xe5, 0x65, 0x1f, 0x4f, 0xe8, 0xe0, - 0xe9, 0xea, 0xcf, 0x72, 0x6c, 0xea, 0x6b, 0x6e, 0xa9, 0x51, 0x97, 0x27, - 0x7d, 0x47, 0x47, 0xf8, 0x17, 0x88, 0x86, 0x55, 0xf3, 0x6c, 0x86, 0xbd, - 0x35, 0x69, 0x21, 0xfd, 0x92, 0x98, 0x2a, 0x32, 0x53, 0xc2, 0x47, 0x09, - 0x7e, 0xad, 0xfc, 0xb1, 0x49, 0x94, 0x30, 0xe0, 0x74, 0x55, 0x9c, 0x17, - 0x89, 0x03, 0x97, 0xfa, 0x01, 0x11, 0xa4, 0xf8, 0x28, 0xcf, 0x90, 0xc5, - 0xb4, 0xe6, 0x2e, 0xb0, 0x1e, 0xc4, 0xf8, 0xeb, 0x2f, 0x61, 0x57, 0x4d, - 0x39, 0x4c, 0x7b, 0xd1, 0xe4, 0x71, 0x04, 0xde, 0x07, 0x6f, 0x8b, 0x7e, - 0xdc, 0x88, 0x8f, 0xce, 0x67, 0x23, 0x82, 0x64, 0x7d, 0xcc, 0x3b, 0x60, - 0xb4, 0x50, 0x96, 0x71, 0x58, 0xa2, 0x97, 0xd8, 0x6e, 0x57, 0xa0, 0xe4, - 0xe2, 0x7c, 0x5f, 0x05, 0xd2, 0x2d, 0xbf, 0xbd, 0xc0, 0xb6, 0x1c, 0xff, - 0x03, 0x21, 0x3c, 0xff, 0x4e, 0x9b, 0x19, 0x23, 0x83, 0x37, 0x41, 0xd3, - 0xb2, 0x91, 0x67, 0xaf, 0xa0, 0xd1, 0x78, 0x63, 0x86, 0x5f, 0x88, 0xce, - 0x0c, 0xc4, 0x88, 0x3d, 0x33, 0xed, 0xd5, 0xc4, 0x74, 0x84, 0x1c, 0x46, - 0xea, 0x46, 0xc6, 0xf4, 0x6b, 0x2b, 0x1e, 0x66, 0xcf, 0xba, 0x92, 0xae, - 0xac, 0xa5, 0xed, 0x7d, 0x81, 0x97, 0xe0, 0xc7, 0x6e, 0x98, 0x98, 0x7e, - 0x22, 0xad, 0x33, 0x72, 0x0e, 0xc1, 0x0a, 0xe6, 0x4b, 0x5d, 0xc5, 0xa2, - 0xa1, 0xfe, 0xfe, 0x29, 0xb6, 0x56, 0x82, 0xd1, 0x81, 0x6a, 0x73, 0x5d, - 0x39, 0xd2, 0x22, 0x41, 0x2a, 0x90, 0x9c, 0x7f, 0x02, 0x6f, 0x66, 0xb8, - 0xb4, 0xa1, 0x3a, 0xbf, 0xe4, 0xd7, 0xcf, 0x87, 0x37, 0xf3, 0x36, 0x66, - 0x7c, 0x52, 0xa3, 0xa5, 0x2d, 0xdd, 0xa0, 0x82, 0xee, 0x68, 0xea, 0x58, - 0xef, 0x05, 0xe8, 0x4f, 0x01, 0xf5, 0x82, 0x98, 0x13, 0xf6, 0x67, 0x6f, - 0x66, 0x2f, 0x2c, 0xd9, 0xbd, 0x01, 0x40, 0x86, 0xe5, 0x52, 0xfa, 0x9d, - 0xca, 0xb6, 0x05, 0x13, 0x96, 0x62, 0x8f, 0xe1, 0x20, 0x34, 0xdc, 0x6f, - 0x8f, 0xdb, 0x4e, 0x0d, 0xac, 0x6c, 0x86, 0x05, 0x1d, 0x8f, 0x99, 0x1f, - 0xfd, 0x71, 0xb9, 0xfe, 0xa8, 0xd0, 0xd7, 0x6c, 0xb0, 0xda, 0x8b, 0xdb, - 0x97, 0x8a, 0xda, 0xda, 0x65, 0x3a, 0xa5, 0x12, 0x44, 0x35, 0x8d, 0xe5, - 0x71, 0xa1, 0xd8, 0x2d, 0x05, 0x0a, 0x97, 0x3a, 0x77, 0x36, 0xce, 0xfd, - 0x93, 0x29, 0x76, 0x73, 0x15, 0x2c, 0x2b, 0x70, 0xd8, 0x47, 0xeb, 0x68, - 0x66, 0xb3, 0x23, 0x17, 0x0b, 0x9a, 0xac, 0x2e, 0x4d, 0x6a, 0xaf, 0x75, - 0xa8, 0xa9, 0xbe, 0xe3, 0x02, 0xfe, 0x92, 0xe0, 0x25, 0x34, 0x00, 0xd0, - 0xa3, 0xaa, 0xd3, 0xc5, 0xf9, 0xf3, 0x79, 0x9c, 0x03, 0xf8, 0x02, 0xc4, - 0xcc, 0x0c, 0x0e, 0xca, 0x5d, 0x46, 0xb4, 0x8f, 0x20, 0xbc, 0x1f, 0x84, - 0x75, 0x5c, 0xe1, 0x15, 0x60, 0x6d, 0x0b, 0x94, 0x89, 0xdb, 0x23, 0x28, - 0xa0, 0x58, 0x7b, 0xaa, 0xf1, 0x17, 0x9e, 0x66, 0xd3, 0x84, 0x81, 0x04, - 0x24, 0xe9, 0xbc, 0x5f, 0xaf, 0xb2, 0xb2, 0x51, 0xf2, 0x8a, 0xee, 0x6d, - 0xc6, 0x27, 0x8d, 0x7b, 0xf4, 0xe4, 0x97, 0xc7, 0xda, 0x81, 0x09, 0xbe, - 0x4d, 0x76, 0xcb, 0xfa, 0x0f, 0x43, 0xf3, 0x86, 0x3f, 0x14, 0x9b, 0xe2, - 0x05, 0x3e, 0x50, 0xc5, 0x61, 0x23, 0x44, 0xb8, 0xa0, 0xc4, 0x69, 0x0f, - 0x42, 0x06, 0x31, 0xd9, 0xc1, 0x53, 0xc2, 0x17, 0x60, 0x63, 0xfb, 0x6b, - 0x45, 0x00, 0x3c, 0x22, 0x14, 0x17, 0x4f, 0x4d, 0xc6, 0x43, 0xc5, 0x42, - 0x76, 0x51, 0x14, 0x20, 0x6f, 0x51, 0xbb, 0x73, 0x5f, 0xf6, 0xee, 0xed, - 0x49, 0x8d, 0x1e, 0xff, 0x76, 0x74, 0x3f, 0x24, 0x1f, 0x91, 0xfd, 0xb8, - 0xb5, 0xd8, 0xa0, 0x4c, 0x8b, 0x8b, 0x22, 0x22, 0x4a, 0x29, 0x49, 0xd7, - 0xfa, 0xa1, 0xde, 0x44, 0x14, 0x61, 0x3e, 0xe4, 0x6b, 0x04, 0x4b, 0x66, - 0x94, 0x28, 0xe7, 0x29, 0x05, 0x78, 0xcb, 0x3f, 0x86, 0xf7, 0x7e, 0x6f, - 0xca, 0x6f, 0xfa, 0x87, 0xd6, 0xcc, 0x7d, 0x56, 0xcf, 0xb3, 0x69, 0x00, - 0x9f, 0x69, 0x69, 0x3f, 0x85, 0x62, 0x88, 0x1f, 0x4f, 0x1b, 0x52, 0xd6, - 0x09, 0x0a, 0x00, 0x9e, 0x67, 0x7d, 0x11, 0x64, 0x20, 0x45, 0xd6, 0x0b, - 0xbf, 0xda, 0xdd, 0x32, 0xa9, 0x6a, 0xa9, 0xf2, 0x7a, 0x0b, 0x99, 0xd9, - 0x4a, 0x5e, 0x63, 0x59, 0x81, 0x71, 0x26, 0x6e, 0x59, 0xe3, 0x6c, 0x9b, - 0xaa, 0x37, 0x45, 0xbb, 0xd6, 0x0d, 0x54, 0x58, 0x81, 0x0d, 0x65, 0x61, - 0x07, 0x66, 0x79, 0x9c, 0x64, 0xf7, 0x2d, 0xea, 0x90, 0x41, 0x06, 0x7a, - 0xeb, 0x0e, 0x71, 0xf5, 0x17, 0x1b, 0x9a, 0x8b, 0xf9, 0x8b, 0x40, 0x22, - 0x69, 0x1b, 0x28, 0xf1, 0x07, 0x73, 0xb4, 0x32, 0x53, 0x71, 0xa1, 0x45, - 0xae, 0x18, 0x5a, 0x82, 0x71, 0x6a, 0x37, 0xff, 0x03, 0x6b, 0x6e, 0x79, - 0xaf, 0xaa, 0x3a, 0xef, 0x4c, 0x33, 0xa7, 0x52, 0xbd, 0x24, 0x21, 0xf2, - 0x45, 0x0b, 0x30, 0x03, 0xe6, 0x27, 0x54, 0x6f, 0x2a, 0x0b, 0x5c, 0x86, - 0x37, 0x64, 0x79, 0xa2, 0xf9, 0x35, 0xcb, 0xec, 0x04, 0xee, 0x9d, 0x56, - 0x2a, 0x74, 0x14, 0x91, 0xd2, 0x5f, 0x89, 0x1f, 0x29, 0x19, 0x14, 0xa3, - 0x70, 0x3a, 0xc3, 0x3b, 0x48, 0x45, 0x4d, 0xc8, 0x53, 0x36, 0x1c, 0x11, - 0xe9, 0x20, 0xbf, 0x24, 0x65, 0xb8, 0x2e, 0x3d, 0xf2, 0xca, 0x34, 0x8d, - 0x95, 0x1a, 0x4a, 0xb3, 0x5f, 0xbb, 0xaa, 0x38, 0xaa, 0xd4, 0xcd, 0x68, - 0x06, 0x5f, 0xa2, 0x8f, 0x02, 0xf3, 0x64, 0x35, 0x5b, 0x79, 0xf1, 0x02, - 0x07, 0x48, 0x97, 0xa1, 0x3d, 0xcb, 0xe5, 0xe8, 0x60, 0x98, 0x2a, 0xc8, - 0x6f, 0x9c, 0xe8, 0xec, 0xc5, 0x22, 0xc4, 0xa2, 0xb4, 0x96, 0x0a, 0xe4, - 0x00, 0x85, 0xfc, 0x6a, 0x23, 0x9f, 0xda, 0x57, 0xd0, 0xc1, 0xc0, 0x9d, - 0x6d, 0xe6, 0x09, 0xba, 0xd2, 0x55, 0x91, 0xe3, 0x49, 0x9b, 0x90, 0x1d, - 0x3e, 0x2a, 0x7d, 0x91, 0xa1, 0xc7, 0x14, 0x27, 0x9c, 0x77, 0xc9, 0x2e, - 0x50, 0x9f, 0x2b, 0x3c, 0x1e, 0x1b, 0x5a, 0xac, 0x86, 0xe1, 0xc5, 0xc6, - 0x51, 0x6a, 0x54, 0x2b, 0x3b, 0x79, 0xec, 0xc9, 0xc5, 0x8e, 0x5e, 0x04, - 0xa8, 0x0d, 0xe0, 0x75, 0xb1, 0xbb, 0x7b, 0x31, 0xaa, 0xf9, 0xad, 0x9f, - 0x0d, 0x41, 0xc7, 0xe8, 0xf7, 0x19, 0xc1, 0x7b, 0x33, 0x7a, 0x76, 0x39, - 0x6f, 0x81, 0x58, 0x92, 0xb7, 0xac, 0x70, 0x89, 0xc3, 0x3e, 0x01, 0xdc, - 0x92, 0xaf, 0xf4, 0x46, 0xf3, 0x00, 0x1e, 0x45, 0x1d, 0xf7, 0x5a, 0xad, - 0x2a, 0x22, 0xaa, 0x34, 0x13, 0x8e, 0xf2, 0xb4, 0xff, 0xb2, 0x08, 0x45, - 0x07, 0x22, 0xed, 0x37, 0x24, 0x42, 0x78, 0x88, 0x28, 0x73, 0x7a, 0xb6, - 0xa2, 0x6a, 0xb8, 0x8c, 0x48, 0x2c, 0x7c, 0x13, 0xc8, 0x1c, 0xd5, 0x61, - 0xa2, 0x89, 0xaf, 0x1c, 0x41, 0x1e, 0xf0, 0x01, 0x0e, 0x89, 0xbb, 0x20, - 0xd1, 0xb9, 0xe1, 0x43, 0x47, 0x17, 0xf3, 0x29, 0xc0, 0x22, 0xdb, 0xcf, - 0x15, 0x84, 0x8d, 0x94, 0xe6, 0xe9, 0x92, 0x13, 0x44, 0xa1, 0xcd, 0xcf, - 0x50, 0xb7, 0x5d, 0xa7, 0xb1, 0x38, 0x49, 0x48, 0xb1, 0xf3, 0x63, 0xb8, - 0x9f, 0x12, 0x08, 0xce, 0xc6, 0x41, 0x5c, 0x82, 0x3a, 0xfb, 0x7e, 0xe3, - 0x06, 0x5e, 0xfa, 0x85, 0x0c, 0xd0, 0x08, 0xe9, 0xb1, 0x4d, 0xd7, 0x4f, - 0xf4, 0x9f, 0x6e, 0x05, 0x75, 0x47, 0xd8, 0xd1, 0xa3, 0xc7, 0x72, 0xbe, - 0x8e, 0x80, 0x51, 0x85, 0x80, 0xc8, 0xc0, 0xf1, 0x44, 0xe7, 0xd7, 0x20, - 0xf1, 0x23, 0x67, 0xde, 0xfa, 0x4c, 0xaf, 0x91, 0x0a, 0x7b, 0x2e, 0x02, - 0x01, 0x24, 0xa1, 0x88, 0x08, 0xaa, 0xf3, 0x33, 0x60, 0xec, 0xde, 0x71, - 0x0f, 0x20, 0x54, 0x33, 0x1c, 0xa1, 0xb0, 0x4d, 0x30, 0xed, 0xbe, 0x00, - 0xda, 0xd6, 0x97, 0x57, 0xe2, 0xc8, 0x0c, 0x10, 0xd1, 0x7e, 0x9c, 0x8c, - 0x7a, 0xbb, 0x9f, 0xdf, 0x66, 0xab, 0xc5, 0x3e, 0x67, 0x52, 0xfa, 0xce, - 0x47, 0x20, 0xf4, 0x6a, 0xed, 0x47, 0x3d, 0x26, 0xb1, 0x13, 0x1a, 0x15, - 0xa3, 0xaf, 0xda, 0x74, 0xf2, 0x6a, 0x47, 0xf7, 0xbd, 0x7e, 0x3e, 0x4b, - 0x68, 0x27, 0x4e, 0xf7, 0x10, 0xee, 0x4e, 0x80, 0xab, 0xf3, 0x45, 0x67, - 0xbf, 0xe2, 0x89, 0x19, 0xa4, 0x07, 0x11, 0x9a, 0xc6, 0x62, 0xa0, 0x85, - 0xa1, 0x07, 0x09, 0x4f, 0xa3, 0xe8, 0xd7, 0x68, 0xd6, 0x62, 0xee, 0x61, - 0x80, 0xb8, 0xd0, 0x94, 0x65, 0x23, 0x97, 0x89, 0xf9, 0x39, 0x85, 0xd6, - 0x0e, 0x6a, 0x56, 0x14, 0x10, 0x54, 0x63, 0xec, 0x3a, 0xa7, 0x16, 0x98, - 0x73, 0x0f, 0x46, 0x8b, 0x70, 0x5f, 0x6f, 0x72, 0x38, 0x77, 0xc6, 0x61, - 0x5e, 0x02, 0x56, 0x3d, 0x81, 0x8c, 0x0f, 0xc9, 0x29, 0x30, 0xe2, 0xd0, - 0x86, 0xc9, 0xf0, 0xd7, 0x77, 0xdc, 0x93, 0x05, 0xf6, 0x0a, 0xd3, 0x3d, - 0x94, 0xcf, 0x02, 0x11, 0x9f, 0xb6, 0xe2, 0xe6, 0x1c, 0xf9, 0xea, 0xea, - 0x37, 0xd5, 0xdc, 0xba, 0x3f, 0x39, 0xf0, 0x7d, 0x21, 0xeb, 0xb4, 0x94, - 0xed, 0x96, 0x40, 0x8d, 0x51, 0x86, 0x38, 0x78, 0x82, 0x11, 0x35, 0xef, - 0x19, 0x17, 0x46, 0x9f, 0x00, 0x35, 0xc0, 0x77, 0xe4, 0x6e, 0xca, 0x4f, - 0x00, 0x44, 0xe1, 0xf5, 0xe5, 0x4f, 0xa8, 0x86, 0xe0, 0x11, 0xa8, 0x0a, - 0x19, 0xd8, 0x2a, 0xfd, 0x89, 0xfd, 0x65, 0x3d, 0x04, 0xbf, 0x58, 0x4e, - 0x9d, 0x9f, 0x30, 0x04, 0xdf, 0xd1, 0x5e, 0x33, 0x59, 0xc0, 0x0a, 0x74, - 0xec, 0xc2, 0x9e, 0xcf, 0x53, 0x07, 0x60, 0x3b, 0x13, 0x6d, 0x32, 0x3e, - 0x0a, 0x29, 0xa5, 0xf2, 0x92, 0xd8, 0x40, 0xe1, 0xa8, 0xc6, 0x7a, 0xc1, - 0x55, 0x2e, 0x12, 0xe8, 0x03, 0x09, 0x0a, 0x88, 0x71, 0x82, 0xb6, 0xe9, - 0x23, 0xa4, 0xb1, 0x29, 0xa0, 0x15, 0x07, 0x83, 0xf7, 0xa0, 0xa8, 0xe2, - 0xbf, 0x51, 0x77, 0x11, 0x53, 0x69, 0xb2, 0x35, 0xc2, 0x62, 0x97, 0x18, - 0x5c, 0x2e, 0x21, 0xcb, 0xf3, 0xe1, 0x6f, 0x24, 0x6f, 0xb8, 0x6a, 0xfa, - 0x90, 0x4c, 0xc0, 0x1c, 0xd6, 0x79, 0x9d, 0xad, 0x1d, 0xbe, 0x11, 0x53, - 0x0d, 0x14, 0xfb, 0xba, 0x78, 0x75, 0x22, 0x04, 0x17, 0xd0, 0x04, 0xdb, - 0xac, 0xa6, 0xb8, 0xef, 0x74, 0xf5, 0x19, 0x43, 0xeb, 0xe5, 0xc7, 0xcc, - 0x97, 0xf4, 0x11, 0x04, 0xcf, 0x01, 0xf2, 0x71, 0x9f, 0x10, 0xf4, 0x79, - 0x09, 0x62, 0x1a, 0xe2, 0x66, 0x0f, 0x4e, 0x81, 0x71, 0xec, 0x91, 0x62, - 0xa8, 0x96, 0x84, 0xc0, 0x9a, 0x25, 0x30, 0x3f, 0x84, 0x48, 0x80, 0xf9, - 0xcc, 0x50, 0xa3, 0xd3, 0x96, 0x30, 0x08, 0xd1, 0xac, 0x2d, 0x57, 0x00, - 0x47, 0x1b, 0xfe, 0x90, 0x9d, 0xb7, 0x48, 0x9c, 0xe0, 0xf2, 0x69, 0x71, - 0x0a, 0x25, 0x78, 0x90, 0x79, 0xd8, 0x8c, 0xfe, 0x64, 0xcf, 0xc6, 0x36, - 0x07, 0x28, 0x04, 0xd2, 0x2a, 0xaa, 0x03, 0x53, 0x9b, 0x34, 0x1c, 0x47, - 0x3e, 0x94, 0x82, 0x9b, 0x4a, 0x98, 0x1e, 0x71, 0x4c, 0x9a, 0x72, 0xc4, - 0x60, 0x29, 0x91, 0x23, 0x06, 0x81, 0x38, 0x35, 0xe1, 0xa5, 0xd5, 0x41, - 0x47, 0xbf, 0xcc, 0x39, 0xa6, 0xe5, 0x7e, 0x9d, 0x98, 0x50, 0xb8, 0xe3, - 0x1c, 0x5d, 0x26, 0x35, 0xf4, 0x01, 0x42, 0x40, 0x14, 0x0d, 0xe6, 0x63, - 0xad, 0x50, 0x82, 0x82, 0xec, 0xaf, 0x22, 0x92, 0x52, 0x66, 0xdd, 0x84, - 0x9f, 0xf2, 0xfa, 0xa5, 0x74, 0xce, 0x49, 0xeb, 0x05, 0x5b, 0xa2, 0x94, - 0x8f, 0x2b, 0x37, 0xc9, 0xdb, 0x47, 0xf8, 0xbd, 0xe9, 0x65, 0x2b, 0x8a, - 0x7e, 0xbf, 0xf2, 0x96, 0x25, 0x9b, 0x56, 0xbc, 0xc5, 0xc0, 0x0c, 0x0d, - 0xf0, 0xa9, 0xca, 0x4e, 0x5f, 0x75, 0x5c, 0x64, 0xec, 0xcb, 0xc1, 0xc9, - 0x61, 0x75, 0xa3, 0xbc, 0x37, 0x5f, 0x5b, 0x5d, 0x9b, 0xe7, 0xa2, 0xaf, - 0x46, 0x28, 0xa6, 0x91, 0x58, 0xef, 0xba, 0x09, 0xf3, 0x18, 0x4a, 0xb1, - 0x18, 0xfe, 0xe4, 0x23, 0xf1, 0x29, 0x44, 0xc8, 0x5c, 0x17, 0x13, 0x8e, - 0xf1, 0x56, 0x41, 0xbb, 0xfc, 0xce, 0x7e, 0x56, 0x7c, 0xb3, 0x2b, 0x02, - 0xa5, 0x3f, 0x47, 0x28, 0x95, 0x91, 0xa7, 0xe3, 0xb2, 0xbd, 0x4f, 0x59, - 0xd4, 0x03, 0xa7, 0x87, 0xa9, 0x15, 0x0c, 0xe7, 0xb7, 0xff, 0x1a, 0x71, - 0xcb, 0xb0, 0x6c, 0xcf, 0x2e, 0x43, 0x6e, 0xb1, 0xa6, 0x7b, 0xf8, 0xe5, - 0xc3, 0xf1, 0xb6, 0xf3, 0x49, 0x4e, 0x36, 0xe5, 0x3e, 0x03, 0x86, 0x9f, - 0x54, 0xd2, 0x1c, 0xc6, 0x36, 0xd5, 0x78, 0xb8, 0x42, 0x5f, 0xc9, 0x7d, - 0x31, 0x58, 0xf8, 0xc9, 0x97, 0xef, 0xbf, 0x29, 0x20, 0x7c, 0x80, 0xcf, - 0x19, 0x5b, 0x4a, 0xaa, 0x26, 0x31, 0x9f, 0xeb, 0x55, 0x55, 0x79, 0x0e, - 0x70, 0x06, 0xc4, 0xd1, 0xd8, 0xa3, 0xbf, 0xdf, 0xd6, 0x6c, 0xea, 0xcc, - 0xf3, 0x65, 0xc4, 0xb2, 0xea, 0x64, 0xf9, 0x43, 0x49, 0xe8, 0xb1, 0xca, - 0xd5, 0x1b, 0xb9, 0x1a, 0x2f, 0x4c, 0xb6, 0x15, 0xe1, 0x45, 0x77, 0xce, - 0xab, 0xcb, 0x33, 0x99, 0xef, 0x70, 0x26, 0x36, 0x40, 0x99, 0x30, 0x0f, - 0x7b, 0xf5, 0xea, 0x0a, 0xed, 0x41, 0x01, 0x99, 0x0b, 0xc4, 0x97, 0x0d, - 0xe3, 0x57, 0xcd, 0xbd, 0x90, 0xa3, 0x7d, 0x68, 0xe2, 0x6b, 0x2a, 0xca, - 0xe7, 0x4a, 0x6a, 0x07, 0xe2, 0xb5, 0x2f, 0x53, 0x03, 0x50, 0x04, 0xd1, - 0xaa, 0xb8, 0x80, 0x2a, 0x4a, 0x2c, 0x2c, 0x80, 0x45, 0x2e, 0x9f, 0x8c, - 0x9c, 0xf4, 0x00, 0x9a, 0x1d, 0xd9, 0x6e, 0x42, 0x79, 0x0d, 0x6a, 0x01, - 0x6b, 0xc2, 0x27, 0xc2, 0x16, 0xfb, 0x7d, 0x62, 0xc1, 0x09, 0x36, 0xf8, - 0x27, 0xc1, 0x20, 0x40, 0x91, 0x8f, 0x33, 0x6e, 0x40, 0x25, 0x20, 0xfa, - 0x75, 0x30, 0xb6, 0xfd, 0x92, 0xcb, 0xaa, 0xbd, 0x94, 0x49, 0xd9, 0x68, - 0x73, 0x12, 0x6a, 0x26, 0xc4, 0xe8, 0x5a, 0x5c, 0xc0, 0x82, 0x5e, 0xe7, - 0xa3, 0xef, 0x76, 0x4c, 0xd6, 0x3f, 0xd6, 0xfd, 0xb9, 0x1e, 0x7c, 0x26, - 0xbc, 0x58, 0xa3, 0x3a, 0x5e, 0xfa, 0xe9, 0x93, 0xbe, 0xaf, 0x99, 0x37, - 0x52, 0xbc, 0x5a, 0xfb, 0x86, 0xad, 0x8f, 0x3d, 0xcf, 0x47, 0xb6, 0xf4, - 0xa7, 0x61, 0x95, 0xd5, 0x86, 0xa0, 0x68, 0x02, 0x3b, 0x6e, 0xd5, 0x17, - 0x0f, 0x85, 0xb5, 0x24, 0xe6, 0xc0, 0x4d, 0xdc, 0x3e, 0x85, 0x7c, 0x82, - 0x9b, 0xf3, 0xf0, 0xb3, 0x43, 0xc1, 0xdf, 0x9c, 0x17, 0x59, 0x6d, 0xf3, - 0x6c, 0x4d, 0xd9, 0x82, 0x5c, 0x0c, 0x36, 0x1a, 0xbd, 0xe7, 0x65, 0x60, - 0x5f, 0xba, 0xec, 0x2f, 0xd8, 0x08, 0x36, 0x9d, 0x5e, 0x78, 0x80, 0x3b, - 0x8a, 0x18, 0x76, 0x89, 0xc5, 0x22, 0x4d, 0xc7, 0x02, 0x8b, 0x18, 0x85, - 0x5e, 0xdd, 0xa0, 0x9d, 0x2d, 0x0a, 0x17, 0xe8, 0xf3, 0x5d, 0x5d, 0xe1, - 0xa0, 0x2e, 0x3c, 0x0a, 0x6a, 0x15, 0x60, 0xdc, 0x1f, 0xc8, 0x38, 0x48, - 0x03, 0x0a, 0x63, 0xfe, 0x14, 0xb2, 0xfb, 0x3e, 0xfd, 0x36, 0x16, 0x6d, - 0xec, 0x60, 0x42, 0xfa, 0xbc, 0x5e, 0x3e, 0x13, 0x05, 0x01, 0x34, 0x59, - 0x46, 0x44, 0xbf, 0xf4, 0x2b, 0x12, 0x7e, 0x15, 0x8a, 0x75, 0x72, 0x39, - 0x85, 0xe2, 0x0b, 0x8e, 0x96, 0x8d, 0x93, 0xaa, 0x6f, 0x75, 0x15, 0xa4, - 0xb8, 0xa8, 0x87, 0x79, 0x35, 0xf2, 0xd6, 0xf5, 0x56, 0x03, 0xe7, 0xfd, - 0x58, 0xe1, 0xfc, 0xc4, 0xd5, 0x79, 0x09, 0x59, 0x68, 0x8a, 0x17, 0xbe, - 0x8b, 0x52, 0xdd, 0x21, 0xd4, 0xf4, 0xe3, 0xeb, 0x6a, 0x2e, 0x9b, 0x53, - 0xdf, 0x55, 0x0d, 0x98, 0xdd, 0x1d, 0x04, 0xbf, 0x9e, 0x16, 0xf9, 0xdc, - 0x0a, 0x16, 0x1f, 0x37, 0xd9, 0xf6, 0xdc, 0xf7, 0x3b, 0x98, 0x32, 0xe6, - 0x41, 0x97, 0x4a, 0x80, 0x3f, 0x81, 0x19, 0x06, 0xc1, 0xd7, 0x91, 0xa8, - 0xd7, 0x5e, 0x83, 0x1a, 0x9f, 0x08, 0xe7, 0x0a, 0x3b, 0xb3, 0x76, 0x98, - 0x33, 0x0d, 0xae, 0xb8, 0x55, 0xfc, 0xb0, 0x14, 0xa2, 0xed, 0xeb, 0xc4, - 0x06, 0xb7, 0xbc, 0x63, 0x89, 0xa3, 0xbf, 0xcf, 0x82, 0x70, 0x62, 0x89, - 0x51, 0xcb, 0xaa, 0xf2, 0xab, 0x77, 0x32, 0x9a, 0xde, 0x4b, 0x7c, 0x60, - 0xe5, 0xe0, 0x97, 0x3d, 0x83, 0xae, 0xe1, 0x25, 0xac, 0xa2, 0x59, 0x9d, - 0xec, 0xe7, 0x16, 0xa5, 0x39, 0x24, 0xa6, 0x4b, 0x75, 0x01, 0x4e, 0xfb, - 0x52, 0x35, 0x19, 0x6c, 0x27, 0x27, 0x46, 0x2f, 0xe1, 0x5b, 0xbe, 0x7e, - 0x52, 0x31, 0x2a, 0x0e, 0xc6, 0x88, 0x86, 0x7f, 0x59, 0x8f, 0xf1, 0xaa, - 0xfd, 0x82, 0xfb, 0xa0, 0xba, 0x46, 0x43, 0x7d, 0xb1, 0x21, 0xaf, 0x92, - 0x36, 0x44, 0x49, 0x12, 0xdf, 0xeb, 0x3b, 0x30, 0x2f, 0x9e, 0xd2, 0x6e, - 0xc9, 0xde, 0x4a, 0x36, 0xb6, 0x8e, 0xc9, 0x6c, 0x72, 0x9c, 0xbe, 0x2d, - 0x6e, 0x0c, 0x45, 0x10, 0xc3, 0xa2, 0xc1, 0x00, 0x9c, 0xf7, 0xb5, 0xc7, - 0xf9, 0xcf, 0xea, 0xb5, 0xaf, 0x04, 0x28, 0xb9, 0x5a, 0xd6, 0xba, 0x4c, - 0x14, 0xcb, 0xa7, 0xb0, 0xed, 0x46, 0x2c, 0xf7, 0xd1, 0x28, 0x4a, 0xbd, - 0x4f, 0xb4, 0xbb, 0x90, 0x47, 0xb0, 0xa0, 0x31, 0xdf, 0xd4, 0x76, 0x51, - 0x3f, 0xfa, 0xc3, 0x59, 0xe3, 0x47, 0xae, 0x16, 0xe2, 0xab, 0x6c, 0xe0, - 0xb1, 0x58, 0x0a, 0x70, 0x8f, 0xf7, 0xf5, 0x2c, 0x7c, 0x26, 0xd7, 0xac, - 0xb0, 0xfb, 0xe7, 0x70, 0x19, 0x8f, 0x51, 0x82, 0x9a, 0x94, 0x53, 0x19, - 0x00, 0x56, 0x79, 0x8c, 0xf0, 0xe3, 0x25, 0xe3, 0x97, 0xa9, 0x07, 0x1a, - 0xc2, 0xcf, 0x2b, 0xaa, 0xa0, 0xef, 0x13, 0x2d, 0x47, 0xff, 0x9e, 0xf0, - 0xca, 0x2f, 0x3c, 0xb8, 0x18, 0x80, 0x79, 0x3c, 0x3d, 0xb2, 0x26, 0x07, - 0x27, 0x4c, 0x76, 0xb1, 0x9a, 0x2b, 0xf1, 0xff, 0xce, 0x5c, 0x6a, 0xd1, - 0xa9, 0x5f, 0x04, 0x5b, 0xb1, 0x05, 0x85, 0xdd, 0x0f, 0x03, 0xb1, 0x0a, - 0x7d, 0x7f, 0xef, 0x78, 0xb7, 0xe0, 0xbb, 0xae, 0xc5, 0x2d, 0x0e, 0xf4, - 0x13, 0x45, 0x4f, 0x25, 0xb1, 0x86, 0xb6, 0x6b, 0x24, 0x68, 0x42, 0x4f, - 0x32, 0x93, 0x18, 0xdb, 0x2b, 0x4e, 0x86, 0x59, 0x11, 0x56, 0x15, 0xae, - 0x72, 0x1c, 0x13, 0x07, 0x30, 0xfc, 0x37, 0xd6, 0x90, 0x71, 0x4f, 0xbf, - 0x4c, 0xef, 0xf1, 0x46, 0xd0, 0x85, 0xb3, 0xb4, 0x25, 0xf5, 0x67, 0xb3, - 0xae, 0x21, 0x16, 0xb0, 0xe0, 0xe7, 0x7d, 0x7e, 0xaf, 0x67, 0x5b, 0x54, - 0xf1, 0x69, 0xa0, 0x7d, 0xba, 0x8b, 0x93, 0xbf, 0x36, 0x66, 0x75, 0x4f, - 0x22, 0x8d, 0xa8, 0xe9, 0x73, 0x68, 0x26, 0xf6, 0x01, 0xbe, 0x26, 0x12, - 0x1d, 0xab, 0xf1, 0x25, 0xc6, 0x16, 0x4e, 0xbc, 0x1e, 0x09, 0x56, 0x44, - 0x59, 0xfa, 0x5b, 0xff, 0x96, 0xc1, 0xca, 0x55, 0xe0, 0x78, 0xfb, 0x26, - 0x15, 0x8d, 0x87, 0x8d, 0xa0, 0xcb, 0x77, 0x68, 0xb6, 0xf9, 0x01, 0x3b, - 0x4d, 0x28, 0x1f, 0x58, 0x0f, 0x79, 0xb3, 0x49, 0xd5, 0x76, 0x80, 0x3e, - 0x26, 0xaa, 0xea, 0x32, 0xff, 0xeb, 0x0b, 0xdc, 0xf2, 0xa8, 0x0b, 0xa5, - 0xf4, 0xa6, 0x83, 0xbe, 0x7e, 0xd7, 0x8a, 0x1f, 0xea, 0xc8, 0xcc, 0x82, - 0xb4, 0x60, 0x90, 0x7c, 0xfa, 0x93, 0x92, 0xaa, 0x04, 0xd5, 0x06, 0xa9, - 0xdb, 0x7a, 0x68, 0x89, 0x11, 0x23, 0x9a, 0xd1, 0x77, 0x79, 0x04, 0x01, - 0xf2, 0x2c, 0x70, 0x2b, 0x1d, 0xbc, 0xe3, 0xbe, 0x08, 0xf5, 0x33, 0x15, - 0x35, 0x62, 0x5b, 0x78, 0x9a, 0x3a, 0x6b, 0xc9, 0xc3, 0x20, 0xfa, 0x2a, - 0xd6, 0xf8, 0xbd, 0xd9, 0xbe, 0x34, 0x93, 0x69, 0xcc, 0xa4, 0x4b, 0x71, - 0xe3, 0xcd, 0x70, 0x94, 0xcb, 0xe9, 0xf1, 0x86, 0xc4, 0x4c, 0xa0, 0x6c, - 0x2f, 0x69, 0x93, 0x32, 0xbc, 0x0b, 0x97, 0x79, 0x31, 0x81, 0x9f, 0x23, - 0x1d, 0x1d, 0xf5, 0x2b, 0xa4, 0x81, 0x8a, 0xf0, 0x71, 0xc3, 0x7c, 0x4d, - 0x2b, 0x6d, 0x49, 0x87, 0x3d, 0x50, 0xa4, 0xe2, 0xd7, 0x38, 0x53, 0x69, - 0x0b, 0x8e, 0xaf, 0x02, 0x52, 0x55, 0xd9, 0x4a, 0xe0, 0x06, 0x7e, 0x19, - 0x6d, 0x7f, 0xd7, 0x20, 0x2d, 0xc7, 0xd7, 0x58, 0xda, 0x1c, 0x08, 0xa1, - 0x1c, 0x68, 0x1a, 0xb6, 0x27, 0x4b, 0x9d, 0x84, 0xc8, 0x5c, 0xd9, 0x9b, - 0x4a, 0x02, 0xf2, 0x0f, 0x4e, 0xaf, 0xe8, 0x1b, 0xc2, 0x46, 0x01, 0x14, - 0xfb, 0x81, 0x7e, 0x81, 0xa2, 0x24, 0x15, 0xa9, 0xc7, 0x36, 0xef, 0x18, - 0x68, 0x9c, 0xc2, 0x80, 0xa8, 0xfd, 0x3d, 0x0f, 0x31, 0x85, 0xa6, 0xd4, - 0x35, 0xe4, 0x03, 0xbd, 0x60, 0x25, 0xbf, 0x92, 0xb8, 0x7d, 0x62, 0x93, - 0xb2, 0x16, 0xab, 0x93, 0x28, 0x87, 0x0d, 0x64, 0x21, 0x64, 0x19, 0x1f, - 0x17, 0xff, 0x8f, 0xb5, 0x9c, 0x10, 0xc6, 0x64, 0x3e, 0x55, 0x8e, 0xe6, - 0x01, 0xe0, 0xcc, 0x1f, 0x1a, 0x47, 0x06, 0x30, 0xa9, 0x27, 0x36, 0x5e, - 0xb5, 0xef, 0xf0, 0x98, 0x5e, 0x1e, 0x8a, 0xb0, 0x8e, 0xde, 0xd0, 0xd7, - 0x0e, 0x7f, 0x6c, 0xdf, 0xf3, 0x06, 0x04, 0x3f, 0xae, 0x23, 0x32, 0x2d, - 0x6b, 0xb9, 0x54, 0x48, 0x2a, 0x43, 0xc3, 0x5a, 0xbe, 0x3c, 0x6d, 0x9a, - 0x23, 0x40, 0x65, 0xeb, 0x28, 0xbf, 0x61, 0x4e, 0x9c, 0x16, 0x28, 0x1a, - 0x6b, 0xfa, 0x89, 0x0e, 0xf9, 0xb1, 0x8d, 0x5b, 0xd9, 0x08, 0xa2, 0x60, - 0xb1, 0xf9, 0xb1, 0x41, 0x61, 0xd2, 0x59, 0x46, 0xc9, 0x4c, 0xf2, 0xe7, - 0x33, 0xe2, 0x84, 0x3e, 0xbf, 0x30, 0x15, 0x83, 0xf3, 0x11, 0xb3, 0x12, - 0xf6, 0x0f, 0xcd, 0x5f, 0x8e, 0x09, 0xe7, 0xb6, 0x46, 0xa3, 0x44, 0xdf, - 0x94, 0xd8, 0x25, 0xc5, 0xc9, 0xe3, 0xec, 0x1f, 0xf8, 0x40, 0x1b, 0x25, - 0x4e, 0xf7, 0x5f, 0x76, 0xb0, 0x66, 0x8f, 0xbd, 0xbd, 0xf7, 0xe2, 0x91, - 0xff, 0x5d, 0xc0, 0x24, 0xd4, 0xbe, 0xec, 0x3c, 0x2f, 0x8e, 0x8a, 0xd9, - 0x3f, 0x88, 0x6e, 0xf9, 0xf8, 0x53, 0x42, 0xa7, 0x57, 0xae, 0x95, 0xc7, - 0xf7, 0xd2, 0xd8, 0x35, 0x4c, 0xf9, 0x11, 0x9b, 0x15, 0xa9, 0x7f, 0x5f, - 0x63, 0xfc, 0xc2, 0x22, 0xef, 0xf7, 0x58, 0x66, 0xbe, 0xd5, 0x90, 0xd5, - 0x7d, 0xd4, 0x3f, 0x6c, 0xf8, 0x36, 0x5d, 0xc4, 0x7b, 0x11, 0x9a, 0x11, - 0xb9, 0x08, 0xae, 0x3a, 0xb6, 0x2d, 0x11, 0x3f, 0x0d, 0x60, 0x13, 0xb6, - 0xad, 0xc3, 0xf3, 0xb3, 0x3a, 0x70, 0xe5, 0x4f, 0x98, 0x9f, 0x38, 0xa5, - 0xb7, 0xb7, 0xa8, 0xdd, 0x35, 0x6d, 0x2b, 0x6b, 0xc6, 0xa1, 0x9c, 0x64, - 0xee, 0xee, 0x15, 0x6e, 0x8a, 0x8b, 0x68, 0xed, 0x47, 0x7c, 0xb3, 0xe8, - 0xde, 0x79, 0x3f, 0x68, 0xc6, 0x28, 0x91, 0xf4, 0xae, 0xa8, 0x3f, 0xbc, - 0xc1, 0xa3, 0xbb, 0x46, 0x8f, 0x0e, 0xbb, 0xf7, 0xf0, 0x31, 0x5b, 0x47, - 0x57, 0xc3, 0xbc, 0x25, 0x46, 0xb2, 0x23, 0x11, 0x0d, 0x38, 0x2d, 0x3e, - 0x00, 0xdb, 0x5c, 0x7c, 0x6b, 0x6d, 0x26, 0xbe, 0x2e, 0x5f, 0x92, 0x20, - 0x25, 0x7d, 0x1c, 0x8c, 0xf5, 0x47, 0x81, 0xca, 0x34, 0x68, 0x0d, 0xe2, - 0x47, 0x29, 0x8f, 0xa2, 0xb9, 0x7a, 0xd4, 0x1d, 0x0d, 0x7e, 0x5d, 0x1f, - 0x55, 0xb1, 0xc3, 0x14, 0x9e, 0x74, 0x6d, 0x00, 0x6b, 0xb3, 0x68, 0xbe, - 0x12, 0x15, 0x39, 0x97, 0x1f, 0x8a, 0xc2, 0xd8, 0xc3, 0xf5, 0x39, 0x96, - 0x78, 0x34, 0x37, 0xc5, 0xbe, 0xa0, 0xca, 0x6e, 0xc2, 0x3f, 0xc0, 0x36, - 0x60, 0xca, 0x74, 0x77, 0x49, 0x19, 0x9e, 0x36, 0xff, 0x12, 0xa8, 0x32, - 0x0c, 0x46, 0x32, 0xf6, 0x73, 0xbc, 0x13, 0x2d, 0xb1, 0xf0, 0xa4, 0x50, - 0xb0, 0xdd, 0x36, 0xb9, 0xa1, 0x4f, 0xf0, 0x70, 0x8d, 0x81, 0xfb, 0x44, - 0x3c, 0x8d, 0xc0, 0xd3, 0xd7, 0x52, 0x11, 0x4e, 0x85, 0xf2, 0xac, 0x04, - 0x7c, 0x7c, 0xfa, 0x89, 0x49, 0xd7, 0xf8, 0x91, 0x1b, 0xa0, 0x23, 0x9a, - 0x06, 0xaa, 0x57, 0xf5, 0x49, 0x52, 0xc9, 0x70, 0x44, 0xff, 0x20, 0xad, - 0xa6, 0xce, 0xdb, 0x2f, 0x03, 0xc5, 0xba, 0xc1, 0x18, 0x97, 0xdb, 0x6b, - 0xb0, 0xbd, 0x5a, 0xa9, 0xa0, 0x0e, 0x5e, 0x85, 0x2f, 0x67, 0x35, 0xdb, - 0x60, 0xaa, 0x59, 0x56, 0xf4, 0x5b, 0x11, 0x56, 0x83, 0x18, 0xc0, 0x82, - 0xcb, 0x76, 0xd9, 0x2d, 0xa9, 0xbf, 0xb3, 0x0f, 0x6c, 0x24, 0xc8, 0xcf, - 0xd8, 0x12, 0xf1, 0x6b, 0x3c, 0x79, 0x20, 0x11, 0x18, 0x09, 0xfc, 0x98, - 0x68, 0xfe, 0x5e, 0xe3, 0x22, 0xd7, 0x03, 0xde, 0x54, 0xe4, 0xb7, 0x48, - 0xbc, 0x91, 0xf0, 0xe2, 0x10, 0xcf, 0xcd, 0xdc, 0x99, 0x75, 0xda, 0x37, - 0xab, 0x71, 0xf8, 0x8a, 0xbf, 0x9d, 0x9a, 0x74, 0xf7, 0x79, 0x20, 0xd3, - 0xdf, 0x32, 0x14, 0x88, 0x00, 0x44, 0x35, 0xa4, 0xdd, 0x9b, 0x36, 0x29, - 0x26, 0x0f, 0x60, 0xa3, 0xa2, 0x00, 0x70, 0x91, 0x2d, 0x2c, 0x50, 0xa6, - 0x6b, 0x66, 0x1c, 0x9c, 0xc6, 0xdd, 0x40, 0x6f, 0x9a, 0xee, 0x31, 0x4e, - 0x36, 0x72, 0xf9, 0x90, 0x2c, 0xa1, 0x5e, 0x13, 0xf3, 0x40, 0xa0, 0xad, - 0x39, 0x01, 0x38, 0xb2, 0xc3, 0x36, 0x22, 0x00, 0xe2, 0x5d, 0xbd, 0xa2, - 0xa0, 0x5d, 0xa9, 0x13, 0xd6, 0x86, 0xd6, 0x32, 0xd9, 0xc7, 0x84, 0x03, - 0xb1, 0xe6, 0x20, 0xca, 0x6d, 0x42, 0xb0, 0xc8, 0x66, 0xb6, 0x37, 0x6c, - 0x60, 0x71, 0x61, 0x41, 0x5f, 0x53, 0xe7, 0x14, 0xc3, 0xfe, 0x15, 0xb7, - 0xe5, 0xf1, 0x8b, 0xa5, 0xb7, 0x00, 0xc2, 0x53, 0xaa, 0x0c, 0xf8, 0xc9, - 0x59, 0xe0, 0x06, 0x51, 0xf5, 0xea, 0xcd, 0xb8, 0x7c, 0x49, 0x05, 0x1f, - 0xc5, 0x1c, 0x92, 0x6b, 0xdf, 0x49, 0xbe, 0x5a, 0x1d, 0xde, 0x17, 0x8e, - 0xbe, 0xfe, 0xa0, 0x70, 0x61, 0x3c, 0x70, 0x85, 0xcf, 0x7b, 0x3b, 0x96, - 0xcd, 0xc7, 0xb9, 0xee, 0xc3, 0xdb, 0x43, 0x83, 0x60, 0x16, 0xa5, 0xff, - 0x4c, 0x53, 0xf5, 0x81, 0x06, 0x43, 0x98, 0xa3, 0xf4, 0xa7, 0x9d, 0x25, - 0x35, 0x2e, 0xf4, 0xe4, 0x7c, 0x8d, 0x46, 0xd2, 0x75, 0xb1, 0xa8, 0xd9, - 0x63, 0x9b, 0xaf, 0x8a, 0x69, 0x9a, 0x9c, 0xf2, 0x84, 0x89, 0x62, 0x76, - 0xc0, 0xa7, 0xc8, 0x1e, 0x87, 0x5c, 0x0a, 0xdf, 0xdc, 0xf4, 0x43, 0xed, - 0xde, 0x86, 0x7a, 0x59, 0x76, 0x32, 0x8f, 0xec, 0x81, 0x81, 0xaa, 0x7f, - 0xb6, 0x91, 0x3b, 0x1d, 0xca, 0x9c, 0x27, 0xdb, 0xfc, 0x7e, 0x30, 0x18, - 0x08, 0x87, 0xd5, 0x43, 0x21, 0xc0, 0xc9, 0x4c, 0x9c, 0x8c, 0xb2, 0x57, - 0x06, 0x04, 0x9f, 0x51, 0x7f, 0x1b, 0x5a, 0x0b, 0xf0, 0xa7, 0x06, 0xb9, - 0xa2, 0x61, 0xc5, 0x35, 0x0c, 0xc0, 0x8e, 0x72, 0x65, 0xfc, 0xf4, 0x7b, - 0xdc, 0xcc, 0x58, 0x5b, 0x28, 0x36, 0xec, 0x27, 0xe7, 0x36, 0xb7, 0xb6, - 0xae, 0x1f, 0x06, 0xad, 0x96, 0x02, 0x20, 0xae, 0x73, 0x1f, 0x2f, 0x6f, - 0x3e, 0x82, 0x66, 0xa4, 0x82, 0x7e, 0x78, 0xb1, 0x3c, 0x85, 0x22, 0x2b, - 0x94, 0xb3, 0xdb, 0x38, 0x17, 0x1c, 0x9f, 0x25, 0x01, 0x01, 0x86, 0xa5, - 0xb0, 0x2f, 0x7a, 0xf3, 0x9d, 0x4b, 0x68, 0x97, 0x0d, 0x01, 0x74, 0x43, - 0x83, 0x19, 0x1a, 0x8e, 0xb3, 0x29, 0x7e, 0x07, 0x69, 0x09, 0xd7, 0xd2, - 0xfe, 0x42, 0xd9, 0xc8, 0xa7, 0x1a, 0x81, 0xdb, 0xe6, 0xe1, 0xff, 0xa8, - 0xd7, 0x7a, 0xd9, 0xc0, 0x08, 0x41, 0xf4, 0xea, 0xc0, 0x5f, 0xf1, 0xb9, - 0x2a, 0xd9, 0x06, 0xe9, 0x07, 0x03, 0x50, 0xc0, 0x13, 0xf9, 0xec, 0x83, - 0x06, 0xb5, 0x46, 0xac, 0x6c, 0xdd, 0x5c, 0x9a, 0x82, 0x3a, 0x10, 0xca, - 0x5c, 0x7a, 0x5e, 0x71, 0x20, 0xf1, 0xd4, 0x4c, 0xf1, 0x15, 0x29, 0x1b, - 0x72, 0x0e, 0x0e, 0xdb, 0x33, 0xb3, 0x81, 0x81, 0xb1, 0x38, 0x7a, 0x97, - 0xe8, 0xa2, 0x53, 0x33, 0x01, 0x0b, 0x81, 0x3f, 0x02, 0xa7, 0xca, 0xcd, - 0x3b, 0x04, 0xa3, 0x11, 0x66, 0x3e, 0x36, 0xc8, 0xa0, 0xa6, 0x65, 0x7e, - 0x42, 0x10, 0x46, 0x2a, 0x00, 0x84, 0xa8, 0xc0, 0x66, 0x5f, 0x1f, 0xab, - 0x05, 0xb9, 0xe8, 0xe2, 0x6b, 0x85, 0x76, 0xdf, 0x51, 0x27, 0x43, 0x46, - 0x05, 0xce, 0xfe, 0x1a, 0xf9, 0x0e, 0xe2, 0xca, 0xaf, 0x07, 0x04, 0x99, - 0x1a, 0xa8, 0xe5, 0x5d, 0xe3, 0x80, 0x5f, 0xe1, 0x40, 0x3d, 0xb2, 0xfe, - 0xb7, 0x75, 0x72, 0xed, 0xee, 0x9c, 0x76, 0x11, 0x19, 0x08, 0x7c, 0xc1, - 0x3c, 0x01, 0xf3, 0x01, 0x8f, 0x39, 0xdf, 0x63, 0xc5, 0x20, 0xf0, 0x2a, - 0x80, 0x4e, 0x03, 0x9a, 0x47, 0x19, 0x5e, 0xc1, 0xc5, 0xf0, 0x5b, 0xf0, - 0x4a, 0x7c, 0x5a, 0x74, 0xc7, 0xa1, 0xb9, 0xd4, 0xd8, 0x0f, 0xd1, 0xf6, - 0xb6, 0x7a, 0x28, 0x3a, 0x01, 0x0e, 0xed, 0xc8, 0x70, 0x13, 0x6d, 0x3d, - 0x36, 0xb1, 0x71, 0xcb, 0x01, 0x07, 0xcc, 0x10, 0xc3, 0x47, 0xfe, 0x79, - 0x4c, 0x0c, 0xa8, 0x9e, 0x92, 0x74, 0xea, 0x13, 0xff, 0x15, 0xaf, 0x36, - 0x1d, 0xef, 0xaa, 0x6a, 0x5f, 0xf4, 0x5a, 0x00, 0x0f, 0x88, 0x91, 0xbe, - 0x53, 0x9c, 0xf6, 0x0d, 0x0c, 0xa7, 0x4e, 0x59, 0x4b, 0x23, 0x07, 0x9d, - 0x38, 0x27, 0x3e, 0x99, 0x1c, 0xb3, 0xda, 0xeb, 0x41, 0xb0, 0x2a, 0x6a, - 0xff, 0xd9, 0xb2, 0x3a, 0xa5, 0x12, 0x91, 0x9a, 0xc5, 0xab, 0x79, 0x35, - 0x45, 0xb4, 0xb4, 0x40, 0x9b, 0xa9, 0x4e, 0x63, 0xda, 0xd4, 0x8b, 0xa3, - 0x5f, 0x4a, 0x74, 0x90, 0x52, 0x88, 0x2b, 0x6f, 0x36, 0x4f, 0xb8, 0x6f, - 0x27, 0xbe, 0x4c, 0xe4, 0xfb, 0xb7, 0x0b, 0x0f, 0xd4, 0x0c, 0xee, 0xcf, - 0xb8, 0xa9, 0x9b, 0x2c, 0x13, 0xb5, 0xb2, 0xfd, 0xff, 0x2f, 0x5f, 0xad, - 0xa3, 0xc1, 0xd2, 0x7f, 0x56, 0xdf, 0x37, 0x06, 0x13, 0xf1, 0x78, 0x28, - 0xd8, 0xc0, 0xfb, 0x51, 0x7a, 0x47, 0x02, 0x13, 0x52, 0xf7, 0x2c, 0xd8, - 0x41, 0xda, 0x93, 0x91, 0x7c, 0x55, 0xe6, 0x77, 0x0a, 0x66, 0xc4, 0x76, - 0x5a, 0x99, 0xe0, 0x13, 0xd9, 0x8e, 0x70, 0xea, 0x23, 0xe5, 0xc6, 0xc7, - 0xda, 0xef, 0x78, 0xf8, 0x4b, 0x32, 0xe2, 0x50, 0xc7, 0x98, 0x94, 0x0a, - 0x32, 0xae, 0xcc, 0x3a, 0xe6, 0xca, 0xe2, 0xd1, 0xd7, 0x80, 0x0c, 0xb6, - 0x24, 0x65, 0xea, 0x21, 0x49, 0x22, 0x86, 0x4c, 0x85, 0x5f, 0x53, 0xca, - 0x53, 0x9a, 0xd4, 0x05, 0xab, 0x49, 0xfc, 0x05, 0xf2, 0xae, 0x1f, 0xdb, - 0x49, 0xdb, 0x84, 0x6e, 0x6c, 0xbf, 0xcb, 0x65, 0xdf, 0xf3, 0xd3, 0x29, - 0x93, 0xb0, 0x91, 0x3e, 0xf7, 0x8a, 0xfa, 0xca, 0xce, 0x82, 0x8c, 0x5e, - 0x2c, 0x04, 0xf7, 0x2a, 0x3b, 0x3a, 0x11, 0xaf, 0x9a, 0x94, 0xba, 0x7e, - 0xea, 0x14, 0x9a, 0x18, 0xc4, 0x26, 0x8a, 0x6f, 0x90, 0x26, 0x65, 0x5d, - 0x3b, 0x9f, 0x6b, 0xe7, 0x60, 0xea, 0x97, 0xf0, 0x4a, 0x40, 0x9e, 0x2e, - 0x23, 0x9b, 0x7b, 0x73, 0x7a, 0x55, 0xf9, 0xe4, 0x51, 0x9d, 0xdb, 0x4b, - 0xf7, 0xff, 0x6e, 0x47, 0xea, 0x02, 0xc0, 0xda, 0xda, 0x7b, 0xd8, 0x8f, - 0x00, 0x51, 0xec, 0xcd, 0xe1, 0xbc, 0xe5, 0x9f, 0xcb, 0xde, 0x8c, 0x9f, - 0x9f, 0x67, 0xbd, 0xaf, 0x25, 0x05, 0xb1, 0xe4, 0xc3, 0xc9, 0xf0, 0x14, - 0x82, 0x98, 0x65, 0x3f, 0x8a, 0x96, 0xa3, 0x83, 0x60, 0x42, 0x5e, 0x3d, - 0x85, 0x15, 0x7d, 0x7e, 0x83, 0x1e, 0x6c, 0x30, 0xfd, 0x03, 0x72, 0x46, - 0x14, 0x47, 0x2a, 0x2b, 0xb9, 0xef, 0x88, 0x7c, 0x65, 0x7d, 0x2d, 0x7e, - 0xdc, 0x29, 0xcd, 0x69, 0x6e, 0x61, 0x24, 0x4e, 0x7e, 0xa0, 0x12, 0x28, - 0x9e, 0xa5, 0x4b, 0x91, 0x97, 0x8b, 0xec, 0x61, 0xfe, 0x78, 0x59, 0xde, - 0xdd, 0xeb, 0x0e, 0xd4, 0x6f, 0xd1, 0xc4, 0xd5, 0x06, 0xb7, 0xf8, 0xe4, - 0xa4, 0x76, 0x90, 0x7d, 0xc2, 0xcb, 0x0c, 0xe4, 0x27, 0x37, 0x50, 0xd7, - 0x97, 0x0c, 0xc5, 0x87, 0xd5, 0x92, 0x65, 0x12, 0xd4, 0xe4, 0xf9, 0x49, - 0xa5, 0x3b, 0x63, 0xe7, 0xe1, 0x46, 0x1c, 0x49, 0xf2, 0xe2, 0x10, 0xf7, - 0x29, 0x7c, 0x45, 0xae, 0x46, 0xbb, 0xe6, 0xd9, 0xd6, 0x08, 0x38, 0x35, - 0x0f, 0x25, 0x7e, 0x2a, 0xe7, 0x29, 0xea, 0xdd, 0xff, 0x37, 0x75, 0x38, - 0xab, 0x8d, 0x2f, 0x26, 0x92, 0xe0, 0xf2, 0x9b, 0x22, 0xb9, 0x4f, 0xb4, - 0x1a, 0x33, 0xad, 0xe2, 0x7d, 0xa9, 0x98, 0x9e, 0xfb, 0x03, 0xd7, 0x60, - 0x3e, 0xa6, 0x03, 0x07, 0xa0, 0x81, 0x96, 0x6f, 0x67, 0x27, 0xa7, 0x5a, - 0x27, 0x69, 0xc4, 0x39, 0xca, 0x0a, 0x0e, 0xb6, 0x52, 0xd6, 0xee, 0x55, - 0xb2, 0xf6, 0x7d, 0x3e, 0x1d, 0x66, 0x5e, 0x8e, 0xbf, 0x80, 0x93, 0xc7, - 0x28, 0x60, 0xb1, 0x42, 0x48, 0xd0, 0x36, 0x85, 0xa1, 0x85, 0x91, 0x4a, - 0x2c, 0x07, 0x55, 0xc9, 0xf0, 0x7c, 0xaa, 0x68, 0x2c, 0x1a, 0xdf, 0xc8, - 0xba, 0xf6, 0xe7, 0xe7, 0xa2, 0xaf, 0xa1, 0xe7, 0x50, 0x74, 0xb5, 0x4d, - 0xf0, 0x45, 0xb7, 0x7f, 0x6c, 0xf0, 0xe6, 0x18, 0x9e, 0xe2, 0x73, 0x07, - 0x7f, 0x1d, 0x17, 0x7d, 0x36, 0xf4, 0x37, 0xef, 0x14, 0x88, 0xb7, 0xed, - 0x97, 0x54, 0x40, 0x7c, 0x1c, 0xd2, 0x7a, 0xc4, 0x35, 0xe9, 0x37, 0xaa, - 0xbe, 0x6c, 0x25, 0x95, 0x5e, 0x10, 0x5a, 0x7c, 0x36, 0x36, 0xbf, 0xdf, - 0x77, 0x01, 0xcb, 0x78, 0x52, 0x60, 0x63, 0xac, 0xc5, 0x52, 0xf3, 0xc3, - 0x73, 0x6d, 0x19, 0x49, 0x84, 0x35, 0x0f, 0x9a, 0x94, 0x2d, 0x89, 0xfb, - 0xa4, 0x73, 0x5d, 0x55, 0xa5, 0x42, 0x3c, 0x49, 0x70, 0xbf, 0xc4, 0x83, - 0x57, 0xd8, 0xfe, 0x1d, 0x31, 0x8d, 0xa0, 0xa0, 0x18, 0xa8, 0x45, 0x2c, - 0xfb, 0xf4, 0xd5, 0x0c, 0x37, 0xd9, 0xf8, 0xfe, 0x89, 0xbd, 0x9b, 0xc2, - 0x7c, 0x9b, 0x4d, 0x1b, 0x5c, 0x2f, 0xe2, 0xa1, 0x68, 0x7f, 0xb2, 0xcd, - 0x2f, 0x80, 0x0e, 0x6b, 0xf0, 0xb4, 0x9c, 0x20, 0xb0, 0x14, 0xf4, 0x06, - 0xb5, 0x27, 0x24, 0x9f, 0x90, 0xc4, 0x5f, 0x7d, 0xd5, 0xde, 0x56, 0xb8, - 0x50, 0x7f, 0x2f, 0xe1, 0x82, 0x0c, 0x52, 0xd6, 0x38, 0x4f, 0x9f, 0xf9, - 0xe5, 0x2f, 0x52, 0xba, 0x5b, 0xaf, 0xa2, 0x6e, 0xe2, 0xee, 0x06, 0xf2, - 0x70, 0xcf, 0x5f, 0x3a, 0x24, 0xf5, 0xa2, 0xc6, 0x74, 0x1b, 0xf8, 0xd5, - 0xf5, 0x3d, 0xa1, 0x24, 0x05, 0x7a, 0xb6, 0xb4, 0x77, 0xa8, 0x38, 0x59, - 0x3f, 0xc6, 0xad, 0x65, 0xc3, 0x01, 0xe0, 0x92, 0xe9, 0x90, 0xd8, 0x82, - 0x04, 0x30, 0x92, 0xea, 0xc4, 0xdd, 0xa5, 0x51, 0xf8, 0xcd, 0x7b, 0x54, - 0xfd, 0xe6, 0x64, 0x5f, 0x41, 0x20, 0xca, 0x7f, 0xfd, 0x6c, 0x0b, 0xb4, - 0xb4, 0xe4, 0xad, 0xaf, 0x04, 0x0a, 0xfc, 0xa1, 0x61, 0xdc, 0x92, 0xcf, - 0xc8, 0xa4, 0x54, 0xe4, 0x8d, 0xd3, 0x11, 0x20, 0x95, 0x9c, 0xeb, 0xdc, - 0xea, 0x69, 0xe9, 0xcf, 0xbd, 0xc0, 0xcb, 0xde, 0xce, 0x3e, 0xfc, 0x01, - 0xbb, 0xee, 0x51, 0xab, 0x7e, 0xf2, 0x3a, 0x01, 0x84, 0xe7, 0x5f, 0x94, - 0xd6, 0x78, 0x77, 0x8a, 0x3d, 0x9c, 0x77, 0xdc, 0x14, 0xec, 0x71, 0xb5, - 0xbe, 0xc5, 0x46, 0xbd, 0x05, 0xba, 0x01, 0xeb, 0x83, 0x6c, 0xec, 0xff, - 0x67, 0x94, 0xef, 0x25, 0x86, 0x95, 0xd4, 0x00, 0x55, 0x93, 0xbd, 0xf7, - 0x7a, 0x22, 0x9f, 0x26, 0x8f, 0xf6, 0x8f, 0xe1, 0x8b, 0xcd, 0x12, 0x1b, - 0xc8, 0x79, 0xb0, 0x4b, 0x0d, 0x33, 0xac, 0x52, 0x46, 0x7b, 0x9e, 0x00, - 0x2b, 0x5e, 0x17, 0x9d, 0x3d, 0xeb, 0x73, 0xe5, 0xa2, 0x84, 0x7e, 0x32, - 0x02, 0x89, 0xe0, 0x7a, 0x8e, 0xcf, 0x18, 0xbb, 0x14, 0xc8, 0x3a, 0x59, - 0x92, 0x48, 0x51, 0x10, 0xd0, 0xd8, 0x46, 0xb1, 0xeb, 0xfc, 0x69, 0xfd, - 0xff, 0x44, 0x4c, 0x1f, 0x64, 0x44, 0xab, 0xcf, 0x4b, 0x74, 0xfc, 0x9e, - 0x7b, 0xea, 0x83, 0x7e, 0x08, 0xdb, 0x44, 0xd7, 0xed, 0x85, 0xa9, 0x08, - 0x02, 0xb4, 0x14, 0xfa, 0x2b, 0xa9, 0x86, 0x7d, 0x26, 0xbb, 0x95, 0x55, - 0x2f, 0xe0, 0x49, 0x71, 0x95, 0xa4, 0xef, 0x6e, 0xb6, 0x6a, 0x17, 0xaa, - 0x56, 0xab, 0xa2, 0xe4, 0xcc, 0x5a, 0x8d, 0x62, 0x3b, 0xaf, 0xe1, 0x59, - 0xa8, 0xf8, 0x0e, 0x20, 0x18, 0x83, 0x25, 0xe6, 0xee, 0xf3, 0xb8, 0x55, - 0x2d, 0x10, 0xa8, 0xaa, 0x82, 0x6e, 0xa1, 0x7d, 0x76, 0x7f, 0x03, 0x36, - 0x70, 0x58, 0x11, 0xbc, 0xa1, 0xe9, 0x18, 0xfe, 0x2c, 0xfc, 0xda, 0xa8, - 0x1f, 0xcc, 0x5f, 0x34, 0x36, 0x33, 0x69, 0x6e, 0x2e, 0xa5, 0x84, 0x44, - 0x02, 0xcc, 0xd7, 0x84, 0xfc, 0xf8, 0x0a, 0xfd, 0xed, 0x3f, 0x73, 0x4a, - 0x6e, 0x39, 0x05, 0x19, 0x8c, 0x0e, 0x98, 0xd3, 0xea, 0x70, 0xd2, 0xc8, - 0xf9, 0xb6, 0x22, 0xd3, 0x85, 0x86, 0xc9, 0xd3, 0xb4, 0x9c, 0x2c, 0xd7, - 0x91, 0x54, 0x95, 0xcf, 0x8c, 0x74, 0xa5, 0x1d, 0xf2, 0x0b, 0xce, 0x7d, - 0x5b, 0xde, 0xca, 0xb4, 0x25, 0x8e, 0x1d, 0x7e, 0x0b, 0x58, 0xb0, 0xaa, - 0x00, 0x64, 0xdf, 0x87, 0xef, 0x4e, 0x50, 0x69, 0x44, 0x20, 0xa5, 0x9c, - 0xf6, 0x4f, 0x1f, 0x68, 0x31, 0xc4, 0x36, 0x0d, 0xdf, 0x5c, 0x66, 0x32, - 0xac, 0x76, 0x16, 0x2b, 0xd8, 0xd5, 0x60, 0xe4, 0xae, 0x8a, 0x97, 0xed, - 0xc4, 0xd5, 0x07, 0xf5, 0x0a, 0xea, 0x4a, 0x50, 0x10, 0xfb, 0x40, 0x4d, - 0xe1, 0x4a, 0x1e, 0x16, 0x7a, 0x2c, 0xd3, 0x17, 0xf9, 0x87, 0x71, 0x3a, - 0xa0, 0x7f, 0x4d, 0xa1, 0x53, 0x47, 0xc7, 0xb6, 0x95, 0x7e, 0x74, 0xbf, - 0x5e, 0x06, 0x16, 0x06, 0x0b, 0x4c, 0xab, 0x0f, 0x9a, 0xb5, 0x37, 0x0f, - 0xd2, 0xd4, 0x9c, 0xae, 0xf8, 0xdd, 0xf8, 0xd7, 0xfd, 0x96, 0xa8, 0x3b, - 0x05, 0xee, 0x1b, 0xb7, 0x5b, 0x4f, 0x62, 0xe9, 0x0b, 0x4f, 0x2a, 0x54, - 0x14, 0x14, 0xdf, 0x69, 0xf2, 0x36, 0xfd, 0x26, 0xce, 0x43, 0x0a, 0x9c, - 0x18, 0xc5, 0x77, 0xd2, 0x89, 0xaf, 0x65, 0xa9, 0x6a, 0xab, 0x42, 0xdb, - 0xde, 0xe9, 0xc2, 0xf8, 0x89, 0xe0, 0xcf, 0x87, 0xac, 0x24, 0xa6, 0xc7, - 0x19, 0x13, 0x6c, 0x62, 0xa6, 0xa9, 0x59, 0x92, 0xdc, 0x4a, 0x3d, 0x78, - 0x17, 0x78, 0x94, 0xd0, 0xbb, 0xb8, 0x74, 0x29, 0xe6, 0x62, 0xaa, 0x86, - 0x6a, 0x62, 0x37, 0xd8, 0xdf, 0x95, 0x31, 0x7a, 0xc6, 0xef, 0x86, 0x6c, - 0x9f, 0x28, 0x53, 0x24, 0x7b, 0x64, 0xc8, 0x3b, 0x37, 0x3b, 0x84, 0x21, - 0x0b, 0x84, 0xc7, 0xb6, 0x23, 0x45, 0x59, 0xf2, 0xcb, 0xf8, 0x28, 0xe7, - 0xf5, 0xeb, 0x3c, 0xdd, 0x40, 0xb9, 0xf5, 0xf7, 0x47, 0xce, 0x7a, 0xee, - 0x43, 0x6c, 0x00, 0xc8, 0x7d, 0x81, 0x5f, 0xc1, 0xb2, 0xfc, 0xef, 0x8c, - 0xd0, 0x47, 0x90, 0x70, 0x86, 0x69, 0xae, 0x47, 0x2c, 0x7e, 0xde, 0x97, - 0x7e, 0x47, 0xe5, 0x66, 0xcf, 0xf2, 0xe7, 0x83, 0xfe, 0xe4, 0xae, 0xbd, - 0x40, 0x68, 0x8a, 0x8f, 0xf9, 0x22, 0xc0, 0xf4, 0x30, 0x0e, 0x41, 0x3c, - 0x80, 0xc6, 0xaf, 0x09, 0x96, 0xf8, 0x64, 0x7b, 0x00, 0x80, 0x89, 0x0e, - 0xa4, 0xf3, 0x7f, 0x84, 0x11, 0xd6, 0x24, 0xf0, 0x82, 0x03, 0xf3, 0x04, - 0xdb, 0x02, 0xdc, 0x50, 0xdf, 0x0b, 0x90, 0x3e, 0xf4, 0xb2, 0x53, 0xa4, - 0xf1, 0xe5, 0x5c, 0x21, 0xb5, 0x43, 0xa5, 0xfc, 0xc4, 0xb1, 0x5e, 0xff, - 0x32, 0x03, 0xcb, 0x64, 0xbd, 0x92, 0x4d, 0x59, 0xbb, 0x05, 0x77, 0x6f, - 0x02, 0xce, 0xd2, 0xc7, 0x67, 0x9b, 0x92, 0xd9, 0x69, 0x5c, 0xe0, 0x70, - 0x2c, 0x61, 0x66, 0xb5, 0x74, 0x4a, 0xb9, 0x0c, 0x67, 0xcb, 0x34, 0xfa, - 0xdd, 0x4d, 0xbd, 0x83, 0xed, 0x9b, 0xc5, 0x1d, 0x8d, 0x75, 0x10, 0x04, - 0x9b, 0xf3, 0xeb, 0xc8, 0x6f, 0x37, 0x9a, 0x8b, 0x51, 0x89, 0xbc, 0xcb, - 0x88, 0x34, 0xf9, 0x66, 0xdb, 0x18, 0x76, 0x2f, 0xd4, 0x31, 0x1f, 0x08, - 0xe0, 0xca, 0x69, 0xc9, 0x35, 0xf8, 0x0b, 0xe4, 0xef, 0x9c, 0x7f, 0x4e, - 0x23, 0x67, 0x23, 0x5c, 0x78, 0xcb, 0x43, 0xbd, 0x3a, 0xe5, 0x5d, 0xc6, - 0x1f, 0x54, 0xbc, 0x7d, 0xf0, 0x00, 0x45, 0x01, 0x03, 0x1b, 0x97, 0x7e, - 0xdf, 0x60, 0x96, 0x67, 0x65, 0x46, 0xe2, 0x8a, 0x5f, 0x98, 0x7d, 0x13, - 0x84, 0x0f, 0x20, 0x18, 0x33, 0xcb, 0x84, 0x90, 0x1a, 0xa6, 0xa1, 0xf2, - 0xc4, 0xf6, 0x0c, 0xd7, 0x75, 0xdf, 0xa8, 0xd0, 0x7d, 0xb7, 0x6f, 0x7c, - 0xa2, 0x8c, 0xcc, 0x59, 0xf0, 0xed, 0x4a, 0x4d, 0x0e, 0x51, 0x5f, 0x24, - 0x2c, 0x00, 0x0f, 0xbb, 0x7e, 0x07, 0xba, 0x9f, 0xe6, 0x06, 0x3e, 0xf1, - 0x94, 0xde, 0x17, 0x09, 0xe4, 0xa2, 0xbe, 0xe6, 0x7e, 0x1e, 0x3e, 0x09, - 0xd4, 0x21, 0xdf, 0xa7, 0xa4, 0xde, 0x06, 0xc8, 0xa5, 0xef, 0x4d, 0x7e, - 0x41, 0xcb, 0xfc, 0x01, 0x68, 0x5e, 0xfb, 0xc1, 0xfb, 0xfa, 0x9a, 0xef, - 0xdc, 0x88, 0xdf, 0x0f, 0x51, 0x78, 0x4f, 0x0f, 0x07, 0x81, 0xd2, 0xc0, - 0x84, 0x98, 0xd7, 0xe2, 0xd5, 0x91, 0x13, 0xf6, 0xc9, 0xa4, 0xa0, 0x2b, - 0x3f, 0x73, 0x28, 0x3d, 0xa1, 0x3f, 0x68, 0x9f, 0x21, 0xe1, 0x34, 0x11, - 0xd9, 0xf2, 0x93, 0xb7, 0x5d, 0xba, 0x06, 0x1e, 0x27, 0x18, 0x1f, 0x92, - 0x5d, 0xc8, 0x78, 0x0d, 0x74, 0xa3, 0x47, 0xe8, 0x80, 0xa4, 0x72, 0x63, - 0xc7, 0x3d, 0x65, 0x4e, 0x8e, 0x9e, 0xbe, 0x06, 0xe6, 0xb6, 0x89, 0x14, - 0xd1, 0x63, 0x0c, 0x09, 0x7b, 0x06, 0x7b, 0x6d, 0x16, 0x00, 0x05, 0xa6, - 0x13, 0x8a, 0xb7, 0x6f, 0x0f, 0x9a, 0x56, 0x11, 0x33, 0x06, 0xa2, 0x70, - 0xcd, 0x23, 0xb5, 0xd3, 0x3c, 0x92, 0xa4, 0xb9, 0x6e, 0x10, 0xd8, 0x2b, - 0xc3, 0xa8, 0xf9, 0x24, 0x8b, 0xcf, 0xb7, 0xb1, 0x45, 0xf0, 0xd5, 0x31, - 0x73, 0x28, 0x45, 0x10, 0xd6, 0xa4, 0x2e, 0x3b, 0xe8, 0xbb, 0x82, 0x1a, - 0x27, 0x3f, 0x61, 0xaa, 0x82, 0xd7, 0xc5, 0x12, 0x89, 0x94, 0xec, 0x05, - 0xe5, 0xd2, 0x7f, 0x49, 0x1d, 0x90, 0xa9, 0xa6, 0x85, 0x14, 0x15, 0xf5, - 0x2d, 0x1a, 0x65, 0xb8, 0x9c, 0x85, 0xd0, 0x6c, 0x37, 0x0d, 0xa8, 0x78, - 0xd5, 0x17, 0x62, 0x8a, 0xb1, 0xa6, 0xf1, 0x3a, 0xf0, 0x18, 0x1e, 0xfc, - 0x0c, 0x7d, 0xa4, 0x57, 0x31, 0x77, 0x5e, 0xf8, 0x8f, 0xfb, 0x8a, 0x28, - 0x10, 0x47, 0xe6, 0xa1, 0xdd, 0x6a, 0xfb, 0x58, 0xf6, 0xc1, 0x6b, 0x51, - 0x4a, 0xa4, 0x4a, 0x70, 0x1c, 0x1f, 0xf0, 0x60, 0xcb, 0x7a, 0x14, 0x04, - 0x3e, 0x8b, 0x6b, 0x2f, 0x55, 0x5c, 0x5c, 0xb1, 0xf2, 0xf6, 0x73, 0x36, - 0xdc, 0x80, 0x1e, 0xe5, 0xdc, 0x4e, 0x93, 0x4c, 0x83, 0x37, 0x66, 0xa4, - 0x13, 0x68, 0x78, 0x25, 0xe4, 0x33, 0x81, 0xfa, 0x0c, 0x38, 0xd4, 0x91, - 0x61, 0x5e, 0x15, 0x5e, 0xf2, 0x26, 0xc4, 0xa7, 0xdc, 0x6b, 0x82, 0xf0, - 0xed, 0xa3, 0x42, 0xf8, 0xff, 0x23, 0xe4, 0x4c, 0x96, 0xd1, 0x38, 0x9f, - 0xad, 0x86, 0xdf, 0x8e, 0xcd, 0xc1, 0xd9, 0x9c, 0xe7, 0x6c, 0x01, 0x43, - 0x2c, 0x3a, 0x4d, 0x77, 0x6c, 0x67, 0x6f, 0xac, 0xee, 0x96, 0x5e, 0x1f, - 0x42, 0xd0, 0x84, 0x12, 0xd7, 0xae, 0x51, 0x6b, 0x42, 0xc4, 0x8e, 0x89, - 0x27, 0xd8, 0x07, 0x6f, 0x48, 0x82, 0x65, 0x43, 0x82, 0x94, 0x85, 0xde, - 0x48, 0xf0, 0x5e, 0x45, 0x3b, 0x3e, 0x31, 0xb1, 0x7d, 0x0c, 0x1c, 0x5d, - 0xdf, 0xc0, 0x7a, 0x06, 0x03, 0xea, 0xf2, 0x3d, 0xad, 0xd4, 0xdf, 0xdb, - 0xc5, 0xb5, 0x9e, 0x6c, 0xed, 0x54, 0x47, 0x4d, 0x47, 0xea, 0x99, 0xe4, - 0x27, 0xad, 0x59, 0x24, 0xfa, 0x47, 0x8c, 0x51, 0xc3, 0xf9, 0x4d, 0x05, - 0x24, 0x2b, 0x94, 0xa5, 0x27, 0xbb, 0xa6, 0x8c, 0x06, 0x57, 0x2d, 0xec, - 0x59, 0x4a, 0x60, 0x00, 0x08, 0x04, 0x5e, 0x1d, 0x4d, 0x6e, 0x50, 0x49, - 0x4c, 0x0c, 0xdf, 0xe2, 0x7d, 0x1e, 0x58, 0x89, 0xee, 0x07, 0x7c, 0x15, - 0x2b, 0x00, 0x3c, 0x50, 0xea, 0x61, 0xc8, 0x9c, 0x22, 0x46, 0xf8, 0xa1, - 0xfa, 0x6d, 0x99, 0x9f, 0xab, 0x04, 0xc5, 0x61, 0xc5, 0x8d, 0xaf, 0xd2, - 0x5e, 0xd2, 0x4e, 0x80, 0x84, 0x61, 0x2c, 0xef, 0xa3, 0x4b, 0xd7, 0xd2, - 0xe4, 0xba, 0x42, 0xbb, 0x9f, 0x5f, 0xac, 0x56, 0xa7, 0x99, 0x29, 0x92, - 0xc1, 0xfb, 0x76, 0xd9, 0xa8, 0xb5, 0xef, 0x96, 0xfe, 0x4d, 0xdb, 0x09, - 0x9e, 0xa2, 0xde, 0xd7, 0x4e, 0x2b, 0x83, 0xb5, 0xf4, 0x0b, 0xd3, 0x8c, - 0x9e, 0xfb, 0xbf, 0x68, 0xb4, 0x14, 0x4e, 0x45, 0x9a, 0x39, 0x69, 0x15, - 0x35, 0x74, 0xcd, 0x46, 0xed, 0x5d, 0x05, 0xf3, 0xcc, 0x81, 0xb3, 0x30, - 0x03, 0x4b, 0x28, 0x6e, 0xa0, 0x8d, 0x07, 0x21, 0x3e, 0x75, 0x1c, 0x8e, - 0x84, 0xa4, 0x2f, 0xd4, 0x4f, 0xa0, 0x60, 0xcd, 0xf7, 0xcb, 0x88, 0xbb, - 0xb9, 0x7f, 0x68, 0x7e, 0xcb, 0x46, 0x95, 0x8d, 0x47, 0x1e, 0xec, 0xc1, - 0x8c, 0x76, 0xf1, 0x2a, 0xa0, 0x9f, 0x85, 0x91, 0xc8, 0xaf, 0xa9, 0x23, - 0x3f, 0x30, 0x6c, 0x7c, 0x5b, 0xdb, 0xf8, 0x80, 0x6d, 0x61, 0x59, 0xe7, - 0x73, 0x81, 0xe6, 0xfd, 0xdf, 0x5c, 0x21, 0x6a, 0x18, 0x1f, 0xe5, 0x32, - 0x7e, 0x8a, 0xa0, 0xe5, 0x53, 0xdc, 0x59, 0xb5, 0x51, 0x44, 0x4a, 0x04, - 0x73, 0x18, 0x89, 0x55, 0xdb, 0x8f, 0x6e, 0x07, 0x03, 0xd8, 0x8e, 0x3c, - 0xdf, 0x16, 0xb6, 0x04, 0x08, 0xb1, 0x52, 0xcb, 0xf3, 0x6d, 0xa5, 0xda, - 0x54, 0x02, 0xeb, 0xfb, 0x75, 0x3d, 0xd2, 0xae, 0xe0, 0xb4, 0x56, 0xc8, - 0xbd, 0x08, 0x50, 0x2d, 0xa6, 0xc0, 0x18, 0x81, 0x98, 0xdd, 0xcd, 0x0b, - 0xfe, 0x1e, 0xdc, 0xb1, 0x26, 0x71, 0xc1, 0xd3, 0xf7, 0xba, 0xbc, 0xc9, - 0x8d, 0x12, 0xc2, 0x14, 0x9e, 0x77, 0xea, 0x60, 0x74, 0x1f, 0x07, 0x61, - 0x0f, 0xd0, 0xb9, 0x3a, 0x56, 0xc0, 0xa5, 0xd8, 0xc7, 0xe1, 0xd4, 0x46, - 0x01, 0x4d, 0x42, 0x63, 0xcb, 0xbc, 0x2b, 0x67, 0xb5, 0xdb, 0x7a, 0x8c, - 0xb0, 0x73, 0x9e, 0x6c, 0x39, 0x8e, 0xe2, 0x30, 0xb4, 0x80, 0x7a, 0xfc, - 0x63, 0x90, 0x9e, 0x21, 0x93, 0xb2, 0x80, 0xaa, 0x67, 0x2f, 0x57, 0x99, - 0x90, 0x7f, 0x63, 0x05, 0x9d, 0x12, 0x02, 0x72, 0x24, 0xd6, 0x08, 0xde, - 0x2f, 0x51, 0x4e, 0x5d, 0x2d, 0x1d, 0x94, 0x6d, 0x36, 0x77, 0x1a, 0x94, - 0x1e, 0x82, 0x4d, 0xc9, 0xed, 0x0f, 0x1b, 0xc6, 0xc0, 0x58, 0xa3, 0xf7, - 0x81, 0x57, 0x02, 0x4d, 0x2e, 0xb6, 0xce, 0xa6, 0xa7, 0x8e, 0x9c, 0xf6, - 0xa0, 0x3f, 0x1e, 0xa1, 0xbd, 0xdf, 0xeb, 0x6b, 0xb0, 0xd9, 0x1a, 0x3f, - 0x2a, 0x61, 0x1f, 0x97, 0x10, 0x04, 0xaf, 0x2e, 0xab, 0x15, 0x8e, 0x42, - 0x1b, 0x6b, 0x31, 0x82, 0x30, 0xeb, 0x91, 0x9f, 0x3b, 0x88, 0x99, 0xb6, - 0x35, 0x5f, 0xb1, 0xf6, 0x36, 0xb5, 0x80, 0xd4, 0x7a, 0xcb, 0xbc, 0x92, - 0x0e, 0xb3, 0x65, 0x8f, 0xfd, 0xc1, 0xe2, 0xb5, 0xaa, 0xe5, 0x01, 0x2e, - 0xc5, 0x59, 0x0d, 0xf4, 0x47, 0x54, 0xdf, 0xae, 0xb8, 0x7a, 0x6d, 0x58, - 0x06, 0x3d, 0x72, 0xe8, 0x2a, 0x6a, 0xfd, 0x2f, 0x1f, 0x28, 0x19, 0x6f, - 0x5d, 0x1e, 0xc3, 0x71, 0xca, 0xfe, 0x91, 0xe5, 0x89, 0xeb, 0x8c, 0xf2, - 0x54, 0xdb, 0x3e, 0xa3, 0x29, 0x19, 0xba, 0x3c, 0x41, 0x22, 0x2d, 0xd0, - 0x39, 0x7b, 0xfb, 0x0b, 0xc3, 0x8a, 0xcc, 0x46, 0xe2, 0x6a, 0x3b, 0x5d, - 0x74, 0xec, 0xf4, 0xe7, 0x95, 0x3d, 0x32, 0x97, 0x58, 0x08, 0xf5, 0x97, - 0x0a, 0x31, 0x2c, 0xc4, 0x7b, 0x19, 0xca, 0x7f, 0xb6, 0xea, 0xc4, 0x9d, - 0xb1, 0xed, 0xd2, 0xc1, 0xf3, 0xe7, 0xf7, 0x61, 0x25, 0x96, 0x3a, 0x70, - 0xb8, 0x57, 0x4a, 0x6f, 0x6e, 0x38, 0xea, 0xb2, 0x9c, 0xed, 0xc7, 0xa2, - 0xa0, 0x56, 0xf1, 0x74, 0x3c, 0x28, 0x73, 0x51, 0x1c, 0xdb, 0xe7, 0x76, - 0x0c, 0xab, 0x0e, 0x5f, 0x43, 0x65, 0x2b, 0xb9, 0x30, 0x44, 0x7f, 0x20, - 0xea, 0x39, 0xcd, 0xca, 0x47, 0x97, 0x75, 0x1a, 0x01, 0x47, 0x23, 0x34, - 0xfb, 0x57, 0x14, 0xdd, 0xdd, 0x40, 0x92, 0xae, 0x05, 0x71, 0xe0, 0xc2, - 0x26, 0x29, 0xdb, 0xc9, 0xdc, 0xf2, 0x46, 0x68, 0x88, 0x29, 0xc3, 0x2f, - 0xa4, 0x16, 0x8b, 0xe1, 0xc7, 0xa0, 0x8e, 0xbd, 0x3c, 0xbc, 0x00, 0x87, - 0x93, 0x93, 0x04, 0x3e, 0x4b, 0x75, 0xfd, 0xbc, 0xf9, 0x98, 0xc2, 0x5e, - 0x6f, 0xf6, 0xe9, 0x5a, 0xcd, 0x9f, 0x84, 0x98, 0x6b, 0x91, 0x77, 0xd7, - 0x64, 0x9d, 0xdc, 0x06, 0x40, 0xf3, 0xf4, 0x78, 0x45, 0x39, 0xaa, 0x0d, - 0x8c, 0x7a, 0x75, 0x4b, 0xa5, 0xa3, 0x7e, 0xc6, 0x24, 0x5e, 0xc5, 0x5f, - 0x47, 0xd1, 0x70, 0x7d, 0xf4, 0x60, 0xdd, 0x11, 0xf8, 0xc0, 0xac, 0x7c, - 0xf0, 0x57, 0xb1, 0x4a, 0x94, 0xfd, 0x9a, 0xb5, 0x56, 0xb5, 0xa1, 0x50, - 0xdd, 0x8e, 0x56, 0x87, 0xe2, 0x14, 0x0a, 0xd7, 0xba, 0x92, 0x18, 0x3a, - 0x1d, 0xef, 0x98, 0xe1, 0x85, 0x59, 0x25, 0x36, 0xc9, 0xbf, 0x7d, 0xd2, - 0x16, 0x4f, 0x90, 0xf6, 0xe5, 0xd2, 0xb0, 0x82, 0x26, 0x3b, 0x4a, 0xca, - 0xd6, 0x94, 0x15, 0x94, 0x55, 0x16, 0x38, 0xe3, 0x96, 0x0c, 0xda, 0x8a, - 0xfd, 0x38, 0x78, 0xc7, 0x41, 0xac, 0xa4, 0x73, 0x7a, 0xc3, 0xd6, 0x60, - 0xef, 0xfb, 0x62, 0xd6, 0x1e, 0xe1, 0x9d, 0xc5, 0x21, 0xa6, 0x6f, 0x0d, - 0x83, 0x29, 0xd8, 0xce, 0x5e, 0x93, 0xef, 0x41, 0xaa, 0x2c, 0x54, 0x95, - 0x6d, 0xd3, 0x0e, 0xad, 0x32, 0xaa, 0x5f, 0xfc, 0x98, 0x3e, 0xdf, 0x7b, - 0x91, 0x8b, 0xa1, 0x87, 0x1d, 0x89, 0x4c, 0x1d, 0x5b, 0xa2, 0x55, 0x19, - 0x65, 0x9c, 0xe2, 0x08, 0xda, 0x07, 0xdf, 0x8a, 0xf8, 0x59, 0x2e, 0x2d, - 0x7b, 0xa8, 0xad, 0x7e, 0x5a, 0xd0, 0x53, 0x75, 0xe4, 0xf8, 0xd3, 0xe9, - 0x62, 0x37, 0x94, 0x97, 0x21, 0x3a, 0xc2, 0x6f, 0xed, 0x28, 0x64, 0xfe, - 0xd8, 0xbe, 0xe8, 0x68, 0xfc, 0x1a, 0x32, 0x93, 0xd3, 0x26, 0xb2, 0x25, - 0x73, 0x97, 0x94, 0x15, 0x76, 0x26, 0xbf, 0xdd, 0x2c, 0xb3, 0x97, 0x0b, - 0x45, 0xe7, 0xcf, 0x9a, 0xcb, 0x77, 0xea, 0x17, 0x34, 0x94, 0x15, 0xf5, - 0xc0, 0xa0, 0x16, 0xa4, 0x35, 0x55, 0xb1, 0xc2, 0x70, 0x89, 0x58, 0x61, - 0xd0, 0x27, 0xd4, 0xb7, 0x1b, 0x36, 0xac, 0xd6, 0xed, 0x86, 0x6d, 0x64, - 0x31, 0x64, 0xa0, 0xcc, 0xbe, 0x09, 0xb9, 0xae, 0x59, 0x07, 0xcb, 0xbd, - 0xf6, 0xa7, 0x93, 0x88, 0x41, 0x44, 0xa9, 0x29, 0x50, 0xde, 0xce, 0xdd, - 0x88, 0xce, 0x38, 0xcb, 0xfd, 0x7f, 0x0f, 0x1e, 0x43, 0x5e, 0xba, 0xbe, - 0x2d, 0x0a, 0x09, 0x10, 0x38, 0xd9, 0x53, 0xc7, 0x6f, 0xfc, 0x9f, 0x05, - 0x4b, 0x42, 0xa9, 0x03, 0x4e, 0xb2, 0x94, 0x7b, 0xa7, 0xc3, 0x57, 0xa8, - 0x35, 0xb1, 0x02, 0x59, 0x6c, 0x74, 0x96, 0x80, 0x9d, 0xd7, 0x56, 0xb3, - 0x4b, 0xd0, 0x6c, 0xa8, 0x64, 0xcd, 0x96, 0xb0, 0x42, 0xe4, 0xa4, 0xb8, - 0x35, 0xa7, 0x98, 0x01, 0x76, 0xaa, 0x22, 0xd3, 0xd3, 0x42, 0x4d, 0x49, - 0xab, 0x47, 0xb4, 0xc0, 0xa1, 0x58, 0x96, 0xfc, 0x37, 0x50, 0x81, 0x24, - 0xf6, 0x4c, 0x25, 0x8a, 0xb4, 0x20, 0x3f, 0xac, 0x2b, 0xaa, 0xde, 0x3b, - 0x62, 0x3e, 0xf7, 0xd7, 0xac, 0x29, 0xe6, 0x59, 0xca, 0x94, 0xe5, 0x7d, - 0x01, 0x88, 0xce, 0xf7, 0x81, 0x1c, 0xb5, 0xae, 0xb3, 0xf8, 0x9d, 0x93, - 0xbb, 0x51, 0xef, 0xd1, 0x0d, 0x96, 0x48, 0x9e, 0x13, 0xe4, 0x25, 0xfd, - 0xe6, 0x78, 0xd2, 0x5a, 0x87, 0x40, 0xd8, 0x40, 0x02, 0x29, 0x33, 0xe8, - 0x74, 0x36, 0x4e, 0xc2, 0xdd, 0x6d, 0x00, 0xc0, 0x6d, 0x21, 0xcc, 0xc5, - 0x8d, 0xa1, 0x33, 0x59, 0xa8, 0x52, 0xc3, 0x80, 0xc5, 0xdc, 0x77, 0xfd, - 0x4e, 0x76, 0xb4, 0x6a, 0x7e, 0x52, 0xfc, 0xe3, 0xae, 0x55, 0x79, 0x12, - 0x6d, 0x8c, 0x4b, 0x2c, 0x00, 0x12, 0x93, 0xa9, 0xc9, 0x9d, 0x2b, 0x97, - 0xc9, 0x1b, 0x59, 0xcf, 0xa0, 0x0b, 0xb2, 0x7b, 0x94, 0xa2, 0x84, 0x15, - 0x67, 0x59, 0xed, 0xf7, 0x79, 0x7c, 0x11, 0x0c, 0x4e, 0x0f, 0xf4, 0x57, - 0xe8, 0x35, 0x31, 0xf5, 0xd8, 0xcf, 0xeb, 0x66, 0xf8, 0x47, 0x3e, 0x86, - 0x48, 0x9a, 0x5f, 0x64, 0x9e, 0x8b, 0x8e, 0xb8, 0x36, 0xe7, 0xfc, 0xca, - 0x13, 0xa5, 0xc2, 0x3f, 0x60, 0x45, 0xfd, 0xbd, 0x7c, 0x94, 0xf8, 0xac, - 0x19, 0xc0, 0xb2, 0xde, 0xf4, 0xfd, 0xba, 0x2b, 0x75, 0x5c, 0xd4, 0x33, - 0xf5, 0xe4, 0xd4, 0x73, 0x7b, 0x35, 0x73, 0x8a, 0x11, 0x98, 0x4f, 0x13, - 0xa3, 0x8d, 0x60, 0xb5, 0x3f, 0xb1, 0x00, 0xd3, 0xa7, 0xb2, 0x98, 0x46, - 0x43, 0x40, 0x45, 0xaf, 0x0b, 0xcb, 0x41, 0xa8, 0xbe, 0xf3, 0xb3, 0x21, - 0x21, 0x76, 0xdf, 0x61, 0x98, 0x6c, 0xa3, 0x39, 0x33, 0xc0, 0x7a, 0xbd, - 0x72, 0x87, 0x6c, 0x7a, 0x1a, 0x20, 0x01, 0xc3, 0x9f, 0x31, 0xf3, 0xd8, - 0x71, 0x77, 0x61, 0x47, 0xef, 0x65, 0xeb, 0xc7, 0xa0, 0xfc, 0xd5, 0xd4, - 0x4e, 0xd0, 0x5c, 0xa1, 0x09, 0x79, 0x12, 0x6c, 0x34, 0x0c, 0xee, 0x6b, - 0x60, 0x0e, 0xab, 0x16, 0x5c, 0xa0, 0x09, 0x34, 0xdd, 0x8d, 0x18, 0xc2, - 0xe9, 0x16, 0xa1, 0x8d, 0xa2, 0x71, 0x8a, 0x95, 0xf2, 0xa0, 0x5b, 0x4c, - 0x34, 0x90, 0xba, 0x9b, 0x5c, 0xa0, 0xe0, 0x88, 0x46, 0x55, 0xc5, 0x15, - 0x89, 0xb8, 0x69, 0xcd, 0x43, 0x96, 0x69, 0xb4, 0xc5, 0x98, 0x86, 0xba, - 0x21, 0x13, 0xac, 0x22, 0x4c, 0x64, 0x6c, 0xbc, 0x76, 0x9f, 0x7c, 0xc6, - 0x5a, 0x04, 0x94, 0x94, 0x72, 0xba, 0x6f, 0xfb, 0x6d, 0xd9, 0xe3, 0x97, - 0xaf, 0xf1, 0x8d, 0x9f, 0x92, 0xb1, 0xc6, 0x2e, 0x17, 0xb9, 0xc4, 0x78, - 0x9f, 0x5b, 0x72, 0x3a, 0x22, 0xe0, 0xfb, 0x8a, 0xbe, 0xd0, 0x3d, 0x50, - 0x88, 0x07, 0xd3, 0x21, 0xb2, 0x42, 0x64, 0xb2, 0xa2, 0xa9, 0xfb, 0x27, - 0x84, 0xd0, 0xe7, 0xa1, 0x16, 0x2b, 0xe1, 0x01, 0x00, 0x37, 0xbd, 0x44, - 0x6d, 0x99, 0x21, 0x48, 0x5c, 0x3d, 0x31, 0xbe, 0x95, 0x66, 0x46, 0x8b, - 0xb1, 0xf6, 0xa8, 0xd9, 0x47, 0xf0, 0x2f, 0xf4, 0x17, 0x1d, 0x93, 0x3f, - 0x24, 0x05, 0x64, 0x41, 0x9d, 0x4b, 0xfe, 0xff, 0xb5, 0xe3, 0xf5, 0x22, - 0xdb, 0xcf, 0xfe, 0x7d, 0xf7, 0x24, 0x64, 0x78, 0xd1, 0xd6, 0xb5, 0xe0, - 0xfa, 0x05, 0x53, 0x2d, 0xca, 0x54, 0x2d, 0x9a, 0xf8, 0x1c, 0x1a, 0x61, - 0xb9, 0x3b, 0xd3, 0x5b, 0x06, 0xbb, 0x0e, 0xb2, 0x24, 0x83, 0x3b, 0x0c, - 0x57, 0x4f, 0x2d, 0xc2, 0x74, 0x6a, 0xb6, 0x7d, 0xad, 0x02, 0x66, 0xc1, - 0x67, 0x93, 0x91, 0xf4, 0x10, 0x0f, 0x1c, 0xc0, 0xc7, 0x0b, 0x74, 0x22, - 0xf2, 0xa7, 0xdd, 0xf4, 0x90, 0xda, 0x7b, 0x9f, 0xc5, 0xaf, 0x24, 0x8f, - 0x7d, 0x8a, 0xa3, 0xdf, 0xef, 0x6e, 0x7d, 0x93, 0x2f, 0xdd, 0x61, 0x99, - 0x30, 0xb4, 0x6c, 0xd0, 0xf3, 0xc9, 0x72, 0xcc, 0xf8, 0xbd, 0x66, 0xe0, - 0x8d, 0x40, 0xdf, 0xfe, 0x2e, 0x2c, 0x1f, 0x51, 0x10, 0xc7, 0x4d, 0x56, - 0x58, 0xa5, 0x54, 0xee, 0x59, 0x0f, 0x6c, 0x37, 0xca, 0xb9, 0xf2, 0x7e, - 0xe6, 0x79, 0xcf, 0x64, 0x54, 0xa3, 0x24, 0x20, 0x36, 0xc8, 0xf9, 0x7b, - 0xd4, 0x39, 0x8d, 0x09, 0xb0, 0xd8, 0x44, 0xd3, 0x97, 0x5b, 0x37, 0x8c, - 0x08, 0x51, 0x02, 0xaa, 0x5d, 0xb8, 0x0f, 0x17, 0xfb, 0xdc, 0xe1, 0xc0, - 0x3e, 0x8b, 0x7b, 0x90, 0x9f, 0xed, 0xf2, 0x03, 0x11, 0x9b, 0x23, 0x0d, - 0xfa, 0x19, 0x08, 0x3c, 0x3c, 0x69, 0x7c, 0xb9, 0xa3, 0x6a, 0x26, 0xd7, - 0xea, 0x96, 0xbd, 0x35, 0xdf, 0x84, 0xf8, 0xdb, 0x1f, 0xf8, 0x83, 0x69, - 0x8c, 0xe0, 0x8e, 0x6f, 0xf9, 0x08, 0x1b, 0x8c, 0xe9, 0xde, 0x00, 0x8c, - 0x8b, 0x6c, 0x59, 0x77, 0x9c, 0xb5, 0xf9, 0x07, 0xea, 0xe4, 0xb2, 0x95, - 0x7e, 0x69, 0xdf, 0x8e, 0x92, 0xdd, 0x2a, 0x0b, 0xac, 0xd6, 0xcd, 0x56, - 0x48, 0x5d, 0x3c, 0xc9, 0x27, 0xd0, 0xad, 0xb4, 0xcb, 0x5d, 0x76, 0xb6, - 0x40, 0x51, 0x55, 0xd6, 0xf4, 0x5a, 0xa5, 0x3d, 0x8e, 0x7b, 0x63, 0xcc, - 0x40, 0x0e, 0x85, 0xaf, 0x6b, 0xa0, 0xe1, 0xbf, 0x19, 0x20, 0xaa, 0xe9, - 0x91, 0x1c, 0x65, 0x20, 0x9b, 0x50, 0x70, 0x85, 0x79, 0x8d, 0x2e, 0x4d, - 0x8d, 0x0a, 0x44, 0x2c, 0xd9, 0x0d, 0x50, 0x2c, 0xe5, 0xca, 0xf0, 0x77, - 0xf6, 0x20, 0x28, 0x91, 0x73, 0x4c, 0xd0, 0x3d, 0x9e, 0x9c, 0x07, 0xa5, - 0x4b, 0xde, 0xac, 0x8e, 0xb4, 0x3d, 0x1a, 0x4f, 0xa1, 0x41, 0x42, 0x32, - 0xf1, 0x21, 0xd9, 0xf8, 0xf9, 0x42, 0x72, 0x08, 0xd6, 0x01, 0x7e, 0xc8, - 0x6d, 0x2a, 0xa6, 0x52, 0x4a, 0xfc, 0x30, 0x41, 0xfa, 0xc5, 0xae, 0x3b, - 0x6a, 0x24, 0xc7, 0xa0, 0xdb, 0x86, 0xfe, 0x06, 0x9a, 0xfa, 0xe4, 0xb5, - 0xac, 0xa5, 0xea, 0x68, 0x4e, 0xd6, 0x74, 0x94, 0x3d, 0xc3, 0x5e, 0x3a, - 0x30, 0xbe, 0x64, 0x12, 0xb3, 0x25, 0xa7, 0x7a, 0x1b, 0xfd, 0x56, 0x0d, - 0xcf, 0x6a, 0xa0, 0x45, 0x2a, 0xef, 0x92, 0x8e, 0x36, 0x85, 0x08, 0xa9, - 0xa3, 0xa6, 0xa2, 0xfa, 0xb8, 0x06, 0x16, 0x68, 0xa6, 0xac, 0x40, 0x5a, - 0xdd, 0xf2, 0x49, 0xaa, 0x24, 0x36, 0x46, 0xa3, 0x52, 0xf5, 0x12, 0x0c, - 0x37, 0xf2, 0x77, 0x5c, 0x81, 0x90, 0x64, 0x70, 0xb4, 0xcf, 0x55, 0x2b, - 0x23, 0x5e, 0x8d, 0x0b, 0xe3, 0x1a, 0x9e, 0x47, 0xbf, 0x0e, 0x55, 0xa5, - 0x10, 0xf2, 0x01, 0x97, 0x85, 0x19, 0x5d, 0xa8, 0x06, 0xd6, 0xe0, 0xe9, - 0xb7, 0xc1, 0x9a, 0x45, 0xab, 0xa3, 0x7b, 0xa2, 0x1f, 0x82, 0xd1, 0xe6, - 0x6f, 0xec, 0xf8, 0x1f, 0xa5, 0x66, 0xb2, 0xaf, 0x36, 0x27, 0xf1, 0x88, - 0x0a, 0x1f, 0x58, 0x5d, 0x96, 0x53, 0x9f, 0x5f, 0x96, 0x35, 0x56, 0x36, - 0x66, 0x65, 0x8f, 0x8f, 0xb6, 0xe3, 0x1b, 0xc6, 0xb7, 0xb8, 0xae, 0x46, - 0x40, 0xa8, 0xe8, 0x26, 0xdd, 0x57, 0x70, 0x66, 0xe6, 0xde, 0x1b, 0x08, - 0x44, 0x99, 0x7a, 0x70, 0x06, 0xa6, 0xb2, 0x16, 0x81, 0xd0, 0x70, 0x3c, - 0x13, 0xf3, 0x94, 0x59, 0x69, 0x15, 0x24, 0x3c, 0x50, 0xa4, 0x7e, 0x3d, - 0x3d, 0x46, 0xed, 0x56, 0x16, 0x30, 0xa3, 0xd7, 0xbd, 0x0f, 0xbb, 0x53, - 0xde, 0xdc, 0x9f, 0xec, 0x46, 0x22, 0xf1, 0xf7, 0xec, 0x3f, 0x5d, 0xaf, - 0x7d, 0x3a, 0x46, 0x9c, 0x20, 0x7d, 0x64, 0xd0, 0x49, 0xbf, 0xbe, 0x11, - 0x0e, 0x67, 0x10, 0x3f, 0x43, 0x7c, 0x9f, 0xa0, 0x12, 0x0a, 0xc6, 0xc0, - 0xfe, 0x85, 0x15, 0x85, 0x3d, 0x19, 0xd7, 0x10, 0x94, 0x6e, 0xf5, 0x82, - 0x72, 0x77, 0x69, 0x73, 0xe1, 0x19, 0x53, 0x7a, 0xff, 0x79, 0xc2, 0x79, - 0xc7, 0xaf, 0x7b, 0xf8, 0xf9, 0xa1, 0xd7, 0x48, 0xb0, 0x55, 0xcd, 0x0c, - 0xc3, 0x10, 0x09, 0x6f, 0x3e, 0xe2, 0xb6, 0xdc, 0x75, 0x35, 0xcb, 0xc7, - 0x75, 0xf4, 0x16, 0x7c, 0x56, 0xc9, 0xc7, 0xe8, 0x92, 0xcc, 0x42, 0x77, - 0x6f, 0x39, 0x47, 0x17, 0x93, 0x03, 0x10, 0xac, 0xdd, 0x84, 0xe4, 0x76, - 0xfd, 0x78, 0xf6, 0xbf, 0x15, 0x6d, 0x0c, 0x4d, 0xc9, 0x21, 0x01, 0x45, - 0xb8, 0x95, 0xce, 0x80, 0x67, 0x27, 0xb5, 0xd4, 0x56, 0x65, 0xf2, 0x93, - 0xa6, 0x31, 0x7f, 0x96, 0xdc, 0x6a, 0x3d, 0xaa, 0x60, 0xa0, 0x2b, 0xeb, - 0x92, 0x11, 0x9d, 0x82, 0x13, 0x51, 0x54, 0x6d, 0x7d, 0x9a, 0x5f, 0x86, - 0x11, 0x5b, 0x42, 0x08, 0xdc, 0x4f, 0xac, 0x5e, 0x6d, 0xc7, 0x10, 0x6d, - 0x94, 0x01, 0x11, 0x75, 0x3c, 0x39, 0x71, 0x95, 0x5f, 0x64, 0x1b, 0x6d, - 0x78, 0xe0, 0x8c, 0xfa, 0x3b, 0x22, 0xb7, 0x0f, 0x44, 0xbf, 0xc0, 0xfd, - 0x9e, 0x05, 0x54, 0x9a, 0x54, 0x05, 0xc8, 0x50, 0x3c, 0xc6, 0xea, 0xed, - 0xfd, 0x6e, 0xf5, 0x05, 0x27, 0x17, 0x91, 0xf0, 0x34, 0xee, 0x1a, 0x54, - 0xff, 0x04, 0x6b, 0x4a, 0x04, 0x6c, 0xf1, 0x15, 0x70, 0xdc, 0x9a, 0x1b, - 0x48, 0x8e, 0xea, 0xc1, 0x27, 0x11, 0xc8, 0xd6, 0x0f, 0x6e, 0xf8, 0x3c, - 0xc6, 0x3d, 0x58, 0x16, 0xf8, 0x21, 0x12, 0xdb, 0xf2, 0x34, 0xcd, 0x89, - 0x7a, 0xd0, 0x16, 0x49, 0x16, 0xd6, 0xc2, 0xed, 0x07, 0x2a, 0x54, 0xe7, - 0xb8, 0xa0, 0xff, 0x0b, 0xaf, 0x58, 0x2b, 0x50, 0xcb, 0xda, 0x8a, 0x2b, - 0x97, 0x36, 0xea, 0x39, 0xe1, 0x09, 0xa5, 0xbf, 0x6e, 0xdd, 0xd7, 0x1d, - 0x22, 0xd8, 0x95, 0x20, 0xc4, 0x9d, 0xad, 0xd7, 0x67, 0xb9, 0x98, 0xb3, - 0x8e, 0x8b, 0xa8, 0x8d, 0xed, 0xf5, 0x45, 0x9f, 0x72, 0xc8, 0x32, 0x75, - 0x08, 0x38, 0x0d, 0x19, 0xf8, 0x24, 0x85, 0x5c, 0x07, 0x16, 0xdc, 0x9f, - 0x65, 0xcb, 0x2c, 0xfc, 0xec, 0x2a, 0x50, 0xc9, 0x95, 0x4e, 0xab, 0x32, - 0x02, 0xe0, 0x6d, 0xba, 0xe4, 0x8a, 0xb7, 0x60, 0xbb, 0x4a, 0x53, 0x70, - 0x2c, 0x09, 0xf4, 0x95, 0x72, 0xc9, 0xe7, 0x4e, 0x53, 0xb3, 0xf7, 0xf3, - 0x6d, 0x4c, 0xf7, 0x1b, 0x4c, 0x89, 0xd9, 0xff, 0xc1, 0xf8, 0x62, 0x26, - 0xd4, 0xcf, 0x9f, 0x40, 0x77, 0x80, 0xd5, 0x17, 0x4b, 0x7f, 0xf7, 0xe1, - 0xbc, 0x68, 0x35, 0x39, 0x2e, 0x4d, 0xf3, 0xbc, 0x4f, 0x26, 0x5f, 0x93, - 0xed, 0xf4, 0x58, 0x60, 0x61, 0x37, 0xb7, 0x02, 0x4a, 0xb7, 0x7e, 0xab, - 0xb2, 0x4b, 0x82, 0x12, 0xd3, 0xd7, 0xc2, 0x26, 0x6b, 0x02, 0xb4, 0xc6, - 0x15, 0x45, 0xbf, 0x19, 0xb7, 0x70, 0x3f, 0xab, 0x74, 0x71, 0x95, 0x3e, - 0xd3, 0x2f, 0x25, 0x3c, 0xc8, 0xa0, 0x36, 0x19, 0xa3, 0xd6, 0x5f, 0x2c, - 0x82, 0xce, 0xc6, 0xbd, 0x41, 0xdd, 0x8f, 0x77, 0x64, 0xab, 0x33, 0xf6, - 0x33, 0xe3, 0x5c, 0x09, 0x41, 0xe1, 0xaa, 0x72, 0xf8, 0x7a, 0x86, 0x4f, - 0xab, 0x29, 0x11, 0x19, 0xb9, 0x79, 0xb6, 0x31, 0xbc, 0x95, 0x60, 0xe9, - 0x1a, 0x1f, 0xf5, 0x16, 0xf1, 0xea, 0x94, 0xaa, 0x94, 0xad, 0x09, 0x8c, - 0x40, 0xbb, 0xdd, 0xa9, 0x63, 0xf0, 0xee, 0xa0, 0x7a, 0x09, 0x1c, 0x11, - 0xa2, 0x7e, 0xd0, 0x95, 0x26, 0x75, 0x46, 0x6c, 0x68, 0x29, 0x58, 0x6e, - 0xd3, 0x99, 0xc4, 0xf1, 0xae, 0x38, 0xeb, 0xc3, 0x37, 0x10, 0x50, 0x5f, - 0x29, 0xf0, 0x03, 0x57, 0x2f, 0x3a, 0x34, 0xa3, 0x76, 0xbb, 0x2f, 0xd2, - 0x95, 0xcc, 0xd7, 0xc7, 0x42, 0x2f, 0x12, 0xdc, 0x52, 0xad, 0x64, 0x0b, - 0x2a, 0xf0, 0xaa, 0x13, 0x8d, 0x2f, 0xfa, 0xd5, 0x21, 0x70, 0x27, 0x92, - 0xbc, 0x89, 0x07, 0x80, 0x45, 0xf2, 0x05, 0x27, 0xee, 0xc0, 0x7b, 0xd8, - 0xb0, 0xa2, 0x0e, 0x87, 0x3e, 0x6e, 0x67, 0x3f, 0x5c, 0xa4, 0x72, 0xd6, - 0x9b, 0xdb, 0x57, 0xb5, 0x52, 0x03, 0xcc, 0x1f, 0x03, 0xd5, 0x30, 0x94, - 0xf6, 0x0b, 0xe6, 0xcb, 0x41, 0xa9, 0xae, 0x55, 0x93, 0x24, 0xd5, 0x48, - 0xef, 0x4e, 0x4f, 0xa5, 0xc5, 0x48, 0x3f, 0xf0, 0x66, 0xa1, 0x52, 0x25, - 0x8f, 0x1f, 0xf5, 0xb4, 0xe1, 0x73, 0x24, 0x08, 0x57, 0x2f, 0xeb, 0x53, - 0x49, 0xe0, 0x7c, 0x1d, 0x89, 0x39, 0xd7, 0xc4, 0x26, 0xe7, 0x1a, 0x01, - 0x41, 0x1c, 0x06, 0x0f, 0x8b, 0x25, 0xd7, 0x6b, 0x1f, 0xd4, 0x60, 0xd3, - 0x27, 0x53, 0x35, 0x4c, 0xb2, 0x05, 0xbe, 0xbe, 0x3c, 0x8e, 0xd0, 0xe8, - 0x24, 0x2f, 0x02, 0x9a, 0xb3, 0x27, 0x5a, 0xe6, 0xe4, 0xb1, 0x0c, 0x16, - 0x9f, 0x08, 0x55, 0x5d, 0x68, 0x95, 0xab, 0xae, 0xba, 0xb0, 0x7c, 0xb0, - 0x7e, 0xef, 0x91, 0x0d, 0x9b, 0xe1, 0xed, 0xa0, 0xa6, 0xf1, 0x79, 0x5e, - 0x2b, 0x21, 0x52, 0x2f, 0xdd, 0xc9, 0xd2, 0xc4, 0xac, 0x73, 0x5d, 0xb4, - 0x80, 0xd8, 0x9e, 0xef, 0xd4, 0xf1, 0x1b, 0xfa, 0x68, 0xff, 0x19, 0xef, - 0x9f, 0x1d, 0x83, 0x4e, 0x82, 0xac, 0x11, 0xbe, 0x81, 0x56, 0x98, 0x70, - 0xeb, 0x44, 0x2e, 0x72, 0x0c, 0xb7, 0x4f, 0xe9, 0x64, 0xb3, 0x0b, 0x8b, - 0x4a, 0x96, 0xfa, 0xb0, 0x53, 0x53, 0xb8, 0x88, 0xbf, 0x25, 0x6f, 0xe8, - 0x96, 0xe2, 0x13, 0x1e, 0xdf, 0x6c, 0x5f, 0x9a, 0x08, 0x6b, 0xb8, 0xcd, - 0x46, 0xd7, 0x94, 0x77, 0xa5, 0x31, 0x0c, 0x6e, 0x46, 0x90, 0xb8, 0xf9, - 0x01, 0xde, 0x08, 0x3c, 0xec, 0xec, 0x79, 0x2a, 0xac, 0x83, 0x94, 0x9d, - 0xbc, 0x19, 0xc5, 0x03, 0xb0, 0xd6, 0xb1, 0x27, 0xfb, 0xa1, 0xb0, 0x22, - 0x2c, 0xdb, 0x39, 0xf6, 0x51, 0x9f, 0x5e, 0xb5, 0xbb, 0x14, 0x27, 0x21, - 0xb8, 0x9e, 0xe2, 0x35, 0xa6, 0x85, 0xf2, 0xe1, 0x1c, 0x53, 0x8b, 0x6e, - 0x2d, 0xde, 0xa9, 0x32, 0x06, 0x2c, 0xe1, 0xab, 0xaa, 0x57, 0x5f, 0x0e, - 0x78, 0xab, 0x67, 0xb5, 0x6d, 0x5d, 0xd3, 0xdd, 0xe9, 0x0a, 0xf8, 0x5d, - 0x27, 0x94, 0x84, 0x4e, 0x5e, 0xcb, 0x45, 0xeb, 0xf3, 0x67, 0x83, 0xe2, - 0x69, 0x71, 0x17, 0xc1, 0x25, 0x71, 0xb3, 0x79, 0xb5, 0x15, 0x20, 0x35, - 0x51, 0x9c, 0x00, 0x10, 0xa4, 0xf7, 0xac, 0xc6, 0xd0, 0xd2, 0x28, 0x66, - 0xae, 0x21, 0xc6, 0x79, 0x6b, 0x06, 0x70, 0x2a, 0xa7, 0x2d, 0xfe, 0x38, - 0x07, 0x11, 0xf6, 0x50, 0x52, 0x0f, 0xb5, 0xc2, 0x69, 0xf9, 0x90, 0x60, - 0x34, 0x2c, 0x76, 0xe2, 0xd2, 0xe3, 0x62, 0xc3, 0xdc, 0xdc, 0x60, 0x6b, - 0xac, 0xfd, 0x82, 0xa4, 0x4c, 0x2d, 0x78, 0x09, 0xf2, 0xaf, 0xa6, 0x2b, - 0x87, 0xf1, 0x73, 0xf2, 0xca, 0xe6, 0x77, 0xea, 0xcb, 0xf5, 0x69, 0x4f, - 0xb9, 0x6d, 0xc5, 0xb7, 0x79, 0x34, 0x73, 0xd8, 0x8c, 0xf8, 0xbf, 0x18, - 0x1a, 0xd1, 0xe2, 0x91, 0x7a, 0xae, 0xe7, 0x9c, 0x62, 0x74, 0x8a, 0x27, - 0xf4, 0x27, 0x80, 0x84, 0x75, 0x91, 0x92, 0x79, 0x2e, 0x23, 0xf3, 0x2b, - 0x84, 0x52, 0x41, 0xc5, 0x7d, 0xf7, 0xe8, 0x80, 0x6f, 0x3e, 0x8e, 0x04, - 0xfd, 0x15, 0xbd, 0xc6, 0x49, 0x8d, 0x22, 0x58, 0x1f, 0x21, 0xcf, 0x5b, - 0x90, 0xdf, 0x0c, 0x15, 0xc0, 0x3a, 0xe6, 0x17, 0x1c, 0xb1, 0xf8, 0xc0, - 0x45, 0x77, 0xc3, 0x94, 0x16, 0xf7, 0x87, 0xaa, 0x11, 0x86, 0xcb, 0xb0, - 0x9f, 0x1e, 0x1a, 0x10, 0x10, 0x60, 0x0a, 0x9f, 0xb8, 0x09, 0xa7, 0x3f, - 0xaa, 0x28, 0xc9, 0x0f, 0xf3, 0x86, 0x6e, 0xbc, 0x5f, 0x74, 0xfa, 0xbe, - 0xde, 0xd4, 0xdf, 0x1e, 0xa5, 0x8a, 0xae, 0xf2, 0xe4, 0x6d, 0xfb, 0x76, - 0x34, 0xf1, 0x2c, 0x61, 0xab, 0x09, 0x0b, 0x89, 0x69, 0x59, 0x92, 0xaf, - 0xad, 0x63, 0xe0, 0xcf, 0xd4, 0x23, 0x78, 0x8c, 0x21, 0x07, 0xe8, 0x39, - 0x13, 0xfe, 0x4a, 0xb2, 0xb1, 0x99, 0x47, 0x39, 0x96, 0x96, 0x06, 0x7f, - 0x6b, 0xe4, 0xb6, 0xa3, 0xd7, 0x48, 0x5d, 0xb7, 0xfb, 0x3d, 0xdc, 0xe0, - 0xfc, 0x34, 0xb8, 0x45, 0xe1, 0x5f, 0x52, 0x14, 0x72, 0xd4, 0x35, 0x26, - 0xf2, 0x0b, 0x03, 0x63, 0x7e, 0x99, 0x06, 0x4b, 0xaf, 0x26, 0xf0, 0xc6, - 0x1f, 0xb6, 0x63, 0xc4, 0xfa, 0xd9, 0xb2, 0xed, 0x95, 0x34, 0x18, 0x42, - 0xd2, 0x55, 0xe4, 0x9d, 0xa5, 0xd7, 0x87, 0xec, 0x96, 0x79, 0x26, 0xef, - 0x10, 0x8a, 0xc7, 0xc1, 0xcf, 0xcf, 0x73, 0x90, 0x55, 0x00, 0x63, 0x9f, - 0x23, 0x94, 0xdf, 0x4c, 0x92, 0xd0, 0x5e, 0x65, 0xc7, 0x3d, 0xce, 0xbd, - 0x9c, 0xdc, 0x49, 0xb9, 0x52, 0x18, 0xd1, 0x4e, 0x93, 0x54, 0x98, 0xc8, - 0x57, 0x7d, 0x68, 0x8f, 0x2e, 0x81, 0xef, 0xc9, 0x29, 0xeb, 0xae, 0xe5, - 0x3a, 0x36, 0xc5, 0x8e, 0x68, 0x55, 0xa8, 0xda, 0x86, 0xd7, 0x45, 0x64, - 0x52, 0x25, 0x5f, 0x34, 0x12, 0x5e, 0x5f, 0x26, 0x4f, 0xb8, 0xd9, 0x64, - 0x04, 0x9f, 0x2e, 0x5a, 0x46, 0x91, 0x05, 0xfc, 0x97, 0xb0, 0x0e, 0x57, - 0x65, 0xf1, 0xe3, 0xd4, 0xe5, 0xb2, 0x08, 0x9c, 0x20, 0x1f, 0x75, 0xc1, - 0x16, 0x9d, 0x29, 0x7b, 0x61, 0x16, 0x37, 0x26, 0xc9, 0x59, 0x05, 0x61, - 0x31, 0xdc, 0xe4, 0x87, 0x15, 0x4a, 0x86, 0xdd, 0x7c, 0xe6, 0x15, 0xb6, - 0x7f, 0xda, 0xd8, 0x61, 0x69, 0x7c, 0xab, 0x25, 0x7e, 0xb7, 0x11, 0x3e, - 0xd3, 0x12, 0x23, 0x39, 0x8a, 0xc7, 0x75, 0xe1, 0xf6, 0x15, 0x3d, 0xcf, - 0x4a, 0xe0, 0xbb, 0x8c, 0xb5, 0x6e, 0xb1, 0xbd, 0xaf, 0xd1, 0x3f, 0x80, - 0xff, 0x82, 0x25, 0x91, 0x15, 0xc8, 0xf2, 0x79, 0xf9, 0xb5, 0xb8, 0xe5, - 0xb1, 0x0b, 0xf9, 0x99, 0xf4, 0x15, 0x3e, 0x72, 0x57, 0x9c, 0x2c, 0xe0, - 0x7d, 0xa2, 0x63, 0xae, 0xb4, 0x11, 0xcb, 0x8b, 0x7a, 0xce, 0x24, 0xbe, - 0x4d, 0x99, 0x82, 0x85, 0x2b, 0xfd, 0x22, 0x08, 0xfc, 0x71, 0xd9, 0xcb, - 0x0e, 0xf7, 0x32, 0xc2, 0xa3, 0x3a, 0xcb, 0xce, 0x78, 0x0b, 0xc6, 0xee, - 0x24, 0xf4, 0xb5, 0x7d, 0x25, 0x79, 0x47, 0x3e, 0x69, 0xea, 0x13, 0xc5, - 0x40, 0xaf, 0xad, 0x74, 0xfd, 0x9a, 0xa7, 0x3d, 0x95, 0x62, 0xa3, 0xdd, - 0xf0, 0x3c, 0xb4, 0xb0, 0x2b, 0x42, 0xc9, 0xe8, 0x4f, 0xe0, 0xf4, 0xb4, - 0x06, 0xf3, 0x56, 0x4d, 0x7c, 0x73, 0x8f, 0x08, 0xd0, 0xae, 0x5f, 0x99, - 0x56, 0xae, 0xf7, 0xc1, 0x15, 0xca, 0xb7, 0x3d, 0x1c, 0x74, 0x75, 0x71, - 0x41, 0xdf, 0xfb, 0x3c, 0xe4, 0x24, 0xff, 0x14, 0x80, 0x2a, 0xfe, 0xe8, - 0x88, 0xc6, 0x5e, 0x83, 0x7d, 0x27, 0xb6, 0x28, 0x10, 0x0c, 0x1f, 0xe9, - 0xc1, 0xea, 0x1b, 0xac, 0x2a, 0x56, 0x4c, 0xb7, 0x7d, 0x83, 0x12, 0xbd, - 0x24, 0x9c, 0x0b, 0x7b, 0x3c, 0xf7, 0xb1, 0x11, 0x96, 0x93, 0xfc, 0xb7, - 0x8d, 0x43, 0x45, 0xb8, 0xe6, 0xa9, 0x13, 0x64, 0x33, 0xba, 0x34, 0xd5, - 0xdc, 0x13, 0x80, 0x7f, 0xb6, 0x0e, 0x7e, 0xea, 0xfc, 0x37, 0x37, 0xfb, - 0xe9, 0xf8, 0x5e, 0x73, 0xa9, 0x9a, 0xea, 0x38, 0x4d, 0xb7, 0x8a, 0x01, - 0x85, 0xbe, 0x0f, 0xf0, 0xbd, 0xfd, 0x5a, 0x92, 0xac, 0xbb, 0x1c, 0x75, - 0xb4, 0x60, 0x0c, 0xb7, 0xe0, 0x98, 0x3d, 0x13, 0x3d, 0x59, 0xb2, 0x06, - 0x4c, 0xaf, 0x8d, 0xd8, 0x50, 0x42, 0x9b, 0xf7, 0xa1, 0xfe, 0xab, 0xdb, - 0x56, 0x05, 0xed, 0xd2, 0x23, 0xa6, 0x79, 0x7a, 0xbc, 0x23, 0x26, 0x20, - 0x2f, 0xde, 0xe1, 0x3e, 0x04, 0x86, 0xe1, 0xcf, 0xc4, 0x0b, 0x8e, 0x34, - 0x01, 0xb2, 0xcb, 0x96, 0xba, 0x51, 0x28, 0xf7, 0xd7, 0x52, 0x2d, 0x40, - 0x9d, 0x7b, 0xac, 0x8f, 0x34, 0xfa, 0xc6, 0xf3, 0x29, 0x03, 0x8c, 0x5a, - 0x08, 0x3f, 0x0d, 0x20, 0x03, 0xbe, 0xc3, 0xe3, 0x46, 0x5d, 0xf9, 0xe8, - 0xe4, 0xd9, 0xeb, 0x48, 0xd3, 0xce, 0x77, 0xf0, 0x46, 0x89, 0xfb, 0x55, - 0xfd, 0x21, 0xcf, 0x48, 0x85, 0x7b, 0x22, 0xae, 0x01, 0x40, 0xf3, 0xa8, - 0xe3, 0x49, 0xa5, 0x39, 0x81, 0xbc, 0x5b, 0x8e, 0x0a, 0x2c, 0x0f, 0x32, - 0x38, 0xab, 0x16, 0x28, 0x89, 0xc3, 0x7d, 0xf6, 0x83, 0x08, 0xfe, 0xd7, - 0xe8, 0xf2, 0xc5, 0x5b, 0x4e, 0x45, 0x6a, 0x6b, 0x06, 0xd0, 0x48, 0x41, - 0x8e, 0xd5, 0x07, 0x74, 0x21, 0x18, 0x48, 0xec, 0x3e, 0x06, 0xcc, 0x49, - 0x0f, 0xf7, 0x16, 0x0e, 0x86, 0xb4, 0x28, 0x83, 0xa2, 0xf2, 0x3b, 0x7b, - 0xb2, 0xe1, 0x1c, 0x52, 0xac, 0x34, 0xc7, 0xf4, 0x4f, 0x77, 0x55, 0x34, - 0xa0, 0x17, 0x59, 0xf8, 0x1a, 0xde, 0xcd, 0x02, 0x8c, 0xd6, 0x3f, 0x8d, - 0xcf, 0xd4, 0x6e, 0x50, 0x45, 0x83, 0xbd, 0xa4, 0xb1, 0x9d, 0x4a, 0xc9, - 0xd1, 0xd4, 0xb4, 0xcc, 0x64, 0xf4, 0x0c, 0x68, 0xfa, 0xad, 0x98, 0xfc, - 0x8d, 0x06, 0xa9, 0x73, 0x6f, 0x89, 0xfb, 0x13, 0x04, 0x85, 0x07, 0x6d, - 0x32, 0xe9, 0x92, 0xfd, 0x1d, 0xb9, 0x6f, 0xd4, 0x0d, 0x0a, 0xbb, 0x14, - 0x38, 0x33, 0x08, 0xc5, 0x7c, 0x12, 0x58, 0x91, 0xda, 0x24, 0x91, 0x67, - 0x58, 0x68, 0x2a, 0x90, 0x02, 0x67, 0x89, 0x53, 0xa7, 0x52, 0xc9, 0x4b, - 0x7c, 0x5a, 0x65, 0x78, 0x5f, 0x37, 0x2c, 0xaf, 0xfc, 0x50, 0xc1, 0xb3, - 0xfd, 0x71, 0xd6, 0x74, 0x74, 0x53, 0x7a, 0x56, 0xa7, 0x4d, 0x6a, 0xe3, - 0xdb, 0x1f, 0x37, 0xbb, 0xcd, 0xb8, 0x52, 0xf9, 0x55, 0x42, 0x8e, 0xc9, - 0x7b, 0x46, 0xf0, 0xb8, 0x81, 0xdb, 0x6e, 0xc7, 0xef, 0xa4, 0xdd, 0xfa, - 0x07, 0xe9, 0xa6, 0x73, 0x82, 0xf8, 0xb6, 0x71, 0x82, 0x99, 0x00, 0xe6, - 0xfd, 0x2c, 0x29, 0xcf, 0x93, 0x2d, 0xa2, 0x93, 0x66, 0xf8, 0x4b, 0xcc, - 0x94, 0x2e, 0xe0, 0x48, 0x86, 0xa4, 0x82, 0x9f, 0x56, 0xe0, 0xa3, 0xdb, - 0xe7, 0xf6, 0x4b, 0xa1, 0x9b, 0x6a, 0xbb, 0x41, 0x66, 0x26, 0x1f, 0x81, - 0x4c, 0x9a, 0xaa, 0xe4, 0xb2, 0x36, 0x39, 0x4e, 0x7d, 0xb6, 0x01, 0xa6, - 0xb1, 0x1f, 0x20, 0xfe, 0xf4, 0x47, 0x6b, 0x40, 0xe5, 0x5e, 0x28, 0x52, - 0x7a, 0xf5, 0xbf, 0xa0, 0x48, 0x5e, 0x3e, 0x72, 0xd1, 0x2e, 0x50, 0x38, - 0xeb, 0x12, 0x1f, 0x16, 0xee, 0x65, 0x15, 0x9a, 0x93, 0xb7, 0x40, 0x5c, - 0x3c, 0x74, 0x64, 0xa9, 0xfb, 0x94, 0x2d, 0xab, 0x5d, 0x2f, 0x9b, 0x8f, - 0xb1, 0xc4, 0x4a, 0xa3, 0xe0, 0xe9, 0x6d, 0x60, 0xef, 0x37, 0xd1, 0x30, - 0xda, 0xad, 0xb4, 0x60, 0x7b, 0x20, 0x9b, 0x17, 0x5e, 0xa5, 0x7f, 0x8d, - 0xd0, 0xe4, 0xea, 0x24, 0xb1, 0xfd, 0x8d, 0x01, 0x15, 0x09, 0x60, 0xbb, - 0xa2, 0x18, 0x59, 0x54, 0x7a, 0xf8, 0x2f, 0x98, 0x19, 0x35, 0x89, 0xfa, - 0xae, 0x27, 0xf5, 0x97, 0xfb, 0x10, 0xb8, 0xbe, 0x6e, 0x64, 0x3a, 0xd3, - 0x47, 0xb3, 0x52, 0xd9, 0x47, 0x72, 0xd9, 0x46, 0xce, 0x7f, 0x0a, 0xe8, - 0x83, 0x17, 0xaf, 0x40, 0x57, 0xf5, 0xa0, 0x9d, 0x30, 0x3f, 0x22, 0x45, - 0x00, 0x62, 0x15, 0x2f, 0xa0, 0xbf, 0x64, 0xb9, 0xcc, 0x39, 0xc1, 0x28, - 0xae, 0xc8, 0x87, 0x2d, 0xdd, 0xdf, 0x1d, 0x18, 0x4c, 0xec, 0x31, 0xc3, - 0xfb, 0x24, 0x2f, 0x73, 0xd4, 0x74, 0xda, 0xd6, 0x55, 0x5c, 0xbe, 0x01, - 0xe3, 0x5a, 0x17, 0x10, 0xce, 0x11, 0x87, 0xfc, 0xcf, 0xbd, 0x5d, 0x46, - 0x3e, 0xc4, 0x57, 0x74, 0x7a, 0x6e, 0x4c, 0xe3, 0x47, 0x5b, 0xac, 0xd6, - 0x92, 0xc5, 0x81, 0xdd, 0x43, 0x82, 0xec, 0x93, 0xb0, 0xca, 0xf7, 0x05, - 0xf9, 0x80, 0xb3, 0xce, 0xad, 0xa8, 0x6b, 0x30, 0x98, 0x21, 0x2a, 0x91, - 0xaa, 0xb2, 0x44, 0xd4, 0xdc, 0xd5, 0xb0, 0x35, 0x82, 0xba, 0x04, 0xb1, - 0x8c, 0x6a, 0x74, 0x3a, 0x05, 0x18, 0x54, 0x8f, 0x7a, 0xe8, 0x12, 0x3b, - 0xee, 0xb2, 0x56, 0x04, 0x5e, 0xda, 0x3e, 0x75, 0x51, 0xfe, 0xff, 0x71, - 0x11, 0xd4, 0x09, 0x96, 0x5c, 0x9f, 0xb9, 0xdc, 0x5d, 0xfb, 0xcf, 0x7e, - 0x92, 0x5d, 0xcb, 0xa5, 0x0d, 0xc0, 0x20, 0xbd, 0xe1, 0xf2, 0x5d, 0x59, - 0x2b, 0x2a, 0xe4, 0x31, 0x13, 0xbc, 0x77, 0xd6, 0x5c, 0x47, 0xa6, 0x75, - 0xf6, 0xb1, 0xd3, 0xa9, 0x7a, 0xac, 0x36, 0x28, 0x65, 0x75, 0x73, 0xa8, - 0x45, 0x1d, 0xb7, 0x7b, 0x6e, 0xe7, 0x3c, 0xb9, 0xfd, 0x71, 0x6b, 0xb9, - 0xb0, 0xd4, 0xcb, 0x06, 0x20, 0xc5, 0xce, 0x87, 0xdb, 0x03, 0xfa, 0x4c, - 0xe5, 0x54, 0x43, 0xbf, 0xa9, 0x93, 0xb6, 0xbf, 0xc2, 0xd8, 0x9e, 0x2b, - 0xc9, 0x08, 0xc5, 0xb4, 0xe2, 0x6a, 0x92, 0x8f, 0x1b, 0x8b, 0x88, 0x5e, - 0xca, 0xfa, 0x72, 0xf4, 0x4d, 0xf4, 0xa2, 0xb7, 0x1f, 0x7d, 0x1c, 0xdd, - 0xcb, 0x57, 0x62, 0xf4, 0x5b, 0x0c, 0x15, 0x8e, 0x9d, 0x35, 0xe0, 0x5a, - 0x04, 0xd1, 0xa3, 0x34, 0x61, 0xac, 0xfa, 0x97, 0xb9, 0xf2, 0x3b, 0x63, - 0xa1, 0x9e, 0xe8, 0x60, 0xad, 0xa9, 0x86, 0x5e, 0x51, 0xb8, 0x77, 0xf8, - 0x89, 0x02, 0x70, 0x5b, 0x5c, 0xfb, 0x98, 0x53, 0xad, 0x73, 0xdf, 0xb1, - 0x4b, 0xc3, 0x90, 0xd8, 0xae, 0x2e, 0x8a, 0xa2, 0x75, 0x2f, 0x8a, 0xb4, - 0xef, 0xc2, 0x0f, 0x05, 0xe2, 0xb0, 0xa6, 0xf6, 0x3b, 0x38, 0xe6, 0x9f, - 0x3a, 0x98, 0xa1, 0x47, 0x7d, 0x20, 0xf1, 0xa3, 0x6f, 0xb1, 0x6d, 0x33, - 0xc0, 0x8f, 0x48, 0xd9, 0x3e, 0x27, 0x5f, 0xb2, 0xe8, 0x4e, 0x51, 0xe1, - 0xf1, 0x8c, 0x5e, 0x58, 0x56, 0xe9, 0x85, 0xab, 0x0d, 0x25, 0xbe, 0x46, - 0x7e, 0xb7, 0x71, 0x62, 0x16, 0xe0, 0x6b, 0x5f, 0x22, 0xc9, 0x8a, 0x45, - 0x1f, 0xbf, 0xb6, 0x7f, 0x49, 0x12, 0x93, 0x59, 0x87, 0xe1, 0xb3, 0xd2, - 0xbc, 0x98, 0xa1, 0x71, 0xf5, 0x9f, 0x8c, 0xa8, 0x88, 0xd1, 0x09, 0x8e, - 0x9d, 0xfc, 0x3e, 0xd4, 0x61, 0x8a, 0xbb, 0x44, 0xa6, 0xc3, 0x8c, 0xf6, - 0x61, 0x37, 0x42, 0xd8, 0x05, 0x84, 0x8c, 0xa3, 0x18, 0xb8, 0x1c, 0xca, - 0xcb, 0x3a, 0xc7, 0x9d, 0xaa, 0xfd, 0xae, 0xbd, 0x1f, 0xbe, 0xc2, 0xf2, - 0xe9, 0xc6, 0xed, 0x6d, 0x8f, 0x85, 0x82, 0x45, 0xf4, 0x23, 0x5d, 0xf6, - 0x95, 0x42, 0x13, 0x1b, 0x7e, 0xb7, 0xad, 0xdf, 0xb8, 0x10, 0xac, 0xdc, - 0xa4, 0xfc, 0xae, 0xbf, 0x10, 0x21, 0x52, 0x79, 0x0d, 0xee, 0x4d, 0x59, - 0xbc, 0x07, 0x1f, 0x5b, 0x45, 0x96, 0x2d, 0x27, 0xcf, 0x5d, 0x31, 0x1a, - 0x1b, 0xdc, 0xde, 0xbc, 0xd9, 0xea, 0xfa, 0xe6, 0x02, 0xca, 0xcb, 0xb8, - 0x0a, 0xd3, 0xfc, 0x61, 0xb0, 0x80, 0x7f, 0xc0, 0x08, 0x4c, 0x0e, 0xcf, - 0x01, 0x8b, 0xac, 0x06, 0x84, 0x4b, 0xa1, 0xbb, 0x96, 0x25, 0xe2, 0xc1, - 0xd0, 0x43, 0xe2, 0xa1, 0x5e, 0x1e, 0x85, 0x26, 0x11, 0x33, 0xd6, 0xe1, - 0x2b, 0xe5, 0x08, 0x9a, 0x14, 0x5b, 0x9e, 0x88, 0xe8, 0x14, 0x02, 0x48, - 0x37, 0x1a, 0x0f, 0x14, 0x68, 0x22, 0xe1, 0x22, 0x94, 0xd0, 0x44, 0x77, - 0xcf, 0xf6, 0xc4, 0x81, 0x46, 0x84, 0x67, 0xdf, 0xb2, 0xcf, 0x7f, 0xf2, - 0x5f, 0x6e, 0x98, 0x24, 0xfa, 0xc9, 0xd7, 0x05, 0x41, 0x1a, 0xdf, 0x7d, - 0xfa, 0x4e, 0xff, 0xa2, 0x24, 0xb5, 0x95, 0x73, 0x32, 0xbc, 0xab, 0x7b, - 0x9b, 0x7e, 0xba, 0x31, 0xde, 0xba, 0x31, 0xaa, 0x2b, 0x63, 0xa6, 0x6e, - 0xf6, 0xa4, 0xe6, 0x62, 0x94, 0x98, 0xc1, 0x1c, 0x21, 0x61, 0x13, 0xdf, - 0xba, 0x76, 0x77, 0xcc, 0x68, 0x02, 0xaf, 0x60, 0x8a, 0xd8, 0xf1, 0x07, - 0x22, 0x85, 0xef, 0x9a, 0x76, 0xf0, 0x12, 0x35, 0x03, 0x7e, 0xf9, 0x83, - 0xd9, 0x2c, 0xa6, 0x46, 0x11, 0xd3, 0xdc, 0xf1, 0x86, 0x2b, 0x3f, 0xe5, - 0xb3, 0xbf, 0x06, 0xcd, 0xcf, 0xaa, 0x63, 0x47, 0x38, 0x05, 0x74, 0x7d, - 0xc7, 0xd0, 0x7d, 0x0f, 0xf3, 0x87, 0xf5, 0x38, 0x7c, 0xbb, 0xa9, 0xcb, - 0xb9, 0x40, 0xaf, 0xdd, 0x0c, 0x04, 0x5d, 0xca, 0x0d, 0xbf, 0xc6, 0x0c, - 0x01, 0x0d, 0xae, 0x24, 0x65, 0x84, 0x64, 0x15, 0x41, 0xa2, 0x29, 0x8a, - 0xb3, 0x9c, 0x8e, 0x24, 0x13, 0xff, 0x9f, 0x70, 0x60, 0x93, 0xfd, 0x30, - 0x2d, 0x38, 0x1b, 0xb8, 0x68, 0x4d, 0x85, 0x01, 0x2c, 0x24, 0x17, 0xda, - 0x6f, 0x06, 0x5f, 0x2d, 0x25, 0xa6, 0xf4, 0x5d, 0x16, 0xd2, 0xab, 0x67, - 0x80, 0x37, 0x1f, 0xef, 0x68, 0x80, 0x9b, 0x26, 0x80, 0x56, 0x00, 0x2f, - 0x5e, 0xb2, 0x22, 0x5f, 0x3c, 0x6c, 0xbf, 0x44, 0x1b, 0x2e, 0x35, 0x66, - 0x21, 0xf4, 0x44, 0x62, 0x57, 0xd2, 0xdb, 0xc4, 0x65, 0x66, 0x3e, 0xe4, - 0xbd, 0xeb, 0x06, 0xe5, 0xca, 0xed, 0x9a, 0xfd, 0x12, 0x6e, 0x02, 0x1b, - 0xdf, 0x8b, 0x09, 0xf7, 0xc1, 0xdc, 0x9a, 0x9d, 0xc5, 0x8d, 0xe0, 0xfc, - 0xe1, 0x79, 0xa7, 0xb3, 0x63, 0x4d, 0x1e, 0x5c, 0xe8, 0x52, 0x18, 0x2e, - 0x2d, 0x25, 0x92, 0x9e, 0xc0, 0x02, 0xa9, 0xc2, 0xdd, 0x68, 0x66, 0xb1, - 0x8e, 0xfd, 0xdf, 0xd1, 0x95, 0x97, 0x30, 0xb9, 0x5f, 0xda, 0xf1, 0x74, - 0x25, 0x1e, 0x10, 0xd4, 0xe1, 0x77, 0x6f, 0x9a, 0x68, 0xd5, 0x0d, 0x58, - 0x06, 0x77, 0x75, 0xe0, 0xe8, 0x9f, 0xe2, 0xff, 0xe6, 0x8a, 0xe3, 0x11, - 0xb6, 0x02, 0xf8, 0xbd, 0x75, 0x01, 0x20, 0xd3, 0x27, 0xa4, 0x14, 0xd2, - 0x7c, 0x6b, 0x81, 0x9a, 0x7a, 0x8a, 0x72, 0xf1, 0xea, 0x3a, 0xb4, 0x8f, - 0xae, 0xa9, 0x8d, 0x5f, 0x91, 0xd7, 0xfc, 0xbc, 0x96, 0xa7, 0xac, 0x84, - 0x5d, 0x10, 0xea, 0xef, 0xfa, 0x66, 0x43, 0x9f, 0xf3, 0x9f, 0xcd, 0x2c, - 0x9a, 0xfc, 0x6b, 0x2d, 0xf0, 0x47, 0xbf, 0xd1, 0x0e, 0x6c, 0xc7, 0xe8, - 0x97, 0xa0, 0x50, 0x76, 0x8b, 0x61, 0xd1, 0xcc, 0xa0, 0xaa, 0x96, 0x71, - 0x4e, 0xfb, 0xe1, 0xe7, 0xe0, 0xf3, 0xe6, 0x67, 0xe3, 0xe5, 0x84, 0x76, - 0x3e, 0xa9, 0x60, 0xb5, 0xb1, 0x46, 0x95, 0x97, 0xef, 0xd9, 0x86, 0x41, - 0x50, 0x44, 0x9f, 0x3b, 0xfd, 0x1c, 0x29, 0x0f, 0x70, 0x54, 0x65, 0xeb, - 0xe5, 0xc3, 0x7c, 0x20, 0x5a, 0xfe, 0xb6, 0x86, 0xcd, 0xf0, 0x52, 0xe9, - 0x4f, 0x97, 0xd9, 0x22, 0xd2, 0x8b, 0x5a, 0x2c, 0xae, 0x57, 0x61, 0xdf, - 0x63, 0x41, 0xb5, 0x7b, 0xa5, 0xdf, 0x3d, 0x03, 0xb0, 0x16, 0xf1, 0xde, - 0x09, 0xf2, 0x43, 0xd6, 0xb9, 0x65, 0x45, 0x7c, 0x35, 0x9c, 0x33, 0x65, - 0x1e, 0xf3, 0x4a, 0xc1, 0xc3, 0x68, 0xc9, 0x98, 0x64, 0x3e, 0x77, 0xf2, - 0x03, 0x42, 0x7a, 0x8b, 0xe7, 0x9f, 0x87, 0x2f, 0xd1, 0xf0, 0x90, 0xd3, - 0x4b, 0xe4, 0xb6, 0xc3, 0xcf, 0x77, 0x1b, 0x28, 0x5e, 0xf2, 0x19, 0xd8, - 0xf5, 0x47, 0x01, 0x59, 0xf1, 0x2b, 0x5c, 0x6f, 0xb4, 0x0f, 0x85, 0x4c, - 0x7b, 0x0c, 0xfb, 0x96, 0x30, 0x40, 0x19, 0x53, 0x5e, 0x17, 0x43, 0xbd, - 0xef, 0xdc, 0xb6, 0x40, 0xe4, 0xf3, 0xd2, 0x0a, 0xf7, 0xa3, 0x72, 0x2e, - 0xde, 0x8c, 0xef, 0x46, 0x55, 0x06, 0xa2, 0xde, 0xfb, 0x41, 0x3a, 0xa0, - 0xb8, 0x64, 0x4b, 0x7f, 0xed, 0xdf, 0x1e, 0x8e, 0x57, 0xea, 0x49, 0xac, - 0x18, 0x22, 0xbc, 0x4d, 0xc7, 0x70, 0xe3, 0x7d, 0xbd, 0x65, 0x93, 0x9f, - 0xfa, 0x62, 0xa1, 0x6e, 0x2f, 0xfd, 0x5f, 0x23, 0xf9, 0xb5, 0x75, 0x6d, - 0x8c, 0xfb, 0xfe, 0x41, 0x12, 0xee, 0xcd, 0x42, 0x27, 0x5e, 0xb8, 0x77, - 0x18, 0x8d, 0xee, 0xf2, 0xd9, 0xd2, 0x4a, 0x57, 0x16, 0x8e, 0xd3, 0xd8, - 0x2f, 0xa1, 0x02, 0x6f, 0x2b, 0x89, 0x31, 0x47, 0x27, 0x72, 0xbe, 0x01, - 0xbb, 0x31, 0xc2, 0x7e, 0x4e, 0x25, 0x3a, 0x0e, 0xfb, 0xad, 0xe6, 0x9c, - 0xa7, 0xff, 0xab, 0x39, 0x73, 0xdb, 0x7b, 0x8c, 0x2d, 0x6a, 0x15, 0xf1, - 0xb3, 0x40, 0x8e, 0x67, 0x09, 0x00, 0xbf, 0x95, 0xe0, 0x8a, 0x2a, 0x93, - 0x75, 0xf9, 0x67, 0x6f, 0x70, 0x62, 0x07, 0x7f, 0x0d, 0x4e, 0x1a, 0xf2, - 0xa1, 0x7a, 0x3e, 0xba, 0x80, 0xfb, 0xd2, 0x9e, 0x69, 0xee, 0xf3, 0xad, - 0x21, 0xb4, 0x46, 0xc2, 0xcc, 0xec, 0x45, 0x1e, 0xe1, 0xd3, 0x17, 0xf7, - 0x6f, 0x27, 0xbe, 0x02, 0x42, 0x57, 0x9f, 0xea, 0x19, 0x53, 0xf4, 0x8c, - 0x90, 0xb2, 0x8c, 0x99, 0x04, 0xc7, 0xe4, 0x96, 0xfe, 0x6a, 0x84, 0x23, - 0x60, 0x96, 0x79, 0x7f, 0x40, 0xa0, 0xcf, 0x77, 0x0d, 0xd7, 0x77, 0xb6, - 0xc3, 0xbb, 0xde, 0x50, 0xc0, 0xd4, 0x78, 0x7e, 0xf0, 0xaf, 0x5e, 0xd1, - 0x95, 0x92, 0x62, 0x44, 0xa4, 0xef, 0x2e, 0x25, 0xc0, 0x82, 0x0f, 0xf4, - 0x2f, 0xee, 0xcf, 0x17, 0xb6, 0x2d, 0x4a, 0x3f, 0xcd, 0x5f, 0x8e, 0x1d, - 0xc1, 0x4f, 0x38, 0xff, 0xcc, 0x9d, 0xad, 0xdf, 0x39, 0x41, 0x62, 0x86, - 0x67, 0x32, 0x37, 0xa8, 0x47, 0xd4, 0x12, 0x65, 0xaa, 0x7a, 0xd0, 0x61, - 0x70, 0xcf, 0x35, 0x9e, 0x9b, 0x11, 0x5b, 0xaf, 0xb3, 0x00, 0x8a, 0x8e, - 0xe3, 0xa8, 0x55, 0x84, 0xcc, 0xd9, 0xa1, 0x7e, 0xa6, 0x9d, 0x02, 0x5e, - 0xa6, 0x0c, 0x08, 0xd0, 0x24, 0x13, 0x95, 0x83, 0x1a, 0x06, 0xcc, 0x4a, - 0x76, 0x73, 0xed, 0x5a, 0x66, 0x8f, 0x5c, 0x0a, 0x3e, 0x45, 0x06, 0x8f, - 0x01, 0xff, 0x1d, 0x40, 0x51, 0xd0, 0xc3, 0x05, 0x48, 0x2b, 0xdf, 0xaa, - 0x25, 0x85, 0xd2, 0xbe, 0x98, 0xcd, 0x97, 0x80, 0x89, 0x79, 0xad, 0x51, - 0xb0, 0xd6, 0x88, 0xd3, 0x82, 0x29, 0x09, 0x5d, 0xce, 0x0e, 0x1b, 0xf1, - 0x8b, 0xf2, 0xb1, 0x18, 0x7e, 0x69, 0x7f, 0xac, 0x07, 0xb7, 0x6c, 0xc8, - 0x02, 0x98, 0x1c, 0x1e, 0x3c, 0x60, 0xdb, 0x3d, 0x4a, 0x02, 0x02, 0x8a, - 0x70, 0x1e, 0x04, 0x55, 0x67, 0xc9, 0xb1, 0x33, 0xf7, 0x20, 0x5a, 0x43, - 0x6a, 0xd4, 0xc1, 0x97, 0x27, 0x6b, 0x27, 0x4b, 0x54, 0x33, 0xc4, 0xf7, - 0x8f, 0x81, 0x00, 0x7c, 0xf0, 0xc8, 0x14, 0x88, 0xae, 0xbf, 0xf3, 0xd3, - 0xf2, 0x45, 0x8f, 0x94, 0x41, 0xd6, 0xa5, 0xe5, 0x7c, 0x1e, 0x5e, 0x4c, - 0x58, 0x5f, 0x61, 0xa7, 0x99, 0x31, 0x37, 0x43, 0x38, 0x69, 0x1c, 0x6a, - 0x0d, 0xc0, 0xe4, 0xff, 0xda, 0x33, 0xaf, 0x0a, 0x65, 0xee, 0x9d, 0x00, - 0xf6, 0xb8, 0xbc, 0x95, 0x63, 0xea, 0x46, 0x2e, 0x4b, 0x3f, 0x8a, 0xf3, - 0xb0, 0xa7, 0x84, 0x35, 0x2e, 0x04, 0x04, 0x68, 0x3f, 0x0a, 0xbb, 0x07, - 0x09, 0xfa, 0x11, 0x9e, 0xb0, 0xd1, 0xae, 0x05, 0x3a, 0x57, 0x62, 0x14, - 0x20, 0x03, 0xce, 0x52, 0xa2, 0xf9, 0x92, 0x71, 0xfd, 0x09, 0xeb, 0x69, - 0xaa, 0x1b, 0xf8, 0xb7, 0x3d, 0x3c, 0x21, 0x7f, 0x21, 0x63, 0xab, 0x76, - 0x26, 0x36, 0xa2, 0xf7, 0x61, 0x90, 0x60, 0xc1, 0xeb, 0x05, 0x1c, 0x16, - 0x83, 0x32, 0x07, 0x4a, 0xc0, 0x39, 0x52, 0xab, 0x8c, 0x05, 0x70, 0xc1, - 0x3c, 0x62, 0xa9, 0x65, 0x4f, 0x4c, 0x92, 0xfc, 0x1a, 0x55, 0xa4, 0xb9, - 0x20, 0x33, 0x6e, 0x72, 0xa7, 0xa2, 0x3d, 0x2d, 0xda, 0xc2, 0x39, 0x39, - 0x38, 0x9d, 0xb3, 0xbb, 0x5e, 0x6d, 0x98, 0x63, 0x1f, 0xaa, 0xcf, 0x9f, - 0xaa, 0x33, 0x98, 0x3d, 0xf2, 0x7f, 0x14, 0xf9, 0xc3, 0xb2, 0xa6, 0x10, - 0xc5, 0x95, 0x8b, 0xe6, 0xa9, 0xcc, 0x08, 0x74, 0x9d, 0xf8, 0xa4, 0x28, - 0x73, 0x9e, 0x10, 0x71, 0x3c, 0x94, 0xd7, 0x7e, 0xae, 0xfb, 0x61, 0x9b, - 0x77, 0x19, 0x8e, 0x2b, 0xee, 0x28, 0x94, 0xa8, 0xea, 0xc8, 0x68, 0x67, - 0x76, 0xb5, 0x33, 0xbd, 0x20, 0xc0, 0x08, 0x46, 0xde, 0xca, 0x86, 0x24, - 0xfd, 0xcc, 0x59, 0xcb, 0x28, 0x04, 0x37, 0x6d, 0x1e, 0x18, 0x53, 0x0d, - 0x97, 0x55, 0x74, 0x50, 0x32, 0x7b, 0xfb, 0x1e, 0x12, 0x73, 0x3a, 0xa1, - 0x08, 0xde, 0xa2, 0x51, 0x0e, 0x8e, 0x54, 0x7c, 0x86, 0xa4, 0xda, 0x10, - 0xaa, 0xc1, 0x96, 0x63, 0xef, 0xa5, 0xe7, 0x9e, 0x5c, 0x3d, 0x43, 0x93, - 0x67, 0x6a, 0x0b, 0xae, 0x48, 0x86, 0xe5, 0xd1, 0x5c, 0x43, 0x94, 0xcd, - 0x2e, 0x90, 0x62, 0xe8, 0xfc, 0xb9, 0xc2, 0x40, 0x99, 0x23, 0xd1, 0x9b, - 0x6c, 0xfd, 0x7b, 0xec, 0x8e, 0x1b, 0xac, 0xd4, 0xe8, 0xe6, 0x61, 0xe8, - 0x5e, 0x55, 0x5d, 0x8d, 0x78, 0xd4, 0x38, 0x0a, 0x0d, 0x30, 0x04, 0x25, - 0x3f, 0x2e, 0xcc, 0x2b, 0xc0, 0x8a, 0x23, 0x5e, 0x17, 0x3b, 0x33, 0x76, - 0xe4, 0x66, 0x7b, 0x88, 0x19, 0x8f, 0x65, 0xe6, 0xaf, 0xc4, 0x9a, 0x22, - 0x46, 0x2b, 0x35, 0x60, 0xbc, 0x0d, 0xb4, 0xbc, 0xa1, 0x33, 0xdf, 0xb8, - 0xd7, 0x94, 0x1b, 0xb0, 0xb9, 0x4f, 0xc9, 0x2e, 0x79, 0xba, 0x08, 0x64, - 0x52, 0xaf, 0x89, 0x18, 0xee, 0x95, 0xba, 0xcf, 0x9f, 0x56, 0xa5, 0x8f, - 0xba, 0xa2, 0x73, 0x5d, 0x9a, 0x33, 0x0b, 0xfe, 0x38, 0x11, 0x02, 0xa6, - 0x28, 0xf0, 0xce, 0xff, 0x6e, 0xaa, 0xdf, 0x3c, 0xf7, 0x5c, 0xc2, 0xd1, - 0x8a, 0x07, 0x1a, 0x24, 0xd1, 0x7f, 0x0c, 0xbf, 0x45, 0x9e, 0x41, 0x4f, - 0x66, 0x97, 0x19, 0x23, 0xa3, 0xbe, 0x9e, 0x81, 0x42, 0x79, 0x70, 0xa9, - 0x84, 0x24, 0x8d, 0x52, 0x5b, 0x01, 0x3e, 0xb3, 0x13, 0x54, 0xee, 0xc8, - 0xbb, 0x4f, 0x25, 0x4e, 0xbc, 0xec, 0x4c, 0xd5, 0x68, 0xeb, 0x09, 0xf8, - 0x4a, 0xcc, 0xea, 0x5b, 0xab, 0x5d, 0x32, 0xa2, 0xee, 0xdc, 0xe2, 0xf5, - 0x89, 0x89, 0x84, 0xfe, 0x5a, 0x4e, 0x11, 0x82, 0x54, 0xb2, 0xb8, 0xf1, - 0xf0, 0x45, 0xd9, 0x6b, 0xde, 0x1e, 0xf4, 0x70, 0x53, 0x13, 0xa9, 0xfd, - 0x60, 0x83, 0x70, 0xae, 0xbe, 0xe5, 0x6f, 0xdc, 0xe4, 0x0a, 0xb1, 0x45, - 0x13, 0x7d, 0xb7, 0x27, 0x45, 0x3a, 0x0a, 0xbd, 0x77, 0x1d, 0x68, 0x33, - 0xdb, 0x59, 0xff, 0xa8, 0x12, 0x14, 0x2d, 0xfa, 0x6d, 0xc1, 0xcc, 0x06, - 0xb8, 0x7b, 0xc2, 0xa3, 0xe4, 0x8b, 0x80, 0x97, 0x00, 0x38, 0x80, 0xf5, - 0xa2, 0xda, 0xf7, 0x50, 0xd9, 0x52, 0x6d, 0x5a, 0x22, 0xb9, 0xcf, 0xa1, - 0x07, 0x5a, 0x9c, 0xa0, 0xbe, 0xb7, 0x55, 0x08, 0x0e, 0x52, 0x58, 0x26, - 0x4b, 0x8b, 0xc4, 0xc3, 0x57, 0x3f, 0xde, 0x9a, 0x9f, 0x95, 0xd8, 0xc2, - 0x6d, 0xea, 0x41, 0x06, 0xf8, 0x0c, 0x4b, 0x85, 0xac, 0x96, 0x16, 0x87, - 0x4b, 0xf5, 0xa8, 0x97, 0x58, 0x88, 0x76, 0xaa, 0x94, 0x3f, 0x30, 0x4b, - 0x81, 0x54, 0xf6, 0x40, 0x1b, 0x64, 0xa4, 0x89, 0x5a, 0x9f, 0x6b, 0x74, - 0x75, 0x5a, 0xa9, 0x57, 0x0b, 0x8f, 0xce, 0xcd, 0x5a, 0x97, 0x6f, 0x31, - 0xcf, 0x15, 0x17, 0xf5, 0x80, 0x34, 0xfc, 0x94, 0x87, 0x18, 0x6d, 0xae, - 0xce, 0x0a, 0xb9, 0xbf, 0x69, 0x07, 0x6f, 0x89, 0x5b, 0xc1, 0x92, 0x8d, - 0x43, 0xc9, 0x6f, 0x83, 0x7e, 0x08, 0x30, 0xd8, 0xba, 0x4c, 0x48, 0x7f, - 0x7e, 0x89, 0xc7, 0xa8, 0x1b, 0xf2, 0xaa, 0x77, 0x0b, 0xc1, 0x85, 0x98, - 0xe8, 0xb1, 0x6e, 0xe9, 0x01, 0x7e, 0x66, 0x8c, 0x8d, 0x06, 0x53, 0xac, - 0x6c, 0x3b, 0xfe, 0xd1, 0xfe, 0x3a, 0x2c, 0x25, 0xa1, 0xf7, 0x2d, 0xf5, - 0xdd, 0xb4, 0x21, 0x08, 0xd1, 0xd8, 0x83, 0x08, 0xfc, 0x40, 0xbe, 0x19, - 0x95, 0x70, 0x9c, 0xc4, 0x6c, 0x18, 0xb6, 0xb5, 0xd6, 0x76, 0x77, 0x7d, - 0x65, 0xf4, 0x08, 0x16, 0x12, 0x44, 0xb0, 0x46, 0xb5, 0x3a, 0x1a, 0xc3, - 0xff, 0xff, 0xca, 0x11, 0x26, 0x8c, 0x26, 0x2d, 0x66, 0x56, 0xef, 0x74, - 0x61, 0xdc, 0x6f, 0x4b, 0xd8, 0xfe, 0x90, 0xe7, 0x6b, 0x3f, 0x6f, 0x72, - 0x72, 0x6d, 0xfc, 0xfd, 0x23, 0xe5, 0x5d, 0xc2, 0xc8, 0x8a, 0x31, 0x6f, - 0x83, 0x34, 0xfa, 0x02, 0xaa, 0x5d, 0x25, 0x0c, 0x7b, 0x33, 0x2c, 0x9c, - 0x6f, 0x98, 0xdd, 0x38, 0xbe, 0xbd, 0xa9, 0x17, 0x58, 0x53, 0x92, 0x6c, - 0xea, 0xcf, 0x38, 0xdd, 0xa0, 0x35, 0x07, 0xac, 0xa3, 0x95, 0xe9, 0x1a, - 0xb2, 0x37, 0x75, 0x04, 0xbe, 0xdb, 0x30, 0xb0, 0xd1, 0x0b, 0x8a, 0x6d, - 0x50, 0x86, 0x49, 0xb5, 0x03, 0x94, 0x55, 0x0b, 0x8b, 0x7b, 0xf2, 0xb0, - 0x3e, 0x18, 0xc9, 0xa4, 0xe4, 0x10, 0x6e, 0x5e, 0xc4, 0x60, 0x31, 0x52, - 0xfc, 0x5c, 0x0c, 0xc3, 0x1e, 0x73, 0x36, 0x06, 0x48, 0x34, 0x78, 0xe5, - 0x4a, 0xc9, 0x5c, 0x0e, 0x80, 0x6b, 0x54, 0x74, 0x4b, 0x52, 0x23, 0x43, - 0xe5, 0xea, 0x55, 0x2a, 0x0d, 0x44, 0xe2, 0x81, 0x56, 0xc0, 0xe4, 0xd1, - 0xcb, 0xc1, 0xdd, 0x22, 0x9e, 0xa2, 0x65, 0x8a, 0x79, 0x0f, 0xd0, 0x27, - 0x74, 0xcc, 0xf1, 0x76, 0x88, 0xa9, 0x19, 0x12, 0xf0, 0xd3, 0x7c, 0xf2, - 0x6f, 0x0e, 0x02, 0x58, 0xd0, 0xb6, 0x08, 0x7e, 0x14, 0x70, 0xbf, 0x0e, - 0x0a, 0x04, 0xce, 0x3e, 0x50, 0x88, 0x81, 0xbd, 0x23, 0x5e, 0x66, 0x12, - 0x46, 0xb8, 0x66, 0x86, 0x94, 0xe1, 0x09, 0xda, 0x60, 0x0e, 0xa3, 0x2c, - 0xa9, 0xb9, 0x5b, 0x5e, 0x92, 0xb5, 0x48, 0xc4, 0xd3, 0x1f, 0x5a, 0xc7, - 0x82, 0xcb, 0x67, 0x78, 0x02, 0xd8, 0x87, 0xb8, 0x2e, 0x38, 0x2c, 0xff, - 0x68, 0x12, 0x90, 0x30, 0xe4, 0xf1, 0x0e, 0x9a, 0x55, 0xd5, 0x16, 0xad, - 0x86, 0xbd, 0x03, 0xea, 0x2a, 0x49, 0x84, 0x2e, 0xa7, 0x2d, 0xcd, 0xaf, - 0x8c, 0x2a, 0x0b, 0xf5, 0xe1, 0x43, 0x55, 0xa6, 0x26, 0x65, 0x33, 0x4b, - 0x6a, 0xa1, 0x3d, 0xd5, 0xe7, 0x40, 0x7a, 0x34, 0x05, 0xdf, 0xbc, 0xe9, - 0x31, 0x5e, 0x93, 0x95, 0x29, 0x19, 0xfb, 0xfa, 0x3e, 0xa3, 0x9f, 0x9e, - 0x0b, 0x28, 0x7c, 0x33, 0xfb, 0xd0, 0x00, 0x34, 0x87, 0xe4, 0xf9, 0x26, - 0xfb, 0x46, 0xe1, 0x8a, 0x4f, 0x4a, 0x22, 0x44, 0x8b, 0x0a, 0xf7, 0xa4, - 0xa6, 0xc5, 0x55, 0x07, 0x7e, 0x1e, 0x11, 0xfd, 0x55, 0xfc, 0xac, 0x5c, - 0xa1, 0x30, 0xf1, 0xbe, 0x16, 0xd3, 0x6d, 0x0f, 0x1e, 0x02, 0xfa, 0x20, - 0x66, 0x4d, 0x7c, 0x3f, 0x86, 0x42, 0x7d, 0x4b, 0x4e, 0x17, 0x43, 0xf7, - 0x39, 0x46, 0x84, 0xfc, 0x2e, 0xd5, 0xe1, 0x3b, 0x72, 0x03, 0xef, 0xf5, - 0xfc, 0xb9, 0x4f, 0x91, 0xe7, 0xa4, 0x39, 0xf5, 0x2e, 0x3f, 0x52, 0xed, - 0xed, 0xa8, 0x22, 0x37, 0xfe, 0x1c, 0x27, 0xeb, 0x83, 0x7d, 0x64, 0xe6, - 0x44, 0x23, 0x04, 0xe0, 0xe4, 0xf7, 0xfe, 0xa4, 0xed, 0x5c, 0x24, 0x7e, - 0xb1, 0x1b, 0xa7, 0x2c, 0xe5, 0x27, 0x78, 0xcf, 0xef, 0x78, 0xff, 0xee, - 0xaf, 0xcd, 0xa1, 0x52, 0x67, 0x8e, 0x6f, 0x35, 0x55, 0xf8, 0xa6, 0xa0, - 0x2b, 0xc8, 0xf2, 0x37, 0xc9, 0xe4, 0x09, 0x3a, 0x7d, 0xcf, 0xd9, 0x23, - 0x17, 0x5f, 0x1b, 0xca, 0x59, 0x0f, 0xea, 0x3e, 0xde, 0xb2, 0xb4, 0x78, - 0x3a, 0x88, 0xdc, 0xd8, 0xcf, 0xc8, 0x45, 0xf3, 0xc7, 0x8a, 0x88, 0x93, - 0x6c, 0xf4, 0x01, 0x52, 0xcf, 0xac, 0xac, 0x88, 0x7d, 0xcd, 0x72, 0x2c, - 0xc5, 0x76, 0xe2, 0x5d, 0xc7, 0xef, 0xa8, 0xea, 0x37, 0xd0, 0xe1, 0xb1, - 0xf0, 0xa9, 0x89, 0xb7, 0x92, 0x35, 0x00, 0xac, 0xb5, 0x85, 0x00, 0xef, - 0x7b, 0x42, 0xa2, 0xfc, 0xcb, 0x4b, 0xc4, 0x45, 0x38, 0xea, 0xba, 0xf7, - 0x7b, 0xc3, 0x05, 0x52, 0x83, 0x31, 0xcd, 0x25, 0x05, 0xef, 0xcb, 0xcd, - 0xe2, 0xfa, 0x4a, 0x5f, 0x74, 0x04, 0x44, 0x30, 0x70, 0x4f, 0x62, 0xde, - 0x99, 0xe0, 0x14, 0xb5, 0x9c, 0xa5, 0x64, 0x09, 0x7f, 0x71, 0x52, 0x0d, - 0xc9, 0xf2, 0xeb, 0xd5, 0x72, 0x1a, 0xfe, 0x52, 0xf6, 0xfb, 0xe4, 0xd9, - 0x1a, 0x6c, 0x1a, 0x6d, 0x0c, 0xc8, 0xa3, 0xde, 0x03, 0xc3, 0x27, 0xde, - 0x46, 0x7c, 0xdd, 0x2c, 0x52, 0x9a, 0x4a, 0xab, 0xa4, 0x80, 0xb2, 0x2d, - 0xe6, 0x36, 0x42, 0x5b, 0x64, 0xb2, 0xa5, 0x6d, 0xae, 0x4d, 0x5a, 0xd7, - 0x07, 0x8b, 0x03, 0x66, 0x07, 0x34, 0xfe, 0xe7, 0xf6, 0x16, 0x2a, 0x57, - 0x3d, 0x5a, 0xd7, 0xf8, 0xec, 0x9f, 0x24, 0x58, 0xc6, 0xca, 0xf1, 0x0a, - 0xf6, 0xd4, 0x38, 0xd1, 0xb0, 0x10, 0x50, 0x18, 0x8d, 0xe7, 0x5b, 0x31, - 0xff, 0xb7, 0xd9, 0x58, 0xe4, 0x6e, 0x80, 0x3c, 0xe6, 0x24, 0xb9, 0x96, - 0x20, 0xaf, 0x74, 0xb4, 0xdb, 0x9b, 0x28, 0x64, 0x85, 0x32, 0x2a, 0x6e, - 0x0f, 0xfb, 0x04, 0x8d, 0x72, 0x34, 0xb6, 0x21, 0xa7, 0x14, 0x40, 0xc2, - 0x1a, 0xb8, 0xd6, 0xb6, 0x6e, 0x70, 0x59, 0xac, 0x2c, 0x07, 0xe9, 0xd8, - 0xcb, 0x75, 0xb9, 0xba, 0xd8, 0x03, 0xab, 0xca, 0xd0, 0x54, 0xe0, 0x73, - 0x61, 0x63, 0x4b, 0xd0, 0x85, 0x11, 0x67, 0x22, 0xb1, 0x14, 0x47, 0x92, - 0x5d, 0x57, 0x51, 0x06, 0x25, 0x6a, 0xcb, 0xb9, 0x2c, 0xb7, 0x44, 0x64, - 0x5c, 0xfc, 0x48, 0x49, 0xf4, 0x70, 0x54, 0xab, 0x9e, 0x9d, 0x05, 0x0a, - 0x01, 0xd5, 0xf1, 0x01, 0x14, 0xd6, 0x7a, 0x0a, 0x90, 0xd4, 0x7a, 0x6b, - 0xc9, 0x38, 0x22, 0x1a, 0xc8, 0xdf, 0xc6, 0x2c, 0x39, 0x57, 0x46, 0x05, - 0xca, 0x73, 0x2f, 0x8a, 0x5c, 0x8d, 0x0c, 0xf6, 0xac, 0xb1, 0x76, 0x55, - 0xa4, 0xc3, 0xfc, 0x4c, 0x84, 0x89, 0x54, 0xd5, 0xdf, 0xd2, 0xcd, 0x37, - 0x96, 0x95, 0x98, 0xb1, 0x42, 0x4a, 0x60, 0x78, 0x63, 0xc7, 0xc4, 0x76, - 0x56, 0x04, 0xbe, 0x1c, 0x42, 0x79, 0x5e, 0xc8, 0x66, 0xbb, 0xb0, 0x94, - 0xe8, 0x29, 0xa9, 0xae, 0xb9, 0x56, 0x5f, 0xa7, 0x8a, 0x86, 0x29, 0xcc, - 0x44, 0x4a, 0x34, 0xdd, 0xef, 0xba, 0xb7, 0x2d, 0x85, 0x73, 0x09, 0x03, - 0x09, 0x80, 0xf0, 0x32, 0xa0, 0x7c, 0x7b, 0xd3, 0xf8, 0x12, 0x8a, 0x25, - 0x67, 0x96, 0xcc, 0x5b, 0x1e, 0x2f, 0xd4, 0x0a, 0x74, 0x80, 0xc2, 0x47, - 0xd3, 0xd9, 0x7c, 0xfe, 0x0a, 0x1e, 0x1c, 0xce, 0xfb, 0x90, 0xbe, 0x0d, - 0xc5, 0x70, 0xd8, 0x7d, 0xea, 0x45, 0x90, 0x6b, 0xb0, 0x6b, 0xa3, 0xb1, - 0x10, 0x2d, 0xf3, 0x99, 0x4a, 0xd5, 0x6b, 0x19, 0x86, 0xfc, 0x7f, 0xae, - 0x83, 0x26, 0x21, 0x27, 0x0e, 0x9b, 0x25, 0x61, 0xbc, 0xda, 0xff, 0xf8, - 0x63, 0xf8, 0xba, 0xf6, 0xaf, 0xdc, 0xe7, 0x1d, 0x48, 0x49, 0x31, 0x85, - 0x19, 0x16, 0x19, 0x18, 0x58, 0x30, 0x7a, 0xfe, 0x1a, 0xf1, 0xa1, 0xe3, - 0xb5, 0x9b, 0xd3, 0x6b, 0x2d, 0x13, 0x7d, 0x0e, 0xaf, 0xf8, 0x07, 0x21, - 0xa1, 0x90, 0x40, 0x46, 0x85, 0x3b, 0x74, 0x1f, 0xa1, 0x32, 0xa3, 0x8d, - 0x7e, 0x9b, 0xdc, 0x5c, 0x77, 0xfe, 0x28, 0x20, 0x04, 0xf8, 0xe7, 0x28, - 0x2a, 0x8f, 0xcf, 0x6f, 0x53, 0x8d, 0xb4, 0x9d, 0x8c, 0x69, 0xd0, 0xc0, - 0x21, 0x63, 0xaa, 0x30, 0x6b, 0xf4, 0xf5, 0x31, 0x56, 0x14, 0xc3, 0x92, - 0x94, 0x00, 0x99, 0x01, 0xa5, 0xa1, 0x64, 0x69, 0xe6, 0x1a, 0xa9, 0xa4, - 0x13, 0x4f, 0x7f, 0x0b, 0x3b, 0xd8, 0x72, 0x5d, 0x4c, 0x3d, 0x3f, 0x6c, - 0x2b, 0x75, 0x3b, 0x33, 0x52, 0xce, 0x09, 0x50, 0xdf, 0x4b, 0xe5, 0xcc, - 0x3c, 0x19, 0x14, 0x90, 0x93, 0x15, 0x99, 0x14, 0x6c, 0x56, 0xff, 0x21, - 0xb6, 0xb3, 0x67, 0x38, 0x3f, 0x6a, 0xfd, 0xd4, 0x32, 0x9f, 0x86, 0x86, - 0x2e, 0xf4, 0x5b, 0x19, 0xb8, 0x6a, 0x6e, 0xc9, 0xe7, 0xb0, 0xaa, 0xae, - 0x6b, 0x3b, 0x22, 0x00, 0x5e, 0xea, 0xc6, 0x0b, 0xa7, 0x9a, 0x3e, 0x96, - 0xa2, 0x1a, 0x4b, 0x2d, 0x09, 0xc9, 0xef, 0x2e, 0x9e, 0x59, 0xec, 0xd1, - 0x8c, 0x1a, 0xba, 0x2e, 0x7c, 0xce, 0x67, 0x03, 0xdb, 0x6f, 0x1a, 0x1d, - 0x46, 0x3a, 0x04, 0x70, 0x24, 0x94, 0x69, 0xc6, 0x3f, 0x5f, 0x87, 0x27, - 0x7b, 0xe4, 0xfd, 0x63, 0x7d, 0xb0, 0xac, 0x12, 0xc5, 0x3b, 0xaa, 0x67, - 0xa7, 0x60, 0xbd, 0x4f, 0xc3, 0xd6, 0x81, 0x21, 0xff, 0xc5, 0x91, 0x5c, - 0x7a, 0x3a, 0x01, 0x21, 0x79, 0x61, 0x1f, 0x82, 0x17, 0x6f, 0xb7, 0x07, - 0x8e, 0x64, 0x10, 0xe7, 0x2d, 0x51, 0xef, 0x4b, 0x41, 0x3e, 0xb1, 0x90, - 0x93, 0xfc, 0x27, 0xdc, 0x64, 0x2b, 0x00, 0x85, 0x6c, 0x03, 0x41, 0xf4, - 0xac, 0x6b, 0xb1, 0x82, 0xb2, 0xe0, 0xe3, 0x90, 0xf6, 0x6a, 0xc5, 0x88, - 0x65, 0x82, 0xfe, 0x22, 0x7c, 0x5a, 0x94, 0x94, 0xb4, 0x6d, 0x94, 0x6f, - 0x5e, 0x14, 0x57, 0x4d, 0xdc, 0x49, 0x18, 0xa8, 0x69, 0x46, 0x0a, 0x62, - 0x64, 0x88, 0x8d, 0xc3, 0x39, 0x40, 0x78, 0x2b, 0x3a, 0xb0, 0xb9, 0x13, - 0x6c, 0x79, 0xbd, 0xed, 0x72, 0xa9, 0xa3, 0xa6, 0x73, 0xac, 0xf9, 0xfd, - 0x34, 0xe5, 0x0c, 0x2d, 0x28, 0x94, 0xc8, 0xb1, 0xec, 0x71, 0x2a, 0x99, - 0x20, 0x4c, 0x2b, 0x91, 0x9a, 0xb4, 0x4c, 0x04, 0x09, 0xe8, 0x26, 0xcf, - 0x9d, 0xf2, 0xbe, 0xb2, 0xd0, 0x43, 0x90, 0xbe, 0xe3, 0xba, 0x66, 0x59, - 0x46, 0x45, 0xaa, 0xeb, 0xc6, 0xe8, 0xf8, 0x32, 0xf3, 0xce, 0x23, 0x94, - 0x6d, 0x25, 0x64, 0x73, 0xcd, 0xec, 0x06, 0x69, 0x8d, 0x1d, 0xb8, 0x51, - 0xe4, 0x5f, 0x62, 0x61, 0x27, 0xf8, 0x2a, 0x55, 0xc5, 0xe0, 0xec, 0x39, - 0xec, 0x92, 0x6c, 0xc7, 0xab, 0x30, 0x26, 0xeb, 0x36, 0xa8, 0x15, 0x38, - 0x74, 0x9b, 0xac, 0x54, 0x5f, 0x30, 0x8a, 0xf1, 0x3b, 0x85, 0xf1, 0x37, - 0x94, 0x00, 0xda, 0x34, 0xe4, 0x9b, 0xab, 0x92, 0xce, 0x3f, 0xdc, 0x0f, - 0x8e, 0x03, 0xca, 0x95, 0x9b, 0xc7, 0x39, 0xcc, 0x25, 0x48, 0xc9, 0xd0, - 0x2e, 0xa5, 0x85, 0x08, 0x22, 0xf5, 0x17, 0xc1, 0xb1, 0x37, 0x4f, 0x52, - 0x3e, 0xa5, 0x18, 0x68, 0xe9, 0x73, 0xa8, 0x16, 0x0a, 0xc2, 0xff, 0x7c, - 0xa3, 0x8a, 0xc3, 0x0d, 0xfd, 0xe0, 0x7a, 0x09, 0xc9, 0x72, 0x7d, 0xfb, - 0x45, 0x45, 0xc1, 0xab, 0xd6, 0xce, 0xe6, 0xc3, 0xfa, 0x02, 0xc7, 0x9c, - 0x57, 0x63, 0x03, 0x0d, 0x9a, 0xf1, 0x53, 0xaa, 0xfb, 0x6a, 0xff, 0x38, - 0x3a, 0x8f, 0x25, 0x37, 0x81, 0x28, 0x8a, 0x7e, 0x10, 0x0b, 0x72, 0x5a, - 0x92, 0x73, 0xce, 0xda, 0x91, 0x05, 0x22, 0x67, 0xf8, 0x7a, 0x33, 0x2e, - 0xbb, 0xca, 0x55, 0xb6, 0xcc, 0x48, 0xdd, 0xaf, 0xef, 0x3b, 0x47, 0x84, - 0x9e, 0x32, 0xe9, 0xda, 0xda, 0x4a, 0xa0, 0x8c, 0x3c, 0xb0, 0x5d, 0x7d, - 0x95, 0x12, 0x0d, 0x9b, 0xcf, 0x77, 0xf1, 0x0e, 0x70, 0xdd, 0xd6, 0x8b, - 0x4f, 0x3e, 0x9f, 0x7d, 0x5e, 0xc4, 0x14, 0xe8, 0xdd, 0xe9, 0xe0, 0x80, - 0xdc, 0x06, 0xa7, 0xa5, 0x44, 0xf5, 0xf5, 0x37, 0x5e, 0x3b, 0xef, 0xdf, - 0xf3, 0x11, 0x7b, 0xdb, 0xa9, 0xa2, 0x33, 0x42, 0xc5, 0xa0, 0xe6, 0xe3, - 0x55, 0xca, 0xd6, 0xdd, 0x7d, 0x4b, 0x83, 0xb0, 0xc4, 0x00, 0x12, 0x55, - 0xf9, 0x77, 0x00, 0x7e, 0xe7, 0xf3, 0xf9, 0xa0, 0x5e, 0x25, 0x25, 0x1c, - 0xad, 0x6a, 0x23, 0x57, 0x7b, 0x8d, 0xf8, 0x3a, 0x23, 0x17, 0x3f, 0x59, - 0x90, 0xd8, 0x20, 0xbb, 0xc0, 0x6e, 0x71, 0x57, 0xc5, 0xb7, 0x72, 0xbe, - 0xbb, 0xac, 0x8a, 0x8e, 0xf8, 0xba, 0x6e, 0x55, 0x51, 0xc4, 0x43, 0x3c, - 0xdc, 0xba, 0x3c, 0x14, 0xac, 0x5e, 0x77, 0x72, 0xc2, 0x77, 0xac, 0x87, - 0x5f, 0x46, 0x4e, 0xf6, 0xdb, 0xf4, 0x4e, 0x1c, 0x89, 0xe7, 0x32, 0x94, - 0xc8, 0x81, 0x61, 0x69, 0xea, 0x34, 0xa9, 0xef, 0xa3, 0x53, 0x8d, 0xca, - 0x16, 0x1e, 0x51, 0x13, 0x7f, 0x5b, 0x0b, 0xef, 0x95, 0x90, 0xb3, 0xf7, - 0x6e, 0x78, 0x32, 0x7e, 0x04, 0xa6, 0xfc, 0xd4, 0x37, 0xae, 0x97, 0xe4, - 0xb6, 0xc5, 0xd2, 0xd1, 0x3c, 0xd1, 0x98, 0x08, 0x3c, 0xf8, 0xaa, 0x2e, - 0xbf, 0xaa, 0x9e, 0x06, 0x65, 0x61, 0xf8, 0x15, 0xc2, 0xe9, 0xfd, 0x2b, - 0x76, 0xd3, 0xe8, 0x7d, 0x25, 0xc6, 0x99, 0xfd, 0xfc, 0xd8, 0xd1, 0x87, - 0x37, 0x9f, 0x7c, 0xa5, 0x0c, 0x0f, 0xc1, 0x64, 0x48, 0x76, 0xc8, 0x4c, - 0xee, 0x4f, 0xda, 0x1d, 0xcd, 0xe1, 0xd8, 0xc9, 0xc7, 0x0f, 0x62, 0x40, - 0xc7, 0xdb, 0xbf, 0x3b, 0xf2, 0x16, 0xbf, 0xa0, 0x3c, 0x31, 0xb8, 0x5d, - 0x6a, 0x47, 0x63, 0x0c, 0x1f, 0x57, 0x6b, 0x36, 0x7a, 0x4c, 0xbb, 0x2b, - 0x03, 0x50, 0x05, 0x25, 0x78, 0x2c, 0xc0, 0x1b, 0x93, 0xd9, 0xb5, 0x50, - 0xe2, 0x4e, 0x92, 0x82, 0x5c, 0x3a, 0xd0, 0x72, 0xb1, 0x08, 0xfa, 0x42, - 0xe2, 0xb1, 0x33, 0x41, 0xac, 0x63, 0xd7, 0xe4, 0x82, 0xa6, 0x5a, 0xbf, - 0xc9, 0xd2, 0x64, 0x60, 0x80, 0x09, 0xd0, 0x42, 0x32, 0x90, 0xc8, 0x50, - 0xa9, 0xa6, 0xf7, 0x82, 0x14, 0xd6, 0x92, 0xa1, 0xca, 0x44, 0x84, 0xc5, - 0xa3, 0x30, 0xd1, 0xef, 0x6f, 0xb6, 0xa6, 0x7f, 0x91, 0x82, 0x40, 0x63, - 0x63, 0x2c, 0x9f, 0x43, 0x41, 0xb2, 0x9b, 0x18, 0x8d, 0x57, 0xe2, 0x2c, - 0xe8, 0xa2, 0x27, 0x8f, 0x5b, 0x98, 0x5a, 0x60, 0xe6, 0xb7, 0x22, 0xe9, - 0x6f, 0x9c, 0x1e, 0x42, 0xc5, 0xe7, 0x38, 0x07, 0x16, 0x3b, 0x71, 0x02, - 0xbf, 0x40, 0x22, 0x13, 0xc6, 0x22, 0x8b, 0x48, 0x34, 0x15, 0xaa, 0x5e, - 0xbb, 0x2c, 0xc8, 0x18, 0x0e, 0x8f, 0x0a, 0xa2, 0x0b, 0x9e, 0x14, 0x38, - 0xc8, 0x98, 0x5b, 0x83, 0xb2, 0x0a, 0x79, 0xf7, 0x74, 0x02, 0x10, 0x54, - 0xf5, 0xb6, 0x3e, 0xb6, 0xf2, 0x40, 0xc2, 0xb6, 0x9f, 0x06, 0x91, 0x5d, - 0x26, 0xda, 0x74, 0xa1, 0xc2, 0x8c, 0xf6, 0xcc, 0x44, 0xab, 0xe0, 0x13, - 0x41, 0xef, 0x98, 0x25, 0xcc, 0x57, 0x79, 0x6b, 0xdc, 0x68, 0x47, 0x12, - 0xfa, 0xb2, 0x6e, 0x97, 0x62, 0x87, 0x61, 0x41, 0x9f, 0xe4, 0x2d, 0xca, - 0xa5, 0x62, 0xfc, 0xe3, 0x95, 0x44, 0x77, 0xd1, 0xa9, 0x35, 0xd5, 0xdc, - 0xfb, 0xd9, 0x11, 0x5d, 0xeb, 0x66, 0x5a, 0x87, 0x76, 0x7a, 0x81, 0x27, - 0x3c, 0x9d, 0xdb, 0x96, 0x58, 0x45, 0x21, 0x72, 0xcd, 0xcd, 0xe9, 0x27, - 0xa5, 0x1a, 0x22, 0x84, 0x6f, 0x11, 0x18, 0x2e, 0x82, 0xb4, 0x68, 0xfd, - 0xfb, 0x82, 0x33, 0x4a, 0x62, 0x9f, 0xda, 0x10, 0x2b, 0x72, 0x94, 0x4e, - 0x93, 0xec, 0x4f, 0xf4, 0x45, 0x5f, 0x54, 0x06, 0xbe, 0x72, 0x6e, 0xab, - 0x1c, 0xcb, 0x5e, 0x5c, 0x16, 0x75, 0x5b, 0x1c, 0x65, 0x3f, 0xd0, 0x0a, - 0x21, 0xc9, 0xa9, 0xb8, 0x36, 0xa0, 0xb6, 0xf3, 0x17, 0x8f, 0x53, 0xd8, - 0x84, 0x88, 0xfb, 0xc9, 0x24, 0x14, 0xd9, 0x03, 0x0b, 0xb6, 0x64, 0x15, - 0xc1, 0x25, 0xba, 0x62, 0x7f, 0x82, 0xe7, 0x21, 0xe9, 0xc3, 0x7a, 0x3a, - 0x95, 0xf7, 0x1f, 0xe3, 0x9a, 0xd1, 0x9d, 0xb4, 0x1f, 0xd8, 0xe8, 0x77, - 0x7e, 0xc9, 0x29, 0xa0, 0xf0, 0x51, 0x89, 0x06, 0x89, 0x42, 0x8d, 0xd2, - 0x36, 0x65, 0x99, 0x7a, 0xbc, 0xcc, 0xd8, 0xd2, 0x10, 0xd1, 0xfc, 0xe8, - 0x9e, 0x2d, 0x84, 0x6a, 0x72, 0xd6, 0x50, 0xae, 0x37, 0xf5, 0xcf, 0x18, - 0x9f, 0xb7, 0x83, 0xf9, 0x85, 0x65, 0xad, 0xc2, 0x2b, 0x0b, 0x82, 0xff, - 0x53, 0x21, 0x4b, 0x17, 0xab, 0xf0, 0x54, 0x14, 0x2c, 0x82, 0xcd, 0x8f, - 0xb8, 0x27, 0x93, 0x8c, 0xa1, 0x39, 0x1b, 0x08, 0xee, 0x4f, 0xca, 0xce, - 0x50, 0xfb, 0x80, 0xc3, 0xf6, 0x10, 0x1a, 0xf2, 0xec, 0x98, 0x98, 0x39, - 0x51, 0x44, 0xb2, 0x3c, 0x7f, 0xf8, 0x40, 0x20, 0x72, 0xe5, 0x01, 0x6d, - 0xd5, 0x66, 0xa1, 0xb7, 0xd5, 0x2a, 0xe4, 0x71, 0xcc, 0x1a, 0x6d, 0x4f, - 0xed, 0x45, 0x68, 0x0d, 0xd9, 0xf2, 0xec, 0x28, 0xdd, 0x47, 0xb8, 0x23, - 0xe6, 0xb9, 0xb4, 0xa5, 0x61, 0xb3, 0x3a, 0xf7, 0x71, 0x3b, 0x57, 0xa9, - 0x37, 0xdf, 0x64, 0x57, 0x36, 0x86, 0xfd, 0x0d, 0x1a, 0x04, 0x36, 0x8d, - 0x7b, 0x54, 0xc2, 0x90, 0x08, 0x24, 0x3e, 0x68, 0x0f, 0xe5, 0xde, 0x87, - 0x43, 0xf2, 0xe0, 0x46, 0xe8, 0x9e, 0xb9, 0x79, 0xb2, 0x5b, 0x27, 0xe7, - 0x0b, 0xf4, 0x55, 0x5b, 0xa4, 0x62, 0x34, 0x4e, 0x2c, 0x17, 0xc7, 0xf0, - 0x15, 0x56, 0xa4, 0x4c, 0x55, 0x06, 0x3a, 0xce, 0x26, 0x6c, 0x69, 0xe0, - 0xb3, 0xfa, 0xd9, 0x36, 0x01, 0xef, 0x14, 0xf0, 0x61, 0x14, 0x3d, 0x6d, - 0x84, 0xb7, 0xc5, 0xef, 0x24, 0x97, 0x9f, 0x6f, 0xee, 0x53, 0x88, 0x42, - 0xdb, 0xf2, 0x22, 0x16, 0xab, 0xd3, 0xad, 0x41, 0xd8, 0xb6, 0x00, 0x20, - 0x86, 0x1e, 0x8a, 0x3a, 0x82, 0x3e, 0x30, 0xd2, 0x5a, 0x74, 0x14, 0x9e, - 0x9b, 0xe5, 0xae, 0x6b, 0xe5, 0xf2, 0x1c, 0xc6, 0x40, 0x2a, 0xca, 0xe4, - 0x28, 0x0d, 0xf0, 0x90, 0xd2, 0x0d, 0xc8, 0x69, 0xb9, 0xf8, 0x18, 0x3b, - 0x37, 0x47, 0x12, 0x5b, 0xd7, 0xb0, 0x7d, 0x3f, 0x6d, 0x74, 0xf0, 0x52, - 0x5a, 0x00, 0xb4, 0x93, 0xd6, 0x60, 0xe0, 0xdd, 0x92, 0x30, 0xb8, 0xef, - 0x9d, 0x8d, 0x9e, 0x4a, 0x44, 0x1e, 0x27, 0x65, 0x5a, 0x28, 0x40, 0x85, - 0x65, 0xbd, 0x15, 0x3e, 0x8b, 0x04, 0xb9, 0xe7, 0xd2, 0x1b, 0xe0, 0x7f, - 0x26, 0x84, 0xf8, 0x3b, 0xdf, 0xe6, 0xa3, 0x26, 0x63, 0xd2, 0xc5, 0x37, - 0x77, 0xa9, 0xa6, 0x6f, 0xcc, 0x49, 0x43, 0x12, 0x1f, 0xa6, 0xf2, 0x26, - 0x33, 0x58, 0xae, 0x47, 0x9f, 0x49, 0x61, 0xf4, 0x0b, 0x16, 0xa6, 0x1b, - 0x4b, 0x28, 0x8f, 0xe9, 0x07, 0xf6, 0xdc, 0x97, 0xb8, 0xc8, 0xd3, 0x06, - 0x44, 0xa7, 0x73, 0xa2, 0x53, 0xaa, 0x22, 0x92, 0xf2, 0x86, 0x58, 0x9e, - 0x4c, 0x22, 0x9f, 0xf9, 0x22, 0xd3, 0xb3, 0x7f, 0xa3, 0xec, 0xf1, 0x29, - 0x09, 0xfa, 0x99, 0x28, 0xdf, 0xfb, 0x32, 0x4c, 0x83, 0xa0, 0x57, 0xda, - 0xd1, 0x6e, 0x1e, 0x98, 0x4d, 0xdc, 0xd4, 0x3e, 0xf0, 0xfb, 0x40, 0xf3, - 0x86, 0xd6, 0x04, 0xa9, 0x47, 0xc0, 0x24, 0x91, 0x3f, 0xe3, 0xda, 0x4a, - 0xec, 0xa7, 0xf5, 0x76, 0x9b, 0xe5, 0x9d, 0x03, 0x86, 0x52, 0x9f, 0x00, - 0xfe, 0xb6, 0x92, 0xd6, 0x81, 0xd0, 0x46, 0x5d, 0xd4, 0x8b, 0x36, 0x3d, - 0xe4, 0x1e, 0x94, 0x3e, 0x7b, 0xee, 0x12, 0xf1, 0x0f, 0x55, 0x61, 0x1e, - 0x34, 0xfc, 0xac, 0x42, 0x9a, 0x6f, 0x90, 0x34, 0x16, 0x7b, 0x18, 0x74, - 0x5f, 0x41, 0x4b, 0x0d, 0xdf, 0x3a, 0x4d, 0x63, 0xf5, 0xec, 0xfb, 0x1b, - 0xac, 0xee, 0x4c, 0x8d, 0x9e, 0xe7, 0xda, 0x4f, 0x5c, 0xd3, 0x44, 0xa2, - 0x85, 0xb4, 0x58, 0x43, 0xa9, 0x3a, 0x32, 0xb4, 0x4c, 0x56, 0x16, 0x68, - 0x12, 0xe7, 0xef, 0x2e, 0xd1, 0x6c, 0xae, 0xf4, 0xe7, 0x57, 0x6c, 0x1a, - 0xf5, 0xa0, 0xa8, 0x1e, 0x9c, 0xa0, 0x46, 0xdf, 0xc5, 0xdf, 0x3d, 0x99, - 0x8c, 0xc2, 0xa4, 0xfc, 0x0b, 0xe5, 0xed, 0xc4, 0xed, 0xbf, 0x2a, 0x28, - 0x5c, 0xcc, 0x72, 0x03, 0xae, 0x50, 0x07, 0xe8, 0x77, 0x19, 0xbc, 0xd2, - 0xd1, 0xbf, 0x9c, 0x84, 0x3a, 0x39, 0xb2, 0xc8, 0x90, 0x5a, 0x10, 0xa1, - 0x56, 0xef, 0x54, 0xbb, 0x14, 0x77, 0xb0, 0xa9, 0x00, 0x64, 0x04, 0xfc, - 0x39, 0xc9, 0x07, 0x5c, 0xb1, 0xc2, 0x07, 0x50, 0xf6, 0xfa, 0x15, 0xda, - 0x4e, 0xf0, 0x38, 0x2c, 0x5d, 0xe3, 0x65, 0x75, 0xd0, 0xe6, 0x92, 0x22, - 0x51, 0x05, 0xb6, 0x52, 0xd0, 0xbd, 0xf8, 0x4d, 0x4c, 0xea, 0xd6, 0x13, - 0x81, 0xeb, 0x93, 0x15, 0x6d, 0x5a, 0x15, 0x35, 0x26, 0x25, 0x84, 0xd6, - 0x0d, 0xcf, 0x92, 0x63, 0xc0, 0x5a, 0x09, 0x7a, 0x98, 0x50, 0x2c, 0xb4, - 0xa2, 0xab, 0xf7, 0x85, 0x2a, 0xa3, 0x25, 0xc5, 0x6d, 0x55, 0x98, 0x8e, - 0x39, 0xbf, 0xa6, 0x3b, 0xc4, 0xc0, 0xb2, 0x92, 0x0e, 0x37, 0x83, 0xd9, - 0x5a, 0xef, 0x41, 0xd5, 0x5c, 0xfe, 0xce, 0x9b, 0xaf, 0xfc, 0xdb, 0xf8, - 0x3b, 0x26, 0x51, 0xf0, 0x3a, 0xa5, 0x7d, 0x14, 0xcf, 0x32, 0x92, 0x6c, - 0xa1, 0xbe, 0x3e, 0x6c, 0xc1, 0x1c, 0x21, 0x79, 0xfb, 0x2c, 0xd2, 0xdc, - 0xf3, 0x6d, 0xe1, 0x1d, 0x10, 0x5d, 0x4e, 0xb4, 0x5a, 0x4f, 0x08, 0xd6, - 0xa0, 0x3f, 0xeb, 0xa3, 0x4e, 0xe0, 0x67, 0xad, 0x3b, 0xea, 0x1c, 0x3a, - 0x5c, 0x34, 0x44, 0x77, 0x57, 0x3b, 0x9d, 0x80, 0x0d, 0xff, 0x6f, 0x1b, - 0x53, 0x49, 0x6b, 0x11, 0xa5, 0x21, 0x0d, 0x8d, 0xfa, 0xc0, 0x46, 0xb6, - 0x47, 0x05, 0xca, 0xd7, 0xe0, 0xe1, 0xcc, 0x88, 0xcc, 0x2f, 0xe1, 0x0c, - 0x7d, 0xad, 0x16, 0xb6, 0xa3, 0xeb, 0xb6, 0x45, 0xa3, 0x73, 0xf2, 0x30, - 0xa4, 0x82, 0x5f, 0xb3, 0xb8, 0x0c, 0x2d, 0x14, 0xe1, 0x02, 0xfe, 0x5c, - 0xd9, 0x94, 0x3f, 0x1d, 0x6f, 0x1f, 0x0f, 0xee, 0x19, 0x59, 0x6b, 0x30, - 0x99, 0xc0, 0xad, 0xdb, 0x59, 0x9c, 0x9b, 0x93, 0x75, 0xe5, 0xfa, 0x20, - 0xc8, 0xe3, 0x43, 0xc7, 0xa2, 0x01, 0x07, 0x05, 0xf4, 0x1b, 0x41, 0x48, - 0xa9, 0x4d, 0x82, 0x5f, 0x96, 0x65, 0x3e, 0x33, 0x9d, 0x86, 0x09, 0xba, - 0xbf, 0x15, 0x2e, 0xcb, 0xec, 0x63, 0xc5, 0x5d, 0xf4, 0x3d, 0x33, 0x24, - 0x39, 0xf9, 0x1d, 0xd8, 0xde, 0xd9, 0xc2, 0x06, 0x14, 0x84, 0xb0, 0x44, - 0x92, 0x0d, 0x31, 0xcc, 0xd3, 0x1e, 0x0e, 0xe3, 0xc4, 0xdd, 0x18, 0x70, - 0x94, 0x5c, 0xbc, 0x22, 0xc1, 0x18, 0xf4, 0x6a, 0xbf, 0x7d, 0x29, 0xda, - 0xb9, 0xce, 0x33, 0xce, 0xb5, 0x40, 0xad, 0x54, 0x0c, 0x86, 0x28, 0x39, - 0x63, 0x95, 0xa2, 0x26, 0x80, 0x8b, 0x53, 0xc2, 0x1d, 0x6c, 0x99, 0x00, - 0xb1, 0x11, 0x6e, 0xe8, 0xcb, 0x5b, 0x34, 0xbd, 0xbb, 0xc7, 0xd7, 0xea, - 0x9a, 0xc6, 0xcc, 0x99, 0x22, 0xc2, 0xfa, 0xfb, 0x22, 0x1e, 0x21, 0xe0, - 0xbe, 0x29, 0x5c, 0x57, 0xb2, 0x2a, 0x32, 0x50, 0xdf, 0x28, 0x01, 0xee, - 0xdf, 0xd4, 0xd9, 0x42, 0xe7, 0x06, 0xd4, 0xc9, 0x27, 0xf7, 0xd7, 0x41, - 0x75, 0xce, 0x23, 0xbb, 0x1e, 0x8e, 0x22, 0xd4, 0x7b, 0x29, 0x9f, 0x09, - 0xf9, 0xe2, 0x4b, 0xb2, 0x39, 0x3d, 0x6d, 0xe5, 0x3e, 0x65, 0x5e, 0xd5, - 0xf1, 0x1a, 0x94, 0xc8, 0xdb, 0xe2, 0x67, 0x15, 0x07, 0x8f, 0x14, 0x4e, - 0x47, 0x7e, 0xca, 0xd4, 0xdc, 0xe0, 0xf9, 0xf1, 0x4f, 0x39, 0x32, 0xf1, - 0x27, 0x47, 0x3d, 0xfb, 0x2e, 0x7f, 0x80, 0x40, 0x2d, 0xc6, 0x35, 0x34, - 0x4e, 0x5f, 0x12, 0x90, 0x69, 0xb4, 0x2e, 0x7c, 0xb4, 0x5d, 0x6d, 0x9d, - 0x73, 0xf9, 0xd3, 0x94, 0xed, 0x07, 0x81, 0x63, 0xb3, 0xcb, 0xad, 0xee, - 0x30, 0x86, 0x79, 0xaf, 0xa9, 0xad, 0x45, 0x73, 0x56, 0x3e, 0x97, 0xd7, - 0x73, 0xb0, 0xeb, 0x08, 0x63, 0x97, 0x00, 0xb5, 0x57, 0x47, 0x8d, 0x3e, - 0x4b, 0xe0, 0xf4, 0x2b, 0x29, 0xeb, 0x94, 0x12, 0xe4, 0x84, 0x13, 0xc3, - 0x2e, 0xe3, 0xcb, 0xd6, 0x16, 0x98, 0xef, 0x44, 0x62, 0x78, 0x2c, 0xdb, - 0x54, 0x3a, 0xf0, 0x43, 0xf6, 0xc4, 0xaa, 0x55, 0x47, 0xbf, 0xc0, 0xcd, - 0x5c, 0x2b, 0xbe, 0x24, 0x27, 0x30, 0xd5, 0x3f, 0xfe, 0xfd, 0xb1, 0x26, - 0x28, 0x7d, 0xad, 0x9c, 0xcc, 0x4c, 0x1c, 0x47, 0xf3, 0x39, 0x35, 0x08, - 0xc4, 0x2a, 0xd0, 0x50, 0x3e, 0x2b, 0xe4, 0xe5, 0xeb, 0x94, 0xf9, 0x3e, - 0x9e, 0x3f, 0xa4, 0x04, 0xe8, 0xe2, 0xfb, 0x07, 0x52, 0xae, 0x93, 0x9c, - 0x76, 0xe8, 0x04, 0x3c, 0xc2, 0xbc, 0xda, 0xef, 0x14, 0xe2, 0xae, 0xeb, - 0xc8, 0xe3, 0x12, 0xe2, 0xc0, 0x1b, 0x32, 0xf4, 0x31, 0x0b, 0x5f, 0xb5, - 0x19, 0x09, 0x71, 0x02, 0xd6, 0x51, 0xff, 0xc6, 0xbc, 0xd6, 0x7e, 0x81, - 0xda, 0x04, 0xda, 0xec, 0x9b, 0x68, 0xc4, 0xe5, 0x5f, 0x9d, 0x21, 0xc9, - 0x0c, 0xd6, 0xfc, 0x30, 0xe8, 0x43, 0xf1, 0xbc, 0x65, 0xca, 0x96, 0xa3, - 0x4c, 0xb5, 0x0a, 0xb2, 0x28, 0xe0, 0x56, 0xf3, 0x78, 0x6d, 0x31, 0xfd, - 0x65, 0xe5, 0x25, 0x87, 0x23, 0xb9, 0x83, 0xfa, 0xa0, 0xb9, 0x6d, 0x8f, - 0x53, 0x55, 0x07, 0xc4, 0xc5, 0xeb, 0x7c, 0x3f, 0x51, 0xc5, 0x94, 0x46, - 0x08, 0x71, 0xe4, 0x43, 0x03, 0x99, 0xbc, 0x55, 0x46, 0x68, 0x5c, 0xa3, - 0x25, 0x17, 0x67, 0x11, 0xa7, 0xc8, 0xe4, 0x95, 0xf0, 0x84, 0xbd, 0x2b, - 0xfc, 0x98, 0x3d, 0x0f, 0x12, 0xdc, 0xe7, 0x4a, 0x7d, 0xe7, 0xa8, 0xd7, - 0xad, 0x56, 0xd1, 0x83, 0x2e, 0x6a, 0xa1, 0xdf, 0xd5, 0x92, 0x91, 0xf4, - 0xcc, 0x26, 0x02, 0x23, 0x6a, 0x86, 0x76, 0x7a, 0x62, 0x09, 0x87, 0xca, - 0xe6, 0xf9, 0xf6, 0xd5, 0x5c, 0x5b, 0xc0, 0x71, 0x0c, 0x05, 0x0c, 0x1f, - 0xa7, 0x9d, 0x28, 0xf2, 0x0d, 0x7e, 0x36, 0xed, 0xf9, 0xde, 0x8b, 0xd4, - 0xa4, 0x29, 0xe2, 0x35, 0x4a, 0xe5, 0xe4, 0xa5, 0x15, 0xab, 0x9b, 0x61, - 0x22, 0xab, 0xf7, 0x63, 0x2b, 0x6a, 0x65, 0xb9, 0xbc, 0x5e, 0x51, 0x90, - 0xf7, 0x90, 0xac, 0xed, 0x6e, 0x97, 0xcd, 0xa1, 0xe1, 0x41, 0x73, 0x10, - 0x5c, 0xc0, 0x1c, 0x16, 0x65, 0x31, 0xdc, 0xcf, 0xc4, 0xd6, 0xc9, 0xc5, - 0xbf, 0x0f, 0x36, 0x97, 0x4f, 0x73, 0x0b, 0x13, 0x8a, 0x37, 0x45, 0x25, - 0x56, 0x27, 0x07, 0xd2, 0x42, 0x6d, 0xac, 0x2b, 0x66, 0xfe, 0xea, 0xb5, - 0x50, 0xf7, 0xb7, 0xf6, 0xeb, 0x84, 0x66, 0xf4, 0x56, 0x52, 0xa5, 0x2b, - 0xef, 0x6f, 0xa3, 0xee, 0xb1, 0xaa, 0x88, 0xcb, 0xf0, 0x61, 0x46, 0x43, - 0xd1, 0x36, 0x8b, 0xb4, 0x4c, 0x93, 0xbf, 0x32, 0x5d, 0x4d, 0x9f, 0xbc, - 0x7a, 0xd1, 0xdc, 0x2f, 0xc8, 0x62, 0xda, 0x28, 0x9e, 0x9b, 0x56, 0x21, - 0xe5, 0x5e, 0xa5, 0xbe, 0x0a, 0x6a, 0xf9, 0x56, 0x66, 0x93, 0xd0, 0x6f, - 0x67, 0x57, 0xe3, 0x47, 0xe6, 0x07, 0xba, 0x09, 0x61, 0x6c, 0x6c, 0x02, - 0xb0, 0xa6, 0xab, 0xac, 0x6a, 0x31, 0xb0, 0xda, 0xa7, 0xc8, 0x23, 0x54, - 0x76, 0x9e, 0x3f, 0x3c, 0xdb, 0x10, 0xa6, 0x5f, 0x60, 0x31, 0x4e, 0x42, - 0xb4, 0x4c, 0x7c, 0xc7, 0x34, 0xc1, 0x1b, 0xb5, 0x5d, 0x03, 0x29, 0xc8, - 0x4c, 0x36, 0x74, 0x90, 0x51, 0x8b, 0x59, 0xbc, 0x1e, 0x29, 0xd2, 0x5f, - 0x7f, 0x99, 0x08, 0x76, 0x9b, 0x1a, 0xb4, 0xa3, 0x63, 0xb4, 0x26, 0xea, - 0x9e, 0x89, 0x9c, 0xa3, 0xd8, 0xa7, 0xdc, 0x8b, 0x59, 0x6f, 0x01, 0xb6, - 0xaa, 0x06, 0xf8, 0x59, 0x08, 0x10, 0x96, 0xa1, 0x6c, 0x8c, 0x7d, 0xaa, - 0x68, 0x55, 0xec, 0x10, 0x36, 0xda, 0x6e, 0x9a, 0xdd, 0xf4, 0x82, 0x9b, - 0x8a, 0x4e, 0x12, 0x83, 0x1f, 0x1e, 0xad, 0x26, 0xc9, 0xb5, 0x90, 0xb6, - 0xbd, 0xd7, 0x32, 0xf8, 0x05, 0xd3, 0x47, 0x3c, 0x35, 0xb2, 0x55, 0xa2, - 0x32, 0xbc, 0xf4, 0x41, 0x19, 0x95, 0x2f, 0x4b, 0x56, 0x2c, 0x4d, 0x74, - 0x64, 0xbe, 0xc5, 0x0b, 0x4f, 0x7d, 0xca, 0x40, 0x1c, 0x1a, 0xb1, 0xfa, - 0x0d, 0x68, 0xa9, 0xc8, 0x88, 0xb3, 0x1f, 0x04, 0x0e, 0x38, 0x34, 0x29, - 0x3e, 0x39, 0xba, 0x3f, 0xc5, 0x51, 0x0d, 0x43, 0x58, 0x7e, 0xf2, 0x25, - 0xbb, 0x1d, 0x71, 0x12, 0x86, 0x69, 0x5f, 0x5c, 0x6c, 0x8c, 0x38, 0x89, - 0x56, 0x69, 0x35, 0xb5, 0x8e, 0xf4, 0xfc, 0x3c, 0x6b, 0x82, 0xc7, 0xf2, - 0x3a, 0xd8, 0x0c, 0x3e, 0x31, 0xfd, 0x45, 0x28, 0x42, 0x52, 0x59, 0x68, - 0xaa, 0xd0, 0x8a, 0x18, 0x44, 0x45, 0xcf, 0xb2, 0x53, 0x11, 0xbc, 0x76, - 0xe1, 0xa7, 0xa0, 0x60, 0xc2, 0x6f, 0x36, 0xe0, 0x07, 0x2a, 0xba, 0x05, - 0x4f, 0x48, 0x94, 0xfb, 0xc6, 0x03, 0x30, 0x9b, 0x71, 0x86, 0xad, 0x81, - 0x23, 0x65, 0xde, 0x63, 0x45, 0x69, 0x52, 0x98, 0x3f, 0x93, 0x9f, 0x23, - 0x13, 0x1c, 0x54, 0xb8, 0x5f, 0x53, 0xb8, 0x79, 0xaa, 0xf0, 0x30, 0xeb, - 0xaf, 0xb8, 0x53, 0xa6, 0x58, 0x54, 0x47, 0xbe, 0x2f, 0x10, 0x48, 0x67, - 0xa4, 0xad, 0xda, 0x37, 0x11, 0xd3, 0x60, 0x95, 0xa4, 0x25, 0x09, 0xb6, - 0x5f, 0x7c, 0xbc, 0xfc, 0x48, 0xef, 0x68, 0x76, 0xc4, 0x7f, 0x11, 0x31, - 0xbe, 0xea, 0x12, 0xe5, 0x5b, 0x0f, 0xdf, 0xc1, 0x56, 0x2c, 0x2f, 0x38, - 0x95, 0x59, 0x36, 0xb0, 0xc8, 0xfa, 0xf7, 0xf4, 0x29, 0x71, 0x9b, 0x93, - 0x42, 0x0a, 0x6f, 0xf9, 0x5a, 0x12, 0x34, 0x7c, 0x65, 0xa5, 0x2e, 0xa4, - 0xa8, 0xd8, 0xf6, 0xb0, 0xf8, 0x7c, 0x6f, 0x83, 0xf1, 0x32, 0xdd, 0xb7, - 0xa5, 0x21, 0x18, 0x78, 0x56, 0x5d, 0xf7, 0xac, 0x6b, 0x3c, 0x4a, 0xd4, - 0xb9, 0x9a, 0x3c, 0x0b, 0xfb, 0xd3, 0x38, 0x44, 0xf1, 0x46, 0x5e, 0x46, - 0x5d, 0xb3, 0x91, 0x6c, 0x17, 0xc8, 0x2d, 0x50, 0x69, 0xa5, 0xbe, 0x8d, - 0xda, 0xf5, 0x2d, 0x80, 0x1c, 0xbd, 0xe6, 0x72, 0x74, 0x85, 0xa6, 0x4b, - 0xd6, 0x36, 0x99, 0x64, 0x20, 0x7d, 0x29, 0xf4, 0x0f, 0x33, 0x43, 0xb1, - 0xcc, 0x3d, 0xbc, 0x9f, 0x02, 0x00, 0xff, 0xb2, 0x58, 0x6c, 0xc8, 0xe6, - 0x2f, 0x30, 0x32, 0xcb, 0x31, 0x58, 0xc6, 0x7a, 0xd4, 0x7a, 0x6c, 0x8a, - 0x80, 0x8f, 0xe5, 0x16, 0xbd, 0xa0, 0xcf, 0xe1, 0x75, 0x27, 0xd1, 0x71, - 0x9f, 0x8f, 0xba, 0xdf, 0xd5, 0xfd, 0xc9, 0x85, 0xe3, 0xc1, 0x80, 0x4d, - 0x22, 0x47, 0x78, 0xae, 0xc2, 0x41, 0xa3, 0x9c, 0xdd, 0x28, 0xf3, 0x4a, - 0x4b, 0x74, 0xec, 0x17, 0x03, 0xab, 0xf2, 0x99, 0x89, 0x0a, 0xd4, 0x58, - 0xe2, 0x84, 0xfb, 0x71, 0xca, 0x6c, 0xec, 0x1b, 0x21, 0x6c, 0x1a, 0xb0, - 0x0e, 0x0d, 0x26, 0xd2, 0x6f, 0x93, 0x99, 0x43, 0x2b, 0x38, 0xed, 0x67, - 0x77, 0x63, 0x2d, 0xc2, 0x6e, 0x68, 0xb6, 0xb0, 0x05, 0x02, 0xb2, 0x96, - 0x10, 0x89, 0x01, 0xdc, 0xeb, 0xd3, 0x42, 0xdc, 0x84, 0x69, 0xa2, 0x32, - 0xb2, 0x18, 0xd2, 0x16, 0x37, 0x12, 0x01, 0x63, 0x8c, 0xf3, 0x68, 0x73, - 0x7a, 0xed, 0x58, 0x07, 0x85, 0xfe, 0xb0, 0x0a, 0x98, 0x1d, 0x0f, 0x71, - 0x15, 0xb1, 0x31, 0xb8, 0x26, 0xf7, 0x9d, 0x68, 0x3b, 0x74, 0x57, 0x95, - 0x31, 0xba, 0x4f, 0xbf, 0x0a, 0x4f, 0xde, 0x06, 0xa0, 0xc6, 0x0b, 0x28, - 0xce, 0x4f, 0xaa, 0x9b, 0x51, 0x7b, 0x6f, 0x4a, 0x60, 0x7e, 0x07, 0x8f, - 0x12, 0xe3, 0x79, 0xb5, 0x67, 0x11, 0x8c, 0x7f, 0xba, 0xfc, 0x00, 0xc7, - 0xa9, 0xfb, 0x3d, 0xef, 0xa2, 0x26, 0x57, 0xed, 0x60, 0x02, 0xb6, 0x9f, - 0xcc, 0x37, 0x14, 0x4b, 0x2b, 0xe4, 0x58, 0xf1, 0x46, 0x28, 0x0c, 0x88, - 0x44, 0x89, 0x51, 0x45, 0xf4, 0xf1, 0x26, 0x3f, 0xf8, 0x15, 0x7e, 0x15, - 0x0c, 0x5d, 0xbc, 0x3c, 0xfb, 0xd4, 0xa1, 0x19, 0x10, 0x75, 0x74, 0x3a, - 0xe5, 0xfa, 0xd7, 0x37, 0x70, 0x53, 0x55, 0x55, 0x05, 0x87, 0x40, 0x0f, - 0x94, 0xd3, 0xbf, 0x73, 0xc3, 0x3d, 0xec, 0xf7, 0x53, 0x4e, 0xd4, 0x1a, - 0xa9, 0xb1, 0x59, 0xae, 0x7d, 0xeb, 0x65, 0xd7, 0xbc, 0xc5, 0x29, 0xc7, - 0xa6, 0x83, 0x71, 0xe6, 0x00, 0x70, 0xe4, 0xfa, 0x0c, 0x68, 0x4d, 0x95, - 0xeb, 0xa1, 0x1a, 0x3f, 0x7d, 0x58, 0x76, 0x08, 0x9d, 0x16, 0xb5, 0x82, - 0xf5, 0xc3, 0x70, 0xcb, 0xba, 0x34, 0x64, 0x83, 0x73, 0x15, 0x6e, 0x54, - 0x0d, 0xf2, 0xf8, 0x6d, 0xbf, 0xb5, 0xfb, 0x70, 0x31, 0x4c, 0xd3, 0xc5, - 0x94, 0x42, 0x58, 0x87, 0x65, 0x48, 0x1a, 0x32, 0x76, 0x22, 0xd1, 0x58, - 0xc2, 0x90, 0x95, 0x87, 0xfc, 0xa0, 0xe1, 0xde, 0x56, 0xc8, 0x5c, 0xb9, - 0xfd, 0x51, 0x1a, 0xdb, 0x3f, 0xd6, 0xb9, 0xec, 0x3d, 0x76, 0x7b, 0x7c, - 0xb7, 0x1f, 0x6d, 0xc6, 0x95, 0x82, 0xb4, 0xea, 0x74, 0xe9, 0xac, 0x16, - 0x63, 0xf1, 0x3d, 0xf0, 0x29, 0x22, 0xe7, 0xb7, 0xeb, 0x68, 0x9c, 0x24, - 0x0c, 0x68, 0x96, 0x59, 0x42, 0x8d, 0x06, 0x08, 0xaf, 0x9b, 0x4c, 0x9e, - 0x90, 0x4f, 0x4b, 0xe1, 0x01, 0x72, 0x16, 0x8e, 0xe4, 0x4c, 0x7d, 0x50, - 0xd2, 0x67, 0xb9, 0x21, 0xdb, 0x98, 0x20, 0x58, 0x49, 0x81, 0x04, 0x09, - 0x8e, 0x9e, 0x09, 0x29, 0xe3, 0xf3, 0xd4, 0x6c, 0x4a, 0x53, 0x47, 0x47, - 0xe3, 0xbf, 0x9b, 0xeb, 0xa8, 0x61, 0xc5, 0xb3, 0xdc, 0x90, 0x30, 0xa5, - 0x37, 0x78, 0xa4, 0xf7, 0xf0, 0x78, 0x44, 0x43, 0xdf, 0xcf, 0x14, 0xb6, - 0x7d, 0x58, 0xc9, 0x59, 0xa6, 0xd2, 0x1d, 0xc0, 0x61, 0x3c, 0xed, 0x71, - 0x91, 0x85, 0x6e, 0xe6, 0x9d, 0x68, 0xb4, 0x54, 0xf9, 0xf2, 0xf6, 0xdc, - 0xc9, 0x99, 0x2f, 0x4a, 0xac, 0x7b, 0xec, 0xd5, 0x98, 0xc0, 0xbe, 0x93, - 0x96, 0xc5, 0xd4, 0x47, 0x26, 0xd2, 0x68, 0x3d, 0xf2, 0x0d, 0xff, 0xc6, - 0x26, 0x73, 0x21, 0x6d, 0x80, 0xad, 0x52, 0xb7, 0x3a, 0x91, 0xc7, 0x4c, - 0x4b, 0x63, 0xef, 0x49, 0xaf, 0x71, 0xd6, 0x40, 0x61, 0x6f, 0xd2, 0x96, - 0x0c, 0xbf, 0x5c, 0x67, 0x72, 0xe5, 0x76, 0x8c, 0xa8, 0x0b, 0x00, 0x75, - 0xbd, 0x0f, 0xd6, 0x3b, 0x6f, 0xf1, 0x67, 0xbe, 0xb6, 0x23, 0x6d, 0xcf, - 0xc4, 0x8e, 0xe7, 0x31, 0xd7, 0x17, 0x51, 0xf3, 0x58, 0xba, 0x0e, 0x3f, - 0x72, 0x2c, 0x7f, 0xdc, 0xb4, 0xea, 0x73, 0x54, 0xbc, 0xe0, 0x1f, 0x17, - 0x44, 0x68, 0x1d, 0x12, 0xd0, 0xd2, 0x15, 0x73, 0xbc, 0xed, 0x40, 0xe3, - 0x46, 0x67, 0x7b, 0x7e, 0xad, 0x8f, 0xc6, 0x8e, 0x6c, 0xf5, 0x8a, 0x63, - 0xdb, 0x21, 0x99, 0x49, 0xe6, 0x5f, 0x48, 0xb0, 0xf2, 0x47, 0xc6, 0xd5, - 0xc3, 0x6c, 0x8f, 0xe2, 0x00, 0xba, 0x2f, 0x67, 0x04, 0xbf, 0x04, 0xd4, - 0x96, 0x29, 0xaa, 0x00, 0x75, 0x58, 0x4b, 0xb2, 0x38, 0x78, 0xee, 0xe9, - 0x0b, 0x71, 0x1a, 0xaf, 0xf8, 0x20, 0xcf, 0xbd, 0xf4, 0x55, 0x92, 0x8d, - 0xbf, 0xeb, 0x8e, 0xae, 0xf9, 0x93, 0x10, 0x93, 0x9b, 0xd8, 0xee, 0xf3, - 0x93, 0x83, 0x43, 0x11, 0xbe, 0x27, 0xb9, 0xeb, 0x43, 0xba, 0x9f, 0xc3, - 0x97, 0x07, 0x5a, 0x51, 0x07, 0x39, 0xed, 0xb8, 0x70, 0xd7, 0x3c, 0xb6, - 0xed, 0x75, 0x0e, 0x03, 0xb5, 0xb9, 0xf3, 0x5d, 0x2d, 0x4f, 0x7c, 0x3c, - 0xbb, 0x8d, 0x3a, 0xb4, 0x10, 0x8a, 0xf7, 0x07, 0xb9, 0x15, 0x80, 0x4d, - 0x84, 0xa2, 0x3e, 0x6f, 0xc6, 0xb7, 0x85, 0x55, 0x64, 0xca, 0x0a, 0xc8, - 0x2c, 0xe0, 0x46, 0xd9, 0x38, 0xae, 0x8a, 0x56, 0x46, 0x93, 0xbf, 0xd3, - 0xed, 0xaf, 0x5b, 0xfb, 0x32, 0xde, 0x85, 0x2f, 0x66, 0x36, 0x06, 0x42, - 0xbe, 0xef, 0xe5, 0xb1, 0x63, 0x53, 0x56, 0x4e, 0xfa, 0xfc, 0xb2, 0xea, - 0x28, 0x71, 0xe5, 0x9b, 0xb9, 0x7d, 0x2a, 0x25, 0x17, 0xc3, 0xb0, 0x69, - 0xad, 0x32, 0x6f, 0x6c, 0x5c, 0x5a, 0x80, 0x02, 0x06, 0xe9, 0x58, 0xdf, - 0x9b, 0x78, 0x82, 0xaf, 0x33, 0xcc, 0x71, 0xe8, 0xa6, 0x3d, 0xf4, 0x3a, - 0xd6, 0x71, 0x40, 0x7d, 0x8f, 0x76, 0xbf, 0x14, 0x84, 0x02, 0x64, 0x30, - 0x8d, 0xc4, 0xfc, 0xe9, 0x0f, 0xd4, 0x1a, 0xda, 0x47, 0x08, 0xf9, 0x93, - 0x9c, 0x59, 0xb6, 0x58, 0x6e, 0xe5, 0x03, 0x35, 0xf2, 0x8f, 0x76, 0xcc, - 0x5d, 0xb9, 0x4c, 0x48, 0x02, 0x90, 0x61, 0x1c, 0x52, 0x09, 0xda, 0x1d, - 0xa0, 0xed, 0x51, 0xab, 0xdc, 0xe4, 0x2f, 0xe4, 0xbe, 0xf3, 0x5a, 0xa6, - 0xfa, 0x74, 0xd5, 0xf8, 0xc1, 0x4d, 0xe5, 0xaf, 0xb7, 0x61, 0xa4, 0x1c, - 0xf7, 0x42, 0x48, 0x59, 0xa4, 0xfc, 0x56, 0x03, 0x11, 0xf2, 0xd0, 0xf7, - 0x80, 0x19, 0xf6, 0xb3, 0x81, 0x6b, 0x1e, 0x43, 0xce, 0x8a, 0x59, 0xd4, - 0x84, 0xcd, 0xe0, 0x5b, 0xb2, 0xc3, 0xf1, 0x70, 0x4d, 0x53, 0x2f, 0xd9, - 0x62, 0xd3, 0x34, 0xe3, 0x73, 0xdc, 0x73, 0xbf, 0x6d, 0x46, 0x8a, 0xee, - 0x68, 0x30, 0xef, 0xc6, 0xe4, 0x2c, 0x13, 0x3f, 0x82, 0xbd, 0x1a, 0x95, - 0x94, 0x82, 0x27, 0xf1, 0x13, 0xf3, 0x61, 0x9f, 0x0c, 0xb2, 0x9d, 0x1a, - 0xd0, 0x40, 0xa6, 0xe0, 0xfe, 0xeb, 0xbd, 0x0d, 0x8b, 0x86, 0x1c, 0x32, - 0x8f, 0x4b, 0x50, 0xd7, 0x69, 0xd4, 0xa6, 0x7a, 0x62, 0x64, 0x13, 0x67, - 0x0a, 0x57, 0x17, 0x0c, 0x6a, 0x05, 0xcd, 0x2d, 0x83, 0xd1, 0x93, 0x33, - 0x30, 0xbb, 0x67, 0xde, 0x94, 0xf4, 0x40, 0xf4, 0x44, 0x60, 0x33, 0x93, - 0xc3, 0xa4, 0xba, 0x04, 0xb9, 0xc7, 0xce, 0x64, 0x6e, 0xc5, 0xd6, 0x40, - 0xe4, 0xbe, 0xb3, 0xb8, 0x3c, 0x77, 0x17, 0x22, 0xec, 0xf4, 0x24, 0x6b, - 0x09, 0xd6, 0x9d, 0xb7, 0x6b, 0x29, 0xb6, 0x84, 0xaa, 0xa9, 0x62, 0xbc, - 0xbd, 0x5d, 0x95, 0x2e, 0x8b, 0xa6, 0xf8, 0xc1, 0xdd, 0xeb, 0xbb, 0x3b, - 0x6e, 0x1e, 0x09, 0x61, 0xaf, 0x44, 0x56, 0x99, 0xe6, 0x01, 0xcd, 0x81, - 0xfc, 0xe7, 0x88, 0x47, 0x9f, 0x7d, 0x1a, 0x92, 0xdb, 0x42, 0x98, 0x93, - 0xa0, 0x99, 0xd9, 0x49, 0xec, 0x6b, 0x74, 0xe3, 0x59, 0x18, 0x56, 0xf4, - 0x65, 0x12, 0xe7, 0x99, 0x50, 0xe5, 0xb7, 0x99, 0x12, 0xaa, 0x24, 0x7b, - 0xee, 0x5e, 0x34, 0x3d, 0xf1, 0x14, 0x01, 0xbe, 0x05, 0x32, 0x7f, 0xa5, - 0x63, 0x99, 0x14, 0xda, 0xb0, 0x54, 0x74, 0x50, 0xe5, 0xe3, 0x5b, 0xdc, - 0xe4, 0x17, 0x98, 0xdb, 0x2e, 0x4f, 0x71, 0xc4, 0x3e, 0xf1, 0x2f, 0x8e, - 0xe1, 0x9c, 0xc7, 0x3c, 0x89, 0xe4, 0x38, 0xfd, 0x1c, 0x96, 0x12, 0x2a, - 0xcc, 0x3e, 0xda, 0xd8, 0x8a, 0xe0, 0x08, 0x7b, 0xe0, 0x5a, 0x51, 0xc9, - 0x68, 0xed, 0xb3, 0x16, 0x01, 0x07, 0x7c, 0x57, 0x96, 0x0a, 0xf1, 0xfb, - 0xfa, 0x5e, 0xdc, 0xb2, 0xe8, 0x6d, 0x6a, 0x5c, 0x74, 0xa8, 0xd3, 0x54, - 0x02, 0x1e, 0xa4, 0x9b, 0xce, 0xf2, 0xbb, 0x6e, 0x1a, 0x14, 0xbf, 0x30, - 0x69, 0x06, 0xd1, 0x56, 0x11, 0x75, 0x94, 0x5c, 0xca, 0x36, 0x2e, 0xa0, - 0xdf, 0x04, 0x9c, 0x21, 0x35, 0xc7, 0x95, 0x3d, 0x9f, 0x51, 0xd8, 0x95, - 0x95, 0xfd, 0x20, 0x9b, 0xde, 0xbc, 0xc4, 0x28, 0x2f, 0x1f, 0x7a, 0x26, - 0x27, 0x38, 0x45, 0x0f, 0x79, 0x5d, 0xc4, 0xd1, 0xdb, 0xb6, 0x83, 0xe1, - 0xaf, 0x29, 0xac, 0x23, 0x3d, 0x36, 0x71, 0x4a, 0xa9, 0x32, 0x49, 0x98, - 0xd0, 0xef, 0xb7, 0x8a, 0x76, 0xaa, 0xca, 0x93, 0x92, 0x99, 0x5c, 0x7b, - 0x38, 0x58, 0xc0, 0xa5, 0xfd, 0xc0, 0x76, 0x2f, 0xd8, 0x93, 0xa6, 0x97, - 0x05, 0xf4, 0x00, 0xd2, 0x4f, 0xa3, 0x99, 0xb9, 0x44, 0x14, 0x45, 0xc2, - 0x20, 0xce, 0xbc, 0x72, 0x38, 0x91, 0x13, 0x73, 0xd9, 0xba, 0x96, 0x23, - 0x8e, 0xe3, 0xa7, 0x83, 0x9b, 0xe2, 0x90, 0x94, 0x8c, 0x6f, 0x10, 0x0f, - 0x57, 0x08, 0x1c, 0xb4, 0xe4, 0xde, 0xf0, 0x19, 0xd5, 0x5a, 0x39, 0xf3, - 0x14, 0xa2, 0x9a, 0xdd, 0xc8, 0x73, 0xbc, 0xbb, 0x6c, 0x25, 0x0a, 0xde, - 0x91, 0x38, 0xca, 0x48, 0x08, 0x57, 0xec, 0xa9, 0x8f, 0x63, 0x4b, 0x89, - 0xbe, 0x05, 0x06, 0x6f, 0xfe, 0x76, 0xda, 0xc6, 0x64, 0xce, 0x4a, 0x95, - 0x71, 0x19, 0xe1, 0xfb, 0x5e, 0xeb, 0x34, 0xf0, 0x08, 0x90, 0x41, 0x34, - 0xff, 0x08, 0x84, 0x02, 0x2f, 0x1f, 0x26, 0x93, 0xc8, 0x41, 0x62, 0xc2, - 0x6c, 0x17, 0xe0, 0x34, 0xf9, 0x3c, 0x4b, 0x7a, 0xcb, 0x78, 0xe3, 0x7d, - 0x69, 0x7a, 0xe6, 0x38, 0x35, 0x76, 0x52, 0x34, 0x1b, 0x09, 0xa1, 0x8f, - 0x3c, 0x2b, 0xa7, 0xd3, 0x99, 0xaf, 0x32, 0x3b, 0x84, 0xdd, 0xf5, 0xc8, - 0xd8, 0xb3, 0xb6, 0xca, 0xa3, 0xfe, 0x80, 0x7b, 0x94, 0xb2, 0x1f, 0xdd, - 0xfc, 0x96, 0xda, 0xde, 0x60, 0xa3, 0x9e, 0xf9, 0xb7, 0x4e, 0x8b, 0xcb, - 0xf0, 0x21, 0xcb, 0xab, 0xe4, 0x5d, 0x0d, 0x89, 0x8f, 0xa3, 0x5b, 0xfb, - 0xb9, 0xf9, 0xf2, 0xce, 0x58, 0x02, 0x97, 0xd9, 0xef, 0x32, 0xf6, 0xab, - 0xef, 0x5d, 0x88, 0xe7, 0x83, 0xae, 0x9f, 0xef, 0x75, 0x64, 0xfc, 0xc0, - 0x25, 0xb9, 0xf3, 0x58, 0x42, 0x8b, 0xe3, 0xb6, 0x31, 0xd6, 0x2e, 0x73, - 0x2b, 0x8b, 0x92, 0xa6, 0xaf, 0x7d, 0x47, 0x1c, 0x06, 0x84, 0x68, 0x77, - 0x76, 0x98, 0x50, 0x21, 0x38, 0x46, 0x5d, 0x6a, 0x14, 0x79, 0xf6, 0xdf, - 0x63, 0x09, 0xa3, 0x56, 0xe5, 0x9b, 0xa2, 0x72, 0x24, 0x3b, 0xcd, 0xce, - 0xb1, 0x30, 0x1d, 0x83, 0x92, 0x60, 0x50, 0xab, 0x60, 0xd0, 0x1b, 0x2f, - 0xb7, 0x57, 0xb9, 0xe2, 0x87, 0x7f, 0xdd, 0x18, 0x07, 0x5c, 0x49, 0xdc, - 0xec, 0x46, 0x98, 0xe7, 0x43, 0x9b, 0x0b, 0x0e, 0xf9, 0xff, 0xf0, 0xcd, - 0x27, 0x6b, 0x25, 0xa3, 0x95, 0xd9, 0xfc, 0x03, 0xa1, 0x50, 0xd0, 0x94, - 0xb1, 0xb0, 0xf3, 0xcd, 0x3e, 0x1c, 0xf6, 0x9c, 0xe8, 0xaf, 0x02, 0x5d, - 0x1c, 0x06, 0x15, 0x21, 0x38, 0x81, 0x34, 0x78, 0x0d, 0x1b, 0xaa, 0x6d, - 0xea, 0x9b, 0x30, 0xd9, 0xe7, 0x3e, 0xdf, 0x7a, 0x4f, 0x34, 0x65, 0x12, - 0x0b, 0x9d, 0x1b, 0x0f, 0x1c, 0x3b, 0xe8, 0x49, 0x51, 0xde, 0xd5, 0xf7, - 0x01, 0x28, 0x31, 0x6b, 0xd7, 0x82, 0xd3, 0xd9, 0x55, 0xf7, 0x41, 0x4f, - 0x32, 0x6c, 0x84, 0x9c, 0x69, 0xd9, 0x4b, 0xc3, 0x35, 0xf4, 0x51, 0x99, - 0x0c, 0x7c, 0x7c, 0x52, 0xaf, 0xbe, 0x59, 0x2d, 0x9b, 0xfa, 0xdb, 0xdd, - 0x9a, 0xdc, 0x60, 0xd2, 0x00, 0xdf, 0xee, 0x56, 0x4a, 0xac, 0x4e, 0xd1, - 0x93, 0x68, 0x7b, 0xcc, 0x55, 0x58, 0x16, 0x93, 0xd6, 0x49, 0x94, 0x19, - 0xa4, 0x5d, 0xad, 0xf6, 0x7e, 0x53, 0x0b, 0x13, 0x64, 0xe1, 0xe6, 0x14, - 0xf2, 0x75, 0x82, 0x67, 0xa8, 0xdd, 0x82, 0xfd, 0xa3, 0x5f, 0x07, 0xc1, - 0x67, 0xa6, 0xe3, 0x11, 0x06, 0x1a, 0xac, 0xc9, 0x39, 0x7f, 0xed, 0x70, - 0x78, 0x52, 0xea, 0xc4, 0xac, 0x4f, 0x71, 0x4e, 0x2a, 0x7e, 0x2b, 0x36, - 0xd7, 0x58, 0xeb, 0x40, 0x4b, 0x1d, 0xb6, 0xc9, 0x01, 0x9a, 0xec, 0x12, - 0x73, 0x08, 0xf7, 0x7e, 0x50, 0x09, 0xcf, 0xfa, 0xcb, 0xfb, 0xf9, 0x8c, - 0x3d, 0x95, 0x44, 0xc7, 0xab, 0x8b, 0x3f, 0x26, 0x78, 0xe6, 0x3a, 0x51, - 0x77, 0x2b, 0x68, 0x67, 0xe7, 0xd5, 0x11, 0xfd, 0x9d, 0xa8, 0x36, 0xae, - 0x62, 0x67, 0xe1, 0xa5, 0x9b, 0x14, 0x39, 0x6e, 0x0e, 0xe1, 0x73, 0xa6, - 0xa3, 0x1a, 0x5f, 0x3d, 0x21, 0xe3, 0xe5, 0x91, 0xc2, 0xe5, 0xc6, 0x75, - 0x27, 0x55, 0x1c, 0x86, 0x16, 0x46, 0xf8, 0xfb, 0xc7, 0xf1, 0x01, 0x8d, - 0xac, 0x07, 0xa6, 0x9f, 0x41, 0xc0, 0xa5, 0xa8, 0xcf, 0x5e, 0xfa, 0x0d, - 0xf5, 0x0d, 0x37, 0x90, 0x1f, 0x3f, 0x03, 0x0e, 0xc3, 0x39, 0xd1, 0x64, - 0x38, 0x83, 0xe2, 0x33, 0x4a, 0x25, 0x68, 0xbb, 0x6f, 0x81, 0x30, 0x1b, - 0xb8, 0xa7, 0xe8, 0x9c, 0x63, 0xc0, 0x5b, 0xcf, 0x4a, 0x36, 0x18, 0x43, - 0xf2, 0x7e, 0xe5, 0x06, 0x5d, 0x79, 0x76, 0x3d, 0x66, 0x6a, 0x4d, 0xdd, - 0x7f, 0x3f, 0xa0, 0x57, 0x64, 0x7c, 0xde, 0x02, 0xed, 0x17, 0xb5, 0xa4, - 0x88, 0xb1, 0x47, 0xc8, 0x40, 0x79, 0x34, 0x33, 0xc0, 0x80, 0xc6, 0x1e, - 0x13, 0x39, 0xe0, 0x93, 0x95, 0xd4, 0x91, 0xa9, 0x5d, 0x37, 0x89, 0x14, - 0x5c, 0xe7, 0x94, 0x4c, 0x6f, 0x04, 0x35, 0xfa, 0x7c, 0x7f, 0x43, 0x19, - 0xe2, 0xc7, 0x35, 0xa6, 0x70, 0x1e, 0xbf, 0xe2, 0x81, 0x0d, 0x29, 0x48, - 0x37, 0xf4, 0x0c, 0x94, 0x60, 0x29, 0x0d, 0xc6, 0x67, 0x2d, 0x71, 0x75, - 0xfe, 0x8e, 0x9f, 0x9a, 0x9c, 0xd4, 0x0d, 0x39, 0x80, 0xb2, 0x3a, 0x3e, - 0xe3, 0xa5, 0x9b, 0x44, 0x60, 0x35, 0x01, 0x96, 0x37, 0x8f, 0x50, 0x2c, - 0x05, 0x10, 0x20, 0xc6, 0xfa, 0x83, 0xb3, 0x9c, 0xcc, 0x11, 0x3c, 0xdc, - 0x35, 0x7d, 0x7a, 0x2a, 0x71, 0x11, 0x69, 0x8b, 0x84, 0xe9, 0x02, 0xc8, - 0xd0, 0x71, 0x89, 0x6e, 0x03, 0x00, 0x73, 0x74, 0xb8, 0xc8, 0xac, 0xfa, - 0x12, 0xf7, 0x4b, 0x05, 0x32, 0x28, 0xd9, 0xf4, 0x04, 0x1d, 0x20, 0x9a, - 0x2e, 0x7b, 0x12, 0xab, 0x19, 0x14, 0x53, 0x43, 0x1e, 0xda, 0x39, 0xcb, - 0xca, 0xdb, 0x04, 0xdb, 0x7b, 0x85, 0xa7, 0x7c, 0xa1, 0x5e, 0xd7, 0x5e, - 0xf1, 0xfa, 0x87, 0xa6, 0xdd, 0x45, 0x1b, 0x6e, 0x09, 0x2d, 0x29, 0x14, - 0x0e, 0xa4, 0xef, 0xf0, 0x09, 0x12, 0x93, 0x8e, 0xdf, 0x30, 0x9b, 0xbf, - 0xa6, 0x28, 0xbf, 0x3d, 0xdc, 0xa3, 0x97, 0x4f, 0x9d, 0xbc, 0x00, 0x5f, - 0x55, 0x3a, 0xc9, 0x97, 0xe8, 0x36, 0x1d, 0x31, 0x61, 0x3d, 0x29, 0x4b, - 0xc6, 0x5f, 0x9a, 0x5f, 0xbf, 0x5c, 0x81, 0x02, 0xc7, 0x83, 0xfa, 0x2d, - 0xd1, 0xc6, 0xac, 0x0c, 0xa7, 0xbe, 0x0e, 0xf9, 0x0d, 0xcd, 0xd9, 0xed, - 0x82, 0x90, 0x00, 0x19, 0x0a, 0x8c, 0x1a, 0x65, 0x8a, 0xc0, 0x55, 0xa2, - 0xfb, 0x36, 0x03, 0x85, 0xb9, 0xdd, 0xfa, 0x16, 0x71, 0xaa, 0x7a, 0xcb, - 0x76, 0xd5, 0xf0, 0x8d, 0x22, 0xe2, 0xd7, 0x90, 0x0c, 0xc3, 0x57, 0x7c, - 0x56, 0x82, 0x6a, 0xea, 0xe8, 0xe1, 0x96, 0xd1, 0x46, 0xd8, 0x50, 0x4e, - 0xe0, 0x6a, 0xcc, 0xa6, 0x36, 0x14, 0xa7, 0x89, 0x29, 0x71, 0x15, 0xa4, - 0x1b, 0xb9, 0x6c, 0xa4, 0xf1, 0x3f, 0x1b, 0xd2, 0x64, 0x6b, 0x97, 0xdc, - 0xe2, 0xe8, 0xb4, 0x15, 0x69, 0x68, 0xd7, 0x28, 0x10, 0x26, 0x19, 0x26, - 0x27, 0x08, 0x34, 0xa9, 0x61, 0xb7, 0x79, 0x13, 0x01, 0x38, 0xe1, 0x18, - 0x0d, 0xc8, 0x56, 0x86, 0xea, 0xca, 0x18, 0xd8, 0xbb, 0xf8, 0xc1, 0xc4, - 0x6d, 0x97, 0x82, 0x9a, 0x0d, 0xb7, 0xde, 0xf6, 0xfa, 0xc0, 0x69, 0x1d, - 0xb2, 0x8e, 0x82, 0xc4, 0x17, 0x33, 0x05, 0xa2, 0x46, 0xcb, 0xaa, 0x11, - 0x19, 0xde, 0x84, 0x35, 0x28, 0x5e, 0x4a, 0x50, 0x98, 0x96, 0xe2, 0x39, - 0xa1, 0x77, 0x99, 0xd2, 0x15, 0xee, 0x88, 0xe7, 0xd7, 0x74, 0x41, 0x21, - 0xe5, 0x51, 0xfd, 0xfa, 0x21, 0xe0, 0x02, 0x63, 0x35, 0x86, 0xc4, 0x27, - 0xac, 0x45, 0x00, 0x15, 0xce, 0x85, 0xed, 0xe0, 0xc1, 0xc7, 0xcd, 0xac, - 0x1f, 0x74, 0xfc, 0x02, 0x55, 0xc0, 0xe1, 0x0f, 0x9e, 0x5a, 0x20, 0x89, - 0xe0, 0xf3, 0x14, 0x4e, 0x63, 0x53, 0xc7, 0xd7, 0xd7, 0xaf, 0x1f, 0x01, - 0x08, 0x4d, 0xb9, 0x66, 0x23, 0x37, 0xfa, 0xd0, 0x28, 0x42, 0xc6, 0xa1, - 0xce, 0xeb, 0x14, 0x69, 0xd9, 0x17, 0x62, 0xc6, 0x5e, 0x10, 0x9d, 0x3f, - 0x74, 0x9e, 0xb0, 0x97, 0xfc, 0x25, 0x27, 0x95, 0x7f, 0xf9, 0xd2, 0x65, - 0x52, 0x81, 0xb8, 0x86, 0xb7, 0xbf, 0xf3, 0x26, 0xf2, 0xe3, 0x17, 0x50, - 0xd9, 0x4e, 0x2e, 0x2b, 0xce, 0x17, 0x31, 0x03, 0x08, 0x5b, 0x6d, 0xa9, - 0x22, 0xad, 0xe9, 0x99, 0x00, 0x6f, 0x22, 0xee, 0x03, 0xa7, 0xde, 0xb3, - 0x14, 0x94, 0xc4, 0xa1, 0xfb, 0x8f, 0xd8, 0x64, 0xab, 0x69, 0x7e, 0x42, - 0xa9, 0xb6, 0xbc, 0xc9, 0xe4, 0x7d, 0x9f, 0xf6, 0xbb, 0x1d, 0x93, 0xf2, - 0xd4, 0x49, 0x1f, 0xc8, 0xf8, 0x9e, 0xe1, 0x42, 0x6c, 0x05, 0xbc, 0x2d, - 0x61, 0x9e, 0xc8, 0x17, 0xa0, 0xc4, 0x10, 0xb9, 0xaf, 0x9b, 0x33, 0xa0, - 0x26, 0x8f, 0x03, 0x0f, 0xf7, 0xcc, 0x69, 0x74, 0xaa, 0xf0, 0x47, 0x5a, - 0xf1, 0x2e, 0x8a, 0x36, 0xb9, 0x68, 0x43, 0xbb, 0x3b, 0x70, 0x91, 0x78, - 0xf3, 0x67, 0x38, 0x24, 0xe9, 0x78, 0xc2, 0x99, 0x80, 0xf4, 0x5a, 0x06, - 0xbf, 0xab, 0x14, 0xf6, 0xc8, 0x5b, 0x63, 0xae, 0xef, 0x4f, 0xd7, 0xd9, - 0x24, 0x21, 0x5a, 0x90, 0xf6, 0xcc, 0x6e, 0x2a, 0x21, 0x7c, 0x6b, 0x45, - 0xbe, 0x7e, 0x44, 0xf0, 0xe5, 0x72, 0xd2, 0xe5, 0x91, 0xae, 0x3b, 0x83, - 0xd5, 0xdb, 0x45, 0x51, 0x55, 0x3b, 0xb8, 0x7c, 0xdb, 0xdd, 0x47, 0xf6, - 0xe3, 0x31, 0x88, 0x9f, 0x7b, 0x73, 0x9d, 0x1f, 0xae, 0xdd, 0xfb, 0xdf, - 0xb3, 0xb2, 0xbb, 0xfe, 0xe6, 0x31, 0xd1, 0x39, 0x8c, 0xa6, 0xb8, 0x3e, - 0xd8, 0x5b, 0xbb, 0x87, 0x58, 0x9b, 0x57, 0x98, 0x46, 0x83, 0x28, 0x46, - 0x48, 0xb7, 0x45, 0x70, 0xb7, 0xa5, 0x5d, 0x2d, 0x74, 0xf1, 0x5d, 0x31, - 0x1f, 0x5a, 0xc4, 0x13, 0x10, 0x42, 0x01, 0x05, 0xe0, 0x1e, 0x3c, 0x0f, - 0x46, 0x25, 0x9a, 0x52, 0xc4, 0xd4, 0xab, 0xbd, 0x1d, 0x58, 0xb3, 0x73, - 0x60, 0x72, 0x1c, 0xa3, 0xfd, 0x26, 0x42, 0xdd, 0x3b, 0x47, 0x1b, 0xf5, - 0x19, 0x1d, 0x5e, 0xaf, 0x24, 0xe2, 0x89, 0x8c, 0x9e, 0xb1, 0x82, 0x6e, - 0xcf, 0x85, 0x88, 0x3a, 0xbc, 0xa0, 0x8c, 0x68, 0x16, 0xde, 0xa0, 0xd6, - 0x7e, 0xc6, 0x53, 0x99, 0x2b, 0xea, 0x4d, 0x6f, 0x33, 0x0b, 0x5d, 0x19, - 0x26, 0x51, 0x8c, 0x74, 0x61, 0xa3, 0x0d, 0x06, 0x96, 0x1c, 0x27, 0x2f, - 0xff, 0xc0, 0x78, 0xe5, 0x35, 0x4f, 0x4e, 0xe0, 0xcb, 0xa5, 0xc8, 0x64, - 0xb1, 0xc9, 0x17, 0x7b, 0xe7, 0x00, 0x7b, 0x53, 0x6d, 0xfa, 0x55, 0xae, - 0xb6, 0xf1, 0x22, 0xfb, 0x8c, 0x78, 0x87, 0x9c, 0x3a, 0x9c, 0xa0, 0x50, - 0x9f, 0xca, 0x50, 0x60, 0x5d, 0xf9, 0x60, 0x5f, 0x3a, 0x78, 0x8b, 0x43, - 0xf8, 0xc6, 0x2b, 0x5e, 0x2c, 0x32, 0xb4, 0x80, 0x0d, 0xa2, 0xbf, 0x26, - 0x0e, 0x55, 0x78, 0x42, 0x74, 0x84, 0x8b, 0xbf, 0x60, 0xe9, 0x3e, 0x44, - 0x85, 0x0c, 0x83, 0xec, 0x5b, 0x59, 0x6c, 0x77, 0xa6, 0x81, 0x71, 0x91, - 0x67, 0xd4, 0xc5, 0xa1, 0x35, 0x3d, 0x37, 0xff, 0xce, 0xe4, 0xe1, 0x33, - 0x60, 0xde, 0x3b, 0x90, 0x1a, 0x5d, 0xd9, 0xcd, 0x52, 0x58, 0x7a, 0x51, - 0x2c, 0x6b, 0x1e, 0xb5, 0x4e, 0x8d, 0x98, 0x75, 0xe6, 0xbd, 0x6e, 0xdb, - 0xac, 0xb9, 0x97, 0x4d, 0x4a, 0xfd, 0x6c, 0xd6, 0xf0, 0x16, 0xff, 0x71, - 0x10, 0x33, 0x08, 0x43, 0x19, 0x8c, 0x30, 0xca, 0xa7, 0xbe, 0x89, 0x29, - 0xf0, 0x24, 0x7e, 0x7f, 0x9e, 0x08, 0x8a, 0xd3, 0x4c, 0x3b, 0xd2, 0xd9, - 0x09, 0x0a, 0xeb, 0xcd, 0x74, 0xd8, 0x6b, 0x7a, 0x5e, 0x92, 0xd2, 0xac, - 0x9e, 0x2e, 0xbd, 0xb0, 0x79, 0xa3, 0x3e, 0x09, 0x05, 0x1d, 0xaa, 0x1a, - 0xb5, 0xb0, 0x75, 0xa5, 0x62, 0x8d, 0x3d, 0xd1, 0x3c, 0x31, 0xb8, 0x25, - 0xd5, 0x4d, 0xd7, 0xa5, 0x41, 0x84, 0x82, 0x0e, 0x2f, 0xef, 0x84, 0x40, - 0x54, 0x5a, 0x2c, 0xbb, 0x70, 0x01, 0x61, 0x11, 0xd7, 0xe7, 0x9a, 0x4a, - 0x78, 0xea, 0xaa, 0x19, 0x68, 0xc1, 0x18, 0x94, 0xa7, 0x9a, 0x16, 0x8d, - 0x0c, 0x9d, 0x23, 0x6e, 0x1e, 0xca, 0x7e, 0x73, 0x95, 0x18, 0x0f, 0xfe, - 0x77, 0x53, 0x23, 0x57, 0x1d, 0xba, 0xea, 0x0a, 0x07, 0xfd, 0x99, 0xda, - 0x4c, 0x75, 0x36, 0xcd, 0x1e, 0xca, 0x1d, 0xb9, 0x1d, 0x1f, 0x7d, 0xf8, - 0x7d, 0x29, 0x81, 0x5f, 0x17, 0x7c, 0x84, 0x5c, 0xcc, 0xdb, 0x6f, 0xa0, - 0x11, 0xb4, 0xaa, 0x4a, 0x31, 0x7b, 0x37, 0x58, 0xa0, 0x9e, 0x24, 0x19, - 0x28, 0x48, 0x62, 0xea, 0x65, 0x0d, 0x0a, 0x95, 0xfa, 0x09, 0x51, 0xae, - 0x79, 0xb1, 0xe7, 0xc7, 0x6f, 0x07, 0x06, 0x97, 0xda, 0xc8, 0x53, 0xa4, - 0x0a, 0x2f, 0x3b, 0xf2, 0x7c, 0x64, 0x21, 0xfb, 0xe6, 0xea, 0x98, 0x50, - 0xfa, 0xb1, 0x90, 0xa6, 0x84, 0x78, 0xe4, 0x37, 0xe8, 0x6f, 0xe0, 0xa2, - 0xf1, 0x3b, 0x6d, 0x05, 0xa2, 0xea, 0x48, 0x0a, 0x1d, 0x62, 0x59, 0x7c, - 0xd4, 0xf6, 0xfd, 0xc5, 0x70, 0x5c, 0x67, 0xd6, 0xdc, 0xcc, 0x26, 0x64, - 0x54, 0xdb, 0x6f, 0xd3, 0x59, 0x4a, 0x04, 0xef, 0xb4, 0x7c, 0xea, 0xbd, - 0x2b, 0xa7, 0x38, 0xaf, 0x9e, 0xca, 0x7c, 0x01, 0x62, 0x8a, 0x67, 0xbe, - 0xfc, 0xf9, 0x25, 0xfa, 0x17, 0x8b, 0x63, 0xa1, 0x4f, 0xd4, 0x9c, 0x66, - 0x56, 0xb3, 0x70, 0xa5, 0xf6, 0x5d, 0x0a, 0xf2, 0xeb, 0xfa, 0x08, 0xaf, - 0x95, 0x69, 0x19, 0x39, 0xa3, 0xf9, 0x63, 0x80, 0x98, 0x4c, 0x47, 0xb8, - 0x35, 0x9b, 0xc0, 0x72, 0xc7, 0xf4, 0x63, 0x50, 0x79, 0xc8, 0xa6, 0x5f, - 0x82, 0xfe, 0x14, 0x1f, 0x3d, 0xdb, 0x58, 0x32, 0x43, 0xaf, 0x93, 0xae, - 0x51, 0x30, 0xc5, 0x23, 0xbb, 0x4c, 0x82, 0x88, 0xa6, 0x1e, 0x7b, 0xfa, - 0xa2, 0x8a, 0x8e, 0x45, 0xe8, 0x06, 0xa2, 0x8d, 0x55, 0x78, 0x78, 0xa4, - 0xbe, 0xc3, 0xa6, 0x7d, 0x1d, 0x2b, 0x41, 0xa0, 0xcb, 0x30, 0x5b, 0x94, - 0xa5, 0xa9, 0x28, 0x73, 0x40, 0x2a, 0xcd, 0x53, 0x10, 0x1f, 0xc2, 0xc5, - 0x25, 0x60, 0x3a, 0xa5, 0x7f, 0x01, 0x9a, 0xbd, 0xd2, 0x3d, 0x5d, 0x86, - 0xdd, 0xc8, 0x79, 0x29, 0xc3, 0x9a, 0x46, 0x03, 0xbd, 0x06, 0xbc, 0xba, - 0x21, 0x9b, 0x3a, 0x11, 0x01, 0x30, 0xd9, 0x81, 0x75, 0x24, 0xda, 0xf1, - 0x1a, 0x7f, 0x9e, 0x10, 0x9b, 0xcf, 0x3d, 0x85, 0xf2, 0x9d, 0xab, 0x57, - 0x7b, 0x92, 0x82, 0xd9, 0x56, 0x05, 0xe5, 0x2b, 0x3d, 0x80, 0x6f, 0x18, - 0xb9, 0xeb, 0x32, 0xc9, 0x04, 0x52, 0x4e, 0x87, 0xfb, 0xc4, 0x22, 0xf5, - 0x64, 0x8a, 0x9b, 0x99, 0x14, 0x94, 0x8b, 0x92, 0x99, 0xd0, 0xd6, 0x3a, - 0xcf, 0x15, 0xc6, 0xcd, 0x8d, 0x89, 0x1a, 0xfe, 0xe3, 0x5e, 0x4c, 0xf9, - 0x7e, 0x38, 0x52, 0x08, 0xc3, 0x09, 0x27, 0xdc, 0x4a, 0x4e, 0x53, 0x5f, - 0x79, 0xb0, 0x6c, 0xd6, 0x4c, 0xec, 0xcd, 0x13, 0x22, 0x4a, 0xa2, 0x2f, - 0x62, 0x35, 0xe1, 0xde, 0x62, 0xf7, 0x63, 0x3e, 0xfa, 0xae, 0x00, 0x1b, - 0xe5, 0x93, 0x0c, 0xf1, 0x6b, 0xae, 0x05, 0x1c, 0x7e, 0x06, 0x32, 0x78, - 0x8d, 0xa7, 0xf9, 0xae, 0x78, 0x5a, 0xdf, 0xb3, 0x56, 0xd2, 0x2c, 0x11, - 0xe9, 0xc8, 0x23, 0x4b, 0xf4, 0x40, 0x7d, 0x33, 0x52, 0xc1, 0xde, 0xe6, - 0xa1, 0x8d, 0xb6, 0xfd, 0x1e, 0xf5, 0xef, 0x6a, 0x7c, 0x81, 0x23, 0xd4, - 0xaf, 0xa4, 0x07, 0x3a, 0x59, 0xde, 0xa1, 0x2a, 0x5e, 0x3e, 0x49, 0x84, - 0xfa, 0x40, 0xa5, 0xe0, 0x25, 0xd6, 0xdb, 0x57, 0x5b, 0x46, 0x8c, 0x00, - 0xd8, 0x51, 0x40, 0x1c, 0xe0, 0x0b, 0xf7, 0x20, 0xff, 0xc9, 0xd8, 0x48, - 0x09, 0x95, 0x71, 0x0a, 0xb3, 0xbb, 0x94, 0xb4, 0x77, 0xdd, 0x4c, 0x86, - 0x4c, 0x56, 0xe3, 0x68, 0x26, 0x3c, 0x9e, 0x74, 0x85, 0xf3, 0xa3, 0x68, - 0x95, 0xdb, 0xc3, 0xbf, 0xe7, 0xd2, 0x1f, 0x8d, 0x09, 0xa8, 0x59, 0xec, - 0xc5, 0xba, 0x45, 0xc8, 0x2c, 0x21, 0x76, 0xbf, 0x40, 0x6e, 0x5f, 0x6e, - 0xf6, 0x5f, 0x2f, 0xfe, 0xf1, 0x65, 0x0c, 0x16, 0x34, 0xd4, 0x29, 0x31, - 0x38, 0xa9, 0x7a, 0x8e, 0xa5, 0xb1, 0x47, 0x67, 0x85, 0xe6, 0x0a, 0x76, - 0x3d, 0x6b, 0x4d, 0x2a, 0x56, 0x03, 0x18, 0x71, 0x03, 0x25, 0x26, 0x8f, - 0x9d, 0xc7, 0xcd, 0x46, 0x6c, 0x77, 0x99, 0xcb, 0x2c, 0xee, 0x96, 0x8d, - 0xc3, 0x03, 0x17, 0x54, 0x2f, 0xe9, 0x62, 0x47, 0x1e, 0x30, 0x02, 0xa8, - 0xe1, 0x95, 0x24, 0xe4, 0x10, 0xfc, 0x9a, 0x4b, 0xd0, 0x52, 0x58, 0x5d, - 0x32, 0x87, 0xf6, 0xe9, 0x11, 0xf0, 0xf5, 0x31, 0x12, 0xd1, 0x8b, 0xc8, - 0x11, 0x3c, 0x7e, 0x3f, 0xa8, 0xba, 0xbe, 0x43, 0x01, 0xee, 0xbb, 0x51, - 0xca, 0xbf, 0x40, 0x69, 0x23, 0x3d, 0x73, 0x65, 0x29, 0x93, 0xf0, 0x9a, - 0xeb, 0xf9, 0xeb, 0x23, 0xaa, 0x94, 0x59, 0xea, 0xbb, 0xab, 0xf1, 0x24, - 0x65, 0xb0, 0xce, 0x49, 0xe0, 0xa1, 0x52, 0x4b, 0xbb, 0xa8, 0x4b, 0x2f, - 0x68, 0xd2, 0xf2, 0x1a, 0x94, 0x28, 0xd2, 0xec, 0xba, 0x63, 0x33, 0xcd, - 0x33, 0xdb, 0xd7, 0x26, 0x05, 0x81, 0xf9, 0x51, 0x47, 0xde, 0xd8, 0x95, - 0x10, 0x73, 0x25, 0x14, 0xb1, 0x75, 0xc7, 0x93, 0xdb, 0x7e, 0xa9, 0x57, - 0xe1, 0x9c, 0xbc, 0x1a, 0xba, 0x24, 0x36, 0xd1, 0x89, 0xe7, 0xb5, 0x50, - 0xa8, 0x9d, 0x31, 0x10, 0x86, 0xce, 0x86, 0x65, 0x5d, 0x82, 0x65, 0xa8, - 0x9f, 0x25, 0x18, 0xcc, 0xcf, 0x9e, 0x70, 0xac, 0xb3, 0x9d, 0x10, 0x75, - 0x87, 0x46, 0x77, 0x9f, 0xd4, 0x05, 0xd5, 0x2c, 0x99, 0x83, 0x29, 0x26, - 0x82, 0x9d, 0xe8, 0x31, 0xff, 0x05, 0xa8, 0x24, 0x4e, 0x5a, 0x5e, 0x92, - 0x8f, 0xae, 0x61, 0xf9, 0xbf, 0x1c, 0x31, 0x6d, 0x37, 0xb6, 0x83, 0x4d, - 0xb5, 0xfa, 0x3b, 0xff, 0x79, 0x1f, 0xcf, 0x6a, 0x00, 0x75, 0xf7, 0x24, - 0x7f, 0x40, 0x62, 0x76, 0x9c, 0x3e, 0x8f, 0x37, 0xd1, 0x78, 0xdc, 0x75, - 0x4f, 0x29, 0xa2, 0xa2, 0x78, 0x96, 0x6d, 0x74, 0xe1, 0x88, 0xf0, 0x95, - 0x54, 0x56, 0x1c, 0x02, 0xeb, 0xef, 0xe9, 0x47, 0x89, 0xf9, 0x80, 0x45, - 0x0c, 0xfe, 0x42, 0xad, 0xe8, 0xf5, 0xa1, 0xae, 0x01, 0x0e, 0x85, 0xee, - 0xf3, 0xf2, 0xe8, 0x49, 0x4d, 0x95, 0x41, 0x15, 0xc7, 0x2d, 0x8f, 0x7e, - 0x15, 0x4e, 0x95, 0xef, 0x88, 0xbf, 0x42, 0x90, 0x75, 0x6f, 0x9b, 0xee, - 0xaa, 0xf3, 0xa2, 0xc7, 0x9e, 0x01, 0x01, 0x32, 0xea, 0xf2, 0xc4, 0x0e, - 0x79, 0xaf, 0xdc, 0x3f, 0x2d, 0x29, 0xf8, 0x14, 0xc1, 0xea, 0x05, 0x00, - 0x53, 0x30, 0xae, 0x09, 0xbf, 0xb3, 0x38, 0x99, 0x61, 0x06, 0x1a, 0x6b, - 0x47, 0xea, 0x62, 0xc7, 0x00, 0x0d, 0xdb, 0xfa, 0xe4, 0x50, 0xa2, 0x6b, - 0x7b, 0xfd, 0x56, 0x15, 0xea, 0x6e, 0x71, 0x7a, 0x20, 0x0e, 0xbf, 0x6b, - 0x0d, 0x3d, 0xba, 0x66, 0xf0, 0x06, 0xa6, 0x1f, 0xbc, 0x93, 0x9e, 0xfa, - 0xc9, 0xba, 0x5b, 0x01, 0xcc, 0x5f, 0xd1, 0xc5, 0x2b, 0xee, 0x4c, 0x36, - 0x39, 0x22, 0x49, 0xaa, 0xbb, 0xb9, 0x03, 0xb6, 0x8f, 0x57, 0x9a, 0x09, - 0xf0, 0xc8, 0xa5, 0x3e, 0x5d, 0x97, 0xd4, 0xe4, 0x33, 0xb6, 0xdc, 0x08, - 0x7a, 0xc9, 0x60, 0x38, 0x42, 0xa0, 0x24, 0xbd, 0xac, 0x3b, 0xb2, 0xd1, - 0x73, 0xea, 0x22, 0xf4, 0x9a, 0x3d, 0x78, 0x05, 0xec, 0x35, 0xc3, 0x11, - 0xf9, 0xdb, 0xa6, 0x48, 0xb9, 0x06, 0x04, 0x09, 0xb9, 0x4c, 0xad, 0x6d, - 0x3c, 0xca, 0x5c, 0x23, 0x05, 0x14, 0x47, 0x1d, 0x48, 0x6d, 0x88, 0x47, - 0xd5, 0xfb, 0xd6, 0x4c, 0x53, 0x7b, 0xe0, 0xc6, 0x9f, 0xf9, 0xcc, 0x57, - 0x1d, 0x54, 0xf3, 0xc0, 0x89, 0xc7, 0x0d, 0x16, 0x88, 0x6b, 0x2d, 0x56, - 0x79, 0x5d, 0x80, 0xf4, 0x22, 0x00, 0xa5, 0x94, 0x94, 0x4b, 0x15, 0xd0, - 0x1f, 0x26, 0x92, 0x7f, 0xf8, 0xd6, 0x43, 0x8f, 0x70, 0x1c, 0x9b, 0x53, - 0xd6, 0xbe, 0x6d, 0x0c, 0x92, 0x3f, 0x6f, 0x1a, 0xa3, 0x30, 0xf5, 0xc1, - 0xae, 0xa8, 0x9b, 0xeb, 0x75, 0x2d, 0x99, 0x9d, 0x5b, 0x93, 0xb2, 0x7c, - 0x5b, 0x48, 0x09, 0x45, 0xcd, 0xd4, 0xb3, 0x0c, 0xf2, 0xb9, 0x3c, 0xa8, - 0xc1, 0x9c, 0xe7, 0x36, 0x97, 0x9c, 0x95, 0x8f, 0xdc, 0xec, 0xd4, 0x0e, - 0x83, 0xae, 0x46, 0x35, 0x2b, 0x0a, 0xbb, 0xdc, 0x63, 0x03, 0x36, 0x5b, - 0x6a, 0x15, 0x0b, 0xd4, 0x64, 0x63, 0xa8, 0xe2, 0xe8, 0x9b, 0x2f, 0xf5, - 0xf8, 0x79, 0x50, 0x1b, 0x56, 0xc3, 0xec, 0x45, 0x9b, 0x09, 0xc1, 0x82, - 0x96, 0xd2, 0xe1, 0xa7, 0x83, 0xaa, 0x63, 0x01, 0x3d, 0x84, 0xc3, 0xf2, - 0x7b, 0x1d, 0xce, 0x4e, 0x22, 0xf1, 0x13, 0x73, 0xc8, 0x19, 0xb0, 0xbd, - 0xaf, 0x57, 0xca, 0x3c, 0x50, 0x52, 0x15, 0x48, 0x2c, 0x93, 0x87, 0x27, - 0xad, 0x3c, 0x29, 0x2c, 0x74, 0x6b, 0x15, 0x64, 0xc2, 0xcf, 0x30, 0x7e, - 0xee, 0x91, 0x55, 0x5d, 0xe6, 0xef, 0x21, 0x74, 0x5c, 0x99, 0xb3, 0x66, - 0x56, 0x40, 0x33, 0xa2, 0x68, 0x86, 0xfb, 0xbb, 0xc9, 0xfc, 0x62, 0xca, - 0x74, 0xfa, 0x0a, 0xe5, 0x4a, 0x9c, 0x29, 0xf4, 0xfb, 0x50, 0xd3, 0x03, - 0x5c, 0xcb, 0x03, 0x45, 0x76, 0xec, 0x8e, 0x16, 0xbb, 0x94, 0xcd, 0x6d, - 0x26, 0x1a, 0xfc, 0x09, 0x00, 0xd8, 0xee, 0x5e, 0x21, 0xf0, 0x21, 0x50, - 0x3d, 0xe9, 0x33, 0x66, 0xfb, 0x4f, 0xbf, 0xcc, 0xe3, 0x37, 0xbc, 0xc4, - 0xd7, 0x92, 0xda, 0xf0, 0x12, 0x20, 0x12, 0xa3, 0x2b, 0xca, 0x32, 0xd1, - 0xd6, 0x95, 0x1c, 0xd1, 0xaf, 0x0c, 0x83, 0xeb, 0x0a, 0x7c, 0x17, 0xdd, - 0xc9, 0xa5, 0x05, 0x01, 0x38, 0x39, 0x9a, 0x72, 0x53, 0x57, 0x98, 0xbf, - 0xa1, 0xc0, 0x0e, 0x63, 0x67, 0xc4, 0x25, 0xef, 0xaf, 0x3a, 0xfa, 0x41, - 0xd9, 0x23, 0xc1, 0x1f, 0xdb, 0x20, 0x3c, 0x84, 0xc2, 0x6b, 0x1e, 0x6d, - 0xf7, 0xe9, 0xd5, 0x6b, 0xae, 0xa5, 0x63, 0xd9, 0x1d, 0xc8, 0x9f, 0xe0, - 0x23, 0x93, 0xaf, 0x0c, 0x80, 0x04, 0x5a, 0x1f, 0xdd, 0xd7, 0x7a, 0x95, - 0x2d, 0x5f, 0x50, 0x31, 0xf1, 0x2c, 0xed, 0x43, 0xdb, 0x4a, 0x76, 0x12, - 0x12, 0xe6, 0x25, 0xa6, 0xd7, 0x16, 0x83, 0xaa, 0x5f, 0x16, 0xc7, 0x33, - 0x64, 0x4f, 0xd4, 0x89, 0x20, 0xfc, 0xf6, 0x81, 0x65, 0x66, 0x80, 0xab, - 0xa2, 0xcc, 0x1d, 0x2f, 0x3e, 0xbd, 0x78, 0xfb, 0xbe, 0xd5, 0x51, 0x51, - 0x1b, 0x87, 0x1d, 0xea, 0x83, 0x1c, 0xea, 0x8d, 0x09, 0x6c, 0x86, 0xa6, - 0x01, 0x54, 0xb5, 0xe3, 0x1c, 0xc7, 0x32, 0x41, 0x2e, 0x30, 0x40, 0x70, - 0x9e, 0x7a, 0x36, 0x65, 0x56, 0x7d, 0xe8, 0xab, 0x43, 0x0d, 0xb6, 0x32, - 0x7d, 0xf2, 0x36, 0x01, 0x01, 0xe4, 0x05, 0xf8, 0x73, 0x32, 0x79, 0xec, - 0xaf, 0xfb, 0xf9, 0x0a, 0x66, 0x1d, 0x43, 0xaf, 0x7d, 0x92, 0x09, 0xed, - 0xb0, 0x24, 0x9d, 0x64, 0x98, 0x14, 0xbf, 0xa6, 0xf2, 0x51, 0x42, 0x76, - 0x79, 0xa9, 0x52, 0xed, 0xd7, 0xda, 0x81, 0xe8, 0x98, 0x2c, 0xe7, 0x54, - 0xe7, 0x88, 0x52, 0x36, 0x08, 0x46, 0x91, 0x8c, 0xe2, 0x20, 0xd7, 0xe7, - 0x0b, 0xdc, 0xbb, 0x8f, 0xee, 0xbb, 0xa5, 0x6f, 0x86, 0xb6, 0x1d, 0xa4, - 0x0e, 0x2d, 0xd4, 0x87, 0xcf, 0xe8, 0x1d, 0xec, 0xfa, 0xb7, 0x10, 0xcb, - 0x8b, 0x90, 0x7f, 0xf0, 0xcd, 0x4c, 0x09, 0x36, 0x82, 0xe7, 0x41, 0xff, - 0x42, 0xc3, 0x26, 0xe0, 0x04, 0x5d, 0x24, 0x64, 0xca, 0x6a, 0x42, 0x45, - 0x02, 0x6b, 0x63, 0xe5, 0x3a, 0x51, 0x4d, 0xa9, 0xd8, 0x18, 0x49, 0x5e, - 0xa1, 0x93, 0x20, 0x09, 0x06, 0x92, 0xdf, 0x59, 0xb0, 0x01, 0xe9, 0xbc, - 0xbe, 0x51, 0xfd, 0x2d, 0xa7, 0xae, 0x7e, 0x0a, 0xac, 0x59, 0xe9, 0x0e, - 0x98, 0x7f, 0x91, 0x10, 0x64, 0x22, 0x8f, 0x84, 0xbc, 0xcb, 0x7a, 0x89, - 0xa8, 0x30, 0xb8, 0xa6, 0x5a, 0x80, 0xaf, 0x4e, 0xd0, 0x0f, 0x16, 0x48, - 0x5c, 0xef, 0x88, 0x00, 0x63, 0x1e, 0x18, 0x07, 0xf6, 0x9e, 0x14, 0xfa, - 0xad, 0x2e, 0xa1, 0xbe, 0x8e, 0xbf, 0xce, 0x56, 0x10, 0xce, 0x0c, 0x35, - 0x61, 0xcc, 0x36, 0x53, 0xb3, 0xdf, 0x52, 0xc9, 0x38, 0x36, 0x57, 0x3f, - 0x64, 0xdf, 0xd8, 0x10, 0x44, 0x1f, 0xcd, 0x28, 0xe9, 0x17, 0x5a, 0x44, - 0x0b, 0x64, 0x2e, 0xd0, 0xe7, 0x0b, 0xe4, 0xef, 0x70, 0x31, 0xeb, 0x2f, - 0x7f, 0xa6, 0xe3, 0xd7, 0x35, 0xdc, 0xb8, 0xc5, 0xae, 0x8d, 0x08, 0x54, - 0x33, 0x04, 0xb6, 0x7e, 0x68, 0x02, 0x03, 0x7f, 0x81, 0xcc, 0xa0, 0x79, - 0xe8, 0xfa, 0x8a, 0x5e, 0x8d, 0xb4, 0xa1, 0x8b, 0xfa, 0x30, 0x59, 0xf8, - 0x84, 0x50, 0xd3, 0x31, 0x78, 0x38, 0x52, 0x49, 0x61, 0x40, 0xcf, 0x3b, - 0x95, 0x8a, 0x6d, 0x43, 0x57, 0xc2, 0x6b, 0x0c, 0xfb, 0x14, 0x80, 0xe8, - 0xfe, 0x57, 0x26, 0xa3, 0xad, 0xa1, 0x0e, 0x5d, 0xa4, 0x68, 0xa0, 0xe2, - 0x3e, 0x9b, 0x42, 0x23, 0xe8, 0x2f, 0xcd, 0xc2, 0x73, 0x7a, 0x82, 0x9c, - 0x43, 0x98, 0x01, 0x1d, 0x3a, 0x08, 0xda, 0xf5, 0x08, 0xf8, 0x10, 0x66, - 0x83, 0xde, 0xa5, 0x7b, 0x51, 0x00, 0xad, 0xf5, 0x6e, 0xb6, 0x11, 0xc7, - 0xda, 0xb6, 0xe7, 0x2f, 0x20, 0x2b, 0x95, 0x4e, 0x0a, 0xe9, 0xe7, 0x87, - 0x06, 0x9b, 0x34, 0x86, 0x02, 0x49, 0x2c, 0x53, 0xfc, 0x10, 0x9e, 0xea, - 0x7d, 0xe2, 0x63, 0xbc, 0x04, 0xc1, 0x82, 0x50, 0xb1, 0xb8, 0xbe, 0x89, - 0x65, 0xa1, 0x5b, 0xdc, 0xb0, 0x66, 0xb7, 0xa8, 0xaf, 0xdd, 0xcd, 0xcd, - 0x4b, 0xb6, 0x93, 0xff, 0x28, 0xc9, 0x96, 0xed, 0xad, 0x6e, 0xba, 0x1d, - 0x2c, 0x42, 0xae, 0x4a, 0xef, 0x1c, 0xd2, 0x2a, 0x2a, 0xeb, 0x74, 0xb6, - 0xc0, 0xe3, 0xe7, 0x45, 0x31, 0x18, 0xb6, 0x5f, 0x5f, 0x41, 0x8e, 0x2a, - 0x00, 0x7d, 0x02, 0x11, 0x52, 0xaa, 0xa6, 0x15, 0x8c, 0x61, 0xb3, 0xf4, - 0xab, 0xef, 0x48, 0x81, 0x20, 0x2d, 0x48, 0xcf, 0xb5, 0xd7, 0x39, 0xa5, - 0x48, 0xba, 0x78, 0x5d, 0x9f, 0x2e, 0x8e, 0x36, 0x40, 0xa0, 0x72, 0x8b, - 0x5c, 0xe1, 0xea, 0xc3, 0x3f, 0x7c, 0xc1, 0x85, 0x45, 0xf7, 0xa1, 0x79, - 0xf4, 0x90, 0xa5, 0x8f, 0x67, 0x77, 0x8f, 0x1b, 0xb3, 0x65, 0xd7, 0x54, - 0x72, 0x77, 0x25, 0x76, 0xa3, 0xea, 0x13, 0xd6, 0xbe, 0xf3, 0x82, 0x18, - 0xca, 0x2a, 0xa0, 0x5d, 0xc8, 0x26, 0x93, 0x20, 0x96, 0x90, 0x94, 0xc4, - 0x03, 0xec, 0x83, 0xd7, 0x5d, 0xd4, 0x0b, 0xd0, 0x87, 0xbe, 0xb9, 0xca, - 0xa8, 0x50, 0x21, 0xfd, 0xe4, 0xe3, 0x3f, 0x8c, 0xbd, 0xdd, 0xed, 0x32, - 0xc4, 0x76, 0x31, 0xb8, 0xf8, 0x89, 0x18, 0x77, 0xcf, 0x68, 0xaa, 0x96, - 0x6d, 0xfb, 0xe8, 0x6e, 0xc0, 0xad, 0x5b, 0x1c, 0xd1, 0x2d, 0x68, 0x50, - 0xbf, 0xc0, 0x21, 0xe3, 0x01, 0x30, 0x5f, 0xb8, 0xba, 0xbf, 0x19, 0x4d, - 0xd9, 0x8e, 0x02, 0xdd, 0x2e, 0x9b, 0x2d, 0x56, 0x60, 0x19, 0xd4, 0x6c, - 0xf4, 0xf1, 0x4f, 0x78, 0x00, 0x3c, 0x2c, 0xd3, 0x1b, 0x53, 0x32, 0x69, - 0xf0, 0x3c, 0xa8, 0xaa, 0xbd, 0x22, 0xfe, 0x8d, 0xa5, 0x82, 0x82, 0x8d, - 0x31, 0x15, 0xc5, 0x22, 0x4b, 0xf8, 0x36, 0xd5, 0x39, 0xa4, 0x47, 0x26, - 0x8d, 0x07, 0x48, 0x97, 0x32, 0x59, 0xa2, 0xa1, 0x9d, 0x5a, 0x0e, 0x30, - 0x77, 0x48, 0x07, 0xcf, 0xce, 0xbe, 0xf1, 0x08, 0xd6, 0x0a, 0x03, 0xce, - 0xc1, 0x2d, 0x13, 0xa7, 0xa3, 0xec, 0x07, 0x6a, 0x3a, 0xfd, 0x17, 0x5b, - 0xb6, 0xb8, 0x7b, 0x36, 0xea, 0x80, 0xcf, 0x87, 0x5a, 0x34, 0x87, 0x56, - 0xb4, 0x1e, 0xb2, 0xb1, 0x7e, 0xa3, 0x45, 0x36, 0x96, 0xdf, 0x99, 0x07, - 0x82, 0xb4, 0x73, 0xb7, 0x25, 0xf0, 0x7f, 0x92, 0xf2, 0x2d, 0x37, 0xf0, - 0xfb, 0x70, 0x8c, 0x1e, 0x0d, 0x82, 0x1e, 0x8e, 0xf4, 0x14, 0x50, 0x84, - 0x3b, 0x47, 0x74, 0x95, 0x70, 0x03, 0x03, 0x55, 0xdd, 0xbb, 0x54, 0x26, - 0x86, 0x6c, 0x12, 0x20, 0x69, 0xfb, 0x2e, 0x49, 0x43, 0x10, 0x1c, 0x2b, - 0x02, 0x00, 0xdf, 0xe1, 0x10, 0x1a, 0x2f, 0x8b, 0xf1, 0x70, 0xd2, 0xaf, - 0x6f, 0xe9, 0x34, 0x48, 0x72, 0x30, 0xcd, 0xe5, 0x7e, 0x56, 0xc6, 0x1f, - 0x52, 0x37, 0x54, 0x3b, 0x61, 0x3b, 0x8a, 0x61, 0x84, 0x2c, 0x4b, 0x08, - 0xc6, 0x49, 0xff, 0x81, 0xb6, 0x1f, 0x2f, 0x5f, 0x57, 0x87, 0x5d, 0x0d, - 0x35, 0xba, 0xce, 0x54, 0x1e, 0xe7, 0x7c, 0xf9, 0x91, 0xb6, 0x2d, 0x2e, - 0x4b, 0x8e, 0xfd, 0x97, 0xd4, 0x39, 0x6e, 0xa6, 0x0d, 0xaf, 0x17, 0x87, - 0x99, 0x51, 0x56, 0x3c, 0x19, 0x18, 0x42, 0x0b, 0x63, 0xed, 0xd3, 0x83, - 0x49, 0x83, 0x5f, 0xa0, 0x54, 0x69, 0x45, 0xd5, 0xc6, 0xe6, 0x3d, 0xf2, - 0x08, 0xd0, 0x11, 0xd7, 0xad, 0xc6, 0xe8, 0xa4, 0xd2, 0x18, 0xbd, 0x78, - 0xa5, 0x08, 0x01, 0x3b, 0x71, 0xf5, 0x59, 0x5e, 0x39, 0x60, 0x6b, 0x97, - 0x7c, 0x02, 0x07, 0x14, 0xd5, 0x15, 0x5f, 0x0f, 0xe6, 0x53, 0xb8, 0x23, - 0x26, 0x40, 0xf4, 0x8a, 0xb2, 0x35, 0x54, 0xed, 0x41, 0x78, 0xed, 0x15, - 0x9a, 0x3e, 0x2a, 0xfa, 0xf1, 0x19, 0x23, 0x7a, 0x5c, 0x4d, 0xec, 0xcb, - 0x24, 0xe2, 0xfc, 0x51, 0x3a, 0x03, 0x8a, 0x91, 0x5d, 0x92, 0x8e, 0xe7, - 0x39, 0x5d, 0xbc, 0xd4, 0x8e, 0x5b, 0xde, 0x40, 0x83, 0x72, 0xcc, 0x7d, - 0xba, 0xd6, 0x4f, 0x51, 0xad, 0xfb, 0x23, 0x01, 0x23, 0x9e, 0x02, 0xf4, - 0x3e, 0xdd, 0xaf, 0x86, 0xf6, 0x53, 0xdd, 0xb3, 0x97, 0x6b, 0xd2, 0xb4, - 0xea, 0xc0, 0x69, 0x79, 0x93, 0xba, 0xd5, 0x26, 0x48, 0x83, 0x1a, 0x24, - 0x0d, 0xa9, 0xaa, 0x26, 0x22, 0xb7, 0x1e, 0x1c, 0x30, 0x43, 0xf0, 0x08, - 0xf2, 0x5a, 0xe6, 0xea, 0xf6, 0x7f, 0xb0, 0x66, 0xae, 0x4d, 0x15, 0xe6, - 0x3a, 0xdc, 0x43, 0x1d, 0x3f, 0x46, 0x83, 0xd4, 0x3e, 0x73, 0x6f, 0x8f, - 0x38, 0x62, 0xed, 0x92, 0x02, 0x28, 0xfa, 0x7c, 0xc1, 0x00, 0x29, 0x33, - 0x95, 0x3d, 0x41, 0x50, 0xc8, 0x32, 0xcb, 0x80, 0x52, 0x60, 0xb2, 0xdb, - 0x32, 0x92, 0xca, 0x0f, 0x05, 0xa8, 0xc9, 0x78, 0x7f, 0x2f, 0x06, 0x37, - 0x65, 0x1c, 0x2f, 0x1a, 0x83, 0xf0, 0x3f, 0x6f, 0x94, 0xdd, 0x13, 0x4e, - 0x47, 0x8b, 0x68, 0x96, 0x48, 0x15, 0x3b, 0x20, 0x86, 0x44, 0xbf, 0x56, - 0xf2, 0xaf, 0x01, 0xbb, 0xb5, 0x96, 0xf3, 0x03, 0xda, 0x4c, 0xcc, 0x76, - 0x04, 0xb0, 0xe1, 0x93, 0x1b, 0x4b, 0xa4, 0xc3, 0x27, 0x6c, 0xc8, 0x45, - 0xbe, 0xf9, 0x13, 0x6a, 0xd3, 0xa9, 0x02, 0xcd, 0xc9, 0x17, 0xb2, 0x7c, - 0x80, 0x42, 0xe2, 0xd8, 0x1a, 0xe6, 0x72, 0x7f, 0x40, 0xf4, 0x28, 0x09, - 0x58, 0xb7, 0x69, 0xa0, 0x98, 0xab, 0x98, 0x76, 0xdf, 0x00, 0xc7, 0xb0, - 0x5e, 0xbb, 0xe6, 0x65, 0x5e, 0x65, 0x47, 0xa7, 0x88, 0x6b, 0x27, 0x66, - 0xfb, 0x43, 0x21, 0x43, 0x6c, 0x82, 0x44, 0xdf, 0xe2, 0xfd, 0x4a, 0x79, - 0x42, 0x49, 0xea, 0x47, 0x1b, 0x5c, 0xd6, 0x4c, 0x7e, 0x94, 0x5a, 0xff, - 0x89, 0x9f, 0x76, 0x4b, 0x40, 0x13, 0x83, 0x1a, 0x1c, 0xe7, 0x08, 0x2f, - 0x1c, 0x1e, 0xc8, 0xa3, 0xf7, 0x3c, 0xf7, 0x6d, 0x00, 0x31, 0x11, 0xba, - 0xed, 0x7f, 0x46, 0xa8, 0xb6, 0x2c, 0x75, 0x67, 0x19, 0x0d, 0x61, 0xae, - 0xc7, 0x0c, 0x83, 0xf1, 0xc0, 0xbc, 0x08, 0x77, 0xa5, 0xdd, 0xeb, 0x38, - 0xef, 0x7c, 0xe7, 0xd3, 0xfe, 0x48, 0x7a, 0x6f, 0x55, 0x83, 0xa4, 0xb8, - 0xd0, 0x81, 0xe7, 0xd2, 0xe7, 0x88, 0x0f, 0xc2, 0x57, 0x24, 0xc7, 0x6c, - 0xd2, 0xfd, 0x57, 0x4e, 0x97, 0x54, 0xd9, 0x7a, 0x5a, 0xb9, 0x48, 0xe6, - 0xbd, 0xf5, 0x47, 0x63, 0x9f, 0x4f, 0x34, 0x87, 0x20, 0x41, 0x29, 0x63, - 0xf9, 0x23, 0x9e, 0x25, 0xe5, 0xda, 0xe3, 0x66, 0x57, 0xac, 0xff, 0x50, - 0xe1, 0x78, 0x9c, 0xcf, 0x81, 0x6a, 0x8b, 0x3f, 0x36, 0x2d, 0x21, 0x0b, - 0x48, 0x2b, 0x57, 0xb6, 0x59, 0x54, 0xe0, 0x87, 0x79, 0x7d, 0x36, 0x06, - 0xad, 0x7d, 0x42, 0x56, 0x01, 0xd1, 0xc8, 0x97, 0x1f, 0xb1, 0x58, 0x7b, - 0x75, 0xe4, 0x77, 0xae, 0xc3, 0x67, 0x58, 0xb7, 0x03, 0x17, 0xc1, 0xe4, - 0xec, 0x66, 0x02, 0x4f, 0x5c, 0x02, 0xa9, 0x90, 0xed, 0x1b, 0x6b, 0x31, - 0x58, 0x59, 0x91, 0xb4, 0xfc, 0xa4, 0xfa, 0xc8, 0x15, 0xfe, 0xec, 0x77, - 0xc2, 0x40, 0xb3, 0xed, 0x2e, 0x0e, 0x56, 0x80, 0x63, 0x97, 0x5a, 0x91, - 0xca, 0x16, 0xda, 0x03, 0xb0, 0x2f, 0x7f, 0xce, 0x0f, 0x72, 0x40, 0xd3, - 0xd3, 0xc8, 0x33, 0x7b, 0xcb, 0x9a, 0x80, 0x24, 0x9c, 0x82, 0xac, 0x87, - 0x29, 0x9e, 0x60, 0x72, 0x22, 0x0f, 0x5a, 0x20, 0x61, 0xe2, 0xc8, 0xc8, - 0x0b, 0x1b, 0x01, 0x06, 0x2d, 0x25, 0x25, 0x7e, 0x73, 0xa4, 0x41, 0x1f, - 0x85, 0x34, 0xce, 0xf5, 0xf8, 0xa9, 0xf4, 0x05, 0x98, 0x9b, 0x6c, 0x51, - 0xc7, 0x74, 0xb7, 0x4b, 0x0d, 0x14, 0x7c, 0xdc, 0x17, 0xcc, 0xb9, 0xa6, - 0x93, 0xb3, 0xfd, 0x08, 0xc4, 0x21, 0xb2, 0xf1, 0x16, 0x11, 0xf8, 0x63, - 0x76, 0xd0, 0xce, 0x90, 0x83, 0x69, 0x3d, 0x69, 0xdf, 0x6a, 0xd1, 0xda, - 0xa1, 0x10, 0x17, 0x77, 0x03, 0xae, 0x4d, 0x66, 0x4f, 0xb4, 0x6f, 0xf6, - 0x0f, 0x3f, 0x2a, 0xc4, 0xc9, 0x88, 0xa0, 0x62, 0x87, 0x93, 0x18, 0xe6, - 0x5c, 0x9e, 0xa0, 0xc9, 0x43, 0x5a, 0xfd, 0x49, 0x67, 0x21, 0x7e, 0x83, - 0x97, 0xdc, 0xc4, 0xf4, 0xb5, 0xfa, 0xee, 0xd6, 0x3a, 0x5e, 0x1a, 0xb7, - 0x60, 0x9d, 0x9d, 0xac, 0x46, 0x2a, 0x54, 0xf0, 0xa5, 0x63, 0xdd, 0xbd, - 0xa2, 0xed, 0x99, 0x5a, 0x4f, 0xb7, 0x70, 0x93, 0x56, 0x53, 0x5b, 0xeb, - 0xa5, 0xf7, 0xdc, 0x16, 0x9e, 0x30, 0xdd, 0x7f, 0x21, 0xc0, 0xd3, 0x3c, - 0x9d, 0xd0, 0xb4, 0xef, 0x55, 0x8b, 0x45, 0x69, 0x26, 0xac, 0x46, 0xe1, - 0x1f, 0x7d, 0xd1, 0xb7, 0xe8, 0xf3, 0xa1, 0x7f, 0x4a, 0xcf, 0x2d, 0x2d, - 0xa2, 0x0f, 0x8c, 0x21, 0x13, 0xce, 0x47, 0xad, 0xbb, 0xbf, 0x0b, 0xeb, - 0xc6, 0x02, 0x35, 0x2e, 0x4e, 0xa4, 0x0f, 0x5a, 0xde, 0x9b, 0x0d, 0xaf, - 0xe4, 0xc2, 0x4a, 0xc5, 0x7a, 0x86, 0x2e, 0xca, 0xda, 0x74, 0x54, 0x3e, - 0x40, 0x17, 0x31, 0x8e, 0x8c, 0x46, 0xd3, 0xdf, 0x44, 0x0c, 0x77, 0x70, - 0x80, 0x09, 0xcf, 0x41, 0x1b, 0x69, 0x3e, 0x67, 0x36, 0xda, 0xad, 0x60, - 0x3a, 0x11, 0x2e, 0x06, 0xaf, 0xa6, 0xde, 0x89, 0x91, 0x75, 0x03, 0x78, - 0x4b, 0x6a, 0x3b, 0x48, 0x93, 0x9f, 0x7f, 0xb5, 0xe8, 0x82, 0x53, 0x77, - 0xba, 0x13, 0xe5, 0xde, 0xc4, 0xd4, 0xfa, 0xbb, 0xd8, 0x8e, 0x02, 0xc3, - 0x4b, 0xb7, 0x7f, 0x9d, 0x31, 0xc7, 0x9c, 0x5d, 0x1f, 0x8a, 0xd7, 0xb5, - 0x37, 0x9c, 0x5a, 0xe8, 0x29, 0x3a, 0xbf, 0x86, 0x1c, 0x16, 0x38, 0x89, - 0x4f, 0xac, 0x15, 0xeb, 0xaf, 0x9e, 0x27, 0x92, 0x91, 0xf8, 0x9c, 0xb3, - 0xed, 0xda, 0x07, 0xfe, 0x72, 0x0c, 0xf8, 0x72, 0x92, 0x85, 0x79, 0xb9, - 0xd1, 0x35, 0xf2, 0xf3, 0x76, 0xdf, 0xdc, 0xf6, 0x73, 0xb6, 0x56, 0x64, - 0x2d, 0x6f, 0x64, 0xf8, 0xb5, 0xa8, 0x08, 0x3a, 0xcd, 0x14, 0x2f, 0x5b, - 0xa1, 0x12, 0xa9, 0x96, 0x57, 0x90, 0xcc, 0xa6, 0x4f, 0x64, 0xe8, 0x0c, - 0xd6, 0x45, 0x1d, 0x28, 0x43, 0x88, 0xfc, 0xeb, 0x25, 0x25, 0xf2, 0x8e, - 0xf2, 0x45, 0x1c, 0x7a, 0x15, 0x36, 0x71, 0xaa, 0x43, 0x45, 0xd3, 0x06, - 0x24, 0xa2, 0x6c, 0x1f, 0xe8, 0x14, 0x1a, 0x4b, 0x58, 0x4c, 0x71, 0x84, - 0x8d, 0x6e, 0xb7, 0x25, 0x0d, 0x8e, 0xde, 0x74, 0xda, 0x8a, 0xeb, 0x9e, - 0x0c, 0x12, 0x63, 0x4b, 0x8b, 0x79, 0x88, 0xfa, 0x97, 0xcb, 0x4a, 0x5e, - 0x1c, 0x57, 0xf1, 0x2b, 0xa4, 0xe7, 0x6a, 0xd1, 0xf9, 0x28, 0x14, 0x5f, - 0xb9, 0x44, 0x62, 0x69, 0x17, 0xec, 0x28, 0xfb, 0x39, 0x35, 0x02, 0xdb, - 0x80, 0xb7, 0x1d, 0x2f, 0x7b, 0xb6, 0x90, 0x65, 0x96, 0x34, 0x92, 0x56, - 0x4f, 0xe7, 0x99, 0x5c, 0xa3, 0x5c, 0x36, 0xe5, 0x56, 0x72, 0x7b, 0xb1, - 0x73, 0x00, 0xe0, 0xbc, 0x85, 0x78, 0xf0, 0x02, 0x37, 0xf4, 0xcc, 0xba, - 0x76, 0x9b, 0x22, 0xa4, 0xf2, 0xd1, 0xa6, 0x31, 0x8a, 0x52, 0x01, 0xa0, - 0xcc, 0xeb, 0x7d, 0x37, 0x3d, 0x2d, 0x46, 0x37, 0xc3, 0xc2, 0x3a, 0x41, - 0xcb, 0x6f, 0xc5, 0x3d, 0xf7, 0x87, 0xff, 0x19, 0x78, 0xaa, 0x45, 0xcb, - 0xee, 0xb0, 0xf2, 0xa6, 0x2b, 0xb6, 0x93, 0x35, 0xf7, 0xdc, 0x01, 0xbd, - 0xa4, 0x40, 0xa0, 0xc3, 0x45, 0xca, 0xb5, 0xa1, 0xe3, 0x12, 0x38, 0xc3, - 0xf6, 0x64, 0x19, 0x9c, 0x72, 0x63, 0xf7, 0x53, 0xfc, 0xe9, 0xd8, 0x8e, - 0x5b, 0x97, 0x10, 0x9b, 0x5b, 0x1c, 0x50, 0x9d, 0x03, 0xa9, 0xe8, 0x23, - 0x14, 0x51, 0xbf, 0x3f, 0x86, 0x60, 0x17, 0xca, 0xc8, 0xc3, 0xf6, 0xfe, - 0x7d, 0xde, 0xce, 0x9f, 0xb4, 0xe7, 0xf1, 0xf9, 0x79, 0x87, 0xa3, 0x26, - 0x59, 0xd8, 0x6e, 0xe9, 0x52, 0x7c, 0x78, 0x27, 0xf6, 0x8e, 0xd1, 0x3f, - 0x03, 0x14, 0x09, 0xb3, 0xa5, 0x67, 0x20, 0xbb, 0x4f, 0x49, 0xed, 0x9c, - 0xa5, 0xec, 0x1e, 0xea, 0x74, 0x8e, 0x29, 0x3d, 0x68, 0x2d, 0x72, 0x14, - 0xf4, 0xf6, 0x31, 0x9b, 0x1a, 0x6f, 0xf9, 0xad, 0x8c, 0x65, 0xb6, 0x0f, - 0x8c, 0x94, 0x9a, 0x7f, 0x63, 0xb5, 0xd6, 0x40, 0x8b, 0x0c, 0x35, 0xd5, - 0xca, 0x72, 0x5f, 0x7f, 0xce, 0x7a, 0xa5, 0xc7, 0x52, 0x3f, 0xc7, 0xba, - 0x02, 0xcf, 0x06, 0x92, 0xdb, 0x10, 0x73, 0x28, 0x22, 0x18, 0xab, 0x9e, - 0x67, 0x87, 0x5f, 0x40, 0x51, 0xac, 0x9d, 0xff, 0x90, 0x0c, 0x04, 0x45, - 0xe5, 0x37, 0x8a, 0xd4, 0x20, 0x5f, 0x9f, 0x62, 0xe8, 0xa1, 0xcc, 0xb0, - 0x66, 0x9e, 0xf6, 0xa4, 0x0a, 0xb2, 0x65, 0x18, 0xfc, 0x95, 0x4e, 0xf0, - 0xc2, 0x93, 0xac, 0xac, 0x9f, 0xcd, 0x03, 0xf6, 0xe6, 0x6c, 0x50, 0x9a, - 0xc3, 0xc8, 0x1c, 0x7b, 0xb5, 0x3a, 0x8f, 0xc7, 0xe2, 0x9a, 0xf4, 0x65, - 0xe1, 0x2e, 0x78, 0xa3, 0x1d, 0xbb, 0x0e, 0x02, 0x1b, 0x6d, 0xb7, 0x81, - 0xc9, 0xc5, 0x85, 0x0a, 0x50, 0xa9, 0x0b, 0xe9, 0x07, 0x92, 0x8a, 0x42, - 0xe2, 0x09, 0x9a, 0xfd, 0xa2, 0x22, 0x57, 0x55, 0x40, 0x91, 0x37, 0x4a, - 0x9d, 0xc9, 0xcc, 0x82, 0x04, 0xf7, 0x12, 0xd4, 0x93, 0x9b, 0x3b, 0xbe, - 0x7c, 0x81, 0x92, 0x57, 0x56, 0xfb, 0xa9, 0x6c, 0xd1, 0x41, 0x1d, 0xfe, - 0xba, 0xc8, 0xce, 0xc7, 0x94, 0xef, 0xc0, 0x97, 0x09, 0x02, 0x73, 0x6d, - 0xa2, 0x1d, 0xa5, 0x9e, 0xe7, 0xc4, 0xac, 0x17, 0x4f, 0xfc, 0x25, 0x30, - 0x97, 0x79, 0x0c, 0x58, 0x10, 0x02, 0x6e, 0xb9, 0xea, 0x78, 0x60, 0xc0, - 0x83, 0x7b, 0x4b, 0x0d, 0xc8, 0xfa, 0x6c, 0x17, 0x7e, 0xaa, 0x25, 0x1a, - 0xa2, 0xaa, 0x23, 0x04, 0x2a, 0xc8, 0xf0, 0xe7, 0xba, 0xbf, 0xe4, 0xdd, - 0x7c, 0xb7, 0xbb, 0xc2, 0x91, 0x63, 0xb3, 0xfb, 0x55, 0xc2, 0xfd, 0xc9, - 0x93, 0x9b, 0x21, 0xb5, 0x79, 0xb3, 0x4e, 0xc0, 0xd5, 0x9d, 0xf0, 0xae, - 0xb2, 0xb7, 0xfb, 0xf5, 0x04, 0x14, 0xc8, 0x60, 0x81, 0x25, 0x73, 0xe4, - 0x42, 0x43, 0xfb, 0xeb, 0xa3, 0xb7, 0xa1, 0x44, 0x9e, 0xac, 0x37, 0xe2, - 0xd9, 0xe1, 0x28, 0x00, 0xbf, 0x6b, 0x82, 0x3e, 0x36, 0x8e, 0xe8, 0x7f, - 0x62, 0x9a, 0x32, 0x1e, 0x55, 0xf5, 0x66, 0x98, 0x7e, 0xe9, 0xf2, 0xd1, - 0xab, 0x19, 0x8c, 0xd1, 0x9e, 0xab, 0x99, 0x32, 0xfb, 0x78, 0x65, 0x86, - 0x06, 0x23, 0x86, 0xb1, 0x52, 0xad, 0xc4, 0x4a, 0x5a, 0x16, 0x7d, 0xc3, - 0x71, 0x62, 0xab, 0xa1, 0xc2, 0xa1, 0xc9, 0xdd, 0x29, 0x88, 0xc9, 0xec, - 0x4e, 0xe3, 0x81, 0xeb, 0x5b, 0xc2, 0xdf, 0x28, 0x24, 0xe4, 0xef, 0x72, - 0x67, 0x3c, 0xec, 0x47, 0x25, 0x10, 0x24, 0x4b, 0x05, 0xe2, 0x3b, 0xcc, - 0x96, 0x90, 0xc3, 0xdf, 0x9d, 0x19, 0xdf, 0x5b, 0x70, 0x93, 0xc2, 0x73, - 0xe6, 0xaf, 0x04, 0x61, 0x99, 0x71, 0x51, 0xa3, 0xeb, 0x5e, 0x3a, 0x98, - 0x7d, 0xf9, 0xe3, 0x31, 0x50, 0x27, 0x04, 0xec, 0x7b, 0xcc, 0xd6, 0x5a, - 0xa6, 0x55, 0x82, 0x38, 0xfc, 0xe6, 0x57, 0x6f, 0xa5, 0x2c, 0x6a, 0x6e, - 0xf8, 0x81, 0x97, 0xcf, 0xa0, 0xe4, 0xab, 0xd1, 0xd0, 0x2f, 0x86, 0x13, - 0x7b, 0x4e, 0x68, 0xd9, 0x83, 0x7d, 0xd7, 0x80, 0x89, 0x08, 0xb9, 0x99, - 0x95, 0xd1, 0x1e, 0xa5, 0x26, 0xa9, 0xf8, 0xdc, 0x5c, 0xa8, 0x1d, 0x2e, - 0x60, 0x1c, 0xbe, 0x75, 0xb2, 0x67, 0xb9, 0xc0, 0xc3, 0x80, 0xb8, 0x43, - 0x91, 0x28, 0xfa, 0xdb, 0x0f, 0xd0, 0x3c, 0x80, 0x1b, 0x68, 0xec, 0x9d, - 0x4a, 0x00, 0x70, 0x14, 0x30, 0x09, 0x4f, 0x7e, 0x2d, 0x97, 0x21, 0x31, - 0x78, 0xd5, 0xe5, 0xdf, 0xee, 0x84, 0xe1, 0xe7, 0x5d, 0xfa, 0x7f, 0xa7, - 0x27, 0x82, 0xa6, 0xb1, 0x46, 0x91, 0x50, 0x76, 0x3e, 0x7a, 0x88, 0xef, - 0x75, 0x9e, 0x44, 0x07, 0x96, 0x01, 0x73, 0xbe, 0x48, 0xcb, 0x7c, 0x85, - 0xd6, 0xde, 0xb8, 0xbb, 0x49, 0xdd, 0x84, 0x4e, 0xd4, 0xa9, 0x33, 0x04, - 0xda, 0xf2, 0x38, 0x51, 0x5c, 0x84, 0x82, 0xba, 0x79, 0x3a, 0x52, 0x92, - 0x3e, 0xa3, 0xa5, 0x01, 0xfa, 0x15, 0x04, 0x81, 0x9a, 0x85, 0x60, 0x6c, - 0x32, 0x49, 0x71, 0x9d, 0x7a, 0x2d, 0xdd, 0xf9, 0x0a, 0x65, 0x8d, 0x3d, - 0x08, 0xe6, 0x74, 0x23, 0xaa, 0x71, 0x61, 0x17, 0xe8, 0x08, 0x07, 0x92, - 0x46, 0x15, 0x4f, 0x9a, 0x2f, 0xb5, 0x71, 0xff, 0x3a, 0x20, 0x33, 0x34, - 0xc8, 0xf2, 0xe0, 0xaf, 0x76, 0x9f, 0x57, 0x6c, 0xc4, 0x03, 0xc8, 0x32, - 0x7d, 0x5b, 0xa8, 0xa2, 0xfe, 0xf9, 0xac, 0x64, 0xac, 0xeb, 0xc6, 0xac, - 0x1a, 0xf0, 0x43, 0x93, 0xfa, 0xb3, 0x75, 0x6f, 0x5a, 0x6e, 0xdd, 0xd4, - 0xe8, 0xef, 0xd0, 0xe1, 0x55, 0xd1, 0x80, 0xc7, 0x88, 0xf8, 0xde, 0x27, - 0x90, 0x94, 0xa6, 0xac, 0x45, 0x6d, 0x1b, 0x5f, 0x25, 0x99, 0xa5, 0xeb, - 0x98, 0xe1, 0x6b, 0xdf, 0xa3, 0xf5, 0x92, 0xb4, 0xc4, 0x9c, 0x26, 0x2b, - 0x9f, 0x9a, 0x13, 0x82, 0xad, 0x2a, 0x5c, 0x5e, 0xc9, 0x62, 0x8e, 0xe7, - 0x60, 0xcd, 0x9b, 0xee, 0xbf, 0xea, 0xa9, 0xea, 0x1b, 0x7b, 0xe6, 0x86, - 0x1d, 0xea, 0x58, 0x0a, 0x94, 0x86, 0xec, 0xf9, 0x20, 0x49, 0xe4, 0x28, - 0x78, 0x50, 0x5a, 0x66, 0x72, 0x30, 0xf8, 0xda, 0x06, 0x34, 0xda, 0x4b, - 0xb5, 0x1f, 0x4b, 0x89, 0x7e, 0x8c, 0x48, 0x6e, 0x56, 0xc1, 0x6f, 0xd8, - 0x8d, 0x86, 0xd7, 0xaf, 0x7e, 0xcb, 0x80, 0x8f, 0xa7, 0x64, 0xff, 0x23, - 0x73, 0x29, 0x2e, 0xe1, 0x11, 0x92, 0x13, 0x0e, 0x65, 0xb5, 0x49, 0xb8, - 0x67, 0x67, 0x07, 0x28, 0x03, 0xcc, 0x10, 0x0b, 0xff, 0xe1, 0xd4, 0x59, - 0x99, 0x10, 0x0a, 0xe0, 0x26, 0x9a, 0xe5, 0x0d, 0xf4, 0x8b, 0x99, 0xb2, - 0x8e, 0x78, 0x70, 0xfb, 0x35, 0xd1, 0x4c, 0x04, 0x6a, 0xd5, 0x6b, 0x40, - 0x85, 0x94, 0xdf, 0xf9, 0x5a, 0x7d, 0x28, 0x8e, 0x76, 0x94, 0xef, 0xed, - 0xc0, 0xdd, 0xed, 0xee, 0x48, 0x30, 0x1c, 0x76, 0xdf, 0xf0, 0xbe, 0xf2, - 0x45, 0xdb, 0xa7, 0x38, 0x92, 0x7a, 0x96, 0x16, 0x1a, 0x95, 0x8f, 0x35, - 0x27, 0x65, 0x42, 0x47, 0x0e, 0xd3, 0x0f, 0xe3, 0xb3, 0x4a, 0xd7, 0x38, - 0x1a, 0x8d, 0xe8, 0xee, 0x44, 0xfc, 0x10, 0x93, 0x18, 0x03, 0xdd, 0xf1, - 0x08, 0x7d, 0xf4, 0x3c, 0xc7, 0xfa, 0x35, 0x8d, 0x97, 0xb6, 0x50, 0x90, - 0x81, 0xfa, 0x16, 0x3f, 0xa3, 0x44, 0xfa, 0x49, 0x7c, 0x93, 0xb4, 0xfc, - 0x46, 0xe1, 0x96, 0x4f, 0x67, 0x8a, 0x5b, 0xc4, 0x6a, 0xf3, 0xf0, 0x2b, - 0xfa, 0x5a, 0x37, 0x42, 0xe9, 0xa6, 0x13, 0x00, 0x4f, 0xcc, 0x3c, 0x18, - 0x80, 0x98, 0xfe, 0xfb, 0xfc, 0xe6, 0xd2, 0x3f, 0xf6, 0xc1, 0x15, 0xda, - 0xe5, 0x3b, 0x56, 0x4c, 0x1c, 0x5d, 0x27, 0xc0, 0x9d, 0x8d, 0x70, 0x80, - 0x59, 0x2e, 0x41, 0x3f, 0xae, 0x16, 0x9f, 0x43, 0x43, 0xdb, 0xc1, 0x83, - 0x16, 0xed, 0x79, 0x28, 0xb4, 0x45, 0xa2, 0x4a, 0x7e, 0xbc, 0x85, 0xe3, - 0x04, 0x8c, 0xe8, 0xf3, 0x5e, 0x4e, 0xdd, 0x6a, 0x41, 0xd6, 0xa2, 0x43, - 0x16, 0x58, 0x2f, 0x4c, 0x63, 0xe7, 0x69, 0xfd, 0x95, 0xfb, 0xbc, 0x13, - 0x83, 0x13, 0x4a, 0xe1, 0xb4, 0x28, 0xc1, 0x25, 0xd7, 0x66, 0xf7, 0xf3, - 0x83, 0x9d, 0x93, 0x0b, 0x59, 0xdf, 0xeb, 0xa4, 0x66, 0xbf, 0x42, 0xd8, - 0x56, 0xe2, 0x71, 0x20, 0x20, 0xa3, 0xa9, 0xeb, 0x76, 0xdb, 0x8b, 0x7b, - 0x2d, 0xe0, 0xf6, 0xb7, 0x52, 0x1b, 0x51, 0x91, 0x29, 0x35, 0x01, 0xad, - 0xab, 0x12, 0xca, 0x61, 0x5f, 0xec, 0xe7, 0x90, 0x64, 0xce, 0xdb, 0xae, - 0x6a, 0x81, 0xc6, 0x6b, 0x5a, 0xf5, 0xc3, 0x12, 0x34, 0x5c, 0xbb, 0x5a, - 0xbb, 0xa6, 0xce, 0x75, 0x83, 0xab, 0x7d, 0xbe, 0x15, 0xf6, 0x0c, 0x13, - 0x46, 0x35, 0xcf, 0x9a, 0xd3, 0xce, 0x78, 0x1c, 0x1f, 0xe3, 0x24, 0xe9, - 0x92, 0xd8, 0xe6, 0x8f, 0x9f, 0x57, 0x26, 0xcc, 0x86, 0x3e, 0xb2, 0x12, - 0x5f, 0xf4, 0xe7, 0x1f, 0x00, 0x13, 0xcb, 0x23, 0xba, 0x23, 0x0f, 0xf5, - 0x19, 0xaa, 0x20, 0xb5, 0x59, 0x25, 0x18, 0x6b, 0xc6, 0x52, 0x38, 0xac, - 0x51, 0xe8, 0x21, 0x3f, 0xf4, 0x65, 0x6d, 0x40, 0xbc, 0x1a, 0x3b, 0x70, - 0xa7, 0xaa, 0x1b, 0x94, 0x23, 0xd9, 0x95, 0xf9, 0x06, 0x69, 0xe8, 0x6a, - 0x4a, 0x52, 0x87, 0xbe, 0x59, 0x70, 0x36, 0x14, 0x41, 0x99, 0x85, 0x0c, - 0xe8, 0x7e, 0x09, 0x47, 0x13, 0xbc, 0x9e, 0xe5, 0xc9, 0xe4, 0xd6, 0x74, - 0x7f, 0x8f, 0x20, 0xc1, 0x3f, 0xfe, 0xb4, 0x5b, 0x30, 0x07, 0xdd, 0x15, - 0x3f, 0x87, 0x98, 0x2b, 0xee, 0xb4, 0x7e, 0x14, 0x3a, 0xe2, 0x3e, 0x3c, - 0x69, 0xa1, 0x91, 0x8f, 0x49, 0xe7, 0x14, 0x9e, 0xce, 0x7a, 0x0b, 0xe8, - 0x8f, 0xa0, 0xa6, 0xe4, 0x64, 0xf9, 0xdb, 0x9d, 0x4d, 0xd7, 0x0c, 0xb5, - 0x1f, 0x29, 0x2d, 0xc1, 0xf2, 0x77, 0x61, 0xa4, 0xae, 0x8b, 0x1b, 0x1c, - 0xa5, 0x51, 0x8d, 0x4b, 0xcc, 0x2a, 0x94, 0x6e, 0xa7, 0x7f, 0x4f, 0x27, - 0xa4, 0xde, 0x6a, 0x0f, 0xdf, 0x5e, 0xee, 0xec, 0xe4, 0xe7, 0xae, 0x96, - 0x63, 0xbe, 0xa3, 0x08, 0xb6, 0x11, 0x3f, 0xcb, 0x38, 0x1e, 0xa6, 0x8a, - 0x72, 0x24, 0x6c, 0xd3, 0xc3, 0x6a, 0x4b, 0x63, 0x28, 0x78, 0x41, 0xba, - 0x69, 0xd9, 0xe6, 0xc4, 0xc1, 0x3c, 0x73, 0xf3, 0x09, 0x98, 0xcc, 0xcb, - 0x2e, 0x3c, 0x64, 0xf0, 0x0e, 0x80, 0x0a, 0x45, 0xbe, 0xbf, 0x83, 0x02, - 0xfb, 0x21, 0x1b, 0x2a, 0x9f, 0x5a, 0x96, 0xe7, 0xeb, 0x59, 0x22, 0xbc, - 0x2c, 0x26, 0x02, 0x9a, 0x29, 0x47, 0x7e, 0x4a, 0x8d, 0xbf, 0xe2, 0x48, - 0x94, 0xe2, 0x2a, 0xcd, 0x06, 0xec, 0x82, 0x40, 0x64, 0x13, 0x7c, 0xf1, - 0xf4, 0x4d, 0x9a, 0xc5, 0xc7, 0x34, 0x47, 0x58, 0xeb, 0x2d, 0xde, 0x62, - 0x6b, 0x25, 0x00, 0x20, 0x30, 0xc2, 0x80, 0x6c, 0xca, 0x94, 0x4b, 0x30, - 0xa1, 0x44, 0x41, 0xeb, 0x7b, 0xf6, 0x22, 0x4e, 0x18, 0xf0, 0xdb, 0xf5, - 0xed, 0x03, 0x57, 0x5a, 0xf2, 0x36, 0x7e, 0x06, 0x97, 0xcb, 0x5b, 0x3f, - 0xe6, 0xbe, 0xfd, 0xb6, 0xa7, 0xef, 0x2e, 0x5c, 0x83, 0x05, 0x6c, 0x6b, - 0x64, 0x89, 0xc3, 0x95, 0x5a, 0xf8, 0x2b, 0x8c, 0x2f, 0xb3, 0x5f, 0xf4, - 0x47, 0x6e, 0x88, 0xae, 0x5d, 0xfd, 0xfd, 0x06, 0xc1, 0x46, 0x40, 0x07, - 0x0c, 0x88, 0x58, 0x00, 0x8b, 0x40, 0xbf, 0x46, 0x22, 0x1b, 0xa1, 0xc7, - 0x6f, 0x24, 0x0f, 0x8c, 0xf4, 0x08, 0x73, 0xb1, 0xe1, 0x09, 0xbc, 0xcd, - 0x24, 0xbe, 0x69, 0x90, 0x3c, 0xfe, 0x48, 0xd2, 0x0a, 0xcd, 0x6f, 0x95, - 0xaa, 0x5a, 0xf6, 0xd5, 0x37, 0xe2, 0x47, 0x4d, 0x1d, 0xf6, 0x93, 0xed, - 0x41, 0x7b, 0x96, 0x0b, 0xab, 0xe5, 0x32, 0x4d, 0x1b, 0x97, 0xe3, 0xe9, - 0x79, 0xdb, 0x8a, 0x1c, 0x15, 0xd9, 0x94, 0x98, 0xcb, 0x1a, 0xdc, 0x83, - 0x75, 0xbc, 0x35, 0x15, 0xcc, 0xb4, 0xa6, 0x6d, 0xe1, 0x18, 0xbf, 0x5f, - 0x95, 0xa4, 0x2b, 0xe2, 0x60, 0xc9, 0x33, 0xfd, 0xad, 0xe5, 0xf5, 0xe1, - 0x29, 0xb8, 0x04, 0x34, 0x3e, 0x52, 0x74, 0x4b, 0x4b, 0x82, 0x65, 0xba, - 0xd8, 0x8a, 0x6c, 0x96, 0xb7, 0x77, 0xac, 0x1c, 0xd9, 0x63, 0x60, 0xe3, - 0xa7, 0xa4, 0x27, 0x92, 0xe1, 0xd8, 0xbe, 0x23, 0xba, 0xc6, 0xc0, 0x52, - 0x6e, 0x24, 0x8b, 0x51, 0x7b, 0x1f, 0x87, 0x4d, 0x6a, 0x44, 0x54, 0x2e, - 0xce, 0x90, 0x39, 0xc7, 0x92, 0x95, 0xd0, 0x6c, 0xa7, 0x5f, 0x7a, 0x35, - 0xea, 0xd4, 0x4a, 0x76, 0x3d, 0xfd, 0x49, 0xec, 0xaf, 0x42, 0x51, 0xbb, - 0x41, 0x7f, 0x90, 0x82, 0x11, 0xc3, 0x71, 0x61, 0xab, 0xcc, 0xf5, 0x9c, - 0xba, 0xb7, 0xbf, 0xd0, 0x04, 0x1e, 0xf9, 0x3a, 0xa0, 0xd0, 0x2a, 0x7f, - 0x9c, 0x92, 0x6a, 0x6e, 0x13, 0x8c, 0x07, 0xa1, 0x3a, 0x8b, 0x28, 0x3d, - 0xd1, 0x6c, 0x7c, 0xee, 0x64, 0xca, 0xcb, 0xa2, 0xc3, 0x92, 0xa6, 0xc2, - 0x46, 0x05, 0x98, 0x10, 0x17, 0xac, 0x76, 0xc9, 0x7f, 0xa5, 0xdd, 0x5c, - 0xde, 0x82, 0xa0, 0xc1, 0x23, 0x2a, 0x17, 0x03, 0x33, 0xe3, 0x8d, 0x24, - 0x9f, 0xf6, 0x5d, 0x18, 0x1b, 0x7f, 0x29, 0x48, 0xb5, 0x18, 0x21, 0xfa, - 0xf5, 0x21, 0xfa, 0x55, 0x01, 0x55, 0x41, 0xea, 0xca, 0xbe, 0xeb, 0x44, - 0x3c, 0x6c, 0x7f, 0x49, 0x26, 0x8e, 0x0a, 0x0d, 0xaa, 0x78, 0x2b, 0xaa, - 0x5e, 0x04, 0xec, 0xeb, 0x45, 0x0f, 0x96, 0xd9, 0xcd, 0xca, 0x66, 0x53, - 0x7b, 0x8e, 0x1b, 0xae, 0xb0, 0x34, 0x2f, 0xd9, 0x21, 0x33, 0x97, 0x28, - 0xfe, 0xbd, 0xf5, 0xbf, 0x6f, 0xcf, 0xb0, 0xc1, 0xf6, 0x46, 0x0d, 0x82, - 0xa4, 0x74, 0xb8, 0xdc, 0x38, 0x0c, 0xc4, 0xa4, 0xf8, 0xc2, 0xbc, 0x21, - 0xbd, 0x54, 0xca, 0x1a, 0x49, 0xa0, 0xa2, 0xfa, 0x63, 0x97, 0x61, 0x64, - 0xb2, 0x0a, 0x6d, 0x39, 0x8f, 0xea, 0x06, 0xd0, 0xdd, 0x4a, 0xc4, 0xef, - 0x7a, 0x8a, 0xe7, 0xbe, 0xfa, 0xa5, 0x2d, 0x57, 0xbf, 0x83, 0xf8, 0xec, - 0xa2, 0x21, 0x80, 0x7f, 0x52, 0xa8, 0x63, 0xe3, 0x1c, 0x51, 0x16, 0x07, - 0x82, 0xe8, 0xcd, 0xa7, 0x7b, 0x7e, 0xe1, 0xde, 0xa5, 0x87, 0x03, 0x3a, - 0xcd, 0xf3, 0x5c, 0x71, 0x04, 0x7e, 0x47, 0x15, 0xb2, 0x3e, 0x12, 0x65, - 0x19, 0x7f, 0x72, 0x69, 0xa2, 0x3f, 0x5b, 0x44, 0xca, 0x44, 0x12, 0x4f, - 0x31, 0x88, 0x65, 0x5d, 0x90, 0x74, 0x4b, 0x72, 0x13, 0xb0, 0x86, 0xca, - 0x37, 0xb5, 0xa4, 0x7f, 0x17, 0xc4, 0xa6, 0xd2, 0xef, 0x20, 0x1a, 0xf0, - 0x52, 0x4f, 0xcd, 0xff, 0x41, 0xa0, 0xd7, 0x70, 0xed, 0x65, 0x41, 0x6d, - 0x69, 0x7f, 0x14, 0x55, 0x74, 0x3e, 0x44, 0xc4, 0x09, 0xb5, 0x89, 0xd4, - 0x80, 0xf4, 0x60, 0xf4, 0xaa, 0x91, 0xa1, 0x84, 0x16, 0x89, 0xec, 0xdb, - 0x79, 0x86, 0xf4, 0xcb, 0x90, 0x9d, 0xe4, 0x06, 0x2a, 0x58, 0x6e, 0x67, - 0x1b, 0x0d, 0xc0, 0xb8, 0x43, 0x0e, 0xee, 0xb1, 0x09, 0x9a, 0xb7, 0x88, - 0x9f, 0xd2, 0x8d, 0x98, 0x8c, 0x2a, 0xc6, 0xcf, 0x8a, 0xe2, 0x81, 0x0d, - 0xa2, 0x66, 0x3c, 0xf5, 0xb5, 0x65, 0x1e, 0xf1, 0x3b, 0x53, 0x71, 0x77, - 0x27, 0xd9, 0xf6, 0xd5, 0x51, 0x30, 0xfe, 0xfa, 0x48, 0x48, 0xed, 0xbc, - 0x9a, 0xe5, 0xab, 0x1d, 0x06, 0x0b, 0x52, 0x8b, 0x81, 0x7e, 0xdd, 0xc1, - 0xf2, 0xe2, 0xb3, 0xf4, 0xa8, 0x30, 0xe7, 0x69, 0xfa, 0x7c, 0xb4, 0x98, - 0x36, 0x4b, 0x08, 0xcc, 0x75, 0x79, 0xc4, 0x7c, 0x84, 0x6b, 0xbf, 0xad, - 0x23, 0x2b, 0x17, 0xcb, 0x9c, 0xe6, 0xc6, 0xa7, 0xed, 0x48, 0x1a, 0x93, - 0xe2, 0x95, 0x0d, 0xf9, 0xc5, 0x89, 0x0f, 0xcd, 0xc7, 0xe6, 0xef, 0x02, - 0x15, 0x8b, 0x31, 0xaa, 0xf6, 0x20, 0x8e, 0xf1, 0x67, 0x5e, 0x6f, 0x7b, - 0x82, 0x29, 0x6f, 0x77, 0xea, 0x2c, 0x28, 0xa0, 0x79, 0xd7, 0x45, 0x94, - 0xf2, 0xaa, 0x76, 0xd9, 0x22, 0x6b, 0xcc, 0xe8, 0x94, 0xff, 0xf1, 0x2d, - 0xe8, 0x97, 0x2c, 0x45, 0xa1, 0xf8, 0xb9, 0xeb, 0xf8, 0xb3, 0x65, 0x8c, - 0x92, 0x95, 0xb1, 0xcf, 0x9f, 0xf2, 0x0f, 0x44, 0x94, 0x34, 0x46, 0x11, - 0x24, 0xba, 0xfd, 0x92, 0x84, 0x77, 0xfe, 0x00, 0x6a, 0xd0, 0x5c, 0xed, - 0xe7, 0xcb, 0xe1, 0x01, 0x79, 0xbb, 0x99, 0x1c, 0xc0, 0xbd, 0x54, 0x4b, - 0xe2, 0x44, 0x66, 0x03, 0xac, 0xe3, 0x4e, 0xba, 0x7d, 0xb6, 0x3d, 0xa3, - 0x9a, 0x79, 0x08, 0x5e, 0x1e, 0x74, 0x0b, 0x30, 0xee, 0x2e, 0xaa, 0xf3, - 0x1f, 0x25, 0xd6, 0x89, 0x33, 0xca, 0x34, 0xb7, 0x0c, 0x71, 0x60, 0x2c, - 0x3b, 0x61, 0xf0, 0x86, 0x2a, 0xc3, 0x87, 0xa7, 0x94, 0x4f, 0x2f, 0x84, - 0xdf, 0x66, 0xc0, 0xe0, 0x1d, 0xe7, 0xa2, 0xe6, 0x98, 0x48, 0xa0, 0x2f, - 0xeb, 0x81, 0x1c, 0x66, 0xd2, 0x50, 0x26, 0xdd, 0x2f, 0xda, 0xaf, 0x4d, - 0x76, 0x62, 0x17, 0xb8, 0x9a, 0x39, 0x6c, 0xfa, 0xb2, 0x94, 0xf3, 0xce, - 0x20, 0xe8, 0x7b, 0xa6, 0x3f, 0x3d, 0x19, 0x56, 0x34, 0xfd, 0x01, 0xed, - 0xd4, 0x05, 0xe2, 0x9c, 0x73, 0x3b, 0xce, 0x62, 0xea, 0x5f, 0x2b, 0x88, - 0x8d, 0x17, 0x04, 0xea, 0xcf, 0x31, 0xe6, 0xdd, 0x09, 0x22, 0xad, 0x45, - 0x48, 0x7a, 0x34, 0xc4, 0x8c, 0xfb, 0x7d, 0xd9, 0x48, 0x64, 0x4f, 0xd5, - 0x55, 0x99, 0x54, 0x9d, 0x67, 0x13, 0x20, 0x07, 0x98, 0x60, 0x78, 0xe8, - 0x49, 0xbe, 0xd6, 0x0f, 0x5b, 0x3f, 0x4a, 0x53, 0x27, 0x38, 0xab, 0x57, - 0x8b, 0xfd, 0x0c, 0x85, 0x64, 0xc3, 0xed, 0x9a, 0xcd, 0xd7, 0x2b, 0xee, - 0xf3, 0x8b, 0x6b, 0x23, 0x52, 0x1a, 0xe9, 0x8a, 0xc5, 0x61, 0xd5, 0xa4, - 0xe6, 0xef, 0xc0, 0xce, 0x03, 0x16, 0x1e, 0x80, 0xa2, 0x18, 0x77, 0x39, - 0x2b, 0x66, 0x50, 0xd7, 0xcd, 0x88, 0x3e, 0x5a, 0x7c, 0x44, 0x7b, 0x86, - 0x87, 0xe4, 0x15, 0x43, 0xb4, 0x78, 0x8d, 0x8b, 0xf9, 0x54, 0x55, 0xdf, - 0x13, 0x3f, 0x50, 0x4e, 0x51, 0x98, 0x15, 0x05, 0x0f, 0x68, 0xba, 0xd5, - 0x24, 0xda, 0xaa, 0x12, 0x2c, 0xee, 0x17, 0x1f, 0x0c, 0x11, 0x40, 0xe4, - 0x90, 0xc2, 0x1f, 0xd8, 0x5c, 0x44, 0xb5, 0x32, 0x55, 0xe3, 0xa7, 0xfd, - 0x72, 0x91, 0xb5, 0x29, 0x65, 0xbe, 0xfd, 0x89, 0xe6, 0x31, 0x5d, 0x25, - 0x60, 0x5e, 0xcf, 0x09, 0x30, 0x21, 0x36, 0x16, 0x0a, 0x8e, 0x56, 0xd6, - 0x77, 0x56, 0x6e, 0xdb, 0x64, 0xa3, 0x84, 0xd2, 0xb2, 0x1f, 0xe3, 0x16, - 0x9d, 0xb3, 0x36, 0xa5, 0xbe, 0x5c, 0xdd, 0x2a, 0xb8, 0x41, 0x4d, 0x9b, - 0x54, 0x49, 0x48, 0x6d, 0xd5, 0x6a, 0xaf, 0x25, 0xe4, 0xf0, 0x2f, 0x90, - 0x7d, 0x93, 0x88, 0xff, 0xb6, 0x02, 0xef, 0xe8, 0xfa, 0x01, 0xeb, 0x63, - 0x83, 0x1c, 0xa5, 0x04, 0x5c, 0xa1, 0x23, 0xbd, 0x91, 0xd4, 0x8e, 0xfa, - 0xf7, 0x10, 0xaa, 0x71, 0x03, 0xd6, 0x41, 0x84, 0x9d, 0x9a, 0xf9, 0x1a, - 0xe8, 0x13, 0xc8, 0x48, 0x63, 0x0b, 0x9f, 0x50, 0xd3, 0x3b, 0x8a, 0xa1, - 0x24, 0xe1, 0xbb, 0x70, 0x4c, 0xb7, 0xdc, 0xa7, 0x50, 0x7c, 0xa9, 0x10, - 0xdd, 0x9e, 0xc5, 0xe3, 0xd6, 0x23, 0xb5, 0xc9, 0x45, 0x61, 0x99, 0x4a, - 0xfd, 0xd8, 0x29, 0x75, 0x46, 0x78, 0xbf, 0x68, 0x2b, 0x69, 0x21, 0x9d, - 0x54, 0x75, 0xdd, 0x5c, 0xf5, 0xba, 0xe9, 0x5b, 0x9a, 0x4e, 0xd6, 0xf1, - 0xfa, 0x82, 0x51, 0xb7, 0x48, 0x26, 0x00, 0x6b, 0x87, 0x00, 0xad, 0x55, - 0x40, 0x04, 0x94, 0xf2, 0x13, 0x4b, 0x3b, 0xa5, 0x9b, 0x9c, 0xbe, 0xa6, - 0xc0, 0xb5, 0x45, 0xc9, 0x65, 0x9c, 0x0f, 0x0c, 0x90, 0x4c, 0x0a, 0x14, - 0x76, 0x1f, 0x61, 0x93, 0x20, 0xf7, 0xaf, 0xea, 0x6c, 0x2d, 0x74, 0x64, - 0x31, 0xce, 0x20, 0x22, 0x4e, 0x59, 0x46, 0x1f, 0xeb, 0x7f, 0xd7, 0x63, - 0xca, 0xb5, 0xd5, 0x90, 0x26, 0x58, 0x24, 0x8e, 0xd2, 0xbc, 0x78, 0x7d, - 0x34, 0x9d, 0x31, 0xde, 0x3e, 0x26, 0xaa, 0x50, 0xf0, 0xe3, 0xeb, 0xc1, - 0x63, 0x04, 0x33, 0xdd, 0x07, 0x8f, 0xe7, 0x40, 0x6d, 0x3e, 0xaf, 0x16, - 0xb8, 0xfb, 0xef, 0x06, 0x3a, 0x58, 0xf5, 0x9b, 0x32, 0x6a, 0x4a, 0xb7, - 0xb6, 0x5b, 0x81, 0x5c, 0xe2, 0xf6, 0xb7, 0xab, 0xc3, 0x9b, 0x00, 0x92, - 0xba, 0x06, 0xee, 0xdd, 0x2d, 0x66, 0x1e, 0x2c, 0x6e, 0xa6, 0x69, 0x8d, - 0x8f, 0x8b, 0x93, 0x3a, 0x48, 0x91, 0x09, 0xfe, 0xa1, 0x6c, 0xfb, 0x53, - 0x2c, 0x95, 0x84, 0x23, 0xcb, 0x32, 0xab, 0x35, 0xf4, 0xc0, 0x2f, 0xe3, - 0xb8, 0xaa, 0xc4, 0x5d, 0x84, 0x42, 0x44, 0xf5, 0xf7, 0x46, 0x29, 0x84, - 0x4a, 0xe7, 0xf3, 0x0c, 0xc3, 0xea, 0xb7, 0xa1, 0x61, 0x1e, 0xf3, 0x2f, - 0x58, 0xf2, 0xa9, 0xa6, 0x02, 0xe0, 0x89, 0x1c, 0x11, 0xfa, 0xb1, 0x7b, - 0xe6, 0x1b, 0x97, 0x79, 0xf6, 0xa8, 0x35, 0x40, 0xa2, 0xc4, 0xab, 0x98, - 0x79, 0x5f, 0x0b, 0xfc, 0xce, 0xe7, 0x9f, 0x88, 0xfc, 0x7b, 0xce, 0x08, - 0xc8, 0x77, 0xd4, 0x4b, 0x90, 0xe2, 0x9c, 0x78, 0x17, 0xd3, 0x38, 0xa5, - 0xd3, 0x9c, 0xce, 0xa1, 0xd5, 0x81, 0x1a, 0x1d, 0xd5, 0x7c, 0xa5, 0xd2, - 0xed, 0x08, 0xf1, 0x27, 0xf5, 0x61, 0x49, 0xaf, 0x05, 0xc9, 0x49, 0xfa, - 0x02, 0x93, 0xee, 0x82, 0x44, 0xc8, 0x9d, 0xb6, 0x8b, 0xe4, 0x93, 0xd5, - 0xd8, 0xb0, 0xce, 0xe8, 0x00, 0x56, 0x0b, 0x71, 0xc3, 0x6a, 0x22, 0x59, - 0x01, 0x56, 0x78, 0x44, 0x3a, 0x75, 0x3f, 0x4d, 0xf6, 0x64, 0x63, 0x5f, - 0x82, 0x39, 0xc7, 0x6c, 0x1c, 0x98, 0x2d, 0x87, 0xd8, 0x3c, 0x28, 0x37, - 0x67, 0x62, 0x20, 0x73, 0xe3, 0x6e, 0x9a, 0xe9, 0xa7, 0xc8, 0x53, 0x8d, - 0x7b, 0x1e, 0x0c, 0x50, 0xdd, 0xc4, 0xa0, 0xaf, 0x4b, 0x53, 0x76, 0xe0, - 0x75, 0x9a, 0x97, 0xa9, 0xc1, 0x98, 0xeb, 0x8f, 0xd4, 0x49, 0xeb, 0xf2, - 0x09, 0x8a, 0xe0, 0xf3, 0xcb, 0x7a, 0xf8, 0x50, 0x93, 0x44, 0x66, 0xeb, - 0x6b, 0xcf, 0x6e, 0x61, 0xe6, 0x3b, 0xe4, 0x4d, 0xce, 0x09, 0x34, 0x75, - 0x61, 0x10, 0x42, 0xcd, 0x9d, 0xf9, 0x99, 0x6a, 0xa7, 0x5e, 0xc3, 0x14, - 0x8d, 0x79, 0xc0, 0x7c, 0xfe, 0xe5, 0x42, 0x3b, 0x71, 0x2f, 0x49, 0x46, - 0xe5, 0x37, 0xe3, 0x1a, 0xbb, 0xa7, 0x0e, 0x12, 0xb0, 0xfb, 0xae, 0x84, - 0x79, 0x6f, 0x2a, 0x84, 0xbb, 0x8c, 0x14, 0x30, 0xc6, 0xda, 0xe8, 0x73, - 0x58, 0xc9, 0xdf, 0x6e, 0x56, 0x38, 0x68, 0x11, 0x8c, 0x8a, 0x2a, 0x61, - 0xaf, 0x93, 0x99, 0xaf, 0xb1, 0x98, 0x01, 0xde, 0xc5, 0xf4, 0x10, 0x54, - 0xba, 0x04, 0x9f, 0x12, 0x72, 0x83, 0x1c, 0x74, 0xc6, 0xfb, 0x33, 0xbd, - 0xfd, 0xc7, 0x6f, 0x66, 0xd5, 0x96, 0xdb, 0xf2, 0x73, 0x7d, 0x40, 0x87, - 0x5f, 0x72, 0x91, 0xae, 0xd4, 0x12, 0x6d, 0xee, 0x70, 0xf8, 0x6a, 0xfa, - 0xb8, 0x9b, 0x61, 0xb3, 0xc2, 0x5f, 0xc6, 0x19, 0xf5, 0x0f, 0xb6, 0x78, - 0xb0, 0x25, 0x7e, 0x07, 0x3a, 0x45, 0xaa, 0x89, 0x60, 0xc9, 0xf6, 0xf5, - 0x9d, 0xea, 0x7d, 0xb9, 0xa3, 0x58, 0x51, 0xe8, 0xb6, 0xb1, 0x19, 0x90, - 0x0f, 0xf2, 0x2b, 0x67, 0xe7, 0x15, 0xab, 0xc2, 0x73, 0x19, 0x8c, 0xf2, - 0xf2, 0x30, 0xb0, 0x61, 0x44, 0xae, 0x8b, 0x55, 0xc9, 0x77, 0x64, 0xb4, - 0x53, 0xef, 0x6a, 0xd3, 0x78, 0x72, 0x9a, 0xd1, 0x6c, 0x4b, 0xcf, 0x02, - 0x62, 0xcf, 0x9e, 0xe9, 0x07, 0xb0, 0xb9, 0xa3, 0x2c, 0x81, 0xe9, 0xa5, - 0x23, 0xa6, 0xa5, 0x75, 0x85, 0xa1, 0xba, 0xee, 0xb6, 0xef, 0x1b, 0x96, - 0x7e, 0xb2, 0x80, 0x31, 0x43, 0xd5, 0xe0, 0x2d, 0x47, 0xe1, 0xe1, 0xc0, - 0xd7, 0xd0, 0xe6, 0xfc, 0x75, 0xa3, 0xc9, 0x4b, 0x97, 0x6d, 0xf8, 0xf9, - 0xb0, 0x98, 0x5c, 0x91, 0x6c, 0x73, 0xd2, 0x74, 0x98, 0x67, 0x2b, 0x6b, - 0x40, 0x12, 0x98, 0xfa, 0x4b, 0xf5, 0xb4, 0x74, 0x13, 0xd0, 0xe7, 0xda, - 0x2f, 0x2d, 0xbf, 0x13, 0x34, 0xc6, 0xbf, 0x0e, 0x42, 0x17, 0xa6, 0x7a, - 0xb5, 0x90, 0x8e, 0x9b, 0x82, 0xc8, 0x05, 0xf6, 0x64, 0x6a, 0x32, 0x5a, - 0xfe, 0xce, 0x90, 0x4c, 0x38, 0xd6, 0xd4, 0x6e, 0xa6, 0xf9, 0x7e, 0x5b, - 0x8e, 0x2d, 0xbc, 0x8e, 0xb0, 0x53, 0x02, 0x17, 0x71, 0x92, 0x41, 0x05, - 0x47, 0x2c, 0x98, 0xd2, 0xbe, 0xb7, 0xfb, 0x56, 0x47, 0xbf, 0x02, 0xee, - 0x1f, 0x94, 0xdc, 0xd1, 0x6e, 0x55, 0xd0, 0x66, 0x59, 0x5d, 0x80, 0xfd, - 0xdd, 0xf2, 0xa7, 0x25, 0x72, 0x53, 0x8d, 0xf6, 0xf4, 0x41, 0xd2, 0xd5, - 0x83, 0x69, 0xaa, 0xbf, 0xe2, 0x4a, 0x2b, 0x77, 0x12, 0xc1, 0xf1, 0x62, - 0xd6, 0x81, 0xba, 0x12, 0x81, 0x0b, 0x37, 0xaf, 0xa0, 0xea, 0xc9, 0x51, - 0x82, 0xf9, 0xeb, 0xf1, 0x0f, 0x97, 0x14, 0x3b, 0x9f, 0x31, 0x7f, 0x7e, - 0xb7, 0xe6, 0xc4, 0xd3, 0x0c, 0x13, 0x4e, 0x7d, 0x96, 0x14, 0xf9, 0xc0, - 0x21, 0x54, 0x47, 0x86, 0xfb, 0xb1, 0x04, 0xc0, 0xe2, 0xd6, 0x4c, 0x04, - 0x25, 0x2e, 0x0f, 0xde, 0x6c, 0x88, 0xc1, 0x32, 0x3c, 0x28, 0x83, 0xe3, - 0x66, 0x39, 0x49, 0x9e, 0x1b, 0x4e, 0x27, 0xad, 0x92, 0x80, 0x03, 0x36, - 0x16, 0xfc, 0x52, 0x3f, 0x98, 0xc2, 0xd5, 0xda, 0x55, 0x12, 0x15, 0x58, - 0xe3, 0x67, 0x6c, 0xdf, 0x94, 0x34, 0x75, 0xb4, 0xcd, 0x3f, 0xba, 0xf7, - 0xb7, 0xd1, 0xfd, 0xa2, 0x03, 0x15, 0x69, 0xd1, 0x07, 0x50, 0xc9, 0xca, - 0x2f, 0xe3, 0xd6, 0x17, 0x7f, 0xe6, 0xd7, 0x70, 0x61, 0x60, 0xa6, 0xbb, - 0x50, 0x5c, 0x7f, 0x4a, 0xfe, 0xca, 0x3c, 0xd1, 0xb6, 0x2b, 0x1c, 0xe1, - 0xe4, 0xb4, 0xf5, 0xbb, 0x47, 0xe0, 0x6f, 0x24, 0x13, 0x6c, 0x1b, 0x4d, - 0xd8, 0x9d, 0x3e, 0x69, 0xba, 0x69, 0x66, 0x29, 0x86, 0x25, 0x16, 0xb2, - 0xf7, 0x05, 0x08, 0xc8, 0xbb, 0xaa, 0xf8, 0xc2, 0x37, 0x8d, 0xa8, 0x8e, - 0x74, 0x05, 0x82, 0x5e, 0x93, 0x54, 0x62, 0xea, 0x5b, 0x72, 0x68, 0x97, - 0xbe, 0xf1, 0x40, 0xfd, 0xdd, 0x1f, 0xf7, 0x7d, 0x87, 0xea, 0x9c, 0x84, - 0x20, 0xef, 0x97, 0x29, 0x87, 0x78, 0x69, 0xb9, 0x34, 0xbb, 0x21, 0xb5, - 0xaf, 0xc3, 0x2c, 0xf9, 0xdb, 0x5c, 0x83, 0x95, 0xc2, 0x1b, 0xc1, 0xd7, - 0x54, 0xe4, 0xbb, 0xd8, 0xbd, 0x94, 0x34, 0xbc, 0x62, 0xd9, 0x19, 0x17, - 0x93, 0x6c, 0xd3, 0x32, 0x49, 0x2e, 0xf3, 0xb3, 0x14, 0x08, 0xf4, 0x0d, - 0x14, 0x8c, 0x46, 0xc6, 0x1c, 0x54, 0x4f, 0x51, 0xea, 0xa1, 0x21, 0xbc, - 0x4d, 0x9f, 0xa1, 0xed, 0x77, 0x80, 0xf8, 0x59, 0xd6, 0xb0, 0xf0, 0x9b, - 0x9b, 0x60, 0xea, 0xca, 0xe8, 0xd4, 0x75, 0x8b, 0x89, 0x27, 0xfd, 0x98, - 0x6a, 0x42, 0xc5, 0x8a, 0x14, 0x0e, 0x9d, 0xa5, 0x58, 0x25, 0xa7, 0x09, - 0xe8, 0x14, 0xe1, 0x7e, 0x73, 0x0b, 0x2d, 0xae, 0xd8, 0x14, 0xec, 0x93, - 0x91, 0xf6, 0xde, 0xc4, 0x27, 0x5d, 0x88, 0xfa, 0x62, 0xd6, 0x3e, 0x4a, - 0xe9, 0x44, 0x03, 0xfc, 0x48, 0x4e, 0xa4, 0x62, 0x6a, 0x30, 0x02, 0xd5, - 0xce, 0x18, 0xc9, 0xb0, 0x43, 0xbe, 0x0c, 0xfe, 0x39, 0xa8, 0x71, 0x7e, - 0xf9, 0x16, 0xba, 0x4c, 0x51, 0x0b, 0xdd, 0x37, 0xe4, 0x3d, 0xd4, 0xd6, - 0x09, 0x2a, 0xb1, 0x96, 0x2b, 0x31, 0x17, 0x22, 0xcd, 0xfc, 0x28, 0x05, - 0x3a, 0x4b, 0x0b, 0x82, 0x19, 0xca, 0x86, 0xe6, 0x58, 0xac, 0xb1, 0x75, - 0xe3, 0x3d, 0x7c, 0x30, 0xf4, 0xa3, 0x7c, 0x9d, 0x9f, 0x27, 0xb7, 0x14, - 0x5c, 0xe5, 0xb1, 0xbb, 0xa2, 0xea, 0x87, 0x83, 0x51, 0x06, 0x84, 0xa4, - 0xa2, 0xd4, 0x0d, 0xb9, 0x6f, 0xa6, 0x75, 0xb8, 0xbf, 0x3b, 0xf2, 0xb5, - 0xaf, 0xc6, 0x54, 0x42, 0xba, 0x46, 0x67, 0x99, 0xde, 0xe8, 0x8c, 0x34, - 0x85, 0x5e, 0x78, 0x63, 0xcd, 0x55, 0xe4, 0x22, 0x23, 0x0d, 0x0a, 0x08, - 0xd0, 0xae, 0x86, 0xf7, 0x76, 0x2d, 0x06, 0x8e, 0x86, 0xbc, 0xea, 0x69, - 0xce, 0x95, 0x9f, 0x81, 0x54, 0x53, 0x3a, 0x2b, 0x57, 0x3b, 0xb5, 0xd8, - 0x02, 0x4e, 0x1c, 0x89, 0xf4, 0x53, 0xda, 0xfa, 0x16, 0xee, 0x48, 0x05, - 0xe2, 0x07, 0x9a, 0x6f, 0xb2, 0x55, 0xfb, 0x34, 0x58, 0x96, 0x93, 0x4f, - 0xc4, 0xd5, 0xe1, 0x24, 0xb2, 0xd4, 0x1b, 0xc2, 0x18, 0xd0, 0x22, 0x2d, - 0x12, 0x9f, 0xfc, 0x53, 0x2f, 0x27, 0xc9, 0x76, 0x50, 0xc0, 0x5d, 0x95, - 0x03, 0xa4, 0x84, 0x45, 0x9d, 0x2f, 0x42, 0xaa, 0x4d, 0x2a, 0xa6, 0xf3, - 0xaf, 0x27, 0x01, 0xf1, 0xba, 0x3e, 0x61, 0xda, 0x0c, 0x70, 0x3b, 0xca, - 0xb9, 0x23, 0x57, 0x30, 0x1e, 0x8c, 0xa0, 0x40, 0x5e, 0xa8, 0xea, 0x16, - 0x06, 0xbc, 0x65, 0x09, 0x3a, 0x1f, 0x49, 0x87, 0x31, 0x98, 0xb7, 0x84, - 0x44, 0x25, 0xb2, 0x3c, 0xf6, 0xb7, 0x9b, 0x37, 0x90, 0x4e, 0x42, 0x63, - 0x02, 0xc8, 0x1e, 0x5a, 0xb0, 0x81, 0xf2, 0xbc, 0x45, 0xc8, 0x59, 0x8f, - 0xb2, 0x41, 0xab, 0x7e, 0x27, 0x00, 0x22, 0xc6, 0x38, 0x3d, 0x20, 0x7d, - 0x18, 0x2a, 0xa3, 0x6b, 0x96, 0xac, 0x17, 0x26, 0x8e, 0xdd, 0xb9, 0xcf, - 0xdf, 0xc7, 0x5b, 0x70, 0xf3, 0x64, 0x0a, 0x7c, 0xe6, 0xbf, 0x98, 0xfd, - 0x90, 0x43, 0x97, 0xe8, 0xef, 0xc0, 0x50, 0xf2, 0x37, 0xcf, 0x1c, 0xf8, - 0x13, 0xeb, 0x9e, 0x33, 0x4e, 0xa1, 0xa6, 0xbd, 0x03, 0x37, 0x8c, 0xeb, - 0x67, 0xfb, 0xf5, 0x6b, 0x65, 0xab, 0x51, 0x62, 0xb9, 0x3a, 0x9e, 0x61, - 0xde, 0xe6, 0x78, 0x5e, 0xc4, 0x71, 0x14, 0x7f, 0x4c, 0x1c, 0xa9, 0xbd, - 0x14, 0xf0, 0xd4, 0x82, 0xb7, 0x05, 0x41, 0x52, 0x47, 0xe6, 0x82, 0x79, - 0xa8, 0xeb, 0x5d, 0x47, 0xea, 0x7f, 0x5a, 0xa7, 0x8a, 0x95, 0x10, 0x90, - 0x8f, 0xaa, 0x3f, 0x9a, 0x50, 0x8c, 0x46, 0x1c, 0xee, 0x82, 0x18, 0x4e, - 0xbc, 0x63, 0x5d, 0x65, 0x6e, 0x4c, 0x18, 0xd1, 0xce, 0x7a, 0x45, 0xf6, - 0xa2, 0x9c, 0x69, 0x85, 0xf6, 0xc4, 0x8b, 0xe3, 0x49, 0x87, 0x0d, 0x19, - 0x80, 0x41, 0x6f, 0xc5, 0x87, 0xb1, 0x59, 0x00, 0x97, 0x38, 0xe6, 0x4b, - 0x13, 0x14, 0x84, 0xfe, 0x1c, 0xd4, 0x27, 0xc8, 0xed, 0x5d, 0xbf, 0xa1, - 0xa1, 0xe4, 0xa5, 0xcf, 0x2a, 0x1e, 0x40, 0x2b, 0x0e, 0xdb, 0x49, 0x81, - 0x9d, 0xa8, 0xc3, 0x88, 0xc8, 0x3b, 0xac, 0x7a, 0x87, 0x67, 0x67, 0x12, - 0x32, 0x6b, 0x5b, 0x17, 0x28, 0x5b, 0x8c, 0x75, 0x41, 0x54, 0xec, 0x33, - 0xd1, 0x9a, 0x8c, 0xf5, 0x81, 0x9c, 0xcf, 0x6f, 0x8f, 0x0e, 0xd5, 0x66, - 0x23, 0xdd, 0x91, 0xfb, 0xd4, 0x56, 0xfc, 0x1f, 0x98, 0x1e, 0x3b, 0xe8, - 0xda, 0xbc, 0x73, 0xed, 0x27, 0x82, 0x4b, 0xdd, 0x2f, 0xa7, 0x10, 0xfb, - 0xed, 0x94, 0x65, 0x8d, 0x6d, 0xdb, 0x23, 0x71, 0xf6, 0x70, 0xd1, 0x44, - 0x60, 0x91, 0xc4, 0xbe, 0xbf, 0x09, 0x2e, 0xdb, 0xc4, 0xf2, 0x39, 0x6c, - 0x7c, 0x4b, 0x42, 0x1a, 0x81, 0x89, 0xc0, 0xab, 0xa5, 0x0f, 0x53, 0x37, - 0xb5, 0x02, 0xd0, 0x2d, 0x90, 0x9a, 0xae, 0x01, 0x7e, 0xf2, 0xd8, 0xb0, - 0xa5, 0xfa, 0x63, 0x23, 0x40, 0x6d, 0x08, 0x15, 0x1c, 0x90, 0x9d, 0x2a, - 0x5d, 0x0b, 0xd3, 0x09, 0x29, 0x23, 0xcb, 0xfa, 0x8f, 0xb5, 0xfb, 0x93, - 0xed, 0x51, 0x7c, 0xa7, 0x4c, 0xc5, 0xdb, 0x27, 0x68, 0xfe, 0x91, 0x21, - 0xcc, 0xda, 0x1e, 0x51, 0xa2, 0x07, 0xbb, 0xa4, 0x2d, 0xd5, 0x7d, 0xe5, - 0x2f, 0x47, 0xbb, 0xb8, 0xff, 0x15, 0xdd, 0x42, 0xc9, 0x31, 0xe3, 0x37, - 0xec, 0xd1, 0x0c, 0x1f, 0x3a, 0xf0, 0xeb, 0xc3, 0x50, 0xe0, 0x0d, 0x83, - 0x19, 0xc9, 0x77, 0x18, 0xe6, 0x79, 0x25, 0x53, 0xe9, 0xbb, 0x6a, 0xd3, - 0x6a, 0x82, 0xf2, 0xde, 0xdf, 0x96, 0x8d, 0xff, 0x68, 0x46, 0x7b, 0x3f, - 0x89, 0x55, 0x78, 0x14, 0xc1, 0x53, 0x16, 0xaf, 0x6c, 0x20, 0x5a, 0x40, - 0x95, 0x93, 0x0d, 0xd3, 0xf1, 0x01, 0xfa, 0xec, 0xe0, 0x5d, 0x27, 0x7a, - 0xf8, 0xef, 0xbd, 0x85, 0xeb, 0x30, 0x1a, 0x11, 0xb2, 0xab, 0x34, 0x20, - 0x4f, 0x60, 0x3b, 0x88, 0xda, 0x06, 0x4e, 0xc6, 0xd2, 0x67, 0x2a, 0x3e, - 0x7c, 0x73, 0xbe, 0x61, 0xc4, 0x3c, 0xf5, 0x90, 0x12, 0x69, 0x41, 0xa9, - 0x23, 0x9f, 0x1e, 0xde, 0x09, 0x09, 0x32, 0xdc, 0xe8, 0x87, 0x31, 0x8a, - 0x98, 0x51, 0x9c, 0xe8, 0x44, 0x57, 0x10, 0x9d, 0x2e, 0x8a, 0xf9, 0x4d, - 0xe3, 0x33, 0xf5, 0xb1, 0xb9, 0x41, 0xbb, 0x98, 0xa2, 0x1e, 0x83, 0x38, - 0x4b, 0xd1, 0x30, 0xcd, 0x3c, 0x9a, 0x45, 0x34, 0x0b, 0x3f, 0x37, 0x05, - 0x40, 0x4a, 0x93, 0xde, 0x7b, 0x82, 0x09, 0xf0, 0x96, 0x6e, 0x23, 0x44, - 0x9f, 0x13, 0xac, 0x6a, 0xbe, 0xe5, 0x83, 0xec, 0x53, 0x24, 0x3c, 0x98, - 0x71, 0x1a, 0xea, 0x48, 0xcf, 0x39, 0x5a, 0xfa, 0x4e, 0x3a, 0x62, 0x9a, - 0x68, 0xfb, 0x33, 0x07, 0xd0, 0x1b, 0x45, 0x17, 0x7a, 0x46, 0x37, 0x99, - 0x3d, 0x3c, 0x91, 0x12, 0x3b, 0x06, 0x9d, 0x4a, 0xcf, 0xdb, 0x0f, 0x78, - 0x17, 0xab, 0x2f, 0x1d, 0x5e, 0xcd, 0x31, 0xba, 0xae, 0x58, 0x18, 0x4d, - 0x49, 0x9d, 0xca, 0xd1, 0x56, 0x69, 0x92, 0xc9, 0x1d, 0x69, 0xbf, 0xac, - 0x12, 0xb5, 0xfb, 0x37, 0x31, 0x4f, 0x75, 0x6f, 0x15, 0x05, 0x4a, 0x9f, - 0x8c, 0x1d, 0xfa, 0x4e, 0xd6, 0x73, 0x85, 0x84, 0x54, 0xc4, 0x96, 0xcf, - 0x9f, 0x2f, 0x2d, 0x86, 0x37, 0x91, 0x06, 0x56, 0x75, 0x0e, 0x7f, 0xa9, - 0xc1, 0x12, 0x0e, 0xe7, 0xb0, 0x9f, 0x02, 0xfe, 0xf4, 0x5e, 0x7b, 0x91, - 0x0d, 0x89, 0x91, 0xa2, 0xaa, 0xb5, 0x67, 0x51, 0xbf, 0x8e, 0x65, 0xb6, - 0xb9, 0x30, 0xf6, 0x75, 0x19, 0x55, 0x26, 0x4d, 0xcf, 0x80, 0xf6, 0xe9, - 0x79, 0xf3, 0xb5, 0x53, 0x06, 0x8b, 0x8c, 0x27, 0x25, 0xab, 0xaa, 0xda, - 0x0f, 0x04, 0x46, 0x8d, 0x39, 0x26, 0xf5, 0x1e, 0x06, 0xac, 0x0f, 0x81, - 0x6a, 0xe6, 0xdf, 0x63, 0x03, 0x2e, 0xf6, 0xe4, 0x27, 0xd1, 0x9a, 0x82, - 0xe2, 0xf2, 0xaa, 0x60, 0xaa, 0x21, 0xd1, 0xac, 0x4c, 0x9b, 0x24, 0x4b, - 0xfb, 0x7b, 0xad, 0x81, 0x9c, 0x37, 0xa0, 0xa7, 0x19, 0x91, 0x21, 0xc2, - 0x29, 0x4c, 0x16, 0xa5, 0x11, 0xcb, 0xe1, 0xaf, 0xb8, 0x8b, 0x0e, 0xdc, - 0x27, 0xa4, 0x6a, 0xa1, 0x3c, 0x8c, 0xd1, 0xf9, 0x9e, 0x38, 0xf4, 0x26, - 0xaa, 0x54, 0xc0, 0xf6, 0x76, 0x91, 0xd1, 0x0e, 0x28, 0x6d, 0xff, 0xb8, - 0x0f, 0x5a, 0x08, 0xdd, 0x39, 0x41, 0x68, 0xe2, 0xae, 0x8a, 0xdd, 0xab, - 0x3f, 0x68, 0x03, 0x72, 0x55, 0xdb, 0x72, 0xb6, 0xef, 0x62, 0x57, 0x5e, - 0x81, 0x15, 0x46, 0x2f, 0x42, 0x77, 0x04, 0x35, 0xf8, 0x70, 0x4a, 0x94, - 0x3d, 0xf4, 0x45, 0xcd, 0xeb, 0xa3, 0x5e, 0xa6, 0xbd, 0x1d, 0x34, 0x02, - 0x9a, 0x2d, 0x32, 0x2f, 0x76, 0x3c, 0x12, 0xd4, 0xbb, 0x26, 0x67, 0x45, - 0x72, 0x60, 0xbf, 0xb8, 0xb6, 0x7b, 0x18, 0x15, 0xf9, 0x51, 0xee, 0xb3, - 0x20, 0xa5, 0x27, 0xe5, 0x2f, 0x42, 0xec, 0xf6, 0x6d, 0xa4, 0xdf, 0x74, - 0xc0, 0x9e, 0xac, 0x4c, 0xaf, 0x92, 0xec, 0x3e, 0x39, 0x0d, 0x14, 0x44, - 0x3f, 0x14, 0x82, 0x21, 0x7c, 0x2c, 0x6e, 0x51, 0x78, 0x31, 0xeb, 0x54, - 0xa0, 0x9f, 0x4a, 0x26, 0xcd, 0x6b, 0x13, 0x76, 0xc0, 0x0c, 0x24, 0x37, - 0xcb, 0xdd, 0xbc, 0x5f, 0x7c, 0x6d, 0x2e, 0x9e, 0xf3, 0x49, 0xe0, 0xb4, - 0x58, 0xc5, 0x6b, 0xfb, 0x9e, 0x77, 0xfe, 0xd8, 0x44, 0x00, 0x04, 0xc0, - 0x6a, 0xee, 0x7c, 0x28, 0x5d, 0x83, 0xa6, 0x90, 0xd9, 0x2b, 0x31, 0x67, - 0x80, 0x13, 0x5b, 0x2b, 0xd6, 0x69, 0x91, 0x5f, 0x11, 0x68, 0xd9, 0x82, - 0x1c, 0x74, 0x41, 0xe5, 0xf9, 0x33, 0xd5, 0x3c, 0x0a, 0x62, 0x7e, 0xa5, - 0x06, 0xa9, 0x91, 0x91, 0xd8, 0x2b, 0x1c, 0xe4, 0x1b, 0xda, 0x00, 0xb3, - 0xb6, 0x83, 0xd1, 0x7a, 0x96, 0x53, 0x17, 0xdd, 0x83, 0xfd, 0x5a, 0x76, - 0xf9, 0xe5, 0x81, 0x11, 0xc1, 0x2c, 0xd5, 0xab, 0xe5, 0xf1, 0x93, 0xdd, - 0x35, 0xf1, 0x55, 0x0e, 0x66, 0x5d, 0xb4, 0xf9, 0xae, 0xf0, 0x06, 0x85, - 0xf6, 0xa3, 0x45, 0x82, 0xf7, 0xe3, 0x67, 0x6b, 0x25, 0xd1, 0xcb, 0xca, - 0x17, 0x4d, 0x04, 0x6a, 0x8c, 0x72, 0xc0, 0x14, 0x7c, 0xc2, 0x6f, 0x6d, - 0x37, 0xc2, 0x2d, 0xb4, 0x5a, 0xc8, 0x8b, 0xea, 0x2d, 0x24, 0xc1, 0xce, - 0x5d, 0xfa, 0x9b, 0x40, 0xec, 0x12, 0x64, 0x79, 0x6b, 0x20, 0xf6, 0x55, - 0xa4, 0x6a, 0x12, 0x78, 0x2f, 0x4d, 0x84, 0x38, 0x7c, 0x6e, 0x10, 0x87, - 0xe2, 0xb7, 0x26, 0xdf, 0xb7, 0x81, 0x6e, 0x90, 0xba, 0xda, 0xf9, 0x03, - 0x30, 0x86, 0x55, 0xd3, 0x4c, 0x9e, 0x18, 0x4b, 0x80, 0x27, 0x05, 0xe1, - 0x49, 0x75, 0x09, 0x8f, 0x26, 0xa6, 0x0e, 0x99, 0xcf, 0xf4, 0x2d, 0x3a, - 0xc9, 0xbe, 0x07, 0x4f, 0xcc, 0xc0, 0x1b, 0x97, 0x40, 0xb2, 0x70, 0x46, - 0x6b, 0x5a, 0x79, 0x1e, 0xab, 0xe1, 0x20, 0xc9, 0x64, 0x61, 0xa5, 0xd7, - 0xf7, 0x31, 0x59, 0x19, 0x23, 0x92, 0xef, 0x3d, 0x6e, 0x62, 0x57, 0x6f, - 0x7b, 0x7a, 0xae, 0xa7, 0xf4, 0x8f, 0xf7, 0x38, 0xb9, 0xa8, 0x07, 0x09, - 0x4e, 0x16, 0x4d, 0xf6, 0x43, 0xec, 0x87, 0xb3, 0x1e, 0xbd, 0x9f, 0x37, - 0x6c, 0x9e, 0x22, 0xf1, 0x63, 0x3f, 0x3c, 0xf7, 0xad, 0xa3, 0xf8, 0x63, - 0x36, 0x01, 0x4b, 0xa0, 0x3e, 0xab, 0x73, 0x77, 0x2d, 0x80, 0xf8, 0xe6, - 0x9d, 0x86, 0xf8, 0x84, 0xa0, 0x12, 0xa7, 0x38, 0x8e, 0xff, 0xdd, 0xf8, - 0xa2, 0x82, 0xbf, 0x5c, 0x47, 0xb6, 0xbb, 0xcb, 0x5e, 0x3d, 0x83, 0x37, - 0x5c, 0x47, 0x55, 0x0a, 0x41, 0x29, 0xc1, 0x0d, 0x98, 0xe6, 0x71, 0x40, - 0x07, 0x7a, 0x88, 0x57, 0xba, 0x8f, 0x80, 0x61, 0x9d, 0xec, 0x29, 0xf5, - 0x41, 0x6a, 0x35, 0x50, 0xd4, 0xe2, 0x3a, 0x4b, 0x3f, 0xad, 0x00, 0xda, - 0x11, 0x0a, 0xb6, 0xf8, 0x47, 0xaa, 0xdf, 0xb7, 0x58, 0x15, 0x2b, 0xdb, - 0xed, 0x58, 0xf6, 0x6a, 0xa8, 0xbc, 0x3c, 0xe0, 0x56, 0x29, 0x05, 0x5a, - 0xff, 0xd2, 0xcf, 0x26, 0x94, 0x34, 0xb5, 0xa8, 0xb0, 0x05, 0x56, 0xe0, - 0x7d, 0xbc, 0xc7, 0xf2, 0xd4, 0xa8, 0xde, 0x5c, 0xac, 0x1c, 0x7e, 0x63, - 0xca, 0x51, 0xf3, 0x08, 0x7b, 0x3f, 0x74, 0x45, 0x34, 0x20, 0xed, 0x1d, - 0xf3, 0xf4, 0xa3, 0x99, 0xff, 0xf5, 0x9e, 0xc4, 0x42, 0x3a, 0x56, 0xc2, - 0x24, 0xdd, 0x63, 0xc1, 0x2b, 0xcb, 0xc8, 0xb7, 0x9d, 0x3f, 0xfb, 0x9b, - 0x0e, 0x73, 0xf0, 0x6d, 0x4e, 0xfb, 0xf2, 0x9a, 0xdb, 0x61, 0xfd, 0x58, - 0x17, 0xa3, 0x30, 0xbb, 0xdc, 0xf1, 0xeb, 0x89, 0x5b, 0x53, 0xb7, 0xfb, - 0x47, 0x9d, 0x53, 0x9b, 0x03, 0xd6, 0x27, 0xc1, 0xd2, 0x4b, 0xbf, 0x24, - 0x56, 0xb9, 0x98, 0x48, 0x29, 0xfb, 0x01, 0x1b, 0xa2, 0x60, 0x8e, 0x4a, - 0xbd, 0x89, 0x2c, 0x22, 0xf9, 0x4e, 0x99, 0x52, 0x52, 0xdb, 0xfa, 0x77, - 0x1b, 0xef, 0xb1, 0x1d, 0xe2, 0x33, 0x2d, 0x39, 0x18, 0xf3, 0xa0, 0x07, - 0xb6, 0x71, 0xbe, 0x5c, 0xf6, 0xc1, 0xaf, 0x82, 0x6c, 0xbe, 0x6c, 0xc9, - 0x74, 0xb3, 0xa2, 0x6b, 0xd3, 0xf4, 0xdb, 0x42, 0x94, 0x01, 0xc0, 0x85, - 0x9c, 0x3e, 0xc7, 0x58, 0x80, 0x08, 0x38, 0x25, 0x9f, 0x04, 0x60, 0xa8, - 0x1d, 0x66, 0x7f, 0x95, 0xde, 0x1a, 0x64, 0xdf, 0xe1, 0x3a, 0xeb, 0xed, - 0xaf, 0x07, 0x3f, 0x39, 0x7f, 0xcb, 0x67, 0x50, 0x33, 0xb3, 0xe0, 0x30, - 0xd7, 0xbc, 0xde, 0x2c, 0xb4, 0x32, 0x33, 0xbc, 0x1a, 0x55, 0x38, 0x06, - 0x05, 0x65, 0xdf, 0x7c, 0x68, 0x10, 0x30, 0x54, 0xbc, 0x14, 0x14, 0x92, - 0x21, 0x2a, 0x74, 0xd3, 0xe9, 0x32, 0x45, 0xca, 0xbc, 0x4a, 0x54, 0xb9, - 0x47, 0x5e, 0x1c, 0x86, 0xd1, 0x4e, 0xcb, 0x46, 0x0e, 0xc8, 0xce, 0xb7, - 0x66, 0x59, 0x8f, 0x06, 0x4c, 0xee, 0xe1, 0x2f, 0x5b, 0x5d, 0x34, 0x0b, - 0xfb, 0xa8, 0x9f, 0xa8, 0x6b, 0x7d, 0x43, 0xa6, 0x01, 0x78, 0x2d, 0xc6, - 0xc9, 0x03, 0x6e, 0xc9, 0x60, 0x59, 0xb7, 0x0f, 0x4b, 0xce, 0x17, 0x04, - 0xa3, 0x76, 0x0d, 0x2e, 0x57, 0xad, 0x32, 0xb0, 0xc7, 0xff, 0x1a, 0x32, - 0xc6, 0x7c, 0x42, 0xc5, 0x55, 0xc6, 0xf5, 0x77, 0x55, 0xcb, 0xac, 0x8c, - 0xdd, 0x62, 0x8d, 0x9c, 0x7e, 0xe7, 0x4f, 0xe0, 0x0f, 0x0d, 0xdc, 0x68, - 0xab, 0x2b, 0x00, 0x84, 0xff, 0xea, 0xa3, 0x01, 0x95, 0xdb, 0x89, 0x24, - 0xa7, 0xbb, 0x0d, 0x0f, 0x10, 0x0e, 0x83, 0x4c, 0x78, 0xf0, 0x41, 0xde, - 0x27, 0x9a, 0x22, 0x7a, 0x4b, 0xe5, 0x24, 0x5e, 0x0e, 0xb3, 0x38, 0x4d, - 0x60, 0x9f, 0x1b, 0x98, 0x71, 0xac, 0x84, 0x04, 0x13, 0x03, 0x30, 0x89, - 0xc7, 0xb9, 0x1e, 0x7d, 0xb5, 0x76, 0xe0, 0xb7, 0x00, 0xad, 0xc6, 0x90, - 0x7c, 0xa3, 0xc5, 0xd0, 0x4a, 0x3d, 0x1d, 0xad, 0x3f, 0xc2, 0xc5, 0x81, - 0x4d, 0x3a, 0x17, 0x39, 0xca, 0xbc, 0xa2, 0xd0, 0x90, 0x22, 0xd9, 0x25, - 0x80, 0xc5, 0xcf, 0x5d, 0xf7, 0x35, 0x04, 0xe5, 0x07, 0x2b, 0x35, 0xf2, - 0xbd, 0x18, 0xa3, 0xce, 0x2c, 0xbb, 0xfd, 0x58, 0xdf, 0xef, 0x77, 0x55, - 0x49, 0x8e, 0xde, 0xc2, 0x4b, 0x2b, 0x49, 0x5d, 0xfa, 0x6a, 0xaa, 0xe8, - 0x99, 0x0c, 0x44, 0xbd, 0x65, 0xf4, 0xc9, 0x3e, 0x10, 0x1a, 0x25, 0x1d, - 0xc5, 0xee, 0x9d, 0x52, 0x8c, 0xe7, 0x0d, 0x4a, 0x9f, 0x7b, 0x8c, 0x21, - 0x2f, 0xe1, 0xbb, 0x74, 0xa4, 0x43, 0x6b, 0x23, 0x3f, 0xdf, 0x48, 0x3c, - 0x96, 0x4c, 0x49, 0xe0, 0x07, 0x42, 0x9e, 0x2c, 0x45, 0xec, 0x54, 0x42, - 0xb2, 0x67, 0x78, 0xc4, 0x92, 0xe3, 0xf0, 0xaf, 0xc7, 0xd5, 0xb3, 0x44, - 0x61, 0xf5, 0x47, 0x9e, 0xed, 0xc6, 0xfc, 0xea, 0x26, 0xf1, 0xcb, 0x7f, - 0x76, 0x73, 0x8c, 0xdc, 0x0a, 0x06, 0xf3, 0x02, 0x7f, 0x2e, 0x02, 0xdb, - 0x1f, 0xcf, 0xc5, 0x5c, 0xb3, 0x94, 0xf2, 0xb0, 0xfd, 0xbc, 0x71, 0xaf, - 0xa2, 0xfe, 0x6d, 0xc5, 0x8d, 0xf6, 0x99, 0xc9, 0x95, 0xaa, 0x00, 0xd4, - 0x63, 0x7b, 0xb2, 0x4c, 0xc9, 0xd4, 0xb6, 0x7b, 0xef, 0x97, 0xb1, 0x67, - 0x47, 0x4b, 0x25, 0x9e, 0x53, 0xee, 0x0c, 0x97, 0x48, 0x31, 0x14, 0xbd, - 0x74, 0x14, 0x2a, 0x4e, 0xed, 0x9c, 0xe3, 0x3f, 0xf8, 0x28, 0xcb, 0x9f, - 0x27, 0x08, 0x1b, 0xba, 0xf0, 0xf4, 0x95, 0x52, 0xf9, 0x33, 0xd2, 0x1a, - 0x64, 0x55, 0x7d, 0x21, 0x9e, 0x91, 0x1f, 0x4e, 0xb2, 0x6d, 0x65, 0x32, - 0xb3, 0xe8, 0x2a, 0xd0, 0x7c, 0x19, 0x6d, 0xc3, 0xfc, 0xee, 0x6f, 0x0b, - 0x00, 0xeb, 0xd8, 0x8b, 0xce, 0x0b, 0x24, 0xd5, 0xe8, 0x68, 0x68, 0xeb, - 0xae, 0xf5, 0xee, 0x35, 0xb5, 0xcc, 0xf9, 0x6b, 0xa2, 0x9a, 0x86, 0xf9, - 0xd9, 0xb0, 0x04, 0x0d, 0xc5, 0x7c, 0x90, 0x55, 0x20, 0x8f, 0x53, 0xc3, - 0x28, 0x3e, 0x79, 0xb1, 0xab, 0xab, 0x32, 0x11, 0x8a, 0xa8, 0x76, 0x9a, - 0x31, 0xd3, 0xee, 0x7b, 0xcc, 0xf9, 0x87, 0xfa, 0xd0, 0xdb, 0x05, 0x02, - 0x9a, 0x0c, 0xe6, 0xc2, 0xfb, 0xb9, 0x7b, 0x82, 0x98, 0x14, 0xad, 0x3f, - 0x3b, 0x92, 0x97, 0xf8, 0x2f, 0xd9, 0xc4, 0xe8, 0xb7, 0x27, 0xa1, 0x84, - 0x83, 0x5d, 0xae, 0x6d, 0x6d, 0x45, 0x03, 0x3b, 0x5b, 0x1a, 0xbf, 0x40, - 0x2e, 0x01, 0x59, 0x46, 0xba, 0x5f, 0x66, 0xb6, 0x6c, 0x89, 0xd7, 0x65, - 0x1b, 0x16, 0x4f, 0xb3, 0x01, 0x83, 0xeb, 0xfa, 0x1a, 0x24, 0xdd, 0x61, - 0xf3, 0x25, 0xb7, 0x3a, 0x15, 0x26, 0xe3, 0x1a, 0x66, 0x1a, 0x50, 0x6e, - 0x72, 0xfe, 0xd9, 0xa1, 0xa0, 0x54, 0x93, 0xb1, 0x7f, 0xce, 0x66, 0xbf, - 0x56, 0x36, 0x95, 0x22, 0xe1, 0x3a, 0x29, 0x03, 0x40, 0x52, 0xb5, 0x2f, - 0x8a, 0x15, 0x54, 0xc5, 0xf2, 0x40, 0xa6, 0x80, 0x72, 0x26, 0x3c, 0xd9, - 0xd7, 0xbe, 0xe6, 0x7d, 0x60, 0xa1, 0xc3, 0x1c, 0x24, 0xa5, 0xd4, 0xf9, - 0xf8, 0xd7, 0x23, 0x3f, 0x16, 0x97, 0xa1, 0x31, 0x16, 0xd6, 0x04, 0xbc, - 0x66, 0x2c, 0x84, 0xf0, 0xdb, 0x6f, 0x0b, 0x80, 0xf4, 0x35, 0x35, 0xd3, - 0xb8, 0x25, 0x4c, 0xa7, 0x68, 0x7e, 0xfe, 0x08, 0xc5, 0x9b, 0x3a, 0xc9, - 0xd0, 0xab, 0x77, 0xc9, 0x13, 0xce, 0xc9, 0xc9, 0xac, 0x5b, 0x8b, 0xd1, - 0x41, 0xaf, 0x11, 0x52, 0x60, 0x44, 0x15, 0x7d, 0xcf, 0x7c, 0xe3, 0xed, - 0x24, 0x64, 0xd6, 0xae, 0x82, 0x8a, 0xb5, 0x8f, 0xbf, 0x01, 0x53, 0xc6, - 0xa5, 0xe5, 0x36, 0x8a, 0x39, 0x44, 0x6e, 0xe6, 0x28, 0x44, 0x55, 0x3a, - 0x40, 0x4e, 0xff, 0xa6, 0x24, 0x48, 0x8f, 0xa0, 0xa9, 0xdc, 0x5d, 0x51, - 0xcf, 0x49, 0x5c, 0xec, 0xd0, 0x5b, 0x56, 0xcf, 0x66, 0xe7, 0xe5, 0xa9, - 0xde, 0x65, 0xc5, 0xd5, 0x3e, 0x70, 0xe6, 0xb2, 0xf6, 0x95, 0x02, 0xcb, - 0x4e, 0x29, 0xd7, 0x86, 0x42, 0x29, 0x80, 0x5c, 0x8e, 0xc6, 0x5e, 0xbd, - 0x20, 0xf2, 0x07, 0xeb, 0xfa, 0x64, 0xa5, 0x25, 0x1a, 0xc8, 0x52, 0xab, - 0xc9, 0x8f, 0x78, 0x3b, 0xc6, 0x8f, 0x58, 0xcf, 0xcc, 0xbe, 0x5e, 0xed, - 0xbe, 0xaa, 0xf2, 0xf7, 0x01, 0x34, 0x5a, 0x5e, 0x53, 0x52, 0x78, 0x86, - 0x4a, 0x05, 0x07, 0xd7, 0xce, 0x7d, 0x53, 0x24, 0x79, 0x16, 0xcb, 0x70, - 0xad, 0xe6, 0x09, 0x1e, 0x2a, 0x8b, 0x60, 0xde, 0x72, 0xe3, 0xd5, 0x06, - 0x27, 0x15, 0xd2, 0x88, 0x39, 0xf7, 0xab, 0xf6, 0x20, 0xaf, 0xa7, 0x45, - 0x4b, 0x7a, 0x4c, 0x58, 0xfb, 0xe0, 0x91, 0xf7, 0x8d, 0x95, 0x97, 0x7f, - 0xf9, 0xbf, 0xeb, 0x1d, 0x6d, 0xc1, 0x15, 0x3c, 0x17, 0xbf, 0x84, 0x5c, - 0xcb, 0x83, 0x22, 0x73, 0x97, 0x34, 0x79, 0x12, 0xf2, 0xbb, 0x5f, 0x3b, - 0xca, 0x90, 0x1c, 0x8f, 0x35, 0xb6, 0xd4, 0x7b, 0xca, 0x28, 0xcf, 0x11, - 0xce, 0x72, 0x08, 0xb0, 0x3b, 0x07, 0x46, 0x0d, 0xcd, 0x2f, 0xae, 0xf1, - 0x6f, 0x8e, 0xc1, 0xbc, 0xe0, 0x61, 0xc8, 0xc3, 0x91, 0xf1, 0xe3, 0x28, - 0x93, 0xb9, 0x4a, 0x88, 0xac, 0xa6, 0x6b, 0x63, 0x62, 0x80, 0x11, 0xe9, - 0x49, 0x04, 0xac, 0xb9, 0x77, 0x92, 0x3d, 0xf2, 0xf6, 0x92, 0x4d, 0xc7, - 0x3c, 0xc9, 0xa9, 0x96, 0x54, 0xbc, 0x6a, 0x9c, 0x1c, 0x8e, 0x5b, 0x20, - 0x50, 0x5a, 0x34, 0xe0, 0x60, 0x95, 0x95, 0x8d, 0x2f, 0x2a, 0x57, 0xb9, - 0x03, 0x7a, 0xb7, 0x31, 0x64, 0x7c, 0x5a, 0x49, 0x77, 0xe8, 0x72, 0x1b, - 0xd8, 0x36, 0x87, 0xc1, 0x44, 0xfd, 0x56, 0x97, 0x1a, 0xa9, 0x24, 0xb3, - 0x05, 0x31, 0x97, 0x52, 0xc5, 0x97, 0xf7, 0x05, 0xce, 0xc5, 0x6d, 0x4a, - 0xcb, 0x6d, 0xbe, 0x8a, 0x45, 0x26, 0x5c, 0x94, 0x05, 0xdd, 0x43, 0x23, - 0x95, 0xe7, 0xf3, 0x93, 0x25, 0x74, 0x71, 0xb1, 0x0d, 0x93, 0xa4, 0x88, - 0x00, 0x4f, 0xee, 0x86, 0x67, 0x3e, 0x76, 0xd6, 0xa7, 0xb1, 0xe2, 0x2b, - 0xe2, 0x3d, 0x11, 0x6b, 0x14, 0x23, 0xb3, 0xb8, 0x4e, 0x1a, 0x9e, 0x4b, - 0xbc, 0x3a, 0x66, 0x12, 0xc9, 0xaa, 0x18, 0x91, 0x24, 0xac, 0x26, 0x2d, - 0x8c, 0x50, 0x46, 0x4a, 0xfd, 0xdc, 0x03, 0x41, 0x3e, 0xd8, 0xfd, 0x78, - 0x1a, 0x30, 0xb7, 0x91, 0x48, 0x12, 0xe7, 0xe8, 0x77, 0x2e, 0xdc, 0xfd, - 0xbc, 0x46, 0x64, 0xa8, 0x5a, 0x4e, 0x94, 0x9b, 0xba, 0xb8, 0x66, 0x92, - 0x5e, 0x8b, 0x5e, 0x7f, 0x1d, 0xa7, 0x3d, 0x2c, 0x06, 0xbc, 0xd2, 0xde, - 0x64, 0x13, 0x2f, 0x71, 0x9f, 0xf2, 0x7a, 0x1e, 0xc4, 0xfa, 0xcc, 0x4f, - 0x67, 0xb2, 0xa2, 0x45, 0x28, 0x2c, 0xa3, 0xbf, 0x4a, 0xdd, 0xa3, 0xf3, - 0x5a, 0xe7, 0xee, 0x07, 0x9c, 0x5d, 0x96, 0xbd, 0x5e, 0x3f, 0xb8, 0xd2, - 0xba, 0x29, 0xe7, 0x56, 0x96, 0xee, 0x34, 0xd1, 0x74, 0x46, 0x33, 0x3f, - 0xbc, 0xd6, 0x43, 0x17, 0xb9, 0x19, 0x46, 0x6a, 0xf6, 0xe3, 0x2b, 0xb7, - 0xf2, 0xec, 0xd3, 0x1b, 0x13, 0xaa, 0xd6, 0xb3, 0x99, 0xfa, 0xc5, 0x6a, - 0xb0, 0xa7, 0xd7, 0x0b, 0x40, 0x13, 0xd3, 0x87, 0x3f, 0xdd, 0x4c, 0x7f, - 0xbb, 0x90, 0xad, 0x84, 0xae, 0x20, 0x1c, 0x89, 0x8b, 0x4b, 0x02, 0xa4, - 0x33, 0x81, 0xc7, 0x12, 0x3b, 0x51, 0x0c, 0xb4, 0x2d, 0xce, 0xf7, 0xaa, - 0xc5, 0x51, 0x84, 0xe5, 0xcd, 0x96, 0xa2, 0xbf, 0x0d, 0x84, 0x40, 0xfe, - 0x03, 0xec, 0x54, 0x1a, 0x9c, 0x25, 0x30, 0x47, 0xf4, 0xa1, 0x74, 0x43, - 0xcf, 0x50, 0x55, 0x7b, 0x41, 0x91, 0x1f, 0x51, 0xd8, 0xd0, 0xbb, 0xca, - 0xa3, 0x75, 0x41, 0xc5, 0x4d, 0xc1, 0x54, 0x7c, 0x99, 0xef, 0x87, 0xa6, - 0x27, 0xa6, 0x08, 0xab, 0x75, 0xfc, 0xdb, 0xbc, 0xd2, 0xaf, 0x18, 0x4d, - 0x23, 0x03, 0x6f, 0x56, 0x4d, 0x59, 0x2e, 0x3b, 0x6c, 0xd4, 0x07, 0xd0, - 0xc5, 0x33, 0xab, 0x26, 0x3b, 0xe8, 0xdb, 0xa1, 0x77, 0xa3, 0x3e, 0xed, - 0x75, 0xab, 0xa5, 0x3b, 0x7d, 0x80, 0x72, 0x52, 0x36, 0x1c, 0x21, 0xb2, - 0x87, 0x97, 0x3e, 0x16, 0x2b, 0xf2, 0xea, 0xaa, 0x56, 0xc4, 0x19, 0x7c, - 0xdf, 0x59, 0xed, 0x2f, 0x9b, 0xc9, 0x24, 0x9e, 0xd0, 0xf4, 0xf0, 0xb3, - 0x45, 0x57, 0x3f, 0xae, 0x67, 0xa6, 0x7a, 0x28, 0x8f, 0xdf, 0x5d, 0x54, - 0x23, 0x4a, 0x5e, 0xd8, 0x5b, 0xcb, 0x4a, 0xb3, 0x23, 0x65, 0x9a, 0x2b, - 0x2f, 0xa0, 0xe5, 0x99, 0x82, 0xb0, 0x36, 0xf1, 0x47, 0xbf, 0xc0, 0x58, - 0xc6, 0xdc, 0xba, 0x02, 0x88, 0x0c, 0xfe, 0xa9, 0x80, 0x58, 0xc7, 0x0c, - 0xa8, 0x7e, 0x17, 0x2f, 0xdc, 0x74, 0xf3, 0xae, 0x0b, 0x1b, 0x5f, 0xbe, - 0x9d, 0x60, 0x6a, 0xbd, 0x90, 0xb8, 0x44, 0x4d, 0x66, 0x6c, 0xc7, 0x93, - 0xc3, 0x98, 0xba, 0xaf, 0x2d, 0x8d, 0x63, 0x31, 0x71, 0xbf, 0x5d, 0x6e, - 0x65, 0xe1, 0x2b, 0x2c, 0x5a, 0x8b, 0x10, 0xdf, 0x0b, 0x15, 0xca, 0x20, - 0xdf, 0x17, 0x4d, 0x3b, 0xf8, 0x84, 0x47, 0xf5, 0xe8, 0x91, 0x0c, 0x90, - 0xd0, 0xb4, 0x51, 0x59, 0xa8, 0xcc, 0xb2, 0xf6, 0x17, 0x05, 0x9a, 0x26, - 0xef, 0xe4, 0x5c, 0x00, 0x08, 0x96, 0xc9, 0x7e, 0x9d, 0x81, 0x61, 0x68, - 0x77, 0xa8, 0x8e, 0x0e, 0xc4, 0xfe, 0xe0, 0xe0, 0x4f, 0xfc, 0xf2, 0xf9, - 0xf7, 0x86, 0x29, 0xbb, 0xcb, 0x0c, 0x86, 0x99, 0x59, 0xb7, 0x3f, 0x19, - 0x8e, 0x0c, 0x62, 0xad, 0x5f, 0x1f, 0xfb, 0x0a, 0x1e, 0x4a, 0xcf, 0xf0, - 0xbc, 0x59, 0x85, 0xf6, 0x66, 0x2e, 0xef, 0x49, 0x98, 0xe4, 0x69, 0xc6, - 0xa3, 0x12, 0x22, 0x21, 0xb6, 0x50, 0x68, 0x1d, 0x6b, 0x18, 0xb3, 0x2a, - 0x84, 0x54, 0x3f, 0x60, 0x2d, 0x19, 0x84, 0xf9, 0xa6, 0xd4, 0x93, 0xda, - 0x10, 0x94, 0x62, 0xaa, 0x94, 0x92, 0x6b, 0xbb, 0xfb, 0x8d, 0x54, 0x91, - 0xfa, 0x6f, 0x07, 0x74, 0xde, 0x11, 0xba, 0x7c, 0x61, 0x1b, 0xe3, 0xdb, - 0x44, 0x5e, 0x26, 0xb7, 0x8e, 0x87, 0xdd, 0xb6, 0x85, 0xa9, 0xa4, 0x91, - 0x39, 0xf1, 0x89, 0x4e, 0xee, 0xc2, 0x16, 0x4a, 0x03, 0x84, 0xdf, 0x75, - 0x97, 0x56, 0x97, 0x3b, 0x6d, 0x01, 0xcd, 0x0d, 0x69, 0x8d, 0xed, 0xdf, - 0x49, 0x27, 0xdf, 0xcc, 0x05, 0x18, 0xe0, 0xa0, 0xed, 0xe4, 0x38, 0xb0, - 0xfa, 0x98, 0x9f, 0xf0, 0x9d, 0x36, 0x17, 0xef, 0xd1, 0xd8, 0xd8, 0x84, - 0xac, 0xd8, 0x96, 0x09, 0x2d, 0x59, 0x46, 0x76, 0x25, 0xe1, 0x3c, 0xb0, - 0x37, 0x7b, 0xe7, 0xa9, 0xf9, 0x8e, 0xab, 0x16, 0x5a, 0xe0, 0x42, 0xa1, - 0xea, 0x3a, 0xc7, 0xb6, 0x8c, 0x80, 0xd2, 0xc8, 0x88, 0x46, 0x95, 0x9c, - 0xa5, 0x08, 0x49, 0xfc, 0xe0, 0x6a, 0xc9, 0x6a, 0xac, 0x4c, 0xd9, 0xcb, - 0x10, 0xa8, 0x2c, 0x84, 0x2d, 0xd3, 0x6b, 0x87, 0xf1, 0xe4, 0x67, 0xe7, - 0x26, 0xa7, 0x1b, 0x05, 0xf7, 0xbb, 0x06, 0x2e, 0x03, 0x38, 0xc0, 0x04, - 0xa4, 0x3c, 0xac, 0x20, 0xfc, 0x98, 0xfb, 0xf9, 0xef, 0x24, 0x43, 0xdb, - 0x6e, 0x45, 0xfc, 0xc7, 0x60, 0x50, 0x7f, 0x42, 0xab, 0x57, 0xf0, 0x4e, - 0xfb, 0x6b, 0xc5, 0x19, 0xa1, 0x97, 0x4f, 0x52, 0x6c, 0x6e, 0x63, 0x61, - 0xf9, 0x98, 0x5b, 0xda, 0x63, 0x73, 0x6e, 0x79, 0x32, 0x1e, 0x0f, 0xb9, - 0x8c, 0x03, 0x06, 0x0e, 0x0f, 0xbb, 0xbd, 0x97, 0xff, 0x9a, 0x52, 0xf9, - 0x88, 0x86, 0xcf, 0xdb, 0x79, 0xc8, 0x38, 0xe8, 0xdc, 0x1b, 0xb2, 0x80, - 0xe9, 0x69, 0x57, 0x9e, 0xe3, 0x1d, 0x30, 0x7a, 0x1f, 0xc7, 0x56, 0x22, - 0x32, 0x69, 0xb6, 0xb3, 0xe9, 0x58, 0x47, 0xbd, 0x39, 0x7f, 0xc2, 0x2e, - 0x21, 0xa6, 0x41, 0x9b, 0xf8, 0xbd, 0xe9, 0x37, 0x26, 0xd0, 0x24, 0x63, - 0x99, 0xf0, 0xa0, 0x96, 0x92, 0x72, 0x43, 0x5b, 0xe2, 0x50, 0xbc, 0xdb, - 0x4a, 0xa1, 0x87, 0x64, 0xca, 0x29, 0xba, 0x34, 0xf1, 0x6a, 0x7a, 0x42, - 0xf1, 0xfc, 0x4d, 0x5e, 0x29, 0xd2, 0x8f, 0x3b, 0x48, 0x10, 0x97, 0xb5, - 0xf6, 0x2f, 0x1a, 0xfb, 0x6d, 0x28, 0x7c, 0x70, 0x96, 0x7f, 0x94, 0x16, - 0xa5, 0x5d, 0x87, 0xac, 0xc1, 0xa1, 0xd8, 0x28, 0x2f, 0x5a, 0xcf, 0xbd, - 0x70, 0x0c, 0x58, 0xce, 0x75, 0x4d, 0x0f, 0x0c, 0xce, 0xb7, 0x69, 0xce, - 0xaa, 0x71, 0x68, 0x70, 0x10, 0xbd, 0x74, 0xe1, 0x12, 0xb2, 0x09, 0xb2, - 0x8b, 0xe0, 0xcb, 0xd2, 0x81, 0x3a, 0xd3, 0x39, 0xcb, 0x9b, 0xc2, 0xba, - 0xf9, 0xfb, 0xf8, 0xb5, 0x8c, 0xb4, 0x56, 0x0e, 0xa8, 0x8a, 0x10, 0x8d, - 0x61, 0x68, 0x4c, 0x80, 0xe4, 0x99, 0x16, 0x14, 0xc0, 0x19, 0x32, 0x61, - 0xa2, 0xf9, 0x6d, 0xae, 0x33, 0x09, 0xb9, 0x16, 0xc4, 0x80, 0xc7, 0xc8, - 0x20, 0xbb, 0xec, 0xe8, 0xcb, 0xcd, 0xe0, 0xc9, 0x5f, 0x71, 0x04, 0xfd, - 0x15, 0x07, 0x26, 0xbd, 0x39, 0x31, 0x4a, 0x0d, 0xeb, 0x23, 0xcd, 0x5a, - 0x5f, 0x46, 0x41, 0xa6, 0xa6, 0x81, 0xd3, 0x0a, 0x2b, 0x90, 0x82, 0xd0, - 0x62, 0xb3, 0xda, 0x5a, 0x4c, 0x2d, 0x78, 0x43, 0xc7, 0x27, 0x37, 0xcc, - 0x30, 0x5f, 0x09, 0xd5, 0xef, 0xab, 0xfc, 0x7a, 0x86, 0xcb, 0x18, 0xbf, - 0x5f, 0xf2, 0xa5, 0x8c, 0xb6, 0xfe, 0xfc, 0xec, 0x54, 0x49, 0x8d, 0x6b, - 0xcb, 0xe5, 0xf4, 0x03, 0x99, 0x43, 0x9d, 0x0c, 0x67, 0x3b, 0x7d, 0x16, - 0x04, 0xf6, 0x88, 0x9a, 0xd5, 0xe3, 0xd2, 0x08, 0xc1, 0xf1, 0xe7, 0x87, - 0x96, 0x36, 0x9f, 0x69, 0xd8, 0x50, 0x85, 0xca, 0x8e, 0x54, 0xbd, 0x4c, - 0x76, 0xf0, 0xf9, 0x96, 0x94, 0xcf, 0xee, 0x16, 0x28, 0x9c, 0x99, 0x4b, - 0x57, 0xe0, 0x68, 0xaf, 0xb8, 0xf7, 0x65, 0x42, 0x9a, 0x7d, 0x4b, 0xaa, - 0xb9, 0xf3, 0xa1, 0xc1, 0x24, 0xdf, 0xc7, 0xae, 0xb7, 0xc3, 0x0f, 0x5e, - 0xf1, 0xf9, 0xf5, 0xd3, 0x3e, 0x7c, 0x48, 0x2c, 0xe1, 0xdf, 0xce, 0x2d, - 0x7f, 0xd3, 0x5f, 0xff, 0xc3, 0x6a, 0x71, 0xfe, 0xab, 0xf8, 0x30, 0xb6, - 0x4c, 0xd7, 0x23, 0x3b, 0x07, 0xf1, 0x2d, 0x68, 0xca, 0xbd, 0x8f, 0xbb, - 0xef, 0x26, 0x53, 0x90, 0xf3, 0x66, 0x8c, 0xe2, 0x4e, 0x87, 0x0f, 0x9a, - 0x6d, 0xed, 0x2f, 0xc9, 0x8a, 0x97, 0x54, 0x4e, 0xcf, 0x7d, 0x4c, 0x1b, - 0x1c, 0x19, 0x8e, 0xd0, 0x0f, 0xe3, 0x88, 0x03, 0x34, 0x7a, 0xca, 0x0e, - 0x98, 0x32, 0x56, 0xe0, 0xa3, 0xe8, 0xc0, 0xc6, 0xef, 0x10, 0x81, 0xce, - 0xf6, 0xe2, 0xbc, 0x60, 0xab, 0x25, 0xc3, 0x73, 0x65, 0xe1, 0x70, 0xcc, - 0xf6, 0x16, 0xf8, 0x5a, 0xd3, 0x47, 0x42, 0x3a, 0xb6, 0x1c, 0xd9, 0x17, - 0xc4, 0x51, 0x46, 0xac, 0x8f, 0x16, 0x1b, 0x70, 0x0d, 0xd0, 0xc0, 0x34, - 0xde, 0xc4, 0xac, 0x1e, 0xad, 0x9b, 0x28, 0x84, 0x91, 0xcb, 0x56, 0x9f, - 0x99, 0xe1, 0xef, 0xf2, 0xad, 0x5e, 0x9b, 0xd5, 0x36, 0x65, 0x54, 0x0f, - 0x85, 0x67, 0xd7, 0x9f, 0x9f, 0xae, 0xa6, 0xce, 0xa2, 0x8d, 0xe1, 0xd4, - 0xc9, 0xd9, 0xd5, 0xe1, 0xaf, 0xf6, 0x45, 0x86, 0x1b, 0x98, 0xb6, 0x7c, - 0xb5, 0xbe, 0x32, 0x81, 0x0b, 0x51, 0x4f, 0x58, 0x69, 0x1b, 0x23, 0x2f, - 0xfa, 0x91, 0x47, 0x12, 0x89, 0x0a, 0x14, 0x47, 0x62, 0xd2, 0x54, 0x44, - 0x75, 0x4f, 0x11, 0xbe, 0x0e, 0xb8, 0x63, 0x35, 0x34, 0xeb, 0x88, 0xaf, - 0x07, 0x9f, 0x20, 0xe9, 0xd8, 0x41, 0x49, 0x66, 0xd8, 0x7d, 0x4d, 0x08, - 0xfc, 0xde, 0x93, 0x23, 0x52, 0xd7, 0xa9, 0x8d, 0x99, 0x5f, 0xad, 0x20, - 0xed, 0xa6, 0x4f, 0x04, 0xf0, 0x96, 0x91, 0x4d, 0x51, 0x4c, 0x85, 0xa0, - 0x49, 0xe2, 0x9e, 0xcd, 0x78, 0xaa, 0x75, 0xc7, 0xc8, 0xaf, 0xf9, 0xbc, - 0x5d, 0xb4, 0x4d, 0xe1, 0xd0, 0x51, 0x90, 0x6f, 0x06, 0xcd, 0xae, 0x41, - 0x64, 0x4d, 0x2f, 0xdd, 0x44, 0x63, 0x7d, 0xf3, 0xa1, 0x8d, 0xf7, 0xed, - 0xd2, 0x2a, 0xcb, 0x9d, 0xca, 0x32, 0x62, 0xfa, 0xc0, 0x7c, 0x7a, 0xe4, - 0x52, 0x26, 0xf7, 0x22, 0xe4, 0x8c, 0x4f, 0x3b, 0x61, 0x80, 0x8a, 0x4d, - 0xf6, 0xc7, 0x87, 0xd3, 0xa0, 0xe0, 0xd7, 0xfb, 0x44, 0x40, 0xc5, 0x91, - 0xb1, 0x2b, 0xf6, 0x57, 0x76, 0x04, 0x7c, 0xfc, 0x86, 0xcc, 0x12, 0x33, - 0x67, 0x86, 0x11, 0xdb, 0xc7, 0x80, 0x8d, 0xcf, 0x69, 0xfd, 0x2e, 0x3f, - 0x9c, 0xd3, 0x5a, 0xd5, 0xd6, 0x0b, 0xe6, 0xc6, 0x64, 0x31, 0x36, 0x34, - 0x44, 0x73, 0x93, 0xca, 0x6c, 0x84, 0xd5, 0x8a, 0x12, 0xe9, 0x5b, 0x92, - 0x1b, 0xd6, 0x51, 0x18, 0x21, 0xff, 0xfb, 0xc3, 0x85, 0xbd, 0x7e, 0x5f, - 0xfe, 0xfe, 0xd0, 0x70, 0xce, 0x59, 0xb6, 0x93, 0xe9, 0xb7, 0x67, 0xe8, - 0x86, 0x2c, 0xf1, 0x68, 0x64, 0x25, 0x16, 0xe4, 0x40, 0x10, 0xab, 0x18, - 0x8e, 0x63, 0x24, 0xe6, 0xc8, 0x36, 0xe6, 0x2d, 0x31, 0xfd, 0xd4, 0xa1, - 0xf5, 0xe4, 0xb8, 0x97, 0x6f, 0xf4, 0x91, 0x6d, 0xd8, 0x3f, 0x6f, 0xc0, - 0x40, 0x36, 0xea, 0xe5, 0x5b, 0x29, 0x1a, 0xd5, 0x50, 0x50, 0x38, 0x4f, - 0x4a, 0x6d, 0x76, 0x87, 0xe4, 0x33, 0x11, 0x4f, 0x59, 0xf9, 0x08, 0x9c, - 0x41, 0x78, 0x9a, 0x56, 0x4d, 0xf3, 0xcd, 0xe2, 0x38, 0x93, 0xf9, 0xc4, - 0x4d, 0x3b, 0xb5, 0xec, 0xf5, 0x95, 0x85, 0xf7, 0x22, 0x42, 0x70, 0xaf, - 0x29, 0xd6, 0xb6, 0x2d, 0x63, 0xb3, 0x04, 0xbf, 0x44, 0xea, 0x52, 0x77, - 0x31, 0x01, 0x87, 0xca, 0xe4, 0x1a, 0x8f, 0x56, 0xe4, 0x39, 0x7d, 0x38, - 0x69, 0xe3, 0x68, 0x23, 0xc7, 0xbe, 0xec, 0x8d, 0x8f, 0x26, 0x29, 0x0b, - 0xeb, 0x8d, 0x7a, 0x3e, 0x0d, 0x50, 0x7c, 0x06, 0xca, 0x0c, 0x01, 0x59, - 0x51, 0x23, 0x9c, 0x1a, 0xf5, 0x6b, 0x0d, 0x9f, 0x1e, 0xf0, 0x56, 0x94, - 0x11, 0x75, 0x32, 0x7f, 0xc4, 0x71, 0x4e, 0x38, 0x91, 0x22, 0x75, 0xad, - 0x4e, 0x82, 0x88, 0x39, 0xa6, 0xdb, 0x99, 0xaa, 0xd4, 0xfd, 0x78, 0x54, - 0xaa, 0x7c, 0xc3, 0xae, 0xf8, 0xf4, 0x68, 0x74, 0x65, 0x2b, 0x49, 0xa8, - 0xb1, 0x44, 0xc1, 0x70, 0x45, 0x13, 0xa2, 0x3e, 0xf9, 0x8b, 0xd9, 0x0c, - 0xc2, 0x8c, 0xa7, 0x3b, 0x57, 0x4e, 0x2c, 0x9b, 0xf7, 0x00, 0x92, 0xd3, - 0x33, 0x03, 0x7a, 0xf1, 0x3c, 0xbf, 0xe8, 0x57, 0xa1, 0x1f, 0xa3, 0x88, - 0x32, 0xf9, 0x00, 0x0b, 0xa6, 0x34, 0x08, 0x7c, 0xf5, 0xe7, 0x1e, 0x3b, - 0x9c, 0x20, 0xc8, 0xd0, 0x8c, 0x1d, 0x6e, 0x5e, 0xed, 0x6f, 0x8e, 0x3c, - 0xfe, 0xee, 0x5c, 0xa8, 0x58, 0xfa, 0x28, 0xfd, 0x1f, 0x6d, 0xfb, 0x31, - 0x08, 0xc6, 0xb5, 0x55, 0x6d, 0x84, 0x39, 0x50, 0x12, 0x0d, 0x17, 0x26, - 0xa8, 0x5b, 0xe5, 0xac, 0x17, 0x71, 0x28, 0x9c, 0xdf, 0x21, 0x8e, 0xd9, - 0x4c, 0xef, 0x05, 0xa2, 0xf7, 0xb9, 0x02, 0x39, 0x85, 0x58, 0x29, 0x44, - 0xae, 0x45, 0xed, 0xcb, 0x90, 0x62, 0xe3, 0xb1, 0x7f, 0x80, 0xd6, 0x7c, - 0xa7, 0x5b, 0x93, 0xe5, 0xd5, 0xd5, 0xd7, 0xd5, 0x6f, 0x02, 0xd4, 0xa8, - 0x1e, 0xc1, 0x34, 0xdd, 0x1c, 0x6f, 0x26, 0xae, 0x85, 0xe4, 0x2a, 0x70, - 0x67, 0x43, 0xce, 0x54, 0x5e, 0xcb, 0x92, 0x59, 0x98, 0xb5, 0x6f, 0x14, - 0x01, 0x63, 0x7f, 0x52, 0xa4, 0xc7, 0x1b, 0x63, 0x22, 0xc1, 0xd7, 0x59, - 0x4e, 0xbc, 0x89, 0x0e, 0x10, 0xa4, 0x55, 0xfd, 0xb5, 0x0d, 0xe5, 0x62, - 0x3b, 0x2a, 0x4f, 0x7f, 0x05, 0x8f, 0xcc, 0xa5, 0xd7, 0xda, 0x27, 0xbd, - 0xca, 0xc9, 0x06, 0xac, 0xa0, 0xef, 0xe7, 0x0e, 0x23, 0xd2, 0xb4, 0xd2, - 0xda, 0x6e, 0x69, 0xa2, 0x57, 0x7f, 0x26, 0x5c, 0xac, 0xda, 0x86, 0x17, - 0x87, 0x0d, 0x06, 0x8a, 0xc8, 0xe4, 0xf9, 0x9a, 0xd4, 0x79, 0xab, 0x2b, - 0x2a, 0x2a, 0x27, 0xf6, 0x1b, 0x16, 0x80, 0x99, 0x43, 0x5f, 0x6e, 0x9c, - 0xd2, 0xb7, 0xf5, 0x88, 0x3f, 0x99, 0x71, 0x6a, 0xbc, 0xfe, 0x18, 0xb8, - 0x71, 0x28, 0xb1, 0xbc, 0xb6, 0x41, 0x41, 0xcb, 0xbf, 0x94, 0x2d, 0x1f, - 0x96, 0xdc, 0x09, 0x2a, 0xd6, 0xf2, 0xc7, 0xbc, 0x29, 0x42, 0x1c, 0x4f, - 0x85, 0xc9, 0xbd, 0x4b, 0xf3, 0x28, 0x94, 0x33, 0x53, 0x27, 0x03, 0x49, - 0xbf, 0xfd, 0x08, 0x3f, 0xb5, 0x3f, 0x95, 0xc4, 0xff, 0xcd, 0xb1, 0xf5, - 0xe9, 0x51, 0x49, 0xd1, 0xa4, 0x9f, 0xa3, 0x12, 0x89, 0x95, 0x41, 0xe6, - 0x14, 0x6e, 0x1e, 0xa7, 0xc8, 0x5f, 0x28, 0xd9, 0x75, 0xc4, 0x96, 0x82, - 0x51, 0x11, 0x5b, 0x50, 0x96, 0xde, 0xce, 0x7a, 0xb8, 0x88, 0x63, 0xc6, - 0x89, 0x0e, 0x75, 0xb7, 0x11, 0xd2, 0x3a, 0x19, 0xbc, 0x48, 0x7e, 0x9e, - 0x67, 0xf9, 0xb2, 0xb8, 0x08, 0xc7, 0x23, 0x8c, 0xd6, 0x96, 0xa8, 0x92, - 0x2c, 0xaf, 0x5b, 0x12, 0x9f, 0x60, 0xe6, 0x56, 0x2d, 0xdf, 0xe8, 0x77, - 0xf2, 0xae, 0xb2, 0x8e, 0x2a, 0x8f, 0x76, 0xb0, 0x2e, 0xf2, 0x25, 0x76, - 0x45, 0x58, 0x1d, 0x94, 0x03, 0xfd, 0xd6, 0x1c, 0xed, 0xf2, 0x24, 0x4d, - 0xee, 0xe5, 0xc1, 0xb7, 0x2e, 0x55, 0xb9, 0x66, 0xd6, 0xad, 0xd7, 0x82, - 0x17, 0x8b, 0xd4, 0x4a, 0x6b, 0xc1, 0x60, 0xa4, 0x5c, 0xc0, 0x3b, 0x63, - 0xaa, 0x99, 0x07, 0xc6, 0xc3, 0x58, 0xbb, 0xcd, 0x57, 0xcf, 0xb1, 0xbc, - 0x55, 0xa0, 0xae, 0x35, 0x14, 0xe7, 0x01, 0x35, 0x9e, 0xd2, 0xa5, 0x13, - 0x25, 0x42, 0x96, 0x32, 0x97, 0x80, 0x34, 0xf5, 0x3e, 0x8c, 0xc3, 0x04, - 0xd4, 0x2e, 0x76, 0x75, 0xbb, 0x70, 0x09, 0xd1, 0x4e, 0x0d, 0xe1, 0x42, - 0xbc, 0xb9, 0x1d, 0x3e, 0x9e, 0x46, 0x10, 0xe8, 0x0f, 0xb4, 0x85, 0xa1, - 0x4f, 0xd7, 0xa7, 0x28, 0x2a, 0xfc, 0x30, 0xaf, 0xf0, 0x69, 0x4b, 0xeb, - 0x59, 0x5b, 0x5f, 0x77, 0xdf, 0xd8, 0x63, 0x4a, 0xbc, 0xf4, 0x63, 0xdf, - 0x18, 0xab, 0xaf, 0x10, 0xc2, 0xdc, 0x82, 0x97, 0xb2, 0x8d, 0xe6, 0xc1, - 0xd7, 0xa0, 0x89, 0x4d, 0xea, 0xbc, 0x19, 0x63, 0x8f, 0x48, 0xd4, 0xe1, - 0x4c, 0x6c, 0x91, 0x03, 0xcd, 0xbc, 0x64, 0x1d, 0x96, 0xed, 0xa1, 0xfa, - 0x3d, 0x78, 0x4d, 0x01, 0xf1, 0x20, 0x8e, 0x93, 0x12, 0x2a, 0x54, 0xd7, - 0x08, 0xbc, 0xdb, 0x43, 0x8e, 0x21, 0x07, 0xa1, 0x51, 0x58, 0x05, 0x4b, - 0x98, 0x15, 0x93, 0xf7, 0xa0, 0xf3, 0x72, 0xb3, 0x57, 0x3f, 0xce, 0x3f, - 0xd0, 0x8a, 0x95, 0x47, 0xf6, 0xf7, 0x49, 0x22, 0x45, 0x71, 0xe9, 0x73, - 0x89, 0xcc, 0xca, 0x3f, 0x52, 0xe4, 0xe3, 0xc2, 0x49, 0x1b, 0xc3, 0xd8, - 0x99, 0xc5, 0xc0, 0x6d, 0xbf, 0x40, 0x2d, 0x01, 0x32, 0x39, 0x56, 0x1b, - 0xba, 0x66, 0xd8, 0x72, 0x1f, 0x53, 0xe6, 0xbd, 0x0d, 0x21, 0xeb, 0x48, - 0xc3, 0xb3, 0x7d, 0x21, 0x44, 0x11, 0x96, 0xc1, 0xa9, 0x53, 0x23, 0xd6, - 0x18, 0x18, 0xda, 0x9a, 0x46, 0xd5, 0x45, 0xc3, 0x43, 0xbe, 0x5a, 0xbf, - 0x2f, 0x87, 0xee, 0x4b, 0x34, 0x33, 0x8a, 0x8f, 0x91, 0x29, 0x5b, 0x11, - 0x39, 0x23, 0xd5, 0x51, 0xde, 0x7f, 0xb1, 0x3b, 0xf5, 0x1f, 0x06, 0xbc, - 0x38, 0xa3, 0x9f, 0xd5, 0x34, 0x66, 0x3f, 0x8b, 0x01, 0x66, 0x72, 0xb2, - 0x4a, 0x4f, 0xf3, 0x0c, 0x3f, 0xe0, 0x94, 0x21, 0x1d, 0xa4, 0xba, 0x6c, - 0x43, 0x36, 0x69, 0xf8, 0x98, 0x13, 0x13, 0x6f, 0x44, 0x0a, 0x97, 0x3e, - 0xe3, 0x30, 0xdd, 0xb2, 0x2f, 0xe2, 0x45, 0x2f, 0x84, 0x81, 0xfa, 0x43, - 0x0e, 0x33, 0x2d, 0x56, 0xd3, 0x4b, 0x59, 0x5b, 0x3a, 0xdb, 0x4d, 0xbb, - 0xd6, 0x95, 0x76, 0x22, 0xe9, 0x92, 0x57, 0x7a, 0x87, 0xb1, 0x9b, 0x97, - 0x5a, 0x98, 0x9f, 0xec, 0x40, 0x64, 0x13, 0xec, 0x30, 0x8c, 0x2a, 0xea, - 0x1f, 0x1a, 0x4e, 0x60, 0x2f, 0x03, 0x2f, 0x36, 0xe1, 0x06, 0x7d, 0x14, - 0x7e, 0x3e, 0x02, 0xe0, 0x55, 0x47, 0x7c, 0x4a, 0x30, 0x5d, 0x20, 0xf6, - 0x19, 0x97, 0x3e, 0xa5, 0x62, 0xbd, 0xe4, 0x24, 0x77, 0x96, 0xe4, 0xf0, - 0x2d, 0xd9, 0x88, 0x4b, 0x0a, 0xdf, 0x3f, 0x7f, 0x07, 0x7e, 0xe7, 0x80, - 0x6d, 0x3f, 0xe7, 0x2d, 0xe1, 0x1e, 0x0b, 0x04, 0xbe, 0x2e, 0x60, 0xc5, - 0x87, 0x5b, 0xa9, 0x43, 0x33, 0x8d, 0x54, 0x9b, 0x6b, 0x55, 0x15, 0x9a, - 0x0c, 0xd9, 0x42, 0x8f, 0x0d, 0x20, 0x12, 0x41, 0xe9, 0x6b, 0xd9, 0x1f, - 0xc3, 0xe5, 0x1d, 0x4d, 0xc5, 0xfa, 0x62, 0x93, 0x58, 0x8f, 0xd8, 0xbd, - 0x70, 0x8c, 0xbb, 0x43, 0x53, 0x34, 0xaa, 0xaa, 0x3a, 0x7b, 0xcd, 0x7e, - 0xa3, 0x73, 0x08, 0xe7, 0x4b, 0xdc, 0x06, 0x5a, 0xbe, 0x96, 0x6f, 0xb7, - 0x5b, 0x91, 0x78, 0xe1, 0xb3, 0xf1, 0xe0, 0x29, 0xa3, 0x52, 0x20, 0x3b, - 0xfb, 0x70, 0x2c, 0x91, 0x8c, 0x54, 0xa3, 0x55, 0x6f, 0x74, 0x08, 0x66, - 0xb7, 0x79, 0x8e, 0xc7, 0xe7, 0x6f, 0x93, 0x10, 0xdf, 0x8c, 0xbd, 0x94, - 0xe6, 0x56, 0xcd, 0x7f, 0x66, 0x83, 0x3a, 0x14, 0x0d, 0x23, 0xad, 0x34, - 0x49, 0x61, 0x97, 0xdf, 0x57, 0xc0, 0xc9, 0xbe, 0xad, 0x42, 0x0f, 0xed, - 0x0f, 0xa3, 0xdb, 0xb3, 0x54, 0xa1, 0x0f, 0x44, 0xee, 0x30, 0x1f, 0x87, - 0x6d, 0x35, 0xd3, 0x8e, 0xe2, 0xd0, 0x83, 0x09, 0x49, 0xbf, 0x2d, 0x19, - 0x93, 0x0f, 0xef, 0xc0, 0x43, 0x03, 0xe0, 0x2e, 0x89, 0x78, 0x64, 0xf9, - 0xf7, 0x64, 0xb5, 0xda, 0x24, 0x8a, 0x8f, 0xb0, 0x7d, 0x77, 0x8d, 0x73, - 0x34, 0x26, 0x4a, 0x7f, 0x59, 0x3c, 0xf5, 0x90, 0x32, 0x70, 0x83, 0x2d, - 0x7c, 0x57, 0xbc, 0xe4, 0xfb, 0x8c, 0x55, 0xbe, 0x71, 0x4f, 0xa1, 0x26, - 0x95, 0x26, 0xf6, 0xfb, 0xc2, 0x99, 0xf5, 0x78, 0x6f, 0x37, 0xac, 0xc9, - 0x8a, 0x1b, 0x62, 0x3c, 0x5c, 0xe8, 0x47, 0x8c, 0x7b, 0x65, 0xb8, 0xb1, - 0x56, 0xf1, 0x3e, 0xb4, 0xc8, 0xc1, 0xfc, 0x6a, 0xc6, 0x54, 0xce, 0xc4, - 0x27, 0x05, 0xe8, 0x71, 0x19, 0x5d, 0xe3, 0x4b, 0xdb, 0x11, 0xc6, 0x36, - 0x67, 0x6c, 0xaa, 0xad, 0xd9, 0x2d, 0xa1, 0x24, 0xfb, 0x4c, 0x34, 0x1d, - 0x80, 0x8e, 0x46, 0x6f, 0x95, 0x6d, 0xf7, 0x11, 0xa9, 0x95, 0x85, 0x35, - 0x37, 0xc1, 0x31, 0x30, 0x39, 0x48, 0x82, 0xf4, 0x9b, 0xb8, 0xb3, 0xa7, - 0x90, 0x16, 0x5e, 0xf4, 0x6b, 0x6c, 0xf4, 0xa8, 0x38, 0xa1, 0x13, 0x8f, - 0xa8, 0x1f, 0x2b, 0x3d, 0xf3, 0x08, 0x25, 0x0e, 0xe7, 0x30, 0xb4, 0x2d, - 0x40, 0x71, 0x86, 0x96, 0xce, 0xc0, 0x19, 0x6a, 0x4d, 0x58, 0x57, 0x83, - 0x8d, 0x83, 0x2d, 0x89, 0x7e, 0xbe, 0x53, 0xcb, 0xf9, 0xb6, 0xae, 0x51, - 0x57, 0x6a, 0xa4, 0x32, 0x7a, 0xf1, 0xef, 0xc2, 0x3d, 0x6f, 0xd5, 0xa8, - 0x6b, 0xec, 0xde, 0x45, 0x52, 0x22, 0xef, 0xa1, 0xd3, 0x23, 0x8f, 0xaf, - 0xd0, 0xe7, 0xcf, 0x21, 0x1b, 0x0a, 0x11, 0x68, 0x03, 0x64, 0xca, 0x02, - 0xde, 0x5e, 0xc0, 0x2f, 0xfa, 0x1d, 0x86, 0xa8, 0x9c, 0xcf, 0xe6, 0x67, - 0x76, 0x33, 0x1d, 0x5c, 0x68, 0x12, 0xeb, 0x77, 0x2c, 0x27, 0x82, 0xe3, - 0xb2, 0xb3, 0x76, 0x85, 0xf9, 0xe4, 0xea, 0xa2, 0xf1, 0xb9, 0xcf, 0x17, - 0x7a, 0xc7, 0x10, 0xe5, 0xc0, 0xd3, 0xe5, 0x73, 0x27, 0x5b, 0xbf, 0xe3, - 0xa0, 0x4a, 0xee, 0xe6, 0xa9, 0x6f, 0xd5, 0x7e, 0xbb, 0x6a, 0xcc, 0x1b, - 0x3c, 0xd9, 0xa3, 0x9b, 0xca, 0x8c, 0x3b, 0xa7, 0x81, 0x90, 0xd4, 0xf9, - 0xf1, 0xde, 0x5b, 0xb1, 0x5f, 0x93, 0x89, 0x40, 0xee, 0x90, 0xfd, 0xee, - 0x18, 0xe5, 0x35, 0x7e, 0x13, 0xaf, 0xb9, 0xc4, 0xcf, 0x1c, 0x5b, 0x3b, - 0x89, 0xa1, 0x4a, 0xca, 0x28, 0xea, 0x9e, 0x94, 0x36, 0x06, 0xab, 0x49, - 0x58, 0xee, 0xd3, 0xa0, 0x01, 0x03, 0xb0, 0x62, 0x8a, 0x8c, 0x76, 0x61, - 0xb7, 0x30, 0x0e, 0x35, 0xfa, 0x62, 0xe5, 0x5c, 0x0e, 0xba, 0x93, 0x5f, - 0x84, 0x75, 0x0b, 0x21, 0x94, 0xf8, 0x2f, 0x81, 0xee, 0x1d, 0x2e, 0x7c, - 0x7e, 0xcf, 0x13, 0x67, 0xba, 0xc8, 0xb8, 0x06, 0xc6, 0xa4, 0xc1, 0x6d, - 0xe1, 0x07, 0x34, 0x41, 0x18, 0xac, 0x07, 0xd0, 0x57, 0x97, 0x3e, 0x1d, - 0x37, 0x89, 0x06, 0x23, 0x59, 0x49, 0x47, 0xf5, 0x88, 0x18, 0x3c, 0x46, - 0xc3, 0x8b, 0xf1, 0xa6, 0x4a, 0x31, 0xe8, 0x03, 0xec, 0xc4, 0xaa, 0x09, - 0xb0, 0x94, 0x2a, 0xb8, 0xfd, 0x86, 0x9f, 0x01, 0x4f, 0x5d, 0xd5, 0x29, - 0x6d, 0xa8, 0xa9, 0xd3, 0x52, 0x7b, 0xed, 0x51, 0xe0, 0xaa, 0x26, 0x03, - 0xf4, 0x11, 0xf9, 0xfa, 0xd1, 0x23, 0xed, 0xdd, 0x9c, 0x1e, 0x74, 0xd9, - 0xbb, 0x36, 0x28, 0x82, 0x24, 0x62, 0xad, 0x65, 0xf0, 0xe9, 0xd7, 0x60, - 0x32, 0x74, 0x34, 0x47, 0x63, 0xb4, 0x64, 0x30, 0xea, 0x54, 0xf1, 0x12, - 0x7e, 0x3e, 0xeb, 0xcd, 0x81, 0xb4, 0x25, 0x21, 0xfe, 0x0b, 0xf8, 0xb1, - 0x26, 0x16, 0x36, 0x50, 0x26, 0xa1, 0x0c, 0x3b, 0x1b, 0x71, 0xda, 0xad, - 0x9a, 0x58, 0x99, 0xf0, 0xd8, 0xc0, 0x53, 0xdd, 0xca, 0x28, 0x74, 0x10, - 0x92, 0xc7, 0xe4, 0xab, 0xce, 0xf6, 0x79, 0x8a, 0xf0, 0x4d, 0x2b, 0xa2, - 0xf4, 0xa3, 0xbd, 0x8e, 0x9c, 0xdc, 0x4a, 0x73, 0x2e, 0x56, 0x95, 0x8d, - 0xed, 0x2d, 0x62, 0xe0, 0xf7, 0x69, 0x65, 0xa5, 0xce, 0xf4, 0xad, 0xe6, - 0x3f, 0xfc, 0x78, 0x9c, 0xf1, 0xbc, 0x74, 0xfe, 0xe7, 0x64, 0xa2, 0x77, - 0x78, 0x82, 0xd5, 0xa5, 0x6a, 0xa0, 0xe1, 0xf0, 0x00, 0xd5, 0xbf, 0xb9, - 0x93, 0x88, 0xbd, 0x18, 0x16, 0x0a, 0x3a, 0x7c, 0xa0, 0x2c, 0x7b, 0x01, - 0xbb, 0xe9, 0x9a, 0x81, 0x89, 0x84, 0x12, 0x3f, 0xda, 0x3e, 0x49, 0xdd, - 0xdd, 0x57, 0x9b, 0x50, 0x75, 0xa3, 0xcc, 0xe6, 0xf3, 0xc4, 0x03, 0x95, - 0x23, 0x82, 0x23, 0x36, 0xb8, 0xe7, 0x31, 0x94, 0x90, 0xf2, 0x35, 0x6c, - 0x7b, 0xc6, 0x40, 0x32, 0xd5, 0x3e, 0xd3, 0xd7, 0x2e, 0x20, 0x63, 0x5b, - 0x8e, 0x63, 0xde, 0x61, 0x80, 0xdd, 0xd3, 0x8d, 0x17, 0xeb, 0xe0, 0x62, - 0x76, 0x7a, 0x10, 0x8d, 0x9a, 0x30, 0x4c, 0x10, 0x62, 0xf6, 0xc6, 0x68, - 0xe5, 0x91, 0xa0, 0x94, 0x05, 0x8a, 0x0e, 0x7b, 0xb0, 0x7f, 0x17, 0x19, - 0x99, 0x71, 0xdd, 0x7f, 0xa5, 0x67, 0x23, 0x61, 0x0e, 0x80, 0xcc, 0x12, - 0xd7, 0x57, 0xcb, 0x24, 0xa3, 0x6e, 0x9a, 0x35, 0x32, 0xe1, 0x8c, 0x5f, - 0xf6, 0x0a, 0xb5, 0x78, 0xe3, 0x10, 0x76, 0x4d, 0xc4, 0x22, 0xe5, 0x77, - 0x2c, 0x45, 0x83, 0x41, 0xaa, 0x4a, 0x22, 0x35, 0x72, 0xba, 0xfe, 0x3e, - 0x93, 0xdc, 0x30, 0xdd, 0xa6, 0xdd, 0xbb, 0xf4, 0xf1, 0x53, 0xc1, 0x5b, - 0x7b, 0xa6, 0x97, 0x55, 0xdf, 0xb2, 0x98, 0x19, 0x18, 0x3f, 0x87, 0x75, - 0x07, 0x0d, 0x69, 0x76, 0xb9, 0x4f, 0x58, 0x9f, 0x87, 0xff, 0x05, 0x09, - 0xc9, 0x7c, 0xaf, 0xf3, 0xd1, 0xab, 0xb8, 0xa4, 0x36, 0xa6, 0x51, 0x53, - 0x89, 0x11, 0xf4, 0xd7, 0x6d, 0xd8, 0xd6, 0xc8, 0x4f, 0x54, 0x3f, 0x64, - 0xac, 0x68, 0xdb, 0x2b, 0xb0, 0x7e, 0x0a, 0x67, 0x69, 0xf5, 0x95, 0x8a, - 0xb3, 0x9b, 0x27, 0xc9, 0x22, 0x27, 0x67, 0xe0, 0xcf, 0xa7, 0xae, 0x26, - 0xa6, 0xfc, 0xf9, 0x60, 0x7c, 0xc2, 0x82, 0x11, 0x85, 0x62, 0x5f, 0x94, - 0x47, 0x24, 0x76, 0x95, 0x13, 0x34, 0x0f, 0x45, 0x47, 0x6c, 0xc5, 0x2f, - 0x0e, 0xba, 0xe0, 0xca, 0xbb, 0x75, 0x80, 0x98, 0xc1, 0x71, 0x3b, 0xc4, - 0x4c, 0xe6, 0x36, 0x00, 0x1a, 0x63, 0x2f, 0xaf, 0x26, 0xb5, 0xba, 0x38, - 0x5a, 0xcb, 0xa3, 0x36, 0x8d, 0x65, 0x7a, 0xa5, 0xc9, 0x1a, 0x00, 0xb8, - 0x1a, 0x9d, 0x58, 0xb1, 0x1a, 0xd9, 0x0f, 0x99, 0x76, 0x18, 0xfa, 0xac, - 0x16, 0xfc, 0x77, 0x3b, 0xbc, 0x9a, 0x1e, 0x7b, 0xde, 0x37, 0xfe, 0x7c, - 0x7d, 0x85, 0xe6, 0x8e, 0xd0, 0xc6, 0xec, 0xfa, 0x27, 0xc8, 0x74, 0xc6, - 0xb5, 0xfd, 0x41, 0x9d, 0x5a, 0xff, 0xd5, 0xfd, 0xa6, 0x78, 0x41, 0x1b, - 0xec, 0x04, 0x15, 0x15, 0x3e, 0xd6, 0x57, 0x89, 0x7f, 0x24, 0x5a, 0xea, - 0x3a, 0xd4, 0xc2, 0x45, 0x38, 0xa0, 0x1a, 0xde, 0x29, 0x21, 0x13, 0x9f, - 0xc9, 0xc2, 0xaf, 0x81, 0x9f, 0x56, 0xeb, 0xaa, 0xb3, 0xd8, 0xdd, 0x72, - 0x2f, 0x91, 0x0e, 0x23, 0x66, 0xe4, 0x16, 0x73, 0x8b, 0x6d, 0x07, 0x70, - 0xe9, 0xd9, 0xe4, 0xb4, 0x9d, 0xa7, 0x9f, 0x1e, 0x16, 0x30, 0x9b, 0xde, - 0xea, 0xe2, 0xd3, 0x18, 0x90, 0xfe, 0x1d, 0x15, 0xa6, 0xc9, 0x4f, 0x66, - 0xe6, 0xd1, 0x92, 0xc1, 0x1b, 0xc9, 0x74, 0x43, 0xf7, 0x44, 0xd9, 0x8e, - 0xfd, 0x1a, 0xfc, 0xbe, 0xd9, 0x23, 0x97, 0x23, 0x4b, 0x67, 0xf7, 0x3a, - 0x5f, 0x36, 0xee, 0xb6, 0x9e, 0x66, 0x7b, 0x53, 0x94, 0x58, 0xcd, 0x12, - 0xe0, 0x7f, 0xba, 0x29, 0xfb, 0x84, 0x1c, 0xdd, 0x5f, 0x0a, 0x1b, 0x67, - 0xfd, 0x29, 0x22, 0xe6, 0x26, 0x52, 0x40, 0x8c, 0x64, 0xda, 0x32, 0xf8, - 0x80, 0x43, 0xfe, 0xc8, 0x0c, 0x97, 0xc1, 0x59, 0xe8, 0x7d, 0x51, 0x48, - 0x9c, 0x1c, 0x94, 0xf2, 0xcf, 0x7a, 0xae, 0xf3, 0x23, 0xfd, 0x10, 0x13, - 0x3b, 0x50, 0xdd, 0xc4, 0xbb, 0xe1, 0xd8, 0xea, 0x81, 0x39, 0x4f, 0x4a, - 0xd8, 0xe6, 0x4c, 0xcb, 0x04, 0x7d, 0x67, 0x62, 0xb7, 0x1a, 0xbf, 0xd0, - 0xd3, 0x85, 0x3c, 0x36, 0x57, 0x35, 0xea, 0xc4, 0x05, 0xea, 0x32, 0x6c, - 0x11, 0xe7, 0xbe, 0x6e, 0xe8, 0xe1, 0x19, 0x4d, 0xf4, 0x40, 0x3e, 0x33, - 0xb1, 0xa4, 0x44, 0xc1, 0x4f, 0xf7, 0xf2, 0x2b, 0x0f, 0x9a, 0x3a, 0xbb, - 0x36, 0x25, 0x67, 0x6d, 0x12, 0x51, 0x5f, 0x41, 0xf4, 0x79, 0x9e, 0x13, - 0xe3, 0xb3, 0x62, 0x3d, 0xe3, 0x40, 0x62, 0x66, 0xd6, 0x4c, 0xc5, 0x20, - 0x19, 0xbe, 0x57, 0xb1, 0x96, 0xbd, 0x84, 0x27, 0x67, 0x64, 0x53, 0xfa, - 0x1a, 0x04, 0x28, 0x09, 0xee, 0xf5, 0x8c, 0x27, 0xe8, 0xa7, 0xe8, 0x7c, - 0x47, 0x88, 0xd2, 0x87, 0x1b, 0xab, 0xcb, 0x6e, 0xbd, 0x0d, 0xcc, 0x82, - 0xb9, 0x1b, 0xae, 0xcf, 0x87, 0x58, 0xda, 0xd5, 0x19, 0x5d, 0xfd, 0x28, - 0x0a, 0x5e, 0xb1, 0x2f, 0x77, 0x8b, 0x6a, 0x16, 0x10, 0x45, 0xd4, 0xb2, - 0xa8, 0x6f, 0x3f, 0x3f, 0x01, 0xbe, 0x89, 0x4f, 0xf6, 0xd5, 0x18, 0x4c, - 0x6b, 0x0f, 0x19, 0xdd, 0x3d, 0x5d, 0x62, 0x3e, 0x46, 0x52, 0x25, 0x3f, - 0x0e, 0xd1, 0x2d, 0xb4, 0x74, 0xe3, 0x7c, 0xb8, 0x54, 0x9c, 0x30, 0x3c, - 0x38, 0x25, 0x0d, 0xbd, 0x54, 0x62, 0x8d, 0xd5, 0x07, 0xd6, 0xc3, 0x30, - 0x35, 0x27, 0x2c, 0x97, 0xb7, 0x72, 0x92, 0x49, 0x7b, 0xd7, 0x62, 0x5f, - 0x02, 0x18, 0x0a, 0x12, 0x5a, 0xd9, 0x1e, 0xea, 0xc2, 0x40, 0xbe, 0x33, - 0x25, 0x97, 0xdb, 0xd7, 0x1b, 0x37, 0x12, 0x00, 0x17, 0xba, 0xed, 0x4b, - 0x81, 0x13, 0x7e, 0x6c, 0xb9, 0xe5, 0x1a, 0x48, 0x6c, 0x08, 0xfa, 0x1a, - 0x15, 0xfe, 0xcd, 0x03, 0x4e, 0x9e, 0x94, 0xfa, 0x81, 0x73, 0x96, 0x8e, - 0x71, 0x99, 0x9b, 0x34, 0xf0, 0x5a, 0x9d, 0xf5, 0xa0, 0x94, 0xb8, 0x39, - 0x86, 0x6f, 0xd5, 0xbf, 0xa2, 0x1b, 0xe8, 0xdb, 0x0c, 0xce, 0xad, 0xc6, - 0x3a, 0x22, 0xbb, 0x9b, 0x99, 0x47, 0x85, 0xee, 0xd1, 0xac, 0xf3, 0x6f, - 0x64, 0xa5, 0x6d, 0xe3, 0x2c, 0x94, 0xb0, 0x1a, 0xdf, 0x37, 0xcf, 0xe8, - 0x8a, 0x52, 0x88, 0xe9, 0x69, 0xea, 0xeb, 0x7c, 0x20, 0x7a, 0x25, 0x3f, - 0xb9, 0x54, 0x32, 0x3f, 0xca, 0x1a, 0x0e, 0x87, 0xb6, 0x10, 0xab, 0x1c, - 0x4d, 0xd6, 0xe1, 0xe5, 0xcc, 0xf7, 0x0f, 0xe6, 0x67, 0x7c, 0xbf, 0x82, - 0xfc, 0xf6, 0x8b, 0xf8, 0xe7, 0x0e, 0xf6, 0x7e, 0xb5, 0x72, 0x9d, 0x77, - 0x50, 0xc3, 0x10, 0xfd, 0x05, 0x98, 0xbd, 0x72, 0x2a, 0x3a, 0xd6, 0xfe, - 0x66, 0x98, 0x70, 0x92, 0x94, 0x71, 0x07, 0x01, 0x35, 0xbf, 0x1a, 0xc2, - 0xe4, 0x02, 0x60, 0x94, 0xf3, 0xdb, 0xc7, 0xd6, 0xe6, 0x57, 0x84, 0x5a, - 0x81, 0x31, 0x3b, 0x46, 0x06, 0xa5, 0x56, 0x64, 0x2d, 0x3a, 0x4e, 0xaa, - 0x5d, 0x2c, 0xb0, 0x8d, 0x42, 0x17, 0x9d, 0x98, 0x71, 0x36, 0xfe, 0x46, - 0xc8, 0xfb, 0x25, 0xc3, 0xe7, 0xe5, 0x73, 0x42, 0x32, 0xeb, 0xb2, 0x32, - 0x9a, 0x20, 0x0a, 0x53, 0x4d, 0x8f, 0x5a, 0xd2, 0x81, 0xec, 0x24, 0x73, - 0x7d, 0x0b, 0x35, 0x59, 0xdc, 0x4f, 0x1a, 0x30, 0xb1, 0xb1, 0x3a, 0xa3, - 0x3f, 0xf3, 0x05, 0x84, 0xdc, 0x46, 0xd1, 0x2e, 0x99, 0x46, 0xf0, 0xa6, - 0x77, 0x93, 0x93, 0xb0, 0x37, 0xb3, 0xe6, 0xef, 0x7a, 0x87, 0x0d, 0x83, - 0x16, 0xe5, 0x9f, 0x2a, 0xfe, 0x9c, 0xd6, 0xd7, 0xbe, 0x4b, 0x5b, 0xa7, - 0xdf, 0x57, 0x2c, 0x26, 0x4a, 0x47, 0x1b, 0xd1, 0xb0, 0xd6, 0x2b, 0x9b, - 0x3b, 0x46, 0x51, 0x54, 0xee, 0x65, 0xd9, 0x18, 0x5b, 0xe7, 0xc1, 0x3c, - 0xa7, 0x61, 0xe2, 0x94, 0x12, 0x92, 0x6a, 0x9b, 0xdc, 0x49, 0x8f, 0x01, - 0x92, 0xc1, 0x8b, 0xf7, 0x78, 0x44, 0x7c, 0x9c, 0xc2, 0x42, 0xc2, 0xfb, - 0x31, 0x91, 0xa4, 0xa2, 0xf9, 0x10, 0x06, 0xd5, 0x96, 0x8b, 0xdc, 0x29, - 0x27, 0x64, 0xac, 0xe8, 0x3f, 0x99, 0x25, 0x26, 0x79, 0x00, 0x70, 0x80, - 0x64, 0x07, 0xad, 0x99, 0x66, 0xc3, 0x6e, 0x45, 0x32, 0x4d, 0x48, 0x42, - 0xf4, 0x35, 0x9b, 0x17, 0x00, 0x59, 0xfb, 0x95, 0x80, 0xaf, 0xbf, 0x63, - 0x18, 0x19, 0x0a, 0xb1, 0xdc, 0xe4, 0x3e, 0xd4, 0xf3, 0x1c, 0x2e, 0x08, - 0x0a, 0x44, 0xeb, 0xe2, 0x14, 0x7e, 0xe6, 0x2d, 0xb8, 0x64, 0xad, 0x84, - 0xc5, 0x9f, 0x59, 0x24, 0xbb, 0xe4, 0xc1, 0x76, 0xde, 0xc1, 0x74, 0x90, - 0xdd, 0x80, 0xbb, 0x98, 0x43, 0x52, 0x21, 0x25, 0xa1, 0xed, 0x13, 0x34, - 0x11, 0x1e, 0xad, 0x70, 0xe9, 0x38, 0xc6, 0x48, 0x6c, 0xd8, 0xa7, 0x79, - 0xeb, 0x10, 0x18, 0x95, 0x2b, 0x19, 0xdb, 0x59, 0x9c, 0x6d, 0xac, 0xf5, - 0xb5, 0x64, 0x2d, 0x71, 0xb5, 0x2c, 0x1c, 0x69, 0x4c, 0xaf, 0x23, 0xd3, - 0xdf, 0xbe, 0x36, 0x48, 0xd5, 0xae, 0xa7, 0x2f, 0x3d, 0x3a, 0xbc, 0xd7, - 0x20, 0x89, 0x38, 0x4f, 0x8f, 0x31, 0x38, 0x82, 0xc3, 0x5a, 0xce, 0x63, - 0xe7, 0x16, 0xec, 0xbf, 0x13, 0xab, 0xd9, 0x31, 0xed, 0x9b, 0x88, 0xa5, - 0x5a, 0x84, 0x7f, 0x1e, 0xcf, 0xd3, 0x5c, 0x89, 0xad, 0xac, 0xa4, 0x25, - 0x8b, 0x89, 0x52, 0x4c, 0x0c, 0xbc, 0x8d, 0x85, 0xfc, 0xf4, 0x85, 0xde, - 0x29, 0xb2, 0x6f, 0x80, 0xfd, 0xc1, 0x0e, 0x89, 0xa6, 0x1a, 0xe8, 0xad, - 0x75, 0x02, 0xdc, 0xb4, 0x54, 0xd5, 0xca, 0x3d, 0x5a, 0xd7, 0xa3, 0xaa, - 0xfe, 0xca, 0x77, 0xcc, 0x7f, 0xaf, 0xda, 0xb6, 0x20, 0x5b, 0xcc, 0x88, - 0x70, 0xc1, 0xf0, 0xac, 0x63, 0x3a, 0xc0, 0x92, 0x1e, 0xb4, 0xb7, 0xc1, - 0x57, 0x48, 0x64, 0x9b, 0xd0, 0x8d, 0x11, 0x48, 0xe8, 0xbc, 0xeb, 0x87, - 0xb0, 0x1b, 0xf4, 0x00, 0xcf, 0x83, 0xd3, 0x4f, 0x97, 0xe4, 0xa1, 0x67, - 0xf7, 0xe2, 0x6c, 0xe2, 0x43, 0xc1, 0x21, 0x06, 0x53, 0x88, 0x16, 0x71, - 0x68, 0x07, 0xfc, 0xee, 0xe0, 0x94, 0xe4, 0xa8, 0xba, 0x56, 0x80, 0x51, - 0xac, 0xb7, 0xb3, 0x19, 0xe6, 0xb0, 0x8d, 0x28, 0x6c, 0xd3, 0xa4, 0x66, - 0xf6, 0x9d, 0xd4, 0x60, 0x79, 0x75, 0x57, 0x3a, 0x15, 0x7c, 0x41, 0xcc, - 0xe3, 0xe2, 0x04, 0x9a, 0x5f, 0x0b, 0x32, 0xe6, 0xe5, 0xf8, 0xd8, 0x14, - 0x8f, 0x79, 0x7d, 0x43, 0xf9, 0x7f, 0xcf, 0xbc, 0xb4, 0x04, 0xf4, 0xd5, - 0x51, 0x2f, 0xe8, 0x1e, 0x7d, 0x97, 0xda, 0xea, 0xbc, 0x3c, 0x46, 0xff, - 0xd8, 0xd0, 0xf0, 0xc1, 0xcd, 0xd6, 0x09, 0xee, 0x68, 0xf4, 0x8c, 0xc5, - 0x6c, 0x0b, 0x30, 0xd0, 0x78, 0xdf, 0x1b, 0xb1, 0x4a, 0xdb, 0xf6, 0xf0, - 0x2c, 0xe5, 0x1f, 0xeb, 0xb5, 0x32, 0x7f, 0x83, 0xa0, 0xf6, 0x93, 0x8d, - 0xe7, 0xa4, 0x91, 0xdf, 0x5d, 0xf3, 0xb5, 0xee, 0xb9, 0x1d, 0x2f, 0xa7, - 0x0a, 0x5b, 0x80, 0x34, 0xa0, 0xdb, 0x00, 0x8e, 0x87, 0x07, 0xec, 0xad, - 0x29, 0x7d, 0x7a, 0x6c, 0xb4, 0xa3, 0x78, 0x73, 0xcc, 0x68, 0x78, 0xe0, - 0x7f, 0xb7, 0x6e, 0xdb, 0xe8, 0xd9, 0xfd, 0xde, 0xae, 0xec, 0x16, 0x55, - 0x73, 0xa1, 0x0c, 0xf5, 0xba, 0xbd, 0x40, 0xb1, 0x73, 0x17, 0x1f, 0x73, - 0x66, 0x71, 0x3a, 0x53, 0xb3, 0x50, 0xfc, 0xa9, 0xf6, 0xbc, 0xe8, 0x23, - 0x9f, 0x1f, 0x18, 0x32, 0x32, 0xb6, 0x44, 0x48, 0x4f, 0x46, 0xb8, 0x96, - 0xa8, 0xc2, 0x87, 0xf7, 0x93, 0x3f, 0xbf, 0x4a, 0x60, 0xff, 0x9e, 0x46, - 0x9f, 0x7c, 0xc4, 0xee, 0xe0, 0x36, 0x1b, 0x90, 0x9f, 0x19, 0xb1, 0xe5, - 0xc3, 0x0d, 0xb2, 0xc3, 0x72, 0x32, 0xd4, 0xf2, 0x6f, 0xb2, 0xcd, 0xa6, - 0x78, 0x26, 0x65, 0x94, 0x4b, 0x49, 0xd9, 0x17, 0xad, 0x71, 0x59, 0x8d, - 0xaf, 0xc9, 0xfb, 0xeb, 0xf5, 0x01, 0xfa, 0x49, 0xaf, 0x21, 0xbf, 0x0d, - 0x63, 0xbd, 0x42, 0x52, 0x96, 0x22, 0x23, 0xb8, 0x3b, 0x43, 0x74, 0x07, - 0x0b, 0x7d, 0x74, 0x81, 0xb4, 0x45, 0x4e, 0xe3, 0x8d, 0x5b, 0xdc, 0x46, - 0x67, 0x60, 0xea, 0x3f, 0xb0, 0xfa, 0xf7, 0x9d, 0x6b, 0x38, 0x76, 0x9f, - 0xbf, 0x93, 0xd7, 0x9a, 0x73, 0x27, 0x54, 0x0c, 0xed, 0x12, 0xd1, 0x58, - 0xa7, 0xf1, 0x22, 0x59, 0xf1, 0xa9, 0x29, 0x13, 0xe4, 0x32, 0x9f, 0xca, - 0x85, 0xa2, 0xc9, 0xfd, 0xd0, 0x8a, 0x71, 0xd5, 0xb2, 0x60, 0xdf, 0x7d, - 0x9c, 0x9a, 0xa3, 0x5e, 0xb2, 0x1e, 0x0b, 0x2c, 0xea, 0xba, 0xbb, 0x6f, - 0x49, 0xec, 0x7a, 0x24, 0x73, 0xcb, 0x82, 0x12, 0xf3, 0x34, 0x3b, 0x22, - 0x36, 0x7a, 0xd4, 0x17, 0xf5, 0x4a, 0x18, 0x00, 0x79, 0xdc, 0x3d, 0x6b, - 0x00, 0x42, 0xc1, 0x28, 0xbb, 0xa0, 0x77, 0xd4, 0x8e, 0x5f, 0x15, 0x9d, - 0x2a, 0xe1, 0x07, 0xbc, 0x5c, 0x66, 0xf1, 0xbd, 0x18, 0x7f, 0x70, 0xfe, - 0xed, 0x94, 0x70, 0x7a, 0x87, 0xe2, 0x39, 0x55, 0x56, 0xa5, 0x20, 0x8f, - 0xdd, 0xac, 0x65, 0x96, 0x2f, 0x6a, 0xc6, 0x90, 0xb1, 0x0c, 0x8d, 0x49, - 0x11, 0xb1, 0x77, 0x61, 0x80, 0xdf, 0xfa, 0xca, 0x88, 0x53, 0x8a, 0xb8, - 0x69, 0xc7, 0x6b, 0x9f, 0x72, 0xec, 0xea, 0x10, 0x50, 0xfc, 0x75, 0xdb, - 0x51, 0xe1, 0x39, 0x44, 0x3c, 0x09, 0x7a, 0xaf, 0x08, 0x83, 0xc9, 0x15, - 0x31, 0xe4, 0xe5, 0xe4, 0x92, 0x13, 0x99, 0x9e, 0x9e, 0x3a, 0x53, 0x4a, - 0xf6, 0x89, 0xdc, 0x49, 0x72, 0xcb, 0xf4, 0xcb, 0x79, 0x68, 0x40, 0xd6, - 0x4b, 0xf8, 0xea, 0x55, 0x5e, 0x37, 0x01, 0x00, 0xe9, 0xc1, 0xfe, 0x65, - 0xa1, 0xcc, 0x90, 0x94, 0x62, 0x1c, 0x16, 0x29, 0xeb, 0x31, 0xca, 0x32, - 0xdc, 0xaa, 0xe2, 0x83, 0xaf, 0x36, 0xcf, 0xf8, 0x8b, 0x27, 0x75, 0x9d, - 0x59, 0x44, 0x9a, 0x01, 0x7c, 0xe6, 0x0b, 0x5a, 0x33, 0x22, 0xe6, 0xe2, - 0x2a, 0x35, 0x13, 0xf4, 0xca, 0x93, 0x31, 0x67, 0x84, 0x5b, 0x2e, 0x07, - 0x09, 0x7e, 0xb1, 0x24, 0xbf, 0x8b, 0x73, 0xbf, 0xec, 0x27, 0x67, 0xe0, - 0xb6, 0x68, 0x8d, 0x93, 0x3e, 0x67, 0x9d, 0xec, 0xea, 0x87, 0xbc, 0x21, - 0xd2, 0x9f, 0x64, 0x99, 0x34, 0xca, 0x04, 0x55, 0x89, 0xca, 0x84, 0xe1, - 0x53, 0x87, 0xcb, 0x93, 0x54, 0xc9, 0x91, 0xee, 0x7f, 0x04, 0xa8, 0xe1, - 0xda, 0xaa, 0x83, 0xb7, 0x0b, 0x7f, 0x95, 0xae, 0xb0, 0x10, 0x53, 0x06, - 0x4f, 0x2c, 0x53, 0x2f, 0xf8, 0xda, 0x64, 0xc8, 0xdf, 0x93, 0x40, 0x33, - 0x36, 0xa9, 0x70, 0x9f, 0x53, 0xc1, 0x27, 0x3b, 0xad, 0xf8, 0x19, 0xe9, - 0x7e, 0x3b, 0x82, 0xbc, 0x8a, 0xa3, 0xba, 0x88, 0xc2, 0x6d, 0x9f, 0xe0, - 0xe2, 0x4e, 0x47, 0x45, 0x51, 0xb0, 0xca, 0xbd, 0x18, 0x6f, 0xdb, 0xa0, - 0x8c, 0xc2, 0x76, 0x5c, 0xf2, 0x71, 0x56, 0x75, 0x4d, 0x6e, 0x7f, 0x3f, - 0xfc, 0x25, 0x55, 0x95, 0xe2, 0xba, 0xca, 0x38, 0xc3, 0x9d, 0x04, 0xc1, - 0xac, 0xa0, 0x8b, 0x17, 0x18, 0x74, 0x70, 0xdb, 0x1c, 0xaa, 0xd0, 0xef, - 0x6f, 0x74, 0xe2, 0x1c, 0x48, 0x95, 0xc8, 0x3d, 0xc6, 0x7c, 0x63, 0xe3, - 0xa6, 0x51, 0x51, 0x6b, 0x5b, 0x46, 0x19, 0x89, 0xfc, 0x20, 0xed, 0xf7, - 0xcb, 0xc5, 0xbf, 0x0b, 0x25, 0x67, 0x72, 0xd3, 0x60, 0x28, 0x26, 0x4e, - 0xf3, 0x7e, 0xe0, 0x15, 0x74, 0xb5, 0x8e, 0x2a, 0x1f, 0x95, 0xbb, 0xa7, - 0x72, 0xd3, 0x05, 0xb2, 0x4f, 0x22, 0x61, 0x22, 0xce, 0x85, 0xb3, 0x7b, - 0xeb, 0xb2, 0x58, 0xf5, 0x0c, 0x36, 0x2f, 0x3c, 0x7b, 0x2e, 0xae, 0x48, - 0x09, 0x12, 0x8a, 0xc0, 0x2a, 0xbe, 0x1c, 0xfe, 0xc9, 0xcf, 0xaa, 0x41, - 0xf1, 0x9a, 0x12, 0xe7, 0xa3, 0x6e, 0x01, 0x04, 0x80, 0xb5, 0x75, 0x65, - 0xb0, 0xc9, 0xb0, 0x24, 0x40, 0x71, 0x61, 0x6b, 0xa9, 0x1b, 0x92, 0x6a, - 0x39, 0x98, 0x88, 0x67, 0xe0, 0x75, 0x47, 0x1c, 0x87, 0x69, 0xda, 0xc9, - 0x16, 0xc7, 0xb1, 0x24, 0x9b, 0xdf, 0xf4, 0xd9, 0xff, 0xec, 0xa1, 0x7c, - 0xc3, 0x97, 0xad, 0x92, 0x94, 0x4f, 0xc1, 0xfc, 0xc8, 0x49, 0x3a, 0xe7, - 0xac, 0xc6, 0x62, 0x84, 0xe2, 0xad, 0xd7, 0x11, 0x8b, 0x56, 0xd6, 0xf8, - 0xd0, 0xda, 0xf1, 0xb9, 0xbe, 0x7d, 0xcb, 0xca, 0x96, 0x72, 0x76, 0x02, - 0x35, 0x38, 0x2b, 0xe4, 0x8a, 0xcd, 0xa1, 0x9c, 0x42, 0x01, 0x7e, 0x00, - 0x9b, 0x2b, 0xbe, 0x8e, 0x08, 0x5a, 0x54, 0xad, 0x0f, 0xcd, 0x7c, 0x0f, - 0xa9, 0x95, 0xcc, 0x27, 0xd8, 0x63, 0xc2, 0xa2, 0x6b, 0xf0, 0x73, 0x42, - 0x51, 0x7d, 0xe5, 0xb6, 0x34, 0xd4, 0x5f, 0x54, 0x3a, 0x64, 0xc1, 0x32, - 0x6b, 0x16, 0x55, 0x82, 0xc7, 0x63, 0x5f, 0x21, 0x1a, 0x75, 0xb7, 0xcc, - 0xb5, 0xcd, 0x51, 0xb7, 0x42, 0x77, 0xea, 0x10, 0x5f, 0x17, 0x4e, 0xf3, - 0xaa, 0xe8, 0x53, 0x67, 0x72, 0xaa, 0xf1, 0x7d, 0x0b, 0xb4, 0xe1, 0x15, - 0x9e, 0x87, 0x75, 0xdc, 0x78, 0x8e, 0xb1, 0xd9, 0x94, 0x06, 0x8a, 0xe8, - 0x2a, 0x3a, 0xf2, 0x6c, 0x36, 0xe1, 0x35, 0x84, 0x15, 0xe6, 0xd4, 0x6a, - 0xc4, 0x14, 0x9c, 0xbc, 0x0e, 0xe7, 0xce, 0xad, 0xb8, 0xc7, 0x32, 0x62, - 0xff, 0xb6, 0x6d, 0xde, 0x44, 0xc2, 0xa1, 0x27, 0xdf, 0x59, 0x10, 0xb9, - 0x0f, 0x70, 0x53, 0x07, 0x81, 0xee, 0xf4, 0x76, 0xd2, 0x0a, 0xd7, 0x77, - 0x24, 0x20, 0x74, 0xc0, 0xc5, 0xda, 0x6a, 0x07, 0x8d, 0x6f, 0x03, 0x96, - 0x9d, 0xe6, 0x66, 0xc2, 0x37, 0xa3, 0x11, 0xe4, 0x07, 0xa8, 0x0a, 0x05, - 0xaa, 0x10, 0x3d, 0xe9, 0xd4, 0xb4, 0x6a, 0xc6, 0x54, 0xf9, 0xd2, 0xed, - 0xfa, 0x73, 0x5d, 0xfd, 0x9a, 0x9d, 0x08, 0x59, 0xcf, 0xf9, 0xd0, 0xe5, - 0xe3, 0x6d, 0xc2, 0x0b, 0xb9, 0x5d, 0x02, 0x2e, 0x1f, 0xbd, 0x9c, 0x16, - 0x97, 0x99, 0x92, 0x4d, 0x2a, 0xe0, 0xa2, 0x06, 0x7c, 0x41, 0x79, 0x18, - 0x4d, 0xbe, 0x5c, 0x2f, 0x29, 0xab, 0xfc, 0x8c, 0xd5, 0xb8, 0xc9, 0x5d, - 0x54, 0xbe, 0xfd, 0x7c, 0x2f, 0x4b, 0x1c, 0x1e, 0x8a, 0x0c, 0x31, 0xbf, - 0xd7, 0xb0, 0x44, 0xfe, 0xa0, 0x3d, 0x86, 0x17, 0x47, 0x7c, 0xd9, 0xab, - 0xb9, 0x84, 0xe3, 0x12, 0x84, 0xb5, 0x73, 0x66, 0x31, 0x33, 0x8a, 0x53, - 0x6b, 0x33, 0x68, 0x0f, 0xaf, 0x75, 0x5b, 0x86, 0xea, 0xba, 0x15, 0xe1, - 0xfd, 0x75, 0xc6, 0x45, 0x23, 0x87, 0x03, 0xba, 0x91, 0x98, 0x1c, 0x62, - 0xb7, 0x9f, 0x75, 0xab, 0x83, 0xf9, 0xcf, 0xeb, 0x02, 0x3a, 0xd9, 0x3c, - 0x17, 0x68, 0xdf, 0xd7, 0x06, 0x12, 0x65, 0xcb, 0x30, 0x52, 0x7f, 0x15, - 0x42, 0xaa, 0x7d, 0x1b, 0xe3, 0xfe, 0x62, 0x88, 0x3b, 0xb8, 0x89, 0xfe, - 0xe3, 0xf6, 0x2a, 0x2c, 0x23, 0x5d, 0xdb, 0xa2, 0x6d, 0x70, 0x9f, 0xbd, - 0xa7, 0x4c, 0x7c, 0xff, 0x7c, 0x8c, 0x29, 0xa8, 0x93, 0xd9, 0xea, 0x1b, - 0xd8, 0x0c, 0xaa, 0x2f, 0xfe, 0xf5, 0x49, 0x4c, 0x9c, 0x01, 0xa5, 0xf6, - 0xb6, 0xc5, 0x36, 0xad, 0x05, 0x2d, 0x89, 0x12, 0xb7, 0x1f, 0x36, 0x57, - 0xd6, 0x26, 0x82, 0x06, 0x37, 0xcb, 0xcc, 0x0d, 0x18, 0x31, 0xcd, 0x91, - 0xed, 0x95, 0xe6, 0xbc, 0x3a, 0x92, 0x7c, 0x01, 0xf9, 0xd8, 0x1c, 0xc9, - 0xe5, 0x66, 0x33, 0x47, 0x6e, 0xde, 0xe2, 0xd1, 0x1a, 0xbc, 0x3e, 0x1e, - 0x74, 0x56, 0x93, 0x11, 0x86, 0x51, 0x57, 0x4d, 0x6c, 0xa2, 0x95, 0x39, - 0xb9, 0xe3, 0x0a, 0x31, 0x3f, 0x3d, 0xb7, 0x9f, 0x6e, 0x0f, 0x5c, 0x01, - 0x37, 0x24, 0xde, 0x2c, 0xab, 0xb2, 0x28, 0x28, 0x81, 0x1b, 0xa9, 0x38, - 0x22, 0xcb, 0x67, 0x2e, 0x17, 0xb4, 0x3f, 0x93, 0x2d, 0x85, 0x1c, 0x4a, - 0xc8, 0xa9, 0xab, 0x3a, 0xaa, 0xb5, 0xec, 0x33, 0x77, 0x3f, 0xfc, 0x1f, - 0xa2, 0x3e, 0xab, 0xac, 0xaa, 0x15, 0x0d, 0xc4, 0x13, 0x11, 0xc4, 0xc5, - 0x9d, 0xf6, 0xb5, 0x52, 0xba, 0x01, 0xd1, 0x19, 0x7f, 0x1b, 0x87, 0x81, - 0x33, 0xed, 0xe0, 0x01, 0x48, 0x5c, 0xbf, 0xef, 0x03, 0xf8, 0xf3, 0x56, - 0x34, 0x70, 0xd8, 0xf1, 0x92, 0x9d, 0x71, 0xce, 0xc7, 0x0e, 0xbc, 0x68, - 0xff, 0xd1, 0x8b, 0x5a, 0xec, 0x97, 0x3f, 0x98, 0x3d, 0xe6, 0x1c, 0xa2, - 0x37, 0xc7, 0xbd, 0x26, 0x3c, 0x8c, 0x8f, 0xcd, 0x21, 0x17, 0x3d, 0xac, - 0x61, 0x44, 0x89, 0xa7, 0x41, 0xa7, 0xb8, 0x03, 0xde, 0xa1, 0x2c, 0x52, - 0x52, 0xd8, 0x01, 0xb3, 0x47, 0x57, 0x92, 0x00, 0x1c, 0x7a, 0x97, 0x0c, - 0x15, 0x5f, 0x31, 0xa4, 0x53, 0xa3, 0x74, 0x3f, 0x1d, 0xdf, 0x6d, 0x4e, - 0x78, 0xb6, 0x9e, 0x19, 0x55, 0x52, 0x47, 0xec, 0xc3, 0xb5, 0x38, 0x3a, - 0x75, 0xd6, 0x2e, 0x43, 0x47, 0x1d, 0x03, 0xec, 0xa6, 0xe3, 0xc1, 0x33, - 0x97, 0x25, 0x4e, 0xa3, 0x17, 0xe1, 0x1b, 0x52, 0xd5, 0x4d, 0xe4, 0x4d, - 0x9d, 0x54, 0x7c, 0x89, 0x8d, 0x36, 0xab, 0x22, 0x96, 0x2a, 0x19, 0x7f, - 0x57, 0x6a, 0xc0, 0x5c, 0x3a, 0x7e, 0xe8, 0x59, 0xb1, 0x97, 0xe6, 0x94, - 0xcc, 0x64, 0x21, 0x2b, 0x44, 0xd9, 0xf7, 0xd2, 0x20, 0x75, 0x5a, 0x0f, - 0x49, 0x73, 0x1b, 0xd9, 0x06, 0x61, 0x78, 0x37, 0xcd, 0x20, 0xf0, 0x83, - 0xed, 0x3b, 0x74, 0xde, 0x33, 0x7d, 0xb2, 0x10, 0x69, 0x0c, 0x5a, 0xdb, - 0x61, 0x64, 0xf1, 0xc4, 0x8b, 0x19, 0x20, 0xc3, 0xb2, 0x4e, 0x8d, 0xbd, - 0x90, 0xb8, 0x11, 0x06, 0xac, 0xe6, 0xf4, 0x25, 0xa4, 0x2e, 0x80, 0xa5, - 0x57, 0x07, 0xc2, 0x8b, 0xf7, 0x87, 0x73, 0x36, 0xe4, 0xfe, 0x22, 0x49, - 0x4f, 0xa1, 0x83, 0x5d, 0x7f, 0x3b, 0x95, 0x66, 0x53, 0x99, 0x14, 0x4e, - 0xe9, 0x2b, 0x5f, 0xe4, 0x39, 0x20, 0x1b, 0x2c, 0xa4, 0x57, 0x90, 0x58, - 0xe4, 0x8d, 0xe4, 0xbf, 0x76, 0x3f, 0x58, 0x96, 0x98, 0x1b, 0xe8, 0x9e, - 0xd9, 0xdc, 0x37, 0x7e, 0xb2, 0xbc, 0x7c, 0x3c, 0x56, 0x91, 0xd9, 0x83, - 0x0e, 0xa7, 0x1e, 0x8e, 0x2c, 0x2a, 0x3c, 0xee, 0x2d, 0x2f, 0x6c, 0xc8, - 0xab, 0xdf, 0x61, 0xfa, 0x1e, 0x35, 0x01, 0x88, 0x40, 0x2e, 0xb6, 0x35, - 0x7f, 0x70, 0x3c, 0x41, 0x57, 0x41, 0xa4, 0x70, 0x51, 0xd2, 0x46, 0xe8, - 0xe9, 0xd0, 0x5c, 0xd1, 0x3e, 0x07, 0xbb, 0x8d, 0x54, 0x49, 0xf5, 0x1a, - 0x5b, 0x07, 0xe2, 0x53, 0x57, 0x85, 0x0c, 0x7f, 0x14, 0x6d, 0x32, 0x80, - 0xbd, 0x0a, 0x78, 0xf6, 0x8a, 0xd7, 0x41, 0x27, 0xe7, 0x2a, 0x68, 0x2c, - 0x5c, 0xe5, 0x06, 0x7f, 0x2d, 0x80, 0x5b, 0xd2, 0x49, 0x00, 0xaa, 0x6d, - 0xf6, 0xa4, 0x3a, 0xc7, 0x44, 0xdc, 0x79, 0xc3, 0xc4, 0xc2, 0x3f, 0x0b, - 0x14, 0x31, 0xb9, 0x02, 0x55, 0x7e, 0x31, 0x1d, 0xa4, 0x3d, 0xbf, 0xc0, - 0x6f, 0x1a, 0xf7, 0x82, 0x59, 0xb7, 0xfc, 0x62, 0xb0, 0x5f, 0xe6, 0x55, - 0x15, 0xe5, 0xa7, 0xf1, 0x61, 0xbc, 0xad, 0x2c, 0x44, 0xd5, 0x23, 0x86, - 0xce, 0x38, 0xdb, 0x74, 0x48, 0xcf, 0x0c, 0x04, 0xec, 0x34, 0x52, 0xc5, - 0xe0, 0xdc, 0x92, 0xf7, 0x24, 0x7b, 0x4d, 0x2f, 0xc8, 0x55, 0x69, 0x94, - 0x9f, 0xa0, 0x95, 0xfe, 0xda, 0x43, 0xc0, 0x46, 0xfc, 0xcd, 0xf0, 0x1c, - 0x05, 0x33, 0x7d, 0xc2, 0x96, 0x33, 0xa8, 0x2d, 0xd9, 0x03, 0x5a, 0x02, - 0xb5, 0x9e, 0xfc, 0x60, 0x16, 0x76, 0xe3, 0x2e, 0xb4, 0x3d, 0xbb, 0xc6, - 0x45, 0xa0, 0x7d, 0xa4, 0xec, 0x6d, 0xcb, 0xf6, 0xdb, 0xed, 0xca, 0x60, - 0x4d, 0x6f, 0x96, 0xf9, 0xda, 0x6b, 0x1b, 0x7d, 0x3c, 0xf5, 0x4e, 0xec, - 0x8b, 0xfc, 0xee, 0x2a, 0x81, 0xc6, 0x7d, 0x60, 0xe1, 0xe6, 0x1d, 0x66, - 0x5d, 0x22, 0xcd, 0x39, 0x08, 0x4e, 0x1f, 0x09, 0x5a, 0x39, 0xe6, 0x78, - 0x34, 0x2f, 0x4a, 0xcc, 0x70, 0x35, 0x7e, 0xef, 0x22, 0x21, 0xdd, 0xcf, - 0x47, 0xb5, 0xfc, 0xb5, 0xfb, 0xcc, 0xc6, 0xf6, 0x6d, 0x90, 0x86, 0x17, - 0x58, 0x4e, 0xe9, 0x83, 0x78, 0x58, 0x98, 0x6d, 0xa8, 0xcd, 0x5c, 0xe9, - 0x40, 0x7f, 0x09, 0x3f, 0xbd, 0x33, 0xec, 0x6d, 0x68, 0xe9, 0x59, 0x9a, - 0xcd, 0x01, 0x74, 0x6b, 0xe7, 0x8c, 0x18, 0x63, 0x18, 0x9d, 0x80, 0x4f, - 0x2f, 0xca, 0x5e, 0xef, 0xd3, 0x65, 0xb6, 0xfe, 0xa4, 0x08, 0x43, 0x18, - 0x0f, 0xb5, 0x17, 0x1b, 0xa2, 0x71, 0xad, 0xea, 0x6b, 0x26, 0x8a, 0x7f, - 0x95, 0x22, 0x18, 0x55, 0x1c, 0xa3, 0x41, 0x0f, 0x13, 0x9c, 0xc8, 0xe0, - 0x24, 0xf7, 0x0d, 0x86, 0xa2, 0xf7, 0x2d, 0xbb, 0x4d, 0xc5, 0x47, 0x70, - 0xfb, 0xcc, 0xa7, 0x77, 0x83, 0xb5, 0x16, 0x72, 0xcb, 0xb1, 0x98, 0x89, - 0xe6, 0xef, 0xe8, 0xa5, 0x14, 0xe8, 0xf5, 0x34, 0x19, 0x30, 0x9c, 0xe9, - 0xd5, 0xcd, 0x34, 0x07, 0x39, 0x0e, 0xef, 0x56, 0xcf, 0x32, 0x5a, 0x90, - 0x48, 0x42, 0x28, 0x1a, 0xb5, 0xb9, 0xa5, 0x56, 0x65, 0x48, 0xce, 0xf8, - 0xf9, 0x2e, 0xc8, 0x97, 0xf9, 0x0c, 0x62, 0x16, 0x8d, 0x63, 0x15, 0xaf, - 0x70, 0x8a, 0x9c, 0xd5, 0xd7, 0x4a, 0x19, 0x53, 0xe0, 0x69, 0xb6, 0xba, - 0x92, 0x49, 0xc8, 0x95, 0xbb, 0x00, 0x37, 0x12, 0x6f, 0xb8, 0xe7, 0x5f, - 0x0b, 0xcc, 0xc9, 0x58, 0x17, 0xb1, 0x22, 0x98, 0x9e, 0x0b, 0x2b, 0xc4, - 0x66, 0xfb, 0x9c, 0x0f, 0xa8, 0x71, 0x32, 0x3d, 0x22, 0x3b, 0x5d, 0x7d, - 0x5a, 0xe5, 0x40, 0x11, 0xba, 0xca, 0x9d, 0x6f, 0x0a, 0xc9, 0x4c, 0xfe, - 0x1d, 0x41, 0x3b, 0x66, 0x90, 0x8f, 0x1f, 0xd7, 0x1c, 0xbf, 0xf0, 0x3f, - 0x4e, 0xff, 0xac, 0x52, 0x66, 0xb5, 0xdb, 0x35, 0x3a, 0xdc, 0x50, 0x3f, - 0xf4, 0xcf, 0x3b, 0x39, 0xc0, 0xe0, 0xb7, 0x4b, 0x7d, 0x11, 0x10, 0x87, - 0xdf, 0xf7, 0xd9, 0x8c, 0x17, 0x28, 0x00, 0x53, 0x9e, 0x90, 0x07, 0x85, - 0x66, 0x52, 0xd8, 0x84, 0xb0, 0x9a, 0x57, 0x4b, 0xf6, 0x74, 0x5e, 0xde, - 0x6c, 0x33, 0x60, 0x8d, 0xe6, 0x0f, 0x29, 0x54, 0x36, 0x9a, 0xbd, 0xc6, - 0x65, 0x62, 0x42, 0x3b, 0x5f, 0x2f, 0x57, 0x20, 0x26, 0x4e, 0xc3, 0x10, - 0x07, 0xce, 0x1f, 0x28, 0xa5, 0x67, 0xe6, 0x35, 0x1e, 0x8c, 0x32, 0x05, - 0x9d, 0x85, 0xe3, 0x9d, 0x7f, 0x74, 0x34, 0x0f, 0xfd, 0xa3, 0x98, 0x42, - 0x44, 0xf0, 0x16, 0x27, 0xe3, 0x39, 0x35, 0xec, 0x6f, 0x6f, 0x33, 0xf5, - 0x68, 0x19, 0x83, 0xa4, 0x40, 0xbd, 0x1f, 0xf8, 0x4b, 0x0e, 0x9b, 0x2d, - 0x7c, 0x41, 0x85, 0xec, 0x2f, 0x72, 0xa5, 0xa0, 0x4a, 0x47, 0x55, 0x94, - 0xc6, 0x17, 0x18, 0x6c, 0xfd, 0x03, 0x44, 0x1b, 0xae, 0xeb, 0xb6, 0xdf, - 0x05, 0x5d, 0xa6, 0x99, 0xb3, 0x53, 0xcb, 0x67, 0x77, 0x85, 0xb6, 0xb2, - 0xab, 0x8d, 0x7a, 0x64, 0xb9, 0xfe, 0xda, 0xd2, 0xad, 0x18, 0x86, 0x7b, - 0xe5, 0x98, 0x7e, 0x08, 0x4b, 0x78, 0x38, 0xde, 0x23, 0x23, 0x10, 0x76, - 0x0d, 0x61, 0xf6, 0x86, 0xd6, 0xba, 0xb6, 0xb8, 0x98, 0x0c, 0xca, 0xe6, - 0x17, 0xb6, 0x08, 0x58, 0x42, 0xef, 0x9d, 0x12, 0x51, 0xef, 0x52, 0x28, - 0xf8, 0xb5, 0x19, 0x82, 0xe1, 0x6f, 0x5f, 0xfa, 0x2c, 0x80, 0x9c, 0xe8, - 0x30, 0x74, 0x8c, 0x78, 0x63, 0x47, 0x91, 0xda, 0x1f, 0x4f, 0x59, 0x24, - 0x92, 0x76, 0xc3, 0x3c, 0x19, 0x18, 0xa9, 0x15, 0xbc, 0x18, 0xd0, 0xb4, - 0x15, 0xd7, 0x46, 0xed, 0x73, 0xa5, 0xdd, 0xcb, 0x28, 0x8a, 0xe8, 0x68, - 0x80, 0xfb, 0x44, 0x3f, 0x9c, 0x60, 0xf6, 0x21, 0x3e, 0xf3, 0x9e, 0x46, - 0x99, 0x0f, 0x55, 0x24, 0xd7, 0xa4, 0xa1, 0x5e, 0x42, 0x20, 0xf2, 0xf9, - 0x99, 0x42, 0x93, 0x39, 0xf2, 0x66, 0x2e, 0x47, 0x1e, 0x5b, 0x22, 0xb8, - 0xc7, 0x38, 0x45, 0x16, 0x47, 0x08, 0x88, 0xb4, 0xbf, 0xc2, 0xc3, 0x7e, - 0x58, 0x31, 0xad, 0xb0, 0xa6, 0x9b, 0x12, 0x0f, 0xb5, 0x18, 0x3c, 0x2e, - 0x46, 0x05, 0xba, 0x85, 0x9b, 0x1f, 0xdf, 0x47, 0xeb, 0xe7, 0x09, 0x41, - 0x2d, 0x9f, 0xcb, 0x5c, 0xa1, 0xc4, 0x0e, 0xb1, 0x7c, 0x50, 0x11, 0x0a, - 0x4d, 0x50, 0x8a, 0x29, 0x5a, 0x89, 0x02, 0xa5, 0xda, 0x3b, 0x6e, 0x0d, - 0x29, 0xba, 0xa5, 0xde, 0xac, 0x0f, 0x3b, 0xa3, 0xb5, 0xf2, 0x29, 0x38, - 0xe1, 0xbc, 0x90, 0x31, 0xb8, 0xe6, 0x13, 0xf6, 0x11, 0xd5, 0x4f, 0xd3, - 0xfa, 0xac, 0x92, 0xa7, 0x1d, 0x01, 0x47, 0x07, 0xe1, 0x1c, 0xf9, 0xc5, - 0x70, 0x6c, 0xf9, 0x1c, 0x4e, 0xdd, 0x97, 0x6c, 0xac, 0xa4, 0xd4, 0x1f, - 0x71, 0xde, 0xac, 0x7c, 0x8d, 0x7f, 0x12, 0x63, 0x40, 0x79, 0x6b, 0x78, - 0x78, 0xf9, 0x8b, 0x67, 0xe0, 0xfe, 0x0a, 0xfc, 0xc2, 0x3a, 0x8d, 0x02, - 0xcf, 0x89, 0xa1, 0xb1, 0x1c, 0x1e, 0x6e, 0xaf, 0x94, 0xef, 0x24, 0xee, - 0xd4, 0xd1, 0x95, 0xe2, 0x85, 0xab, 0x24, 0xe7, 0x85, 0xd1, 0xbd, 0xe0, - 0x2c, 0xdc, 0x27, 0x3e, 0x51, 0x9e, 0x9f, 0x77, 0xf8, 0xca, 0x52, 0x2d, - 0x00, 0xb6, 0xcd, 0xb6, 0x38, 0x3a, 0xfd, 0xb8, 0x1c, 0x10, 0x31, 0xe3, - 0x87, 0x90, 0xa1, 0x74, 0x84, 0x26, 0x09, 0xcf, 0x5f, 0x5b, 0xf3, 0x43, - 0x76, 0x50, 0xbc, 0x91, 0x71, 0x94, 0x8d, 0x2c, 0xe3, 0x0b, 0x88, 0xff, - 0x50, 0x04, 0xac, 0x3d, 0x96, 0x17, 0x7e, 0x6f, 0xcd, 0xc9, 0x77, 0x50, - 0x48, 0x1c, 0x3b, 0x7a, 0x95, 0x27, 0x3e, 0x1f, 0x7d, 0x2a, 0x70, 0x1d, - 0xa9, 0x57, 0x47, 0x9c, 0x20, 0x84, 0x8b, 0xe1, 0x97, 0x80, 0x9d, 0xd9, - 0xf8, 0xb4, 0x5c, 0xea, 0xbb, 0x31, 0x5a, 0x48, 0x33, 0xa5, 0x46, 0x69, - 0x92, 0x76, 0x71, 0x1e, 0x14, 0xec, 0x5b, 0x07, 0xbd, 0x91, 0xc7, 0x18, - 0xc3, 0x97, 0xe3, 0x1e, 0x0d, 0x4b, 0xe2, 0x0c, 0x25, 0xf4, 0xbe, 0xb3, - 0x7a, 0xa2, 0xdf, 0x4f, 0x2c, 0x2b, 0x0f, 0x88, 0xa2, 0x1a, 0xfc, 0xe9, - 0x65, 0x19, 0x23, 0xbb, 0xc3, 0xdb, 0x39, 0x85, 0x30, 0x8f, 0x49, 0x7e, - 0x88, 0xc1, 0x44, 0x0b, 0x99, 0xfb, 0x29, 0x15, 0x06, 0x00, 0x7e, 0x77, - 0x41, 0xc3, 0xc6, 0x7a, 0x09, 0x0d, 0x78, 0x29, 0xe4, 0x4b, 0x0a, 0x2c, - 0x78, 0x22, 0x10, 0x22, 0x43, 0xf0, 0x2e, 0x1c, 0x82, 0x24, 0x24, 0x23, - 0x41, 0x84, 0xdb, 0xc6, 0x19, 0x39, 0xbf, 0xb8, 0x4e, 0x22, 0xfa, 0xe6, - 0x89, 0x21, 0x57, 0x29, 0xa3, 0x6e, 0xc7, 0xb5, 0xc0, 0xaf, 0xc8, 0xa8, - 0xbd, 0x20, 0xf2, 0x32, 0xe0, 0x88, 0x39, 0xe6, 0x1c, 0xea, 0xa0, 0xdb, - 0xce, 0xd9, 0x2e, 0xd9, 0x00, 0xb9, 0xad, 0xd0, 0xd2, 0x68, 0xa5, 0x2b, - 0x04, 0x8d, 0xa4, 0x9c, 0x4e, 0xdc, 0xf7, 0x27, 0x56, 0xc7, 0x73, 0x4a, - 0xec, 0xf3, 0xd7, 0x9a, 0x52, 0xb7, 0x62, 0xa6, 0x2c, 0xa1, 0xe0, 0xb4, - 0x67, 0x16, 0x4c, 0xf8, 0x04, 0x5a, 0xa9, 0xf1, 0xf6, 0x8f, 0x49, 0x89, - 0x81, 0x62, 0x7d, 0x3e, 0x55, 0x0f, 0x4e, 0xb0, 0xb7, 0xec, 0xeb, 0x3d, - 0xb0, 0x73, 0x29, 0x81, 0x4b, 0x07, 0xa0, 0xce, 0x2b, 0x6a, 0x22, 0x75, - 0x70, 0x9f, 0x51, 0xde, 0x9e, 0xee, 0xe4, 0x65, 0xbf, 0x16, 0x1c, 0xfc, - 0xba, 0x93, 0xba, 0x48, 0x54, 0x22, 0x8e, 0xac, 0x7f, 0xac, 0xb4, 0xd8, - 0x65, 0x93, 0x65, 0x4a, 0x56, 0x8f, 0x1a, 0xa6, 0xe1, 0x9c, 0x2f, 0xab, - 0x87, 0x06, 0xd4, 0x32, 0xa5, 0xbd, 0x3c, 0x41, 0xa2, 0xd0, 0x42, 0x85, - 0x95, 0xdd, 0xb9, 0xaf, 0x1f, 0x20, 0xe2, 0xdd, 0x59, 0x66, 0xc9, 0x0d, - 0xb9, 0xea, 0x19, 0x4c, 0xb0, 0x00, 0xd1, 0xe5, 0x29, 0xa2, 0x40, 0x2f, - 0xf8, 0x0b, 0xde, 0x78, 0x52, 0xcb, 0x72, 0x81, 0xd6, 0xdf, 0x38, 0x03, - 0xe0, 0xba, 0xa8, 0xbf, 0x84, 0x7c, 0xcd, 0xeb, 0x2b, 0x43, 0x17, 0x34, - 0x9a, 0xab, 0x5b, 0xf4, 0xd3, 0x0c, 0x89, 0xb0, 0x47, 0x05, 0xaa, 0x89, - 0x3f, 0x34, 0x53, 0x28, 0x8e, 0xe1, 0x6c, 0x6b, 0xc7, 0x0b, 0x1f, 0x49, - 0xd2, 0x92, 0xe3, 0x71, 0x4b, 0x34, 0xc7, 0x59, 0x6f, 0x93, 0x0d, 0x43, - 0xd9, 0xc1, 0x0a, 0xfc, 0x85, 0xc8, 0x5a, 0x91, 0xd9, 0x8d, 0x71, 0x22, - 0x0c, 0xe5, 0x65, 0xde, 0x66, 0x29, 0xcd, 0x00, 0xf2, 0x1d, 0x72, 0x37, - 0xb8, 0xf7, 0x9b, 0xb0, 0xf3, 0x9e, 0xdb, 0xfb, 0x0f, 0x4f, 0xa1, 0xcc, - 0x22, 0xe5, 0x4d, 0x27, 0xa7, 0x80, 0xb7, 0x16, 0x8c, 0x96, 0xf5, 0xd2, - 0x59, 0xfb, 0x31, 0xfc, 0x8b, 0x1f, 0xf0, 0x83, 0x42, 0x1d, 0x42, 0xf6, - 0xc5, 0x01, 0xcd, 0x53, 0xe5, 0x13, 0xc0, 0x3b, 0x85, 0xa6, 0x3a, 0xc4, - 0x04, 0x61, 0x7e, 0x26, 0xd5, 0xf8, 0x02, 0xb7, 0xc6, 0xc4, 0x61, 0xa8, - 0x1d, 0x52, 0xb6, 0xf4, 0x43, 0x94, 0x76, 0x6c, 0x81, 0x1e, 0x96, 0x10, - 0xb3, 0x2e, 0x4c, 0x4a, 0xf7, 0x6a, 0x32, 0xa5, 0xef, 0x55, 0x61, 0x0d, - 0x0d, 0x06, 0x5e, 0x65, 0x54, 0x6f, 0x4f, 0xb7, 0x69, 0x9d, 0xf2, 0x3b, - 0x90, 0x6b, 0xa9, 0xdb, 0xbd, 0x2b, 0xe1, 0x05, 0xc6, 0x4e, 0x78, 0xb6, - 0xdd, 0x6a, 0xbf, 0x59, 0xb9, 0xbb, 0x09, 0xc9, 0xd5, 0x1b, 0xb4, 0x7b, - 0xf0, 0x96, 0xdb, 0x59, 0x41, 0x93, 0x3a, 0x45, 0x0d, 0xc0, 0x09, 0xcd, - 0xfd, 0x38, 0x06, 0x92, 0x1b, 0x34, 0x48, 0x50, 0xbc, 0x10, 0x53, 0x05, - 0x11, 0x0f, 0x19, 0x7b, 0x0f, 0x99, 0x38, 0x08, 0xe2, 0xec, 0xf0, 0x97, - 0x60, 0x4f, 0x28, 0xb7, 0x4f, 0x4a, 0x29, 0x2f, 0xac, 0x94, 0x2e, 0x14, - 0x4b, 0x1f, 0x07, 0x51, 0xdb, 0xb5, 0x16, 0x78, 0xc5, 0xfc, 0xdd, 0x4d, - 0x41, 0xab, 0xcb, 0x4f, 0xe4, 0x35, 0xc6, 0xd3, 0xa8, 0x27, 0xfe, 0x46, - 0x86, 0x9b, 0x49, 0x64, 0x4f, 0xb5, 0xf4, 0x81, 0x1f, 0x3a, 0x32, 0x94, - 0x19, 0x16, 0xcd, 0x09, 0xaf, 0xbc, 0xf3, 0xa9, 0x72, 0xd1, 0x27, 0xee, - 0xae, 0xf7, 0x3f, 0x3c, 0xd9, 0x4b, 0x94, 0x99, 0xd4, 0x13, 0x17, 0x3d, - 0x68, 0x86, 0xf8, 0x42, 0x2d, 0xdc, 0xc5, 0xc3, 0xad, 0x79, 0x23, 0x18, - 0xa2, 0x31, 0x20, 0x7d, 0xb7, 0x3e, 0x06, 0xb7, 0x1a, 0xf7, 0x7f, 0xf8, - 0xbc, 0xe9, 0xba, 0xba, 0xeb, 0xfa, 0xcf, 0xcf, 0xf7, 0xe0, 0x05, 0x1b, - 0xf7, 0x7b, 0x87, 0x45, 0xae, 0x61, 0x36, 0x3e, 0xb3, 0x8d, 0xe5, 0x67, - 0x5e, 0xe6, 0x0c, 0xb6, 0xe9, 0xe8, 0x00, 0x3a, 0x5b, 0x80, 0xf2, 0x73, - 0x99, 0x84, 0x33, 0x7d, 0x97, 0x65, 0x48, 0x81, 0xe0, 0xa9, 0x98, 0xf2, - 0x98, 0x37, 0x8f, 0x8c, 0x51, 0x31, 0x96, 0xcb, 0xf5, 0x62, 0xf6, 0x47, - 0x43, 0x4f, 0xd8, 0xf5, 0xa0, 0xaa, 0x19, 0x12, 0x91, 0xad, 0xbb, 0x5c, - 0x87, 0x96, 0x94, 0xe6, 0xba, 0x00, 0x1f, 0x26, 0x27, 0x21, 0xba, 0x23, - 0x01, 0xa8, 0xaa, 0x17, 0x7a, 0xb4, 0x55, 0xca, 0xba, 0xbe, 0x59, 0x0d, - 0x1f, 0x54, 0x43, 0x1a, 0xdb, 0x28, 0x1b, 0x5a, 0x77, 0x94, 0xb3, 0x3f, - 0x1e, 0x20, 0x0f, 0xc5, 0x6a, 0x2f, 0xf2, 0xe7, 0xdf, 0x37, 0xab, 0x3f, - 0x2e, 0xb2, 0xe3, 0x86, 0x68, 0xc3, 0x5c, 0x2a, 0x39, 0xb0, 0x31, 0x1e, - 0xcf, 0x1d, 0xa4, 0x38, 0x8a, 0x4a, 0x26, 0x32, 0x2b, 0xea, 0x8c, 0xc0, - 0xc6, 0xe7, 0x80, 0xca, 0xea, 0x92, 0x44, 0xad, 0x6b, 0xcf, 0x92, 0xfd, - 0xf9, 0x13, 0xfc, 0x3e, 0xf5, 0xcd, 0xd6, 0x53, 0x35, 0xf6, 0x6c, 0x6f, - 0x9d, 0x4f, 0xf1, 0xa1, 0x1d, 0xce, 0x14, 0xe5, 0xc0, 0x36, 0x79, 0x14, - 0x5c, 0x9b, 0x57, 0x55, 0xd2, 0x04, 0xd1, 0x74, 0x61, 0xa6, 0x89, 0x41, - 0x2d, 0xd4, 0x34, 0x1c, 0xe1, 0xf7, 0x23, 0x0c, 0x3d, 0x7b, 0x0a, 0xf3, - 0xca, 0x6c, 0xd7, 0x65, 0x1c, 0x93, 0xde, 0xe3, 0x66, 0xfb, 0xcb, 0x79, - 0x7c, 0x73, 0x8b, 0xcf, 0x44, 0x07, 0x58, 0x66, 0x29, 0xd6, 0x0c, 0x10, - 0xbe, 0xda, 0x38, 0x12, 0xf9, 0xb1, 0x15, 0xa4, 0x8f, 0xbf, 0xf0, 0x05, - 0xe9, 0x48, 0x6f, 0x7f, 0xd8, 0x88, 0x25, 0xa4, 0xbf, 0x5d, 0xf5, 0x6a, - 0x17, 0x7c, 0x94, 0xbb, 0xff, 0x05, 0xdd, 0xbc, 0xe0, 0xbf, 0xd6, 0xeb, - 0x2f, 0x8c, 0x9a, 0x84, 0xdf, 0x40, 0x2c, 0x5e, 0xa3, 0x18, 0xdf, 0x64, - 0x45, 0x44, 0xbd, 0x6a, 0x74, 0x6d, 0xb8, 0x19, 0xb8, 0x77, 0x60, 0x6d, - 0xae, 0x7f, 0xe9, 0x5d, 0xa8, 0xd2, 0x6d, 0x92, 0x8b, 0xa9, 0x40, 0x17, - 0x69, 0xbf, 0x72, 0xb1, 0x11, 0x49, 0x51, 0x2d, 0x81, 0x7e, 0x7d, 0x89, - 0xa5, 0x71, 0x47, 0x2a, 0x9c, 0xe3, 0x69, 0x01, 0xf0, 0xc6, 0x74, 0x0e, - 0x40, 0x61, 0x55, 0x1a, 0x43, 0xba, 0x3a, 0xf1, 0x08, 0x29, 0x44, 0x9d, - 0x51, 0x16, 0x30, 0x4f, 0xff, 0x4e, 0xc1, 0xe4, 0x53, 0xc7, 0x1c, 0x34, - 0x5e, 0x08, 0x7f, 0xdc, 0x0c, 0x35, 0xef, 0xaa, 0x7b, 0x4c, 0x89, 0x14, - 0xc6, 0x1e, 0x65, 0xb6, 0x99, 0x82, 0x11, 0x33, 0xbb, 0x6b, 0xee, 0xa7, - 0xb9, 0x1e, 0xe4, 0x37, 0x0a, 0x37, 0xb8, 0xa6, 0xa2, 0xb0, 0xfe, 0x12, - 0x99, 0x9e, 0x43, 0xec, 0x35, 0x64, 0x79, 0x7e, 0x43, 0x2d, 0xa3, 0xcc, - 0xbf, 0xcb, 0x63, 0x9f, 0xc1, 0xf0, 0x36, 0x79, 0xd5, 0x1e, 0x43, 0xb3, - 0x3f, 0x47, 0xf5, 0x03, 0x29, 0x06, 0xec, 0x9d, 0x32, 0xdd, 0x67, 0x19, - 0xcb, 0x7d, 0x75, 0x98, 0x21, 0x5e, 0xba, 0x2a, 0xd9, 0xd2, 0xce, 0x6f, - 0x46, 0xd4, 0x74, 0xc2, 0xd3, 0x13, 0x77, 0x9d, 0x3a, 0x95, 0x28, 0x6a, - 0x5a, 0xa1, 0x2c, 0xb5, 0x40, 0x3c, 0xdc, 0x78, 0x69, 0x5d, 0x99, 0x3e, - 0xf6, 0x0d, 0x36, 0xa2, 0x06, 0x13, 0xe4, 0xae, 0x1b, 0x7e, 0x24, 0x30, - 0x5f, 0x99, 0xff, 0x20, 0x94, 0x26, 0xd9, 0x97, 0x27, 0xe7, 0x26, 0x27, - 0x7a, 0x9d, 0x48, 0x9c, 0x97, 0x52, 0x82, 0x29, 0xba, 0x64, 0xc3, 0xb1, - 0xc4, 0x6f, 0xed, 0xf4, 0x03, 0x14, 0xf5, 0x30, 0x09, 0x59, 0x8d, 0x5e, - 0xb7, 0xed, 0x2f, 0x4a, 0xe8, 0x39, 0x8a, 0xb9, 0x9f, 0xc9, 0x80, 0xb9, - 0xc2, 0x77, 0x7a, 0x32, 0xd6, 0xa5, 0x4a, 0x7c, 0x86, 0x6a, 0x27, 0xf5, - 0xc3, 0x8b, 0xc5, 0x99, 0x6b, 0xfc, 0x5d, 0x8c, 0x1d, 0x37, 0x92, 0xa9, - 0x57, 0xf2, 0x64, 0xac, 0x2e, 0x7a, 0x26, 0xfa, 0x90, 0xf1, 0x61, 0x8b, - 0x8c, 0x22, 0x17, 0xbc, 0xf3, 0x49, 0x1f, 0x85, 0x19, 0xfb, 0x62, 0xe9, - 0xab, 0x61, 0x4d, 0xc3, 0x9a, 0x90, 0x6f, 0xb6, 0x30, 0x57, 0x99, 0x57, - 0x94, 0x4e, 0x6b, 0x8b, 0xa5, 0x1c, 0x8c, 0x70, 0x04, 0x40, 0xac, 0x4c, - 0x07, 0x22, 0x1a, 0x06, 0x1f, 0x17, 0xda, 0xb5, 0x1f, 0x26, 0x51, 0xfc, - 0x7c, 0x3f, 0x22, 0xcf, 0x82, 0x80, 0x7b, 0x3c, 0x7c, 0x38, 0x01, 0x1f, - 0xc9, 0xb1, 0x0e, 0x08, 0x0e, 0x04, 0xde, 0x82, 0xda, 0xf3, 0xd3, 0x25, - 0x74, 0xae, 0x21, 0xf9, 0xed, 0xe5, 0x5f, 0x32, 0xf2, 0x7f, 0xc5, 0x22, - 0x2b, 0x60, 0xbf, 0xf8, 0x34, 0xc7, 0xdd, 0x9a, 0x25, 0x09, 0xaa, 0xe2, - 0xae, 0x5f, 0xd0, 0x03, 0x76, 0x7e, 0xd8, 0x10, 0xc6, 0xcc, 0x04, 0xec, - 0xa8, 0xc9, 0xaf, 0xad, 0xf5, 0x86, 0x38, 0x54, 0x36, 0x94, 0xde, 0x58, - 0x01, 0xe6, 0x49, 0x63, 0x67, 0x69, 0x3f, 0x81, 0x95, 0x55, 0x39, 0x43, - 0x73, 0x2d, 0x6e, 0xe6, 0x07, 0xef, 0x0f, 0x71, 0x9a, 0x94, 0x8c, 0xf8, - 0x56, 0xb0, 0x7e, 0x93, 0x95, 0x30, 0x44, 0x3b, 0x4f, 0x5e, 0x04, 0x68, - 0xfc, 0x60, 0xb6, 0x6c, 0xbf, 0xc1, 0xad, 0x0f, 0x3e, 0x5f, 0x1a, 0x13, - 0xee, 0x5f, 0x70, 0xa9, 0x18, 0xd0, 0x64, 0x5c, 0x04, 0x91, 0xdf, 0xe0, - 0xcb, 0xcb, 0x1a, 0xa9, 0x44, 0xbc, 0xf8, 0x95, 0x4c, 0xae, 0x93, 0x23, - 0xc2, 0x8f, 0xf1, 0x80, 0x59, 0xb2, 0xe5, 0xa3, 0x66, 0xb7, 0x83, 0xad, - 0xaf, 0x41, 0xdf, 0xe2, 0xe1, 0x33, 0x44, 0x1d, 0xc0, 0xb5, 0xa9, 0x6a, - 0xaf, 0x2d, 0x99, 0x50, 0x64, 0xa1, 0x20, 0x85, 0x85, 0x1d, 0xbb, 0xb9, - 0x60, 0x65, 0x30, 0x13, 0x52, 0xa1, 0x1c, 0x27, 0xd6, 0xbe, 0x75, 0x74, - 0x1f, 0x76, 0x1a, 0x3d, 0xe7, 0x78, 0xb5, 0xf2, 0x82, 0x38, 0x81, 0x5d, - 0x7f, 0xad, 0x08, 0x9a, 0xe0, 0xac, 0x27, 0xf5, 0x0a, 0x2b, 0x1e, 0xe8, - 0x4b, 0x3e, 0xe5, 0x38, 0xa0, 0x55, 0x9b, 0xb1, 0x3d, 0xe8, 0x8a, 0xce, - 0x80, 0x4a, 0x20, 0xf9, 0xb5, 0x65, 0x5f, 0x05, 0xb0, 0x2c, 0xde, 0x71, - 0xba, 0x31, 0x37, 0xfb, 0x67, 0xb7, 0xa8, 0xf8, 0xcc, 0xc4, 0xd6, 0x93, - 0xae, 0xc3, 0x4a, 0x85, 0x43, 0x41, 0x57, 0x14, 0x27, 0xf6, 0xa7, 0xc7, - 0x18, 0x27, 0xc5, 0x03, 0x55, 0x93, 0xf9, 0x92, 0xb5, 0x71, 0xe8, 0x26, - 0x50, 0x0e, 0x84, 0xc4, 0x4b, 0x24, 0xca, 0x20, 0xec, 0x3b, 0x73, 0x71, - 0xed, 0xf4, 0xe7, 0x9d, 0x56, 0x03, 0xda, 0x4d, 0xd7, 0x6c, 0x58, 0xc7, - 0x5c, 0x0b, 0xaf, 0x98, 0xaf, 0xe2, 0xa4, 0x45, 0xa3, 0x87, 0xdb, 0xc6, - 0x27, 0x08, 0xdb, 0xc2, 0x33, 0xdc, 0x19, 0x1b, 0x0c, 0xda, 0x14, 0x70, - 0xc2, 0x93, 0xcc, 0xfc, 0x4d, 0xb4, 0xb0, 0x66, 0x2c, 0x93, 0x91, 0xd0, - 0x07, 0xca, 0x8c, 0x41, 0x07, 0xb0, 0xfa, 0xa4, 0x58, 0x32, 0x8d, 0x0d, - 0xf9, 0x43, 0x6d, 0x88, 0xa8, 0x46, 0x42, 0x11, 0xcd, 0xaa, 0x6b, 0x0b, - 0x34, 0xd2, 0x68, 0x29, 0x03, 0xab, 0x37, 0x58, 0xc5, 0xc2, 0xd3, 0x38, - 0xa3, 0xb8, 0x20, 0x5c, 0x75, 0x6e, 0x36, 0xa1, 0x64, 0x38, 0x48, 0x48, - 0x5f, 0x5d, 0x1f, 0x2e, 0x4d, 0x6d, 0x0f, 0xf6, 0x1a, 0xe2, 0xec, 0x87, - 0x34, 0x65, 0xd5, 0xef, 0x08, 0xc6, 0xdc, 0x73, 0x11, 0xed, 0xc2, 0x7b, - 0x38, 0x5f, 0x4e, 0xf4, 0x94, 0x0c, 0xbc, 0x22, 0x91, 0x20, 0x5c, 0xb1, - 0x72, 0x70, 0xfd, 0xdb, 0xa7, 0xf8, 0x9b, 0x2a, 0xbd, 0x26, 0x7d, 0xae, - 0x44, 0x41, 0x47, 0xea, 0xd0, 0x62, 0x88, 0x5b, 0xc2, 0x61, 0x67, 0x59, - 0x75, 0x15, 0x57, 0xa2, 0x66, 0xa4, 0x84, 0xef, 0xfa, 0x95, 0xe9, 0x5f, - 0xd3, 0x0d, 0x31, 0x95, 0xe9, 0x72, 0xc7, 0xd2, 0x1f, 0x4b, 0x14, 0x2c, - 0x0b, 0x1f, 0x63, 0xbc, 0xea, 0xbe, 0x60, 0xcb, 0x53, 0xa6, 0x37, 0xaa, - 0x85, 0xf2, 0x38, 0xa5, 0x2c, 0xe5, 0x42, 0xb7, 0xe4, 0xf2, 0xe6, 0xaf, - 0xd6, 0xbd, 0x60, 0x17, 0x1a, 0x7a, 0xd8, 0x0c, 0x48, 0x8a, 0x38, 0xb0, - 0x06, 0x94, 0x4b, 0x02, 0xa9, 0x08, 0xed, 0x41, 0x01, 0x22, 0xc5, 0x6a, - 0x56, 0x80, 0x61, 0x8d, 0xa1, 0x60, 0x28, 0x65, 0x78, 0x0d, 0xc2, 0x36, - 0x8a, 0x52, 0x9d, 0xa0, 0x3f, 0x18, 0x30, 0xc5, 0xd2, 0xf3, 0xf2, 0xdd, - 0x5f, 0xfc, 0x30, 0x48, 0x76, 0x89, 0xb1, 0x47, 0x2d, 0xd0, 0x1b, 0x60, - 0x49, 0x1e, 0x31, 0xc9, 0x44, 0xd4, 0x56, 0xe4, 0xe1, 0x1d, 0x66, 0x07, - 0xf0, 0x6f, 0x1a, 0xc4, 0x6c, 0xaa, 0x7e, 0x65, 0x3f, 0xbf, 0x0c, 0x6a, - 0xd4, 0x6b, 0x06, 0x51, 0x02, 0x82, 0xb9, 0xda, 0x90, 0x51, 0x2e, 0x09, - 0x05, 0x5e, 0xb4, 0x9d, 0x61, 0x87, 0x2e, 0x96, 0x97, 0xab, 0x92, 0xc2, - 0x4a, 0xe1, 0xda, 0x07, 0x13, 0x55, 0x08, 0xc2, 0xb1, 0x50, 0xf0, 0xa7, - 0x76, 0xfb, 0x66, 0x60, 0xb3, 0xbc, 0x39, 0xd0, 0x41, 0x0f, 0x80, 0x49, - 0xea, 0xa5, 0xdd, 0x27, 0x81, 0xef, 0x9c, 0x47, 0x92, 0xf5, 0xd2, 0xbf, - 0x77, 0x6b, 0x6c, 0x1c, 0x54, 0xae, 0x05, 0x16, 0xf7, 0x1e, 0xef, 0x05, - 0xf3, 0x9b, 0xe0, 0x06, 0xc2, 0xe2, 0xe1, 0xed, 0x56, 0x3f, 0xa0, 0xb8, - 0x9d, 0x5c, 0xa6, 0x12, 0x59, 0xcb, 0xea, 0x61, 0xd1, 0x47, 0xec, 0x8d, - 0x1e, 0x03, 0xc4, 0xfb, 0x6d, 0x4a, 0x9f, 0xf8, 0xc2, 0xc3, 0x83, 0x49, - 0x3d, 0x43, 0x90, 0x4e, 0xc5, 0x89, 0x19, 0x0b, 0x62, 0xd1, 0xe7, 0x76, - 0xbe, 0x90, 0xcc, 0xd3, 0xcd, 0x14, 0xa6, 0xf1, 0x09, 0xfd, 0x8e, 0xb5, - 0x5e, 0x73, 0x9a, 0xde, 0xb8, 0xf3, 0x53, 0xeb, 0xc2, 0x77, 0x24, 0xc0, - 0xfd, 0x53, 0x4d, 0xf1, 0x91, 0xdc, 0x33, 0x09, 0x82, 0x23, 0xde, 0xdf, - 0x14, 0x92, 0x08, 0xa4, 0xa3, 0x98, 0x82, 0xf9, 0xe5, 0x9b, 0xc2, 0x95, - 0xbc, 0xea, 0xc0, 0xc1, 0x81, 0xa0, 0xba, 0x07, 0x94, 0xd8, 0xaf, 0x75, - 0x9d, 0xaa, 0x16, 0xc4, 0x40, 0xa5, 0x44, 0x5e, 0x48, 0x74, 0x2e, 0xb6, - 0xeb, 0x85, 0x09, 0x0d, 0xe4, 0x63, 0x80, 0xeb, 0xd7, 0x7f, 0x44, 0xfe, - 0x23, 0x0a, 0xc6, 0x60, 0x0b, 0x30, 0xb3, 0x76, 0x98, 0x46, 0xf9, 0x45, - 0x02, 0x44, 0x34, 0xb8, 0xdf, 0x69, 0xbc, 0x4f, 0xb1, 0xce, 0x86, 0x04, - 0xdb, 0xb1, 0x95, 0xf7, 0x25, 0x7f, 0x9b, 0xcf, 0x1b, 0x59, 0x30, 0x15, - 0xa2, 0xba, 0xaf, 0xfa, 0xd7, 0xe0, 0x1e, 0xb7, 0x59, 0x1c, 0x5d, 0xb3, - 0x32, 0x38, 0x79, 0xa1, 0x34, 0xde, 0x6f, 0x29, 0x38, 0x2e, 0x4d, 0x48, - 0x36, 0x2a, 0x87, 0x1b, 0xc6, 0xfd, 0x7c, 0x79, 0xfd, 0x5d, 0xe0, 0xbe, - 0xcf, 0x0b, 0x66, 0x9c, 0x2b, 0x5f, 0x94, 0x49, 0xce, 0xe5, 0x48, 0x42, - 0x25, 0x65, 0x05, 0xf5, 0xab, 0x7c, 0x03, 0xd6, 0xa7, 0x2b, 0x61, 0x38, - 0x5f, 0xd2, 0x7e, 0x82, 0x93, 0x11, 0x9e, 0x18, 0xf6, 0xc2, 0x9c, 0xb7, - 0xb6, 0x58, 0x82, 0x90, 0x59, 0x55, 0x42, 0x07, 0x0f, 0x35, 0xdd, 0x2c, - 0x63, 0xe0, 0xc3, 0x7a, 0x41, 0x2d, 0x01, 0x00, 0xb9, 0x6c, 0xea, 0xe0, - 0x9b, 0x45, 0x73, 0x9c, 0x5c, 0x49, 0xe7, 0xed, 0xe3, 0x3a, 0x8d, 0x29, - 0x05, 0x27, 0x27, 0x7e, 0x99, 0x2d, 0xf9, 0x51, 0x25, 0x22, 0x68, 0x6b, - 0xc3, 0x0c, 0x21, 0xee, 0xdd, 0x89, 0xee, 0xeb, 0x96, 0x64, 0xa1, 0x11, - 0x56, 0x49, 0x08, 0xd6, 0x3c, 0x73, 0x70, 0xbe, 0x4d, 0x1a, 0x69, 0xaa, - 0xaf, 0x40, 0x26, 0x9d, 0x67, 0xb9, 0x8a, 0x8e, 0x3b, 0xae, 0x1f, 0x3b, - 0xa7, 0x63, 0x83, 0x03, 0x53, 0xad, 0x95, 0x0a, 0xb1, 0xad, 0x84, 0x31, - 0x4f, 0xaf, 0xbb, 0xe7, 0x76, 0xe6, 0x8b, 0xcf, 0xa4, 0x62, 0x98, 0x9b, - 0x45, 0x7d, 0x7e, 0x7b, 0x95, 0x47, 0x3a, 0x57, 0x6c, 0xa1, 0x6a, 0x02, - 0x57, 0xc5, 0xb2, 0x87, 0xc3, 0xa6, 0x18, 0x1e, 0xa3, 0xbe, 0xa3, 0x25, - 0x43, 0xeb, 0x74, 0x96, 0xf4, 0x1b, 0x83, 0x6d, 0xd1, 0xcf, 0x0b, 0xfa, - 0xd4, 0x37, 0xb2, 0xaf, 0x5e, 0x37, 0x0e, 0x16, 0x3c, 0x1f, 0x1c, 0x62, - 0xf8, 0xa3, 0xf9, 0x78, 0x8e, 0xb8, 0xe5, 0x9d, 0x2d, 0xb0, 0x48, 0x14, - 0x04, 0x52, 0xb8, 0x2e, 0x82, 0xd6, 0xd0, 0x7d, 0x87, 0xf9, 0x26, 0x0a, - 0x72, 0xb4, 0xe1, 0x8e, 0xac, 0xda, 0xef, 0x8e, 0x7c, 0x9d, 0x93, 0x1d, - 0x81, 0x1f, 0x10, 0xaf, 0x7d, 0x91, 0xfc, 0xbe, 0x7d, 0x9d, 0xba, 0x8a, - 0x96, 0xeb, 0x9f, 0x45, 0x2a, 0x46, 0xeb, 0x73, 0xfe, 0xdd, 0x1e, 0x70, - 0x28, 0x1b, 0x66, 0x6b, 0x60, 0xd7, 0x07, 0xea, 0xf6, 0xfb, 0xa5, 0xd8, - 0xf1, 0x02, 0xa9, 0x14, 0xc5, 0xc9, 0xdd, 0xda, 0x8c, 0xf7, 0x1b, 0x53, - 0xe9, 0xfb, 0xf1, 0xfb, 0xaf, 0x11, 0x18, 0x8c, 0xcf, 0x8f, 0xe1, 0x68, - 0xd4, 0x54, 0x14, 0x84, 0x08, 0x31, 0xda, 0xaa, 0x3b, 0xb0, 0x73, 0xf5, - 0xa9, 0x02, 0xa7, 0x45, 0x00, 0x0f, 0x4c, 0x40, 0xa7, 0xa2, 0x56, 0x90, - 0x38, 0x60, 0x8a, 0x30, 0xe2, 0xe4, 0x33, 0xc0, 0xec, 0xef, 0x8e, 0xeb, - 0xd9, 0x55, 0xe8, 0xef, 0x91, 0xfc, 0xd9, 0x95, 0x7d, 0x73, 0x2a, 0x7a, - 0x1a, 0x1f, 0x75, 0x3e, 0xfb, 0xd7, 0xf7, 0x1a, 0xa0, 0x65, 0x13, 0x76, - 0x07, 0xcb, 0xa6, 0xfb, 0x29, 0x28, 0xe0, 0x2a, 0xf5, 0xb4, 0xa5, 0x88, - 0x61, 0xcd, 0xb0, 0x7d, 0x02, 0x0e, 0xd0, 0x8e, 0xa7, 0x23, 0x20, 0x1b, - 0x0b, 0x8c, 0x0c, 0x1c, 0xa2, 0xd9, 0x2e, 0x7b, 0x7e, 0xca, 0x40, 0x6f, - 0xc9, 0xcc, 0xa9, 0x13, 0x16, 0x27, 0x6b, 0x84, 0x83, 0x6a, 0x7d, 0xc7, - 0x83, 0x36, 0xaa, 0x27, 0xd4, 0xdc, 0x4f, 0x6e, 0xbc, 0x3e, 0x54, 0xad, - 0x9f, 0xe2, 0xcb, 0x89, 0x9f, 0xde, 0x84, 0xeb, 0x96, 0x4e, 0xbe, 0xc0, - 0x9b, 0xdc, 0xe0, 0x4c, 0x86, 0x6b, 0xe6, 0x4f, 0x1e, 0x86, 0x42, 0xa8, - 0x76, 0x4a, 0x6d, 0x9a, 0xe6, 0xa6, 0xe8, 0x72, 0xfb, 0x08, 0xdb, 0x43, - 0xb1, 0x92, 0x0c, 0x23, 0x76, 0x81, 0xab, 0x8a, 0x4c, 0xd4, 0x90, 0xf3, - 0x66, 0xa1, 0x48, 0x01, 0x2a, 0x71, 0xc3, 0x97, 0xb1, 0xed, 0x81, 0x29, - 0x1e, 0x22, 0xbb, 0x21, 0x37, 0xbe, 0x98, 0x8a, 0xb6, 0xe3, 0x8b, 0x0c, - 0x4d, 0xb7, 0x2a, 0x4a, 0xab, 0x45, 0x6c, 0x7d, 0x51, 0x67, 0xb5, 0x0f, - 0x87, 0x64, 0xe4, 0xa9, 0x4e, 0x01, 0x08, 0x5c, 0xc8, 0xb1, 0xa5, 0x9f, - 0xad, 0xbc, 0x89, 0xea, 0x4a, 0xe9, 0x54, 0x86, 0x86, 0x61, 0x1d, 0x89, - 0x27, 0x9a, 0xe7, 0x5a, 0x76, 0xcb, 0xcf, 0xe2, 0x4f, 0x88, 0xd7, 0x16, - 0xa2, 0x3b, 0x88, 0xca, 0x44, 0xc1, 0x45, 0x60, 0x63, 0x87, 0x99, 0xab, - 0x58, 0x7f, 0xa0, 0xdb, 0xcc, 0xb5, 0x99, 0x01, 0x4c, 0xa4, 0x1d, 0xbc, - 0x98, 0x11, 0xea, 0x45, 0x1e, 0x4d, 0xf2, 0xf1, 0xe5, 0x37, 0xc9, 0x9f, - 0x6e, 0x8f, 0x87, 0x76, 0x41, 0x4e, 0x72, 0xf8, 0x4e, 0xf3, 0xa8, 0xd7, - 0x98, 0x34, 0xf8, 0x51, 0x7d, 0x1f, 0x72, 0x7b, 0xe8, 0x54, 0x92, 0x53, - 0x52, 0xcf, 0xe6, 0x8d, 0x86, 0x0a, 0x57, 0x5a, 0xd8, 0xc4, 0x92, 0x0f, - 0x8b, 0x63, 0x15, 0xea, 0x28, 0xef, 0x50, 0x1d, 0x80, 0x16, 0xcd, 0xf6, - 0x8e, 0xd8, 0x6a, 0x3c, 0xbf, 0x2a, 0x47, 0x00, 0xb0, 0xac, 0xcc, 0x7e, - 0x5b, 0x1b, 0xdc, 0x0c, 0x36, 0x86, 0xb7, 0x10, 0x18, 0x89, 0x61, 0x82, - 0x02, 0x28, 0xf4, 0x20, 0x3e, 0xa4, 0x5c, 0x32, 0x9e, 0x49, 0xa3, 0xe3, - 0xb7, 0x63, 0x77, 0x6c, 0x1b, 0xa8, 0x23, 0x11, 0x37, 0x3b, 0x73, 0x36, - 0x01, 0xf7, 0x68, 0x95, 0x78, 0xe4, 0x84, 0xc1, 0x72, 0x60, 0x00, 0x7f, - 0xde, 0xaa, 0x56, 0xe2, 0x03, 0x0d, 0x09, 0x92, 0x1f, 0x3b, 0x75, 0x7c, - 0x97, 0x50, 0x82, 0xcf, 0xfa, 0x5a, 0x37, 0x77, 0x0e, 0x79, 0xec, 0x91, - 0x03, 0x77, 0x2c, 0xf2, 0x9d, 0x96, 0x97, 0x2f, 0x28, 0xb7, 0xea, 0x9b, - 0x25, 0xec, 0x77, 0x2c, 0x46, 0x39, 0x31, 0x02, 0x09, 0x3b, 0x39, 0xe9, - 0x93, 0xf1, 0x4e, 0x6a, 0xf7, 0x8e, 0x90, 0x4b, 0xe6, 0xcf, 0x84, 0x7e, - 0x12, 0xcf, 0xaa, 0x0b, 0x72, 0x31, 0x44, 0x33, 0xbd, 0x73, 0x31, 0x16, - 0xde, 0x93, 0x42, 0xe4, 0x90, 0xcf, 0x66, 0x70, 0xe5, 0x75, 0xe9, 0xcd, - 0x17, 0xf9, 0xa6, 0x49, 0x41, 0x4f, 0x58, 0xcc, 0xb3, 0x23, 0x9d, 0x04, - 0x46, 0x92, 0x16, 0xce, 0xfc, 0x23, 0x86, 0xd7, 0xe7, 0x47, 0xb9, 0x27, - 0x08, 0xc2, 0x67, 0x51, 0xa4, 0x86, 0xca, 0xd9, 0x52, 0xef, 0x59, 0x01, - 0x15, 0x96, 0x42, 0x0b, 0x10, 0x44, 0x85, 0x79, 0xa6, 0x88, 0x1b, 0x8b, - 0xfc, 0xa3, 0x9f, 0x99, 0x20, 0x49, 0x43, 0xc6, 0x28, 0x14, 0x9b, 0xb4, - 0xc6, 0x41, 0x47, 0xf6, 0xe7, 0x43, 0xe5, 0xbd, 0x0a, 0x81, 0xa1, 0x66, - 0xc2, 0xfd, 0x79, 0x47, 0x8f, 0x6d, 0xee, 0x40, 0x37, 0xa9, 0xa0, 0x0f, - 0x71, 0x75, 0xbf, 0xd3, 0x74, 0xb1, 0x7d, 0x22, 0xab, 0xb3, 0x7a, 0x61, - 0x29, 0x27, 0x2d, 0x09, 0xb6, 0x4c, 0xab, 0x0c, 0x2c, 0x65, 0xa6, 0x2f, - 0xb9, 0x1e, 0xbb, 0xfb, 0x33, 0x68, 0x22, 0x74, 0xcd, 0x0b, 0x56, 0x4e, - 0x12, 0x8b, 0x27, 0x0c, 0x41, 0x8c, 0x06, 0x80, 0xd5, 0x85, 0xbd, 0x44, - 0xa1, 0x22, 0x7f, 0xcf, 0x06, 0x4b, 0x18, 0xd0, 0x6a, 0x1f, 0x5e, 0xea, - 0xce, 0x81, 0x7f, 0xc2, 0x89, 0x3d, 0xf5, 0x23, 0xc6, 0x4c, 0x8e, 0x88, - 0xc5, 0x3e, 0x1d, 0xdf, 0x45, 0x6e, 0xe1, 0x1d, 0xaa, 0xdc, 0x7a, 0xa0, - 0xb3, 0x3d, 0xb6, 0x61, 0x02, 0xa1, 0xec, 0xfa, 0x1e, 0xb6, 0xf4, 0x0d, - 0x3c, 0x43, 0xd9, 0xea, 0x54, 0x35, 0xeb, 0xe4, 0x4f, 0x1e, 0x62, 0xdf, - 0x4f, 0x42, 0x6f, 0x68, 0x48, 0x64, 0x7c, 0x33, 0x9e, 0xdb, 0x7b, 0xbc, - 0x47, 0x23, 0x55, 0xa8, 0x1a, 0x1c, 0xf7, 0x55, 0xfb, 0xfd, 0x18, 0x30, - 0x34, 0x63, 0x9d, 0x23, 0x58, 0x2c, 0x23, 0xbc, 0x23, 0x38, 0x5c, 0xcc, - 0x13, 0x8c, 0x20, 0x7d, 0x2b, 0x7e, 0x23, 0x67, 0xb9, 0xa7, 0x5f, 0x18, - 0x37, 0x11, 0xb9, 0x2d, 0x03, 0xd1, 0xdc, 0x1a, 0x13, 0x18, 0xca, 0xca, - 0x59, 0x26, 0x22, 0xa5, 0x0d, 0xb6, 0x66, 0xb2, 0x86, 0x16, 0x60, 0x2a, - 0xd2, 0xa2, 0x22, 0x21, 0xae, 0xb2, 0xe3, 0xdc, 0xa7, 0x15, 0x2f, 0x81, - 0xeb, 0x16, 0xd2, 0xc6, 0x31, 0x7f, 0x37, 0xa0, 0x81, 0xea, 0x5a, 0x49, - 0x74, 0xa9, 0x4c, 0x80, 0x5c, 0xa2, 0x6d, 0xf7, 0x08, 0xb8, 0x98, 0xb9, - 0x5d, 0xdb, 0xb7, 0x82, 0x2d, 0xd1, 0xf1, 0x26, 0x8a, 0xf9, 0xf8, 0x4e, - 0x9c, 0xaf, 0x39, 0xc3, 0xb3, 0xe4, 0xfd, 0xa6, 0x29, 0x60, 0x16, 0x37, - 0x03, 0x80, 0x75, 0x67, 0x5b, 0x68, 0x99, 0x9c, 0xd9, 0x0b, 0xa8, 0xdd, - 0x91, 0xe8, 0x3a, 0x3f, 0x35, 0x59, 0xa2, 0xbb, 0xa2, 0x82, 0x0c, 0xa4, - 0x55, 0x6f, 0xbb, 0x87, 0x9b, 0xfe, 0xa8, 0x40, 0x1c, 0x27, 0xdd, 0xa4, - 0x75, 0xe7, 0xf4, 0x85, 0xe6, 0xc2, 0x53, 0x0c, 0xbd, 0x78, 0xe3, 0x24, - 0x59, 0xfc, 0x0f, 0x22, 0x29, 0x4d, 0xa1, 0x36, 0x80, 0xa1, 0xbc, 0xce, - 0x9d, 0x9a, 0x75, 0xb6, 0x3c, 0x56, 0xb1, 0x0a, 0xd7, 0xbd, 0x1b, 0x1d, - 0xe9, 0xf8, 0x3d, 0xfc, 0xbb, 0x53, 0xf7, 0x9c, 0xe6, 0xc2, 0x7a, 0x8f, - 0xbe, 0x7d, 0x7e, 0x5b, 0xdc, 0x5e, 0x94, 0x88, 0x5f, 0x22, 0xee, 0x30, - 0xaa, 0xc7, 0x92, 0xcd, 0xcf, 0x37, 0x27, 0xc9, 0xeb, 0xb8, 0x51, 0xfa, - 0x7e, 0xab, 0x3c, 0x34, 0xb9, 0x30, 0x1c, 0x7b, 0xe5, 0xfd, 0x17, 0x83, - 0xb2, 0x36, 0xcf, 0x30, 0x80, 0x26, 0xdd, 0xb5, 0x26, 0x6b, 0x38, 0xe4, - 0x2d, 0x62, 0xbb, 0x43, 0x6c, 0xa7, 0x72, 0xea, 0xd7, 0xba, 0x57, 0x6b, - 0xc7, 0xd0, 0x0a, 0x03, 0x8a, 0x80, 0x93, 0x92, 0x8a, 0x9b, 0xdb, 0xc0, - 0x55, 0x2e, 0x10, 0x13, 0x4d, 0x5c, 0xe5, 0xcf, 0x7a, 0x0d, 0x14, 0x54, - 0x4c, 0x54, 0xda, 0xdf, 0x37, 0x6a, 0x58, 0xf8, 0x92, 0x51, 0x19, 0x48, - 0xf2, 0xcf, 0x3c, 0x22, 0x62, 0xcb, 0xce, 0x54, 0x00, 0xc7, 0x7e, 0xaf, - 0xbd, 0x7a, 0x1c, 0xef, 0x72, 0x94, 0x08, 0x05, 0x5e, 0xea, 0x7f, 0xc4, - 0x5b, 0x49, 0x94, 0x49, 0x8f, 0xb0, 0xb1, 0xae, 0x38, 0x36, 0x33, 0x95, - 0xf1, 0xe0, 0xd8, 0xab, 0xc4, 0xfa, 0xce, 0xe1, 0x60, 0x97, 0x00, 0x2a, - 0xdc, 0xed, 0x21, 0x24, 0x2d, 0x56, 0xac, 0xb5, 0x05, 0xc4, 0x1e, 0xcd, - 0x93, 0xf6, 0x03, 0xb1, 0xb5, 0x32, 0x8b, 0xbd, 0xd4, 0x27, 0x4d, 0x8d, - 0xb7, 0x98, 0x16, 0x79, 0x04, 0x12, 0x31, 0x04, 0xd8, 0xa2, 0x3a, 0x74, - 0x6c, 0x1f, 0x64, 0xa8, 0x45, 0xc7, 0x33, 0x9b, 0x8d, 0xd8, 0xb3, 0xd1, - 0xc3, 0xa5, 0x72, 0xeb, 0xe3, 0x09, 0xd9, 0xa5, 0x85, 0x0f, 0x8d, 0x3b, - 0x1a, 0x33, 0xe0, 0x93, 0xdf, 0x8b, 0x36, 0xa6, 0x3f, 0x48, 0x63, 0xbb, - 0xb2, 0xe9, 0xd9, 0x9c, 0x35, 0x48, 0x64, 0x6c, 0x89, 0xc0, 0x67, 0x38, - 0x6b, 0x21, 0xea, 0xcf, 0x49, 0xdc, 0x6e, 0x2f, 0x59, 0xec, 0x24, 0x14, - 0x7e, 0x2a, 0x54, 0x0a, 0xad, 0x29, 0x6d, 0x82, 0x70, 0xc3, 0x97, 0x1f, - 0x37, 0xbf, 0x62, 0xac, 0xad, 0x1a, 0x5f, 0x94, 0xbe, 0x60, 0x5d, 0x47, - 0x42, 0xdb, 0x6a, 0x66, 0x94, 0x15, 0x73, 0x8d, 0x71, 0x6c, 0xa1, 0xbf, - 0x87, 0x43, 0x7c, 0x39, 0x2f, 0xd6, 0xf4, 0x8e, 0xe4, 0x28, 0xd4, 0xa2, - 0x3c, 0xd7, 0x9d, 0x22, 0xfa, 0x74, 0x07, 0xe7, 0xab, 0x4b, 0xb6, 0x5b, - 0x39, 0x55, 0xe3, 0x03, 0x53, 0x6f, 0xd4, 0xd6, 0xc4, 0x9f, 0xa3, 0xf7, - 0x5b, 0xb2, 0xe3, 0xed, 0x7e, 0x23, 0x7f, 0x4c, 0x8a, 0xf4, 0x45, 0x3a, - 0x71, 0xff, 0xd9, 0x57, 0x5e, 0xfc, 0x32, 0x21, 0x64, 0xba, 0x7e, 0xd9, - 0xaa, 0x43, 0xe9, 0xd3, 0x0c, 0x7e, 0xb3, 0x8d, 0x8c, 0x53, 0xeb, 0x62, - 0xe5, 0xf6, 0xd2, 0x38, 0x2f, 0x61, 0xce, 0xb9, 0x83, 0x6f, 0x33, 0x28, - 0x18, 0x8f, 0x3a, 0x84, 0xb7, 0xfb, 0xb7, 0xa6, 0x93, 0xf2, 0xa1, 0x50, - 0x5d, 0xfb, 0x97, 0xfd, 0xb1, 0xe1, 0x4f, 0x70, 0x68, 0xb9, 0x8d, 0xc6, - 0xca, 0x8f, 0xe7, 0x95, 0x85, 0xfd, 0x6b, 0xdd, 0x8d, 0xcc, 0xfc, 0x08, - 0xb1, 0xc3, 0x6a, 0xd5, 0xcf, 0x66, 0x74, 0x5b, 0x90, 0x4d, 0xa4, 0xc5, - 0x5c, 0xc6, 0x60, 0x14, 0x80, 0x4a, 0x3c, 0x07, 0x2b, 0x81, 0x56, 0x67, - 0x07, 0x76, 0x7a, 0x3e, 0x3f, 0x28, 0x3d, 0xfd, 0xdc, 0x11, 0x08, 0xda, - 0x15, 0x7a, 0x4a, 0xcf, 0xa0, 0xb5, 0x88, 0x60, 0xd5, 0x9e, 0x58, 0xbf, - 0xdc, 0xb6, 0x25, 0x89, 0x33, 0x0f, 0x9a, 0xd2, 0xd4, 0xa7, 0x08, 0x33, - 0x76, 0x2f, 0x18, 0x8d, 0x6c, 0x15, 0xff, 0x44, 0xbd, 0xda, 0x39, 0xe4, - 0xf2, 0x61, 0xeb, 0x6b, 0xac, 0x0e, 0x12, 0xf2, 0xff, 0xb1, 0xf7, 0x9f, - 0x4b, 0x8e, 0x23, 0x59, 0xa2, 0x20, 0xfc, 0x7f, 0x9e, 0x22, 0x36, 0xd7, - 0xc6, 0xba, 0x7b, 0x58, 0x91, 0xd0, 0xaa, 0x67, 0xaa, 0x6d, 0x01, 0x10, - 0x8a, 0x00, 0x15, 0x40, 0x02, 0x24, 0xae, 0x8d, 0x95, 0x01, 0x84, 0x24, - 0x24, 0xa1, 0xc1, 0x6b, 0x7b, 0xdf, 0xe5, 0x7b, 0xa3, 0xef, 0x91, 0xd6, - 0x41, 0x46, 0x64, 0x46, 0x66, 0x46, 0x8a, 0xaa, 0xca, 0xaa, 0xae, 0xee, - 0xe9, 0x14, 0x11, 0xa4, 0xc3, 0x71, 0xfc, 0xf8, 0xd1, 0xc7, 0xe5, 0x22, - 0x0d, 0x54, 0xc1, 0x99, 0xb5, 0x79, 0xc3, 0x80, 0x54, 0x3c, 0x29, 0x78, - 0x24, 0x64, 0x0d, 0x79, 0x94, 0x05, 0x2e, 0xc2, 0x8e, 0x07, 0x7b, 0x77, - 0xbe, 0x9e, 0x49, 0x68, 0x3c, 0x54, 0x6c, 0xea, 0xf4, 0xba, 0xb7, 0xdd, - 0x9e, 0x43, 0x97, 0x4f, 0x66, 0xec, 0x52, 0x8e, 0x16, 0xe1, 0x7a, 0xa9, - 0x33, 0xd9, 0x3e, 0x5c, 0xab, 0xfb, 0xad, 0x7b, 0x72, 0xfa, 0xf3, 0x9c, - 0x25, 0x95, 0x8d, 0xad, 0x08, 0xda, 0x20, 0x35, 0xc6, 0xbe, 0xf1, 0x4e, - 0x19, 0xc9, 0x4b, 0xd7, 0x11, 0x8e, 0x66, 0x59, 0x77, 0xe8, 0xd1, 0xad, - 0x7d, 0x18, 0xcb, 0x9c, 0x31, 0x18, 0x03, 0x8d, 0xbd, 0x35, 0x15, 0xe7, - 0xa3, 0x82, 0x5f, 0x70, 0x69, 0x46, 0x6c, 0x1d, 0xcb, 0x8d, 0xe1, 0xd5, - 0x45, 0x6b, 0xb3, 0xed, 0x22, 0x19, 0xd6, 0xdc, 0x5c, 0x76, 0xb9, 0x26, - 0x66, 0xa1, 0x55, 0xb0, 0x82, 0xc7, 0x4b, 0x8a, 0xc9, 0xf3, 0x76, 0x46, - 0x73, 0x72, 0x0f, 0x42, 0x39, 0x0e, 0x18, 0xd5, 0xb9, 0x95, 0xaf, 0xe2, - 0x75, 0xa3, 0x1c, 0x12, 0x39, 0x1c, 0xda, 0x06, 0xa5, 0x2a, 0x74, 0xb1, - 0xe2, 0xf6, 0xd9, 0xea, 0x40, 0xfa, 0xa2, 0x8a, 0xa2, 0xea, 0x41, 0xef, - 0x09, 0xfb, 0x30, 0xb3, 0x08, 0xf0, 0xe8, 0xd4, 0x2f, 0xaf, 0xae, 0x3f, - 0x5f, 0x6f, 0xeb, 0x11, 0xbe, 0x8e, 0x44, 0x38, 0x12, 0xad, 0xbb, 0x39, - 0x6d, 0xb4, 0x94, 0x98, 0x0f, 0xea, 0xa1, 0x3c, 0xad, 0x80, 0x36, 0x5c, - 0x5d, 0xef, 0x7a, 0x8e, 0x5c, 0x5c, 0xbc, 0x42, 0xe7, 0x76, 0x87, 0xd1, - 0xb1, 0x18, 0xf7, 0x3b, 0x4c, 0x3d, 0x85, 0x30, 0xdb, 0xcc, 0xe9, 0xcd, - 0x85, 0x2d, 0x18, 0x05, 0x98, 0xbf, 0xed, 0x8c, 0x2a, 0x18, 0x84, 0xc2, - 0xb6, 0x2e, 0xe6, 0x6d, 0x17, 0xab, 0x73, 0xa0, 0x2e, 0x32, 0x2b, 0x35, - 0xb6, 0xa7, 0xd9, 0x85, 0x72, 0xda, 0xcc, 0xa6, 0xaf, 0xb3, 0x58, 0x44, - 0xe5, 0x6d, 0x8b, 0xb8, 0xc0, 0x0c, 0x27, 0xc5, 0x96, 0xb9, 0xf0, 0x8b, - 0xec, 0xd2, 0xd3, 0xf8, 0xdc, 0x9b, 0x69, 0xe7, 0xa2, 0x64, 0xf5, 0x2b, - 0x11, 0x89, 0x7b, 0x12, 0xa4, 0xac, 0xd0, 0x72, 0x86, 0x95, 0x01, 0x2a, - 0xad, 0xd8, 0x78, 0xb9, 0x4f, 0xf0, 0x4d, 0xb4, 0xd4, 0x83, 0x4a, 0xea, - 0x34, 0x77, 0xa5, 0xa6, 0xb4, 0xd8, 0xc7, 0x97, 0xf3, 0x78, 0xec, 0x57, - 0x9c, 0x58, 0xa4, 0x53, 0xc6, 0x7c, 0x2c, 0x8a, 0x8d, 0x9c, 0x90, 0x9b, - 0x58, 0x3d, 0xf1, 0x82, 0xbb, 0x88, 0x9a, 0x16, 0x0b, 0x3b, 0x32, 0xe1, - 0xb8, 0x02, 0x59, 0x9f, 0x14, 0xc5, 0xc7, 0x73, 0x38, 0x16, 0xa4, 0x44, - 0xc8, 0x7c, 0x8d, 0x77, 0x7a, 0x1b, 0xdd, 0x8b, 0xb4, 0x68, 0x11, 0xf6, - 0xea, 0xc4, 0xd5, 0x67, 0x58, 0x80, 0x24, 0x46, 0xdd, 0xd4, 0xc2, 0xbc, - 0xad, 0x98, 0x6d, 0xe2, 0x85, 0x3a, 0x0f, 0x91, 0xaa, 0x66, 0xe7, 0x9e, - 0xe0, 0x9f, 0x1b, 0x54, 0xce, 0x2e, 0xe3, 0xa5, 0xd0, 0xfd, 0xc3, 0xc2, - 0x20, 0x8f, 0xea, 0x45, 0x9d, 0x66, 0xa6, 0xf4, 0x4b, 0x22, 0x50, 0xad, - 0xab, 0x4a, 0x7c, 0x71, 0xf2, 0xcf, 0x81, 0xb0, 0x93, 0xf8, 0x45, 0x7e, - 0xad, 0xe7, 0xc6, 0x3a, 0xcf, 0xb2, 0x82, 0x38, 0x29, 0x29, 0xb9, 0xe0, - 0xe0, 0x29, 0xb1, 0x9c, 0x91, 0x8b, 0x85, 0xb8, 0xe2, 0x6b, 0xd3, 0x06, - 0xc2, 0x70, 0x58, 0xce, 0x0e, 0x0e, 0xca, 0xd3, 0x3b, 0x8c, 0xb5, 0x28, - 0xca, 0x94, 0x97, 0x98, 0x0c, 0x51, 0x4c, 0x9c, 0xe6, 0x14, 0x1a, 0xe0, - 0x20, 0xf8, 0xd0, 0x76, 0x76, 0xb0, 0x94, 0x24, 0xd4, 0xe8, 0x71, 0x5c, - 0xb0, 0x58, 0x51, 0xf6, 0x1d, 0xed, 0xc2, 0x1d, 0xb6, 0x61, 0x14, 0xf4, - 0x7e, 0x21, 0x24, 0xf4, 0x96, 0x95, 0x8b, 0x8d, 0x76, 0xf5, 0xb4, 0x96, - 0x0b, 0x92, 0xc2, 0x07, 0xde, 0xcc, 0xb6, 0xcd, 0x8d, 0x46, 0x08, 0x12, - 0xda, 0x05, 0xf8, 0xb6, 0x92, 0x98, 0x82, 0x22, 0x74, 0x65, 0x9f, 0x47, - 0xb3, 0x7d, 0xae, 0x87, 0x1c, 0xbf, 0x3e, 0x1d, 0xbd, 0x94, 0x97, 0xad, - 0x43, 0x15, 0x33, 0x9b, 0xdd, 0x22, 0x63, 0x6a, 0x54, 0x12, 0x51, 0x35, - 0xd3, 0xae, 0xac, 0xb3, 0x12, 0xa7, 0x45, 0xd0, 0xda, 0xdc, 0x71, 0xab, - 0xe5, 0xb1, 0xf2, 0x1d, 0x0a, 0xa7, 0x30, 0x9f, 0xe8, 0x25, 0x37, 0x0d, - 0xc9, 0xf8, 0xe2, 0xcc, 0x91, 0x3d, 0x9f, 0x1a, 0xcb, 0xf0, 0x0c, 0x5f, - 0x74, 0xb6, 0x95, 0x0a, 0xd7, 0xc8, 0x18, 0x52, 0x91, 0x48, 0x83, 0x8a, - 0xaf, 0xcb, 0x86, 0x15, 0xaf, 0x5b, 0x05, 0x14, 0x12, 0x4d, 0x36, 0xb7, - 0x2c, 0xc8, 0x03, 0x61, 0xde, 0x5a, 0x58, 0xb4, 0xfd, 0x92, 0x81, 0x97, - 0xc3, 0x99, 0x0f, 0x57, 0xea, 0x16, 0x71, 0x62, 0x41, 0xb0, 0xaf, 0x97, - 0x98, 0x3a, 0x2b, 0x94, 0x1f, 0x84, 0x76, 0x6e, 0xac, 0x5a, 0x77, 0x31, - 0x1c, 0x0a, 0x5d, 0xc8, 0xe3, 0x9d, 0x39, 0xee, 0x17, 0x9e, 0x11, 0xc6, - 0xde, 0x4e, 0xad, 0xd4, 0xeb, 0x78, 0xd9, 0x23, 0xec, 0x74, 0x16, 0x60, - 0x20, 0x5d, 0x0b, 0x64, 0xcf, 0xae, 0x77, 0x17, 0xb1, 0x69, 0x7a, 0x6b, - 0x8c, 0x0b, 0x34, 0xb2, 0x22, 0x2d, 0x5f, 0xad, 0x76, 0x7b, 0xaf, 0x4c, - 0xed, 0x59, 0xd8, 0xd8, 0x7c, 0x7b, 0x9c, 0x43, 0xb2, 0x04, 0x1f, 0x5b, - 0x01, 0xb6, 0x5d, 0x0e, 0x49, 0x24, 0xe9, 0x84, 0xb3, 0x56, 0x2f, 0x08, - 0x5e, 0xb3, 0xe3, 0x4e, 0x5b, 0x67, 0x08, 0xc5, 0x0c, 0x83, 0xfc, 0x65, - 0x67, 0xec, 0x92, 0x59, 0x3e, 0x74, 0x18, 0xcd, 0xd1, 0xec, 0x10, 0xed, - 0x71, 0xa6, 0xe9, 0x53, 0x69, 0x9d, 0x75, 0x94, 0xc3, 0x9d, 0xa4, 0x63, - 0xc8, 0x05, 0x94, 0x64, 0x92, 0x59, 0x7c, 0xa4, 0xb0, 0x71, 0x38, 0xaf, - 0x6b, 0x9c, 0x8e, 0xb9, 0x84, 0x42, 0xaf, 0x10, 0x59, 0xc0, 0x70, 0x11, - 0xb3, 0xd2, 0xa6, 0xcb, 0x61, 0xb1, 0x27, 0x31, 0xed, 0x10, 0xe1, 0xdb, - 0xa5, 0x69, 0x90, 0xa1, 0x89, 0xb7, 0xab, 0x0b, 0xb1, 0xf4, 0x21, 0xce, - 0x45, 0x7d, 0x61, 0xb6, 0xdc, 0x5f, 0x4d, 0x27, 0xd2, 0x8e, 0x7b, 0x61, - 0x81, 0x2b, 0xc7, 0x0b, 0x45, 0xdb, 0x9c, 0xd2, 0x27, 0x5a, 0xa8, 0xe8, - 0x39, 0x43, 0xf2, 0x30, 0x61, 0x69, 0x5a, 0x65, 0xa2, 0x61, 0x35, 0x9f, - 0x1f, 0xa4, 0xaa, 0x35, 0x5c, 0xcc, 0x72, 0x66, 0xb6, 0x4d, 0xe9, 0xf1, - 0xdc, 0x2c, 0x57, 0x0d, 0x29, 0xce, 0x1b, 0x23, 0x5f, 0xd7, 0xbd, 0x72, - 0x41, 0x13, 0x21, 0x5c, 0x60, 0x5b, 0x34, 0xab, 0xd7, 0x97, 0x20, 0xab, - 0x52, 0x6e, 0x13, 0xa6, 0x8b, 0x2b, 0x37, 0xdf, 0xbb, 0x1d, 0x90, 0xdf, - 0x35, 0x74, 0xb5, 0x8c, 0xed, 0xc5, 0x39, 0xef, 0x91, 0x34, 0xaa, 0x74, - 0x81, 0xb1, 0xe3, 0xc3, 0x96, 0x6c, 0xae, 0x1a, 0xd7, 0x70, 0x7c, 0xb1, - 0x74, 0xf6, 0xb8, 0x59, 0xf4, 0x06, 0xc9, 0xce, 0x2f, 0x86, 0x13, 0x1e, - 0xe3, 0x99, 0x79, 0xc2, 0xad, 0xba, 0x02, 0x8e, 0xb9, 0xec, 0x25, 0xe8, - 0x7c, 0x09, 0xea, 0x65, 0xe2, 0x48, 0xe5, 0x45, 0x87, 0x2b, 0xa6, 0x36, - 0x0a, 0x7d, 0xbb, 0x2f, 0xdb, 0x83, 0x4a, 0x54, 0x47, 0x2d, 0xe9, 0x3c, - 0x31, 0xce, 0x1d, 0x11, 0x77, 0x47, 0x7e, 0xab, 0xb6, 0x9e, 0x49, 0x44, - 0x86, 0x00, 0x35, 0xb6, 0x07, 0x95, 0x20, 0xff, 0x36, 0x74, 0xba, 0x5f, - 0x35, 0xd8, 0x2e, 0x61, 0x97, 0x3b, 0xac, 0x42, 0x66, 0x20, 0x3a, 0x30, - 0xb1, 0x63, 0x9c, 0x5d, 0x99, 0x79, 0x58, 0x6a, 0xf8, 0xac, 0xa2, 0x7a, - 0x66, 0x5b, 0xa6, 0xf5, 0x06, 0xb3, 0xe4, 0x05, 0x11, 0xe2, 0x66, 0xa5, - 0x6e, 0xb1, 0x53, 0xb1, 0xb9, 0x74, 0x36, 0x17, 0x14, 0xb4, 0xad, 0xf4, - 0xa7, 0x0e, 0x3b, 0x50, 0x4a, 0x94, 0x6c, 0xa7, 0x1d, 0x43, 0x3d, 0x99, - 0x9f, 0x98, 0xd6, 0x72, 0x73, 0xd7, 0xbd, 0x5c, 0x84, 0xb5, 0x47, 0xcf, - 0x60, 0x5a, 0xdf, 0x79, 0xa3, 0xee, 0x63, 0x3b, 0x68, 0x41, 0x23, 0x33, - 0x2c, 0x20, 0xc7, 0x70, 0x86, 0x0e, 0xf9, 0x2a, 0xf1, 0x57, 0x4d, 0x09, - 0x7c, 0xbb, 0xbf, 0xba, 0x66, 0xeb, 0x52, 0xde, 0x7b, 0xf9, 0x40, 0x9d, - 0xd0, 0x5d, 0xaa, 0x37, 0x7c, 0x46, 0x11, 0xf5, 0xbc, 0x9b, 0x9b, 0x3e, - 0x7b, 0xf1, 0xdd, 0x43, 0x98, 0x50, 0x35, 0x5c, 0x8b, 0xcb, 0x43, 0xcd, - 0xf5, 0x87, 0x52, 0x87, 0x10, 0x04, 0xb8, 0x3e, 0x17, 0x8e, 0xd0, 0xd9, - 0x42, 0x4a, 0x89, 0xb0, 0xca, 0xc6, 0x5d, 0xa0, 0xeb, 0xca, 0x11, 0xed, - 0x9b, 0x4a, 0xb6, 0xb4, 0x95, 0x70, 0x75, 0x64, 0x31, 0x8a, 0x47, 0x72, - 0x08, 0x2d, 0xae, 0xec, 0x45, 0x78, 0x19, 0x11, 0xdc, 0xcc, 0xa5, 0xe4, - 0xa1, 0xf5, 0x0e, 0x58, 0xeb, 0xe7, 0xab, 0x90, 0x5b, 0xdb, 0x0c, 0xdb, - 0xcb, 0x78, 0x29, 0xca, 0xce, 0xea, 0xaa, 0xab, 0xae, 0xd5, 0x8e, 0x06, - 0x83, 0x27, 0x81, 0x01, 0xad, 0xe8, 0x13, 0x56, 0x17, 0x58, 0xac, 0x0c, - 0xc3, 0x9e, 0x36, 0xba, 0xcd, 0x52, 0xc1, 0x0e, 0xee, 0x55, 0xa9, 0x37, - 0x72, 0x9f, 0x99, 0xe3, 0xb2, 0x52, 0x31, 0xfa, 0x48, 0x2f, 0x82, 0x2b, - 0x70, 0x3a, 0xe3, 0x09, 0x64, 0x43, 0xb2, 0x85, 0x58, 0x7e, 0xb6, 0x68, - 0x21, 0x7a, 0x95, 0x5d, 0xeb, 0xea, 0xc2, 0x34, 0x47, 0xe6, 0x44, 0xd5, - 0xed, 0x2e, 0x9c, 0x1d, 0x8b, 0x9e, 0x39, 0xcc, 0xed, 0xdd, 0xb5, 0xcf, - 0x2c, 0xdf, 0x3a, 0x70, 0xa3, 0xcb, 0xda, 0x3b, 0x98, 0x22, 0xb5, 0xeb, - 0x79, 0x3b, 0x42, 0x90, 0x69, 0x6e, 0xaf, 0xc7, 0x81, 0xde, 0x74, 0xd8, - 0x78, 0x5d, 0x67, 0xea, 0x68, 0x2e, 0x84, 0x4d, 0x1f, 0xda, 0x3b, 0xd4, - 0x35, 0x83, 0xb0, 0xe1, 0x05, 0xb3, 0xde, 0xce, 0xe1, 0xad, 0x3a, 0xe7, - 0xe2, 0x11, 0x15, 0x12, 0xc2, 0x26, 0x30, 0x63, 0xab, 0x6b, 0x8d, 0x62, - 0x5d, 0x92, 0x88, 0xe8, 0x77, 0xfc, 0x3e, 0xb7, 0x2b, 0x45, 0xd9, 0xee, - 0x73, 0xb5, 0x11, 0xc1, 0x4b, 0x6b, 0xbc, 0xb9, 0x6c, 0xb9, 0xd9, 0xa9, - 0xe4, 0x62, 0x5c, 0x51, 0xaf, 0xea, 0x7a, 0xd5, 0x52, 0xc6, 0xea, 0x58, - 0x1c, 0x98, 0xbe, 0xb0, 0x10, 0x63, 0x54, 0xac, 0xb5, 0xc9, 0x8a, 0x45, - 0x74, 0x5e, 0x0e, 0xdc, 0x18, 0xc5, 0xe7, 0x43, 0x0c, 0xd5, 0x81, 0x41, - 0x91, 0x50, 0x61, 0x39, 0x55, 0x7b, 0x0e, 0x93, 0x65, 0xbb, 0x5c, 0xce, - 0x15, 0xd2, 0xde, 0x60, 0xbe, 0x09, 0x11, 0xc2, 0x45, 0x88, 0xe7, 0x5d, - 0x18, 0xaf, 0x7b, 0xb6, 0xe8, 0xe4, 0xca, 0xc5, 0x28, 0xb9, 0x88, 0xb5, - 0x55, 0x92, 0xed, 0x79, 0x48, 0xc2, 0xcf, 0x2e, 0x91, 0xac, 0x7d, 0x42, - 0xe9, 0x1a, 0x60, 0x7e, 0x59, 0x41, 0x5b, 0xa8, 0x54, 0x19, 0x0d, 0x54, - 0x9d, 0x75, 0x0b, 0x4d, 0x42, 0xe5, 0x91, 0x11, 0x2e, 0x88, 0xa4, 0xc0, - 0x2a, 0x05, 0x21, 0xeb, 0x85, 0xa3, 0x55, 0xce, 0x98, 0x1e, 0xe3, 0x30, - 0xd3, 0xe2, 0x12, 0xa4, 0x97, 0x3a, 0x47, 0x9f, 0xe7, 0x99, 0x24, 0xcb, - 0x47, 0xac, 0x6d, 0xe7, 0xe5, 0xd6, 0x26, 0x54, 0x96, 0x84, 0x14, 0xb7, - 0x02, 0x8a, 0x2c, 0xb2, 0x99, 0x19, 0xca, 0x33, 0x76, 0xb5, 0xd5, 0x68, - 0x5a, 0xd0, 0x74, 0xbd, 0x92, 0x2e, 0x26, 0xbb, 0xc3, 0xe9, 0xd1, 0x6c, - 0x2f, 0xec, 0xd8, 0x61, 0xac, 0xc3, 0x9e, 0xf9, 0x62, 0xa5, 0xaa, 0x14, - 0xec, 0x69, 0x1a, 0x1b, 0x38, 0x1a, 0x5d, 0x51, 0xae, 0x76, 0xdc, 0x94, - 0x33, 0xc4, 0x1a, 0x67, 0x4c, 0xd8, 0xb4, 0x9b, 0x99, 0x10, 0xd6, 0xab, - 0x5e, 0xec, 0x54, 0x61, 0xe7, 0x86, 0xda, 0x61, 0x24, 0x33, 0x02, 0x12, - 0xdc, 0xab, 0x30, 0x20, 0x44, 0xc0, 0xb0, 0x9c, 0x4d, 0x42, 0x6c, 0x7e, - 0x80, 0xcf, 0x75, 0x7d, 0x61, 0xf3, 0x73, 0x9e, 0x1b, 0x1b, 0xc8, 0xba, - 0x20, 0xec, 0x55, 0x74, 0x8b, 0x4e, 0xdd, 0xa3, 0x67, 0x39, 0x66, 0x05, - 0xf5, 0xdc, 0x53, 0xa3, 0x49, 0xca, 0xf4, 0x6a, 0x58, 0x69, 0x83, 0x7a, - 0xa2, 0x4e, 0x08, 0x48, 0x43, 0x18, 0x2b, 0x2c, 0x1a, 0x5f, 0xec, 0x5d, - 0xde, 0x64, 0x96, 0x94, 0x86, 0xf9, 0xa2, 0xbc, 0x44, 0x3b, 0xab, 0x6d, - 0xac, 0xb6, 0x73, 0x9d, 0x46, 0x07, 0xea, 0x58, 0x6d, 0xcf, 0x63, 0x2b, - 0x8e, 0x5a, 0xa3, 0x75, 0x25, 0x08, 0x43, 0x0f, 0x46, 0x5c, 0x10, 0xf1, - 0x09, 0x3d, 0x3b, 0xcc, 0xb1, 0xf1, 0x0f, 0x1c, 0x6e, 0xc4, 0x4a, 0x7c, - 0x11, 0x69, 0xa8, 0x3b, 0x54, 0x03, 0x79, 0xf4, 0x7a, 0xa9, 0xec, 0x29, - 0x4b, 0x5d, 0x3b, 0xa7, 0xc3, 0x45, 0xe2, 0x30, 0xcc, 0x30, 0x58, 0x7c, - 0x43, 0x93, 0xa9, 0x2a, 0xf5, 0x5a, 0x09, 0x13, 0x9d, 0xaa, 0x62, 0x38, - 0x3b, 0x4e, 0x6d, 0x61, 0x96, 0xbd, 0x1d, 0x95, 0x85, 0x8d, 0x88, 0x5c, - 0x77, 0xd8, 0x52, 0xfc, 0x91, 0xe5, 0xd9, 0xb5, 0x10, 0x9f, 0x18, 0x85, - 0x42, 0x36, 0xc1, 0xd9, 0xf3, 0xfc, 0x1a, 0x67, 0xe8, 0xf4, 0x70, 0xe8, - 0x04, 0xfc, 0x54, 0x97, 0xaa, 0xb1, 0x65, 0xad, 0x72, 0x2e, 0xeb, 0xb4, - 0x06, 0xe7, 0xe7, 0x32, 0xc7, 0x8e, 0xeb, 0x66, 0x11, 0x04, 0xe6, 0x78, - 0x51, 0x4f, 0xa2, 0x4a, 0x65, 0x58, 0x0d, 0xe8, 0x93, 0x6e, 0x95, 0x35, - 0xc4, 0x65, 0x3b, 0xc6, 0x4c, 0xd9, 0x2e, 0x42, 0x10, 0xfe, 0x7c, 0x24, - 0x8b, 0xce, 0xb6, 0x8e, 0xca, 0xb2, 0xce, 0x6b, 0x5c, 0xa3, 0x17, 0xd7, - 0x1a, 0x8b, 0x63, 0x39, 0x26, 0x4c, 0x52, 0xd0, 0x40, 0xcc, 0x37, 0x78, - 0x0d, 0x0b, 0x82, 0x5d, 0x09, 0x65, 0xd2, 0xe2, 0x1a, 0x93, 0xbd, 0xc5, - 0x26, 0x67, 0x0b, 0x5a, 0x9e, 0x93, 0x3d, 0xc1, 0x09, 0x79, 0x82, 0x2d, - 0xd6, 0xcc, 0x78, 0x8a, 0xa8, 0x32, 0x4b, 0x78, 0x9f, 0x6b, 0x5c, 0xb3, - 0x50, 0x57, 0x66, 0x10, 0xad, 0x5b, 0xa4, 0xdb, 0x87, 0x31, 0x69, 0xdb, - 0x8b, 0x6a, 0x9f, 0x4a, 0xd8, 0x28, 0x4b, 0x82, 0xb5, 0xe9, 0x58, 0x74, - 0xac, 0x34, 0xb1, 0x2f, 0x47, 0xeb, 0xb4, 0xa9, 0xd6, 0xe8, 0xa9, 0xb4, - 0x20, 0x68, 0xa7, 0x63, 0x41, 0xe9, 0x2f, 0x2b, 0xdd, 0x39, 0x99, 0xfc, - 0x59, 0x5e, 0x9c, 0xb0, 0x22, 0xc3, 0xcf, 0x98, 0x2c, 0xbb, 0x16, 0x49, - 0xd1, 0x9b, 0x28, 0x47, 0x59, 0x76, 0x48, 0x0e, 0xdb, 0xa5, 0x0c, 0xd4, - 0x24, 0x0a, 0xe5, 0x74, 0x9f, 0x41, 0xd7, 0xb8, 0x1e, 0xd1, 0xc4, 0xb6, - 0x36, 0x88, 0x95, 0xce, 0xda, 0xa0, 0x2b, 0xfd, 0xed, 0x49, 0x62, 0x1c, - 0x07, 0x9f, 0xf9, 0x19, 0xc6, 0xcd, 0x0c, 0x37, 0xd2, 0xb6, 0xc0, 0xd8, - 0x85, 0x20, 0xb2, 0xf7, 0xe6, 0xe5, 0x2a, 0x60, 0xe3, 0x24, 0x3b, 0x0e, - 0x4e, 0x9e, 0x0a, 0xe4, 0x71, 0x79, 0xcd, 0x75, 0x67, 0x51, 0x26, 0x05, - 0xde, 0x68, 0x1b, 0x55, 0xcb, 0xe6, 0x91, 0x61, 0x0f, 0x43, 0xb6, 0xdc, - 0x43, 0xdc, 0x59, 0xbf, 0x36, 0xb1, 0xa4, 0x51, 0xed, 0x39, 0xcf, 0x34, - 0x78, 0x85, 0x4a, 0x99, 0x8f, 0xb3, 0xe7, 0x0b, 0xbd, 0x4f, 0x5b, 0xfa, - 0x6a, 0x77, 0x41, 0xd9, 0x0b, 0xd0, 0x42, 0x27, 0x93, 0x68, 0x2e, 0x6d, - 0xf2, 0x84, 0x1b, 0xc9, 0x28, 0x56, 0xeb, 0x71, 0xb7, 0x49, 0xb6, 0x23, - 0xad, 0xcb, 0x97, 0xab, 0xea, 0x90, 0xa4, 0x5a, 0xd8, 0xa9, 0xb4, 0x61, - 0x93, 0x9a, 0xca, 0xe4, 0xae, 0x75, 0xea, 0x38, 0xa4, 0x45, 0x76, 0x4f, - 0x9f, 0x33, 0x02, 0x45, 0x98, 0x7a, 0x9b, 0xaa, 0x2b, 0xa1, 0x5e, 0x51, - 0x58, 0x98, 0x66, 0xe2, 0x30, 0xee, 0x97, 0x43, 0x13, 0x46, 0x61, 0xb9, - 0xcc, 0x3b, 0x23, 0x85, 0x15, 0x83, 0x8c, 0xea, 0x7e, 0xbd, 0x20, 0x9d, - 0x32, 0x86, 0x97, 0xeb, 0x88, 0xe1, 0x2d, 0x96, 0x29, 0x90, 0x64, 0x17, - 0xc8, 0x06, 0xa5, 0x15, 0x84, 0x17, 0xf2, 0xc4, 0x72, 0x89, 0xcc, 0x7d, - 0x90, 0xfa, 0x04, 0xc3, 0xec, 0xd2, 0xaf, 0x1d, 0xcc, 0xbc, 0x2c, 0x4b, - 0xf1, 0x12, 0x74, 0x5c, 0xb1, 0x35, 0xd4, 0xb5, 0xc1, 0x6c, 0x57, 0x8c, - 0x7d, 0x1d, 0xe5, 0x9d, 0x77, 0x82, 0x5c, 0x95, 0xd6, 0x93, 0xa4, 0x0a, - 0x84, 0x15, 0xc4, 0xcd, 0xb2, 0x4d, 0x5e, 0xa6, 0x24, 0x83, 0x7a, 0x31, - 0x81, 0x6c, 0x3a, 0x0a, 0xc0, 0xb7, 0x68, 0x80, 0x6e, 0x17, 0xd9, 0x4e, - 0x30, 0x78, 0x85, 0x04, 0x9b, 0xca, 0x72, 0x00, 0x10, 0x39, 0xc1, 0x37, - 0x74, 0xb8, 0x3d, 0xb3, 0x99, 0xe6, 0xa2, 0xda, 0xd8, 0x5f, 0xa9, 0xe1, - 0xca, 0xaf, 0x14, 0x2a, 0x0e, 0xfa, 0xc1, 0x1a, 0x05, 0x8a, 0x72, 0xcf, - 0x08, 0x8b, 0xce, 0x84, 0x9d, 0xc2, 0xce, 0x36, 0xb8, 0xde, 0x0b, 0x11, - 0xc7, 0x86, 0x8a, 0xc8, 0x27, 0xe7, 0xbc, 0xee, 0x22, 0x98, 0x0f, 0x7a, - 0x84, 0x5f, 0xf0, 0x35, 0x56, 0xaf, 0x0f, 0xc0, 0x2f, 0x6e, 0x05, 0xd3, - 0xcb, 0x95, 0x24, 0xd4, 0x06, 0x26, 0x77, 0x47, 0x5f, 0x87, 0x3a, 0x22, - 0x91, 0x4a, 0x31, 0x1b, 0x82, 0x9e, 0x2b, 0xc7, 0x62, 0xa9, 0xa6, 0x38, - 0x9f, 0x6c, 0x74, 0xf8, 0x2a, 0x0e, 0xbe, 0x0a, 0xcb, 0x5b, 0x95, 0x90, - 0x95, 0xcb, 0x79, 0x1e, 0x9e, 0xcb, 0xfd, 0x66, 0x91, 0x37, 0xca, 0x1c, - 0x29, 0xce, 0x0e, 0x2c, 0x0e, 0x2b, 0x7a, 0x9a, 0x94, 0xb7, 0x8d, 0x7e, - 0xeb, 0x59, 0x62, 0x61, 0xb1, 0xb2, 0xdc, 0x5c, 0x9c, 0xb1, 0x3a, 0x9e, - 0xbd, 0x2a, 0x59, 0x6d, 0x79, 0x6e, 0x3f, 0x37, 0xb7, 0xac, 0xa4, 0x19, - 0xd7, 0x74, 0xbd, 0xcb, 0x2b, 0x3a, 0x49, 0x32, 0x86, 0x81, 0x56, 0xb6, - 0xad, 0x10, 0x88, 0x55, 0x81, 0x70, 0x9c, 0x55, 0xd6, 0x65, 0x9f, 0xaa, - 0x18, 0x36, 0x0b, 0xb6, 0xf8, 0xac, 0x63, 0xb3, 0x93, 0xc6, 0x30, 0x38, - 0xc3, 0x9f, 0xcf, 0xd4, 0xd6, 0xbc, 0x6e, 0x74, 0x4e, 0xc2, 0x18, 0xbc, - 0x5b, 0x1b, 0x16, 0x71, 0xde, 0x2c, 0xd1, 0xad, 0xb0, 0x6d, 0x7a, 0x72, - 0x2e, 0xb2, 0xf3, 0x58, 0xda, 0xa6, 0xcb, 0xed, 0x74, 0x5a, 0x0f, 0x7e, - 0x30, 0x8e, 0xd6, 0x7a, 0x2d, 0xd1, 0x26, 0x6a, 0xf9, 0x65, 0x6c, 0x2c, - 0x35, 0x21, 0x94, 0xc5, 0x9e, 0x1e, 0x84, 0x18, 0x16, 0x5d, 0x69, 0x18, - 0x65, 0x3f, 0xd0, 0x71, 0x49, 0x48, 0x91, 0xda, 0x17, 0x2b, 0x45, 0x13, - 0x28, 0xbc, 0x2a, 0x63, 0x4f, 0x71, 0x6d, 0x8e, 0xb2, 0x10, 0x6d, 0xd6, - 0x8e, 0x2e, 0xc6, 0x67, 0x79, 0x6a, 0x2d, 0x49, 0xd3, 0x28, 0x0a, 0x2b, - 0x90, 0xb4, 0xeb, 0xa6, 0x9f, 0x5f, 0xe0, 0x23, 0x0a, 0x09, 0x83, 0x9f, - 0x45, 0x9b, 0x39, 0x0e, 0x34, 0x72, 0x2f, 0x0e, 0xed, 0x66, 0x7f, 0x59, - 0x17, 0x07, 0xa3, 0xa5, 0x57, 0xf5, 0x60, 0x39, 0x3b, 0x37, 0xd6, 0xb3, - 0xb9, 0xc2, 0xd4, 0x52, 0xa0, 0x71, 0x02, 0x84, 0x9c, 0x24, 0xbb, 0x4d, - 0x05, 0x38, 0xc7, 0x91, 0x79, 0x4b, 0x8e, 0x7d, 0x38, 0xa0, 0xe3, 0xee, - 0x9c, 0xea, 0xfd, 0x59, 0x93, 0x3a, 0x53, 0x61, 0xaf, 0x29, 0xe7, 0x9e, - 0x8f, 0x55, 0x5d, 0x0d, 0x25, 0x32, 0x72, 0x89, 0x24, 0x24, 0x9b, 0x70, - 0x5f, 0x46, 0xfe, 0x22, 0xb3, 0x11, 0x7d, 0xb5, 0x24, 0x03, 0xf9, 0xdc, - 0x69, 0x6c, 0xdb, 0xed, 0xcf, 0x41, 0x69, 0x4a, 0x70, 0x3b, 0xdd, 0xbb, - 0xc0, 0x97, 0xf2, 0xac, 0xdc, 0xb4, 0x3b, 0x72, 0xb6, 0xdd, 0x68, 0xe6, - 0x6e, 0x2e, 0x1a, 0xf6, 0xc6, 0xc9, 0x32, 0x03, 0x4b, 0xf0, 0xa6, 0x1a, - 0x05, 0x77, 0x8e, 0xf5, 0x1b, 0xaf, 0x34, 0x76, 0xfb, 0x75, 0x53, 0x42, - 0xa7, 0xb9, 0x6e, 0x58, 0x28, 0x09, 0xf9, 0xc7, 0xbc, 0x73, 0x14, 0x12, - 0x1d, 0xbb, 0xd1, 0x1c, 0xdb, 0x8d, 0x4c, 0x31, 0xa4, 0x1e, 0xad, 0x6d, - 0x32, 0x75, 0x14, 0xae, 0x2e, 0x93, 0x8a, 0xed, 0xf0, 0x63, 0x88, 0x5e, - 0x8c, 0xa0, 0xba, 0x58, 0x24, 0x21, 0x6d, 0x03, 0xc6, 0x3d, 0x8d, 0x7a, - 0xc8, 0x66, 0x91, 0x18, 0x78, 0x23, 0x76, 0x20, 0x2d, 0xcf, 0x39, 0x25, - 0x1e, 0x5b, 0x87, 0xcb, 0x51, 0xdc, 0x2f, 0x2b, 0xdf, 0x3e, 0x9f, 0x05, - 0x46, 0xd2, 0xe5, 0x50, 0x10, 0x4b, 0x39, 0x29, 0xa0, 0x61, 0xad, 0x2e, - 0x0d, 0x69, 0x89, 0xfa, 0xf3, 0xa3, 0x56, 0x02, 0x03, 0x55, 0xef, 0xea, - 0x44, 0xce, 0xa3, 0x8a, 0xae, 0x77, 0xd7, 0x30, 0xc5, 0xf5, 0x60, 0x17, - 0x1d, 0x10, 0x68, 0x9b, 0x9c, 0xcd, 0x7e, 0x4e, 0xac, 0x1b, 0x57, 0xeb, - 0x91, 0x8d, 0x17, 0xb1, 0xfc, 0xb8, 0xb6, 0xa2, 0xeb, 0x71, 0x03, 0xeb, - 0x86, 0x86, 0x16, 0xee, 0x1e, 0xb6, 0x75, 0x1e, 0xaf, 0xe6, 0x6b, 0x71, - 0x60, 0xb5, 0x4c, 0x94, 0x16, 0xeb, 0x98, 0xc8, 0xe0, 0x93, 0x95, 0xa4, - 0x3e, 0x62, 0x8e, 0x18, 0x6b, 0xb0, 0xab, 0xbe, 0x9b, 0x19, 0xa8, 0x51, - 0x31, 0x3c, 0x3a, 0x6f, 0x39, 0x28, 0x98, 0x5b, 0x1a, 0xbf, 0x61, 0xe0, - 0xd0, 0x87, 0x4e, 0x8b, 0xc8, 0x5a, 0x36, 0xc4, 0x61, 0xd1, 0xa4, 0x45, - 0xee, 0x01, 0xce, 0xea, 0x62, 0xb5, 0x5a, 0xa5, 0xfb, 0xd9, 0x32, 0x4e, - 0x6b, 0xa1, 0x57, 0xf1, 0x74, 0x40, 0xa6, 0x9d, 0xb0, 0xd3, 0x3c, 0x7d, - 0x0f, 0x12, 0x1b, 0x5b, 0xb3, 0x31, 0x95, 0x0d, 0xcb, 0xad, 0x94, 0x4b, - 0x57, 0xce, 0x59, 0xa6, 0xb2, 0x61, 0xa6, 0x07, 0x04, 0xcd, 0x66, 0x12, - 0x36, 0x8f, 0x8a, 0x45, 0xb3, 0x82, 0xed, 0x8a, 0xc4, 0x6b, 0x75, 0x06, - 0x39, 0x78, 0x1e, 0xc9, 0xbc, 0xae, 0x1e, 0x2e, 0x2b, 0x1c, 0x39, 0x6b, - 0x05, 0x47, 0xa0, 0xa4, 0x76, 0x76, 0x39, 0x1b, 0x13, 0x36, 0x19, 0x08, - 0xd5, 0x19, 0xa1, 0xa5, 0x7a, 0x43, 0x89, 0x41, 0x02, 0x19, 0x96, 0x33, - 0xda, 0x72, 0x39, 0xb3, 0x70, 0xb7, 0x07, 0x16, 0xc2, 0x24, 0x81, 0xbf, - 0x20, 0xce, 0x7c, 0xe7, 0x6f, 0x8a, 0xf8, 0x98, 0xe5, 0x33, 0xa8, 0xd3, - 0x33, 0x12, 0x04, 0xc8, 0x8b, 0x23, 0x92, 0xa6, 0x52, 0xc9, 0xb9, 0xa6, - 0x7d, 0x85, 0x3d, 0xa9, 0xb1, 0x90, 0xad, 0xbc, 0xa6, 0xfa, 0x4e, 0x3e, - 0x1c, 0x7b, 0xc8, 0x94, 0xd4, 0x96, 0x85, 0x96, 0xc9, 0x7e, 0x8b, 0xd4, - 0x34, 0x04, 0xc8, 0xac, 0xc9, 0xea, 0x95, 0xde, 0x48, 0x6a, 0xea, 0x43, - 0xd2, 0x11, 0x92, 0x1c, 0x82, 0x8c, 0x44, 0x21, 0xb8, 0xf6, 0x2c, 0x8b, - 0x6b, 0x4b, 0xda, 0xc8, 0xbc, 0x64, 0x3c, 0xf0, 0x58, 0xbb, 0x2c, 0xf8, - 0xee, 0x7a, 0xe4, 0x4b, 0xa3, 0x55, 0xf1, 0xb8, 0x43, 0xf7, 0x4b, 0xf9, - 0xe4, 0xb7, 0xb9, 0x50, 0x91, 0xe4, 0x2e, 0x54, 0x09, 0xb5, 0x3a, 0xd4, - 0x4b, 0xb2, 0x8d, 0x4c, 0x32, 0xe7, 0x68, 0x27, 0xda, 0xd4, 0xa5, 0xcb, - 0xc9, 0x2a, 0x62, 0xa8, 0xe8, 0x70, 0x62, 0x7c, 0x1d, 0x3b, 0xe4, 0xc3, - 0x3e, 0x9d, 0x5f, 0x7b, 0xf4, 0xd4, 0x98, 0xb3, 0xfd, 0xe2, 0x94, 0x5b, - 0x9d, 0xd5, 0xc7, 0x48, 0xef, 0xac, 0xd8, 0x1a, 0x0e, 0xea, 0x33, 0xbd, - 0xca, 0x8f, 0x1a, 0xbd, 0xb1, 0x6d, 0x92, 0x5a, 0x35, 0x1e, 0xc8, 0x38, - 0xa8, 0x60, 0x2f, 0xe3, 0x18, 0xe1, 0xad, 0xb6, 0xb3, 0xe5, 0xb2, 0xa1, - 0x0b, 0x22, 0x5c, 0x26, 0x1b, 0xb4, 0x88, 0x0f, 0xe7, 0x48, 0xb6, 0x68, - 0x06, 0x04, 0x5d, 0x67, 0xb4, 0x15, 0x58, 0x73, 0x75, 0xa0, 0x3d, 0xbf, - 0x5d, 0x9f, 0x0d, 0x6c, 0x55, 0x6a, 0x33, 0x7e, 0xdb, 0xae, 0xc9, 0xf5, - 0x89, 0xd9, 0xcb, 0xc7, 0xeb, 0x09, 0x46, 0x45, 0x32, 0x86, 0x8d, 0x1d, - 0xae, 0x9d, 0x2f, 0xfa, 0xa0, 0x46, 0x5a, 0x3d, 0x5c, 0x37, 0xd8, 0x18, - 0x5f, 0x2e, 0x25, 0x7d, 0x58, 0xaf, 0x8d, 0xf5, 0xb2, 0x4b, 0x2f, 0xe7, - 0x3d, 0x8c, 0xe1, 0x51, 0x1f, 0xcd, 0xe2, 0x03, 0x06, 0xfc, 0x7d, 0xaf, - 0x30, 0xa5, 0xb2, 0xe2, 0x30, 0x6a, 0x55, 0xac, 0xe2, 0xe9, 0x72, 0x05, - 0x4c, 0xd4, 0x62, 0xe8, 0x54, 0x91, 0x08, 0x14, 0x1f, 0xb4, 0x5a, 0xc0, - 0x4e, 0xce, 0xf9, 0xb2, 0x52, 0xb5, 0x75, 0x9e, 0xf6, 0xe4, 0x61, 0xb5, - 0x8b, 0x66, 0xfe, 0x0a, 0x43, 0x97, 0x30, 0xa6, 0x5f, 0xe5, 0x99, 0xc4, - 0xc3, 0xd5, 0x4a, 0x0f, 0xcc, 0x2a, 0x37, 0x96, 0xdd, 0x62, 0xd1, 0xf3, - 0xe7, 0xb4, 0x3a, 0x0c, 0x5b, 0xac, 0x11, 0x56, 0x84, 0xd4, 0xb3, 0xdb, - 0xa4, 0x39, 0x1e, 0xfd, 0x0d, 0xbd, 0xa0, 0x98, 0x2b, 0x4e, 0xae, 0x63, - 0x7b, 0xe3, 0xe5, 0xda, 0x2c, 0xc8, 0x79, 0xe4, 0x20, 0x96, 0x30, 0x96, - 0x48, 0xeb, 0xb3, 0x75, 0x92, 0x00, 0x0f, 0xba, 0xf5, 0x11, 0xd9, 0xcd, - 0x54, 0x32, 0xa6, 0x14, 0x03, 0x88, 0xf3, 0xa8, 0x10, 0x38, 0x3c, 0x36, - 0x81, 0xb6, 0xd0, 0xa8, 0x39, 0x4c, 0x1a, 0xd5, 0xc1, 0x1a, 0xd3, 0x64, - 0x77, 0x05, 0x7a, 0x0f, 0xa2, 0xaf, 0x06, 0x0f, 0x69, 0x8b, 0x54, 0x2c, - 0x3d, 0xf2, 0xf4, 0xd3, 0x0c, 0xb3, 0x50, 0x3b, 0x60, 0x9d, 0xe3, 0x49, - 0x59, 0x64, 0xf4, 0x3a, 0x22, 0x77, 0x94, 0x82, 0x84, 0xe8, 0x50, 0x4a, - 0x07, 0xf4, 0x92, 0x8b, 0x4a, 0x53, 0x45, 0xe4, 0xfe, 0x30, 0x6b, 0x92, - 0xb9, 0xa7, 0x71, 0x31, 0x5c, 0xc9, 0x67, 0x45, 0x6a, 0x21, 0x35, 0x6b, - 0x63, 0x06, 0xdb, 0xac, 0x96, 0xcb, 0x65, 0x95, 0xc7, 0xba, 0xc8, 0xe1, - 0x07, 0x81, 0x6a, 0xb2, 0xeb, 0x01, 0x6e, 0x70, 0x63, 0x91, 0xf4, 0x3a, - 0x79, 0x8e, 0x83, 0x8a, 0xbd, 0xce, 0x03, 0xe2, 0xb2, 0xdc, 0x96, 0xc4, - 0xfe, 0x30, 0x5a, 0xd0, 0xb1, 0x5d, 0xd1, 0xa6, 0x61, 0xe7, 0xe4, 0x5e, - 0x72, 0xaa, 0x4b, 0x31, 0x24, 0x4c, 0x88, 0xb6, 0x07, 0x2d, 0xb8, 0x2c, - 0xf4, 0x83, 0xd8, 0x65, 0xf6, 0x46, 0x38, 0xcf, 0x76, 0x0b, 0x3f, 0x21, - 0xfb, 0xc8, 0xa5, 0x5c, 0x5e, 0xd4, 0xd6, 0x73, 0x71, 0x61, 0x06, 0x4e, - 0x50, 0x51, 0xbb, 0x39, 0x1c, 0x08, 0xc2, 0x49, 0x58, 0x47, 0xac, 0x6c, - 0xe0, 0x68, 0x81, 0x9e, 0x4f, 0xaa, 0x10, 0x24, 0x78, 0x2e, 0x62, 0x74, - 0x10, 0x0a, 0x9c, 0xa3, 0x2a, 0x5e, 0xe0, 0x30, 0xf6, 0xea, 0x9a, 0x53, - 0x5b, 0xb9, 0x3d, 0xe4, 0xc2, 0x4e, 0x15, 0xcb, 0xc1, 0x52, 0x58, 0x5e, - 0xdd, 0xac, 0xb2, 0x95, 0x0b, 0x55, 0xe8, 0x1e, 0x72, 0x8e, 0x01, 0xca, - 0x8d, 0xdd, 0x65, 0x9f, 0xea, 0x8e, 0x9e, 0x8a, 0x97, 0x39, 0xac, 0xeb, - 0xbc, 0x57, 0xe9, 0xd2, 0x7e, 0x46, 0x06, 0x7c, 0x90, 0x5c, 0xd5, 0xe0, - 0xa2, 0xcf, 0x4e, 0x32, 0x1a, 0x6c, 0x18, 0xd1, 0xe6, 0x61, 0xa8, 0xc4, - 0x58, 0xb9, 0xe6, 0x4d, 0x62, 0x8d, 0x70, 0x6a, 0x08, 0xad, 0x3d, 0xf8, - 0xca, 0xc5, 0x75, 0x73, 0x4e, 0x88, 0x13, 0x88, 0xfc, 0xbb, 0x55, 0xe5, - 0xef, 0x37, 0x67, 0x57, 0xdd, 0x55, 0x48, 0x50, 0x40, 0x70, 0x0a, 0xa5, - 0xae, 0x4f, 0x3b, 0xf2, 0xd0, 0x3b, 0x63, 0xde, 0x35, 0x36, 0x26, 0x57, - 0x8b, 0xab, 0x77, 0xb2, 0xa9, 0xf3, 0x6a, 0xa9, 0xd3, 0x59, 0x44, 0xce, - 0x46, 0xb3, 0x5e, 0x84, 0xfb, 0x62, 0x36, 0x08, 0x72, 0x32, 0x8f, 0xcf, - 0xfb, 0x91, 0xb3, 0x75, 0x31, 0x65, 0x98, 0xda, 0xda, 0xa9, 0x29, 0x63, - 0x1d, 0x96, 0x86, 0x8e, 0xcb, 0x8b, 0xa3, 0x6e, 0x0f, 0xec, 0x8e, 0xe8, - 0xc6, 0x8e, 0x33, 0x10, 0xc8, 0x33, 0x11, 0x73, 0x17, 0xac, 0x98, 0x39, - 0x61, 0x78, 0x3a, 0xc5, 0x5e, 0xa4, 0x25, 0x71, 0xae, 0x85, 0x98, 0x72, - 0x17, 0x42, 0x50, 0x35, 0xec, 0x7e, 0x76, 0xb9, 0xb2, 0x29, 0x64, 0x80, - 0x40, 0x8e, 0x58, 0x52, 0x25, 0x61, 0x8d, 0x58, 0xea, 0x36, 0x1e, 0xae, - 0x56, 0xee, 0x9e, 0xf4, 0x25, 0xa9, 0xe0, 0x7b, 0x61, 0x39, 0xf3, 0x6b, - 0xba, 0x54, 0xb5, 0x33, 0x86, 0x89, 0xc8, 0x1a, 0x70, 0x00, 0x9b, 0x9b, - 0xad, 0x64, 0xc0, 0x27, 0x0d, 0xf2, 0xd7, 0x7c, 0x2a, 0x5d, 0x16, 0x44, - 0x09, 0xe1, 0x47, 0xc3, 0xd2, 0xe7, 0x8a, 0x91, 0x83, 0x04, 0x85, 0x90, - 0x31, 0x14, 0x22, 0xf6, 0x1b, 0x67, 0x75, 0x54, 0x34, 0xbe, 0x9d, 0xb5, - 0x61, 0xec, 0x2e, 0x28, 0x0d, 0x96, 0x71, 0x7f, 0xde, 0x5e, 0x5a, 0x61, - 0x43, 0xd5, 0x88, 0x9a, 0x85, 0xdb, 0x91, 0x38, 0x38, 0x57, 0xdc, 0x80, - 0x83, 0x1d, 0x39, 0xc2, 0x84, 0xe8, 0x8f, 0xd4, 0x50, 0x8b, 0x70, 0x11, - 0x16, 0x5d, 0x9b, 0x9c, 0x03, 0x14, 0xe9, 0x6b, 0x3b, 0xda, 0x74, 0x52, - 0x13, 0x26, 0xc6, 0x75, 0x7f, 0x59, 0x5d, 0xe1, 0x71, 0xa4, 0x8b, 0x02, - 0xa4, 0xf6, 0xe3, 0x25, 0xd2, 0xe6, 0x09, 0x8c, 0x98, 0x47, 0x0a, 0x15, - 0xa3, 0x96, 0xf2, 0x56, 0x99, 0x74, 0x5a, 0x9c, 0x60, 0x2b, 0x28, 0x31, - 0xb2, 0x12, 0x0b, 0x79, 0x69, 0x6b, 0x6d, 0x4c, 0x58, 0xba, 0x95, 0x45, - 0x38, 0x2b, 0xed, 0x47, 0x65, 0x18, 0x0f, 0x2a, 0xb9, 0xac, 0x96, 0xb1, - 0x20, 0x72, 0xde, 0x99, 0xf5, 0xd0, 0xed, 0xe2, 0x62, 0x9f, 0x37, 0xe6, - 0x91, 0x1f, 0xce, 0x87, 0x91, 0xe0, 0x64, 0xd7, 0xbe, 0x62, 0xb6, 0x4b, - 0x5d, 0x6a, 0xdc, 0x85, 0x99, 0x48, 0x15, 0x51, 0xa6, 0x3f, 0xf7, 0xe7, - 0x8c, 0xe4, 0x4e, 0xb9, 0x52, 0x70, 0x27, 0x25, 0xd4, 0xd7, 0x6e, 0x23, - 0xd4, 0x43, 0xc0, 0x3b, 0x67, 0xbf, 0x37, 0x2f, 0x28, 0xb5, 0x1e, 0xe0, - 0xdd, 0x09, 0xeb, 0x97, 0x6b, 0x9e, 0x17, 0xcd, 0x95, 0x7b, 0xdd, 0xf2, - 0x07, 0x48, 0xa9, 0x53, 0x1c, 0x35, 0x67, 0xce, 0x8e, 0x50, 0x62, 0x38, - 0xbc, 0x48, 0x9e, 0x6a, 0xa1, 0x8a, 0x57, 0x0d, 0xd0, 0x6a, 0x5b, 0xad, - 0xcf, 0x7d, 0xb4, 0x3b, 0x5c, 0xd5, 0x21, 0x09, 0xc7, 0x45, 0x68, 0x76, - 0x8b, 0xad, 0x1f, 0x67, 0xaa, 0xc0, 0x6c, 0x8f, 0xcb, 0xc6, 0xae, 0x8e, - 0xca, 0x71, 0x79, 0x84, 0xc2, 0x56, 0x9a, 0xfb, 0x1a, 0x09, 0xb9, 0x59, - 0x4f, 0x85, 0xab, 0xe8, 0xb8, 0x8b, 0xe5, 0xa1, 0xce, 0xe0, 0xd8, 0x76, - 0x8d, 0x2a, 0x1f, 0x03, 0x69, 0xd4, 0x89, 0x11, 0xf2, 0xfc, 0x91, 0x5c, - 0x2a, 0x4c, 0xd5, 0x98, 0xc8, 0x41, 0x0a, 0x17, 0x52, 0xbd, 0x69, 0xe2, - 0x9e, 0x94, 0x0f, 0xe6, 0xbe, 0x0e, 0xed, 0x42, 0x09, 0x30, 0x1f, 0xc2, - 0xd8, 0x68, 0x5e, 0xb9, 0xb9, 0x75, 0x3d, 0x3b, 0xc6, 0xe2, 0x0c, 0x5f, - 0x62, 0x15, 0xc9, 0xc5, 0x25, 0x12, 0x0e, 0x5b, 0x45, 0xed, 0x90, 0x6d, - 0xa8, 0xcd, 0x9a, 0x63, 0x65, 0x84, 0x34, 0xb5, 0xd6, 0x04, 0xf1, 0x28, - 0xd9, 0x9b, 0xa1, 0xda, 0xd1, 0x94, 0x47, 0xd4, 0x59, 0x1b, 0x5c, 0x71, - 0x27, 0xd5, 0xb1, 0x51, 0x71, 0x18, 0x4f, 0x6f, 0xf3, 0x68, 0x08, 0xd9, - 0x39, 0x0b, 0x79, 0x41, 0xe1, 0xe9, 0xf6, 0x19, 0x3b, 0x37, 0xbe, 0xbb, - 0xbd, 0x34, 0x31, 0xd0, 0x14, 0x76, 0xb1, 0xc3, 0xa0, 0x96, 0x0d, 0x8f, - 0x9d, 0x68, 0xd6, 0x3b, 0xca, 0x9f, 0x67, 0x98, 0x4b, 0x5c, 0xd3, 0x0e, - 0x91, 0x1d, 0xe0, 0xf9, 0x22, 0x4b, 0xd8, 0x4a, 0x49, 0x73, 0xa0, 0x8c, - 0x6d, 0x04, 0x8c, 0x49, 0x20, 0x18, 0xe7, 0x14, 0xbb, 0x76, 0x5d, 0x80, - 0x43, 0x89, 0x12, 0x5e, 0x81, 0x69, 0x0a, 0x0a, 0xb3, 0x3b, 0xf6, 0x63, - 0x3b, 0xaf, 0x39, 0x03, 0xf3, 0x10, 0x8b, 0x33, 0xf9, 0xab, 0x52, 0x1a, - 0xda, 0xce, 0x42, 0xf7, 0x18, 0x7c, 0x5c, 0x76, 0xea, 0xa2, 0x1f, 0x07, - 0x6a, 0x17, 0xf9, 0x06, 0x24, 0x1b, 0x83, 0x3a, 0x6b, 0xc5, 0xbe, 0xbb, - 0x98, 0x22, 0x79, 0x3a, 0x71, 0x45, 0x9c, 0x34, 0xbb, 0x61, 0x3f, 0xdf, - 0xcd, 0xbd, 0x22, 0x6a, 0xf8, 0x03, 0xb5, 0xb7, 0xcd, 0x2b, 0x8a, 0xeb, - 0xc8, 0x0e, 0x9a, 0x0f, 0x16, 0xb1, 0x59, 0xb8, 0x99, 0xc2, 0xc1, 0xd8, - 0x99, 0x18, 0x68, 0xff, 0x04, 0x05, 0x72, 0xb4, 0x74, 0x4d, 0x87, 0x37, - 0xa6, 0x73, 0x8c, 0x4e, 0xa8, 0x21, 0xac, 0x70, 0x7a, 0x70, 0xb0, 0x52, - 0x2e, 0xab, 0x62, 0xbb, 0x1a, 0x16, 0xd4, 0xb1, 0xea, 0x20, 0x06, 0x9e, - 0x01, 0xeb, 0x25, 0x2f, 0x1b, 0x84, 0xe1, 0xf8, 0x4b, 0x74, 0x54, 0xf9, - 0x54, 0x28, 0xb2, 0x42, 0x50, 0x95, 0x5c, 0xa9, 0xb6, 0x90, 0x6b, 0x0f, - 0xc1, 0x69, 0xbe, 0x71, 0x73, 0x90, 0x8e, 0x2d, 0x6b, 0xc7, 0x12, 0xf6, - 0xb1, 0x31, 0x0f, 0xae, 0x47, 0x2d, 0xbc, 0xf2, 0x57, 0x49, 0x6e, 0x06, - 0x9b, 0x2a, 0xed, 0xd1, 0xe6, 0xb3, 0x78, 0x34, 0xb1, 0x65, 0xa1, 0x5c, - 0x7d, 0xee, 0x2a, 0xa2, 0xf0, 0x79, 0x88, 0x82, 0x98, 0x5d, 0x55, 0xc9, - 0xec, 0x1a, 0x0a, 0x6b, 0xee, 0x80, 0xe9, 0x85, 0xbd, 0x33, 0x57, 0xf0, - 0x2a, 0x96, 0x97, 0xfb, 0xfd, 0x5e, 0xcd, 0x13, 0x79, 0xa7, 0x2c, 0x35, - 0x47, 0xcc, 0x4c, 0x6f, 0x4e, 0x2d, 0x0e, 0xdb, 0x0d, 0xb5, 0x3c, 0xc3, - 0xfc, 0x79, 0xb9, 0x67, 0x1d, 0x7d, 0x71, 0x71, 0x1b, 0x1a, 0xc6, 0x15, - 0x38, 0x30, 0x98, 0x48, 0xdb, 0x54, 0x35, 0xdc, 0x84, 0x6a, 0xc2, 0x05, - 0x42, 0xad, 0x5a, 0x63, 0x17, 0x6d, 0xd0, 0x93, 0x2b, 0xd8, 0xc0, 0x07, - 0xce, 0x95, 0xe3, 0xce, 0xe8, 0x8e, 0xb8, 0xb9, 0x20, 0x4f, 0xe1, 0xb0, - 0x28, 0xd5, 0x26, 0xba, 0xd8, 0x59, 0xa3, 0xa2, 0x0c, 0xb5, 0xb1, 0x2c, - 0x45, 0xde, 0x1c, 0x99, 0xe3, 0xc5, 0xdb, 0x2b, 0xfe, 0x52, 0x5d, 0xb1, - 0x19, 0x83, 0xf4, 0x8b, 0x65, 0xa0, 0x6e, 0x51, 0x35, 0xaf, 0x0e, 0x61, - 0x48, 0x90, 0x5c, 0x35, 0xd0, 0x63, 0xd5, 0xc4, 0x9c, 0x92, 0xdb, 0x78, - 0x32, 0xe0, 0xec, 0x55, 0x55, 0xec, 0xb5, 0x71, 0x54, 0x2c, 0x46, 0x22, - 0xc6, 0xf5, 0xc1, 0x29, 0x77, 0x19, 0xb4, 0x91, 0xa4, 0x1a, 0x5b, 0xed, - 0xcf, 0x4d, 0x59, 0x7b, 0xe4, 0x19, 0x3a, 0x85, 0x32, 0xda, 0xb9, 0x9e, - 0x69, 0x5b, 0x0e, 0x3f, 0x77, 0x17, 0x30, 0x88, 0xd0, 0xd0, 0x4d, 0x3f, - 0xdb, 0x08, 0xa3, 0xe7, 0x74, 0xe7, 0x34, 0x76, 0x13, 0x4e, 0x67, 0xfb, - 0x21, 0x87, 0x1c, 0x13, 0xa3, 0x82, 0x88, 0x56, 0xb8, 0x25, 0x92, 0xad, - 0x17, 0x17, 0x47, 0xa7, 0x48, 0x03, 0xca, 0xd1, 0xb9, 0x55, 0xa9, 0x67, - 0x25, 0x6f, 0x5c, 0xe5, 0xb2, 0x72, 0x96, 0x42, 0xc3, 0x1c, 0xc4, 0xba, - 0x0e, 0xf6, 0xd5, 0xb8, 0xf0, 0x0c, 0x1e, 0xa6, 0x8a, 0x99, 0x81, 0x87, - 0xa5, 0x36, 0xd8, 0x9a, 0xba, 0x81, 0x17, 0xd7, 0x03, 0x19, 0xb0, 0x42, - 0x98, 0xd4, 0xbe, 0xe5, 0xad, 0x4d, 0xa4, 0x73, 0xa9, 0x43, 0x22, 0xdb, - 0xdc, 0x68, 0x00, 0x6a, 0x36, 0xe1, 0x99, 0xb6, 0x93, 0x05, 0xcf, 0x6d, - 0xbc, 0xd4, 0xdc, 0xb1, 0x17, 0x14, 0xa4, 0x51, 0xa2, 0x12, 0xb6, 0x23, - 0x8e, 0x3b, 0xc2, 0xc2, 0x2c, 0xed, 0xc2, 0xe1, 0xd8, 0x8b, 0xad, 0xe3, - 0xc7, 0x13, 0xde, 0xf6, 0x47, 0xfb, 0xd2, 0x04, 0x26, 0x71, 0x41, 0xf4, - 0x33, 0xd9, 0x9a, 0x7a, 0x7e, 0x99, 0xe1, 0x78, 0x47, 0x59, 0x87, 0xfd, - 0x4c, 0xc0, 0x33, 0x98, 0xc7, 0xfd, 0x8d, 0x7d, 0x59, 0x9b, 0x17, 0x4d, - 0xb9, 0x54, 0x54, 0xab, 0x61, 0xde, 0x89, 0xeb, 0xf5, 0x81, 0x86, 0x06, - 0x93, 0x0f, 0xd5, 0xf1, 0xc0, 0x75, 0xb3, 0x39, 0x90, 0x8b, 0x63, 0x72, - 0x6e, 0x4f, 0x07, 0x78, 0xd8, 0xce, 0x38, 0x04, 0xbf, 0x92, 0xaa, 0x52, - 0x6d, 0x0e, 0xab, 0x63, 0x7e, 0x36, 0x8f, 0xa9, 0xbb, 0xbe, 0xaa, 0x8d, - 0x8e, 0x1e, 0x3d, 0x08, 0x28, 0x0b, 0x77, 0xda, 0x5b, 0x46, 0x80, 0x20, - 0x69, 0xc3, 0x92, 0xde, 0x81, 0x84, 0x96, 0xec, 0xb1, 0x1b, 0xe1, 0x00, - 0x84, 0x1f, 0x3a, 0xb2, 0x38, 0x2d, 0x6b, 0x17, 0x6b, 0x20, 0xf3, 0x78, - 0x3c, 0x26, 0xe3, 0x7e, 0xad, 0x1c, 0x66, 0xd0, 0xd2, 0x5a, 0x9d, 0x60, - 0x59, 0xe6, 0x57, 0xa7, 0x44, 0xee, 0xca, 0xc8, 0xdd, 0x53, 0x6b, 0x85, - 0x67, 0x97, 0xc2, 0x5a, 0xa1, 0x77, 0xda, 0x9e, 0x42, 0x4f, 0x40, 0xaa, - 0x60, 0xaf, 0x5a, 0xb4, 0xc7, 0x6c, 0x3e, 0x89, 0x4b, 0xae, 0xa3, 0xe8, - 0xda, 0x23, 0xcc, 0x34, 0xa7, 0x73, 0x17, 0xd6, 0xe4, 0xd0, 0x6e, 0x30, - 0xca, 0x90, 0x11, 0x6b, 0x3c, 0x59, 0x9b, 0xcb, 0x7e, 0xb6, 0x6b, 0xfb, - 0xda, 0xdc, 0xcc, 0xcf, 0x67, 0x06, 0x2e, 0x75, 0xab, 0x4c, 0x57, 0xf2, - 0x38, 0x57, 0x20, 0x1a, 0xf7, 0xce, 0x83, 0x0f, 0x73, 0xc4, 0xc2, 0x06, - 0x81, 0x39, 0xb6, 0x30, 0xc8, 0x7a, 0x86, 0x6a, 0x87, 0x93, 0x13, 0x1d, - 0x00, 0x9c, 0x1a, 0xdb, 0xa3, 0xc4, 0xd2, 0xf1, 0xc3, 0x43, 0x4e, 0xf1, - 0x8b, 0x95, 0xb4, 0x9e, 0x99, 0x03, 0xa7, 0x6e, 0xc3, 0xc5, 0xb8, 0xb3, - 0xb7, 0x9e, 0x40, 0xcd, 0x20, 0x5c, 0x88, 0x07, 0xa2, 0x26, 0xd3, 0x38, - 0xe6, 0x46, 0x61, 0x48, 0xcb, 0xab, 0xb3, 0x58, 0x62, 0xd6, 0x5e, 0xd6, - 0x61, 0xae, 0x5e, 0x96, 0x3c, 0xeb, 0x24, 0xa7, 0xd9, 0x30, 0x76, 0x0e, - 0xb1, 0xbd, 0x66, 0x31, 0x97, 0x96, 0x87, 0x74, 0x2e, 0x11, 0x6c, 0x28, - 0x9c, 0x4d, 0x55, 0x29, 0xeb, 0x50, 0x5c, 0x08, 0x42, 0x18, 0x6d, 0xec, - 0x2c, 0x4d, 0x9a, 0x45, 0x27, 0x49, 0x5b, 0x13, 0x24, 0x62, 0x78, 0x01, - 0x02, 0x1b, 0xc6, 0x6d, 0xc3, 0xcd, 0x80, 0x5c, 0x7d, 0x62, 0xe4, 0x66, - 0xb6, 0x82, 0x74, 0xe7, 0x24, 0x5c, 0x2a, 0xf5, 0xb9, 0x90, 0x4e, 0x88, - 0xc0, 0x4b, 0xaa, 0xcf, 0x8e, 0x06, 0xcc, 0x88, 0x62, 0x21, 0xa6, 0x76, - 0x12, 0x5b, 0xc6, 0xda, 0xca, 0xf3, 0x34, 0xed, 0x17, 0xf8, 0x4a, 0x53, - 0x14, 0x98, 0x5b, 0xe9, 0x8b, 0x58, 0xc5, 0xa5, 0x7d, 0xdf, 0xeb, 0xc6, - 0x1e, 0xce, 0x06, 0xb1, 0x8f, 0x60, 0xa3, 0x61, 0x2b, 0x79, 0xcd, 0x87, - 0x6b, 0x4e, 0xcc, 0xaf, 0xcb, 0x3e, 0x41, 0x63, 0x1b, 0x76, 0xf3, 0xa1, - 0x2c, 0x62, 0x7b, 0xcf, 0x0e, 0x71, 0x24, 0x8a, 0x39, 0x2c, 0x21, 0x62, - 0xce, 0xc7, 0x4e, 0x8f, 0x9e, 0xb9, 0xa4, 0x6d, 0xe6, 0xde, 0x7c, 0xd5, - 0xb5, 0x42, 0xbf, 0x9e, 0x19, 0x54, 0x98, 0x91, 0x78, 0x42, 0x6e, 0xc4, - 0x03, 0xb3, 0x10, 0xea, 0x6b, 0xb6, 0xdb, 0x19, 0xb5, 0x7b, 0x8c, 0x7a, - 0x4b, 0x29, 0x82, 0x2a, 0x3e, 0xe1, 0xcc, 0xa2, 0x3a, 0xa8, 0x8d, 0x60, - 0xba, 0x8c, 0x38, 0x52, 0x33, 0x7f, 0xb8, 0xe2, 0x97, 0xf3, 0x21, 0xd8, - 0x0d, 0xca, 0x8e, 0x2b, 0xad, 0x2b, 0xd5, 0x52, 0x07, 0x86, 0x99, 0xcd, - 0xe6, 0x1a, 0x8c, 0xf4, 0x3d, 0x02, 0xd9, 0xfd, 0x45, 0x92, 0x51, 0x9f, - 0x4f, 0x89, 0xa2, 0x54, 0x4c, 0x3c, 0x85, 0x30, 0x6a, 0x96, 0xb6, 0x47, - 0x74, 0x6f, 0xc7, 0x2d, 0x46, 0x6f, 0x66, 0x1b, 0xd6, 0x53, 0x96, 0x75, - 0xaf, 0x9c, 0x81, 0x55, 0x71, 0xe3, 0x42, 0x0f, 0x61, 0x7f, 0x93, 0x14, - 0x51, 0x1f, 0x3b, 0xdd, 0x5e, 0x9f, 0xe5, 0xcc, 0x55, 0x3e, 0x34, 0xa5, - 0x3b, 0xce, 0x78, 0x46, 0x3b, 0xed, 0x76, 0x36, 0x8a, 0xda, 0x23, 0x31, - 0x6b, 0x5c, 0xc7, 0xd2, 0x96, 0xa5, 0xdb, 0x56, 0xbb, 0x03, 0xa4, 0xed, - 0x96, 0x12, 0x88, 0xf9, 0xa3, 0x66, 0x14, 0x56, 0xc9, 0x06, 0x09, 0xe3, - 0x5a, 0x0e, 0x0f, 0xfa, 0x89, 0x20, 0xc3, 0xf3, 0x91, 0x3b, 0x6c, 0xe6, - 0x96, 0x10, 0xb8, 0x88, 0x99, 0x67, 0x21, 0x1c, 0xe0, 0x4b, 0x57, 0xc0, - 0xd7, 0x74, 0x71, 0x5a, 0x90, 0x03, 0x54, 0xce, 0xac, 0xc0, 0xbd, 0x88, - 0x03, 0x56, 0x75, 0x81, 0x3e, 0xbf, 0x02, 0x5e, 0xfa, 0x14, 0xa3, 0x7b, - 0xfd, 0x8a, 0x80, 0xf2, 0x93, 0x75, 0x75, 0x97, 0x8c, 0x88, 0xc4, 0xa5, - 0x83, 0xb7, 0xa9, 0x63, 0x45, 0x5b, 0x0a, 0xdb, 0xce, 0x36, 0x46, 0xb0, - 0x91, 0x17, 0x0e, 0x0b, 0x39, 0x44, 0x7a, 0x18, 0x78, 0x68, 0xc0, 0xcd, - 0x8a, 0x4d, 0xb7, 0x2b, 0xcc, 0x07, 0x9e, 0xd0, 0x58, 0xaf, 0x77, 0xbd, - 0x24, 0x5a, 0x2b, 0x42, 0x34, 0x8e, 0xd7, 0x25, 0x70, 0x26, 0xe9, 0x65, - 0xee, 0x58, 0xc0, 0xdf, 0x29, 0x59, 0x8f, 0x84, 0xbc, 0xeb, 0x38, 0xae, - 0xb1, 0xc0, 0x61, 0xf5, 0xb4, 0xb2, 0x95, 0xbe, 0x58, 0xea, 0x7d, 0x82, - 0x47, 0x16, 0x61, 0x5d, 0xe3, 0xad, 0xba, 0x18, 0x2e, 0x33, 0x2e, 0x25, - 0xba, 0xda, 0x39, 0x1c, 0x71, 0x81, 0x43, 0xba, 0x56, 0xa2, 0x1c, 0xcf, - 0x6e, 0x77, 0xc1, 0x96, 0x30, 0x8f, 0xf2, 0x4a, 0x3f, 0x58, 0xf3, 0x63, - 0xe0, 0x1c, 0xad, 0x80, 0x92, 0x2d, 0xf2, 0xd0, 0xa4, 0xe9, 0x86, 0x86, - 0x37, 0xa7, 0x35, 0x91, 0x9d, 0x17, 0xca, 0x1e, 0x11, 0x5a, 0x54, 0x1e, - 0x20, 0xa3, 0x5a, 0x39, 0x67, 0xbd, 0x44, 0x13, 0xbd, 0x5c, 0x5b, 0xb5, - 0x83, 0xa6, 0xbb, 0xb9, 0x6f, 0x98, 0x5b, 0xd3, 0x45, 0xcf, 0x24, 0xa7, - 0x89, 0x98, 0x3d, 0x0c, 0xd4, 0x92, 0xd4, 0x9d, 0x05, 0xb7, 0x46, 0xd0, - 0xeb, 0x4a, 0xce, 0x4f, 0x35, 0x69, 0x2e, 0x54, 0x60, 0x8f, 0x91, 0x45, - 0xb3, 0x10, 0xf9, 0xe2, 0x80, 0xcd, 0xf0, 0x2b, 0x74, 0x40, 0x2d, 0x6c, - 0x50, 0xa9, 0x04, 0xf6, 0x55, 0x99, 0x46, 0x6c, 0x34, 0xbd, 0xb0, 0x17, - 0xa8, 0x27, 0x92, 0x59, 0x72, 0x66, 0xb3, 0x63, 0x96, 0x1c, 0x12, 0x9a, - 0x3f, 0xcf, 0x88, 0xc4, 0x08, 0x3c, 0x28, 0x2f, 0x96, 0xb4, 0x23, 0x05, - 0x26, 0xb3, 0xd9, 0x41, 0xcb, 0xae, 0x6a, 0xb5, 0x3d, 0x84, 0x1d, 0x78, - 0x63, 0xbf, 0x19, 0x0e, 0x76, 0xca, 0xab, 0xb5, 0x90, 0xf4, 0xc2, 0xac, - 0x6e, 0xf8, 0xa4, 0xc1, 0x20, 0x92, 0xf4, 0x64, 0x51, 0x0a, 0x3c, 0x99, - 0x08, 0x4c, 0xd1, 0x61, 0x06, 0x57, 0xe6, 0x1b, 0xeb, 0x52, 0x64, 0xe1, - 0x61, 0x06, 0xcc, 0x9c, 0x37, 0x6f, 0xfa, 0xf5, 0x16, 0x17, 0xba, 0x4e, - 0x9f, 0xb1, 0xbc, 0xa6, 0x43, 0x90, 0xc5, 0x15, 0x87, 0x0b, 0x4c, 0xe1, - 0x92, 0x42, 0x9e, 0x7b, 0x5f, 0xf6, 0xae, 0xd8, 0x12, 0xa6, 0x67, 0x47, - 0xa4, 0x06, 0x51, 0x7b, 0x31, 0x08, 0x74, 0xe1, 0x9d, 0xa9, 0x03, 0x77, - 0xa8, 0x66, 0xb6, 0xec, 0x9f, 0x4d, 0x0a, 0x37, 0x6d, 0xb9, 0x62, 0xd0, - 0xd2, 0x82, 0x0a, 0xb2, 0x0e, 0x2f, 0xc7, 0x34, 0xa0, 0x77, 0x5c, 0xbf, - 0x5c, 0x46, 0x5e, 0xe7, 0x44, 0x55, 0x99, 0x01, 0xcf, 0x90, 0x44, 0x4d, - 0xa7, 0x1d, 0xb7, 0xdb, 0x6e, 0x04, 0xbc, 0x6e, 0xa4, 0x05, 0xbd, 0x3d, - 0x75, 0x39, 0x35, 0xce, 0x79, 0x84, 0x41, 0xfd, 0xc3, 0x96, 0xb6, 0xcf, - 0x6c, 0x4e, 0x95, 0x1c, 0x7c, 0x20, 0x62, 0x91, 0x0c, 0x0e, 0x7d, 0x55, - 0x56, 0xc6, 0xba, 0xe8, 0x40, 0xe2, 0x90, 0x5c, 0x56, 0xd1, 0xe1, 0x3c, - 0xc3, 0x81, 0x58, 0xe0, 0x4e, 0x52, 0x1c, 0x43, 0xc4, 0x0c, 0xbc, 0xf4, - 0xc0, 0x15, 0xab, 0x35, 0xd7, 0x5e, 0x57, 0x11, 0x7e, 0x4a, 0x23, 0xa4, - 0x5e, 0x76, 0xd7, 0x05, 0x3d, 0xad, 0x36, 0x75, 0x0f, 0xe5, 0xd2, 0x05, - 0x39, 0x07, 0x9c, 0x38, 0x14, 0x89, 0xf7, 0xd4, 0x12, 0xde, 0xfb, 0xe1, - 0x5a, 0x2e, 0xd9, 0x2d, 0xe1, 0xcc, 0x99, 0xb9, 0x45, 0x5b, 0xb2, 0xc8, - 0x24, 0x52, 0x9e, 0x78, 0x30, 0x9c, 0xa9, 0xc6, 0x76, 0xaf, 0x8a, 0xe7, - 0x41, 0x6f, 0x19, 0x69, 0x65, 0x6b, 0xab, 0xe5, 0xaa, 0xa7, 0x1d, 0x10, - 0xe4, 0xd8, 0x8a, 0x8e, 0x50, 0xc6, 0x45, 0x36, 0x02, 0xa5, 0x8e, 0x7b, - 0x33, 0x63, 0x8c, 0x78, 0x73, 0x36, 0x72, 0xcd, 0x0b, 0x36, 0x80, 0xcd, - 0x08, 0x57, 0x53, 0xb2, 0xaf, 0x31, 0x82, 0x3e, 0xf0, 0x24, 0xef, 0x5d, - 0x57, 0x38, 0xc8, 0x66, 0x1b, 0x6d, 0x2c, 0xd6, 0x9b, 0xed, 0x85, 0x5e, - 0xe4, 0xca, 0x86, 0xa8, 0x99, 0x74, 0x57, 0xce, 0x88, 0x21, 0x5a, 0x14, - 0x55, 0x8d, 0x92, 0x5e, 0xe6, 0x38, 0x6b, 0x3b, 0xd8, 0x54, 0x24, 0x70, - 0xe4, 0xdb, 0x83, 0xc1, 0x28, 0xe4, 0x89, 0xcb, 0xf0, 0x2a, 0xa6, 0x49, - 0x53, 0x13, 0xe2, 0x75, 0x3d, 0x73, 0x07, 0x25, 0xc2, 0x0e, 0xed, 0x4c, - 0x55, 0x63, 0x3a, 0x85, 0x0f, 0x86, 0x44, 0xcd, 0x1d, 0x35, 0xdc, 0x02, - 0xe5, 0x0b, 0x10, 0x56, 0xb6, 0xe9, 0x16, 0xcb, 0x0c, 0x22, 0x0c, 0x92, - 0xd9, 0xcc, 0x8b, 0x77, 0xb4, 0xe6, 0x54, 0xbc, 0x08, 0xd7, 0x85, 0xb0, - 0x89, 0xfc, 0x1d, 0x21, 0xd7, 0x94, 0xc1, 0x6a, 0x2b, 0xc4, 0x19, 0xd7, - 0xc7, 0xde, 0x10, 0x17, 0xe9, 0x3c, 0x71, 0xaf, 0x88, 0x2d, 0x42, 0xca, - 0xac, 0xc8, 0xeb, 0x73, 0x12, 0x58, 0xb1, 0xaa, 0x2e, 0x0f, 0x5b, 0x7c, - 0xe1, 0xd9, 0x45, 0xee, 0x73, 0xbd, 0x3c, 0x3b, 0xc5, 0x97, 0x01, 0xa9, - 0x87, 0xf5, 0x59, 0x3e, 0xb1, 0x34, 0x3f, 0x28, 0x5a, 0xc9, 0xc2, 0x32, - 0x51, 0x9e, 0xe2, 0x6d, 0x4c, 0xd4, 0x8a, 0x46, 0xd1, 0x97, 0x30, 0x30, - 0x9d, 0x76, 0x8f, 0x5d, 0xb6, 0xba, 0x82, 0xed, 0xb1, 0x22, 0x87, 0xf7, - 0x42, 0x81, 0xe1, 0xed, 0x06, 0x8f, 0x66, 0xdd, 0x41, 0xd6, 0xfb, 0x8b, - 0x71, 0x18, 0xcf, 0xd1, 0xdc, 0xd8, 0x09, 0xc4, 0xb2, 0x46, 0x13, 0x51, - 0xed, 0xaf, 0x98, 0x78, 0xe6, 0x49, 0x28, 0x4c, 0x71, 0x92, 0xa8, 0x36, - 0xe6, 0x79, 0x35, 0x12, 0xbc, 0xda, 0x8f, 0x69, 0xd5, 0x99, 0x78, 0x05, - 0x91, 0x61, 0x5d, 0x71, 0xc3, 0x62, 0xd1, 0xaa, 0x67, 0xbb, 0xb6, 0xb4, - 0xae, 0x33, 0x17, 0x67, 0x9e, 0x59, 0xa7, 0x7b, 0x24, 0xcb, 0x36, 0x79, - 0xcf, 0x2c, 0xd6, 0x65, 0x30, 0xab, 0xe8, 0x2b, 0x86, 0xf8, 0x9b, 0x0e, - 0x58, 0x1d, 0x2d, 0xa1, 0xe2, 0x59, 0x5b, 0xa0, 0x21, 0x45, 0x43, 0x1b, - 0x90, 0x9c, 0xa8, 0xb9, 0x7e, 0xd0, 0xfa, 0x43, 0x80, 0xd1, 0x04, 0xba, - 0x61, 0xdb, 0x9d, 0x45, 0x16, 0x1b, 0x10, 0x8c, 0x2c, 0x8b, 0x8b, 0xb2, - 0x26, 0x67, 0x62, 0x7f, 0x5d, 0x28, 0xb6, 0x30, 0xc0, 0xfa, 0x4c, 0xf4, - 0xb9, 0x05, 0xd9, 0x2b, 0xba, 0x29, 0x5f, 0xd6, 0x42, 0xbe, 0x83, 0xa2, - 0x4e, 0xc0, 0x42, 0xb5, 0xd8, 0x22, 0x45, 0x6b, 0x7a, 0xd8, 0x85, 0xda, - 0x65, 0x0d, 0xc6, 0x59, 0x01, 0x5b, 0x1c, 0xf7, 0x03, 0xe4, 0x32, 0xe5, - 0xa9, 0xcd, 0x30, 0x7c, 0x3b, 0x40, 0xf6, 0x99, 0x68, 0xc2, 0x9d, 0xb9, - 0x65, 0x2e, 0xb1, 0x76, 0xa5, 0x33, 0x5a, 0x1c, 0x2b, 0x4c, 0x47, 0x94, - 0xd6, 0xc9, 0x96, 0x87, 0xe8, 0xba, 0x08, 0xbd, 0xf1, 0xea, 0xf3, 0x56, - 0x89, 0x8c, 0x31, 0xa1, 0xd9, 0x4a, 0x0c, 0xe5, 0x9b, 0x9e, 0x28, 0x62, - 0x60, 0x2c, 0x2e, 0xf0, 0x79, 0x53, 0x8e, 0xe7, 0x79, 0x62, 0xc7, 0x78, - 0xcb, 0xf6, 0xfa, 0xcc, 0x57, 0x14, 0x7c, 0x5c, 0x8d, 0xb8, 0x64, 0xc7, - 0x30, 0x7e, 0xf4, 0x17, 0x22, 0xc8, 0xbd, 0x77, 0x61, 0x92, 0xea, 0xb1, - 0x46, 0x7a, 0xca, 0x62, 0x47, 0x69, 0x4d, 0xcb, 0x44, 0x9c, 0x31, 0x5b, - 0xcf, 0x71, 0x25, 0x54, 0x39, 0x2b, 0xdb, 0x74, 0x83, 0x56, 0x1d, 0x88, - 0x59, 0xa2, 0x68, 0xf3, 0xa0, 0xc3, 0x89, 0xf3, 0x02, 0x23, 0x27, 0x3e, - 0x2e, 0x9d, 0x79, 0x74, 0x0d, 0xb2, 0x4a, 0xd2, 0xb7, 0xe5, 0x8a, 0xb7, - 0xba, 0x4d, 0xcb, 0x5e, 0x57, 0xbb, 0x66, 0x4f, 0x3a, 0x69, 0x36, 0xae, - 0xb3, 0x84, 0xc9, 0xac, 0xed, 0xa5, 0x16, 0xb7, 0xeb, 0xf9, 0x96, 0x62, - 0x78, 0xef, 0xa0, 0x31, 0xc7, 0xc3, 0x4e, 0x88, 0xce, 0xdb, 0x1d, 0x80, - 0xec, 0xf7, 0x92, 0xdd, 0xcc, 0x81, 0xcb, 0x47, 0x12, 0xb9, 0x14, 0x5a, - 0x02, 0xb6, 0x11, 0x36, 0xd8, 0x88, 0xbb, 0x1c, 0x27, 0xba, 0xc3, 0x46, - 0x38, 0xce, 0x23, 0x5c, 0x50, 0x75, 0x12, 0x65, 0x97, 0x50, 0xbe, 0x1e, - 0xb8, 0x8b, 0xe2, 0xa8, 0x57, 0x11, 0x34, 0x6d, 0xe3, 0xb0, 0x99, 0xf7, - 0x2d, 0xba, 0x66, 0xa1, 0xc3, 0x89, 0x49, 0x02, 0x4f, 0x84, 0x61, 0x2f, - 0x30, 0x91, 0xad, 0xcc, 0x54, 0xbc, 0x60, 0x1f, 0x9d, 0xb5, 0xcb, 0xd1, - 0x57, 0x2b, 0xde, 0x93, 0xe5, 0x61, 0xef, 0xe8, 0x36, 0xe6, 0x58, 0xb3, - 0x6d, 0x04, 0x02, 0x3e, 0xfc, 0xd0, 0x5e, 0xe6, 0xed, 0xe9, 0x98, 0x66, - 0x4b, 0xda, 0x3b, 0x99, 0x34, 0x59, 0x3b, 0x3d, 0x1d, 0x6c, 0xf6, 0x3c, - 0x8f, 0x55, 0x22, 0xda, 0xef, 0x36, 0xd7, 0x53, 0xd9, 0xcc, 0x04, 0x06, - 0x56, 0xb6, 0xb4, 0x46, 0x49, 0x9b, 0x65, 0xac, 0xcc, 0xed, 0x81, 0xc0, - 0x09, 0x71, 0x10, 0x4c, 0x46, 0x62, 0x9c, 0x4b, 0xec, 0xc7, 0xa5, 0x4c, - 0x0e, 0xec, 0xbe, 0x3b, 0x4a, 0x02, 0xa6, 0x5d, 0xbb, 0x64, 0x2d, 0x58, - 0x7d, 0xeb, 0xc8, 0xbd, 0xc1, 0xcb, 0x87, 0x73, 0x7e, 0x8e, 0x33, 0xd4, - 0x3e, 0xb2, 0x21, 0x08, 0x82, 0x15, 0x68, 0x0a, 0xfa, 0xc6, 0x4d, 0x2f, - 0xf3, 0xb3, 0x83, 0x7f, 0x3d, 0x86, 0x62, 0x8e, 0x68, 0xec, 0x25, 0x95, - 0xcf, 0x03, 0x9e, 0x0e, 0x63, 0x64, 0x9c, 0xe2, 0x5d, 0x85, 0x0e, 0x99, - 0x86, 0xea, 0x97, 0xb3, 0x6d, 0xd6, 0x57, 0x2d, 0x3f, 0x0a, 0xba, 0x72, - 0x29, 0xb3, 0x0d, 0x64, 0x67, 0xda, 0xb5, 0x70, 0x76, 0xd7, 0xb9, 0xc5, - 0xc8, 0x90, 0x47, 0xd9, 0xd6, 0x72, 0x79, 0xde, 0x60, 0x14, 0x7d, 0xb6, - 0x3c, 0xa7, 0xd0, 0x98, 0x6c, 0x1f, 0xb4, 0x83, 0xa0, 0x1c, 0xca, 0xd1, - 0xdd, 0x67, 0xd6, 0x18, 0x6c, 0x41, 0x10, 0xb8, 0xd2, 0x75, 0x41, 0x96, - 0x67, 0x20, 0x57, 0xa6, 0x4f, 0xda, 0x51, 0x04, 0x29, 0x8f, 0xcb, 0xad, - 0x42, 0x83, 0xa2, 0x2e, 0x5c, 0xbe, 0xc9, 0x04, 0x04, 0xf1, 0x92, 0x63, - 0x85, 0xa5, 0xe5, 0x25, 0xe9, 0x2d, 0x47, 0x3d, 0x0a, 0x97, 0x39, 0x88, - 0xc6, 0xf7, 0xf6, 0xac, 0x38, 0x5b, 0xf1, 0xf5, 0x4a, 0x50, 0x3e, 0xaa, - 0x01, 0x03, 0x02, 0x65, 0xb5, 0x00, 0x52, 0xc6, 0x44, 0x64, 0x23, 0xf5, - 0x88, 0xd2, 0x87, 0x28, 0xe8, 0xe6, 0x72, 0xba, 0xea, 0xfa, 0x99, 0x55, - 0x6f, 0x83, 0x92, 0x4e, 0x91, 0x53, 0xb7, 0xd8, 0x14, 0xd1, 0x56, 0xf7, - 0x82, 0x40, 0x3f, 0xaa, 0xf1, 0x5c, 0xda, 0xcc, 0xc3, 0xa1, 0x8f, 0x57, - 0xe7, 0xd0, 0xde, 0xc6, 0xd2, 0xd9, 0xef, 0x72, 0xdc, 0x15, 0xd5, 0x50, - 0x2a, 0xdc, 0xc2, 0x60, 0x9c, 0x93, 0x55, 0x84, 0xe3, 0xea, 0x34, 0x9d, - 0xe0, 0xe8, 0x54, 0xc4, 0xb9, 0x3d, 0x6a, 0x24, 0xa2, 0xc8, 0x47, 0xfe, - 0xe0, 0xf7, 0xd7, 0xce, 0xa0, 0x43, 0xdb, 0xaf, 0x1b, 0x8e, 0xeb, 0x2b, - 0xa7, 0xa8, 0xbb, 0xf3, 0xde, 0xea, 0xae, 0x7a, 0x44, 0x30, 0xeb, 0xe8, - 0xb0, 0x06, 0xb4, 0x15, 0xc2, 0x80, 0x9e, 0xe6, 0x66, 0x28, 0x6e, 0x59, - 0x93, 0x88, 0x4b, 0xdb, 0x7c, 0xdb, 0xc1, 0x9e, 0xb0, 0xe7, 0xfb, 0x15, - 0x4d, 0x62, 0x65, 0x51, 0x9f, 0x2e, 0x20, 0x53, 0xc2, 0xc2, 0x82, 0x46, - 0x18, 0xa3, 0x9a, 0x05, 0xe8, 0x81, 0x95, 0x7b, 0x9d, 0x03, 0xfa, 0x89, - 0xb5, 0xc0, 0x58, 0x5c, 0xbc, 0x65, 0x26, 0xd2, 0x22, 0xc1, 0x2a, 0x3b, - 0x5a, 0x9f, 0x67, 0xde, 0xae, 0x3a, 0x0a, 0x4b, 0x4f, 0x07, 0x21, 0x69, - 0xb6, 0x14, 0x8c, 0x92, 0xa5, 0xe6, 0x20, 0xfa, 0xc6, 0xb8, 0x58, 0xc2, - 0x0f, 0xcb, 0xf3, 0x62, 0x4d, 0x75, 0xf3, 0xe6, 0xba, 0xb7, 0x34, 0x8d, - 0x1e, 0x36, 0x55, 0x40, 0x29, 0xca, 0x4a, 0xe2, 0x29, 0x86, 0x4b, 0x75, - 0x18, 0x9a, 0xb9, 0x11, 0x95, 0x2a, 0x4a, 0x48, 0x1a, 0x3b, 0x60, 0xb2, - 0x5a, 0x45, 0x12, 0x32, 0x20, 0x79, 0x09, 0xdc, 0xd6, 0xfd, 0x15, 0x59, - 0x76, 0xf9, 0x4a, 0x38, 0x64, 0x67, 0xc7, 0x03, 0xa6, 0x00, 0x4e, 0xb5, - 0xf5, 0x06, 0x78, 0xa5, 0xd5, 0x4e, 0x0f, 0x96, 0x79, 0xaf, 0xa2, 0x05, - 0xd7, 0x01, 0x03, 0x2f, 0x22, 0xa3, 0x11, 0x04, 0xc3, 0x75, 0xc5, 0x8d, - 0xcb, 0x48, 0xcd, 0x17, 0x50, 0xc2, 0x2f, 0xbd, 0x4d, 0x8a, 0x0d, 0x21, - 0xac, 0x18, 0xab, 0xe6, 0x48, 0x63, 0xd0, 0x40, 0x5d, 0x11, 0x8e, 0x91, - 0xe3, 0x95, 0xb1, 0x61, 0xb9, 0xf0, 0x1c, 0x11, 0x4b, 0xcd, 0xda, 0x89, - 0x8b, 0x21, 0xb6, 0xdc, 0x03, 0x4e, 0x2f, 0xa9, 0x15, 0x7d, 0xe2, 0xb7, - 0xd8, 0x92, 0x56, 0xe9, 0x63, 0x09, 0x71, 0x14, 0x85, 0x3b, 0x74, 0x62, - 0x6a, 0xa6, 0x17, 0xc4, 0xbe, 0x22, 0xeb, 0xf2, 0xb1, 0xf2, 0xb5, 0x9e, - 0x86, 0x93, 0xcc, 0xdc, 0xa6, 0x62, 0x9b, 0x8d, 0x44, 0x37, 0x5c, 0x22, - 0xff, 0xdc, 0x6c, 0x02, 0x4d, 0x96, 0x52, 0x32, 0xcd, 0x4c, 0x21, 0xd2, - 0xb6, 0x55, 0xbd, 0xec, 0x07, 0x7b, 0xef, 0xab, 0x96, 0x5f, 0x56, 0xc7, - 0xb5, 0x62, 0x6e, 0x36, 0xa2, 0xca, 0xed, 0x4d, 0x3a, 0x5b, 0xe5, 0x40, - 0x57, 0x9c, 0x04, 0xad, 0x8b, 0xde, 0xab, 0x58, 0x8a, 0x1f, 0xe6, 0x5b, - 0x23, 0x5d, 0x4d, 0x57, 0x07, 0x6a, 0xc4, 0x9a, 0xb2, 0x58, 0xd6, 0x60, - 0x0f, 0x75, 0xc2, 0xed, 0x63, 0x49, 0xae, 0xb3, 0x03, 0xd3, 0x90, 0x16, - 0x8b, 0x70, 0x26, 0xc1, 0xc8, 0xdc, 0x76, 0x1f, 0x4a, 0xf2, 0x9c, 0xe7, - 0x8e, 0x83, 0x3f, 0xb7, 0xb7, 0x58, 0xd5, 0x16, 0x19, 0xba, 0x0d, 0x7a, - 0xff, 0x8a, 0xd3, 0x1e, 0xcb, 0x9e, 0xb2, 0x2d, 0x3f, 0x33, 0x37, 0x3c, - 0x30, 0x5d, 0x92, 0x93, 0x5d, 0xec, 0x71, 0x84, 0x70, 0x4a, 0xae, 0x52, - 0x1a, 0x81, 0x47, 0x53, 0xd8, 0x52, 0x09, 0x08, 0xb2, 0x36, 0x90, 0x5f, - 0x1d, 0x63, 0x7c, 0x33, 0xaf, 0x54, 0x6b, 0xdd, 0x4e, 0xa3, 0x78, 0xc7, - 0x73, 0xbb, 0x17, 0x4d, 0x1c, 0x39, 0x6f, 0x02, 0x27, 0x44, 0xc5, 0x10, - 0x5e, 0x66, 0xd2, 0x92, 0x5a, 0x8f, 0x9b, 0x15, 0x24, 0x83, 0x70, 0x3c, - 0x19, 0xd2, 0xb9, 0x7b, 0xf4, 0x7d, 0x6d, 0x48, 0x02, 0x72, 0x24, 0x70, - 0x90, 0x88, 0xc9, 0x3b, 0x29, 0x44, 0x37, 0xf2, 0xbe, 0xf4, 0xae, 0xcd, - 0x12, 0xc5, 0x44, 0x94, 0x4a, 0xb5, 0x11, 0x98, 0xa9, 0xcb, 0x86, 0x9f, - 0x13, 0x57, 0x01, 0xc1, 0xd4, 0xe5, 0xd2, 0x5b, 0xe9, 0xab, 0xfa, 0x4a, - 0x71, 0xdb, 0x0d, 0x34, 0x2f, 0x1a, 0x59, 0xbf, 0xf4, 0xf8, 0x28, 0x8c, - 0x7a, 0x21, 0x8d, 0x95, 0xbf, 0x95, 0xf2, 0xa3, 0xcb, 0xc2, 0xd7, 0x03, - 0x50, 0xd8, 0x26, 0x49, 0x8c, 0x4c, 0x62, 0x4c, 0xd8, 0x5e, 0x22, 0xb3, - 0x15, 0x63, 0x11, 0xae, 0x98, 0x1f, 0x3b, 0x2c, 0x2c, 0x4f, 0x3e, 0xb2, - 0x5f, 0xa3, 0xe9, 0xf6, 0xc0, 0xe1, 0xa4, 0x21, 0xf0, 0x5c, 0xc8, 0xd3, - 0x9b, 0x5a, 0x22, 0x14, 0xa3, 0x39, 0x84, 0x99, 0x0d, 0x69, 0x1b, 0xd9, - 0xde, 0xbb, 0x11, 0x74, 0x54, 0x58, 0xda, 0x9f, 0x11, 0x3b, 0xbd, 0x76, - 0xae, 0xd2, 0xfc, 0xa2, 0xa1, 0xcc, 0x69, 0x9f, 0xb6, 0xde, 0xa6, 0xe4, - 0x72, 0x11, 0x6a, 0x42, 0xd6, 0x2b, 0x7b, 0x88, 0x74, 0xfd, 0xd3, 0x4c, - 0xd1, 0x24, 0x27, 0xa7, 0x4f, 0x59, 0xde, 0x52, 0x1b, 0xc8, 0x31, 0x36, - 0x06, 0xaa, 0xd2, 0xb3, 0xbe, 0xb4, 0xfc, 0xb4, 0xd7, 0x28, 0xd6, 0x84, - 0xe7, 0xc7, 0x4c, 0x43, 0xfc, 0x12, 0x3a, 0xc8, 0x51, 0x58, 0xb6, 0x96, - 0xbc, 0xa7, 0xe0, 0x05, 0xa7, 0x5a, 0x66, 0x85, 0x6f, 0xb9, 0x5d, 0x77, - 0xbd, 0x2e, 0x9b, 0xf9, 0x40, 0x99, 0x18, 0xdd, 0x25, 0x20, 0xd8, 0xe9, - 0xe5, 0x71, 0x3d, 0x3f, 0xaf, 0xbc, 0xcc, 0x97, 0xad, 0x02, 0x24, 0x1b, - 0x78, 0x28, 0xf3, 0x70, 0x3d, 0x53, 0xb9, 0x3a, 0x37, 0xcb, 0x43, 0x37, - 0xd7, 0x1c, 0x4a, 0x9c, 0x57, 0xf3, 0x45, 0xc7, 0x65, 0x94, 0xe9, 0xad, - 0x91, 0xe3, 0xbe, 0x51, 0x58, 0x68, 0x95, 0xdb, 0x0d, 0xc4, 0xd5, 0xc9, - 0x72, 0x6c, 0x4f, 0x9d, 0xbc, 0x14, 0x74, 0x53, 0x9c, 0xcf, 0x72, 0x75, - 0xb5, 0x5e, 0x68, 0xab, 0xd9, 0xc2, 0x5c, 0xca, 0xf3, 0x02, 0xde, 0xeb, - 0x89, 0x09, 0x31, 0xc7, 0x68, 0x20, 0x27, 0x3f, 0xd5, 0xe0, 0x64, 0x1e, - 0x35, 0xf2, 0x48, 0x17, 0xa6, 0x05, 0xbc, 0x24, 0x69, 0x70, 0xb4, 0x52, - 0x8e, 0xa1, 0xa5, 0x26, 0xbc, 0x39, 0xac, 0x81, 0x4d, 0xab, 0x85, 0x0a, - 0x29, 0x49, 0xbe, 0xbf, 0x9c, 0x69, 0x62, 0xc4, 0xed, 0x4e, 0x3a, 0x04, - 0x3c, 0x45, 0x9a, 0xf0, 0x32, 0x02, 0x51, 0xad, 0xb6, 0xd8, 0x0b, 0x16, - 0xd9, 0x35, 0xf0, 0xee, 0x98, 0x2d, 0x47, 0xc6, 0x6c, 0x07, 0x74, 0x9f, - 0xce, 0xe7, 0x19, 0xdd, 0xa5, 0x57, 0xc9, 0x37, 0x6c, 0x67, 0xbc, 0x5a, - 0xcd, 0x6e, 0x85, 0xe2, 0x87, 0x15, 0x52, 0xb6, 0x99, 0x43, 0x31, 0xaa, - 0x34, 0x36, 0x78, 0xb9, 0xa0, 0x37, 0xe5, 0xc6, 0x9e, 0xd7, 0x81, 0xe0, - 0x49, 0x3b, 0x4e, 0xf2, 0xd4, 0x55, 0x7c, 0x08, 0x45, 0x75, 0x63, 0x6e, - 0x56, 0xdb, 0xb2, 0x80, 0xb5, 0x11, 0xd8, 0x80, 0x60, 0xbd, 0x55, 0x6d, - 0x0c, 0xbd, 0x42, 0xe3, 0x66, 0x4b, 0xea, 0x9e, 0x1c, 0x5e, 0x36, 0x62, - 0xe4, 0xc3, 0x4c, 0x78, 0x2a, 0xf3, 0xad, 0xdd, 0x57, 0xfa, 0x75, 0xcc, - 0x78, 0x6f, 0xd7, 0x2e, 0x13, 0x36, 0xe9, 0xae, 0x2d, 0x93, 0xa3, 0x30, - 0x46, 0xd5, 0x17, 0xe6, 0x20, 0x57, 0xeb, 0x75, 0x3b, 0xef, 0x14, 0xa0, - 0x2d, 0x75, 0x93, 0x07, 0xcc, 0x19, 0xf3, 0xed, 0xec, 0x9c, 0xf6, 0x27, - 0xec, 0xe0, 0x27, 0x94, 0x56, 0xc2, 0x52, 0x3e, 0x87, 0xbb, 0x56, 0x1c, - 0xb6, 0xf0, 0x71, 0x69, 0xb1, 0xd9, 0x94, 0xd0, 0x23, 0xf4, 0x8a, 0xde, - 0x8f, 0x98, 0x6f, 0x06, 0xae, 0x3d, 0xac, 0xae, 0x14, 0xb9, 0x9a, 0x37, - 0x3c, 0xde, 0x07, 0x75, 0x4d, 0x1d, 0x77, 0x0b, 0xca, 0x6d, 0x4a, 0xba, - 0xf7, 0x4e, 0xea, 0x6e, 0x1d, 0x7a, 0x92, 0x29, 0x29, 0x5b, 0xc4, 0x17, - 0xa4, 0x54, 0x3d, 0xaf, 0x8e, 0xd9, 0x82, 0x38, 0x9e, 0x2e, 0x9c, 0x78, - 0xb0, 0xed, 0x93, 0xb1, 0xea, 0x78, 0x8e, 0x28, 0xfa, 0xeb, 0xb0, 0xd1, - 0x7c, 0xe1, 0x34, 0x9a, 0xf1, 0x18, 0xa4, 0x49, 0xc0, 0x64, 0xad, 0x94, - 0xcb, 0x1d, 0x26, 0x2c, 0xd0, 0x3c, 0xc6, 0x41, 0x6c, 0x54, 0x0a, 0x34, - 0x3c, 0x68, 0x11, 0xc4, 0x9d, 0x25, 0xfa, 0xac, 0x62, 0x26, 0xb4, 0xc0, - 0x21, 0x2f, 0x81, 0x72, 0xc2, 0x33, 0xad, 0x19, 0x3f, 0xa3, 0xd5, 0x60, - 0x43, 0xcf, 0xf8, 0xd3, 0x99, 0xa1, 0x66, 0x52, 0xc1, 0x20, 0xd5, 0xae, - 0xdb, 0x72, 0x24, 0xbd, 0x19, 0x70, 0x69, 0x63, 0xf8, 0x70, 0x43, 0x43, - 0x8b, 0xe0, 0x84, 0xc0, 0xc7, 0xd9, 0x8c, 0x4f, 0xf1, 0xa1, 0x32, 0x2e, - 0xfc, 0x29, 0xc5, 0xe9, 0x20, 0x38, 0x9b, 0x19, 0xc4, 0xd4, 0x83, 0x7a, - 0x3d, 0x3a, 0x96, 0xc0, 0x1f, 0xd9, 0xae, 0xed, 0x48, 0x08, 0x73, 0x86, - 0xa3, 0xa3, 0x03, 0x87, 0xb0, 0x5f, 0xae, 0xbb, 0x18, 0x6e, 0x0b, 0x11, - 0x1b, 0x93, 0x1e, 0xf6, 0xd7, 0xfa, 0x79, 0x30, 0xa3, 0x4b, 0x6b, 0x46, - 0x51, 0xd5, 0x17, 0x3b, 0x4b, 0x1d, 0xf1, 0x3d, 0xcb, 0xd7, 0x08, 0x7f, - 0xa8, 0xd7, 0xc8, 0x7a, 0x87, 0x21, 0x7b, 0x8f, 0xae, 0x87, 0x00, 0x89, - 0x29, 0xac, 0x9a, 0xad, 0x36, 0x55, 0x2e, 0x48, 0x7a, 0xb1, 0x1c, 0xc7, - 0x0b, 0x72, 0xe0, 0xfa, 0xd5, 0xb9, 0xa2, 0x7d, 0x33, 0xec, 0x6b, 0xae, - 0x33, 0xe3, 0x7a, 0xb3, 0xc6, 0x10, 0x83, 0x98, 0x55, 0xf3, 0xe5, 0x70, - 0xdc, 0x1f, 0x97, 0x70, 0x02, 0xe2, 0xc5, 0xf1, 0x50, 0x1e, 0x60, 0xcd, - 0xb7, 0x0b, 0xa1, 0x25, 0x9b, 0xa3, 0x7f, 0xba, 0xba, 0x3b, 0x3d, 0x0a, - 0x24, 0x9e, 0xf5, 0xd7, 0xe8, 0x69, 0x27, 0x5d, 0x28, 0x6b, 0x74, 0xb7, - 0xf5, 0xb5, 0x61, 0xd4, 0xb9, 0xb2, 0x9a, 0xaf, 0x50, 0x6c, 0x0c, 0xbb, - 0x2b, 0xc1, 0x5c, 0x8f, 0x84, 0x80, 0x49, 0x50, 0xdb, 0x16, 0x94, 0x90, - 0x89, 0x43, 0xd6, 0x87, 0x0c, 0x95, 0x1d, 0xcd, 0x45, 0xb5, 0xe8, 0x3b, - 0xeb, 0xcc, 0x27, 0x49, 0x0a, 0xed, 0xa5, 0x71, 0xa8, 0xf4, 0xb5, 0x14, - 0xaa, 0xd4, 0xac, 0xe9, 0x0e, 0x47, 0x06, 0x1b, 0x4d, 0x79, 0x08, 0x98, - 0xc0, 0xb8, 0x74, 0xd2, 0x45, 0xd3, 0x3a, 0x2f, 0x47, 0x1c, 0xb4, 0xc0, - 0xcd, 0x55, 0x52, 0xf9, 0xea, 0x16, 0xdb, 0x1f, 0x4c, 0x46, 0x3d, 0x09, - 0x33, 0x7b, 0xb9, 0xde, 0x36, 0x7b, 0xc4, 0x03, 0x3a, 0x04, 0xc1, 0xf5, - 0x7c, 0x53, 0xcf, 0x18, 0xda, 0x85, 0x56, 0x08, 0xa5, 0x18, 0xc1, 0xfe, - 0x3c, 0x47, 0x54, 0x6f, 0xbf, 0xb2, 0x8c, 0x85, 0xde, 0x06, 0x7e, 0x07, - 0x5b, 0x03, 0x84, 0x88, 0xbc, 0x8b, 0x6c, 0x0d, 0x14, 0xc4, 0x7f, 0xf2, - 0x86, 0xdb, 0x2f, 0x96, 0x97, 0x23, 0x8c, 0x6e, 0xfb, 0xcd, 0x6a, 0x86, - 0x10, 0xee, 0xb9, 0xe7, 0x4b, 0x9e, 0xd5, 0xf8, 0x8b, 0x92, 0xc4, 0xe2, - 0x55, 0xdd, 0x53, 0x64, 0xce, 0x21, 0xac, 0x83, 0xb0, 0x26, 0x50, 0xb5, - 0xb0, 0xf7, 0x0a, 0x60, 0x59, 0xf6, 0x5e, 0xa5, 0xa7, 0xe1, 0xee, 0x24, - 0x80, 0x60, 0x40, 0x86, 0xb1, 0xeb, 0x09, 0x45, 0x3c, 0x27, 0xba, 0x5e, - 0xc7, 0x18, 0x24, 0x48, 0xcb, 0xdd, 0x76, 0x0c, 0x77, 0xb4, 0x20, 0x22, - 0x28, 0x5e, 0x78, 0xdb, 0x61, 0x46, 0xb1, 0x38, 0xe1, 0x58, 0x32, 0x32, - 0xa2, 0x5b, 0x61, 0x73, 0xca, 0xd7, 0xbd, 0x9c, 0x07, 0xcb, 0x2c, 0x70, - 0x76, 0xa8, 0x94, 0xe9, 0xc1, 0x96, 0x1e, 0x97, 0xf3, 0x71, 0x27, 0x1e, - 0xdc, 0x08, 0x5f, 0xed, 0x4e, 0x5d, 0x4a, 0x6d, 0xb9, 0x55, 0xd1, 0x41, - 0x34, 0xb4, 0x72, 0xa2, 0x43, 0x6b, 0x90, 0xbd, 0x0d, 0x29, 0x73, 0x83, - 0x2e, 0x0e, 0xf3, 0x75, 0xcd, 0x48, 0xc9, 0x4c, 0x9e, 0xc9, 0x2d, 0x50, - 0x67, 0x4c, 0x3e, 0x71, 0xec, 0x92, 0xdd, 0x60, 0x8c, 0x23, 0xb1, 0x0a, - 0x1f, 0x40, 0x74, 0x40, 0x31, 0x20, 0x6e, 0x31, 0x2a, 0x85, 0x0d, 0x17, - 0xca, 0x52, 0x6e, 0x0a, 0xf1, 0xc8, 0xf5, 0x46, 0x04, 0xb2, 0x1e, 0x6e, - 0x65, 0x26, 0xa5, 0xda, 0x7a, 0xe3, 0xb4, 0xae, 0x6e, 0x3e, 0xe7, 0x17, - 0x71, 0x11, 0x3a, 0xea, 0x30, 0x6b, 0xe8, 0x2d, 0xe4, 0xa1, 0x1d, 0x0c, - 0x9f, 0xd6, 0x73, 0x5e, 0x5d, 0xa2, 0x67, 0x65, 0xef, 0x1b, 0x0a, 0xa2, - 0x6c, 0x25, 0x7c, 0x3f, 0xd2, 0xf0, 0x12, 0x3b, 0x0f, 0xf4, 0x0a, 0x87, - 0x66, 0xce, 0xa8, 0x86, 0xe7, 0xc1, 0xb8, 0x48, 0x16, 0x72, 0xc0, 0x93, - 0xb5, 0x15, 0x47, 0x0a, 0xab, 0x50, 0x87, 0x93, 0x3b, 0x04, 0xe1, 0x32, - 0x3a, 0x67, 0xa4, 0x1e, 0x29, 0x52, 0xbb, 0xe3, 0xc6, 0xd5, 0x92, 0x1e, - 0x51, 0x08, 0xc1, 0x47, 0xeb, 0x90, 0x00, 0xd7, 0xbb, 0x86, 0xb6, 0x35, - 0xb2, 0x66, 0x19, 0x96, 0xe7, 0x1c, 0xe5, 0x68, 0x9d, 0x62, 0xbd, 0x1e, - 0xce, 0xfd, 0xca, 0xd9, 0x53, 0x2d, 0xcc, 0xeb, 0x1a, 0x46, 0x92, 0xd0, - 0x91, 0xae, 0x7b, 0xde, 0xb2, 0xc8, 0xb0, 0x80, 0x9b, 0x0d, 0x15, 0xee, - 0x15, 0x88, 0x91, 0xcf, 0xb0, 0xe1, 0x6f, 0x96, 0x42, 0xb1, 0xce, 0xf0, - 0xb9, 0xb1, 0x20, 0x76, 0x31, 0x3a, 0xee, 0xe3, 0x83, 0x4f, 0x0c, 0xc3, - 0xdc, 0xc1, 0x08, 0xaf, 0x36, 0x2c, 0xd9, 0xad, 0x38, 0x3c, 0x0e, 0x82, - 0xf5, 0xb8, 0xc4, 0xdb, 0x1d, 0x21, 0xa1, 0x3b, 0x88, 0x5a, 0x08, 0x20, - 0x9f, 0xd1, 0xb3, 0x15, 0xed, 0x14, 0x82, 0x28, 0x01, 0x8b, 0xb1, 0x74, - 0x96, 0xe3, 0xf5, 0x74, 0xee, 0x11, 0xab, 0xe5, 0xd6, 0x44, 0x8d, 0xaf, - 0xd7, 0xeb, 0x63, 0x27, 0x01, 0x22, 0x5f, 0xeb, 0xe4, 0xe8, 0x11, 0x72, - 0x21, 0xb3, 0x6a, 0xe8, 0x8e, 0xd1, 0xbc, 0xce, 0x0f, 0x32, 0x2a, 0x0c, - 0x9b, 0xde, 0xcb, 0x96, 0x83, 0xbe, 0x39, 0xed, 0xa3, 0x42, 0x3b, 0x6f, - 0x1b, 0x71, 0xcd, 0x2a, 0xd6, 0x22, 0x2f, 0xac, 0xc1, 0x5a, 0x1b, 0xa5, - 0x66, 0x74, 0x5c, 0xea, 0x4a, 0xeb, 0x61, 0xed, 0x2c, 0x88, 0xc2, 0x10, - 0x8e, 0x83, 0x82, 0x6f, 0xc9, 0x25, 0xe2, 0x32, 0x5b, 0x28, 0x80, 0x10, - 0xb3, 0xcf, 0x9c, 0x24, 0xec, 0x45, 0x60, 0x82, 0x67, 0xb3, 0x65, 0xe8, - 0x9b, 0x17, 0xb8, 0x8d, 0xd2, 0x4b, 0x94, 0xa3, 0xfc, 0xb2, 0x3e, 0x2f, - 0xae, 0x57, 0xbc, 0x4c, 0x43, 0x69, 0x51, 0x0b, 0x9b, 0xca, 0x8c, 0x67, - 0xf3, 0x2c, 0x97, 0xa0, 0x23, 0x13, 0x4a, 0x83, 0x0b, 0x07, 0xa5, 0x13, - 0x1e, 0x56, 0x85, 0x5d, 0xd7, 0xe8, 0x96, 0x69, 0x28, 0x4d, 0xe2, 0x76, - 0x08, 0x3b, 0x13, 0x7c, 0xf4, 0x8c, 0xed, 0x72, 0x51, 0x64, 0x45, 0x26, - 0x24, 0xea, 0xab, 0xc2, 0xc0, 0x25, 0xe5, 0x8b, 0x80, 0xdf, 0x88, 0x6d, - 0xf3, 0x88, 0x7e, 0x36, 0x3a, 0xe8, 0xe4, 0x5c, 0xa8, 0xbd, 0x1d, 0x86, - 0xa5, 0x97, 0x6e, 0xc7, 0x0a, 0x04, 0xa2, 0xae, 0x19, 0x5e, 0xb5, 0x91, - 0xac, 0x2c, 0x05, 0x0b, 0xf6, 0xa8, 0x5c, 0xd4, 0x75, 0xe3, 0x0a, 0x32, - 0x6d, 0xaf, 0x16, 0x26, 0xbd, 0xad, 0xb9, 0x8b, 0x3c, 0xf4, 0x44, 0x5e, - 0x88, 0x08, 0xb0, 0xb3, 0x95, 0x44, 0xa2, 0x58, 0x27, 0xac, 0x00, 0x43, - 0x87, 0x00, 0xd8, 0x9b, 0xfd, 0x80, 0x6e, 0x4f, 0x12, 0xb7, 0x1f, 0x48, - 0x14, 0x04, 0xcc, 0xd1, 0x59, 0xdb, 0x01, 0xf9, 0x8d, 0x76, 0xba, 0x53, - 0xac, 0x1a, 0x67, 0x57, 0x5c, 0xd9, 0x8d, 0xd2, 0x9f, 0xc4, 0xa2, 0xa3, - 0xd8, 0x91, 0x31, 0xb0, 0x2e, 0x91, 0xc7, 0xf3, 0xc1, 0xe8, 0x0d, 0x42, - 0xed, 0xf3, 0xec, 0x58, 0xbb, 0x02, 0xe4, 0x0c, 0x76, 0x20, 0x61, 0x0b, - 0x73, 0x36, 0xdb, 0x14, 0xb4, 0x80, 0x97, 0xfa, 0x55, 0x86, 0xf7, 0x19, - 0x23, 0x49, 0xad, 0x24, 0xcc, 0xc2, 0x3c, 0x4f, 0x6d, 0x11, 0x1f, 0x48, - 0x2a, 0xdd, 0x9f, 0x65, 0xd5, 0xf6, 0x70, 0x84, 0x13, 0x59, 0x1e, 0xb8, - 0x3d, 0x2c, 0x4c, 0x65, 0x43, 0xed, 0xfb, 0x5e, 0x18, 0xcf, 0x25, 0xd2, - 0x93, 0x2b, 0x17, 0xb7, 0xd6, 0xc1, 0x61, 0x96, 0xe6, 0x4c, 0x7a, 0x49, - 0x0e, 0x5c, 0xa8, 0x88, 0x73, 0x3a, 0x46, 0xf6, 0x91, 0x79, 0x8e, 0x30, - 0x1f, 0x52, 0xd6, 0xc5, 0x62, 0xd7, 0x4b, 0x46, 0x13, 0xcd, 0x8f, 0xf1, - 0x26, 0xe0, 0xf3, 0xde, 0x4d, 0xb9, 0x85, 0xb4, 0xbc, 0x2e, 0x07, 0x2e, - 0xc8, 0xb3, 0x4b, 0x84, 0x1f, 0xc8, 0x35, 0x91, 0x8c, 0xad, 0x08, 0x2d, - 0xd5, 0x43, 0xe8, 0xe5, 0x90, 0x88, 0xe5, 0x5b, 0xf7, 0xc0, 0x1e, 0x8a, - 0x46, 0x84, 0x23, 0x1d, 0xd7, 0x41, 0x9e, 0xbe, 0xe6, 0xe6, 0x2b, 0x79, - 0xc9, 0x33, 0xe7, 0xf0, 0xe8, 0x9d, 0x92, 0xcb, 0x42, 0x96, 0x39, 0x9a, - 0x3a, 0x71, 0xd8, 0x25, 0xc0, 0x09, 0xaf, 0x51, 0x1a, 0x2b, 0x64, 0xab, - 0x7e, 0x66, 0x4b, 0x31, 0x9f, 0x19, 0x67, 0x1b, 0x3b, 0xbb, 0xfd, 0x4e, - 0xf1, 0x61, 0xca, 0xa5, 0x6c, 0x12, 0x56, 0xbb, 0x61, 0x4f, 0x2e, 0x2e, - 0xf8, 0x6a, 0x9e, 0x1c, 0xbb, 0xa2, 0x69, 0xa8, 0x0c, 0xda, 0xfb, 0x7c, - 0x7f, 0xaa, 0xd6, 0xab, 0x40, 0x5f, 0xf7, 0x4d, 0xba, 0xbc, 0xea, 0x41, - 0x7d, 0x44, 0x65, 0x77, 0x1e, 0x2f, 0x36, 0xb2, 0xbe, 0xe9, 0x53, 0x3e, - 0xa2, 0x7d, 0x40, 0x64, 0x89, 0x59, 0x2f, 0xdd, 0xb9, 0x79, 0xd1, 0xf1, - 0xdd, 0x3c, 0x96, 0xd6, 0x95, 0x4a, 0x50, 0x45, 0x52, 0xb7, 0xea, 0x85, - 0x0a, 0xcd, 0xbe, 0xa2, 0x3d, 0x78, 0x50, 0x05, 0x35, 0x2d, 0x7a, 0x5f, - 0x5d, 0xc2, 0x7b, 0x95, 0x0c, 0xf6, 0xd6, 0xec, 0x7a, 0xe2, 0x0d, 0x2a, - 0xb9, 0x8e, 0x92, 0xb8, 0x1f, 0x0b, 0xa3, 0x4e, 0xfd, 0x42, 0x59, 0x44, - 0x70, 0x90, 0xa5, 0x29, 0xc3, 0xc4, 0x6d, 0x85, 0x15, 0x0d, 0x39, 0xfa, - 0x39, 0x64, 0x2b, 0x88, 0x9f, 0xca, 0xf4, 0x6a, 0x66, 0x6e, 0x89, 0x75, - 0x1b, 0x90, 0x52, 0x4d, 0x10, 0x51, 0x55, 0x0e, 0x83, 0x1d, 0x9f, 0xd0, - 0x23, 0xb6, 0xd2, 0x66, 0xde, 0x7c, 0x13, 0x6e, 0xca, 0x15, 0xa7, 0x70, - 0x46, 0xb5, 0x12, 0x11, 0xde, 0x37, 0x8b, 0x18, 0x38, 0x65, 0xaa, 0x08, - 0x76, 0xcc, 0x9c, 0x58, 0x47, 0x67, 0x55, 0x55, 0xea, 0xd9, 0x5e, 0x68, - 0xd4, 0xed, 0x8e, 0x38, 0xb9, 0x7a, 0x9e, 0xb2, 0xc7, 0x52, 0xe9, 0x47, - 0x5e, 0x05, 0xf2, 0x93, 0xcb, 0x1b, 0x37, 0x9f, 0xe7, 0x55, 0xb3, 0x89, - 0xb6, 0x8b, 0xd8, 0xe3, 0xf4, 0x99, 0xc7, 0xc7, 0x03, 0x2a, 0x0f, 0xf3, - 0x01, 0xf7, 0x23, 0xe5, 0xcc, 0x5f, 0xe0, 0xfd, 0x69, 0xcc, 0x48, 0x1f, - 0x3f, 0xd7, 0x89, 0xb7, 0xb8, 0x94, 0x65, 0x4c, 0x67, 0x3c, 0x63, 0xf4, - 0xf1, 0x29, 0x93, 0xce, 0x6b, 0xfa, 0xd8, 0x02, 0x85, 0x53, 0xb4, 0x68, - 0xd6, 0x13, 0xb3, 0x18, 0x38, 0x89, 0x45, 0xc2, 0x99, 0x65, 0xdd, 0x06, - 0x6a, 0x61, 0x5c, 0x51, 0xaf, 0x18, 0x8a, 0xac, 0xbe, 0x9e, 0x84, 0x80, - 0xcc, 0xa5, 0xf3, 0x66, 0x41, 0x69, 0xaa, 0xb2, 0xd1, 0x25, 0xc3, 0xa9, - 0x69, 0xa5, 0xbd, 0x2c, 0x96, 0x9b, 0x81, 0x3a, 0xba, 0x49, 0x1a, 0xa5, - 0x9a, 0xbe, 0x00, 0xb1, 0xa1, 0xdc, 0xac, 0x37, 0x8e, 0x83, 0x6c, 0x6d, - 0x44, 0xb9, 0x6c, 0x6b, 0x1a, 0x1b, 0x57, 0xe6, 0x92, 0xf7, 0x23, 0x6d, - 0x07, 0x53, 0x20, 0x63, 0xa0, 0x95, 0x2d, 0x4a, 0x30, 0x27, 0x8e, 0x59, - 0x39, 0xa1, 0x68, 0xe3, 0x73, 0xb6, 0xdd, 0x1e, 0x8a, 0x52, 0x6b, 0x65, - 0xbc, 0x68, 0x39, 0x41, 0x5d, 0x24, 0x39, 0x87, 0xb5, 0xfa, 0xf5, 0xba, - 0xf5, 0xda, 0x68, 0x5f, 0xc4, 0x5d, 0xd5, 0xcb, 0x3a, 0x09, 0x09, 0xc8, - 0x42, 0x88, 0xab, 0x80, 0x45, 0x4b, 0x8f, 0xf3, 0x04, 0x3c, 0xb8, 0x1e, - 0xb6, 0xeb, 0x88, 0xa6, 0xce, 0xf4, 0x5e, 0xf2, 0x70, 0x08, 0x99, 0x77, - 0x45, 0xb2, 0x5e, 0xfa, 0xb8, 0xe6, 0xca, 0x87, 0xe4, 0x64, 0x57, 0xa6, - 0x7a, 0xb9, 0x8a, 0xa5, 0x24, 0x0d, 0x03, 0x0c, 0x83, 0xf0, 0x9e, 0xd1, - 0x84, 0xde, 0xc9, 0x5d, 0xd6, 0x8d, 0xad, 0xa5, 0xd3, 0xa2, 0xd7, 0x33, - 0x23, 0x67, 0x42, 0x8e, 0x27, 0xcb, 0xae, 0x8c, 0xbb, 0x25, 0x3d, 0x3f, - 0x5f, 0x72, 0x1d, 0x1d, 0xcb, 0xae, 0x59, 0x6d, 0xf4, 0x41, 0x3e, 0xb8, - 0xb1, 0x43, 0xd4, 0x4d, 0x03, 0x52, 0xa9, 0xc1, 0x40, 0xa1, 0x33, 0x0c, - 0x32, 0x94, 0x75, 0x4e, 0x2f, 0x5d, 0xf6, 0x3c, 0x50, 0x12, 0x8b, 0x74, - 0x3e, 0xe8, 0x44, 0x51, 0xeb, 0xe4, 0x79, 0x6c, 0x38, 0x93, 0x59, 0x8f, - 0x47, 0xd3, 0x15, 0x47, 0x84, 0xcc, 0x28, 0x12, 0x8e, 0x14, 0x1c, 0x0f, - 0xb9, 0xfe, 0x0c, 0x92, 0x2b, 0x56, 0xaf, 0x5b, 0xc7, 0x5e, 0xe3, 0x20, - 0xcf, 0xcd, 0x16, 0x2c, 0x82, 0xd1, 0x5e, 0xe0, 0x66, 0x20, 0x48, 0xdb, - 0xb2, 0xe0, 0xcf, 0x8f, 0x3f, 0xfe, 0xe5, 0x21, 0x28, 0xaa, 0xcc, 0x69, - 0xfe, 0xfc, 0xa6, 0x2f, 0x82, 0x00, 0x7d, 0xf3, 0x97, 0xff, 0xfc, 0xb7, - 0xff, 0xf7, 0xdf, 0xfe, 0x2d, 0x6a, 0xb2, 0xf4, 0x87, 0x7f, 0x73, 0x0b, - 0x6f, 0x7c, 0xf8, 0xdf, 0xff, 0xf6, 0xf0, 0x10, 0xf9, 0x71, 0x18, 0x35, - 0x7f, 0x7d, 0x40, 0x60, 0xf8, 0xdf, 0xff, 0x13, 0x7c, 0x6f, 0x8a, 0xf6, - 0x14, 0x3d, 0x3a, 0xa7, 0x26, 0x2e, 0xf2, 0xbf, 0x3e, 0x64, 0x4e, 0x1e, - 0x97, 0x6d, 0xea, 0x4c, 0xdf, 0xa6, 0xa7, 0x7d, 0xec, 0x35, 0xd1, 0x73, - 0x65, 0x00, 0xec, 0x1d, 0x18, 0xd7, 0x39, 0x25, 0x61, 0x55, 0xb4, 0xb9, - 0xf7, 0x78, 0x2a, 0xd2, 0xa2, 0xfa, 0xeb, 0x43, 0xe7, 0x54, 0x7f, 0x7e, - 0xbc, 0x7f, 0x01, 0x3f, 0xbd, 0xc7, 0xb0, 0x72, 0xc6, 0xbf, 0x4c, 0x30, - 0x82, 0x22, 0x6f, 0x1e, 0x03, 0x27, 0x8b, 0xd3, 0xf1, 0xaf, 0x0f, 0x6f, - 0xd6, 0x75, 0xef, 0xa4, 0xde, 0x9b, 0x1f, 0x1e, 0x6a, 0x27, 0xaf, 0x1f, - 0x6b, 0xbf, 0x8a, 0x83, 0xff, 0x7c, 0x05, 0xad, 0xcc, 0xa9, 0xc2, 0x18, - 0x20, 0x04, 0x4f, 0x5f, 0x8a, 0xce, 0xaf, 0x02, 0xa0, 0x23, 0x7f, 0x7d, - 0x88, 0x62, 0xcf, 0xf3, 0x6f, 0x98, 0x95, 0x8e, 0xe7, 0xc5, 0x79, 0xf8, - 0x54, 0xe3, 0x63, 0x3c, 0xff, 0xe3, 0x86, 0xe4, 0x63, 0xef, 0xbb, 0x49, - 0xdc, 0x3c, 0x36, 0x4e, 0xf9, 0x18, 0x01, 0xf8, 0xe9, 0xd4, 0xc6, 0x33, - 0xbe, 0x55, 0xe8, 0x3a, 0x7f, 0x86, 0x7f, 0x78, 0x78, 0xfa, 0x77, 0x43, - 0xf5, 0xdd, 0x0b, 0x37, 0xa2, 0x9c, 0x9c, 0x34, 0x2d, 0x5a, 0x80, 0x54, - 0x5e, 0xe4, 0xfe, 0xcb, 0xc7, 0x2d, 0x40, 0x1b, 0xa0, 0x9e, 0xfa, 0xa7, - 0x97, 0x0f, 0x93, 0x89, 0xd2, 0x9f, 0x79, 0x96, 0x15, 0xd7, 0xcf, 0x3d, - 0xa9, 0x5f, 0x7f, 0xf0, 0x4a, 0x21, 0xe8, 0x17, 0xf4, 0x1f, 0xff, 0x01, - 0x48, 0x13, 0xe7, 0x0f, 0x27, 0x40, 0x54, 0xf0, 0xdb, 0xaf, 0x1e, 0xfe, - 0x03, 0xfa, 0xb7, 0xb7, 0xa1, 0x5b, 0x3f, 0xbe, 0x2f, 0xf9, 0x3a, 0x7f, - 0x32, 0x50, 0xef, 0xb1, 0x8e, 0x9c, 0xa0, 0xb9, 0x75, 0xdb, 0x8b, 0xeb, - 0x32, 0x75, 0x00, 0x77, 0xe2, 0x3c, 0x9d, 0x9e, 0xb8, 0x69, 0x71, 0x4a, - 0x3e, 0xcf, 0x95, 0xc7, 0xd4, 0x0f, 0x40, 0xa1, 0xd3, 0x36, 0xc5, 0x8b, - 0xc2, 0xea, 0x5e, 0xf5, 0x7d, 0xe9, 0xf0, 0xf8, 0xc4, 0x15, 0x1c, 0xc1, - 0xcb, 0xe1, 0xb3, 0x7c, 0x2c, 0xea, 0xf8, 0x2e, 0x7b, 0x95, 0x3f, 0xc9, - 0x5d, 0xe7, 0xbf, 0xc6, 0xcf, 0x77, 0xfd, 0xae, 0x4f, 0x95, 0xef, 0xdf, - 0x7e, 0x15, 0x69, 0xea, 0xb8, 0xa9, 0xff, 0xe0, 0x54, 0xbe, 0xf3, 0x8e, - 0x08, 0xf7, 0xf2, 0x0f, 0x04, 0x1d, 0x70, 0xf1, 0xf4, 0xe7, 0x09, 0xd0, - 0xc3, 0xe3, 0x03, 0x01, 0x10, 0xf9, 0xcb, 0x0b, 0x9c, 0x5d, 0x60, 0xca, - 0x8b, 0x0c, 0xb4, 0x83, 0xd3, 0x1f, 0x62, 0xf8, 0x38, 0xbc, 0xc4, 0xf1, - 0x5d, 0xe9, 0xf8, 0xdc, 0x3f, 0x80, 0xd2, 0x8b, 0xf6, 0xfe, 0xfa, 0xd7, - 0x67, 0xc9, 0xb8, 0x7f, 0x77, 0x9d, 0x3b, 0x13, 0x9e, 0x7a, 0x81, 0x4e, - 0xb0, 0xbf, 0xfa, 0xc6, 0x63, 0x53, 0x01, 0x9e, 0x7d, 0xc4, 0xbc, 0xbf, - 0x3e, 0x80, 0xd2, 0xbc, 0x2e, 0x41, 0x27, 0xf3, 0xe6, 0x9b, 0x80, 0x44, - 0x6d, 0xe6, 0x7e, 0x83, 0x04, 0x94, 0x55, 0x0c, 0x68, 0x70, 0x57, 0x50, - 0xb7, 0xa8, 0x3c, 0x20, 0x6c, 0x95, 0xe3, 0xc5, 0x6d, 0x0d, 0xd0, 0x85, - 0x9f, 0xf0, 0x85, 0xfe, 0xe3, 0xc1, 0x6d, 0x01, 0x81, 0xf2, 0xfa, 0x1d, - 0x7d, 0xef, 0xdf, 0x6f, 0xf0, 0x9d, 0xb2, 0xf4, 0x1d, 0x80, 0xdc, 0xc9, - 0x7f, 0x2f, 0xb4, 0xdf, 0x2a, 0x75, 0x8f, 0x37, 0x4d, 0x7c, 0xad, 0xf1, - 0x27, 0x49, 0xb9, 0x97, 0x02, 0xc6, 0x94, 0xc3, 0x83, 0xe7, 0xd4, 0x91, - 0xef, 0xdd, 0xf5, 0xf5, 0x95, 0x2e, 0x3c, 0x4e, 0x0f, 0xfe, 0x02, 0x34, - 0xf8, 0x2d, 0x7a, 0x03, 0xf8, 0x52, 0xbd, 0xbf, 0x58, 0x9d, 0xbc, 0x57, - 0x6f, 0xab, 0x7a, 0xaa, 0x5f, 0x16, 0x71, 0xde, 0xf8, 0xd5, 0xcd, 0x60, - 0xa5, 0xfe, 0x00, 0xcc, 0xd7, 0x24, 0xa7, 0xc8, 0x27, 0x06, 0x2c, 0xce, - 0x23, 0x60, 0xb3, 0x9a, 0x77, 0xe5, 0x75, 0x7c, 0xf5, 0x27, 0x01, 0xba, - 0xe3, 0x7d, 0x2b, 0xea, 0x9f, 0x24, 0x0f, 0x83, 0xe1, 0x97, 0xa6, 0x0c, - 0x7d, 0x12, 0xb1, 0xb6, 0x99, 0x94, 0xec, 0x5b, 0x4c, 0x1b, 0x00, 0xfa, - 0xf0, 0x24, 0x98, 0xaf, 0xab, 0x49, 0xe3, 0x0f, 0xcd, 0xa3, 0x03, 0x88, - 0x39, 0x95, 0x4f, 0x8d, 0xbe, 0x2b, 0x7c, 0x0f, 0xd7, 0x4f, 0xd3, 0xb8, - 0xac, 0xe3, 0xfa, 0xf6, 0x68, 0x12, 0xa6, 0x27, 0x38, 0xc0, 0xb8, 0x4d, - 0x34, 0xab, 0x1f, 0x26, 0x6c, 0x9c, 0xea, 0x33, 0x36, 0x07, 0x08, 0x71, - 0x14, 0x37, 0x80, 0x6d, 0xa5, 0x73, 0x67, 0x74, 0x5f, 0x39, 0xe5, 0x7b, - 0x41, 0xbc, 0xcb, 0xc3, 0xff, 0x02, 0x06, 0x64, 0xd2, 0x45, 0xef, 0xbf, - 0x6f, 0x92, 0x51, 0x80, 0xba, 0x71, 0x03, 0x68, 0x05, 0xbf, 0xc5, 0xee, - 0xb8, 0xdf, 0x48, 0xfb, 0xe8, 0x77, 0x40, 0x88, 0xeb, 0x17, 0xd6, 0xec, - 0x25, 0x88, 0xc9, 0x03, 0x75, 0xfe, 0x1d, 0xc0, 0x4b, 0xee, 0xd7, 0x45, - 0x1a, 0x7b, 0x5f, 0x10, 0xdd, 0x61, 0x92, 0x28, 0x6f, 0xea, 0x68, 0x9c, - 0xd7, 0x7e, 0xf3, 0x00, 0x83, 0xbf, 0x24, 0x78, 0x6f, 0xa2, 0xdd, 0xb7, - 0x88, 0xcc, 0x0f, 0x00, 0xca, 0xc3, 0xcf, 0x7e, 0xeb, 0x85, 0xa0, 0xbd, - 0x8e, 0xda, 0x87, 0xbd, 0xfb, 0xe9, 0xa7, 0xda, 0x07, 0xf6, 0xd9, 0x03, - 0xcf, 0x3e, 0xe9, 0xe0, 0xe7, 0xc4, 0xfb, 0xdd, 0x1b, 0xef, 0xdb, 0xc5, - 0xbe, 0x28, 0xe0, 0xaf, 0xbc, 0x40, 0x7d, 0x09, 0x93, 0x0f, 0x49, 0xfe, - 0x89, 0xe6, 0x7e, 0x2b, 0xfc, 0xd7, 0xd8, 0xf5, 0xed, 0x9d, 0xf9, 0x99, - 0x0c, 0x7c, 0x05, 0xce, 0xc7, 0x2c, 0xa4, 0xbf, 0xf9, 0xbd, 0xcf, 0x30, - 0xd1, 0x4d, 0x01, 0x2d, 0xfe, 0xf2, 0x4e, 0x5d, 0xa6, 0x98, 0xea, 0xaf, - 0xc0, 0xe1, 0x38, 0xa9, 0xff, 0x67, 0xf8, 0x2d, 0x43, 0xbf, 0x42, 0xd2, - 0xcc, 0xcf, 0xdb, 0x1b, 0x15, 0x3f, 0x52, 0xf5, 0x0f, 0xbc, 0xd8, 0x87, - 0xda, 0x7a, 0xf2, 0xef, 0xd6, 0xe6, 0x63, 0x50, 0x65, 0xe5, 0x4f, 0x44, - 0xf8, 0xdf, 0x9f, 0x33, 0x43, 0x4f, 0xe6, 0xe6, 0xa9, 0x81, 0x67, 0x1f, - 0x87, 0x3f, 0x99, 0x9f, 0x9b, 0xf7, 0x7e, 0xe7, 0xb4, 0x9f, 0x2a, 0x3d, - 0x23, 0x85, 0x3c, 0x59, 0x92, 0x17, 0xd6, 0xe5, 0xb3, 0x36, 0x04, 0x58, - 0x8f, 0x26, 0x06, 0x5d, 0x7e, 0x7e, 0xd0, 0x14, 0xe5, 0x27, 0xb6, 0x20, - 0xce, 0x81, 0x25, 0x71, 0xd2, 0x57, 0x24, 0x2c, 0x2d, 0x5e, 0xef, 0xc1, - 0x87, 0xe8, 0x91, 0x1f, 0xa2, 0xf7, 0x84, 0x0e, 0x70, 0x12, 0xef, 0xaa, - 0x10, 0xe4, 0x47, 0x28, 0xd3, 0x5f, 0x40, 0xf9, 0x99, 0xd8, 0xd8, 0x07, - 0xee, 0xf6, 0x25, 0x4e, 0x7f, 0xfd, 0xab, 0xeb, 0x03, 0x6e, 0xfa, 0x37, - 0xdc, 0x5e, 0x61, 0xfc, 0x3b, 0x21, 0x79, 0x92, 0x0c, 0xc0, 0xa1, 0x7c, - 0x8a, 0x68, 0x9a, 0xa6, 0xfa, 0xf3, 0x04, 0x2b, 0x77, 0x32, 0xff, 0x2f, - 0x1f, 0x73, 0xe2, 0x09, 0xc5, 0x8f, 0xac, 0x24, 0x08, 0xc3, 0xd3, 0xcf, - 0x21, 0x01, 0xfc, 0xdf, 0x53, 0x90, 0xf6, 0x15, 0xbf, 0xfc, 0x29, 0x06, - 0x99, 0xdf, 0x38, 0x1f, 0x46, 0x6c, 0xef, 0x42, 0xb5, 0x97, 0x38, 0xc1, - 0xaf, 0x49, 0x03, 0xfe, 0x0a, 0xa2, 0x40, 0xda, 0x3e, 0xc5, 0x12, 0x48, - 0x60, 0x91, 0xb6, 0x93, 0x93, 0xf8, 0xaa, 0x18, 0xe2, 0x1f, 0x8a, 0x21, - 0x81, 0x7e, 0xa1, 0xe1, 0x8f, 0xc4, 0x70, 0xe2, 0xf3, 0x73, 0x7c, 0x08, - 0xff, 0x5e, 0x92, 0xf9, 0xbe, 0x6b, 0x80, 0xde, 0x37, 0x0d, 0xbc, 0x75, - 0xf1, 0x5b, 0x14, 0xf3, 0xe5, 0xab, 0xa5, 0x53, 0xd7, 0x20, 0xd2, 0x02, - 0xe6, 0x32, 0x8c, 0xee, 0x34, 0xfa, 0x1a, 0xf1, 0xe1, 0x2f, 0x7a, 0xf1, - 0xa2, 0xfc, 0xeb, 0xc3, 0x23, 0xfe, 0x9a, 0xd8, 0x4e, 0x22, 0x00, 0x42, - 0xbb, 0x57, 0x19, 0xf1, 0x0c, 0x9c, 0xa4, 0x3f, 0x24, 0x30, 0xfa, 0x11, - 0x35, 0xc9, 0xef, 0x45, 0xcd, 0x77, 0x3a, 0x46, 0x7f, 0x09, 0xd7, 0xa7, - 0x5c, 0xf2, 0x8b, 0x28, 0x3f, 0x2b, 0xf6, 0x87, 0x44, 0x7a, 0xc5, 0x1a, - 0xbc, 0x82, 0xf4, 0x3d, 0x30, 0xbd, 0x99, 0xdc, 0xe7, 0xa8, 0xf4, 0x9d, - 0xfd, 0xfd, 0xb6, 0xac, 0xf4, 0xd3, 0xe8, 0xf3, 0xc6, 0x81, 0xf7, 0xee, - 0xeb, 0xff, 0x46, 0xe9, 0xe9, 0xef, 0xbd, 0xc2, 0x3d, 0x43, 0x80, 0xdf, - 0x39, 0xab, 0xf8, 0x7a, 0xa3, 0xea, 0xd3, 0x9b, 0xa0, 0xe8, 0x3f, 0xbf, - 0xae, 0xc9, 0xef, 0xd4, 0x75, 0x22, 0xc8, 0x07, 0x84, 0xc0, 0x5f, 0xb7, - 0x70, 0xef, 0x05, 0xc5, 0x71, 0x6f, 0x72, 0xe7, 0x7f, 0xce, 0x81, 0x7c, - 0x9a, 0x2b, 0xbd, 0x23, 0xc9, 0x4f, 0x3f, 0xa5, 0x45, 0x58, 0xdc, 0x08, - 0xf3, 0x0e, 0x81, 0xe7, 0xa8, 0xee, 0x99, 0xce, 0xaf, 0x27, 0x71, 0xf4, - 0x07, 0xfe, 0x0b, 0x7d, 0x9f, 0x85, 0x3d, 0x04, 0xb1, 0x9f, 0x7a, 0x93, - 0x87, 0x7a, 0xa6, 0xfd, 0xbb, 0x82, 0xff, 0xfd, 0x4d, 0xc1, 0xfc, 0x67, - 0xe2, 0x83, 0x4f, 0x42, 0x2c, 0xe4, 0x2f, 0xbf, 0x8a, 0xe0, 0x2f, 0x15, - 0x92, 0xf8, 0x50, 0x3d, 0xe8, 0xaf, 0x51, 0xfc, 0xbd, 0x6a, 0x3e, 0x13, - 0xf3, 0xb9, 0x8f, 0x80, 0xa0, 0x7e, 0xe8, 0xe7, 0xde, 0x87, 0x24, 0x7d, - 0x99, 0x34, 0x3f, 0xfc, 0x5f, 0x71, 0x56, 0x16, 0x55, 0xe3, 0xe4, 0xcd, - 0x67, 0x1c, 0xc5, 0xd7, 0x03, 0xf9, 0x29, 0xbb, 0xfe, 0xac, 0x6e, 0x7e, - 0x0e, 0xa5, 0x47, 0xa0, 0x46, 0x69, 0xf9, 0x15, 0xe7, 0xf2, 0x19, 0x07, - 0xf7, 0x66, 0x7a, 0xf5, 0xa7, 0xbb, 0x40, 0xbd, 0xf9, 0x5c, 0x4e, 0xf4, - 0xc1, 0x20, 0xce, 0xd2, 0x01, 0xc5, 0xc0, 0x26, 0x3c, 0x28, 0x00, 0x48, - 0xfd, 0xe6, 0xa3, 0xae, 0xa2, 0xf8, 0x57, 0xad, 0x1d, 0xfd, 0x41, 0x4a, - 0x1c, 0x81, 0xd4, 0x7a, 0xc2, 0xe1, 0xe1, 0xd5, 0xae, 0x7d, 0xad, 0x53, - 0xa7, 0xa2, 0x2a, 0x41, 0x2b, 0x7f, 0xf9, 0x02, 0xbf, 0xbc, 0xb8, 0xfb, - 0x3c, 0xcf, 0x5e, 0xa3, 0x75, 0x06, 0x92, 0xb1, 0xf4, 0xfd, 0x90, 0x4b, - 0x73, 0x1b, 0x69, 0x00, 0x22, 0x7f, 0x87, 0x0f, 0xdc, 0x66, 0xe0, 0x83, - 0x8c, 0xfc, 0xe4, 0xd7, 0x2f, 0xf3, 0xfc, 0x0f, 0x35, 0xf0, 0x65, 0xa5, - 0xc6, 0xfb, 0x2c, 0xf6, 0x71, 0x0a, 0xda, 0x7e, 0x3c, 0x45, 0xa0, 0xe1, - 0xd3, 0x3d, 0xba, 0xf8, 0x54, 0x16, 0x5e, 0x07, 0xf9, 0xbf, 0x9a, 0x22, - 0x0c, 0x53, 0x60, 0xa6, 0xfb, 0xb8, 0x39, 0x45, 0xff, 0xfd, 0xc3, 0x6b, - 0x75, 0x6e, 0x45, 0xf1, 0xe9, 0xc9, 0x1c, 0x7f, 0xc2, 0xd7, 0x57, 0x01, - 0x57, 0xef, 0x12, 0x83, 0xcf, 0xa3, 0xfd, 0x69, 0xa2, 0xf3, 0x21, 0x88, - 0xe7, 0xa6, 0x5f, 0x94, 0x02, 0x07, 0x11, 0xc5, 0xa9, 0xf7, 0x2d, 0xb2, - 0xf9, 0x55, 0xb4, 0xbe, 0x37, 0x6c, 0xef, 0xc1, 0xcf, 0x7e, 0x06, 0x87, - 0x3e, 0x8d, 0xbe, 0x3e, 0xb1, 0xaf, 0xaf, 0x04, 0xeb, 0xf7, 0xa2, 0x66, - 0x4c, 0x5f, 0x44, 0x88, 0x5f, 0x8c, 0x89, 0xdf, 0x0f, 0x4f, 0x7d, 0x58, - 0x7c, 0xd3, 0xa0, 0x0f, 0x5c, 0xf0, 0xcb, 0xce, 0x7c, 0xc8, 0xf2, 0x17, - 0x78, 0xbc, 0x0b, 0x8c, 0x81, 0x19, 0x07, 0x14, 0x99, 0x34, 0xb3, 0x7e, - 0x2f, 0xd3, 0x2f, 0x46, 0xce, 0x6e, 0xcf, 0xd3, 0x60, 0x7a, 0xf6, 0x8a, - 0xeb, 0xba, 0xf9, 0x74, 0x2f, 0xae, 0xfc, 0xa7, 0x21, 0x63, 0x40, 0xa5, - 0x36, 0xcb, 0x27, 0xc0, 0x2f, 0xe1, 0xfc, 0xed, 0xb9, 0x89, 0xff, 0x35, - 0x45, 0xcd, 0x3f, 0xbe, 0xb9, 0xe7, 0x35, 0xf5, 0x9b, 0xff, 0x7e, 0x35, - 0x2e, 0xf8, 0x65, 0x2d, 0x7e, 0x6a, 0xc4, 0x43, 0xe7, 0xbd, 0x6d, 0xf9, - 0x36, 0x6c, 0xfe, 0xf6, 0xf0, 0x81, 0x03, 0x7b, 0x31, 0xec, 0xfc, 0x4c, - 0xdb, 0x8f, 0xc2, 0xe1, 0x8f, 0xb0, 0xfb, 0x70, 0x44, 0xee, 0x9b, 0x1a, - 0x7a, 0xfb, 0x54, 0xf8, 0x1d, 0x29, 0xf1, 0xff, 0xfe, 0x72, 0x24, 0xfe, - 0xf6, 0xf0, 0x2c, 0x41, 0xdf, 0x86, 0xd3, 0x47, 0x2e, 0xfe, 0x89, 0xf0, - 0xaf, 0x63, 0x3a, 0x8d, 0x15, 0xfd, 0xf5, 0xe1, 0x3e, 0x62, 0xf4, 0xf0, - 0x70, 0x6e, 0xeb, 0x26, 0x0e, 0xc6, 0xc7, 0x77, 0x7e, 0xe7, 0x16, 0x5f, - 0x3e, 0x3a, 0xb7, 0x78, 0xed, 0x0b, 0x52, 0xff, 0x72, 0xf4, 0xf5, 0xde, - 0xc3, 0xd7, 0x07, 0xce, 0x9e, 0x59, 0xf1, 0x14, 0x87, 0x02, 0xa3, 0xe0, - 0xf9, 0x75, 0x02, 0x94, 0xe5, 0xb5, 0x08, 0xe8, 0xb9, 0x72, 0xd1, 0x36, - 0x65, 0xdb, 0x3c, 0x02, 0x18, 0xfe, 0xc3, 0x8b, 0x82, 0xaf, 0xbf, 0x72, - 0xab, 0xf1, 0xa5, 0xa0, 0xe1, 0x5e, 0xed, 0xa7, 0x9f, 0x26, 0x73, 0x7e, - 0x1b, 0xa3, 0xfe, 0x65, 0x83, 0xa6, 0xef, 0x47, 0x23, 0x5e, 0xa7, 0xfc, - 0x73, 0x70, 0xf5, 0x0e, 0xda, 0xcf, 0x09, 0x99, 0x6e, 0x71, 0xfe, 0x5f, - 0xfe, 0xf3, 0x0b, 0x91, 0x3a, 0x0e, 0xc3, 0xaf, 0x0d, 0x5b, 0xbe, 0x53, - 0xbc, 0x67, 0x26, 0x01, 0xf1, 0xb9, 0x19, 0x99, 0x67, 0x34, 0xde, 0x8f, - 0x48, 0x7f, 0xc1, 0x7b, 0x7c, 0xa6, 0xa3, 0xef, 0xdf, 0x7d, 0x72, 0xac, - 0x4d, 0x14, 0xe7, 0x9f, 0x27, 0xec, 0xe7, 0x46, 0xdf, 0x5f, 0x1d, 0xd6, - 0x7e, 0x11, 0xd4, 0xbe, 0x34, 0xa0, 0xdf, 0x00, 0xf3, 0xd5, 0xf1, 0xf9, - 0x9f, 0xc5, 0xb1, 0x5f, 0xd0, 0xe4, 0xf7, 0x1a, 0xcd, 0x7f, 0x2f, 0x27, - 0xd4, 0xab, 0x63, 0xaa, 0xcf, 0x38, 0x3f, 0x23, 0x97, 0x16, 0x8e, 0xf7, - 0x14, 0x72, 0xdd, 0x22, 0x91, 0x47, 0x20, 0x27, 0x59, 0xfd, 0x32, 0xeb, - 0xf8, 0x65, 0x13, 0x4c, 0x1f, 0xe7, 0x3f, 0xcf, 0x43, 0x63, 0x9f, 0xd8, - 0x86, 0xf7, 0x0d, 0xdd, 0x27, 0x9b, 0xe0, 0x0f, 0x03, 0xca, 0x20, 0x1e, - 0x7c, 0xef, 0x5d, 0x34, 0x09, 0x7f, 0x36, 0x0d, 0x7a, 0xea, 0x47, 0x9c, - 0x85, 0xaf, 0x89, 0xc4, 0xb3, 0xf0, 0xbe, 0x1c, 0x84, 0xbc, 0x0d, 0x23, - 0xe2, 0x4f, 0xe3, 0x8f, 0x9f, 0xa3, 0xf1, 0x73, 0x5b, 0xe4, 0x07, 0x1c, - 0xbd, 0x37, 0xf6, 0xc3, 0xab, 0x93, 0xa4, 0xe0, 0xdd, 0x10, 0xa8, 0x47, - 0x5b, 0xa5, 0x7f, 0x7e, 0xe3, 0x39, 0x8d, 0xf3, 0xd7, 0x5b, 0x01, 0x54, - 0x77, 0xe1, 0x6c, 0xc8, 0xd2, 0x1f, 0xfe, 0x1d, 0xe3, 0xc1, 0xc7, 0x07, - 0xf0, 0x31, 0xaf, 0x7f, 0xfc, 0x53, 0xd4, 0x34, 0xe5, 0x5f, 0x21, 0xa8, - 0xef, 0xfb, 0xb7, 0x3d, 0xf6, 0xb6, 0xa8, 0x42, 0x08, 0xa4, 0x60, 0xf0, - 0x54, 0xf9, 0x4f, 0x0f, 0x5d, 0xec, 0xf7, 0x5c, 0x31, 0xfc, 0xf8, 0xa7, - 0x09, 0x51, 0x0c, 0xc6, 0xa7, 0xff, 0x7f, 0xba, 0x23, 0xf4, 0xe3, 0x9f, - 0x10, 0x02, 0xfd, 0xd3, 0x13, 0x6d, 0xef, 0x5f, 0xfe, 0x1d, 0x13, 0x00, - 0xe8, 0xd2, 0x69, 0x22, 0x40, 0xb2, 0x34, 0xfd, 0xf1, 0x4f, 0xff, 0x8e, - 0x62, 0x30, 0x7c, 0x82, 0x03, 0xf7, 0x4f, 0xb7, 0x82, 0xc7, 0xa7, 0xb1, - 0x7a, 0x00, 0xee, 0x2d, 0x00, 0xe3, 0xfd, 0xf8, 0xa7, 0x25, 0x8e, 0xbf, - 0x45, 0x1e, 0x50, 0x14, 0x77, 0x88, 0x07, 0x02, 0x34, 0x81, 0x80, 0xbf, - 0xf0, 0x03, 0x2a, 0xc3, 0xdd, 0x23, 0x1a, 0x4d, 0xcf, 0xae, 0x19, 0xe8, - 0xf6, 0x03, 0x4e, 0x7f, 0xf4, 0x9c, 0x46, 0xa7, 0x0a, 0x08, 0x8a, 0x4e, - 0x35, 0x08, 0xea, 0x2d, 0xfd, 0x88, 0x93, 0x2f, 0xab, 0x3c, 0xa2, 0x32, - 0xc0, 0xb4, 0x43, 0xa3, 0x47, 0xfc, 0x56, 0x05, 0x14, 0x7f, 0xf1, 0x39, - 0xf9, 0x16, 0x7d, 0x44, 0x90, 0x8f, 0xb0, 0x88, 0x1e, 0x69, 0x50, 0xfe, - 0xe1, 0x6b, 0xd1, 0x54, 0x74, 0xcd, 0x1e, 0x51, 0x82, 0x7c, 0xfc, 0x04, - 0x2b, 0xf8, 0x8e, 0xd4, 0x0d, 0x6b, 0x9a, 0x78, 0x4b, 0x3f, 0x60, 0xf8, - 0x2b, 0x6f, 0xbf, 0xd6, 0xc8, 0x75, 0x89, 0x12, 0xf4, 0xc3, 0xf4, 0xea, - 0xfb, 0xa7, 0x8f, 0xe8, 0x03, 0x6c, 0xc2, 0x11, 0xda, 0xdd, 0x21, 0x3e, - 0x92, 0x38, 0x50, 0x2f, 0xfa, 0xc3, 0xe7, 0xdd, 0x23, 0x81, 0x7f, 0x00, - 0x71, 0x2a, 0x9b, 0x8a, 0xae, 0x19, 0x4e, 0x3f, 0x22, 0x0c, 0xfd, 0x16, - 0x35, 0x69, 0x38, 0x22, 0xd1, 0xa9, 0xab, 0x24, 0x6e, 0xa2, 0xc8, 0x5b, - 0xe6, 0xc3, 0xda, 0x13, 0x81, 0x01, 0x71, 0x4c, 0x12, 0x8f, 0x70, 0xf2, - 0x46, 0x10, 0xda, 0xc4, 0xa8, 0x4f, 0x6b, 0x3d, 0x22, 0x28, 0xfd, 0xc0, - 0x90, 0x26, 0x40, 0x21, 0x42, 0xc8, 0xee, 0x15, 0x54, 0x51, 0x04, 0x8e, - 0x1e, 0xc1, 0xa3, 0x47, 0x8a, 0x7c, 0xf9, 0xec, 0xe9, 0x75, 0xe2, 0x2d, - 0xf3, 0xf8, 0x51, 0xeb, 0x13, 0xc9, 0x00, 0xd1, 0x3b, 0x9c, 0x96, 0x01, - 0xb5, 0x98, 0x8f, 0xf8, 0x83, 0x20, 0x80, 0xc7, 0x38, 0x1d, 0x3d, 0xf7, - 0xfe, 0x2d, 0xfa, 0x80, 0x60, 0xf0, 0xc7, 0x95, 0xa8, 0xa9, 0x3d, 0xfc, - 0xe3, 0xf6, 0x4c, 0x14, 0x9f, 0xfa, 0x0b, 0xdf, 0xde, 0x44, 0x48, 0xd0, - 0xf3, 0x4f, 0x80, 0x4f, 0xcd, 0x46, 0x08, 0xfc, 0xc1, 0x9b, 0x77, 0x84, - 0xee, 0xcd, 0x3e, 0x4e, 0xcf, 0xae, 0x4b, 0x92, 0x7c, 0x40, 0x69, 0xfc, - 0xd3, 0xbe, 0x52, 0xb8, 0x4c, 0xc0, 0x1d, 0x06, 0x7a, 0x0c, 0xaa, 0x63, - 0x80, 0xeb, 0xf4, 0x9d, 0x4d, 0x4b, 0x14, 0x03, 0xbd, 0x7f, 0x00, 0x78, - 0x7d, 0x04, 0x17, 0x45, 0xc9, 0x8e, 0x01, 0x34, 0xa6, 0x3b, 0x50, 0xfb, - 0xf6, 0x12, 0x3c, 0xd1, 0xba, 0x7b, 0x64, 0x9e, 0xbb, 0x88, 0x02, 0x89, - 0x79, 0xfc, 0xa4, 0x87, 0xa0, 0xa5, 0x0e, 0xff, 0x14, 0x01, 0x04, 0x27, - 0x9f, 0x50, 0xbc, 0x09, 0x06, 0xf3, 0xb1, 0x74, 0x03, 0x36, 0x75, 0x8f, - 0x80, 0xf3, 0x13, 0x3f, 0x10, 0xfc, 0x2e, 0xe6, 0x1f, 0x57, 0x41, 0xa7, - 0x53, 0x84, 0x6f, 0x2c, 0xa3, 0x27, 0xce, 0xdd, 0x90, 0x98, 0x84, 0x11, - 0xf0, 0x09, 0xfe, 0x18, 0x7b, 0x0a, 0xbd, 0x89, 0xe2, 0xd4, 0xd3, 0x1b, - 0x5d, 0x18, 0x20, 0xad, 0x30, 0x60, 0xe7, 0x84, 0x88, 0x4c, 0x60, 0x9f, - 0x70, 0x8f, 0x01, 0xed, 0x7e, 0xd4, 0xe6, 0x24, 0x07, 0xcb, 0xa9, 0xea, - 0x27, 0x6a, 0x21, 0xd3, 0x77, 0x41, 0xc7, 0xf0, 0x1b, 0x28, 0xa0, 0x8e, - 0xa0, 0x8d, 0x07, 0xf0, 0xc9, 0x24, 0xc9, 0x49, 0xd5, 0x49, 0x5c, 0x26, - 0x99, 0x4f, 0x9a, 0x00, 0x2f, 0x01, 0xa1, 0xc5, 0xd0, 0xd7, 0xc4, 0x75, - 0x79, 0x43, 0xee, 0x81, 0x46, 0x3f, 0xe6, 0x3b, 0xfa, 0x9a, 0x74, 0x9b, - 0xf4, 0xc4, 0x12, 0xfa, 0x6e, 0x6d, 0x5e, 0x11, 0x16, 0xa0, 0x18, 0xaf, - 0xb1, 0x00, 0xd0, 0x0e, 0x25, 0x6f, 0x2f, 0xc1, 0x28, 0x90, 0x4e, 0x94, - 0xfa, 0x98, 0x6a, 0x0c, 0x10, 0x0a, 0xfc, 0xc6, 0x6c, 0x84, 0x04, 0x4c, - 0xc6, 0x6f, 0xf2, 0x81, 0x03, 0x39, 0xc6, 0x99, 0x89, 0x72, 0xe4, 0x8d, - 0x3d, 0x18, 0x7e, 0x63, 0x01, 0x89, 0x4e, 0xb2, 0x31, 0x09, 0xde, 0x24, - 0x7f, 0xe4, 0x5d, 0x36, 0x48, 0xf2, 0xc6, 0x40, 0xec, 0x49, 0xb1, 0x90, - 0xcf, 0x11, 0x14, 0xa1, 0x3f, 0x42, 0x79, 0x52, 0x75, 0x19, 0x68, 0x32, - 0x7c, 0x13, 0x4c, 0xfa, 0x89, 0xac, 0x40, 0xb6, 0x41, 0x5e, 0xf6, 0x71, - 0xef, 0x98, 0x89, 0xb5, 0x40, 0x98, 0x6f, 0xba, 0x7f, 0xc7, 0xe0, 0x46, - 0x0a, 0xf0, 0xed, 0xbd, 0x89, 0x03, 0xf5, 0x1f, 0x19, 0x20, 0x9f, 0x68, - 0x84, 0xbe, 0x85, 0x29, 0x07, 0x7b, 0xc0, 0x6e, 0x20, 0xe0, 0x07, 0xe2, - 0x2d, 0x50, 0x11, 0x18, 0x28, 0x22, 0x7d, 0xef, 0x09, 0xfd, 0x8a, 0x8d, - 0x31, 0x27, 0xb1, 0x01, 0x18, 0x45, 0x8f, 0x04, 0x7d, 0xb7, 0xc6, 0x9f, - 0xc8, 0x2b, 0x82, 0x51, 0x29, 0x86, 0x4e, 0x9a, 0x84, 0x31, 0xaf, 0x41, - 0x20, 0x27, 0x8a, 0x00, 0xa9, 0xa0, 0x52, 0x50, 0x07, 0x74, 0x02, 0xe8, - 0x29, 0x35, 0x75, 0x69, 0x42, 0xf5, 0x81, 0x81, 0x3f, 0x66, 0xce, 0xcd, - 0x08, 0x11, 0x88, 0x86, 0x50, 0xc4, 0x5b, 0x02, 0xc8, 0x01, 0x0c, 0xa4, - 0xfd, 0x35, 0xeb, 0x77, 0xe3, 0x3c, 0xe0, 0x06, 0xc1, 0x68, 0x80, 0xcb, - 0x0f, 0x80, 0x40, 0x6f, 0x71, 0xa4, 0x03, 0x2f, 0x91, 0xcc, 0xcd, 0x30, - 0xbe, 0xa4, 0xd6, 0x1d, 0x2e, 0xc3, 0xdc, 0xe0, 0x02, 0x9b, 0x00, 0xe0, - 0x32, 0x24, 0x70, 0x23, 0xef, 0x1b, 0x9f, 0xaa, 0x01, 0x42, 0x3f, 0x82, - 0xff, 0xdd, 0x0b, 0x32, 0xdd, 0xff, 0x4e, 0x84, 0xba, 0x97, 0xbe, 0xa7, - 0xe8, 0x53, 0x65, 0x79, 0xf2, 0x16, 0x38, 0x80, 0x4a, 0x02, 0xd9, 0x00, - 0x48, 0x02, 0x14, 0x80, 0xe5, 0x9e, 0x50, 0x00, 0xba, 0x8b, 0x7f, 0x20, - 0x90, 0x77, 0x24, 0x30, 0x80, 0x43, 0x7a, 0x63, 0x8f, 0x09, 0xf8, 0x85, - 0xdd, 0x75, 0x93, 0x80, 0x65, 0xd0, 0x02, 0x31, 0x41, 0x4a, 0xc1, 0x13, - 0xe0, 0x34, 0x41, 0x73, 0x00, 0xc8, 0x92, 0x00, 0x8d, 0x4f, 0x28, 0xe1, - 0xb7, 0xd7, 0xee, 0x8f, 0x6e, 0x76, 0x1c, 0x25, 0x3f, 0x31, 0x7f, 0x00, - 0x38, 0x79, 0x83, 0x70, 0x87, 0xfe, 0x91, 0x66, 0x3f, 0x79, 0x82, 0x9b, - 0xc3, 0xa0, 0x99, 0x5b, 0x43, 0x18, 0x88, 0x09, 0x70, 0xe0, 0xf7, 0xde, - 0xd2, 0xe8, 0x9d, 0x81, 0xe6, 0x47, 0xaa, 0x7a, 0x57, 0x47, 0x74, 0x52, - 0x68, 0xf4, 0x63, 0xfd, 0x98, 0x3a, 0x0d, 0xbc, 0x3b, 0x06, 0x7e, 0x9b, - 0x80, 0xbb, 0xa4, 0x46, 0x4f, 0x54, 0x9d, 0x84, 0x00, 0x60, 0x0a, 0x98, - 0x4b, 0x4e, 0x4e, 0xf4, 0x63, 0xe1, 0x06, 0x22, 0x0d, 0xba, 0x95, 0x52, - 0xe0, 0xa5, 0xc7, 0xe9, 0x47, 0x37, 0xb5, 0xad, 0xa1, 0xcc, 0xf4, 0xf9, - 0x01, 0x10, 0x01, 0xa5, 0x6e, 0x92, 0x71, 0x47, 0xf3, 0x13, 0x73, 0x4a, - 0x03, 0xb5, 0xa2, 0x26, 0x12, 0xa7, 0x40, 0xd5, 0x11, 0xf2, 0xf6, 0x72, - 0x0a, 0xc8, 0xfc, 0x30, 0x09, 0xe8, 0xe4, 0xc1, 0x9e, 0x84, 0x1f, 0xd0, - 0xe7, 0x53, 0x5d, 0x21, 0xa7, 0x9e, 0xa2, 0x93, 0xb4, 0x00, 0x6c, 0x01, - 0xa6, 0x08, 0x83, 0xcb, 0x1f, 0x3b, 0x35, 0x50, 0x0d, 0x9f, 0xe0, 0x6b, - 0x93, 0xeb, 0x40, 0x80, 0x14, 0x32, 0x93, 0x37, 0x7a, 0xd6, 0x40, 0x02, - 0x9e, 0xfc, 0xd8, 0xc7, 0xe1, 0xce, 0x64, 0x2d, 0x09, 0x12, 0xf4, 0x7f, - 0xfa, 0x01, 0xb0, 0x06, 0xd1, 0x09, 0xf5, 0x31, 0xd4, 0x08, 0x01, 0x92, - 0xa7, 0x01, 0xbb, 0x0b, 0xa2, 0xb3, 0xb7, 0xc0, 0x0f, 0x13, 0xc0, 0x36, - 0xc0, 0xe4, 0xdd, 0xc3, 0xdd, 0xa0, 0xa2, 0x9f, 0xd8, 0xc7, 0xc9, 0x90, - 0xdc, 0x90, 0xbd, 0x91, 0x15, 0xa8, 0xe8, 0xab, 0xc8, 0xde, 0xb8, 0x40, - 0xa3, 0x53, 0x70, 0x71, 0x43, 0x96, 0x78, 0x32, 0x17, 0xcb, 0x89, 0xb5, - 0x40, 0xe7, 0x3b, 0xe4, 0x2d, 0x89, 0x68, 0x53, 0xad, 0x07, 0x60, 0x8e, - 0x6f, 0x31, 0xce, 0x54, 0x51, 0x03, 0x7a, 0x78, 0xa3, 0xc2, 0xdd, 0x74, - 0x83, 0x8a, 0xc0, 0xb8, 0x3d, 0xbc, 0xa2, 0x0e, 0xd3, 0x7f, 0x19, 0x7b, - 0x4b, 0x63, 0xec, 0x4b, 0x75, 0xc0, 0x80, 0xcd, 0x44, 0xa8, 0x7b, 0x37, - 0x5e, 0xd8, 0x3d, 0x19, 0xed, 0x6e, 0x11, 0xd9, 0xd4, 0x38, 0x0a, 0x78, - 0x4b, 0x62, 0xb7, 0x07, 0xe4, 0x53, 0x70, 0x05, 0x44, 0x0d, 0x3c, 0x43, - 0x28, 0x20, 0x14, 0x4f, 0xd1, 0x16, 0x79, 0x0f, 0x91, 0x26, 0x3f, 0x06, - 0x04, 0x86, 0xc2, 0xa6, 0xb2, 0x5b, 0x60, 0xf7, 0xfc, 0x84, 0x04, 0x04, - 0xc2, 0x26, 0xeb, 0x8c, 0x75, 0x08, 0x71, 0x37, 0xc6, 0x93, 0x9d, 0xc2, - 0x5f, 0x9a, 0x66, 0x7a, 0x82, 0x0a, 0xac, 0x12, 0x68, 0x99, 0x25, 0xde, - 0xc2, 0xe8, 0xc3, 0xed, 0xc7, 0xbd, 0x07, 0xe4, 0x03, 0xf3, 0x52, 0x65, - 0xc9, 0x07, 0x1c, 0xa8, 0xd2, 0xe3, 0x47, 0x56, 0x10, 0x7e, 0x9c, 0xd4, - 0xdb, 0x64, 0x6e, 0xa8, 0xd3, 0x80, 0xa5, 0x14, 0x7a, 0xf7, 0x96, 0xf7, - 0xf0, 0xe0, 0x9a, 0x4d, 0xfc, 0x7c, 0xb8, 0x7d, 0xff, 0xc0, 0x2e, 0x3c, - 0xde, 0xcd, 0xe7, 0x53, 0xf1, 0x7b, 0xb2, 0x01, 0x6a, 0xde, 0x8c, 0x3b, - 0x78, 0x09, 0xfe, 0x04, 0xa3, 0xc9, 0x96, 0x30, 0xe6, 0x47, 0x14, 0x9d, - 0xbe, 0x02, 0x3b, 0x4c, 0xdc, 0x8c, 0x22, 0x03, 0x22, 0x40, 0x00, 0x75, - 0x02, 0xfa, 0xb2, 0xca, 0x14, 0xbf, 0x83, 0x6a, 0xe6, 0xfb, 0x60, 0xeb, - 0xd9, 0x08, 0xdd, 0x5e, 0xbb, 0xf1, 0x6a, 0xe2, 0xdf, 0x47, 0xc6, 0xeb, - 0x11, 0x99, 0x60, 0x4f, 0x3f, 0x3e, 0xc1, 0xf3, 0xc9, 0x80, 0x81, 0x78, - 0x80, 0x9a, 0x72, 0xa1, 0x0f, 0x28, 0x02, 0xac, 0xe7, 0x0b, 0x7e, 0x03, - 0x36, 0x00, 0x40, 0xe4, 0x97, 0x6b, 0xdc, 0x54, 0xf6, 0x57, 0x57, 0x81, - 0xbf, 0x5a, 0x63, 0xb2, 0x81, 0x40, 0xb9, 0x7f, 0x6d, 0x43, 0x93, 0x06, - 0xd0, 0x5f, 0x69, 0xe9, 0x9b, 0xc0, 0x7c, 0x95, 0x30, 0xf0, 0xe3, 0x37, - 0xa0, 0xfb, 0xb5, 0x2a, 0x00, 0xdd, 0xaf, 0xb7, 0xf3, 0x55, 0xd2, 0xdd, - 0x23, 0xa4, 0xaf, 0xe1, 0x02, 0x7f, 0xb5, 0x06, 0xf3, 0xab, 0xb9, 0xf8, - 0x4d, 0xd2, 0x32, 0x79, 0xd0, 0xaf, 0x35, 0xf4, 0x75, 0xda, 0x7e, 0x03, - 0xf9, 0xbf, 0x4e, 0x39, 0xe6, 0xab, 0x64, 0xf9, 0x96, 0x3e, 0x7f, 0x15, - 0x95, 0xaf, 0x37, 0xf3, 0x6d, 0x3c, 0xfc, 0x7a, 0x87, 0x80, 0x40, 0xc1, - 0xdf, 0x41, 0x9e, 0xbe, 0x01, 0xdd, 0x5f, 0x5f, 0x65, 0x89, 0x03, 0xe3, - 0xf6, 0xeb, 0x3b, 0xf4, 0x75, 0x1d, 0x5a, 0x62, 0xd8, 0x03, 0x49, 0x7f, - 0x95, 0xb8, 0x5f, 0x33, 0x1c, 0xc0, 0x87, 0xe0, 0xf0, 0xaf, 0x56, 0xf9, - 0x6f, 0xe1, 0xf4, 0x37, 0x98, 0xcb, 0x6f, 0x90, 0x3a, 0x1a, 0xb0, 0x9a, - 0x22, 0x7f, 0xad, 0x5d, 0x78, 0xfc, 0x06, 0xb1, 0xfb, 0x06, 0xab, 0xfb, - 0x0d, 0x50, 0xbe, 0xc1, 0xa2, 0x82, 0x6c, 0xe9, 0xab, 0x5d, 0x7a, 0xfc, - 0x2e, 0xfe, 0xe8, 0xab, 0x35, 0xee, 0x21, 0xcf, 0xaf, 0xb6, 0x1e, 0xdf, - 0xe4, 0x46, 0xe0, 0xaf, 0x62, 0x42, 0xe3, 0x5f, 0xe5, 0xd0, 0xaf, 0x37, - 0x2f, 0x4f, 0xa3, 0x89, 0xd0, 0x34, 0x9c, 0xf8, 0xf4, 0xb1, 0xee, 0x42, - 0xf0, 0xe9, 0xcd, 0x8b, 0x91, 0xe3, 0x3e, 0x0e, 0xe2, 0x9f, 0x7e, 0x4a, - 0xe3, 0xba, 0xf9, 0x64, 0x69, 0xd5, 0x87, 0x93, 0xd9, 0x2f, 0x2a, 0x36, - 0xd5, 0x07, 0x2b, 0xf6, 0x31, 0xfa, 0x95, 0xd5, 0x41, 0xd8, 0x07, 0x4b, - 0x06, 0x5e, 0xbe, 0x7c, 0x9f, 0xf6, 0xfd, 0x70, 0x1e, 0xf5, 0x09, 0xc2, - 0x17, 0x97, 0x50, 0xbc, 0x80, 0xf1, 0x7e, 0xce, 0xf4, 0xff, 0x3c, 0xc3, - 0x7b, 0x75, 0x38, 0xf9, 0xc3, 0x66, 0xff, 0xcf, 0xbb, 0x1f, 0x3f, 0x63, - 0xde, 0xf9, 0x0e, 0x22, 0xce, 0x9f, 0xa7, 0x90, 0x3e, 0x37, 0xf1, 0xf2, - 0x5a, 0x7f, 0x6f, 0x6f, 0x3d, 0x3e, 0xfa, 0x55, 0x55, 0x3c, 0x8d, 0xcd, - 0xe7, 0x71, 0xe6, 0xdc, 0x47, 0xc4, 0x6f, 0x2b, 0xb1, 0x9e, 0xe6, 0x7b, - 0x00, 0x2d, 0x12, 0xbf, 0x7a, 0x00, 0xa9, 0xc0, 0xf3, 0xea, 0xee, 0x87, - 0x38, 0x0f, 0xa6, 0x75, 0x5c, 0xf7, 0xf9, 0xa9, 0xf7, 0xad, 0xbf, 0xba, - 0xa3, 0xe5, 0x69, 0xc1, 0xd7, 0x47, 0x6b, 0x59, 0xbe, 0x5a, 0xe5, 0x25, - 0xae, 0x8f, 0xbd, 0x53, 0xe5, 0x71, 0x1e, 0xbe, 0x8a, 0xe5, 0x17, 0xd1, - 0x7b, 0x7d, 0x9e, 0xea, 0x0e, 0xed, 0x2f, 0x9f, 0x5f, 0x1a, 0x55, 0x7d, - 0xc8, 0xf8, 0xfb, 0x82, 0xae, 0xa7, 0xa9, 0x8f, 0xeb, 0x63, 0x9c, 0x7b, - 0xfe, 0x70, 0x23, 0xf0, 0xd3, 0xea, 0xb1, 0xc2, 0x73, 0xd2, 0xfb, 0xe4, - 0xf7, 0xc7, 0x53, 0xa5, 0x45, 0x56, 0x36, 0x6f, 0xfe, 0xfb, 0x87, 0x8f, - 0xca, 0x9d, 0x14, 0x48, 0xd2, 0x9b, 0x2f, 0x2e, 0x95, 0x7e, 0xbf, 0x95, - 0xe8, 0x2d, 0x43, 0xfe, 0xe5, 0x93, 0xb5, 0x63, 0xaf, 0x4e, 0x63, 0xbc, - 0xd2, 0x03, 0xf8, 0xe5, 0xac, 0xc6, 0xbb, 0xd5, 0x5c, 0x13, 0xbe, 0xd3, - 0x3a, 0xe3, 0xba, 0x76, 0x42, 0xff, 0x13, 0xc5, 0x7a, 0xb7, 0x9c, 0xef, - 0xe5, 0x02, 0x81, 0xcf, 0xac, 0x25, 0x78, 0xb9, 0x0a, 0x40, 0x16, 0xb4, - 0x8d, 0xa0, 0x1b, 0x13, 0x1d, 0xfe, 0xd7, 0x7d, 0x16, 0xf5, 0xbf, 0x3f, - 0x9d, 0xf8, 0xfc, 0x98, 0xc7, 0xff, 0xeb, 0x3e, 0x5d, 0x5c, 0x84, 0x15, - 0xc0, 0xe6, 0xbf, 0x3f, 0x5a, 0x53, 0xfb, 0xf1, 0x82, 0xd5, 0xe7, 0x7a, - 0x2f, 0x17, 0x4d, 0x03, 0xf2, 0xb5, 0xe5, 0xe3, 0x7b, 0x19, 0x7c, 0x65, - 0xb5, 0xd1, 0xc7, 0xd3, 0x43, 0x2f, 0x88, 0xf7, 0x7e, 0x73, 0xc1, 0x17, - 0xd6, 0xc9, 0x7d, 0x79, 0x52, 0xe8, 0x69, 0xc7, 0xc1, 0xf3, 0x92, 0xde, - 0x1f, 0xdf, 0x08, 0x80, 0xe7, 0x23, 0xe0, 0xee, 0xff, 0x79, 0xf8, 0xf2, - 0xf3, 0x2f, 0x4c, 0x0a, 0xdf, 0x96, 0x2f, 0x7d, 0x7d, 0x85, 0xd2, 0xcf, - 0x5a, 0xdd, 0xf0, 0xca, 0x4a, 0xdb, 0x57, 0xad, 0xdc, 0x8b, 0x95, 0x6d, - 0x93, 0xed, 0x9e, 0x16, 0xc1, 0xbf, 0x9c, 0xa4, 0x7d, 0xda, 0xae, 0x85, - 0xbe, 0xb2, 0x78, 0xfa, 0x79, 0xa9, 0xd9, 0xc7, 0x8b, 0x82, 0x1f, 0xa7, - 0x76, 0x3e, 0xec, 0xdc, 0x8b, 0x29, 0xf2, 0x77, 0x7d, 0xfd, 0x0c, 0x2d, - 0xde, 0x2d, 0x3e, 0x79, 0xb6, 0x2e, 0xf7, 0xc5, 0x63, 0xbe, 0xd3, 0xb4, - 0x00, 0x74, 0xed, 0x37, 0x0d, 0xc0, 0xaa, 0xfe, 0xeb, 0xc3, 0x1b, 0x80, - 0x84, 0xf3, 0xe6, 0x3f, 0x3f, 0xae, 0x58, 0x67, 0x45, 0x31, 0xcd, 0xf8, - 0x86, 0x80, 0xa9, 0xf9, 0x64, 0x65, 0x62, 0xa7, 0xbe, 0x4f, 0xf6, 0xbd, - 0xa0, 0x52, 0xda, 0x54, 0x5f, 0xdc, 0xb9, 0xf6, 0x4b, 0xd6, 0xab, 0xbd, - 0xbe, 0x40, 0xe7, 0x83, 0x2d, 0x3d, 0x2f, 0xd6, 0xed, 0x80, 0x6e, 0x4c, - 0x06, 0x71, 0x12, 0xc7, 0x09, 0xd5, 0xcf, 0xad, 0xe8, 0x79, 0x47, 0xf2, - 0x17, 0x9b, 0x09, 0xbe, 0xb8, 0xb5, 0x06, 0x14, 0x03, 0x33, 0xfe, 0xb4, - 0x76, 0xe2, 0xe3, 0x95, 0xe4, 0x93, 0xb0, 0x7c, 0x69, 0x19, 0xca, 0x5d, - 0x14, 0x7e, 0xfa, 0xe9, 0xae, 0xed, 0x8f, 0x53, 0x2c, 0xf4, 0xbf, 0x3f, - 0xb7, 0xb2, 0xe2, 0xdd, 0xe2, 0xa1, 0xbb, 0x98, 0x4c, 0x8b, 0xe5, 0x82, - 0xe6, 0xf9, 0x8d, 0x0f, 0x65, 0xe7, 0x33, 0x2f, 0x44, 0x40, 0xb8, 0xbf, - 0x50, 0xff, 0x7d, 0x69, 0xf5, 0x72, 0x79, 0x13, 0x00, 0xf3, 0xff, 0x64, - 0xbe, 0x17, 0x3b, 0x0f, 0x7f, 0x7e, 0xb9, 0x08, 0x7c, 0x5a, 0xa7, 0xf9, - 0x97, 0x1b, 0xac, 0x17, 0x4a, 0xf8, 0xd7, 0x68, 0x5a, 0xe7, 0x71, 0x2b, - 0xfd, 0x39, 0xdb, 0x82, 0xbe, 0xdf, 0xc6, 0xa0, 0x5f, 0xb6, 0x35, 0xe8, - 0xab, 0xeb, 0x53, 0x01, 0x0d, 0x3e, 0xe8, 0xe7, 0x8b, 0x6d, 0x39, 0x1f, - 0x76, 0xf9, 0x57, 0x6c, 0xcb, 0xf9, 0x75, 0x1b, 0x73, 0xbe, 0xe7, 0xd6, - 0x9c, 0x5f, 0xba, 0x39, 0xe7, 0x2b, 0xdb, 0x73, 0x3e, 0xbf, 0x41, 0xe7, - 0x35, 0x02, 0xbf, 0x5c, 0x4a, 0xff, 0x62, 0xf1, 0xfc, 0x53, 0x8c, 0xf0, - 0xbe, 0xfe, 0xbb, 0xc5, 0xe4, 0x0f, 0xef, 0xd7, 0xcf, 0x3c, 0xa9, 0xcd, - 0xcf, 0x58, 0xbf, 0x8c, 0xbf, 0x23, 0xe2, 0xfd, 0xdd, 0x17, 0x8b, 0xe8, - 0x3f, 0x56, 0x96, 0x27, 0xbb, 0xfc, 0x89, 0xb6, 0xbc, 0x2f, 0x7f, 0x75, - 0x1d, 0xed, 0x4b, 0x37, 0xf7, 0x21, 0xf6, 0x2f, 0xd6, 0x7d, 0x7f, 0xc1, - 0x42, 0xbe, 0x7f, 0xe7, 0x79, 0xc1, 0xd4, 0xc7, 0x6f, 0x3c, 0x9b, 0xa9, - 0x4f, 0x6b, 0x7e, 0xb8, 0xb4, 0xea, 0xb5, 0x05, 0x91, 0xef, 0xdf, 0x79, - 0xb1, 0x5c, 0xea, 0x17, 0x6d, 0x10, 0xfd, 0x20, 0x1a, 0xe8, 0xa2, 0x7b, - 0xd1, 0x9d, 0x72, 0xef, 0x36, 0x16, 0xbf, 0xba, 0x34, 0xe4, 0x99, 0x40, - 0xcf, 0x55, 0x9e, 0x0c, 0xcd, 0xf3, 0x7e, 0xe0, 0xae, 0x7f, 0x78, 0xbc, - 0x43, 0x78, 0x6a, 0xe6, 0x65, 0x98, 0xf8, 0x69, 0x07, 0x3e, 0x5a, 0xc8, - 0xf5, 0xe9, 0xfe, 0xe2, 0x2e, 0x02, 0xf0, 0x90, 0x77, 0xf0, 0x3e, 0x7e, - 0xff, 0x85, 0xff, 0xfc, 0x70, 0xa7, 0xf6, 0x67, 0x57, 0xa5, 0x7c, 0x61, - 0x5d, 0xca, 0xb7, 0xcb, 0xdf, 0xa7, 0x9c, 0xf9, 0x0c, 0xe6, 0xe4, 0x7b, - 0x42, 0xbc, 0x8c, 0x22, 0x31, 0xf4, 0x63, 0xfd, 0x78, 0x5e, 0x41, 0xf8, - 0x21, 0x63, 0x5f, 0xa7, 0x06, 0xf9, 0x8e, 0x18, 0x93, 0xd1, 0x4f, 0xfc, - 0x31, 0xa8, 0x40, 0x40, 0x55, 0xbf, 0x96, 0xac, 0x4c, 0x60, 0x08, 0xf8, - 0xdf, 0xbf, 0xc9, 0xd4, 0xbf, 0x4c, 0x07, 0x5e, 0x05, 0xfd, 0x2a, 0xcc, - 0x0f, 0x23, 0xc7, 0xdb, 0x7b, 0x53, 0xf1, 0x7f, 0x41, 0x37, 0x97, 0xff, - 0xb7, 0xfb, 0x97, 0x69, 0x87, 0xd5, 0xc3, 0x53, 0xcc, 0x5f, 0x96, 0xa9, - 0x0f, 0x42, 0x6f, 0x37, 0x06, 0xbf, 0x40, 0x80, 0xf2, 0x08, 0x0a, 0x1e, - 0x4f, 0x4e, 0x39, 0xad, 0x05, 0x7f, 0xf3, 0x1c, 0xeb, 0xfe, 0xf8, 0x66, - 0xf4, 0xeb, 0x37, 0x0f, 0xd0, 0xd3, 0xeb, 0x53, 0xc3, 0x93, 0x96, 0xfe, - 0xf8, 0x66, 0x0a, 0x82, 0xde, 0x3c, 0x34, 0x63, 0x09, 0x20, 0xdd, 0xd7, - 0xfa, 0x94, 0x79, 0xf8, 0xe6, 0x21, 0xaa, 0xfc, 0xe0, 0xc7, 0x97, 0x2b, - 0x80, 0x40, 0xe9, 0x7f, 0xba, 0x20, 0xc0, 0x21, 0xf1, 0x1f, 0x62, 0x93, - 0x5b, 0xeb, 0x3d, 0xac, 0x4a, 0x61, 0x31, 0x1d, 0xe8, 0xb0, 0x32, 0xf6, - 0x91, 0xb0, 0x0f, 0xc1, 0x27, 0x7e, 0xfa, 0xca, 0x86, 0x3c, 0xbb, 0x04, - 0xbf, 0x38, 0xa1, 0x54, 0x2a, 0x69, 0x2a, 0x30, 0x45, 0x6e, 0x69, 0x0a, - 0x7b, 0xf0, 0x69, 0x0e, 0x81, 0x3f, 0xc4, 0x2c, 0xc8, 0x23, 0xdc, 0x17, - 0x54, 0x3e, 0xbc, 0x96, 0xa4, 0x9f, 0xf7, 0xf4, 0x66, 0xce, 0xf7, 0xf4, - 0xb2, 0xd2, 0xf8, 0x41, 0xd0, 0xf7, 0xf6, 0xce, 0x14, 0x77, 0x07, 0x84, - 0x09, 0x96, 0xd7, 0x25, 0x5a, 0x5e, 0x2e, 0x97, 0xb8, 0xb8, 0x2c, 0xd6, - 0xbb, 0x84, 0xf6, 0xe4, 0x98, 0xa7, 0x5a, 0x6a, 0x14, 0xa3, 0x22, 0xbc, - 0x2e, 0xaf, 0xc6, 0x50, 0xbb, 0xaa, 0x95, 0x12, 0xbe, 0x9e, 0x94, 0x8b, - 0xf8, 0x88, 0x5a, 0x5e, 0x6e, 0x13, 0x98, 0x7f, 0x48, 0x1b, 0x37, 0xa3, - 0x89, 0xf5, 0xb5, 0x1d, 0xf6, 0x21, 0xb1, 0xbe, 0x21, 0xb2, 0x4f, 0x85, - 0xad, 0xb9, 0xc5, 0x47, 0xca, 0xd2, 0x0d, 0x4a, 0x15, 0x14, 0x76, 0x10, - 0xdd, 0xbe, 0x57, 0xe2, 0xee, 0x0c, 0x31, 0x10, 0x85, 0xcd, 0x8e, 0x71, - 0x46, 0x29, 0x29, 0x6a, 0xf6, 0x90, 0x2f, 0xe9, 0xfc, 0x6e, 0x1d, 0xed, - 0xfb, 0xfe, 0x70, 0x1a, 0x67, 0xe1, 0x96, 0x5d, 0xd7, 0x21, 0x6e, 0xb1, - 0x39, 0x6f, 0xee, 0xa3, 0x00, 0x2d, 0x84, 0x15, 0xb7, 0x24, 0x06, 0x9a, - 0xd7, 0x46, 0x1b, 0x16, 0xc4, 0x5d, 0x75, 0xd0, 0x77, 0x16, 0x96, 0xed, - 0xe7, 0xe1, 0x61, 0xee, 0x2b, 0xd2, 0x01, 0x37, 0x87, 0xc5, 0xb0, 0x67, - 0xf5, 0xfe, 0xd4, 0x11, 0xeb, 0xac, 0x86, 0xb9, 0xcb, 0xb6, 0x10, 0x34, - 0xa1, 0x50, 0x13, 0x7d, 0x13, 0xac, 0x14, 0x13, 0xa6, 0x60, 0xf1, 0xdc, - 0x5f, 0x8a, 0x48, 0xcd, 0xe6, 0x5b, 0x9b, 0xf4, 0xb6, 0x7e, 0x68, 0xc6, - 0x82, 0x07, 0xe7, 0xe7, 0x6b, 0xcf, 0x86, 0xd7, 0x19, 0xa7, 0x03, 0x34, - 0x6a, 0x76, 0x91, 0xae, 0x38, 0x1b, 0x97, 0xa2, 0x9e, 0x70, 0x62, 0xa2, - 0xca, 0xe5, 0x53, 0x98, 0x7b, 0x7b, 0x9f, 0x39, 0x44, 0xe2, 0x32, 0x54, - 0x1c, 0x4d, 0x5f, 0x8d, 0x03, 0x6b, 0x8b, 0xd4, 0x96, 0x42, 0x62, 0x5b, - 0xc5, 0x57, 0xa8, 0xe7, 0xd9, 0x52, 0x28, 0x1e, 0xb6, 0x17, 0x63, 0x1e, - 0x96, 0x2a, 0xb4, 0x96, 0x56, 0xb3, 0xf3, 0x35, 0xc5, 0x6a, 0x8d, 0x13, - 0xb4, 0xd6, 0x37, 0x22, 0x92, 0x88, 0x05, 0x8a, 0xee, 0x48, 0xe1, 0xb0, - 0xe6, 0x39, 0xa2, 0x52, 0x89, 0x30, 0xad, 0x06, 0xac, 0x4d, 0xcb, 0x63, - 0x37, 0xeb, 0x42, 0x51, 0x57, 0x17, 0xed, 0x98, 0x59, 0x56, 0xe0, 0x0d, - 0xba, 0x90, 0x60, 0x6e, 0xbc, 0x20, 0x25, 0x8b, 0x5c, 0xa0, 0x6e, 0xde, - 0x1f, 0xd2, 0x1c, 0x37, 0xd1, 0xbc, 0xf3, 0x37, 0xc1, 0x4c, 0x5a, 0xcc, - 0xa4, 0x64, 0xbd, 0x6b, 0xb5, 0x71, 0xa5, 0x78, 0x1c, 0x93, 0x8d, 0xcd, - 0x42, 0x17, 0xbb, 0xcb, 0x3e, 0x1b, 0x7a, 0x66, 0x79, 0x1d, 0xf1, 0x8d, - 0x84, 0xb3, 0xc1, 0x8c, 0x95, 0x71, 0x92, 0x3f, 0x92, 0x73, 0xd9, 0x3e, - 0x84, 0x37, 0x69, 0x10, 0x52, 0x71, 0x97, 0x18, 0xed, 0x36, 0xe3, 0xf9, - 0xd7, 0xc4, 0xef, 0x2e, 0xbc, 0xf7, 0x73, 0x2c, 0xee, 0xa2, 0xf8, 0x4b, - 0x24, 0x8f, 0xd3, 0xa6, 0xa3, 0x45, 0x0c, 0xf8, 0x49, 0xf2, 0xd6, 0x91, - 0x23, 0xe9, 0x53, 0x85, 0x23, 0x72, 0x93, 0x3c, 0x62, 0x08, 0x68, 0x20, - 0x97, 0x7b, 0x0e, 0x08, 0x98, 0xb9, 0x97, 0x0a, 0xcf, 0x25, 0x94, 0x4b, - 0x56, 0x27, 0x48, 0x0b, 0x29, 0x73, 0x31, 0x82, 0xcf, 0x91, 0x0a, 0xab, - 0xcb, 0xfd, 0x12, 0xeb, 0x37, 0x89, 0xa4, 0x18, 0x7d, 0x76, 0x76, 0xc3, - 0xbe, 0x6a, 0x85, 0xb9, 0x14, 0x6f, 0x57, 0xab, 0xe4, 0x74, 0x38, 0xca, - 0xf4, 0xb5, 0xf1, 0x6b, 0xd3, 0x3a, 0x1c, 0x75, 0x3d, 0x85, 0x03, 0x8f, - 0xa8, 0x55, 0x6d, 0xd7, 0xb7, 0x25, 0x93, 0xb8, 0x76, 0x71, 0x6c, 0x0a, - 0x66, 0xab, 0x2c, 0xce, 0xdb, 0x3a, 0xa7, 0x69, 0xd7, 0x29, 0xea, 0xed, - 0x06, 0xd9, 0x46, 0x81, 0xba, 0xdc, 0xed, 0xa4, 0x6d, 0x91, 0x2e, 0xd9, - 0xf5, 0x1a, 0x26, 0xca, 0x3c, 0xb3, 0x27, 0x69, 0x4c, 0x13, 0x78, 0x92, - 0x46, 0x1d, 0x47, 0xdb, 0x2b, 0x17, 0xde, 0x4e, 0x44, 0xe1, 0xd9, 0x62, - 0x83, 0x96, 0x22, 0x99, 0xdc, 0xf5, 0xe7, 0x7b, 0xfd, 0x91, 0xe6, 0x28, - 0x2e, 0x3c, 0x7d, 0x5e, 0x9e, 0xa1, 0x46, 0x17, 0xf7, 0xe6, 0xf7, 0xfc, - 0x73, 0xdc, 0x33, 0x6b, 0xee, 0x09, 0xfe, 0x66, 0x01, 0xb9, 0x5b, 0xfd, - 0xbb, 0x82, 0x37, 0x2d, 0x61, 0x33, 0xbf, 0x13, 0x88, 0x0d, 0x37, 0x43, - 0x20, 0xc1, 0xe2, 0xf7, 0x85, 0xef, 0xc5, 0x73, 0xb6, 0xbf, 0x13, 0x48, - 0xd9, 0x40, 0x07, 0x3d, 0xe5, 0xbe, 0x2b, 0x78, 0x31, 0x70, 0x9f, 0xb0, - 0x67, 0xd9, 0x71, 0x33, 0x43, 0x04, 0xf3, 0xfb, 0xd2, 0x27, 0xda, 0xc1, - 0xef, 0xd8, 0x4b, 0xe7, 0x4c, 0xc3, 0x7d, 0x67, 0xf2, 0x1c, 0xb7, 0xf4, - 0x13, 0x7b, 0x79, 0x16, 0x12, 0x69, 0x77, 0xfb, 0x7d, 0xc1, 0x9b, 0xa8, - 0xb2, 0x9c, 0xb3, 0x4f, 0xec, 0x85, 0x18, 0x4f, 0xda, 0x7f, 0x57, 0xfc, - 0xf7, 0xa6, 0xd7, 0x16, 0xc5, 0x1a, 0x86, 0x0b, 0xfe, 0xc2, 0x16, 0x5d, - 0xe4, 0xeb, 0xc5, 0x85, 0xdd, 0xc6, 0x56, 0xe2, 0x8e, 0xd0, 0x90, 0xa3, - 0x5b, 0xf9, 0x58, 0xa1, 0x65, 0x4c, 0x55, 0x25, 0xb5, 0x9b, 0x49, 0xb5, - 0xb7, 0xfd, 0x58, 0x79, 0x78, 0x05, 0x47, 0x8a, 0xa8, 0x0a, 0xd2, 0xc3, - 0xf6, 0x1a, 0x23, 0x2e, 0xcf, 0x57, 0xf0, 0xd9, 0x12, 0x68, 0xf4, 0x34, - 0x77, 0xec, 0xd4, 0xd2, 0xe5, 0xfd, 0xfd, 0xb7, 0x6a, 0x8b, 0xc7, 0xcb, - 0xd1, 0x4c, 0xac, 0x4c, 0xcf, 0xa4, 0x54, 0xb4, 0xc5, 0x22, 0xb1, 0xd3, - 0x42, 0xcf, 0x74, 0x67, 0x91, 0x99, 0xb6, 0x50, 0x26, 0x66, 0x5c, 0x46, - 0x96, 0xee, 0xd8, 0xd2, 0xd1, 0xd9, 0x83, 0x6a, 0xb1, 0x9e, 0x59, 0x91, - 0x04, 0xaa, 0x65, 0xb6, 0x99, 0x18, 0x99, 0x6e, 0xa9, 0x19, 0x78, 0xa9, - 0x4c, 0xec, 0xa8, 0xd4, 0xcd, 0x1d, 0x24, 0xd8, 0x8b, 0xd3, 0x2a, 0x9f, - 0x9e, 0xed, 0x90, 0x45, 0xb6, 0x62, 0x14, 0xdb, 0x3b, 0x63, 0x19, 0x0a, - 0xbe, 0x6f, 0x31, 0x78, 0xb8, 0x50, 0x69, 0x3a, 0x64, 0xf0, 0xa8, 0x1a, - 0x28, 0x9a, 0x78, 0x52, 0xae, 0x10, 0xa0, 0x1d, 0x3d, 0xe3, 0x9c, 0x4c, - 0x37, 0xe2, 0x2c, 0xb2, 0x12, 0x3d, 0xce, 0xd2, 0xc8, 0x2a, 0xf4, 0xd8, - 0x2a, 0x43, 0xab, 0xb0, 0x43, 0xab, 0x4c, 0xf6, 0x45, 0x59, 0x98, 0xa5, - 0x70, 0x2c, 0xcb, 0xa3, 0x79, 0x11, 0x8e, 0xe9, 0xe5, 0x28, 0x5e, 0x24, - 0xf0, 0xdf, 0x16, 0x55, 0xd5, 0x11, 0x1d, 0x5d, 0x52, 0x1d, 0x4b, 0x74, - 0x22, 0x69, 0xe1, 0x00, 0x38, 0xd1, 0x33, 0xac, 0xe1, 0xb8, 0xce, 0xcd, - 0x83, 0x7b, 0x6e, 0x37, 0x0c, 0x8d, 0xd3, 0x24, 0x9c, 0x9c, 0x95, 0x46, - 0x3e, 0x5b, 0xcd, 0xb2, 0x23, 0xf0, 0xdc, 0xa0, 0x3b, 0x82, 0xc4, 0xa9, - 0x40, 0x91, 0xda, 0x35, 0x34, 0xf3, 0x0f, 0x84, 0xef, 0x39, 0x8e, 0x79, - 0xb6, 0xce, 0x43, 0x6c, 0xb5, 0x87, 0x7c, 0xc0, 0x7a, 0xc6, 0x5d, 0xcd, - 0xa4, 0x8b, 0x8f, 0x42, 0xbb, 0x79, 0x4b, 0xbb, 0x6e, 0xb7, 0x1b, 0x18, - 0x12, 0x3e, 0x9d, 0x85, 0x66, 0xba, 0x02, 0x67, 0xed, 0xb9, 0xd7, 0xd9, - 0x99, 0x82, 0xaf, 0xfa, 0x06, 0x86, 0xb1, 0x1a, 0xd3, 0x68, 0x0b, 0x16, - 0x6e, 0xcf, 0xae, 0x56, 0x57, 0x92, 0xd8, 0x96, 0xa9, 0xe9, 0xdd, 0x75, - 0x56, 0xa7, 0xa4, 0x75, 0x34, 0xa3, 0x4b, 0x36, 0xec, 0xb0, 0x9d, 0x5a, - 0x77, 0xe5, 0x52, 0xdb, 0xad, 0x6a, 0x18, 0xab, 0x36, 0x8b, 0xd2, 0x12, - 0x2f, 0xae, 0x28, 0x7b, 0x2b, 0x47, 0x6b, 0xbb, 0xfd, 0x8a, 0x81, 0xb8, - 0xd3, 0x1c, 0xb6, 0x60, 0xba, 0xe2, 0x9a, 0xcd, 0xb9, 0x73, 0x7c, 0x2c, - 0xf7, 0xac, 0xcb, 0x2c, 0xc6, 0x6c, 0xd7, 0x23, 0x1d, 0x33, 0xcc, 0x72, - 0xc6, 0xf6, 0x99, 0x53, 0x3a, 0x5b, 0x0a, 0xfd, 0x76, 0xae, 0xea, 0x1e, - 0x27, 0x6e, 0x45, 0x51, 0x3f, 0xb9, 0x28, 0x03, 0x21, 0x6b, 0xd4, 0xd8, - 0x95, 0x0d, 0x9a, 0xa0, 0xa4, 0x2a, 0xc7, 0x0b, 0x7c, 0x3f, 0x64, 0x74, - 0x5c, 0x2f, 0xb6, 0xc4, 0xf1, 0x1a, 0x70, 0xa7, 0xb0, 0x16, 0x17, 0xce, - 0x45, 0xb8, 0x0a, 0xeb, 0x83, 0x6d, 0x77, 0x03, 0xbf, 0x9a, 0xaf, 0x34, - 0x72, 0x1e, 0xea, 0x25, 0xe7, 0xd9, 0x8b, 0x91, 0xb9, 0xba, 0xfb, 0x31, - 0xaf, 0x16, 0x80, 0x1f, 0x5b, 0xb3, 0x0a, 0x42, 0x9e, 0x6f, 0x7a, 0xbe, - 0x2c, 0xaf, 0xa7, 0x94, 0x50, 0xea, 0x4d, 0x70, 0x11, 0x0a, 0xc9, 0x31, - 0xd1, 0x00, 0x86, 0x63, 0x4d, 0x35, 0x45, 0x4c, 0x80, 0x67, 0x46, 0xe1, - 0x5c, 0x2e, 0xa4, 0x62, 0x05, 0x18, 0x7e, 0x4a, 0x70, 0xc7, 0xa8, 0x76, - 0x08, 0xef, 0xaf, 0xc3, 0xf0, 0x42, 0x16, 0x24, 0xbd, 0xdb, 0x57, 0xb0, - 0xd1, 0x99, 0x95, 0x19, 0xbb, 0x46, 0xb3, 0x57, 0x87, 0x82, 0x34, 0xc4, - 0xe5, 0x3c, 0x77, 0x57, 0x6d, 0x6d, 0x8a, 0x53, 0x36, 0x72, 0x6a, 0xae, - 0xad, 0xb6, 0x3d, 0x8a, 0x3a, 0xb2, 0xb9, 0x44, 0x23, 0xb0, 0x58, 0xd7, - 0xdd, 0x22, 0xc1, 0xd2, 0xdd, 0x6c, 0x71, 0x28, 0x17, 0x46, 0xb9, 0x0c, - 0x0a, 0x34, 0xa5, 0x62, 0xdc, 0x24, 0x46, 0x25, 0x19, 0x8c, 0x8b, 0x57, - 0x70, 0xfa, 0x36, 0x88, 0x7a, 0x0d, 0x9b, 0x13, 0xab, 0x38, 0x85, 0x88, - 0xd6, 0x10, 0x19, 0xd9, 0x74, 0xea, 0x8a, 0x12, 0xfc, 0xdd, 0x36, 0x29, - 0x45, 0x67, 0x4f, 0x19, 0x6d, 0xd3, 0xce, 0x23, 0xcf, 0xd9, 0x84, 0x1a, - 0x72, 0xd2, 0x39, 0x2b, 0x0d, 0x72, 0x43, 0x4a, 0x06, 0x38, 0x90, 0x22, - 0xc9, 0xf2, 0x1a, 0x38, 0x8a, 0x23, 0x1b, 0xf7, 0xfa, 0xf3, 0x89, 0x52, - 0x8b, 0x56, 0xf3, 0x5a, 0x5b, 0x85, 0x24, 0x72, 0x7e, 0x71, 0xac, 0xb3, - 0xba, 0xe3, 0x6a, 0x7b, 0x43, 0x2d, 0x17, 0x7e, 0xd9, 0x1e, 0xe4, 0x24, - 0x58, 0x20, 0xfc, 0x05, 0xb4, 0xaf, 0x6f, 0xf7, 0x36, 0x84, 0xe6, 0x23, - 0xdb, 0xf3, 0x8d, 0x4a, 0xae, 0x05, 0x6f, 0x11, 0xf7, 0xc9, 0x6c, 0xb5, - 0x3e, 0xac, 0x0c, 0x6d, 0x57, 0x1b, 0x2a, 0xa5, 0xdb, 0xbb, 0xd5, 0x32, - 0xa6, 0xb7, 0x69, 0x59, 0x6f, 0x65, 0x88, 0x87, 0x13, 0x81, 0x30, 0x38, - 0xca, 0xe1, 0x3c, 0xa1, 0x40, 0x6d, 0xc3, 0x13, 0xf9, 0x98, 0x36, 0xca, - 0x6b, 0x6d, 0x53, 0xcb, 0x30, 0xcf, 0x94, 0x18, 0xa1, 0x6c, 0x5c, 0xbe, - 0xc2, 0x35, 0xc2, 0x59, 0x51, 0x90, 0xf3, 0x00, 0x37, 0xdd, 0xb9, 0xc4, - 0x01, 0xc4, 0x9b, 0x9d, 0x9b, 0xc2, 0x87, 0x7e, 0x10, 0x2c, 0xe3, 0x52, - 0xa9, 0xf9, 0xe1, 0xc2, 0xa2, 0x6b, 0x18, 0x89, 0xe9, 0xc8, 0xf2, 0x44, - 0x81, 0x1d, 0x83, 0x19, 0x71, 0x3a, 0xec, 0xc5, 0xb5, 0x50, 0x9f, 0x7d, - 0xd1, 0xc1, 0x53, 0xe3, 0x30, 0xf3, 0xe6, 0x7a, 0x05, 0x84, 0xfd, 0x3a, - 0xeb, 0xeb, 0x7e, 0xa1, 0xc0, 0xc6, 0xba, 0x73, 0x28, 0x1e, 0x6f, 0x16, - 0x5d, 0xcc, 0x20, 0x2c, 0xc4, 0x5b, 0x31, 0xd9, 0x2e, 0x0d, 0xc5, 0x9a, - 0xf5, 0xa5, 0x6e, 0xac, 0x43, 0x10, 0x6d, 0xf1, 0x27, 0xe9, 0x8c, 0x6e, - 0xfc, 0xd3, 0x9e, 0x91, 0xa3, 0x85, 0xb5, 0xe0, 0x4b, 0xe4, 0xbc, 0x18, - 0xe4, 0x14, 0x75, 0x70, 0xb2, 0x31, 0x2c, 0xb8, 0xad, 0x36, 0xd9, 0x71, - 0x03, 0x9d, 0x8d, 0x72, 0x9b, 0xac, 0x1c, 0x10, 0x3e, 0xa6, 0x4e, 0x78, - 0xf6, 0x99, 0xd8, 0x11, 0x0e, 0xc7, 0x14, 0xf3, 0x73, 0xcc, 0x4c, 0xea, - 0x31, 0x96, 0x2c, 0x5c, 0x4a, 0xc6, 0xa0, 0xa4, 0xb3, 0xf9, 0xa8, 0xc4, - 0x98, 0x6b, 0x5e, 0x34, 0x74, 0x65, 0x4a, 0x05, 0xdd, 0x48, 0x3d, 0x40, - 0x27, 0x9d, 0xb9, 0xd9, 0x89, 0x83, 0x25, 0x93, 0xb3, 0x4a, 0x2f, 0xdb, - 0xa1, 0xa9, 0x2e, 0x94, 0x07, 0xe9, 0x02, 0xeb, 0xf1, 0x12, 0x39, 0x7a, - 0x5e, 0x90, 0xd3, 0x6d, 0xd9, 0x55, 0x8a, 0xa1, 0xbb, 0xe7, 0xf5, 0x82, - 0x58, 0x94, 0xf2, 0x61, 0xef, 0x98, 0xf6, 0x92, 0x11, 0x57, 0x25, 0x67, - 0x1e, 0xca, 0x19, 0x0d, 0x1d, 0xed, 0xfd, 0x12, 0xae, 0x8a, 0xb1, 0x85, - 0x33, 0x2d, 0xde, 0xee, 0x2a, 0x49, 0x2e, 0x65, 0x3b, 0x34, 0x0f, 0xf8, - 0x7c, 0x59, 0x6f, 0x28, 0xaa, 0x55, 0xbc, 0x0c, 0x04, 0x2a, 0x64, 0x26, - 0x64, 0xfd, 0x96, 0x11, 0xc8, 0x7a, 0x69, 0x9e, 0x5c, 0x43, 0xaa, 0x69, - 0x6f, 0xaf, 0x55, 0x73, 0x53, 0x98, 0x64, 0xd4, 0xce, 0x9d, 0x9d, 0x48, - 0x5e, 0xca, 0xa5, 0xe0, 0xf5, 0x82, 0xbd, 0xe1, 0x72, 0xcc, 0xcb, 0x97, - 0x6d, 0x47, 0x35, 0xd4, 0x05, 0x3d, 0x5d, 0x90, 0x83, 0x2a, 0x55, 0xbe, - 0x9b, 0xe2, 0x4a, 0x8f, 0x31, 0x0b, 0x35, 0xa1, 0x96, 0x72, 0x84, 0x32, - 0x6e, 0x65, 0xf0, 0x0d, 0x4f, 0xad, 0xb5, 0x46, 0x0c, 0x0f, 0x8c, 0xbe, - 0x68, 0xb9, 0xab, 0x1a, 0x50, 0x7c, 0xb9, 0x9f, 0x8f, 0x58, 0x4f, 0xc0, - 0xe4, 0xb0, 0x9e, 0xcf, 0x05, 0xf2, 0x68, 0x3b, 0xba, 0x99, 0xf2, 0x9b, - 0x7d, 0x5b, 0x09, 0x6b, 0x56, 0x53, 0x36, 0x45, 0x58, 0x6d, 0xdb, 0x6b, - 0x48, 0xe9, 0x47, 0x89, 0x86, 0x81, 0x53, 0x37, 0x40, 0x87, 0x4c, 0x2c, - 0xbc, 0xb6, 0x3c, 0x9c, 0x2b, 0xdb, 0x9e, 0x23, 0x24, 0xbe, 0xc0, 0xc2, - 0x32, 0x3b, 0xaf, 0x3b, 0xa1, 0xd2, 0xf2, 0x39, 0xae, 0x41, 0xfd, 0x45, - 0xb3, 0x17, 0x73, 0x6b, 0xda, 0xe8, 0x6a, 0x5d, 0x54, 0xe7, 0x48, 0x85, - 0x8c, 0x21, 0xfa, 0x9b, 0x6c, 0x44, 0x5a, 0x5c, 0xa3, 0x94, 0xc4, 0xdc, - 0x50, 0xf1, 0x09, 0x18, 0xc8, 0x45, 0x79, 0xf2, 0xed, 0xbd, 0x05, 0x45, - 0x8a, 0xab, 0x6d, 0x79, 0x52, 0x13, 0xce, 0x55, 0x9b, 0xf5, 0x8d, 0x66, - 0x5b, 0x7b, 0xa1, 0x25, 0xe7, 0x1d, 0xdb, 0x1d, 0x36, 0x5a, 0x4f, 0x8d, - 0xeb, 0xad, 0x57, 0x33, 0x4d, 0x86, 0xef, 0x00, 0xd5, 0x99, 0xe3, 0x0c, - 0x18, 0x5e, 0x28, 0x3a, 0x5e, 0x2d, 0x9e, 0x1c, 0xd8, 0xad, 0x79, 0x39, - 0xd8, 0x66, 0x53, 0x2e, 0x8f, 0x8b, 0x1d, 0xb7, 0x39, 0xc5, 0x41, 0x13, - 0x55, 0xab, 0xed, 0xb9, 0x9d, 0x57, 0x2a, 0xd9, 0x08, 0xc0, 0x67, 0x19, - 0xc4, 0x59, 0x45, 0xda, 0x00, 0x2e, 0x0b, 0x8a, 0x16, 0x0e, 0xe1, 0x22, - 0x39, 0x57, 0x75, 0x06, 0x10, 0xd4, 0xc5, 0xb4, 0x45, 0xca, 0xf9, 0x6e, - 0xc6, 0x76, 0xaa, 0xe0, 0xf6, 0xec, 0x4a, 0xa5, 0x58, 0x61, 0x56, 0xf0, - 0x7d, 0x8a, 0x15, 0x3a, 0x8b, 0xc2, 0x55, 0x69, 0x49, 0x1d, 0x2e, 0xc2, - 0x5b, 0xaf, 0x3c, 0xd8, 0xc7, 0x55, 0x79, 0xb2, 0xb2, 0xe5, 0xd1, 0xa5, - 0x84, 0x46, 0x92, 0x77, 0x33, 0x5c, 0x1f, 0x96, 0xcc, 0x5a, 0x5c, 0xac, - 0xc6, 0x05, 0xd1, 0x49, 0xf1, 0x89, 0x11, 0x36, 0xdc, 0x65, 0x66, 0xc8, - 0x5b, 0x85, 0x95, 0x1a, 0x20, 0x5b, 0xb6, 0x89, 0xee, 0x09, 0x47, 0xa9, - 0x8a, 0x88, 0x54, 0x34, 0xaa, 0x2b, 0x16, 0x85, 0xcf, 0x0e, 0x05, 0x24, - 0x32, 0x71, 0x0c, 0x89, 0xb3, 0x8a, 0x48, 0x4a, 0x87, 0xa0, 0x9b, 0x39, - 0x56, 0xf0, 0x87, 0xde, 0x6e, 0xc3, 0xca, 0x00, 0xe1, 0xbc, 0x6b, 0x90, - 0x15, 0x2f, 0xb4, 0xc8, 0xb2, 0xa0, 0x17, 0x78, 0x12, 0x9d, 0x28, 0xbc, - 0x19, 0x6c, 0xcd, 0x0b, 0x5b, 0xc7, 0x3e, 0x2d, 0x68, 0xe3, 0xd2, 0x74, - 0xbd, 0xed, 0x47, 0xd7, 0x42, 0x05, 0xa2, 0x73, 0xd9, 0x35, 0x02, 0x39, - 0x64, 0x87, 0x50, 0x9e, 0xb5, 0xde, 0xe9, 0xc0, 0xed, 0xe6, 0x05, 0xcc, - 0xe3, 0x20, 0x60, 0xb4, 0xa5, 0x16, 0x17, 0xc5, 0xfc, 0xe8, 0xd1, 0xba, - 0x57, 0xf9, 0x9b, 0xd8, 0xbc, 0xf6, 0x57, 0xa3, 0x8d, 0xcf, 0xae, 0x21, - 0x34, 0xa6, 0x14, 0x11, 0xac, 0xde, 0x51, 0xd6, 0x16, 0xa7, 0xc2, 0xa3, - 0xc3, 0xf1, 0x81, 0xaa, 0x5d, 0x25, 0xa6, 0xd7, 0x7a, 0x22, 0x3d, 0x38, - 0xfe, 0x3e, 0x0f, 0x96, 0x5d, 0xbc, 0x27, 0x15, 0xdc, 0x58, 0xb7, 0x71, - 0xb5, 0xd0, 0x2c, 0xc7, 0x2a, 0xcf, 0x01, 0xbe, 0x99, 0x8d, 0xa7, 0x75, - 0x25, 0x44, 0x84, 0x22, 0xf3, 0x79, 0xcf, 0x1e, 0xae, 0x72, 0x98, 0x5d, - 0xda, 0x50, 0x60, 0xca, 0xc2, 0x3f, 0xc3, 0xe2, 0x75, 0xa4, 0x15, 0x38, - 0x9b, 0x03, 0xc1, 0x52, 0xc5, 0x46, 0xbb, 0xc8, 0xf3, 0x62, 0x15, 0x6c, - 0x8e, 0x49, 0x03, 0x82, 0xee, 0x61, 0x43, 0xcf, 0x22, 0x48, 0xef, 0x57, - 0x28, 0xbe, 0xab, 0x17, 0x3b, 0x8b, 0x38, 0x5e, 0xe4, 0xcd, 0x28, 0x90, - 0xcf, 0xf0, 0x0d, 0xbf, 0x22, 0x64, 0xd4, 0xf0, 0xae, 0x88, 0x40, 0x43, - 0xda, 0x00, 0x2f, 0x68, 0x97, 0x21, 0x42, 0xd7, 0x4b, 0x8f, 0x6b, 0x38, - 0xd8, 0xb8, 0xf3, 0x25, 0x55, 0xf8, 0x4d, 0x45, 0xec, 0x54, 0xf8, 0x5c, - 0x15, 0x5d, 0x7c, 0x40, 0x5a, 0x63, 0x1b, 0xe6, 0xc1, 0x7a, 0x5d, 0xce, - 0x12, 0x7f, 0x13, 0x4a, 0x7e, 0x18, 0x6e, 0x1d, 0x7d, 0x33, 0xc7, 0x4e, - 0xa1, 0xb2, 0x56, 0x24, 0xd8, 0x5a, 0xb6, 0x55, 0xb7, 0xe4, 0x2a, 0x35, - 0x50, 0x0a, 0xc5, 0x2a, 0xd3, 0xc5, 0x99, 0x50, 0x48, 0xa2, 0xc2, 0xd3, - 0xc8, 0x3d, 0xd7, 0xf8, 0xfa, 0x9a, 0xf3, 0x34, 0xbc, 0x16, 0xba, 0x81, - 0x16, 0x04, 0x77, 0x86, 0xd6, 0x7b, 0x33, 0xd0, 0x71, 0x67, 0x27, 0x19, - 0x57, 0xf8, 0x18, 0x8b, 0xb3, 0xc5, 0xfe, 0x8c, 0x58, 0xcc, 0xb6, 0xf4, - 0x56, 0x80, 0x7f, 0x22, 0x6d, 0xc0, 0xcd, 0x26, 0x59, 0xca, 0x1d, 0x6b, - 0xcf, 0x1b, 0x79, 0xbe, 0x2b, 0x21, 0x7a, 0x68, 0x76, 0xd8, 0xe9, 0x4c, - 0x29, 0x20, 0xfd, 0xe8, 0x34, 0xe4, 0x9a, 0xb4, 0xeb, 0x2d, 0x73, 0xd1, - 0x83, 0xa4, 0x07, 0xfd, 0x71, 0xfc, 0x85, 0x6b, 0xad, 0x96, 0xeb, 0xf9, - 0xb8, 0x8c, 0xb8, 0x55, 0x3f, 0x77, 0xe4, 0x2b, 0x9f, 0xf9, 0x94, 0x1d, - 0x0e, 0xec, 0x92, 0x3a, 0x88, 0x45, 0xc3, 0x74, 0xde, 0x51, 0x1f, 0x29, - 0x76, 0x1b, 0x1e, 0xed, 0x52, 0x36, 0x57, 0x90, 0x70, 0xd1, 0x66, 0x4b, - 0x24, 0x6f, 0x5d, 0x14, 0xdb, 0x4b, 0xc1, 0x96, 0x0b, 0xe8, 0x48, 0x6a, - 0xbc, 0x7e, 0x03, 0x1f, 0xb9, 0x73, 0x69, 0x5b, 0x94, 0xbb, 0x56, 0x65, - 0x2e, 0x40, 0xf0, 0x92, 0x94, 0x15, 0x15, 0xa9, 0xe8, 0x42, 0x82, 0xbb, - 0x94, 0xf2, 0xe8, 0xf5, 0x4a, 0xc5, 0x9c, 0x5d, 0x84, 0xbb, 0x7d, 0x37, - 0xbf, 0x44, 0xc3, 0xc0, 0xa4, 0x0b, 0x01, 0x73, 0xe0, 0x66, 0xb1, 0x0b, - 0x68, 0xae, 0x47, 0x8e, 0x6d, 0x5e, 0xf6, 0x23, 0xdf, 0x38, 0x33, 0x40, - 0xf0, 0xea, 0xb0, 0xbb, 0xe4, 0x7a, 0xe7, 0x5d, 0x23, 0x9b, 0x0e, 0x58, - 0x71, 0x79, 0xcd, 0x80, 0x45, 0xb2, 0x49, 0x2d, 0x97, 0xf4, 0x15, 0x22, - 0xee, 0x3b, 0x9d, 0x13, 0x99, 0xf1, 0xd8, 0xd1, 0xab, 0x28, 0xd7, 0x6b, - 0x57, 0xc1, 0xdb, 0x33, 0x7e, 0xf2, 0x16, 0xea, 0xbe, 0x83, 0x20, 0x7c, - 0xdc, 0x6f, 0x65, 0x47, 0x47, 0x76, 0xbb, 0x41, 0x35, 0xb0, 0x58, 0xe1, - 0x52, 0xb6, 0x3e, 0x7b, 0x02, 0xe9, 0xcf, 0xac, 0xac, 0xd9, 0x27, 0xa9, - 0x95, 0x77, 0x3a, 0x0c, 0x6d, 0x50, 0x36, 0xdb, 0x8e, 0x12, 0x8a, 0x77, - 0x3d, 0x1e, 0xeb, 0x47, 0x6c, 0x2c, 0x86, 0xcb, 0x1e, 0x72, 0x50, 0xf7, - 0x34, 0x5f, 0x0c, 0x70, 0xa3, 0x73, 0xea, 0x7e, 0x5f, 0xd9, 0xbb, 0x31, - 0x4e, 0x8d, 0x30, 0xd5, 0x1b, 0x74, 0x17, 0x1b, 0xa6, 0xb1, 0xac, 0x89, - 0xa3, 0x75, 0x76, 0x10, 0xd9, 0x10, 0xda, 0x3d, 0x3c, 0x5f, 0x1d, 0x39, - 0x29, 0x11, 0x3b, 0xa1, 0xd4, 0x36, 0xb6, 0x2c, 0xec, 0xb1, 0xd9, 0xbe, - 0x95, 0xe2, 0x58, 0xf1, 0x85, 0x9d, 0xe2, 0xe8, 0x14, 0x64, 0x28, 0x9d, - 0x4a, 0xad, 0x49, 0x11, 0x58, 0x8c, 0xb9, 0x59, 0x91, 0x41, 0xb8, 0x99, - 0xd3, 0x5c, 0x4a, 0x92, 0xcb, 0x70, 0x17, 0x84, 0xcc, 0x39, 0x5e, 0x94, - 0x71, 0x2e, 0xae, 0x61, 0xff, 0x22, 0xa4, 0x76, 0x93, 0xce, 0xd7, 0xd5, - 0x39, 0xce, 0xcd, 0x79, 0xdd, 0x5d, 0x51, 0x77, 0x9b, 0x6f, 0x93, 0xd6, - 0xdf, 0x10, 0xc7, 0x3d, 0xb4, 0x53, 0x65, 0x1e, 0x30, 0x74, 0xe8, 0x3c, - 0x71, 0xe9, 0x97, 0xdc, 0xa1, 0x57, 0x0d, 0xc4, 0x2a, 0x9d, 0x86, 0x41, - 0xf4, 0x00, 0x0b, 0xed, 0x95, 0xa3, 0x0a, 0x7b, 0x7b, 0x36, 0x0b, 0x0e, - 0xcb, 0xe4, 0x62, 0x5e, 0xe6, 0x8d, 0xbf, 0x3a, 0x44, 0x6b, 0xf8, 0xa8, - 0xf9, 0x2e, 0x23, 0xbb, 0x8b, 0xe5, 0xa2, 0x3e, 0xfa, 0xd7, 0xc3, 0x72, - 0xb3, 0x18, 0x13, 0x37, 0x1e, 0xdd, 0x1a, 0x6e, 0x2e, 0xa1, 0x7d, 0xd0, - 0xc5, 0xb9, 0x96, 0x18, 0xb9, 0x4e, 0x6f, 0xcf, 0x15, 0x43, 0x31, 0x33, - 0x60, 0x51, 0x0b, 0xc7, 0x15, 0x56, 0x52, 0x82, 0xc7, 0x6d, 0x3b, 0x0c, - 0xf1, 0x9d, 0x0f, 0x2b, 0xab, 0x1b, 0xd1, 0x7d, 0x7a, 0x26, 0x96, 0xda, - 0x21, 0xde, 0x9a, 0xc7, 0xcd, 0x92, 0x2f, 0xc8, 0x43, 0x2b, 0x2e, 0xfb, - 0xf0, 0x34, 0x3b, 0x5c, 0xd6, 0x1e, 0xd6, 0xf2, 0x17, 0xf1, 0x64, 0xef, - 0x47, 0x72, 0x39, 0x1e, 0x4a, 0x6a, 0xaf, 0x44, 0x95, 0x53, 0x44, 0x75, - 0x8b, 0x6a, 0x8b, 0x68, 0xbf, 0x97, 0xa4, 0x0d, 0x43, 0x19, 0xfc, 0x0e, - 0x39, 0x59, 0x17, 0x12, 0x1b, 0xaa, 0x2a, 0x60, 0x9a, 0x1e, 0xf8, 0x00, - 0x78, 0x7f, 0x60, 0x16, 0x17, 0x73, 0xd8, 0xae, 0x13, 0x1d, 0x3f, 0x63, - 0x71, 0x21, 0x55, 0xaa, 0x14, 0x1b, 0x44, 0x69, 0x6c, 0xaa, 0x6d, 0xb2, - 0x0f, 0x78, 0x76, 0xb7, 0x3b, 0x5b, 0xaa, 0xc6, 0x4a, 0x68, 0x48, 0xa4, - 0xdd, 0x86, 0x9f, 0x1d, 0x51, 0xd7, 0xcb, 0x4b, 0xda, 0x0a, 0x56, 0x56, - 0x9f, 0xf1, 0x9c, 0xee, 0x78, 0x84, 0x8f, 0x5c, 0xe6, 0xe1, 0x49, 0x4a, - 0xf4, 0xb9, 0x0b, 0x5f, 0xb9, 0x2c, 0x11, 0x65, 0x75, 0x97, 0x1e, 0x1a, - 0x62, 0x3d, 0xa0, 0x85, 0x21, 0xf2, 0xa3, 0x78, 0xd9, 0x81, 0xee, 0x43, - 0x3a, 0xdd, 0x23, 0xfa, 0xe2, 0x0c, 0xa1, 0x87, 0x33, 0x09, 0xd1, 0x18, - 0x31, 0x6f, 0x3c, 0x83, 0xd2, 0x80, 0xd0, 0x5d, 0x95, 0x28, 0x3a, 0xf2, - 0x0e, 0x42, 0xa4, 0x6b, 0xcf, 0xd4, 0x69, 0x79, 0x80, 0x5b, 0x45, 0xf2, - 0x2f, 0x7e, 0x1d, 0x52, 0x5b, 0xbe, 0xbb, 0xec, 0x44, 0xb5, 0x4a, 0xe1, - 0x84, 0x30, 0xaf, 0x5b, 0xef, 0x74, 0xd9, 0x12, 0xe2, 0x25, 0x65, 0x19, - 0x7b, 0xb6, 0x34, 0x35, 0xf8, 0xc0, 0xf7, 0x12, 0x10, 0x74, 0x37, 0x86, - 0xb5, 0xc6, 0x8f, 0x16, 0x2a, 0xdc, 0x1f, 0x4f, 0x0a, 0xa7, 0x97, 0x46, - 0xc8, 0x2e, 0x08, 0xce, 0x4a, 0x12, 0xe5, 0x08, 0xfc, 0x25, 0x8e, 0xe3, - 0x57, 0x43, 0x69, 0x92, 0xd1, 0xb6, 0x0e, 0x98, 0xe1, 0x26, 0xcd, 0xf5, - 0x5c, 0x71, 0x44, 0x2c, 0x71, 0x35, 0xc4, 0x6f, 0x03, 0xd8, 0x3e, 0xe9, - 0xd9, 0xdc, 0x86, 0x8e, 0x90, 0x18, 0xb6, 0xe1, 0x56, 0x34, 0xe0, 0xf9, - 0x75, 0x8a, 0xf5, 0xac, 0xd4, 0xcb, 0xce, 0x07, 0xe3, 0x54, 0xc1, 0x29, - 0x19, 0x1d, 0x75, 0xce, 0x1c, 0xa2, 0xb0, 0xf5, 0xaf, 0x86, 0x35, 0x03, - 0xa2, 0xc0, 0xea, 0x8c, 0x35, 0x5c, 0xcb, 0x55, 0xc8, 0xad, 0xb2, 0x9c, - 0xda, 0x28, 0xfd, 0x85, 0xb2, 0x87, 0xb4, 0x1d, 0x01, 0xd7, 0x15, 0x15, - 0xee, 0x62, 0x7a, 0x56, 0x2e, 0xf7, 0x31, 0xef, 0x23, 0x8b, 0x18, 0x4e, - 0x38, 0xf9, 0x3a, 0x37, 0x4f, 0x7b, 0x5c, 0xa8, 0xe1, 0x5a, 0x98, 0x61, - 0x0c, 0x99, 0x8a, 0x07, 0xc3, 0xbf, 0x88, 0x88, 0x57, 0xa8, 0xd7, 0x26, - 0x03, 0xec, 0x2c, 0xe7, 0x16, 0x43, 0x9b, 0xbc, 0x95, 0x92, 0xf3, 0x2d, - 0xb2, 0xcd, 0xc2, 0x50, 0xec, 0x96, 0x8a, 0x27, 0xe2, 0xd8, 0x35, 0x6d, - 0x8d, 0xb8, 0x11, 0x91, 0x8b, 0x61, 0x35, 0xb8, 0x62, 0x27, 0xfe, 0xad, - 0xee, 0x8a, 0x76, 0xe6, 0x0d, 0xa7, 0x4b, 0x3c, 0x42, 0x2e, 0xa9, 0xe1, - 0x7c, 0x8c, 0xf6, 0x05, 0x59, 0x09, 0xb2, 0x5c, 0x79, 0xee, 0x79, 0x5b, - 0x75, 0xb2, 0x17, 0xf9, 0x1e, 0x1a, 0xa9, 0x89, 0xe8, 0xec, 0x90, 0x20, - 0x10, 0xc2, 0x6a, 0x2f, 0xf2, 0x16, 0xb5, 0x10, 0xc2, 0x23, 0x3a, 0x04, - 0x57, 0xbc, 0xce, 0x8f, 0xec, 0x59, 0x17, 0xeb, 0x76, 0x35, 0xaf, 0x78, - 0x02, 0x02, 0x7e, 0x91, 0x37, 0x95, 0xc9, 0x3e, 0x4a, 0x33, 0x60, 0xfc, - 0xdc, 0x0b, 0x16, 0x60, 0x8e, 0xbd, 0x5f, 0xf3, 0x2c, 0xc1, 0xb0, 0x0d, - 0xc9, 0x5c, 0xa1, 0x78, 0x6d, 0xf2, 0x02, 0x91, 0x6f, 0x48, 0x42, 0xe4, - 0x00, 0xd0, 0x2d, 0x92, 0x07, 0x92, 0x65, 0x56, 0xb5, 0xdb, 0xc0, 0xa7, - 0x2e, 0x3b, 0x31, 0x1d, 0x0d, 0x9f, 0x66, 0x97, 0x86, 0xc9, 0x2f, 0xb4, - 0x1b, 0xf9, 0x96, 0x45, 0x09, 0x0e, 0xbb, 0xda, 0x83, 0x8a, 0x20, 0x3e, - 0x96, 0xc4, 0xa6, 0x6c, 0xad, 0x20, 0xb2, 0x8d, 0xe5, 0x11, 0x65, 0xd1, - 0x98, 0xc1, 0xc2, 0x0e, 0xdd, 0x6b, 0x47, 0x6b, 0x3e, 0xd6, 0xc7, 0x8d, - 0xe7, 0xd8, 0x80, 0xd2, 0xc9, 0xea, 0x88, 0x0d, 0xa9, 0xe8, 0x30, 0x17, - 0x46, 0x1e, 0x85, 0x90, 0xb5, 0xa9, 0xb1, 0xcd, 0x4e, 0x95, 0x57, 0x98, - 0x62, 0x4d, 0x90, 0x0b, 0x35, 0x3f, 0x87, 0xe4, 0x7c, 0xa5, 0x80, 0x20, - 0x74, 0xde, 0x5d, 0x17, 0x47, 0x8f, 0x3b, 0x0a, 0xac, 0x1a, 0x9d, 0xc5, - 0x42, 0xe2, 0xfa, 0xf3, 0xde, 0x39, 0x43, 0xd0, 0xcc, 0xac, 0x91, 0xc3, - 0x8a, 0xa8, 0xc7, 0xa4, 0x38, 0x02, 0x76, 0x5d, 0xa9, 0x6e, 0x35, 0x00, - 0xc7, 0xc0, 0xed, 0x0c, 0x94, 0x3e, 0xf1, 0x8b, 0x18, 0xa1, 0x63, 0x3b, - 0xf7, 0x57, 0xd7, 0x6d, 0xa6, 0xf5, 0x9a, 0xc1, 0x73, 0x2b, 0x4d, 0xe9, - 0x39, 0x11, 0x75, 0xb9, 0xd2, 0xac, 0x52, 0xb3, 0x0b, 0x57, 0x8b, 0x98, - 0xdc, 0x9a, 0x5a, 0xcc, 0x95, 0xb8, 0xb7, 0xf4, 0x74, 0x95, 0x8e, 0xc5, - 0x0d, 0x9e, 0x7b, 0xae, 0xbd, 0x68, 0x14, 0x60, 0x17, 0x16, 0xab, 0x96, - 0xaa, 0xa8, 0x7e, 0xb5, 0xdf, 0x27, 0x20, 0x28, 0xb1, 0x7a, 0x95, 0x4f, - 0x38, 0x87, 0x9e, 0x63, 0x5d, 0xc7, 0x0f, 0xc9, 0xb8, 0x55, 0x22, 0x1c, - 0x2e, 0x36, 0x9b, 0x93, 0x7e, 0x91, 0x71, 0xc2, 0xe6, 0x61, 0x43, 0x2c, - 0xb8, 0x90, 0x10, 0xac, 0x6e, 0xcd, 0x10, 0x9b, 0xbd, 0x4b, 0x9d, 0x40, - 0xaf, 0xdb, 0x20, 0x9a, 0xf1, 0x22, 0xbb, 0xdb, 0x8a, 0x20, 0x3a, 0x8b, - 0x4c, 0x11, 0x06, 0x46, 0x27, 0xda, 0x36, 0x6b, 0xab, 0x3e, 0xb0, 0x28, - 0x9f, 0x57, 0xfb, 0x9e, 0xd5, 0x48, 0x1a, 0xf6, 0x25, 0xe7, 0x5a, 0xf1, - 0xeb, 0x6b, 0x2c, 0xd9, 0x6b, 0x00, 0xa7, 0x12, 0x32, 0x72, 0x2f, 0x52, - 0x18, 0x10, 0x3c, 0x34, 0x13, 0x06, 0x79, 0x66, 0x6d, 0xba, 0xd3, 0x76, - 0x33, 0xdf, 0x0e, 0x1c, 0x95, 0x15, 0x16, 0x9c, 0x3a, 0x0b, 0x1e, 0x8b, - 0xc5, 0x95, 0xca, 0xaf, 0x00, 0x8d, 0xbb, 0x63, 0x8e, 0x96, 0xad, 0xcf, - 0xc2, 0x06, 0x51, 0x20, 0x12, 0x88, 0xd3, 0x3d, 0xb5, 0x43, 0xf1, 0xd3, - 0x6c, 0x0e, 0xea, 0x0d, 0x40, 0x31, 0x17, 0x46, 0xb7, 0xbe, 0xa6, 0xe9, - 0x2e, 0xa5, 0x1d, 0x45, 0x89, 0xc8, 0x40, 0x72, 0x7a, 0x32, 0x44, 0xc9, - 0x20, 0x36, 0x28, 0x60, 0x53, 0x2b, 0x01, 0x25, 0x2d, 0xf3, 0xb0, 0x12, - 0xe6, 0x68, 0x87, 0xce, 0xe5, 0x61, 0x26, 0x61, 0xf6, 0xd9, 0xd5, 0x15, - 0x77, 0xe0, 0xa3, 0xca, 0x65, 0x71, 0x3f, 0xd1, 0x3d, 0x45, 0x95, 0x14, - 0x03, 0x0e, 0x79, 0x54, 0x70, 0x47, 0xd7, 0x11, 0x41, 0xec, 0xb0, 0xe5, - 0xc7, 0x91, 0xa0, 0xe6, 0xd0, 0xb2, 0xb2, 0xf3, 0xaa, 0x3c, 0x65, 0x8e, - 0x2e, 0x04, 0xfc, 0xb5, 0x29, 0xdd, 0x23, 0x7d, 0x25, 0xe0, 0xd1, 0xe1, - 0xd6, 0xe3, 0xd1, 0xa0, 0xaa, 0xb9, 0x7f, 0xa4, 0x36, 0x42, 0x55, 0x32, - 0xe8, 0x6a, 0x95, 0xe9, 0x84, 0x3a, 0xf5, 0x2d, 0x0a, 0x27, 0x2d, 0xab, - 0xd6, 0x57, 0x39, 0x66, 0x5b, 0xb6, 0x12, 0xb8, 0x8d, 0x6f, 0x9b, 0x29, - 0x9b, 0x86, 0x33, 0x2a, 0xde, 0x8b, 0xb6, 0x74, 0xab, 0x73, 0x8c, 0xad, - 0xc6, 0x75, 0xaf, 0x50, 0xae, 0xe4, 0xbe, 0x70, 0x06, 0x7d, 0x11, 0xf1, - 0x6a, 0xde, 0xf5, 0x92, 0xe9, 0x74, 0xb9, 0xb6, 0xcf, 0x0d, 0x05, 0xd8, - 0x9b, 0xb3, 0xd6, 0xc2, 0x49, 0xe7, 0xc0, 0x43, 0x1f, 0x5c, 0x31, 0x7e, - 0x85, 0xb7, 0xda, 0x6e, 0x5b, 0x22, 0x7e, 0x6f, 0xed, 0xfa, 0x8d, 0x53, - 0x79, 0x4b, 0x90, 0x8a, 0xf9, 0x2a, 0x8f, 0x10, 0x82, 0x73, 0x62, 0x36, - 0x87, 0x6d, 0x7a, 0xcc, 0x04, 0x3f, 0x42, 0xab, 0x43, 0x6e, 0xee, 0x8d, - 0x2a, 0xb4, 0x21, 0x23, 0x3c, 0x5d, 0x34, 0xb7, 0x39, 0x81, 0xe8, 0x30, - 0x75, 0x02, 0x34, 0x68, 0x85, 0xb4, 0xf2, 0xb1, 0x8a, 0x9d, 0x13, 0x14, - 0xe4, 0x2c, 0xe5, 0xb9, 0xab, 0xcc, 0x03, 0xa2, 0x97, 0xdc, 0x73, 0x08, - 0xdb, 0x88, 0x58, 0x46, 0x46, 0xd6, 0x38, 0x29, 0x7b, 0x10, 0xd3, 0x49, - 0xbf, 0x66, 0x4a, 0x5d, 0x59, 0x0a, 0x4e, 0xe2, 0xb0, 0x65, 0x2f, 0x37, - 0x21, 0xde, 0x03, 0xa1, 0x46, 0xb3, 0x0e, 0x27, 0x9d, 0x7e, 0x16, 0xee, - 0x9b, 0x5b, 0xfd, 0xa4, 0x85, 0xcb, 0xed, 0xbe, 0x59, 0xa0, 0x39, 0x93, - 0x53, 0x91, 0x6a, 0x30, 0x14, 0x6e, 0xed, 0xd7, 0x72, 0xbd, 0x9e, 0x47, - 0xb3, 0x2b, 0xbd, 0x1e, 0x8e, 0xb3, 0x3c, 0x27, 0x05, 0xca, 0x5f, 0x44, - 0x2b, 0x8e, 0x17, 0x97, 0x8e, 0x97, 0xf2, 0x70, 0x57, 0x40, 0x27, 0x9b, - 0xb5, 0x36, 0x3c, 0x8f, 0x9e, 0x1b, 0xa9, 0xed, 0x97, 0x2b, 0x72, 0x8b, - 0x2f, 0x60, 0x24, 0xd9, 0x1c, 0xe5, 0xf9, 0xfa, 0x90, 0x86, 0xd3, 0xa5, - 0xb4, 0x88, 0x6f, 0x98, 0x45, 0x52, 0x1d, 0x58, 0xce, 0x58, 0x76, 0x4c, - 0xbe, 0xeb, 0x0b, 0x59, 0x72, 0x32, 0x0f, 0x09, 0xc8, 0x6c, 0xdf, 0xb4, - 0xe2, 0x2e, 0x32, 0x55, 0x7c, 0x1d, 0xab, 0x34, 0x8b, 0x5b, 0x84, 0x62, - 0x19, 0x46, 0x13, 0xb2, 0x2b, 0x85, 0x37, 0x2b, 0xae, 0x76, 0xec, 0xa0, - 0x10, 0xb4, 0x6a, 0xbc, 0x1e, 0x91, 0xd0, 0x54, 0x21, 0xa0, 0xa4, 0x6d, - 0x22, 0x26, 0x6b, 0xdc, 0xf7, 0x32, 0xfa, 0xc0, 0x0d, 0x37, 0x7d, 0x58, - 0x2a, 0x94, 0xb1, 0x8f, 0x96, 0x14, 0x85, 0xf0, 0x75, 0x79, 0x40, 0x3a, - 0x8e, 0x66, 0x13, 0xb1, 0xed, 0x53, 0xc2, 0x50, 0xb0, 0x2d, 0x74, 0xe1, - 0x48, 0xb9, 0xb4, 0x34, 0x48, 0x67, 0x6f, 0xb2, 0x7c, 0x6c, 0xcf, 0x8d, - 0x52, 0x71, 0xd4, 0xb5, 0x9d, 0xf9, 0xd0, 0x7c, 0x1b, 0x58, 0x69, 0x76, - 0x38, 0xa7, 0xec, 0x46, 0xde, 0x90, 0xfe, 0xa0, 0x49, 0x8e, 0x3b, 0xc9, - 0xbc, 0x32, 0x13, 0x25, 0xca, 0x48, 0x42, 0x66, 0x40, 0xb3, 0x06, 0xef, - 0xd7, 0xca, 0x96, 0xa6, 0xca, 0x25, 0xed, 0x19, 0xdb, 0x2b, 0x08, 0x40, - 0x3b, 0x88, 0xb0, 0xaf, 0xfe, 0x75, 0xbb, 0x67, 0x36, 0xcc, 0x11, 0x87, - 0x6f, 0xba, 0xd6, 0x2a, 0x7c, 0x6a, 0xbb, 0xb4, 0xec, 0x0f, 0x4b, 0x2f, - 0x2c, 0xae, 0x01, 0x92, 0x97, 0xbc, 0x7d, 0x9a, 0x71, 0x4b, 0xfc, 0x24, - 0xac, 0xbc, 0xb4, 0xb0, 0x2f, 0xb3, 0x66, 0xc6, 0xd0, 0xc9, 0xd6, 0x53, - 0x62, 0x67, 0x6b, 0x2d, 0x33, 0x6a, 0x27, 0x31, 0x97, 0x21, 0x8d, 0x70, - 0x6e, 0x9b, 0x5b, 0x4b, 0xfd, 0x7c, 0xdd, 0x69, 0xe5, 0x09, 0x27, 0x42, - 0x84, 0x6b, 0x77, 0xb9, 0x76, 0x4e, 0xcd, 0xec, 0x8c, 0xd0, 0x4d, 0xd0, - 0x08, 0x87, 0x9b, 0xec, 0xec, 0xd6, 0xd7, 0xfd, 0x1a, 0xc3, 0xac, 0xc5, - 0x0c, 0x0f, 0x36, 0x9b, 0xa2, 0xc3, 0x93, 0xdc, 0xb4, 0x36, 0x3a, 0xa2, - 0x0e, 0x21, 0x5e, 0xeb, 0xe8, 0x76, 0xdd, 0xdb, 0x6c, 0xba, 0x38, 0x41, - 0x0b, 0x98, 0xdf, 0x36, 0x42, 0xe4, 0xe0, 0xbe, 0x92, 0x68, 0x7a, 0x7e, - 0x5d, 0x61, 0xbd, 0x57, 0x66, 0x6b, 0xbd, 0x75, 0x85, 0x82, 0xdf, 0x86, - 0x06, 0x2a, 0x9f, 0xd8, 0x74, 0xa5, 0x16, 0xc0, 0xb5, 0x8f, 0x04, 0x08, - 0x4c, 0x7a, 0xc6, 0x3e, 0xd2, 0x9c, 0xc6, 0x53, 0x4e, 0x15, 0xa2, 0x6d, - 0x05, 0x95, 0x3c, 0x6a, 0x88, 0x09, 0x60, 0x15, 0x70, 0xff, 0x88, 0x7d, - 0x98, 0x75, 0x3d, 0x95, 0xee, 0x4b, 0x73, 0x4e, 0x25, 0xb6, 0x6b, 0xd3, - 0xc7, 0x4b, 0xe7, 0xcc, 0x5b, 0x99, 0x84, 0x8a, 0x0d, 0xb6, 0xae, 0xf0, - 0xbc, 0x6c, 0x22, 0x64, 0xb8, 0x36, 0xa1, 0x1c, 0x56, 0x02, 0xe6, 0x5d, - 0xe1, 0x0c, 0x01, 0xba, 0x17, 0x6f, 0x22, 0x7d, 0x0d, 0x03, 0x1f, 0x0d, - 0x51, 0x20, 0x42, 0x6e, 0xb7, 0x4b, 0x56, 0xe2, 0x48, 0x2e, 0x9e, 0x77, - 0xe9, 0xb1, 0x3d, 0xd0, 0x12, 0x0d, 0x2c, 0x08, 0x1f, 0x13, 0xa8, 0x19, - 0x9e, 0x8b, 0xa8, 0xca, 0xa1, 0x2b, 0x99, 0x8d, 0xdb, 0x26, 0x49, 0x5d, - 0x76, 0x2d, 0x24, 0x1a, 0x9c, 0x5c, 0xaa, 0x65, 0x29, 0xac, 0xc6, 0x53, - 0x61, 0x47, 0x99, 0x8f, 0x8d, 0x3b, 0x1c, 0x8a, 0xaa, 0x03, 0x1e, 0x23, - 0x90, 0x71, 0x88, 0xe7, 0x8e, 0xc4, 0x8c, 0x56, 0x8e, 0xcd, 0xac, 0x12, - 0xd0, 0x85, 0x8f, 0x42, 0xca, 0x39, 0x49, 0x48, 0x2f, 0x79, 0xa5, 0x35, - 0x5b, 0x2f, 0x8b, 0x04, 0x46, 0x3b, 0x6f, 0xb6, 0x0e, 0xe7, 0xb3, 0x5d, - 0x77, 0xa5, 0xb0, 0xe0, 0xa4, 0xd1, 0x27, 0xb1, 0x63, 0x9e, 0xfb, 0x74, - 0x14, 0xa7, 0x3e, 0x99, 0x6c, 0x7c, 0x62, 0x6d, 0x03, 0xb7, 0xe7, 0x22, - 0xd1, 0x25, 0x74, 0xbf, 0x51, 0x64, 0x08, 0x52, 0xf8, 0x85, 0x85, 0x07, - 0xa7, 0x51, 0xbe, 0x9c, 0xe7, 0xba, 0x09, 0x47, 0xce, 0x42, 0x45, 0xb7, - 0x27, 0x5b, 0xb4, 0x96, 0x87, 0x30, 0x88, 0x41, 0x30, 0x56, 0xf1, 0xa4, - 0x8a, 0x63, 0x27, 0xed, 0x40, 0xad, 0x20, 0x60, 0x0b, 0xe1, 0xb0, 0x95, - 0x60, 0xf1, 0x00, 0xed, 0xc4, 0x24, 0xd3, 0x4a, 0x6e, 0x3f, 0x6a, 0xcd, - 0xe2, 0xd2, 0x6c, 0x7c, 0x21, 0x42, 0xf0, 0x5e, 0x96, 0xd0, 0xd1, 0xf2, - 0x30, 0x7f, 0xce, 0xcf, 0xba, 0x11, 0x39, 0x2c, 0x25, 0xd3, 0x76, 0x0f, - 0xd4, 0xa0, 0xdc, 0xe5, 0x6f, 0x9c, 0x37, 0xd2, 0x4e, 0x0c, 0x5c, 0x2c, - 0x80, 0x62, 0x6a, 0x53, 0x42, 0x6d, 0x56, 0xfa, 0x97, 0x19, 0xb1, 0xe0, - 0x76, 0xb0, 0x86, 0x65, 0x94, 0x7c, 0x75, 0x00, 0xbf, 0x75, 0x19, 0xa8, - 0x88, 0xe3, 0xe4, 0x8b, 0x19, 0x01, 0x72, 0xc6, 0x4e, 0xa1, 0xcd, 0xb2, - 0x1d, 0xc7, 0x39, 0xa6, 0x9f, 0x9c, 0x63, 0xb2, 0x14, 0x62, 0x35, 0x5a, - 0x07, 0x9b, 0x9d, 0x90, 0xdd, 0xfa, 0x65, 0x71, 0x63, 0xb2, 0x72, 0x5d, - 0x7f, 0x81, 0x54, 0xa1, 0x46, 0x33, 0x14, 0x4b, 0x20, 0x28, 0x31, 0x40, - 0x3e, 0x48, 0x6d, 0x57, 0xe3, 0x52, 0x93, 0xe9, 0x6e, 0x41, 0x9a, 0xa5, - 0x7a, 0xb3, 0x8b, 0x22, 0xeb, 0x95, 0xf6, 0x76, 0x8d, 0x42, 0x04, 0x04, - 0xad, 0x88, 0x1e, 0xa3, 0x2f, 0xe7, 0xb0, 0x70, 0x62, 0x97, 0x73, 0xf0, - 0x6d, 0xbb, 0xbf, 0x9e, 0x62, 0xea, 0x38, 0x6e, 0x19, 0x20, 0xa3, 0x47, - 0x6b, 0x01, 0xe2, 0x1a, 0x87, 0x3a, 0xc0, 0xcb, 0x1d, 0xbe, 0xdc, 0xc8, - 0xf5, 0xe5, 0xbc, 0x2a, 0xda, 0x7e, 0x86, 0x5c, 0x76, 0x05, 0x11, 0x24, - 0x26, 0x81, 0x43, 0x3c, 0xbc, 0x01, 0xb2, 0x99, 0x89, 0xbc, 0xc0, 0x39, - 0xf3, 0x3c, 0x0b, 0xdb, 0x8a, 0xf5, 0x73, 0x7c, 0x7d, 0xde, 0xa9, 0xfc, - 0xbc, 0x82, 0xe0, 0x73, 0xd4, 0x15, 0xa3, 0x95, 0xc4, 0x64, 0x8b, 0xa5, - 0xb6, 0x12, 0x31, 0x6d, 0x31, 0xea, 0x65, 0xe2, 0xee, 0xf8, 0x1e, 0x21, - 0x1c, 0x3b, 0x54, 0x48, 0x8e, 0xa5, 0x66, 0x74, 0x75, 0x6d, 0xe7, 0x31, - 0x16, 0x0b, 0x0e, 0xb2, 0xda, 0xbb, 0x6b, 0x72, 0xb6, 0xca, 0xb7, 0x9d, - 0xd4, 0x2f, 0x8d, 0x23, 0xd0, 0x73, 0xfd, 0x3a, 0xe5, 0xa6, 0x01, 0xbe, - 0x25, 0xb9, 0x33, 0xcd, 0x70, 0xfb, 0x4b, 0xb6, 0xda, 0x83, 0xa8, 0xf6, - 0xc0, 0xd3, 0xaa, 0xd6, 0xa6, 0x35, 0x7d, 0x59, 0x59, 0x07, 0xc3, 0x32, - 0x6e, 0xb2, 0x10, 0x8e, 0x6c, 0xc3, 0x5d, 0x47, 0xdc, 0x82, 0x24, 0x2f, - 0xef, 0xd7, 0x49, 0x78, 0x42, 0x7d, 0x25, 0x92, 0x37, 0xc3, 0x69, 0xd1, - 0x31, 0xf1, 0x25, 0x52, 0x83, 0x39, 0x92, 0x0d, 0x8a, 0x15, 0x1b, 0x4d, - 0xcd, 0x72, 0xca, 0x38, 0x93, 0x8d, 0x6e, 0x21, 0x53, 0x5c, 0xc8, 0x88, - 0x8b, 0xb3, 0xa7, 0x62, 0x3a, 0x32, 0x6b, 0x74, 0x5e, 0x71, 0x92, 0x6a, - 0x1d, 0x2c, 0xe6, 0xc1, 0xba, 0x9c, 0xec, 0x50, 0x5d, 0x50, 0xea, 0xc1, - 0xf4, 0xe9, 0x99, 0x9c, 0xf6, 0x10, 0x77, 0x62, 0x7b, 0xad, 0x28, 0xce, - 0xba, 0x4c, 0xe5, 0xe2, 0x02, 0x55, 0x1d, 0x73, 0x55, 0xee, 0xc6, 0x7a, - 0x1f, 0xdf, 0x6c, 0xdb, 0x11, 0x64, 0xd3, 0xa5, 0xb3, 0x5c, 0x9f, 0xfa, - 0xe8, 0xb4, 0x52, 0x8f, 0xd3, 0x65, 0xd8, 0x67, 0x53, 0xd9, 0x6c, 0x83, - 0x40, 0x75, 0x2a, 0x63, 0x43, 0x2f, 0x36, 0x2e, 0x1a, 0xc5, 0x37, 0x7e, - 0xc9, 0xea, 0x98, 0xda, 0x56, 0xd5, 0x1d, 0xf6, 0x9d, 0x39, 0x96, 0x2c, - 0xbd, 0xc6, 0x77, 0x50, 0xc0, 0x2f, 0xea, 0x0a, 0x44, 0x3f, 0x43, 0x3d, - 0x13, 0x3b, 0x19, 0x2f, 0x92, 0xc8, 0x5e, 0xa8, 0x43, 0x0c, 0xec, 0xd9, - 0xbe, 0x53, 0xb6, 0x94, 0xdd, 0x1e, 0xcf, 0xb9, 0x7d, 0xb6, 0x91, 0x64, - 0x7b, 0x8a, 0xb4, 0xd8, 0xe1, 0x13, 0x86, 0x74, 0xad, 0x33, 0x4b, 0xe3, - 0x17, 0xfb, 0xd6, 0xa7, 0xbd, 0xc6, 0x5b, 0x48, 0xa3, 0x91, 0x5a, 0xab, - 0x71, 0x07, 0x82, 0xba, 0x2e, 0xce, 0x08, 0xc7, 0xd1, 0x5c, 0x47, 0xf2, - 0xce, 0x8a, 0xd2, 0x76, 0x08, 0xc2, 0x8e, 0xab, 0xcb, 0xfc, 0x72, 0x6b, - 0x5f, 0x60, 0xe7, 0x46, 0x9d, 0xd3, 0xb6, 0x4f, 0xad, 0x3a, 0x5a, 0xe4, - 0x83, 0x82, 0xdd, 0x84, 0x1e, 0x52, 0x69, 0x49, 0xd0, 0x94, 0x29, 0x7d, - 0xc0, 0xcd, 0x60, 0xa5, 0x26, 0xee, 0x76, 0x56, 0x1f, 0x7c, 0x74, 0x8d, - 0x52, 0xfc, 0x96, 0xdb, 0x89, 0x5c, 0xb6, 0x89, 0x8f, 0x6a, 0x18, 0x05, - 0xf3, 0x53, 0x42, 0x41, 0xb3, 0x7d, 0x6a, 0xaa, 0xa5, 0x79, 0x60, 0xf6, - 0x9d, 0x75, 0x3c, 0x69, 0xd8, 0x21, 0xeb, 0x96, 0xfc, 0x05, 0x39, 0x68, - 0x56, 0x1e, 0xe5, 0xc1, 0xd1, 0x4a, 0x19, 0xae, 0xe0, 0x61, 0x88, 0x3f, - 0xf9, 0x71, 0xa9, 0x84, 0x9a, 0x59, 0xf0, 0x05, 0x67, 0x07, 0xd7, 0x33, - 0x91, 0x05, 0x51, 0xe4, 0x7a, 0x7d, 0xc7, 0x54, 0x40, 0x29, 0xac, 0x78, - 0x6c, 0xce, 0x34, 0xe7, 0x5a, 0x65, 0x2d, 0x29, 0x83, 0xd7, 0x0f, 0x9d, - 0x0d, 0xed, 0xfa, 0x39, 0xcd, 0x22, 0x19, 0x7e, 0x15, 0x1b, 0xf7, 0x3c, - 0x4b, 0xe2, 0x71, 0x07, 0xb3, 0x69, 0x64, 0x6b, 0xe4, 0xb0, 0x66, 0xcb, - 0xa3, 0x59, 0xf5, 0x07, 0x66, 0x43, 0x92, 0xf0, 0x22, 0xdd, 0xf2, 0x78, - 0x3c, 0x2c, 0xfb, 0xcb, 0xb2, 0x0f, 0x4a, 0xfc, 0x92, 0x2f, 0x44, 0x77, - 0x27, 0x0b, 0xad, 0x56, 0x06, 0x7b, 0x6e, 0x26, 0x5c, 0xaa, 0x61, 0xe9, - 0xc3, 0x27, 0x71, 0x44, 0xe6, 0x30, 0x7a, 0x86, 0x60, 0xed, 0x7a, 0xed, - 0x0f, 0x9b, 0x3d, 0x9e, 0x05, 0xa8, 0xa3, 0xb7, 0x2b, 0xc5, 0xd9, 0xeb, - 0xa3, 0x39, 0x56, 0x8b, 0x20, 0x47, 0x0a, 0x05, 0x65, 0x5d, 0x79, 0x1f, - 0x5d, 0x0e, 0x22, 0x9c, 0x14, 0xc1, 0x01, 0xcd, 0x6d, 0x28, 0x82, 0x73, - 0x10, 0xbd, 0x9a, 0xd0, 0xc1, 0xbf, 0x2c, 0x28, 0xee, 0x2c, 0x58, 0xb0, - 0xcf, 0xa4, 0xfb, 0xd5, 0xde, 0x3c, 0x60, 0xd6, 0x55, 0x44, 0x7c, 0x86, - 0x6e, 0x03, 0x42, 0xc8, 0x9c, 0x35, 0xaa, 0x08, 0xc3, 0x9c, 0xb9, 0x82, - 0xb0, 0xcc, 0x71, 0xac, 0x4d, 0x05, 0x6c, 0xba, 0x58, 0x96, 0x9b, 0x39, - 0x5e, 0x55, 0x74, 0x60, 0x46, 0xc0, 0x06, 0x2f, 0xce, 0x46, 0xaa, 0xd9, - 0x20, 0x01, 0x37, 0x45, 0x13, 0x86, 0x0c, 0x96, 0xe9, 0x89, 0xd9, 0x66, - 0x7f, 0xa4, 0xb0, 0x8e, 0x13, 0xe5, 0xc4, 0x6e, 0xce, 0x8e, 0x2b, 0xc1, - 0x49, 0xed, 0x1d, 0xac, 0xb6, 0x66, 0x41, 0xd6, 0x33, 0x5f, 0x56, 0x3e, - 0xbb, 0x58, 0xca, 0x56, 0x79, 0xc1, 0x47, 0x17, 0x1e, 0xca, 0x81, 0xf6, - 0x9b, 0x2d, 0x82, 0xe3, 0x30, 0x65, 0x36, 0x9a, 0x24, 0xf0, 0xc7, 0x4b, - 0xb2, 0x32, 0xf0, 0x16, 0x44, 0x47, 0x97, 0x19, 0x9c, 0x2e, 0xe6, 0x20, - 0x12, 0x6f, 0x66, 0xdd, 0xbc, 0xdc, 0xb4, 0xca, 0xe2, 0x02, 0xd2, 0xc7, - 0x33, 0x88, 0x4f, 0x23, 0x0f, 0xf2, 0x98, 0x15, 0x92, 0x00, 0x83, 0x9a, - 0x2b, 0xf3, 0x4a, 0x83, 0xb3, 0x45, 0x59, 0x1e, 0xc9, 0xae, 0x59, 0x17, - 0x69, 0x5e, 0xed, 0xb6, 0x84, 0xe2, 0x02, 0x8f, 0x06, 0xb2, 0xcf, 0x38, - 0xeb, 0xe5, 0xf5, 0x8c, 0x59, 0x2c, 0x93, 0x79, 0x8e, 0xcf, 0xf1, 0x55, - 0x1d, 0xcf, 0xad, 0x20, 0xa9, 0x35, 0xdb, 0xb6, 0xf0, 0x76, 0x6e, 0xf4, - 0x69, 0x30, 0x50, 0xf3, 0xa3, 0x36, 0x5e, 0x0c, 0xce, 0x32, 0xdd, 0xfe, - 0x60, 0xe9, 0xeb, 0x9a, 0x4e, 0xe8, 0xd5, 0x56, 0x8b, 0x5a, 0xeb, 0x08, - 0xe7, 0xab, 0xd2, 0xf1, 0xfd, 0xb8, 0x18, 0x3c, 0xd0, 0x7f, 0xc3, 0x5a, - 0x37, 0x94, 0xd1, 0x2a, 0x97, 0xfe, 0x48, 0x4a, 0x75, 0x97, 0xd5, 0x55, - 0x48, 0x8d, 0x4a, 0xae, 0x13, 0x3b, 0xa0, 0x4d, 0xc9, 0x11, 0x36, 0x25, - 0x84, 0x56, 0x56, 0xae, 0x81, 0x22, 0xc7, 0x89, 0xef, 0xcd, 0x46, 0x32, - 0x91, 0x0a, 0x5d, 0x2c, 0x46, 0xb8, 0x6f, 0x2d, 0x11, 0x9f, 0xcd, 0x41, - 0xb8, 0x68, 0x5a, 0x91, 0x37, 0x8b, 0x2a, 0x6d, 0x59, 0xb0, 0x4d, 0x4a, - 0x74, 0x50, 0x53, 0x39, 0x37, 0x9e, 0xda, 0x7b, 0xb4, 0x6b, 0x54, 0x72, - 0xb0, 0x7d, 0x4b, 0xaa, 0xf9, 0x2a, 0x5b, 0x25, 0xf0, 0xbe, 0x5b, 0x46, - 0xfb, 0x0c, 0x77, 0xe4, 0x46, 0xcd, 0x1d, 0xba, 0xa3, 0x9a, 0xd5, 0x61, - 0xa3, 0xf1, 0xa8, 0x65, 0x36, 0x25, 0x6e, 0xc0, 0x8d, 0x9c, 0x22, 0x0e, - 0x13, 0xf2, 0x7b, 0x38, 0x19, 0xd7, 0xd4, 0xf5, 0x74, 0x3e, 0x1e, 0x4e, - 0x47, 0x77, 0x36, 0x9e, 0x0f, 0x57, 0x87, 0x4e, 0x30, 0xc4, 0x90, 0xca, - 0xd3, 0xc1, 0x30, 0xa2, 0x32, 0x70, 0xf4, 0xc3, 0x50, 0x1e, 0xcc, 0xae, - 0x67, 0x75, 0x96, 0xb9, 0x22, 0xeb, 0x23, 0xb5, 0xf2, 0x69, 0xf1, 0xc4, - 0x79, 0xab, 0xf1, 0xec, 0x40, 0xd7, 0x36, 0x1a, 0xfb, 0x26, 0x4d, 0x5d, - 0x63, 0x26, 0x94, 0x55, 0x3c, 0xe2, 0xcd, 0x12, 0x4d, 0xfb, 0x21, 0x87, - 0xbd, 0x64, 0x7d, 0x74, 0x64, 0xd7, 0x9b, 0xaf, 0x29, 0x67, 0x7e, 0x74, - 0x1a, 0x9f, 0x2f, 0xcf, 0x5e, 0x5d, 0xe9, 0x47, 0x2b, 0xc9, 0xcf, 0xaa, - 0x01, 0x5f, 0x75, 0x80, 0x2b, 0x8a, 0x08, 0x0c, 0x22, 0xb4, 0x38, 0xc8, - 0xe1, 0x10, 0x69, 0x14, 0x2a, 0x81, 0x99, 0xbb, 0x47, 0x4a, 0xc4, 0x6d, - 0x01, 0x00, 0x15, 0x23, 0xc7, 0xd8, 0xaf, 0xb7, 0x26, 0xc8, 0x14, 0x35, - 0x10, 0xc9, 0x09, 0x3d, 0x0b, 0x02, 0x55, 0xd5, 0xbb, 0x9e, 0x4b, 0x96, - 0xf7, 0x58, 0xee, 0xb4, 0x33, 0x69, 0x74, 0xa5, 0x98, 0x77, 0x5e, 0x6f, - 0x05, 0x67, 0x6f, 0x39, 0xb1, 0x78, 0x9a, 0x5b, 0x9d, 0xea, 0x2f, 0x38, - 0x03, 0xda, 0x2e, 0x01, 0xa5, 0xe0, 0x52, 0x53, 0x76, 0xe2, 0xb9, 0x9c, - 0xc9, 0x6c, 0xb0, 0x38, 0x5a, 0xc6, 0xd8, 0x00, 0x8b, 0xaf, 0xf0, 0x2b, - 0x4e, 0x3d, 0xfb, 0x76, 0xe4, 0x6e, 0xd6, 0x97, 0xea, 0x70, 0x5a, 0xaf, - 0xdb, 0x99, 0x72, 0xd8, 0xef, 0x4a, 0xd4, 0x69, 0xe6, 0xa6, 0xce, 0xdf, - 0xfa, 0xa3, 0xc2, 0x2a, 0x90, 0xc8, 0x7e, 0xd9, 0xa4, 0x32, 0x3e, 0x47, - 0x0a, 0x5f, 0xdc, 0x84, 0xab, 0x56, 0x4a, 0x17, 0xb2, 0x23, 0x35, 0xe5, - 0x72, 0xe9, 0x9b, 0x77, 0xfa, 0xa4, 0x27, 0xab, 0x0b, 0xa5, 0xd9, 0x4c, - 0xd2, 0x81, 0x51, 0x83, 0x85, 0xcb, 0x80, 0xab, 0x40, 0x97, 0x12, 0x9e, - 0x33, 0x18, 0x21, 0xd0, 0x6b, 0x37, 0x17, 0x86, 0xa4, 0xb9, 0xe9, 0x71, - 0x2a, 0xe7, 0x72, 0x2e, 0xda, 0xbb, 0xcc, 0x5e, 0x66, 0x2c, 0xe7, 0xa6, - 0xd0, 0x38, 0x36, 0x3b, 0xed, 0x70, 0x3c, 0xce, 0x90, 0x7d, 0x69, 0xec, - 0x5d, 0x99, 0xd2, 0x13, 0xc7, 0xd9, 0x2f, 0x70, 0x3d, 0xd9, 0xd0, 0x35, - 0xbf, 0xb9, 0x26, 0xd1, 0x86, 0x65, 0x87, 0x0e, 0x46, 0xda, 0xf9, 0x81, - 0x9d, 0xcd, 0x8f, 0xfd, 0x65, 0xb5, 0xe0, 0xf8, 0x8b, 0xa9, 0x9a, 0x48, - 0x6b, 0xee, 0x7d, 0x91, 0x6d, 0x34, 0x15, 0x86, 0x15, 0xb8, 0x28, 0x77, - 0x91, 0x8c, 0x2f, 0x49, 0x7e, 0xed, 0xbb, 0xb3, 0x5d, 0xa6, 0x98, 0x80, - 0xb1, 0x1b, 0x7a, 0x3e, 0xab, 0x54, 0x44, 0x31, 0xd3, 0x92, 0x71, 0x37, - 0xc3, 0x51, 0x22, 0x6c, 0x2b, 0x4b, 0xf9, 0x58, 0x75, 0x16, 0x4b, 0x04, - 0x71, 0x0e, 0x9e, 0x28, 0x6f, 0xe6, 0x08, 0x79, 0x72, 0x16, 0x3b, 0x72, - 0x79, 0x36, 0x66, 0x31, 0x96, 0x9d, 0x09, 0xd7, 0xca, 0xe4, 0x9c, 0x05, - 0x3a, 0x6e, 0x86, 0xd5, 0x2e, 0xbe, 0xce, 0x87, 0x9a, 0xd5, 0x97, 0xac, - 0x37, 0x74, 0xbd, 0x6d, 0xcb, 0xd0, 0xb9, 0xc8, 0xae, 0x9b, 0xbc, 0x49, - 0x9c, 0x9d, 0x0c, 0x89, 0xfe, 0x4c, 0xb1, 0x06, 0xf7, 0xb0, 0x4e, 0xab, - 0xeb, 0x7e, 0x53, 0xc3, 0x73, 0x6a, 0x46, 0x1c, 0x81, 0xf2, 0x45, 0x9c, - 0xb8, 0xe1, 0xbb, 0xb5, 0x38, 0xd1, 0x66, 0x96, 0x6f, 0xd7, 0x9a, 0x76, - 0x64, 0xf9, 0x4d, 0x20, 0xa2, 0x11, 0x85, 0x6f, 0xc3, 0x64, 0x11, 0x2a, - 0xc6, 0x7a, 0x51, 0xf1, 0xda, 0x72, 0x77, 0x46, 0x79, 0xdb, 0xa8, 0x2c, - 0xb3, 0xa8, 0x2b, 0x67, 0x1b, 0x55, 0x1c, 0xaf, 0xed, 0x1b, 0xdd, 0xb1, - 0xa0, 0x6d, 0x66, 0xb5, 0x51, 0x01, 0xc2, 0x9d, 0x69, 0x68, 0x81, 0x5f, - 0x2e, 0x8a, 0x56, 0xb7, 0xbb, 0x7a, 0x64, 0x57, 0x5a, 0x7c, 0x4d, 0x62, - 0x2d, 0xa8, 0xf7, 0x80, 0xf3, 0x26, 0x34, 0x88, 0x9b, 0x45, 0x9f, 0x63, - 0x8b, 0xa4, 0x94, 0x85, 0xe1, 0x94, 0xc8, 0x76, 0xa0, 0x81, 0x18, 0x7f, - 0x77, 0xcc, 0x92, 0xe1, 0xa2, 0x81, 0xe0, 0x79, 0x71, 0xee, 0x53, 0x72, - 0xe5, 0x8e, 0xec, 0x8e, 0x5d, 0xef, 0x95, 0x5a, 0x31, 0x38, 0x85, 0xcd, - 0x28, 0x88, 0x50, 0x52, 0x1c, 0xd8, 0xca, 0xab, 0x2e, 0x5e, 0xb2, 0x04, - 0x91, 0xbb, 0x68, 0x68, 0x1d, 0x76, 0x1e, 0xa3, 0xf0, 0xd1, 0xdd, 0xef, - 0x7c, 0x0f, 0xc1, 0x94, 0x94, 0xd9, 0x78, 0x83, 0x3c, 0xd9, 0x53, 0x15, - 0xdd, 0xb3, 0x8e, 0x2f, 0x58, 0xfc, 0x0e, 0x92, 0x2c, 0xff, 0x68, 0x90, - 0xe2, 0x3a, 0x26, 0xe9, 0x0d, 0x48, 0xd0, 0xcc, 0xbe, 0xe7, 0x7a, 0xc1, - 0xdd, 0x74, 0xc0, 0xb8, 0x00, 0x43, 0x50, 0xf7, 0x91, 0xe3, 0xc1, 0x6e, - 0xb8, 0xe3, 0x09, 0x55, 0x26, 0x71, 0x76, 0x89, 0xcc, 0xe9, 0x25, 0xee, - 0x30, 0x79, 0x57, 0x1f, 0x40, 0xfe, 0x8c, 0x68, 0xa3, 0x97, 0x14, 0x68, - 0x06, 0x04, 0x7f, 0x88, 0x48, 0xdd, 0xd4, 0xc6, 0x45, 0xac, 0x9a, 0xf8, - 0xca, 0xd9, 0x20, 0x19, 0xdc, 0x41, 0xfe, 0x71, 0x00, 0x79, 0x45, 0xd8, - 0x1d, 0x7d, 0xf8, 0x7c, 0x25, 0x0c, 0x5f, 0x66, 0x01, 0x57, 0x33, 0x61, - 0x63, 0x64, 0x69, 0xcb, 0x29, 0xfc, 0xe9, 0xd0, 0x1c, 0xd2, 0x82, 0xce, - 0xc2, 0xe1, 0x80, 0x56, 0x3d, 0x54, 0x11, 0xe7, 0x4d, 0xbb, 0xd6, 0x53, - 0x4b, 0x2c, 0x6b, 0x57, 0x37, 0x86, 0xb4, 0x71, 0xaa, 0x22, 0xc0, 0x6a, - 0x82, 0xae, 0xd9, 0x1d, 0xb7, 0xcd, 0x4e, 0xe9, 0x32, 0xda, 0x78, 0x90, - 0x2e, 0x38, 0x61, 0x96, 0xdb, 0xcc, 0x62, 0x51, 0xeb, 0x57, 0x66, 0x11, - 0x43, 0xaa, 0x21, 0x2e, 0x2a, 0xf9, 0xcc, 0x58, 0x3c, 0x09, 0x3c, 0xee, - 0x61, 0xc1, 0xf2, 0x97, 0x30, 0xe0, 0x08, 0x58, 0x87, 0xd7, 0x32, 0x1f, - 0xdd, 0xe4, 0xb3, 0x14, 0xa4, 0x94, 0x08, 0x20, 0xf7, 0xc2, 0x36, 0xd8, - 0x25, 0xd4, 0xd9, 0xbd, 0xad, 0x47, 0xc3, 0xb5, 0x3b, 0x23, 0x33, 0xa1, - 0x39, 0xd5, 0xd5, 0x0a, 0x66, 0x10, 0x6a, 0x04, 0x76, 0xfc, 0x9c, 0xa4, - 0x95, 0xbc, 0xdd, 0x49, 0xfb, 0x45, 0x83, 0x79, 0x50, 0xe4, 0x1e, 0x65, - 0xe4, 0x88, 0xce, 0xd5, 0x5d, 0x6b, 0xd2, 0x8b, 0x9e, 0xda, 0xc3, 0x73, - 0xce, 0x06, 0xa8, 0x93, 0x92, 0x63, 0x1f, 0xad, 0x13, 0x3c, 0x38, 0x55, - 0x74, 0x0a, 0x31, 0xc2, 0x24, 0x3c, 0x68, 0xd5, 0x9f, 0x17, 0x30, 0x3b, - 0x93, 0xc2, 0x05, 0x8f, 0xac, 0x17, 0x17, 0xce, 0xbd, 0x2e, 0xf6, 0x37, - 0xdb, 0x05, 0x43, 0x8d, 0x32, 0x66, 0xc3, 0xf1, 0x78, 0x2a, 0xe9, 0xab, - 0xd4, 0x58, 0xfc, 0xa6, 0x55, 0x17, 0xcd, 0x9c, 0xa8, 0x29, 0x67, 0xbf, - 0x3d, 0x5c, 0x75, 0x67, 0xdd, 0x1d, 0x0d, 0x7a, 0x04, 0x69, 0x3d, 0xc8, - 0x6b, 0x57, 0x2b, 0xca, 0xf0, 0x0b, 0x38, 0x0a, 0x97, 0x11, 0x1d, 0x64, - 0x50, 0x24, 0x1d, 0xce, 0x82, 0x80, 0x6c, 0x13, 0x7a, 0xc4, 0xc5, 0x50, - 0xbe, 0xca, 0xe9, 0xca, 0x39, 0x1e, 0x29, 0xe0, 0x00, 0x09, 0xd9, 0x52, - 0x42, 0x5d, 0x8b, 0xa1, 0x7c, 0x91, 0xc2, 0x4d, 0x15, 0xb0, 0xc5, 0x1e, - 0x35, 0xda, 0xdd, 0x9e, 0xd5, 0x42, 0xfe, 0x1c, 0x6b, 0xab, 0xa5, 0xad, - 0x7a, 0x84, 0x7b, 0xc4, 0xe6, 0x59, 0x62, 0xba, 0x6b, 0x38, 0x13, 0x81, - 0xd3, 0x72, 0x75, 0x9f, 0x31, 0x96, 0x5b, 0xd4, 0x3c, 0x0a, 0x26, 0x15, - 0x87, 0xfc, 0x91, 0x4b, 0xf5, 0x7a, 0xb3, 0x47, 0x57, 0xf0, 0x76, 0x33, - 0xc3, 0x42, 0x89, 0x3d, 0xcc, 0x28, 0xa9, 0x69, 0x2c, 0x11, 0xc8, 0xad, - 0xbb, 0xe5, 0x4a, 0x61, 0x5f, 0x99, 0x48, 0x9f, 0x67, 0x03, 0x92, 0x72, - 0xd1, 0x74, 0xdd, 0xa3, 0x1d, 0x81, 0xfa, 0x9e, 0x15, 0x67, 0x82, 0x7e, - 0xe5, 0x37, 0x92, 0xdf, 0x90, 0x9e, 0x99, 0x28, 0x87, 0x8d, 0xb5, 0x27, - 0x97, 0xaa, 0x73, 0x56, 0x27, 0x1f, 0x7a, 0x71, 0x15, 0x46, 0x1d, 0x31, - 0x7c, 0x2f, 0xb7, 0x17, 0xe8, 0x94, 0xd1, 0x1a, 0x7a, 0x2a, 0x21, 0xe4, - 0x78, 0x2c, 0x71, 0x64, 0x99, 0x06, 0x87, 0xda, 0xc0, 0x4a, 0xaf, 0x8a, - 0x5b, 0x63, 0x3c, 0x74, 0x9a, 0x92, 0x15, 0xd7, 0x05, 0x6a, 0xf6, 0xd2, - 0xd8, 0xda, 0x2b, 0xc5, 0xe8, 0x41, 0x02, 0xa7, 0x19, 0x20, 0x4c, 0xf7, - 0xb7, 0xc8, 0xa5, 0x81, 0x62, 0x7e, 0x7d, 0xa8, 0x62, 0xf2, 0xca, 0x12, - 0xba, 0xc8, 0xe2, 0x78, 0x82, 0x06, 0x24, 0x23, 0xe1, 0xda, 0xb2, 0xd3, - 0x4c, 0xc3, 0x57, 0xf2, 0xb9, 0xd7, 0x55, 0xc8, 0x99, 0x62, 0x66, 0x1a, - 0xa2, 0x2f, 0x36, 0x92, 0x8b, 0xec, 0x0b, 0x16, 0x78, 0xd2, 0xa3, 0xe1, - 0x38, 0xf0, 0x41, 0x31, 0x23, 0xe7, 0xaa, 0xd4, 0x3b, 0x63, 0xdd, 0x21, - 0x26, 0xa3, 0x1f, 0xac, 0x91, 0xba, 0x0e, 0x2b, 0xd7, 0x0b, 0x4b, 0xa7, - 0x24, 0x3a, 0xc7, 0xab, 0xf0, 0x52, 0x6d, 0x76, 0x28, 0x12, 0xca, 0xa9, - 0x89, 0xd6, 0x55, 0x70, 0xd1, 0x57, 0x24, 0xa9, 0x56, 0xba, 0x2c, 0xda, - 0x56, 0x6e, 0x32, 0xc3, 0x61, 0xe6, 0xa2, 0xda, 0x6a, 0x41, 0xca, 0x27, - 0x0f, 0xe8, 0xc0, 0xa8, 0x09, 0x70, 0x5c, 0x51, 0xea, 0xae, 0x47, 0x3c, - 0x7b, 0x96, 0xc1, 0xed, 0x2e, 0xd4, 0xe3, 0x3c, 0xce, 0x49, 0xfd, 0xb4, - 0x12, 0xed, 0xb9, 0x45, 0x6b, 0xb3, 0xb9, 0x02, 0xa1, 0x5a, 0xbd, 0x5b, - 0x09, 0x1e, 0xa7, 0x28, 0x73, 0x90, 0x1d, 0x17, 0x86, 0xc8, 0xed, 0x4d, - 0x0f, 0xc7, 0xb0, 0xcd, 0xec, 0xb0, 0xb4, 0x37, 0x8e, 0xc7, 0xa9, 0x9a, - 0x84, 0xcc, 0x3b, 0xb6, 0x5c, 0xd5, 0x3e, 0xd4, 0x43, 0x7a, 0x2a, 0x5e, - 0x2c, 0x10, 0x4d, 0x8c, 0x5d, 0xce, 0x18, 0x4e, 0x2b, 0x52, 0x2b, 0x31, - 0xd1, 0xd0, 0xc3, 0x1c, 0x11, 0xc4, 0x84, 0xe1, 0xfc, 0xd3, 0x78, 0x39, - 0x92, 0x7c, 0x9a, 0x26, 0xac, 0xc0, 0x63, 0xf5, 0xa9, 0xf7, 0x58, 0x92, - 0x14, 0x3d, 0xa4, 0xed, 0x8d, 0xeb, 0xbe, 0xaf, 0xb8, 0x41, 0x75, 0x57, - 0x2a, 0x59, 0x87, 0xc3, 0x86, 0xa8, 0xc7, 0x13, 0xab, 0x9e, 0x37, 0xca, - 0x31, 0xc1, 0x5a, 0x81, 0x29, 0x7d, 0x08, 0x32, 0x7a, 0x15, 0xc6, 0xc6, - 0x8b, 0xe4, 0x38, 0xd8, 0x78, 0xb0, 0x96, 0xe2, 0x89, 0xe9, 0x82, 0x75, - 0xbd, 0x01, 0x9d, 0xbf, 0x5c, 0xb6, 0xdb, 0x36, 0xd9, 0x9f, 0xad, 0x26, - 0x3e, 0x3b, 0x8b, 0x4c, 0xe9, 0x3b, 0x4c, 0xbf, 0x8a, 0x6e, 0x93, 0xcb, - 0xb6, 0x04, 0x79, 0xfb, 0xea, 0x6a, 0xe9, 0xa7, 0xaa, 0x42, 0x71, 0x6a, - 0xd0, 0xcd, 0x7a, 0x7b, 0x66, 0xa0, 0x34, 0x4a, 0xb3, 0x4b, 0x7d, 0x4a, - 0xaf, 0x23, 0xe1, 0xc3, 0x30, 0x91, 0x55, 0x74, 0x61, 0x9c, 0x97, 0x14, - 0xe0, 0x64, 0x83, 0x60, 0xfe, 0xd6, 0x22, 0x3d, 0x24, 0x95, 0x4e, 0x7b, - 0x2a, 0xc9, 0x97, 0xe4, 0x99, 0x2b, 0x12, 0x33, 0x62, 0x49, 0xa1, 0x04, - 0x28, 0xaf, 0x58, 0x15, 0xda, 0xae, 0x5c, 0xbb, 0x42, 0x66, 0xa6, 0xba, - 0x6e, 0xdc, 0x71, 0xdc, 0x65, 0xdd, 0x75, 0xed, 0xa0, 0x6e, 0xe8, 0x98, - 0x57, 0x4c, 0x70, 0x76, 0xbb, 0xad, 0xc1, 0xcc, 0x20, 0xba, 0xf7, 0xa0, - 0xd0, 0x98, 0xcf, 0x36, 0x10, 0xe5, 0x35, 0x1b, 0xa5, 0x6d, 0x87, 0x83, - 0xe8, 0xb8, 0x3c, 0x90, 0x6c, 0xc7, 0x3d, 0x7b, 0xd2, 0xe6, 0x9c, 0x57, - 0x03, 0xa3, 0x21, 0x51, 0xdc, 0x22, 0xdc, 0x0c, 0x81, 0x96, 0xbb, 0x14, - 0x5a, 0xa7, 0x8a, 0xcd, 0xed, 0x5a, 0x57, 0xca, 0x95, 0x13, 0xa0, 0xaa, - 0xdf, 0x47, 0xde, 0x95, 0x13, 0x9a, 0x2b, 0x2b, 0x34, 0x0c, 0x69, 0x59, - 0x3e, 0xa2, 0x27, 0x86, 0x05, 0x5d, 0x3d, 0xfb, 0x72, 0xd9, 0xc1, 0xd8, - 0x2e, 0x4b, 0x99, 0x3a, 0xef, 0x23, 0x12, 0xbb, 0xd2, 0x24, 0xd6, 0xc9, - 0xe4, 0x52, 0x13, 0xad, 0x79, 0x82, 0xed, 0xbc, 0x4d, 0x03, 0x42, 0x1f, - 0x39, 0xaa, 0x77, 0x6a, 0x09, 0x9d, 0x1b, 0x25, 0xc7, 0x2b, 0x81, 0x68, - 0x56, 0xc6, 0x50, 0x59, 0x7b, 0xd5, 0xda, 0xcc, 0x61, 0x19, 0xb9, 0x1c, - 0xf9, 0xd1, 0x3c, 0x31, 0x88, 0xb4, 0xc7, 0xc8, 0xdd, 0x8c, 0x94, 0x37, - 0x9b, 0x88, 0x73, 0x76, 0x20, 0x1f, 0x21, 0x91, 0x35, 0xef, 0x48, 0xc2, - 0xa6, 0x80, 0xad, 0x76, 0x63, 0x8d, 0x5b, 0xfc, 0x9a, 0xef, 0x89, 0x03, - 0xbf, 0xe7, 0x73, 0xc4, 0x05, 0xc9, 0xd0, 0x0e, 0x33, 0x9b, 0x4a, 0x83, - 0xb2, 0x5c, 0x6b, 0x5c, 0xd4, 0xb0, 0x17, 0x7a, 0x45, 0xb6, 0x39, 0x20, - 0x8c, 0x19, 0xa4, 0xcb, 0x0a, 0x2e, 0x42, 0x8b, 0x28, 0x04, 0xcb, 0xed, - 0xcd, 0x3a, 0x59, 0xb5, 0x75, 0x76, 0xd0, 0xa1, 0xed, 0x61, 0x46, 0xaf, - 0x45, 0x7d, 0xe0, 0xce, 0xed, 0x7e, 0x89, 0xed, 0x93, 0x46, 0xd1, 0x20, - 0x53, 0x57, 0x27, 0x42, 0x2e, 0xd9, 0x11, 0x33, 0x2a, 0x97, 0xbb, 0xce, - 0x82, 0xf9, 0xdc, 0xa1, 0xd1, 0xf5, 0xfe, 0x40, 0x53, 0x15, 0x7e, 0x34, - 0xbd, 0x38, 0xae, 0xd6, 0xbb, 0x64, 0x6f, 0x65, 0x4e, 0x24, 0x68, 0x0b, - 0x43, 0x80, 0xb7, 0x1a, 0x0d, 0x8b, 0xda, 0xb8, 0xdd, 0xa1, 0x95, 0x55, - 0xce, 0x24, 0x11, 0xe8, 0x90, 0xa6, 0x39, 0x82, 0xa0, 0xed, 0x37, 0x45, - 0xb7, 0xdd, 0x97, 0xab, 0x73, 0xa1, 0x9b, 0x78, 0xb9, 0x72, 0x55, 0x51, - 0x55, 0x45, 0xdf, 0x11, 0xc5, 0x9d, 0x26, 0x70, 0xe2, 0x9e, 0xbc, 0xda, - 0x79, 0x04, 0xcf, 0x35, 0xbd, 0xb8, 0x20, 0xb0, 0x7c, 0x56, 0xec, 0xce, - 0xf6, 0xcb, 0xc2, 0x59, 0x24, 0x71, 0xb1, 0x22, 0x88, 0x4b, 0x18, 0xc7, - 0x51, 0x90, 0x45, 0xba, 0x5d, 0xa8, 0x79, 0x99, 0x53, 0x15, 0x97, 0x30, - 0xbd, 0x2e, 0xc5, 0xe5, 0xc1, 0x65, 0xda, 0x64, 0x8e, 0xbb, 0x6a, 0xa5, - 0xc0, 0x1e, 0x1b, 0xaf, 0x2f, 0x5a, 0x74, 0x5d, 0x2b, 0x02, 0x7c, 0x5a, - 0xd0, 0xb0, 0xa1, 0x96, 0x91, 0x0e, 0xef, 0xe8, 0xc2, 0xef, 0xb6, 0x11, - 0x1e, 0x4a, 0xf9, 0x81, 0x92, 0x6d, 0x33, 0x21, 0x5a, 0x1d, 0x77, 0x16, - 0x52, 0x26, 0x72, 0x6c, 0xdc, 0xa6, 0x3d, 0xb1, 0x75, 0xb7, 0x7d, 0x40, - 0xe9, 0x78, 0x7e, 0x92, 0xaf, 0xa7, 0x68, 0x26, 0x75, 0x5d, 0xd7, 0xa2, - 0x99, 0x7f, 0xe5, 0xda, 0xc3, 0xc0, 0x2d, 0x9a, 0xc0, 0xb2, 0xae, 0x8a, - 0xe0, 0x09, 0xa0, 0x2e, 0x5e, 0xce, 0x04, 0xf7, 0xda, 0xa6, 0x02, 0x80, - 0xaf, 0xf0, 0x85, 0x70, 0x58, 0xaa, 0x6b, 0xae, 0x6c, 0x4f, 0x33, 0x27, - 0x3e, 0x78, 0xd0, 0x2c, 0x5c, 0xb0, 0xe9, 0x02, 0x1b, 0x33, 0x05, 0x6b, - 0xd3, 0x21, 0x44, 0xd6, 0x86, 0xed, 0x44, 0x2c, 0x83, 0x34, 0x9b, 0xa3, - 0x1d, 0x18, 0x3d, 0x9b, 0x35, 0x59, 0x1a, 0x64, 0x23, 0x7a, 0xc5, 0xb9, - 0x22, 0xdf, 0x6d, 0xbb, 0x46, 0x09, 0x5b, 0xa6, 0x5b, 0xc7, 0xd0, 0x1c, - 0xe7, 0x4e, 0x1b, 0x86, 0x99, 0x49, 0xd7, 0xfd, 0xb5, 0x5c, 0x03, 0xb7, - 0xa6, 0x45, 0x58, 0x16, 0x32, 0x94, 0x85, 0xae, 0x41, 0x5c, 0x52, 0xe6, - 0xeb, 0x46, 0x4e, 0xc8, 0x6b, 0x44, 0xa8, 0x92, 0xc4, 0x93, 0x0b, 0xe4, - 0xda, 0x5d, 0xb7, 0x4a, 0x53, 0x52, 0x30, 0xbd, 0x80, 0x64, 0x06, 0xaf, - 0x6b, 0xd9, 0x63, 0xdc, 0xd3, 0x39, 0x27, 0x42, 0x03, 0xd5, 0x8a, 0x1a, - 0x41, 0xb7, 0x6c, 0x93, 0x5f, 0x65, 0x6a, 0x8c, 0xd7, 0x9b, 0x14, 0x3d, - 0xc6, 0x56, 0x1b, 0xd4, 0x3b, 0x34, 0x66, 0x22, 0xb1, 0x38, 0xe8, 0x15, - 0xb5, 0xa7, 0x36, 0x78, 0x0a, 0x0c, 0x47, 0x3a, 0x48, 0xeb, 0x88, 0xd8, - 0x42, 0x99, 0x9e, 0xc5, 0xab, 0xa8, 0x1a, 0xb6, 0xce, 0x91, 0x29, 0x72, - 0x77, 0x09, 0x15, 0xc1, 0x5e, 0x75, 0x1a, 0xf9, 0x28, 0xaf, 0x0f, 0xd9, - 0xd1, 0x3c, 0xae, 0xc7, 0xee, 0x20, 0x32, 0xbe, 0x44, 0x19, 0xc2, 0x12, - 0xdd, 0x86, 0x8d, 0xba, 0x33, 0xf1, 0x22, 0x33, 0x38, 0x87, 0xa0, 0x7b, - 0x57, 0x73, 0x34, 0x77, 0xe3, 0x19, 0x97, 0x75, 0xae, 0x2e, 0x33, 0xdc, - 0x83, 0xf3, 0xdd, 0x3e, 0xf2, 0x47, 0x14, 0x76, 0x16, 0xe6, 0x58, 0x47, - 0xa9, 0x63, 0xc0, 0x2b, 0xff, 0x22, 0x02, 0x61, 0x6b, 0x83, 0xa5, 0x3c, - 0xa2, 0x31, 0x39, 0x90, 0xa8, 0x96, 0xd0, 0xe6, 0xfa, 0xb4, 0x5b, 0xf5, - 0xa4, 0x9e, 0x62, 0x32, 0xec, 0x2e, 0x82, 0x31, 0x9f, 0xe3, 0x65, 0x1d, - 0x31, 0x47, 0x32, 0x59, 0x79, 0x0b, 0x51, 0xdf, 0xe9, 0xeb, 0x69, 0xce, - 0x9f, 0x5f, 0x48, 0x44, 0xb4, 0x45, 0xb5, 0xfd, 0x8c, 0x18, 0xe8, 0x39, - 0x79, 0x92, 0x2c, 0xe0, 0x53, 0xa8, 0x6e, 0xc3, 0x36, 0x81, 0x76, 0xde, - 0x47, 0x12, 0xa9, 0x99, 0x07, 0x3a, 0xaf, 0x4a, 0xbe, 0x61, 0x9b, 0x25, - 0x61, 0xf3, 0x9a, 0xa1, 0x1c, 0x4b, 0x89, 0xa5, 0x1c, 0xcd, 0x4c, 0x03, - 0x86, 0x25, 0xc2, 0x2d, 0xb5, 0x70, 0x4a, 0x5b, 0x65, 0x82, 0x5c, 0x3a, - 0xad, 0x0f, 0xa2, 0x32, 0xee, 0x76, 0x9e, 0x14, 0xd7, 0xa3, 0xd2, 0x09, - 0xd4, 0x5a, 0x41, 0x92, 0xfc, 0xaa, 0xcf, 0x5a, 0xeb, 0x9c, 0x77, 0xc7, - 0x4b, 0x4e, 0xd5, 0xe9, 0xc6, 0x17, 0x76, 0x1b, 0x48, 0x30, 0x65, 0x5f, - 0x85, 0xb8, 0xbe, 0x53, 0xa5, 0x7e, 0x0f, 0x62, 0xa7, 0xcc, 0x16, 0x5b, - 0xb8, 0x90, 0xe3, 0x08, 0xc5, 0xbd, 0x6b, 0x94, 0xc5, 0x5e, 0x23, 0x70, - 0x85, 0x60, 0x2f, 0x5b, 0x51, 0x73, 0x8b, 0x06, 0x39, 0x15, 0x87, 0x18, - 0xab, 0xf7, 0xa2, 0xbb, 0x92, 0x0d, 0x1f, 0x42, 0xf6, 0x7b, 0xf7, 0x62, - 0x1f, 0x82, 0x61, 0xd5, 0x3b, 0x95, 0x53, 0x9c, 0x2b, 0x42, 0x5d, 0xa8, - 0xea, 0x02, 0x81, 0x13, 0x35, 0xd2, 0x4d, 0x7d, 0xe7, 0x52, 0xfc, 0xd5, - 0x3e, 0x35, 0x7b, 0x95, 0x99, 0x95, 0xbb, 0x80, 0x62, 0x98, 0xc0, 0xaa, - 0x2e, 0x59, 0x43, 0xf9, 0x32, 0x85, 0x36, 0x1d, 0x0a, 0x6d, 0xcc, 0x8b, - 0x1d, 0x2c, 0xf2, 0x6a, 0x8b, 0x1e, 0x39, 0x78, 0x57, 0x96, 0xf3, 0x2c, - 0x26, 0x86, 0x26, 0xdb, 0xed, 0x90, 0xe8, 0x82, 0x92, 0x8d, 0x45, 0x2c, - 0x3c, 0x89, 0xf5, 0x5a, 0x6b, 0xe7, 0xaf, 0xcc, 0x0b, 0x45, 0x77, 0xeb, - 0x53, 0x93, 0xab, 0xe8, 0x45, 0xbb, 0x8c, 0x62, 0x32, 0xa7, 0x8c, 0x30, - 0xb0, 0x0f, 0xd5, 0xf6, 0xba, 0x57, 0xf5, 0x75, 0x5b, 0x73, 0xfb, 0x5d, - 0xe5, 0xd5, 0xca, 0xec, 0x3c, 0xc2, 0xc3, 0x70, 0xba, 0xd2, 0xe1, 0xa9, - 0x50, 0x9a, 0xf8, 0xaa, 0x19, 0x4c, 0x66, 0x43, 0x14, 0x6a, 0xcc, 0x8a, - 0x14, 0x87, 0xe1, 0xae, 0xda, 0x95, 0x47, 0xca, 0xca, 0x3c, 0x8a, 0x54, - 0x45, 0x9b, 0xf5, 0x04, 0xd2, 0x81, 0x65, 0x5d, 0x49, 0x2e, 0xb9, 0xbd, - 0xa7, 0xa3, 0x60, 0xa5, 0x4b, 0x74, 0x7d, 0x62, 0x4a, 0x19, 0x69, 0xe5, - 0xce, 0xde, 0x29, 0x5b, 0xbf, 0x81, 0x72, 0x7a, 0x5f, 0xb5, 0x88, 0x8a, - 0xeb, 0x69, 0x6a, 0x1e, 0xd0, 0xdd, 0xfa, 0x1a, 0x39, 0x0b, 0xaa, 0x81, - 0x2e, 0x92, 0xca, 0x39, 0x0b, 0x18, 0xb5, 0xa9, 0xdd, 0x09, 0xb5, 0x2e, - 0x73, 0x0a, 0x85, 0x53, 0x03, 0xba, 0x1e, 0xf8, 0xab, 0xca, 0xf4, 0xb1, - 0x9d, 0xfa, 0xba, 0x91, 0xe7, 0xa6, 0xbc, 0x76, 0xa9, 0x6d, 0xa7, 0x1d, - 0xad, 0x1e, 0x76, 0xaf, 0xb4, 0xda, 0x79, 0xbe, 0x23, 0xc8, 0x88, 0x14, - 0x42, 0xe2, 0xfc, 0x9a, 0x84, 0xd6, 0x25, 0x58, 0x89, 0x06, 0x86, 0xa5, - 0x92, 0x0c, 0x68, 0xb6, 0x2e, 0x1c, 0x71, 0xb6, 0x02, 0x56, 0x2f, 0x4b, - 0x20, 0x56, 0xcd, 0xa3, 0xde, 0x84, 0xcc, 0x9d, 0x94, 0x64, 0xe9, 0x2c, - 0x67, 0xc8, 0x5a, 0xcb, 0x97, 0xfa, 0xe9, 0x82, 0xd8, 0x35, 0xc9, 0x64, - 0x54, 0xe1, 0x5b, 0xbe, 0x92, 0xa5, 0x62, 0x46, 0x97, 0x45, 0x7e, 0xf0, - 0xb7, 0x97, 0x15, 0x12, 0x5f, 0x83, 0xd2, 0xda, 0xec, 0xf7, 0x1d, 0xb7, - 0x21, 0xf6, 0x0d, 0x24, 0xcc, 0xf2, 0xee, 0x12, 0x9f, 0x56, 0xa1, 0xb3, - 0x72, 0x73, 0x53, 0xcf, 0x35, 0x87, 0xf4, 0x09, 0x3f, 0xdb, 0x99, 0xa3, - 0xa5, 0xbb, 0x96, 0x2e, 0x26, 0xd9, 0xee, 0x44, 0x15, 0xeb, 0x4c, 0x44, - 0xca, 0x6c, 0x16, 0x10, 0x91, 0xb3, 0xd5, 0x76, 0x6b, 0x94, 0x80, 0x74, - 0xba, 0x66, 0x60, 0x52, 0x8f, 0xbc, 0x0b, 0xcb, 0x1c, 0x53, 0xd2, 0xec, - 0x2d, 0x8f, 0x3c, 0xfa, 0xd1, 0x3e, 0x2a, 0x1c, 0x25, 0x26, 0x51, 0x78, - 0x66, 0x9a, 0xb2, 0x8d, 0x74, 0x0a, 0xb9, 0x5a, 0x15, 0x45, 0x8e, 0x9a, - 0x79, 0x8f, 0x6e, 0xdd, 0xdd, 0x0e, 0x43, 0x58, 0xa7, 0x41, 0x50, 0x21, - 0x77, 0xf9, 0x18, 0xd1, 0x4f, 0x18, 0x48, 0x81, 0xc3, 0x62, 0x5b, 0xe9, - 0x1b, 0x6c, 0x45, 0xed, 0xe8, 0x3d, 0xec, 0x5c, 0x67, 0xae, 0x24, 0x72, - 0x09, 0x66, 0x39, 0x0b, 0xa3, 0x3e, 0xf9, 0x1b, 0x7e, 0x3e, 0x57, 0x7c, - 0x6b, 0x06, 0x49, 0xcb, 0x80, 0x00, 0xb9, 0x22, 0x3d, 0xee, 0xbc, 0x7c, - 0xbb, 0xf2, 0x8a, 0x63, 0x15, 0x2a, 0x5e, 0xcc, 0x4b, 0xde, 0x40, 0x69, - 0xaa, 0x0f, 0xcb, 0x9d, 0x35, 0x3b, 0xdb, 0x97, 0xa2, 0x4f, 0x4f, 0x28, - 0x77, 0x5d, 0x53, 0xdb, 0xd0, 0x9e, 0xed, 0xc2, 0x6c, 0xaf, 0x84, 0x56, - 0x16, 0xac, 0x39, 0x03, 0xdb, 0x44, 0x7b, 0xfb, 0xb4, 0x3b, 0x1f, 0xf5, - 0x73, 0xd3, 0xc8, 0xb1, 0x8d, 0xc6, 0x7b, 0xc7, 0x99, 0x77, 0xe1, 0x69, - 0x39, 0x1c, 0xd7, 0xe9, 0x26, 0x39, 0xf0, 0x25, 0x15, 0xb5, 0xd1, 0xa5, - 0xad, 0x51, 0x4c, 0x05, 0xa2, 0xd8, 0xe4, 0xa8, 0x07, 0x31, 0xc5, 0x59, - 0xd7, 0x66, 0xd5, 0xa8, 0xa2, 0xe7, 0x32, 0x3d, 0x9f, 0x56, 0x03, 0xca, - 0x85, 0x8d, 0x15, 0x0d, 0xf4, 0xa5, 0x74, 0x1c, 0x01, 0xe6, 0xe1, 0x6b, - 0xd9, 0x83, 0xbc, 0x8f, 0x04, 0x79, 0x6e, 0x60, 0xf8, 0x20, 0x6e, 0x52, - 0xab, 0x80, 0xc9, 0x61, 0xca, 0xd2, 0x06, 0x2f, 0x31, 0x90, 0x9d, 0xb0, - 0xcc, 0x2c, 0x6f, 0x75, 0x99, 0xf5, 0x08, 0xd4, 0x1c, 0xb1, 0x75, 0x9c, - 0x1d, 0x67, 0xa3, 0x33, 0x9e, 0xd3, 0x16, 0xa5, 0xd4, 0x65, 0x91, 0x45, - 0xf6, 0x25, 0x63, 0xc4, 0xbd, 0x69, 0xa0, 0x27, 0x50, 0x99, 0xc8, 0xd9, - 0xa3, 0x97, 0x28, 0x5a, 0xdd, 0xe5, 0x47, 0x11, 0x8f, 0xcb, 0x49, 0x4e, - 0x91, 0x39, 0x48, 0x8f, 0x0e, 0xb3, 0x55, 0xa9, 0xb5, 0x5c, 0x79, 0x50, - 0x5b, 0x9c, 0x12, 0x9b, 0x98, 0x9c, 0x21, 0x94, 0x7e, 0x3e, 0xec, 0x73, - 0x92, 0x50, 0xd6, 0x9b, 0x9c, 0xf0, 0x2f, 0x87, 0x74, 0xad, 0x49, 0xd2, - 0x06, 0x1d, 0x88, 0x22, 0x80, 0x87, 0x7e, 0xc0, 0xd6, 0x6c, 0x49, 0x15, - 0xe1, 0x1e, 0xdd, 0x04, 0x6a, 0x40, 0xba, 0x05, 0x0f, 0x78, 0xdf, 0xca, - 0xc0, 0xed, 0x07, 0xee, 0x62, 0x74, 0x73, 0x72, 0x79, 0x22, 0xc9, 0x75, - 0xc0, 0xa9, 0xa7, 0x0e, 0x05, 0xb6, 0xcd, 0x17, 0x29, 0x18, 0x1d, 0xe3, - 0x78, 0xe5, 0x2e, 0x66, 0xc3, 0xca, 0x41, 0xe5, 0x06, 0x59, 0x21, 0x15, - 0xdc, 0x2e, 0x37, 0x71, 0x35, 0x2c, 0x45, 0x7d, 0xdd, 0x25, 0x8a, 0x59, - 0x1d, 0x31, 0x2b, 0xe6, 0xd6, 0x6a, 0xe4, 0xa8, 0x29, 0x5c, 0x2a, 0x62, - 0x99, 0xcf, 0x19, 0x99, 0xe7, 0xc3, 0x2a, 0xdf, 0x2f, 0xbb, 0xbd, 0x18, - 0xce, 0xf5, 0x75, 0x8e, 0x2a, 0x62, 0x77, 0x64, 0xad, 0x98, 0x8f, 0xa9, - 0x9c, 0x75, 0x93, 0x3d, 0xaa, 0xb3, 0xaa, 0x86, 0x70, 0xb1, 0xe8, 0x58, - 0x82, 0x10, 0xf8, 0x58, 0x6e, 0xd7, 0x36, 0x41, 0xe3, 0x52, 0x92, 0xb2, - 0x2b, 0x91, 0x8c, 0x06, 0xb6, 0xa1, 0x78, 0x09, 0x0e, 0x57, 0x15, 0x6e, - 0x2c, 0x7c, 0x65, 0x67, 0xd5, 0x13, 0xdc, 0x4e, 0x70, 0x54, 0x51, 0xd4, - 0xb7, 0xbe, 0x5a, 0xb4, 0xad, 0x8e, 0xa4, 0x35, 0x79, 0x48, 0x0c, 0x56, - 0x39, 0x5b, 0x3e, 0xae, 0x17, 0xc7, 0xad, 0xc9, 0x04, 0x1b, 0x0a, 0x39, - 0x29, 0x86, 0xa7, 0x19, 0x68, 0xc5, 0xb1, 0x73, 0xdd, 0x2f, 0x4f, 0x5b, - 0xed, 0x74, 0x3d, 0x77, 0x56, 0xc0, 0x7b, 0x10, 0x90, 0x6e, 0x6c, 0x2c, - 0x2e, 0xf8, 0x96, 0x2f, 0xba, 0xfd, 0x4c, 0x31, 0xcb, 0x23, 0xbe, 0x33, - 0xb9, 0x8b, 0xc2, 0x5c, 0x9a, 0xb2, 0x71, 0x83, 0xc5, 0x59, 0xdb, 0xb0, - 0x4b, 0x16, 0xd8, 0x81, 0xd5, 0xb6, 0xda, 0xf6, 0xc0, 0x36, 0xcc, 0x76, - 0x0d, 0x57, 0x2e, 0xac, 0x16, 0xc6, 0xf5, 0x26, 0x3b, 0x4b, 0xf6, 0x78, - 0xd8, 0xa8, 0x02, 0x1b, 0x73, 0x0e, 0x35, 0x58, 0x71, 0xa4, 0xef, 0xf7, - 0x01, 0xb7, 0x5e, 0x5c, 0xbd, 0xd3, 0x45, 0x3d, 0x9f, 0xaa, 0xcb, 0xc5, - 0xa5, 0x47, 0x9a, 0x3d, 0x03, 0x9a, 0x78, 0xdb, 0xca, 0xe8, 0xc3, 0x44, - 0x3d, 0x92, 0x8a, 0xcb, 0x69, 0x80, 0x57, 0xf2, 0x7e, 0x0d, 0xd7, 0x8a, - 0xc6, 0xb7, 0xb8, 0x5d, 0x04, 0xd6, 0xbc, 0x3b, 0x67, 0xf0, 0x96, 0x0b, - 0x95, 0x63, 0xdc, 0xda, 0xa3, 0x22, 0x80, 0x44, 0x30, 0x2c, 0x2e, 0x8b, - 0x55, 0x04, 0x19, 0x64, 0xbc, 0xe3, 0x2c, 0x8d, 0xe8, 0x0c, 0x69, 0x06, - 0x72, 0x00, 0xdd, 0xe1, 0x45, 0x47, 0x07, 0x31, 0x92, 0xae, 0xd4, 0x45, - 0x51, 0x98, 0x85, 0xb0, 0xb7, 0x60, 0x81, 0x47, 0x63, 0x80, 0x42, 0xac, - 0x03, 0x9b, 0x0f, 0xda, 0x51, 0x94, 0xf4, 0xa2, 0x88, 0xa9, 0xb4, 0x86, - 0x81, 0x48, 0x6c, 0x06, 0x1d, 0x2a, 0x62, 0xd3, 0x41, 0xb6, 0x94, 0x6e, - 0xb5, 0xbe, 0xa8, 0x35, 0x6d, 0xb1, 0x30, 0x2f, 0x0b, 0xa2, 0x89, 0x5c, - 0x17, 0xdb, 0x95, 0xb2, 0x79, 0x89, 0x45, 0x2b, 0x59, 0x5f, 0x78, 0xd3, - 0x89, 0xf7, 0x86, 0x76, 0xbc, 0xa8, 0xa6, 0xa1, 0x6d, 0x8b, 0x45, 0x7a, - 0x59, 0xe8, 0xc0, 0xd2, 0x15, 0xa5, 0xa9, 0x34, 0x7c, 0x98, 0x59, 0x45, - 0x2a, 0xc4, 0xa8, 0x1a, 0xa7, 0xfb, 0x18, 0x56, 0x79, 0xfb, 0xe7, 0xd5, - 0xdd, 0xe1, 0x73, 0xbf, 0x48, 0xad, 0x62, 0x73, 0xf2, 0xac, 0x0a, 0x45, - 0x29, 0x58, 0x3d, 0x0d, 0x83, 0x49, 0x6e, 0xf4, 0xd3, 0x37, 0x2d, 0x31, - 0x0f, 0x39, 0x86, 0x3a, 0x3d, 0xaf, 0x5a, 0x5f, 0xef, 0x20, 0x34, 0x8c, - 0x2f, 0xdf, 0xf5, 0x4f, 0xad, 0x80, 0x84, 0x36, 0x7c, 0x5a, 0x63, 0x9e, - 0x41, 0xab, 0x42, 0xfd, 0xbe, 0xf0, 0x2b, 0x56, 0xe6, 0x7a, 0xe5, 0x06, - 0x7e, 0xbb, 0x21, 0xbb, 0xb3, 0xc3, 0x7f, 0x57, 0xf0, 0xea, 0xbb, 0x35, - 0xfe, 0x2c, 0x9b, 0x6c, 0x98, 0x4a, 0x21, 0xbf, 0x2f, 0x7d, 0xf8, 0xbc, - 0x79, 0xc2, 0x9e, 0x65, 0x89, 0x0d, 0xe4, 0xf0, 0xdf, 0x99, 0x3c, 0x7d, - 0x84, 0xbf, 0x63, 0xef, 0xcc, 0xa5, 0xd1, 0xf0, 0xf2, 0x9d, 0xd9, 0xcb, - 0x9e, 0x9e, 0xd8, 0xcb, 0xb1, 0xd0, 0x65, 0xf6, 0x9d, 0xd9, 0x5b, 0x5c, - 0xa8, 0xa5, 0xf4, 0xb4, 0x43, 0x81, 0xdf, 0x42, 0x68, 0x7d, 0xbe, 0x7c, - 0x57, 0xf8, 0xa5, 0xea, 0x63, 0x00, 0xfc, 0x6d, 0xe7, 0xd3, 0xbc, 0x80, - 0x66, 0x0d, 0xca, 0xf1, 0xc5, 0x2f, 0xde, 0xae, 0x71, 0x60, 0x77, 0xa5, - 0xb8, 0x26, 0x50, 0x3f, 0x71, 0x0e, 0xdb, 0x3b, 0x4d, 0x16, 0xfa, 0x9e, - 0x10, 0xaa, 0x64, 0x11, 0x86, 0xe1, 0x8f, 0x3f, 0xbe, 0xdf, 0x3d, 0xf3, - 0xb5, 0xbd, 0x5f, 0x75, 0xe3, 0x34, 0xed, 0x74, 0x80, 0x41, 0x75, 0xdf, - 0x25, 0xfe, 0x62, 0x13, 0xd8, 0x6d, 0x53, 0xea, 0x87, 0x90, 0x9e, 0x76, - 0xbe, 0xde, 0xe1, 0x4d, 0xa7, 0x36, 0x4f, 0x87, 0x28, 0xbc, 0x79, 0x2a, - 0x7d, 0xf7, 0xe2, 0xf3, 0x83, 0xc7, 0x20, 0x6e, 0x7e, 0x3c, 0x4d, 0x3b, - 0x7f, 0x7f, 0x78, 0x3a, 0x69, 0xe3, 0xe4, 0xdc, 0xee, 0x37, 0xfd, 0x31, - 0x2f, 0x7e, 0x78, 0x3a, 0xde, 0xd9, 0xf3, 0xbb, 0xf8, 0xe4, 0xdf, 0x37, - 0x4c, 0xff, 0xf0, 0xbc, 0xa3, 0xf4, 0x56, 0xd1, 0xff, 0x11, 0xf9, 0x61, - 0xba, 0x71, 0x35, 0xce, 0xda, 0xec, 0xb9, 0xe0, 0xde, 0xd4, 0x0d, 0xa3, - 0xff, 0x82, 0x22, 0xdf, 0xf1, 0x6e, 0x9f, 0x6e, 0x67, 0x53, 0x37, 0x8e, - 0x7b, 0xdb, 0xea, 0xf8, 0xe3, 0x1b, 0x18, 0xf4, 0x21, 0x75, 0xea, 0xfa, - 0xc7, 0x37, 0x1f, 0xee, 0xf3, 0xff, 0x68, 0xdf, 0xe2, 0x9b, 0xa7, 0x7e, - 0x4d, 0xf7, 0xa8, 0xbc, 0xa8, 0xff, 0x6e, 0x23, 0xe3, 0xd3, 0xf3, 0x4f, - 0x6b, 0x4c, 0xdb, 0x51, 0xdf, 0x3d, 0x04, 0x8f, 0xeb, 0x2e, 0x7c, 0xf7, - 0xe5, 0x76, 0x3c, 0x4b, 0x1d, 0x17, 0xf9, 0x8f, 0x6f, 0x90, 0xb7, 0xf0, - 0x9b, 0x17, 0xe5, 0xf7, 0x63, 0xb0, 0xdf, 0x7c, 0xfe, 0x18, 0xec, 0x97, - 0x95, 0x9f, 0x0f, 0xc4, 0x7e, 0x03, 0xff, 0x00, 0xff, 0x80, 0xd2, 0xf8, - 0x0f, 0x0c, 0xf3, 0xf2, 0xf1, 0x47, 0xc8, 0xdc, 0xf7, 0xc6, 0xbe, 0xaf, - 0xf0, 0xb7, 0x17, 0x55, 0xff, 0x6b, 0x3a, 0xd8, 0xe6, 0xc5, 0xf7, 0x87, - 0xfb, 0x11, 0xd9, 0x55, 0x0b, 0xc8, 0xf9, 0x66, 0xba, 0xbc, 0xb2, 0xf0, - 0xbc, 0x37, 0x1f, 0x3c, 0x3f, 0xa5, 0x71, 0xf9, 0xa5, 0xe7, 0xb7, 0x33, - 0xb7, 0xdf, 0xfc, 0xdf, 0x30, 0x32, 0xfd, 0xfd, 0xf0, 0x91, 0xf7, 0xe3, - 0x9b, 0x25, 0x4a, 0x63, 0x6f, 0x71, 0x92, 0x78, 0x60, 0xa8, 0xb7, 0x0c, - 0x4d, 0xca, 0xb7, 0x23, 0x77, 0xef, 0x45, 0xdd, 0xbd, 0xe8, 0xfa, 0xf2, - 0x1d, 0xe8, 0xf7, 0xc1, 0xf5, 0x76, 0x3a, 0xf8, 0x2b, 0xb8, 0x52, 0xf0, - 0x5b, 0x98, 0x44, 0x1f, 0x28, 0xe2, 0x2d, 0x4c, 0x9b, 0x24, 0xfc, 0xf6, - 0x76, 0xa0, 0x33, 0x42, 0xbd, 0x85, 0xf1, 0x0e, 0x01, 0x8f, 0x28, 0xe6, - 0x04, 0x3f, 0xa0, 0x6f, 0x49, 0x18, 0x7f, 0x04, 0x3f, 0xa9, 0xdb, 0xe9, - 0x88, 0x8f, 0xe0, 0x07, 0x45, 0xdc, 0x3e, 0x46, 0x8f, 0x28, 0xfc, 0x96, - 0x40, 0x99, 0xd3, 0x23, 0x0e, 0x3a, 0x86, 0xdd, 0xce, 0x59, 0xc4, 0x31, - 0xf0, 0x05, 0xc5, 0xee, 0x9f, 0xe8, 0xb7, 0x28, 0x43, 0x77, 0x8f, 0xd3, - 0xa9, 0x8c, 0xd8, 0x09, 0x9e, 0x60, 0x90, 0xf4, 0x03, 0x02, 0xbe, 0xd0, - 0xa0, 0x12, 0x4d, 0x62, 0x0f, 0xe0, 0xe7, 0xd3, 0xc7, 0x08, 0x80, 0x62, - 0x18, 0xe2, 0x04, 0xea, 0xd0, 0xf8, 0xed, 0xec, 0x45, 0x64, 0x3a, 0xaa, - 0xfb, 0x2d, 0xce, 0xa0, 0x4f, 0x9f, 0xf1, 0xb7, 0x38, 0x8d, 0x9a, 0x18, - 0x0d, 0x6a, 0x47, 0x37, 0x14, 0x4d, 0x94, 0x7a, 0x4b, 0x4e, 0x70, 0x29, - 0x50, 0x44, 0x4d, 0xcd, 0x92, 0x8f, 0x08, 0xf1, 0x96, 0x01, 0xad, 0x23, - 0xd8, 0x5b, 0x18, 0x63, 0x9e, 0xbe, 0xc9, 0x28, 0x8a, 0xbc, 0x45, 0x00, - 0x96, 0xd4, 0x5b, 0x0c, 0x66, 0xa6, 0x83, 0x16, 0x89, 0xa9, 0x4b, 0x0f, - 0x13, 0x9e, 0xc4, 0xf3, 0x17, 0x04, 0x34, 0x4c, 0x4c, 0xa7, 0xbb, 0xbe, - 0xc5, 0x68, 0x0a, 0xf4, 0x9a, 0x7c, 0x4b, 0xc0, 0xf4, 0x0d, 0x3f, 0xec, - 0x61, 0x82, 0x46, 0xde, 0xce, 0x0d, 0x9f, 0x4e, 0x15, 0xbe, 0x7d, 0x89, - 0x00, 0x1e, 0x38, 0x75, 0x22, 0xc1, 0xbb, 0xe4, 0x74, 0x3e, 0x07, 0xf6, - 0x96, 0xa0, 0x29, 0xd0, 0x69, 0x1a, 0xc6, 0x9e, 0xbf, 0x80, 0xea, 0x14, - 0x86, 0x5f, 0x97, 0x08, 0x03, 0x03, 0xcc, 0x69, 0xd0, 0x0b, 0x82, 0x44, - 0x65, 0xf0, 0x06, 0x42, 0x69, 0x00, 0x3a, 0x0d, 0x44, 0x04, 0x90, 0x02, - 0x89, 0x10, 0x20, 0x1d, 0x0c, 0x92, 0x3e, 0xbe, 0x85, 0x61, 0x6a, 0x3a, - 0xa5, 0x1c, 0xc3, 0xe9, 0x2f, 0x88, 0xc8, 0xb4, 0x61, 0xf9, 0x03, 0x3e, - 0xbe, 0xdb, 0x2e, 0xff, 0xe3, 0x9b, 0xdb, 0xc7, 0xd4, 0x69, 0xfc, 0x3f, - 0x4f, 0x07, 0xc1, 0x12, 0xd4, 0x03, 0x0d, 0x1a, 0x20, 0xfe, 0xf2, 0xcd, - 0xe2, 0xfb, 0xe2, 0x7c, 0x8d, 0x1f, 0xdf, 0xfc, 0x89, 0xcd, 0xea, 0x78, - 0x53, 0x15, 0x8f, 0x5c, 0x91, 0x7a, 0x4a, 0x33, 0x5d, 0x94, 0xf3, 0xa7, - 0x57, 0xaa, 0x4f, 0xa7, 0x6d, 0xfc, 0xf8, 0x86, 0x01, 0x7d, 0x45, 0x3f, - 0x82, 0xf6, 0xe1, 0x61, 0x1a, 0x3f, 0xbe, 0x79, 0xfc, 0x40, 0x85, 0xff, - 0xf6, 0x41, 0x5d, 0x89, 0x33, 0x5e, 0x76, 0x12, 0x9a, 0x7a, 0xf9, 0x41, - 0xb7, 0xc3, 0x0f, 0xeb, 0x7f, 0xaa, 0x29, 0x5f, 0xd7, 0x95, 0xaf, 0x6b, - 0xcb, 0x17, 0x89, 0x73, 0xd7, 0x18, 0x02, 0x30, 0x88, 0xc1, 0x9e, 0x95, - 0x1b, 0x83, 0x27, 0xc5, 0xc6, 0xdf, 0xa9, 0x38, 0xfe, 0x9a, 0x8a, 0x7f, - 0xc4, 0xc1, 0xdf, 0x1c, 0x79, 0x51, 0x14, 0x5f, 0xc5, 0x9c, 0x02, 0x62, - 0x89, 0x92, 0xdf, 0xa8, 0xeb, 0x24, 0xf3, 0x19, 0x65, 0xa7, 0xef, 0xca, - 0x8e, 0xff, 0x0c, 0x65, 0xa7, 0xbe, 0xa8, 0xec, 0xd8, 0x93, 0xb2, 0x53, - 0x2f, 0x94, 0x9d, 0xfa, 0xf9, 0xca, 0x4e, 0x3f, 0x7d, 0x8b, 0x1e, 0x31, - 0xa0, 0x85, 0x18, 0x76, 0xd3, 0x76, 0xe4, 0x59, 0xd9, 0x89, 0x97, 0xca, - 0x4e, 0x7c, 0x41, 0xd9, 0xf1, 0xcf, 0x2b, 0x3b, 0xf2, 0xa1, 0xb6, 0x93, - 0x2f, 0xb5, 0x9d, 0x7c, 0xa7, 0xed, 0x38, 0x03, 0xb4, 0x99, 0xc0, 0x9e, - 0xb4, 0x1d, 0x9b, 0x28, 0x4b, 0x4f, 0xba, 0x8d, 0xa1, 0x0f, 0x77, 0xdd, - 0x7e, 0xa9, 0xef, 0xe4, 0x6b, 0xfa, 0xfe, 0xa9, 0xbc, 0x7c, 0xa2, 0xf3, - 0x9f, 0xd1, 0x7a, 0x6c, 0xea, 0x1e, 0x8a, 0xbc, 0xaa, 0xf6, 0x5f, 0x91, - 0xed, 0x9f, 0xa9, 0xfa, 0x5f, 0x55, 0xfe, 0xaf, 0xa9, 0xff, 0xc7, 0x06, - 0xe0, 0x63, 0x13, 0xf0, 0xaa, 0x11, 0x80, 0x5e, 0x58, 0x81, 0xff, 0x9a, - 0x42, 0x86, 0x17, 0x5f, 0xef, 0x27, 0x82, 0xbc, 0xa8, 0x7d, 0xbb, 0x3b, - 0xe9, 0x7e, 0xb2, 0xd0, 0xfb, 0xdb, 0x92, 0x5e, 0x8f, 0x21, 0x9e, 0x2e, - 0x40, 0xff, 0xe4, 0xf6, 0xdf, 0xe7, 0x73, 0x8f, 0x5e, 0xbe, 0x76, 0xbf, - 0xaf, 0xec, 0xd5, 0x50, 0xe3, 0x76, 0xfa, 0xd5, 0x0b, 0x04, 0xef, 0xb0, - 0xbe, 0x19, 0xc7, 0xa7, 0x73, 0x38, 0x7e, 0x35, 0x8e, 0x2f, 0x51, 0x7a, - 0x82, 0xf9, 0xd3, 0x09, 0x04, 0xac, 0x95, 0xf3, 0xcb, 0x71, 0x03, 0xb2, - 0x03, 0x98, 0x59, 0x7f, 0x57, 0xdc, 0xdc, 0xb4, 0xad, 0x7e, 0x7a, 0xd1, - 0xe4, 0xcf, 0x46, 0xea, 0xc5, 0x05, 0x69, 0xdf, 0x15, 0xb1, 0xa6, 0xcd, - 0xfd, 0x5f, 0x8e, 0x15, 0x08, 0xe8, 0xfd, 0xb4, 0x28, 0x41, 0xfc, 0xfc, - 0xeb, 0x85, 0xed, 0x7e, 0x7e, 0xdb, 0xab, 0x48, 0xbe, 0x6b, 0xe6, 0xa7, - 0xac, 0xf0, 0x7e, 0x05, 0xba, 0xf5, 0x58, 0x37, 0x7e, 0xf6, 0x7d, 0x19, - 0x5b, 0xa4, 0x9f, 0x57, 0x83, 0xff, 0x82, 0x40, 0x36, 0xf1, 0xb9, 0xcc, - 0xe2, 0x7e, 0x49, 0xd2, 0x07, 0xb9, 0xc5, 0x1d, 0xcf, 0x87, 0x0f, 0x2f, - 0x3d, 0xfb, 0xc0, 0x2a, 0xbc, 0xbb, 0xeb, 0xed, 0x05, 0xa0, 0xe7, 0xb2, - 0x37, 0x0f, 0xb7, 0xa4, 0x0e, 0xbc, 0xf9, 0xe2, 0x52, 0xb9, 0xe9, 0x32, - 0xdd, 0x37, 0x1f, 0x99, 0xd8, 0xa7, 0x3b, 0x25, 0x5f, 0x01, 0xf1, 0xee, - 0xbe, 0xc9, 0xcf, 0xdf, 0xd0, 0xf9, 0xe6, 0x63, 0x5b, 0xf6, 0x71, 0xbf, - 0x6e, 0xb4, 0xfa, 0x9b, 0x53, 0x97, 0xa0, 0x37, 0x3f, 0x55, 0xd3, 0xb1, - 0x89, 0x1f, 0x90, 0xe1, 0xe5, 0x6b, 0x7f, 0xd3, 0xdf, 0x5d, 0x4d, 0xf7, - 0x4a, 0x9d, 0xff, 0x82, 0xee, 0xed, 0x7e, 0x54, 0xfa, 0x7f, 0x3d, 0x3e, - 0x4e, 0x27, 0xbc, 0x35, 0x4d, 0x0c, 0x2c, 0x6e, 0x1c, 0xe6, 0xd3, 0xd9, - 0x7d, 0x8f, 0x8f, 0x1f, 0x55, 0x6a, 0xd3, 0x8f, 0xd3, 0xc2, 0x4f, 0xf1, - 0x4e, 0xe3, 0xbf, 0xf1, 0x51, 0x51, 0xd4, 0xfe, 0x83, 0x93, 0x3f, 0x3c, - 0x9d, 0x05, 0xf3, 0xe2, 0xae, 0xbc, 0xa0, 0x2a, 0xb2, 0x87, 0x26, 0x02, - 0x4c, 0x78, 0x78, 0x62, 0xc5, 0x5b, 0x80, 0x51, 0xfc, 0x1a, 0x98, 0x63, - 0xd1, 0x56, 0x0f, 0xf7, 0x93, 0x25, 0xa7, 0x37, 0x7b, 0xe0, 0x7c, 0x1e, - 0x9c, 0xb4, 0x2e, 0x1e, 0x5c, 0x7f, 0xca, 0x85, 0x3d, 0xe0, 0x40, 0xc0, - 0xf3, 0xc6, 0xa9, 0x9a, 0xb6, 0x7c, 0x0b, 0xbc, 0x2d, 0x0d, 0x4f, 0xfb, - 0x9e, 0x1f, 0xe2, 0x1a, 0xb4, 0x77, 0x2a, 0x32, 0x20, 0x66, 0xde, 0x53, - 0xa5, 0xd5, 0xce, 0xe0, 0x1f, 0x6a, 0x00, 0x0e, 0xe8, 0xf9, 0x0f, 0xf7, - 0x9a, 0x08, 0x8c, 0xe2, 0xb7, 0x67, 0x1b, 0x56, 0x7b, 0xfb, 0x71, 0xe3, - 0x9f, 0x41, 0x68, 0x0f, 0x90, 0x06, 0xa8, 0xdf, 0xce, 0x8d, 0x3b, 0x45, - 0x00, 0xf6, 0xe6, 0x49, 0x98, 0x1e, 0x8a, 0xf2, 0x86, 0x62, 0x53, 0x3c, - 0xdc, 0x6f, 0xdd, 0x04, 0x28, 0x36, 0xbd, 0xef, 0xe7, 0xb7, 0xea, 0x4d, - 0x5f, 0xdc, 0xee, 0xd3, 0x9d, 0x0e, 0xbb, 0x04, 0x39, 0x78, 0x3a, 0x3e, - 0xfc, 0x79, 0xf3, 0xf2, 0x96, 0x49, 0xc7, 0xfd, 0xcb, 0x37, 0x22, 0x60, - 0xdc, 0x89, 0x91, 0x87, 0x0f, 0xce, 0x4b, 0x9a, 0xde, 0x88, 0x92, 0x39, - 0x09, 0x00, 0x16, 0x37, 0xb7, 0x26, 0x73, 0xbf, 0x7f, 0xa6, 0xcc, 0x13, - 0x99, 0x5f, 0xa1, 0xf2, 0x7f, 0x41, 0x6d, 0xfa, 0x51, 0xc9, 0x47, 0x42, - 0xf7, 0xbe, 0x8d, 0x4f, 0xf9, 0xfc, 0x89, 0x4d, 0xf8, 0x16, 0xd5, 0x7f, - 0x01, 0xf0, 0x93, 0x37, 0xef, 0xa9, 0xf8, 0xed, 0x24, 0x4b, 0x60, 0x53, - 0xbe, 0xf8, 0xfc, 0xf1, 0x7e, 0x7e, 0xce, 0x34, 0x20, 0xf2, 0x7a, 0x3d, - 0x10, 0xe9, 0x9e, 0x92, 0x1f, 0xdf, 0xdc, 0x8f, 0xc9, 0x7b, 0xbd, 0x0a, - 0x20, 0x25, 0x90, 0x90, 0xe6, 0xf1, 0x76, 0xfc, 0xc9, 0x1d, 0x3f, 0x84, - 0x41, 0x27, 0xc1, 0xa0, 0xe1, 0xd7, 0xdf, 0x00, 0x86, 0xe5, 0x9d, 0x01, - 0xf9, 0xb8, 0xc6, 0xdf, 0x3e, 0x79, 0x63, 0x02, 0x06, 0x8c, 0x4f, 0xe9, - 0xe4, 0x7f, 0xbb, 0xc1, 0x04, 0xd1, 0xc6, 0xf4, 0xf9, 0x13, 0x4e, 0x7f, - 0x6c, 0x6c, 0x7f, 0x17, 0xf2, 0x96, 0x7f, 0x17, 0xf2, 0x3e, 0xeb, 0xdd, - 0x77, 0x21, 0x2f, 0x00, 0xf6, 0x9e, 0xbc, 0x28, 0xfe, 0x87, 0x22, 0x6f, - 0xf0, 0x77, 0x23, 0x2f, 0x30, 0x80, 0xdf, 0x9b, 0xba, 0x00, 0xe4, 0x1f, - 0x8a, 0xb8, 0xe1, 0xdf, 0x8d, 0xb8, 0x14, 0xfa, 0xdd, 0x89, 0x0b, 0x40, - 0xfe, 0xa1, 0x88, 0x1b, 0xfd, 0x3d, 0x88, 0x0b, 0x88, 0x30, 0xe0, 0xdf, - 0xc7, 0xea, 0x02, 0x30, 0xe5, 0x03, 0x41, 0x91, 0xe5, 0xaf, 0x24, 0xe7, - 0x07, 0x44, 0xd1, 0x7e, 0x53, 0xa2, 0x7c, 0x2b, 0xe7, 0x3e, 0x53, 0xfc, - 0xf8, 0x78, 0xbf, 0x13, 0xf3, 0xe1, 0xd5, 0x53, 0x43, 0xbf, 0x5d, 0xc0, - 0x89, 0x44, 0xbe, 0x1a, 0xd3, 0x14, 0xc1, 0xbc, 0xe8, 0xf3, 0xef, 0xc1, - 0x8a, 0xd7, 0x23, 0xd8, 0xa6, 0x7b, 0x35, 0x6e, 0x7d, 0x8a, 0x5c, 0x11, - 0x42, 0x95, 0xaf, 0xaf, 0x07, 0xb6, 0xbf, 0x86, 0x81, 0xea, 0xb7, 0x30, - 0xd0, 0x39, 0x7d, 0x5e, 0x3f, 0xfe, 0x21, 0x58, 0x68, 0xdc, 0x02, 0xdc, - 0x0d, 0x40, 0x65, 0x17, 0x55, 0x45, 0x1b, 0x46, 0xbf, 0x1d, 0x17, 0xeb, - 0xde, 0x29, 0x7f, 0x9a, 0x62, 0xd9, 0xfa, 0x0b, 0xdc, 0xfc, 0x94, 0x2c, - 0x1f, 0x76, 0xba, 0x04, 0x4f, 0x1f, 0x9b, 0x27, 0x54, 0x3f, 0x05, 0xf1, - 0xf0, 0x30, 0x75, 0xe5, 0xe1, 0xa9, 0x2f, 0x9f, 0xb6, 0xf0, 0xed, 0x52, - 0xf2, 0x49, 0xd5, 0xff, 0x82, 0x9e, 0xb3, 0xb0, 0x6f, 0x4e, 0x03, 0x1f, - 0x5e, 0x4b, 0x1c, 0x7f, 0xa7, 0xac, 0xef, 0x36, 0x2a, 0xf4, 0xf9, 0x74, - 0xef, 0x29, 0x0b, 0xf9, 0xfb, 0xe4, 0x7a, 0x4a, 0xf0, 0x30, 0x16, 0xed, - 0x43, 0xef, 0xe4, 0xcd, 0x2d, 0xfd, 0x71, 0x3a, 0x7f, 0x2a, 0xa8, 0x1e, - 0x4e, 0x6d, 0x0d, 0x52, 0x9e, 0xf8, 0x7a, 0x3b, 0xe1, 0x1f, 0x64, 0x5d, - 0x41, 0x5c, 0xd5, 0xcd, 0x53, 0x3a, 0x07, 0xd2, 0x97, 0x3a, 0x2d, 0x9a, - 0x5b, 0xfe, 0x75, 0xab, 0x3c, 0xe5, 0x2b, 0x77, 0x02, 0xff, 0x30, 0xe5, - 0x2f, 0xf9, 0x1d, 0x0e, 0x80, 0x07, 0x2a, 0x4c, 0xd7, 0xe7, 0x3e, 0xa7, - 0x8d, 0x4e, 0x73, 0x7b, 0xf1, 0xed, 0xb7, 0x24, 0x48, 0xb7, 0x16, 0x7e, - 0xb3, 0xd4, 0xe8, 0x59, 0x1c, 0xee, 0x43, 0x21, 0xa0, 0xa9, 0xc7, 0xa8, - 0xc9, 0xd2, 0xbf, 0xbd, 0xc6, 0x84, 0x8f, 0xde, 0x9c, 0x4e, 0xe6, 0xfe, - 0x4e, 0xe9, 0xd4, 0xd3, 0xd8, 0xdc, 0xe3, 0xe7, 0x4c, 0xd7, 0x47, 0x23, - 0x8d, 0x5f, 0xb1, 0x1f, 0x1a, 0x20, 0x34, 0x7f, 0xe3, 0xda, 0xe6, 0x55, - 0xe3, 0xf0, 0x75, 0xf3, 0xf1, 0xf0, 0x50, 0xe4, 0x4f, 0xa6, 0x72, 0xe2, - 0xda, 0x1d, 0xcc, 0x9f, 0xff, 0xf2, 0x4b, 0xad, 0xcc, 0x74, 0x42, 0xed, - 0x4f, 0x4e, 0x55, 0x15, 0xfd, 0x97, 0x7c, 0xc6, 0x4d, 0x3e, 0xee, 0xf8, - 0x7c, 0x17, 0xcf, 0xf1, 0x73, 0x48, 0xfe, 0xad, 0x16, 0xfb, 0x1d, 0x59, - 0x26, 0xb9, 0xfe, 0x1c, 0x59, 0x3e, 0xc3, 0xaf, 0x6f, 0xa5, 0x96, 0xe3, - 0x79, 0x3f, 0x9d, 0xe2, 0xea, 0x94, 0xfa, 0x3f, 0x3d, 0x5d, 0xca, 0xfe, - 0x25, 0xaa, 0xdd, 0x14, 0xec, 0xbb, 0x51, 0xed, 0xfb, 0xd3, 0xec, 0x1d, - 0xc5, 0x2a, 0x3f, 0x2b, 0x3e, 0x4f, 0xb3, 0x57, 0x28, 0xf6, 0x6d, 0x36, - 0x35, 0x8a, 0xc3, 0xe8, 0x76, 0x98, 0xf4, 0x4f, 0xf7, 0x06, 0x3e, 0x6f, - 0x5e, 0xef, 0xcf, 0x3f, 0x4f, 0xab, 0x5f, 0xe1, 0x73, 0x40, 0xe8, 0x7f, - 0x1f, 0xdc, 0xfa, 0xdb, 0xbf, 0x7d, 0x6e, 0xbc, 0xf2, 0x79, 0x48, 0xff, - 0x69, 0x20, 0xf7, 0xdb, 0x87, 0x2d, 0xff, 0x0e, 0x7e, 0xaa, 0x77, 0x7f, - 0xaa, 0xdb, 0x3c, 0x1f, 0x3f, 0x4f, 0x4b, 0x76, 0xce, 0x3f, 0x48, 0x4e, - 0x9c, 0x3f, 0xfc, 0xd9, 0xbd, 0x9d, 0x66, 0x9e, 0x4f, 0x77, 0x80, 0xfc, - 0x7d, 0x1c, 0xd7, 0x0d, 0x8d, 0x19, 0xf4, 0xf8, 0xe0, 0x78, 0xd3, 0x2d, - 0xf3, 0xf5, 0xcd, 0x39, 0x84, 0x53, 0xe1, 0xe4, 0x95, 0xa6, 0x2f, 0xa7, - 0xb6, 0xaa, 0x80, 0x89, 0x4c, 0xc7, 0x9b, 0x0b, 0xf2, 0xbd, 0xcf, 0xbb, - 0x8b, 0x3b, 0x44, 0xb6, 0x05, 0x0e, 0xeb, 0x06, 0x36, 0xce, 0x4f, 0x95, - 0xef, 0xd4, 0xd3, 0xb1, 0xd3, 0xd3, 0xd7, 0x69, 0xc8, 0xf2, 0xd6, 0xdd, - 0x87, 0xe9, 0x9c, 0xf0, 0x7a, 0xfa, 0xf9, 0x7c, 0x00, 0x37, 0x80, 0x0a, - 0x0a, 0x6e, 0x17, 0x3e, 0x3c, 0x79, 0x3e, 0xcf, 0x7f, 0x7e, 0x17, 0x38, - 0xac, 0x7e, 0x2a, 0x99, 0xa6, 0x6d, 0xcb, 0xc9, 0xa7, 0xc5, 0x35, 0x78, - 0xda, 0x00, 0xf1, 0xf0, 0xbd, 0xb7, 0x0f, 0xbc, 0x93, 0xc6, 0x6e, 0xe5, - 0x34, 0xfe, 0x0d, 0x5f, 0xe7, 0x21, 0x98, 0xfc, 0xda, 0x4d, 0x9b, 0xea, - 0x87, 0x69, 0x4c, 0xf0, 0x0e, 0xf4, 0xa1, 0x06, 0xd0, 0xfc, 0xfc, 0x17, - 0xb9, 0xb8, 0xdb, 0xa5, 0x12, 0xaf, 0xdf, 0x1e, 0xf1, 0xe6, 0x17, 0x85, - 0xe1, 0xc5, 0x77, 0xc9, 0xa3, 0x2a, 0xbf, 0xf4, 0x9d, 0xe6, 0xcd, 0x2f, - 0xb3, 0xdb, 0xbf, 0xd4, 0x15, 0xdd, 0x8d, 0xc0, 0xcf, 0xb0, 0xaf, 0x13, - 0xe3, 0xbf, 0x7f, 0x22, 0x93, 0xff, 0xe3, 0x52, 0xf0, 0xe7, 0xb9, 0xa7, - 0xdf, 0x86, 0x7c, 0xbb, 0xdf, 0x38, 0x0f, 0x9c, 0xaa, 0x34, 0x45, 0x18, - 0x4e, 0x11, 0x92, 0xe3, 0x9d, 0x26, 0x83, 0x30, 0xd9, 0x83, 0x5f, 0x48, - 0xe9, 0x6f, 0x73, 0x94, 0xdf, 0x4a, 0xff, 0xf7, 0x06, 0xf7, 0xa7, 0x69, - 0x32, 0xe2, 0x4b, 0xc4, 0x7f, 0x67, 0xc8, 0x7e, 0xef, 0x1c, 0xeb, 0xe5, - 0x5d, 0x12, 0x3f, 0xdf, 0x81, 0x7d, 0xa3, 0x97, 0xfa, 0x70, 0x42, 0xfb, - 0x0b, 0x69, 0x55, 0x7c, 0x9a, 0x2e, 0x26, 0x7a, 0xe0, 0xef, 0xf5, 0xbf, - 0xdd, 0x4b, 0xfd, 0xe6, 0xf1, 0xfe, 0xbb, 0xc9, 0xd3, 0x9f, 0x33, 0x60, - 0xf0, 0x1c, 0x84, 0x25, 0xfe, 0x08, 0xa2, 0x73, 0x3f, 0xf8, 0x86, 0xdc, - 0x1f, 0x54, 0x75, 0x0b, 0xa7, 0xf2, 0xee, 0x31, 0xf8, 0xed, 0x1e, 0xa0, - 0xdf, 0x23, 0xb6, 0xfe, 0xf5, 0xdd, 0x6b, 0xcb, 0x9f, 0xdd, 0xb9, 0xb6, - 0xfc, 0xc7, 0xe8, 0xda, 0x4d, 0x8b, 0x7f, 0x76, 0xef, 0x6e, 0x6f, 0xfd, - 0x32, 0x3d, 0xfe, 0x2e, 0x71, 0xc1, 0xcf, 0xa4, 0xce, 0x9b, 0x29, 0x3c, - 0x9a, 0x56, 0x39, 0x7b, 0x9f, 0xf6, 0xac, 0x06, 0xde, 0x23, 0xfa, 0xa9, - 0xf7, 0xeb, 0x7f, 0x10, 0x59, 0xf4, 0x5e, 0x19, 0x4e, 0xfd, 0x2a, 0xbf, - 0xa6, 0x97, 0x7e, 0x5e, 0xf7, 0xbe, 0x3b, 0x85, 0x41, 0x0c, 0xfa, 0x5d, - 0x25, 0xe6, 0xfb, 0x9a, 0xc0, 0x2f, 0x13, 0xbe, 0x01, 0x82, 0xe9, 0x37, - 0x3f, 0xbe, 0x99, 0x62, 0xb6, 0xef, 0x9c, 0x65, 0x17, 0xa5, 0x9f, 0xff, - 0xd4, 0xc7, 0x4d, 0xf4, 0x25, 0x07, 0xfa, 0xf9, 0x84, 0xf2, 0xb7, 0x90, - 0xd1, 0x6f, 0xa3, 0xc5, 0x6d, 0xf9, 0xff, 0x2f, 0x0d, 0x1e, 0xae, 0x45, - 0x91, 0x4d, 0x61, 0xdb, 0x4f, 0x99, 0x53, 0x7e, 0x71, 0x54, 0x61, 0x6a, - 0xe4, 0x8f, 0xd6, 0xf3, 0xfb, 0xa5, 0x41, 0xf5, 0x2f, 0xed, 0xfb, 0xa9, - 0x2a, 0xca, 0x9f, 0x02, 0x90, 0x45, 0x7d, 0xa9, 0xe3, 0x4f, 0x6d, 0xfc, - 0x3d, 0x03, 0xa6, 0x77, 0x97, 0x6f, 0xfd, 0xcf, 0x8c, 0x9c, 0x3e, 0x08, - 0xf4, 0xa9, 0xef, 0x14, 0xe8, 0xff, 0xaa, 0x4c, 0xe9, 0x67, 0xfa, 0x8e, - 0xdf, 0x23, 0xfe, 0xfa, 0x80, 0x48, 0xff, 0xf1, 0xcf, 0x48, 0xa4, 0xf6, - 0xbb, 0xce, 0xfc, 0x92, 0xff, 0x8c, 0x24, 0xfa, 0xc7, 0x08, 0x06, 0xdf, - 0x3c, 0xf9, 0xe9, 0x3f, 0xa6, 0x63, 0xfe, 0x40, 0x4a, 0xa0, 0x7f, 0x46, - 0x29, 0xf9, 0x07, 0x0c, 0x41, 0x7f, 0x23, 0x67, 0x12, 0xfd, 0xcb, 0x99, - 0x7c, 0x9d, 0x48, 0xf8, 0xbf, 0x9c, 0xc9, 0xd7, 0x48, 0x74, 0xfd, 0x97, - 0x33, 0xf9, 0x16, 0x25, 0xfd, 0x43, 0x78, 0x93, 0xdf, 0x3f, 0xe1, 0xf9, - 0x40, 0x54, 0x88, 0x7f, 0x79, 0x94, 0x7f, 0xae, 0x41, 0x8d, 0x0f, 0xb8, - 0xcb, 0xfd, 0xfd, 0x67, 0x71, 0xfe, 0xe8, 0xee, 0x84, 0xff, 0xe7, 0x23, - 0xd1, 0xf7, 0x75, 0x26, 0xec, 0x3f, 0x1f, 0x81, 0xfe, 0xee, 0xae, 0xe4, - 0xef, 0x30, 0x08, 0xf5, 0x2b, 0x47, 0x23, 0x7f, 0xa3, 0xb1, 0xa9, 0x6f, - 0x94, 0xc1, 0xf9, 0x3f, 0x9f, 0x0c, 0xfe, 0x43, 0xfb, 0xa8, 0x97, 0x23, - 0x88, 0xff, 0xf6, 0xd1, 0xb2, 0x99, 0x2f, 0x8f, 0x23, 0x3e, 0x8f, 0x21, - 0x3e, 0xfe, 0x33, 0x0d, 0x21, 0x7e, 0x36, 0x62, 0xbc, 0xab, 0xdc, 0x2b, - 0x8c, 0xf3, 0xe2, 0xea, 0xbe, 0xf8, 0xea, 0xcd, 0xdf, 0x79, 0xd4, 0xe1, - 0x45, 0x5b, 0xcf, 0x02, 0xfa, 0x19, 0x94, 0x5e, 0x5b, 0x37, 0xfd, 0x39, - 0xe5, 0xfd, 0x96, 0x61, 0xd2, 0x9f, 0x17, 0x6a, 0x7e, 0xa3, 0x2a, 0x7f, - 0x5e, 0x9d, 0x7f, 0xce, 0xd4, 0xda, 0x6b, 0xea, 0xfb, 0x6d, 0xa1, 0xc8, - 0x97, 0x68, 0xfd, 0xb3, 0x08, 0xf6, 0x1f, 0xff, 0x8c, 0x04, 0xfb, 0x24, - 0x30, 0xf9, 0x6e, 0xe4, 0x22, 0xff, 0x19, 0xc9, 0xf5, 0x5a, 0x98, 0xf2, - 0x65, 0x8a, 0xbd, 0x16, 0xae, 0xbc, 0x66, 0x52, 0xbe, 0x21, 0x52, 0xf9, - 0xba, 0xe3, 0xf9, 0x9a, 0x93, 0xf9, 0xe2, 0x1c, 0xfa, 0x77, 0xe3, 0x3c, - 0xf4, 0xcf, 0xc8, 0xf9, 0x57, 0x82, 0x83, 0x6f, 0x24, 0xd8, 0xaf, 0xe6, - 0xd5, 0x2b, 0x41, 0xc1, 0x37, 0xc9, 0xdc, 0x57, 0x0b, 0xbf, 0x92, 0xe8, - 0xfe, 0x8c, 0x51, 0x97, 0xf7, 0xce, 0xf3, 0x8f, 0x33, 0xd6, 0xf2, 0x3b, - 0xf9, 0xd1, 0xe8, 0x5f, 0x7e, 0xf4, 0xe7, 0x11, 0x0c, 0xff, 0x97, 0x1f, - 0xfd, 0x39, 0xe4, 0xba, 0xfe, 0xcb, 0x8f, 0xfe, 0x0f, 0xf5, 0xa3, 0xc4, - 0xbf, 0xfc, 0xe8, 0xbf, 0xfc, 0xe8, 0xdf, 0x7d, 0x30, 0xe8, 0x77, 0x72, - 0xa3, 0xdc, 0xb7, 0x0a, 0xfb, 0xeb, 0x63, 0x4a, 0xff, 0xd3, 0x9c, 0x28, - 0xff, 0xcf, 0x47, 0xae, 0xdf, 0xce, 0x85, 0xb2, 0xff, 0x7c, 0xc4, 0xfa, - 0x97, 0x03, 0xfd, 0x06, 0xbe, 0xcf, 0xff, 0xf9, 0xf8, 0xfe, 0x3f, 0xc2, - 0x7d, 0xbe, 0x18, 0xcb, 0xfe, 0x60, 0x8b, 0xe7, 0x37, 0x6c, 0x99, 0x7d, - 0x3e, 0x69, 0xf2, 0xe7, 0x6e, 0x99, 0x7d, 0x78, 0x7e, 0xf1, 0xef, 0xb0, - 0x75, 0xf6, 0xe9, 0x24, 0xcb, 0xcf, 0x0f, 0x88, 0x8b, 0x77, 0xdc, 0x7e, - 0xf1, 0x5a, 0xda, 0x6f, 0x99, 0x05, 0xfb, 0x15, 0x33, 0x68, 0x5f, 0xd2, - 0xc8, 0xaf, 0x0f, 0x39, 0x7f, 0xbb, 0x36, 0x7e, 0xc3, 0x26, 0xbc, 0x0f, - 0xb7, 0xe1, 0xd5, 0x27, 0x27, 0x9f, 0x36, 0x1b, 0xd6, 0xaf, 0x55, 0xfc, - 0x8e, 0xdb, 0xf0, 0x5e, 0xd7, 0xdd, 0xd7, 0x99, 0x1d, 0x56, 0x8e, 0x17, - 0xfb, 0x79, 0xf3, 0x99, 0x38, 0xed, 0xfd, 0x70, 0xc7, 0x1d, 0xf3, 0xcf, - 0x85, 0x73, 0x9f, 0x57, 0xba, 0x6f, 0x63, 0x85, 0xfa, 0x3b, 0xb0, 0xe2, - 0x17, 0xce, 0xa0, 0xfe, 0x7c, 0x5a, 0x4e, 0x27, 0x86, 0x7e, 0x99, 0x9e, - 0xf1, 0x74, 0xb5, 0x42, 0x1d, 0x37, 0xe3, 0x6f, 0x45, 0xcf, 0xec, 0x77, - 0x16, 0xed, 0xce, 0xab, 0x35, 0x20, 0x1f, 0x77, 0xcb, 0xf0, 0x07, 0x12, - 0xef, 0xb2, 0xe8, 0xfd, 0xea, 0xa7, 0xcf, 0x1f, 0x5a, 0xf3, 0x8e, 0x23, - 0x93, 0x74, 0x3f, 0x19, 0xdd, 0x9f, 0xc9, 0x93, 0xd7, 0xed, 0xe4, 0x37, - 0xec, 0xfc, 0xff, 0xc6, 0x43, 0x04, 0xee, 0x76, 0x3f, 0xfe, 0x9b, 0xf1, - 0xac, 0x83, 0x0f, 0x45, 0x9e, 0x8e, 0x0f, 0x7d, 0x51, 0x25, 0x0f, 0xd3, - 0x6c, 0xdf, 0x03, 0x8a, 0xc3, 0xe5, 0xfb, 0x13, 0x45, 0x8b, 0x6a, 0x3a, - 0x78, 0x2c, 0xbe, 0x3f, 0xe2, 0x0a, 0xf7, 0xc1, 0xf3, 0x27, 0x69, 0xab, - 0xd2, 0xdb, 0xc1, 0xd5, 0xaf, 0x1e, 0x18, 0x70, 0x87, 0x3f, 0xf1, 0xef, - 0xe1, 0xce, 0xc0, 0x07, 0x3f, 0x8d, 0xb3, 0x38, 0x77, 0x1a, 0xd0, 0x98, - 0x9b, 0x16, 0xa7, 0x64, 0x7c, 0x2c, 0xe3, 0xc1, 0x4f, 0x1f, 0x9c, 0xaa, - 0x89, 0x03, 0x90, 0x09, 0xd6, 0xf7, 0xd3, 0x00, 0xda, 0x72, 0x1a, 0x07, - 0x9d, 0x8e, 0x03, 0x70, 0xfd, 0x11, 0x30, 0xeb, 0x76, 0xe4, 0xd9, 0x0f, - 0x0f, 0x0e, 0xf8, 0xf4, 0xe1, 0xc9, 0xa7, 0xaf, 0x9f, 0x53, 0xf0, 0xc9, - 0xae, 0xff, 0x6f, 0x5c, 0xd8, 0xf4, 0xcd, 0x5a, 0x10, 0x7c, 0x9b, 0x16, - 0x7c, 0x7e, 0xbc, 0xe2, 0x67, 0xeb, 0x01, 0x08, 0xc9, 0x12, 0x40, 0x8f, - 0x3f, 0x90, 0x06, 0xdc, 0xbc, 0xf9, 0x24, 0x37, 0x4e, 0xf5, 0x65, 0x0d, - 0x78, 0x42, 0xfd, 0xb7, 0xb2, 0x48, 0xe6, 0xef, 0xce, 0x8b, 0xba, 0xf1, - 0xcb, 0x3f, 0x96, 0xa7, 0xfd, 0xcc, 0x2e, 0xf6, 0xf7, 0x6e, 0x16, 0x60, - 0x3c, 0x1d, 0xa6, 0x5b, 0x16, 0x79, 0xed, 0xff, 0x41, 0xcd, 0xd0, 0xe6, - 0x2e, 0x26, 0x2f, 0xce, 0x15, 0xb9, 0x51, 0x0c, 0x04, 0xe3, 0xc0, 0x3a, - 0x14, 0x2d, 0x50, 0xfd, 0xa8, 0xa8, 0xe2, 0xeb, 0x74, 0xed, 0x4e, 0xfa, - 0xf0, 0x7e, 0xa3, 0xff, 0xc3, 0xd4, 0xb7, 0xfa, 0x9b, 0x6d, 0xc3, 0x93, - 0xc9, 0x9b, 0xe8, 0xa1, 0x3f, 0xd1, 0xe3, 0x45, 0x8b, 0xd3, 0x89, 0x28, - 0x75, 0xe4, 0x54, 0xe5, 0x0d, 0x72, 0x11, 0xbc, 0x6c, 0xf2, 0x54, 0xa4, - 0xb7, 0xa3, 0x98, 0x7f, 0x4e, 0x6b, 0x1f, 0x5b, 0xa2, 0x5f, 0xb2, 0xfd, - 0xed, 0xef, 0x18, 0xb0, 0x7f, 0xfd, 0xac, 0x9b, 0xff, 0xff, 0xff, 0xef, - 0x46, 0x95, 0x53, 0x51, 0x3d, 0x8d, 0xe7, 0xfd, 0x1d, 0xf6, 0xc1, 0xd9, - 0xff, 0x53, 0xce, 0x0b, 0xe1, 0xde, 0x09, 0xfd, 0xdf, 0xe9, 0xd4, 0x90, - 0x7f, 0x92, 0x63, 0x6b, 0x7e, 0x11, 0x1d, 0x7f, 0xd3, 0xc5, 0xd2, 0xab, - 0xff, 0x29, 0x22, 0xcc, 0x3f, 0x99, 0xf4, 0xef, 0x2f, 0xc0, 0xcb, 0xff, - 0x41, 0x02, 0xfc, 0x0b, 0xa8, 0xf8, 0x9b, 0x8a, 0xef, 0xf6, 0x7f, 0x8a, - 0xf8, 0x6e, 0x5c, 0x68, 0xff, 0xf0, 0xdb, 0x1c, 0xdb, 0x24, 0xff, 0x0f, - 0x92, 0xdf, 0x5f, 0x42, 0xc6, 0xdf, 0x54, 0x80, 0x37, 0x7f, 0x3c, 0xe2, - 0xff, 0x66, 0x22, 0x5c, 0x41, 0xe6, 0x6f, 0x24, 0xc2, 0xc6, 0x3f, 0x32, - 0x15, 0x7f, 0xbe, 0x10, 0xff, 0x02, 0x42, 0xfe, 0xa6, 0x42, 0xbc, 0xfe, - 0xe3, 0x5b, 0x90, 0xcf, 0x1d, 0xfd, 0x1c, 0x7c, 0xe1, 0xa2, 0x1f, 0xe5, - 0xb3, 0x4f, 0x7f, 0x8d, 0xac, 0xee, 0xff, 0x71, 0xcd, 0x6d, 0x3d, 0xe5, - 0xd3, 0x79, 0x58, 0xff, 0xe4, 0x3a, 0xa7, 0xa4, 0x2d, 0xa7, 0xe3, 0xc6, - 0x1b, 0x90, 0x58, 0x7f, 0x49, 0x56, 0xe7, 0x7e, 0xe0, 0xb4, 0xe9, 0xaf, - 0x8d, 0x17, 0xbe, 0xe5, 0xd0, 0xd1, 0x6f, 0xcb, 0xf8, 0x6f, 0xf9, 0xfe, - 0xb3, 0x13, 0x78, 0x78, 0x7c, 0x38, 0x45, 0x4e, 0x1e, 0xfa, 0xd3, 0x55, - 0x67, 0xfe, 0x63, 0xda, 0x66, 0xce, 0xad, 0xfc, 0xb3, 0x67, 0x90, 0xbe, - 0xd3, 0xbc, 0xf7, 0x6f, 0x56, 0xbe, 0xf7, 0xc5, 0x17, 0xbf, 0x25, 0x11, - 0x7f, 0x31, 0xeb, 0xf6, 0x99, 0x49, 0xb7, 0x97, 0x37, 0xa9, 0xfd, 0x23, - 0x9c, 0x55, 0x3b, 0xdd, 0xd0, 0xf6, 0x79, 0xc5, 0x32, 0x9e, 0xe4, 0xe8, - 0xdb, 0x53, 0xf6, 0x66, 0x9a, 0x3b, 0xfd, 0xe8, 0x80, 0xf0, 0x77, 0x04, - 0xf9, 0xa4, 0x8d, 0xa6, 0x7a, 0x45, 0x1a, 0x9b, 0x57, 0xa7, 0x5e, 0x3f, - 0xba, 0x6b, 0xea, 0xb5, 0x61, 0xac, 0x6f, 0x1a, 0x70, 0xfa, 0x59, 0x83, - 0x4e, 0xcf, 0xe2, 0xa4, 0x04, 0x0f, 0x7e, 0x7e, 0x9b, 0x15, 0xfe, 0xe1, - 0xc1, 0xbb, 0x2b, 0xca, 0x74, 0x2a, 0xfb, 0xbb, 0xbb, 0xb6, 0xde, 0x5d, - 0xae, 0x05, 0x3e, 0x4f, 0xe3, 0x3e, 0x9f, 0x5c, 0xad, 0xf5, 0x40, 0xc0, - 0x0f, 0x7f, 0xf6, 0x0a, 0xbf, 0x7e, 0xc8, 0xa7, 0xd3, 0xd8, 0xcb, 0x32, - 0x1d, 0x6f, 0x8f, 0x28, 0x14, 0x2e, 0x1f, 0xa0, 0x87, 0xe9, 0x62, 0xa4, - 0xe7, 0x63, 0xd8, 0xeb, 0xbf, 0x7c, 0x66, 0x54, 0xea, 0xf5, 0x51, 0xeb, - 0xdb, 0xf5, 0x8e, 0xde, 0xab, 0x64, 0xfc, 0xda, 0xb0, 0xa8, 0xfd, 0xbb, - 0x0c, 0x8b, 0x7e, 0x2c, 0x72, 0x5f, 0x1c, 0x39, 0x7d, 0xbc, 0xdf, 0x1b, - 0xf6, 0xe3, 0x9b, 0xec, 0xce, 0xee, 0x6f, 0x1b, 0xf4, 0xbc, 0xbf, 0xfb, - 0x53, 0x11, 0x04, 0xdf, 0x44, 0x1c, 0x50, 0x56, 0xfd, 0x1a, 0x51, 0x14, - 0xdb, 0x34, 0x7d, 0x90, 0xfd, 0xcf, 0x2d, 0x3b, 0xf9, 0x76, 0xe1, 0xfa, - 0x19, 0x12, 0x3b, 0x8d, 0x48, 0x16, 0xd9, 0xbb, 0xcb, 0xe2, 0x5e, 0x4a, - 0xe1, 0x24, 0x51, 0x6d, 0x3d, 0x8d, 0x8b, 0x4e, 0x63, 0x93, 0x7e, 0xde, - 0xc4, 0xa0, 0xc1, 0xce, 0xaf, 0x6e, 0xb7, 0xac, 0x7d, 0x7a, 0xf5, 0xdc, - 0x0f, 0x0f, 0xa9, 0xef, 0x74, 0x53, 0xf5, 0x7a, 0x02, 0x78, 0x9f, 0xd6, - 0xb9, 0x5d, 0xd0, 0xfe, 0x59, 0xb9, 0xbb, 0xb7, 0x6f, 0x4d, 0xb3, 0x3a, - 0x2f, 0xfa, 0xfe, 0x5e, 0x25, 0x3e, 0xb8, 0xc7, 0xee, 0x7e, 0x41, 0x5d, - 0x9c, 0xd7, 0x8d, 0xef, 0x78, 0x0f, 0xb7, 0xc5, 0xea, 0x13, 0x96, 0xd3, - 0x9d, 0xa9, 0x0f, 0xd9, 0x44, 0x8b, 0x22, 0xb8, 0x0f, 0xa2, 0xde, 0x4e, - 0x64, 0x7e, 0x88, 0x6e, 0xb0, 0xbe, 0xd2, 0xf4, 0x9f, 0x77, 0x51, 0x5c, - 0xbf, 0x38, 0x88, 0xfa, 0x36, 0x0b, 0xe5, 0x04, 0x81, 0x3f, 0x4d, 0x07, - 0xdd, 0x6e, 0x18, 0x1b, 0x6e, 0x3a, 0xf4, 0x97, 0xdf, 0x49, 0x73, 0xba, - 0xdf, 0x77, 0xca, 0xf8, 0x67, 0xe8, 0x4d, 0x00, 0xf8, 0x73, 0x67, 0xcf, - 0x1f, 0x52, 0x75, 0xb4, 0xa2, 0x9f, 0x06, 0xd5, 0xff, 0xfa, 0x30, 0xdd, - 0x21, 0xb8, 0x7f, 0x9e, 0xc2, 0xfb, 0x3d, 0xb5, 0xe8, 0x09, 0x83, 0xe7, - 0x9b, 0x68, 0x4c, 0x89, 0xbd, 0xdf, 0x36, 0xfb, 0xd7, 0xdb, 0x35, 0x2b, - 0xcf, 0xf7, 0xb0, 0x4c, 0x53, 0x99, 0x77, 0xf4, 0xfc, 0x2f, 0x4b, 0xe6, - 0x04, 0xee, 0xc5, 0xc5, 0x36, 0x4f, 0x53, 0xa1, 0x0f, 0x27, 0x27, 0x9f, - 0xae, 0x67, 0xf4, 0x81, 0xca, 0xf8, 0xd5, 0xc3, 0x74, 0xc3, 0x0b, 0x70, - 0x5d, 0xef, 0x16, 0xb5, 0x4e, 0x12, 0x5c, 0x3d, 0x84, 0x20, 0x0a, 0xb8, - 0xcf, 0x62, 0x7e, 0x76, 0x22, 0xe2, 0xb9, 0x95, 0x77, 0x94, 0x7a, 0xc8, - 0x9c, 0xf1, 0x21, 0x9a, 0xee, 0x2c, 0xb8, 0x29, 0xef, 0x7d, 0x15, 0x2b, - 0x70, 0x20, 0xcf, 0x8f, 0xe3, 0xba, 0x6e, 0xa7, 0x99, 0x58, 0x10, 0xaf, - 0x4d, 0x93, 0x0f, 0x37, 0x7d, 0x3b, 0x15, 0x59, 0xe9, 0x34, 0xf1, 0xe4, - 0x97, 0x6f, 0x13, 0xb3, 0x4f, 0x47, 0xae, 0xd7, 0x5f, 0x69, 0x93, 0x4d, - 0xeb, 0xe2, 0x07, 0xd0, 0xb7, 0x00, 0x74, 0x2f, 0x7a, 0xa8, 0x6e, 0x13, - 0xb2, 0xc5, 0xad, 0x3b, 0x0d, 0x08, 0xa8, 0x80, 0xa7, 0x93, 0xaf, 0xb7, - 0x13, 0xdc, 0x27, 0xf3, 0xd3, 0xfb, 0x40, 0xb9, 0xeb, 0xb6, 0x2c, 0x8b, - 0xaa, 0x01, 0x1d, 0x1d, 0xfd, 0xaf, 0x29, 0xf4, 0x9b, 0x0f, 0xe9, 0xf6, - 0xe6, 0xe1, 0x03, 0xf5, 0x9e, 0xe2, 0x23, 0xa7, 0x01, 0x04, 0x4c, 0x41, - 0x2d, 0x40, 0x29, 0xff, 0xd2, 0x02, 0x4b, 0x06, 0x8c, 0x08, 0x89, 0xdf, - 0x6e, 0xc8, 0x7a, 0xf8, 0x33, 0x81, 0x12, 0xcf, 0xdb, 0x57, 0x6f, 0x06, - 0xec, 0x77, 0xf3, 0x99, 0xc3, 0x1f, 0x56, 0xf3, 0xef, 0x81, 0x96, 0x71, - 0x17, 0x04, 0x3d, 0x74, 0xa3, 0xee, 0x0f, 0x69, 0x01, 0xd6, 0x77, 0x7f, - 0xa4, 0x4b, 0x9c, 0x6c, 0x42, 0x3c, 0x10, 0xcd, 0x22, 0x07, 0x4c, 0xff, - 0x3d, 0x2d, 0xc0, 0x0e, 0x38, 0x9f, 0x67, 0xf7, 0xf9, 0xe4, 0x1d, 0xa7, - 0x8b, 0x7f, 0x27, 0x11, 0xbc, 0x61, 0xf5, 0x03, 0x90, 0xe4, 0xf8, 0x1e, - 0xc7, 0x4e, 0x21, 0x1a, 0x60, 0xe5, 0x5d, 0x6f, 0x26, 0x53, 0x71, 0x9a, - 0x8a, 0xeb, 0x49, 0x26, 0xe5, 0xf9, 0x52, 0x99, 0xa6, 0x1f, 0x27, 0x47, - 0xeb, 0x57, 0x5f, 0x55, 0xa6, 0xfc, 0xc1, 0x1f, 0x4a, 0xbf, 0x8a, 0xa7, - 0xcb, 0x66, 0x80, 0x2c, 0x1f, 0x37, 0xee, 0xa6, 0xba, 0x37, 0x3b, 0x99, - 0x8a, 0xe7, 0xeb, 0x5c, 0xef, 0xd7, 0x02, 0xdd, 0xae, 0x35, 0x78, 0x52, - 0xda, 0x38, 0x8d, 0x9b, 0x71, 0x42, 0xad, 0x6e, 0x26, 0x07, 0x5a, 0x97, - 0x45, 0xd3, 0x8c, 0xbf, 0x97, 0xb0, 0x6b, 0x7f, 0xe0, 0x00, 0x71, 0xba, - 0x69, 0xe9, 0x2e, 0x4b, 0xef, 0x84, 0xe8, 0x8f, 0x2c, 0xef, 0x62, 0x05, - 0xd2, 0xc3, 0x07, 0x1d, 0x58, 0xd1, 0xbf, 0x3e, 0x88, 0x05, 0xf0, 0x11, - 0x4f, 0x59, 0x01, 0x30, 0xa2, 0x93, 0x5d, 0x03, 0xbf, 0x7f, 0x4f, 0x15, - 0xb8, 0xdf, 0x56, 0x55, 0x3d, 0xec, 0xcc, 0x87, 0x77, 0x49, 0xc9, 0x93, - 0xf9, 0xbe, 0xe3, 0xf4, 0xec, 0xc7, 0xfe, 0xfc, 0xe4, 0x2c, 0x26, 0xdf, - 0xd2, 0xe6, 0x49, 0x5e, 0xf4, 0xb7, 0x7b, 0x41, 0x40, 0x74, 0xfe, 0x03, - 0x78, 0x09, 0x78, 0xa3, 0xe9, 0x66, 0xfa, 0x5b, 0x38, 0x77, 0x8f, 0xfe, - 0xfe, 0x02, 0x82, 0xc1, 0x6a, 0x04, 0x05, 0x40, 0x62, 0xef, 0x97, 0x01, - 0xbf, 0x7d, 0x1d, 0x89, 0x2f, 0x6a, 0xcb, 0xa4, 0xa1, 0xc1, 0x8d, 0x60, - 0xb7, 0x8b, 0x3d, 0x6e, 0x01, 0xe5, 0x84, 0x22, 0xd0, 0x10, 0x07, 0x68, - 0x42, 0x56, 0x00, 0x3f, 0xf4, 0x16, 0x78, 0x71, 0x17, 0x7c, 0x00, 0x5e, - 0xe4, 0xd2, 0x02, 0xaf, 0xea, 0xfd, 0x5e, 0x4a, 0x01, 0xff, 0x71, 0x3d, - 0x80, 0x93, 0xde, 0x44, 0xeb, 0xb5, 0xbb, 0x4f, 0xff, 0x00, 0x9a, 0x30, - 0xbf, 0x2f, 0xac, 0x7e, 0x10, 0x06, 0x20, 0x33, 0x39, 0x30, 0x82, 0xfc, - 0xb4, 0xbc, 0xeb, 0x41, 0xf2, 0x73, 0x1f, 0xb0, 0xb9, 0xa8, 0x7e, 0x4f, - 0x05, 0xe0, 0xc6, 0xf7, 0x19, 0xd4, 0x94, 0x34, 0x3d, 0xa3, 0x74, 0xba, - 0xa1, 0x14, 0x3e, 0xa3, 0x34, 0x19, 0xde, 0xa7, 0x2c, 0xe7, 0xbe, 0xea, - 0x6c, 0x4a, 0x6b, 0x9c, 0xf4, 0xeb, 0x01, 0xdb, 0xb1, 0x68, 0x6f, 0x86, - 0xfd, 0x69, 0x31, 0xf9, 0x74, 0x87, 0x4d, 0x7c, 0xbf, 0x21, 0xee, 0x16, - 0xbc, 0xdd, 0xc3, 0xb4, 0xbb, 0x5b, 0xb9, 0xc7, 0x54, 0x77, 0x65, 0x01, - 0x91, 0x9b, 0xff, 0x36, 0x7c, 0xf8, 0x8c, 0x85, 0x78, 0x5d, 0x95, 0xfe, - 0x4e, 0x6a, 0x70, 0xf8, 0xc3, 0xaa, 0xc1, 0x13, 0xcd, 0x9f, 0xc5, 0xec, - 0x26, 0x65, 0xef, 0x84, 0xec, 0x0f, 0xa9, 0x19, 0xd3, 0x75, 0x50, 0xa7, - 0xa7, 0x7b, 0x8c, 0xe2, 0x57, 0x97, 0xb3, 0xfd, 0x66, 0x8a, 0x20, 0xb9, - 0xf5, 0xf3, 0xaa, 0xb3, 0x67, 0x0c, 0x9e, 0x16, 0x39, 0x4d, 0x48, 0x01, - 0x02, 0xdc, 0x52, 0xfa, 0x29, 0xb3, 0x79, 0xba, 0x60, 0xfe, 0xcb, 0x72, - 0xaf, 0xe4, 0x00, 0x4c, 0x7d, 0xcb, 0xf1, 0x9f, 0x16, 0x43, 0x45, 0x71, - 0x30, 0x5d, 0x1a, 0x59, 0x00, 0x8e, 0x64, 0xf5, 0xdd, 0x3b, 0xdc, 0x19, - 0x74, 0x1f, 0xb0, 0x00, 0x0a, 0x16, 0xb4, 0xf9, 0x2d, 0x80, 0xf8, 0xbd, - 0x24, 0xb7, 0xff, 0xc3, 0x4a, 0xee, 0xdd, 0xd4, 0xf0, 0xef, 0x25, 0x01, - 0xf0, 0xe0, 0xef, 0x2e, 0xb0, 0x13, 0x23, 0xa7, 0x9b, 0x99, 0x7f, 0x7c, - 0x83, 0xbe, 0xf9, 0xcc, 0xc0, 0xee, 0x4f, 0x3f, 0x9d, 0xa2, 0x38, 0xf5, - 0x5e, 0x15, 0x33, 0xf6, 0x9e, 0xa5, 0xdd, 0xe2, 0x9f, 0x1d, 0x08, 0x7f, - 0x1f, 0x34, 0xa0, 0x8e, 0xbf, 0x6f, 0xb8, 0xff, 0x2e, 0x16, 0x79, 0x48, - 0x7c, 0xbf, 0xbc, 0x4b, 0xf7, 0x2d, 0xe7, 0xbf, 0x8d, 0xd5, 0x3e, 0xa5, - 0x00, 0xcd, 0xb4, 0xea, 0x38, 0xac, 0x41, 0x28, 0x0e, 0xda, 0x9e, 0x06, - 0xb5, 0x82, 0x78, 0x78, 0x1e, 0x53, 0x7b, 0xb1, 0xc4, 0xaf, 0xf1, 0x9d, - 0xff, 0xaf, 0xbd, 0xaf, 0x6d, 0x6b, 0x1b, 0x59, 0x16, 0xfc, 0x9e, 0x5f, - 0xa1, 0xd1, 0xcd, 0x93, 0xd8, 0x83, 0x31, 0x98, 0xbc, 0x1e, 0x18, 0x92, - 0x87, 0x40, 0x32, 0xe1, 0x4e, 0x12, 0xb8, 0x31, 0x99, 0xec, 0x5d, 0x0e, - 0x0f, 0xc8, 0xb6, 0x00, 0x4d, 0x8c, 0xe5, 0x23, 0xc9, 0x21, 0x0c, 0xc7, - 0xfb, 0xdb, 0xb7, 0xaa, 0xba, 0x5b, 0xea, 0x57, 0x49, 0xc6, 0x26, 0x21, - 0x7b, 0x37, 0x1f, 0x14, 0x2c, 0x75, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, - 0x57, 0x57, 0x55, 0x27, 0xb4, 0xe5, 0x64, 0xb7, 0x70, 0x92, 0xf2, 0x3e, - 0x1e, 0xe3, 0x4b, 0xdc, 0x90, 0x03, 0x90, 0xb0, 0x6a, 0x2b, 0x70, 0x70, - 0x09, 0x7a, 0x53, 0x98, 0x9d, 0xc7, 0x03, 0x76, 0x03, 0x5a, 0xf0, 0x35, - 0x88, 0x86, 0x38, 0xee, 0x6d, 0xef, 0x00, 0x26, 0x07, 0xe3, 0x05, 0xda, - 0xea, 0xf3, 0x42, 0x11, 0x57, 0xd6, 0xb8, 0x2a, 0xe6, 0x9d, 0xc5, 0xcc, - 0x60, 0x37, 0xfa, 0xe2, 0x89, 0x09, 0x96, 0xe6, 0xf6, 0xbe, 0xe1, 0x22, - 0x36, 0x07, 0xb3, 0xb1, 0x87, 0xc4, 0x12, 0xc1, 0x60, 0x00, 0x98, 0x1f, - 0x53, 0xb8, 0x27, 0x85, 0xc7, 0xa8, 0xc3, 0x3e, 0xcb, 0x94, 0xad, 0x39, - 0x83, 0xca, 0x23, 0xc4, 0x6f, 0x2d, 0xea, 0xa0, 0xb0, 0xb7, 0x89, 0x0e, - 0x62, 0xff, 0xee, 0xc0, 0x5c, 0x2d, 0x1b, 0x8c, 0x2e, 0xe1, 0x4c, 0x23, - 0xe1, 0xbd, 0x27, 0xe6, 0xba, 0xcd, 0x01, 0x89, 0xbe, 0xc3, 0x80, 0xa4, - 0xd9, 0x15, 0x7a, 0x5b, 0xf7, 0x27, 0x49, 0x1a, 0x27, 0xeb, 0xde, 0x38, - 0xa6, 0x70, 0x83, 0x7a, 0xc3, 0x40, 0x77, 0x37, 0xd3, 0xcc, 0xbe, 0x6b, - 0x22, 0x73, 0x27, 0x8f, 0x9a, 0x08, 0xf9, 0x38, 0xfd, 0x20, 0x8d, 0x80, - 0xdd, 0xb2, 0x08, 0x12, 0x48, 0xa0, 0x33, 0x20, 0x87, 0x6b, 0xd8, 0x6a, - 0x93, 0xe4, 0xc4, 0xfb, 0xd3, 0x60, 0x07, 0xc8, 0xc4, 0x0e, 0x67, 0xeb, - 0xb4, 0x56, 0xcc, 0x47, 0xae, 0x86, 0xc7, 0x3d, 0xde, 0xc3, 0x75, 0x0f, - 0xb8, 0x02, 0xcf, 0x2e, 0x08, 0x16, 0x6c, 0x2d, 0x15, 0x30, 0xb4, 0xd9, - 0x04, 0x7e, 0x06, 0x04, 0x86, 0xc1, 0x19, 0x59, 0x37, 0x4f, 0x91, 0x37, - 0xc2, 0x04, 0x54, 0x0a, 0x6e, 0x6b, 0xed, 0xc7, 0x17, 0x3d, 0x90, 0xcb, - 0x03, 0xa6, 0x55, 0x4b, 0x51, 0x63, 0x65, 0x08, 0xbc, 0x8f, 0x69, 0x5d, - 0xd8, 0x1a, 0x04, 0x63, 0x5c, 0xa6, 0xd6, 0x3d, 0xe6, 0xe3, 0x91, 0x0a, - 0xf0, 0xd4, 0xcf, 0xf4, 0x3c, 0xbe, 0x4c, 0x99, 0xc1, 0x15, 0x74, 0xa0, - 0x90, 0x05, 0xa1, 0x44, 0x23, 0x0f, 0x4a, 0xa2, 0x9c, 0x06, 0x2a, 0x81, - 0x04, 0xaf, 0x68, 0x08, 0x76, 0xdc, 0xe3, 0x38, 0x4d, 0xd1, 0x0a, 0xdb, - 0x42, 0x22, 0x9e, 0x46, 0x67, 0x98, 0xd7, 0x8f, 0x0e, 0x42, 0x68, 0xaf, - 0x4d, 0xb6, 0x26, 0xd0, 0x93, 0xce, 0x60, 0x1f, 0x9d, 0xe2, 0x8a, 0xc9, - 0xd6, 0xa5, 0xb6, 0xb7, 0x87, 0xfb, 0x83, 0xcb, 0x28, 0x85, 0x7a, 0xec, - 0x94, 0x47, 0xc3, 0xb9, 0x9e, 0x4b, 0xfb, 0x8f, 0x11, 0xff, 0x1a, 0xaa, - 0x37, 0x56, 0xd9, 0x92, 0x3b, 0xab, 0xb2, 0xf5, 0xe2, 0xde, 0x1d, 0x97, - 0xfa, 0x30, 0xc7, 0x6e, 0x4c, 0xf7, 0x7f, 0xdd, 0x59, 0xba, 0x5f, 0x10, - 0x67, 0x09, 0xc6, 0xfa, 0x9e, 0x43, 0x40, 0xd8, 0x0c, 0xc2, 0xaf, 0x1c, - 0x95, 0xfa, 0xe6, 0x8f, 0xf0, 0x6b, 0x38, 0x8c, 0xc7, 0x20, 0x53, 0xde, - 0xc7, 0x83, 0xf0, 0x7b, 0x4a, 0xf4, 0xd7, 0x23, 0x66, 0xb5, 0xce, 0xc8, - 0xf0, 0x2d, 0xb0, 0x00, 0x71, 0x31, 0xc1, 0xcb, 0x71, 0x41, 0x23, 0x40, - 0xa1, 0x1e, 0x44, 0x23, 0xd0, 0x22, 0x83, 0x24, 0x8a, 0x27, 0x28, 0xc3, - 0x7b, 0x93, 0xb3, 0x33, 0x52, 0x7f, 0xe3, 0xd8, 0x2d, 0xda, 0x66, 0xdc, - 0x98, 0x59, 0xbc, 0x4f, 0xf2, 0x11, 0x99, 0x75, 0x00, 0xe8, 0xaa, 0xf9, - 0x3e, 0xdd, 0xd2, 0xbe, 0xcc, 0xc3, 0x5f, 0x6a, 0x8f, 0x44, 0x17, 0x4d, - 0x30, 0x2c, 0xda, 0x10, 0xbb, 0xb8, 0x0f, 0xc4, 0xe8, 0x02, 0xb8, 0xef, - 0x39, 0x24, 0x9f, 0xd1, 0x98, 0x94, 0x9f, 0x9f, 0xe3, 0x25, 0xe4, 0xb0, - 0xcc, 0x00, 0x0e, 0x4c, 0x94, 0x7f, 0x65, 0x36, 0xd5, 0x28, 0xf1, 0xc8, - 0xde, 0xca, 0xe2, 0x22, 0x25, 0xe5, 0xa1, 0xea, 0xa0, 0x9e, 0xee, 0x4f, - 0xe6, 0x69, 0x0c, 0x54, 0xe8, 0x17, 0x30, 0xcc, 0x38, 0xd4, 0xe2, 0xb0, - 0x4d, 0x00, 0x17, 0x0e, 0x63, 0xed, 0x3b, 0x33, 0xd4, 0xf0, 0x06, 0xf1, - 0x5f, 0xc0, 0xd5, 0xe1, 0x39, 0xcb, 0x7f, 0x07, 0x87, 0x2c, 0xbf, 0xae, - 0x3b, 0xa3, 0x2b, 0x28, 0x98, 0xfb, 0xe2, 0x71, 0x8c, 0xe7, 0x0a, 0x95, - 0x9a, 0xfb, 0x02, 0x09, 0x9f, 0x20, 0x30, 0x3d, 0x84, 0xcb, 0xdf, 0xda, - 0x39, 0x98, 0x40, 0xc4, 0x95, 0x79, 0x1b, 0x1e, 0x10, 0x34, 0x4c, 0x6b, - 0x9c, 0xc6, 0x33, 0x25, 0x33, 0xbc, 0x9d, 0xab, 0x98, 0xca, 0x1d, 0x41, - 0x97, 0x6f, 0xf9, 0xba, 0xe4, 0x72, 0x57, 0xd0, 0xb9, 0x6f, 0x3c, 0xb6, - 0xa4, 0x62, 0x2a, 0x1b, 0x9a, 0xf7, 0xaf, 0xdf, 0x7b, 0xef, 0x5c, 0x65, - 0xe6, 0x72, 0xa8, 0x5d, 0xfa, 0x7f, 0x8a, 0x8e, 0x14, 0x21, 0x56, 0x45, - 0xc8, 0x8f, 0xce, 0x42, 0x73, 0x51, 0xb2, 0xf3, 0x3f, 0x8a, 0x23, 0xdf, - 0x76, 0x6f, 0x89, 0x21, 0x57, 0xff, 0x67, 0x31, 0x24, 0xd0, 0x71, 0x56, - 0x7e, 0xbc, 0xd5, 0x68, 0x84, 0x70, 0x21, 0x0e, 0xf6, 0xb5, 0x89, 0x7f, - 0x53, 0x32, 0x0f, 0xa3, 0xb4, 0x94, 0xac, 0xef, 0xe0, 0xbb, 0xb7, 0xc7, - 0xce, 0xef, 0x16, 0xcf, 0xa3, 0xd1, 0xf7, 0xe6, 0xd1, 0x9b, 0x92, 0xc9, - 0x19, 0xa2, 0x91, 0x07, 0xc3, 0x80, 0xea, 0xe9, 0xdd, 0x4e, 0xa8, 0x46, - 0xeb, 0x67, 0x21, 0x52, 0x30, 0x0c, 0x92, 0x8b, 0x32, 0x2a, 0xfd, 0x0e, - 0x9a, 0xe8, 0x9f, 0xd1, 0x20, 0x8c, 0xbd, 0x03, 0x76, 0x20, 0x31, 0xfb, - 0x64, 0xbd, 0xa5, 0xd9, 0xfa, 0xe6, 0xfb, 0xce, 0x56, 0x97, 0x06, 0x37, - 0x47, 0x10, 0x67, 0x70, 0x3c, 0x3e, 0x8f, 0xb3, 0x52, 0x26, 0x7d, 0x93, - 0x84, 0xe1, 0xdf, 0xa0, 0x97, 0x06, 0x63, 0xbc, 0x76, 0xe3, 0xe7, 0xa2, - 0xfd, 0x5d, 0xe0, 0xef, 0xd2, 0x74, 0x10, 0x9c, 0xc6, 0x78, 0xb0, 0xfc, - 0xc6, 0x9d, 0xed, 0x68, 0x2e, 0x41, 0x30, 0xfc, 0x39, 0x96, 0x94, 0x8b, - 0xf0, 0x22, 0x4e, 0x4a, 0x89, 0xb4, 0x7d, 0xd5, 0x87, 0xfd, 0x51, 0x77, - 0xe7, 0xe3, 0xd6, 0xfb, 0xbb, 0xb2, 0x5c, 0xef, 0xfc, 0x2c, 0x4c, 0xd8, - 0x9b, 0x9c, 0x1d, 0x27, 0x21, 0x3a, 0xb3, 0x95, 0x07, 0xbc, 0x41, 0x39, - 0x90, 0xb5, 0xe1, 0xe5, 0x5d, 0x21, 0x70, 0xf0, 0xd3, 0xac, 0x62, 0x33, - 0x85, 0x13, 0xbf, 0x3d, 0x88, 0xb3, 0x60, 0xb8, 0xb4, 0xb4, 0xf8, 0xd9, - 0xbe, 0xf5, 0xb3, 0x10, 0x6c, 0xe6, 0xc8, 0x61, 0x46, 0xb3, 0xe5, 0xe5, - 0xc5, 0xd3, 0xac, 0xfd, 0x73, 0xef, 0x79, 0xd2, 0xab, 0x51, 0xff, 0x98, - 0xbb, 0x13, 0x95, 0x11, 0xf0, 0x63, 0x88, 0x25, 0x3d, 0x46, 0xc7, 0xbb, - 0x32, 0xc1, 0x47, 0x3f, 0x0b, 0xbf, 0xf6, 0x83, 0x61, 0x7f, 0x32, 0x0c, - 0xb2, 0xf2, 0xe8, 0xf6, 0x77, 0xef, 0x3c, 0xf8, 0x1f, 0x94, 0xd5, 0xe4, - 0x36, 0x26, 0xf7, 0xf3, 0x9f, 0x67, 0xe3, 0x83, 0xce, 0x37, 0xc7, 0xe4, - 0xef, 0x96, 0x96, 0x11, 0x6c, 0x97, 0x0a, 0x7a, 0x5d, 0x60, 0xcc, 0xbb, - 0xc2, 0x91, 0x17, 0x3f, 0x0b, 0x91, 0x07, 0xe1, 0xd7, 0x08, 0xdd, 0x26, - 0xc8, 0x5b, 0xb6, 0x8c, 0xc8, 0x48, 0xdd, 0xcf, 0x14, 0x3c, 0x5a, 0xa5, - 0x5e, 0xde, 0x9a, 0x7e, 0x79, 0x87, 0xa5, 0xe7, 0xec, 0x79, 0x01, 0x90, - 0x9e, 0xfb, 0x49, 0x0c, 0xb4, 0x4f, 0xe3, 0xe4, 0xae, 0xb0, 0x6d, 0xfc, - 0xf3, 0xc8, 0x86, 0x14, 0x2d, 0x6e, 0xa5, 0x62, 0x61, 0x0f, 0xa4, 0x42, - 0x1a, 0x5c, 0x8c, 0x87, 0xae, 0x0c, 0x98, 0xb7, 0x9f, 0x71, 0xe5, 0x2e, - 0x90, 0x2a, 0xe7, 0x4d, 0x3a, 0x1c, 0x3b, 0x3e, 0x1f, 0x5c, 0x44, 0x65, - 0x54, 0x7b, 0xba, 0xba, 0x42, 0xbe, 0xf1, 0x18, 0x87, 0x75, 0x0b, 0x13, - 0xfd, 0xf5, 0xcf, 0xb1, 0x91, 0xac, 0xb7, 0xd5, 0xd9, 0x7d, 0xe3, 0x6d, - 0x4d, 0xb2, 0xd8, 0xdb, 0x23, 0x77, 0xee, 0xbb, 0x32, 0x89, 0xff, 0xfe, - 0x39, 0x48, 0xcc, 0xc2, 0x9d, 0x8e, 0xc9, 0x2f, 0xf8, 0xf8, 0xaf, 0x49, - 0x9a, 0x45, 0xa7, 0xa5, 0x3b, 0xf7, 0xee, 0xde, 0xef, 0xde, 0x3b, 0x3c, - 0xc0, 0xad, 0xd4, 0xde, 0x6f, 0x42, 0xb4, 0x7f, 0xfd, 0xdc, 0x0b, 0x10, - 0x46, 0x3c, 0x0e, 0x8f, 0x33, 0x4c, 0x47, 0x5b, 0x92, 0xef, 0x97, 0x2b, - 0xf0, 0x61, 0xe6, 0x6d, 0x9f, 0x47, 0xe3, 0x79, 0xf8, 0xf5, 0x86, 0x2e, - 0x03, 0xe9, 0x55, 0x9a, 0x85, 0x17, 0x77, 0xc7, 0x5f, 0xc0, 0x99, 0xd5, - 0x9d, 0x2f, 0xd1, 0x88, 0xed, 0x0f, 0x48, 0xab, 0xda, 0xff, 0xa1, 0xcc, - 0x38, 0x6f, 0x8e, 0x24, 0xa2, 0xda, 0xf1, 0x64, 0x3c, 0x80, 0x7d, 0x0e, - 0x4c, 0xef, 0x52, 0x09, 0xca, 0x5c, 0xa8, 0xbc, 0xbd, 0x83, 0xad, 0xc5, - 0xaf, 0xd0, 0xc1, 0x0f, 0x30, 0xac, 0xff, 0xb8, 0x3c, 0x53, 0x30, 0xaf, - 0x31, 0x92, 0xe8, 0x07, 0x9d, 0x89, 0xdf, 0x2e, 0x19, 0xbf, 0x8b, 0xb2, - 0x8e, 0x41, 0x59, 0x68, 0x3e, 0x3a, 0x2e, 0xb9, 0xea, 0x41, 0x92, 0xa0, - 0x3c, 0xaf, 0x57, 0xba, 0x68, 0x29, 0xfa, 0x5d, 0x73, 0x59, 0xd5, 0x14, - 0x93, 0xe9, 0xe0, 0xb8, 0x1f, 0x24, 0x03, 0xb7, 0xa4, 0x7c, 0x45, 0x94, - 0xf4, 0x0e, 0xe9, 0x0e, 0x0c, 0xf4, 0x26, 0x47, 0xa7, 0xeb, 0x14, 0x03, - 0x8d, 0xd9, 0xfe, 0xf2, 0xa8, 0xbe, 0x10, 0xad, 0xe3, 0x19, 0x58, 0x2b, - 0x1d, 0x1a, 0xba, 0xc1, 0x33, 0xb4, 0x56, 0x30, 0x31, 0x09, 0x1f, 0xe2, - 0xdc, 0x47, 0x9c, 0xe2, 0xc0, 0xd0, 0x4d, 0xcf, 0xee, 0xca, 0x2e, 0x55, - 0x8f, 0xd0, 0x7f, 0x73, 0x18, 0xb1, 0x4e, 0x09, 0xff, 0x3e, 0xd6, 0x2f, - 0x4a, 0x98, 0x63, 0xad, 0x8e, 0xdd, 0xb0, 0xc1, 0xe8, 0x85, 0xd9, 0x25, - 0xa6, 0xe7, 0xe1, 0xfb, 0x6e, 0xe6, 0x54, 0x4f, 0xde, 0xea, 0x48, 0xad, - 0x73, 0xa0, 0xf2, 0x25, 0x06, 0x2f, 0x25, 0xf0, 0x39, 0xa5, 0x9c, 0xde, - 0x00, 0xc3, 0xec, 0xbf, 0xe1, 0x34, 0x38, 0xd7, 0xda, 0x33, 0xc7, 0x1c, - 0x64, 0x6f, 0xa9, 0x8f, 0xf3, 0x9a, 0xc6, 0x86, 0xf1, 0x64, 0x40, 0x77, - 0x4f, 0x0d, 0xe3, 0x60, 0x50, 0x32, 0xff, 0x3c, 0x16, 0xf1, 0xc1, 0x1c, - 0xfa, 0x95, 0x1f, 0x1c, 0x11, 0x4e, 0xf3, 0x85, 0x48, 0xc2, 0x1f, 0x20, - 0x9e, 0x18, 0x21, 0x26, 0xe3, 0x32, 0x32, 0xb0, 0x28, 0x3b, 0x26, 0x7a, - 0x91, 0x85, 0x95, 0x68, 0x18, 0x3e, 0x1c, 0x54, 0x06, 0xef, 0x78, 0xec, - 0x87, 0xe3, 0x6c, 0xd3, 0x6f, 0xf7, 0xa2, 0x91, 0xbf, 0x32, 0x33, 0x49, - 0xb9, 0x70, 0x7c, 0xf1, 0xb1, 0x64, 0x05, 0xba, 0x4b, 0xd2, 0xae, 0x6e, - 0x7a, 0xfd, 0xe8, 0x34, 0x72, 0x8b, 0xb3, 0xcf, 0xd1, 0xf2, 0x9b, 0xa8, - 0x54, 0x64, 0xdd, 0xbe, 0x93, 0xa8, 0x55, 0x9d, 0xa0, 0x97, 0x88, 0xfb, - 0x72, 0x30, 0xae, 0xed, 0x66, 0x13, 0xf7, 0x49, 0xd6, 0xb9, 0xae, 0xff, - 0x12, 0xa7, 0xc7, 0x7d, 0x34, 0x45, 0x79, 0xfb, 0x18, 0xea, 0x75, 0x93, - 0xa9, 0x33, 0x73, 0x0f, 0x40, 0x5d, 0x51, 0x33, 0x3e, 0x56, 0x1c, 0xf5, - 0x04, 0x83, 0x28, 0xae, 0x12, 0x0b, 0x32, 0xe0, 0xe5, 0x34, 0x8d, 0x06, - 0x2f, 0xba, 0xec, 0xc7, 0x9c, 0x7b, 0xf3, 0x52, 0x1e, 0x2d, 0x5a, 0x46, - 0x8f, 0x26, 0xcb, 0xde, 0xe6, 0xa6, 0xac, 0xeb, 0x24, 0x45, 0x3c, 0xc9, - 0x2a, 0x8c, 0xb5, 0x94, 0xef, 0xc6, 0xeb, 0x76, 0x77, 0x77, 0x1c, 0x3d, - 0xb7, 0xad, 0xbd, 0xb6, 0x34, 0x93, 0xd8, 0x2f, 0x40, 0x10, 0x3a, 0xe6, - 0xbf, 0xb0, 0xb8, 0x8e, 0xbb, 0x66, 0x75, 0xd5, 0xcd, 0x1a, 0x67, 0x69, - 0x8f, 0x83, 0x86, 0x1e, 0x8d, 0x00, 0x57, 0xff, 0x3b, 0xd0, 0x6d, 0x18, - 0x9f, 0x45, 0xa3, 0x8a, 0xe4, 0xee, 0x88, 0x0b, 0xe6, 0x85, 0x98, 0x9d, - 0x74, 0x35, 0x6f, 0x39, 0x22, 0xb1, 0x5c, 0xfb, 0x06, 0x1b, 0x46, 0x23, - 0x26, 0xca, 0x2d, 0x95, 0xc6, 0x18, 0x3c, 0x78, 0x1e, 0x0f, 0x07, 0x61, - 0xb2, 0xe9, 0x23, 0xca, 0xb6, 0x42, 0x6c, 0x99, 0xc8, 0xc2, 0x6f, 0x56, - 0x10, 0x49, 0x18, 0x0c, 0x50, 0x8b, 0x71, 0x84, 0x07, 0x51, 0xd3, 0xb0, - 0x71, 0x87, 0xb9, 0x64, 0xd6, 0x5e, 0xa9, 0x77, 0x61, 0xcd, 0x0f, 0xa7, - 0x0c, 0xe6, 0x89, 0xbb, 0x8c, 0x93, 0x81, 0x9b, 0x3a, 0x65, 0x25, 0x24, - 0x32, 0xb8, 0x8b, 0x2d, 0x96, 0x14, 0xa5, 0xd7, 0x2f, 0x91, 0xa8, 0xe1, - 0xd3, 0x66, 0xd9, 0x59, 0xf2, 0x07, 0xdd, 0x88, 0x34, 0x02, 0xfd, 0x36, - 0x4e, 0xbe, 0x1c, 0xf7, 0xcf, 0x43, 0x8c, 0x4b, 0x2f, 0xbb, 0x19, 0x89, - 0xcf, 0xb6, 0xf9, 0xef, 0x44, 0x72, 0x28, 0x16, 0x37, 0xcc, 0x33, 0x1c, - 0x5f, 0x8c, 0xb3, 0xbb, 0x63, 0xa1, 0x12, 0xbe, 0xc8, 0x6e, 0x76, 0xe2, - 0xea, 0x1a, 0x60, 0xbd, 0xcc, 0x83, 0x88, 0x5f, 0xec, 0xd3, 0xcf, 0xef, - 0x13, 0xe4, 0x62, 0x9f, 0xb5, 0x95, 0x56, 0xe2, 0x72, 0xb1, 0x24, 0x4f, - 0x39, 0xd6, 0x35, 0xc7, 0x44, 0xbf, 0x08, 0xbe, 0x0d, 0xc3, 0xd1, 0x59, - 0x76, 0xbe, 0xe9, 0xaf, 0x19, 0x99, 0x0a, 0x56, 0x16, 0x6a, 0x74, 0x57, - 0x08, 0x1d, 0x8c, 0xfa, 0xe1, 0xb0, 0xa6, 0xca, 0x33, 0x83, 0xe2, 0x9f, - 0x96, 0xdf, 0x3d, 0xb2, 0xf5, 0x61, 0xfb, 0xf5, 0xbb, 0x85, 0x59, 0x78, - 0x78, 0x5f, 0xe2, 0x2f, 0x77, 0x61, 0xd7, 0x03, 0x6b, 0x50, 0x69, 0xdf, - 0xf7, 0xfe, 0xb8, 0x45, 0x73, 0xb5, 0x43, 0x16, 0x04, 0xc3, 0x30, 0xb9, - 0x43, 0xa2, 0xe0, 0x32, 0x48, 0x9c, 0xc6, 0x7d, 0xa6, 0xc2, 0xbf, 0x7b, - 0xfd, 0xf1, 0x60, 0xa6, 0x59, 0x7f, 0xcf, 0x39, 0xee, 0xb9, 0x0c, 0xc8, - 0x03, 0x9f, 0xcf, 0xe3, 0x04, 0x04, 0x00, 0x93, 0x0b, 0xf1, 0x20, 0x18, - 0x1e, 0x1f, 0x73, 0x13, 0xa0, 0x3e, 0xe4, 0x58, 0x82, 0x48, 0x27, 0xe4, - 0x91, 0xf2, 0xfd, 0xc5, 0xbc, 0xd3, 0xb0, 0xe6, 0x3e, 0x23, 0xbf, 0x6e, - 0xfa, 0x26, 0x53, 0x83, 0xa1, 0xff, 0xff, 0x67, 0xc6, 0x3d, 0x17, 0x6a, - 0x2c, 0x78, 0xd1, 0xaf, 0x7f, 0x95, 0x9e, 0xfc, 0xc3, 0x56, 0x7b, 0x91, - 0x13, 0xc5, 0x19, 0x24, 0xc9, 0xe8, 0x45, 0x8d, 0xdf, 0xca, 0xe2, 0x28, - 0xc7, 0x75, 0xf6, 0x87, 0x61, 0x90, 0xcc, 0xc6, 0xc3, 0xc2, 0x23, 0x67, - 0x18, 0x66, 0x92, 0x33, 0xe3, 0x42, 0xcf, 0x8f, 0x71, 0xb9, 0x0d, 0x40, - 0xe5, 0x37, 0x58, 0x29, 0x1a, 0x6c, 0xfa, 0x0c, 0xf3, 0x03, 0x28, 0xb2, - 0x05, 0x45, 0x4a, 0x6d, 0xf5, 0xac, 0xe8, 0xf1, 0xb1, 0x80, 0x67, 0x30, - 0x37, 0xec, 0x15, 0xf9, 0xa7, 0x1b, 0x31, 0xa0, 0x54, 0x48, 0xfd, 0xa1, - 0xf5, 0x12, 0x8d, 0x64, 0x61, 0x02, 0x5b, 0xd3, 0xe8, 0xe2, 0x0c, 0xd6, - 0x7b, 0xa9, 0xac, 0xfc, 0xa7, 0x56, 0x89, 0x14, 0x68, 0x2e, 0x4d, 0x7d, - 0xea, 0xf9, 0x65, 0xd8, 0x4b, 0xe3, 0xfe, 0x97, 0x30, 0xfb, 0xcc, 0xdf, - 0xba, 0xda, 0xc3, 0x21, 0xf2, 0x30, 0xc7, 0xda, 0x17, 0x90, 0x7e, 0xfe, - 0x8b, 0x34, 0x3a, 0x1b, 0x81, 0x24, 0xa4, 0xbd, 0x08, 0x45, 0x60, 0x5b, - 0x9b, 0x4f, 0xfb, 0x49, 0x34, 0xce, 0xbb, 0x07, 0x10, 0x52, 0xd8, 0x9a, - 0x67, 0xc9, 0x04, 0xd3, 0x9d, 0x6c, 0x7a, 0xd7, 0xf4, 0x9e, 0xc2, 0xc8, - 0xd7, 0xbd, 0xc3, 0x9c, 0x06, 0xd7, 0xb4, 0x08, 0xad, 0x7b, 0x3e, 0xfe, - 0xe7, 0xb7, 0x48, 0x5d, 0x82, 0x5f, 0x69, 0x86, 0xb1, 0xf5, 0xf0, 0x3b, - 0x8d, 0xfe, 0x86, 0xdf, 0x6b, 0x4f, 0xbc, 0x69, 0xcb, 0xac, 0xc3, 0x92, - 0x86, 0xc2, 0x76, 0x30, 0xaf, 0xd7, 0xbb, 0xca, 0xc2, 0xbc, 0x56, 0xc7, - 0x5a, 0xa9, 0xb8, 0xca, 0xfc, 0x46, 0xb5, 0xa0, 0x47, 0xa4, 0x89, 0xcd, - 0x56, 0x1b, 0xba, 0x3d, 0x53, 0x05, 0x4c, 0x4f, 0xfb, 0xa7, 0x72, 0x31, - 0xf5, 0xac, 0xb5, 0xf1, 0x02, 0x52, 0x71, 0xff, 0xe8, 0xcc, 0x95, 0xf9, - 0x4d, 0xa9, 0x55, 0xf5, 0x8e, 0x5a, 0xf7, 0xa6, 0x1b, 0xf7, 0xe4, 0x91, - 0xde, 0x0f, 0x92, 0x34, 0x4c, 0xf2, 0xe1, 0x1e, 0xc7, 0x30, 0xd8, 0xab, - 0xac, 0xf0, 0x18, 0x3f, 0xb1, 0x52, 0x5b, 0x49, 0x12, 0x5c, 0x35, 0x7a, - 0x93, 0xd3, 0x53, 0x00, 0xc9, 0x38, 0x64, 0x27, 0x64, 0xec, 0x13, 0x63, - 0x4a, 0x1e, 0xf6, 0xae, 0xc9, 0x81, 0x14, 0xdc, 0xc4, 0x4f, 0x25, 0x18, - 0x10, 0x68, 0xc4, 0xac, 0x7b, 0xc8, 0x5e, 0x1d, 0x6d, 0xe4, 0x35, 0x31, - 0x47, 0x60, 0x1b, 0xf0, 0x80, 0xe2, 0xab, 0xc5, 0x5b, 0x6c, 0x1b, 0xde, - 0x8c, 0xc2, 0x4b, 0xef, 0x53, 0x34, 0xca, 0x9e, 0x17, 0x18, 0x35, 0x8b, - 0x42, 0xd1, 0xa9, 0xd7, 0x50, 0x9a, 0x94, 0x31, 0x2a, 0xb0, 0x62, 0x4d, - 0x76, 0x81, 0x34, 0x00, 0x51, 0x26, 0x43, 0xfb, 0x2c, 0xa4, 0xd7, 0x8d, - 0x92, 0x3e, 0x6e, 0xdc, 0x53, 0xad, 0x14, 0xd9, 0x24, 0x19, 0x79, 0x87, - 0xed, 0x76, 0xbb, 0xc0, 0xa8, 0x8d, 0xc4, 0x7f, 0x47, 0x4c, 0x87, 0xa9, - 0xda, 0xf3, 0xd6, 0x9a, 0x47, 0xed, 0x8b, 0x60, 0xdc, 0x68, 0x34, 0xbd, - 0xcd, 0x17, 0x1a, 0x62, 0x12, 0x2c, 0xa5, 0x03, 0xed, 0x24, 0x1c, 0x4c, - 0xfa, 0x61, 0xa3, 0x11, 0xf4, 0xfb, 0x02, 0x85, 0xdd, 0x2c, 0xbc, 0x70, - 0x80, 0xc0, 0x7f, 0x50, 0xf2, 0xb0, 0x28, 0xd8, 0x46, 0x26, 0x39, 0x82, - 0x7e, 0x12, 0x59, 0xa1, 0x7f, 0x7f, 0x06, 0xc3, 0x49, 0xa8, 0x0c, 0x25, - 0xc1, 0xdb, 0xb0, 0xc2, 0xe2, 0x28, 0x01, 0x48, 0xf3, 0xfb, 0xb4, 0xe5, - 0x5d, 0x4f, 0xb5, 0x7a, 0xf2, 0xef, 0xe9, 0x3d, 0x0d, 0xca, 0x68, 0x32, - 0x1c, 0xb2, 0xcf, 0x9c, 0x1b, 0xdd, 0xd8, 0x48, 0x5d, 0x63, 0x59, 0x57, - 0xbc, 0x86, 0xd4, 0x25, 0x64, 0x71, 0x63, 0x64, 0x31, 0x0b, 0x25, 0xe3, - 0xfa, 0x75, 0x17, 0x65, 0xb1, 0x99, 0x43, 0xc1, 0x5e, 0x4b, 0x4b, 0x47, - 0x1b, 0x16, 0x08, 0x5c, 0x8e, 0x99, 0x30, 0x14, 0x86, 0xde, 0x27, 0xf6, - 0x14, 0xa0, 0x4c, 0xda, 0xe4, 0x3c, 0xbc, 0xb4, 0x29, 0x75, 0xab, 0x8d, - 0xb3, 0x71, 0xc3, 0x85, 0x5d, 0xc1, 0x43, 0x5a, 0x8d, 0xe6, 0x91, 0x75, - 0x6c, 0x24, 0x5e, 0xf2, 0x3d, 0xbf, 0x59, 0x52, 0xe6, 0xb8, 0x7f, 0x1e, - 0x24, 0x2d, 0x2f, 0x1a, 0x0d, 0xc2, 0x6f, 0x25, 0x8c, 0x83, 0xb3, 0x87, - 0x48, 0x24, 0x75, 0x72, 0x89, 0xd5, 0x3a, 0xf2, 0x5e, 0x78, 0x8f, 0x3a, - 0x4d, 0x47, 0x45, 0xa9, 0x13, 0x5d, 0x22, 0x5f, 0xfb, 0x14, 0xb6, 0x70, - 0xdb, 0xd0, 0xe8, 0x36, 0x68, 0x3c, 0x4e, 0x98, 0x0e, 0x9e, 0x9b, 0x96, - 0x71, 0xa2, 0xef, 0x5b, 0x18, 0xd1, 0xd1, 0xf7, 0xbf, 0xe2, 0x68, 0xd4, - 0xf0, 0x5d, 0x94, 0x01, 0x44, 0x2f, 0x1a, 0x06, 0xbb, 0x16, 0x9c, 0x59, - 0x25, 0x07, 0x16, 0x22, 0xeb, 0xaa, 0xa7, 0x3c, 0x6c, 0x86, 0xc7, 0x96, - 0x31, 0x83, 0x6f, 0xc8, 0x5b, 0xf8, 0xd5, 0xc2, 0x55, 0xb6, 0x69, 0x0b, - 0xd3, 0x75, 0xb5, 0x99, 0x4f, 0x3f, 0x58, 0x05, 0x56, 0x7e, 0xf5, 0x7e, - 0x7f, 0xd5, 0xdd, 0xe6, 0x5b, 0x83, 0xdf, 0x87, 0x71, 0x2f, 0x18, 0x7a, - 0x7b, 0xbd, 0xbf, 0x40, 0xc5, 0xfe, 0x75, 0x85, 0xaf, 0x11, 0x52, 0x01, - 0xb1, 0x42, 0x30, 0xb5, 0xef, 0x7d, 0x30, 0x1e, 0xc3, 0x40, 0xaf, 0x4b, - 0x68, 0x75, 0x70, 0xd5, 0xa1, 0x8f, 0xe2, 0x9a, 0x24, 0xbf, 0x58, 0xac, - 0xd6, 0xd4, 0x8f, 0x78, 0x55, 0x92, 0xf4, 0xf5, 0x91, 0xfa, 0xf5, 0xd9, - 0x9a, 0x5c, 0xf5, 0x71, 0xfe, 0x11, 0xde, 0xe3, 0x6d, 0x10, 0xd2, 0xb7, - 0x27, 0x45, 0xc5, 0x7f, 0xac, 0x21, 0x58, 0xe5, 0xeb, 0xd3, 0xe2, 0xeb, - 0x93, 0x2f, 0x6f, 0xff, 0xc6, 0xab, 0x12, 0xc2, 0x9d, 0xf8, 0x72, 0x24, - 0x15, 0x79, 0x9e, 0x17, 0xe9, 0x52, 0x56, 0x36, 0xbc, 0x13, 0xe4, 0x80, - 0x5d, 0x09, 0x22, 0x95, 0xfa, 0x47, 0x5e, 0xea, 0x1d, 0xe8, 0x75, 0xdb, - 0x94, 0x85, 0x88, 0xdd, 0x4b, 0xc5, 0x0b, 0x71, 0xb6, 0xe1, 0xfb, 0xac, - 0x3f, 0xc2, 0xab, 0xf4, 0x7d, 0xdc, 0x8b, 0x86, 0x21, 0x66, 0x7e, 0x82, - 0xba, 0x18, 0x0c, 0xe4, 0x3b, 0x8a, 0xc8, 0x24, 0xc4, 0x72, 0xeb, 0xda, - 0x48, 0xf3, 0xf5, 0x1c, 0x15, 0xca, 0x9d, 0xb8, 0x2f, 0x21, 0x85, 0xff, - 0x30, 0x93, 0x02, 0x7c, 0x7c, 0xa6, 0xbd, 0x9e, 0x8c, 0xe1, 0xe5, 0xaf, - 0xda, 0x4b, 0x4a, 0x17, 0x00, 0xef, 0x9f, 0x6a, 0xef, 0xf1, 0x68, 0x1b, - 0x5e, 0xaf, 0x48, 0xaf, 0x25, 0x2d, 0x83, 0xae, 0x2b, 0xb9, 0x09, 0x4e, - 0xe7, 0x36, 0x9c, 0x1e, 0x3b, 0x70, 0xfa, 0xdb, 0x8e, 0xd3, 0x13, 0x3b, - 0x4e, 0xec, 0x16, 0x94, 0xb4, 0x04, 0xab, 0x4f, 0xe8, 0xf6, 0x63, 0x45, - 0xeb, 0x95, 0x0d, 0xad, 0x6d, 0x07, 0x5a, 0x5b, 0x76, 0xb4, 0x76, 0x4c, - 0xb4, 0xf8, 0x7f, 0x83, 0x20, 0x0b, 0xfe, 0x6b, 0x12, 0x4e, 0xc2, 0x41, - 0xae, 0x45, 0x45, 0xe9, 0xe7, 0x94, 0xe5, 0xc4, 0x5d, 0xf7, 0x4e, 0x83, - 0x61, 0x1a, 0xb2, 0xd7, 0x17, 0xc1, 0xb7, 0x2e, 0x53, 0xad, 0x9f, 0xad, - 0xb1, 0x37, 0xff, 0xa2, 0x7a, 0xb8, 0xcb, 0x81, 0x26, 0x78, 0x0b, 0xa8, - 0xc4, 0xe2, 0xf1, 0xc9, 0x0e, 0xec, 0xb5, 0x95, 0xea, 0xd0, 0xbf, 0xaf, - 0x61, 0xb2, 0xbb, 0x2f, 0x15, 0x65, 0xe2, 0x66, 0x9d, 0x96, 0x59, 0xf6, - 0x0a, 0xb3, 0xd3, 0xc2, 0xae, 0xf2, 0x73, 0xa1, 0xd2, 0x4d, 0x22, 0x99, - 0x68, 0xec, 0x40, 0xfe, 0x15, 0x31, 0xb6, 0x5c, 0xaf, 0xf8, 0xb6, 0xcb, - 0x6e, 0xca, 0x51, 0x3f, 0xb1, 0x2c, 0x5c, 0x88, 0x3d, 0xd3, 0x74, 0x53, - 0xbd, 0x40, 0x9e, 0x80, 0x89, 0x25, 0x20, 0xd5, 0x3f, 0xb3, 0xbd, 0x91, - 0xfe, 0x96, 0xed, 0xdc, 0xb6, 0x71, 0x77, 0xaa, 0x7f, 0x62, 0xbb, 0x06, - 0x86, 0x27, 0x26, 0x5f, 0x30, 0xbf, 0x33, 0xa7, 0x00, 0xe6, 0x5f, 0xe1, - 0xfa, 0xca, 0x3d, 0x05, 0xf4, 0xcf, 0xa8, 0xe9, 0xbb, 0x41, 0xe3, 0xd7, - 0x6d, 0x96, 0x2d, 0xcd, 0x44, 0x19, 0xfa, 0x7e, 0x11, 0xc1, 0x3e, 0xcb, - 0x78, 0x4f, 0xc9, 0x8e, 0x6c, 0xe0, 0xd8, 0x17, 0x20, 0x4b, 0xff, 0xdc, - 0xf6, 0x19, 0xb6, 0x7b, 0x5d, 0xda, 0xee, 0xf1, 0x23, 0x88, 0x28, 0x1e, - 0xf1, 0x8d, 0x9f, 0x51, 0x12, 0x76, 0x76, 0xbc, 0x50, 0xc9, 0x27, 0xfb, - 0xd0, 0x62, 0x01, 0x6b, 0xeb, 0xfc, 0xfd, 0x01, 0xda, 0xa7, 0x6c, 0x1f, - 0xf7, 0xf9, 0x29, 0x93, 0x95, 0x2b, 0xb0, 0x40, 0xb7, 0xbb, 0xe3, 0xfc, - 0xb6, 0x35, 0x76, 0x63, 0xd3, 0xcd, 0x82, 0xd2, 0x8f, 0x38, 0x05, 0xf4, - 0x4f, 0x64, 0x0a, 0xb3, 0xbe, 0xdc, 0xfb, 0x62, 0x7d, 0xbd, 0xcd, 0x8c, - 0x7e, 0x16, 0xf6, 0xb8, 0x18, 0x3b, 0xde, 0x9a, 0x90, 0xd8, 0xfb, 0x6d, - 0x32, 0xb3, 0x3b, 0xbe, 0x95, 0x35, 0x63, 0x50, 0x87, 0xcb, 0x0d, 0xe6, - 0x94, 0x7a, 0xc0, 0xf9, 0x09, 0xd3, 0x0b, 0x27, 0xf9, 0x9c, 0xcd, 0x99, - 0xa2, 0x4b, 0x73, 0xfe, 0x53, 0x32, 0x2c, 0x26, 0x3d, 0xd2, 0x47, 0x5d, - 0x40, 0x68, 0xbd, 0x09, 0xc6, 0x92, 0x84, 0xc2, 0x23, 0xd2, 0xa2, 0x06, - 0x6f, 0xf0, 0x52, 0x99, 0xb4, 0x97, 0xe9, 0x36, 0x1e, 0x8b, 0x69, 0xed, - 0xa6, 0x9c, 0x8b, 0xb6, 0xe3, 0x09, 0x66, 0x66, 0x95, 0x3e, 0x7c, 0x88, - 0xbb, 0x13, 0x72, 0xcb, 0x10, 0x7c, 0x3a, 0x3a, 0x33, 0x0b, 0x21, 0xb4, - 0x18, 0x7b, 0xbb, 0xca, 0xd5, 0x8d, 0x5f, 0xbd, 0xdc, 0x9c, 0x41, 0xf2, - 0x8b, 0xfc, 0xcc, 0x72, 0x55, 0x83, 0x0e, 0xe6, 0x3e, 0xab, 0x7d, 0x05, - 0xa5, 0x43, 0xde, 0x2c, 0xa1, 0x82, 0xfa, 0x4b, 0xa1, 0x92, 0xb4, 0x0b, - 0xd1, 0x2a, 0x6b, 0x63, 0x58, 0x4a, 0x2a, 0x74, 0x99, 0xea, 0x6a, 0xeb, - 0xca, 0xaf, 0x4e, 0x2d, 0x96, 0xfd, 0x5b, 0xa5, 0xe7, 0xf6, 0xde, 0x87, - 0x0f, 0xaf, 0xb7, 0x0f, 0x76, 0x3f, 0xfc, 0x5e, 0x51, 0xbc, 0x43, 0xcf, - 0xbd, 0xfd, 0xd7, 0x1f, 0x2a, 0x0a, 0xae, 0x31, 0xb8, 0xef, 0xf6, 0xba, - 0xd5, 0x40, 0x1f, 0xe5, 0x65, 0x5f, 0xef, 0x54, 0x14, 0x05, 0x12, 0xca, - 0x3f, 0xc5, 0x86, 0x49, 0xa1, 0x41, 0x1b, 0x8f, 0xd3, 0xaf, 0xd0, 0xe9, - 0x24, 0xb4, 0x69, 0xf1, 0xb4, 0xf7, 0xe9, 0xac, 0xdb, 0xdf, 0xaf, 0xad, - 0x5b, 0x11, 0x50, 0xe1, 0xd3, 0x21, 0x51, 0xc3, 0xa1, 0xd2, 0xf7, 0xa0, - 0xf5, 0x2f, 0x1b, 0x76, 0xe8, 0x8f, 0x6a, 0x40, 0xc7, 0x8d, 0x7f, 0xbe, - 0x79, 0xac, 0x01, 0x7c, 0x6a, 0xd9, 0x84, 0xea, 0xcc, 0x63, 0xf2, 0x45, - 0x1f, 0x00, 0x65, 0x61, 0xce, 0x82, 0x96, 0xcd, 0x41, 0x61, 0x3c, 0xc9, - 0x97, 0x56, 0x8d, 0x45, 0xfb, 0x2c, 0xc1, 0x5d, 0x7b, 0x18, 0x9f, 0x35, - 0xfc, 0xbc, 0x90, 0xcf, 0x41, 0x95, 0xb2, 0x66, 0x09, 0x3d, 0x59, 0xf3, - 0x56, 0xce, 0x87, 0xf6, 0x49, 0x2d, 0x60, 0x05, 0x79, 0xca, 0xf8, 0xcf, - 0x20, 0x16, 0xf8, 0xc2, 0xd1, 0x00, 0xb5, 0x20, 0x04, 0x30, 0x39, 0xe6, - 0x5a, 0x2f, 0x2d, 0x53, 0x4c, 0x25, 0xfd, 0x83, 0x07, 0x6c, 0x6a, 0x7e, - 0xcc, 0x19, 0xa8, 0xd1, 0x94, 0xd1, 0x66, 0x7b, 0x0d, 0x07, 0x9e, 0x65, - 0xa2, 0xa2, 0xb0, 0xef, 0x18, 0x63, 0x1d, 0x5e, 0x7a, 0xc5, 0x30, 0xc8, - 0x5f, 0x0d, 0x51, 0xd8, 0xf2, 0x0e, 0xfd, 0x20, 0x19, 0x4c, 0xa2, 0x51, - 0xec, 0x8b, 0x0d, 0xa5, 0x4a, 0xc8, 0x78, 0x04, 0x9a, 0xc8, 0x48, 0xeb, - 0xa6, 0x31, 0x54, 0x97, 0x78, 0xe7, 0x05, 0x16, 0xf4, 0xa5, 0x51, 0xb7, - 0x50, 0x93, 0x68, 0x2d, 0x15, 0x51, 0xda, 0x52, 0xe5, 0xe5, 0xd2, 0x52, - 0x51, 0x8c, 0x8c, 0xee, 0x5c, 0x20, 0xaa, 0xf4, 0xe5, 0x2f, 0x5d, 0x20, - 0xf9, 0x67, 0xdc, 0x4e, 0x86, 0x99, 0x00, 0x90, 0xf3, 0x55, 0xcb, 0x7b, - 0xba, 0xba, 0xba, 0x6a, 0xaf, 0xab, 0xb0, 0x08, 0x32, 0x81, 0xa3, 0x85, - 0x3a, 0x03, 0x34, 0xb5, 0x13, 0x96, 0x78, 0xb4, 0x9a, 0xb2, 0xa2, 0xa4, - 0x4c, 0xda, 0x1b, 0x12, 0xc4, 0xc5, 0xf7, 0x0e, 0x04, 0xf9, 0x41, 0x20, - 0xa2, 0xc8, 0xff, 0xd4, 0x31, 0xbd, 0xad, 0x71, 0x59, 0x7b, 0x76, 0x83, - 0x71, 0x61, 0x13, 0xf4, 0x90, 0xa3, 0xba, 0x03, 0x7b, 0x89, 0xad, 0x6c, - 0xb5, 0xe5, 0x29, 0xbf, 0x3b, 0xda, 0xef, 0x35, 0xed, 0xf7, 0x23, 0xed, - 0xf7, 0x63, 0xed, 0xf7, 0x93, 0x16, 0x1a, 0x03, 0xf9, 0xab, 0x36, 0xee, - 0x57, 0x54, 0xf3, 0xa9, 0xda, 0xb8, 0xf7, 0xcb, 0xa6, 0xe7, 0xff, 0x87, - 0xaf, 0x4b, 0x4a, 0xa9, 0x3b, 0xc5, 0xae, 0x05, 0xed, 0x11, 0x76, 0xb8, - 0x5a, 0x95, 0x62, 0x93, 0xa4, 0x57, 0x69, 0x33, 0x9f, 0x09, 0xb5, 0xa6, - 0x26, 0x92, 0xa4, 0xda, 0x2f, 0x36, 0x3d, 0x20, 0x33, 0x10, 0xda, 0xb2, - 0xa2, 0x49, 0x35, 0x26, 0x51, 0x5b, 0x68, 0xea, 0xed, 0xaf, 0x68, 0x6f, - 0x04, 0x02, 0xd8, 0xec, 0x48, 0xf6, 0x46, 0x14, 0x2b, 0xb4, 0x6b, 0x71, - 0x09, 0x81, 0x13, 0xad, 0xa6, 0x66, 0x7e, 0xe0, 0x81, 0x60, 0x24, 0xf0, - 0x8a, 0x0d, 0x45, 0x1d, 0xef, 0x8e, 0x6e, 0x95, 0x94, 0xc0, 0xbc, 0x46, - 0x2b, 0xcc, 0x20, 0xee, 0x4f, 0xf0, 0x52, 0x41, 0xa4, 0x7c, 0x72, 0xc5, - 0x1c, 0x2a, 0xe3, 0xa4, 0x71, 0x72, 0x88, 0xc7, 0x40, 0xf0, 0x0b, 0xbf, - 0x2d, 0x27, 0xe1, 0xe9, 0xa6, 0x7f, 0xff, 0x5a, 0xb4, 0x3e, 0xf5, 0x8f, - 0x4e, 0x9a, 0x36, 0xb8, 0xec, 0x4a, 0xcd, 0x7d, 0x69, 0x7f, 0xe5, 0x6d, - 0xe6, 0x8d, 0x19, 0x04, 0x7a, 0x99, 0x7f, 0x42, 0x43, 0xf2, 0x56, 0x96, - 0x25, 0x11, 0xf4, 0x24, 0x6c, 0xf8, 0x5a, 0xd3, 0x16, 0x93, 0x1b, 0x9e, - 0x17, 0xc1, 0x1e, 0xd6, 0x77, 0x32, 0x05, 0x0c, 0x92, 0xbe, 0xcd, 0x6b, - 0x9f, 0xc6, 0xc9, 0xeb, 0xa0, 0x7f, 0xde, 0x60, 0xbb, 0x26, 0xf6, 0x81, - 0x4d, 0x9d, 0x86, 0x89, 0x78, 0xd3, 0xda, 0x41, 0xdc, 0xbf, 0x11, 0xf5, - 0xe9, 0x44, 0x67, 0xd9, 0xf7, 0x96, 0xb4, 0xe9, 0xe3, 0xa6, 0x4a, 0x37, - 0xdf, 0x18, 0xce, 0x48, 0x75, 0xd6, 0xa6, 0x85, 0xe6, 0xc8, 0xc9, 0x3a, - 0xec, 0x6a, 0xde, 0x55, 0x37, 0xa8, 0x65, 0x44, 0x61, 0x0d, 0xeb, 0x84, - 0x98, 0x1a, 0x38, 0xa8, 0x02, 0x03, 0x57, 0x78, 0x55, 0x64, 0x18, 0x6f, - 0x9e, 0x58, 0x75, 0x46, 0xa2, 0x15, 0xbb, 0x68, 0xe7, 0xd5, 0x55, 0x16, - 0xae, 0x16, 0x72, 0x85, 0x43, 0x6e, 0xf7, 0xb9, 0x09, 0x78, 0x2b, 0x6b, - 0xac, 0x5a, 0x54, 0x43, 0x1d, 0x42, 0x47, 0x87, 0xf0, 0x78, 0x56, 0x08, - 0x6b, 0x3a, 0x84, 0x27, 0x33, 0x41, 0xc8, 0xa9, 0x0c, 0x60, 0x0e, 0xed, - 0x66, 0xe3, 0x76, 0x7b, 0x84, 0x21, 0xad, 0xb8, 0x4d, 0x8e, 0x99, 0xb5, - 0x5e, 0x93, 0x34, 0xf9, 0xde, 0xbf, 0xd9, 0x9a, 0x07, 0x42, 0x6e, 0x23, - 0xb0, 0x80, 0x39, 0x72, 0x75, 0x83, 0x55, 0x65, 0x17, 0x6c, 0xe0, 0xa2, - 0xc7, 0xe4, 0x4c, 0x8b, 0xb6, 0x85, 0x95, 0x86, 0x7f, 0x2c, 0xda, 0xce, - 0x82, 0xb3, 0x0f, 0x18, 0xf0, 0xb3, 0xb9, 0x09, 0x53, 0xe6, 0x60, 0xc7, - 0x2f, 0x33, 0xf9, 0xf3, 0x2a, 0x11, 0xa8, 0x0d, 0x09, 0x2d, 0x00, 0x9b, - 0xec, 0x82, 0xd3, 0x97, 0x9e, 0x2f, 0x92, 0x7f, 0x8f, 0x7c, 0x9c, 0xf9, - 0x45, 0x2a, 0x70, 0x7f, 0x16, 0x93, 0x7f, 0x4f, 0x4c, 0x3e, 0x0d, 0xb7, - 0x5f, 0x38, 0x6e, 0xd0, 0x10, 0x2f, 0xb2, 0x2e, 0x8a, 0x8c, 0x03, 0xb4, - 0xa3, 0xbf, 0x66, 0xf3, 0x71, 0xc3, 0xd9, 0x59, 0x46, 0x8f, 0xca, 0x9e, - 0xa5, 0x8a, 0x90, 0x63, 0x33, 0xd7, 0x6f, 0xc1, 0xda, 0x31, 0xd3, 0xc9, - 0x85, 0x65, 0x6d, 0xb0, 0xb4, 0xc5, 0x32, 0x46, 0x99, 0xcd, 0xd5, 0x6e, - 0x6a, 0x6a, 0x16, 0xd4, 0xb9, 0x3a, 0x97, 0x1d, 0x7c, 0xb4, 0x4b, 0x58, - 0x42, 0xe6, 0x27, 0x9c, 0x49, 0xc5, 0x28, 0x98, 0x92, 0x9f, 0x95, 0x02, - 0x56, 0xf9, 0xf7, 0xbf, 0xab, 0x7a, 0xe9, 0xaa, 0xcc, 0xef, 0x56, 0x70, - 0xf5, 0x56, 0x6c, 0x69, 0x0b, 0x7c, 0xca, 0x46, 0x8f, 0x1d, 0xe4, 0x05, - 0x83, 0x3e, 0xe6, 0x40, 0xf8, 0x3d, 0x88, 0x46, 0xfe, 0x7a, 0xe9, 0x0e, - 0x5a, 0x9e, 0x35, 0xf9, 0x94, 0x69, 0xc8, 0x82, 0xed, 0x81, 0xb7, 0xfa, - 0x6d, 0xb5, 0x03, 0xe4, 0xda, 0x64, 0x7f, 0x6c, 0x94, 0xc2, 0x73, 0xec, - 0x76, 0xb5, 0x73, 0xc6, 0xdc, 0xa9, 0x61, 0x21, 0xc8, 0xad, 0x09, 0xe4, - 0xd6, 0x16, 0x81, 0xdc, 0x57, 0xc5, 0x91, 0x61, 0x21, 0x08, 0x3e, 0x16, - 0x08, 0x3e, 0x5e, 0x04, 0x82, 0x63, 0xee, 0xee, 0xb0, 0x10, 0xd4, 0x9e, - 0x0b, 0xd4, 0x9e, 0x2f, 0x04, 0xb5, 0xe2, 0x52, 0xd6, 0x45, 0x60, 0xd7, - 0x59, 0xe5, 0xd8, 0x75, 0x56, 0x17, 0x81, 0x9d, 0xed, 0x16, 0xe5, 0x45, - 0xa0, 0xb9, 0x26, 0xd0, 0x5c, 0x9b, 0x13, 0x4d, 0x34, 0x13, 0x76, 0x74, - 0x93, 0x96, 0xd9, 0x8f, 0x0b, 0xca, 0xf8, 0x34, 0x98, 0x13, 0xf7, 0xce, - 0x6d, 0xcc, 0x6c, 0xf5, 0x86, 0xb8, 0x85, 0x20, 0xb8, 0xd8, 0xd9, 0xad, - 0x5d, 0xa5, 0xb3, 0x10, 0x0c, 0x17, 0x3b, 0xbd, 0xf1, 0x92, 0xa5, 0x45, - 0xa1, 0xf5, 0xcb, 0x22, 0xd0, 0x5a, 0x59, 0xe1, 0x98, 0x65, 0xc1, 0xf8, - 0x69, 0x09, 0x6a, 0x50, 0xae, 0x36, 0x6e, 0xcf, 0xeb, 0xe0, 0x46, 0x00, - 0xeb, 0x2d, 0x28, 0x59, 0x38, 0x5e, 0x08, 0xd1, 0x16, 0x2c, 0x71, 0x4e, - 0x27, 0xc3, 0xe1, 0xdb, 0x10, 0x0f, 0x54, 0x17, 0x82, 0xdd, 0x42, 0x05, - 0xcd, 0x5a, 0xb5, 0xa0, 0xb1, 0x5e, 0xd1, 0x3a, 0x5f, 0x47, 0xd6, 0x6e, - 0x43, 0xea, 0xb0, 0xdb, 0x82, 0xd0, 0xc5, 0x01, 0xd6, 0xc5, 0x8f, 0x67, - 0xbd, 0xf3, 0xaf, 0x8b, 0xc1, 0x72, 0xb1, 0xa2, 0xa7, 0xfc, 0xaa, 0xe6, - 0x85, 0x20, 0xbc, 0x08, 0x49, 0x64, 0xd1, 0xae, 0x9b, 0xe5, 0x46, 0xa0, - 0xa9, 0x6c, 0x61, 0x57, 0xcd, 0xe5, 0x55, 0x16, 0x76, 0xe9, 0x68, 0x06, - 0x31, 0x5f, 0x73, 0x9e, 0x09, 0xb8, 0x2d, 0xb5, 0xb2, 0xa9, 0xd9, 0x80, - 0x5f, 0x62, 0xe0, 0x45, 0x03, 0x9a, 0xcd, 0x45, 0x52, 0x36, 0x8b, 0xa7, - 0x59, 0x34, 0xa4, 0x7b, 0xd2, 0x53, 0xba, 0x97, 0xf1, 0x94, 0x6e, 0x2a, - 0x37, 0xec, 0xb9, 0xf5, 0x8e, 0x6c, 0x66, 0x36, 0x3c, 0x17, 0x93, 0x15, - 0xad, 0xbd, 0x43, 0x2f, 0x63, 0xae, 0x39, 0xfa, 0xb4, 0x2d, 0x39, 0xb9, - 0x91, 0xdc, 0xa1, 0x24, 0x7b, 0x71, 0xa5, 0xf5, 0x8e, 0x57, 0x51, 0xed, - 0xb3, 0x53, 0xe9, 0x90, 0x83, 0xea, 0x54, 0x8d, 0xe5, 0xea, 0xf7, 0x1d, - 0xcb, 0xce, 0xe3, 0x9a, 0x83, 0x99, 0x57, 0x6e, 0x61, 0x47, 0x93, 0xab, - 0xd2, 0x91, 0xb4, 0x1f, 0xed, 0xdd, 0x68, 0x28, 0x0d, 0x97, 0xd0, 0x82, - 0xbe, 0x12, 0x55, 0xaf, 0xcb, 0x4a, 0x69, 0xe7, 0x58, 0xbb, 0xd8, 0xc8, - 0x57, 0x90, 0x24, 0x38, 0xe7, 0xf4, 0xc3, 0x38, 0xf5, 0x70, 0x26, 0x3f, - 0xe1, 0x66, 0x46, 0x7b, 0x51, 0xb3, 0x61, 0x3b, 0x78, 0x6e, 0x79, 0x4f, - 0x72, 0xfb, 0xbd, 0x6c, 0x9d, 0x31, 0x8f, 0xe9, 0x35, 0x60, 0x6a, 0x09, - 0x04, 0xc3, 0xce, 0xde, 0x80, 0x81, 0xb7, 0xf6, 0x77, 0x2d, 0xc7, 0xde, - 0xdc, 0x87, 0x0a, 0x31, 0x47, 0xef, 0x7d, 0x09, 0x7b, 0xc1, 0xb5, 0x21, - 0x68, 0xba, 0x8d, 0x93, 0xf3, 0x2c, 0x1b, 0xaf, 0xaf, 0xac, 0xdc, 0xbf, - 0x96, 0xd0, 0x11, 0x4e, 0x40, 0xd3, 0x95, 0xb4, 0xff, 0xf2, 0xfe, 0x35, - 0xd6, 0x9f, 0x3e, 0x18, 0xc5, 0x7d, 0xd8, 0xe2, 0x87, 0x9b, 0xf7, 0xaf, - 0xf1, 0x18, 0x6d, 0x87, 0xce, 0xeb, 0x70, 0xdf, 0x8d, 0xd8, 0x36, 0x9a, - 0xd3, 0x13, 0xf9, 0x2c, 0x50, 0xb8, 0x4a, 0x59, 0x5a, 0x47, 0xd6, 0xc3, - 0x57, 0xc8, 0xc6, 0x7e, 0xe0, 0xc3, 0xde, 0xde, 0xcb, 0x7f, 0x76, 0x7c, - 0x07, 0x5f, 0xbb, 0x8e, 0x67, 0x2a, 0x0d, 0xf2, 0x4b, 0x00, 0xf5, 0x9f, - 0x23, 0x9e, 0x2a, 0xea, 0x9f, 0x23, 0xbf, 0xb2, 0x5a, 0xda, 0x87, 0x37, - 0xc3, 0x83, 0x78, 0xac, 0x1a, 0xd6, 0xcd, 0x22, 0x4c, 0xf5, 0x90, 0x79, - 0x6c, 0x16, 0xba, 0x4e, 0x66, 0xa5, 0x2b, 0x6a, 0x15, 0xdd, 0x77, 0x7b, - 0x07, 0xde, 0x45, 0x30, 0x0a, 0xce, 0xc8, 0x0c, 0x55, 0x8c, 0x35, 0x5e, - 0xcc, 0xc7, 0x4c, 0xd6, 0x96, 0x53, 0xe3, 0xc2, 0x81, 0x74, 0x18, 0x67, - 0x6e, 0x8b, 0xf3, 0x43, 0xb2, 0x38, 0x03, 0x96, 0x98, 0xb5, 0x0e, 0x83, - 0x14, 0x8e, 0x0e, 0x99, 0xa5, 0xe8, 0xe8, 0xa1, 0x74, 0xc8, 0xfc, 0x8b, - 0x04, 0xab, 0xfc, 0xb0, 0x96, 0x35, 0xfd, 0x25, 0xbc, 0x82, 0x26, 0xa5, - 0x4a, 0x55, 0x06, 0xfe, 0x0d, 0x13, 0xef, 0x5d, 0x74, 0xea, 0xad, 0x84, - 0x42, 0x66, 0xf8, 0x68, 0x20, 0x20, 0xc0, 0x2b, 0x16, 0x14, 0xdc, 0xf0, - 0xb7, 0x52, 0x8c, 0x5a, 0xf1, 0x02, 0xb2, 0xd9, 0x7b, 0x3c, 0xba, 0x44, - 0x1e, 0x15, 0xe6, 0xe0, 0x46, 0xf6, 0xf0, 0xf4, 0x50, 0x6e, 0xf4, 0x88, - 0x9c, 0xdc, 0x91, 0x45, 0xa1, 0x1f, 0xc5, 0xd9, 0x43, 0x3b, 0x3b, 0x0f, - 0x47, 0x0d, 0x11, 0x10, 0x80, 0xa6, 0x43, 0xcd, 0xe0, 0x25, 0x85, 0x0b, - 0x90, 0x61, 0x11, 0x8f, 0xba, 0x8b, 0x9f, 0xdc, 0x43, 0x98, 0x99, 0x1b, - 0x5f, 0x03, 0x8a, 0x57, 0x86, 0x35, 0x54, 0xee, 0x6a, 0x6a, 0x74, 0x95, - 0x77, 0x41, 0x6e, 0x5f, 0x95, 0xa1, 0x9c, 0x05, 0x57, 0xb0, 0x47, 0x2b, - 0xc8, 0x1c, 0x2f, 0xc9, 0x31, 0x1a, 0x58, 0x4c, 0xee, 0x1d, 0xb0, 0x1e, - 0x46, 0x7d, 0xe6, 0x2f, 0x09, 0xb7, 0x74, 0xd2, 0x63, 0x9e, 0xea, 0x8d, - 0xd5, 0x96, 0xb7, 0xf6, 0xb8, 0x39, 0x7d, 0x70, 0xff, 0x7a, 0xa9, 0x60, - 0x4c, 0x60, 0x47, 0xde, 0x7b, 0x87, 0x8d, 0x4f, 0xcc, 0xfc, 0x86, 0xff, - 0xd8, 0xaf, 0x28, 0xca, 0xdc, 0x0d, 0xf3, 0x43, 0xce, 0xb2, 0x62, 0x79, - 0xa7, 0x90, 0x22, 0x88, 0x67, 0xda, 0x10, 0xc0, 0x53, 0xb6, 0x40, 0x54, - 0x54, 0x16, 0xa3, 0x92, 0x97, 0xbe, 0xae, 0xf0, 0x7d, 0x11, 0xae, 0x53, - 0x52, 0x83, 0xe5, 0x5a, 0xdf, 0xd4, 0xf9, 0x75, 0xea, 0x32, 0xb5, 0xca, - 0x8b, 0x41, 0xa9, 0x4e, 0x68, 0x3a, 0x8c, 0x48, 0xcc, 0xd8, 0x47, 0x8b, - 0x85, 0xa0, 0x1e, 0x95, 0x55, 0xc4, 0xb0, 0x55, 0x2e, 0x14, 0xa3, 0xf4, - 0xc8, 0x35, 0x4a, 0x5c, 0x45, 0xe8, 0x82, 0x6c, 0xc0, 0x53, 0x54, 0xd4, - 0x3f, 0x1a, 0xbe, 0xe1, 0xa1, 0xe9, 0x37, 0xc9, 0xa2, 0x4f, 0xbe, 0x20, - 0x1a, 0x4d, 0x6b, 0x0c, 0xad, 0xe0, 0x53, 0x60, 0xea, 0x15, 0x9e, 0x77, - 0x49, 0xdc, 0xc1, 0xfa, 0x52, 0x67, 0x3b, 0x8d, 0x24, 0xc0, 0x9c, 0x4f, - 0x56, 0x2d, 0x74, 0x91, 0x7a, 0xcf, 0x2c, 0xdf, 0xd6, 0xfe, 0x2b, 0x13, - 0x84, 0x95, 0x7b, 0xb9, 0x5a, 0x2d, 0x89, 0xed, 0x94, 0xaa, 0xe8, 0xe8, - 0x2c, 0xae, 0x00, 0x7c, 0x67, 0x7e, 0x03, 0x4f, 0x0d, 0xa8, 0x76, 0xb0, - 0xb7, 0xb3, 0xb7, 0xee, 0x61, 0xc6, 0x7d, 0xf2, 0x22, 0x8a, 0xb5, 0x2c, - 0x05, 0xb6, 0x3e, 0x77, 0x6e, 0xda, 0xe7, 0x19, 0xe7, 0xef, 0x5c, 0x73, - 0x77, 0x86, 0x79, 0x3b, 0xc3, 0x9c, 0xb5, 0xcf, 0x57, 0xdb, 0x5c, 0xb5, - 0xce, 0x53, 0x65, 0x4e, 0x02, 0x33, 0xe6, 0x05, 0x14, 0x16, 0xc4, 0x70, - 0x0f, 0x5c, 0x55, 0xde, 0x1e, 0xbc, 0x7f, 0xa7, 0xb1, 0x20, 0x0c, 0xb3, - 0x96, 0xf5, 0x4f, 0x56, 0x22, 0x8a, 0x43, 0xc2, 0x87, 0x5b, 0x0f, 0x5b, - 0xde, 0xc3, 0x57, 0xf8, 0xd8, 0xc6, 0xc7, 0x0e, 0x3e, 0x5e, 0xe3, 0xe3, - 0x0d, 0x3e, 0x7e, 0xc7, 0xc7, 0x5b, 0x7c, 0xec, 0xe2, 0xe3, 0x3f, 0xf1, - 0xf1, 0x07, 0x3e, 0xde, 0xe1, 0xe3, 0x3d, 0x3e, 0x3e, 0xe0, 0x63, 0x0f, - 0x1f, 0xfb, 0xf8, 0xf8, 0x2f, 0x7c, 0x7c, 0xc4, 0x47, 0x17, 0x1f, 0x07, - 0xf8, 0xf8, 0x84, 0x8f, 0x3f, 0xf1, 0xf1, 0x19, 0x1f, 0xff, 0x0b, 0x1f, - 0xff, 0x8d, 0x8f, 0xff, 0xfd, 0xb0, 0x38, 0x25, 0x7c, 0x18, 0xe0, 0x9b, - 0x1e, 0x3e, 0xfa, 0xf8, 0x18, 0xe0, 0x23, 0xc4, 0xc7, 0x29, 0x3e, 0xce, - 0xf0, 0x71, 0x8e, 0x8f, 0x08, 0x1f, 0x7f, 0xe1, 0xe3, 0x0b, 0x3e, 0x86, - 0xf8, 0xb8, 0xc0, 0xc7, 0x08, 0x1f, 0x31, 0x3e, 0xc6, 0xf8, 0xf8, 0x17, - 0x3e, 0x12, 0x7c, 0xa4, 0xf8, 0xc8, 0xf0, 0x31, 0xc1, 0xc7, 0x57, 0x7c, - 0x5c, 0xe2, 0xe3, 0x1b, 0x3e, 0xae, 0xf0, 0xf1, 0xb7, 0x8c, 0xc9, 0x2a, - 0xbe, 0xe9, 0xe0, 0x63, 0x0d, 0x1f, 0x8f, 0xf0, 0xf1, 0x18, 0x1f, 0x4f, - 0xf0, 0xf1, 0x14, 0x1f, 0xcf, 0xf0, 0xf1, 0x1c, 0x1f, 0xff, 0xc0, 0xc7, - 0x32, 0x3e, 0xda, 0xf8, 0x38, 0xc6, 0xc7, 0xff, 0xc1, 0x47, 0x03, 0x1f, - 0x4d, 0x7c, 0xfc, 0x82, 0x8f, 0x5f, 0xf1, 0xb1, 0x8e, 0x8f, 0xd6, 0x43, - 0x16, 0xd4, 0xc8, 0xa2, 0x9c, 0xfa, 0xe7, 0x18, 0xe3, 0x34, 0xd0, 0x23, - 0x9c, 0xf8, 0x48, 0x9d, 0xc8, 0x61, 0xf5, 0x15, 0x49, 0x8f, 0x51, 0xad, - 0x12, 0xda, 0x89, 0x50, 0x58, 0xf0, 0x60, 0x1f, 0x80, 0x4f, 0x8b, 0x0f, - 0x79, 0x22, 0x52, 0x58, 0x99, 0xcf, 0x13, 0xf3, 0x03, 0xcf, 0x40, 0x9a, - 0x32, 0xde, 0x2a, 0x3e, 0x5b, 0x12, 0x8f, 0x1a, 0x4e, 0x04, 0xd4, 0xa8, - 0x09, 0x37, 0x0b, 0x36, 0x7d, 0x0c, 0x9d, 0x79, 0xf0, 0x1f, 0xdf, 0x82, - 0x8d, 0x6f, 0xcf, 0x9e, 0x3e, 0x2f, 0x3e, 0x4a, 0x1a, 0x61, 0xfe, 0x8e, - 0xe7, 0x36, 0x66, 0xb0, 0x04, 0xf2, 0x45, 0xde, 0x81, 0x13, 0x31, 0x13, - 0x58, 0xa4, 0xd4, 0xc3, 0x87, 0xf2, 0x94, 0xe0, 0x68, 0xe3, 0x6c, 0x48, - 0x49, 0x89, 0xb4, 0x0b, 0x65, 0x28, 0xf6, 0x12, 0xff, 0xd8, 0x64, 0x6e, - 0x0f, 0xa6, 0x1a, 0x22, 0x81, 0xd4, 0x66, 0xbd, 0x2e, 0xeb, 0xe3, 0x04, - 0x76, 0x1c, 0xb0, 0x04, 0x44, 0xb4, 0x67, 0x84, 0xff, 0x7e, 0x93, 0x05, - 0xac, 0x88, 0x97, 0x80, 0x0f, 0x4b, 0x4b, 0x66, 0xf0, 0x55, 0x58, 0xe9, - 0x1a, 0x23, 0x8f, 0xa3, 0xe6, 0x9b, 0x11, 0x0e, 0xdd, 0xda, 0x9b, 0x53, - 0x01, 0x8d, 0x98, 0xd6, 0x59, 0x05, 0x06, 0x07, 0x0d, 0xc0, 0x70, 0x09, - 0xc3, 0x56, 0x39, 0xec, 0x7e, 0x83, 0xa2, 0x6b, 0x61, 0xdf, 0xd8, 0x28, - 0x6b, 0x41, 0xc4, 0x4b, 0xb7, 0xbc, 0xce, 0x6a, 0xb3, 0xd9, 0x34, 0x36, - 0xc1, 0xaa, 0xc0, 0xd6, 0x28, 0xaa, 0x6e, 0x74, 0x56, 0x7a, 0xd1, 0x88, - 0xc6, 0x2c, 0xc5, 0x8c, 0x8b, 0xc6, 0xba, 0xad, 0x6b, 0xcd, 0x09, 0x8f, - 0x44, 0x26, 0x78, 0xe2, 0x47, 0x3b, 0x40, 0x7f, 0x85, 0x57, 0x93, 0xd3, - 0x53, 0xd0, 0x49, 0x9a, 0x46, 0x1d, 0xe9, 0xab, 0x45, 0x4b, 0x91, 0xbe, - 0xca, 0x01, 0xb2, 0xa0, 0x97, 0x28, 0x12, 0xdb, 0x1a, 0x8f, 0xcb, 0xa3, - 0xd2, 0x5b, 0xcc, 0x8d, 0x07, 0xd5, 0x99, 0x5f, 0x6d, 0xcc, 0x51, 0xe2, - 0xa7, 0x96, 0x6a, 0x71, 0xed, 0xca, 0xea, 0xc8, 0x02, 0x71, 0x94, 0x96, - 0x8d, 0xe0, 0x67, 0x09, 0xfd, 0x96, 0x67, 0xe0, 0xa3, 0x3a, 0x69, 0x4c, - 0x37, 0xea, 0x1a, 0x93, 0xec, 0xe6, 0x29, 0xdb, 0xe2, 0x54, 0xb0, 0x0e, - 0x0e, 0xb3, 0x60, 0x0c, 0x89, 0xce, 0xe2, 0x90, 0xbc, 0xf8, 0x24, 0x4d, - 0x12, 0xb4, 0xbe, 0xa2, 0xa9, 0x79, 0xdd, 0x7c, 0xa5, 0xb9, 0x7d, 0x8b, - 0x40, 0xcb, 0x3c, 0x88, 0x6f, 0xc3, 0xa8, 0xb2, 0x66, 0x81, 0xb2, 0x56, - 0x02, 0x85, 0xa2, 0xfd, 0x4c, 0x30, 0x8f, 0x2c, 0x60, 0x1e, 0x95, 0x80, - 0xc1, 0xb0, 0x40, 0x13, 0xca, 0x13, 0x0b, 0x94, 0x27, 0x0e, 0x28, 0x79, - 0x8c, 0xa0, 0x09, 0xe6, 0xa9, 0x05, 0xcc, 0x53, 0x3b, 0x98, 0x9d, 0xbd, - 0xcf, 0x1f, 0xba, 0xdb, 0x5b, 0xef, 0x5e, 0x5b, 0xc0, 0x3c, 0xb6, 0x57, - 0x11, 0x91, 0x8b, 0x46, 0x85, 0x8e, 0xab, 0xc2, 0xd3, 0xe7, 0xdf, 0x9e, - 0x3c, 0x7b, 0x6a, 0x56, 0x58, 0xeb, 0xac, 0xa3, 0x4e, 0xd2, 0xbb, 0xc2, - 0x94, 0x6f, 0x5e, 0xc7, 0xf8, 0xbc, 0x26, 0x7f, 0x5e, 0xb3, 0xc2, 0x7e, - 0xf5, 0xdf, 0xfb, 0x5b, 0xdd, 0xae, 0x04, 0x7a, 0xc0, 0x52, 0x46, 0xdb, - 0x31, 0xd9, 0xfe, 0xd4, 0x3d, 0xd8, 0x7b, 0xef, 0x57, 0x88, 0x9e, 0xd7, - 0x49, 0x12, 0x27, 0x1f, 0xd1, 0x96, 0xa8, 0x09, 0x21, 0x49, 0xf3, 0x54, - 0x6b, 0x6c, 0x8d, 0x06, 0xbb, 0xa3, 0x28, 0x43, 0xc9, 0xb6, 0xba, 0x2a, - 0xf3, 0xbb, 0xb5, 0x98, 0x6d, 0x63, 0x20, 0xe9, 0x8f, 0xba, 0x24, 0xb2, - 0x6b, 0xac, 0x64, 0x19, 0x71, 0xa8, 0xa8, 0xae, 0xee, 0xd8, 0x6d, 0xc9, - 0xb6, 0x69, 0x1c, 0x01, 0x9a, 0x9f, 0x76, 0xb9, 0xef, 0x91, 0xa2, 0xd3, - 0x62, 0x94, 0xce, 0xef, 0x30, 0x8b, 0xb3, 0x20, 0x9b, 0x14, 0x5a, 0xb5, - 0x45, 0x9d, 0x66, 0x20, 0xf4, 0x26, 0x2b, 0xb4, 0xe5, 0x0a, 0xe3, 0xb7, - 0xcd, 0x4e, 0xaa, 0x97, 0x91, 0x06, 0xe9, 0x3c, 0x1a, 0x84, 0x18, 0xe4, - 0x4a, 0xc6, 0xe1, 0x8e, 0xea, 0x5d, 0x3e, 0xcd, 0xe3, 0x87, 0x9d, 0xe4, - 0x32, 0x36, 0xbc, 0xce, 0x82, 0xb9, 0xb9, 0x0c, 0xed, 0x3f, 0x51, 0x2a, - 0xdb, 0x44, 0x41, 0xfe, 0x46, 0x01, 0x2e, 0xe8, 0x8d, 0xd3, 0xc9, 0xa8, - 0xcf, 0x46, 0x91, 0xfe, 0xca, 0x43, 0xa3, 0xc7, 0xac, 0x4e, 0x8b, 0x5e, - 0xd3, 0x77, 0xfe, 0xa6, 0x58, 0xbd, 0x80, 0xa1, 0xf3, 0x8a, 0x82, 0xe6, - 0x24, 0xc9, 0x61, 0x51, 0x8d, 0xb3, 0x18, 0x95, 0xb3, 0x36, 0x34, 0x07, - 0x58, 0xe2, 0x7a, 0x38, 0x10, 0x55, 0x9a, 0xcd, 0x96, 0xc0, 0x08, 0x5a, - 0x4b, 0xe3, 0xe1, 0xd7, 0xb0, 0x71, 0x78, 0x84, 0x4b, 0x2f, 0xe2, 0x8a, - 0x19, 0xbd, 0x61, 0xd7, 0x5b, 0xa0, 0xca, 0x0e, 0xa5, 0xde, 0xc2, 0x6b, - 0x7d, 0xeb, 0x0e, 0x9a, 0xcc, 0x39, 0x7b, 0x6d, 0x6c, 0xcf, 0x29, 0x2f, - 0x38, 0xba, 0x4b, 0xc9, 0x32, 0x5f, 0x2a, 0x75, 0x99, 0x44, 0xa8, 0x3e, - 0x50, 0xb1, 0x96, 0xf7, 0x0b, 0xfe, 0xcf, 0x29, 0xcf, 0x58, 0x01, 0x9b, - 0x6b, 0x88, 0xd7, 0x45, 0x48, 0x0a, 0x73, 0x8e, 0x12, 0xb1, 0x97, 0x18, - 0x7a, 0x6c, 0x35, 0x33, 0x0e, 0xb4, 0x12, 0x06, 0x7a, 0x4a, 0x81, 0x1a, - 0x78, 0xaa, 0xe5, 0x01, 0x61, 0xe5, 0x85, 0x82, 0xb9, 0x82, 0x5d, 0xc3, - 0x28, 0xa8, 0xf5, 0x65, 0x5b, 0x37, 0x63, 0x38, 0xcc, 0xa6, 0x66, 0xa9, - 0x3a, 0x16, 0x11, 0x57, 0x77, 0xcc, 0xa2, 0xd0, 0x25, 0xe3, 0xa5, 0xd2, - 0x2d, 0x03, 0xd1, 0x86, 0xb5, 0x82, 0xa6, 0x09, 0x0b, 0xae, 0xa1, 0x81, - 0x54, 0x2d, 0xef, 0xec, 0x55, 0x21, 0x1c, 0x72, 0xcd, 0xb6, 0x17, 0x0f, - 0xae, 0xda, 0xb4, 0x7d, 0x21, 0x87, 0x3e, 0x66, 0x1f, 0x68, 0xe4, 0xd9, - 0xe6, 0x97, 0x71, 0xfa, 0xfa, 0xcd, 0x92, 0x23, 0x15, 0x17, 0xa4, 0x60, - 0x30, 0x70, 0x82, 0xd1, 0xf0, 0x36, 0x58, 0x4c, 0x1d, 0x46, 0x7d, 0x7c, - 0xca, 0x54, 0x73, 0x66, 0xcd, 0xe6, 0x59, 0xbd, 0x36, 0x0b, 0x4e, 0xf2, - 0x15, 0x6b, 0xb6, 0x06, 0xff, 0x5a, 0xd6, 0xb8, 0x0d, 0xbf, 0x49, 0x96, - 0x15, 0xcf, 0x6f, 0xba, 0x8e, 0x10, 0xb4, 0xe0, 0xe4, 0x5a, 0x4e, 0x9e, - 0x75, 0xc8, 0xcf, 0xd3, 0x6b, 0x55, 0x0e, 0x80, 0xb1, 0x4b, 0xe0, 0x08, - 0x6b, 0x4d, 0x96, 0x23, 0x5d, 0xc3, 0x5b, 0xb4, 0x72, 0xa0, 0x9d, 0x08, - 0x97, 0x37, 0xad, 0x0e, 0xa0, 0xdf, 0xce, 0x13, 0x84, 0x35, 0x15, 0x4f, - 0x60, 0x55, 0xca, 0x94, 0xbb, 0x04, 0x6b, 0xfc, 0x65, 0x9d, 0xf6, 0x6c, - 0x3e, 0xcd, 0x36, 0xc3, 0x25, 0x9b, 0xa7, 0x32, 0xbb, 0x14, 0x58, 0x8e, - 0xa3, 0x2c, 0xe8, 0xb9, 0x01, 0xb1, 0x92, 0x57, 0xac, 0x03, 0x5e, 0x05, - 0xb4, 0x62, 0x2c, 0x6d, 0x63, 0x62, 0x02, 0xa9, 0x39, 0x2a, 0x2a, 0x15, - 0x6b, 0x8e, 0x4a, 0x41, 0xea, 0x7c, 0xf7, 0x34, 0x4c, 0x59, 0xa2, 0x90, - 0x75, 0xef, 0x5a, 0x04, 0x14, 0x93, 0xf0, 0xfc, 0x12, 0x5e, 0xb5, 0x3c, - 0x3a, 0xd2, 0xd3, 0xc8, 0x2a, 0xc6, 0x4a, 0x54, 0x54, 0x47, 0x30, 0x7f, - 0x0b, 0x4b, 0xcd, 0xf5, 0x74, 0xa3, 0xac, 0xe2, 0x21, 0x34, 0x81, 0x11, - 0x4c, 0xd4, 0xc8, 0x86, 0x94, 0x53, 0xa0, 0x1f, 0x0c, 0x45, 0x59, 0xdc, - 0xfe, 0x64, 0xe1, 0x45, 0xc3, 0x2f, 0xa8, 0x96, 0x6b, 0x20, 0x30, 0x5c, - 0xff, 0xd9, 0xdd, 0xfb, 0xd0, 0x66, 0xa7, 0x27, 0xd1, 0xe9, 0x55, 0xc3, - 0xd2, 0x48, 0xb3, 0xa9, 0xe4, 0x29, 0x22, 0x06, 0xc3, 0xa3, 0xa5, 0xca, - 0x3e, 0x11, 0x68, 0xda, 0x3a, 0x36, 0x14, 0x8c, 0xce, 0xca, 0x30, 0xa2, - 0x15, 0xd6, 0xbf, 0x9e, 0xca, 0xb3, 0x97, 0x6b, 0xdf, 0x2e, 0x02, 0xc8, - 0x79, 0x5c, 0xd8, 0x20, 0x69, 0x31, 0x05, 0x38, 0x65, 0xc4, 0x2b, 0xd3, - 0x24, 0xa0, 0xeb, 0x41, 0xe9, 0x30, 0xea, 0x83, 0x36, 0x14, 0x0c, 0x87, - 0x45, 0x25, 0x63, 0x35, 0x96, 0x43, 0x4d, 0x10, 0x7c, 0x34, 0x20, 0xc0, - 0xb9, 0x2b, 0xce, 0x31, 0x1d, 0x5e, 0xc1, 0xff, 0xb4, 0x53, 0x96, 0x1a, - 0xad, 0xe7, 0xe1, 0x2e, 0x05, 0x21, 0x54, 0x9c, 0x3d, 0xd2, 0xb4, 0xc6, - 0xd6, 0xa5, 0x4c, 0x16, 0xf5, 0x1c, 0xf6, 0xa5, 0xa5, 0xcc, 0x8c, 0xed, - 0xa4, 0x28, 0x41, 0x75, 0x01, 0x53, 0x67, 0x9d, 0x3b, 0x3b, 0x03, 0x70, - 0xd3, 0xd5, 0x30, 0x6c, 0x73, 0x98, 0x3c, 0x0e, 0xe2, 0x5e, 0x11, 0x36, - 0xe5, 0xf7, 0xd0, 0xd1, 0xa9, 0xc8, 0x45, 0x58, 0x44, 0x43, 0x69, 0xa2, - 0x4f, 0x38, 0x0e, 0x94, 0xfb, 0x0c, 0x15, 0x31, 0x77, 0x3c, 0x60, 0xce, - 0x7b, 0xa1, 0xba, 0x9a, 0x24, 0x21, 0x14, 0x49, 0xb3, 0xad, 0x51, 0x74, - 0x41, 0x3e, 0x6b, 0x6f, 0xd0, 0x25, 0xd5, 0xba, 0xe3, 0xa8, 0x3a, 0x95, - 0xb7, 0xb6, 0xba, 0x51, 0x07, 0xc4, 0x8d, 0x4e, 0xe8, 0xcb, 0x03, 0x0c, - 0xd5, 0xb0, 0xbd, 0xa9, 0x4b, 0x3f, 0xc1, 0x2b, 0xde, 0xf7, 0xe3, 0x44, - 0xdf, 0x33, 0xe6, 0x0b, 0xa2, 0xf8, 0x83, 0x6f, 0xd5, 0xf8, 0xe0, 0x01, - 0xef, 0x80, 0xde, 0x0f, 0x0b, 0x56, 0x76, 0xd5, 0xf0, 0x97, 0x97, 0xbf, - 0x02, 0x10, 0xbc, 0x66, 0x11, 0xf4, 0x21, 0xf2, 0x5d, 0x6c, 0xc1, 0x2e, - 0x6e, 0x34, 0x88, 0x2f, 0x99, 0x38, 0x65, 0x38, 0x7b, 0x4b, 0x9e, 0x3f, - 0xfe, 0xe6, 0xcb, 0x53, 0x45, 0xda, 0x3e, 0xb9, 0x9d, 0x51, 0x80, 0x06, - 0x2c, 0x07, 0x8a, 0xc6, 0xb0, 0x84, 0x08, 0xf2, 0x2b, 0x67, 0xa4, 0x75, - 0x62, 0x92, 0xa6, 0xee, 0x5a, 0xf6, 0x06, 0xb7, 0x54, 0x22, 0x53, 0x20, - 0xdb, 0x54, 0x62, 0x5b, 0x8a, 0xc5, 0x4e, 0x4a, 0x98, 0x90, 0x1b, 0xef, - 0xe2, 0x2f, 0x32, 0x8f, 0xa0, 0x2b, 0xd5, 0x25, 0x85, 0x5a, 0xd3, 0xa6, - 0xac, 0x71, 0xf2, 0xf6, 0xe0, 0x60, 0xdf, 0xbb, 0x7f, 0x9d, 0x17, 0x4f, - 0x09, 0xf2, 0xd4, 0x5b, 0x36, 0x5f, 0xe2, 0x68, 0xe4, 0x67, 0x7d, 0x8a, - 0x57, 0x85, 0x28, 0xa8, 0x9c, 0xef, 0x05, 0x83, 0x77, 0x28, 0x0c, 0x61, - 0xd9, 0x21, 0xc1, 0x81, 0x17, 0xc3, 0x18, 0x5a, 0x22, 0x96, 0x22, 0x47, - 0x14, 0xc4, 0x08, 0x4b, 0x7e, 0xa4, 0x17, 0x62, 0xa7, 0xca, 0x3e, 0xa3, - 0xf2, 0xf2, 0xfa, 0x2b, 0x8c, 0x19, 0x6a, 0x32, 0xe8, 0x36, 0xd8, 0xa0, - 0x6c, 0x3f, 0x40, 0xb2, 0x46, 0x88, 0xaf, 0x35, 0x06, 0x1f, 0xc4, 0x3c, - 0xe7, 0x4b, 0x83, 0x57, 0xe7, 0x7b, 0xbc, 0xc2, 0xc8, 0x26, 0x81, 0xc6, - 0xff, 0xb6, 0xd2, 0x2d, 0xc9, 0xc0, 0x49, 0x78, 0xe6, 0xdb, 0xd4, 0x9e, - 0xb8, 0xb3, 0x49, 0x5c, 0xcb, 0x95, 0xef, 0x01, 0x07, 0x31, 0xbf, 0x4c, - 0xc9, 0xdc, 0x01, 0xb2, 0x4a, 0xd8, 0x1d, 0x9e, 0x24, 0x0e, 0x5f, 0x62, - 0xe2, 0xdc, 0xc2, 0x2f, 0x0a, 0xdf, 0x64, 0x78, 0x69, 0x79, 0xf1, 0x8a, - 0x59, 0x6c, 0xfd, 0x95, 0x74, 0x1c, 0x9d, 0x9e, 0xa6, 0x2b, 0x83, 0x28, - 0xf1, 0x4d, 0xfb, 0x2c, 0x33, 0xcc, 0xb6, 0xff, 0x4a, 0xe3, 0x91, 0xc5, - 0x14, 0x4b, 0xf7, 0x47, 0x69, 0xe4, 0x90, 0x90, 0x41, 0xf7, 0x9c, 0x02, - 0x29, 0xe6, 0x5d, 0xc9, 0x50, 0xa0, 0xd7, 0x46, 0x1c, 0x2e, 0xb7, 0xcc, - 0xe0, 0x1e, 0x3c, 0x2f, 0x43, 0x87, 0x2e, 0xe3, 0x20, 0x3b, 0x67, 0xcb, - 0x80, 0x45, 0xb8, 0x68, 0x06, 0x68, 0xd1, 0x1d, 0x7e, 0x95, 0xd2, 0x4b, - 0x04, 0xb3, 0x79, 0xff, 0x1a, 0x41, 0x38, 0xdd, 0x17, 0x2c, 0x4c, 0x5d, - 0x16, 0x40, 0x2a, 0xe7, 0x01, 0xb2, 0x18, 0xe3, 0x45, 0x01, 0x60, 0x98, - 0x93, 0xfb, 0xd7, 0x38, 0x0e, 0xd3, 0x95, 0xfb, 0xd7, 0xd4, 0x75, 0xe3, - 0xe8, 0x9a, 0x31, 0xd0, 0x28, 0x94, 0xfd, 0xf1, 0xb4, 0x8e, 0xb9, 0x66, - 0xa3, 0x84, 0xf5, 0x83, 0x07, 0x0e, 0xe3, 0x79, 0xc9, 0x31, 0xa5, 0xa9, - 0x06, 0x30, 0x83, 0x08, 0xb7, 0x86, 0x6c, 0x18, 0xae, 0x05, 0xee, 0x21, - 0xe7, 0x42, 0x89, 0x38, 0xbc, 0x48, 0x44, 0x97, 0x0f, 0xa1, 0x92, 0x69, - 0xee, 0xd4, 0x9d, 0x21, 0x10, 0x53, 0x4a, 0x4a, 0xdc, 0x73, 0xc8, 0xf2, - 0xf7, 0xa1, 0x1a, 0x26, 0xe7, 0xba, 0xac, 0x95, 0x83, 0x4e, 0x49, 0x19, - 0xc9, 0xd0, 0x93, 0x20, 0xa3, 0xfe, 0x24, 0xd4, 0xa8, 0x42, 0x43, 0xd3, - 0xf1, 0xaf, 0x82, 0xc0, 0x33, 0x7b, 0x6a, 0x6f, 0x1d, 0x4c, 0x7d, 0x11, - 0x44, 0xa3, 0xb7, 0x42, 0xf8, 0xa8, 0x41, 0x9f, 0x0d, 0x1b, 0xdc, 0x17, - 0x2f, 0xd0, 0xdf, 0xc6, 0x7b, 0xe0, 0xad, 0x3d, 0x79, 0xd2, 0xaa, 0x55, - 0xbc, 0xf3, 0x74, 0xa6, 0xe2, 0xcf, 0x67, 0x2a, 0xbd, 0x6a, 0x94, 0x3e, - 0xd2, 0x7b, 0xc8, 0x36, 0x7a, 0x42, 0x2d, 0x54, 0xbb, 0xd8, 0x6e, 0xb7, - 0x0b, 0x02, 0xb4, 0xf4, 0x4f, 0x3a, 0x05, 0x61, 0x55, 0x8a, 0x32, 0x4c, - 0xa9, 0xc8, 0x4f, 0x5c, 0x89, 0x55, 0xfa, 0x6a, 0x88, 0x6d, 0xd3, 0x80, - 0x32, 0x1b, 0xaf, 0x71, 0x7e, 0x03, 0x4c, 0xe1, 0xc9, 0x2d, 0x74, 0xdc, - 0x70, 0x87, 0x59, 0x25, 0x1b, 0x5a, 0x06, 0xd8, 0xd3, 0x66, 0xb3, 0xe9, - 0x9c, 0xa0, 0x46, 0xde, 0x52, 0x60, 0xc0, 0xc3, 0xa3, 0xa6, 0x95, 0x56, - 0x42, 0x2c, 0xbd, 0x1a, 0xc6, 0x3d, 0x6a, 0x84, 0xfe, 0x38, 0xd4, 0x9a, - 0x93, 0x68, 0xd9, 0x04, 0x40, 0xde, 0x09, 0x9d, 0xe8, 0x8a, 0xb0, 0x7e, - 0x76, 0xc1, 0x99, 0x2a, 0xca, 0xd0, 0xba, 0x78, 0xe2, 0xdc, 0xd8, 0xcf, - 0x24, 0xb2, 0x4e, 0x6c, 0xbe, 0x0b, 0xf9, 0x22, 0xe7, 0x5c, 0x5a, 0xaf, - 0xe5, 0x64, 0x6e, 0xde, 0x54, 0xd7, 0xc7, 0x64, 0x57, 0x3e, 0xac, 0xcf, - 0x24, 0x94, 0x99, 0x6b, 0x97, 0x2f, 0x87, 0xba, 0x58, 0x21, 0x8b, 0x32, - 0x97, 0x28, 0xfc, 0x74, 0x8f, 0xb6, 0x13, 0x8d, 0xc7, 0x2d, 0xef, 0xa9, - 0xa4, 0xdb, 0x4b, 0xa5, 0x0f, 0x57, 0x8f, 0xc8, 0xab, 0x6e, 0xf5, 0xdb, - 0xb3, 0x1e, 0xee, 0x7d, 0xe4, 0x4f, 0x1d, 0xf1, 0x69, 0x4d, 0x71, 0x84, - 0x97, 0x7a, 0xa0, 0x11, 0x49, 0xe4, 0xd3, 0xd7, 0x0d, 0x28, 0x40, 0xbc, - 0x2d, 0x4c, 0xfb, 0xd5, 0xf0, 0x77, 0x47, 0xec, 0x8a, 0x43, 0xbe, 0x4a, - 0x23, 0x3b, 0x6b, 0x19, 0x0a, 0xdc, 0x16, 0x79, 0xb9, 0x5d, 0x63, 0x03, - 0x93, 0x37, 0xad, 0x3a, 0x99, 0x2c, 0x06, 0x8e, 0x86, 0xa1, 0xe2, 0x3e, - 0x36, 0x2f, 0xe8, 0x8d, 0x4a, 0x87, 0xd0, 0xde, 0xaa, 0x32, 0xa4, 0x30, - 0x62, 0x2d, 0xaf, 0xd7, 0x51, 0xdf, 0x75, 0xf0, 0xdd, 0x9a, 0xfa, 0x6e, - 0x0d, 0xdf, 0x3d, 0x52, 0xdf, 0x3d, 0x3a, 0x32, 0xb9, 0x86, 0x8b, 0xe8, - 0x06, 0xb4, 0xf3, 0xdb, 0x6f, 0x24, 0x50, 0x97, 0xe0, 0x47, 0x07, 0x7f, - 0xa0, 0xb8, 0xc4, 0x1f, 0x6b, 0xf8, 0xe3, 0x39, 0xfe, 0xdd, 0x7b, 0x64, - 0x01, 0x40, 0xab, 0x03, 0x80, 0x90, 0x44, 0x83, 0x8d, 0x05, 0xa5, 0xe6, - 0x96, 0xbc, 0xc7, 0xb2, 0xa2, 0x24, 0x89, 0x30, 0x5b, 0xd6, 0xda, 0xbe, - 0x5c, 0x56, 0xa4, 0x92, 0x35, 0xf1, 0xb0, 0x6d, 0xfd, 0x65, 0x0c, 0x9b, - 0xfa, 0xf4, 0x42, 0x05, 0x8a, 0x55, 0x6a, 0xc3, 0x4e, 0x3e, 0x6d, 0xc8, - 0x60, 0x9a, 0x85, 0x4a, 0xc8, 0x12, 0x60, 0xab, 0xd8, 0x9b, 0x0a, 0xa3, - 0xa9, 0xad, 0x99, 0x0a, 0xa6, 0x53, 0x77, 0xc3, 0x3f, 0x73, 0xaf, 0xd8, - 0x86, 0x55, 0x73, 0xc0, 0x22, 0x3c, 0xa1, 0x5d, 0x6a, 0x9b, 0xe3, 0x80, - 0x65, 0x8b, 0x50, 0x5d, 0x52, 0xc8, 0x71, 0x28, 0x40, 0x1f, 0x19, 0x4b, - 0x35, 0xde, 0xae, 0xce, 0x03, 0xca, 0x49, 0xd3, 0xe7, 0x3f, 0x65, 0x85, - 0x48, 0x14, 0x69, 0x07, 0xe3, 0x71, 0x38, 0x1a, 0x34, 0xd8, 0x4d, 0x92, - 0x2d, 0xaf, 0x10, 0xca, 0x32, 0x5a, 0xc0, 0x70, 0xd7, 0x22, 0xf5, 0x27, - 0x54, 0x00, 0xb4, 0x68, 0xcb, 0xbb, 0x12, 0xf7, 0xb3, 0x30, 0x5b, 0x06, - 0x25, 0x22, 0x0c, 0x2e, 0x7c, 0xe0, 0xf9, 0x96, 0x27, 0x90, 0xe2, 0xce, - 0xb3, 0x8d, 0x4e, 0xd3, 0xd4, 0xb4, 0x34, 0xd5, 0x9b, 0xdd, 0x76, 0x09, - 0x6d, 0xab, 0x53, 0xee, 0x82, 0x82, 0x90, 0xa0, 0xc1, 0xfd, 0xbd, 0xee, - 0x81, 0x96, 0x23, 0x14, 0xcd, 0xad, 0xeb, 0x79, 0x1f, 0xa4, 0x44, 0xa1, - 0x35, 0x54, 0x5a, 0xfb, 0xda, 0xc0, 0xe5, 0xfb, 0x9c, 0xfa, 0xac, 0x4d, - 0x97, 0xe5, 0x19, 0xaa, 0xed, 0x43, 0x67, 0x55, 0xe7, 0x8a, 0xfd, 0x9d, - 0xb1, 0x0d, 0xe7, 0xff, 0x2b, 0xba, 0xaa, 0x5d, 0xb0, 0xce, 0xd3, 0x4d, - 0xb9, 0x5b, 0x85, 0x7b, 0x6c, 0x50, 0xe6, 0xc4, 0x5c, 0xac, 0x04, 0x3c, - 0xc0, 0x00, 0x05, 0x87, 0x84, 0xc3, 0x3f, 0x47, 0xfb, 0xc3, 0x10, 0x8f, - 0xcf, 0x2f, 0x83, 0x28, 0xf3, 0x26, 0xa3, 0x2c, 0x1a, 0xd2, 0x91, 0x2d, - 0x74, 0x96, 0x47, 0xca, 0xa4, 0x78, 0x13, 0x2e, 0xde, 0x8e, 0x11, 0xc1, - 0x52, 0xb7, 0xf7, 0x87, 0x25, 0xbf, 0x4d, 0xb9, 0xfb, 0x25, 0x37, 0x1d, - 0x88, 0x1b, 0x2f, 0x41, 0x4c, 0x23, 0xea, 0xe6, 0x26, 0xc0, 0x04, 0x6b, - 0x7a, 0x0d, 0xdb, 0xe8, 0x2e, 0x29, 0x03, 0x85, 0x12, 0x43, 0xe2, 0x15, - 0xfe, 0x6f, 0x91, 0x2f, 0x3d, 0x1a, 0x4f, 0x70, 0x68, 0xdb, 0xd9, 0xb7, - 0xcc, 0x57, 0xfd, 0x1b, 0x81, 0x0e, 0x5f, 0x81, 0x3c, 0xde, 0x55, 0x3c, - 0x49, 0x3c, 0xac, 0x01, 0xba, 0x59, 0x16, 0x7b, 0x01, 0x4d, 0x36, 0xef, - 0xd3, 0xc7, 0x77, 0x5e, 0x23, 0xf0, 0xd2, 0x71, 0xd8, 0xc7, 0x43, 0xd9, - 0x49, 0x82, 0x51, 0x58, 0x01, 0x0a, 0xa8, 0x08, 0x85, 0x02, 0x16, 0x1c, - 0x79, 0x31, 0x93, 0x82, 0xd1, 0x88, 0xae, 0x0c, 0xee, 0x25, 0xf1, 0x25, - 0x0c, 0xcb, 0xc3, 0x14, 0x26, 0xca, 0x45, 0x2c, 0x0e, 0x85, 0xf9, 0xc2, - 0x02, 0x30, 0x3f, 0x25, 0x28, 0xbb, 0x00, 0x70, 0x9b, 0x1d, 0x4e, 0x33, - 0xce, 0x83, 0xdf, 0x84, 0x2f, 0xef, 0x17, 0x22, 0x46, 0x5f, 0x01, 0x11, - 0x8a, 0x3c, 0xe1, 0x36, 0x40, 0x09, 0x16, 0x0b, 0x48, 0x29, 0x0c, 0x3b, - 0x0c, 0x1a, 0x37, 0xeb, 0x10, 0x53, 0xe4, 0xa0, 0xba, 0x21, 0x2b, 0x0e, - 0x38, 0x9d, 0x27, 0xe1, 0x29, 0xa2, 0x4d, 0x1d, 0xc0, 0x3f, 0x10, 0x65, - 0xd1, 0x55, 0x26, 0x43, 0xa1, 0x60, 0x9b, 0x8a, 0x6d, 0x0a, 0x7c, 0x37, - 0x8a, 0x0f, 0x82, 0xc6, 0x28, 0xc1, 0x80, 0xb0, 0x79, 0x13, 0x5b, 0x24, - 0xad, 0x18, 0x52, 0x1c, 0x2a, 0xca, 0x82, 0x7b, 0xe6, 0x61, 0x0c, 0x93, - 0x6b, 0xdb, 0xe7, 0xd1, 0x70, 0xc0, 0xc2, 0x6e, 0x72, 0x18, 0x3b, 0x51, - 0x3a, 0xc6, 0x11, 0xe7, 0xac, 0x46, 0x46, 0x0d, 0x2f, 0x66, 0x54, 0xc5, - 0x92, 0xa2, 0xdc, 0xc1, 0x79, 0x94, 0xe2, 0xdd, 0xcd, 0xc0, 0x9c, 0xe8, - 0x6c, 0x98, 0x5c, 0x79, 0x41, 0xca, 0xb0, 0xa3, 0x8a, 0xc0, 0x2f, 0x83, - 0x18, 0x56, 0x9a, 0x51, 0x9c, 0x79, 0x78, 0xeb, 0x5d, 0x0e, 0x02, 0xc8, - 0x43, 0x52, 0x1d, 0xfa, 0x16, 0x7f, 0x93, 0xba, 0xc4, 0x9b, 0x25, 0xdb, - 0x0a, 0x29, 0xbf, 0xef, 0xe3, 0x49, 0x1a, 0xb2, 0x9f, 0x3e, 0x81, 0x54, - 0x64, 0x60, 0x6f, 0xd2, 0x03, 0xa5, 0x22, 0x5d, 0xa7, 0xc3, 0x15, 0x29, - 0x31, 0x30, 0xa5, 0x45, 0x65, 0xd9, 0x63, 0xd5, 0x2f, 0x68, 0x4d, 0x5b, - 0xe7, 0xd3, 0x80, 0xe7, 0x21, 0x6d, 0x16, 0xbd, 0xfe, 0x48, 0x5a, 0x0b, - 0xa3, 0x1c, 0xae, 0xc1, 0x2e, 0xba, 0x31, 0xed, 0x46, 0xa1, 0x1b, 0x37, - 0xce, 0x7c, 0xde, 0x7d, 0xb3, 0x6b, 0x0d, 0xb9, 0x51, 0x5c, 0x2f, 0xca, - 0xfd, 0xe3, 0xb0, 0xe8, 0x0a, 0xb3, 0x6f, 0x55, 0x7b, 0xc7, 0x95, 0x5b, - 0x5f, 0x78, 0xda, 0x5a, 0x80, 0xe4, 0x96, 0x7c, 0x24, 0x61, 0x36, 0xbd, - 0xa2, 0xa8, 0x3b, 0xec, 0x0f, 0x8a, 0xb4, 0x29, 0xb3, 0x0e, 0x65, 0xe5, - 0x09, 0xc6, 0x65, 0xf9, 0xd8, 0xd0, 0x4e, 0x2d, 0x65, 0xdb, 0xad, 0x9d, - 0xc3, 0xa6, 0x04, 0x84, 0xe5, 0xec, 0xd0, 0xbc, 0x44, 0xaa, 0x12, 0x5c, - 0x9e, 0xe3, 0xd7, 0x79, 0x10, 0x50, 0x0b, 0xab, 0x02, 0x8c, 0xfd, 0x18, - 0xf6, 0x66, 0x98, 0x61, 0x82, 0x61, 0x6e, 0xd9, 0x65, 0x2e, 0xe0, 0x7e, - 0xf7, 0x60, 0xcb, 0xfb, 0xb7, 0xd7, 0x05, 0x96, 0xf6, 0x3e, 0xb0, 0xab, - 0x23, 0xfd, 0x9a, 0xa1, 0xa3, 0x25, 0x94, 0x9c, 0xab, 0xe7, 0x96, 0xf1, - 0x98, 0xbf, 0xe3, 0x73, 0x73, 0x89, 0x6d, 0x3c, 0xe6, 0x64, 0x13, 0x63, - 0x30, 0x4e, 0x94, 0xe8, 0x3c, 0x9a, 0x0e, 0x98, 0xd4, 0x78, 0x7a, 0x52, - 0x1a, 0x57, 0x22, 0xe5, 0xc1, 0xb6, 0xfa, 0x8d, 0x20, 0x08, 0xe3, 0x6c, - 0x42, 0xce, 0x62, 0xdd, 0x96, 0xce, 0x18, 0x79, 0x1a, 0x3e, 0x9e, 0x00, - 0xdb, 0x5a, 0x4d, 0xc9, 0x8e, 0x2d, 0xd7, 0x25, 0x2b, 0xbc, 0xa8, 0xca, - 0x95, 0x75, 0xf7, 0xa9, 0xb3, 0x09, 0xca, 0x42, 0x58, 0xe9, 0x92, 0xd9, - 0xe5, 0xe5, 0x10, 0xed, 0xf7, 0x7e, 0x8d, 0x4d, 0x5d, 0x85, 0xee, 0x6d, - 0xe8, 0xdd, 0xe8, 0x94, 0x80, 0x54, 0x72, 0x7d, 0x47, 0xef, 0x24, 0xd1, - 0xaf, 0xa6, 0x6a, 0xba, 0x26, 0x61, 0x2a, 0xae, 0x50, 0x96, 0x97, 0x0e, - 0x97, 0xea, 0x6c, 0x53, 0x9b, 0xa7, 0x0e, 0xa5, 0x2e, 0x57, 0xe8, 0x4e, - 0xa4, 0xfb, 0x29, 0x2e, 0x31, 0xb2, 0x39, 0x61, 0x0a, 0x1e, 0xa8, 0x24, - 0x03, 0xf6, 0xa2, 0x5f, 0xdc, 0x9c, 0x7c, 0xff, 0x9a, 0x98, 0xa6, 0xed, - 0xc9, 0xda, 0x5e, 0x1a, 0x83, 0x6a, 0xc4, 0xd8, 0x93, 0x2b, 0x79, 0x63, - 0xba, 0x6b, 0x7e, 0xef, 0x8f, 0x93, 0xba, 0x26, 0x02, 0x5d, 0xb9, 0xe3, - 0x8a, 0x83, 0xcf, 0x23, 0x4b, 0x01, 0x59, 0x61, 0x1f, 0xa2, 0x23, 0xe1, - 0x15, 0xbf, 0xe6, 0x26, 0xdf, 0xae, 0xe1, 0x11, 0x83, 0xf2, 0x5b, 0x01, - 0x4a, 0x4f, 0x98, 0xca, 0x26, 0xb8, 0xcd, 0x66, 0x62, 0xd6, 0xce, 0x73, - 0xc1, 0xab, 0x92, 0xd1, 0xdf, 0xb0, 0x26, 0xe3, 0x96, 0xaf, 0x2a, 0x90, - 0xb9, 0x5b, 0x59, 0x5e, 0xf1, 0x64, 0xf9, 0x65, 0xfd, 0x48, 0x45, 0x07, - 0x78, 0x23, 0x71, 0xaa, 0xe6, 0xc3, 0x28, 0xd3, 0xa8, 0xe5, 0x3d, 0xb2, - 0x3b, 0x31, 0xda, 0x27, 0x4a, 0x35, 0xb6, 0xfa, 0x5a, 0xcf, 0xf6, 0x71, - 0xa0, 0x57, 0x87, 0xdf, 0x32, 0x8b, 0x2a, 0x20, 0x79, 0x22, 0x5a, 0x67, - 0xbc, 0xd6, 0x2f, 0x2d, 0x68, 0xba, 0xd8, 0x75, 0x01, 0x10, 0x2e, 0x3a, - 0x94, 0x5e, 0xbf, 0xe4, 0xdf, 0xcc, 0x9d, 0x03, 0xb7, 0xd5, 0xfe, 0x73, - 0x64, 0xdb, 0xad, 0xd0, 0xfe, 0x1f, 0xd3, 0x8f, 0x11, 0x62, 0xf8, 0x87, - 0x28, 0xdf, 0xf2, 0x9b, 0xae, 0xf2, 0x78, 0x7d, 0x0d, 0x61, 0xd0, 0xf2, - 0xc2, 0x11, 0x99, 0xe2, 0xc3, 0x01, 0x13, 0x10, 0x47, 0xe5, 0x37, 0x5a, - 0x5d, 0x7b, 0xce, 0x9a, 0xba, 0xab, 0xbc, 0x36, 0x23, 0xd6, 0xbd, 0xc3, - 0x23, 0xd7, 0x79, 0x07, 0x56, 0x4f, 0xed, 0xc1, 0x3e, 0xf4, 0x49, 0xbb, - 0x3a, 0x2b, 0xe5, 0xfe, 0x0a, 0xd6, 0x23, 0x2a, 0x58, 0x61, 0xa0, 0xd4, - 0xf4, 0xb7, 0x2c, 0x61, 0x31, 0x3f, 0x29, 0x0b, 0x14, 0xc1, 0xff, 0xd9, - 0x52, 0x23, 0xdd, 0x58, 0xf8, 0x5b, 0x36, 0x30, 0xae, 0x76, 0xf4, 0xe8, - 0xe8, 0x76, 0xd3, 0x8f, 0xc7, 0x41, 0x3f, 0xca, 0xae, 0xd6, 0xf1, 0x54, - 0x8b, 0x87, 0x77, 0x30, 0x18, 0x79, 0xff, 0x31, 0xbb, 0xce, 0x0a, 0x3a, - 0xd6, 0x02, 0x48, 0x64, 0xb2, 0xdf, 0x56, 0xb2, 0x81, 0x02, 0xfb, 0x85, - 0xdc, 0xac, 0xf1, 0xd5, 0xbc, 0x54, 0x92, 0x17, 0xcf, 0xe9, 0x8a, 0xee, - 0x06, 0xe4, 0x6d, 0xe0, 0xad, 0xb3, 0x3f, 0x8e, 0x29, 0xad, 0xb5, 0x02, - 0x0a, 0xfe, 0x4e, 0x5e, 0x9c, 0x28, 0x46, 0xcb, 0xc2, 0x47, 0xc2, 0x20, - 0xf4, 0x79, 0x76, 0x31, 0x2c, 0xdd, 0xc1, 0x57, 0xa8, 0x77, 0x36, 0x1b, - 0x24, 0x59, 0x84, 0x01, 0xae, 0x65, 0x39, 0x9c, 0x45, 0x18, 0x21, 0x88, - 0x8d, 0x1a, 0x35, 0xeb, 0xb8, 0x09, 0xda, 0x6b, 0x73, 0x0d, 0xa2, 0x96, - 0xcf, 0x9e, 0x43, 0x09, 0x61, 0x6e, 0x59, 0x42, 0x60, 0xeb, 0x07, 0xd5, - 0x4a, 0x93, 0x05, 0xe9, 0x4d, 0x45, 0x04, 0x2a, 0x53, 0xdd, 0x36, 0xac, - 0x70, 0x67, 0x61, 0xa6, 0xe6, 0xba, 0xb4, 0x45, 0xda, 0xa7, 0x45, 0x98, - 0x7d, 0x7d, 0x15, 0x43, 0x56, 0x29, 0xdd, 0x5a, 0x86, 0x83, 0xca, 0x55, - 0x44, 0x72, 0x93, 0xb7, 0x64, 0x7c, 0x34, 0x5a, 0x66, 0x5b, 0xfb, 0x16, - 0xd7, 0xe6, 0x99, 0xb6, 0x4c, 0x8b, 0xd4, 0x8f, 0xfc, 0xc1, 0xe4, 0xe2, - 0x22, 0xd7, 0x6b, 0xbf, 0xaf, 0xfa, 0xe3, 0x33, 0x97, 0x4c, 0x34, 0x67, - 0x81, 0x7e, 0xb3, 0xb5, 0x4f, 0x6e, 0x47, 0xb9, 0x7e, 0x23, 0xa9, 0x3e, - 0x85, 0x0e, 0xe2, 0x11, 0x1b, 0xa2, 0x7a, 0x54, 0x66, 0xd1, 0xba, 0xb1, - 0xb2, 0xd3, 0xf9, 0xc7, 0x5a, 0xbb, 0xf3, 0xf4, 0x79, 0xfb, 0x71, 0xbb, - 0x73, 0x53, 0x35, 0x87, 0x7c, 0x2d, 0xc4, 0x6d, 0xb4, 0x88, 0x9d, 0x6d, - 0x5b, 0xcf, 0x7b, 0xb3, 0x4d, 0x05, 0xd0, 0x3b, 0x94, 0xfd, 0x36, 0x2c, - 0xd9, 0x4a, 0xe9, 0x3f, 0x58, 0x92, 0x0b, 0xce, 0x22, 0xe6, 0x84, 0xe1, - 0x5f, 0x96, 0xbf, 0x84, 0x57, 0xaa, 0xa5, 0x9f, 0x4d, 0x38, 0x55, 0xe9, - 0x37, 0xee, 0xf1, 0x3a, 0x2c, 0xfb, 0x88, 0x1c, 0xcb, 0x17, 0xb2, 0x3c, - 0x97, 0x29, 0x9b, 0xc5, 0xfa, 0x5d, 0x86, 0x2c, 0x4f, 0x96, 0xb8, 0x59, - 0x4b, 0x0d, 0xc9, 0xe1, 0x6f, 0x79, 0xd5, 0xc3, 0xa2, 0x15, 0xfd, 0x2a, - 0x3d, 0x2d, 0xb5, 0x55, 0x01, 0x93, 0xee, 0xc5, 0x32, 0x81, 0x92, 0x11, - 0x75, 0x16, 0xa8, 0x72, 0x1e, 0x1e, 0x56, 0x9e, 0x0c, 0x46, 0x78, 0xb9, - 0x5a, 0xe9, 0x70, 0x60, 0x8c, 0x7d, 0x91, 0x78, 0x87, 0x95, 0x3a, 0xf4, - 0x51, 0xc6, 0xb0, 0x77, 0xf9, 0x1d, 0x0e, 0x1c, 0x36, 0x1f, 0x5f, 0x79, - 0xb8, 0x73, 0xe0, 0xbc, 0x20, 0xb3, 0x77, 0x6d, 0xc8, 0x97, 0xab, 0xa9, - 0x10, 0xf5, 0x74, 0x3f, 0x58, 0x81, 0xb4, 0x42, 0xc5, 0xb1, 0x4a, 0xea, - 0xc5, 0xa7, 0xf1, 0xfc, 0x7d, 0xe0, 0x8c, 0x8c, 0x01, 0x3d, 0x52, 0xb4, - 0x08, 0xfe, 0x7c, 0x1f, 0x8e, 0x26, 0x6c, 0xa5, 0xb4, 0x87, 0x33, 0x5c, - 0x28, 0xdf, 0xf5, 0x54, 0xd1, 0x0e, 0x3f, 0x7a, 0xe6, 0xf0, 0x8b, 0x55, - 0xfd, 0xa6, 0xfa, 0x69, 0x6b, 0x38, 0x6c, 0xf0, 0xbb, 0xeb, 0xfc, 0xa6, - 0x42, 0x5c, 0xee, 0x75, 0x5f, 0xbf, 0x15, 0x02, 0xc5, 0x6b, 0xe9, 0xb0, - 0xc8, 0x93, 0xcf, 0xed, 0xe7, 0xcf, 0xf0, 0x63, 0xa5, 0xc4, 0xdc, 0x92, - 0x3a, 0x6a, 0x4d, 0x4c, 0xcc, 0x7d, 0x3a, 0x4d, 0x97, 0x2f, 0x61, 0x8f, - 0xb4, 0x1f, 0x59, 0x71, 0x04, 0xcb, 0x12, 0x16, 0xe7, 0x7d, 0xd8, 0x90, - 0x92, 0x43, 0x30, 0x62, 0x14, 0x98, 0xf0, 0x37, 0xd4, 0x06, 0xff, 0xbb, - 0x64, 0x7d, 0xb3, 0x38, 0xde, 0xab, 0x32, 0x4f, 0x0b, 0x49, 0xe6, 0x10, - 0x0f, 0x59, 0x88, 0x36, 0xe8, 0x70, 0xec, 0x37, 0x05, 0x26, 0xab, 0x15, - 0x6b, 0x68, 0x2e, 0x76, 0x4a, 0x66, 0x9c, 0x8c, 0x59, 0x89, 0xeb, 0x6d, - 0x73, 0x63, 0x56, 0x17, 0x5a, 0x22, 0x16, 0x8d, 0x63, 0xee, 0xe1, 0x89, - 0x29, 0x68, 0x3a, 0xb9, 0x10, 0x97, 0x67, 0x15, 0xf2, 0x3b, 0x88, 0xc5, - 0x32, 0x76, 0x0f, 0x72, 0x26, 0x2c, 0x06, 0x12, 0xe6, 0x60, 0xb2, 0x9e, - 0x0b, 0x26, 0xe9, 0x1a, 0x2f, 0x2a, 0xbb, 0x2e, 0xe4, 0x60, 0x4b, 0x4e, - 0xed, 0x81, 0xee, 0xd4, 0x2d, 0xf9, 0x2e, 0x10, 0x7e, 0xdc, 0x30, 0xe3, - 0x4c, 0x22, 0x1e, 0x3f, 0xcc, 0xc3, 0xf4, 0x8f, 0x72, 0x12, 0xf5, 0x4a, - 0x38, 0xd5, 0xb8, 0x09, 0x14, 0xab, 0x72, 0x25, 0xc5, 0xc9, 0x84, 0x8c, - 0x8b, 0x8d, 0xf3, 0xd1, 0xe2, 0xca, 0x12, 0x67, 0x4d, 0x5e, 0xc4, 0x59, - 0xf7, 0x00, 0x96, 0x94, 0x1a, 0xf5, 0x29, 0x3f, 0x81, 0x09, 0x24, 0x10, - 0xd3, 0x87, 0x8f, 0xcc, 0xa1, 0x04, 0xf5, 0x48, 0xbb, 0x6a, 0xb9, 0xe8, - 0x27, 0x6a, 0x59, 0x3c, 0xa3, 0x81, 0xae, 0xcb, 0xcf, 0x3c, 0x8f, 0xd5, - 0xe1, 0xce, 0x6f, 0x6e, 0xa9, 0x73, 0xd3, 0xb0, 0x05, 0xab, 0x24, 0x1c, - 0x87, 0x41, 0xe6, 0xdb, 0x6f, 0x82, 0x46, 0x97, 0x77, 0xf4, 0x9f, 0xb0, - 0x5c, 0x62, 0x53, 0x0f, 0x8b, 0x8d, 0x5a, 0x5d, 0xfd, 0xa5, 0xe1, 0xc3, - 0x3a, 0x11, 0x4f, 0xfa, 0xe7, 0x64, 0x9e, 0xf2, 0xf1, 0xa0, 0x8c, 0x69, - 0x52, 0x4d, 0xdc, 0xae, 0x5d, 0xe0, 0xaa, 0x83, 0xc7, 0x4a, 0x3c, 0x08, - 0x23, 0x2f, 0xe7, 0xa6, 0x8d, 0x40, 0xdc, 0x96, 0x3a, 0x45, 0x5d, 0xa1, - 0x18, 0x4e, 0xd6, 0x45, 0xd6, 0x44, 0xbd, 0x7c, 0xe5, 0xe4, 0x6d, 0x8a, - 0xc5, 0xb3, 0x2c, 0x21, 0xcb, 0x3c, 0x94, 0x98, 0x8c, 0x0b, 0x3a, 0x80, - 0x9e, 0x5d, 0x46, 0x85, 0x59, 0x7b, 0x3a, 0x2d, 0xdf, 0xad, 0xa1, 0xbc, - 0xa2, 0x1b, 0x28, 0xf3, 0x7b, 0x3f, 0xdc, 0xf6, 0x35, 0xe9, 0xbe, 0xca, - 0x19, 0x78, 0xbb, 0xe6, 0xb5, 0x34, 0x26, 0x56, 0x42, 0x3f, 0x41, 0x6d, - 0x12, 0xf5, 0x4a, 0x7b, 0x28, 0x24, 0x2b, 0x95, 0x3a, 0x17, 0x62, 0x49, - 0xbc, 0x71, 0x65, 0x97, 0x69, 0x7d, 0x47, 0x5a, 0x46, 0x37, 0x0e, 0x87, - 0x37, 0x54, 0x17, 0x16, 0x46, 0xa6, 0xf8, 0xaa, 0x2a, 0x26, 0x09, 0x4c, - 0x59, 0xa1, 0x52, 0x24, 0x26, 0x51, 0x63, 0x36, 0xf1, 0x50, 0xa5, 0x6b, - 0xd7, 0xd2, 0xf3, 0x59, 0xd7, 0x7d, 0xf3, 0xde, 0x18, 0x1d, 0xf1, 0x24, - 0x1b, 0xba, 0x18, 0x10, 0x3e, 0xd5, 0xbd, 0xba, 0x61, 0x6a, 0x6f, 0xa8, - 0xd6, 0x8a, 0xab, 0x3b, 0x59, 0xc8, 0x03, 0x74, 0x63, 0x0a, 0xdf, 0x5c, - 0x2a, 0xe9, 0x3a, 0x7f, 0xde, 0xb2, 0xba, 0x9a, 0xdc, 0xbc, 0x59, 0x53, - 0x04, 0xa8, 0x0a, 0xba, 0xde, 0xa0, 0x31, 0x5f, 0xde, 0x85, 0x67, 0x50, - 0xef, 0x2d, 0x0f, 0xd7, 0x56, 0xe7, 0xca, 0x0c, 0x9a, 0x00, 0xa9, 0xad, - 0xa7, 0x51, 0x38, 0x1c, 0xc0, 0x28, 0x1d, 0x1f, 0x0f, 0x09, 0xea, 0xf2, - 0x32, 0x0b, 0xe0, 0x6e, 0x16, 0x94, 0xd7, 0x9d, 0x79, 0xc2, 0x12, 0x7e, - 0x2e, 0x42, 0xc6, 0x5d, 0xc8, 0x7f, 0x22, 0xff, 0x02, 0x51, 0x53, 0xc3, - 0x9e, 0xef, 0xc0, 0x4d, 0xf8, 0x93, 0x91, 0x88, 0x85, 0xb0, 0x5d, 0x72, - 0x96, 0x4b, 0x49, 0x47, 0x52, 0xd4, 0xe6, 0x46, 0xfd, 0x0b, 0x34, 0x2b, - 0xd3, 0xde, 0xa2, 0x53, 0x67, 0x59, 0x81, 0x4e, 0xc5, 0xad, 0x47, 0xae, - 0xa4, 0xb3, 0xd3, 0x2a, 0xe1, 0x5d, 0xdc, 0xab, 0x94, 0x96, 0x0a, 0x6f, - 0xe5, 0x5a, 0x5f, 0xc5, 0xa2, 0x28, 0xa7, 0x02, 0x6b, 0x58, 0xcd, 0x56, - 0xea, 0x7d, 0x4c, 0x33, 0x69, 0x96, 0x66, 0xf2, 0xce, 0x87, 0x86, 0xbe, - 0x5c, 0xa4, 0x90, 0x28, 0xeb, 0x81, 0xa2, 0x2f, 0x17, 0xf7, 0x10, 0xe7, - 0x4d, 0x9f, 0x85, 0xc2, 0x32, 0xf8, 0xea, 0x6a, 0x77, 0x00, 0x33, 0x8e, - 0x56, 0x2b, 0x8c, 0xdb, 0xd9, 0x82, 0xa1, 0x90, 0xf3, 0xd5, 0x94, 0xdd, - 0x39, 0xec, 0x04, 0x97, 0x5f, 0xe4, 0xca, 0x8b, 0xca, 0x00, 0x2d, 0xb7, - 0x35, 0xcf, 0xa8, 0x7a, 0x13, 0x81, 0x1e, 0x32, 0x38, 0x0f, 0x51, 0x05, - 0x2f, 0xb9, 0xad, 0x79, 0x3e, 0xda, 0xdb, 0xef, 0x6c, 0xae, 0xc2, 0x8f, - 0x95, 0x3d, 0xf2, 0x9b, 0x25, 0x17, 0x3b, 0xd7, 0x83, 0xc1, 0xef, 0xbd, - 0x51, 0x40, 0x15, 0xd7, 0x33, 0xbb, 0x36, 0xd3, 0x87, 0xc2, 0x38, 0xbb, - 0x8c, 0x5d, 0xb7, 0x56, 0xe6, 0x77, 0x38, 0x97, 0x6e, 0xc7, 0x99, 0x79, - 0x17, 0x41, 0xe8, 0x10, 0xf2, 0x9b, 0xa5, 0xdd, 0xf5, 0xd3, 0x1e, 0xaf, - 0x2f, 0xac, 0x9c, 0xcd, 0xd2, 0x1b, 0xa8, 0xab, 0xbb, 0xc2, 0xe1, 0x70, - 0x9f, 0x01, 0xa3, 0x53, 0xc5, 0xd5, 0xd2, 0xa5, 0xa9, 0x04, 0xc8, 0x58, - 0x0d, 0x03, 0x8c, 0xb6, 0x6f, 0x18, 0xe0, 0xd2, 0xfb, 0xab, 0xeb, 0x00, - 0x12, 0xc7, 0xdb, 0x26, 0xb0, 0xe2, 0x3e, 0xeb, 0xea, 0xbe, 0x05, 0x63, - 0xb3, 0x3f, 0xc5, 0x95, 0xd7, 0xd5, 0xf5, 0xd1, 0x2b, 0x29, 0xb2, 0x11, - 0x45, 0x5c, 0x8d, 0x5d, 0x1b, 0x04, 0x9d, 0x0a, 0x28, 0x70, 0xc4, 0x6d, - 0xec, 0xa5, 0xac, 0xc2, 0x0a, 0xa9, 0xb3, 0x5c, 0xbd, 0x73, 0xbd, 0x14, - 0x03, 0x51, 0x78, 0x99, 0xf9, 0xaa, 0x1f, 0xd9, 0x00, 0xe5, 0xd7, 0xb3, - 0xd7, 0x83, 0xc4, 0xa3, 0xf0, 0x14, 0x50, 0xca, 0x15, 0xf2, 0xa5, 0x60, - 0x78, 0xee, 0x03, 0x5a, 0x19, 0x15, 0x10, 0xda, 0x7d, 0xef, 0xa5, 0x40, - 0x28, 0xa3, 0x1c, 0x9e, 0x40, 0x29, 0x10, 0x58, 0x17, 0xab, 0xc6, 0x96, - 0xa8, 0xca, 0xe3, 0x45, 0x84, 0x75, 0xae, 0x65, 0x8b, 0x76, 0xa8, 0x07, - 0x82, 0xb8, 0x55, 0x86, 0xa0, 0x65, 0x6d, 0xa8, 0xe8, 0x09, 0x94, 0xb6, - 0x49, 0x22, 0x23, 0xcd, 0x40, 0x1d, 0x82, 0xb0, 0x4a, 0x22, 0x3f, 0xac, - 0x02, 0x8f, 0x5f, 0xd9, 0xee, 0x9a, 0x77, 0xaa, 0x4d, 0x8c, 0x0a, 0xab, - 0xd3, 0x2e, 0xbf, 0xdd, 0xbd, 0x14, 0x0b, 0x2a, 0xb5, 0x1c, 0x7f, 0x31, - 0x9b, 0xce, 0xaf, 0x66, 0xaf, 0x51, 0xbf, 0xcf, 0xca, 0xea, 0xac, 0x4a, - 0x57, 0xc5, 0xd7, 0xeb, 0x00, 0x2b, 0xad, 0xf6, 0xa0, 0xb8, 0x56, 0xbe, - 0x8a, 0xcb, 0xa1, 0x98, 0xde, 0x07, 0xf5, 0xee, 0xf9, 0x3a, 0x00, 0x98, - 0x43, 0xa6, 0x0d, 0x48, 0x2d, 0x4a, 0x08, 0x28, 0x4e, 0x52, 0xcc, 0x22, - 0x48, 0x19, 0x2c, 0xc6, 0xa8, 0x39, 0x4d, 0xa6, 0xba, 0xb1, 0x90, 0xee, - 0x02, 0x19, 0x0a, 0xa5, 0x36, 0xad, 0xab, 0xfb, 0x82, 0x34, 0x88, 0xfe, - 0x0e, 0x2d, 0xba, 0xaf, 0x1a, 0x11, 0xde, 0xd0, 0xb6, 0x51, 0xaa, 0x62, - 0x27, 0x07, 0xd2, 0x58, 0xd4, 0xf7, 0xf3, 0x60, 0x74, 0x16, 0xba, 0x42, - 0x8d, 0x8b, 0x70, 0x09, 0xae, 0x14, 0xca, 0x47, 0xb5, 0x87, 0xe4, 0x79, - 0x9d, 0xfa, 0x47, 0xb2, 0x63, 0x87, 0x14, 0x14, 0xdd, 0x10, 0xf5, 0x0e, - 0x57, 0x8f, 0x9c, 0x91, 0x62, 0x32, 0x76, 0x36, 0x73, 0x81, 0xab, 0xc6, - 0xab, 0x2a, 0xf3, 0x9b, 0x08, 0x5f, 0xae, 0xe1, 0x07, 0xe4, 0x06, 0xa2, - 0x9e, 0x73, 0x57, 0x1d, 0xf7, 0x56, 0xe2, 0x24, 0x95, 0x75, 0xc2, 0xda, - 0x1a, 0xd7, 0x02, 0x93, 0x9f, 0x18, 0x3b, 0x01, 0x15, 0xae, 0x0b, 0x15, - 0x90, 0xb8, 0xab, 0x8e, 0x15, 0x90, 0x9e, 0x26, 0xa7, 0x6a, 0xff, 0xb7, - 0x63, 0xc9, 0x91, 0x55, 0x95, 0xe4, 0xa5, 0x0a, 0xe6, 0xb6, 0x23, 0x49, - 0x95, 0x0a, 0x97, 0x4b, 0xd1, 0x1b, 0x1b, 0xad, 0xa8, 0x7e, 0x2d, 0x7f, - 0x08, 0x71, 0x50, 0xad, 0xe7, 0x53, 0x2b, 0x9d, 0x85, 0x42, 0x44, 0xde, - 0x18, 0x3f, 0x06, 0xa0, 0x16, 0x82, 0x6c, 0xd6, 0x8a, 0xd9, 0x64, 0x03, - 0x63, 0x38, 0x73, 0x8a, 0xfd, 0x2f, 0xab, 0x84, 0xa1, 0x8a, 0x93, 0xd1, - 0x20, 0x3c, 0x05, 0x75, 0x61, 0x80, 0xbb, 0x5e, 0x7a, 0xed, 0xc8, 0xca, - 0xa1, 0xdc, 0x77, 0xa0, 0xd3, 0xa4, 0xa2, 0xf1, 0x66, 0x4d, 0xe7, 0x63, - 0x0b, 0x7c, 0x8c, 0xad, 0x68, 0x58, 0xed, 0x9e, 0x2e, 0xda, 0xb1, 0x25, - 0xe6, 0x7b, 0x0c, 0x40, 0x05, 0xba, 0x65, 0x48, 0xba, 0xe4, 0xf4, 0x97, - 0xf0, 0x8a, 0x8c, 0x56, 0x0e, 0x41, 0x8d, 0x63, 0xc7, 0x64, 0x33, 0x14, - 0xdc, 0x16, 0xa7, 0x04, 0x9d, 0x47, 0xcd, 0xaa, 0x50, 0xac, 0xba, 0x5d, - 0x9a, 0x83, 0xaf, 0xe6, 0xe4, 0xad, 0x05, 0xf1, 0x97, 0x99, 0x75, 0xdd, - 0x71, 0x83, 0x6d, 0x0d, 0x5e, 0xb3, 0x19, 0x6d, 0xdc, 0xa3, 0xb0, 0xf6, - 0xac, 0x39, 0x0f, 0x3b, 0x2b, 0x9a, 0x44, 0xad, 0x3c, 0x88, 0x35, 0x33, - 0x20, 0x2a, 0x99, 0xe8, 0xf2, 0x93, 0xa5, 0x7c, 0x6c, 0x1c, 0x69, 0xa1, - 0x1c, 0xd9, 0x11, 0xc9, 0xc3, 0x53, 0xc2, 0xdf, 0x96, 0x18, 0x51, 0x2e, - 0x63, 0xcd, 0x29, 0x66, 0xab, 0xc4, 0x71, 0x33, 0xb3, 0xe2, 0x20, 0x39, - 0x6e, 0x94, 0xa1, 0x72, 0x43, 0xc9, 0x47, 0xe8, 0xee, 0x34, 0x87, 0x62, - 0x5e, 0xf8, 0x63, 0x4f, 0x68, 0x29, 0xe5, 0xb3, 0x9c, 0xea, 0x59, 0x2d, - 0xf5, 0xa4, 0x96, 0xda, 0x12, 0x92, 0x9b, 0xbd, 0x38, 0x5b, 0xaf, 0xd3, - 0x25, 0x63, 0x22, 0x4b, 0x17, 0xcb, 0x48, 0xc6, 0xde, 0xe4, 0x10, 0x68, - 0xb9, 0xfa, 0x23, 0xbc, 0x92, 0xcd, 0xa9, 0xba, 0x60, 0xa8, 0x23, 0x14, - 0xaa, 0x16, 0xb3, 0x7b, 0x75, 0xf9, 0xda, 0x04, 0xa4, 0x88, 0x3c, 0xb3, - 0xef, 0x88, 0x31, 0x7a, 0x17, 0x3b, 0xad, 0x99, 0xf2, 0xe6, 0x86, 0xfc, - 0x90, 0xf9, 0xdf, 0xe8, 0x27, 0x9d, 0xa7, 0x6b, 0xb2, 0x2d, 0xe2, 0x15, - 0xbe, 0x05, 0xb9, 0x5e, 0x6f, 0x95, 0xb2, 0x13, 0x1c, 0x4b, 0x9d, 0xba, - 0x79, 0x4e, 0x1d, 0x72, 0xab, 0x45, 0x2f, 0x3a, 0xde, 0x4d, 0xf2, 0x84, - 0x46, 0x82, 0xb5, 0xf8, 0x40, 0x39, 0x9c, 0xda, 0x34, 0xf2, 0xd2, 0x68, - 0x59, 0x0e, 0x5f, 0x72, 0xd4, 0x58, 0x17, 0x66, 0xc3, 0x6e, 0x5e, 0xbd, - 0x46, 0xf5, 0xcc, 0x26, 0x2e, 0x50, 0x16, 0xe8, 0x8d, 0x8a, 0xb1, 0x76, - 0x9c, 0x36, 0xdf, 0x9d, 0x3e, 0x19, 0x32, 0xd6, 0x96, 0x96, 0x5c, 0x13, - 0xcd, 0x37, 0x98, 0x9a, 0x39, 0x08, 0xc1, 0xe1, 0x2d, 0x91, 0x8a, 0xfa, - 0xcf, 0x7c, 0x83, 0xe3, 0x64, 0x7a, 0x65, 0x23, 0x5b, 0x93, 0xeb, 0xf9, - 0x32, 0x5e, 0xc1, 0xf6, 0x15, 0x4b, 0x25, 0x25, 0xb7, 0x2c, 0xb0, 0x9c, - 0x83, 0xe1, 0xad, 0x2b, 0x35, 0x80, 0xe7, 0x7f, 0x55, 0xaa, 0x49, 0x54, - 0x14, 0xff, 0xd8, 0x28, 0xd5, 0xc4, 0x18, 0xee, 0xa7, 0xc0, 0x5d, 0x69, - 0xc3, 0x79, 0xe4, 0xb4, 0xab, 0x31, 0xa5, 0x2b, 0xb1, 0xad, 0x58, 0x14, - 0x2c, 0x9b, 0xf5, 0x86, 0x92, 0x13, 0x57, 0xdf, 0x73, 0x6b, 0xc7, 0x33, - 0xf2, 0x6b, 0xe5, 0xb0, 0x4e, 0xfe, 0x20, 0xf9, 0xca, 0x29, 0x0d, 0xe7, - 0x2e, 0x45, 0xf2, 0x5b, 0xe9, 0xe0, 0x5e, 0x79, 0xad, 0x9f, 0x9c, 0xcb, - 0x1f, 0xd5, 0x93, 0x36, 0xf9, 0x8b, 0xba, 0xb6, 0x4a, 0x1f, 0x68, 0x99, - 0x92, 0xc9, 0x87, 0xf9, 0x73, 0xac, 0x0a, 0x46, 0x84, 0x8b, 0x62, 0xe1, - 0x29, 0x1b, 0xa7, 0x59, 0x11, 0x2f, 0x6c, 0xb9, 0x6d, 0x0e, 0x0a, 0x47, - 0x63, 0xe3, 0xeb, 0xa5, 0x7a, 0x31, 0x21, 0x0b, 0x9d, 0x3e, 0xb9, 0x4c, - 0xe9, 0xce, 0xba, 0x68, 0x3c, 0x5d, 0x7f, 0xde, 0x59, 0x39, 0x51, 0xc5, - 0xf5, 0x3d, 0x87, 0xd3, 0x99, 0x6c, 0xca, 0xf5, 0xa2, 0x8b, 0x33, 0x39, - 0xa9, 0x98, 0x96, 0x88, 0x2e, 0xe9, 0x93, 0x61, 0x80, 0xcb, 0x23, 0xcc, - 0x0f, 0xe0, 0x02, 0xfa, 0xf0, 0x30, 0x09, 0x87, 0x9b, 0x94, 0x79, 0x21, - 0x5c, 0xa6, 0xf3, 0x5a, 0x16, 0x97, 0x70, 0xf4, 0x50, 0x82, 0xae, 0x9e, - 0xc1, 0x9f, 0x53, 0x16, 0x47, 0xd9, 0x63, 0x5a, 0xcf, 0xf6, 0xce, 0xe9, - 0x8b, 0x94, 0xc5, 0x3f, 0xef, 0xb1, 0x98, 0x05, 0x96, 0xfe, 0x09, 0x63, - 0x18, 0x7e, 0x5b, 0x41, 0x7f, 0xe9, 0x17, 0xf7, 0x7e, 0x5b, 0x41, 0xf3, - 0xeb, 0x8b, 0x7b, 0xff, 0x17, 0xef, 0x2d, 0xeb, 0x23, 0x14, 0xe3, 0x04, - 0x00 -}; -const unsigned int webui_html_len = 170341;