From 7bc5be8db5dc3fe091de23de4c354568157ca1d2 Mon Sep 17 00:00:00 2001 From: Dmitry Borisenko <49808844+DmitryBorisenko33@users.noreply.github.com> Date: Wed, 19 Feb 2020 03:14:21 +0300 Subject: [PATCH] dht fixed, presets support --- Init.ino | 74 ++- Sensors.ino | 173 +++--- WiFi.ino | 2 + data/.exclude.files | 2 - data/configs/dallas.config.txt | 0 data/configs/dallas.scenario.txt | 0 .../{dht.config.txt => dht11.config.txt} | 0 .../{dht.scenario.txt => dht11.scenario.txt} | 0 data/configs/dht22.config.txt | 5 + data/configs/dht22.scenario.txt | 1 + data/configs/relay_br.config.txt | 1 + data/configs/relay_br.scenario.txt | 8 + data/configs/relay_rm.config.txt | 1 + data/configs/relay_rm.scenario.txt | 3 + data/configs/relay_sr.config.txt | 1 + data/configs/relay_sr.scenario.txt | 4 + data/configs/relay_sw.config.txt | 2 + data/configs/relay_sw.scenario.txt | 3 + data/configuration.json | 55 +- data/edit.htm | 572 ------------------ data/lang/lang.en.json.gz | Bin 3364 -> 0 bytes data/lang/lang.lv.json.gz | Bin 3831 -> 0 bytes data/lang/lang.ru.json.gz | Bin 5071 -> 0 bytes data/lang/lang.ua.json.gz | Bin 4448 -> 0 bytes data/soket.json | 57 -- ...2-esp8266_iot-manager_modules_firmware.ino | 2 +- mqtt.ino | 3 + set.h | 3 + 28 files changed, 243 insertions(+), 729 deletions(-) delete mode 100644 data/.exclude.files create mode 100644 data/configs/dallas.config.txt create mode 100644 data/configs/dallas.scenario.txt rename data/configs/{dht.config.txt => dht11.config.txt} (100%) rename data/configs/{dht.scenario.txt => dht11.scenario.txt} (100%) create mode 100644 data/configs/dht22.config.txt create mode 100644 data/configs/dht22.scenario.txt create mode 100644 data/configs/relay_br.config.txt create mode 100644 data/configs/relay_br.scenario.txt create mode 100644 data/configs/relay_rm.config.txt create mode 100644 data/configs/relay_rm.scenario.txt create mode 100644 data/configs/relay_sr.config.txt create mode 100644 data/configs/relay_sr.scenario.txt create mode 100644 data/configs/relay_sw.config.txt create mode 100644 data/configs/relay_sw.scenario.txt delete mode 100644 data/edit.htm delete mode 100644 data/lang/lang.en.json.gz delete mode 100644 data/lang/lang.lv.json.gz delete mode 100644 data/lang/lang.ru.json.gz delete mode 100644 data/lang/lang.ua.json.gz delete mode 100644 data/soket.json diff --git a/Init.ino b/Init.ino index 14e3752e..84258f7d 100644 --- a/Init.ino +++ b/Init.ino @@ -53,7 +53,9 @@ void Scenario_init() { } void prsets_init() { + //part 1=============================================================================== + server.on("/relay", HTTP_GET, [](AsyncWebServerRequest * request) { writeFile("firmware.config.txt", readFile("configs/relay.config.txt", 2048)); writeFile("firmware.scenario.txt", readFile("configs/relay.scenario.txt", 2048)); @@ -85,7 +87,60 @@ void prsets_init() { Scenario_init(); request->send(200, "text/text", "OK"); // отправляем ответ о выполнении }); + + server.on("/relay_switch", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/relay_sw.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/relay_sw.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + server.on("/relay_button_remote", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/relay_br.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/relay_br.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + server.on("/relay_switch_remote", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/relay_sr.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/relay_sr.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + //part 2=============================================================================== + + server.on("/dht11", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/dht11.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/dht11.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + server.on("/dht22", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/dht22.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/dht22.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + + server.on("/dallas", HTTP_GET, [](AsyncWebServerRequest * request) { + writeFile("firmware.config.txt", readFile("configs/dallas.config.txt", 2048)); + writeFile("firmware.scenario.txt", readFile("configs/dallas.scenario.txt", 2048)); + Device_init(); + Scenario_init(); + request->send(200, "text/text", "OK"); // отправляем ответ о выполнении + }); + + + server.on("/termostat", HTTP_GET, [](AsyncWebServerRequest * request) { writeFile("firmware.config.txt", readFile("configs/termostat.config.txt", 2048)); writeFile("firmware.scenario.txt", readFile("configs/termostat.scenario.txt", 2048)); @@ -94,13 +149,7 @@ void prsets_init() { request->send(200, "text/text", "OK"); // отправляем ответ о выполнении }); - server.on("/dht", HTTP_GET, [](AsyncWebServerRequest * request) { - writeFile("firmware.config.txt", readFile("configs/dht.config.txt", 2048)); - writeFile("firmware.scenario.txt", readFile("configs/dht.scenario.txt", 2048)); - Device_init(); - Scenario_init(); - request->send(200, "text/text", "OK"); // отправляем ответ о выполнении - }); + server.on("/default", HTTP_GET, [](AsyncWebServerRequest * request) { writeFile("firmware.config.txt", readFile("configs/firmware.config.txt", 2048)); @@ -116,21 +165,24 @@ void up_time() { uint32_t mm = ss / 60; uint32_t hh = mm / 60; uint32_t dd = hh / 24; + + String out = ""; if (ss != 0) { - Serial.println(String(ss) + " sec"); + out = "[i] uptime = " + String(ss) + " sec"; jsonWrite(configJson, "uptime", String(ss) + " sec"); } if (mm != 0) { - Serial.println(String(mm) + " min"); + out = "[i] uptime = " + String(mm) + " min"; jsonWrite(configJson, "uptime", String(mm) + " min"); } if (hh != 0) { - Serial.println(String(hh) + " hours"); + out = "[i] uptime = " + String(hh) + " hours"; jsonWrite(configJson, "uptime", String(hh) + " hours"); } if (dd != 0) { - Serial.println(String(dd) + " days"); + out = "[i] uptime = " + String(dd) + " days"; jsonWrite(configJson, "uptime", String(dd) + " days"); } + Serial.println(out + ", mqtt_lost_error: " + String(mqtt_lost_error) + ", wifi_lost_error: " + String(wifi_lost_error)); } diff --git a/Sensors.ino b/Sensors.ino index d37d7185..0453aa5e 100644 --- a/Sensors.ino +++ b/Sensors.ino @@ -137,19 +137,26 @@ void dhtT() { dht.setup(pin.toInt(), DHTesp::DHT22); } choose_viget_and_create(viget_name, page_name, page_number, type, "dhtT"); - ts.add(DHTT, dhtT_update_int + dht.getMinimumSamplingPeriod(), [&](void*) { + ts.add(DHTT, dhtT_update_int, [&](void*) { //dht.getMinimumSamplingPeriod() float value = 0; static float value_old; - value = dht.getTemperature(); - jsonWrite(configJson, "dhtT", String(value)); - //if (value_old != value) { - eventGen ("dhtT", ""); - sendSTATUS("dhtT", String(value)); - if (client.connected()) { - Serial.println("[i] sensor 'dhtT' send date " + String(value)); + static int counter; + if (dht.getStatus() != 0 && counter < 5) { + sendSTATUS("dhtT", String(dht.getStatusString())); + counter++; + } else { + counter = 0; + value = dht.getTemperature(); + jsonWrite(configJson, "dhtT", String(value)); + //if (value_old != value) { + eventGen ("dhtT", ""); + sendSTATUS("dhtT", String(value)); + if (client.connected()) { + Serial.println("[i] sensor 'dhtT' send date " + String(value)); + } + //} + value_old = value; } - //} - value_old = value; }, nullptr, true); } @@ -168,19 +175,26 @@ void dhtH() { dht.setup(pin.toInt(), DHTesp::DHT22); } choose_viget_and_create(viget_name, page_name, page_number, type, "dhtH"); - ts.add(DHTH, dhtH_update_int + dht.getMinimumSamplingPeriod(), [&](void*) { + ts.add(DHTH, dhtH_update_int , [&](void*) { //dht.getMinimumSamplingPeriod() int value = 0; static int value_old; - value = dht.getHumidity(); - jsonWrite(configJson, "dhtH", String(value)); - //if (value_old != value) { - eventGen ("dhtH", ""); - sendSTATUS("dhtH", String(value)); - if (client.connected()) { - Serial.println("[i] sensor 'dhtH' send date " + String(value)); + static int counter; + if (dht.getStatus() != 0 && counter < 5) { + sendSTATUS("dhtH", String(dht.getStatusString())); + counter++; + } else { + counter = 0; + value = dht.getHumidity(); + jsonWrite(configJson, "dhtH", String(value)); + //if (value_old != value) { + eventGen ("dhtH", ""); + sendSTATUS("dhtH", String(value)); + if (client.connected()) { + Serial.println("[i] sensor 'dhtH' send date " + String(value)); + } + //} + value_old = value; } - //} - value_old = value; }, nullptr, true); } @@ -191,13 +205,17 @@ void dhtPerception() { choose_viget_and_create(viget_name, page_name, page_number, "any-data", "dhtPerception"); ts.add(DHTP, dht_calculation_update_int, [&](void*) { byte value; - value = dht.computePerception(jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); - String final_line = perception(value); - jsonWrite(configJson, "dhtPerception", final_line); - eventGen ("dhtPerception", ""); - sendSTATUS("dhtPerception", final_line); - if (client.connected()) { - Serial.println("[i] sensor 'dhtPerception' send date " + final_line); + if (dht.getStatus() != 0) { + sendSTATUS("dhtPerception", String(dht.getStatusString())); + } else { + value = dht.computePerception(jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); + String final_line = perception(value); + jsonWrite(configJson, "dhtPerception", final_line); + eventGen ("dhtPerception", ""); + sendSTATUS("dhtPerception", final_line); + if (client.connected()) { + Serial.println("[i] sensor 'dhtPerception' send date " + final_line); + } } }, nullptr, true); } @@ -213,7 +231,6 @@ String perception(byte value) { if (value == 7) return "Сильно неудобно, полный звиздец"; } - void dhtComfort() { String viget_name = sCmd.next(); String page_name = sCmd.next(); @@ -222,46 +239,50 @@ void dhtComfort() { ts.add(DHTC, dht_calculation_update_int, [&](void*) { float value; ComfortState cf; - value = dht.getComfortRatio(cf, jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); - String comfortStatus; - switch (cf) { - case Comfort_OK: - comfortStatus = "Отлично"; - break; - case Comfort_TooHot: - comfortStatus = "Очень жарко"; - break; - case Comfort_TooCold: - comfortStatus = "Очень холодно"; - break; - case Comfort_TooDry: - comfortStatus = "Очень сухо"; - break; - case Comfort_TooHumid: - comfortStatus = "Очень влажно"; - break; - case Comfort_HotAndHumid: - comfortStatus = "Жарко и влажно"; - break; - case Comfort_HotAndDry: - comfortStatus = "Жарко и сухо"; - break; - case Comfort_ColdAndHumid: - comfortStatus = "Холодно и влажно"; - break; - case Comfort_ColdAndDry: - comfortStatus = "Холодно и сухо"; - break; - default: - comfortStatus = "Неизвестно"; - break; - }; - String final_line = comfortStatus; - jsonWrite(configJson, "dhtComfort", final_line); - eventGen ("dhtComfort", ""); - sendSTATUS("dhtComfort", final_line); - if (client.connected()) { - Serial.println("[i] sensor 'dhtComfort' send date " + final_line); + if (dht.getStatus() != 0) { + sendSTATUS("dhtComfort", String(dht.getStatusString())); + } else { + value = dht.getComfortRatio(cf, jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); + String comfortStatus; + switch (cf) { + case Comfort_OK: + comfortStatus = "Отлично"; + break; + case Comfort_TooHot: + comfortStatus = "Очень жарко"; + break; + case Comfort_TooCold: + comfortStatus = "Очень холодно"; + break; + case Comfort_TooDry: + comfortStatus = "Очень сухо"; + break; + case Comfort_TooHumid: + comfortStatus = "Очень влажно"; + break; + case Comfort_HotAndHumid: + comfortStatus = "Жарко и влажно"; + break; + case Comfort_HotAndDry: + comfortStatus = "Жарко и сухо"; + break; + case Comfort_ColdAndHumid: + comfortStatus = "Холодно и влажно"; + break; + case Comfort_ColdAndDry: + comfortStatus = "Холодно и сухо"; + break; + default: + comfortStatus = "Неизвестно"; + break; + }; + String final_line = comfortStatus; + jsonWrite(configJson, "dhtComfort", final_line); + eventGen ("dhtComfort", ""); + sendSTATUS("dhtComfort", final_line); + if (client.connected()) { + Serial.println("[i] sensor 'dhtComfort' send date " + final_line); + } } }, nullptr, true); } @@ -273,12 +294,16 @@ void dhtDewpoint() { choose_viget_and_create(viget_name, page_name, page_number, "any-data", "dhtDewpoint"); ts.add(DHTD, dht_calculation_update_int, [&](void*) { float value; - value = dht.computeDewPoint(jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); - jsonWrite(configJson, "dhtDewpoint", value); - eventGen ("dhtDewpoint", ""); - sendSTATUS("dhtDewpoint", String(value)); - if (client.connected()) { - Serial.println("[i] sensor 'dhtDewpoint' send date " + String(value)); + if (dht.getStatus() != 0) { + sendSTATUS("dhtDewpoint", String(dht.getStatusString())); + } else { + value = dht.computeDewPoint(jsonRead(configJson, "dhtT").toFloat(), jsonRead(configJson, "dhtH").toFloat(), false); + jsonWrite(configJson, "dhtDewpoint", value); + eventGen ("dhtDewpoint", ""); + sendSTATUS("dhtDewpoint", String(value)); + if (client.connected()) { + Serial.println("[i] sensor 'dhtDewpoint' send date " + String(value)); + } } }, nullptr, true); } diff --git a/WiFi.ino b/WiFi.ino index 982f84dd..3f5ad044 100644 --- a/WiFi.ino +++ b/WiFi.ino @@ -58,6 +58,8 @@ void WIFI_init() { } else { WiFi.begin(_ssid.c_str(), _password.c_str()); + Serial.print("ssid: "); + Serial.println(_ssid); } // Делаем проверку подключения до тех пор пока счетчик tries // не станет равен нулю или не получим подключение diff --git a/data/.exclude.files b/data/.exclude.files deleted file mode 100644 index 955397fa..00000000 --- a/data/.exclude.files +++ /dev/null @@ -1,2 +0,0 @@ -/*.js.gz -/.exclude.files diff --git a/data/configs/dallas.config.txt b/data/configs/dallas.config.txt new file mode 100644 index 00000000..e69de29b diff --git a/data/configs/dallas.scenario.txt b/data/configs/dallas.scenario.txt new file mode 100644 index 00000000..e69de29b diff --git a/data/configs/dht.config.txt b/data/configs/dht11.config.txt similarity index 100% rename from data/configs/dht.config.txt rename to data/configs/dht11.config.txt diff --git a/data/configs/dht.scenario.txt b/data/configs/dht11.scenario.txt similarity index 100% rename from data/configs/dht.scenario.txt rename to data/configs/dht11.scenario.txt diff --git a/data/configs/dht22.config.txt b/data/configs/dht22.config.txt new file mode 100644 index 00000000..eba7dcaf --- /dev/null +++ b/data/configs/dht22.config.txt @@ -0,0 +1,5 @@ +dhtT DHT22 2 Температура#DHT,#t°C Датчики any-data 1 +dhtH DHT22 2 Влажность#DHT,#% Датчики any-data 2 +dhtComfort Степень#комфорта: Датчики 3 +dhtPerception Восприятие: Датчики 4 +dhtDewpoint Точка#росы: Датчики 5 \ No newline at end of file diff --git a/data/configs/dht22.scenario.txt b/data/configs/dht22.scenario.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/data/configs/dht22.scenario.txt @@ -0,0 +1 @@ + diff --git a/data/configs/relay_br.config.txt b/data/configs/relay_br.config.txt new file mode 100644 index 00000000..051c96e2 --- /dev/null +++ b/data/configs/relay_br.config.txt @@ -0,0 +1 @@ +button 1 5 Включить#все Реле 0 1 \ No newline at end of file diff --git a/data/configs/relay_br.scenario.txt b/data/configs/relay_br.scenario.txt new file mode 100644 index 00000000..9eb30933 --- /dev/null +++ b/data/configs/relay_br.scenario.txt @@ -0,0 +1,8 @@ +button1 = 1 +mqtt 3233662-1589485 buttonSet_1_1 +mqtt 2233662-1589486 buttonSet_1_1 +end +button1 = 0 +mqtt 3233662-1589485 buttonSet_1_0 +mqtt 2233662-1589486 buttonSet_1_0 +end \ No newline at end of file diff --git a/data/configs/relay_rm.config.txt b/data/configs/relay_rm.config.txt new file mode 100644 index 00000000..bc49233e --- /dev/null +++ b/data/configs/relay_rm.config.txt @@ -0,0 +1 @@ +switch 1 0 10 \ No newline at end of file diff --git a/data/configs/relay_rm.scenario.txt b/data/configs/relay_rm.scenario.txt new file mode 100644 index 00000000..827e1495 --- /dev/null +++ b/data/configs/relay_rm.scenario.txt @@ -0,0 +1,3 @@ +switch1 = 1 +mqtt 3233662-1589489 buttonChange_1 +end \ No newline at end of file diff --git a/data/configs/relay_sr.config.txt b/data/configs/relay_sr.config.txt new file mode 100644 index 00000000..bc49233e --- /dev/null +++ b/data/configs/relay_sr.config.txt @@ -0,0 +1 @@ +switch 1 0 10 \ No newline at end of file diff --git a/data/configs/relay_sr.scenario.txt b/data/configs/relay_sr.scenario.txt new file mode 100644 index 00000000..0c48cbdf --- /dev/null +++ b/data/configs/relay_sr.scenario.txt @@ -0,0 +1,4 @@ +switch1 = 1 +mqtt 3233662-1589485 buttonChange_1 +mqtt 2233662-1589486 buttonChange_1 +end \ No newline at end of file diff --git a/data/configs/relay_sw.config.txt b/data/configs/relay_sw.config.txt new file mode 100644 index 00000000..9156708c --- /dev/null +++ b/data/configs/relay_sw.config.txt @@ -0,0 +1,2 @@ +button 1 13 Включить#реле Реле 0 1 +switch 1 0 10 \ No newline at end of file diff --git a/data/configs/relay_sw.scenario.txt b/data/configs/relay_sw.scenario.txt new file mode 100644 index 00000000..093de1fe --- /dev/null +++ b/data/configs/relay_sw.scenario.txt @@ -0,0 +1,3 @@ +switch1 = 1 +buttonChange 1 +end \ No newline at end of file diff --git a/data/configuration.json b/data/configuration.json index 733a3cc8..de86d685 100644 --- a/data/configuration.json +++ b/data/configuration.json @@ -38,35 +38,71 @@ }, { "type": "button", - "title": "Включение выключение реле", + "title": "Вкл. выкл. локального реле", "action": "/relay", "class": "btn btn-block btn-primary" - }, + }, { "type": "button", - "title": "Включение выключение реле в определенное время", + "title": "Вкл. выкл. локального реле в определенное время", "action": "/relay_timer", "class": "btn btn-block btn-primary" }, { "type": "button", - "title": "Включение выключение реле на определенный период времени", + "title": "Вкл. выкл. локального реле на определенный период времени", "action": "/relay_countdown", "class": "btn btn-block btn-primary" }, { "type": "button", - "title": "Включение выключение нескольких реле одной кнопкой в приложении", + "title": "Вкл. выкл. нескольких локальных реле кнопкой в приложении", "action": "/relay_several", "class": "btn btn-block btn-primary" }, + { + "type": "button", + "title": "Вкл. выкл. локального реле физической кнопкой (кнопка так же дублируется в приложении)", + "action": "/relay_switch", + "class": "btn btn-block btn-primary" + }, + { + "type": "button", + "title": "Вкл. выкл. нескольких удаленных реле кнопкой в приложении (нужно указать Device ID)", + "action": "/relay_button_remote", + "class": "btn btn-block btn-primary" + }, + { + "type": "button", + "title": "Вкл. выкл. нескольких удаленных реле физической кнопкой (нужно указать Device ID)", + "action": "/relay_switch_remote", + "class": "btn btn-block btn-primary" + }, { "type": "h4", "title": "Раздел 2. Сенсоры" }, { "type": "button", - "title": "Термостат на ds18b20", + "title": "Сенсор DHT11", + "action": "/dht11", + "class": "btn btn-block btn-primary" + }, + { + "type": "button", + "title": "Сенсор DHT22, DHT33, DHT44, AM2302, RHT03", + "action": "/dht22", + "class": "btn btn-block btn-primary" + }, + { + "type": "button", + "title": "Сенсор DS18B20", + "action": "/dallas", + "class": "btn btn-block btn-primary" + }, + { + "type": "button", + "title": "Термостат на DS18B20", "action": "/termostat", "class": "btn btn-block btn-primary" }, @@ -89,12 +125,7 @@ "class": "btn btn-block btn-primary" }, - { - "type": "button", - "title": "Чтение датчика dht", - "action": "/dht", - "class": "btn btn-block btn-primary" - }, + { "type": "hr" }, diff --git a/data/edit.htm b/data/edit.htm deleted file mode 100644 index 5e2f46ce..00000000 --- a/data/edit.htm +++ /dev/null @@ -1,572 +0,0 @@ - - - - ESP Editor - - - - - - -
-
-
- - - - diff --git a/data/lang/lang.en.json.gz b/data/lang/lang.en.json.gz deleted file mode 100644 index 47332483593a7ad1de5433f9647d5600af821b0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3364 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 diff --git a/data/lang/lang.ru.json.gz b/data/lang/lang.ru.json.gz deleted file mode 100644 index 2ce395ac74df891668b106e511d4c0f2622e7fe2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5071 zcmV;=6EN%_iwFn@pr>2_18iY#XD)JeE^2dcZUD_&dv6<8cK<)0VyYrt8<0qmvK+;= zWk{B6E6{_clsFq0Fh=BvniV<29S)^vivp4#>s`oeC!3@-vKuG%woQR_v9wHD)QbZ0 z35MUO=W%D|-r)>Gr!CMwB#|@co_p`P=lss&9{tlh+R)vCU8xwBJ9KGiWMpJ+ac1`8 z)XkLz_&hWWujh5EG-GU<1)~NO-WT4n*YNheQ?Jo|8W1d1UDLK|8Kn4&ch=n@nq#j8 zbZxH{&@CITYg(l-r2E?Ic&FV5@cwo8K91=A)@w^VXFt^|)v|%4-@@y*cjC3WI})qH z0=|0zlN_bOm8`ANYdBNb|gV z4_AO258mE1Yp(5VUSVJR~3fH`BJFcL@ zmFxhcHZbbYY8%pyb*HdSGX54`w!6FDQRL+X|K%H)?HJ}dq-8ZU?+hL`=|vN_=(UD5 z5NQ)cdQU?}V(&a_gO3egv~V%0=s{;`%diuc2+2$XCUGbFL<1_A99DDOeX8Nf@RK*h zyrrQ?wI6@D22A`T_$^L;KdMOGr#~KtOIfttyitM^FdU-j6~wEF-Co_a^DO~|~3 z8%H@HN1QCB#mnf32->_T6xcCr=RR&=A5{;e0lNtofIoG;L>lxR(Cv~O+umWQJ+@^T z1vfad=mCUsdF-DMsAu;{_Yo`&gaa&L2S+%6qx(D9$YIQph)M8B=5iVgY=YEU-QB3z z=YD_9}xAxxDpHEIZ*psXN2{*Z(rvYO25e?OQP`hC`V65*BsH@I?BikurpvAoUGK-l`ilG$N8U*aB>y z)C-BadshRx5340dFVd0xC0-`@rGp322{sl$ZVw-U&HHQ)uv*XxX4Db9;Itmfs{XY5 zFcgDr>8=s#af6UTf*+eUbh)gr8fC3e)@!vZcZT>I{T?X-mEqhOnncwgpzHt!UQW~7 z$xsi=cD*R(fmIyGZV&YNTtvp8g`r3erEPfa^IG>0sO+RhLW_WghM*w=-BYkRvbJHe zL!t*6b?<|wB3zx(@ifWzy++&gPKX;~NT{Kg&0yyR+{TDmDZz#>r_D(X=h}_B8F)$} z=Pe@hBf^EVq`kL6MFfNbfefOI;RqZOV>TP1B`h%BJBbb+r&PIrSS^FYiuH)N0rFwW zEXv9|Dzh1T%L>`a!w{RoVGUy4#|0y^+_i*Nof2@9LZ5XX<1t2}gfd{GFg1Xh9bSU; z-m2Mb#V^PJcgX?o1q5@oTAd>wz(vvngs43UH!Bs>C4zs0<2k~YB$p$ylQ8sIG`2!s zD9C20I%IsTwZR<0z^S^sZae00bRRT618Na!ASOq`CSmT=hN~m-H$e0T6{*+lc2qc| zV>t5{0PiRgP?y-!R)H@VA4-`59)5gYF*r7~-?0wzcHj$bPKwmTLg%bCo9+EM9KoNw zuQd4ZIjs9RNF2Vxr)S>ZH2Cusz4&+d{Utp5Gpgffg6=uK{|v^z^uB`!&*1NWY4H37 zu*=OYj(9)dygk8g6})$9-K|`$8E(DW8}V|KbAl!(`O;8%s(K-aPdlN1@~tZx_98&8 zPF~hE+bWdJ!Uo`kYnMu8Qb#^y-9S_F*!#rc19U^R}Vt?A{Oac4+dcZ@Y4{d>gD zZ+a07r#ztFaAff65vrlrxSZAjd0@I#XA*)}KROj|cbEesK5E?82^rNXJN70931Sy* zfA{EN@3DsL3pixG=?^SR?z$1~AC9i$hgKX0VesS6+k?*mmmI(SxUUSywB>Tmb!@9N*)PiWdAEg`U}zlR zFnJYq67Yh8t42X=hZ!BvfMaB%1jD}H=5P-3qSzBa4+Sv95n6+#Os=svg2cUDP<<|$ zHbrVU_$YRUz9Fl+Lr}LCv11vZBV~NV;4cT~jq~WacIjLWP(!=-!e!oASjjMwqxNy; zL1`$4rXBJGKq8Z8CAbv8)*|IT4$nQ}mxJfTQUdy^9EW=G>kfgVDAM3B(OCn_6WGur zR0GZpw3)?ag*eN(FoqIMvVx0fZZI~LD0B)IyAMhDZDErd1*y-4W?Ex*^6l(q~vcAD$mZz?WByR~^;|5f3zDWRDEya;ZcM zV-meC4Nd87O7GAi37|ctQK(;F_MCoV~q8sxce-2zIIaSAdXx}SxWL# z>I%n_HYVaRY2;ODWYKg)Oe>%*oF0|Fr~0Om4bU7?k``%itqYqJh={Z z6uq8xWxHxHHnzR9_yfu5+pGcm-KQYD&@o~vAS@NlmMRr!bzF*(BY@@QncP&_aNML4 z7wLD)4=WIjP$gq9w4vP@TDC2FZ4J!MPar6P@meD+&n6wjYkZQzc$CnfNmvn7E%rq4 zLqZN*EI{zd-^sO^wS`+N?1;YeLp1i3B4^a2mR~LF+o_UmLtIFfk0nMUtyinHbP@}$J{jBRCzNE zeA2P(QhF5;T1_p9t2j2QCcP%-LmI|)jK+D8S?p#}!6>mf(NHSdv}11=&ahAc_#;$T zXyBz7=^!pra$Whg53jvoI@v?Tz{`p*(wkGNgvBFY@4O|`U9Ydwfw&N#Z|fWOW=&7C z9^FO5xLeyY0i)Af=7yQZ?Tx%UlX-Vy?A@8scc-t@=TZ91zq9mvntqSd?-}|%!B1kh z1<=rB!=e53O=(;#Psu3_;_#Rsg1-vn{Foi?VWhl{)EBsr9tGuja64?xXH
  • p(MX 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