";
+
+const char EM_FLDSET_START[] PROGMEM = "
";
+
+////////////////////////////////////////////////////
+
+const char EM_HTTP_PORTAL_OPTIONS[] PROGMEM = "
";
+const char EM_HTTP_ITEM[] PROGMEM = "
";
+const char JSON_ITEM[] PROGMEM = "{\"SSID\":\"{v}\", \"Encryption\":{i}, \"Quality\":\"{r}\"}";
+
+////////////////////////////////////////////////////
+
+// To permit display stored Credentials on CP
+#ifndef DISPLAY_STORED_CREDENTIALS_IN_CP
+ #define DISPLAY_STORED_CREDENTIALS_IN_CP true
+#endif
+
+#if ( (_ESP32_ETH_MGR_LOGLEVEL_ > 3) && DISPLAY_STORED_CREDENTIALS_IN_CP )
+ #warning Enable DISPLAY_STORED_CREDENTIALS_IN_CP
+#endif
+
+#if DISPLAY_STORED_CREDENTIALS_IN_CP
+const char EM_HTTP_FORM_START[] PROGMEM = "
";
+
+////////////////////////////////////////////////////
+
+const char EM_HTTP_SAVED[] PROGMEM = "
Credentials Saved
";
+
+////////////////////////////////////////////////////
+
+const char EM_HTTP_END[] PROGMEM = "
";
+
+////////////////////////////////////////////////////
+
+const char EM_HTTP_HEAD_CL[] = "Content-Length";
+const char EM_HTTP_HEAD_CT[] = "text/html";
+const char EM_HTTP_HEAD_CT2[] = "text/plain";
+
+const char EM_HTTP_HEAD_JSON[] ="application/json";
+
+//KH Add repeatedly used const
+const char EM_HTTP_CACHE_CONTROL[] = "Cache-Control";
+const char EM_HTTP_NO_STORE[] = "no-cache, no-store, must-revalidate";
+const char EM_HTTP_PRAGMA[] = "Pragma";
+const char EM_HTTP_NO_CACHE[] = "no-cache";
+const char EM_HTTP_EXPIRES[] = "Expires";
+const char EM_HTTP_CORS[] = "Access-Control-Allow-Origin";
+const char EM_HTTP_CORS_ALLOW_ALL[] = "*";
+
+////////////////////////////////////////////////////
+
+#if USE_AVAILABLE_PAGES
+ const char EM_HTTP_AVAILABLE_PAGES[] PROGMEM = "
Available Pages
Page | Function |
---|
/ | Menu page. |
/eth | Enter ETH Config Page |
/ethsave | Save Config. Portal Info with supplied variables. |
/close | Close the Config Portal. |
/i | This Info page. |
/r | Delete ETH configuration and reboot. |
/state | Current device state in JSON format. Interface for ETH configuration. |
";
+#else
+ const char EM_HTTP_AVAILABLE_PAGES[] PROGMEM = "";
+#endif
+
+////////////////////////////////////////////////////
+
+#define ETH_MANAGER_MAX_PARAMS 20
+
+////////////////////////////////////////////////////
+
+// To permit autoConnect() to use STA static IP or DHCP IP.
+#ifndef AUTOCONNECT_NO_INVALIDATE
+ #define AUTOCONNECT_NO_INVALIDATE true
+#endif
+
+////////////////////////////////////////////////////
+
+typedef struct
+{
+ const char *_id;
+ const char *_placeholder;
+ char *_value;
+ int _length;
+ int _labelPlacement;
+} EMParam_Data;
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+
+class ESP32_EMParameter
+{
+ public:
+
+ ESP32_EMParameter(const char *custom);
+ ESP32_EMParameter(const char *id, const char *placeholder, const char *defaultValue, const int& length,
+ const char *custom = "", const int& labelPlacement = WFM_LABEL_BEFORE);
+
+ ESP32_EMParameter(const EMParam_Data& EMParam_data);
+
+ ~ESP32_EMParameter();
+
+ void setEMParam_Data(const EMParam_Data& EMParam_data);
+ void getEMParam_Data(EMParam_Data& EMParam_data);
+
+ const char *getID();
+ const char *getValue();
+ const char *getPlaceholder();
+ int getValueLength();
+ int getLabelPlacement();
+ const char *getCustomHTML();
+
+ private:
+
+ EMParam_Data _EMParam_data;
+
+ const char *_customHTML;
+
+ void init(const char *id, const char *placeholder, const char *defaultValue, const int& length,
+ const char *custom, const int& labelPlacement);
+
+ friend class ESP32_SC_Ethernet_Manager;
+};
+
+////////////////////////////////////////////////////
+
+#define USE_DYNAMIC_PARAMS true
+#define DEFAULT_PORTAL_TIMEOUT 60000L
+
+// To permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used.
+// You have to explicitly specify false to disable the feature.
+#ifndef USE_STATIC_IP_CONFIG_IN_CP
+ #define USE_STATIC_IP_CONFIG_IN_CP true
+#endif
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+
+class ESP32_SC_Ethernet_Manager
+{
+ public:
+
+ ESP32_SC_Ethernet_Manager(const char *iHostname = "");
+
+ ~ESP32_SC_Ethernet_Manager();
+
+ // If you want to start the config portal
+ bool startConfigPortal();
+
+ //sets timeout before webserver loop ends and exits even if there has been no setup.
+ //usefully for devices that failed to connect at some point and got stuck in a webserver loop
+ //in seconds setConfigPortalTimeout is a new name for setTimeout
+ void setConfigPortalTimeout(const unsigned long& seconds);
+ void setTimeout(const unsigned long& seconds);
+
+ //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects
+ void setConnectTimeout(const unsigned long& seconds);
+
+ void setDebugOutput(bool debug);
+
+ //sets config for a static IP
+ void setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn);
+
+ void setSTAStaticIPConfig(const ETH_STA_IPConfig& EM_STA_IPconfig);
+ void getSTAStaticIPConfig(ETH_STA_IPConfig& EM_STA_IPconfig);
+
+#if USE_CONFIGURABLE_DNS
+ void setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn,
+ const IPAddress& dns_address_1, const IPAddress& dns_address_2);
+#endif
+
+ //called when settings have been changed and connection was successful
+ void setSaveConfigCallback(void(*func)());
+
+#if USE_DYNAMIC_PARAMS
+ //adds a custom parameter
+ bool addParameter(ESP32_EMParameter *p);
+#else
+ //adds a custom parameter
+ void addParameter(ESP32_EMParameter *p);
+#endif
+
+ //if this is set, it will exit after config, even if connection is unsucessful.
+ void setBreakAfterConfig(bool shouldBreak);
+
+ //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins)
+ //TODO
+ //if this is set, customise style
+ void setCustomHeadElement(const char* element);
+
+////////////////////////////////////////////////////
+
+ // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+#if USING_CORS_FEATURE
+ void setCORSHeader(const char* CORSHeaders)
+ {
+ _CORS_Header = CORSHeaders;
+
+ LOGWARN1(F("Set CORS Header to : "), _CORS_Header);
+ }
+
+ ///////////////////////////
+
+ inline const char* getCORSHeader()
+ {
+ return _CORS_Header;
+ }
+#endif
+
+ ///////////////////////////
+
+ //returns the list of Parameters
+ ESP32_EMParameter** getParameters();
+
+ // returns the Parameters Count
+ int getParametersCount();
+
+ ///////////////////////////
+
+ void setHostname()
+ {
+ if (RFC952_hostname[0] != 0)
+ {
+ ETH.setHostname(RFC952_hostname);
+ }
+ }
+
+////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+
+ inline String getTimezoneName()
+ {
+ return _timezoneName;
+ }
+
+ ///////////////////////////
+
+ inline void setTimezoneName(const String& inTimezoneName)
+ {
+ _timezoneName = inTimezoneName;
+ }
+
+ ///////////////////////////
+
+ //See: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ // EST5EDT,M3.2.0,M11.1.0 (for America/New_York)
+ // EST5EDT is the name of the time zone
+ // EST is the abbreviation used when DST is off
+ // 6 hours is the time difference from GMT
+ // EDT is the abbreviation used when DST is on
+ // ,M3 is the third month
+ // .2 is the second occurrence of the day in the month
+ // .0 is Sunday
+ // ,M11 is the eleventh month
+ // .1 is the first occurrence of the day in the month
+ // .0 is Sunday
+
+ const char * getTZ(const char * timezoneName)
+ {
+ //const char TZ_NAME[][TIMEZONE_MAX_LEN]
+ for (uint16_t index = 0; index < sizeof(TZ_NAME) / TIMEZONE_MAX_LEN; index++)
+ {
+ if ( !strncmp(timezoneName, (TZ_NAME[index]), strlen((TZ_NAME[index])) ) )
+ {
+ yield();
+
+ return (ESP_TZ_NAME[index]);
+ }
+ }
+
+ return "";
+ }
+
+ ///////////////////////////
+
+ const char * getTZ(const String& timezoneName)
+ {
+ return getTZ(timezoneName.c_str());
+ }
+
+ ///////////////////////////
+
+#endif
+
+ private:
+
+ std::unique_ptr
dnsServer;
+
+ std::unique_ptr server;
+
+ bool needInfo = true;
+ String pager;
+ wl_status_t ethStatus;
+
+#define RFC952_HOSTNAME_MAXLEN 24
+
+ char RFC952_hostname[RFC952_HOSTNAME_MAXLEN + 1];
+
+ char* getRFC952_hostname(const char* iHostname);
+
+ void setupConfigPortal();
+ void startWPS();
+
+ ////////////////////////////////////////////////////
+
+#if USE_ESP_ETH_MANAGER_NTP
+ // Timezone info
+ String _timezoneName = "";
+#endif
+
+ ////////////////////////////////////////////////////
+
+ unsigned long _configPortalTimeout = 0;
+
+ unsigned long _connectTimeout = 0;
+ unsigned long _configPortalStart = 0;
+
+ ////////////////////////////////////////////////////
+
+ ETH_STA_IPConfig _ETH_STA_IPconfig = { IPAddress(0, 0, 0, 0), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0),
+ IPAddress(192, 168, 2, 1), IPAddress(8, 8, 8, 8) };
+
+ ////////////////////////////////////////////////////
+
+ int _paramsCount = 0;
+ int _minimumQuality = -1;
+ bool _removeDuplicateAPs = true;
+ bool _shouldBreakAfterConfig = false;
+ bool _tryWPS = false;
+
+ const char* _customHeadElement = "";
+
+ int status = WL_IDLE_STATUS;
+
+ // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+#if USING_CORS_FEATURE
+ const char* _CORS_Header = EM_HTTP_CORS_ALLOW_ALL; //"*";
+#endif
+
+ wl_status_t waitForConnectResult();
+
+ void setInfo();
+ String networkListAsString();
+
+ void handleRoot();
+ void handleETH();
+ void handleETHSave();
+ void handleServerClose();
+ void handleInfo();
+ void handleState();
+ void handleReset();
+ void handleNotFound();
+ bool captivePortal();
+
+ void reportStatus(String& page);
+
+ // DNS server
+ const byte DNS_PORT = 53;
+
+ //helpers
+ bool isIp(const String& str);
+ String toStringIp(const IPAddress& ip);
+
+ bool connect;
+ bool stopConfigPortal = false;
+
+ bool _debug = false; //true;
+
+ void(*_savecallback)() = NULL;
+
+ ////////////////////////////////////////////////////
+
+#if USE_DYNAMIC_PARAMS
+ int _max_params;
+ ESP32_EMParameter** _params;
+#else
+ ESP32_EMParameter* _params[ETH_MANAGER_MAX_PARAMS];
+#endif
+
+ ////////////////////////////////////////////////////
+
+ template
+ auto optionalIPFromString(T *obj, const char *s) -> decltype(obj->fromString(s))
+ {
+ return obj->fromString(s);
+ }
+
+ ///////////////////////////
+
+ auto optionalIPFromString(...) -> bool
+ {
+ LOGINFO("No IPAddress.fromString(), use ESP8266 core 2.1.0+ for Custom IP configuration to work.");
+
+ return false;
+ }
+
+ ///////////////////////////
+
+};
+
+#endif // ESP32_SC_Ethernet_Manager_hpp
+
diff --git a/src/ESP32_SC_Ethernet_Manager_Debug.h b/src/ESP32_SC_Ethernet_Manager_Debug.h
new file mode 100644
index 0000000..defdb80
--- /dev/null
+++ b/src/ESP32_SC_Ethernet_Manager_Debug.h
@@ -0,0 +1,89 @@
+/****************************************************************************************************************************
+ ESP32_SC_Ethernet_Manager_Debug.h
+
+ For Ethernet shields using ESP32_SC_Ethernet (ESP32_S2/S3/C3 + LwIP W5500 / ENC28J60)
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/ESP32_SC_Ethernet_Manager
+ Licensed under MIT license
+
+ Version: 1.0.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 16/12/2022 Initial coding for (ESP32_S2/S3/C3 + LwIP W5500 / ENC28J60)
+ *****************************************************************************************************************************/
+
+#pragma once
+
+#ifndef ESP32_SC_Ethernet_Manager_Debug_H
+#define ESP32_SC_Ethernet_Manager_Debug_H
+
+#ifdef ESP32_ETH_MGR_DEBUG_PORT
+ #define DBG_PORT_ESP_EM ESP32_ETH_MGR_DEBUG_PORT
+#else
+ #define DBG_PORT_ESP_EM Serial
+#endif
+
+// Change _ESP32_ETH_MGR_LOGLEVEL_ to set tracing and logging verbosity
+// 0: DISABLED: no logging
+// 1: ERROR: errors
+// 2: WARN: errors and warnings
+// 3: INFO: errors, warnings and informational (default)
+// 4: DEBUG: errors, warnings, informational and debug
+
+#ifndef _ESP32_ETH_MGR_LOGLEVEL_
+ #define _ESP32_ETH_MGR_LOGLEVEL_ 1
+#endif
+
+/////////////////////////////////////////////////////////
+
+const char ESP_EM_MARK[] = "[EM] ";
+const char ESP_EM_SP[] = " ";
+
+#define ESP_EM_PRINT DBG_PORT_ESP_EM.print
+#define ESP_EM_PRINTLN DBG_PORT_ESP_EM.println
+
+#define ESP_EM_PRINT_MARK ESP_EM_PRINT(ESP_EM_MARK)
+#define ESP_EM_PRINT_SP ESP_EM_PRINT(ESP_EM_SP)
+
+/////////////////////////////////////////////////////////
+
+#define LOGERROR(x) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); }
+#define LOGERROR0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT(x); }
+#define LOGERROR1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); }
+#define LOGERROR2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); }
+#define LOGERROR3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>0) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); }
+
+/////////////////////////////////////////////////////////
+
+#define LOGWARN(x) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); }
+#define LOGWARN0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT(x); }
+#define LOGWARN1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); }
+#define LOGWARN2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); }
+#define LOGWARN3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>1) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); }
+
+/////////////////////////////////////////////////////////
+
+#define LOGINFO(x) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); }
+#define LOGINFO0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT(x); }
+#define LOGINFO1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); }
+#define LOGINFO2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); }
+#define LOGINFO3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>2) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); }
+
+/////////////////////////////////////////////////////////
+
+#define LOGDEBUG(x) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINTLN(x); }
+#define LOGDEBUG0(x) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT(x); }
+#define LOGDEBUG1(x,y) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(y); }
+#define LOGDEBUG2(x,y,z) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(z); }
+#define LOGDEBUG3(x,y,z,w) if(_ESP32_ETH_MGR_LOGLEVEL_>3) { ESP_EM_PRINT_MARK; ESP_EM_PRINT(x); ESP_EM_PRINT_SP; ESP_EM_PRINT(y); ESP_EM_PRINT_SP; ESP_EM_PRINT(z); ESP_EM_PRINT_SP; ESP_EM_PRINTLN(w); }
+
+/////////////////////////////////////////////////////////
+
+#endif // ESP32_SC_Ethernet_Manager_Debug_H
+
diff --git a/src/ESP32_SC_Ethernet_Manager_Impl.h b/src/ESP32_SC_Ethernet_Manager_Impl.h
new file mode 100644
index 0000000..29d747b
--- /dev/null
+++ b/src/ESP32_SC_Ethernet_Manager_Impl.h
@@ -0,0 +1,1221 @@
+/****************************************************************************************************************************
+ ESP32_SC_Ethernet_Manager_Impl.h
+
+ For Ethernet shields using ESP32_SC_Ethernet (ESP32_S2/S3/C3 + LwIP W5500 / ENC28J60)
+
+ Modified from
+ 1. Tzapu (https://github.com/tzapu/WiFiManager)
+ 2. Ken Taylor (https://github.com/kentaylor)
+ 3. Khoi Hoang (https://github.com/khoih-prog/ESP_WiFiManager)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/ESP32_SC_Ethernet_Manager
+ Licensed under MIT license
+
+ Version: 1.0.0
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 16/12/2022 Initial coding for (ESP32_S2/S3/C3 + LwIP W5500 / ENC28J60)
+ *****************************************************************************************************************************/
+
+#pragma once
+
+#ifndef ESP32_SC_Ethernet_Manager_Impl_h
+#define ESP32_SC_Ethernet_Manager_Impl_h
+
+//////////////////////////////////////////
+
+ESP32_EMParameter::ESP32_EMParameter(const char *custom)
+{
+ _EMParam_data._id = NULL;
+ _EMParam_data._placeholder = NULL;
+ _EMParam_data._length = 0;
+ _EMParam_data._value = NULL;
+ _EMParam_data._labelPlacement = WFM_LABEL_BEFORE;
+
+ _customHTML = custom;
+}
+
+//////////////////////////////////////////
+
+ESP32_EMParameter::ESP32_EMParameter(const char *id, const char *placeholder, const char *defaultValue,
+ const int& length, const char *custom, const int& labelPlacement)
+{
+ init(id, placeholder, defaultValue, length, custom, labelPlacement);
+}
+
+//////////////////////////////////////////
+
+// KH, using struct
+ESP32_EMParameter::ESP32_EMParameter(const EMParam_Data& EMParam_data)
+{
+ init(EMParam_data._id, EMParam_data._placeholder, EMParam_data._value,
+ EMParam_data._length, "", EMParam_data._labelPlacement);
+}
+
+//////////////////////////////////////////
+
+void ESP32_EMParameter::init(const char *id, const char *placeholder, const char *defaultValue,
+ const int& length, const char *custom, const int& labelPlacement)
+{
+ _EMParam_data._id = id;
+ _EMParam_data._placeholder = placeholder;
+ _EMParam_data._length = length;
+ _EMParam_data._labelPlacement = labelPlacement;
+
+ _EMParam_data._value = new char[_EMParam_data._length + 1];
+
+ if (_EMParam_data._value != NULL)
+ {
+ memset(_EMParam_data._value, 0, _EMParam_data._length + 1);
+
+ if (defaultValue != NULL)
+ {
+ strncpy(_EMParam_data._value, defaultValue, _EMParam_data._length);
+ }
+ }
+
+ _customHTML = custom;
+}
+
+//////////////////////////////////////////
+
+ESP32_EMParameter::~ESP32_EMParameter()
+{
+ if (_EMParam_data._value != NULL)
+ {
+ delete[] _EMParam_data._value;
+ }
+}
+
+//////////////////////////////////////////
+
+// Using Struct to get/set whole data at once
+void ESP32_EMParameter::setEMParam_Data(const EMParam_Data& EMParam_data)
+{
+ LOGINFO(F("setEMParam_Data"));
+
+ memcpy(&_EMParam_data, &EMParam_data, sizeof(_EMParam_data));
+}
+
+//////////////////////////////////////////
+
+void ESP32_EMParameter::getEMParam_Data(EMParam_Data& EMParam_data)
+{
+ LOGINFO(F("getEMParam_Data"));
+
+ memcpy(&EMParam_data, &_EMParam_data, sizeof(EMParam_data));
+}
+
+//////////////////////////////////////////
+
+const char* ESP32_EMParameter::getValue()
+{
+ return _EMParam_data._value;
+}
+
+//////////////////////////////////////////
+
+const char* ESP32_EMParameter::getID()
+{
+ return _EMParam_data._id;
+}
+
+//////////////////////////////////////////
+
+const char* ESP32_EMParameter::getPlaceholder()
+{
+ return _EMParam_data._placeholder;
+}
+
+//////////////////////////////////////////
+
+int ESP32_EMParameter::getValueLength()
+{
+ return _EMParam_data._length;
+}
+
+//////////////////////////////////////////
+
+int ESP32_EMParameter::getLabelPlacement()
+{
+ return _EMParam_data._labelPlacement;
+}
+
+//////////////////////////////////////////
+
+const char* ESP32_EMParameter::getCustomHTML()
+{
+ return _customHTML;
+}
+
+//////////////////////////////////////////
+
+/**
+ [getParameters description]
+ @access public
+*/
+ESP32_EMParameter** ESP32_SC_Ethernet_Manager::getParameters()
+{
+ return _params;
+}
+
+//////////////////////////////////////////
+//////////////////////////////////////////
+
+/**
+ [getParametersCount description]
+ @access public
+*/
+int ESP32_SC_Ethernet_Manager::getParametersCount()
+{
+ return _paramsCount;
+}
+
+//////////////////////////////////////////
+
+char* ESP32_SC_Ethernet_Manager::getRFC952_hostname(const char* iHostname)
+{
+ memset(RFC952_hostname, 0, sizeof(RFC952_hostname));
+
+ size_t len = (RFC952_HOSTNAME_MAXLEN < strlen(iHostname)) ? RFC952_HOSTNAME_MAXLEN : strlen(iHostname);
+
+ size_t j = 0;
+
+ for (size_t i = 0; i < len - 1; i++)
+ {
+ if (isalnum(iHostname[i]) || iHostname[i] == '-')
+ {
+ RFC952_hostname[j] = iHostname[i];
+ j++;
+ }
+ }
+
+ // no '-' as last char
+ if (isalnum(iHostname[len - 1]) || (iHostname[len - 1] != '-'))
+ RFC952_hostname[j] = iHostname[len - 1];
+
+ return RFC952_hostname;
+}
+
+//////////////////////////////////////////
+
+ESP32_SC_Ethernet_Manager::ESP32_SC_Ethernet_Manager(const char *iHostname)
+{
+
+ //server = webserver;
+ //dnsServer = dnsserver;
+
+#if USE_DYNAMIC_PARAMS
+ _max_params = ETH_MANAGER_MAX_PARAMS;
+ _params = (ESP32_EMParameter**) malloc(_max_params * sizeof(ESP32_EMParameter*));
+#endif
+
+ if (iHostname[0] == 0)
+ {
+ String _hostname = "ESP32-" + String(ESP_getChipId(), HEX);
+
+ _hostname.toUpperCase();
+
+ getRFC952_hostname(_hostname.c_str());
+
+ }
+ else
+ {
+ // Prepare and store the hostname only not NULL
+ getRFC952_hostname(iHostname);
+ }
+
+ LOGWARN1(F("RFC925 Hostname ="), RFC952_hostname);
+
+ setHostname();
+}
+
+//////////////////////////////////////////
+
+ESP32_SC_Ethernet_Manager::~ESP32_SC_Ethernet_Manager()
+{
+#if USE_DYNAMIC_PARAMS
+
+ if (_params != NULL)
+ {
+ LOGINFO(F("freeing allocated params!"));
+
+ free(_params);
+ }
+
+#endif
+}
+
+//////////////////////////////////////////
+
+#if USE_DYNAMIC_PARAMS
+ bool ESP32_SC_Ethernet_Manager::addParameter(ESP32_EMParameter *p)
+#else
+ void ESP32_SC_Ethernet_Manager::addParameter(ESP32_EMParameter *p)
+#endif
+{
+#if USE_DYNAMIC_PARAMS
+
+ if (_paramsCount == _max_params)
+ {
+ // rezise the params array
+ _max_params += ETH_MANAGER_MAX_PARAMS;
+
+ LOGINFO1(F("Increasing _max_params to:"), _max_params);
+
+ ESP32_EMParameter** new_params = (ESP32_EMParameter**) realloc(_params, _max_params * sizeof(ESP32_EMParameter*));
+
+ if (new_params != NULL)
+ {
+ _params = new_params;
+ }
+ else
+ {
+ LOGINFO(F("ERROR: failed to realloc params, size not increased!"));
+
+ return false;
+ }
+ }
+
+ _params[_paramsCount] = p;
+ _paramsCount++;
+
+ LOGINFO1(F("Adding parameter"), p->getID());
+
+ return true;
+
+#else
+
+ // Danger here. Better to use Tzapu way here
+ if (_paramsCount < (ETH_MANAGER_MAX_PARAMS))
+ {
+ _params[_paramsCount] = p;
+ _paramsCount++;
+
+ LOGINFO1(F("Adding parameter"), p->getID());
+ }
+ else
+ {
+ LOGINFO("Can't add parameter. Full");
+ }
+
+#endif
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setupConfigPortal()
+{
+ stopConfigPortal = false; //Signal not to close config portal
+
+ dnsServer.reset(new DNSServer());
+
+ server.reset(new WebServer(HTTP_PORT_TO_USE));
+
+ /* Setup the DNS server redirecting all the domains to the apIP */
+ if (dnsServer)
+ {
+ dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
+
+ // AsyncDNSServer started with "*" domain name, all DNS requests will be passsed to ETH.localIP()
+ if (! dnsServer->start(DNS_PORT, "*", ETH.localIP()))
+ {
+ // No socket available
+ LOGERROR(F("Can't start DNS Server. No available socket"));
+ }
+ }
+ else
+ {
+ // No space available
+ LOGERROR(F("Can't initiate DNS Server. No enough space"));
+ }
+
+ _configPortalStart = millis();
+
+ LOGDEBUG1(F("_configPortalStart millis() ="), millis());
+
+ LOGWARN1(F("Config Portal IP address ="), ETH.localIP());
+
+ /* Setup web pages: root, eth config pages, SO captive portal detectors and not found. */
+
+ server->on("/", std::bind(&ESP32_SC_Ethernet_Manager::handleRoot, this));
+ server->on("/eth", std::bind(&ESP32_SC_Ethernet_Manager::handleETH, this));
+ server->on("/ethsave", std::bind(&ESP32_SC_Ethernet_Manager::handleETHSave, this));
+ server->on("/close", std::bind(&ESP32_SC_Ethernet_Manager::handleServerClose, this));
+ server->on("/i", std::bind(&ESP32_SC_Ethernet_Manager::handleInfo, this));
+ server->on("/r", std::bind(&ESP32_SC_Ethernet_Manager::handleReset, this));
+ server->on("/state", std::bind(&ESP32_SC_Ethernet_Manager::handleState, this));
+ //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
+ server->on("/fwlink", std::bind(&ESP32_SC_Ethernet_Manager::handleRoot, this));
+ server->onNotFound( std::bind(&ESP32_SC_Ethernet_Manager::handleNotFound, this));
+
+ server->begin(); // Web server start
+
+ LOGWARN(F("HTTP server started"));
+}
+
+//////////////////////////////////////////
+
+bool ESP32_SC_Ethernet_Manager::startConfigPortal()
+{
+ connect = false;
+
+ setupConfigPortal();
+
+ bool TimedOut = true;
+
+ LOGINFO("startConfigPortal : Enter loop");
+
+ while (true)
+ {
+ //DNS
+ dnsServer->processNextRequest();
+ //HTTP
+ server->handleClient();
+
+#if ( USING_ESP32_S2 || USING_ESP32_C3 )
+ // Fix ESP32-S2 issue with WebServer (https://github.com/espressif/arduino-esp32/issues/4348)
+ delay(1);
+#endif
+
+ if (connect)
+ {
+ TimedOut = false;
+
+ if (_shouldBreakAfterConfig)
+ {
+ //flag set to exit after config after trying to connect
+ //notify that configuration has changed and any optional parameters should be saved
+ if (_savecallback != NULL)
+ {
+ //todo: check if any custom parameters actually exist, and check if they really changed maybe
+ _savecallback();
+ }
+
+ LOGDEBUG("Stop ConfigPortal: _shouldBreakAfterConfig");
+
+ break;
+ }
+ }
+
+ if (stopConfigPortal)
+ {
+ TimedOut = false;
+
+ LOGERROR("stopConfigPortal");
+
+ stopConfigPortal = false;
+
+ break;
+ }
+
+ if (_configPortalTimeout > 0 && ( millis() > _configPortalStart + _configPortalTimeout) )
+ {
+ //LOGDEBUG3("startConfigPortal: timeout, _configPortalTimeout =", _configPortalTimeout, "millis() =", millis());
+
+ stopConfigPortal = false;
+
+ break;
+ }
+
+#define TIME_BETWEEN_CONFIG_PORTAL_LOOP 50
+
+ vTaskDelay(TIME_BETWEEN_CONFIG_PORTAL_LOOP / portTICK_PERIOD_MS);
+ }
+
+ //LOGDEBUG3("startConfigPortal: exit, _configPortalTimeout =", _configPortalTimeout, "millis() =", millis());
+
+ server->stop();
+ server.reset();
+ dnsServer->stop();
+ dnsServer.reset();
+
+#if USING_W5500
+ return (ESP32_W5500_isConnected());
+#else
+ return (ESP32_ENC_isConnected());
+#endif
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setTimeout(const unsigned long& seconds)
+{
+ setConfigPortalTimeout(seconds);
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setConfigPortalTimeout(const unsigned long& seconds)
+{
+ _configPortalTimeout = seconds * 1000;
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setConnectTimeout(const unsigned long& seconds)
+{
+ _connectTimeout = seconds * 1000;
+}
+
+void ESP32_SC_Ethernet_Manager::setDebugOutput(bool debug)
+{
+ _debug = debug;
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setBreakAfterConfig(bool shouldBreak)
+{
+ _shouldBreakAfterConfig = shouldBreak;
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::reportStatus(String& page)
+{
+ page += FPSTR(EM_HTTP_SCRIPT_NTP_MSG);
+}
+
+
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn)
+{
+ LOGINFO(F("setSTAStaticIPConfig"));
+
+ _ETH_STA_IPconfig._sta_static_ip = ip;
+ _ETH_STA_IPconfig._sta_static_gw = gw;
+ _ETH_STA_IPconfig._sta_static_sn = sn;
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::setSTAStaticIPConfig(const ETH_STA_IPConfig& EM_STA_IPconfig)
+{
+ LOGINFO(F("setSTAStaticIPConfig"));
+
+ memcpy((void *) &_ETH_STA_IPconfig, &EM_STA_IPconfig, sizeof(_ETH_STA_IPconfig));
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::getSTAStaticIPConfig(ETH_STA_IPConfig& EM_STA_IPconfig)
+{
+ LOGINFO(F("getSTAStaticIPConfig"));
+
+ memcpy((void *) &EM_STA_IPconfig, &_ETH_STA_IPconfig, sizeof(EM_STA_IPconfig));
+}
+
+
+//////////////////////////////////////////
+
+#if USE_CONFIGURABLE_DNS
+void ESP32_SC_Ethernet_Manager::setSTAStaticIPConfig(const IPAddress& ip, const IPAddress& gw, const IPAddress& sn,
+ const IPAddress& dns_address_1, const IPAddress& dns_address_2)
+{
+ LOGINFO(F("setSTAStaticIPConfig for USE_CONFIGURABLE_DNS"));
+
+ _ETH_STA_IPconfig._sta_static_ip = ip;
+ _ETH_STA_IPconfig._sta_static_gw = gw;
+ _ETH_STA_IPconfig._sta_static_sn = sn;
+ _ETH_STA_IPconfig._sta_static_dns1 = dns_address_1; //***** Added argument *****
+ _ETH_STA_IPconfig._sta_static_dns2 = dns_address_2; //***** Added argument *****
+}
+#endif
+
+//////////////////////////////////////////
+
+// Handle root or redirect to captive portal
+void ESP32_SC_Ethernet_Manager::handleRoot()
+{
+ LOGDEBUG(F("handleRoot"));
+
+ // Disable _configPortalTimeout when someone accessing Portal to give some time to config
+ _configPortalTimeout = 0;
+
+ if (captivePortal())
+ {
+ LOGDEBUG(F("handleRoot: captive portal exit"));
+
+ // If captive portal redirect instead of displaying the error page.
+ return;
+ }
+
+ server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE));
+
+#if USING_CORS_FEATURE
+ // For configure CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+ server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header);
+#endif
+
+ server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE));
+ server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1");
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+
+ page.replace("{v}", "Options");
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_SCRIPT_NTP);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(EM_HTTP_HEAD_END);
+
+ page += FPSTR(EM_HTTP_PORTAL_OPTIONS);
+ page += F("");
+ reportStatus(page);
+ page += F("
");
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+}
+
+//////////////////////////////////////////
+
+// ETH config page handler
+void ESP32_SC_Ethernet_Manager::handleETH()
+{
+ LOGDEBUG(F("Handle ETH"));
+
+ // Disable _configPortalTimeout when someone accessing Portal to give some time to config
+ _configPortalTimeout = 0;
+
+ server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE));
+
+#if USING_CORS_FEATURE
+ // For configure CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+ server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header);
+#endif
+
+ server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE));
+ server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1");
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+
+ page.replace("{v}", "Config ESP");
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_SCRIPT_NTP);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(EM_HTTP_HEAD_END);
+ page += F("Configuration
");
+
+ page += FPSTR(EM_HTTP_FORM_START);
+
+ char parLength[2];
+
+ page += FPSTR(EM_FLDSET_START);
+
+ // add the extra parameters to the form
+ for (int i = 0; i < _paramsCount; i++)
+ {
+ if (_params[i] == NULL)
+ {
+ break;
+ }
+
+ String pitem;
+
+ switch (_params[i]->getLabelPlacement())
+ {
+ case WFM_LABEL_BEFORE:
+ pitem = FPSTR(EM_HTTP_FORM_LABEL_BEFORE);
+ break;
+
+ case WFM_LABEL_AFTER:
+ pitem = FPSTR(EM_HTTP_FORM_LABEL_AFTER);
+ break;
+
+ default:
+ // WFM_NO_LABEL
+ pitem = FPSTR(EM_HTTP_FORM_PARAM);
+ break;
+ }
+
+ if (_params[i]->getID() != NULL)
+ {
+ pitem.replace("{i}", _params[i]->getID());
+ pitem.replace("{n}", _params[i]->getID());
+ pitem.replace("{p}", _params[i]->getPlaceholder());
+
+ snprintf(parLength, 2, "%d", _params[i]->getValueLength());
+
+ pitem.replace("{l}", parLength);
+ pitem.replace("{v}", _params[i]->getValue());
+ pitem.replace("{c}", _params[i]->getCustomHTML());
+ }
+ else
+ {
+ pitem = _params[i]->getCustomHTML();
+ }
+
+ page += pitem;
+ }
+
+ if (_paramsCount > 0)
+ {
+ page += FPSTR(EM_FLDSET_END);
+ }
+
+ if (_params[0] != NULL)
+ {
+ page += "
";
+ }
+
+ LOGDEBUG1(F("Static IP ="), _ETH_STA_IPconfig._sta_static_ip.toString());
+
+ // KH, Comment out to permit changing from DHCP to static IP, or vice versa
+ // and add staticIP label in CP
+
+ // To permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used.
+ // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa
+ // You have to explicitly specify false to disable the feature.
+
+#if !USE_STATIC_IP_CONFIG_IN_CP
+
+ if (_ETH_STA_IPconfig._sta_static_ip)
+#endif
+ {
+ page += FPSTR(EM_FLDSET_START);
+
+ String item = FPSTR(EM_HTTP_FORM_LABEL);
+
+ item += FPSTR(EM_HTTP_FORM_PARAM);
+
+ item.replace("{i}", "ip");
+ item.replace("{n}", "ip");
+ item.replace("{p}", "Static IP");
+ item.replace("{l}", "15");
+ item.replace("{v}", _ETH_STA_IPconfig._sta_static_ip.toString());
+
+ page += item;
+
+ item = FPSTR(EM_HTTP_FORM_LABEL);
+ item += FPSTR(EM_HTTP_FORM_PARAM);
+
+ item.replace("{i}", "gw");
+ item.replace("{n}", "gw");
+ item.replace("{p}", "Gateway IP");
+ item.replace("{l}", "15");
+ item.replace("{v}", _ETH_STA_IPconfig._sta_static_gw.toString());
+
+ page += item;
+
+ item = FPSTR(EM_HTTP_FORM_LABEL);
+ item += FPSTR(EM_HTTP_FORM_PARAM);
+
+ item.replace("{i}", "sn");
+ item.replace("{n}", "sn");
+ item.replace("{p}", "Subnet");
+ item.replace("{l}", "15");
+ item.replace("{v}", _ETH_STA_IPconfig._sta_static_sn.toString());
+
+#if USE_CONFIGURABLE_DNS
+ //***** Added for DNS address options *****
+ page += item;
+
+ item = FPSTR(EM_HTTP_FORM_LABEL);
+ item += FPSTR(EM_HTTP_FORM_PARAM);
+
+ item.replace("{i}", "dns1");
+ item.replace("{n}", "dns1");
+ item.replace("{p}", "DNS1 IP");
+ item.replace("{l}", "15");
+ item.replace("{v}", _ETH_STA_IPconfig._sta_static_dns1.toString());
+
+ page += item;
+
+ item = FPSTR(EM_HTTP_FORM_LABEL);
+ item += FPSTR(EM_HTTP_FORM_PARAM);
+
+ item.replace("{i}", "dns2");
+ item.replace("{n}", "dns2");
+ item.replace("{p}", "DNS2 IP");
+ item.replace("{l}", "15");
+ item.replace("{v}", _ETH_STA_IPconfig._sta_static_dns2.toString());
+ //***** End added for DNS address options *****
+#endif
+
+ page += item;
+
+ page += FPSTR(EM_FLDSET_END);
+
+ page += "
";
+ }
+
+ page += FPSTR(EM_HTTP_SCRIPT_NTP_HIDDEN);
+
+ page += FPSTR(EM_HTTP_FORM_END);
+
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+
+ LOGDEBUG(F("Sent config page"));
+}
+
+//////////////////////////////////////////
+
+// Handle the WLAN save form and redirect to WLAN config page again
+void ESP32_SC_Ethernet_Manager::handleETHSave()
+{
+ LOGDEBUG(F("ETH save"));
+
+#if USING_CORS_FEATURE
+ // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+ server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header);
+#endif
+
+#if USE_ESP_ETH_MANAGER_NTP
+
+ if (server->arg("timezone") != "")
+ {
+ _timezoneName = server->arg("timezone");
+ LOGDEBUG1(F("TZ name ="), _timezoneName);
+ }
+ else
+ {
+ LOGDEBUG(F("No TZ arg"));
+ }
+
+#endif
+
+ ///////////////////////
+
+ //parameters
+ for (int i = 0; i < _paramsCount; i++)
+ {
+ if (_params[i] == NULL)
+ {
+ break;
+ }
+
+ //read parameter
+ String value = server->arg(_params[i]->getID()).c_str();
+
+ //store it in array
+ value.toCharArray(_params[i]->_EMParam_data._value, _params[i]->_EMParam_data._length);
+
+ LOGDEBUG2(F("Parameter and value :"), _params[i]->getID(), value);
+ }
+
+
+ if (server->arg("ip") != "")
+ {
+ String ip = server->arg("ip");
+
+ optionalIPFromString(&_ETH_STA_IPconfig._sta_static_ip, ip.c_str());
+
+ LOGDEBUG1(F("New Static IP ="), _ETH_STA_IPconfig._sta_static_ip.toString());
+ }
+
+ if (server->arg("gw") != "")
+ {
+ String gw = server->arg("gw");
+
+ optionalIPFromString(&_ETH_STA_IPconfig._sta_static_gw, gw.c_str());
+
+ LOGDEBUG1(F("New Static Gateway ="), _ETH_STA_IPconfig._sta_static_gw.toString());
+ }
+
+ if (server->arg("sn") != "")
+ {
+ String sn = server->arg("sn");
+
+ optionalIPFromString(&_ETH_STA_IPconfig._sta_static_sn, sn.c_str());
+
+ LOGDEBUG1(F("New Static Netmask ="), _ETH_STA_IPconfig._sta_static_sn.toString());
+ }
+
+#if USE_CONFIGURABLE_DNS
+
+ //***** Added for DNS Options *****
+ if (server->arg("dns1") != "")
+ {
+ String dns1 = server->arg("dns1");
+
+ optionalIPFromString(&_ETH_STA_IPconfig._sta_static_dns1, dns1.c_str());
+
+ LOGDEBUG1(F("New Static DNS1 ="), _ETH_STA_IPconfig._sta_static_dns1.toString());
+ }
+
+ if (server->arg("dns2") != "")
+ {
+ String dns2 = server->arg("dns2");
+
+ optionalIPFromString(&_ETH_STA_IPconfig._sta_static_dns2, dns2.c_str());
+
+ LOGDEBUG1(F("New Static DNS2 ="), _ETH_STA_IPconfig._sta_static_dns2.toString());
+ }
+
+ //***** End added for DNS Options *****
+#endif
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+ page.replace("{v}", "Credentials Saved");
+
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(EM_HTTP_HEAD_END);
+ page += FPSTR(EM_HTTP_SAVED);
+
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+
+ LOGDEBUG(F("Sent eth save page"));
+
+ connect = true; //signal ready to connect/reset
+
+ stopConfigPortal = true; //signal ready to shutdown config portal
+
+ // Restore when Press Save WiFi
+ _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT;
+}
+
+//////////////////////////////////////////
+
+// Handle shut down the server page
+void ESP32_SC_Ethernet_Manager::handleServerClose()
+{
+ LOGDEBUG(F("Server Close"));
+
+ server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE));
+
+
+#if USING_CORS_FEATURE
+ // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+ server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header);
+#endif
+
+ server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE));
+ server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1");
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+
+ page.replace("{v}", "Close Server");
+
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(EM_HTTP_HEAD_END);
+ page += F("");
+ page += F("
");
+ page += F("IP address is
");
+ page += ETH.localIP().toString();
+ page += F("");
+ page += F("Portal closed...
");
+
+ //page += F("Push button on device to restart configuration server!");
+
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+
+ stopConfigPortal = true; //signal ready to shutdown config portal
+
+ LOGDEBUG(F("Sent server close page"));
+
+ // Restore when Press Save WiFi
+ _configPortalTimeout = DEFAULT_PORTAL_TIMEOUT;
+}
+
+//////////////////////////////////////////
+
+// Handle the info page
+void ESP32_SC_Ethernet_Manager::handleInfo()
+{
+ LOGDEBUG(F("Info"));
+
+ // Disable _configPortalTimeout when someone accessing Portal to give some time to config
+ _configPortalTimeout = 0;
+
+ server->sendHeader(FPSTR(EM_HTTP_CACHE_CONTROL), FPSTR(EM_HTTP_NO_STORE));
+
+#if USING_CORS_FEATURE
+ // For configuring CORS Header, default to EM_HTTP_CORS_ALLOW_ALL = "*"
+ server->sendHeader(FPSTR(EM_HTTP_CORS), _CORS_Header);
+#endif
+
+ server->sendHeader(FPSTR(EM_HTTP_PRAGMA), FPSTR(EM_HTTP_NO_CACHE));
+ server->sendHeader(FPSTR(EM_HTTP_EXPIRES), "-1");
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+ page.replace("{v}", "Info");
+
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_SCRIPT_NTP);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+
+ if (connect)
+ page += F("
");
+
+ page += FPSTR(EM_HTTP_HEAD_END);
+
+ page += F("
");
+
+ if (connect)
+ {
+ page += F("- Trying to connect
- ");
+ page += ethStatus;
+ page += F("
");
+ }
+
+ page += pager;
+ page += F("Information
");
+
+ reportStatus(page);
+
+ page += FPSTR(EM_FLDSET_START);
+ page += F("Device Data
");
+ page += F("");
+ page += F("Name | Value |
---|
Chip ID | ");
+
+ page += String(ESP_getChipId(), HEX);
+ page += F(" |
");
+
+ page += F("Chip OUI | ");
+ page += F("0x");
+ page += String(getChipOUI(), HEX);
+ page += F(" |
");
+
+ page += F("Chip Model | ");
+ page += ESP.getChipModel();
+ page += F(" Rev");
+ page += ESP.getChipRevision();
+
+ page += F(" |
");
+
+ page += F("Flash Chip ID | ");
+
+ // TODO
+ page += F("TODO");
+
+ page += F(" |
");
+
+ page += F("IDE Flash Size | ");
+ page += ESP.getFlashChipSize();
+ page += F(" bytes |
");
+
+ page += F("Real Flash Size | ");
+
+ // TODO
+ page += F("TODO");
+
+ page += F(" bytes |
");
+
+ page += F("Station IP | ");
+ page += ETH.localIP().toString();
+ page += F(" |
");
+
+ page += F("Station MAC | ");
+ page += ETH.macAddress();
+ page += F(" |
");
+ page += F("
");
+
+ page += FPSTR(EM_FLDSET_END);
+
+#if USE_AVAILABLE_PAGES
+ page += FPSTR(EM_FLDSET_START);
+ page += FPSTR(EM_HTTP_AVAILABLE_PAGES);
+ page += FPSTR(EM_FLDSET_END);
+#endif
+
+ page += F("More information about ESP32_SC_Ethernet_Manager at");
+ page += F("https://github.com/khoih-prog/ESP32_SC_Ethernet_Manager");
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+
+ LOGDEBUG(F("Sent info page"));
+}
+
+//////////////////////////////////////////
+
+// Handle the state page
+void ESP32_SC_Ethernet_Manager::handleState()
+{
+ LOGDEBUG(F("State-Json"));
+
+ LOGDEBUG(F("Sent state page in json format"));
+}
+
+//////////////////////////////////////////
+
+// Handle the reset page
+void ESP32_SC_Ethernet_Manager::handleReset()
+{
+ LOGDEBUG(F("Reset"));
+
+ server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ server->sendHeader("Pragma", "no-cache");
+ server->sendHeader("Expires", "-1");
+
+ String page = FPSTR(EM_HTTP_HEAD_START);
+
+ page.replace("{v}", "ETH Information");
+ page += FPSTR(EM_HTTP_SCRIPT);
+ page += FPSTR(EM_HTTP_STYLE);
+ page += _customHeadElement;
+ page += FPSTR(EM_HTTP_HEAD_END);
+ page += F("Resetting");
+ page += FPSTR(EM_HTTP_END);
+
+ server->send(200, "text/html", page);
+
+ LOGDEBUG(F("Sent reset page"));
+ delay(5000);
+
+ ESP.restart();
+
+ delay(2000);
+}
+
+//////////////////////////////////////////
+
+void ESP32_SC_Ethernet_Manager::handleNotFound()
+{
+ if (captivePortal())
+ {
+ LOGDEBUG(F("handleNotFound: captive portal exit"));
+
+ // If captive portal redirect instead of displaying the error page.
+ return;
+ }
+
+ String message = "File Not Found\n\n";
+
+ message += "URI: ";
+ message += server->uri();
+ message += "\nMethod: ";
+ message += (server->method() == HTTP_GET) ? "GET" : "POST";
+ message += "\nArguments: ";
+ message += server->args();
+ message += "\n";
+
+ for (uint8_t i = 0; i < server->args(); i++)
+ {
+ message += " " + server->argName(i) + ": " + server->arg(i) + "\n";
+ }
+
+ server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+ server->sendHeader("Pragma", "no-cache");
+ server->sendHeader("Expires", "-1");
+
+ server->send(404, "text/plain", message);
+}
+
+//////////////////////////////////////////
+
+/**
+ HTTPD redirector
+ Redirect to captive portal if we got a request for another domain.
+ Return true in that case so the page handler do not try to handle the request again.
+*/
+bool ESP32_SC_Ethernet_Manager::captivePortal()
+{
+ LOGDEBUG1(F("captivePortal: hostHeader = "), server->hostHeader());
+
+ if (!isIp(server->hostHeader()))
+ {
+ LOGINFO1(F("Request redirected to captive portal : "), server->client().localIP());
+
+ server->sendHeader(F("Location"), (String)F("http://") + toStringIp(server->client().localIP()), true);
+
+ // Empty content inhibits Content-length header so we have to close the socket ourselves.
+ server->send(302, FPSTR(EM_HTTP_HEAD_CT2), "");
+
+ server->client().stop(); // Stop is needed because we sent no content length
+
+ return true;
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////
+
+// start up save config callback
+void ESP32_SC_Ethernet_Manager::setSaveConfigCallback(void(*func)())
+{
+ _savecallback = func;
+}
+
+//////////////////////////////////////////
+
+// sets a custom element to add to head, like a new style tag
+void ESP32_SC_Ethernet_Manager::setCustomHeadElement(const char* element)
+{
+ _customHeadElement = element;
+}
+
+//////////////////////////////////////////
+
+// Is this an IP?
+bool ESP32_SC_Ethernet_Manager::isIp(const String& str)
+{
+ for (unsigned int i = 0; i < str.length(); i++)
+ {
+ int c = str.charAt(i);
+
+ if ( (c != '.') && (c != ':') && ( (c < '0') || (c > '9') ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////
+
+// IP to String
+String ESP32_SC_Ethernet_Manager::toStringIp(const IPAddress& ip)
+{
+ String res = "";
+
+ for (int i = 0; i < 3; i++)
+ {
+ res += String((ip >> (8 * i)) & 0xFF) + ".";
+ }
+
+ res += String(((ip >> 8 * 3)) & 0xFF);
+
+ return res;
+}
+
+//////////////////////////////////////////
+
+uint32_t getChipID()
+{
+ uint64_t chipId64 = 0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8);
+ }
+
+ return (uint32_t) (chipId64 & 0xFFFFFF);
+}
+
+//////////////////////////////////////////
+
+uint32_t getChipOUI()
+{
+ uint64_t chipId64 = 0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ chipId64 |= ( ( (uint64_t) ESP.getEfuseMac() >> (40 - (i * 8)) ) & 0xff ) << (i * 8);
+ }
+
+ return (uint32_t) (chipId64 >> 24);
+}
+
+//////////////////////////////////////////
+
+#endif // ESP32_SC_Ethernet_Manager_Impl_h
diff --git a/src/utils/TZ.h b/src/utils/TZ.h
new file mode 100644
index 0000000..e96b0c7
--- /dev/null
+++ b/src/utils/TZ.h
@@ -0,0 +1,1526 @@
+
+// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
+// by script /tools/TZupdate.sh
+// Thu Nov 12 04:07:03 UTC 2020
+//
+// This database is autogenerated from IANA timezone database
+// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
+// (using https://www.iana.org/time-zones)
+// and can be updated on demand in this repository
+// or by yourself using the above script
+
+#ifndef TZDB_H
+#define TZDB_H
+
+//See: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+// EST5EDT,M3.2.0,M11.1.0 (for America/New_York)
+// EST5EDT is the name of the time zone
+// EST is the abbreviation used when DST is off
+// 6 hours is the time difference from GMT
+// EDT is the abbreviation used when DST is on
+// ,M3 is the third month
+// .2 is the second occurrence of the day in the month
+// .0 is Sunday
+// ,M11 is the eleventh month
+// .1 is the first occurrence of the day in the month
+// .0 is Sunday
+
+
+#if !defined(USING_AFRICA)
+ #define USING_AFRICA false
+#endif
+
+#if !defined(USING_AMERICA)
+ #define USING_AMERICA true
+#endif
+
+#if !defined(USING_ANTARCTICA)
+ #define USING_ANTARCTICA false
+#endif
+
+#if !defined(USING_ASIA)
+ #define USING_ASIA false
+#endif
+
+#if !defined(USING_ATLANTIC)
+ #define USING_ATLANTIC false
+#endif
+
+#if !defined(USING_AUSTRALIA)
+ #define USING_AUSTRALIA true
+#endif
+
+#if !defined(USING_EUROPE)
+ #define USING_EUROPE false
+#endif
+
+#if !defined(USING_INDIAN)
+ #define USING_INDIAN false
+#endif
+
+#if !defined(USING_PACIFIC)
+ #define USING_PACIFIC false
+#endif
+
+#if !defined(USING_ETC_GMT)
+ #define USING_ETC_GMT false
+#endif
+
+////////////////////////////////////////////////////
+
+#define TZ_Africa_Abidjan ("GMT0")
+#define TZ_Africa_Accra ("GMT0")
+#define TZ_Africa_Addis_Ababa ("EAT-3")
+#define TZ_Africa_Algiers ("CET-1")
+#define TZ_Africa_Asmara ("EAT-3")
+#define TZ_Africa_Bamako ("GMT0")
+#define TZ_Africa_Bangui ("WAT-1")
+#define TZ_Africa_Banjul ("GMT0")
+#define TZ_Africa_Bissau ("GMT0")
+#define TZ_Africa_Blantyre ("CAT-2")
+#define TZ_Africa_Brazzaville ("WAT-1")
+#define TZ_Africa_Bujumbura ("CAT-2")
+#define TZ_Africa_Cairo ("EET-2")
+#define TZ_Africa_Casablanca ("<+01>-1")
+#define TZ_Africa_Ceuta ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Africa_Conakry ("GMT0")
+#define TZ_Africa_Dakar ("GMT0")
+#define TZ_Africa_Dar_es_Salaam ("EAT-3")
+#define TZ_Africa_Djibouti ("EAT-3")
+#define TZ_Africa_Douala ("WAT-1")
+#define TZ_Africa_El_Aaiun ("<+01>-1")
+#define TZ_Africa_Freetown ("GMT0")
+#define TZ_Africa_Gaborone ("CAT-2")
+#define TZ_Africa_Harare ("CAT-2")
+#define TZ_Africa_Johannesburg ("SAST-2")
+#define TZ_Africa_Juba ("EAT-3")
+#define TZ_Africa_Kampala ("EAT-3")
+#define TZ_Africa_Khartoum ("CAT-2")
+#define TZ_Africa_Kigali ("CAT-2")
+#define TZ_Africa_Kinshasa ("WAT-1")
+#define TZ_Africa_Lagos ("WAT-1")
+#define TZ_Africa_Libreville ("WAT-1")
+#define TZ_Africa_Lome ("GMT0")
+#define TZ_Africa_Luanda ("WAT-1")
+#define TZ_Africa_Lubumbashi ("CAT-2")
+#define TZ_Africa_Lusaka ("CAT-2")
+#define TZ_Africa_Malabo ("WAT-1")
+#define TZ_Africa_Maputo ("CAT-2")
+#define TZ_Africa_Maseru ("SAST-2")
+#define TZ_Africa_Mbabane ("SAST-2")
+#define TZ_Africa_Mogadishu ("EAT-3")
+#define TZ_Africa_Monrovia ("GMT0")
+#define TZ_Africa_Nairobi ("EAT-3")
+#define TZ_Africa_Ndjamena ("WAT-1")
+#define TZ_Africa_Niamey ("WAT-1")
+#define TZ_Africa_Nouakchott ("GMT0")
+#define TZ_Africa_Ouagadougou ("GMT0")
+#define TZ_Africa_PortomNovo ("WAT-1")
+#define TZ_Africa_Sao_Tome ("GMT0")
+#define TZ_Africa_Tripoli ("EET-2")
+#define TZ_Africa_Tunis ("CET-1")
+#define TZ_Africa_Windhoek ("CAT-2")
+#define TZ_America_Adak ("HST10HDT,M3.2.0,M11.1.0")
+#define TZ_America_Anchorage ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_Anguilla ("AST4")
+#define TZ_America_Antigua ("AST4")
+#define TZ_America_Araguaina ("<-03>3")
+#define TZ_America_Argentina_Buenos_Aires ("<-03>3")
+#define TZ_America_Argentina_Catamarca ("<-03>3")
+#define TZ_America_Argentina_Cordoba ("<-03>3")
+#define TZ_America_Argentina_Jujuy ("<-03>3")
+#define TZ_America_Argentina_La_Rioja ("<-03>3")
+#define TZ_America_Argentina_Mendoza ("<-03>3")
+#define TZ_America_Argentina_Rio_Gallegos ("<-03>3")
+#define TZ_America_Argentina_Salta ("<-03>3")
+#define TZ_America_Argentina_San_Juan ("<-03>3")
+#define TZ_America_Argentina_San_Luis ("<-03>3")
+#define TZ_America_Argentina_Tucuman ("<-03>3")
+#define TZ_America_Argentina_Ushuaia ("<-03>3")
+#define TZ_America_Aruba ("AST4")
+#define TZ_America_Asuncion ("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
+#define TZ_America_Atikokan ("EST5")
+#define TZ_America_Bahia ("<-03>3")
+#define TZ_America_Bahia_Banderas ("CST6CDT,M4.1.0,M10.5.0")
+#define TZ_America_Barbados ("AST4")
+#define TZ_America_Belem ("<-03>3")
+#define TZ_America_Belize ("CST6")
+#define TZ_America_BlancmSablon ("AST4")
+#define TZ_America_Boa_Vista ("<-04>4")
+#define TZ_America_Bogota ("<-05>5")
+#define TZ_America_Boise ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Cambridge_Bay ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Campo_Grande ("<-04>4")
+#define TZ_America_Cancun ("EST5")
+#define TZ_America_Caracas ("<-04>4")
+#define TZ_America_Cayenne ("<-03>3")
+#define TZ_America_Cayman ("EST5")
+#define TZ_America_Chicago ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Chihuahua ("MST7MDT,M4.1.0,M10.5.0")
+#define TZ_America_Costa_Rica ("CST6")
+#define TZ_America_Creston ("MST7")
+#define TZ_America_Cuiaba ("<-04>4")
+#define TZ_America_Curacao ("AST4")
+#define TZ_America_Danmarkshavn ("GMT0")
+#define TZ_America_Dawson ("MST7")
+#define TZ_America_Dawson_Creek ("MST7")
+#define TZ_America_Denver ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Detroit ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Dominica ("AST4")
+#define TZ_America_Edmonton ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Eirunepe ("<-05>5")
+#define TZ_America_El_Salvador ("CST6")
+#define TZ_America_Fortaleza ("<-03>3")
+#define TZ_America_Fort_Nelson ("MST7")
+#define TZ_America_Glace_Bay ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_America_Godthab ("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1")
+#define TZ_America_Goose_Bay ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_America_Grand_Turk ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Grenada ("AST4")
+#define TZ_America_Guadeloupe ("AST4")
+#define TZ_America_Guatemala ("CST6")
+#define TZ_America_Guayaquil ("<-05>5")
+#define TZ_America_Guyana ("<-04>4")
+#define TZ_America_Halifax ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_America_Havana ("CST5CDT,M3.2.0/0,M11.1.0/1")
+#define TZ_America_Hermosillo ("MST7")
+#define TZ_America_Indiana_Indianapolis ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Knox ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Marengo ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Petersburg ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Tell_City ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Vevay ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Vincennes ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Indiana_Winamac ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Inuvik ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Iqaluit ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Jamaica ("EST5")
+#define TZ_America_Juneau ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_Kentucky_Louisville ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Kentucky_Monticello ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Kralendijk ("AST4")
+#define TZ_America_La_Paz ("<-04>4")
+#define TZ_America_Lima ("<-05>5")
+#define TZ_America_Los_Angeles ("PST8PDT,M3.2.0,M11.1.0")
+#define TZ_America_Lower_Princes ("AST4")
+#define TZ_America_Maceio ("<-03>3")
+#define TZ_America_Managua ("CST6")
+#define TZ_America_Manaus ("<-04>4")
+#define TZ_America_Marigot ("AST4")
+#define TZ_America_Martinique ("AST4")
+#define TZ_America_Matamoros ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Mazatlan ("MST7MDT,M4.1.0,M10.5.0")
+#define TZ_America_Menominee ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Merida ("CST6CDT,M4.1.0,M10.5.0")
+#define TZ_America_Metlakatla ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_Mexico_City ("CST6CDT,M4.1.0,M10.5.0")
+#define TZ_America_Miquelon ("<-03>3<-02>,M3.2.0,M11.1.0")
+#define TZ_America_Moncton ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_America_Monterrey ("CST6CDT,M4.1.0,M10.5.0")
+#define TZ_America_Montevideo ("<-03>3")
+#define TZ_America_Montreal ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Montserrat ("AST4")
+#define TZ_America_Nassau ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_New_York ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Nipigon ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Nome ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_Noronha ("<-02>2")
+#define TZ_America_North_Dakota_Beulah ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_North_Dakota_Center ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_North_Dakota_New_Salem ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Ojinaga ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_America_Panama ("EST5")
+#define TZ_America_Pangnirtung ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Paramaribo ("<-03>3")
+#define TZ_America_Phoenix ("MST7")
+#define TZ_America_PortmaumPrince ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Port_of_Spain ("AST4")
+#define TZ_America_Porto_Velho ("<-04>4")
+#define TZ_America_Puerto_Rico ("AST4")
+#define TZ_America_Punta_Arenas ("<-03>3")
+#define TZ_America_Rainy_River ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Rankin_Inlet ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Recife ("<-03>3")
+#define TZ_America_Regina ("CST6")
+#define TZ_America_Resolute ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Rio_Branco ("<-05>5")
+#define TZ_America_Santarem ("<-03>3")
+#define TZ_America_Santiago ("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
+#define TZ_America_Santo_Domingo ("AST4")
+#define TZ_America_Sao_Paulo ("<-03>3")
+#define TZ_America_Scoresbysund ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
+#define TZ_America_Sitka ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_St_Barthelemy ("AST4")
+#define TZ_America_St_Johns ("NST3:30NDT,M3.2.0,M11.1.0")
+#define TZ_America_St_Kitts ("AST4")
+#define TZ_America_St_Lucia ("AST4")
+#define TZ_America_St_Thomas ("AST4")
+#define TZ_America_St_Vincent ("AST4")
+#define TZ_America_Swift_Current ("CST6")
+#define TZ_America_Tegucigalpa ("CST6")
+#define TZ_America_Thule ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_America_Thunder_Bay ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Tijuana ("PST8PDT,M3.2.0,M11.1.0")
+#define TZ_America_Toronto ("EST5EDT,M3.2.0,M11.1.0")
+#define TZ_America_Tortola ("AST4")
+#define TZ_America_Vancouver ("PST8PDT,M3.2.0,M11.1.0")
+#define TZ_America_Whitehorse ("MST7")
+#define TZ_America_Winnipeg ("CST6CDT,M3.2.0,M11.1.0")
+#define TZ_America_Yakutat ("AKST9AKDT,M3.2.0,M11.1.0")
+#define TZ_America_Yellowknife ("MST7MDT,M3.2.0,M11.1.0")
+#define TZ_Antarctica_Casey ("<+11>-11")
+#define TZ_Antarctica_Davis ("<+07>-7")
+#define TZ_Antarctica_DumontDUrville ("<+10>-10")
+#define TZ_Antarctica_Macquarie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#define TZ_Antarctica_Mawson ("<+05>-5")
+#define TZ_Antarctica_McMurdo ("NZST-12NZDT,M9.5.0,M4.1.0/3")
+#define TZ_Antarctica_Palmer ("<-03>3")
+#define TZ_Antarctica_Rothera ("<-03>3")
+#define TZ_Antarctica_Syowa ("<+03>-3")
+#define TZ_Antarctica_Troll ("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
+#define TZ_Antarctica_Vostok ("<+06>-6")
+#define TZ_Arctic_Longyearbyen ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Asia_Aden ("<+03>-3")
+#define TZ_Asia_Almaty ("<+06>-6")
+#define TZ_Asia_Amman ("EET-2EEST,M3.5.4/24,M10.5.5/1")
+#define TZ_Asia_Anadyr ("<+12>-12")
+#define TZ_Asia_Aqtau ("<+05>-5")
+#define TZ_Asia_Aqtobe ("<+05>-5")
+#define TZ_Asia_Ashgabat ("<+05>-5")
+#define TZ_Asia_Atyrau ("<+05>-5")
+#define TZ_Asia_Baghdad ("<+03>-3")
+#define TZ_Asia_Bahrain ("<+03>-3")
+#define TZ_Asia_Baku ("<+04>-4")
+#define TZ_Asia_Bangkok ("<+07>-7")
+#define TZ_Asia_Barnaul ("<+07>-7")
+#define TZ_Asia_Beirut ("EET-2EEST,M3.5.0/0,M10.5.0/0")
+#define TZ_Asia_Bishkek ("<+06>-6")
+#define TZ_Asia_Brunei ("<+08>-8")
+#define TZ_Asia_Chita ("<+09>-9")
+#define TZ_Asia_Choibalsan ("<+08>-8")
+#define TZ_Asia_Colombo ("<+0530>-5:30")
+#define TZ_Asia_Damascus ("EET-2EEST,M3.5.5/0,M10.5.5/0")
+#define TZ_Asia_Dhaka ("<+06>-6")
+#define TZ_Asia_Dili ("<+09>-9")
+#define TZ_Asia_Dubai ("<+04>-4")
+#define TZ_Asia_Dushanbe ("<+05>-5")
+#define TZ_Asia_Famagusta ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Asia_Gaza ("EET-2EEST,M3.4.4/48,M10.4.4/49")
+#define TZ_Asia_Hebron ("EET-2EEST,M3.4.4/48,M10.4.4/49")
+#define TZ_Asia_Ho_Chi_Minh ("<+07>-7")
+#define TZ_Asia_Hong_Kong ("HKT-8")
+#define TZ_Asia_Hovd ("<+07>-7")
+#define TZ_Asia_Irkutsk ("<+08>-8")
+#define TZ_Asia_Jakarta ("WIB-7")
+#define TZ_Asia_Jayapura ("WIT-9")
+#define TZ_Asia_Jerusalem ("IST-2IDT,M3.4.4/26,M10.5.0")
+#define TZ_Asia_Kabul ("<+0430>-4:30")
+#define TZ_Asia_Kamchatka ("<+12>-12")
+#define TZ_Asia_Karachi ("PKT-5")
+#define TZ_Asia_Kathmandu ("<+0545>-5:45")
+#define TZ_Asia_Khandyga ("<+09>-9")
+#define TZ_Asia_Kolkata ("IST-5:30")
+#define TZ_Asia_Krasnoyarsk ("<+07>-7")
+#define TZ_Asia_Kuala_Lumpur ("<+08>-8")
+#define TZ_Asia_Kuching ("<+08>-8")
+#define TZ_Asia_Kuwait ("<+03>-3")
+#define TZ_Asia_Macau ("CST-8")
+#define TZ_Asia_Magadan ("<+11>-11")
+#define TZ_Asia_Makassar ("WITA-8")
+#define TZ_Asia_Manila ("PST-8")
+#define TZ_Asia_Muscat ("<+04>-4")
+#define TZ_Asia_Nicosia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Asia_Novokuznetsk ("<+07>-7")
+#define TZ_Asia_Novosibirsk ("<+07>-7")
+#define TZ_Asia_Omsk ("<+06>-6")
+#define TZ_Asia_Oral ("<+05>-5")
+#define TZ_Asia_Phnom_Penh ("<+07>-7")
+#define TZ_Asia_Pontianak ("WIB-7")
+#define TZ_Asia_Pyongyang ("KST-9")
+#define TZ_Asia_Qatar ("<+03>-3")
+#define TZ_Asia_Qyzylorda ("<+05>-5")
+#define TZ_Asia_Riyadh ("<+03>-3")
+#define TZ_Asia_Sakhalin ("<+11>-11")
+#define TZ_Asia_Samarkand ("<+05>-5")
+#define TZ_Asia_Seoul ("KST-9")
+#define TZ_Asia_Shanghai ("CST-8")
+#define TZ_Asia_Singapore ("<+08>-8")
+#define TZ_Asia_Srednekolymsk ("<+11>-11")
+#define TZ_Asia_Taipei ("CST-8")
+#define TZ_Asia_Tashkent ("<+05>-5")
+#define TZ_Asia_Tbilisi ("<+04>-4")
+#define TZ_Asia_Tehran ("<+0330>-3:30<+0430>,J79/24,J263/24")
+#define TZ_Asia_Thimphu ("<+06>-6")
+#define TZ_Asia_Tokyo ("JST-9")
+#define TZ_Asia_Tomsk ("<+07>-7")
+#define TZ_Asia_Ulaanbaatar ("<+08>-8")
+#define TZ_Asia_Urumqi ("<+06>-6")
+#define TZ_Asia_UstmNera ("<+10>-10")
+#define TZ_Asia_Vientiane ("<+07>-7")
+#define TZ_Asia_Vladivostok ("<+10>-10")
+#define TZ_Asia_Yakutsk ("<+09>-9")
+#define TZ_Asia_Yangon ("<+0630>-6:30")
+#define TZ_Asia_Yekaterinburg ("<+05>-5")
+#define TZ_Asia_Yerevan ("<+04>-4")
+#define TZ_Atlantic_Azores ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
+#define TZ_Atlantic_Bermuda ("AST4ADT,M3.2.0,M11.1.0")
+#define TZ_Atlantic_Canary ("WET0WEST,M3.5.0/1,M10.5.0")
+#define TZ_Atlantic_Cape_Verde ("<-01>1")
+#define TZ_Atlantic_Faroe ("WET0WEST,M3.5.0/1,M10.5.0")
+#define TZ_Atlantic_Madeira ("WET0WEST,M3.5.0/1,M10.5.0")
+#define TZ_Atlantic_Reykjavik ("GMT0")
+#define TZ_Atlantic_South_Georgia ("<-02>2")
+#define TZ_Atlantic_Stanley ("<-03>3")
+#define TZ_Atlantic_St_Helena ("GMT0")
+#define TZ_Australia_Adelaide ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
+#define TZ_Australia_Brisbane ("AEST-10")
+#define TZ_Australia_Broken_Hill ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
+#define TZ_Australia_Currie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#define TZ_Australia_Darwin ("ACST-9:30")
+#define TZ_Australia_Eucla ("<+0845>-8:45")
+#define TZ_Australia_Hobart ("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#define TZ_Australia_Lindeman ("AEST-10")
+#define TZ_Australia_Lord_Howe ("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
+#define TZ_Australia_Melbourne ("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#define TZ_Australia_Perth ("AWST-8")
+#define TZ_Australia_Sydney ("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#define TZ_Europe_Amsterdam ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Andorra ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Astrakhan ("<+04>-4")
+#define TZ_Europe_Athens ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Belgrade ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Berlin ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Bratislava ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Brussels ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Bucharest ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Budapest ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Busingen ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Chisinau ("EET-2EEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Copenhagen ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Dublin ("IST-1GMT0,M10.5.0,M3.5.0/1")
+#define TZ_Europe_Gibraltar ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Guernsey ("GMT0BST,M3.5.0/1,M10.5.0")
+#define TZ_Europe_Helsinki ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Isle_of_Man ("GMT0BST,M3.5.0/1,M10.5.0")
+#define TZ_Europe_Istanbul ("<+03>-3")
+#define TZ_Europe_Jersey ("GMT0BST,M3.5.0/1,M10.5.0")
+#define TZ_Europe_Kaliningrad ("EET-2")
+#define TZ_Europe_Kiev ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Kirov ("<+03>-3")
+#define TZ_Europe_Lisbon ("WET0WEST,M3.5.0/1,M10.5.0")
+#define TZ_Europe_Ljubljana ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_London ("GMT0BST,M3.5.0/1,M10.5.0")
+#define TZ_Europe_Luxembourg ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Madrid ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Malta ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Mariehamn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Minsk ("<+03>-3")
+#define TZ_Europe_Monaco ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Moscow ("MSK-3")
+#define TZ_Europe_Oslo ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Paris ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Podgorica ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Prague ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Riga ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Rome ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Samara ("<+04>-4")
+#define TZ_Europe_San_Marino ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Sarajevo ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Saratov ("<+04>-4")
+#define TZ_Europe_Simferopol ("MSK-3")
+#define TZ_Europe_Skopje ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Sofia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Stockholm ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Tallinn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Tirane ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Ulyanovsk ("<+04>-4")
+#define TZ_Europe_Uzhgorod ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Vaduz ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Vatican ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Vienna ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Vilnius ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Volgograd ("<+04>-4")
+#define TZ_Europe_Warsaw ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Zagreb ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Europe_Zaporozhye ("EET-2EEST,M3.5.0/3,M10.5.0/4")
+#define TZ_Europe_Zurich ("CET-1CEST,M3.5.0,M10.5.0/3")
+#define TZ_Indian_Antananarivo ("EAT-3")
+#define TZ_Indian_Chagos ("<+06>-6")
+#define TZ_Indian_Christmas ("<+07>-7")
+#define TZ_Indian_Cocos ("<+0630>-6:30")
+#define TZ_Indian_Comoro ("EAT-3")
+#define TZ_Indian_Kerguelen ("<+05>-5")
+#define TZ_Indian_Mahe ("<+04>-4")
+#define TZ_Indian_Maldives ("<+05>-5")
+#define TZ_Indian_Mauritius ("<+04>-4")
+#define TZ_Indian_Mayotte ("EAT-3")
+#define TZ_Indian_Reunion ("<+04>-4")
+#define TZ_Pacific_Apia ("<+13>-13<+14>,M9.5.0/3,M4.1.0/4")
+#define TZ_Pacific_Auckland ("NZST-12NZDT,M9.5.0,M4.1.0/3")
+#define TZ_Pacific_Bougainville ("<+11>-11")
+#define TZ_Pacific_Chatham ("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
+#define TZ_Pacific_Chuuk ("<+10>-10")
+#define TZ_Pacific_Easter ("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
+#define TZ_Pacific_Efate ("<+11>-11")
+#define TZ_Pacific_Enderbury ("<+13>-13")
+#define TZ_Pacific_Fakaofo ("<+13>-13")
+#define TZ_Pacific_Fiji ("<+12>-12<+13>,M11.2.0,M1.2.3/99")
+#define TZ_Pacific_Funafuti ("<+12>-12")
+#define TZ_Pacific_Galapagos ("<-06>6")
+#define TZ_Pacific_Gambier ("<-09>9")
+#define TZ_Pacific_Guadalcanal ("<+11>-11")
+#define TZ_Pacific_Guam ("ChST-10")
+#define TZ_Pacific_Honolulu ("HST10")
+#define TZ_Pacific_Kiritimati ("<+14>-14")
+#define TZ_Pacific_Kosrae ("<+11>-11")
+#define TZ_Pacific_Kwajalein ("<+12>-12")
+#define TZ_Pacific_Majuro ("<+12>-12")
+#define TZ_Pacific_Marquesas ("<-0930>9:30")
+#define TZ_Pacific_Midway ("SST11")
+#define TZ_Pacific_Nauru ("<+12>-12")
+#define TZ_Pacific_Niue ("<-11>11")
+#define TZ_Pacific_Norfolk ("<+11>-11<+12>,M10.1.0,M4.1.0/3")
+#define TZ_Pacific_Noumea ("<+11>-11")
+#define TZ_Pacific_Pago_Pago ("SST11")
+#define TZ_Pacific_Palau ("<+09>-9")
+#define TZ_Pacific_Pitcairn ("<-08>8")
+#define TZ_Pacific_Pohnpei ("<+11>-11")
+#define TZ_Pacific_Port_Moresby ("<+10>-10")
+#define TZ_Pacific_Rarotonga ("<-10>10")
+#define TZ_Pacific_Saipan ("ChST-10")
+#define TZ_Pacific_Tahiti ("<-10>10")
+#define TZ_Pacific_Tarawa ("<+12>-12")
+#define TZ_Pacific_Tongatapu ("<+13>-13")
+#define TZ_Pacific_Wake ("<+12>-12")
+#define TZ_Pacific_Wallis ("<+12>-12")
+#define TZ_Etc_GMT ("GMT0")
+#define TZ_Etc_GMTm0 ("GMT0")
+#define TZ_Etc_GMTm1 ("<+01>-1")
+#define TZ_Etc_GMTm2 ("<+02>-2")
+#define TZ_Etc_GMTm3 ("<+03>-3")
+#define TZ_Etc_GMTm4 ("<+04>-4")
+#define TZ_Etc_GMTm5 ("<+05>-5")
+#define TZ_Etc_GMTm6 ("<+06>-6")
+#define TZ_Etc_GMTm7 ("<+07>-7")
+#define TZ_Etc_GMTm8 ("<+08>-8")
+#define TZ_Etc_GMTm9 ("<+09>-9")
+#define TZ_Etc_GMTm10 ("<+10>-10")
+#define TZ_Etc_GMTm11 ("<+11>-11")
+#define TZ_Etc_GMTm12 ("<+12>-12")
+#define TZ_Etc_GMTm13 ("<+13>-13")
+#define TZ_Etc_GMTm14 ("<+14>-14")
+#define TZ_Etc_GMT0 ("GMT0")
+#define TZ_Etc_GMTp0 ("GMT0")
+#define TZ_Etc_GMTp1 ("<-01>1")
+#define TZ_Etc_GMTp2 ("<-02>2")
+#define TZ_Etc_GMTp3 ("<-03>3")
+#define TZ_Etc_GMTp4 ("<-04>4")
+#define TZ_Etc_GMTp5 ("<-05>5")
+#define TZ_Etc_GMTp6 ("<-06>6")
+#define TZ_Etc_GMTp7 ("<-07>7")
+#define TZ_Etc_GMTp8 ("<-08>8")
+#define TZ_Etc_GMTp9 ("<-09>9")
+#define TZ_Etc_GMTp10 ("<-10>10")
+#define TZ_Etc_GMTp11 ("<-11>11")
+#define TZ_Etc_GMTp12 ("<-12>12")
+#define TZ_Etc_UCT ("UTC0")
+#define TZ_Etc_UTC ("UTC0")
+#define TZ_Etc_Greenwich ("GMT0")
+#define TZ_Etc_Universal ("UTC0")
+#define TZ_Etc_Zulu ("UTC0")
+
+////////////////////////////////////////////////////////////
+
+#define TIMEZONE_MAX_LEN 50
+
+static const char TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
+{
+#if USING_AFRICA
+ "Africa/Abidjan", //PSTR("GMT0")
+ "Africa/Accra", //PSTR("GMT0")
+ "Africa/Addis_Ababa", //PSTR("EAT-3")
+ "Africa/Algiers", //PSTR("CET-1")
+ "Africa/Asmara", //PSTR("EAT-3")
+ "Africa/Bamako", //PSTR("GMT0")
+ "Africa/Bangui", //PSTR("WAT-1")
+ "Africa/Banjul", //PSTR("GMT0")
+ "Africa/Bissau", //PSTR("GMT0")
+ "Africa/Blantyre", //PSTR("CAT-2")
+ "Africa/Brazzaville", //PSTR("WAT-1")
+ "Africa/Bujumbura", //PSTR("CAT-2")
+ "Africa/Cairo", //PSTR("EET-2")
+ "Africa/Casablanca", //PSTR("<+01>-1")
+ "Africa/Ceuta", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Africa/Conakry", //PSTR("GMT0")
+ "Africa/Dakar", //PSTR("GMT0")
+ "Africa/Dar_es_Salaam", //PSTR("EAT-3")
+ "Africa/Djibouti", //PSTR("EAT-3")
+ "Africa/Douala", //PSTR("WAT-1")
+ "Africa/El_Aaiun", //PSTR("<+01>-1")
+ "Africa/Freetown", //PSTR("GMT0")
+ "Africa/Gaborone", //PSTR("CAT-2")
+ "Africa/Harare", //PSTR("CAT-2")
+ "Africa/Johannesburg", //PSTR("SAST-2")
+ "Africa/Juba", //PSTR("EAT-3")
+ "Africa/Kampala", //PSTR("EAT-3")
+ "Africa/Khartoum", //PSTR("CAT-2")
+ "Africa/Kigali", //PSTR("CAT-2")
+ "Africa/Kinshasa", //PSTR("WAT-1")
+ "Africa/Lagos", //PSTR("WAT-1")
+ "Africa/Libreville", //PSTR("WAT-1")
+ "Africa/Lome", //PSTR("GMT0")
+ "Africa/Luanda", //PSTR("WAT-1")
+ "Africa/Lubumbashi", //PSTR("CAT-2")
+ "Africa/Lusaka", //PSTR("CAT-2")
+ "Africa/Malabo", //PSTR("WAT-1")
+ "Africa/Maputo", //PSTR("CAT-2")
+ "Africa/Maseru", //PSTR("SAST-2")
+ "Africa/Mbabane", //PSTR("SAST-2")
+ "Africa/Mogadishu", //PSTR("EAT-3")
+ "Africa/Monrovia", //PSTR("GMT0")
+ "Africa/Nairobi", //PSTR("EAT-3")
+ "Africa/Ndjamena", //PSTR("WAT-1")
+ "Africa/Niamey", //PSTR("WAT-1")
+ "Africa/Nouakchott", //PSTR("GMT0")
+ "Africa/Ouagadougou", //PSTR("GMT0")
+ "Africa/PortomNovo", //PSTR("WAT-1")
+ "Africa/Sao_Tome", //PSTR("GMT0")
+ "Africa/Tripoli", //PSTR("EET-2")
+ "Africa/Tunis", //PSTR("CET-1")
+ "Africa/Windhoek", //PSTR("CAT-2")
+#endif
+
+
+#if USING_AMERICA
+ "America/Adak", //PSTR("HST10HDT",M3.2.0",M11.1.0")
+ "America/Anchorage", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/Anguilla", //PSTR("AST4")
+ "America/Antigua", //PSTR("AST4")
+ "America/Araguaina", //PSTR("<-03>3")
+ "America/Argentina/Buenos_Aires", //PSTR("<-03>3")
+ "America/Argentina/Catamarca", //PSTR("<-03>3")
+ "America/Argentina/Cordoba", //PSTR("<-03>3")
+ "America/Argentina/Jujuy", //PSTR("<-03>3")
+ "America/Argentina/La_Rioja", //PSTR("<-03>3")
+ "America/Argentina/Mendoza", //PSTR("<-03>3")
+ "America/Argentina/Rio_Gallegos", //PSTR("<-03>3")
+ "America/Argentina/Salta", //PSTR("<-03>3")
+ "America/Argentina/San_Juan", //PSTR("<-03>3")
+ "America/Argentina/San_Luis", //PSTR("<-03>3")
+ "America/Argentina/Tucuman", //PSTR("<-03>3")
+ "America/Argentina/Ushuaia", //PSTR("<-03>3")
+ "America/Aruba", //PSTR("AST4")
+ "America/Asuncion", //PSTR("<-04>4<-03>",M10.1.0/0",M3.4.0/0")
+ "America/Atikokan", //PSTR("EST5")
+ "America/Bahia", //PSTR("<-03>3")
+ "America/Bahia_Banderas", //PSTR("CST6CDT",M4.1.0",M10.5.0")
+ "America/Barbados", //PSTR("AST4")
+ "America/Belem", //PSTR("<-03>3")
+ "America/Belize", //PSTR("CST6")
+ "America/BlancmSablon", //PSTR("AST4")
+ "America/Boa_Vista", //PSTR("<-04>4")
+ "America/Bogota", //PSTR("<-05>5")
+ "America/Boise", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Cambridge_Bay", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Campo_Grande", //PSTR("<-04>4")
+ "America/Cancun", //PSTR("EST5")
+ "America/Caracas", //PSTR("<-04>4")
+ "America/Cayenne", //PSTR("<-03>3")
+ "America/Cayman", //PSTR("EST5")
+ "America/Chicago", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Chihuahua", //PSTR("MST7MDT",M4.1.0",M10.5.0")
+ "America/Costa_Rica", //PSTR("CST6")
+ "America/Creston", //PSTR("MST7")
+ "America/Cuiaba", //PSTR("<-04>4")
+ "America/Curacao", //PSTR("AST4")
+ "America/Danmarkshavn", //PSTR("GMT0")
+ "America/Dawson", //PSTR("MST7")
+ "America/Dawson_Creek", //PSTR("MST7")
+ "America/Denver", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Detroit", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Dominica", //PSTR("AST4")
+ "America/Edmonton", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Eirunepe", //PSTR("<-05>5")
+ "America/El_Salvador", //PSTR("CST6")
+ "America/Fortaleza", //PSTR("<-03>3")
+ "America/Fort_Nelson", //PSTR("MST7")
+ "America/Glace_Bay", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "America/Godthab", //PSTR("<-03>3<-02>",M3.5.0/-2",M10.5.0/-1")
+ "America/Goose_Bay", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "America/Grand_Turk", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Grenada", //PSTR("AST4")
+ "America/Guadeloupe", //PSTR("AST4")
+ "America/Guatemala", //PSTR("CST6")
+ "America/Guayaquil", //PSTR("<-05>5")
+ "America/Guyana", //PSTR("<-04>4")
+ "America/Halifax", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "America/Havana", //PSTR("CST5CDT",M3.2.0/0",M11.1.0/1")
+ "America/Hermosillo", //PSTR("MST7")
+ "America/Indiana_Indianapolis", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Indiana_Knox", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Indiana_Marengo", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Indiana_Petersburg", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Indiana_Tell_City", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Indiana_Vevay", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Indiana_Vincennes", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Indiana_Winamac", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Inuvik", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Iqaluit", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Jamaica", //PSTR("EST5")
+ "America/Juneau", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/Kentucky_Louisville", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Kentucky_Monticello", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Kralendijk", //PSTR("AST4")
+ "America/La_Paz", //PSTR("<-04>4")
+ "America/Lima", //PSTR("<-05>5")
+ "America/Los_Angeles", //PSTR("PST8PDT",M3.2.0",M11.1.0")
+ "America/Lower_Princes", //PSTR("AST4")
+ "America/Maceio", //PSTR("<-03>3")
+ "America/Managua", //PSTR("CST6")
+ "America/Manaus", //PSTR("<-04>4")
+ "America/Marigot", //PSTR("AST4")
+ "America/Martinique", //PSTR("AST4")
+ "America/Matamoros", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Mazatlan", //PSTR("MST7MDT",M4.1.0",M10.5.0")
+ "America/Menominee", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Merida", //PSTR("CST6CDT",M4.1.0",M10.5.0")
+ "America/Metlakatla", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/Mexico_City", //PSTR("CST6CDT",M4.1.0",M10.5.0")
+ "America/Miquelon", //PSTR("<-03>3<-02>",M3.2.0",M11.1.0")
+ "America/Moncton", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "America/Monterrey", //PSTR("CST6CDT",M4.1.0",M10.5.0")
+ "America/Montevideo", //PSTR("<-03>3")
+ "America/Montreal", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Montserrat", //PSTR("AST4")
+ "America/Nassau", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/New_York", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Nipigon", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Nome", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/Noronha", //PSTR("<-02>2")
+ "America/North_Dakota_Beulah", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/North_Dakota_Center", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/North_Dakota_New_Salem", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Ojinaga", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+ "America/Panama", //PSTR("EST5")
+ "America/Pangnirtung", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Paramaribo", //PSTR("<-03>3")
+ "America/Phoenix", //PSTR("MST7")
+ "America/PortmaumPrince", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Port_of_Spain", //PSTR("AST4")
+ "America/Porto_Velho", //PSTR("<-04>4")
+ "America/Puerto_Rico", //PSTR("AST4")
+ "America/Punta_Arenas", //PSTR("<-03>3")
+ "America/Rainy_River", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Rankin_Inlet", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Recife", //PSTR("<-03>3")
+ "America/Regina", //PSTR("CST6")
+ "America/Resolute", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Rio_Branco", //PSTR("<-05>5")
+ "America/Santarem", //PSTR("<-03>3")
+ "America/Santiago", //PSTR("<-04>4<-03>",M9.1.6/24",M4.1.6/24")
+ "America/Santo_Domingo", //PSTR("AST4")
+ "America/Sao_Paulo", //PSTR("<-03>3")
+ "America/Scoresbysund", //PSTR("<-01>1<+00>",M3.5.0/0",M10.5.0/1")
+ "America/Sitka", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/St_Barthelemy", //PSTR("AST4")
+ "America/St_Johns", //PSTR("NST3:30NDT",M3.2.0",M11.1.0")
+ "America/St_Kitts", //PSTR("AST4")
+ "America/St_Lucia", //PSTR("AST4")
+ "America/St_Thomas", //PSTR("AST4")
+ "America/St_Vincent", //PSTR("AST4")
+ "America/Swift_Current", //PSTR("CST6")
+ "America/Tegucigalpa", //PSTR("CST6")
+ "America/Thule", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "America/Thunder_Bay", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Tijuana", //PSTR("PST8PDT",M3.2.0",M11.1.0")
+ "America/Toronto", //PSTR("EST5EDT",M3.2.0",M11.1.0")
+ "America/Tortola", //PSTR("AST4")
+ "America/Vancouver", //PSTR("PST8PDT",M3.2.0",M11.1.0")
+ "America/Whitehorse", //PSTR("MST7")
+ "America/Winnipeg", //PSTR("CST6CDT",M3.2.0",M11.1.0")
+ "America/Yakutat", //PSTR("AKST9AKDT",M3.2.0",M11.1.0")
+ "America/Yellowknife", //PSTR("MST7MDT",M3.2.0",M11.1.0")
+#endif
+
+#if USING_ANTARCTICA
+ "Antarctica/Casey", //PSTR("<+11>-11")
+ "Antarctica/Davis", //PSTR("<+07>-7")
+ "Antarctica/DumontDUrville", //PSTR("<+10>-10")
+ "Antarctica/Macquarie", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3")
+ "Antarctica/Mawson", //PSTR("<+05>-5")
+ "Antarctica/McMurdo", //PSTR("NZST-12NZDT",M9.5.0",M4.1.0/3")
+ "Antarctica/Palmer", //PSTR("<-03>3")
+ "Antarctica/Rothera", //PSTR("<-03>3")
+ "Antarctica/Syowa", //PSTR("<+03>-3")
+ "Antarctica/Troll", //PSTR("<+00>0<+02>-2",M3.5.0/1",M10.5.0/3")
+ "Antarctica/Vostok", //PSTR("<+06>-6")
+ "Arctic/Longyearbyen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+#endif
+
+#if USING_ASIA
+ "Asia/Aden", //PSTR("<+03>-3")
+ "Asia/Almaty", //PSTR("<+06>-6")
+ "Asia/Amman", //PSTR("EET-2EEST",M3.5.4/24",M10.5.5/1")
+ "Asia/Anadyr", //PSTR("<+12>-12")
+ "Asia/Aqtau", //PSTR("<+05>-5")
+ "Asia/Aqtobe", //PSTR("<+05>-5")
+ "Asia/Ashgabat", //PSTR("<+05>-5")
+ "Asia/Atyrau", //PSTR("<+05>-5")
+ "Asia/Baghdad", //PSTR("<+03>-3")
+ "Asia/Bahrain", //PSTR("<+03>-3")
+ "Asia/Baku", //PSTR("<+04>-4")
+ "Asia/Bangkok", //PSTR("<+07>-7")
+ "Asia/Barnaul", //PSTR("<+07>-7")
+ "Asia/Beirut", //PSTR("EET-2EEST",M3.5.0/0",M10.5.0/0")
+ "Asia/Bishkek", //PSTR("<+06>-6")
+ "Asia/Brunei", //PSTR("<+08>-8")
+ "Asia/Chita", //PSTR("<+09>-9")
+ "Asia/Choibalsan", //PSTR("<+08>-8")
+ "Asia/Colombo", //PSTR("<+0530>-5:30")
+ "Asia/Damascus", //PSTR("EET-2EEST",M3.5.5/0",M10.5.5/0")
+ "Asia/Dhaka", //PSTR("<+06>-6")
+ "Asia/Dili", //PSTR("<+09>-9")
+ "Asia/Dubai", //PSTR("<+04>-4")
+ "Asia/Dushanbe", //PSTR("<+05>-5")
+ "Asia/Famagusta", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Asia/Gaza", //PSTR("EET-2EEST",M3.4.4/48",M10.4.4/49")
+ "Asia/Hebron", //PSTR("EET-2EEST",M3.4.4/48",M10.4.4/49")
+ "Asia/Ho_Chi_Minh", //PSTR("<+07>-7")
+ "Asia/Hong_Kong", //PSTR("HKT-8")
+ "Asia/Hovd", //PSTR("<+07>-7")
+ "Asia/Irkutsk", //PSTR("<+08>-8")
+ "Asia/Jakarta", //PSTR("WIB-7")
+ "Asia/Jayapura", //PSTR("WIT-9")
+ "Asia/Jerusalem", //PSTR("IST-2IDT",M3.4.4/26",M10.5.0")
+ "Asia/Kabul", //PSTR("<+0430>-4:30")
+ "Asia/Kamchatka", //PSTR("<+12>-12")
+ "Asia/Karachi", //PSTR("PKT-5")
+ "Asia/Kathmandu", //PSTR("<+0545>-5:45")
+ "Asia/Khandyga", //PSTR("<+09>-9")
+ "Asia/Kolkata", //PSTR("IST-5:30")
+ "Asia/Krasnoyarsk", //PSTR("<+07>-7")
+ "Asia/Kuala_Lumpur", //PSTR("<+08>-8")
+ "Asia/Kuching", //PSTR("<+08>-8")
+ "Asia/Kuwait", //PSTR("<+03>-3")
+ "Asia/Macau", //PSTR("CST-8")
+ "Asia/Magadan", //PSTR("<+11>-11")
+ "Asia/Makassar", //PSTR("WITA-8")
+ "Asia/Manila", //PSTR("PST-8")
+ "Asia/Muscat", //PSTR("<+04>-4")
+ "Asia/Nicosia", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Asia/Novokuznetsk", //PSTR("<+07>-7")
+ "Asia/Novosibirsk", //PSTR("<+07>-7")
+ "Asia/Omsk", //PSTR("<+06>-6")
+ "Asia/Oral", //PSTR("<+05>-5")
+ "Asia/Phnom_Penh", //PSTR("<+07>-7")
+ "Asia/Pontianak", //PSTR("WIB-7")
+ "Asia/Pyongyang", //PSTR("KST-9")
+ "Asia/Qatar", //PSTR("<+03>-3")
+ "Asia/Qyzylorda", //PSTR("<+05>-5")
+ "Asia/Riyadh", //PSTR("<+03>-3")
+ "Asia/Sakhalin", //PSTR("<+11>-11")
+ "Asia/Samarkand", //PSTR("<+05>-5")
+ "Asia/Seoul", //PSTR("KST-9")
+ "Asia/Shanghai", //PSTR("CST-8")
+ "Asia/Singapore", //PSTR("<+08>-8")
+ "Asia/Srednekolymsk", //PSTR("<+11>-11")
+ "Asia/Taipei", //PSTR("CST-8")
+ "Asia/Tashkent", //PSTR("<+05>-5")
+ "Asia/Tbilisi", //PSTR("<+04>-4")
+ "Asia/Tehran", //PSTR("<+0330>-3:30<+0430>",J79/24",J263/24")
+ "Asia/Thimphu", //PSTR("<+06>-6")
+ "Asia/Tokyo", //PSTR("JST-9")
+ "Asia/Tomsk", //PSTR("<+07>-7")
+ "Asia/Ulaanbaatar", //PSTR("<+08>-8")
+ "Asia/Urumqi", //PSTR("<+06>-6")
+ "Asia/UstmNera", //PSTR("<+10>-10")
+ "Asia/Vientiane", //PSTR("<+07>-7")
+ "Asia/Vladivostok", //PSTR("<+10>-10")
+ "Asia/Yakutsk", //PSTR("<+09>-9")
+ "Asia/Yangon", //PSTR("<+0630>-6:30")
+ "Asia/Yekaterinburg", //PSTR("<+05>-5")
+ "Asia/Yerevan", //PSTR("<+04>-4")
+#endif
+
+#if USING_ATLANTIC
+ "Atlantic/Azores", //PSTR("<-01>1<+00>",M3.5.0/0",M10.5.0/1")
+ "Atlantic/Bermuda", //PSTR("AST4ADT",M3.2.0",M11.1.0")
+ "Atlantic/Canary", //PSTR("WET0WEST",M3.5.0/1",M10.5.0")
+ "Atlantic/Cape_Verde", //PSTR("<-01>1")
+ "Atlantic/Faroe", //PSTR("WET0WEST",M3.5.0/1",M10.5.0")
+ "Atlantic/Madeira", //PSTR("WET0WEST",M3.5.0/1",M10.5.0")
+ "Atlantic/Reykjavik", //PSTR("GMT0")
+ "Atlantic/South_Georgia", //PSTR("<-02>2")
+ "Atlantic/Stanley", //PSTR("<-03>3")
+ "Atlantic/St_Helena", //PSTR("GMT0")
+#endif
+
+#if USING_AUSTRALIA
+ "Australia/Adelaide", //PSTR("ACST-9:30ACDT",M10.1.0",M4.1.0/3")
+ "Australia/Brisbane", //PSTR("AEST-10")
+ "Australia/Broken_Hill", //PSTR("ACST-9:30ACDT",M10.1.0",M4.1.0/3")
+ "Australia/Currie", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3")
+ "Australia/Darwin", //PSTR("ACST-9:30")
+ "Australia/Eucla", //PSTR("<+0845>-8:45")
+ "Australia/Hobart", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3")
+ "Australia/Lindeman", //PSTR("AEST-10")
+ "Australia/Lord_Howe", //PSTR("<+1030>-10:30<+11>-11",M10.1.0",M4.1.0")
+ "Australia/Melbourne", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3")
+ "Australia/Perth", //PSTR("AWST-8")
+ "Australia/Sydney", //PSTR("AEST-10AEDT",M10.1.0",M4.1.0/3")
+#endif
+
+#if USING_EUROPE
+ "Europe/Amsterdam", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Andorra", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Astrakhan", //PSTR("<+04>-4")
+ "Europe/Athens", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Belgrade", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Berlin", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Bratislava", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Brussels", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Bucharest", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Budapest", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Busingen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Chisinau", //PSTR("EET-2EEST",M3.5.0",M10.5.0/3")
+ "Europe/Copenhagen", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Dublin", //PSTR("IST-1GMT0",M10.5.0",M3.5.0/1")
+ "Europe/Gibraltar", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Guernsey", //PSTR("GMT0BST",M3.5.0/1",M10.5.0")
+ "Europe/Helsinki", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Isle_of_Man", //PSTR("GMT0BST",M3.5.0/1",M10.5.0")
+ "Europe/Istanbul", //PSTR("<+03>-3")
+ "Europe/Jersey", //PSTR("GMT0BST",M3.5.0/1",M10.5.0")
+ "Europe/Kaliningrad", //PSTR("EET-2")
+ "Europe/Kiev", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Kirov", //PSTR("<+03>-3")
+ "Europe/Lisbon", //PSTR("WET0WEST",M3.5.0/1",M10.5.0")
+ "Europe/Ljubljana", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/London", //PSTR("GMT0BST",M3.5.0/1",M10.5.0")
+ "Europe/Luxembourg", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Madrid", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Malta", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Mariehamn", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Minsk", //PSTR("<+03>-3")
+ "Europe/Monaco", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Moscow", //PSTR("MSK-3")
+ "Europe/Oslo", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Paris", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Podgorica", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Prague", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Riga", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Rome", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Samara", //PSTR("<+04>-4")
+ "Europe/San_Marino", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Sarajevo", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Saratov", //PSTR("<+04>-4")
+ "Europe/Simferopol", //PSTR("MSK-3")
+ "Europe/Skopje", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Sofia", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Stockholm", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Tallinn", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Tirane", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Ulyanovsk", //PSTR("<+04>-4")
+ "Europe/Uzhgorod", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Vaduz", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Vatican", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Vienna", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Vilnius", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Volgograd", //PSTR("<+04>-4")
+ "Europe/Warsaw", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Zagreb", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+ "Europe/Zaporozhye", //PSTR("EET-2EEST",M3.5.0/3",M10.5.0/4")
+ "Europe/Zurich", //PSTR("CET-1CEST",M3.5.0",M10.5.0/3")
+#endif
+
+#if USING_INDIAN
+ "Indian/Antananarivo", //PSTR("EAT-3")
+ "Indian/Chagos", //PSTR("<+06>-6")
+ "Indian/Christmas", //PSTR("<+07>-7")
+ "Indian/Cocos", //PSTR("<+0630>-6:30")
+ "Indian/Comoro", //PSTR("EAT-3")
+ "Indian/Kerguelen", //PSTR("<+05>-5")
+ "Indian/Mahe", //PSTR("<+04>-4")
+ "Indian/Maldives", //PSTR("<+05>-5")
+ "Indian/Mauritius", //PSTR("<+04>-4")
+ "Indian/Mayotte", //PSTR("EAT-3")
+ "Indian/Reunion", //PSTR("<+04>-4")
+#endif
+
+#if USING_PACIFIC
+ "Pacific/Apia", //PSTR("<+13>-13<+14>",M9.5.0/3",M4.1.0/4")
+ "Pacific/Auckland", //PSTR("NZST-12NZDT",M9.5.0",M4.1.0/3")
+ "Pacific/Bougainville", //PSTR("<+11>-11")
+ "Pacific/Chatham", //PSTR("<+1245>-12:45<+1345>",M9.5.0/2:45",M4.1.0/3:45")
+ "Pacific/Chuuk", //PSTR("<+10>-10")
+ "Pacific/Easter", //PSTR("<-06>6<-05>",M9.1.6/22",M4.1.6/22")
+ "Pacific/Efate", //PSTR("<+11>-11")
+ "Pacific/Enderbury", //PSTR("<+13>-13")
+ "Pacific/Fakaofo", //PSTR("<+13>-13")
+ "Pacific/Fiji", //PSTR("<+12>-12<+13>",M11.2.0",M1.2.3/99")
+ "Pacific/Funafuti", //PSTR("<+12>-12")
+ "Pacific/Galapagos", //PSTR("<-06>6")
+ "Pacific/Gambier", //PSTR("<-09>9")
+ "Pacific/Guadalcanal", //PSTR("<+11>-11")
+ "Pacific/Guam", //PSTR("ChST-10")
+ "Pacific/Honolulu", //PSTR("HST10")
+ "Pacific/Kiritimati", //PSTR("<+14>-14")
+ "Pacific/Kosrae", //PSTR("<+11>-11")
+ "Pacific/Kwajalein", //PSTR("<+12>-12")
+ "Pacific/Majuro", //PSTR("<+12>-12")
+ "Pacific/Marquesas", //PSTR("<-0930>9:30")
+ "Pacific/Midway", //PSTR("SST11")
+ "Pacific/Nauru", //PSTR("<+12>-12")
+ "Pacific/Niue", //PSTR("<-11>11")
+ "Pacific/Norfolk", //PSTR("<+11>-11<+12>",M10.1.0",M4.1.0/3")
+ "Pacific/Noumea", //PSTR("<+11>-11")
+ "Pacific/Pago_Pago", //PSTR("SST11")
+ "Pacific/Palau", //PSTR("<+09>-9")
+ "Pacific/Pitcairn", //PSTR("<-08>8")
+ "Pacific/Pohnpei", //PSTR("<+11>-11")
+ "Pacific/Port_Moresby", //PSTR("<+10>-10")
+ "Pacific/Rarotonga", //PSTR("<-10>10")
+ "Pacific/Saipan", //PSTR("ChST-10")
+ "Pacific/Tahiti", //PSTR("<-10>10")
+ "Pacific/Tarawa", //PSTR("<+12>-12")
+ "Pacific/Tongatapu", //PSTR("<+13>-13")
+ "Pacific/Wake", //PSTR("<+12>-12")
+ "Pacific/Wallis", //PSTR("<+12>-12")
+#endif
+
+#if USING_ETC_GMT
+ "Etc/GMT", //PSTR("GMT0")
+ "Etc/GMTm0", //PSTR("GMT0")
+ "Etc/GMTm1", //PSTR("<+01>-1")
+ "Etc/GMTm2", //PSTR("<+02>-2")
+ "Etc/GMTm3", //PSTR("<+03>-3")
+ "Etc/GMTm4", //PSTR("<+04>-4")
+ "Etc/GMTm5", //PSTR("<+05>-5")
+ "Etc/GMTm6", //PSTR("<+06>-6")
+ "Etc/GMTm7", //PSTR("<+07>-7")
+ "Etc/GMTm8", //PSTR("<+08>-8")
+ "Etc/GMTm9", //PSTR("<+09>-9")
+ "Etc/GMTm10", //PSTR("<+10>-10")
+ "Etc/GMTm11", //PSTR("<+11>-11")
+ "Etc/GMTm12", //PSTR("<+12>-12")
+ "Etc/GMTm13", //PSTR("<+13>-13")
+ "Etc/GMTm14", //PSTR("<+14>-14")
+ "Etc/GMT0", //PSTR("GMT0")
+ "Etc/GMTp0", //PSTR("GMT0")
+ "Etc/GMTp1", //PSTR("<-01>1")
+ "Etc/GMTp2", //PSTR("<-02>2")
+ "Etc/GMTp3", //PSTR("<-03>3")
+ "Etc/GMTp4", //PSTR("<-04>4")
+ "Etc/GMTp5", //PSTR("<-05>5")
+ "Etc/GMTp6", //PSTR("<-06>6")
+ "Etc/GMTp7", //PSTR("<-07>7")
+ "Etc/GMTp8", //PSTR("<-08>8")
+ "Etc/GMTp9", //PSTR("<-09>9")
+ "Etc/GMTp10", //PSTR("<-10>10")
+ "Etc/GMTp11", //PSTR("<-11>11")
+ "Etc/GMTp12", //PSTR("<-12>12")
+ "Etc/UCT", //PSTR("UTC0")
+ "Etc/UTC", //PSTR("UTC0")
+ "Etc/Greenwich", //PSTR("GMT0")
+ "Etc/Universal", //PSTR("UTC0")
+ "Etc/Zulu", //PSTR("UTC0")
+#endif
+};
+
+////////////////////////////////////////////////////////////
+
+static const char ESP_TZ_NAME[][TIMEZONE_MAX_LEN] /*PROGMEM*/ =
+{
+#if USING_AFRICA
+ TZ_Africa_Abidjan, //PSTR("GMT0")
+ TZ_Africa_Accra, //PSTR("GMT0")
+ TZ_Africa_Addis_Ababa, //PSTR("EAT-3")
+ TZ_Africa_Algiers, //PSTR("CET-1")
+ TZ_Africa_Asmara, //PSTR("EAT-3")
+ TZ_Africa_Bamako, //PSTR("GMT0")
+ TZ_Africa_Bangui, //PSTR("WAT-1")
+ TZ_Africa_Banjul, //PSTR("GMT0")
+ TZ_Africa_Bissau, //PSTR("GMT0")
+ TZ_Africa_Blantyre, //PSTR("CAT-2")
+ TZ_Africa_Brazzaville, //PSTR("WAT-1")
+ TZ_Africa_Bujumbura, //PSTR("CAT-2")
+ TZ_Africa_Cairo, //PSTR("EET-2")
+ TZ_Africa_Casablanca, //PSTR("<+01>-1")
+ TZ_Africa_Ceuta, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Africa_Conakry, //PSTR("GMT0")
+ TZ_Africa_Dakar, //PSTR("GMT0")
+ TZ_Africa_Dar_es_Salaam, //PSTR("EAT-3")
+ TZ_Africa_Djibouti, //PSTR("EAT-3")
+ TZ_Africa_Douala, //PSTR("WAT-1")
+ TZ_Africa_El_Aaiun, //PSTR("<+01>-1")
+ TZ_Africa_Freetown, //PSTR("GMT0")
+ TZ_Africa_Gaborone, //PSTR("CAT-2")
+ TZ_Africa_Harare, //PSTR("CAT-2")
+ TZ_Africa_Johannesburg, //PSTR("SAST-2")
+ TZ_Africa_Juba, //PSTR("EAT-3")
+ TZ_Africa_Kampala, //PSTR("EAT-3")
+ TZ_Africa_Khartoum, //PSTR("CAT-2")
+ TZ_Africa_Kigali, //PSTR("CAT-2")
+ TZ_Africa_Kinshasa, //PSTR("WAT-1")
+ TZ_Africa_Lagos, //PSTR("WAT-1")
+ TZ_Africa_Libreville, //PSTR("WAT-1")
+ TZ_Africa_Lome, //PSTR("GMT0")
+ TZ_Africa_Luanda, //PSTR("WAT-1")
+ TZ_Africa_Lubumbashi, //PSTR("CAT-2")
+ TZ_Africa_Lusaka, //PSTR("CAT-2")
+ TZ_Africa_Malabo, //PSTR("WAT-1")
+ TZ_Africa_Maputo, //PSTR("CAT-2")
+ TZ_Africa_Maseru, //PSTR("SAST-2")
+ TZ_Africa_Mbabane, //PSTR("SAST-2")
+ TZ_Africa_Mogadishu, //PSTR("EAT-3")
+ TZ_Africa_Monrovia, //PSTR("GMT0")
+ TZ_Africa_Nairobi, //PSTR("EAT-3")
+ TZ_Africa_Ndjamena, //PSTR("WAT-1")
+ TZ_Africa_Niamey, //PSTR("WAT-1")
+ TZ_Africa_Nouakchott, //PSTR("GMT0")
+ TZ_Africa_Ouagadougou, //PSTR("GMT0")
+ TZ_Africa_PortomNovo, //PSTR("WAT-1")
+ TZ_Africa_Sao_Tome, //PSTR("GMT0")
+ TZ_Africa_Tripoli, //PSTR("EET-2")
+ TZ_Africa_Tunis, //PSTR("CET-1")
+ TZ_Africa_Windhoek, //PSTR("CAT-2")
+#endif
+
+#if USING_AMERICA
+ TZ_America_Adak, //PSTR("HST10HDT,M3.2.0,M11.1.0")
+ TZ_America_Anchorage, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_Anguilla, //PSTR("AST4")
+ TZ_America_Antigua, //PSTR("AST4")
+ TZ_America_Araguaina, //PSTR("<-03>3")
+ TZ_America_Argentina_Buenos_Aires, //PSTR("<-03>3")
+ TZ_America_Argentina_Catamarca, //PSTR("<-03>3")
+ TZ_America_Argentina_Cordoba, //PSTR("<-03>3")
+ TZ_America_Argentina_Jujuy, //PSTR("<-03>3")
+ TZ_America_Argentina_La_Rioja, //PSTR("<-03>3")
+ TZ_America_Argentina_Mendoza, //PSTR("<-03>3")
+ TZ_America_Argentina_Rio_Gallegos, //PSTR("<-03>3")
+ TZ_America_Argentina_Salta, //PSTR("<-03>3")
+ TZ_America_Argentina_San_Juan, //PSTR("<-03>3")
+ TZ_America_Argentina_San_Luis, //PSTR("<-03>3")
+ TZ_America_Argentina_Tucuman, //PSTR("<-03>3")
+ TZ_America_Argentina_Ushuaia, //PSTR("<-03>3")
+ TZ_America_Aruba, //PSTR("AST4")
+ TZ_America_Asuncion, //PSTR("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
+ TZ_America_Atikokan, //PSTR("EST5")
+ TZ_America_Bahia, //PSTR("<-03>3")
+ TZ_America_Bahia_Banderas, //PSTR("CST6CDT,M4.1.0,M10.5.0")
+ TZ_America_Barbados, //PSTR("AST4")
+ TZ_America_Belem, //PSTR("<-03>3")
+ TZ_America_Belize, //PSTR("CST6")
+ TZ_America_BlancmSablon, //PSTR("AST4")
+ TZ_America_Boa_Vista, //PSTR("<-04>4")
+ TZ_America_Bogota, //PSTR("<-05>5")
+ TZ_America_Boise, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Cambridge_Bay, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Campo_Grande, //PSTR("<-04>4")
+ TZ_America_Cancun, //PSTR("EST5")
+ TZ_America_Caracas, //PSTR("<-04>4")
+ TZ_America_Cayenne, //PSTR("<-03>3")
+ TZ_America_Cayman, //PSTR("EST5")
+ TZ_America_Chicago, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Chihuahua, //PSTR("MST7MDT,M4.1.0,M10.5.0")
+ TZ_America_Costa_Rica, //PSTR("CST6")
+ TZ_America_Creston, //PSTR("MST7")
+ TZ_America_Cuiaba, //PSTR("<-04>4")
+ TZ_America_Curacao, //PSTR("AST4")
+ TZ_America_Danmarkshavn, //PSTR("GMT0")
+ TZ_America_Dawson, //PSTR("MST7")
+ TZ_America_Dawson_Creek, //PSTR("MST7")
+ TZ_America_Denver, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Detroit, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Dominica, //PSTR("AST4")
+ TZ_America_Edmonton, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Eirunepe, //PSTR("<-05>5")
+ TZ_America_El_Salvador, //PSTR("CST6")
+ TZ_America_Fortaleza, //PSTR("<-03>3")
+ TZ_America_Fort_Nelson, //PSTR("MST7")
+ TZ_America_Glace_Bay, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_America_Godthab, //PSTR("<-03>3<-02>,M3.5.0/-2,M10.5.0/-1")
+ TZ_America_Goose_Bay, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_America_Grand_Turk, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Grenada, //PSTR("AST4")
+ TZ_America_Guadeloupe, //PSTR("AST4")
+ TZ_America_Guatemala, //PSTR("CST6")
+ TZ_America_Guayaquil, //PSTR("<-05>5")
+ TZ_America_Guyana, //PSTR("<-04>4")
+ TZ_America_Halifax, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_America_Havana, //PSTR("CST5CDT,M3.2.0/0,M11.1.0/1")
+ TZ_America_Hermosillo, //PSTR("MST7")
+ TZ_America_Indiana_Indianapolis, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Knox, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Marengo, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Petersburg, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Tell_City, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Vevay, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Vincennes, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Indiana_Winamac, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Inuvik, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Iqaluit, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Jamaica, //PSTR("EST5")
+ TZ_America_Juneau, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_Kentucky_Louisville, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Kentucky_Monticello, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Kralendijk, //PSTR("AST4")
+ TZ_America_La_Paz, //PSTR("<-04>4")
+ TZ_America_Lima, //PSTR("<-05>5")
+ TZ_America_Los_Angeles, //PSTR("PST8PDT,M3.2.0,M11.1.0")
+ TZ_America_Lower_Princes, //PSTR("AST4")
+ TZ_America_Maceio, //PSTR("<-03>3")
+ TZ_America_Managua, //PSTR("CST6")
+ TZ_America_Manaus, //PSTR("<-04>4")
+ TZ_America_Marigot, //PSTR("AST4")
+ TZ_America_Martinique, //PSTR("AST4")
+ TZ_America_Matamoros, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Mazatlan, //PSTR("MST7MDT,M4.1.0,M10.5.0")
+ TZ_America_Menominee, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Merida, //PSTR("CST6CDT,M4.1.0,M10.5.0")
+ TZ_America_Metlakatla, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_Mexico_City, //PSTR("CST6CDT,M4.1.0,M10.5.0")
+ TZ_America_Miquelon, //PSTR("<-03>3<-02>,M3.2.0,M11.1.0")
+ TZ_America_Moncton, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_America_Monterrey, //PSTR("CST6CDT,M4.1.0,M10.5.0")
+ TZ_America_Montevideo, //PSTR("<-03>3")
+ TZ_America_Montreal, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Montserrat, //PSTR("AST4")
+ TZ_America_Nassau, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_New_York, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Nipigon, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Nome, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_Noronha, //PSTR("<-02>2")
+ TZ_America_North_Dakota_Beulah, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_North_Dakota_Center, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_North_Dakota_New_Salem, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Ojinaga, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+ TZ_America_Panama, //PSTR("EST5")
+ TZ_America_Pangnirtung, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Paramaribo, //PSTR("<-03>3")
+ TZ_America_Phoenix, //PSTR("MST7")
+ TZ_America_PortmaumPrince, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Port_of_Spain, //PSTR("AST4")
+ TZ_America_Porto_Velho, //PSTR("<-04>4")
+ TZ_America_Puerto_Rico, //PSTR("AST4")
+ TZ_America_Punta_Arenas, //PSTR("<-03>3")
+ TZ_America_Rainy_River, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Rankin_Inlet, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Recife, //PSTR("<-03>3")
+ TZ_America_Regina, //PSTR("CST6")
+ TZ_America_Resolute, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Rio_Branco, //PSTR("<-05>5")
+ TZ_America_Santarem, //PSTR("<-03>3")
+ TZ_America_Santiago, //PSTR("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
+ TZ_America_Santo_Domingo, //PSTR("AST4")
+ TZ_America_Sao_Paulo, //PSTR("<-03>3")
+ TZ_America_Scoresbysund, //PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
+ TZ_America_Sitka, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_St_Barthelemy, //PSTR("AST4")
+ TZ_America_St_Johns, //PSTR("NST3:30NDT,M3.2.0,M11.1.0")
+ TZ_America_St_Kitts, //PSTR("AST4")
+ TZ_America_St_Lucia, //PSTR("AST4")
+ TZ_America_St_Thomas, //PSTR("AST4")
+ TZ_America_St_Vincent, //PSTR("AST4")
+ TZ_America_Swift_Current, //PSTR("CST6")
+ TZ_America_Tegucigalpa, //PSTR("CST6")
+ TZ_America_Thule, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_America_Thunder_Bay, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Tijuana, //PSTR("PST8PDT,M3.2.0,M11.1.0")
+ TZ_America_Toronto, //PSTR("EST5EDT,M3.2.0,M11.1.0")
+ TZ_America_Tortola, //PSTR("AST4")
+ TZ_America_Vancouver, //PSTR("PST8PDT,M3.2.0,M11.1.0")
+ TZ_America_Whitehorse, //PSTR("MST7")
+ TZ_America_Winnipeg, //PSTR("CST6CDT,M3.2.0,M11.1.0")
+ TZ_America_Yakutat, //PSTR("AKST9AKDT,M3.2.0,M11.1.0")
+ TZ_America_Yellowknife, //PSTR("MST7MDT,M3.2.0,M11.1.0")
+#endif
+
+#if USING_ANTARCTICA
+ TZ_Antarctica_Casey, //PSTR("<+11>-11")
+ TZ_Antarctica_Davis, //PSTR("<+07>-7")
+ TZ_Antarctica_DumontDUrville, //PSTR("<+10>-10")
+ TZ_Antarctica_Macquarie, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
+ TZ_Antarctica_Mawson, //PSTR("<+05>-5")
+ TZ_Antarctica_McMurdo, //PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
+ TZ_Antarctica_Palmer, //PSTR("<-03>3")
+ TZ_Antarctica_Rothera, //PSTR("<-03>3")
+ TZ_Antarctica_Syowa, //PSTR("<+03>-3")
+ TZ_Antarctica_Troll, //PSTR("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
+ TZ_Antarctica_Vostok, //PSTR("<+06>-6")
+ TZ_Arctic_Longyearbyen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+#endif
+
+
+#if USING_ASIA
+ TZ_Asia_Aden, //PSTR("<+03>-3")
+ TZ_Asia_Almaty, //PSTR("<+06>-6")
+ TZ_Asia_Amman, //PSTR("EET-2EEST,M3.5.4/24,M10.5.5/1")
+ TZ_Asia_Anadyr, //PSTR("<+12>-12")
+ TZ_Asia_Aqtau, //PSTR("<+05>-5")
+ TZ_Asia_Aqtobe, //PSTR("<+05>-5")
+ TZ_Asia_Ashgabat, //PSTR("<+05>-5")
+ TZ_Asia_Atyrau, //PSTR("<+05>-5")
+ TZ_Asia_Baghdad, //PSTR("<+03>-3")
+ TZ_Asia_Bahrain, //PSTR("<+03>-3")
+ TZ_Asia_Baku, //PSTR("<+04>-4")
+ TZ_Asia_Bangkok, //PSTR("<+07>-7")
+ TZ_Asia_Barnaul, //PSTR("<+07>-7")
+ TZ_Asia_Beirut, //PSTR("EET-2EEST,M3.5.0/0,M10.5.0/0")
+ TZ_Asia_Bishkek, //PSTR("<+06>-6")
+ TZ_Asia_Brunei, //PSTR("<+08>-8")
+ TZ_Asia_Chita, //PSTR("<+09>-9")
+ TZ_Asia_Choibalsan, //PSTR("<+08>-8")
+ TZ_Asia_Colombo, //PSTR("<+0530>-5:30")
+ TZ_Asia_Damascus, //PSTR("EET-2EEST,M3.5.5/0,M10.5.5/0")
+ TZ_Asia_Dhaka, //PSTR("<+06>-6")
+ TZ_Asia_Dili, //PSTR("<+09>-9")
+ TZ_Asia_Dubai, //PSTR("<+04>-4")
+ TZ_Asia_Dushanbe, //PSTR("<+05>-5")
+ TZ_Asia_Famagusta, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Asia_Gaza, //PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49")
+ TZ_Asia_Hebron, //PSTR("EET-2EEST,M3.4.4/48,M10.4.4/49")
+ TZ_Asia_Ho_Chi_Minh, //PSTR("<+07>-7")
+ TZ_Asia_Hong_Kong, //PSTR("HKT-8")
+ TZ_Asia_Hovd, //PSTR("<+07>-7")
+ TZ_Asia_Irkutsk, //PSTR("<+08>-8")
+ TZ_Asia_Jakarta, //PSTR("WIB-7")
+ TZ_Asia_Jayapura, //PSTR("WIT-9")
+ TZ_Asia_Jerusalem, //PSTR("IST-2IDT,M3.4.4/26,M10.5.0")
+ TZ_Asia_Kabul, //PSTR("<+0430>-4:30")
+ TZ_Asia_Kamchatka, //PSTR("<+12>-12")
+ TZ_Asia_Karachi, //PSTR("PKT-5")
+ TZ_Asia_Kathmandu, //PSTR("<+0545>-5:45")
+ TZ_Asia_Khandyga, //PSTR("<+09>-9")
+ TZ_Asia_Kolkata, //PSTR("IST-5:30")
+ TZ_Asia_Krasnoyarsk, //PSTR("<+07>-7")
+ TZ_Asia_Kuala_Lumpur, //PSTR("<+08>-8")
+ TZ_Asia_Kuching, //PSTR("<+08>-8")
+ TZ_Asia_Kuwait, //PSTR("<+03>-3")
+ TZ_Asia_Macau, //PSTR("CST-8")
+ TZ_Asia_Magadan, //PSTR("<+11>-11")
+ TZ_Asia_Makassar, //PSTR("WITA-8")
+ TZ_Asia_Manila, //PSTR("PST-8")
+ TZ_Asia_Muscat, //PSTR("<+04>-4")
+ TZ_Asia_Nicosia, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Asia_Novokuznetsk, //PSTR("<+07>-7")
+ TZ_Asia_Novosibirsk, //PSTR("<+07>-7")
+ TZ_Asia_Omsk, //PSTR("<+06>-6")
+ TZ_Asia_Oral, //PSTR("<+05>-5")
+ TZ_Asia_Phnom_Penh, //PSTR("<+07>-7")
+ TZ_Asia_Pontianak, //PSTR("WIB-7")
+ TZ_Asia_Pyongyang, //PSTR("KST-9")
+ TZ_Asia_Qatar, //PSTR("<+03>-3")
+ TZ_Asia_Qyzylorda, //PSTR("<+05>-5")
+ TZ_Asia_Riyadh, //PSTR("<+03>-3")
+ TZ_Asia_Sakhalin, //PSTR("<+11>-11")
+ TZ_Asia_Samarkand, //PSTR("<+05>-5")
+ TZ_Asia_Seoul, //PSTR("KST-9")
+ TZ_Asia_Shanghai, //PSTR("CST-8")
+ TZ_Asia_Singapore, //PSTR("<+08>-8")
+ TZ_Asia_Srednekolymsk, //PSTR("<+11>-11")
+ TZ_Asia_Taipei, //PSTR("CST-8")
+ TZ_Asia_Tashkent, //PSTR("<+05>-5")
+ TZ_Asia_Tbilisi, //PSTR("<+04>-4")
+ TZ_Asia_Tehran, //PSTR("<+0330>-3:30<+0430>,J79/24,J263/24")
+ TZ_Asia_Thimphu, //PSTR("<+06>-6")
+ TZ_Asia_Tokyo, //PSTR("JST-9")
+ TZ_Asia_Tomsk, //PSTR("<+07>-7")
+ TZ_Asia_Ulaanbaatar, //PSTR("<+08>-8")
+ TZ_Asia_Urumqi, //PSTR("<+06>-6")
+ TZ_Asia_UstmNera, //PSTR("<+10>-10")
+ TZ_Asia_Vientiane, //PSTR("<+07>-7")
+ TZ_Asia_Vladivostok, //PSTR("<+10>-10")
+ TZ_Asia_Yakutsk, //PSTR("<+09>-9")
+ TZ_Asia_Yangon, //PSTR("<+0630>-6:30")
+ TZ_Asia_Yekaterinburg, //PSTR("<+05>-5")
+ TZ_Asia_Yerevan, //PSTR("<+04>-4")
+#endif
+
+#if USING_ATLANTIC
+ TZ_Atlantic_Azores, //PSTR("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
+ TZ_Atlantic_Bermuda, //PSTR("AST4ADT,M3.2.0,M11.1.0")
+ TZ_Atlantic_Canary, //PSTR("WET0WEST,M3.5.0/1,M10.5.0")
+ TZ_Atlantic_Cape_Verde, //PSTR("<-01>1")
+ TZ_Atlantic_Faroe, //PSTR("WET0WEST,M3.5.0/1,M10.5.0")
+ TZ_Atlantic_Madeira, //PSTR("WET0WEST,M3.5.0/1,M10.5.0")
+ TZ_Atlantic_Reykjavik, //PSTR("GMT0")
+ TZ_Atlantic_South_Georgia, //PSTR("<-02>2")
+ TZ_Atlantic_Stanley, //PSTR("<-03>3")
+ TZ_Atlantic_St_Helena, //PSTR("GMT0")
+#endif
+
+#if USING_AUSTRALIA
+ TZ_Australia_Adelaide, //PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
+ TZ_Australia_Brisbane, //PSTR("AEST-10")
+ TZ_Australia_Broken_Hill, //PSTR("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
+ TZ_Australia_Currie, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
+ TZ_Australia_Darwin, //PSTR("ACST-9:30")
+ TZ_Australia_Eucla, //PSTR("<+0845>-8:45")
+ TZ_Australia_Hobart, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
+ TZ_Australia_Lindeman, //PSTR("AEST-10")
+ TZ_Australia_Lord_Howe, //PSTR("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
+ TZ_Australia_Melbourne, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
+ TZ_Australia_Perth, //PSTR("AWST-8")
+ TZ_Australia_Sydney, //PSTR("AEST-10AEDT,M10.1.0,M4.1.0/3")
+#endif
+
+#if USING_EUROPE
+ TZ_Europe_Amsterdam, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Andorra, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Astrakhan, //PSTR("<+04>-4")
+ TZ_Europe_Athens, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Belgrade, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Berlin, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Bratislava, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Brussels, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Bucharest, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Budapest, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Busingen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Chisinau, //PSTR("EET-2EEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Copenhagen, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Dublin, //PSTR("IST-1GMT0,M10.5.0,M3.5.0/1")
+ TZ_Europe_Gibraltar, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Guernsey, //PSTR("GMT0BST,M3.5.0/1,M10.5.0")
+ TZ_Europe_Helsinki, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Isle_of_Man, //PSTR("GMT0BST,M3.5.0/1,M10.5.0")
+ TZ_Europe_Istanbul, //PSTR("<+03>-3")
+ TZ_Europe_Jersey, //PSTR("GMT0BST,M3.5.0/1,M10.5.0")
+ TZ_Europe_Kaliningrad, //PSTR("EET-2")
+ TZ_Europe_Kiev, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Kirov, //PSTR("<+03>-3")
+ TZ_Europe_Lisbon, //PSTR("WET0WEST,M3.5.0/1,M10.5.0")
+ TZ_Europe_Ljubljana, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_London, //PSTR("GMT0BST,M3.5.0/1,M10.5.0")
+ TZ_Europe_Luxembourg, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Madrid, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Malta, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Mariehamn, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Minsk, //PSTR("<+03>-3")
+ TZ_Europe_Monaco, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Moscow, //PSTR("MSK-3")
+ TZ_Europe_Oslo, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Paris, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Podgorica, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Prague, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Riga, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Rome, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Samara, //PSTR("<+04>-4")
+ TZ_Europe_San_Marino, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Sarajevo, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Saratov, //PSTR("<+04>-4")
+ TZ_Europe_Simferopol, //PSTR("MSK-3")
+ TZ_Europe_Skopje, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Sofia, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Stockholm, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Tallinn, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Tirane, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Ulyanovsk, //PSTR("<+04>-4")
+ TZ_Europe_Uzhgorod, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Vaduz, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Vatican, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Vienna, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Vilnius, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Volgograd, //PSTR("<+04>-4")
+ TZ_Europe_Warsaw, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Zagreb, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+ TZ_Europe_Zaporozhye, //PSTR("EET-2EEST,M3.5.0/3,M10.5.0/4")
+ TZ_Europe_Zurich, //PSTR("CET-1CEST,M3.5.0,M10.5.0/3")
+#endif
+
+#if USING_INDIAN
+ TZ_Indian_Antananarivo, //PSTR("EAT-3")
+ TZ_Indian_Chagos, //PSTR("<+06>-6")
+ TZ_Indian_Christmas, //PSTR("<+07>-7")
+ TZ_Indian_Cocos, //PSTR("<+0630>-6:30")
+ TZ_Indian_Comoro, //PSTR("EAT-3")
+ TZ_Indian_Kerguelen, //PSTR("<+05>-5")
+ TZ_Indian_Mahe, //PSTR("<+04>-4")
+ TZ_Indian_Maldives, //PSTR("<+05>-5")
+ TZ_Indian_Mauritius, //PSTR("<+04>-4")
+ TZ_Indian_Mayotte, //PSTR("EAT-3")
+ TZ_Indian_Reunion, //PSTR("<+04>-4")
+#endif
+
+#if USING_PACIFIC
+ TZ_Pacific_Apia, //PSTR("<+13>-13<+14>,M9.5.0/3,M4.1.0/4")
+ TZ_Pacific_Auckland, //PSTR("NZST-12NZDT,M9.5.0,M4.1.0/3")
+ TZ_Pacific_Bougainville, //PSTR("<+11>-11")
+ TZ_Pacific_Chatham, //PSTR("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
+ TZ_Pacific_Chuuk, //PSTR("<+10>-10")
+ TZ_Pacific_Easter, //PSTR("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
+ TZ_Pacific_Efate, //PSTR("<+11>-11")
+ TZ_Pacific_Enderbury, //PSTR("<+13>-13")
+ TZ_Pacific_Fakaofo, //PSTR("<+13>-13")
+ TZ_Pacific_Fiji, //PSTR("<+12>-12<+13>,M11.2.0,M1.2.3/99")
+ TZ_Pacific_Funafuti, //PSTR("<+12>-12")
+ TZ_Pacific_Galapagos, //PSTR("<-06>6")
+ TZ_Pacific_Gambier, //PSTR("<-09>9")
+ TZ_Pacific_Guadalcanal, //PSTR("<+11>-11")
+ TZ_Pacific_Guam, //PSTR("ChST-10")
+ TZ_Pacific_Honolulu, //PSTR("HST10")
+ TZ_Pacific_Kiritimati, //PSTR("<+14>-14")
+ TZ_Pacific_Kosrae, //PSTR("<+11>-11")
+ TZ_Pacific_Kwajalein, //PSTR("<+12>-12")
+ TZ_Pacific_Majuro, //PSTR("<+12>-12")
+ TZ_Pacific_Marquesas, //PSTR("<-0930>9:30")
+ TZ_Pacific_Midway, //PSTR("SST11")
+ TZ_Pacific_Nauru, //PSTR("<+12>-12")
+ TZ_Pacific_Niue, //PSTR("<-11>11")
+ TZ_Pacific_Norfolk, //PSTR("<+11>-11<+12>,M10.1.0,M4.1.0/3")
+ TZ_Pacific_Noumea, //PSTR("<+11>-11")
+ TZ_Pacific_Pago_Pago, //PSTR("SST11")
+ TZ_Pacific_Palau, //PSTR("<+09>-9")
+ TZ_Pacific_Pitcairn, //PSTR("<-08>8")
+ TZ_Pacific_Pohnpei, //PSTR("<+11>-11")
+ TZ_Pacific_Port_Moresby, //PSTR("<+10>-10")
+ TZ_Pacific_Rarotonga, //PSTR("<-10>10")
+ TZ_Pacific_Saipan, //PSTR("ChST-10")
+ TZ_Pacific_Tahiti, //PSTR("<-10>10")
+ TZ_Pacific_Tarawa, //PSTR("<+12>-12")
+ TZ_Pacific_Tongatapu, //PSTR("<+13>-13")
+ TZ_Pacific_Wake, //PSTR("<+12>-12")
+ TZ_Pacific_Wallis, //PSTR("<+12>-12")
+#endif
+
+#if USING_ETC_GMT
+ TZ_Etc_GMT, //PSTR("GMT0")
+ TZ_Etc_GMTm0, //PSTR("GMT0")
+ TZ_Etc_GMTm1, //PSTR("<+01>-1")
+ TZ_Etc_GMTm2, //PSTR("<+02>-2")
+ TZ_Etc_GMTm3, //PSTR("<+03>-3")
+ TZ_Etc_GMTm4, //PSTR("<+04>-4")
+ TZ_Etc_GMTm5, //PSTR("<+05>-5")
+ TZ_Etc_GMTm6, //PSTR("<+06>-6")
+ TZ_Etc_GMTm7, //PSTR("<+07>-7")
+ TZ_Etc_GMTm8, //PSTR("<+08>-8")
+ TZ_Etc_GMTm9, //PSTR("<+09>-9")
+ TZ_Etc_GMTm10, //PSTR("<+10>-10")
+ TZ_Etc_GMTm11, //PSTR("<+11>-11")
+ TZ_Etc_GMTm12, //PSTR("<+12>-12")
+ TZ_Etc_GMTm13, //PSTR("<+13>-13")
+ TZ_Etc_GMTm14, //PSTR("<+14>-14")
+ TZ_Etc_GMT0, //PSTR("GMT0")
+ TZ_Etc_GMTp0, //PSTR("GMT0")
+ TZ_Etc_GMTp1, //PSTR("<-01>1")
+ TZ_Etc_GMTp2, //PSTR("<-02>2")
+ TZ_Etc_GMTp3, //PSTR("<-03>3")
+ TZ_Etc_GMTp4, //PSTR("<-04>4")
+ TZ_Etc_GMTp5, //PSTR("<-05>5")
+ TZ_Etc_GMTp6, //PSTR("<-06>6")
+ TZ_Etc_GMTp7, //PSTR("<-07>7")
+ TZ_Etc_GMTp8, //PSTR("<-08>8")
+ TZ_Etc_GMTp9, //PSTR("<-09>9")
+ TZ_Etc_GMTp10, //PSTR("<-10>10")
+ TZ_Etc_GMTp11, //PSTR("<-11>11")
+ TZ_Etc_GMTp12, //PSTR("<-12>12")
+ TZ_Etc_UCT, //PSTR("UTC0")
+ TZ_Etc_UTC, //PSTR("UTC0")
+ TZ_Etc_Greenwich, //PSTR("GMT0")
+ TZ_Etc_Universal, //PSTR("UTC0")
+ TZ_Etc_Zulu, //PSTR("UTC0")
+#endif
+};
+
+#endif // TZDB_H
diff --git a/travis/common.sh b/travis/common.sh
new file mode 100644
index 0000000..d115085
--- /dev/null
+++ b/travis/common.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+function build_examples()
+{
+ # track the exit code for this platform
+ local exit_code=0
+ # loop through results and add them to the array
+ examples=($(find $PWD/examples/ -name "*.pde" -o -name "*.ino"))
+
+ # get the last example in the array
+ local last="${examples[@]:(-1)}"
+
+ # loop through example sketches
+ for example in "${examples[@]}"; do
+
+ # store the full path to the example's sketch directory
+ local example_dir=$(dirname $example)
+
+ # store the filename for the example without the path
+ local example_file=$(basename $example)
+
+ echo "$example_file: "
+ local sketch="$example_dir/$example_file"
+ echo "$sketch"
+ #arduino -v --verbose-build --verify $sketch
+
+ # verify the example, and save stdout & stderr to a variable
+ # we have to avoid reading the exit code of local:
+ # "when declaring a local variable in a function, the local acts as a command in its own right"
+ local build_stdout
+ build_stdout=$(arduino --verify $sketch 2>&1)
+
+ # echo output if the build failed
+ if [ $? -ne 0 ]; then
+ # heavy X
+ echo -e "\xe2\x9c\x96"
+ echo -e "----------------------------- DEBUG OUTPUT -----------------------------\n"
+ echo "$build_stdout"
+ echo -e "\n------------------------------------------------------------------------\n"
+
+ # mark as fail
+ exit_code=1
+
+ else
+ # heavy checkmark
+ echo -e "\xe2\x9c\x93"
+ fi
+ done
+
+ return $exit_code
+}
diff --git a/utils/astyle_library.conf b/utils/astyle_library.conf
new file mode 100644
index 0000000..8a73bc2
--- /dev/null
+++ b/utils/astyle_library.conf
@@ -0,0 +1,70 @@
+# Code formatting rules for Arduino libraries, modified from for KH libraries:
+#
+# https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf
+#
+
+# astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino
+
+--mode=c
+--lineend=linux
+--style=allman
+
+# -r or -R
+#--recursive
+
+# -c => Converts tabs into spaces
+convert-tabs
+
+# -s2 => 2 spaces indentation
+--indent=spaces=2
+
+# -t2 => tab =2 spaces
+#--indent=tab=2
+
+# -C
+--indent-classes
+
+# -S
+--indent-switches
+
+# -xW
+--indent-preproc-block
+
+# -Y => indent classes, switches (and cases), comments starting at column 1
+--indent-col1-comments
+
+# -M120 => maximum of 120 spaces to indent a continuation line
+--max-continuation-indent=120
+
+# -xC120 => max‑code‑length will break a line if the code exceeds # characters
+--max-code-length=120
+
+# -f =>
+--break-blocks
+
+# -p => put a space around operators
+--pad-oper
+
+# -xg => Insert space padding after commas
+--pad-comma
+
+# -H => put a space after if/for/while
+pad-header
+
+# -xb => Break one line headers (e.g. if/for/while)
+--break-one-line-headers
+
+# -c => Converts tabs into spaces
+#--convert-tabs
+
+# if you like one-liners, keep them
+#keep-one-line-statements
+
+# -xV
+--attach-closing-while
+
+#unpad-paren
+
+# -xp
+remove-comment-prefix
+
diff --git a/utils/restyle.sh b/utils/restyle.sh
new file mode 100644
index 0000000..bcd846f
--- /dev/null
+++ b/utils/restyle.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+for dir in . ; do
+ find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \;
+done
+