Compare commits

..

22 Commits

Author SHA1 Message Date
Siwat Sirichai fb61fa85f3 2.10.0, full support for Digital Input/Output cards 2024-11-04 00:26:20 +07:00
Siwat Sirichai a22c8ef55c card not installed handling 2024-11-03 22:32:36 +07:00
Siwat Sirichai 268218f546 input (not working) 2024-11-03 21:51:35 +07:00
Siwat Sirichai 09aee8d5f8 digital output card 2024-11-03 13:33:10 +07:00
Siwat Sirichai 85f789e216 enable default static IP if there are no ip in fram 2024-10-11 22:56:31 +07:00
Siwat Sirichai 5bce34bc5e fix networking stack crash 2024-10-10 19:07:23 +07:00
Siwat Sirichai d276e6d255 initial network config 2024-10-08 23:32:37 +07:00
Siwat Sirichai 8ea85254a0 add uptime feature 2024-10-07 15:08:12 +07:00
Siwat Sirichai 520fd76b91 Update ESPMegaCommon.hpp 2024-06-28 22:17:13 +07:00
Siwat Sirichai c2e45490b0 energy load error handling 2024-06-28 22:16:44 +07:00
Siwat Sirichai 8aeb6ab30a improve debounce 2024-06-21 23:11:08 +07:00
Siwat Sirichai 4ea2122f6e allow input preload and state toggling 2024-06-21 21:34:51 +07:00
Siwat Sirichai b778fb6a02 Update DigitalInputCard.cpp 2024-06-21 21:02:11 +07:00
Siwat Sirichai 221d8e59f5 Update ESPMegaCommon.hpp 2024-06-21 20:57:53 +07:00
Siwat Sirichai d0ce4bf391 change debouce logic 2024-06-21 16:35:26 +07:00
Siwat Sirichai b62ef700ed working timezone config 2024-05-22 00:06:12 +07:00
Siwat Sirichai b30cfde0b0 working ntp without offset 2024-05-21 23:50:21 +07:00
Siwat Sirichai 64d6c4fab3 Update ESPMegaCommon.hpp 2024-05-20 01:29:36 +07:00
Siwat Sirichai 2430b43f77 info request 2024-05-20 01:25:25 +07:00
Siwat Sirichai 3e7d3041f2 mqtt summary request 2024-05-20 00:53:09 +07:00
Siwat Sirichai ea49576b20 global state request 2024-05-20 00:44:18 +07:00
Siwat Sirichai 6b67591cc1 Update ESPMegaCommon.hpp 2024-05-20 00:13:43 +07:00
16 changed files with 876 additions and 478 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.DS_Store
/ESPMegaPRO-OS-SDK

View File

@ -84,6 +84,9 @@ void CurrentTransformerCard::saveEnergy(){
}
void CurrentTransformerCard::loadEnergy(){
this->fram->read(this->framAddress, (uint8_t*)&this->energy, sizeof(this->energy));
if (this->energy < 0 || isnan(this->energy)) {
this->energy = 0;
}
}
void CurrentTransformerCard::setEnergyAutoSave(bool autoSave){

View File

@ -57,12 +57,16 @@ bool DigitalInputCard::begin()
{
this->inputBankA = PCF8574(this->address_a);
this->inputBankB = PCF8574(this->address_b);
if (!this->inputBankA.begin()) {
if (!this->inputBankA.begin())
{
ESP_LOGE("DigitalInputCard", "Input Card ERROR: Failed to install input bank A");
this->initOk = false;
return false;
}
if (!this->inputBankB.begin()) {
if (!this->inputBankB.begin())
{
ESP_LOGE("DigitalInputCard", "Input Card ERROR: Failed to install input bank B");
this->initOk = false;
return false;
}
// Set the debounce time for all pins to 50ms
@ -77,6 +81,7 @@ bool DigitalInputCard::begin()
this->pinMap[i] = i;
this->virtualPinMap[i] = i;
}
this->initOk = true;
return true;
}
@ -100,6 +105,11 @@ bool DigitalInputCard::digitalRead(uint8_t pin)
*/
bool DigitalInputCard::digitalRead(uint8_t pin, bool refresh)
{
if(!this->initOk)
{
ESP_LOGE("DigitalInputCard", "Input Card ERROR: Card not initialized");
return false;
}
pin = pinMap[pin];
// First check if the pin is in bank A or B
if (pin >= 0 && pin <= 7)
@ -118,7 +128,7 @@ bool DigitalInputCard::digitalRead(uint8_t pin, bool refresh)
// Extract the bit from the buffer
return ((inputBufferB >> (15 - pin)) & 1);
}
return 255;
return false;
}
/**
@ -134,26 +144,82 @@ void DigitalInputCard::handlePinChange(int pin, uint8_t &currentBuffer, uint8_t
{
// Get the index of the pin in the pin map
uint8_t virtualPin = virtualPinMap[pin];
// Handle Bank A
if (((previousBuffer >> (7 - pin)) & 1) != ((currentBuffer >> (7 - pin)) & 1))
if (pin < 8)
{
if (millis() - lastDebounceTime[pin] > debounceTime[pin])
// Handle Bank A
if (((previousBuffer >> (7 - pin)) & 1) != ((currentBuffer >> (7 - pin)) & 1))
{
lastDebounceTime[pin] = millis();
previousBuffer ^= (-((currentBuffer >> (7 - pin)) & 1) ^ previousBuffer) & (1UL << (7 - pin));
for(const auto& callback : callbacks)
callback.second(virtualPin, ((currentBuffer >> (7 - pin)) & 1));
// When the pin first change, store the time
if (!pinChanged[virtualPin])
{
ESP_LOGD("DigitalInputCard", "Pin %d changed", virtualPin);
pinChanged[virtualPin] = true;
lastDebounceTime[virtualPin] = millis();
}
else
{
ESP_LOGD("DigitalInputCard", "Pin %d (%d>%d) debounce time: %d", virtualPin, ((previousBuffer >> (7 - pin)) & 1), ((currentBuffer >> (7 - pin)) & 1), millis() - lastDebounceTime[virtualPin]);
// If the pin was already changed, check if the debounce time has passed
if ((millis() - lastDebounceTime[virtualPin]) > debounceTime[virtualPin])
{
ESP_LOGD("DigitalInputCard", "Pin %d triggered", virtualPin);
// Call the callback function
for (auto const &callback : callbacks)
{
callback.second(virtualPin, ((currentBuffer >> (7 - pin)) & 1));
}
// Store the previous buffer at the specified pin (bitwise operation)
// new value : (currentBuffer >> (7 - pin)) & 1)
previousBuffer = (previousBuffer & ~(1 << (7 - pin))) | (((currentBuffer >> (7 - pin)) & 1) << (7 - pin));
// Reset the pin changed flag
pinChanged[virtualPin] = false;
}
}
}
else
{
// Pin bounce back to previous state, reset the debounce time
lastDebounceTime[virtualPin] = millis();
pinChanged[virtualPin] = false;
}
}
// Handle Bank B
if (((previousBuffer >> (15 - pin)) & 1) != ((currentBuffer >> (15 - pin)) & 1))
else
{
if (millis() - lastDebounceTime[pin] > debounceTime[pin])
// Handle Bank B
if (((previousBuffer >> (15 - pin)) & 1) != ((currentBuffer >> (15 - pin)) & 1))
{
lastDebounceTime[pin] = millis();
previousBuffer ^= (-((currentBuffer >> (15 - pin)) & 1) ^ previousBuffer) & (1UL << (15 - pin));
for (const auto& callback : callbacks)
callback.second(virtualPin, ((currentBuffer >> (15 - pin)) & 1));
// When the pin first change, store the time
if (!pinChanged[virtualPin])
{
ESP_LOGD("DigitalInputCard", "Pin %d changed", virtualPin);
pinChanged[virtualPin] = true;
lastDebounceTime[virtualPin] = millis();
}
else
{
ESP_LOGD("DigitalInputCard", "Pin %d (%d>%d) debounce time: %d", virtualPin, ((previousBuffer >> (15 - pin)) & 1), ((currentBuffer >> (15 - pin)) & 1), millis() - lastDebounceTime[virtualPin]);
// If the pin was already changed, check if the debounce time has passed
if ((millis() - lastDebounceTime[virtualPin]) > debounceTime[virtualPin])
{
ESP_LOGD("DigitalInputCard", "Pin %d triggered", virtualPin);
// Call the callback function
for (auto const &callback : callbacks)
{
callback.second(virtualPin, ((currentBuffer >> (15 - pin)) & 1));
}
// Store the previous buffer at the specified pin (bitwise operation)
// new value : (currentBuffer >> (15 - pin)) & 1)
previousBuffer = (previousBuffer & ~(1 << (15 - pin))) | (((currentBuffer >> (15 - pin)) & 1) << (15 - pin));
// Reset the pin changed flag
pinChanged[virtualPin] = false;
}
}
}
else
{
// Pin bounce back to previous state, reset the debounce time
lastDebounceTime[virtualPin] = millis();
pinChanged[virtualPin] = false;
}
}
}
@ -233,6 +299,11 @@ uint8_t DigitalInputCard::registerCallback(std::function<void(uint8_t, bool)> ca
*/
void DigitalInputCard::refreshInputBankA()
{
if(!this->initOk)
{
ESP_LOGE("DigitalInputCard", "Input Card ERROR: Card not initialized");
return;
}
inputBufferA = inputBankA.read8();
}
@ -241,6 +312,11 @@ void DigitalInputCard::refreshInputBankA()
*/
void DigitalInputCard::refreshInputBankB()
{
if(!this->initOk)
{
ESP_LOGE("DigitalInputCard", "Input Card ERROR: Card not initialized");
return;
}
inputBufferB = inputBankB.read8();
}
@ -300,3 +376,26 @@ uint8_t DigitalInputCard::getType()
{
return CARD_TYPE_DIGITAL_INPUT;
}
/**
* @brief Preload the previous input buffer and the input buffer
*
* @note This function is useful if you want to preload the input buffers with a run-time value
*/
void DigitalInputCard::preloadInputBuffer()
{
refreshInputBankA();
refreshInputBankB();
previousInputBufferA = inputBufferA;
previousInputBufferB = inputBufferB;
}
/**
* @brief Get the status of the card
*
* @return True if the card is initialized, false otherwise
*/
bool DigitalInputCard::getStatus()
{
return this->initOk;
}

View File

@ -41,9 +41,14 @@ class DigitalInputCard : public ExpansionCard {
void unregisterCallback(uint8_t handler);
// Load a new pin map
void loadPinMap(uint8_t pinMap[16]);
// Preload previousInputBuffer and inputBuffer
void preloadInputBuffer();
// Status of card
bool getStatus();
// Get type of card
uint8_t getType();
private:
bool initOk = false;
PCF8574 inputBankA;
PCF8574 inputBankB;
uint8_t address_a;
@ -54,6 +59,7 @@ class DigitalInputCard : public ExpansionCard {
uint8_t previousInputBufferB;
uint32_t debounceTime[16];
uint32_t lastDebounceTime[16];
bool pinChanged[16];
// A map of the physical pin to the virtual pin
uint8_t pinMap[16];
// A map of the virtual pin to the physical pin

View File

@ -17,6 +17,9 @@
*/
bool DigitalInputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) {
this->card = (DigitalInputCard *)card;
if(!this->card->getStatus()) {
return false;
}
this->card_id = card_id;
this->mqtt = mqtt;
this->base_topic = base_topic;

View File

@ -32,7 +32,7 @@ DigitalOutputCard::DigitalOutputCard(uint8_t address) : change_callbacks(){
* @param bit4 The position of the fifth switch on the dip switch
*/
DigitalOutputCard::DigitalOutputCard(bool bit0, bool bit1, bool bit2, bool bit3, bool bit4) :
DigitalOutputCard(0x20+bit0+bit1*2+bit2*4+bit3*8+bit4*16)
DigitalOutputCard(0x40+bit0+bit1*2+bit2*4+bit3*8+bit4*16)
{
@ -307,3 +307,12 @@ void DigitalOutputCard::saveStateToFRAM() {
uint16_t packed = packStates();
this->fram->write16(framAddress, packed);
}
/**
* @brief Toggle the state of the specified pin
*
* @param pin The pin to toggle
*/
void DigitalOutputCard::toggleState(uint8_t pin) {
this->setState(pin, !this->state_buffer[pin]);
}

View File

@ -58,6 +58,8 @@ public:
void setValue(uint8_t pin, uint16_t value);
// Get the state of the specified pin
bool getState(uint8_t pin);
// Toggle the state of the specified pin
void toggleState(uint8_t pin);
// Get the pwm value of the specified pin
uint16_t getValue(uint8_t pin);
// Register a callback function that will be called when the state of a pin changes

View File

@ -1,3 +1,3 @@
#pragma once
#define SDK_VESRION "2.6.1"
#define SDK_VESRION "2.10.0"

View File

@ -56,6 +56,22 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length)
{
callback.second(topic_without_base, payload_buffer);
}
// Check for global state request
if (!strcmp(topic_without_base,"requeststate")) {
for (int i = 0; i < 255; i++)
{
if (components[i] != NULL)
{
components[i]->publishReport();
}
}
return;
}
// Check for global summary request
if (!strcmp(topic_without_base,"requestinfo")) {
this->publishSystemSummary();
return;
}
// Call the respective card's mqtt callback
// Note that after the base topic, there should be the card id
// /base_topic/card_id/...
@ -128,6 +144,12 @@ void ESPMegaIoT::registerCard(uint8_t card_id)
{
return;
}
// Check if the physical card is installed
if (cards[card_id] == NULL)
{
ESP_LOGE("ESPMegaIoT", "Registering card %d failed: Card not installed", card_id);
return;
}
// Get the card type
uint8_t card_type = cards[card_id]->getType();
// Create the respective IoT component
@ -379,6 +401,18 @@ void ESPMegaIoT::publish(const char *topic, const char *payload)
mqtt.publish(topic, payload);
}
/**
* @brief Publish a message to a topic
*
* @param topic The topic to publish to
* @param payload The payload to publish
* @param length The length of the payload
*/
void ESPMegaIoT::publish(const char *topic, const char *payload, unsigned int length)
{
mqtt.publish(topic, (const uint8_t *)payload, length);
}
/**
* @brief Register a callback for MQTT messages
*
@ -402,7 +436,7 @@ void ESPMegaIoT::unregisterMqttCallback(uint16_t handler)
}
/**
* @brief Subscribe to all components's topics
* @brief Subscribe to all components's topics and all other topics
*/
void ESPMegaIoT::mqttSubscribe()
{
@ -422,6 +456,9 @@ void ESPMegaIoT::mqttSubscribe()
mqtt.loop();
}
}
// Global topics
this->subscribeRelative("requeststate");
this->subscribeRelative("requestinfo");
}
/**
@ -517,6 +554,21 @@ void ESPMegaIoT::publishRelative(const char *topic, const char *payload)
mqtt.loop();
}
/**
* @brief Publish a message relative to the base topic
*
* @param topic The topic to publish to
* @param payload The payload to publish
* @param length The length of the payload
*/
void ESPMegaIoT::publishRelative(const char *topic, const char *payload, unsigned int length)
{
char absolute_topic[100];
sprintf(absolute_topic, "%s/%s", this->mqtt_config.base_topic, topic);
mqtt.publish(absolute_topic, (const uint8_t *)payload, length);
mqtt.loop();
}
/**
* @brief Subscribe to a topic relative to the base topic
*
@ -579,6 +631,22 @@ void ESPMegaIoT::loadNetworkConfig()
network_config.wifiUseAuth = fram->read8(IOT_FRAM_ADDRESS + 54);
fram->read(IOT_FRAM_ADDRESS + 55, (uint8_t *)network_config.ssid, 32);
fram->read(IOT_FRAM_ADDRESS + 87, (uint8_t *)network_config.password, 32);
// If ip,gateway,subnet,dns1,dns2 is 0, the device is not configured
// set to default values
// ip: 192.168.0.99
// gateway: 192.168.0.1
// subnet: 255.255.255.0
// dns1: 1.1.1.1
// dns2: 9.9.9.9
if ((uint32_t)network_config.ip == 0 && (uint32_t)network_config.gateway == 0 && (uint32_t)network_config.subnet == 0 && (uint32_t)network_config.dns1 == 0 && (uint32_t)network_config.dns2 == 0)
{
network_config.ip = IPAddress(192, 168, 0, 99);
network_config.gateway = IPAddress(192, 168, 0, 1);
network_config.subnet = IPAddress(255, 255, 255, 0);
network_config.dns1 = IPAddress(1, 1, 1, 1);
network_config.useStaticIp = true;
}
}
/**
@ -834,3 +902,30 @@ String ESPMegaIoT::getMac()
else
return this->getETHMac();
}
/**
* @brief Publish a json object containing the system summary
*/
void ESPMegaIoT::publishSystemSummary() {
char payload[1024];
StaticJsonDocument<1024> doc;
JsonObject root = doc.to<JsonObject>();
root["ip"] = this->getIp().toString();
root["firmware"] = SW_VERSION;
root["sdk_version"] = SDK_VESRION;
root["board_model"] = BOARD_MODEL;
JsonArray cards = root.createNestedArray("cards");
for (int i = 0; i < 255; i++)
{
if (components[i] != NULL)
{
JsonObject card = cards.createNestedObject();
card["id"] = i;
card["type"] = components[i]->getType();
}
}
serializeJson(doc, payload);
ESP_LOGD("ESPMegaIoT", "Publishing system summary: %s", payload);
mqtt.loop();
this->publishRelative("info", payload, strlen(payload));
}

View File

@ -16,6 +16,8 @@
#include <WiFi.h>
#include <FRAM.h>
#include <map>
#include <ArduinoJson.h>
#include <ESPMegaCommon.hpp>
// MQTT Connection Parameters
#define TCP_TIMEOUT_SEC 5
@ -81,6 +83,7 @@ public:
void publishCard(uint8_t card_id);
// Publish topic appended with base topic
void publishRelative(const char *topic, const char *payload);
void publishRelative(const char *topic, const char *payload, unsigned int length);
// Subscribe topic appended with base topic
void subscribeRelative(const char *topic);
void subscribe(const char *topic);
@ -105,6 +108,7 @@ public:
bool mqttConnected();
void disconnectFromMqtt();
void publish(const char *topic, const char *payload);
void publish(const char *topic, const char *payload, unsigned int length);
uint16_t registerMqttCallback(std::function<void(char *, char *)> callback);
void unregisterMqttCallback(uint16_t handler);
uint16_t registerRelativeMqttCallback(std::function<void(char *, char *)> callback);
@ -115,6 +119,7 @@ public:
void bindEthernetInterface(ETHClass *ethernetIface);
bool networkConnected();
void bindFRAM(FRAM *fram);
void publishSystemSummary();
IoTComponent* getComponent(uint8_t card_id);
IPAddress getETHIp();

View File

@ -1,4 +1,5 @@
#include <ESPMegaProOS.hpp>
#include "esp_sntp.h"
// Reserve FRAM address 0 - 1000 for ESPMegaPRO Internal Use
// (34 Bytes) Address 0-33 for Built-in Digital Output Card
@ -11,6 +12,7 @@
*/
ESPMegaPRO::ESPMegaPRO()
{
}
/**
@ -102,6 +104,13 @@ void ESPMegaPRO::loop()
if (iotEnabled)
{
iot->loop();
static int64_t lastNTPUpdate = (esp_timer_get_time() / 1000) - NTP_UPDATE_INTERVAL_MS + NTP_INITIAL_SYNC_DELAY_MS;
if ((esp_timer_get_time() / 1000) - lastNTPUpdate > NTP_UPDATE_INTERVAL_MS)
{
ESP_LOGV("ESPMegaPRO", "Updating time from NTP");
lastNTPUpdate = esp_timer_get_time() / 1000;
this->updateTimeFromNTP();
}
}
if (internalDisplayEnabled)
{
@ -153,19 +162,35 @@ bool ESPMegaPRO::installCard(uint8_t slot, ExpansionCard *card)
bool ESPMegaPRO::updateTimeFromNTP()
{
struct tm timeinfo;
if (getLocalTime(&timeinfo))
uint32_t start = esp_timer_get_time() / 1000;
time_t now;
time(&now);
localtime_r(&now, &timeinfo);
if (!(timeinfo.tm_year > (2016 - 1900)))
{
rtctime_t rtctime = this->getTime();
if (rtctime.hours != timeinfo.tm_hour || rtctime.minutes != timeinfo.tm_min ||
rtctime.seconds != timeinfo.tm_sec || rtctime.day != timeinfo.tm_mday ||
rtctime.month != timeinfo.tm_mon + 1 || rtctime.year != timeinfo.tm_year + 1900)
{
this->setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
}
return true;
ESP_LOGI("ESPMegaPRO", "NTP is not ready yet!");
return false;
}
return false;
rtctime_t rtctime = this->getTime();
if (rtctime.hours != timeinfo.tm_hour || rtctime.minutes != timeinfo.tm_min ||
rtctime.seconds != timeinfo.tm_sec || rtctime.day != timeinfo.tm_mday ||
rtctime.month != timeinfo.tm_mon + 1 || rtctime.year != timeinfo.tm_year + 1900)
{
this->setTime(timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
}
ESP_LOGV("ESPMegaPRO", "Time updated from NTP: %s", asctime(&timeinfo));
return true;
}
/**
* @brief Sets the timezone for the internal RTC.
*
* @note This function takes POSIX timezone strings (e.g. "EST5EDT,M3.2.0,M11.1.0").
*/
void ESPMegaPRO::setTimezone(const char* offset)
{
setenv("TZ", offset, 1);
}
/**
@ -222,6 +247,10 @@ void ESPMegaPRO::enableIotModule()
this->iot->bindFRAM(&fram);
this->iot->intr_begin(cards);
iotEnabled = true;
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, this->iot->getMqttConfig()->mqtt_server);
sntp_setservername(1, "pool.ntp.org");
sntp_init();
}
/**

View File

@ -24,6 +24,11 @@
#define PWM_BANK_ADDRESS 0x5F
#define RTC_ADDRESS 0x68
// Constants
#define NTP_TIMEOUT_MS 5000
#define NTP_UPDATE_INTERVAL_MS 60000
#define NTP_INITIAL_SYNC_DELAY_MS 15000
/**
* @brief The ESPMegaPRO class is the main class for the ESPMegaPRO library.
*
@ -47,6 +52,7 @@ class ESPMegaPRO {
void enableIotModule();
void enableInternalDisplay(HardwareSerial *serial);
void enableWebServer(uint16_t port);
void setTimezone(const char* offset);
rtctime_t getTime();
void dumpFRAMtoSerial(uint16_t start, uint16_t end);
void dumpFRAMtoSerialASCII(uint16_t start, uint16_t end);

View File

@ -482,6 +482,7 @@ void ESPMegaWebServer::getDeviceInfoHandler(AsyncWebServerRequest *request) {
doc["software_version"] = SW_VERSION;
doc["sdk_version"] = SDK_VESRION;
doc["idf_version"] = IDF_VER;
doc["uptime"] = esp_timer_get_time() / 1000000; // Uptime in seconds
char buffer[512];
serializeJson(doc, buffer);
request->send(200, "application/json", buffer);

View File

@ -14,6 +14,10 @@
MAC Address
<span style="float: right" id="mac_address">Loading ...</span>
</p>
<p style="text-align: left">
Uptime
<span style="float: right" id="uptime">Loading ...</span>
</p>
<p style="text-align: left">
Model
<span style="float: right" id="model">Loading ...</span>
@ -60,7 +64,7 @@
<b>SIWAT SYSTEM 2023</b>
</form>
<script>
window.onload =function () {
window.onload = function () {
fetch("/get_device_info")
.then(response => response.json())
.then(data => {
@ -75,6 +79,19 @@
document.getElementById("api_server").innerHTML = data.mqtt_server + ":" + data.mqtt_port;
document.getElementById("api_endpoint").innerHTML = data.base_topic;
document.getElementById("centrally_managed").innerHTML = data.mqtt_connected;
var uptime = data.uptime;
var uptime_string = "";
// Uptime is in seconds, convert it to X days, HH:MM:SS
var days = Math.floor(uptime / (24 * 3600));
uptime -= days * 24 * 3600;
var hours = Math.floor(uptime / 3600);
uptime -= hours * 3600;
var minutes = Math.floor(uptime / 60);
uptime -= minutes * 60;
var seconds = uptime;
if (days > 0) uptime_string += days + " days, ";
uptime_string += hours.toString().padStart(2, "0") + ":" + minutes.toString().padStart(2, "0") + ":" + seconds.toString().padStart(2, "0");
document.getElementById("uptime").innerHTML = uptime_string;
}).catch(error => {
console.error(error);
});

View File

@ -51,449 +51,517 @@ const char ota_html[] PROGMEM = {
0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79,
0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69,
0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79,
0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72,
0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x6d, 0x6f,
0x64, 0x65, 0x6c, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67,
0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x70, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78,
0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66,
0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x46, 0x57, 0x20,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65,
0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67,
0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x66, 0x77, 0x5f, 0x76,
0x20, 0x20, 0x20, 0x20, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74,
0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20,
0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x75,
0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69,
0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e,
0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20,
0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74,
0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c,
0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x4d,
0x6f, 0x64, 0x65, 0x6c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73,
0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66,
0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22,
0x20, 0x69, 0x64, 0x3d, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x3e,
0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c,
0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f,
0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79,
0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69,
0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x46, 0x57, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61,
0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f,
0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69,
0x64, 0x3d, 0x22, 0x66, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e,
0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20,
0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20,
0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d,
0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x22,
0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x44, 0x4b, 0x20, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d,
0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68,
0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x73, 0x64, 0x6b, 0x5f, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64,
0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61,
0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22,
0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20,
0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x53, 0x44, 0x4b, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0d,
0x49, 0x44, 0x46, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73,
0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a,
0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22,
0x73, 0x64, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
0x69, 0x64, 0x66, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e,
0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74,
0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c,
0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x49, 0x44, 0x46, 0x20, 0x56, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73,
0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66,
0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22,
0x20, 0x69, 0x64, 0x3d, 0x22, 0x69, 0x64, 0x66, 0x5f, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e,
0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20,
0x3c, 0x70, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65,
0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65,
0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x41, 0x50,
0x49, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c,
0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x61, 0x70, 0x69,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x3e, 0x4c, 0x6f, 0x61,
0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70,
0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d,
0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a,
0x20, 0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x41, 0x50, 0x49, 0x20, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e,
0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64,
0x3d, 0x22, 0x61, 0x70, 0x69, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x41, 0x50, 0x49, 0x20, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70,
0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c,
0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20,
0x69, 0x64, 0x3d, 0x22, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20,
0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70,
0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74,
0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74,
0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x43, 0x65, 0x6e, 0x74,
0x72, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
0x64, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e,
0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61,
0x74, 0x3a, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64,
0x3d, 0x22, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x6c, 0x79, 0x5f,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x22, 0x3e, 0x4c, 0x6f, 0x61,
0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70,
0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x3c, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x74,
0x79, 0x70, 0x65, 0x3d, 0x22, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x22,
0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x66,
0x22, 0x20, 0x6f, 0x6e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x3d, 0x22, 0x77,
0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x27, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x27, 0x22, 0x3e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x3c, 0x2f, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x3e, 0x3c,
0x62, 0x72, 0x20, 0x2f, 0x3e, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x3c, 0x68, 0x72, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x68, 0x33, 0x3e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x53, 0x6f,
0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x61,
0x67, 0x65, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22,
0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22,
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22,
0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x6e,
0x67, 0x65, 0x3d, 0x22, 0x73, 0x75, 0x62, 0x28, 0x74, 0x68, 0x69, 0x73,
0x29, 0x22, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 0x22, 0x64, 0x69,
0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x22,
0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3d, 0x22, 0x2e, 0x62, 0x69,
0x6e, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x6c, 0x61,
0x62, 0x65, 0x6c, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65,
0x2d, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x3d,
0x22, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x3e, 0x43, 0x68, 0x6f, 0x6f, 0x73,
0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x6c,
0x61, 0x62, 0x65, 0x6c, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x69, 0x6e,
0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x73, 0x75,
0x62, 0x6d, 0x69, 0x74, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d,
0x22, 0x62, 0x74, 0x6e, 0x22, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d,
0x22, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x22, 0x20, 0x2f, 0x3e,
0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d,
0x22, 0x70, 0x72, 0x67, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x70,
0x72, 0x67, 0x62, 0x61, 0x72, 0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x62, 0x61,
0x72, 0x22, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0d, 0x0a, 0x20,
0x20, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x68, 0x72,
0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x68, 0x33, 0x3e, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3c,
0x2f, 0x68, 0x33, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x69, 0x6e, 0x70,
0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x62, 0x75, 0x74,
0x74, 0x6f, 0x6e, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22,
0x62, 0x74, 0x6e, 0x22, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22,
0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x22, 0x20, 0x6f, 0x6e, 0x63, 0x6c,
0x69, 0x63, 0x6b, 0x3d, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e,
0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x72, 0x65,
0x66, 0x3d, 0x27, 0x2f, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x27, 0x22,
0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x62, 0x3e, 0x53, 0x49,
0x57, 0x41, 0x54, 0x20, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x20, 0x32,
0x30, 0x32, 0x33, 0x3c, 0x2f, 0x62, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x66,
0x6f, 0x72, 0x6d, 0x3e, 0x0d, 0x0a, 0x3c, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77,
0x2e, 0x6f, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x3d, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x28, 0x22, 0x2f,
0x67, 0x65, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69,
0x6e, 0x66, 0x6f, 0x22, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x2e, 0x74, 0x68, 0x65, 0x6e, 0x28, 0x72, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x20, 0x3d, 0x3e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, 0x74, 0x68, 0x65, 0x6e,
0x28, 0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73,
0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x64, 0x61, 0x74, 0x61,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74,
0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28,
0x22, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x2e,
0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
0x65, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74,
0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28,
0x22, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22,
0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20,
0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x69, 0x70, 0x5f, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42,
0x79, 0x49, 0x64, 0x28, 0x22, 0x6d, 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72,
0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x6d, 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f,
0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x6d,
0x6f, 0x64, 0x65, 0x6c, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72,
0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42,
0x79, 0x49, 0x64, 0x28, 0x22, 0x66, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48,
0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x73,
0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67,
0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49,
0x64, 0x28, 0x22, 0x73, 0x64, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54,
0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x73, 0x64,
0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3b, 0x0d, 0x0a,
0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x41, 0x50, 0x49, 0x20,
0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c,
0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x61, 0x70, 0x69,
0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x3e, 0x4c,
0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f,
0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x70,
0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x70, 0x20, 0x73, 0x74, 0x79, 0x6c,
0x65, 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67,
0x6e, 0x3a, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x22, 0x3e, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x6c, 0x79,
0x20, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x3c, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x73, 0x74, 0x79, 0x6c,
0x65, 0x3d, 0x22, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x63, 0x65, 0x6e,
0x74, 0x72, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x64, 0x22, 0x3e, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20,
0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x62,
0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22,
0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x22, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x22, 0x20, 0x6f, 0x6e, 0x63,
0x6c, 0x69, 0x63, 0x6b, 0x3d, 0x22, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77,
0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x72,
0x65, 0x66, 0x3d, 0x27, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x27, 0x22,
0x3e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x3c, 0x2f, 0x62,
0x75, 0x74, 0x74, 0x6f, 0x6e, 0x3e, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e,
0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x68,
0x72, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x68, 0x33, 0x3e, 0x55, 0x70,
0x6c, 0x6f, 0x61, 0x64, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,
0x65, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x3c, 0x2f, 0x68,
0x33, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22,
0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22,
0x20, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x22, 0x73,
0x75, 0x62, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x22, 0x20, 0x73, 0x74,
0x79, 0x6c, 0x65, 0x3d, 0x22, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79,
0x3a, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x22, 0x20, 0x61, 0x63, 0x63, 0x65,
0x70, 0x74, 0x3d, 0x22, 0x2e, 0x62, 0x69, 0x6e, 0x22, 0x20, 0x2f, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x20, 0x69,
0x64, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75,
0x74, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65,
0x22, 0x3e, 0x43, 0x68, 0x6f, 0x6f, 0x73, 0x65, 0x20, 0x66, 0x69, 0x6c,
0x65, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74,
0x79, 0x70, 0x65, 0x3d, 0x22, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x22,
0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x74, 0x6e, 0x22,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22, 0x50, 0x72, 0x6f, 0x67,
0x72, 0x61, 0x6d, 0x22, 0x20, 0x2f, 0x3e, 0x3c, 0x62, 0x72, 0x20, 0x2f,
0x3e, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x70, 0x72, 0x67, 0x22,
0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c,
0x62, 0x72, 0x20, 0x2f, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x64, 0x69,
0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x70, 0x72, 0x67, 0x62, 0x61, 0x72,
0x22, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76,
0x20, 0x69, 0x64, 0x3d, 0x22, 0x62, 0x61, 0x72, 0x22, 0x3e, 0x3c, 0x2f,
0x64, 0x69, 0x76, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x69,
0x76, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x62, 0x72, 0x20, 0x2f, 0x3e,
0x0d, 0x0a, 0x20, 0x20, 0x3c, 0x68, 0x72, 0x3e, 0x0d, 0x0a, 0x20, 0x20,
0x3c, 0x68, 0x33, 0x3e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x43,
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79,
0x70, 0x65, 0x3d, 0x22, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x22, 0x20,
0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x62, 0x74, 0x6e, 0x22, 0x20,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x22, 0x52, 0x65, 0x62, 0x6f, 0x6f,
0x74, 0x22, 0x20, 0x6f, 0x6e, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x3d, 0x22,
0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2e, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x27, 0x2f, 0x72,
0x65, 0x62, 0x6f, 0x6f, 0x74, 0x27, 0x22, 0x20, 0x2f, 0x3e, 0x0d, 0x0a,
0x20, 0x20, 0x3c, 0x62, 0x3e, 0x53, 0x49, 0x57, 0x41, 0x54, 0x20, 0x53,
0x59, 0x53, 0x54, 0x45, 0x4d, 0x20, 0x32, 0x30, 0x32, 0x33, 0x3c, 0x2f,
0x62, 0x3e, 0x0d, 0x0a, 0x3c, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 0x0d,
0x0a, 0x3c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0x0d, 0x0a, 0x20,
0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6f, 0x6e, 0x6c, 0x6f,
0x61, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x66, 0x65, 0x74, 0x63, 0x68, 0x28, 0x22, 0x2f, 0x67, 0x65, 0x74, 0x5f,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22,
0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, 0x74, 0x68,
0x65, 0x6e, 0x28, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20,
0x3d, 0x3e, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
0x6a, 0x73, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2e, 0x74, 0x68, 0x65, 0x6e, 0x28, 0x64, 0x61, 0x74,
0x61, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e,
0x6c, 0x6f, 0x67, 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75,
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x69, 0x64, 0x66,
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x2e, 0x69,
0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x69, 0x64, 0x66, 0x5f, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67,
0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49,
0x64, 0x28, 0x22, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d,
0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x71, 0x74,
0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x2b, 0x20, 0x22,
0x3a, 0x22, 0x20, 0x2b, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x71,
0x74, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x61, 0x70, 0x69, 0x5f, 0x65,
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x29, 0x2e, 0x69, 0x6e,
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x68, 0x6f, 0x73,
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65,
0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61,
0x2e, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75,
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x69, 0x70, 0x5f,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x29, 0x2e, 0x69, 0x6e,
0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61,
0x74, 0x61, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, 0x70, 0x69,
0x63, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x74, 0x61, 0x2e, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74,
0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28,
0x22, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e,
0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74,
0x61, 0x2e, 0x6d, 0x71, 0x74, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x65, 0x64, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x29, 0x2e, 0x63, 0x61, 0x74, 0x63, 0x68, 0x28, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x20, 0x3d, 0x3e, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c,
0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x75, 0x62,
0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x76, 0x61, 0x72, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d,
0x65, 0x20, 0x3d, 0x20, 0x6f, 0x62, 0x6a, 0x2e, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x22, 0x5c, 0x5c, 0x22,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75,
0x22, 0x6d, 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c,
0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x61, 0x63, 0x5f,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c,
0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x6f, 0x64, 0x65,
0x6c, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74,
0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28,
0x22, 0x66, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20,
0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x73, 0x6f, 0x66, 0x74, 0x77,
0x61, 0x72, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f,
0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x73,
0x64, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x29,
0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d,
0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x73, 0x64, 0x6b, 0x5f, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42,
0x79, 0x49, 0x64, 0x28, 0x22, 0x69, 0x64, 0x66, 0x5f, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72,
0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x69, 0x64, 0x66, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f,
0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x61,
0x70, 0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x29, 0x2e,
0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x71, 0x74, 0x74, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x20, 0x2b, 0x20, 0x22, 0x3a, 0x22, 0x20, 0x2b,
0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x71, 0x74, 0x74, 0x5f, 0x70,
0x6f, 0x72, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67,
0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49,
0x64, 0x28, 0x22, 0x61, 0x70, 0x69, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48,
0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x62,
0x61, 0x73, 0x65, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x6f, 0x63, 0x75,
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x66, 0x69, 0x6c,
0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x29, 0x2e, 0x69, 0x6e,
0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x22, 0x20, 0x2b,
0x20, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x5b, 0x66, 0x69,
0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74,
0x68, 0x20, 0x2d, 0x20, 0x31, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d,
0x0d, 0x0a, 0x20, 0x20, 0x24, 0x28, 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x22,
0x29, 0x2e, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x28, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x65, 0x29, 0x20, 0x7b, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x2e, 0x70, 0x72, 0x65, 0x76, 0x65,
0x6e, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x28, 0x29, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x66, 0x6f,
0x72, 0x6d, 0x20, 0x3d, 0x20, 0x24, 0x28, 0x22, 0x23, 0x75, 0x70, 0x6c,
0x6f, 0x61, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x29, 0x5b, 0x30,
0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20,
0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x46,
0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x28, 0x66, 0x6f, 0x72, 0x6d,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x24, 0x2e, 0x61, 0x6a,
0x61, 0x78, 0x28, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x75, 0x72, 0x6c, 0x3a, 0x20, 0x22, 0x2f, 0x6f, 0x74, 0x61, 0x5f, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x22, 0x50, 0x4f,
0x53, 0x54, 0x22, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x61, 0x74, 0x61, 0x3a, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2c, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73,
0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72,
0x6f, 0x63, 0x65, 0x73, 0x73, 0x44, 0x61, 0x74, 0x61, 0x3a, 0x20, 0x66,
0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x78, 0x68, 0x72, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x78, 0x68, 0x72,
0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f,
0x77, 0x2e, 0x58, 0x4d, 0x4c, 0x48, 0x74, 0x74, 0x70, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x28, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x68, 0x72, 0x2e, 0x75, 0x70, 0x6c,
0x6f, 0x61, 0x64, 0x2e, 0x61, 0x64, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x28, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x65, 0x76, 0x74, 0x29, 0x20, 0x7b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x65, 0x76, 0x74, 0x2e, 0x6c, 0x65,
0x6e, 0x67, 0x74, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x62,
0x6c, 0x65, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72,
0x20, 0x70, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x65, 0x76, 0x74, 0x2e, 0x6c,
0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x2f, 0x20, 0x65, 0x76, 0x74, 0x2e,
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
0x20, 0x28, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x28, 0x70, 0x65, 0x72, 0x20, 0x2a, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20,
0x3c, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x70, 0x72, 0x67, 0x22, 0x29, 0x2e,
0x68, 0x74, 0x6d, 0x6c, 0x28, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x69,
0x6e, 0x67, 0x20, 0x2e, 0x20, 0x2e, 0x20, 0x2e, 0x20, 0x28, 0x22, 0x20,
0x2b, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x28, 0x70, 0x65, 0x72, 0x20, 0x2a, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20,
0x2b, 0x20, 0x22, 0x25, 0x29, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0d,
0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x63, 0x65, 0x6e,
0x74, 0x72, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x64, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54,
0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6d, 0x71,
0x74, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76,
0x61, 0x72, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x3d, 0x20,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61,
0x72, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x72,
0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x22, 0x22, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x55, 0x70,
0x74, 0x69, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x76,
0x65, 0x72, 0x74, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x58, 0x20,
0x64, 0x61, 0x79, 0x73, 0x2c, 0x20, 0x48, 0x48, 0x3a, 0x4d, 0x4d, 0x3a,
0x53, 0x53, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x76, 0x61, 0x72, 0x20, 0x64, 0x61, 0x79, 0x73, 0x20, 0x3d, 0x20, 0x4d,
0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x75, 0x70,
0x74, 0x69, 0x6d, 0x65, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x34, 0x20, 0x2a,
0x20, 0x33, 0x36, 0x30, 0x30, 0x29, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
0x20, 0x2d, 0x3d, 0x20, 0x64, 0x61, 0x79, 0x73, 0x20, 0x2a, 0x20, 0x32,
0x34, 0x20, 0x2a, 0x20, 0x33, 0x36, 0x30, 0x30, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x68,
0x6f, 0x75, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e,
0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
0x20, 0x2f, 0x20, 0x33, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d,
0x65, 0x20, 0x2d, 0x3d, 0x20, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x20, 0x2a,
0x20, 0x33, 0x36, 0x30, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6d, 0x69, 0x6e, 0x75,
0x74, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66,
0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x20,
0x2f, 0x20, 0x36, 0x30, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x2d,
0x3d, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x20, 0x2a, 0x20,
0x36, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73,
0x20, 0x3d, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28,
0x64, 0x61, 0x79, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x29, 0x20, 0x75, 0x70,
0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
0x2b, 0x3d, 0x20, 0x64, 0x61, 0x79, 0x73, 0x20, 0x2b, 0x20, 0x22, 0x20,
0x64, 0x61, 0x79, 0x73, 0x2c, 0x20, 0x22, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65,
0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x2b, 0x3d, 0x20, 0x68,
0x6f, 0x75, 0x72, 0x73, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x28, 0x29, 0x2e, 0x70, 0x61, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74,
0x28, 0x32, 0x2c, 0x20, 0x22, 0x30, 0x22, 0x29, 0x20, 0x2b, 0x20, 0x22,
0x3a, 0x22, 0x20, 0x2b, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73,
0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x2e,
0x70, 0x61, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x28, 0x32, 0x2c, 0x20,
0x22, 0x30, 0x22, 0x29, 0x20, 0x2b, 0x20, 0x22, 0x3a, 0x22, 0x20, 0x2b,
0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x2e, 0x74, 0x6f, 0x53,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x2e, 0x70, 0x61, 0x64, 0x53,
0x74, 0x61, 0x72, 0x74, 0x28, 0x32, 0x2c, 0x20, 0x22, 0x30, 0x22, 0x29,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64,
0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45,
0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, 0x64, 0x28, 0x22,
0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e,
0x65, 0x72, 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x3d, 0x20, 0x75, 0x70, 0x74,
0x69, 0x6d, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x2e, 0x63, 0x61,
0x74, 0x63, 0x68, 0x28, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x3e,
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x28, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x7d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x73, 0x75, 0x62, 0x28, 0x6f, 0x62, 0x6a, 0x29, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x66,
0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x6f, 0x62,
0x6a, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x73, 0x70, 0x6c, 0x69,
0x74, 0x28, 0x22, 0x5c, 0x5c, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67,
0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49,
0x64, 0x28, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75,
0x74, 0x22, 0x29, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x48, 0x54, 0x4d,
0x4c, 0x20, 0x3d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x20, 0x20, 0x20, 0x22, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x4e,
0x61, 0x6d, 0x65, 0x5b, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x2d, 0x20, 0x31, 0x5d,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x24, 0x28,
0x22, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x29, 0x2e, 0x73, 0x75, 0x62, 0x6d,
0x69, 0x74, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x28, 0x65, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
0x2e, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x66, 0x61,
0x75, 0x6c, 0x74, 0x28, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x76, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x3d, 0x20, 0x24,
0x28, 0x22, 0x23, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x66, 0x6f,
0x72, 0x6d, 0x22, 0x29, 0x5b, 0x30, 0x5d, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x3d,
0x20, 0x6e, 0x65, 0x77, 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x44, 0x61, 0x74,
0x61, 0x28, 0x66, 0x6f, 0x72, 0x6d, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x24, 0x2e, 0x61, 0x6a, 0x61, 0x78, 0x28, 0x7b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c, 0x3a, 0x20, 0x22,
0x2f, 0x6f, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22,
0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x3a, 0x20, 0x22, 0x50, 0x4f, 0x53, 0x54, 0x22, 0x2c, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x20,
0x64, 0x61, 0x74, 0x61, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x44,
0x61, 0x74, 0x61, 0x3a, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78, 0x68, 0x72, 0x3a, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76,
0x61, 0x72, 0x20, 0x78, 0x68, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77,
0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x58, 0x4d, 0x4c, 0x48,
0x74, 0x74, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x29,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78,
0x68, 0x72, 0x2e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x61, 0x64,
0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e,
0x65, 0x72, 0x28, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
0x22, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28,
0x65, 0x76, 0x74, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28,
0x65, 0x76, 0x74, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x43, 0x6f,
0x6d, 0x70, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x29, 0x20, 0x7b, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x70, 0x72, 0x67,
0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x22, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
0x64, 0x2c, 0x20, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67,
0x20, 0x2e, 0x20, 0x2e, 0x20, 0x2e, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x70, 0x65, 0x72, 0x20, 0x3d,
0x20, 0x65, 0x76, 0x74, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20,
0x2f, 0x20, 0x65, 0x76, 0x74, 0x2e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x4d, 0x61, 0x74, 0x68,
0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x28, 0x70, 0x65, 0x72, 0x20, 0x2a,
0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x3c, 0x20, 0x31, 0x30, 0x30, 0x29,
0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23,
0x70, 0x72, 0x67, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x28, 0x22,
0x55, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x20, 0x2e,
0x20, 0x2e, 0x20, 0x28, 0x22, 0x20, 0x2b, 0x20, 0x4d, 0x61, 0x74, 0x68,
0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x28, 0x70, 0x65, 0x72, 0x20, 0x2a,
0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x22, 0x25, 0x29, 0x22,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24,
0x28, 0x22, 0x23, 0x70, 0x72, 0x67, 0x22, 0x29, 0x2e, 0x68, 0x74, 0x6d,
0x6c, 0x28, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x43, 0x6f,
0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x52, 0x65, 0x62,
0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x20, 0x2e, 0x20, 0x2e,
0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x24, 0x28, 0x22, 0x23, 0x62, 0x61,
0x72, 0x22, 0x29, 0x2e, 0x63, 0x73, 0x73, 0x28, 0x22, 0x77, 0x69, 0x64,
0x74, 0x68, 0x22, 0x2c, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x72, 0x6f,
0x75, 0x6e, 0x64, 0x28, 0x70, 0x65, 0x72, 0x20, 0x2a, 0x20, 0x31, 0x30,
0x30, 0x29, 0x20, 0x2b, 0x20, 0x22, 0x25, 0x22, 0x29, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x78, 0x68, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x64, 0x2c, 0x20, 0x73, 0x29, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63,
0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22,
0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x21, 0x22, 0x29, 0x3b, 0x0d,
0x24, 0x28, 0x22, 0x23, 0x62, 0x61, 0x72, 0x22, 0x29, 0x2e, 0x63, 0x73,
0x73, 0x28, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x2c, 0x20, 0x4d,
0x61, 0x74, 0x68, 0x2e, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x28, 0x70, 0x65,
0x72, 0x20, 0x2a, 0x20, 0x31, 0x30, 0x30, 0x29, 0x20, 0x2b, 0x20, 0x22,
0x25, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x61, 0x6c,
0x73, 0x65, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x78, 0x68, 0x72, 0x3b, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c,
0x20, 0x62, 0x2c, 0x20, 0x63, 0x29, 0x20, 0x7b, 0x20, 0x7d, 0x2c, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x7d, 0x29, 0x3b, 0x0d, 0x0a, 0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x3e, 0x0d, 0x0a, 0x3c, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0x0d,
0x0a, 0x20, 0x20, 0x68, 0x72, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f,
0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a,
0x20, 0x23, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x74, 0x6f,
0x70, 0x3a, 0x20, 0x30, 0x2e, 0x35, 0x65, 0x6d, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x62, 0x6f,
0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x20, 0x30, 0x2e, 0x35, 0x65, 0x6d, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e,
0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e,
0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x61, 0x75, 0x74, 0x6f,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3a, 0x20, 0x69, 0x6e, 0x73,
0x65, 0x74, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72,
0x64, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30,
0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x69,
0x67, 0x68, 0x74, 0x3a, 0x20, 0x33, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x69, 0x6c,
0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x2c, 0x0d, 0x0a, 0x20, 0x20,
0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x30, 0x30, 0x25,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68,
0x74, 0x3a, 0x20, 0x34, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x72, 0x61, 0x64,
0x69, 0x75, 0x73, 0x3a, 0x20, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x31,
0x30, 0x70, 0x78, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65,
0x3a, 0x20, 0x31, 0x35, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d,
0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20, 0x23, 0x66, 0x31, 0x66, 0x31,
0x66, 0x31, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72,
0x64, 0x65, 0x72, 0x3a, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x20,
0x31, 0x35, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a,
0x0d, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x7b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75,
0x6e, 0x64, 0x2d, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x3a, 0x20, 0x75, 0x72,
0x6c, 0x28, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x66,
0x73, 0x2e, 0x73, 0x69, 0x77, 0x61, 0x74, 0x73, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x6f, 0x6e, 0x61, 0x5f,
0x62, 0x67, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
0x64, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x63, 0x6f, 0x76, 0x65,
0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74,
0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x20, 0x73, 0x61, 0x6e,
0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a,
0x20, 0x31, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x37, 0x37, 0x37, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x23,
0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x7b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72,
0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20,
0x23, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x35, 0x45,
0x35, 0x45, 0x35, 0x45, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x30, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20,
0x31, 0x70, 0x78, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x23, 0x64,
0x64, 0x64, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e,
0x65, 0x2d, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x34,
0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78,
0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e,
0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69,
0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x75, 0x72, 0x73, 0x6f,
0x72, 0x3a, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d,
0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x23, 0x62,
0x61, 0x72, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x23, 0x70, 0x72, 0x67, 0x62,
0x61, 0x72, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61,
0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x3a, 0x20, 0x23, 0x44, 0x39, 0x44, 0x39, 0x44, 0x39, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72,
0x2d, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x31, 0x30, 0x70,
0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20,
0x20, 0x23, 0x62, 0x61, 0x72, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28,
0x64, 0x2c, 0x20, 0x73, 0x29, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65,
0x2e, 0x6c, 0x6f, 0x67, 0x28, 0x22, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
0x73, 0x21, 0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x3a, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x29,
0x20, 0x7b, 0x20, 0x7d, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x29, 0x3b, 0x0d, 0x0a, 0x3c,
0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0x0d, 0x0a, 0x3c, 0x73,
0x74, 0x79, 0x6c, 0x65, 0x3e, 0x0d, 0x0a, 0x20, 0x20, 0x68, 0x72, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c,
0x61, 0x79, 0x3a, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x32, 0x39, 0x43, 0x44,
0x31, 0x46, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64,
0x74, 0x68, 0x3a, 0x20, 0x30, 0x25, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x31, 0x30, 0x70,
0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20,
0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a,
0x20, 0x72, 0x67, 0x62, 0x61, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32,
0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x30, 0x2e, 0x39,
0x35, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78,
0x2d, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x32, 0x35, 0x38, 0x70,
0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67,
0x69, 0x6e, 0x3a, 0x20, 0x37, 0x35, 0x70, 0x78, 0x20, 0x61, 0x75, 0x74,
0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64,
0x69, 0x6e, 0x67, 0x3a, 0x20, 0x33, 0x30, 0x70, 0x78, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x72,
0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x31, 0x35, 0x70, 0x78, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61,
0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72,
0x67, 0x69, 0x6e, 0x2d, 0x74, 0x6f, 0x70, 0x3a, 0x20, 0x30, 0x2e, 0x35,
0x65, 0x6d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72,
0x67, 0x69, 0x6e, 0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x20,
0x30, 0x2e, 0x35, 0x65, 0x6d, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a,
0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74,
0x3a, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x79, 0x6c,
0x65, 0x3a, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x74, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x77, 0x69,
0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x33,
0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a,
0x20, 0x20, 0x23, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69, 0x6e, 0x70, 0x75,
0x74, 0x2c, 0x0d, 0x0a, 0x20, 0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
0x3a, 0x20, 0x31, 0x30, 0x30, 0x25, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x34, 0x70,
0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64,
0x65, 0x72, 0x2d, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x34,
0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72,
0x67, 0x69, 0x6e, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 0x20, 0x61, 0x75,
0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e,
0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x35, 0x70, 0x78,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20,
0x2e, 0x62, 0x74, 0x6e, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20,
0x23, 0x43, 0x41, 0x33, 0x44, 0x33, 0x44, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66,
0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x75, 0x72, 0x73,
0x6f, 0x72, 0x3a, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x2e,
0x63, 0x6f, 0x6e, 0x66, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20,
0x23, 0x34, 0x31, 0x37, 0x64, 0x66, 0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66,
0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x75, 0x72, 0x73,
0x6f, 0x72, 0x3a, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a,
0x20, 0x31, 0x30, 0x30, 0x25, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x20, 0x34, 0x34, 0x70, 0x78,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x2d, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a, 0x20, 0x34, 0x70,
0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x72, 0x67,
0x69, 0x6e, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 0x20, 0x61, 0x75, 0x74,
0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74,
0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x35, 0x70, 0x78, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72,
0x3a, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x3c,
0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e
0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a,
0x20, 0x23, 0x66, 0x31, 0x66, 0x31, 0x66, 0x31, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x30,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69,
0x6e, 0x67, 0x3a, 0x20, 0x30, 0x20, 0x31, 0x35, 0x70, 0x78, 0x3b, 0x0d,
0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x62, 0x6f,
0x64, 0x79, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61,
0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x69, 0x6d, 0x61,
0x67, 0x65, 0x3a, 0x20, 0x75, 0x72, 0x6c, 0x28, 0x22, 0x68, 0x74, 0x74,
0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x66, 0x73, 0x2e, 0x73, 0x69, 0x77, 0x61,
0x74, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x61, 0x72, 0x6f, 0x6e, 0x61, 0x5f, 0x62, 0x67, 0x2e, 0x70, 0x6e, 0x67,
0x22, 0x29, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63,
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x73, 0x69, 0x7a, 0x65,
0x3a, 0x20, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c,
0x79, 0x3a, 0x20, 0x73, 0x61, 0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69,
0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74,
0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x20, 0x31, 0x34, 0x70, 0x78, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a,
0x20, 0x23, 0x37, 0x37, 0x37, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d,
0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x23, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x69,
0x6e, 0x70, 0x75, 0x74, 0x20, 0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63,
0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x43, 0x43, 0x43, 0x43, 0x43,
0x43, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x3a, 0x20, 0x23, 0x35, 0x45, 0x35, 0x45, 0x35, 0x45, 0x3b, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
0x3a, 0x20, 0x30, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f,
0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x31, 0x70, 0x78, 0x20, 0x73, 0x6f,
0x6c, 0x69, 0x64, 0x20, 0x23, 0x64, 0x64, 0x64, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x2d, 0x68, 0x65, 0x69, 0x67,
0x68, 0x74, 0x3a, 0x20, 0x34, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67,
0x6e, 0x3a, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x3a,
0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d, 0x0a,
0x0d, 0x0a, 0x20, 0x20, 0x23, 0x62, 0x61, 0x72, 0x2c, 0x0d, 0x0a, 0x20,
0x20, 0x23, 0x70, 0x72, 0x67, 0x62, 0x61, 0x72, 0x20, 0x7b, 0x0d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75,
0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x44,
0x39, 0x44, 0x39, 0x44, 0x39, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x72, 0x61, 0x64, 0x69, 0x75,
0x73, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x23, 0x62, 0x61, 0x72, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a,
0x20, 0x23, 0x32, 0x39, 0x43, 0x44, 0x31, 0x46, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x30, 0x25,
0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68,
0x74, 0x3a, 0x20, 0x31, 0x30, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x7d, 0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20,
0x7b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20, 0x72, 0x67, 0x62, 0x61, 0x28,
0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35,
0x35, 0x2c, 0x20, 0x30, 0x2e, 0x39, 0x35, 0x29, 0x3b, 0x0d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x77, 0x69, 0x64, 0x74, 0x68,
0x3a, 0x20, 0x32, 0x35, 0x38, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x37, 0x35,
0x70, 0x78, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x33,
0x30, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f,
0x72, 0x64, 0x65, 0x72, 0x2d, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3a,
0x20, 0x31, 0x35, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20,
0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d,
0x0d, 0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x2e, 0x62, 0x74, 0x6e, 0x20, 0x7b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72,
0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20, 0x23, 0x43, 0x41, 0x33, 0x44, 0x33,
0x44, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x7d, 0x0d,
0x0a, 0x0d, 0x0a, 0x20, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x20, 0x7b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72,
0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x20, 0x23, 0x34, 0x31, 0x37, 0x64, 0x66,
0x33, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x30, 0x30, 0x25, 0x3b,
0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74,
0x3a, 0x20, 0x34, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x72, 0x61, 0x64, 0x69,
0x75, 0x73, 0x3a, 0x20, 0x34, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x31, 0x30,
0x70, 0x78, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x0d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a,
0x20, 0x31, 0x35, 0x70, 0x78, 0x3b, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x30, 0x3b, 0x0d, 0x0a,
0x20, 0x20, 0x7d, 0x0d, 0x0a, 0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65,
0x3e
, 0x00};

View File

@ -1,7 +1,7 @@
/**
* @file main.cpp
* @brief Test firmware for the ESPMegaPRO OOP library
*/
*/
#include <ESPMegaProOS.hpp>
#include <InternalDisplay.hpp>
#include <ETH.h>
@ -12,22 +12,39 @@
#include <AnalogCard.hpp>
#include <SmartVariable.hpp>
#define INPUT_DEBOUNCE_TIME_MS 1000
// #define FRAM_DEBUG
// #define MQTT_DEBUG
#define WRITE_DEFAULT_NETCONF
//#define CLIMATE_CARD_ENABLE
// #define RTC_DEBUG
// #define WRITE_DEFAULT_NETCONF
// #define CLIMATE_CARD_ENABLE
#define MQTT_CARD_REGISTER
#define DISPLAY_ENABLE
// #define DISPLAY_ENABLE
#define WEB_SERVER_ENABLE
#define LCD_OTA_ENABLE
//#define REMOTE_VARIABLE_ENABLE
//#define CT_ENABLE
#define SMART_VARIABLE_ENABLE
// #define LCD_OTA_ENABLE
// #define REMOTE_VARIABLE_ENABLE
// #define CT_ENABLE
// #define SMART_VARIABLE_ENABLE
#define EXTERNAL_DIGITAL_OUTPUT_CARD_ENABLE
#define EXTERNAL_DIGITAL_INPUT_CARD_ENABLE
// Demo PLC firmware using the ESPMegaPRO OOP library
ESPMegaPRO espmega = ESPMegaPRO();
#ifdef EXTERNAL_DIGITAL_OUTPUT_CARD_ENABLE
DigitalOutputCard externalDigitalOutputCard = DigitalOutputCard(1, 0, 1, 1, 0);
#endif
#ifdef EXTERNAL_DIGITAL_INPUT_CARD_ENABLE
void handleExternalDigitalInput(uint8_t pin, uint8_t state)
{
Serial.printf("Digital Input External %d: %d\n", pin, state);
}
DigitalInputCard externalDigitalInputCard = DigitalInputCard(0, 0, 1, 0, 1, 1);
#endif
// Remote Variable
#ifdef REMOTE_VARIABLE_ENABLE
RemoteVariable testVar = RemoteVariable();
@ -115,6 +132,7 @@ void input_change_callback(uint8_t pin, uint8_t value)
Serial.print(pin);
Serial.print(" ");
Serial.println(value);
espmega.outputs.toggleState(pin);
}
void mqtt_callback(char *topic, char *payload)
@ -162,6 +180,14 @@ void setup()
{
ESP_LOGI("Initializer", "Starting ESPMegaPRO OOP demo");
espmega.begin();
#ifdef EXTERNAL_DIGITAL_OUTPUT_CARD_ENABLE
espmega.installCard(6, &externalDigitalOutputCard);
#endif
#ifdef EXTERNAL_DIGITAL_INPUT_CARD_ENABLE
espmega.installCard(7, &externalDigitalInputCard);
externalDigitalInputCard.registerCallback(handleExternalDigitalInput);
#endif
espmega.setTimezone("UTC-7");
ESP_LOGI("Initializer", "Enabling IOT module");
espmega.enableIotModule();
ESP_LOGI("Initializer", "Enabling Ethernet");
@ -185,11 +211,29 @@ void setup()
ESP_LOGI("Initializer", "Connecting to MQTT");
espmega.iot->connectToMqtt();
espmega.iot->registerMqttCallback(mqtt_callback);
// Set debounce time
for (uint8_t i = 0; i < 16; i++)
{
espmega.inputs.setDebounceTime(i, INPUT_DEBOUNCE_TIME_MS);
}
// Set all pin values to 4095
for (uint8_t i = 0; i < 16; i++)
{
espmega.outputs.setValue(i, 4095);
}
#ifdef MQTT_CARD_REGISTER
ESP_LOGI("Initializer", "Registering cards 0");
espmega.iot->registerCard(0);
ESP_LOGI("Initializer", "Registering cards 1");
espmega.iot->registerCard(1);
#ifdef EXTERNAL_DIGITAL_OUTPUT_CARD_ENABLE
ESP_LOGI("Initializer", "Registering cards 6");
espmega.iot->registerCard(6);
#endif
#ifdef EXTERNAL_DIGITAL_INPUT_CARD_ENABLE
ESP_LOGI("Initializer", "Registering cards 7");
espmega.iot->registerCard(7);
#endif
#endif
ESP_LOGI("Initializer", "Registering Input change callback");
espmega.inputs.registerCallback(input_change_callback);
@ -225,7 +269,7 @@ void setup()
#endif
#ifdef REMOTE_VARIABLE_ENABLE
ESP_LOGI("Initializer", "Initializing testvar");
testVar.begin(32, "/xm/fan_speed", espmega.iot, true,"/pm/request_fan_speed");
testVar.begin(32, "/xm/fan_speed", espmega.iot, true, "/pm/request_fan_speed");
testVar.enableSetValue("/pm/request_switch_state");
#endif
#ifdef CT_ENABLE
@ -236,6 +280,7 @@ void setup()
ct.bindFRAM(&espmega.fram, 7000);
ct.loadEnergy();
ct.setEnergyAutoSave(true);
espmega.iot->registerCard(3);
#endif
#ifdef SMART_VARIABLE_ENABLE
ESP_LOGI("Initializer", "Initializing smart variable");
@ -325,4 +370,13 @@ void loop()
smartVar.setValue(last_smartvar_state ? "true" : "false");
}
#endif
#ifdef RTC_DEBUG
static uint32_t last_time_print = 0;
if (millis() - last_time_print >= 1000)
{
last_time_print = millis();
rtctime_t time = espmega.getTime();
Serial.printf("Time: %02d:%02d:%02d %02d/%02d/%04d\n", time.hours, time.minutes, time.seconds, time.day, time.month, time.year);
}
#endif
}