From baecaf02da6ac4606a398b269650957cde8be65e Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Tue, 22 Jun 2021 20:36:53 +0200 Subject: [PATCH 01/17] cleanup --- src/main.cpp | 80 ++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5dd7ac2..422f7ba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,32 +13,6 @@ extern "C" { #define ESP12_LED 2 #define NODEMCU_LED 16 - -os_timer_t Timer1; // Verwaltungsstruktur des Timers - -int c; -bool toggle = false; -uint32_t m=0; - -uint32_t dimmtimer = 0; -uint8_t direction = 1; -uint8_t onoff = 1; - - -void ledsequence(uint8_t direction, uint8_t onoff, uint8_t factor); -uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval, uint8_t factor); - -void timerCallback(void *pArg) -{ - *((int *) pArg) += 1; - - ledsequence(direction, onoff, 4); - // Serial.print("["); - // Serial.print(micros()-m); - // Serial.print("] timerCallback\n"); - // m = micros(); -} - // OTA & WEB #include "wifi_credentials.h" #include @@ -57,6 +31,9 @@ void timerCallback(void *pArg) const char* ssid = STASSID; const char* password = STAPSK; +os_timer_t timer1; +int timer_arg; + void setup_webserver(); void setup_ota(); void setup_pwm_pca9685(); @@ -106,21 +83,6 @@ void handleNotFound() { void setup_webserver() { - pinMode(led, OUTPUT); - digitalWrite(led, 0); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); server.on("/", handleRootGz); server.on("/style.css", handleCssGz); @@ -182,6 +144,23 @@ void setup_pwm_pca9685() { Serial.println(pwmController.getChannelPWM(0)); // Should output 2048, which is 128 << 4 } + +uint32_t dimmtimer = 0; +uint8_t direction = 1; +uint8_t onoff = 1; + +void ledsequence(uint8_t direction, uint8_t onoff, uint8_t factor); +uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval, uint8_t factor); + +void timer_callback(void *pArg) +{ + *((int *) pArg) += 1; + + ledsequence(direction, onoff, 4); +} + + + void setup() { #ifdef WITH_DEBUGGING_ON Serial.begin(460800); @@ -207,9 +186,24 @@ void setup() { ESP.restart(); } - os_timer_setfn(&Timer1, timerCallback, &c); - os_timer_arm(&Timer1, 1, true); + pinMode(led, OUTPUT); + digitalWrite(led, 0); + Serial.println(""); + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + os_timer_setfn(&timer1, timer_callback, &timer_arg); + os_timer_arm(&timer1, 1, true); Serial.println("Ready"); Serial.print("IP address: "); From b696703d456c13039d362475f782bb1c5bff1c50 Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Tue, 22 Jun 2021 23:38:39 +0200 Subject: [PATCH 02/17] littefs working --- data/test.txt | 75 ++++++++++++++++++++++++++ include/filesys.h | 15 ++++++ src/filesys.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 18 ++++--- 4 files changed, 232 insertions(+), 8 deletions(-) create mode 100644 data/test.txt create mode 100644 include/filesys.h create mode 100644 src/filesys.cpp diff --git a/data/test.txt b/data/test.txt new file mode 100644 index 0000000..ec82874 --- /dev/null +++ b/data/test.txt @@ -0,0 +1,75 @@ + 0xEA, 0x0C, 0xD2, 0x04, 0xE1, 0x9D, 0xC4, 0x18, 0xF6, 0xC1, + 0x40, 0xA7, 0x08, 0x35, 0x3D, 0x67, 0x1A, 0xB5, 0x23, 0x81, + 0x4C, 0x96, 0x42, 0xFD, 0x43, 0xDA, 0x99, 0x71, 0x68, 0xF1, + 0xEA, 0x1E, 0xB9, 0xE4, 0xD0, 0xBB, 0x05, 0xAC, 0xF7, 0x5E, + 0x38, 0x0B, 0x31, 0x66, 0x0D, 0x8A, 0x1B, 0x6F, 0x29, 0x2B, + 0xEC, 0x8C, 0xED, 0xAD, 0x03, 0xE2, 0x44, 0xBA, 0xB3, 0xA1, + 0xB8, 0x85, 0xFC, 0xF6, 0xFB, 0xD1, 0x12, 0x63, 0x7E, 0x86, + 0x5A, 0x22, 0x6F, 0xEF, 0x55, 0xD4, 0x27, 0x3F, 0xCC, 0xE9, + 0x9A, 0x60, 0xC5, 0xD0, 0xF8, 0x29, 0x0B, 0x06, 0x2C, 0x9B, + 0xDC, 0x95, 0xDD, 0xA6, 0x22, 0x65, 0x3F, 0xCC, 0x7E, 0x6C, + 0xD3, 0x77, 0x26, 0x23, 0x9C, 0x5C, 0xD3, 0x8E, 0xB2, 0xBD, + 0xD1, 0xC8, 0xEA, 0xC1, 0x87, 0x2A, 0x67, 0x5B, 0xA4, 0x66, + 0x32, 0x60, 0x79, 0x6D, 0xE4, 0xCC, 0x6B, 0x4D, 0xA4, 0x26, + 0x7E, 0x06, 0x12, 0x6E, 0x3B, 0xB5, 0x55, 0x05, 0x42, 0x37, + 0x75, 0x2C, 0x89, 0xB7, 0x94, 0xA7, 0x28, 0x97, 0x4A, 0x2E, + 0x0B, 0x90, 0xFD, 0x66, 0xE8, 0xD4, 0x7C, 0xC6, 0x09, 0xFA, + 0x1D, 0xED, 0x54, 0x43, 0x27, 0x65, 0x49, 0xF5, 0x17, 0x03, + 0x1F, 0x4E, 0x6F, 0x06, 0xA7, 0x67, 0x90, 0x9D, 0xC5, 0xFA, + 0x61, 0xF4, 0x3C, 0x8B, 0x27, 0xB6, 0xDF, 0x92, 0x4E, 0x15, + 0xB2, 0xDF, 0xAE, 0xA6, 0xF3, 0x01, 0xB1, 0x56, 0x32, 0x99, + 0xB0, 0xEA, 0x35, 0x0B, 0xA6, 0x89, 0x62, 0x05, 0xA4, 0xC0, + 0x23, 0x0C, 0x5B, 0x43, 0x66, 0xB3, 0x03, 0x61, 0x9A, 0x2F, + 0x98, 0x02, 0x84, 0x3B, 0x0A, 0xBB, 0xFB, 0x03, 0x0E, 0x45, + 0x4D, 0x1C, 0xB7, 0xAF, 0x23, 0xE0, 0x15, 0xEA, 0xE5, 0xC1, + 0x92, 0x2D, 0x0E, 0x19, 0x7C, 0xFA, 0xFA, 0x5E, 0xA7, 0xBB, + 0xD8, 0x8F, 0x87, 0x4E, 0x8A, 0x99, 0x1C, 0x6A, 0x5D, 0x49, + 0xA8, 0xFE, 0x38, 0x84, 0x85, 0x44, 0x01, 0xCB, 0x78, 0xF9, + 0x6D, 0xA3, 0xD2, 0x95, 0x4A, 0xB5, 0xF7, 0xF0, 0xF9, 0x10, + 0xA6, 0x4B, 0xCF, 0xBE, 0x4A, 0x46, 0x21, 0x57, 0x40, 0xCB, + 0x91, 0xDD, 0x7A, 0xA3, 0xA9, 0x48, 0x40, 0x27, 0x98, 0x65, + 0xFE, 0xDC, 0x8A, 0x6B, 0xF3, 0xBB, 0x04, 0x37, 0x65, 0x09, + 0xFB, 0x09, 0x95, 0x62, 0xE6, 0x5B, 0x53, 0x82, 0x82, 0x70, + 0x3D, 0x23, 0x6C, 0xAD, 0x23, 0x84, 0xE8, 0x9F, 0xF2, 0x00, + 0xE0, 0x68, 0x34, 0xA8, 0xC5, 0x0C, 0xC0, 0x4A, 0xB6, 0x4A, + 0xD8, 0xA6, 0xB6, 0x4A, 0xF8, 0xF8, 0x75, 0x60, 0xD2, 0xE4, + 0x0B, 0xF9, 0x0C, 0xA6, 0xA1, 0x9C, 0xF5, 0x2E, 0x17, 0x2C, + 0x29, 0x8A, 0x21, 0x24, 0xEA, 0xDB, 0x95, 0xE7, 0x75, 0x25, + 0xAF, 0x3B, 0xC2, 0x16, 0x0E, 0x69, 0x36, 0x8F, 0x80, 0xB4, + 0x1A, 0x01, 0xEF, 0x0B, 0x1B, 0x09, 0x74, 0x86, 0x3C, 0xFB, + 0x0D, 0xF5, 0x1A, 0x01, 0x56, 0xE4, 0xA0, 0x32, 0xB0, 0x40, + 0x36, 0xAB, 0x40, 0x80, 0x4C, 0x39, 0x05, 0x1D, 0x43, 0xC7, + 0x76, 0x82, 0x51, 0x80, 0x1E, 0x13, 0xF9, 0x76, 0x44, 0xD9, + 0xEA, 0xB9, 0x14, 0x98, 0x72, 0x2E, 0x46, 0xC6, 0x63, 0x1D, + 0xB9, 0xF6, 0xD5, 0xA6, 0x75, 0xBB, 0xB2, 0x0B, 0x34, 0xA8, + 0x8D, 0x6E, 0x1F, 0xFF, 0xCE, 0xDA, 0x20, 0xD6, 0xEE, 0xB8, + 0x7B, 0xBB, 0x35, 0x35, 0xFA, 0x65, 0xBA, 0xE3, 0x62, 0xAB, + 0xC2, 0x64, 0x77, 0x10, 0x9D, 0xC0, 0x4F, 0xCD, 0xCF, 0xFB, + 0x97, 0xF4, 0x23, 0x47, 0xD7, 0x2E, 0xC9, 0xF9, 0x5E, 0x3C, + 0x68, 0x4E, 0x92, 0x5F, 0x06, 0x40, 0x95, 0xA1, 0x30, 0xFA, + 0xF1, 0xFC, 0xDC, 0xFB, 0x45, 0xF7, 0x24, 0x8D, 0xEF, 0x4D, + 0x49, 0xD0, 0xFE, 0x77, 0x34, 0x6D, 0x8D, 0xDB, 0x59, 0x11, + 0x86, 0xE2, 0x37, 0xD3, 0x2F, 0xD0, 0xB7, 0x08, 0x1E, 0x95, + 0xCB, 0x51, 0xD5, 0x02, 0x4C, 0x28, 0xF8, 0xAA, 0x7B, 0x7D, + 0x61, 0xFA, 0xCA, 0xE3, 0x66, 0x04, 0x9D, 0x95, 0x78, 0x7B, + 0x33, 0xD2, 0xEF, 0x77, 0xDB, 0xB3, 0xD7, 0xE5, 0x48, 0xDF, + 0x9A, 0x6E, 0x99, 0x21, 0x59, 0xFE, 0x99, 0xFC, 0x12, 0x8F, + 0x44, 0xC2, 0xB7, 0xA6, 0x46, 0xE3, 0x8A, 0x6B, 0x84, 0x23, + 0x08, 0x6C, 0x2F, 0xAB, 0x77, 0x78, 0x4D, 0x02, 0x6B, 0xCD, + 0x06, 0xDD, 0x24, 0xC1, 0x24, 0xDB, 0x36, 0xF3, 0x48, 0x5D, + 0xF4, 0x57, 0x73, 0xDD, 0x7F, 0xAA, 0xA2, 0x66, 0xE5, 0x37, + 0xEB, 0xFD, 0x1C, 0x7C, 0x40, 0x89, 0x03, 0x19, 0xDC, 0x61, + 0x9C, 0xC2, 0xD7, 0xB5, 0x83, 0xFA, 0x3A, 0x64, 0x23, 0xDE, 0xB2, 0x6A, + 0x90, 0xDF, 0x43, 0x60, 0xAC, 0x88, 0x3D, 0xBA, 0x35, 0x1D, + 0x34, 0x66, 0x38, 0x97, 0x01, 0xB9, 0x83, 0x9F, 0x3D, 0x74, + 0x12, 0x8C, 0x61, 0x2B, 0x91, 0x4A, 0x9B, 0x4B, 0x95, 0x40, + 0xC7, 0x11, 0x4F, 0x59, 0xF3, 0xCE, 0x56, 0x3B, 0x96, 0x42, + 0xC9, 0x4E, 0xE1, 0x77, 0xB0, 0x81, 0xB3, 0x2C, 0x3C, 0xB2, + 0x05, 0x1C, 0x3A, 0x66, 0xF5, 0xE0, 0x4F, 0xEE, 0x5B, 0xC8, + 0xD6, 0x52, 0x97, 0x9F, 0x1B, 0x80, 0x44, 0x53, 0xD7, 0x5D, + 0x8A, 0xB9, 0xA2, 0xDD, 0x99, 0xB4, 0xFA, 0xFB, 0xB9, 0xAA, + 0xA0, 0xA8, 0x11, 0xFA, 0xCF, 0xF5, 0xB6, 0xDF, 0xB4, 0xD7, + 0x56, 0x11, 0xD1, 0xE1, 0xF0, 0x45, 0xA0, 0x6C, 0xA1, 0xAE, + 0x92, 0xD7, 0x6F, 0xD0, 0x18, 0xF7, 0x73, 0x07, 0x15, 0xDC, + 0xEE, 0x37, 0xD8, 0xB1, 0x72, 0x2C, 0xAC, 0x57, 0x99, 0x57, + 0xD5, 0x59, 0xC7, 0xE8, 0x \ No newline at end of file diff --git a/include/filesys.h b/include/filesys.h new file mode 100644 index 0000000..1603367 --- /dev/null +++ b/include/filesys.h @@ -0,0 +1,15 @@ +#ifndef __FILESYS_H +#define __FILESYS_H + +#include + +bool mount_fs(); +bool format_fs(); + +void listDir(const char * dirname); +void readFile(const char * path); +void writeFile(const char * path, const char * message); +void appendFile(const char * path, const char * message); +void renameFile(const char * path1, const char * path2); +void deleteFile(const char * path); +#endif // __FILESYS_H \ No newline at end of file diff --git a/src/filesys.cpp b/src/filesys.cpp new file mode 100644 index 0000000..2771761 --- /dev/null +++ b/src/filesys.cpp @@ -0,0 +1,132 @@ +#include "filesys.h" + +// listDir("/"); +// deleteFile("/hello.txt"); +// writeFile("/hello.txt", "Hello "); +// appendFile("/hello.txt", "World!\n"); +// readFile("/hello.txt"); +// listDir("/"); + +FSInfo fsinfo; + +void listDir(const char * dirname) { + Serial.printf("Listing directory: %s\n", dirname); + Dir root = LittleFS.openDir(dirname); + + while (root.next()) { + File file = root.openFile("r"); + Serial.print(" FILE: "); + Serial.print(root.fileName()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t cr = file.getCreationTime(); + time_t lw = file.getLastWrite(); + file.close(); + struct tm * tmstruct = localtime(&cr); + Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + tmstruct = localtime(&lw); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + } +} + + +void readFile(const char * path) { + Serial.printf("Reading file: %s\n", path); + + File file = LittleFS.open(path, "r"); + if (!file) { + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while (file.available()) { + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(const char * path, const char * message) { + Serial.printf("Writing file: %s\n", path); + + File file = LittleFS.open(path, "w"); + if (!file) { + Serial.println("Failed to open file for writing"); + return; + } + if (file.print(message)) { + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + delay(2000); // Make sure the CREATE and LASTWRITE times are different + file.close(); +} + +void appendFile(const char * path, const char * message) { + Serial.printf("Appending to file: %s\n", path); + + File file = LittleFS.open(path, "a"); + if (!file) { + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)) { + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(const char * path1, const char * path2) { + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (LittleFS.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(const char * path) { + Serial.printf("Deleting file: %s\n", path); + if (LittleFS.remove(path)) { + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + + +bool mount_fs() { + if(!LittleFS.begin()) { + Serial.println("[ERROR] LittleFS.info(), reset ..."); + return false; + } + + if(!LittleFS.info(fsinfo)) { + Serial.println("[ERROR] LittleFS.info(), reset ..."); + return false; + } + + printf("Filesystem opened: \n"); + printf("\ttotalBytes:\t%d\n", fsinfo.totalBytes); + printf("\tusedBytes:\t%d\n", fsinfo.usedBytes); + printf("\tblockSize:\t%d\n", fsinfo.blockSize); + printf("\tpageSize:\t%d\n", fsinfo.pageSize); + printf("\tmaxOpenFiles:\t%d\n", fsinfo.maxOpenFiles); + printf("\tmaxPathLength:\t%d\n", fsinfo.maxPathLength); + printf("\n"); + + return true; +} + +bool format_fs() { + printf("Formatting FS ! \n"); + return LittleFS.format(); +} + + + + + \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 422f7ba..7451a3c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ extern "C" { #include #include +#include "filesys.h" #include #include @@ -83,7 +84,6 @@ void handleNotFound() { void setup_webserver() { - server.on("/", handleRootGz); server.on("/style.css", handleCssGz); server.on("/favicon.png", handleFaviconGz); @@ -171,6 +171,11 @@ void setup() { Serial.println(F("Booting ....")); + mount_fs(); + //format_fs(); + listDir(""); + readFile("/test.txt"); + pinMode(NODEMCU_LED, OUTPUT); pinMode(ESP12_LED, OUTPUT); @@ -214,10 +219,6 @@ void setup() { setup_pwm_pca9685(); } -uint32_t t; -#define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("µs") -#define TIMEIF_US(_str,_f, _l) t=micros(); _f; t=micros()-t; if(t > _l) { SP_US(_str, t); } - uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval, uint8_t factor){ static uint8_t lastled = 255; static uint8_t current_pwm = 0; @@ -300,11 +301,11 @@ void ledsequence(uint8_t direction, uint8_t onoff, uint8_t factor){ } } +uint32_t t; +#define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("us") +#define TIMEIF_US(_str,_f, _l) t=micros(); _f; t=micros()-t; if(t > _l) { SP_US(_str, t); } void loop() { - - - if(millis() - dimmtimer > 2){ //ledsequence(direction, onoff, 4); dimmtimer = millis(); @@ -316,4 +317,5 @@ void loop() { } TIMEIF_US("OTA", ArduinoOTA.handle(), 1000); TIMEIF_US("HTTP", server.handleClient(), 1000); + } \ No newline at end of file From 6596346d3d3bd3d6823738902cfeca76a6717140 Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Wed, 23 Jun 2021 01:30:28 +0200 Subject: [PATCH 03/17] ls -l implement and ota fw fix --- .vscode/settings.json | 4 ++- data/tt.html | 1 + doku.md | 15 +++++++++++ include/filesys.h | 2 +- src/filesys.cpp | 53 +++++++++++++++++++------------------- src/main.cpp | 60 ++++++++++++++++++++++++++----------------- 6 files changed, 83 insertions(+), 52 deletions(-) create mode 100644 data/tt.html diff --git a/.vscode/settings.json b/.vscode/settings.json index e9afe7d..34629f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,8 @@ "vector": "cpp", "string_view": "cpp", "memory": "cpp", - "ranges": "cpp" + "ranges": "cpp", + "initializer_list": "cpp", + "utility": "cpp" } } \ No newline at end of file diff --git a/data/tt.html b/data/tt.html new file mode 100644 index 0000000..74076d0 --- /dev/null +++ b/data/tt.html @@ -0,0 +1 @@ +Hello from LittleFS ;) \ No newline at end of file diff --git a/doku.md b/doku.md index 20bbf7b..6f9dc96 100644 --- a/doku.md +++ b/doku.md @@ -22,4 +22,19 @@ GDB-Version aus Arduino Toolchain hat Support ```sh $ ./start_xtensa_gdb_stub.sh +``` + +### __Achtung !__ +Don`t forget __\r__ + +ESP-OTA wird von ufw oder Defender geblockt. +- Windows -> Python needs to be granted with rights +- Linux -> open udp port in ufw -> + +```sh +platform.ini +upload_flags = + --host-port +... +$ sudo ufw allow tcp/ ``` \ No newline at end of file diff --git a/include/filesys.h b/include/filesys.h index 1603367..454079b 100644 --- a/include/filesys.h +++ b/include/filesys.h @@ -6,7 +6,7 @@ bool mount_fs(); bool format_fs(); -void listDir(const char * dirname); +void ls(const char * dirname); void readFile(const char * path); void writeFile(const char * path, const char * message); void appendFile(const char * path, const char * message); diff --git a/src/filesys.cpp b/src/filesys.cpp index 2771761..8b84428 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -3,35 +3,36 @@ // listDir("/"); // deleteFile("/hello.txt"); // writeFile("/hello.txt", "Hello "); -// appendFile("/hello.txt", "World!\n"); +// appendFile("/hello.txt", "World!\n\r"); // readFile("/hello.txt"); // listDir("/"); FSInfo fsinfo; -void listDir(const char * dirname) { - Serial.printf("Listing directory: %s\n", dirname); +void ls(const char * dirname) { + Serial.printf("ls -l %s\n\r", dirname); Dir root = LittleFS.openDir(dirname); while (root.next()) { File file = root.openFile("r"); - Serial.print(" FILE: "); - Serial.print(root.fileName()); - Serial.print(" SIZE: "); - Serial.print(file.size()); - time_t cr = file.getCreationTime(); + time_t lw = file.getLastWrite(); + struct tm * tmstruct = localtime(&lw); + Serial.printf("%8d %02d %02d %02d:%02d %s\n\r", + file.size(), + tmstruct->tm_mon + 1, + tmstruct->tm_mday, + tmstruct->tm_hour, + tmstruct->tm_min, + root.fileName().c_str()); file.close(); - struct tm * tmstruct = localtime(&cr); - Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); - tmstruct = localtime(&lw); - Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); } + Serial.println(); } void readFile(const char * path) { - Serial.printf("Reading file: %s\n", path); + Serial.printf("Reading file: %s\n\r", path); File file = LittleFS.open(path, "r"); if (!file) { @@ -47,7 +48,7 @@ void readFile(const char * path) { } void writeFile(const char * path, const char * message) { - Serial.printf("Writing file: %s\n", path); + Serial.printf("Writing file: %s\n\r", path); File file = LittleFS.open(path, "w"); if (!file) { @@ -64,7 +65,7 @@ void writeFile(const char * path, const char * message) { } void appendFile(const char * path, const char * message) { - Serial.printf("Appending to file: %s\n", path); + Serial.printf("Appending to file: %s\n\r", path); File file = LittleFS.open(path, "a"); if (!file) { @@ -80,7 +81,7 @@ void appendFile(const char * path, const char * message) { } void renameFile(const char * path1, const char * path2) { - Serial.printf("Renaming file %s to %s\n", path1, path2); + Serial.printf("Renaming file %s to %s\n\r", path1, path2); if (LittleFS.rename(path1, path2)) { Serial.println("File renamed"); } else { @@ -89,7 +90,7 @@ void renameFile(const char * path1, const char * path2) { } void deleteFile(const char * path) { - Serial.printf("Deleting file: %s\n", path); + Serial.printf("Deleting file: %s\n\r", path); if (LittleFS.remove(path)) { Serial.println("File deleted"); } else { @@ -109,20 +110,20 @@ bool mount_fs() { return false; } - printf("Filesystem opened: \n"); - printf("\ttotalBytes:\t%d\n", fsinfo.totalBytes); - printf("\tusedBytes:\t%d\n", fsinfo.usedBytes); - printf("\tblockSize:\t%d\n", fsinfo.blockSize); - printf("\tpageSize:\t%d\n", fsinfo.pageSize); - printf("\tmaxOpenFiles:\t%d\n", fsinfo.maxOpenFiles); - printf("\tmaxPathLength:\t%d\n", fsinfo.maxPathLength); - printf("\n"); + printf("Filesystem opened:\n\r"); + printf("\ttotalBytes:\t%d\n\r", fsinfo.totalBytes); + printf("\tusedBytes:\t%d\n\r", fsinfo.usedBytes); + printf("\tblockSize:\t%d\n\r", fsinfo.blockSize); + printf("\tpageSize:\t%d\n\r", fsinfo.pageSize); + printf("\tmaxOpenFiles:\t%d\n\r", fsinfo.maxOpenFiles); + printf("\tmaxPathLength:\t%d\n\r", fsinfo.maxPathLength); + printf("\n\r"); return true; } bool format_fs() { - printf("Formatting FS ! \n"); + printf("Formatting FS ! \n\r"); return LittleFS.format(); } diff --git a/src/main.cpp b/src/main.cpp index 7451a3c..db09149 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,6 +87,10 @@ void setup_webserver() { server.on("/", handleRootGz); server.on("/style.css", handleCssGz); server.on("/favicon.png", handleFaviconGz); + // void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); + + server.serveStatic("/static", LittleFS, "/tt.html"); + server.onNotFound(handleNotFound); server.begin(); @@ -152,15 +156,15 @@ uint8_t onoff = 1; void ledsequence(uint8_t direction, uint8_t onoff, uint8_t factor); uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval, uint8_t factor); +uint8_t flag = 0; void timer_callback(void *pArg) { *((int *) pArg) += 1; - ledsequence(direction, onoff, 4); + flag = 1; } - void setup() { #ifdef WITH_DEBUGGING_ON Serial.begin(460800); @@ -173,8 +177,9 @@ void setup() { mount_fs(); //format_fs(); - listDir(""); - readFile("/test.txt"); + ls("/"); + ls("tester/"); + // readFile("/test.txt"); pinMode(NODEMCU_LED, OUTPUT); pinMode(ESP12_LED, OUTPUT); @@ -191,6 +196,23 @@ void setup() { ESP.restart(); } + + + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + os_timer_setfn(&timer1, timer_callback, &timer_arg); + os_timer_arm(&timer1, 1000, true); + + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + setup_ota(); + pinMode(led, OUTPUT); digitalWrite(led, 0); Serial.println(""); @@ -200,21 +222,6 @@ void setup() { delay(500); Serial.print("."); } - - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - os_timer_setfn(&timer1, timer_callback, &timer_arg); - os_timer_arm(&timer1, 1, true); - - Serial.println("Ready"); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - - setup_ota(); setup_webserver(); setup_pwm_pca9685(); } @@ -301,9 +308,9 @@ void ledsequence(uint8_t direction, uint8_t onoff, uint8_t factor){ } } -uint32_t t; +uint32_t _t=0; #define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("us") -#define TIMEIF_US(_str,_f, _l) t=micros(); _f; t=micros()-t; if(t > _l) { SP_US(_str, t); } +#define TIMEIF_US(_f, _l, _str) _t=micros(); _f; _t=micros()-_t; if(_t > _l) { SP_US(_str, _t); } void loop() { if(millis() - dimmtimer > 2){ @@ -313,9 +320,14 @@ void loop() { if(millis() > 25000 && onoff == 1 && direction == 1) onoff = 0; if(millis() > 35000 && direction == 1){ onoff = 1; - direction = 0; + direction = 0; } - TIMEIF_US("OTA", ArduinoOTA.handle(), 1000); - TIMEIF_US("HTTP", server.handleClient(), 1000); + TIMEIF_US(ArduinoOTA.handle(), 1000, "OTA"); + TIMEIF_US(server.handleClient(), 1000, "HTTP"); + if(flag) { + flag = 0; + ledsequence(direction, onoff, 4); + Serial.printf("[%lu] interrupt\n\r", millis()); + } } \ No newline at end of file From 642ee7d0a68b2c844aeb28a36475b750785d049b Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Wed, 23 Jun 2021 02:13:48 +0200 Subject: [PATCH 04/17] gzip works from FS --- data/http/favicon.png | Bin 0 -> 531 bytes data/http/firefox.png | Bin 0 -> 55480 bytes data/http/index.html | 40 +++++++++++++ data/http/input.js | 8 +++ data/http/style.css | 132 ++++++++++++++++++++++++++++++++++++++++++ data/tt.html | 1 - data/tt.html.gzip | Bin 0 -> 430 bytes doku.md | 15 +++++ src/main.cpp | 13 +++-- 9 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 data/http/favicon.png create mode 100644 data/http/firefox.png create mode 100644 data/http/index.html create mode 100644 data/http/input.js create mode 100644 data/http/style.css delete mode 100644 data/tt.html create mode 100644 data/tt.html.gzip diff --git a/data/http/favicon.png b/data/http/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..d768c7bbed8b06eed40912f5e6aba1e0b1b91572 GIT binary patch literal 531 zcmV+u0_^>XP) zPiPZC6oOlmL;#DblvtSRR2R&|(q&Ge3LDaJcJ$V(u zgJ3nqOVp+&Ig}oxAcD1Z+a$X?BfBBhuA6jDGw=O=-^_b6Bg72-b@n8p?*L~21DHqa z`;srdi^?S$(9O~{lsp2=NKT=+B@_0;f8*N#da+c%kPk8Du1CZNbylomr3cv#Xq2C! znTjiGE2eoadHYH~Km*M&vxFQcx2dUD}3eG#>a*W*=)8o5b$DQA(i>QKKFZL zv(WCim}Y`ZI>nx$p<4dn$j*RjwYq!NGruGZ<4CYmtJ9&?YU6A5_R_gi=XWe2Fui;; zH`QvpvxZ1Ee2AXEwB|T7GnX&EiazuIeq&GYX?b~{>$uZF$I@Q%>Ez_$pHXwL{sY%I VuMu}alw<$^002ovPDHLkV1j&e^>_dP literal 0 HcmV?d00001 diff --git a/data/http/firefox.png b/data/http/firefox.png new file mode 100644 index 0000000000000000000000000000000000000000..c3af1220cdd3b57c820c1975eaa0620dbf01cd38 GIT binary patch literal 55480 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

lhMo*Oc1ce|)Kp4pH6i6{YrHsRnJc<3BJ}eC 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 V5(shxW2OKA002ovPDHLkV1mJH?->99 literal 0 HcmV?d00001 diff --git a/data/http/index.html b/data/http/index.html new file mode 100644 index 0000000..6dbf624 --- /dev/null +++ b/data/http/index.html @@ -0,0 +1,40 @@ + + + + ESP8266 Treppenlicht + + + + + + +

+ ESP8266 Treppenlicht Controller +
+
+
+
+
+ toggle all + + +
+
+ + +
+
+ + +
+
+ + + + + + + diff --git a/data/http/input.js b/data/http/input.js new file mode 100644 index 0000000..f1ea08e --- /dev/null +++ b/data/http/input.js @@ -0,0 +1,8 @@ +var slider = document.getElementById("range1"); +var output = document.getElementById("l_pwm"); +output.innerHTML = slider.value; // Display the default slider value + +// Update the current slider value (each time you drag the slider handle) +slider.oninput = function() { + output.innerHTML = this.value; +} \ No newline at end of file diff --git a/data/http/style.css b/data/http/style.css new file mode 100644 index 0000000..f4edb62 --- /dev/null +++ b/data/http/style.css @@ -0,0 +1,132 @@ +html { + font-size: 10px; + font-family: sans-serif, Arial, Helvetica; + background-color: #b3b3b3; +} + +.topbar { + padding: 1em; + background-color: #1f1f1f; + + color: white; + font-size: x-large; + text-align: center; +} + +.control { + padding: 1em; +} + +p, li { + font-size: 16px; + line-height: 2; + letter-spacing: 1px; +} + + +body { + margin: 0 auto; + border: 1px solid black; + border-radius: 3; +} + + + +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked + .slider { + background-color: #04AA6D; +} + +input:focus + .slider { + box-shadow: 0 0 1px #04AA6D; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} +.slider.round:before { + border-radius: 50%; +} + + + + +/* The slider itself */ +.rangeslider { + -webkit-appearance: none; /* Override default CSS styles */ + appearance: none; + width: 50%; /* Full-width */ + height: 34px; /* Specified height */ + border-radius: 34px; /* range round corners */ + background: #d3d3d3; /* Grey background */ + outline: none; /* Remove outline */ + opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */ + -webkit-transition: .2s; /* 0.2 seconds transition on hover */ + transition: opacity .2s; + +} +/* Mouse-over effects */ +.rangeslider:hover { + opacity: 1; /* Fully shown on mouse-over */ +} +/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */ +.rangeslider::-webkit-slider-thumb { + -webkit-appearance: none; /* Override default look */ + appearance: none; + width: 26px; /* Set a specific slider handle width */ + height: 26px; /* Slider handle height */ + border-radius: 50%; /* Round Element */ + background: #04AA6D; /* Green background */ + cursor: pointer; /* Cursor on hover */ +} +.rangeslider::-moz-range-thumb { + width: 26px; /* Set a specific slider handle width */ + height: 26px; /* Slider handle height */ + background: #04AA6D; /* Green background */ + cursor: pointer; /* Cursor on hover */ +} diff --git a/data/tt.html b/data/tt.html deleted file mode 100644 index 74076d0..0000000 --- a/data/tt.html +++ /dev/null @@ -1 +0,0 @@ -Hello from LittleFS ;) \ No newline at end of file diff --git a/data/tt.html.gzip b/data/tt.html.gzip new file mode 100644 index 0000000000000000000000000000000000000000..6c077181a70b6b207ef2c5605c41b014bea56dcd GIT binary patch literal 430 zcmV;f0a5-RiwFn^cG6$~19WsQXmo9C0JT%WQo|q=y!R`f+}pIy*zu6|qMmg|FP=Jt zye23C23~9H*Gm9vYO9_+WO%U4?mh_R#qIsg)APd}wA88Ps7wPu*&?s|B9tUa;qvbB z;renuhbM>DqE=G0R2B(Kyo>P|IxaPM+A9R#A`*UwXzYz1(xX}B?(oKXs0+FpeHr%EER4pKv`afa=Zb|4!FQrivXV-qck*UIdU8QyYz zP*Ac)2hMDC-P`rp!0p)n$L{P~$4)ZFM*3GU%iZ|4A76E{xMDgDqE^ zfM10&n?-8M&7w(MnEibRBs+A!<;;ZtOBxMUN#RV~K{-laS)?DlFTHTm5_l)VlZlBY YFFxK`1Oh3%i}>(A09kC`P7nkD05{pzwEzGB literal 0 HcmV?d00001 diff --git a/doku.md b/doku.md index 6f9dc96..c119866 100644 --- a/doku.md +++ b/doku.md @@ -37,4 +37,19 @@ upload_flags = --host-port ... $ sudo ufw allow tcp/ +``` + + +```c++ +server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); + +=====> + +const String& p = SRH::_path; +if(p.endsWith(".gzip")) { + server.sendHeader("Content-Encoding", "gzip"); + server.streamFile(f, mime::getContentType(p.substring(0, p.length()-5)), requestMethod); +} +else + server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); ``` \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index db09149..6c956ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -84,12 +84,15 @@ void handleNotFound() { void setup_webserver() { - server.on("/", handleRootGz); - server.on("/style.css", handleCssGz); - server.on("/favicon.png", handleFaviconGz); + // server.on("/", handleRootGz); + // server.on("/style.css", handleCssGz); + // server.on("/favicon.png", handleFaviconGz); // void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); - server.serveStatic("/static", LittleFS, "/tt.html"); + server.serveStatic("/static", LittleFS, "/tt.html.gzip"); + server.serveStatic("/http", LittleFS, "/http/"); + server.serveStatic("/http", LittleFS, "/http/"); + server.serveStatic("/http", LittleFS, "/http/"); server.onNotFound(handleNotFound); @@ -178,7 +181,7 @@ void setup() { mount_fs(); //format_fs(); ls("/"); - ls("tester/"); + ls("http/"); // readFile("/test.txt"); pinMode(NODEMCU_LED, OUTPUT); From 278f746b339b3cda9716851e501d365443dbc9e7 Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Wed, 23 Jun 2021 13:34:54 +0200 Subject: [PATCH 05/17] templ ini --- templ_platformio_ini | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/templ_platformio_ini b/templ_platformio_ini index a333f62..1f5f0c9 100644 --- a/templ_platformio_ini +++ b/templ_platformio_ini @@ -12,23 +12,29 @@ platform = espressif8266 board = nodemcuv2 framework = arduino + +; for http files +board_build.filesystem = littlefs +board_build.ldscript = eagle.flash.4m1m.ld +extra_scripts = pre:create_gz_files.py + monitor_speed = 115200 -extra_scripts = pre:extra_script.py [env:serial] upload_protocol = esptool upload_speed = 921600 [env:ota] -; stuff for OTA -; https://docs.platformio.org/en/latest/platforms/espressif8266.html#over-the-air-ota-update +; OTA => https://docs.platformio.org/en/latest/platforms/espressif8266.html#over-the-air-ota-update upload_protocol = espota upload_port = upload_flags = --port=8266 + --host_port= --auth=admin [env:debug] +; look at doku.md build_flags = -DWITH_DEBUGGING_ON -Os -g3 -ggdb3 upload_protocol = esptool upload_speed = 921600 From 4b608c42cad9caad68c63a6e67c9b0676355b0c7 Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Wed, 23 Jun 2021 13:37:13 +0200 Subject: [PATCH 06/17] tryin on win --- data/{tt.html.gzip => compressed.html.gzip} | Bin data/{http => }/favicon.png | Bin data/http/firefox.png | Bin 55480 -> 0 bytes data/{http => }/index.html | 0 data/{http => }/input.js | 0 data/{http => }/style.css | 0 data/test.txt | 75 -------------------- src/main.cpp | 57 ++++----------- templ_platformio_ini | 2 +- 9 files changed, 14 insertions(+), 120 deletions(-) rename data/{tt.html.gzip => compressed.html.gzip} (100%) rename data/{http => }/favicon.png (100%) delete mode 100644 data/http/firefox.png rename data/{http => }/index.html (100%) rename data/{http => }/input.js (100%) rename data/{http => }/style.css (100%) delete mode 100644 data/test.txt diff --git a/data/tt.html.gzip b/data/compressed.html.gzip similarity index 100% rename from data/tt.html.gzip rename to data/compressed.html.gzip diff --git a/data/http/favicon.png b/data/favicon.png similarity index 100% rename from data/http/favicon.png rename to data/favicon.png diff --git a/data/http/firefox.png b/data/http/firefox.png deleted file mode 100644 index c3af1220cdd3b57c820c1975eaa0620dbf01cd38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55480 zcmZ^K1yo$ivi88>1PdWJg9HukI#_U*Ai>?;2G<}7?(PyKNbq1oaMuKP_rV>0&bjx! zcmBKHo3&=m?&|uw>Z|JNy?gIH5z2~E7-&Rj0000(M*4#)008%L2nRqxdil|H{$~DH z%SBa63{W{rviH(Jb(Ge20RYf(|N6oK(lZGF00bH%xB8S-7+Pm;Wged>k;D0&(OUyz^{bq7c(a_ zDoSak0^@HTU;V&&AN=sK)M}8I-4-XG!4-RGrXA2fKK0ZDcR(2M4cBU5% zCKpe8S0f0My$jX92KldXKA5?fI9oZoS~=L0|23|Wv4fkd5GCbbhW`8WFF#$a%>T!d zz01F8y%1#itA~Y+nU&>#gPB3B{twt+J^v@n)a1WeIl4L9{>{nMgvHF(%+Ac-)#U}p z_P?5YiS2&_|34=oMvnh7_ID8f#ZB-p&-qo&TpVoO{tCfIdn;EkyWro1{!{!v5&0KN z+`-P#+04b|1qNpQH{_qP|J2v|A2VQ{|FZE<;eP^@oULA%8vW%LnC;&N{we!UeeM6v zz(0lm0Q?nteq}3&nXT3btCxWO&4QhaTae{{?fFlnxPz^OvznukiP>MC{SEnt=s&gp zwxj)j+WAM%Kai#-{4Q?B)@CNI|H#)%*8ZOTVn!A${}2nZ{IA-AFLQxk!NJtZ-1CEx zs~MP`m5q;ym5qswPo0g8pOuZDhewd*KXm@#!CyV%&Splg4$kTh4z}RGY1sYMBrq%RbJfIfw5U=*!@~111|Kyes8dx^x+2NuFl-u+l{H9BX(KNJa<+9C6qQ1a>RpJ&f@^gfN-KJoVPbHvQ5z+0l(XCe_8D8V5?;g*W%rr8~S z!PKB#PjSxw8mQ-5jZU5g3vVoR$Z4r$zkGe+eWg8NyX7pQ#`` z6E%^FN(CrF4N3aRxseq|n0y`(@`!8^h1Kfe`;t)_$7<7)MCK=jc_f zVfY8}fJO9GjLvkQS8{=PvLnyKKasWt0<<-kTGw>{06ZRXraPDuF1}36Yl7KHUsZyt1Bq6bST zC>SEGAEpgG2ps8Rv@vW4rkeGPWQ^!x7+&~;gKnLTlyUc^)@ar0Zba4W1aVAVbz-x6 zavzwp@p28x%vJtk!N_2@Y0R7wvB=5FF2$t9k`C^$QX&pax7Rrhz zi(QVLWl8TC^>VSUzzsJIZewiMA%$*XXpQ9*H9qb(HM|w}OFZdE!7&gf>bn#BweXqB z8R-hMa@3_1KghEphbZ*~a93L7nFUk@-X8rRp}5yyE6#>bH+e)cY`D5URE5{xK;5Oo zWNEq&i0*%H`kotS$4K&TW8Z#mC+*ZBy%Bx$#I0@E1L;Ev$4gJ=9ZoIMlx%kV&=%C<3N@bv6g3`MEEkX3#Xx$hj^Z6{7BO;9r!f4++ z!R11dKx|*Rw+*}773q?jOavt<6glu06d-OX%nc5>-IRG{qIAplIGeYND8nez~Jhbvpal(G;Lw>iG;`zT)Ud}9Cu_HO5qjF zEI9mvf^e8DJ})oKiRwg!ch}}Pd*ut%fPtrg_!BPovsNciNqnLinRN;?pcmo7;(Nf)|G@Pn@76MmmU7%P3do#qffhN zuuwTu+#NK4vpRnRubv8=k!Yd0d?VjX&Y9jsO2fhT*ucituVXUqiNKAOU)w|+xv;w0 z$F9|(K!beJbqGf)PI%^BecCAR$0B$sxI$R zB)7sZQS#S$hT8CAX>kkI?r1kQe)`w^`pVI9F=KK^6H-V=ZiJ&n}rSCtI?!f9; zNtlN!oP4^7U;^>oFRgT6X?S{~6bN*>%|A?@ zF((ajIDfRs{+Nls0H8=J+qpdo80ykVnKU_1hz{UkyiHH*t##cMC=+Dl2^>8^! zU~3uR^l8{|%(2d~E5pecPQO+vBG(NL?qrI#$PYsQ8^BwNzvK3P~(E$JU!v%LZ zq8Zdlf}VL2OujGd`RNdWP`FXU7~oP+&QGL4ps4BvNQVe8$u;N{8}3V97x)7;hq~B5 zE3WP+OI+Qk_&1xM;rJA95**UP+BZDzIruN?$#_Ts8Tj*Cx()Hcer}TfckNub!1|rK z+Ib}k%&{RG;B3VPwV}?30yF42BhzjKhauNx5A}P1896))IU7fOpKZD9pNbtF*4lI+ zOI!~JaEN&~J*%ktx12@_RVdG(#8CUXIhrXlG+3}m(?8fy7-!m|p__>*T?@00&9Ws8 zdT`ngQ}_G+Aa+&p#2@&;aYiz%t6w_r=1GrsmG;QENMZ8Sv|fVhYH|I+G-mbtY^a3YGkF>*#Rb?t65!xM5vej6lnvgGMrUA2la( z7Jbrmw!UI$HXHqNOTfR*JxYNQL*mxif^Qz2BhjMoB8^|C-Xuuu*+aS$ssEIqq}Y(b z(_k})kA0Jp7qKzW=){;&!~C18jb}0d2-cHz!*Eo);3jgsLA8x}pCd^opB=qkW&yVw zEU?uBme)uM72y_^r``JT+aHuPmPzsbbPZ&?NXojpjgZdQLCp%iMy}=whE3d6(aNSe)|}lZo#R3k*|KRH$;KLvlDI9755 z=Xo{hFqlta+x^iUa0BRvL-uF>+5B_%1l>@E)t%=AvsJXgB;yRz6}~TpOfmUE309on zkIuQf(e90arKvEO6x((bfd2@vhC?rEn%DQ7xZE+OIwAee=q;l`Ot8r*>|kOP zG1AuBd&wBIjL&tAV^a4OLGlZ-IMY#&Ch5~EETUAiM4#pDBy%FBC2T{EV7Fh|Gq$hc zqu{v>`*2#yEBoXUx2&ggOz0E%5kH9|_euAQEY|BVWhgZq62#Bn@DN!G)7G1MG{*nS zgBv8=D`x-qmPDT4MJDt&zX*RwUmDF;FqHY@Qs3Sf1rKoc=XzRLUa%iNvl1Z8LTbC5 zxjXsP1X)TSvZSUd{H$Z}0pd?p#lB2`)0)jY_|o zYeQNRHvxGkn{XN^2KTbcW;9KLWfL31MXjBq*O8J0r=nD+`pVHtKv&}096>scam2VS zQvSDK|DtN;1M~tce**sRq@Uh8h@J_BL~QWlLI~%V4K~JNUefcq<%v>>N#S`z8{qK@ zX)FF=$oaHxj^r0wm@cw1aj5}+CYNGrcTijbZB>ywAg#g+(s^UzOl!Er(cv{ezvH(t zrjqYq+}-g8XJu7A2SZT`B8=F$imB%7zt+Vl0>m7S4Go7M+er4(`FQn|WY$0vqsyyz zBK!xP*Lv!r-n?bE3~aM3UKDlxagyyBJYwVg6o0_R_QfX+tVa5H-H1BLgPAjH)iZa| z>lTJu9z?rpCBcXqie!ND*de+r405YiwL5xXGK-6tVe2U!aM&{Fv0ZgS3mbk-o`N+^ z2Hsy_5sz)lQu9MJSUW@u{V|V{3`ZO2-`81oaJln*j&l^)o8+nC?VCSHsw4s^pPtC!L(@2(t(Ag(tFNJ{B|(9gII6B zJuiqiQLl~f4&8bj8^wQKjMKkq==K1`%3q9L;wL_O`0mB>Ifij(DuKF;40V_!D}&ZI(<+V(Z6{$#~lMs$d0U&(GNt%ifDKHuW!O z2JEU0q8zNF>Q@vt?*oemzJU%(BOLh5aq)#=)8FouD)2Wt;fJAE;R!T_Q!W+-Xf>G- z*}e(l&1L<)S$xM0qdWh@T_Fep#O4~4eB-VIWJm_iK{@Jk-sX>VPe#YWAocswpTIy`3vIH&cbTpp$Xh} zkSmoB+e9y$ftBxq$BX_qZ@`J?ERcjF-Q~flFb_x`s$a;AYJh7g{#`fZb2Kgje;PG! z$K3(Zn~8VAEDEm~(u_lh1YYBX(n$>S==swqno~#lOo}GiTO}*6wImH#g)N2R!}BQ} zBTao5(Iz7S*W|mOb9?vzb7t8tt1<02OcvOSd`51$&rE`0&OyPqsBV^e4q zZ{!^s+zK=+Z_vj_6$n@!Kf*D*gRUhkgE12m(_H*I-VOm4sUh%x;2+cwJ`TZU^ZY(I zTYJ!nDUtfK!yBuN$PpAJCG0Y=ISwnSZZ{Z0_Cq=4;>o1HLUMf@AaHat=XZ$stdn$o zzEfB7^t&t}=dMS%(rj*pax~hZk!@+_^^H{*+J~Gs(1EETlR*OC#ey=} ziI&!%f3FpV{G0NUj)}@P%tc?Rx@2%aq`{0&kl=IG)9Q;I< zB{H+8Q$uuzhe$hOdymr^N(>mr7f( zT22GgzE)0i^u6+Q-`WWLeJ-WSHqN{@!n93vbh5)6vagDeRc4&b>_5l{g}k$|;ADTD z_NcKo!O6Xy@pVCSQjzaMXRTfu!gjCQLZ9dxjk)l@Q<$6t*H|GWn z9=g|!j~aWWN_PorG_`rc27XHj*A)nKa9KLqFec7&b^{ zb33=Snyv{Cy5Q@+M`!&4Ueu>3xb#JNx;IntP06tTWU%#k_>23}Uoo3n^XMj5m&Zvz z&aS^C|AOKC0duh>{MHoFpB__K6sa|9U=1ixkGo5{_=+KCMpPkQ9`}d0N^ZZE)e&c0 z0qec>BE!wESYWm=mOU{ebSA5Ji^0$byc!$YR{`u_xa9c*^Rmr0@+wM7(M5#yPt4J5 zm2ENu$WSJYI+83vz4Ge^#K*V2qkGo37gJTuBx+kqYgql2(<(Wh*X)ym3V9!z^4~Bm z-^;jCHlM#95{i~G^Te_mS#3M}B4H3e!+1x`=YlX+bPsSavi6rhA~O(H=EB!-oa8;u z`o!|g?FVNLSKhe`Z!YH)sad9j6sK%w>=)@Rv|o)Z70XCGOVPzO8sQC?nL);jXQwsw zm&n7x^h@+)N;bFz<>7{#>s0`k@dy%g#vBq^%#`9C0{BhW*!BR&UB1ue*+LGP7*Har zgCvOTec6;vk+7-hom=0;r;U&+!*gH5)~Ry0cd2Jsb;U^FaPPa5UiE@M+n61Sw?k$7 z^Jkd(O(KEXmp&MAOjD-kXNB(`Hs2<{jebZpiwYsbEAW>U`u}PIbB0Mo*1*!*zY-4`m~ilX90mS zf)X$RjgR{L>Nbo7T|5MJOt(m&oT3`ujY0Jxmj|RbJTq6u=am}e9go?#EH@i zy;t2YXJ;(U0re|w!Rhn(xBSE&202{^ugL8WSxx8%adIQGg!<%i~U5A~l$ICKA;0DP25d6x`PxF=`n7tC(CMkXWKYDht4joD5%L zVgg%&E(_laVpVL3o&cPiEBrLU?({oX5^nI~U6dnNMWtMv7XbV3$M1uLf;PUfr$3M% zqxozfPi4D2u?gSt>kGIzZd>K}QF1hI{sfkkvQlXe*Zw?D6MD-| z^ix6pTm|fT9&fWblk!|yLF$FQv|Rm)({X4b>x*14Q)Kvc?rrL+RAYxYxanx-G=&*< z=!Nk;Dgki`U}`d53Lqex*6f*c-6+@o?8nmXhUAB90e8jpi%*Mhl2aI)R7CYSME>hI zD2taquHvTtW|o+NL!1^Cp7Xof-qQ=C`L#du7U)L;%)FBVg@Xk1`uP>vr`mho$Ysd# zije-$Pg8jtS(5Peo6ekR;KkE=jP`z_I#J>hr{8SzJn#q zWm{4Hog?u052j~9B&Mm|cYbyzUBsw0;yQx7d! z;xvUXO3o@rKnZPjejPzn!ghw;(3!F52^ln3Yms0Cb=^+Qdi#fNWb|L?C>9pMW4jDLpdqaK*aAJhlp}h4&a2#YI>jKn4`&x4JLCZ78>d$Y zmx&mO_Q&e(wmOFX1pAI}msEtKTqp*2TDip1wtIuy!Zq_Je}M+hO=!*eY*_t{p@#Q8 z@xe3w%%;T<0=$5fA=UILgOi+OtrK4bn7$yD8EXSd)kDN$w;Q?PU2ugaqinJWxk6YXRpp0di&r^@c zuDoyjt=TU#Yq`K$tru-6$RJ02Zz}3b5*WiLf`N~QHMwh0QQC!V58Ja(>+Tb{UL(EC z+66SgC^D{Oo7?IY?d>X41kw*o)!IpjW2pMc{Ppn;!9^K)ZM3@8iy9I?2<_gzMseX;Ds|EV^*)Y{*I#D&e+~MAWpa|8~VDC&wejj zeALfSOZeTLiu#1ytgZ=G47H!KK){m8ZRt%aQuh7K$5wr3Qi6$9?I_!8jjV1wsB*SN zY9>9F*Lu#J)_7{-XCT3rQ)^`)bVJ9IXj6HTVzK0+0NHPvR?TM&zt7Q5HFQFTM1LXh z{^WXKY8u&Dv=2tdy>M*%J?TUt``t=9FA!@vlM$;h);dIp z{v{6pjzoi+%>XQ0aMOINx7{f zSHIe{Y*loE2DH)b|C+#x>OjR(z2 z@JRzGGZaQXo}GC=>mH}^zAXvb`+=sdaWf-KU;K9J8Tt;vqhcwlik}e$Pj$C9Oka7- z48NlScXwLq!%kcFnk>mX(@irZ%a`Prcq9_MGc_7hTqPJrV0~V>#ckwYZ8GR04kq5R znM3NNyPWNMsfz05KP-2%@Bt+bq;Lmu3SU?E>uSvx$}&wzg(IXCt_Smb5xCp==6^{? zCG?gCVhB?}6=Iqpxe;W=7Nw^OIBC0Ic`APBCiA%W_lVC7_I&M#&brlcjg0?Nk~F>IxRBYB{lPHhYyJd&$-pLcFvU6PzQsT|!76p{$(6n$toSJyKTJcs6R@r;y_}I-ztU8UH1U_x7@;vDl(HRHW zLzJaswLqHo_nWF|wl#jma8FzMZN$)o65JCyv69nq@l0N}NsEcD@vp<=lNE*%s<|~m zeFw8mdUboitozQ$3O}Tin^}4h3L^- ziK&#~KlFiHN!>7pqd6=4@jY6#z^AZ<0GCbLYM+3?)v)0&C%-eD&xnV9u64d+&a`l! zg=ArZFDBS(fsncgGm+2bu~C$}ye@*=wqGvr?-}1;%TO!6cJ`u;2#k|&38I%k8~lZ3 zA^RZy4*j75#k*fC>q*fM=$-*G;k6_cX<_c8RK}cAAq||^4ot8hO_KB*f918Tyry{n zNl?{`QSwoO>oDKaME290fg3<6b`Tby`d}X3IbI2~TsJTmoT@>pKXY;ao6BH-<(`W~ zbK_}%>ns}CUrs>gfTsTC@igm|M8QBEwriRd9;AK0r)ehY*0hF#7-0o9$N2&#Q2cga z8`bt$g2sG4uHjUc^sxslka%bGa*^Qdg%u$xrm>(&=T_YhwY9`juEBzl(VI;XtsZLOV~ms=JZcIfiLODA}=5GpZlGpnvQ_ZYe`#irw33 z?$#6f7Sua4ZJVl!RVr$$_Ddm*{s;m%a{tx=b}h94Pxnq`KWB$6vtTLM24G4`BHmP( zOeulPil6maqjYP%r7PqzIIf!(%_D%Z|5 zXP)r;l|IkSxBjp@v~8X<1;1GDMN8d?D#1J3+k>MNd^LX!>=}f#1xR7Dm?I%}!n-}r zGyQd~;wHQ|+KJ}y**W`l#Lh$Zt?Ua}o8D^)9zgR+k~AZAX(}p>lZp}Y$+DMP$T5fy zoO@?$VIg+@OVJQf@;O0w0{JwlGx;G@2K3dHhO6CRD`U`995=9wVU021dC``9hF-Yb zoKNa8P|9ft!{0~T<*Rkl5hGar*gp|V4?}+bhUyQ`;$b9aY2!6t${89zD@~=L=Qw6$ zc2>}}UBh;apCC9I*<$&6+*_HJfb`}AX<(rFfuA|PxNIMLwm4%|x37`9M&OhI{kR+< zXEDU`>QZbX zIfFo9qAY;9R3_r9!L3`#2b{@16iiv<0GF{(%@u2nk6gP>Klt~lwlIaWM^g&e)~g&2 zJC9LLUcbS}gXR-aa)9OEoKLe(^IvFx>95R)+W+8g+gWNC20FLy; z+$^Qfu(I;_X0t~F&O7>PO5rhYlIL3`%Li-xDK^EOQoVWlRIpmc_r2jFdSS@LJ3@!6 z^AF_bYj#fFf8Z>US%E{t1vqng%bmN%D^pU&;yHMXDM_fW!+J5dD1hHPqP3v_ZbZJL zwOY8CiO^NiJ%GKw+Zr7hwj_X#BOflBMTb}2-_yIcFUjb=AS{}d2Y%mRu=og)~Q z>=%sTMk#aH2haVw#iupu7R5QIW6R1}E;w7NpH|D7w-TD-uKP}S`D<^$-MGl+-gMLP z^{SFmDFF|k+S$isx_5=h37*BQyL8@h-mNoy?J92D`kqkVz$%Zmq_?|E|^P+UWOs@GOADp`uimM}% zy_q%ob~lXcSoHEzOZ!4Jx|?h%NuM`mdN(k9_;`pZ_I<>y`d(~}?vu2cWQI+_l+OUI zmMlrV|3>!I=AE8JF!U~E%9kvupd%?TG(hBaDLhOqZn7QFZQ_}0;;BBXKFTOAW#}dE zq}tm5@C7~DV`cuy)YBB+Mo%qIPg8{EsHMQ=pez+dYz@s1u^jt#x$-wdJZ`*SXc|Q; z(TB$3t5LX)=<=X+FEu}`WFRumOKGzv&AeUZJe5^oJ~%D?Mg`*pl?SXIpW>cps*1Cb zsUoR2Sr-0olHLm%PdIt(Zs%0S6>v+04Lek^Ck`HGbqjWl;9L6-T+tI+Ih}uno{9Ef z-+TT<6PcyQPDN;Ueyxw+W(ZvA3}cC$BxBiPi)vk9%;R*i8rW{L*~(a`Zk}_Hv)S1A zcFG9NF}EH76 zGLAC%inJZ@aX-)Sb9K;1l!!EVH7qw!IgrA6K5cT8u7_j}l{SHUYhpd4!q1Tv+WO|SiT>*8roeK)dqL>Pg) z4@hoPW<=uD{z&b^%Rarg8N+9hYU|$P=P?#%4Rw&y8!f?w-lDh>jCZ&f!b}c-7EumFr}`Y!NG8S=a5N@_{gx5%BKV zQ4qN#)vtm+_L^HyRr!4;<6y3l`=Cw@aSoCCHdTOwCel7w z!I~ZIS+?P}!LB{7>5k$WgS%mL)wCaTsK;dB1^e}s0_R9|v;f0pit4BOW{|^Bu-}(R zsf{=!qX6ZEH$hHj`?-tQu!krfhR{IKnXBBrv-7U+9Iorq1^X!lF9;Y$I*th_NflCE zxgJ2g;m{{~vQ)aN2>&fRfl#WKX&Dlvq^(_{~&s3mR;u`uWx1VvTnu5$ktla;Fa{)v!7|Bo`IJg)u+;Oei3c`-r9j-!#$%!5brMQ#aR%k-!gAc)Y%=c`xm1~DU68_jDe9ebZj)F6Jqd`B{lX?PGf=DVY;;XMTw zeA-QqEDwncM23x^q!uI*`U#F5@N+|m>cAL3MRqG3ci;6M^lCC~Z^Z0fynocvrWC%g z`I%hY>a@56>dHG4_4GPwITPMg8sD9u$L55rava5)9 zJjon{>5g3RYtc28#*k9eGXlGC;D{d?Lt_@HmEUK!6e6-)ALttpyJzkGXU<;e?AKRV z((=mc^)p63O-QIiQs^7_!5~3$^S#gX9R(aPu-s@X)`r_nxNlhb`d|sS#wg*vNoT+ zhrBZWtc9d|^Xse9)hy)~gzt||pI=D!-ZI<|aSmQU7dv4b9x)N_+={K0kwK5~lM zAe5X3$ke)_Q61#<5h>}emyr?g{YwGmS=ttVyiJ-d)=hn1Oe%120?Bl~QhX2!l!)lf zj7Kg6&eq)_N)_lmQ~bFN?&<0{4mo1~G+4VAS|0FAtMipA*?V2L@5VC3F_Ji`W7AT| zD~D7DaT%3c1&W6YFy1XBLsV-BuCwe@#i_k#%>(W{RtFv&(DZvQMi;JpB#4J|YlF65 zfnG*|3>h-4=4LPpwa9K4?0mVfE8Mswda6W{Uc&A!Sbm1Bo^M5GNrh<(Nsz|gS#L0P za<`XS$OW!%qN&x=^Wtbwylf4V-p;`@?Inkcu~cIir3ZYuORDYa(h2^m0s7ilxDpFV zS92Z}2zaQdMPfC%XDoiQDS6mE$%toxsPmzWi~T8ZURPs&MUqlSn&cI?V(-;G&CGmL_?)eoyaTI<9i6uYS0=N@#v5O8+a2x&F_^|(~3ygzET~@4G9k4V>f!c zB}sDO+g{j(lSI8uZ_i#UPUL}7Y~qfQ3E}~Iq7B*%WuJC!?F$%eD9&AcQFZUTSR-#| zOyr!Y1k3;Ddf+bd8Znk(pE|6u*_R$MkJBGTri}f^cWm&-_FK;EqGg5Z%d1ihE5ELQEI`g9%}6wPMy&7xByF(~ zJ*LAeh14wU6D_pqQoOoZ<_k^vt(&zQp6jj$Yi8~11(agc)NkIRJ}N=R>i|>10=XiF zF22SZo+iL3%SKtoR%^SoK z1yLd8yhD=3EO>P?;8*{qV1KPH%m&XcCIz?tlN8NK1)s6Ouq3>8t(HUMG$KW!4FB7a zp~S7txa@uajf18SSShi{reW6{EqVUi6SvlL&=JQ}cLUOSEf)a-}) zR4;dY#l+tyvooY)9%wlgvte?*k2%BDE?W@oYLBuYzB)Dz1vsn_#l2U04Dq?Bz-lRK z!@auJ>8fkGGTr?Fh2fL;3e^UEY(VWrZJBgL;@3M&%lhIqphh@a8_2)t-j#LMpUqKw zZt9`F&nG&eFh**seb0kzQ~x=E;Bjd>2=0hEWvB;{*XgV!xGG#-#%k~okiI{@Cl8_4 zyNM$9UhMy-IcX*tVDCfAtTjOn;II2ajKGb6Q=6#S@D#s^tqCy5;&jleT}R{NmYE{~p%Ypb?BeO7+)CQ;$-u zH>$e(EOqP;mmQPeP9z_Ur*|p<{t?I=aIOSoJKx4WIhHcv{E}Xok$&ZJ-$nk4QQ+>! zXTKyeUsqU~(&oyUjGK1t-mVgvG381S&V4jBWFH@2%WW4+?2c97OaOB~E=Ju#tZpYz zp&+y`$)FD-)Tpy>YOC`QrMbmDg9VvxoFW=3PMh}Ox@5wqo^GK-83TfGZ6Vst-%bp+3 zjU>k^u(H#BD1Z(&AuWcijAzNQzQ#G*bd(xrXR2uhx~)7LTAeh^&+bd36gj^?b?W!7 zku^pZA-%*3fiotBbK3~^N>}QRvFfS^27roi$cKUcSQBp1!8b0P+IQoLPoI7Ly3%{BC9(vk`JMX>CPWiMGw!xX$8?H2dOp>e3M&gX}COgI&h) zLq4xtbBANb^R++&!tcLhT$Jwa8vt?WrrAjXv)smXQv-7;pGPY|WNtzFaUPxL)O33i zMQ9DERl!&*Z#kbHrYV1y=hvW0k8>~&$c5}D`o%Laa1ksFbC4GCEkR*<#Nkcf!yT|H zD(#YouD>dD+$6=%-o!G*eVT8iAyP5PZ*(VPQHU{CN34&1bDNjZ?zKW@hC}&bu)9JtjZ< zvIfgF8tSKRUC+46=Z49p4V6?{0(E{n-UOk+zh2RR;QeC$IoBVss`Z@;|XfKlS zq#S@Al86d^uE~Dy9Oru*r+q$H&BdXgG3cA-)48d~v_Ix~5+7j%WtXI>pZ+}kIP)L{ ze)XFj5=1I8;K9flOjooZ8=$ADT?Ch!83c>|70~KCV6nNGx8Pf^Md)KKx*YfGb9V7q zi+DDS4Q@gJUVIpr*Qyx8ym~jHl(5orWbuUnNk{Y%c#vH7`U>yUN*LyKPsJgFqp*3o zdIVjf?BVOU-PA}ccm{S)N-Dk$=ym%v^I2aN5)=Qr?t@XyIpwim!Tk~(XVGnWm$t9d zSDQO!l1v2DF}fSmQv?&~JuM``Gu(GI;_NMZ7e#$PG!iN5vt+;;;|!qTFT??l0Jo|9 zBGbZc5@%up^payuVe=mZ$URy>s^mokBtJ)WZay{&dExssj2pI`%L z8F*w1ICRXafnQuVkj=$TKQ{oermnjrQ+b;+N!5=tRRIwr^j~YOe`v0(BBI0Li$K|e zoh5JHqA~2{4k)uZOuepVB4y?dj2`}xGD-&cr$fjNhn zUO{#B75OoOEaq!7A>=doc)HYYDJ1Mj9(Y>gnh`C7tsR)e>~t;>=6%}G-9h}FnL($I zb7P^62BZMV$Lm+-bB?8lbW~LZ!1qFvL8x)sTGn^+YS|O=N3c8U9FElq=6a@6AMjx9 z1J!dWlLWPQmCZx=yL1i$bHrulQY1ICp6NGU)bkeRg48-c>YH`BxoYAh8);0+!me@n zL+m*(%S~55uU>;a>YCrG-z;EWP-H}ss^%%m(pch8o#Z!JcZY8z&t2!4%GGlcvLi9 z$hZwKr;Y1ry^U2qgmWy5p}`iFmC9$}ukvpJ81@auuXd;!e_m87If@Z49LN6)DFEx#l&TynSs*8 z1q>?C$His3Id)k{xo>*<#p1|77KMrQul656u&~}8fcX;Ks_f&Wp#})eOv31k$0NGE zM**naOb^@Cs~Q8OrJM7%T|dii;i2uri$4~?Lq(0`B$$pOJwWm zp;A66B0LGDNY_{N3TdaXie63kte8EHvmc@OA=6YjNMNp?FMpG;sw+{j#UBccS?8wf zASvV?M$d`pE9t7dxsuvUKB67=QH$N$oG_<#1giSTiJT~<1595HauZG=h#6kTs+0hs z=x&7QRDJ`IAKszU^m-WgUA58=!(-||B1!7k5Ji23W3}A?jZ7Vf-Ji1ch+>|OMYH$g zSK~DSO8q@1^{rp4Wwkv=b6kkl24U^58tckg)L>Rc*&XCH)=6YrY&pCq1trh`wr|+w z-(GH#X;-I%6sSC_`!u~imBX%4vSWUbqiyt(Y;0G(8Fu`Xzn0^tre7)^zPUN$Xyc3k zB(VDxYN*z5tVdmS+ZZ!+#}I)yoNgBwtCv4G~(1;?LfmWx!2G8RNkEa zh;{2}vtecscpu%#$3Y3_Bu-r^c;=fY2lw*wlnM4!_wH*`HfJU#5W5jr6czp9t73bWp#Ny88J#$>rrx?hSFy=he_ z${P4N7XZ?Io!7o|x#?XbqyA?c#&Mnz-RWxeY}l)CI{L9nFGAL{{$5-^*^{oG?Pu}n z1&_v;s`@iENm(`ets>X)n)#1ozlA?Gl+w7BU6ese?c~pEmSn$u>nqFm*w8MQUFzn1 zx?1%=6p#XY2_Mt^hGAnX^%JqFO<@Rrb3H<6jpU}d*^3D~{kd8ZWWC=-XWkO8&zTe?f2o`;W~nihFHJJg%vQDfQaNFGf}s>p8Gj)Ymig9GtO3r}aPdj#ki#+v*SEldkLGJx`7*zI{LS}foCE2{9qv(@|L?lcC8K0+hva!+ zP-S`A-i55%Mq;tupxj=(qHcpep%PWCAmevcDUCTg{s75Di;5E4liZY?mot~4^48ny zc^)3k{vmF^Pwh1cO7ZKc{NSWMhwCDY%&UE%@b*`Jq&(c*>@k)?R2Kbvsn3 zRzNU&3U4XS(qGhS^3r-*bJssJ0+-wRkkt%CCv1%*Ndd` z4VGbUJy6=3&)Ug9L;=`$8=~&n8cHvWe~Y?O9AVi)B7%W)upbJYW_PpCxUdG>vi9O= zMjeo=aSaDseQ2Q_)V^Dnngf0I4|8*42%HX^6U%{$fHAbXMyi;yVl0X8$V7#PKgb>o zB}49*oi62D7~1La)^qXGESu4!lmkh5fE=DGehbb24{bn_zq5WOpsE&_Z3q0|@Si<0 z&$5g7v5zwF1Rg^``v^5Gla3K{eWR=$2xXW@SNpwJXI2k!$-XRJG( z7Z0aW{Cejdvg!EFrSs!;HIFL3=V{)i+lvPsmWR+pI#4@W8ZA!iW(DYO`-57$`O=ZB zv1Af|t)*&7=9?g#`NDa(1)o)2mZiEKC5eqGOz94TE;=)^V;Oxpt7ZiK=2@j@Jh;!6 zjY<9>pN&s|S*PW-B31E&Ih{@^b<6k(@@Kn#Nlr)9spjp-Q)*!3fdBwN07*naR1^LXs0?7k`nwku9mVv>) z5S_rTN6^5rPoetSgUGM_$9rY>Hu=NtbTKzzp7md z2o$JW<+B7mWIaR`Wlv7LLSx3PnH8XLKUa2aYYP#qi_pLy#i*x#?L3)A86{*<7>{XC zO<-O&B-ideSN>qv%j6&TohSR+c*&>E0K$kzf7EN>-un=4z1av7^0B;Q@33JpLeN4- zY4U;7#O~>8$3a_V5&?Kz6aEnBfDq{g)FVvT2`pOfI)O=)U-N+g9o%o<@Jq6DVv&5} zybodtj5>_tR(<#R!+e?#!X6(hX>e1NoiREF@;d;`4!&n}*zlQ+(^su3@iyOvln*x|OozBrA31kXcpEz&k)? zL4{_kFbmi@gs`Z}ql#ze%)+6uVyAp}zF5Ar>jm-$yDyc0A3q&@bSV6oDA)QHm<(dR zk3VcnMbKfik9=we58s-#<qrb#gC9I)Q^#=nAroMoh9mF`zN+F!Q=?V6lc)BW zXL32Pdnf*Y>K?eDZy4htrqBG~O|os@;qph%ezzD8MI$%dYbZ@0(npA$QpOzt|W8D}>$DJ+5 z==K0co-u9;L_*6tVihO@e@eFIE95T`_(^xKNIU@3nI179Y7+hj*`0*ti zf;AlG7dinYz_65x1ke`nS_hO9q5|4%Ky|&yPDTT{!Y242Vsd4=@>yrYlUjHgvZACh!B|#Su+aCHvteIk(u?Lw z@BAd!v#0Z(LOW49G`y$5<4=gcnu?l-~W|-cN1nl9LhA$X;O$Qfn{&r zjoAR67ieP!r9CP&y;Jk8#t{)vLzn`T?8S3xWxZZJ_=@Y7hI-wQ@|gh1pOatv%)SP6 zpNl5bb^wbOHlEzbYS=n%d!&>>%COu^teEnel$$;w|Jm!E7qPG0c$e<`24^~D&$ zp$qd$2zf(Vg_}|9VN~f&$P?cfU?*U@DvyYO2Bgr{KqcRUsziEZSMtE@ur*%f%+6m~ zkh25GvXf=~o?}g`-*nm@19$f?Ss;ztZW;TJMwZ_;D2>-Q@t12@*YmKSHNZwNgiooh z-6#2-SfA@#g4Ti|#LoT0vP`bt{Sq9P$mXddz(c^}-o6HrW>0-K5?m2JSI>hF_z>73 zumjL;-s`EraHR1RUR$M?S;xVM3OX=Wal|t{DmA6&X=7>zd+wH=oL1n>MDu}+5PUl_$igfDb!+;@3o`*PV;RE%-U93k@Qwy&2DHT! zYHis5@^{}ao32L(fk~BidciN~UO2=hP+eS)DcmY--r>)|+JHHNML+}6g9jbfg&O(X ztZpoGqgAhq4((Mh7-b9shw`%Qax01uCBJ##c0IAJ_*UxU{7U`=Z0Hp4Dymn?XW za{^Z3J)HHE*KBoyT_5G>QA8C5Ulod!4Pc(N4x5Q0{dima{?GtAbwr@w}pg9RcT`hb=?O&JKz4nsR^h82Ro*h75Yh5xW`QB!G@O@c3fB8^WAJDq?<+db#2-tYNQe4hT2SgEV9o?kpBf4}P)^1Lm-CI7PbOc}u%e-LYY_jxr2KPO^H@e)sM2up?m2EHHh zD}x-FSR*OPd-37YY~qw>thCuO^*kcPH8p-BQ{7l6(j%K-Iu`Kk6iOX~?+935e1nji zgEkAGE$Zu<-9Ihg*#1ChAmjcDpC znesrh{!~aMfYqm?$mrym4owwIC!zUNpk&A3GaW~pq@UEPr$hG!c{8?Lvr8uP_Q#&G z_tTrRy!O(j>uOaul&8ZI3=>*frSn+wrY%>uE~-nRr}fvx&e*ia%R%?9StM6H@;2Gg zT7b`WqeIXJgApH7`V60i&N6(35rLl#VjmWNXoIr>*N9+GAEh8C56sHL%ev~Dt)=i2 zbd6^z^GNW}kjal^$~PWTCydJISro;fKEQ}mb^`1G^o>RcRMwUzJ|yy<$#==bD4vJ- zE_5)9SKuX$?W=IF8j@J2jb+*-ZWXq+K#Z_anJIXSN*_6kNDgQ@YT zP(jn*KsJo!5N?U|4_!Ne=4kziIMKYlXYga+U-HJ&Gs#YE+M3h+vmD)^hpdOF!rL4K zV?P-NohUz!L@5NlR8T?BL>Ghm(&dlHQA-{~uw#_hfI};1;KOwd>wAv+HM}|JIt0!L zxE!!f0GTnrQozSFaQX~~$t+FmHGlGAzUf*T%X;CE5tvx{v_Tusr=^BXe|98#>IXdj zwV_dT0Ht!2$Kcr6D&ir zHC&0`zvboF(O!t9D}vq!cMbQx8Tk1ADtJZEqiZhFp>c6!3=IpJF+V*FXPO?VO{{A& zOJm!Z*9(tj<~!lBkoezmfYr(Liad`YEQ7clh|dX~=0|RMv+O;Kdn7Qw7sq#SV4Fod zfixemOVCTse5UTfaVPR*=Sxfdafy|~92(8kz<5T}UU|ldXf>;#)du<|C!*g|$ev_g z`bjH0fX`z3j{#uW_|V{=!U=BbWEZwvPT^b&=hFmnp*S~~p71oT`q3%5;5l?TkD2%~ zT}$IUrsE;|;}+g8_v~JU4uBhe_`|7a*freC$LuR~2(Dv*Gc*{T2{6?onhCHID2?Dw zKQuCJY~(>N#j9*%UzD3o;77bFpQf)e=rZG&=UD~M%TqnGk5kS9_=vLxqqoDY!CUV; zMgDp_W&zj^&`Y}w>3`s`&B545inBZh-DFdnF&n`8LN{k|@pwKKBeb>iGe7aU7|(QQ zsXcL(nG-m*Legy8Ctfgf?P}u=U zjyFffroKT3tw!r9`2PQ5J_yXL2$nj^ev?4z(2L}lYFGO(U(=*j##Ox3jp{_@;LuQI zw?DkfJQHRY|D$-aZ3urf)7|Hfr})Jv?>dAky3h|nzLmWTG+)h!|6|P zOCukYbRaa;Kq&7zN= z$_`+`Wc}{*&1AasHpjjbW)!wO}i>y>bgS* zc_`2F^adSzUHtc}N4NdznjX?2yuLfcZ}kCc-0|lIATDY#3yAR|;LEcC>O>wu82IrGUtE4!X|CZGAv z<&qDB&!qsHF)uyO9UJ;`2M%l6segz{5X)l$`3(MvTaj{;!IvTEKtao7j0&13M?X9a zsicjGR8gbN3^X4CZMQk+=?m=iOUkFqM|md5;{!F6{b?;UsOrCG*Ey22NCmLAdH8cv zY?eP|$IeO0OKEB;uPBEacGYuk!*Abu<{xRlHX)M&;rs1_cnVP0_GrxN6?I<@a2NP) z6A(Cp$;nO6$%{?^{!2lD0$KoCC%`fX9gla&Ovh3f1)F~GD!VEkeUaZyR*@H%0sO|H zeq9*2mJ2CnRNuJksdCHxc%*kd{GEgY+bgbOk@6Oy-6jO85b_2U<6d0iQEt#4M<)Ph zEv_@z4j|OS6nfC=Cz2b@%!t#EB0ee6)QRP!vr-3;e|F9C{O?w+w35VWWd~pi-y7Mw z7QO0;P0QTpZ{;$*V(P;t+Z(j36)HT15_B*it>Tr8QXLJUYP%|5GvTSO_s=qruCk}B z3SwQ4vy)|P>V{Se9RVtJU14u0sfokQJ{7{Tp79vH;dW#CkDLaqq`E3gekx ziJ#^}+o&97qdfDQ+Du2|TJYtkP-ghSP(QJ6p?vNK7n2a-9da%OST+J%KQ{9PgLhX5 zWr7Cr7-AXu+zXh%Z9?q?=-ewX<%L%T!VGN4D1sW}bF+c{JIC{94Qj zvZ+6piTZOLr~KQq188ThCp4tKNM8gl+kq;AoyF=OW?)z4IOU}@3!-bWA|EYVrCvp; z`_iLt996op%PM&l&)e+6=dSim;VD0~P(Jln9@%ZAw@v|f3D5{shYt!FZYdgq*=vUq zf(!*<8LRcOSnm_Ew~)uQ-iAK6->`g z!0IZ{aM+;_2K6Y=#N*7{>f9MQnj3+ctjRy%&+^AB-zOvZRscU5QUP&QREQgAV=uab z9|xDiizPxVbEYhECwMyus^#9Ir;s}E!+;M#@AI#+BQNErG+lPnqia?N-`e9FZ={jr zcwAMl5lH2ck9{eV2b}U4n2!Pc-u>tivUg$_?(tMm2iy$uozSIfOMvtOnsDb7| zTMY;XMd?5RN`b}`0x#CLh8Fa^yu^=qrl)D*A8{EPuE{Mg^A}R;+QD*7bMSisd@>N{ z8_o&Ks@u05E8n~CR5${x_lI3eyH@vrAI}6rzTg`URKaLVQ+}H>0dxZTmx>__dLF5y zjfqrIqs>01sYBX>)eA{i_bdM3s_wW zJki5y)+_@nFM^^-iNJJdfWQeZ1L74@I@lQ!>4nUTTwTE;U5X-ckfgkBdNj~r$I`J? zmx-|fnV4wE)MP`N_%qFU3sFm3oK_9zRmY$Fsx?|NGBk;eC-9d~N@HY7K6CR6<>C$B zlM`1wK##$Oe-XD)N3eUie$%PQr-l!`y5|5mf``i2o`*DhAf^O|bCWg)4>u2e$}D)D z9Bq0`(^GeTl3#yLcHLEKJX2Mg*E#Z7#WQ_P6MfAfwKoH=8;MKhF||15GXZ=vavY;C zX9B)#?a4v;@~zL1^H0R~KdbJEIJV;8egOURU{&7h(-S=pi9%ck<1y{U&$%an^~K-` zC=0_3%0b^Fngpho_oDldxu!At<}YtO1Mg8>jq@GQJ0F=G6&Ky`t{nhh1>TZxJE_S( z9*JPXC&6LEBL?3Y7+(Y2nQi@ z&0|&xXItfK!UXL+9m;Pfe(m;iq&eO|hl{Ak+r)A#4lLJoc1FKESS|PAz(hhe;IL{3 zs?aU}Zu}PR4ou#SPT)A0^Sq!KbUji@2d3AL=?E|RqkG6)nMY-F`;Wmn8lUcP=UA() z{%n5Mz+1BaoB}5RTXZG7V(65kQRa8!&wdYJUKtuW{|q=AJNpBd8ckk$;IyHq2MSxr z$pej?9S=J&W&#=Wnl(K+#lo{RPjvKEu{?`+t{P|b^i5lIa-4o|et5BL zN6@#iu5Z*ae?rjP2+s+$;!Go)bDI&|zWe_8(ei5#T`GH8!!m*gQF2U4>v$q<^WLRu zH;Rv0?wuTxPv7(+`G-57ChvUm7v*Q3^#9BCn@*OW``WL_0G1E*pW_0v3U%F%v}mQS zd)Eu9e70O`!EtIAz^7XI(8W1sC{vEqW^_E009p^AG;^PtP<{AHHa*H>Jm>q$sMc85HS)+F>AiDYmlUQD>pMpC8J`Z?-L*FbzzM7@a*U7vOW=_68yow4-ddgu5 zr-9gkshWSInfBCUKK{`18BKOByY~*u?f0ybt=rJ;Lq34u*AX60Lkd;46&L(&;9vy~ zAfR?(i}|-VUnF~)gP^&FM`17uaUIW>d)$bG83giLi0>;uyl;{G@;BZh@4NQ(^6HcR zRhHoM)_erm?c6gg@gR`5FE;-Qc_DLol<7#1n}G0RM_JF?a-+v>9{F;!>^L!=0~=2) zBdzC_*r-mVYkFpDsrsaUe+0hem-vnKsH^2+K2-;Of^QpvIB$0j&gZx8KEuhOqV~ri z#hpX#19>6s;6-Nhz!F~Ypr7)QDA0d=cy>=7b*462 zxYwgo^TF?Sv*Y6T6k0fHXrNVrN3d!47dy_8+xM)JVeA38J0kJ7lhFy_Z9dHD@xDe2GYh=g$K?d>^?&B3 zi)9mL2m{y*aZZrY;=;$R`+0yn|;#6HuuNAZJ}`5Jhs_4fy{3Ct^9* zKwYzgh71o6$~qi(;fQAel(DK9KU(V9 z^5W6P0-l^L~ZZ{Y9X>8rlzFur`} zIp`ExxQjq3x*eYv^~!<2tyx)utMGaxgAk?Wobc-6Nfd1$MxCOtKRgE;Bxinz@ z0chgHj@6A;KK%lrzUft^^kh1UdxE-3`;>|Dyqw8&Kz%L&)Xp3-ZOYvbA0ZDtx?I*T z!<&3$@i+>{12`D$u{v>9)fkR@a2$)H3d|;zrF_zSb8zB5bOMR9u7OUQ*b(qRCOGp~ z8Glew+5rG%CqNcEu&F*ffUn9s7v%ZWQJgurD@6niLjzrz>eMw9-x;XP^qF=CHcD@$ zWur%5>`o&Jc%%?`zC4r%o=2G25!;i8Al|lfp*(~sf5X=KP>x4-7wE1X6nqOI*AWb1 zjsL^3wfIc;QutvjLU}lH^8z3psNq8%xDCWVa7m~!z_c#8-p4IJbPP4*-)xObyE%@* z3(GWZz$_$f*b3v+&e!;$$>N2EKRiq5&w@4-M0&(g4xJT1MS)@>{q?$ybSWKY#`BPzrSLN;I4V zKRs}|qMq66^dB_qaR5Ki%dNO{@FlNe#w92BjzLcx#oXp+oEWF&#@P604_Q8=i$fW(ui-P zzv@C~5Ho0n8s)(#=wxO9=T7E2i>{2OSD$`ob-`WZ0n0|3F{YN?!}6*4f{$f<*itP>9CvSb~0s5g^4Ki;SE z)(pQdL^!oK@bnT2)Fu=I%0;Tv`wG2mLL(oA##_1`hd*G@X zoH&0hGY>W;e0dseh7UuRpt1wNV73mQ0K?=KQz!#me0S@}7?!fJ5d76rJ(oZE>?rup z%`d?T7nO*!q_v{v0;EGDMo{v)&be~KPZf{Cz;}6W-LX(6C+oV?&(eoLkJk1U;BG&_ z>%?-8v;9AUd;B&EyRxuT8AQGFm|ruWvHrp^i*f^{jK?2|~v$5#UQZ0r1FXy`mm`?-KER zR+JNhE^yk@Fy>Jw)+J3)9)GA@B#!9vtLo5a2g=UZo4U@qDI2%pRvfD;22S%=^Bipn zFoa6rc{TOMCM^O~b^v+1eH1sST5LQ~K%12{0-FV}0k8;4Q%NtfX}gpx>hOBFPGP!P zK-u1BkTBJma~w-tVLZoL0LiwDjStFBJlQwEr}*I1ru3l`sN}g2V;hJMo;BP5WXlf; zXmFMr{+t?Qj&{#d(9#8|(F}f${b?s)dM;(f!PbJFsn3NSt2>KyvyV2=((A$!S>EKs zN)s);^QAmq59*nYm#Yjoj6x^ib;5v9Tv%5$qv1`9s)0zqq`lB|m^wjWOBMkp4k8<4 z^-N*N82~#`HoO2Wd1%KnX-)C@4A!Fuy5~N?eK@Ro$+H8f6%qG)-Q5H39YijuqClG} zNcp7sd_WyjkIV*UFoRx#)2GV3LX4}-^9^U&tbA;q>;NWlCm?~!4gepcI5Khv6ILP) zRHj{YlWP+v;p@2w0dE6QB=(BlTK$=YcL0r03sm!}$~I9YpXD>1yjgJCJKVSvuhsX9hiOq$f_3&>7NDVbaY0vBj zXCb&*$r%7)5Ge*c)JK0E0RGIdn?jcv`qqqu&qgJ5vg@OS!j?a$Fp%VCAFwCD`16JUxO$DyV0xCJj#ZPZTYf}c1c z(r0~eqz2aof2>2iOk1#<4=!U|2M;~?ii6+qV54%XK@YgvX{wpSCC?pxm?cl!QlKvQ zeO&}TXm$z&FH+pI3MYwNmEs>7v)*vT9ROAE494!U5!pR~4q!pl0Z_&fl283v2Vmv0 zvM@EA!Sx6Z&Kisdw1kr;#PTY-iE`AjyI4o>!x@VLjDnp#p~Rng8)Td)~D zBwB@b0z5|-etJP|qb`i#Y@CF0Cr~T{$}-J>!O!z%X5BgotywN7c#26!0$Ufr-ri^p zIMyfSOlVyMw4R0OMtrBwvxGL}aVOy7-udK%Uexu4f;J6s=xA5PR}J?=JpwZcV1x;S z0Eo$eYG=uFW&V)}`Hta1pgm)l1*R^jw-g7*NVB0%70%9r8-{$4h%*7|#4sIA-B@Q5 zQ;K0uL6D*Hy)edujmdnf`~)XCg&*xt;1j2-9df3BN1he|Iy!*Q%LfLrQeMu^6L*8Y zQm@O;(w|*Rvm`GRSSwS1v=iVpcR<876!oD@(Auat7f=uW7gWIjiiSuAosrK&!6PMJ zBr<-`_f~k$f8QAXwlN&BX_Q8K<@4Z#2gamq5owMe($FlzWb{ItpL=F(@cX175Aq!=13J)gWkVu+`Upsh{_4^$ZS;a3f!RU$1lp1L5Gv1t z9tG~xHy1302!iSp%)}wVO>>95E-Sn^SS|2UUtbE_TGr(S&6k80wF;PG22w$cA40Kg z!px4=i!Z9s)QO7}6O{$@a9o z%qP0}FuB{7?*vvl&2IoGlk|AT-?Gj8EUW#t^*p}``%tM~Vv2mnz>quiuN%3omz8qZ z3dshh+7YNS_(09H@!(gq>7&;@vQFsI|HYoXBv<*7KeIH;XA?C`?J^+c~NOW)n z4h$SVKedfVheFGM$5$lqIJ&%=Uc5(oichoE$!vhD;MkkolpCCS&+AaNHQ;?x&ZCbei0(TmNk3~!+f3BW2r zI>*95xGeZz@f&sbW==C&WYBRGX7J>!=odsk@zqayrNX^G+Zyqr4`qk|kN$2!897Z& z<&WUEz_0O%^rNT#Tl%LvFG#!fOF+HOV*ySDL9|AHJ~Afd7`Ooz>BjYnEFheWGy16>K$9k$xTcMCL>eC@afc&joZTGpLKZl<|gnW zP~09w6zjLXw+T=N|L@Q3{XUG=Oyc%nXx$QUIAqwo^gD25yuj)had*hi@O;8|9J*!;Uq z1T!^p-`@UBKh{qQDw%wSE&c=dz$H%=Cy$5V5nPN3{&_!(wz7#+WWkd?GNl+t4Gq_A zz(}Fv)Oyd9Q+=S-ijc}kxSD50lR%3d8mMx=%sv37-9)j&UEp*VVa1C?Arsodp-Hve zIc?se?kOf%uZMGNDx)>=tjj`wUOsr2Uzc-x35fcvtgJl&XfPe49|38lH1YnlGCQre z0c5EpKlED^CkB#3`0D)J>2BbY0QyuXQj0eI%u(fx>{E=>H61GWgXIbV!~j!kp{KNw;az~!{hr`WADPKUh!z9KZKjfnLGd+{SAa2kvW z;E)Q&2SV9aFrM%U9yhep$O=H=e!P10=H03La6E^P6CX(ErQPBuuB02)yqZ?cAIsAm4LrJ7>D*%H* zXN%xbCgBvrJgG4tjj}ev2ehe#(AunF7OAmDPv*#NZLfm%A_X7c`u&D}foZJFcAb2t znOOy_HUUu1umvX@#jSm0B={m*smmWnFX>Gq{ea9;J=O~@!(!Wqi^tWU{Rsx}@rr2l zSJ+@!8JPg6ZYybFc!Kh};sxmq^UDL>31~yWdxoa-!<17e^?`Ct2VV2dp?n;YE|UQF|HlaT&Cr9|rCxgiP;+h3i$EWy zEP9TsPgUwC0pRizFr(sm>qsZd8Sc`x)ljXNTe#_>?>22&whKqn;k*3=c09)GTLB>VtG?{Lnu56iLEBYd zJPZ8L6I~_=@zBwJz}cJcN^gALAEzgta+OvBd{k8a%i*13v@S)X!R)Q)eB{`MUeFcK z0!udn9lZ!(|H&}&#z(=;*7@*^FJ2?}z$wArqvJNZG9xp8aiw=Z^@K2j=lsLA1br^6 z@$)2s?b=5!hb92q1e70wit+F=zFnjTm%e$K>A%-+A1LY zqDu-I7^%w(8adw#pxo+DGX{ckGQ8#ojyU7{R4Cp9*e)M&ks7Ytl^%cH+M9r?#B%qfR=uJe_!MDF}c;gVUbVp%Kg4H zji1K>mNuEofF|-i0oReScrjkUD?UP_$r>+|K#6h-GvFxa^(Bm!7BpE1v9|)Vna07^ zxdS??383o{TLuaffUSMA0);{r5O&}Jk#j4+h9G!1b$R3HWo}V)=oh7)q-eU?An<@F z1rFS;0&7QVu(&y=HyO-au~dTMOrd74ug-YeiQi3 zBtS_lOUhmjc;k**PdGDd%(7;m?d*y$oi=Sbn11?+?@Ig)fRBFt5ot~z1SR(-5xC>% z2hH|2Lxk+gv|LFcee4om4e|cH*=rX<#J^2j!O-h zSILKNW0?gA%aIF!QsD_Hxcmuk_5flckUpk%pd5Gy*8CbT6GYaJiGaalNA{_|D0Je+ zJ?Rxsey6qJCvLvL{+7UmzB)`vy!4$wkAZ7aoP|6J3{Qz=qWZyG37PZDiXj5lD=B?x zO5gg*tQy=JqLzoP@iaY$%%EKL&|VgrK9`9mu=2S+#Xv&e#6^Ts+qeN5VH&1mBIBC? zY<)@o2TSwnceRho=}C3aUeKw>-kBz+#phAkxP*xZO)gW9B09N?t=v{u@#rchfw*`J zEqdUQ!gd_ZX5ggW35W>*J+sM%Ej*kFlJ`9t2d63c^-{mlu6u1{Rl_`z8rFBGi@y}q zv(m+E0_vx3)K-Teo$J}K1Syp91(V8p0bVFvaron?21l7{>;V0dge*cAU zOs{>`TXbu1SDIhY?5_T4?*G+78nDd)-OsaoZgl0q2YJ@zUbp3=zL&3LS{CBlmWNz1 zR1P-GjYcLvmPbJOj67F`Ie)*;_j_@CQKs-0FksAMGr>3s=w+{UmEG-NNeH92|{IE{A1hAugmMwwuiwiB}22#4(PXW z2R<}!q=PENnJNTjAh8NqS-IMY_PMTRTaqb_<-6?*v*b(V3@We%2?7ll6Bx|2$>8h1 zpFoU&;q@^Nez+?64S-J<=#hyj=mg4D0Y*-seMd_!KUs(V#@+&^6hp!isHRXAHDn!# zf9%T<^58*(SNv!+UPRJ+0^k4WkEM&w{$hH|XP=YadDWBCuKCS+bC7|GAvY=R!h6qo zV&z1Smds_Nnu#n|d|}>FV&acg8VbUP`ZghtLl?C{$;yL2dNMP$m}YfLVt=1dYD<#M zFVE=n@pF1&G;J-09&a|<25I;-sFG%y>e@ZOate61ps1}6Da66eQQDKd172z|_r zfh5ZuZO)b4G7E|L+(YZINe)kxMUW>B4?E>%FPrhgMzHIyj*PBuWj2E1Cr_#^pP|_2 ztIIQ5PF57e6S|+UfXYf9T<)!lvkKj>Vad?M{_FfgA zkH0l--+WKnykWmT7gu&mEBd9};s*WEl5OdRdrnPX+IepJ?5!81uibHG+I?t?O%zNP z7T@YayPcpf`7h`w<3O}2(f^cFxEm~7>iAUKv4^`CF#C><*;abRSLQJrlc=oO zgJ&KCQ0ZxBeJSlav?=}7XTBrdy7zeh(_s3$gP!WZkI4W@&5uGfa{h|(f&zI`eoj8- z&h+i4eJwrxoX@4lpZ=9}#&P;?!K^ZG)N@_}xPmWu-sFwxseB4TIG@kD=B_i+`>%d- z`o}LlJAL8S^Atamwt7GTv%af-@LZ1HT30l-s;bvkTK?bL3!kpSS;=i3U+b(&EFIJY zKqHg8pOD=wQ1;{IF6GwBKW_5}-8Yd4`t6&fr!XuA5y1IV4G^Sl1D;XO{ zSrFqVpxIP1_Cv^?AfvlQU0Z)N# zGY4MoL15@oG^62FxOb-qK76CiFWTe*QzsXSa6j%P%aKuGgQkF*r^2HrMBod*B=C$n zqdGHF6nVBYI@@4Zj*y4X&$SYsF*mc2&N=Sp^u&jLC0+DwpH1I>>ete? zt-M+)7f}XX9GW_GaCEF}4WCb^oxlBtbpAtbNI!Mq-=_~=^Q82qkNsf!*!7Ro!v_9P zs#XM)N#&#Yyzg=2JOTbYAGfCD#feEl>>@X1ov^Vo1C=P6dopDFiT+wVVEY(WpsdMX zc0PCet?8s=^ezl@XtalA)Z@+yE&e!pn0Ud0Y9RcWs~c`qq~Ub!YnoLI`xucT@B>nb zqA!G}7IV@+L3VbL5s$}#!{Haz>_s!&0oR@Y2I=M{WoTD^3sPChRjdT)aGM0wQqlRe z8fCQLCx6S4mh{8;!mXRJM-!3RHMp6TQ!YQCdxVbhbB2cNB>$Fe=ol0~0^N(0bvT;#T5?OpCjnuqD`O&f zAUUMV7(qtg&@8pwY~eZ6uuK))5%VC_JTx+EQ>_4sBaJ7iEH6!^C!T#xn$YhvEKsnp z0yd_-SjT;@PB3d-aDtEstNG}zmu6?yc4zZ)q%ZJ;M!1~)GbSC%KWi$p9%@LK12)cTkfZZbMG6zd5`Si^5KX2bJX|XmIY|}(g7}RC{?SOeoU96d@CpBto__9U(yzYj<>~J=8B9+t>0+Zto8FZ=Ya? zuOor$@j-jl#i;Y?+V|38aw}s$2hWa7PbY&o%sBPs@g_h1A^1(Mlm6h8t{|VSv##+q zCji|8?ift2>`@`Mbpw3#>hFQ<9qi$3HtOv@=-rRZhDRPe;JNb&Bq~B@gQ|nwYnGD{ z^7^Q22Oa}51`N>fj#1%f2Ss0c7SP$Q=9976;j2pIIZ`%w(kVx_txdu66?;}Y^k<#0 zBb~)PD;EIEM=)@q<_pM`hQSs(@cI(+BT01`!(J2C$^7Qw#lMjre)6^HcmDOIDuQ0P z(kIcVI)QIyoUGqy5*5Jy>m>BNN4^bVTX0y7BX8k$UcHP1$)1QEpOkgO;=8O(l-FWhtknzrj@)Z}It zelkSf${SjW#?z@!1`}T-dK0<_mwV)aQRKn_7;2UAB;^eCz|f>O1}>ow)h# z^b7C!8C|e6QpB@n*BG&>-3e9G`Bq{1bhkQ(Z{xvL5--@LfwIUIdd_+*I$X@}(Kp`H z;^Jg_yn_Ga<8}W}o31C3c~gK6(1xu>frrxyX0q_uP+m@7 z7<}hFBR>K{m9*yYc|^K+L3!UWpmFI!26Tpg-L80ewDQo^B!@OJFlivO1HSxNa5x`r z_Xm>gU@BR@ju>qx&p@b`$DsKW3t4?Y^bVd{2_5L{FRmc99rEr(Vi|Sv%k^r4zn05k z$m=Cy6h*3*f(DXmI(U8j&@-ca3f{ee;jin1I%qZUq9?yE{nq#VzOGnOuosQA9^j>& z{E`p5^5umf4eI&@Azl*dz9pHew)-S z|2Ud@jZ4^cQ|%{Y@Vb3m%fbd;;6PH)+ya!q$$~;l2^{4v51O&Nl0JgfxU>M1Ky1I} z3IIa||5bV!==pJlAA!oL@G?&Bu@_JR*h)ljxAlEt?`QlFWKdQw!<*u}gi5>ID=sp( zLmOrt%vlcUQBZ%X`E`$FZN#R+DL1U~$kbWwU>6@zIiy_hO2#B(d`?Q)y%U*+$l?~i z%R`8Lq&|7b?hWjgF??wfc=3hrNngKfdwTr`USb=A6v)P>>S<>5t&-2JS>_xod#z(^ zQ+6y{7Iq)9qWk}${=#x;Y_)-Y+MZ6_vO7KJQD1H^|HA?82ms;KQ>rIt|l!g5s1!c{wcn<*@fQ07quT3GEERxCNz?RSE(< za^*HJ`6LCCXTvC9K-0=PHP0GALd?9f8Hdj07?E}O_(li6z(`#hK0H#b2R)9DtS|NX z?$aB`8)vWE)t`CpThgble|Y-D^^elK0{q1!6_>WK|BL|`I`X98q=dOnF*(2|`S^0& z&v@)fGUV#tJpXrxi+bhyX^;DAI^z_*3&Z|OU&?tG5m~HutI*XC!!941Nu*w9_vwT^ za6~SKH3Bdz1T@l!c0-|0p36hM{4@In|8gnHqiJ0ez{K+4%7w|L;e?{RnFQ!GH98G1 zzugspO$gTglA|Zw59%S@>=f_}4wH!+JUp6jubfQ|R(9#YiZNgrQw|DX3JnsxfMFAA zHLPWUw_tJJScTsflu@CD6r5s(Eb|!{BzsOPSdVn_#x_!vrRLSLK7Pn+So;aQmV@J~ zn}1hl9Ic?4nO#h;eAZjjzg>TUE!FYmle-()QvsniDZnzhBUX*5i^f708(j0G_FY-n ztMQ?RHCuPY?Z6K`^@_u*6In9>L|N9#yiYH9z`(;#mxkZv1zV)-)5^8_+hBK13?@#nFNCSrO2Av7(qhh|@h!mN!;{D$J#EQ#Ex=9gdLHCx zQeT~I=`TqA!D$eLN@!ta&Vi9YTZh{l4+r&395%f$+l6lilog=sAG*qejvAMLE#p>% zvY2jVLs=w>Y#~QzV`e@$KE@?{)oC@|(2M-TcAQP09G)ISKk3Xbr-yF4HQjXg$@Wwr zuJ-22`j%>04>sjj8@F7dSEmkHi|{tod-KC3JprIW2pXj&ZAhMX%5CX6kG|6ODOPQ( z+9BpgvI4+|XWe*%?(+Kd`gmri6O&qzXJ>K22uLPbWD|y&4Bz91-nvDM)TJfpJlNWd=SSr*0xN{$aZ zq*M69*$04LGw~dPaWtvJ-+~q0px`PZ^Be9BeyA(U!5@NxW*1J|Qd z>yN`%^TQzP+KIPu=1@9e(>?YMOTD>gxCXOt0Onr+LI*Ez?)e5@Y~+o~yPJUMujujL zP`{va-)^&@*O*`Qv@6o)t$HykuISzJ_R-XlutOu&_ zT&(8x=ze8zXa=;k(ru6C6Ku?f(u6AH#nlKhi=$_t0W<7 zZUMy4mw5|vRk%D$HVZGla+I;#o2QXLN9Z~Yq@3d6-yGm%^~7F;)lq-#XP95a@RGMj zy-yY7Y1(pH$!!Mn!nkeDvt0c}TgL)9C>)4Vg*qeiAhJr~2U6E! zNqhEh(z{7{_g=i1*qd7b3g88172!HD&6u@ul*<_SI7mfp`JX;9_`ZX^KLDz0yRHcU z1O1iYPiSbrlAoXsdE-mnVnH3jZ^52B+HjZC$r0=kB0vVa(OH*nhUSdl2!3b_3`PN! zw$WgO*F!8++6Vq?o(O2tx>o_zd08(}>1VOaY9?J}ICvat<)AD&?2R*I%D^TA$(<)T zc`+eKkG~$==z}{So*z_AJgR0B1h!SGs$6j$MMmnFIP*R@ua=*Fy?XhTk4!h-zCBIr z)nS_tRVklPDWi=2zXZD3>sFlOY;=ZacGzl$C>E8d}(y1rw zk8S7)g(VzTc9}a0(5qJfXpC#y_3*noUAoVIt-~0xBv{aljL3?@JF?NLVBHhIV0rlI zLlY}%R(+_9;H`q(aO)^02M=Hi@}fhzX?Y#udB@Y)4Q|1YU%2_|3uRXhWNpD2Tj!8fUc6bmMntn zBlGlPhED|8`9xA|GAM7f32K7m^?<*uP6JKBkSdDWOhfpPHA zjP{oXY15p3bFV)fXL;wcedW3{)33k%C%Av|SA%6@3aFtYWtz?teeIaBYz&FcybO#{ zOk7=U#3FR+b3H8R0U@DqR| z6GHCj;9JKVFWZ4rejW6O;qt{ln*?^er@ z4$$8~*s?D@;hY=O!%x4>y5O@noR!}H<>#h72amBozQNa+DFgjvi7dr{^4v{mb#VCs4|ClaS){}n--i;A0E6o-C(9`oYp-7@P|U)J9zCUCezdf zOZvb_|7`%dsS`UBg7M(15f}`9)Hs8}TZnpsNAUaL;f%aVuE#kiP&+J>jEhnDAr~}P zSuYgOBY7d)_EMdh)+?qO81swzPMc;STMZDjx*hUKpbmQR%S6$^wTiHy0Kl%9d#jl^54lU_V$Ev)%>Wle}cWg_ayyi^9&8-S?+}2qIzoHHX&IHSSKP)RS zJVay$&jHNLDJ++`pRCmYu~)SFzqAm`e_fh1F`aSZUFqd7(A9rE_wkWosxuX_T($@0qZLu%ibY6xo#X}Pc5 zV)^ed-vZEb>S#JRRse=Bb@FGM%oEi&W*0aWxEl_D@S_4hLDm!rKIKA_(KLyTj;qenetjVAW;FuU(Uiizw zm#!v(u($GrAM=R}f65p-PXrdc@Ste~lQ~?Cw#k4Mg>1@XfPLm6w{IoRET=sOHl(** z_PF$yAA3@|dgnK9`H=U-LfOJppYR+B941He`Z)@{_#bv>9fPK{;DKjIf|83eJ^wVJ_K0<;bp6H*TmRP7MnXdJxJCeZdA&Z_Fno(%w$pDQyY3Z*I ze=aQSwrVm=X}b8KZ;zNtq1SBZNP4vzb?N^kF#Bm9y&2TDS+8j(0m)y zSCor`e;B+d-3@y^>98h%E7H{UPfAN)m>5nzc||+qY+CuIAA?GVI<#Ez!PTu@nyxN9 za64iEP(KZkY|CIaT4#LQptV~0Z~0)N3BdFkU zQP#%b)-AWCgYyT|-u>Hk4?3+syvk|-p-K$2K#YLTJPT0Q=?nC*?~}Pd`Jw71&{ZJA zorjJ+v9!D!UAI+{j4xea)}5ZBABX8fUp+7V;bj-5D{eU5K3mSmMl7kgmgIPHLaQEq zT$E;5)@|U5J;}iDK)*QMl;$S&NA=hwm0Y>&L_YkdpN)w!EK9DFiL3`@x|waj7-8iC z+Tp+Q{dFJ!y7U_i8NvBVpe*56LK`zA*ue6hyKu~{ADGenwMLI&LmLl)RRa| zCW3X)dmz_5HH8JYcox_WTPuamM8QW$3H~qLc2aud<&RJQ`jvBai#M4z=sN`J9;>&! zDCnoO%-^6#dUL|HF+k+0p3AE3vX=yL*^A>sbZ~unr(EL>TKfnL7^u$Nrg0~hf6X4jnK;(F0T@2J zPP+WHXzW+hiLr?ic+szDK0vyVKB~XzHTLU2ZrDB_)&zj5+V#D<4S20y3)X6{dmEq* zwT>6GAaC{roUY{ZWRrn>I&|6xg$5FN<%z-uH~LiGIu@;_&FoQHbU33I<8lZoIQ&{Z zM#fcupfec0!mhH>KER|lytW;8L)xTo{qNp=TH3!~e_dUXH!-OzQ(g(gmAy3qM4(Ei zd&^MtE$}6`;0`_IPcS139|l#^e`$%yfxmv?4bQXq=o>MOk3`zu<|3kRVVNLL3_+R$ zGcXM!-MgPNSLIkqhjjI~_a=0nUz|!8o_~FM&G%jAS8sf9w9VXn93LtAT>a_yu&v7@ zc1eBwE-z?&1s)E%H2f|P+ITvZz|TrShdY#iXZj_pzFYA^_8KoO${d> zHniJ-9Ml9W!JmV+JrQJ?N?7FJakM6lnA5TGTA@cnluaYrgTYQ)lIkJe!D%i*>S z-PNh&Y>1I;xnJ?kSJ+j2oU&4o!OYCwbmI0a)0X*T((YZSrG0yKYoKrJvm#(Ju)@Zb z-U5|?CTLW0f|-ec3dMvFFl*_r-$*!bou&EEl7PWLR#q<^~RjPzGuJWrn++ni>_ zv#Y*Uk7xH2X>LNxc`fO|33>vKS`zq{=orupz3rW*OmbCZCFqSQDqMsPFuMaWHF%^J z;Y#@1H-DGfR-gS+`Ia?j9k*#;`kkMAXWFRu5?U|tV4w3de{pL04QAFo8XJIJ|6Mw= z?BkE{#DEt89}pj*%WOQKuGXylPS}T&4toO7Ukf_)?%}VzcXBZKu*G~E!2Opk`2-mZ zJ`rf}@UIixg|?odcXZTt*k>8`Hh|2(Q`QhR7QAPp4aTnmq5+kaH6-~34y@!>mXK9^ z<=@z3zO4=_z8;UDG^fA7Jok`$(s7H|r9FF2Nw?{n`pf%|Nn5qawxVEOCO`!33LU}S zg*n*UD~7xR&}32g-3fq+r1q*t)>`j_Q?i_YzYm8;1jBLdd1k+T&5ruV#MVgA9y zwzvor}SxgSXeL#5dGYn$+Z(*PHXslQTSbH#FXrJ7`W``2I)**#LcjZ}T0bR?+ z*@$nt64=Px{*nn^mpiHC+EafA5@R=tlfxU5)+}})Eiuo#+M_X1fZ29L(M5ioEC0! zPPLBH*#N@ax;A6NNZWWkFn_1Ar33Uv;{0@a)pvh9{oph8wI99%LJDQ4{G5vweY7 zQy1thY;|^CDr!L3gkUfSvwEJuWKaMj=;_ijX@KkCpYfq($3L^t*$0(P2f{^5)%BaU zJF-=Pe3gKvoGOAHIu*R)bDKb;o2=qTG*K{QtO)et%o)erlb(Ifm(p*3`ibeEcQ2+B z)Z%CA*7=;-K{`_}7M?V%zuKc2e3sxPplCbcObAR4J~1#ss3jEC{t^z8MaBiemn7e> zvfZw~3xDmw>GY*NbLlI)H>TST&gxa>32owOb)t6|tax&({}!|xCN`u^6C1VM*Y3Uo z-{RU@mbN!7QMug(y-#Fp7=Bb=OEtuf1TW(@DY!=yA(M!Sfzyr7{4R}dA8#CgJ-W3H zI1zj({qf+(((SlC+;l_}fZYb9UwQlFaPor1fp(1vZuJsyMX+4GGmp+Sz9Pq03=FAk z1MD31lJOXg8Mi?ooCZB=s{jI@RDYC%MzzE9a$F2}=oek|GM{o5U%^8zzP?BQqvv0h zuGn!(`p9h$Nq1_Cd55kvm+v3yr5Sw+T!Fbwy>Psa6LlOnHAu(m1)EL!V=NoBQb0$j z-NP$9)3Sn{z4rskd$01mTUV?*^t0C;3zKQ5UfI1z8)ApFIZ1KlN>_YV8|*=dphyUm zW(Lz~v+nh0_-Tjea-UBdTY?L|9*COyUF!6kC7Ct125_A39{n78$ZWME2DvpU+laYm z@oxRT|A3l*pez4Wdh&TUrr-Ukcj*a*CN=ghNv`gA6x*rhTxZbLj~9o~uJs!0_4B*- zU3y#|wO-Xst@4Bp7otPyF0ESrXI;d@!H;MH@UjoyHlLP$equN=ZLbAu0Q3icUj9p7 z0-Y5D|7xCkFXYVdhO4s+E{+efd^KVutAUVvdA!=b3dk)d|CsrKec<9-Fb5s7G5QwV zlG&9%bg|9)<5mT>si>>3HroE%6Rt=v``~w`9S1h*4{Q+1p7v|-?$vRFu0Fw~b(m-D zkQ$I+(ppQ;yZOe=K)+H1stA;URuIsHu=W<@O20{0{SCU`*F(!3_^yE; zZzMqqh*NmEtsM_Os-CY0y%|WGoJekmiz3fH8=b6&g`4LRkS__#LE68xI~}t7{y{pV ziS7}n??`|6s&}Mgx9CsduC-(jSMIQV_JUebZTat8B3_oz44t5B*e6?yx0W3LwN4)% zJffF-{~u4c)Wtd+oFRQg=>;i$L2t5tVoGa}637}5f!l{P7+~r^;~@j@qk~^TdL{H3 zX!vM&6gku8S7bCwjlwI3^zp&2ec^>X%Ub-uE36IMU7s$v6U1XtV=5M;xcc(Nn1E~2K?>b8EiC}a7^o# z!KVflh=Apgj_uFr%wKicqM$!vuqEkk-{vwolP{HFRfx_y^>ho-)^)q`ArSnaqr-WT zcebl!{!x&j{!;PobYSrw8%gt8>6~}U9qCQ4`G<5Wuln-H&a3Ir`l5%|$FJ?cWB0$y zm#CF$c?kM=$ZCGzef%yDI#Sqmp~i}?{}7UZ}lo zi$}`DjPK9~H?6?(&iT$W93J|1)Ohf`SnkUeW0?rg3~6Bzk*D*rJxog|Wc^^l52IRU zxK6<{`>?I}$Srkv#?L~49hp|ppT2EZI&pR(eeRZX)10ovNVw{I-*V=9*G}ewHf*!a zcj4u>Lw1MM(HAK$%1tJ)~7r<~bt#IIwtG_Md zaV!V!T+sbFo%t=@T3@;hnAYt;wl{wG4W4Mz6|Gl>zxUj)qCZp+)O0M5+vJRU z`UOp*i~6FC9v0?*)PMqxNfvls1zJkpl?{t}-EwGh;U0fR!OspqjpphUFl#ddP;biv zSmWe7j+V$|T^MDhEK&08!`y{G?3Bpc|5vqi9XuRV@bA%;A7AYDKkl4c(;Hv?&UE_8 z`WqMVs;+x#s!-G5xT{kX5ne6BAGZ=UuhvDsPJOa2Z!J3fjnng{aIMe@XtSe!?z@oQ z7;cUf9`Oo*4BwJIaNtMMGtZh$Q%_tT@J_aZ&MqwkpX1b{!96IUX>8+%+@SYCu|Wwx z$efw|L%R>_{g6q|lmo~Jkq`9D%(~{V;FYX)P~<`a$DiRHUY8F|qTscyRsxUSew*0K z=`%a@-o1n@`PGKHFXx!HV@~)iK`g#rv>iES#4{UdY+^%CaI=>9n+LP9pAj`_lYzBc zX+s}D6o(YWvi`_)X>a<-c)2f)%6*Y1pSu5QyT)H*>nnq7AAaS>Zb8g9FWP6#P=rM%N2k&p3>k?=7%dk#b)4&g3>!wR{-HFbTCl0;mH7ZsnB$D zc^aS*YP8M_kLF{ z39Vp`bp&Fn{mcdJ2!bbX({SNj>;rQc6#TGq|42ykP?Q`A-zE^tcl@)y>f`;KZOvFZ z;@hK5^BE_6D_<+5HvE?Nraeo$?3;dzYNsE2*5}eMz2w7b!<-_&4*oE&Va}f7mej{9 zLLme`D}b;G{aPpRKG|BluDnb4`L4?n`T>d9`E*6vb7ar`BfEh2Y6XCkzf70z_*#0# z({wdDhhGRXFzo7_q0!Q#PVfs2E@q+854{c)ne83%!IJ$&V-Y|F&-!M_kj|-!w< z@ZVl^S^Bvj__*F-(5*}JV1sO%1YXlfx^(dRbb0naZer>4gD+B_tjp`m&#g!8yS81u zkn=mN<@A$-m+RHvqmb_P1aOH8@sjk6y?Sr_hwX}82Aw)N4`>T~8-QMmm7IAi=W1`&a+*aEo5;I$)!)CoUz>f?>HJggO0WOv_oWv;)g z`x+ldcXiMs!RMf2`TR2gFH@htqMqX#Cm^T{iya)87nUmVP%}+*^3B zCjbiYqv_E%ET_5e*017Ew)fn{i&$xbJr9ID5!j#r7t$U`IY#hN9YS3OY@zCk=dTB9Bfht^Y>7ArUgikx;x^%~ZE$O;@PLP_n z3vP}^vTDeY71fIFebKB6vdnavej;zT^>%IdlaJoQGcwy&e%uHAt_)g_H-`&)dFk%7 zZ&B-T-6Fi`>0eH-`>B6P=bfQF0G8(X^{j9;9`DLbxuYLEAQg+NzcoxPtnfPTirp#` z{64)duS<`!qde$_K9HGmIo+WN;Ki4`E9q0mM<*SX3E(a1isc_k&sdrsOnndQlM?i; zU{{-GnxeOG)zk)>PBHi`R*Z&+fkRMI&2t7!`)@MS%gT<&tw6;DwL_=OHebb2$emjp zhg}#2Z9a4g+RWCVsfZ?ljWhGhs;d{_ihMFaLL+R$J)CoO|;K z0P{TN)Ya+In8Ax9+;B_51Q4mu4%s;VI9cd-^II*SutA4L4!VX+0M{S8Grj&hfA^BT zUmJJRf``LOM`Z#a#}}m+T(g|!e^9G{;}}dN3t~fj5KuE4M6HQIx?=i-;Pr0?Owi^o z+u|7g;I-{di55f$RfA4Idve+p#6e)f9=;129n&@CikE4en>-_dn^>oDbQUm0oxlCo zbm3_?rd{(J(ha+g*AHOyC7#@#cs*KaTv5EJO^}+NF)Lp5uL=`=MY#fZ-_jq^W4l*3 zvHEb$J-XMw^Uy&B`(k?OcYGoJ&QE+OJ?b32&d$*8y9@FmMK(=%>*^RXH)`~<9Z!MpsRX}rLJ90dPe`k~fWPMAyQ-u;)CeEx2|2yt}MQJVn%HobpA zdjS)A{`_4$&Gvv+>07}rGSk$|gEIzJhH3!QF$nI5#!c22%yqX(AQJ}cM4nQ}{D3Zx zRX~=TUMO~W!8RRaLV_pK^Qd^Hw+J?Q-_2h)!EeTu#L^j(j;F8%h8 zUz)!E>0i|ok$lxhiR9Tfu;z8~K6)Gve)sARZ><#NsrCAJ$l=$r8ehvkbOWNVHz3pJ zx9k32zvUdP{P`tc*rne-ADwis9|P9KSV$9Z9t@X$Mz;cI@|cge+}PdapFbk>_u2gm zGvb4THo)WTJcdymG35MZB8H*s!Y4Lu$f?oFh93>+Y6gvDNouo(pz@KC0!}Ap zSn%MX$5qJqS+DSd&bDL{_VKuom-oZB)a+&cpu?y67n3|oUMPvy<1ZeKJ>`sR(-Tg; zDShbr^U^!6d~~|zt`n_FQ+##|zxP3k-FqrPTYGHhaw$K5)Ec=vzdn~DVW_&frrzP# z=fmz;IG9!@52TA8d2@Q1uKE{VpjX&Y;A%_)Z?ZC$ooe1V97SZLC?0t5YCcPU+Pv07 zUh6`4Q=hz#hwncAdU@oFE(e$BtGD?IU>3(mH+7rfUVDF6`sJV1%Pg;3930fI(3Z7) z)faIxoaB9V;rz)h1f+9w~e|)tt#QCY*-b#?<6%rmjv+kDCB+TI)q7T^=+C!M}4uN}oK{$K=%T zP?{M&dhplRT^*+P79Q0V0EL-J8~^ms@W3ml^2kAp+8_^cqNnxYwQ@ z)FC;vYcUAX_TDw9QEBZLdPrX$Q&B+@l2m~pgT))AA@j*QNGD#LWM&tBai+v-A^epxpesK4BGW6x{KD^9dX4y*XMZhSdB@4=L)V_4uK4;x z(~dpIs15bvkRBiM*{}O9sZDc{y&>p}9A|}3?%d<+_xekEi*K+mZ9i#e`ku#LlV13Q zYty->YV%q)wgivo`q0?-L9vT$EgU&MB1M_Hym+z@dh3PZudCnXLkBNlZPUj?9{hmt z4r%~=_9RVMg8T`#q~AjyyH9@x>FA}pd5)UbccqJ8J~x>7qou*2W)+|-m0#`Ks{+5$ zi>JXGtAOA+6d#!)!R7UpzgZa&(7qzbP;^}N9imGWnH-QgZi9xAU9R}zgRjc#>h#dH zJ$V)X_+Cw4vamH+>4u%&AWZu5&)$O@(-(ICxxjke>6HYts|Y-Kh_zYPXHKiJ-T3UjFbXkJSFLO&_^d7^%VfcQgQ!cez^3CnKb<D^XU{`qLW~E%5Z&3E!A`sd-Ib;yfkOYxIWD)pG0jBM;Y-f7i`*>`-ye`d^ zpN_BZ{prB68lViy9~}~tL0sX(f2;&3MBw!$ShZ@Vcy@{HTlF3826G_)aOV*B2k1{by-Ue-Ar z5q_Uc0541zANc3=%fF_;{=4`kU`zyTA~nAQh``U204=x1W*|eCyL-DOu**2XtTrdW z=yCnG;SH1E7Xt|i%9Aui*d`ZT1RQlx+H$^!*VTb0S-{K5$V6ZT@<8rR3bieP9)V9` z0*|0KSo4M3_Xnq~o*O0?)5A}>B|ZGKud6V8IAb>5zHf_73fJ6mQo8Z3)bs<{8TMh5Zph;m%pD-UmA4yuxu9ktv(U(uHTgxe5$mr+0 z^vd7mCpUr5*gjr6muKwzlG-UWYY#_^-zO6Qr8$ru`45BPmp`aKDe>$jHsly=3fQ>k zj~@EcmuQKfa-~e0Ok0 zUooDWUbKMUy6Ip#cJqO>ZSy{ZTQ=&}ZbqY)Whn+Rfa@#0*tByip_}`n1zSp)2wlka z;GqYs^QCO{eSa-Ow@&2Km&WnYt!2>;U4HGe)(<`GB5}We>8bimlqP{$&7}GWjI999 z(*DWjCH>8_qnlQ1j(eTcd(y97sQdCu2ZO~Ke*RjX3S^vn_IOHAaPjP3Kko_HlLO#Um&ALb|fD?V%g z9lv2`d5_WS>Y&@li@d{^>E-(HR6%X)2l-Hr3W5hM)No)VnU{nfDQx=i;B{fxcKJ2E zUc9RZ9cevR{<=)BzT&F&ko_q=_r^mS zgO44&B7HSXj|L>m`z$>_{qp6D!<9Er4`&HITW-du!VK!tY+%(p-Oy6znzEnCM#-2yq4n&?sMj7&Gb)KrOHg=xlel=60%cmXIL1SpHzO@{h4#&3O zq7BcwHQv>&W#D#X`*AovdhIAnH&1o9J{4|z2wDv!ePu^4mk8=ot`CaZZZlV)dD(Gr z<&1+s;vSko9)s4(FWSnGVU73cg-xF zU2~9qV8=lueo^=QpV6*A6E;`=B^|nOr6=mWpQ+)M`T*Fq(mJY%Z12;g#pET2hRZt! z!>JPB1hfS_%ljPUzE_YZ0h8wdN5_sT$a5faS;4WRv|kQ*!91f4|GX=I^+0J zKFz(un>VGE%TDuQi7zJG1%>D1^m_EE+Vo#Y?;Tvcu5C0uoPrz|CM71J7&t%AHq|V`c3D{)2EN9S{i2z*uxD^QKzQk4sy4>*+ z$g(Q~$?%|oI^fay5io}1Bgx37w#UT=|0*+Dhn?kcUo`(*!yN-Gw0!Sj)S< zY8m=9UE|2ql#7?1l~!&zE@^=*RgF)c}4<1#Qqcg-9M(8qn3AP+Q}yrNo;Z&gcc4NGTWhtXZ#YnCU-s8cYE~oNG}TjCdIbNBv=M3 zl|q{xeoPoAoVYu;$utDMk&#R%6TyQSc$C9*J9;52Fgxtp8eNzuW&a&sBM5~C_W5WE zX_i%?ohIll0Rzu0?@A{E??R-(%Vq|G*M(jEkO#k}>!1$b$m0m!TCnyxPPeN=-jTYp zaeQnP=Zlx0k(NGln!oIWuCDxp^X^WQ&%0jl)GOZcw>Y>_6V_`kdEe1}0f_8K_uB+O zWeKyi3R1&-&DEGHfiJENvog-SWsw^nXH^Pbs2kL&8%vmk%*>6D zZ*-Am1J{X3APe0xJIJ0)(L7ID-E;$z8VUrz(pRNvc zov-=NHj!8DGxU3*nBGkdG`)Q4%7R`^2U)FG<00z{{-{Fj`*84XK7F?6kaw+HZ7f-0-Jp7ZE5P+H~5vGCjk6yx8=ca4*rkf2m9O|4c`573lIf; zmj1N3UcGtc(r~zMpj&~m?AO(W<$k^N_a(jG9+X=FyA8;<4Qe!7GF5QoHUPiK&3~m| z`1D`Rr=(7M$L5g~%VX4tA$9n!+6n2hK&y$B<&PMXmcB%UH)2hA-s)EksYnG#O8B-<#&1dsUh|SG)au_#-B0-u7G?{QTg*3_o7GJleSKMDG8zH$C$A z)9{PW+K^^nxTsqjUdiRU%g=f2w*aE)UwHo80j~NaS}_(a;Pkd1{_?P2y;%wPZw1hm zR~wkjs^lQ3zfp%7i+m-yB`;#3$HAY3o==yh2tUUmwB!FB#w_GOO`1yuub@crb#t3^`SPD;*b%+6KRrtH&l}Ht0L@7EjI? zNGvGfPTNQqkkF@x_AWl#8s1102~4Hnv1O>DVRC>yki#tW2fSD6H| zo+;KijF#_A7^r2TI)#{0s=uMS?j_}0kszJ%Yf34ltyC4Kms9~oSv z*MnxBRsV%y>ut4z{+Gm5f+oDD0U^2Gw5L?0O zLS?#L##>R53WDMlO%ee6> zeyvk*8P(ld%TDZ0ew92m6u#`-#qv4R{a|~0Z^Ei4WIq-LuvU@bA#y% z>~9LdR6FRuC7_RK@6B$Ycj;_q_O%b3wCN^~mY}7S%aDW0M8!{~SkOSQ%eVoZLNr2W zLC(YVLb>vTps)ikj3&RLlw}4&@7}=GY_rUQxks-AIWisAmB36>P2)o=Mc@Xkd8Uw0 zS-obB;P~hsBT8c!wH+!1KR?o`gM1Zys2^M{-f?W&c)srS&)VTV!>)e>KDKtqH~Te9 zgIff@Z}8hocaAC1QD=X{CxADnOIKc!p87$x_48*2lP4`}m&aovZUrRC9i2gL1bRma zW;uKx0DJf0K_7O;)5&SUunRvSDFz5U)&82vq*5$sMhtZDqJvKnp%eU^zvbu|Mn$|3 zArG0k3FCmqbp4_ivQ?moR*{=W^1^2lO?c&UM~zk zYr)zdfv*>J)*Ji;IW?O)W^bC{6K*W`sSmdh26O$G3~Xas-_Ki0FCJVn|LHp0`x^g- zPXJW#E$O2N^fv`QuE6>My$iL`K0O^Zr+w7Z2J)qWaa|5c>s3IQ0Ye94>`Ul7VXDT1 zCZVT;abdO@A_^ZMrY;3H^K+%(#@WXBHD1&+VxWU}b(+k*Ao$Ct~q@o!Ri zIsjDIkgNyUqJv+<4qkk8Y$J&Ke3~rlhhF%B4tc?Ap6pCF!@w<{F{dc<81V=@e3Cyu znT~PeeGgp;ftwSCm3Z&SDU_Ed(oj#d()*Z-dd4&@omIOy|cnCvQ(ZMsD z%rAIHA0Kg8UilQf^}?{_n+d#`M}BccFhd)zKreXkDj0SKvo3XF>AyJmwZU&5`tOn5 z{Rx%(11r66;ul{%Gnn}O;b2k0=3fztuLb+pgZL6qd=-c<3`55ed~PFxSL56wh;O$U zdLux%)6S2t1v#Hp2mChlClibyhN+-h(4a9yt8eXDJ(Co;LDyTIzlJV7WncQKeT7Yi zGlw{RBI8`5tbc#Sxrfx`Wk9xy9_sPSJ7KXS#32T$Fo9}PX# z-W1GjWuU@AGnq|u`(*(aypU&>=^37dF3(r|xI&7VukURKSi6D2Vr%@c7*UXJ<{8kb zs1(G?Wv9?}BJ)EJGVm^}WW`6NV`$J_-QceW_UUAvUD@QjT*>}CH5B<>XLdwtMzWIqarR(

lhMo*Oc1ce|)Kp4pH6i6{YrHsRnJc<3BJ}eC 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 V5(shxW2OKA002ovPDHLkV1mJH?->99 diff --git a/data/http/index.html b/data/index.html similarity index 100% rename from data/http/index.html rename to data/index.html diff --git a/data/http/input.js b/data/input.js similarity index 100% rename from data/http/input.js rename to data/input.js diff --git a/data/http/style.css b/data/style.css similarity index 100% rename from data/http/style.css rename to data/style.css diff --git a/data/test.txt b/data/test.txt deleted file mode 100644 index ec82874..0000000 --- a/data/test.txt +++ /dev/null @@ -1,75 +0,0 @@ - 0xEA, 0x0C, 0xD2, 0x04, 0xE1, 0x9D, 0xC4, 0x18, 0xF6, 0xC1, - 0x40, 0xA7, 0x08, 0x35, 0x3D, 0x67, 0x1A, 0xB5, 0x23, 0x81, - 0x4C, 0x96, 0x42, 0xFD, 0x43, 0xDA, 0x99, 0x71, 0x68, 0xF1, - 0xEA, 0x1E, 0xB9, 0xE4, 0xD0, 0xBB, 0x05, 0xAC, 0xF7, 0x5E, - 0x38, 0x0B, 0x31, 0x66, 0x0D, 0x8A, 0x1B, 0x6F, 0x29, 0x2B, - 0xEC, 0x8C, 0xED, 0xAD, 0x03, 0xE2, 0x44, 0xBA, 0xB3, 0xA1, - 0xB8, 0x85, 0xFC, 0xF6, 0xFB, 0xD1, 0x12, 0x63, 0x7E, 0x86, - 0x5A, 0x22, 0x6F, 0xEF, 0x55, 0xD4, 0x27, 0x3F, 0xCC, 0xE9, - 0x9A, 0x60, 0xC5, 0xD0, 0xF8, 0x29, 0x0B, 0x06, 0x2C, 0x9B, - 0xDC, 0x95, 0xDD, 0xA6, 0x22, 0x65, 0x3F, 0xCC, 0x7E, 0x6C, - 0xD3, 0x77, 0x26, 0x23, 0x9C, 0x5C, 0xD3, 0x8E, 0xB2, 0xBD, - 0xD1, 0xC8, 0xEA, 0xC1, 0x87, 0x2A, 0x67, 0x5B, 0xA4, 0x66, - 0x32, 0x60, 0x79, 0x6D, 0xE4, 0xCC, 0x6B, 0x4D, 0xA4, 0x26, - 0x7E, 0x06, 0x12, 0x6E, 0x3B, 0xB5, 0x55, 0x05, 0x42, 0x37, - 0x75, 0x2C, 0x89, 0xB7, 0x94, 0xA7, 0x28, 0x97, 0x4A, 0x2E, - 0x0B, 0x90, 0xFD, 0x66, 0xE8, 0xD4, 0x7C, 0xC6, 0x09, 0xFA, - 0x1D, 0xED, 0x54, 0x43, 0x27, 0x65, 0x49, 0xF5, 0x17, 0x03, - 0x1F, 0x4E, 0x6F, 0x06, 0xA7, 0x67, 0x90, 0x9D, 0xC5, 0xFA, - 0x61, 0xF4, 0x3C, 0x8B, 0x27, 0xB6, 0xDF, 0x92, 0x4E, 0x15, - 0xB2, 0xDF, 0xAE, 0xA6, 0xF3, 0x01, 0xB1, 0x56, 0x32, 0x99, - 0xB0, 0xEA, 0x35, 0x0B, 0xA6, 0x89, 0x62, 0x05, 0xA4, 0xC0, - 0x23, 0x0C, 0x5B, 0x43, 0x66, 0xB3, 0x03, 0x61, 0x9A, 0x2F, - 0x98, 0x02, 0x84, 0x3B, 0x0A, 0xBB, 0xFB, 0x03, 0x0E, 0x45, - 0x4D, 0x1C, 0xB7, 0xAF, 0x23, 0xE0, 0x15, 0xEA, 0xE5, 0xC1, - 0x92, 0x2D, 0x0E, 0x19, 0x7C, 0xFA, 0xFA, 0x5E, 0xA7, 0xBB, - 0xD8, 0x8F, 0x87, 0x4E, 0x8A, 0x99, 0x1C, 0x6A, 0x5D, 0x49, - 0xA8, 0xFE, 0x38, 0x84, 0x85, 0x44, 0x01, 0xCB, 0x78, 0xF9, - 0x6D, 0xA3, 0xD2, 0x95, 0x4A, 0xB5, 0xF7, 0xF0, 0xF9, 0x10, - 0xA6, 0x4B, 0xCF, 0xBE, 0x4A, 0x46, 0x21, 0x57, 0x40, 0xCB, - 0x91, 0xDD, 0x7A, 0xA3, 0xA9, 0x48, 0x40, 0x27, 0x98, 0x65, - 0xFE, 0xDC, 0x8A, 0x6B, 0xF3, 0xBB, 0x04, 0x37, 0x65, 0x09, - 0xFB, 0x09, 0x95, 0x62, 0xE6, 0x5B, 0x53, 0x82, 0x82, 0x70, - 0x3D, 0x23, 0x6C, 0xAD, 0x23, 0x84, 0xE8, 0x9F, 0xF2, 0x00, - 0xE0, 0x68, 0x34, 0xA8, 0xC5, 0x0C, 0xC0, 0x4A, 0xB6, 0x4A, - 0xD8, 0xA6, 0xB6, 0x4A, 0xF8, 0xF8, 0x75, 0x60, 0xD2, 0xE4, - 0x0B, 0xF9, 0x0C, 0xA6, 0xA1, 0x9C, 0xF5, 0x2E, 0x17, 0x2C, - 0x29, 0x8A, 0x21, 0x24, 0xEA, 0xDB, 0x95, 0xE7, 0x75, 0x25, - 0xAF, 0x3B, 0xC2, 0x16, 0x0E, 0x69, 0x36, 0x8F, 0x80, 0xB4, - 0x1A, 0x01, 0xEF, 0x0B, 0x1B, 0x09, 0x74, 0x86, 0x3C, 0xFB, - 0x0D, 0xF5, 0x1A, 0x01, 0x56, 0xE4, 0xA0, 0x32, 0xB0, 0x40, - 0x36, 0xAB, 0x40, 0x80, 0x4C, 0x39, 0x05, 0x1D, 0x43, 0xC7, - 0x76, 0x82, 0x51, 0x80, 0x1E, 0x13, 0xF9, 0x76, 0x44, 0xD9, - 0xEA, 0xB9, 0x14, 0x98, 0x72, 0x2E, 0x46, 0xC6, 0x63, 0x1D, - 0xB9, 0xF6, 0xD5, 0xA6, 0x75, 0xBB, 0xB2, 0x0B, 0x34, 0xA8, - 0x8D, 0x6E, 0x1F, 0xFF, 0xCE, 0xDA, 0x20, 0xD6, 0xEE, 0xB8, - 0x7B, 0xBB, 0x35, 0x35, 0xFA, 0x65, 0xBA, 0xE3, 0x62, 0xAB, - 0xC2, 0x64, 0x77, 0x10, 0x9D, 0xC0, 0x4F, 0xCD, 0xCF, 0xFB, - 0x97, 0xF4, 0x23, 0x47, 0xD7, 0x2E, 0xC9, 0xF9, 0x5E, 0x3C, - 0x68, 0x4E, 0x92, 0x5F, 0x06, 0x40, 0x95, 0xA1, 0x30, 0xFA, - 0xF1, 0xFC, 0xDC, 0xFB, 0x45, 0xF7, 0x24, 0x8D, 0xEF, 0x4D, - 0x49, 0xD0, 0xFE, 0x77, 0x34, 0x6D, 0x8D, 0xDB, 0x59, 0x11, - 0x86, 0xE2, 0x37, 0xD3, 0x2F, 0xD0, 0xB7, 0x08, 0x1E, 0x95, - 0xCB, 0x51, 0xD5, 0x02, 0x4C, 0x28, 0xF8, 0xAA, 0x7B, 0x7D, - 0x61, 0xFA, 0xCA, 0xE3, 0x66, 0x04, 0x9D, 0x95, 0x78, 0x7B, - 0x33, 0xD2, 0xEF, 0x77, 0xDB, 0xB3, 0xD7, 0xE5, 0x48, 0xDF, - 0x9A, 0x6E, 0x99, 0x21, 0x59, 0xFE, 0x99, 0xFC, 0x12, 0x8F, - 0x44, 0xC2, 0xB7, 0xA6, 0x46, 0xE3, 0x8A, 0x6B, 0x84, 0x23, - 0x08, 0x6C, 0x2F, 0xAB, 0x77, 0x78, 0x4D, 0x02, 0x6B, 0xCD, - 0x06, 0xDD, 0x24, 0xC1, 0x24, 0xDB, 0x36, 0xF3, 0x48, 0x5D, - 0xF4, 0x57, 0x73, 0xDD, 0x7F, 0xAA, 0xA2, 0x66, 0xE5, 0x37, - 0xEB, 0xFD, 0x1C, 0x7C, 0x40, 0x89, 0x03, 0x19, 0xDC, 0x61, - 0x9C, 0xC2, 0xD7, 0xB5, 0x83, 0xFA, 0x3A, 0x64, 0x23, 0xDE, 0xB2, 0x6A, - 0x90, 0xDF, 0x43, 0x60, 0xAC, 0x88, 0x3D, 0xBA, 0x35, 0x1D, - 0x34, 0x66, 0x38, 0x97, 0x01, 0xB9, 0x83, 0x9F, 0x3D, 0x74, - 0x12, 0x8C, 0x61, 0x2B, 0x91, 0x4A, 0x9B, 0x4B, 0x95, 0x40, - 0xC7, 0x11, 0x4F, 0x59, 0xF3, 0xCE, 0x56, 0x3B, 0x96, 0x42, - 0xC9, 0x4E, 0xE1, 0x77, 0xB0, 0x81, 0xB3, 0x2C, 0x3C, 0xB2, - 0x05, 0x1C, 0x3A, 0x66, 0xF5, 0xE0, 0x4F, 0xEE, 0x5B, 0xC8, - 0xD6, 0x52, 0x97, 0x9F, 0x1B, 0x80, 0x44, 0x53, 0xD7, 0x5D, - 0x8A, 0xB9, 0xA2, 0xDD, 0x99, 0xB4, 0xFA, 0xFB, 0xB9, 0xAA, - 0xA0, 0xA8, 0x11, 0xFA, 0xCF, 0xF5, 0xB6, 0xDF, 0xB4, 0xD7, - 0x56, 0x11, 0xD1, 0xE1, 0xF0, 0x45, 0xA0, 0x6C, 0xA1, 0xAE, - 0x92, 0xD7, 0x6F, 0xD0, 0x18, 0xF7, 0x73, 0x07, 0x15, 0xDC, - 0xEE, 0x37, 0xD8, 0xB1, 0x72, 0x2C, 0xAC, 0x57, 0x99, 0x57, - 0xD5, 0x59, 0xC7, 0xE8, 0x \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6c956ed..e953052 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,7 +27,6 @@ extern "C" { #include "style.css.gz.h" #include "favicon.png.gz.h" // images are possible -// maybe check out FS <- SPIFFS const char* ssid = STASSID; const char* password = STAPSK; @@ -38,33 +37,13 @@ int timer_arg; void setup_webserver(); void setup_ota(); void setup_pwm_pca9685(); -void handleRootGz(); -void handleCssGz(); void handleNotFound(); const int led = 13; ESP8266WebServer server(80); PCA9685 pwmController; -void handleRootGz() { - const char* dataType = "text/html"; - server.sendHeader(F("Content-Encoding"), F("gzip")); - server.send(200, dataType, (const char*)index_html_gz, index_html_gz_len); -} - -void handleCssGz() { - const char* dataType = "text/css"; - server.sendHeader(F("Content-Encoding"), F("gzip")); - server.send(200, dataType, (const char*)style_css_gz, style_css_gz_len); -} -void handleFaviconGz() { - const char* dataType = "image/png"; - server.sendHeader(F("Content-Encoding"), F("gzip")); - server.send(200, dataType, (const char*)favicon_png_gz, favicon_png_gz_len); -} - void handleNotFound() { - digitalWrite(led, 1); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); @@ -77,27 +56,23 @@ void handleNotFound() { for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } - server.send(404, "text/plain", message); - digitalWrite(led, 0); } void setup_webserver() { - // server.on("/", handleRootGz); - // server.on("/style.css", handleCssGz); - // server.on("/favicon.png", handleFaviconGz); - // void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); - - server.serveStatic("/static", LittleFS, "/tt.html.gzip"); - server.serveStatic("/http", LittleFS, "/http/"); - server.serveStatic("/http", LittleFS, "/http/"); - server.serveStatic("/http", LittleFS, "/http/"); + // //experimental, see doku.md + // server.serveStatic("/compressed", LittleFS, "/compressed.html.gzip"); + server.serveStatic("", LittleFS, "/index.html"); + server.serveStatic("/", LittleFS, "/index.html"); + server.serveStatic("/#", LittleFS, "/index.html"); + server.serveStatic("/style.css", LittleFS, "/style.css"); + server.serveStatic("/index.js", LittleFS, "/index.js"); + server.serveStatic("/favicon.png", LittleFS, "/favicon.png"); server.onNotFound(handleNotFound); server.begin(); - Serial.println("HTTP server started"); } void setup_ota() { @@ -199,8 +174,8 @@ void setup() { ESP.restart(); } - - + pinMode(led, OUTPUT); + digitalWrite(led, 0); Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); @@ -216,17 +191,11 @@ void setup() { setup_ota(); - pinMode(led, OUTPUT); - digitalWrite(led, 0); - Serial.println(""); - - // Wait for connection - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } setup_webserver(); + Serial.println("HTTP server started !"); + setup_pwm_pca9685(); + Serial.println("PCA9685 connected !"); } uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval, uint8_t factor){ diff --git a/templ_platformio_ini b/templ_platformio_ini index a333f62..4d0f7d0 100644 --- a/templ_platformio_ini +++ b/templ_platformio_ini @@ -13,7 +13,7 @@ platform = espressif8266 board = nodemcuv2 framework = arduino monitor_speed = 115200 -extra_scripts = pre:extra_script.py +extra_scripts = pre:create_gz_files.py [env:serial] upload_protocol = esptool From 006404fccfd84cd324e3c8b88a6cad7e1981f01e Mon Sep 17 00:00:00 2001 From: Simon Schmidt Date: Wed, 23 Jun 2021 15:22:38 +0200 Subject: [PATCH 07/17] ugly hack --- .vscode/settings.json | 37 +++++++++++++++++++++- include/filesys.h | 1 + include/httpserver.h | 49 +++++++++++++++++------------ src/filesys.cpp | 71 +++++++++++++++++++++---------------------- src/httpserver.cpp | 20 ++++++++++++ src/main.cpp | 46 +++++++++------------------- 6 files changed, 135 insertions(+), 89 deletions(-) create mode 100644 src/httpserver.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 34629f0..4eaa233 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,41 @@ "memory": "cpp", "ranges": "cpp", "initializer_list": "cpp", - "utility": "cpp" + "utility": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "map": "cpp", + "set": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "iosfwd": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/include/filesys.h b/include/filesys.h index 454079b..49b03ea 100644 --- a/include/filesys.h +++ b/include/filesys.h @@ -12,4 +12,5 @@ void writeFile(const char * path, const char * message); void appendFile(const char * path, const char * message); void renameFile(const char * path1, const char * path2); void deleteFile(const char * path); + #endif // __FILESYS_H \ No newline at end of file diff --git a/include/httpserver.h b/include/httpserver.h index 2d5b305..933b9f2 100644 --- a/include/httpserver.h +++ b/include/httpserver.h @@ -1,37 +1,48 @@ #ifndef __HTTPSERVER_H #define __HTTPSERVER_H +#include "filesys.h" #include + class HTTPServer { private: - int port; - ESP8266WebServer* server; + bool configured = false; + const int port; + const char* rootDir; + std::function callbackFn; + + bool addRootFileHandler(); + bool formatFS() { + return format_fs(); + } + void listRoot() { + ls(rootDir); + } public: - HTTPServer(int port) { - server = new ESP8266WebServer; + ESP8266WebServer server; - // server->on("/", handleRootGz); - // server->on("/style.css", handleCssGz); - // server->on("/favicon.png", handleFaviconGz); - // server->onNotFound(handleNotFound); - - server->begin(port); - } - ~HTTPServer() { - server->stop(); - delete server; + HTTPServer(const int _port, const char* _rootDir, std::function fn) : + port(_port), rootDir(_rootDir), callbackFn(fn) + { } + ~HTTPServer() + { + server.stop(); } - void initialize() { - server->begin(port); + bool start() { + if(!mount_fs()) + return false; + Serial.printf("LittleFS mounted => Starting Webserver on Port %d\n\r", this->port); + server.begin(port); + return true; } - - void handleClient() { - server->handleClient(); + void handleClient() { + server.handleClient(); } }; + #endif // __HTTPSERVER_H \ No newline at end of file diff --git a/src/filesys.cpp b/src/filesys.cpp index 8b84428..0e3f42b 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -1,14 +1,42 @@ #include "filesys.h" -// listDir("/"); -// deleteFile("/hello.txt"); -// writeFile("/hello.txt", "Hello "); -// appendFile("/hello.txt", "World!\n\r"); -// readFile("/hello.txt"); -// listDir("/"); +// listDir("/"); +// deleteFile("/hello.txt"); +// writeFile("/hello.txt", "Hello "); +// appendFile("/hello.txt", "World!\n\r"); +// readFile("/hello.txt"); +// listDir("/"); FSInfo fsinfo; +bool mount_fs() { + if(!LittleFS.begin()) { + Serial.println("[ERROR] LittleFS.info(), reset ..."); + return false; + } + + if(!LittleFS.info(fsinfo)) { + Serial.println("[ERROR] LittleFS.info(), reset ..."); + return false; + } + + printf("Filesystem opened:\n\r"); + printf("\ttotalBytes:\t%d\n\r", fsinfo.totalBytes); + printf("\tusedBytes:\t%d\n\r", fsinfo.usedBytes); + printf("\tblockSize:\t%d\n\r", fsinfo.blockSize); + printf("\tpageSize:\t%d\n\r", fsinfo.pageSize); + printf("\tmaxOpenFiles:\t%d\n\r", fsinfo.maxOpenFiles); + printf("\tmaxPathLength:\t%d\n\r", fsinfo.maxPathLength); + printf("\n\r"); + + return true; +} + +bool format_fs() { + printf("Formatting FS ! \n\r"); + return LittleFS.format(); +} + void ls(const char * dirname) { Serial.printf("ls -l %s\n\r", dirname); Dir root = LittleFS.openDir(dirname); @@ -30,7 +58,6 @@ void ls(const char * dirname) { Serial.println(); } - void readFile(const char * path) { Serial.printf("Reading file: %s\n\r", path); @@ -99,35 +126,5 @@ void deleteFile(const char * path) { } -bool mount_fs() { - if(!LittleFS.begin()) { - Serial.println("[ERROR] LittleFS.info(), reset ..."); - return false; - } - - if(!LittleFS.info(fsinfo)) { - Serial.println("[ERROR] LittleFS.info(), reset ..."); - return false; - } - - printf("Filesystem opened:\n\r"); - printf("\ttotalBytes:\t%d\n\r", fsinfo.totalBytes); - printf("\tusedBytes:\t%d\n\r", fsinfo.usedBytes); - printf("\tblockSize:\t%d\n\r", fsinfo.blockSize); - printf("\tpageSize:\t%d\n\r", fsinfo.pageSize); - printf("\tmaxOpenFiles:\t%d\n\r", fsinfo.maxOpenFiles); - printf("\tmaxPathLength:\t%d\n\r", fsinfo.maxPathLength); - printf("\n\r"); - - return true; -} - -bool format_fs() { - printf("Formatting FS ! \n\r"); - return LittleFS.format(); -} - - - \ No newline at end of file diff --git a/src/httpserver.cpp b/src/httpserver.cpp new file mode 100644 index 0000000..b1f6f33 --- /dev/null +++ b/src/httpserver.cpp @@ -0,0 +1,20 @@ +#include "httpserver.h" + + +bool HTTPServer::addRootFileHandler() { + + // //experimental, see doku.md + // server.serveStatic("/compressed", LittleFS, "/compressed.html.gzip"); + + server.serveStatic("", LittleFS, "/index.html"); + server.serveStatic("/", LittleFS, "/index.html"); + server.serveStatic("/#", LittleFS, "/index.html"); + server.serveStatic("/style.css", LittleFS, "/style.css"); + server.serveStatic("/input.js", LittleFS, "/input.js"); + server.serveStatic("/favicon.png", LittleFS, "/favicon.png"); + server.onNotFound(callbackFn); + + server.begin(); + + configured = true; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e953052..1166645 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,9 +19,7 @@ extern "C" { #include #include -#include "filesys.h" -#include -#include +#include "httpserver.h" #include "index.html.gz.h" #include "style.css.gz.h" @@ -40,40 +38,29 @@ void setup_pwm_pca9685(); void handleNotFound(); const int led = 13; -ESP8266WebServer server(80); -PCA9685 pwmController; +HTTPServer httpServer(80, "/", handleNotFound); void handleNotFound() { String message = "File Not Found\n\n"; message += "URI: "; - message += server.uri(); + message += httpServer.server.uri(); message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += (httpServer.server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; - message += server.args(); + message += httpServer.server.args(); message += "\n"; - for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + for (uint8_t i = 0; i < httpServer.server.args(); i++) { + message += " " + httpServer.server.argName(i) + ": " + httpServer.server.arg(i) + "\n"; } - server.send(404, "text/plain", message); + + httpServer.server.send(404, "text/plain", message); } +PCA9685 pwmController; -void setup_webserver() { - // //experimental, see doku.md - // server.serveStatic("/compressed", LittleFS, "/compressed.html.gzip"); - server.serveStatic("", LittleFS, "/index.html"); - server.serveStatic("/", LittleFS, "/index.html"); - server.serveStatic("/#", LittleFS, "/index.html"); - server.serveStatic("/style.css", LittleFS, "/style.css"); - server.serveStatic("/index.js", LittleFS, "/index.js"); - server.serveStatic("/favicon.png", LittleFS, "/favicon.png"); - server.onNotFound(handleNotFound); - server.begin(); -} void setup_ota() { ArduinoOTA.setPort(8266); @@ -153,11 +140,6 @@ void setup() { Serial.println(F("Booting ....")); - mount_fs(); - //format_fs(); - ls("/"); - ls("http/"); - // readFile("/test.txt"); pinMode(NODEMCU_LED, OUTPUT); pinMode(ESP12_LED, OUTPUT); @@ -183,7 +165,7 @@ void setup() { Serial.println(WiFi.localIP()); os_timer_setfn(&timer1, timer_callback, &timer_arg); - os_timer_arm(&timer1, 1000, true); + os_timer_arm(&timer1, 1, true); Serial.println("Ready"); Serial.print("IP address: "); @@ -191,7 +173,7 @@ void setup() { setup_ota(); - setup_webserver(); + httpServer.start(); Serial.println("HTTP server started !"); setup_pwm_pca9685(); @@ -295,11 +277,11 @@ void loop() { direction = 0; } TIMEIF_US(ArduinoOTA.handle(), 1000, "OTA"); - TIMEIF_US(server.handleClient(), 1000, "HTTP"); + TIMEIF_US(httpServer.handleClient(), 1000, "HTTP"); if(flag) { flag = 0; ledsequence(direction, onoff, 4); - Serial.printf("[%lu] interrupt\n\r", millis()); + //Serial.printf("[%lu] interrupt\n\r", millis()); } } \ No newline at end of file From 8d8ffe4173e240318ef584cd78f1840920ae4f05 Mon Sep 17 00:00:00 2001 From: Pupsmuckel Date: Wed, 23 Jun 2021 15:56:27 +0200 Subject: [PATCH 08/17] =?UTF-8?q?=C3=A4nderung=20an=20der=20website?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/http/index.html | 41 +++++++++++++-------------- include/http/light.png | Bin 0 -> 12432 bytes include/http/style.css | 61 +++++++++++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 include/http/light.png diff --git a/include/http/index.html b/include/http/index.html index 6dbf624..5b851ad 100644 --- a/include/http/index.html +++ b/include/http/index.html @@ -3,37 +3,34 @@ ESP8266 Treppenlicht - + - -

- ESP8266 Treppenlicht Controller +
+ Treppenlicht
-
-
-
-
- toggle all - -