From 01a419d987522e3053f882bb1d9edd0215160a71 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <49808844+DmitryBorisenko33@users.noreply.github.com> Date: Tue, 26 May 2020 22:12:35 +0200 Subject: [PATCH 1/6] uncomment --- set.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/set.h b/set.h index c1de1f87..00a94f64 100644 --- a/set.h +++ b/set.h @@ -9,12 +9,12 @@ boolean mb_4_of_memory = true; //#define layout_in_ram #define UDP_enable /*==========================SENSORS===============================*/ -//#define level_enable -//#define analog_enable -//#define dallas_enable -//#define dht_enable //подъедает оперативку сука -//#define bmp_enable -//#define bme_enable +#define level_enable +#define analog_enable +#define dallas_enable +#define dht_enable //подъедает оперативку сука +#define bmp_enable +#define bme_enable /*=========================LOGGING================================*/ #define logging_enable /*==========================GEARS=================================*/ From 48ddb1a505740702e520a091d9a8e563cc722455 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <49808844+DmitryBorisenko33@users.noreply.github.com> Date: Tue, 26 May 2020 22:18:27 +0200 Subject: [PATCH 2/6] Update set.h --- set.h | 1 + 1 file changed, 1 insertion(+) diff --git a/set.h b/set.h index 00a94f64..18f53186 100644 --- a/set.h +++ b/set.h @@ -1,6 +1,7 @@ /******************************************************************* **********************FIRMWARE SETTINGS**************************** ******************************************************************/ + //dev String firmware_version = "2.3.3"; boolean mb_4_of_memory = true; //#define OTA_enable From 3135e5658f49902bd8bd7419f7a9813be7bf5778 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <49808844+DmitryBorisenko33@users.noreply.github.com> Date: Thu, 28 May 2020 00:33:26 +0200 Subject: [PATCH 3/6] Global Webinterface Upgrade --- Cmd.ino | 10 +- Init.ino | 131 +------- Scenario.ino | 4 +- Time.ino | 20 +- Upgrade.ino | 42 --- Web.ino | 315 ++++++++++++++++++ WiFi.ino | 60 +--- data/config.json | 6 +- data/index.json | 30 +- data/lang/lang.ru.json | 6 + data/{configuration.json => set.device.json} | 31 +- data/{mqtt.json => set.mqtt.json} | 0 data/{pushingbox.json => set.push.json} | 0 data/{dev.json => set.udp.json} | 23 +- data/{utilities.json => set.utilities.json} | 0 data/{setup.json => set.wifi.json} | 0 ...2-esp8266_iot-manager_modules_firmware.ino | 13 +- mqtt.ino | 38 +-- push_pushingbox.ino | 13 - udp.ino | 36 +- 20 files changed, 390 insertions(+), 388 deletions(-) create mode 100644 Web.ino create mode 100644 data/lang/lang.ru.json rename data/{configuration.json => set.device.json} (85%) rename data/{mqtt.json => set.mqtt.json} (100%) rename data/{pushingbox.json => set.push.json} (100%) rename data/{dev.json => set.udp.json} (69%) rename data/{utilities.json => set.utilities.json} (100%) rename data/{setup.json => set.wifi.json} (100%) diff --git a/Cmd.ino b/Cmd.ino index 6e1b58a1..9001fb42 100644 --- a/Cmd.ino +++ b/Cmd.ino @@ -107,8 +107,8 @@ void button() { digitalWrite(button_param.toInt(), start_state.toInt()); } - if (button_param == "scenario") { - jsonWriteStr(configSetup, "scenario", start_state); + if (button_param == "scen") { + jsonWriteStr(configSetup, "scen", start_state); Scenario_init(); saveConfig(); } @@ -135,12 +135,12 @@ void buttonSet() { String button_state = sCmd.next(); String button_param = jsonReadStr(optionJson, "button_param" + button_number); - if (button_param != "na" || button_param != "scenario" || button_param.indexOf("line") != -1) { + if (button_param != "na" || button_param != "scen" || button_param.indexOf("line") != -1) { digitalWrite(button_param.toInt(), button_state.toInt()); } - if (button_param == "scenario") { - jsonWriteStr(configSetup, "scenario", button_state); + if (button_param == "scen") { + jsonWriteStr(configSetup, "scen", button_state); Scenario_init(); saveConfig(); } diff --git a/Init.ino b/Init.ino index 49922054..4465b97f 100644 --- a/Init.ino +++ b/Init.ino @@ -1,50 +1,11 @@ void All_init() { - - server.on("/init", HTTP_GET, [](AsyncWebServerRequest * request) { - String value; - if (request->hasArg("arg")) { - value = request->getParam("arg")->value(); - } - if (value == "0") { //выкл сценариев - jsonWriteStr(configSetup, "scenario", value); - saveConfig(); - Scenario_init(); - request->send(200, "text/text", "OK"); - } - if (value == "1") { //вкл сценариев - jsonWriteStr(configSetup, "scenario", value); - saveConfig(); - Scenario_init(); - request->send(200, "text/text", "OK"); - } - if (value == "2") { //инициализация - Device_init(); - request->send(200, "text/text", "OK"); - } - if (value == "3") { -#ifdef logging_enable - clean_log_date(); -#endif - request->send(200, "text/text", "OK"); - } - if (value == "4") { - Scenario_init(); - request->send(200, "text/text", "OK"); - } - if (value == "5") { - i2c_scanning = true; - request->redirect("/?utilities"); - } - }); - - prsets_init(); Device_init(); Scenario_init(); Timer_countdown_init(); } void Device_init() { - + logging_value_names_list = ""; enter_to_logging_counter = LOG1 - 1; @@ -86,99 +47,11 @@ void Device_init() { //-------------------------------сценарии----------------------------------------------------- void Scenario_init() { - if (jsonReadStr(configSetup, "scenario") == "1") { + if (jsonReadStr(configSetup, "scen") == "1") { scenario = readFile("firmware.s.txt", 2048); } } -void prsets_init() { - server.on("/preset", HTTP_GET, [](AsyncWebServerRequest * request) { - String value; - if (request->hasArg("arg")) { - value = request->getParam("arg")->value(); - } - if (value == "1") { - writeFile("firmware.c.txt", readFile("configs/relay.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay.s.txt", 2048)); - } - if (value == "2") { - writeFile("firmware.c.txt", readFile("configs/relay_t.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_t.s.txt", 2048)); - } - if (value == "3") { - writeFile("firmware.c.txt", readFile("configs/relay_c.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_c.s.txt", 2048)); - } - if (value == "4") { - writeFile("firmware.c.txt", readFile("configs/relay_s.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_s.s.txt", 2048)); - } - if (value == "5") { - writeFile("firmware.c.txt", readFile("configs/relay_sw.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_sw.s.txt", 2048)); - } - if (value == "6") { - writeFile("firmware.c.txt", readFile("configs/relay_br.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_br.s.txt", 2048)); - } - if (value == "7") { - writeFile("firmware.c.txt", readFile("configs/relay_sr.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/relay_sr.s.txt", 2048)); - } - if (value == "8") { - writeFile("firmware.c.txt", readFile("configs/pwm.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/pwm.s.txt", 2048)); - } - if (value == "9") { - writeFile("firmware.c.txt", readFile("configs/dht11.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/dht11.s.txt", 2048)); - } - if (value == "10") { - writeFile("firmware.c.txt", readFile("configs/dht22.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/dht22.s.txt", 2048)); - } - if (value == "11") { - writeFile("firmware.c.txt", readFile("configs/analog.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/analog.s.txt", 2048)); - } - if (value == "12") { - writeFile("firmware.c.txt", readFile("configs/dallas.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/dallas.s.txt", 2048)); - } - if (value == "13") { - writeFile("firmware.c.txt", readFile("configs/termostat.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/termostat.s.txt", 2048)); - } - if (value == "14") { - writeFile("firmware.c.txt", readFile("configs/level.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/level.s.txt", 2048)); - } - if (value == "15") { - writeFile("firmware.c.txt", readFile("configs/moution_r.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/moution_r.s.txt", 2048)); - } - if (value == "16") { - writeFile("firmware.c.txt", readFile("configs/moution_s.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/moution_s.s.txt", 2048)); - } - if (value == "17") { - writeFile("firmware.c.txt", readFile("configs/stepper.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/stepper.s.txt", 2048)); - } - if (value == "18") { - writeFile("firmware.c.txt", readFile("configs/servo.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/servo.s.txt", 2048)); - } - if (value == "19") { - writeFile("firmware.c.txt", readFile("configs/firmware.c.txt", 2048)); - writeFile("firmware.s.txt", readFile("configs/firmware.s.txt", 2048)); - } - Device_init(); - Scenario_init(); - request->redirect("/?configuration"); - }); -} - void up_time() { uint32_t ss = millis() / 1000; uint32_t mm = ss / 60; diff --git a/Scenario.ino b/Scenario.ino index 52828b79..8422b0fa 100644 --- a/Scenario.ino +++ b/Scenario.ino @@ -1,6 +1,6 @@ void handleScenario() { - if (jsonReadStr(configSetup, "scenario") == "1") { + if (jsonReadStr(configSetup, "scen") == "1") { if ((jsonReadStr(optionJson, "scenario_status") != "")) { int i = 0; String str = scenario; //читаем переменную с сценариями (то что из файла на странице) @@ -73,7 +73,7 @@ void handleScenario() { void eventGen (String event_name, String number) { //событие выглядит как имя плюс set плюс номер: button+Set+1 - if (jsonReadStr(configSetup, "scenario") == "1") { + if (jsonReadStr(configSetup, "scen") == "1") { String tmp = jsonReadStr(optionJson, "scenario_status") ; //генерирование события //Serial.println(event_name); jsonWriteStr(optionJson, "scenario_status", tmp + event_name + number + ","); diff --git a/Time.ino b/Time.ino index 365d40e4..b1fc9b66 100644 --- a/Time.ino +++ b/Time.ino @@ -1,16 +1,4 @@ void Time_Init() { - server.on("/time", HTTP_GET, [](AsyncWebServerRequest * request) { - if (request->hasArg("timezone")) { - jsonWriteStr(configSetup, "timezone", request->getParam("timezone")->value()); - } - if (request->hasArg("ntp")) { - jsonWriteStr(configSetup, "ntp", request->getParam("ntp")->value()); - } - saveConfig(); - reconfigTime(); - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); - ts.add(TIME_SYNC, 30000, [&](void*) { time_check(); }, nullptr, true); @@ -24,11 +12,11 @@ void time_check() { } void reconfigTime() { - if (WiFi.status() == WL_CONNECTED) { + if (WiFi.status() == WL_CONNECTED) { String ntp = jsonReadStr(configSetup, "ntp"); - configTime(0, 0, ntp.c_str()); + configTime(0, 0, ntp.c_str()); int i = 0; - Serial.println("[i] Awaiting for time "); + Serial.println("[i] Awaiting for time "); #ifdef ESP32 struct tm timeinfo; while (!getLocalTime(&timeinfo) && i <= 4) { @@ -41,7 +29,7 @@ void reconfigTime() { //while (!time(nullptr) && i < 4) { // Serial.print("."); // i++; - delay(2000); + delay(2000); //} #endif if (GetTimeUnix() != "failed") { diff --git a/Upgrade.ino b/Upgrade.ino index f576bfe6..6154acfe 100644 --- a/Upgrade.ino +++ b/Upgrade.ino @@ -1,5 +1,4 @@ void initUpgrade() { - #ifdef ESP8266 if (WiFi.status() == WL_CONNECTED) last_version = getURL("http://91.204.228.124:1100/update/esp8266/version.txt"); #endif @@ -9,47 +8,6 @@ void initUpgrade() { jsonWriteStr(configSetup, "last_version", last_version); Serial.print("[i] Last firmware version: "); Serial.println(last_version); - - server.on("/check", HTTP_GET, [](AsyncWebServerRequest * request) { - upgrade_url = true; - Serial.print("[i] Last firmware version: "); - Serial.println(last_version); - String tmp = "{}"; - if (WiFi.status() == WL_CONNECTED) { - if (mb_4_of_memory) { - if (last_version != "") { - if (last_version != "error") { - if (last_version == firmware_version) { - jsonWriteStr(tmp, "title", "Последняя версия прошивки уже установлена."); - jsonWriteStr(tmp, "class", "pop-up"); - } else { - jsonWriteStr(tmp, "title", "Имеется новая версия прошивкиИдет обновление прошивки, после обновления страница перезагрузится автоматически...')\">Установить"); - jsonWriteStr(tmp, "class", "pop-up"); - } - } else { - jsonWriteStr(tmp, "title", "Ошибка... Cервер не найден. Попробуйте позже..."); - jsonWriteStr(tmp, "class", "pop-up"); - } - } else { - jsonWriteStr(tmp, "title", "Нажмите на кнопку \"обновить прошивку\" повторно..."); - jsonWriteStr(tmp, "class", "pop-up"); - } - } else { - jsonWriteStr(tmp, "title", "Обновление по воздуху не поддерживается, модуль имеет меньше 4 мб памяти..."); - jsonWriteStr(tmp, "class", "pop-up"); - } - } else { - jsonWriteStr(tmp, "title", "Устройство не подключен к роутеру..."); - jsonWriteStr(tmp, "class", "pop-up"); - } - request->send(200, "text/text", tmp); - }); - - server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest * request) { - upgrade = true; - String tmp = "{}"; - request->send(200, "text/text", "ok"); - }); } void do_upgrade_url() { diff --git a/Web.ino b/Web.ino new file mode 100644 index 00000000..fc4c9b11 --- /dev/null +++ b/Web.ino @@ -0,0 +1,315 @@ +void web_init() { + /****************************************************************************** + **********************************INITIALIZATION******************************* + ******************************************************************************/ + server.on("/set", HTTP_GET, [](AsyncWebServerRequest * request) { + String value; + //============================device settings===================================== + if (request->hasArg("devinit")) { + Device_init(); + request->send(200, "text/text", "OK"); + } + + if (request->hasArg("scen")) { + value = request->getParam("scen")->value(); + if (value == "0") { + jsonWriteStr(configSetup, "scen", value); + saveConfig(); + Scenario_init(); + } + if (value == "1") { + jsonWriteStr(configSetup, "scen", value); + saveConfig(); + Scenario_init(); + } + request->send(200, "text/text", "OK"); + } + + if (request->hasArg("sceninit")) { + Scenario_init(); + request->send(200, "text/text", "OK"); + } + + if (request->hasArg("cleanlog")) { +#ifdef logging_enable + clean_log_date(); +#endif + } + //==============================udp settings============================================= + if (request->hasArg("udponoff")) { + value = request->getParam("udponoff")->value(); + if (value == "0") { + jsonWriteStr(configSetup, "udponoff", value); + saveConfig(); + Scenario_init(); + } + if (value == "1") { + jsonWriteStr(configSetup, "udponoff", value); + saveConfig(); + Scenario_init(); + } + request->send(200, "text/text", "OK"); + } + + if (request->hasArg("updatelist")) { + SPIFFS.remove("/dev.csv"); + addFile("dev.csv", "device id;device name;ip address"); + request->redirect("/?set.udp"); + } + + if (request->hasArg("updatepage")) { + request->redirect("/?set.udp"); + } + + + + + /*if (value == "5") { + i2c_scanning = true; + request->redirect("/?utilities"); + }*/ + + /*if (value == "2") { + mqtt_send_settings_to_udp = true; + request->send(200, "text/text", "ok"); + }*/ + }); + /****************************************************************************** + **********************************TIME***************************************** + ******************************************************************************/ + server.on("/time", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("timezone")) { + jsonWriteStr(configSetup, "timezone", request->getParam("timezone")->value()); + } + if (request->hasArg("ntp")) { + jsonWriteStr(configSetup, "ntp", request->getParam("ntp")->value()); + } + saveConfig(); + reconfigTime(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + /****************************************************************************** + **********************************UPDATE*************************************** + ******************************************************************************/ + server.on("/check", HTTP_GET, [](AsyncWebServerRequest * request) { + upgrade_url = true; + Serial.print("[i] Last firmware version: "); + Serial.println(last_version); + String tmp = "{}"; + if (WiFi.status() == WL_CONNECTED) { + if (mb_4_of_memory) { + if (last_version != "") { + if (last_version != "error") { + if (last_version == firmware_version) { + jsonWriteStr(tmp, "title", "Последняя версия прошивки уже установлена."); + jsonWriteStr(tmp, "class", "pop-up"); + } else { + jsonWriteStr(tmp, "title", "Имеется новая версия прошивкиИдет обновление прошивки, после обновления страница перезагрузится автоматически...')\">Установить"); + jsonWriteStr(tmp, "class", "pop-up"); + } + } else { + jsonWriteStr(tmp, "title", "Ошибка... Cервер не найден. Попробуйте позже..."); + jsonWriteStr(tmp, "class", "pop-up"); + } + } else { + jsonWriteStr(tmp, "title", "Нажмите на кнопку \"обновить прошивку\" повторно..."); + jsonWriteStr(tmp, "class", "pop-up"); + } + } else { + jsonWriteStr(tmp, "title", "Обновление по воздуху не поддерживается, модуль имеет меньше 4 мб памяти..."); + jsonWriteStr(tmp, "class", "pop-up"); + } + } else { + jsonWriteStr(tmp, "title", "Устройство не подключен к роутеру..."); + jsonWriteStr(tmp, "class", "pop-up"); + } + request->send(200, "text/text", tmp); + }); + + server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest * request) { + upgrade = true; + String tmp = "{}"; + request->send(200, "text/text", "ok"); + }); + /****************************************************************************** + **********************************WIFI***************************************** + ******************************************************************************/ + server.on("/ssid", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("ssid")) { + jsonWriteStr(configSetup, "ssid", request->getParam("ssid")->value()); + } + if (request->hasArg("password")) { + jsonWriteStr(configSetup, "password", request->getParam("password")->value()); + } + saveConfig(); + request->send(200, "text/text", "OK"); + }); + server.on("/ssidap", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("ssidAP")) { + jsonWriteStr(configSetup, "ssidAP", request->getParam("ssidAP")->value()); + } + if (request->hasArg("passwordAP")) { + jsonWriteStr(configSetup, "passwordAP", request->getParam("passwordAP")->value()); + } + saveConfig(); + request->send(200, "text/text", "OK"); + }); + server.on("/web", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("web_login")) { + jsonWriteStr(configSetup, "web_login", request->getParam("web_login")->value()); + } + if (request->hasArg("web_pass")) { + jsonWriteStr(configSetup, "web_pass", request->getParam("web_pass")->value()); + } + saveConfig(); + //Web_server_init(); + request->send(200, "text/text", "OK"); + }); + server.on("/restart", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("device")) { + if (request->getParam("device")->value() == "ok") ESP.restart(); + } + request->send(200, "text/text", "OK"); + }); + /****************************************************************************** + **********************************MQTT**************************************** + ******************************************************************************/ + server.on("/mqttSave", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("mqttServer")) { + jsonWriteStr(configSetup, "mqttServer", request->getParam("mqttServer")->value()); + } + if (request->hasArg("mqttPort")) { + int port = (request->getParam("mqttPort")->value()).toInt(); + jsonWriteInt(configSetup, "mqttPort", port); + } + if (request->hasArg("mqttPrefix")) { + jsonWriteStr(configSetup, "mqttPrefix", request->getParam("mqttPrefix")->value()); + } + if (request->hasArg("mqttUser")) { + jsonWriteStr(configSetup, "mqttUser", request->getParam("mqttUser")->value()); + } + if (request->hasArg("mqttPass")) { + jsonWriteStr(configSetup, "mqttPass", request->getParam("mqttPass")->value()); + } + saveConfig(); + mqtt_connection = true; + request->send(200, "text/text", "ok"); + }); + server.on("/mqttCheck", HTTP_GET, [](AsyncWebServerRequest * request) { + String tmp = "{}"; + jsonWriteStr(tmp, "title", "" + stateMQTT()); + jsonWriteStr(tmp, "class", "pop-up"); + request->send(200, "text/text", tmp); + }); + /****************************************************************************** + **********************************PUSH***************************************** + ******************************************************************************/ +#ifdef push_enable + server.on("/pushingboxDate", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("pushingbox_id")) { + jsonWriteStr(configSetup, "pushingbox_id", request->getParam("pushingbox_id")->value()); + } + saveConfig(); + request->send(200, "text/text", "ok"); + }); +#endif + /****************************************************************************** + **********************************PRESETS************************************** + ******************************************************************************/ + server.on("/preset", HTTP_GET, [](AsyncWebServerRequest * request) { + String value; + if (request->hasArg("arg")) { + value = request->getParam("arg")->value(); + } + if (value == "1") { + writeFile("firmware.c.txt", readFile("configs/relay.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay.s.txt", 2048)); + } + if (value == "2") { + writeFile("firmware.c.txt", readFile("configs/relay_t.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_t.s.txt", 2048)); + } + if (value == "3") { + writeFile("firmware.c.txt", readFile("configs/relay_c.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_c.s.txt", 2048)); + } + if (value == "4") { + writeFile("firmware.c.txt", readFile("configs/relay_s.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_s.s.txt", 2048)); + } + if (value == "5") { + writeFile("firmware.c.txt", readFile("configs/relay_sw.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_sw.s.txt", 2048)); + } + if (value == "6") { + writeFile("firmware.c.txt", readFile("configs/relay_br.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_br.s.txt", 2048)); + } + if (value == "7") { + writeFile("firmware.c.txt", readFile("configs/relay_sr.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/relay_sr.s.txt", 2048)); + } + if (value == "8") { + writeFile("firmware.c.txt", readFile("configs/pwm.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/pwm.s.txt", 2048)); + } + if (value == "9") { + writeFile("firmware.c.txt", readFile("configs/dht11.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/dht11.s.txt", 2048)); + } + if (value == "10") { + writeFile("firmware.c.txt", readFile("configs/dht22.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/dht22.s.txt", 2048)); + } + if (value == "11") { + writeFile("firmware.c.txt", readFile("configs/analog.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/analog.s.txt", 2048)); + } + if (value == "12") { + writeFile("firmware.c.txt", readFile("configs/dallas.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/dallas.s.txt", 2048)); + } + if (value == "13") { + writeFile("firmware.c.txt", readFile("configs/termostat.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/termostat.s.txt", 2048)); + } + if (value == "14") { + writeFile("firmware.c.txt", readFile("configs/level.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/level.s.txt", 2048)); + } + if (value == "15") { + writeFile("firmware.c.txt", readFile("configs/moution_r.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/moution_r.s.txt", 2048)); + } + if (value == "16") { + writeFile("firmware.c.txt", readFile("configs/moution_s.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/moution_s.s.txt", 2048)); + } + if (value == "17") { + writeFile("firmware.c.txt", readFile("configs/stepper.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/stepper.s.txt", 2048)); + } + if (value == "18") { + writeFile("firmware.c.txt", readFile("configs/servo.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/servo.s.txt", 2048)); + } + if (value == "19") { + writeFile("firmware.c.txt", readFile("configs/firmware.c.txt", 2048)); + writeFile("firmware.s.txt", readFile("configs/firmware.s.txt", 2048)); + } + Device_init(); + Scenario_init(); + request->redirect("/?configuration"); + }); + /****************************************************************************** + **********************************UDP****************************************** + ******************************************************************************/ + server.on("/name", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("arg")) { + jsonWriteStr(configSetup, "name", request->getParam("arg")->value()); + jsonWriteStr(configJson, "name", request->getParam("arg")->value()); + saveConfig(); + } + request->send(200, "text/text", "OK"); + }); +} diff --git a/WiFi.ino b/WiFi.ino index 501e5a8f..a4af35cd 100644 --- a/WiFi.ino +++ b/WiFi.ino @@ -1,54 +1,7 @@ -void WIFI_init() { - - // --------------------Получаем ssid password со страницы - server.on("/ssid", HTTP_GET, [](AsyncWebServerRequest * request) { - if (request->hasArg("ssid")) { - jsonWriteStr(configSetup, "ssid", request->getParam("ssid")->value()); - } - if (request->hasArg("password")) { - jsonWriteStr(configSetup, "password", request->getParam("password")->value()); - } - saveConfig(); // Функция сохранения данных во Flash - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); - // --------------------Получаем ssidAP passwordAP со страницы - server.on("/ssidap", HTTP_GET, [](AsyncWebServerRequest * request) { - if (request->hasArg("ssidAP")) { - jsonWriteStr(configSetup, "ssidAP", request->getParam("ssidAP")->value()); - } - if (request->hasArg("passwordAP")) { - jsonWriteStr(configSetup, "passwordAP", request->getParam("passwordAP")->value()); - } - saveConfig(); // Функция сохранения данных во Flash - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); - - // --------------------Получаем логин и пароль для web со страницы - server.on("/web", HTTP_GET, [](AsyncWebServerRequest * request) { - if (request->hasArg("web_login")) { - jsonWriteStr(configSetup, "web_login", request->getParam("web_login")->value()); - } - if (request->hasArg("web_pass")) { - jsonWriteStr(configSetup, "web_pass", request->getParam("web_pass")->value()); - } - saveConfig(); // Функция сохранения данных во Flash - //Web_server_init(); - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); - - server.on("/restart", HTTP_GET, [](AsyncWebServerRequest * request) { - if (request->hasArg("device")) { - if (request->getParam("device")->value() == "ok") ESP.restart(); - } - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); - ROUTER_Connecting(); -} - void ROUTER_Connecting() { - - led_blink("slow"); + led_blink("slow"); + WiFi.mode(WIFI_STA); byte tries = 20; @@ -94,11 +47,9 @@ void ROUTER_Connecting() { Serial.print(WiFi.localIP()); Serial.println(""); jsonWriteStr(configJson, "ip", WiFi.localIP().toString()); - led_blink("off"); - //add_dev_in_list("dev.txt", chipID, WiFi.localIP().toString()); - + MQTT_init(); } } @@ -117,17 +68,16 @@ bool StartAPMode() { Serial.println(myIP); jsonWriteStr(configJson, "ip", myIP.toString()); - if (jsonReadInt(optionJson, "pass_status") != 1) { + //if (jsonReadInt(optionJson, "pass_status") != 1) { ts.add(ROUTER_SEARCHING, 10 * 1000, [&](void*) { Serial.println("->try find router"); if (RouterFind(jsonReadStr(configSetup, "ssid"))) { ts.remove(ROUTER_SEARCHING); WiFi.scanDelete(); ROUTER_Connecting(); - MQTT_init(); } }, nullptr, true); - } + //} return true; } diff --git a/data/config.json b/data/config.json index 180bdcd3..c78bdfd1 100644 --- a/data/config.json +++ b/data/config.json @@ -3,8 +3,8 @@ "chipID": "", "ssidAP": "WiFi2", "passwordAP": "", - "ssid": "rise", - "password": "hostel3333", + "ssid": "VOLODYA", + "password": "BELCHENKO", "timezone": 2, "ntp": "pool.ntp.org", "mqttServer": "91.204.228.124", @@ -12,7 +12,7 @@ "mqttPrefix": "/rise", "mqttUser": "test", "mqttPass": "test", - "scenario": "1", + "scen": "1", "pushingbox_id": "v7C133E426B0C69E", "web_login": "admin", "web_pass": "admin", diff --git a/data/index.json b/data/index.json index 26adcc1a..2f430b87 100644 --- a/data/index.json +++ b/data/index.json @@ -41,8 +41,8 @@ { "type": "link", "title": "Конфигурация устройства", - "action": "/?configuration", - "class": "btn btn-block btn-primary" + "action": "/?set.device", + "class": "btn btn-block btn-default" }, { "type": "hr" @@ -50,32 +50,32 @@ { "type": "link", "title": "Список других устройств в сети", - "action": "/?dev", - "class": "btn btn-block btn-success" + "action": "/?set.udp", + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Конфигурация WIFI", - "action": "/?setup", - "class": "btn btn-block btn-success" + "action": "/?set.wifi", + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Конфигурация MQTT", - "action": "/?mqtt", - "class": "btn btn-block btn-success" + "action": "/?set.mqtt", + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Конфигурация push", - "action": "/?pushingbox", - "class": "btn btn-block btn-success" + "action": "/?set.push", + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Утилиты", - "action": "/?utilities", - "class": "btn btn-block btn-success" + "action": "/?set.utilities", + "class": "btn btn-block btn-default" }, { "type": "h3", @@ -91,7 +91,7 @@ "title": "Обновить прошивку", "action": "/check", "response": "[[my-block]]", - "class": "btn btn-block btn-danger" + "class": "btn btn-block btn-default" }, { "type": "hr" @@ -100,13 +100,13 @@ "type": "link", "title": "Скачать приложение IoT Manager для android", "action": "https://play.google.com/store/apps/details?id=ru.esp8266.iotmanager", - "class": "btn btn-block btn-warning" + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Скачать приложение IoT Manager для iphone", "action": "https://apps.apple.com/ru/app/iot-manager/id1155934877", - "class": "btn btn-block btn-warning" + "class": "btn btn-block btn-default" } ] } diff --git a/data/lang/lang.ru.json b/data/lang/lang.ru.json new file mode 100644 index 00000000..881f9556 --- /dev/null +++ b/data/lang/lang.ru.json @@ -0,0 +1,6 @@ +{ + "SetDevConf": "Конфигурация устройства", + "SetDevPreset": "Выберите из выпадающего списка подходящий пресет кофигураций", + "SetUDPList": "Список других устройств в сети:", + "SetUDPWarn1": "После нажатия на кнопку 'Переформировать список устройств' ждите примерно минуту, а затем обновите страницу и список появится вновь" +} \ No newline at end of file diff --git a/data/configuration.json b/data/set.device.json similarity index 85% rename from data/configuration.json rename to data/set.device.json index fb4381dd..99b9cee8 100644 --- a/data/configuration.json +++ b/data/set.device.json @@ -2,7 +2,8 @@ "configs": [ "/config.live.json", "/config.setup.json", - "/config.option.json" + "/config.option.json", + "/lang/lang.ru.json" ], "class": "col-sm-offset-1 col-sm-10", "content": [ @@ -33,10 +34,10 @@ { "type": "dropdown", "name": "help-url", - "class": "btn btn-warning btn-lg", + "class": "btn btn-default", "style": "display:inline", "title": { - "#": "Выбирите то, во что Вы хотите превратить это устройство ", + "#": "{{SetDevPreset}}", "/preset?arg=1": "1.Вкл. выкл. локального реле", "/preset?arg=2": "2.Вкл. выкл. локального реле в определенное время", "/preset?arg=3": "3.Вкл. выкл. локального реле на определенный период времени", @@ -60,21 +61,21 @@ }, { "type": "h2", - "title": "Конфигурация устройства" + "title": "{{SetDevConf}}" }, { "type": "file", "state": "firmware.c.txt", "style": "width:100%;height:400px", "title": "Сохранить", - "action": "/init?arg=2", - "class": "btn btn-block btn-success" + "action": "/set?devinit", + "class": "btn btn-block btn-default" }, { "type": "link", - "title": "Подробная инструкция", + "title": "Инструкция", "action": "https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/wiki/Instruction", - "class": "btn btn-block btn-primary" + "class": "btn btn-block btn-default" }, { "type": "h2", @@ -82,21 +83,17 @@ }, { "type": "checkbox", - "name": "scenario", + "name": "scen", "title": "Включить сценарии", - "action": "/init?arg=[[scenario]]", - "state": "{{scenario}}" - }, - { - "type": "h6", - "title": "" + "action": "/set?scen=[[scen]]", + "state": "{{scen}}" }, { "type": "file", "state": "firmware.s.txt", "style": "width:100%;height:400px", "title": "Сохранить", - "action": "/init?arg=4", + "action": "/set?sceninit", "class": "btn btn-block btn-success" }, { @@ -105,7 +102,7 @@ { "type": "link", "title": "Очистить логи сенсоров", - "action": "/init?arg=3", + "action": "/set?cleanlog", "class": "btn btn-block btn-success" }, { diff --git a/data/mqtt.json b/data/set.mqtt.json similarity index 100% rename from data/mqtt.json rename to data/set.mqtt.json diff --git a/data/pushingbox.json b/data/set.push.json similarity index 100% rename from data/pushingbox.json rename to data/set.push.json diff --git a/data/dev.json b/data/set.udp.json similarity index 69% rename from data/dev.json rename to data/set.udp.json index 9b474644..d65056dd 100644 --- a/data/dev.json +++ b/data/set.udp.json @@ -1,7 +1,8 @@ { "configs": [ "/config.live.json", - "/config.setup.json" + "/config.setup.json", + "/lang/lang.ru.json" ], "title": "Главная", "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", @@ -13,7 +14,7 @@ }, { "type": "h3", - "title": "Список других устройств в сети:" + "title": "{{SetUDPList}}" }, { "type": "hr" @@ -35,22 +36,22 @@ { "type": "link", "title": "Переформировать список устройств", - "action": "udp?arg=3", - "class": "btn btn-block btn-success" + "action": "set?updatelist", + "class": "btn btn-block btn-default" }, { "type": "link", "title": "Обновить страницу", - "action": "udp?arg=4", - "class": "btn btn-block btn-success" + "action": "set?updatepage", + "class": "btn btn-block btn-default" }, { "type": "hr" }, { "type": "text", - "class": "alert alert-warning", - "title": "После нажатия на кнопку 'Переформировать список устройств' ждите примерно минуту, а затем обновите страницу и список появится вновь" + "title": "
{{SetUDPWarn1}}
vrH~ZP-f-v)mGcWqvH4Z7n%nt?SSuF)q z0lSuYqL-A=yD746v0iHrYvqVSO`kbVC(SSt4Z>4_5k@d`bQzYz>H~Pb>rrFyx-4E9a1FYW@|6W!QC*x`(u` zRWhC7%Ts`)5(*8f=@_QC$3p45aMRAapmu*(#8fGWa#}m2c>F*D#UA8=4MVyiWwGZ> zczYh`Pnfl(MHOqUV}+IvWD(~UAA~`yK0Jh*#L23aB^4^1C52x&jheeijyQ2HGoW}p zu~CEtptf_Cgt3ckTi=ky{HmQV;lK|w(MluL`XiM%c$P5WtZmxQNe4aWoLeQ3UA2H8 zls|_TmsZU+umXtLDWe!!es3L-D-3_cejemS;H!@h$wK3bs0)|Ppcicg>+Q1y%q*IE zGu%iZ!DS5?842ylXG2fK04+3Pd8_wSDBgtvP{V|=q0&-i8yZZDU^?|=4Rr^V&}F0Z z2&$>eDNk#xGrdrjSVcp3n@5h)&vfL?ZM`qFmnb7p=8es#Uy-p?>if3L8@%e^g0{Rx zSXeR@O8P%GJgCMv 9U=ZcQZosaHl@?V@? z+nVSyWHDpV*Rz #K@blTSwU?%cuIyGOZP(rdQwbR zhTB_5C@W!%3w^#$>1mL^ Xuxu>=^`f>4gHk9^UYykFB`S-qK0| z! M{>~tmpwKnMspzfx%ZOq6efDd2O=7FN7dY zE=mVcYmn&MATReW+-lxvHU32@R7W{29Es)kkXY0* tpTWp`_EUY38PE z?ed$uCe6vBt`nUT;{)wj$dwyU`G; @l?il?_7>7ZW*;jU%|L2*$V^2<> z*o^NA`DdF+JCG#Jx tZBfO9H*pq&W0^7M}Z4*_7R`@al$vHuvt z{xNuPPOd>B|6fn09XbCo?Eho oN)4>lm!bS>TQ{<3q{1xX*jG6iXCWZDw@JU;(4Jp^NheB(BzwQjZ zE-r7;DpcdokZNqm5#5!}6SayrX2$Opo-xZvY7LTv*?ab`4RuGfH$X`NFF=J(?E*Q$ zx$>w^v<;jrxgnfwzcU`}fNs=U$;Q}0LpuQV>=icvwG}EHOV1GAkw}Pc5U90hw4uJQ zfZpdYIk2HBB1FTLtwOc>v>_Qob4G8Cv~K7@?!e+Hy*W8bib}&-Y2^U69h lS6ixsF3I>3kgpJ zl%F$#$0kM2YM#f?1;KUvV4_|CO#&7teaf$LdEs`npv>;g0Q>w7?ME7cD{U{=s+=C2 z6KeD5D7~ppMxP{W zZSW@7Tei?%b7MVg2nJDP~Y$D!^Au9 z03$n5zb+hQ2)IAZqo-XP*(kKc5ndMJC^6))kNUSa*?w?4y3SaFv^;F$abHG3pFbR( zBbZHvY53%?_jyf!s5<|dI+`&hq(7--eoC^&pSt0}gn%wYWqc}bnUDsepQ2Q_@n58W zgGXkOaUXl46=U3>lVQEhVhs{RwB_273SIazOcldubg$G;pse10b|XHO+uf^YS6}N4 zz}qPa%!NsGZc@=+7SQN;XxEeD(RHtcP}^abNwQ*FWQ0qNWzNsl#vft29eO0j9m$RV z=Iz7nxB;d+GrMdE*#yaH7R}1An{y{=d;c6O-;y?PCeskAGK`+__wCY**POj+ *kInRX{C6m@eB|Li2!g(DCsUc7 z)9?f@E$rUVc3sU#>Le0cvAjrdrtZ9`0i1oTg}cCEMv7otOe=M35w-<#H q z3xImdeZlrn2D;>_b>aMEj_vbj*?UvLOR#3bNJ{1xN1qPU;#RKoEE5;vaLpqFr{#c9 zH~1;xkrqX^ha1(oyW$Y-xi!}=v&}$pUaUD8Y@OUOQxlbR#EYZn8O@s|G*k@Caj6jc zD3Z5(HSw4C#C(x>1J%)f*SL}h)!j#XMu6@UU*%B~ibpIxjh|nF4;&h9r9zf@kkqQl zfk;k plA}^FVV+trO+@aaoQboFz*^RY6J)S#uQPvY}cV;rxYLVPg z>_8h=qO3| Tpilmclg4fICuuz-lFHCgeGukxEvAaxStX%=<^0 (0 z{sv`=y^2WNICSOD+T{YBo>{8BNRL&2Z!#{Q@E^iai(}q#aYsx4ra;`hlt)pVexd$k z7;RbanIt=~fKX{F%X=*@g*GLrL%=WS6oj?xY>Mp%e5Dk9sziL|z}Z`+qNn?AQt(z* z@?q6s@_5Ohb}L9j%%mG5mRTsO9b>sL6kFX8W66LrKRmRtQPF!$JYX$?h|V?6QYi6E zPyu0JNN|2={y}P9V0EJ%?!-CxMd*PsnzDy)R)c-*`448?dL+m|d&yCdA^^h=vU4N~ za>o9TTBo|beesU}0@7e{<3M1gdg+N8swgUO;`_WG47W3>s{3!mNIR3UwYOoRD`}xo zRzgJjsPUk8_a+@*RV*E{b8#0R;&^i1!Y*sN;7Ip*7RXXM`q^fb zpU3ah{R@n+^=&@AVj!*_>Nz!wOgMMra2D#E8gd=TZoo2@F~=TWO}1*6b4^eN<2rpb zOc_Dh)7I<__|sohu`YEkn&gPlCruQ3@JrXkS+}y;;M$3L9-Vq(0DwrRbBvBgw!`wG zX3OowFbY@|9cLp?lD^W)v4xw%MQIsZ*yP>5xSh~afLWU8pNBD8RS$gjv?JogJv{3f zCjS~%Pvs0GT=)xVGz4Mmy0n%)*&^LXlbL<9xmD>LF2}Tx9{=F+1THruu9uNOQ{=H) ztK5w7QxOcpmjDQHa{x?-^6{dJH@1w9HoksM{XJx3gUr0Ozkpwgh$+!{VWG-KptG%l z{{%^+;`U>-qSuroQzC(7q-R4pjRv=FadBM}-bwy(CXq)dMI&4_L|Y;EIw^W0C%0uG z4f!aDS3WLr)DrjXm+I*(I&oXWeTMwr`eBWL48FDk@)+!~J)mzV>%0RxKUwHkVp@kv zqEsZ5@)ZQiZVIpzH!wliA{dxo(or-IAIcpq<_DM$wq#xp`)m=Dq2^BoCo8%V;;_Kl z&-mMr1p4%22*bE0iITW8tfUN4M2NNA1!%_3Rj?Dlz9eobDV*ZV@cZv0WT7MO=AEhf z5@PA^Z2GkASAgEC45-&WF;doF1<&Hss9QNB5G@emIQ2gSE|0?!G8t##$lswBf6iX} zLUre_YgHFKYkGqqCQE pw!n#8>SC76baud*5nE91BZ9^~;_PZ6ua_<9z=>~9O|HEi z%rG+zv|W#4vHDs-%fg_(-efIismmJ1Y1Irm$xIzIfdEI9h@#-DJ-8CyX|ydiRs4*} zc)pV(D*Nl0=d6bv?#GkryC$ltIQK!F&Skr^7eI&2ls?B-$r3ydjWbzyE@6m782VCY z9`qdP-mD#FKpuKgJ4}FLzPrU9i-UiWrzw&Ha2L*#WPuS@lWWhMM^FyOz#<9+JiUKy z2+l$kGT$f2vEi?4Oy~6Cen>G)#+f892(Khw!XSKj!Z7f2BlyOpGQc`>A~tai{FXhO ztHDygBu;Dqu_XLgQx`b@UNn|~BajXLdrcVBFY2RX=R( -S0{(Dp;FWMB#<9f%Y=*rXdG20)Sc zQC}!gX2S@6FSctQTyn8t;P^80#K2j5vE9_KYi(N=nYvut44ZU|$LA{-#U_ws8N}~# zI$x;^u8HItP~t=)`z^y=^SP)=;3Z>COq3&NUlDOtw3cgG%%wNNU>gZvMZX2tHdqcz zmVE;CkQzZaGmbG6+99TV@hLGJY(QlAuLb)MOc6BFdTyfMir`YlrNRFEXr$1#2PV%; z{* ;t> zGv{jwVKA!MO6j$BUp?-pZqa(T!>|KLS5-A#fAAzmB3?m0e#YLWvoc0R-T>^-R}40* z{sSfRafkCKBO|WdY=cB+NI4WNo?4p$GM4gi)i7gMh&(@whR(Hl`Vv5Ha1m)b(;FMF z B*Xl7hl5g(BH} 9|-$Rs4NLOzXh z)eU7LA+p-~?zRw~J7u}~D2-kq%?kA;=xVG7E4e-(#RRA8VSn&GP8fa&^e5xN76h$P zk!a_IpV2;tVo*Ct|Iv32A6n2jzQ4i2s1$<05?7e$FrfHb(GW*Wxd3A+x~{ww&>9x~ zzTg!0d$3Ceswf1nJqA#kF2oT@B3C&A9sLLz#Ge7lvpnpHLk4T0uHT_qvU5swW71d+ zfj?9Q03VZ2Ho8UT$g( J<%*H@_^bwa(3YO5c7XFZy zBLoVZcW(*0_VV?T9VC!bhdIThT9gKHy+IJK1f2MWP3RU!eACl={nInk6ue{dodL4i z^9&1+g?WvQKfP(0`DT4~s0j_KCDNq!8b~6-Y(76Q8oadJCt#X-{QYW!X`xV&V-)|L zsq6=*V#}go*z`#z 6X 6rh}bKsQ+{#t+i1WVNdW^Lztmvct_vAVQP$WaEap!CIa=> zA4DI~d6|+O_?$5R)PgdgZ39-n@04rH&L23q@YOpoESJ%o)pEoB{R<=XbIN?Eu*Nx1 zUa#8idcHei(0e$TMn7Paw %_l!vlnDSU@&ZB_Z`Q7=)z-@^AAFVpFU- zQ%z`;So+mBD-djF<#!7B1f0p$@C?O @efL+8>{5lA=O@E# zK_1~nKLK9M2$4-nJrv?=!VrS;*2`~1Sk0(Q5=H8|HG>Xkv_glO=mz(HaN}WBRf0{f zrf1d~^CIs!OnAwrAkKJ3ehkP+l$my@7w3}5WusymCXMNne?(6D;Dcl-q4GNnfgw!C_ zWEi84Dsyj(udWNnVl-N)6Ayw85)2{)2Kz-UtZu?2^PzGsD6=uOI+Lh@e3*wS1ge-= ze8G1V_r>5Yp+gWPiFsI!&qk_kRDV}^J_2BEf$|Ig9(g0>e_K7G+_mN@h9R!{zI!j| zKde4B8i-MGCB@#N^5Cae#sM0qlp75*rqSO@m1&Zvl&@h?_p=p?-RmOw`;uMtbQXSo zYDFW>%&I$ m5z^ToL>#wcnc zoR*%sK|sj4K?*yCYW>~!vP%! %;L;uG zq7;yqpD{Vtjh~fg4M#cb#HCG}xw-u82yrj?_A|GeuhZ)@_xp>Flk?Aq9+iCC_k*KZ zqiO5;EwO9c{5>7z*D-mqKHWP4KLIWCC^la*!w;rN^{&*b7-{=6=YZuKzenpqM4nxl z&dt}IV;8I2f%cvD%{*NATL)^NPL|H2O&*8A53{QmcKR3Zpp&W}Ux(ZNTlm1q9omkX z&rP-0E9=9Lp}ZS>Jb^Dvho#M=yJP2 B%)ziv(+~v>s2cYT4-Mg`Sk(%#D9ouKw(c-pb3#z)+=-74(uwxlp `h+-yF1 z;%Uy!4-fVue%imZ?BC|OwbH~bUf<$$FGh_{uD^X*THL*OI&$!2fBdw&835Y0t)33H z2cOsLw5-8ic7|_m`V%(2%eq3ZA84_;DYhrao!(5o@5{Eb^>X0kdv8TscT0A$HC9^R zs3TuWAv=Fe0MG5)t-ItB9s>3XFFemt z6<0 zQjcHzEl!IOh#m+tHTu^vSv&jN xeal_y1Jao&0`@ds+ z)@?Uqb~1SM2$~gU!#E1}Ur(m>zU&S+F0TENuIGpQA3wyo^c@V+=p_~pT{<;7*C6tI zC~zP||RC-na|Z@Uw$dW^hMcx(o_Z&k u_aDEF9QgkBt60uQu3U z6qa7UsQt#M**x5Iu%NJbCXndA+ 2HlkRRAWlx#EIbOaI zdTc?%Rr~b&cD_A_Va-YV>{R}m>*0#JUVnCL2DEk)xX}kBEBIyWzJGRiudkQY|6Esi zbNGI)gwMFQSiEd^tXi>VIwYN_*sR>b-`pU$%X2_nmNu@KI4r!md-&n^^r&|Jw0?em zUd+T%yjEj0_iiHY9Dl@(@0b*-?s~QRb#ZpVcaEkcRW6wDp668md)*WoaWSW OTsWp7|nOTCt?S=g(9R~~N4@Vz2v|9teP0uYnUIB!h zgujO!yV-u7J-9WULC%2gFK%Ca@6yKA8Ju4mdVs>NN8Jt{Og8GEPM1kO0|)I!@peC_ zZ}+vX9?$D+&!oz|z4iA$OV}*r?}Wp8fPq~OO(!0UpAweWZ zV)Aaj!oypK*pruod#e+pW%f|W#oG 1~mve)!Mn2jvq{|fn@EJVa zFfzOSys@F-=FP~tX#s}4d47C-`IvrwIwRTu@O544sSZRv=sE1t?7rsYue aX3_hoj<`W*av-yuNu}9L?8mTiCS@_OrF});zBg z5^IQw`^N?w*tM26t~6 M=6e-&G*xRyYKhWZ*OKAfo7S-(wxF`Kc8Di_ht`$A9wc(zEkEN&R#BovvQiT z*wDWV+AsE!bU84Xg?!h#`pvJ^b{ pMT4*rBn5WQ!lp+oJPs*feTs(gXDH! zC57>cynlhriwu2wxX5n#xVIH%{z+ z_n1* =AL-5U zGNJ~k=?;+yTN}8AJ@lQi)X(8`g-~hD)%T>71)r=6_*lsLm>*YEd)Q IwS}Nvt;HYM4t*$yHL5(k}ag)* NsRhB1M7shfx;UZ!CFQP$;4b%0pfY`4Vff0?lU<7^@W{lW#Jty&@>nu^8N2I z`BM$L8S1}7h-gIM2dz|CrNmsz_;&7Y$j_|J2cQS3)Q0jjURJVA$AI5dCsHxFXRt|_ z=maWk?1E&&uZ=3nhPTqfo5QbXdW2EBM$8T`mt*~9(iRnJHmel1+ij4 zczXPVzJA98It{E9Zzk}URyg_Lf9^|QqkuB)y>_XP`NKuaL5k~97~%S>Ozz$rx~w|j zXvrN=>`|m`5wQ3 ?Fznc789uxbxiy q zk?mc;VbJ>4H~|tFC{Zn6hI8gNytU>Z%DVydeZPx`wO$mqI6Ws-Du{ae4vC+P^Ovr{ z1-@8M*BmE^mSj2vZ7K7q 2w*2n&v(Lo>5tv17 zM1@vCoPvk=AyZ`|9AzZgy<(d3Xxt`Q835&(AcjZ4Tv|8X%f3o5fVR^2Jer$GU_JE` zl7ZeeKsHNJ3RvxGliry^&8>os6ITc@rrYJNcF0=Xe!{QlFP5VdUCZ1Z&Y3nG?DWRi z!N3E+c93e&c-Xd=Gp8BZ55YJ!!i1A(+sz4aU{@FMjTtj2U;GRd3i*l7qT-*~hX}Uu z+6< {6lT8{22SH002ei~8yf&nS4Mc`QLXt^SX+u&o9gl2KuB8hbPtOOtpSA@S zKgjOx!NwKJ2wt!vukJBqyq?N_)en3!2+Meu4&ZuD!uDa7$$I_uZy3?y#F t z64-kFZC+DzDgftb9}--P9VrQj)Dxj@UTJx9r`JzA^QE<>MQwe965IM Q?(-lh vAz|`Jm<_=YXop Hye$F=t52{3rP}lvp%J zhzg9tF1~PwLb8ZnKEp6Zd$1-Uo@!lqU|Lx*g7I}@AzZ^oj6qHl&thiNtXe0F1-Zxz zaM;gnuC>;(uS46ENG$5<(jKa{#j*fe7e>1KGbe-|hP=X;Fav;E536w|K(lSv#RvY- zY%d@`{Hxp59^p1f2THMStxFZ3H+D;iKcD)VGRerLs+e;`Xc^(nfv^Wok&6D4Lg{$d zPivy;EA}@<0z-Gs>Fw{G`P Iz<#(iy6B1=7&>CUs hgNA zZtsJe%R0<5Tds=$Bz-kK}H?l74_+ zuYuq?cka4>hjpI4k!4(;>Ekcvg4oG;l22;;&X+{>?DmAY<&mi3a04}ZuAynTQYgEA zC~^txQk$tn7b-qBwPIjPdnZ0>I$cA8__CbuY~6uAuWe>xHh*G68~qeH?8-U20*4R= znbZ&mdVavDd)V=bqx5Y{<5`sdn(O95_P;#={KeE|h}GkcvQqgY$(b%L(re2gB|e{i zf#BNBMTYer&$Q@5HxG%*`V2UmldpGo*ru1SHWp*Ie0jN%Qr%NLWSDn(03E5zH&S9M z; PFbY-U#hDtu@wVN%>`%_I7)wI~$<(q}m$=9HCOksa^u(;7%xvTv;13 z mp8g+P>^Idqc+6o>zC^e zx; >tO&k8gmpMF^ug*4gpYL*cCN>$=-SbG&S@b7A+d zNmKKyB_^%UCub8gDVDh9`tGJ%H*y;7gxhn*bj?~3Bm`L2yZM8O^`*qXX>0n#-nv4e zg$ZrqpTPFqp?(`bXJVVq1|P0^yM>j^+$6hK-L+nLX}AYGv7VKe=P)WmPQKH+5PtxV z?0QHhS2n0<4Ocyjnw*!?TC~W)Fysz?um^gfu(4njOpqHASZyh7WI{yVXpNxrE)4li zcJ6O>iN@)}e;eJBb}rqA*HLM-cJS|y2dm%G)_v_;&+@vw$DD`I!Ja2|?&T^LLC1wi zMiL7W%cR|s%S2uD>KkH3U8=-p6x;x<)tEuvtB4M`@(pw$Od vIu+stN}r` zmshuiymnERi*FM7t6N8*p>w3gn HpDqTwSNA;WE;d!Tz`x_&nQR6U}3+^I3r3*YS z9y9OPi>IVtr(xc)am%=QE6!iHDY$>DVh Pyg5Es?@;Y*#dCksA=~$Pkk@* za=0(F%l}01eP%W);11L!F#mlB+}oum%t`<5KIY(-?ZAfz*t%>zNsL2;uPB|B{}LEZ L*>aDB0S5XXFI1CK diff --git a/data/index.htm.gz b/data/index.htm.gz index 0e9eb07009732d5d4eceb41176264f1db8bef789..139f0040889174476a6bea5be844dae04d7ea073 100644 GIT binary patch literal 1444 zcmV;V1zY+biwFp#k1|^V0BLSyWq2-VbZr2&SJ{r!Fcf|7SC}A3$}~yKPTK%t-vkH{ zh)p9mxoJ#YJJ?P;1LEJgc9JGjHi5)T;@WpPK6gv!r|vwv{p#)WyQDB{etj^nUu0eY z&G1d;r^0aX1{UNFY=FxW)RepcL5(JlVWWU+62MVJ-pMZ&r^CTZW?+iOOgW9??RFbU zk#d% >+j|Zy8gmI5AM+v z7E-QGILMpLD3$BD)4tElgKAMrY7|{EQ&fvRp?gZMr{oDW8%9UuHRWptiVniiU40FP zI{gqnS8S7b_5vVGXb`DK()w5888|YrC2mI2f+`IrsZ1VT^_&&X#0qc46HgaXnY1#5 zp{hr$mBeFfx`g;BtoI59dE(`CV}C~YsBP#}vC@zXa!^F8H1R&^cu_H)Mb@K Qspf&fnv2*wQD7`gcAs<%~9pmOVoL+K7{K%JyDA zg!)hP (ZC@!uTYmNpih{9z^z6cmrtwp zkbJE*NV5@!vwFkYcAJ_c#OXvE$}5O;$(aef55gPvMK#Kp=h8}#M+8KM>pe{lVrhz2 zDVHj+ibqyshOc?;t`WnXgM$tpVR?X(3F&|@(DG{btr6$|93&)gmfjzIY>XXDc38i4 zm^+lUcw>5})LLv*Ed(12i7$66ORl5&r4<~KQwi}Zfw_ftGOvfd7SCl`>0k$h{LBbq zX}$hR?yksC%0cgB6qrg0VpIit7j2Jn%5{78&85kfiA>rN!X>pP+oTB^ B)hg zGo_91z&p!b4dAjFXY+;3j$P(vY(r8`wZ=lUV+jdS#JT|$E|%VP=YL*t!ZK`Miib_X zc&%2!vJ8aRPO!wwki0cYL`yJtIoRc`}V$LyW*tGM?Ewt?aa|@i yjqL8=x}^b+_9@vYpa;JgU(NToesY#m_CVcGVa6J ztvVyQlsKSK=*J_-nE5}P)%Tz_>6Ui394 hht!Bjk^E4k4$ekp~_^TRjn9y`?dDUufPmaSNP=Fa%cwe$9Q>#loV zanIYmoy+cdr`?&HxjJ#rTI*_9;>eHigW=4Dd*?iYL9)Q_I~c_JKt|b)GvH;&)=SGW zyKYbCF>OdNP1kH?v0<$p=}L0T@(PZt5 k;clgQLdZa$agWa&DkF!eI;<7 z7GT5TDzQ$mos9M0`rFGTP)aH%)TP2+-Y$#?mr7P8v8x4_>B>gZi7`=DrYGn`bd{!{ zbraTROieG2&-7r~Y1T`oelx&x+Y7qeCjJvFZYGvd6!|mzu@?Bfvi3*BC#c|&TH1S! zw%f_QsEm=~_jofZmY{wMSJMsj;M(?%2%cju=%nd%$P0A?T?18V5$S4y-x!EGm<*e- z=AZS4@5di!Hhb@2$2Ac6v47B7I`AVKh-mo*Z= iD@%C zZL@WoFZMOJx;`C5ekH;N2@U`y+qpc$_9ok-WN)-D0FokQ*S$#ga+in%f$#T&&-W*g z>1W4(J39OO$!n76l)pTfx*sx4fX4Vsrl0x#!8@3fV^{$fImj`23mMgl{25jfxFTJ+ z4#>~qw&1jPaLP1{QJBuhgTZ>e4n!7l7F`8=b#NpyO(Q)fEL#Y2PW1(8d_BFo$#JPP z!VkZG@%-Ry&9pZ9zI{v6TL$XjI~u`Uh^v-@ML8HmA{}g2f6w#}#oWzQICaT%Qp~p| zeJ4daCO=ZWVzf_wqC90F>4ERtt*4-=UGKv`3bqP8vjNDouMw$7BKH=08m{%g5H}%F zLZt#77JA{o@T?ThvMbyb4?UF#siQ&@hD$wSq=X(z=@JIlz8gy @VQqdAOtLyOAg%*#7z4oJE*7{E+lV^Visd7IF@vIEJfbc zvVh(MH82u!s#NHST>C6tqN$99LoXMKnN5us>>A>UWXnX4NBK3%&+V_sX~gu+co>X~ zpaH|bwBAH1)c~L@L&q>&f%NA~N9?rVcB2iHUbQG;aST~wr@$fYcIwRp&IxbdWHDTa zL#w^uPHaV>VHRYQ!xk Ev|IgnUXM)q^ _PO^K#*Y0}$l&S`e_u(5{|`*j;xquN zZf0+Uo-G)MnYvLL(!rWtG0Z52!O(Lxj=VEt4d+XM=hpkIADI=UFPRv|xTF$jHFqIo zY8jD&8w#%ArpU1>DJ+I8{u2gk*P38Oc>#SF9VUc3J=|^%oJR>5&K8s_@HQlyIW|3% z`nC)WQVLm5s_fKqs=3bmr4&U@%+s8U=&EF%Oj(v=8Qn~@Q&bT}VDf8e2Aj;rUk#r% zV3`EiuyixEnC~Xw>)nQ(A2G^UwhV%xGconOod)`(LvVpd+-&bBE8C^Nd7-t)9>yEf zY>9sQ5L`u9(12_5Cn7k(jzNWG-b7xgtpN(CjFLbVb1X}Ux;sM8%{jxZ{jSqHA6`t1 zw;iK%Ys_bZ&KKQE)Hl_`xWkN(cY0rR0%MzCd5arVki|2JEf6R@Gq9{j^v$-rO^4|J zw!lV0-6hXjCu=Z%YU#O`ak|a6={dK!J~Uj{mB5gWgxWIXJd;$fp;w2TQAxBQCr8bQ ztJl?0w~4sBsj7UyKkXXjo5XWBGm%{6K869dkLzE{F}936e>UN;(BtRBXOqgChFDut zOj9iL?Kl6>4w @a}qEzQDk6Ymo+e~`lqO9lLn~F;E-15raXc4C9oI3=SG<<$}!ZBMyIYiD7 z?R4PQ-YdwG*tdH7EbgZwF7UmqOUY=DwTFAG{c?}BU+uB>`5tS3zx!I_gS)QoQ`;l< zW!Xu3FHP(H>C$iqat91KH7C=o#G*9%e}zb4odVqeW^?}&>&S8GTFCfu)okQfReWD_ z-2v{h_9KaP;5WiuHrU-kW2`wQvp*H9wso3|>mB4 ZdC{(o{F0h*K%cwb1>`tlab 5R+L6%gBu=Bq`_jNklVJU_bNzJ+}PJM9_y1b=SK)4#!;^ z$Eo#iQt5dz-FEJl?jtisx__*$(s~;`?M|JTmUe+&r^m#!v6Fo`xVdACQ#ba2?%nmF z6SkH86*D&JzB%qa0;y$MYAbkU2TAw)*Jr(rInU3H;){#Na3fo8w>fk*_$l<&6{)SU zx<#~io0idlyuPMs&SCtR>dRWWrTxT>HdPM&uc?3g%K!P}fBgUc^W(q#kN*yS`Nby} z???T^;bR0*Sx?$X{$d9$3w?rO>_Kr*o*nBW<(6*DcAtEUQr|<|J@Iun-u&wL_}(-5 zuUvw_f)-rga}nFvcV{F0hzoW9ng8yQzm~myPxt@3e0$fpeA_<% cl-v^l diff --git a/data/index.json b/data/index.json index 2f430b87..bd0b9d88 100644 --- a/data/index.json +++ b/data/index.json @@ -9,7 +9,7 @@ { "type": "h5", "title": "{{name}}", - "class": "alert-warning" + "class": "alert-default" }, { "type": "h4", diff --git a/data/js/build.chart.js.gz b/data/js/build.chart.js.gz index bb94fbc947e0700e157bf190bdafdfc173049ad4..ac021668f0edf424e2fb22d4a8fe7ba6388bb3da 100644 GIT binary patch delta 17 ZcmcbXd@Y$nzMF&N!Sb~+8#&Gy0sutp2Ymnl delta 17 YcmcbXd@Y$nzMF&Nb@;xxjU49;0YiibO8@`> diff --git a/data/js/function.js.gz b/data/js/function.js.gz index 7e661ff6e29542314bda1c757bee5e25ed3e1fde..443fbca2101295756f788b4771ce9a9c1e023b20 100644 GIT binary patch literal 17521 zcmV(xK w@V{~b6ZZ2wb0PH>KdfP^l|Me7Y?3Xk+yhPcaNhp%q zjN&Ao_{e7|lkAEbeIVHsVSxY#0CiZ=bL<1{i)~ePH_!k95VV!uB(we^iR`1guCA*a zNcT^BKZyzZT3ib+Sc$OD-U;7{Blf+x4uuynTikZoe+D1cp3~SnabwYEi#T5OyWN|c zn@-?QJ$HK5@vird13z}Aai6*VJYZ)|e9nyCldHQGObrqE!Ixh=-#fi=;~3Zb_jk_n zgDaxFZ=9)^1i@8ifw^kzOoL@No&BvFf482 ~;|z?lE`H>>Jmg z1vj0aU%&bemVGDwxfW4O<8Tnn_Qeg$_Sy}Y`@n#aA~)_USm#>&{C4tQOk>-6?M}lW z3g$6^KRx}yqM3WZv3MQ&5(~goq8bT*mce!%dabGBc@t-P)mn;p5zJaMCw5v+bmvbA zN2EaZuqQ*tfB5l~LwmHIEZz8G=0?uM6Eiyw*P?OwAcxarHXIJw+MkKJ>x-ErS9LHP zEzu-SL5t)hk$u|%h4O8+=x|6&9`SEqobo>BP1)S!ywO7JC8Bbg9|~u77sXC2rVGcv z6q}ME{BAom@B{|}n(UeEs!8hH0jUtJjA`Bx$Y>S#kvJ8%aRd6G|KTvhz9GVVdqO}_ zrXY@3$@@FNM}#)V%^>`^9fQ{M7URxp1v|k(0=l &qCT3iTTgui( z*)>vmUy67`+$7#a=Bb=f5`as12Q$vj0V=G-Y;3&}cd$7b!6wXUSZB447Pds=$9FG} zgC&p;xZ5zi(d0wkEa*cRXE5Nrq3}-B5^-zV5;72X8841N=uO%1K5%`Tf6g0y6nla^ z=|sz4ds+=r%2(?@Hsz?BC6ouz?}~JjDBK*a9N{K`WG$8+8p`1m_HZnImfw^)1o#Qv zh5cmDN(?gXNd>&jBBMdhkIPzQzG0Dh&LYdHV3j33U<57zRqrBpmtYjh!w^Ie2^W`c z6bmk!-$#M}gL5g;Z|{`N0oKfd>3Rv=1}g}x2J(DE32f0&!WP$YFnJGMiU;7o{rHG} z_k|kb2?R7uAc7TnA>00X_i|=)F>~YgR9Y$`4rhVE4Ua+c0Qw{jUH`H(2RC}GT5Y** z=Vswf7mZFFyb5kac S3L1VS)j|UK;z)@(i0mb>Sj<^qqT62XzLoFKB{{a663!Xb7$?LhT)z7WgvyS zKpgCN;YKZBu%~cBsl%So;`0LO9AGy&;dIdfUlkGe?Ovl3f$xA2;d85TwtwE_9Xa=K zCmK<6K~a-k6|Vh@D41S}824^sLtuh0 X3hfRjyj*c}DwZHR;HNe|tvnu^ zIsz6=#W6O-Vlc%EoY}<+J`qby0D3KC0S<^#%T!afmGv-}AV8q<04r%eL+m*!uI4 z{?O;JuDB(g*TGXVO6?wS%deey(Fq+uacMVN_YbYa#_9l2%Dt51Xqpi%wUs-IP|N|L zWF?DMvQPlsF3Z||8KUZio(%ant|#6E@izek+MGOCGTKz51T_Saz GJYL RGKu$)z-_2z%8^-Gnk!-eI5k18k{mP5A7_4abCea#_EvD3}UoKy`h~^ zN_)|iw;m=%S%0dA=5)1e!@;7hJjistZZ`);Lg+YA XS+&^S@ zY#@EH8VD`Trnyy3>wIQ`puY-3=gw-L-JPE&e*Ery1MAGhj-EHH5$$9gSG*9%L2%_# zsFdj6l$umn#1DBoC#4R?_ZSg4G@#TXGaY_**Y2I`@M}n!MH1b2|G~N~&Kt;viWxnV zH-*fJ0`QE1|0=k2G5n7NeLabT5CsX^_c9hsG`Hz6q}XJWO1B`XjzRZJ_bGK7+yeE< z%xv6ezUG7EhhiUrY7V@t5p>hgH_lQpQ&X|A1UBvEda!Az36~m5;D!QYQml5G ?wQX4XefSAhHWoIlY92Nie(18%b^Ry0gHC{G+pomx*~>xU-q?+qV(R z8oHcm(uQvpL@w^F{@lG4v%^Uc$HB6{e`t*ct_C@GuG{Vs?CzlJjv$ZBL}i^
m`ilK&`2w^_@^vZkO)5 ze6EnMH8eIYSvmw$L_m@Ln7b$&F(DR4Ftk0dG#CSN_iT$6i=1m=wJbUvvYOWP%K8|t zY;nz6AskPHF{9twNojprf||L0|M}{cp%N)z%t3q3eDGm&^kG;%1&^J}AT3aij8of9 ze1zmA9MR9BC*5YjDs1ZbhzYW~153it!2+iojQ%57V=qINGWaiaFBdV5IWW;GsS<7U z=gUP|RndR5Zh26{D^~>-pv8Dvw-kQ`w|SK-ebft|A+@d_*Q;7pKB@;8+lpV6p^?@9 zqGxRsz*5+CN@2<1`bDvH&O`Zfm4&j*qV-B YrI% z`MKk{*Fu6n$FUjPfTd@Ou^HBV(MqrgToDWAvI`N++Kp|FuBMZ#GCk#H2Zdt_;gjuZ zR49eSzUO4{+PRwub_Wc+aljeG0izuo1rS9^CL-HJB>IwNgT+(k&LHrBJ_uhT$Ud`4 zQh+DI7>`gY^a{S>p-P9AeX2NKkD*C1j(2gPqnR5HyS%dcMqZaExB)z-C7`Qkl0{Xe zwqz6p^kJM73T>w~Y22&RFx%;%AqST*p%0CtUf;GSy3tXM?OuN$B1;7ravDl$Tq;Al zgLEO4%(zA_qs=@GICIYlqROxA_Ok{Br=+j!mtR=<$iJi`JC`5Q3S_CCrQF-lv?REt zJp{}?l38?aWtq)&xIDknsdi?NiZ)Siweyx%ihdiG3a=yRZ`oo!=9{mB*%}mSNq?f& z99&;=wu4_}f26}lEdX^$tfr+GEK~y>`X+9afIb A_&~YRBo2)NS M6O5n=PYznZ!ztX{Ey( z$$r)c *tG z2x`sFAJ8BGDRebG)dFJ#-jKrnA@<^z!_?gCJ~G&g&?q`6b ziF~n@HxnT>dCuk*EZ!rpl5IOEXnR`F_N<`oc|qHsw-d;ldP }<5K&D?9$Y9(2G zi82tKAl;OnDy5(chZtanfyb&e1gmC-p*iB}%aFq8q+OdQm_TLYMc_f8yWO~H{jxC4 zSd%qOEEEMtTcnFe9Zo2me*pn&Qh&cP9%Y0(=xU0#N_hpC-vr_8UqH%#$ZgD&JcbtX zpB(#eOnY|>o%GexGTy%DC+j%I8g^}6pyv*Lvx<;nucO( ngq9ovdL?)&@5(|bC)C&nhCrBWE42n ziCLV0?KSRA5b7g8WSK)YQ={)Ub($W97+P4JqfO<`TJnPecQod`G4GH0{uqyYerrmT zRP{cYGRtIKi4w}o3E9xMR5OcBSWaK19%=n354IJ~upZkX)+T(bFE3>@YQIpUhL-jC zO0`d{@BIOl%A~B0QqA0JEp}P5ZA-HP4*41n7IW%m49|=!=wTs~L`z$Op_9_qyxMKG zs|s#9!&FIg ^^AOC0ikQPr08HLnQ@0 zW{IJdDo!#6g!8trG!ewd_;PMKUI-`aq{~t(oLnp3*kHqGAXmW-`qVbaNiR{I{ljU0 z*l&M%-o12NyiFp5sUiH#MuREfB*Mz0B6&)Xxuc>^k1&(c0J;dRi(toH!Uo{uJsgQ1 ze%b{+fPqu!19B+cporWlHl=Q8hmuSLVwmnyllhHrV5*I;)K!60*-&67M5-!x5_5EK z!FhljY($O Pwk=ANQ5&SLgNvb1zG`kA_=dw1t~`IV1X=x#A3rzmu)P$ z-p6FC)%h r_$)Q0MEosZ*7L4SlFj{qRw6BwdO@k+t?VRt4PGOkP_oh{Uowy7rJWW|UK!bIJ=H z+qKk`E3&M>H>J%rjee~|gU9n%k|R0B7=&4dE{s!UpxdDo(~OhISVlZ!>&BhMi~bkS zKO0+#$j6rSAg8L}XmhI`LoB}K@y)t$+VW;?OG~$FOoUZh+@0Ih6)x@Z7{G3D559=_ zplPwPzNbxVjJeDGrk8~FF8D8?JwBR=Yj-M!!4(eH&xgWi)!zoV)MH!`PVRU#?#stN zv<~*+AAG=z>SN24S}HI46s@OI5k+I2YLBe~nogW+0TiitaI7*TkhfK&|AuW)p|8|~ z-t*5ko}ZvslH^Q>RbU>bUa+2R+J*FbF%2*-7-#mw6cjB^w!^@@JZvJq&8#SD=%!YG z{}7+&=sW8;kOqe^fJLNPuONXw{J6qRN`^0cF7Hgy0Jb(dl(H6B$AsM#>?kk+$0-`h ztfI51iT>B>8Ox6$pc7-Q`4NfG$ZV3KE&=I{UWL(-er$AzcX%w8e6>uJl4nb|WA($a zi4QuRLZ!=^+d?lahwCBc^8$# m)mtDz=|ffq=G?0)sx1m?)fX(ju>E$U_#jf6B>~k>w8c@^QD;5$txV3j>tLzM@bk zymIFu0DFv!2e70BrUjEJV|*O3K!k)@<7fiB? kv) zYEUE7z2X&Cvf#VG2HTE-Ov4)e_kRJ4 Qnb$0vU`3|s9Z5`0cuJ!Z1a=6~AZReCz4SKNN^10(HSj52|CX6E%h zeBLi+v3i68udm;>?pki^LxT+=y=Ch3v*6tlym?!39*)F;_BwdZb*IB{`PC&)C(pif z*7A&_x#Z0c^kxfr;K;Te@0ba-iHungR?oBpBiiu-8 ^E#+EBVG&meE>hFYf)>)4aChY z{uF+GQm-=Iy2fG+zn|e6@Tty>dFaCL=kW6le5#z0a?8O--u{f-a^j*nRce>KO{PTg z(nCsFy*gGsw#-{f6p!5WSDu%uo%zhyBcUeuM7Z{QQYqn6yH^-6yn`_YD&1m5H1G6* zS#0C>F1!w4vE-Jiy?=&w_LrXga{zyyo;U11{C$2-ZH@bb2P=Q;bOS@QJ 3*`|a%JH!_dm 1#AYs2Z6*--%8t zd17 MW zuEw7p!hj1v`Gq!}4}4PXzeddxUDX?LbGpD+iE1NjKJ%(yLqWAw&z*}l0MM_ZFy2E^ zdW``R8YjH_-*waGqFX)ni5#2_qbZ$yML5?aFzdQ&xWn>ee`$fDXtp8>_D#cSV2tS5 z`>=zs?WM2J?Nk{^C*NoEMc-+7iBF`ScSx-ohmy!^Aust+BY-Q|cCd308+k> dbGHs^G9YtaY^-21LRn3TI=whq9 Lv%F6<9Pm?BFV zz!GG2%_T#Wib&jfj-+Hj5VmQ~jszP;fr0?Yo#TV>b+iInX7pa4oUwggWU;e%Vupo2 z?ZrRWw5#l4BfY i>>pTU0N#6kJQQQ^ebK`3zIsA9#T#q_)9E7mUPc^ekDCv*;m zjiUaOK;1+rp=1j}il&c2X!KDCJt-FFn;=dAKgo!+T0t{OXsPbeelfz9oDx3URKg^{ z$ixo_GV4}8Dx}ax>_A&1vYDGkt6;;Ixp{n~y{!`9thd)Sydv%;<$=5lqI(Tian+!R z*`tD|zIM%|NJK^=RbxsJmZn|+4ZHJKkn@*o^7oN4c3j%b4OyZvHF_DDLRj*ZkLTDa z0%T?LN)jzAbmckeilVAnw8LPHibB~Y*Yh~O4S#hM(Rk!BtdPWG=Gi+if?~*V5=2%p zA`OHSmQ>M?kZZ}v%Aq#4vZ2wo_snl>TD**;8awz7HoT9(ORAOXf58Kvnq_aN7-uXL z1}8d5t3RVCl567KCCF_Qs&v(e5}w>_M3Yf(Y2Z5^C!sG5 >D!9i@`p!Go??+no*px~I4Jf@`9Om=lh?E^f+)s( zt361fiW))1uV{|y<`J5i0PmpC24}OZV;LuWC%jcYKcbHI0(uT)T%kY*0Q(@5D7bUE z-e#(h |!43i199S6l=| C@fk zoIVeIeDo?Eo4NY#Lo;fdeh%f`o5WLb1o _AyY_zv|s*k+x{Q zr;M3gicEeakgGbq$aA|T0zqC?m{Uu>|4;A#`u>0Y`fq>zckloE`~Ug=uSJsT$qOBM z-NFX<9ng1W$4p=px;xzFKuUd5#ug6gqFo*>INCSZhZ e?{v0H^)laKhh;-h{tW!LWeKZ9ZTfthE-49GZHQI}4*JI{5Rm z)k(TcejW)g0cDC)a-ih|(tEk%XaoD9H9Rol9b+<3Aa1v}-+C3zT7CYD5$ZV%HT{($ zMdVDub0>Mh@VsQ)R971Y>(f0ssuiAvheKAqD>Mo7dn>ScCIXx9S&_}*(hQvHHzKYt z0n21lPnpSx0H6qDg+R_dNU|WAkJIH6&RwW_=~R{wvlv;b{56I{s(ZsI$O3Cl0vAqT z5>vgQTnv};IGv@-{_Ufqqd_i4_bOdT6ZXzPTC}Uc-9I-ereOaI_}^eLn&8U`-nYRP z$ bz# zR?Uao*|RJLb6yI2${etwtCKOj(6)TPy~Y-4PdSM>-J&*)Bcix?%lg*OF|Ttxv|W_1 z8tABkMFgdk6V|5|x+q5fCr~X^=0)N9V0S%dEP$&RQUiqmzUIfuEW~3VSfnp%ww;SQ zKAufSOUb2Ji3pS^DWVJJ@--16WR8ix4hyf^*G|&2WroSFc02p=X)>pe-TgS5j_G4> zf8AZaJU-lzRnhnb4(aUlFh@_@-rATKFqytpd 1w5Z-HZo8N5n8CSN+x^h;}mtQ?X##O;bYulWm9NFV)Z*K8}<(kdrwG|lEB+Ecl zt8P=v_4(oT<66w-x&CJ~vRbr)v;1Q8Q~D+wwO^(4^yui|hvduTAbXpv#wSr68Xn>G zMo1iew*sb6a7b1gph`6Omx!y!JhTsotjRQQO{!&sYk0wE$1+rUaN?A5-v%xGVhh7p zfnAxZ$_a|GfQdEF785{8Q8A+i$In4I&S _#l%4pS+||1&$!v EwGAXaU81gC=h7_ *GdtAKNxtb?~m-ztDF(zij)YtP^}`2bck+y)*esQvJ&_j$M5rhj_v=hO5B zh{v &)@dP(JVd764>~E6rcPP zMyxcKX$lOF*9%FdRc)EH m0`dc~agq3|h$8OUpM zIv=wN>lAibvH x*hb ze|9sO#x4HC(P`|I*EvgWGub=kP2dngK@vO&J{troJ&EtdgZvP}MpAF-P>m9(3PXrS zx_!E(iz&D#P ?2$V-0ONBnP)<(i`%L2G;}_hy_{ zHCm!45Y)$092h6J^qC_NJWhj|99`5Dn0m~55o63K0Maw_o_2_ltd7GA#bLXU!--)? zKn4H-;Ber{p@O^jjly;Y=#KfPkBW7bu)`oe)oPa!811VJ9y(_Z2`Yt(yUG4;luRPZ zi~_Til8dJ%BLHg)^bE{B^t)eiWuLB+w=B$jtX{j1-bPj;J =Sy9W@);tS(y5?OJS8_99!6zlZZ(%+YS3{+$DTJ zBB%!B13wEQirMX_kAKG@Z`rWlz5M+g(7)B@^BxMyJsnxE81+d{kiX5jr4vt}Gg+;W z!Ksl#Ky46g--tHY2qIsb@a4zmC7!FW5Yn+lW_j}NovOK7b)qp$???g8lkEBEc}*gr zu6HaT5f>brk;4BOYU7YNMS<9~^m&MHqO#lwE~fA{xYUTI?sZ5*T_?{SDaUWblzm5U zjC$Ht!p(gx;!WIoNeKObiGo =X+cZG-Yu;#le7cf1kvuf%7qt67SS=~7li<@8 z$i3y>{FlA?-trgxciBFU!@W5iaN=bKKYKY70oTEg7~SGsCu?E~JOOwho_u(?Y= v$Dq9!v^u!y^yPmT^iL*;A2ow(pm z^z)z{s?%;+W}(EQnut(IfQ`2pt3%WytKklZI-|jkPK;p(LN{c$Zr}LQsjJ)|9+32) zsXHGIyE`hmfe1L8o4+lGnFwghrM@hYs3J20!kT@MPuB=|!rmIR37p&33`wBQ6yngb zH$Zi}`vaMi@LcDDAO<0Qo0;sJ<-+xF20M2*nfyh@Z{U%`O6>=$WmLcA+(-zrxQRq( zG?*9|#~F5uRdE*;dJR{TI9Qzk3yg%7+q5$OAM}NA94P?hOGkP{HFkd#H>dBZTB60O z%<_Us_W5dRm6T{fJySK6by8Tvhm^fjrJls8GfPFajSRAQD`juE3@iPZCUZJq_!^<} zp6_?8#-(`dQ3aDGq-!3qM{&YYKYYXq#c2Ga9rUDMUl@nG^t!Z!%`>O8(XbnVR-4Eu zHopMEec1e`_y4u|>%V{hADZv~%dh{jf6xjr9MS%}ZVc?;W$3tIitH8+j#&sDO(Nz) z6wVhy_+m64hQ07ZL?9<-#7I($99Rp-a20tVXI{sm*$@-Zes}mI5O~eS>f~>wWF82W z3EKufp-89&yu}HK`mli%&+ot?vs&KE-Uk_RAk{YQ_P?05xk<@QaN;(10T3A_Rn!`= zOuB(mKNwsC$Uq0k!6MgCtcXV+)R0Vs;33R*2bfZOh+h>CEQ^Xfu+p0pyV;FUtYX!P zI)bcD3a+tc*al^yUJ{7G@W`W+P-0gyLk6FK%5EXxl?10Sm0GBo_00@bLMo&xk_CJ$ zNx~zz3^y#PGy;CW%m}%*wh@M}$VU(@;~yV-ji?xQhy!%IFe9mYXo%!%wFaucs9~-! zh1QY<9zZCNqfyn!VO3h@Ga$C3m9L<@j~lU&m)iJrF&ZbUi+-oo8<c% zuh*e%%PyTIoOZP;?zQWs0AxTAjmWUpRDTm$<_HwTMxWO!H1)-47QQ;?nR6pj_eKn7 zG5-p@sS!}AkSW}C%Aee|AIKF2kewY|9BjxNxGS~uu6!k-g-fVH1rhefA9j$3X;wmR z3Pu_dc}6L+IdoxJM0I)4K3rGx$>^e3PiznSXMNcT!{N+#V>>T`qI$=1h0qn}3}q$5 zSouyT5yi?KhKdA5VXZ4NoJ(OhnX57A4Cfal*rN0$%Y zZU{_7W#X7pHmKg!Kyk1s8`Rd-Kyef*8`Rw^j*7xl*`V%S4HU<%vO(Ry@)}Y=D?53; z*{H~(nt@hq9+f0UzGDhcjJ0I3W8P168;8ZiC#=jfvW=DQQUyHKuFX=n;yr1L0SU|# zSF5z>$Y$9SyM0cgS1ZX-7YTT@#zB%L9TuALTuzSx8t@On%jxmc^F=MJ?e6VmdwZ|; z8#{Fn_~1)pZ*S5-3)Jv5ITp;PPtjgbwLu3OPowxS9@pQA)iitkOEPI-S7E~(aU=W# z%p3h_YvcM(81_e(ZWnK%us5;B?kGV%lwuVfz2Dthds~w#pC8^V;h&T#Wc!P2t-Yu4 zcXpvL^pVWaw@C;2OVDQ2q9(MgE-EcqeaWqk>$dukR4f7OSO|(kQ)v#7O!|P=Ee&4G zr#OKF=ByE6c;ex3sMy&ZS=8ScjMiyX+YUFudzdu#JLEy4hF(9dAA|#dG=qvmak3li z9)Aeea9uY&XdhD)G5rfr69Xd)Jr^L1b5Q_ _(O-ft}vFq-z1W`*uy zpKeHo6M1_wU5eMBO!1eto(q3r{UH28N)x!L{14Chr~~4WzTW5#{8~z1E4=8aYw_}D z4Ak~)-I9s2&@3}MTVPCmZn@ptDeePmDzjDs5}^UbpNQ;dzCss1LcV5?x2_giB5H7l zB7|` Cp&N5wwj!6+UFqt%W>g20P*5tS q8@r`dwCvw1B4S(!#f=fEe0U_OTE(aG)-qyMxvs(QmLKRAOqZKqg1XIScOWT} ze&Z`JUHVpxKY-0<^2#;QeRKapUXH#?aqyzrWvp)o(wWc0R!6XLs-c@4mw3EZyCI zzxmuZpNS{$#b;IW-Ft>`oF4v2*PcK+|JwR#dXZ643#-=fJz#P+o+_UVOwySFb;JSG zWU-ll*oE)t1PE>E us2_3;<5p0YKMdc(NuIuKS&?Y*z5CK>e9Vnp&&V6@IXOfZ>2q{iW$q ;yn!-Rwlkes;^lsCjhr@`_6y>5skYyqvvXZxY)Sv;GzEVcg>rHr^b&xz>?q!=l zYPjZGG-K*pFOSSe)i-jYTzgjVHHn)+jfkw%cua;}ScNU?zoqQ`n%k(p9eSlbDt9Sv zQafx_K8az}Sf$FiT7Y&j?WG%wId bTs#z5;mE$O#o!zlE8+9$a+#7Tje>jW zuqlHD@%ldJ*I`#J?!I#*RncTY5;pmMy!mUhffZ|byyjtr<~po5wbYo&UuemqbuvZ% zct?E_mJw$&E5 Buq87X} bp0a6Xphpcb-K$4@Nh>MvMhTdr6k@ zvH*atG5Pdt#1zJ%lYqvoZWXgdf>y9tgkP%|E2_qIH&dM>#~Wa%{SNoS5a(}<5amH( z@m+4Z$TyLM;H8vflW;X Bck2+ZT4JQkJ5u)}DdE-N t9UX6|VE;PI5S_mj>mm;y3A`wf02bu7W DL$ z%)ZvFzG0_HQ&3}OO=8J)f~VV>*nfjtB8RI%W9n(g|DND|O(=OwpdwCZ%)gin3Kk}l z7~cclRlQ%6iF_WA;d9@Km6Xp4dhM8N!UA9h17HLr3~yL??-9BbtCd1^K7iBB4j9G- zjAtVvH4tj9q;^obaEGVUENq0?2>v>rh8V`;c?vC7!7^%aY>P&;M2}>9?pCBA=qYBG z15Aiw!v}c 5>F=lmg>p1U h9X{-9!!!9<8e)DGUy@2_DYwhPe!Ye==)3YwI-fn=u2y~Sil4^dgy8t##9mH z*~8i{Pj5dC-q9mNKcGx@ZC3qU*5e>-hYdM-1lex0l(c}^*J=U{hR3z|g*A4RY$J-_ zVYhub7@tHWa0sXIbYA25
dMO5~NTXLhTM#kw zit`!XZs%SMp&u?M(wgG=BkJp;6;P(*RLWr@!PO*6@>UThF%qI}Vx+7uI3T?eqGXL1 zJGR3sX?`}Fp<<7I_{0ojQ&$>l*}No1r{UL3ki^ph9Q;@DVXk)gNoV6$MzOqmakFPW zIH*?+dV0e-+P~P74c^Hkf(oAljhjB&^yA>N2%IdDEa3Eu4>(sJ=4!hDlite$Ouys- z-%?>7Wf!Z_F^?Y3j%UwbeE-_)U!E#{MV8%NeQ;Uc!;@$K7zMxl;wpNG1%a#N>#o13 z=P%mw7v1$2-SZdSH&J5;Vb}~kdi_{Ssl)Fh*QXZ@*HaR<*nBb(kDKdyFiTuseHfM_ zm+7T{Z*d-U2BAO5luRhPZTjh}&@C!4nU(<_pbT(lwi@sYnd5cLrya81(LE>DhWDV) zF3Qx^l^lK9+N0k-bo@`#aH5leB>WJmo8gMf?p<{MDk_K0ub#e^i>IFbFaQFgz+pQ% zOEBw}nTu!zoO_1%4rSOI82O1Pn={CHt7#KD7*C }K0T?dSXMT=F6BE=|G<(zJiC&HoRIG#=% zh{f66)x1EFEtSp0;cdlnHu<}OzUs|k1lu}dWS}YoTn9Ut)m1 xv#^u^xUp@Wi>0_%~PZD}M zLHK#o#0&MO>NwuPxQPM3^rhK9L$n*`tH)nQ_ebw!4$}b>DF%Yglh4ZUQ~`s6$#xeq zo9!+WjJBt+S5~-HR(Q9p@LpNreR~sJhv_!6n!0;?{qWH@PovzXMD|mW3I(G^QNL!_ zh~3n_w#SEdZ=6(3cc&ZS#b**Z*DQ8(WqINT1qx+UrUeJ{xHXu~3gX7dlr^#n!bTwh zT24cFRSex2em0tpG%RYjiT2O}{(R*R(4E&u37M*rhB$k4@tR4q7V0Sau7Ld#6$Q4# zkow7R4^Rzc4rpQnWJ7$WNY-MMMAtOVK|#AJyhV~p%%7+q?50G;U6)1@l@#K9N25Q- zz@7o-UR;fmc~(;{NM^PG8V*qp`>y1)&dcd(`es@)yqC<<(F9G6mCuWtP<0Oyh^G$& zkllmTxl? g{YVIOA6!3y(A;WnFDGC&I_k41*@-Yst0jH1Bt!!DXf9_Z{u;cbcD7 z2Jo2!z-OK2=am6`?f~$4r};%?0ADx&e9>ukI}!q|jZ$)ynJX*mRaVQ+p0g~O ({{|#YwpJR$|-v+rr5;G5Y ?suqiHWWIc z!_oMsvqfvMOx{d^&w0}ZJhg!_6^n_Ed{n>HIe+x1)9D->!7e*F$daF@2i