From 13ee5e19e834fbfebd8652d5ee08e73d3b06eefd Mon Sep 17 00:00:00 2001 From: luc lebosse Date: Mon, 13 Nov 2017 16:17:07 +0100 Subject: [PATCH] Merge Development version to master --- .travis.yml | 31 +- README.md | 294 +- UI/mousediv.html | 150 - UI/{ => repetier}/testui.htm | 2 +- docs/Commands.txt | 39 +- docs/EEPROM_OUTPUT_SAMPLE.txt | 122 - docs/keywords.txt | 150 - embedded/build.bat | 1 + embedded/gulpfile.js | 125 + embedded/install.bat | 15 + embedded/package.json | 30 + embedded/tool.html.gz | Bin 0 -> 4776 bytes .../css.inc => embedded/www/css/style.css | 87 + .../settings.tpl => embedded/www/js/script.js | 182 +- embedded/www/tool.html | 100 + esp3d/bridge.cpp | 138 +- esp3d/command.cpp | 1314 ++++-- esp3d/command.h | 4 +- esp3d/config.cpp | 1627 +++++-- esp3d/config.h | 270 +- esp3d/data/404.htm | 18 + esp3d/data/404.tpl | 30 - esp3d/data/config_ap.tpl | 65 - esp3d/data/config_sta.tpl | 66 - esp3d/data/css2.inc | 27 - esp3d/data/footer.inc | 6 - esp3d/data/header.inc | 30 - esp3d/data/home.tpl | 55 - esp3d/data/index.html.gz | Bin 0 -> 79433 bytes esp3d/data/login.tpl | 21 - esp3d/data/macrocfg.json | 74 + esp3d/data/password.tpl | 111 - esp3d/data/printer.tpl | 870 ---- esp3d/data/restart.tpl | 27 - esp3d/data/system.tpl | 108 - esp3d/data/tags.json | 4 - esp3d/esp3d.ino | 172 +- esp3d/esp3d.ino.nodemcu.bin | Bin 372592 -> 0 bytes esp3d/nofile.h | 326 ++ esp3d/storestrings.cpp | 2 +- esp3d/storestrings.h | 2 +- esp3d/webinterface.cpp | 4125 ++++------------- esp3d/webinterface.h | 54 +- esp3d/{wifi.cpp => wificonf.cpp} | 287 +- esp3d/{wifi.h => wificonf.h} | 18 +- images/docs/embedded.png | Bin 0 -> 31622 bytes libraries/DNSServer/.gitignore | 32 + libraries/DNSServer/.travis.yml | 83 + libraries/DNSServer/README.md | 7 + .../examples/CaptivePortal/CaptivePortal.ino | 41 + .../CaptivePortalAdvanced.ino | 157 + .../CaptivePortalAdvanced/credentials.ino | 47 + .../CaptivePortalAdvanced/handleHttp.ino | 137 + .../examples/CaptivePortalAdvanced/tools.ino | 21 + .../examples/DNSServer/DNSServer.ino | 48 + libraries/DNSServer/library.properties | 9 + libraries/DNSServer/src/DNSServer.cpp | 171 + libraries/DNSServer/src/DNSServer.h | 71 + libraries/WebServer/.gitignore | 32 + libraries/WebServer/.travis.yml | 99 + libraries/WebServer/LICENSE | 504 ++ libraries/WebServer/README.md | 9 + .../AdvancedWebServer/AdvancedWebServer.ino | 160 + .../examples/FSBrowser/FSBrowser.ino | 345 ++ .../examples/FSBrowser/data/edit.htm.gz | Bin 0 -> 4116 bytes .../examples/FSBrowser/data/favicon.ico | Bin 0 -> 1150 bytes .../examples/FSBrowser/data/graphs.js.gz | Bin 0 -> 1971 bytes .../examples/FSBrowser/data/index.htm | 97 + .../examples/HelloServer/HelloServer.ino | 91 + .../examples/HttpBasicAuth/HttpBasicAuth.ino | 47 + .../examples/SDWebServer/SDWebServer.ino | 290 ++ .../SDWebServer/SdRoot/edit/index.htm | 674 +++ .../examples/SDWebServer/SdRoot/index.htm | 22 + .../examples/SDWebServer/SdRoot/pins.png | Bin 0 -> 177869 bytes .../SimpleAuthentification.ino | 137 + .../examples/WebUpdate/WebUpdate.ino | 78 + libraries/WebServer/keywords.txt | 36 + libraries/WebServer/library.properties | 9 + libraries/WebServer/src/ESP8266WebServer.h | 29 + libraries/WebServer/src/Parsing.cpp | 610 +++ libraries/WebServer/src/WebServer.cpp | 530 +++ libraries/WebServer/src/WebServer.h | 236 + .../WebServer/src/detail/RequestHandler.h | 19 + .../src/detail/RequestHandlersImpl.h | 191 + tools/server.py | 105 - tools/tags.json | 4 - 86 files changed, 10000 insertions(+), 6357 deletions(-) delete mode 100644 UI/mousediv.html rename UI/{ => repetier}/testui.htm (99%) delete mode 100644 docs/EEPROM_OUTPUT_SAMPLE.txt delete mode 100644 docs/keywords.txt create mode 100644 embedded/build.bat create mode 100644 embedded/gulpfile.js create mode 100644 embedded/install.bat create mode 100644 embedded/package.json create mode 100644 embedded/tool.html.gz rename esp3d/data/css.inc => embedded/www/css/style.css (59%) rename esp3d/data/settings.tpl => embedded/www/js/script.js (60%) create mode 100644 embedded/www/tool.html create mode 100644 esp3d/data/404.htm delete mode 100644 esp3d/data/404.tpl delete mode 100644 esp3d/data/config_ap.tpl delete mode 100644 esp3d/data/config_sta.tpl delete mode 100644 esp3d/data/css2.inc delete mode 100644 esp3d/data/footer.inc delete mode 100644 esp3d/data/header.inc delete mode 100644 esp3d/data/home.tpl create mode 100644 esp3d/data/index.html.gz delete mode 100644 esp3d/data/login.tpl create mode 100644 esp3d/data/macrocfg.json delete mode 100644 esp3d/data/password.tpl delete mode 100644 esp3d/data/printer.tpl delete mode 100644 esp3d/data/restart.tpl delete mode 100644 esp3d/data/system.tpl delete mode 100644 esp3d/data/tags.json delete mode 100644 esp3d/esp3d.ino.nodemcu.bin create mode 100644 esp3d/nofile.h rename esp3d/{wifi.cpp => wificonf.cpp} (55%) rename esp3d/{wifi.h => wificonf.h} (83%) create mode 100644 images/docs/embedded.png create mode 100644 libraries/DNSServer/.gitignore create mode 100644 libraries/DNSServer/.travis.yml create mode 100644 libraries/DNSServer/README.md create mode 100644 libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino create mode 100644 libraries/DNSServer/examples/CaptivePortalAdvanced/CaptivePortalAdvanced.ino create mode 100644 libraries/DNSServer/examples/CaptivePortalAdvanced/credentials.ino create mode 100644 libraries/DNSServer/examples/CaptivePortalAdvanced/handleHttp.ino create mode 100644 libraries/DNSServer/examples/CaptivePortalAdvanced/tools.ino create mode 100644 libraries/DNSServer/examples/DNSServer/DNSServer.ino create mode 100644 libraries/DNSServer/library.properties create mode 100644 libraries/DNSServer/src/DNSServer.cpp create mode 100644 libraries/DNSServer/src/DNSServer.h create mode 100644 libraries/WebServer/.gitignore create mode 100644 libraries/WebServer/.travis.yml create mode 100644 libraries/WebServer/LICENSE create mode 100644 libraries/WebServer/README.md create mode 100644 libraries/WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino create mode 100644 libraries/WebServer/examples/FSBrowser/FSBrowser.ino create mode 100644 libraries/WebServer/examples/FSBrowser/data/edit.htm.gz create mode 100644 libraries/WebServer/examples/FSBrowser/data/favicon.ico create mode 100644 libraries/WebServer/examples/FSBrowser/data/graphs.js.gz create mode 100644 libraries/WebServer/examples/FSBrowser/data/index.htm create mode 100644 libraries/WebServer/examples/HelloServer/HelloServer.ino create mode 100644 libraries/WebServer/examples/HttpBasicAuth/HttpBasicAuth.ino create mode 100644 libraries/WebServer/examples/SDWebServer/SDWebServer.ino create mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/edit/index.htm create mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/index.htm create mode 100644 libraries/WebServer/examples/SDWebServer/SdRoot/pins.png create mode 100644 libraries/WebServer/examples/SimpleAuthentification/SimpleAuthentification.ino create mode 100644 libraries/WebServer/examples/WebUpdate/WebUpdate.ino create mode 100644 libraries/WebServer/keywords.txt create mode 100644 libraries/WebServer/library.properties create mode 100644 libraries/WebServer/src/ESP8266WebServer.h create mode 100644 libraries/WebServer/src/Parsing.cpp create mode 100644 libraries/WebServer/src/WebServer.cpp create mode 100644 libraries/WebServer/src/WebServer.h create mode 100644 libraries/WebServer/src/detail/RequestHandler.h create mode 100644 libraries/WebServer/src/detail/RequestHandlersImpl.h delete mode 100644 tools/server.py delete mode 100644 tools/tags.json diff --git a/.travis.yml b/.travis.yml index 05bda5a3..002c1bc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ before_install: before_script: - "export DISPLAY=:99.0" - sleep 3 # give xvfb some time to start - - wget http://downloads.arduino.cc/arduino-1.8.0-linux64.tar.xz - - tar xf arduino-1.8.0-linux64.tar.xz - - mv arduino-1.8.0 $HOME/arduino_ide + - wget http://downloads.arduino.cc/arduino-1.8.4-linux64.tar.xz + - tar xf arduino-1.8.4-linux64.tar.xz + - mv arduino-1.8.4 $HOME/arduino_ide - cd $HOME/arduino_ide/hardware - mkdir esp8266com - cd esp8266com @@ -21,13 +21,22 @@ before_script: - cd esp8266/tools - python get.py - cd .. - - touch pt.txt - - echo 'build.flash_ld=eagle.flash.4m.ld' >> pt.txt - - echo 'build.flash_freq=40' >> pt.txt - - echo 'build.flash_size=4M' >> pt.txt - - cat ./platform.txt >> pt.txt - - rm -fr platform.txt - - mv pt.txt platform.txt + - echo 'build.flash_ld=eagle.flash.4m.ld' >> platform.txt + - echo 'build.flash_freq=40' >> platform.txt + - echo 'build.flash_size=4M' >> platform.txt + - echo 'build.flash_mode=dio' >> platform.txt + - echo 'build.f_cpu=160000000L' >> platform.txt + - sed -i "s/generic.build.f_cpu=80000000L/generic.build.f_cpu=160000000L/g" ./boards.txt + - cd $HOME/arduino_ide/hardware + - mkdir esp32 + - cd esp32 + - git clone https://github.com/espressif/arduino-esp32.git esp32 + - cd esp32/tools + - python get.py + - cd .. + - echo 'build.flash_freq=40m' >> platform.txt + - mv $TRAVIS_BUILD_DIR/libraries/WebServer $HOME/arduino_ide/hardware/esp32/esp32/libraries/ + - mv $TRAVIS_BUILD_DIR/libraries/DNSServer $HOME/arduino_ide/hardware/esp32/esp32/libraries/ script: @@ -37,6 +46,8 @@ script: - arduino --board esp8266com:esp8266:generic --save-prefs - arduino --get-pref sketchbook.path - build_sketch esp3d/esp3d.ino + - arduino --board esp32:esp32:esp32 --save-prefs + - build_sketch esp3d/esp3d.ino notifications: email: diff --git a/README.md b/README.md index d633c41e..c550aa82 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,32 @@ # ESP3D[![Code Climate](https://codeclimate.com/github/luc-github/ESP3D/badges/gpa.svg)](https://codeclimate.com/github/luc-github/ESP3D) -Firmware for ESP8266/ESP8285 used with 3D printer using [arduino core version](https://github.com/esp8266/Arduino) +Firmware for ESP8266/ESP8285 and ESP32 used with 3D printer using [ESP8266 core version](https://github.com/esp8266/Arduino) and [ESP32 core version](https://github.com/espressif/arduino-esp32) + This firmware allows not only to have a cheap bridge between Wifi and serial, but also to have a web UI to configure wifi, to monitor 3D printer and even control it, and to make things easy, UI is fully customizable without reflashing FW. -Firmware should work with any 3D printer firmware (repetier/marlin/etc..) if serial connection has correct setup. -I currently use it with my personnal flavor of [repetier for Due based boards](https://github.com/luc-github/Repetier-Firmware-0.92). -Please use ESP with at least 1M flash, for ESP with 512K there is limited version [here](https://github.com/luc-github/ESP3D/tree/ESP-512K-64KSPIFFS) -Stable version: +Firmware should work with any 3D printer firmware (repetier/marlin/smoothieware using GCODE) if serial connection has a correct setup. +I currently use it with my personnal flavor of [repetier for Due based boards](https://github.com/luc-github/Repetier-Firmware-0.92). + +The web interface files are present in data directory but UI has it's own repository [ESP3D-WEBUI](https://github.com/luc-github/ESP3D-WEBUI). +* be aware ESP3D-WEBUI is for firmware 0.9.99 minimum - previous released version use tpl files which are no more used. + +Stable version (ESP8266 only): Arduino ide 1.6.5 with stable [2.0.0](http://arduino.esp8266.com/versions/2.0.0/package_esp8266com_index.json) from ESP8266, please use https://github.com/luc-github/ESP3D/releases/tag/v0.5.1 Arduino ide 1.6.8 with stable [2.2.0](http://arduino.esp8266.com/versions/2.2.0/package_esp8266com_index.json) from ESP8266, please use https://github.com/luc-github/ESP3D/releases/tag/v0.6.2 -Development version: -Arduino ide 1.8.0 with git from ESP8266 : [![Build Status](https://travis-ci.org/luc-github/ESP3D.svg?branch=master)](https://travis-ci.org/luc-github/ESP3D) +RC version for 1.0(master branch) very stable but waiting for 2.4 release of ESP8266: +Arduino ide 1.8.4 with git version from ESP8266 or ESP32 : [![Build Status](https://travis-ci.org/luc-github/ESP3D.svg?branch=master)](https://travis-ci.org/luc-github/ESP3D) + +Development version for 2.0 (asyncwebserver branch) pre alpha : +Arduino ide 1.8.4 with git version from ESP8266 or ESP32 : [![Build Status](https://travis-ci.org/luc-github/ESP3D.svg?branch=asyncwebserver)](https://travis-ci.org/luc-github/ESP3D) [All releases](https://github.com/luc-github/ESP3D/wiki) -:question:Any question ? check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) or [![Join the chat at https://gitter.im/luc-github/ESP3D](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/luc-github/ESP3D?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -:exclamation:Any issue ? check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) and [FAQ](https://github.com/luc-github/ESP3D/issues?utf8=%E2%9C%93&q=label%3AFAQ+) or [submit ticket](https://github.com/luc-github/ESP3D/issues) - - :+1:Thanks * to @disneysw for bringing this module idea * to @lkarlslund for suggestion about independent reset using GPIO2 -* to all contributors (treepleks, j0hnlittle, openhardwarecoza, TRoager, all feedbacks owners and donations) +* to all contributors, feedbacks owners and donations. Every support is welcome: [PayPal – The safer, easier way to pay online.](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y8FFE7NA4LJWQ) Especially if need to buy new modules for testing. @@ -31,7 +34,7 @@ Especially if need to buy new modules for testing. ##Features * Serial/Wifi bridge using configurable port 8888, here to enable/disable [TCP_IP_DATA_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Use GPIO2 to ground to reset all settings in hard way - 2-6 sec after boot / not before!! Set GPIO2 to ground before boot change boot mode and go to special boot that do not reach FW. Currently boot take 10 sec - giving 8 seconds to connect GPIO2 to GND and do an hard recovery for settings, here to enable/disable [RECOVERY_FEATURE](https://github.com/luc-github/ESP8266/blob/master/esp8266/config.h) -* Wifi configuration by web browser (Station or Access point) +* Complete configuration by web browser (Station or Access point) or by Serial commands * Authentication for sensitive pages, here to enable/disable [AUTHENTICATION_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Update firmware by web browser, here to enable/disable [WEB_UPDATE_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Control ESP module using commands on serial or data port, here to enable/disable [SERIAL_COMMAND_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) @@ -41,6 +44,8 @@ Especially if need to buy new modules for testing. * SSDP, this feature is a discovery protocol, supported on Windows out of the box, here to enable/disable [SSDP_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Printer monitoring / control (temperatures/speed/jog/list SDCard content/launch,pause or stop a print/etc...), here to enable/disable [MONITORING_FEATURE/INFO_MSG_FEATURE/ERROR_MSG_FEATURE/STATUS_MSG_FEATURE](https://github.com/luc-github/ESP3D/blob/master/esp3d/config.h) * Fail safe mode (Access point)is enabled if cannot connect to defined station at boot. +* The web ui add even more feature : https://github.com/luc-github/ESP3D-WEBUI/blob/master/README.md#features + ##Web configuration *Wifi Mode : Access point / Client station @@ -63,7 +68,7 @@ IP Mode: Static IP IP: 192.168.0.1 Mask: 255.255.255.0 GW:192.168.0.1 -Baud rate: 9600 +Baud rate: 115200 Web port:80 Data port: 8888 Web Page refresh: 3 secondes @@ -72,168 +77,163 @@ Password: admin User:user Password: user -These are the pages defined using template: -Home page : -
-System Configuration Page: -
-Access Point Configuration Page: -
-Client Configuration Page: -
-Printer Status Page for 64K SPIFFS, due to limited space available no fancy: -
-Printer Status Page for more than 64K SPIFFS, fancy one: -
-Extra Settings Page, for web UI and for printer: -
-Change password Page: -
-Login Page: -
-the template files are stored on SPIFFS: -
-and uploaded using [pluggin IDE](http://esp8266.github.io/Arduino/versions/2.1.0/doc/filesystem.html#uploading-files-to-file-system) -Any files on SPIFFS can be called on web interface without having the path hard coded, this give more flexibility, favicon.ico is a good example of it. -So UI is kind of separated from FW which allow easier modifications. For this a light file manager is available in extra settings page, it allows to upload/download/delete files. -Because SPIFFS is flat filesystem, no directory management is necessary, so it is very simple. -Additionally 404.tpl (the page not found) and restart.tpl(restart page when applying changes) are not mandatory, a fail safe version is embedded if they are not present. ##Direct commands: ``` -* Change STA SSID -[ESP100] -if authentication is on, need admin password -[ESP100]pwd= +* Change STA SSID +[ESP100] +if authentication is on, need admin password +[ESP100]pwd= -* Change STA Password -[ESP101] -if authentication is on, need admin password -[ESP101]pwd= +* Change STA Password +[ESP101] +if authentication is on, need admin password +[ESP101]pwd= -* Change Hostname -[ESP102] -if authentication is on, need admin password -[ESP102]pwd= +* Change Hostname +[ESP102] +if authentication is on, need admin password +[ESP102]pwd= -* Change Wifi mode (STA/AP) -[ESP103] -if authentication is on, need admin password -[ESP103]pwd= +* Change Wifi mode (STA/AP) +[ESP103] +if authentication is on, need admin password +[ESP103]pwd= -* Change STA IP mode (DHCP/STATIC) -[ESP104] -if authentication is on, need admin password -[ESP104]pwd= +* Change STA IP mode (DHCP/STATIC) +[ESP104] +if authentication is on, need admin password +[ESP104]pwd= -* Change AP SSID -[ESP105] -if authentication is on, need admin password -[ESP105]pwd= +* Change AP SSID +[ESP105] +if authentication is on, need admin password +[ESP105]pwd= -* Change AP Password -[ESP106] -if authentication is on, need admin password -[ESP106]pwd= +* Change AP Password +[ESP106] +if authentication is on, need admin password +[ESP106]pwd= -* Change AP IP mode (DHCP/STATIC) -[ESP107] -if authentication is on, need admin password -[ESP107]pwd= +* Change AP IP mode (DHCP/STATIC) +[ESP107] +if authentication is on, need admin password +[ESP107]pwd= -* Get current IP -[ESP111]
+* Set wifi on/off +[ESP110] +state can be ON, OFF, RESTART +if authentication is on, need admin password +[ESP110]pwd= -* Get hostname -[ESP112]
+* Get current IP +[ESP111]
-* Get/Set ESP mode -cmd can be RESET, SAFEMODE, CONFIG, RESTART -[ESP444] -if authentication is on, need admin password for RESET, RESTART and SAFEMODE -[ESP444]pwd= +* Get hostname +[ESP112]
-* Change / Reset user password -[ESP555]pwd= -if no password set it use default one -* Read SPIFFS file and send each line to serial -[ESP700] +*Get/Set pin value +[ESP201]P V [PULLUP=YES RAW=YES] +if no V get P value +if V 0/1 set INPUT_PULLUP value, but for GPIO16 INPUT_PULLDOWN_16 +GPIO1 and GPIO3 cannot be used as they are used for serial +if PULLUP=YES set input pull up, if not set input +if RAW=YES do not set pinmode just read value -* Get fw version -[ESP800]
-* Clear status/error/info list -cmd can be ALL, ERROR, INFO, STATUS -[ESP999] - +*Save data string +[ESP300] pwd= +*Get data string +[ESP301] pwd= + +*Get full EEPROM settings content +but do not give any passwords +can filter if only need wifi or printer +[ESP400] + +*Set EEPROM setting +position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask) +[ESP401]P= T= V= pwd= + +*Get available AP list (limited to 30) +output is JSON or plain text according parameter +[ESP410] + +*Get current settings of ESP3D +output is JSON or plain text according parameter +[ESP420] + +* Get/Set ESP mode +cmd can be RESET, SAFEMODE, CONFIG, RESTART +[ESP444] +if authentication is on, need admin password for RESET, RESTART and SAFEMODE +[ESP444]pwd= + +* Change / Reset user password +[ESP555]pwd= +if no password set it use default one + +* Read SPIFFS file and send each line to serial +[ESP700] + +* Format SPIFFS +[ESP710]FORMAT pwd= + +* SPIFFS total size and used size +[ESP720]
+ +* Get fw version and basic information +[ESP800]
+ +* Get fw target +[ESP801]
+ +* Clear status/error/info list +cmd can be ALL, ERROR, INFO, STATUS +[ESP999] + ``` ##Installation -* For stable: -Please use [Arduino IDE 1.6.5](http://arduino.cc/en/Main/Software) with the esp8266 module from board manager use 2.0.0 stable version by adding in your preferences http://arduino.esp8266.com/version/2.0.0/package_esp8266com_index.json -with https://github.com/luc-github/ESP3D/releases/tag/v0.5.1 -or -use [Arduino IDE 1.6.8](http://arduino.cc/en/Main/Software) with the esp8266 module from board manager use 2.2.0 stable version by adding in your preferences http://arduino.esp8266.com/stable/package_esp8266com_index.json -with https://github.com/luc-github/ESP3D/releases/tag/v0.6.2 +1. Please follow installation of the ESP core you want to use : [ESP8266 core version](https://github.com/esp8266/Arduino) or [ESP32 core version](https://github.com/espressif/arduino-esp32) +2. Add missing libraries if you target ESP32 present in libraries directory +* DNSServer (from https://github.com/bbx10/DNSServer_tng) +* WebServer (from https://github.com/bbx10/WebServer_tng) +* NetBIOS and SSDP are currently disabled for ESP32 as not yet supported +3. Compile project (ESP3D.ino) according target: ESP8266 board or ESP32 board, please review config.h to enable disable a feature, by default athenticatio is disabled and all others are enabled. +* for ESP8266 set CPU freq to 160MHz for better (https://github.com/luc-github/ESP3D/wiki/Install-Instructions) +4. Upload the data content on ESP3D file system +* Using SPIFFS uploader, this plugin and install instructions is available on each ESP core - please refere to it +* Using embedded uploader (you may need to format SPIFFS using : [ESP710]FORMAT on ESP8266 first) +if embedded uploader does not show up you can force it ti display using : http://your_IP_address?forcefallback=yes +
-* For development: -Please use [Arduino IDE 1.6.8](http://arduino.cc/en/Main/Software) and [git version of esp8266 module](http://esp8266.github.io/Arduino/versions/2.2.0/doc/installing.html#using-git-version) +##Update +* Generate a binary using the export binary menu from Arduino IDE and upload it using ESP-WEBUI or embedded interface -* To flash the module : -You must define the targeted FW, can be REPETIER (Original Repetier)/ REPETIER4DV (Repetier for Davinci) / MARLIN (Marlin)/ SMOOTHIEWARE (Smoothieware) in config.h and enable/disable any others features -``` -//MDNS_FEATURE: this feature allow type the name defined -//in web browser by default: http:\\esp8266.local and connect -//#define MDNS_FEATURE - -//SSDD_FEATURE: this feature is a discovery protocol, supported on Windows out of the box -#define SSDP_FEATURE - -//CAPTIVE_PORTAL_FEATURE: In SoftAP redirect all unknow call to main page -#define CAPTIVE_PORTAL_FEATURE - -//AUTHENTICATION_FEATURE: protect pages by login password -#define AUTHENTICATION_FEATURE - -//WEB_UPDATE_FEATURE: allow to flash fw using web UI -#define WEB_UPDATE_FEATURE - -//SERIAL_COMMAND_FEATURE: allow to send command by serial -#define SERIAL_COMMAND_FEATURE - -//TCP_IP_DATA_FEATURE: allow to connect serial from TCP/IP -#define TCP_IP_DATA_FEATURE - -//RECOVERY_FEATURE: allow to use GPIO2 pin as hardware reset for EEPROM, add 8s to boot time to let user to jump GPIO2 to GND -#define RECOVERY_FEATURE - -//FIRMWARE_TARGET: the targeted FW, can be REPETIER (Original Repetier)/ REPETIER4DV (Repetier for Davinci) / MARLIN (Marlin)/ SMOOTHIEWARE (Smoothieware) -#define FIRMWARE_TARGET REPETIER4DV - -//DEBUG Flag -//#define DEBUG_ESP3D -``` - -For better performance select CPU Frequency to be 160MHz instead of default 80MHz -Use IDE to upload directly (latest version of board manager module generate one binary) -* To flash the html files present in data directory you need to use another tool, installation and usage is explained [here](https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md#uploading-files-to-file-system) -Once flashed you also can use the web updater to flash new FW in System Configuration Page or go to settings to change html files - -

:warning:Do not flash Printer fw with ESP connected - it bring troubles, at least on DaVinci

+

:warning:Do not flash your Printer fw with ESP connected - it bring troubles, at least on DaVinci

##Contribution/customization -To modifying and Testing tpl files a local tool has been created by [j0hnlittle](https://github.com/j0hnlittle) to avoid to upload every time your tpl files just to see the results of your modifications. It is a python script (2.7+) located in tools directory, launch it: python server.py, then open browser: http://localhost:8080 -It will display the web ui and allow some navigation +* To style the code before pushing PR please use [astyle --style=otbs *.h *.cpp *.ino](http://astyle.sourceforge.net/) +* The embedded page is created using nodejs then gulp to generate a compressed html page (tool.html.gz), all necessary modules can be installed using the install.bat file content, then it is included using bin2c (https://sourceforge.net/projects/bin2c/) to generate the h file used to create the file nofile.h, update the array and size according new out.h. +* The current UI is located [here](https://github.com/luc-github/ESP3D-WEBUI) +* An optional UI is under development using old repetier UI - check [UI\repetier\testui.htm] (https://github.com/luc-github/ESP3D/blob/master/UI/repetier/testui.htm) file -To style the code before pushing PR please use [astyle --style=otbs *.h *.cpp *.ino](http://astyle.sourceforge.net/) - -Feedback/suggestion/discussions are always welcome +Feedback/suggestion/discussions are always welcome -##Need more information about board or wiring ? +##Need more information about supported boards or wiring ? [Check the wiki](https://github.com/luc-github/ESP3D/wiki) + +##:question:Any question ? +Check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) or [![Join the chat at https://gitter.im/luc-github/ESP3D](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/luc-github/ESP3D?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +##:exclamation:Any issue/feedback ? +Check [Wiki](https://github.com/luc-github/ESP3D/wiki/Install-Instructions) and [FAQ](https://github.com/luc-github/ESP3D/issues?utf8=%E2%9C%93&q=label%3AFAQ+) or [submit ticket](https://github.com/luc-github/ESP3D/issues) + ##TODO -- Close open topics -- Do testing (a lot) -- UI Improvement +-- ESP3D V2 diff --git a/UI/mousediv.html b/UI/mousediv.html deleted file mode 100644 index b73843b4..00000000 --- a/UI/mousediv.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - -
-
-
-
-
- - - - diff --git a/UI/testui.htm b/UI/repetier/testui.htm similarity index 99% rename from UI/testui.htm rename to UI/repetier/testui.htm index 66f85add..c8a7bf59 100644 --- a/UI/testui.htm +++ b/UI/repetier/testui.htm @@ -522,7 +522,7 @@ function initrange( element) -Z + diff --git a/docs/Commands.txt b/docs/Commands.txt index 962b93fb..92c03b73 100644 --- a/docs/Commands.txt +++ b/docs/Commands.txt @@ -38,12 +38,20 @@ if authentication is on, need admin password if authentication is on, need admin password [ESP107]pwd= +* Set wifi on/off +[ESP110] +state can be ON, OFF, RESTART +if authentication is on, need admin password +[ESP110]pwd= + * Get current IP [ESP111]
* Get hostname [ESP112]
+* Restart time client +[ESP114] *Get/Set pin value [ESP201]P V [PULLUP=YES RAW=YES] @@ -53,6 +61,29 @@ GPIO1 and GPIO3 cannot be used as they are used for serial if PULLUP=YES set input pull up, if not set input if RAW=YES do not set pinmode just read value + +*Save data string +[ESP300] pwd= +*Get data string +[ESP301] pwd= + +*Get full EEPROM settings content +but do not give any passwords +can filter if only need wifi or printer +[ESP400] + +*Set EEPROM setting +position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask) +[ESP401]P= T= V= pwd= + +*Get available AP list (limited to 30) +output is JSON or plain text according parameter +[ESP410] + +*Get current settings of ESP3D +output is JSON or plain text according parameter +[ESP420] + * Get/Set ESP mode cmd can be RESET, SAFEMODE, CONFIG, RESTART [ESP444] @@ -66,7 +97,13 @@ if no password set it use default one * Read SPIFFS file and send each line to serial [ESP700] -* Get fw version +* Format SPIFFS +[ESP710]FORMAT pwd= + +* SPIFFS total size and used size +[ESP720]
+ +* Get fw version and basic information [ESP800]
* Get fw target diff --git a/docs/EEPROM_OUTPUT_SAMPLE.txt b/docs/EEPROM_OUTPUT_SAMPLE.txt deleted file mode 100644 index 8d48ee3a..00000000 --- a/docs/EEPROM_OUTPUT_SAMPLE.txt +++ /dev/null @@ -1,122 +0,0 @@ -EPR:0 1028 7 Language -EPR:2 75 230400 Baudrate -EPR:0 1125 1 Display Mode: -EPR:0 1119 1 Light On: -EPR:0 1127 1 Keep Light On: -EPR:0 1126 0 Filament Sensor On: -EPR:0 1176 0 Top Sensor On: -EPR:0 1120 1 Sound On: -EPR:0 1177 1 Wifi On: -EPR:3 129 0.000 Filament printed [m] -EPR:2 125 0 Printer active [s] -EPR:2 79 0 Max. inactive time [ms,0=off] -EPR:2 83 360000 Stop stepper after inactivity [ms,0=off] -EPR:2 1121 0 Powersave after [ms,0=off]: -EPR:3 1160 180.000 Temp Ext PLA: -EPR:3 1164 230.000 Temp Ext ABS: -EPR:3 1168 60.000 Temp Bed PLA: -EPR:3 1172 90.000 Temp Bed ABS: -EPR:3 1179 2.000 Load Feed Rate: -EPR:3 1183 4.000 Unload Feed Rate: -EPR:3 1187 60.000 Unload/Load Distance: -EPR:3 3 80.0000 X-axis steps per mm -EPR:3 7 80.0000 Y-axis steps per mm -EPR:3 11 2560.0000 Z-axis steps per mm -EPR:3 15 200.000 X-axis max. feedrate [mm/s] -EPR:3 19 200.000 Y-axis max. feedrate [mm/s] -EPR:3 23 5.000 Z-axis max. feedrate [mm/s] -EPR:3 27 40.000 X-axis homing feedrate [mm/s] -EPR:3 31 40.000 Y-axis homing feedrate [mm/s] -EPR:3 35 4.000 Z-axis homing feedrate [mm/s] -EPR:3 39 20.000 Max. jerk [mm/s] -EPR:3 47 0.342 Max. Z-jerk [mm/s] -EPR:3 133 0.000 X min pos [mm] -EPR:3 137 0.000 Y min pos [mm] -EPR:3 141 0.000 Z min pos [mm] -EPR:3 145 199.000 X max length [mm] -EPR:3 149 204.000 Y max length [mm] -EPR:3 153 200.000 Z max length [mm] -EPR:3 51 1000.000 X-axis acceleration [mm/s^2] -EPR:3 55 1000.000 Y-axis acceleration [mm/s^2] -EPR:3 59 100.000 Z-axis acceleration [mm/s^2] -EPR:3 63 1000.000 X-axis travel acceleration [mm/s^2] -EPR:3 67 1000.000 Y-axis travel acceleration [mm/s^2] -EPR:3 71 150.000 Z-axis travel acceleration [mm/s^2] -EPR:3 1024 0.000 Coating thickness [mm] -EPR:3 1128 100.000 Manual-probe X1 [mm] -EPR:3 1132 180.000 Manual-probe Y1 [mm] -EPR:3 1136 100.000 Manual-probe X2 [mm] -EPR:3 1140 10.000 Manual-probe Y2 [mm] -EPR:3 1144 50.000 Manual-probe X3 [mm] -EPR:3 1148 95.000 Manual-probe Y3 [mm] -EPR:3 1152 150.000 Manual-probe X4 [mm] -EPR:3 1156 95.000 Manual-probe Y4 [mm] -EPR:3 808 0.280 Z-probe height [mm] -EPR:3 929 5.000 Max. z-probe - bed dist. [mm] -EPR:3 812 1.000 Z-probe speed [mm/s] -EPR:3 840 30.000 Z-probe x-y-speed [mm/s] -EPR:3 800 0.000 Z-probe offset x [mm] -EPR:3 804 0.000 Z-probe offset y [mm] -EPR:3 816 36.000 Z-probe X1 [mm] -EPR:3 820 -7.000 Z-probe Y1 [mm] -EPR:3 824 36.000 Z-probe X2 [mm] -EPR:3 828 203.000 Z-probe Y2 [mm] -EPR:3 832 171.000 Z-probe X3 [mm] -EPR:3 836 203.000 Z-probe Y3 [mm] -EPR:3 1036 0.000 Z-probe bending correction A [mm] -EPR:3 1040 0.000 Z-probe bending correction B [mm] -EPR:3 1044 0.000 Z-probe bending correction C [mm] -EPR:0 880 0 Autolevel active (1/0) -EPR:0 106 2 Bed Heat Manager [0-3] -EPR:0 107 255 Bed PID drive max -EPR:0 124 80 Bed PID drive min -EPR:3 108 196.000 Bed PID P-gain -EPR:3 112 33.000 Bed PID I-gain -EPR:3 116 290.000 Bed PID D-gain -EPR:0 120 255 Bed PID max value [0-255] -EPR:0 1020 0 Enable retraction conversion [0/1] -EPR:3 992 3.000 Retraction length [mm] -EPR:3 996 13.000 Retraction length extruder switch [mm] -EPR:3 1000 40.000 Retraction speed [mm/s] -EPR:3 1004 0.000 Retraction z-lift [mm] -EPR:3 1008 0.000 Extra extrusion on undo retract [mm] -EPR:3 1012 0.000 Extra extrusion on undo switch retract [mm] -EPR:3 1016 20.000 Retraction undo speed -EPR:3 200 99.000 Extr.1 steps per mm -EPR:3 204 50.000 Extr.1 max. feedrate [mm/s] -EPR:3 208 20.000 Extr.1 start feedrate [mm/s] -EPR:3 212 5000.000 Extr.1 acceleration [mm/s^2] -EPR:0 216 3 Extr.1 heat manager [0-3] -EPR:0 217 230 Extr.1 PID drive max -EPR:0 245 40 Extr.1 PID drive min -EPR:3 218 3.0000 Extr.1 PID P-gain/dead-time -EPR:3 222 2.0000 Extr.1 PID I-gain -EPR:3 226 40.0000 Extr.1 PID D-gain -EPR:0 230 255 Extr.1 PID max value [0-255] -EPR:2 231 0 Extr.1 X-offset [steps] -EPR:2 235 0 Extr.1 Y-offset [steps] -EPR:2 290 0 Extr.1 Z-offset [steps] -EPR:1 239 1 Extr.1 temp. stabilize time [s] -EPR:1 250 150 Extr.1 temp. for retraction when heating [C] -EPR:1 252 0 Extr.1 distance to retract when heating [mm] -EPR:0 254 255 Extr.1 extruder cooler speed [0-255] -EPR:3 246 0.000 Extr.1 advance L [0=off] -EPR:3 300 99.000 Extr.2 steps per mm -EPR:3 304 50.000 Extr.2 max. feedrate [mm/s] -EPR:3 308 20.000 Extr.2 start feedrate [mm/s] -EPR:3 312 5000.000 Extr.2 acceleration [mm/s^2] -EPR:0 316 3 Extr.2 heat manager [0-3] -EPR:0 317 230 Extr.2 PID drive max -EPR:0 345 40 Extr.2 PID drive min -EPR:3 318 3.0000 Extr.2 PID P-gain/dead-time -EPR:3 322 2.0000 Extr.2 PID I-gain -EPR:3 326 40.0000 Extr.2 PID D-gain -EPR:0 330 255 Extr.2 PID max value [0-255] -EPR:2 331 -2852 Extr.2 X-offset [steps] -EPR:2 335 12 Extr.2 Y-offset [steps] -EPR:2 390 0 Extr.2 Z-offset [steps] -EPR:1 339 1 Extr.2 temp. stabilize time [s] -EPR:1 350 150 Extr.2 temp. for retraction when heating [C] -EPR:1 352 0 Extr.2 distance to retract when heating [mm] -EPR:0 354 255 Extr.2 extruder cooler speed [0-255] -EPR:3 346 0.000 Extr.2 advance L [0=off] diff --git a/docs/keywords.txt b/docs/keywords.txt deleted file mode 100644 index 1d1487a4..00000000 --- a/docs/keywords.txt +++ /dev/null @@ -1,150 +0,0 @@ -[COMMON] -$INCLUDE[] : only one per line and alone, others will be ignored -$IP$ : current active ip -$WEB_ADDRESS$: current active ip , if port is not 80 it will add port like xxx.xxx.xxxx.xxx:XX -$MENU_HOME$/$MENU_SYSTEM$/$MENU_AP$/$MENU_STA$/$MENU_PRINTER$/$MENU_SETTINGS$: to highlight menu of active page (css use class active for active menu) -$SERVICE_PAGE$ : to add extra code like redirection or anything not managed by page -$PAGE_TILE$ : page title -$FILENAME$ : file name of tpl -$SHORT_FILENAME$ : file name of tpl without extension -$MODE$ : the mode when displaying page AP/STA/AP_STA -$FW_VER$ : Firmware version - -[HOME] -$HOSTNAME$: Hostname -$HOSTNAME_VISIBLE$ : if AP mode then hostname is not applicable so set to hidden, if in STA mode set to visible -$CHIP_ID$ : Chip ID -$CPU_FREQ$ : CPU Frequency -$FREE_MEM$ : Free memory on heap -$SDK_VER$ : SDK version -$MDNS_VISIBLE$: set to hidden if no MDNS and visible if present -$MDNS_NAME$ : mDNS name if enabled or "Not enabled" if not enabled -$SSDP_VISIBLE$ : set to hidden if no MDNS and visible if present -$SSDP_STATUS$ : set to Enabled / Not enabled according compilation settings -$CAPTIVE_PORTAL_VISIBLE$: set to hidden if no Captive portal and visible if present -$CAPTIVE_PORTAL_STATUS$: set to Enabled / Not enabled according compilation settings -$NET_PHY$ : Network type (b/g/n) -$SLEEP_MODE$ : Sleep Mode -$BOOT_VER$ : Boot version -$BAUD_RATE$ : Baud rates for serial communication -$WEB_PORT$ : Port for web access -$DATA_PORT$ : Port for tcp ip connection -$DATA_PORT_VISIBILITY$ : set to hidden if no enabled and visible if enabled - -$AP_STATUS_ENABLED$ : is Access Point enabled or disabled -$AP_VISIBILITY$ : if Access Point is enabled set visible, else set to hidden -$AP_MAC$ : Mac address of AP -$AP_SSID$ : SSID of AP -$AP_IS_VISIBLE$ : Is AP visible -$AP_CHANNEL$ : Channel -$AP_AUTH$ : Autehntification mode -$AP_MAX_CON$ : Maximum connections allowed -$AP_DHCP_STATUS$ : AP DHCP server status (started/stopped) -$AP_IP$ : AP IP address -$AP_GW$ : AP gateway address -$AP_SUBNET$ : AP mask of subnet - -$CONNECTED_STATIONS[ Repetive template using $ROW_NUMBER$ $MAC_CONNECTED$ $IP_CONNECTED$ ]$ -$CONNECTED_STATIONS_NB_ITEMS$ : number of item for connected stations list - or can get variables in direct access: - $ROW_NUMBER[0]$ - $MAC_CONNECTED[0]$ - $IP_CONNECTED[0]$ - until - $ROW_NUMBER[$CONNECTED_STATIONS_NB_ITEMS$ -1]$ - $MAC_CONNECTED[$CONNECTED_STATIONS_NB_ITEMS$ -1]$ - $IP_CONNECTED[$CONNECTED_STATIONS_NB_ITEMS$ -1]$ - -$STA_STATUS_ENABLED$ : is Station enabled or disabled -$STA_VISIBILITY$ : if Station is enabled set visible, else set to hidden -$STA_MAC$ : Mac address of Station -$STA_SSID$ : SSID used by STA -$STA_CHANNEL$ : Channel -$STA_STATUS$ : Connection Status -$STA_SIGNAL$ : Signal strength -$STA_DHCP_STATUS$ : DHCP Client status -$STA_IP$ : STA IP -$STA_GW$ : STA Gateway -$STA_SUBNET$ : STA Mask - -[SYSTEM CONFIGURATION] -$BAUD_RATE_OPTIONS_LIST$ : Baud rate list -$SLEEP_MODE_OPTIONS_LIST$ : Sleep mode list -$POLLING_OPTIONS_LIST$ : Refresh delay list -$WEB_PORT$ : Port for web access -$DATA_PORT$ : Port for tcp ip connection -$DATA_PORT_VISIBILITY$ : set to hidden if no enabled and visible if enabled -$ERROR_MSG$ : Error message if any -$SUCCESS_MSG$ : Success message announcing restart -$ERROR_MSG_VISIBILITY$ : Show/Hide Error message -$SUCCESS_MSG_VISIBILITY$ : Show/Hide Success message -$SUBMIT_BUTTON_VISIBILITY$ : Show if no submission or any error, hide if submission is successful -$BAUD_RATE_STATUS$ : change to has-error if issue, or has-success if ok -$SLEEP_MODE_STATUS$ : change to has-error if issue, or has-success if ok -$WEB_PORT_STATUS$ : change to has-error if issue, or has-success if ok -$DATA_PORT_STATUS$ : change to has-error if issue, or has-success if ok - -[AP CONFIGURATION] -$AP_SSID$ : Access point SSID -$AP_PASSWORD$ Access point password -$IS_SSID_VISIBLE$ : set to checked if SSID is visible -$NETWORK_OPTION_LIST$ : Option list for network for AP -$CHANNEL_OPTION_LIST$ : Channel list -$AUTH_OPTION_LIST$ Authentification methods list -$IS_STATIC_IP$ : set to checked if use static address -$AP_IP$ : Access point IP if static address -$AP_GW$ : Access point Gaieway if static address -$AP_SUBNET$ : : Access point network mask if static address -$ERROR_MSG$ : Error message if any -$SUCCESS_MSG$ : Success message announcing restart -$ERROR_MSG_VISIBILITY$ : Show/Hide Error message -$SUCCESS_MSG_VISIBILITY$ : Show/Hide Success message -$SUBMIT_BUTTON_VISIBILITY$ : Show if no submission or any error, hide if submission is successful -$AP_SSID_STATUS$ : change to has-error if issue, or has-success if ok -$AP_PASSWORD_STATUS$ : change to has-error if issue, or has-success if ok -$IS_SSID_VISIBLE_STATUS$ : change to has-error if issue, or has-success if ok -$NETWORK_OPTION_LIST_STATUS$ : change to has-error if issue, or has-success if ok -$CHANNEL_OPTION_LIST_STATUS$ : change to has-error if issue, or has-success if ok -$AUTH_OPTION_LIST_STATUS$ : change to has-error if issue, or has-success if ok -$AP_STATIC_IP_STATUS$ : change to has-error if issue, or has-success if ok -$AP_IP_STATUS$ : change to has-error if issue, or has-success if ok -$AP_GW_STATUS$ : change to has-error if issue, or has-success if ok -$AP_SUBNET_STATUS$ : change to has-error if issue, or has-success if ok - -[STATION CONFIGURATION] -$STA_SSID$ : Access point SSID -$STA_PASSWORD$ Access point password -$NETWORK_OPTION_LIST$ : Option list for network for AP -$IS_STATIC_IP$ : set to checked if use static address -$STA_IP$ : Access point IP if static address -$STA_GW$ : Access point Gaieway if static address -$STA_SUBNET$ : : Access point network mask if static address -$ERROR_MSG$ : Error message if any -$SUCCESS_MSG$ : Success message announcing restart -$ERROR_MSG_VISIBILITY$ : Show/Hide Error message -$SUCCESS_MSG_VISIBILITY$ : Show/Hide Success message -$SUBMIT_BUTTON_VISIBILITY$ : Show if no submission or any error, hide if submission is successful -$STA_SSID_STATUS$ : change to has-error if issue, or has-success if ok -$STA_PASSWORD_STATUS$ : change to has-error if issue, or has-success if ok -$NETWORK_OPTION_LIST_STATUS$ : change to has-error if issue, or has-success if ok -$STA_STATIC_IP_STATUS$ : change to has-error if issue, or has-success if ok -$STA_IP_STATUS$ : change to has-error if issue, or has-success if ok -$STA_GW_STATUS$ : change to has-error if issue, or has-success if ok -$STA_SUBNET_STATUS$ : change to has-error if issue, or has-success if ok -$AP_SCAN_VISIBILITY$ : Hide scan table which is not executed when saving to EEPROM - -[PRINTER STATUS] -$REFRESH_PAGE$ : Delay for refreshing pages -$XY_FEEDRATE$ : XY axis feedrate -$Z_FEEDRATE$ : Z axis feedrate -$E_FEEDRATE$ : Extruder feedrate - -[PRINTER SETTINGS] -$REFRESH_PAGE$ : Delay for refreshing pages -$XY_FEEDRATE$ : XY axis feedrate -$Z_FEEDRATE$ : Z axis feedrate -$E_FEEDRATE$ : Extruder feedrate -$REFRESH_PAGE_STATUS$ : change to has-error if issue, or has-success if ok -$XY_FEEDRATE_STATUS$ : change to has-error if issue, or has-success if ok -$Z_FEEDRATE_STATUS$ : change to has-error if issue, or has-success if ok -$E_FEEDRATE_STATUS$ : change to has-error if issue, or has-success if ok diff --git a/embedded/build.bat b/embedded/build.bat new file mode 100644 index 00000000..f4a9a8df --- /dev/null +++ b/embedded/build.bat @@ -0,0 +1 @@ +bin2c /infile tool.html.gz /outfile out.h /targetfolder . diff --git a/embedded/gulpfile.js b/embedded/gulpfile.js new file mode 100644 index 00000000..8deb4a79 --- /dev/null +++ b/embedded/gulpfile.js @@ -0,0 +1,125 @@ +var gulp = require('gulp'), + jshint = require('gulp-jshint'), + gulpif = require('gulp-if'), + concat = require('gulp-concat'), + uglify = require('gulp-uglify'), + cleanCSS = require('gulp-clean-css'), + removeCode = require('gulp-remove-code'), + merge = require('merge-stream'), + del = require('del'), + zip = require('gulp-zip'), + gzip = require('gulp-gzip'), + htmlmin = require('gulp-htmlmin'), + replace = require('gulp-replace'), + fs = require('fs'), + smoosher = require('gulp-smoosher'); + +var demoMode = false; +var testMode = false; + +function clean() { + return del(['dist']); +} + +function clean2() { + return del(['dist/js', 'dist/css']); +} +function lint() { + return gulp.src('www/js/**/script.js') + .pipe(jshint()) + .pipe(jshint.reporter('default')); +} + +function Copytest() { + return merge( + gulp.src(['www/tool.html']) + .pipe(removeCode({production: false})) + .pipe(gulp.dest('dist')), + gulp.src(['www/images/**/*.*']) + .pipe(gulp.dest('dist/images')) + ) +} + +function Copy() { + return merge( + gulp.src(['www/tool.html']) + .pipe(removeCode({production: true})) + .pipe(gulp.dest('dist')), + gulp.src(['www/images/**/*.*']) + .pipe(gulp.dest('dist/images')) + ) +} + +function concatApptest() { + return merge( + gulp.src([ 'www/js/**/*.js']) + .pipe(concat('script.js')) + .pipe(removeCode({production: false})) + .pipe(gulp.dest('./dist/js')), + + gulp.src([ 'www/css/**/*.css']) + .pipe(concat('style.css')) + .pipe(gulp.dest('./dist/css/')) + ) +} + +function concatApp() { + return merge( + gulp.src([ 'www/js/**/*.js']) + .pipe(concat('script.js')) + .pipe(removeCode({production: true})) + .pipe(gulp.dest('./dist/js')), + + gulp.src([ 'www/css/**/*.css']) + .pipe(concat('style.css')) + .pipe(gulp.dest('./dist/css/')) + ) +} + +function minifyApp() { + return merge( + gulp.src(['dist/js/script.js']) + .pipe(uglify({mangle: true})) + .pipe(gulp.dest('./dist/js/')), + + gulp.src('dist/css/style.css') + .pipe(cleanCSS({debug: true}, function(details) { + console.log(details.name + ': ' + details.stats.originalSize); + console.log(details.name + ': ' + details.stats.minifiedSize); + })) + .pipe(gulp.dest('./dist/css/')), + + gulp.src('dist/tool.html') + .pipe(htmlmin({collapseWhitespace: true, minifyCSS: true})) + .pipe(gulp.dest('dist')) + ) +} + +function smoosh() { + return gulp.src('dist/tool.html') + .pipe(smoosher()) + .pipe(gulp.dest('dist')) +} + +function compress() { + return gulp.src('dist/tool.html') + .pipe(gzip()) + .pipe(gulp.dest('.')); +} + +gulp.task(clean); +gulp.task(lint); +gulp.task(Copy); +gulp.task(Copytest); +gulp.task(concatApp); +gulp.task(concatApptest); +gulp.task(minifyApp); +gulp.task(smoosh); +gulp.task(clean2); + +var defaultSeries = gulp.series(clean, lint, Copy, concatApp, smoosh); +var packageSeries = gulp.series(clean, lint, Copy, concatApp,minifyApp, smoosh, compress, clean2); + +gulp.task('default', defaultSeries); +gulp.task('package', packageSeries); + diff --git a/embedded/install.bat b/embedded/install.bat new file mode 100644 index 00000000..e3f2831a --- /dev/null +++ b/embedded/install.bat @@ -0,0 +1,15 @@ +npm install --global gulp-cli +npm install --save-dev gulp +npm install --save-dev gulp-jshint +npm install --save-dev jshint +npm install --save-dev gulp-if +npm install --save-dev gulp-concat +npm install --save-dev gulp-uglify +npm install --save-dev gulp-clean-css +npm install --save-dev gulp-remove-code +npm install --save-dev del +npm install --save-dev gulp-zip +npm install --save-dev gulp-gzip +npm install --save-dev gulp-htmlmin +npm install --save-dev gulp-replace +npm install --save-dev gulp-smoosher diff --git a/embedded/package.json b/embedded/package.json new file mode 100644 index 00000000..00299619 --- /dev/null +++ b/embedded/package.json @@ -0,0 +1,30 @@ +{ + "name": "embedded4ESP3D", + "description": "Embedded files for ESP3D", + "devDependencies": { + "del": "^2.2.2", + "deprecated": "0.0.1", + "fs": "0.0.1-security", + "gulp": "github:gulpjs/gulp#4.0", + "gulp-bytediff": "^1.0.0", + "gulp-cdnizer": "^1.1.7", + "gulp-clean-css": "^2.4.0", + "gulp-concat": "^2.6.1", + "gulp-gzip": "^1.4.0", + "gulp-htmlmin": "^3.0.0", + "gulp-if": "^2.0.2", + "gulp-jshint": "^2.0.4", + "gulp-ng-annotate": "^2.0.0", + "gulp-remove-code": "^1.0.2", + "gulp-replace": "^0.5.4", + "gulp-smoosher": "0.0.9", + "gulp-uglify": "^2.1.2", + "gulp-util": "^3.0.1", + "gulp-zip": "^3.2.0", + "jshint": "^2.9.5", + "merge-stream": "^1.0.1" + }, + "repository": "https://github.com/luc-github/ESP3D", + "author": "Luc LEBOSSE", + "license": "(ISC OR GPL-3.0)" +} diff --git a/embedded/tool.html.gz b/embedded/tool.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..de11ef0170ba9cdda845977d8bdfbb586c26aef0 GIT binary patch literal 4776 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 literal 0 HcmV?d00001 diff --git a/esp3d/data/css.inc b/embedded/www/css/style.css similarity index 59% rename from esp3d/data/css.inc rename to embedded/www/css/style.css index f3ace5a2..d8b50635 100644 --- a/esp3d/data/css.inc +++ b/embedded/www/css/style.css @@ -50,3 +50,90 @@ caption{padding-top:8px;padding-bottom:8px;color:#777777;text-align:left;} .btnroundimg:hover{background-color:#F0F0F0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;} .blacklink {color:#000000;} .blacklink:hover, .filelink:focus {color:#0094FF;} +input[type="file"]::-webkit-file-upload-button{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer; +background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px; +* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #5bc0de;border-color: #46b8da;} +input[type="file"]::-webkit-file-upload-button:focus{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer; +background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px; +* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #31b0d5;border-color: #1b6d85;} +input[type="file"]::-webkit-file-upload-button:hover{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation; touch-action:manipulation;cursor:pointer; +background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px; +* -webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none; color: #ffffff;background-color: #31b0d5;border-color: #269abc;} +.filelink {color:#000000;} +.filelink:hover, .filelink:focus {color:#0094FF;} +.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;} +.loader { + border: 4px solid #f3f3f3; /* Light grey */ + border-top: 4px solid #3498db; /* Blue */ + border-radius: 50%; + width: 12px; + height: 12px; + animation: spin 2s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} +.panel-footer{padding:10px 15px;color:#31708f;background-color:#f5f5f5;border-color:#dddddd;border-top:1px solid #dddddd;} + +.modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 10000; /* Sit on top */ + padding-top: 100px; /* Location of the box */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content */ +.modal-content { + border-top-left-radius: 10px; + border-top-right-radius: 10px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + border: 2px solid #337AB7; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + position: relative; + margin: auto; + padding: 0; + background-color: #fefefe; +} + +.modal-header { + padding: 2px 16px; + color: #0f0f0f; + background-color: #f2f2f2; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + border-bottom: 1px solid #cfcfcf; +} + +.modal-body {padding: 10px 16px;} + +.modal-footer { + padding: 16px 16px; + height: 4.5em; + color: #0f0f0f; + background-color: #f2f2f2; + border-top: 1px solid #cfcfcf; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} + +@media (min-width: 768px) { + .modal-content { + width: 580px; + } +} + +@media screen and (max-width: 767px) { + .modal-content { + width: 100%; + } +} diff --git a/esp3d/data/settings.tpl b/embedded/www/js/script.js similarity index 60% rename from esp3d/data/settings.tpl rename to embedded/www/js/script.js index 69f5c0fe..f6f7428e 100644 --- a/esp3d/data/settings.tpl +++ b/embedded/www/js/script.js @@ -1,52 +1,3 @@ -$INCLUDE[header.inc]$ -$INCLUDE[css2.inc]$ - -

-
Extra Settings
-
-
-

-
-

-
-

-
-

-
- - -
-
- -
-
-
-
Flash Filesystem
-
- -   -

-
- -
-
- + -
-
 
-
-
TypeNameSize
-
- -
-
-
- -$INCLUDE[footer.inc]$ - +function RequestLogin(){ + document.getElementById('loader').style.visibility="hidden"; + document.getElementById('loginpage').style.display='block'; +} +function SubmitRequest (){ + document.getElementById('loginpage').style.display='none'; + var user = document.getElementById('login_user_text').value.trim(); + var password = document.getElementById('login_password_text').value.trim(); + var url = "/login?USER="+encodeURIComponent(user) + "&PASSWORD=" + encodeURIComponent(password) + "&SUBMIT=yes" ; + var xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange = function() { + if (xmlhttp.readyState == 4 && xmlhttp.status != 200) { + RequestLogin(); + } + }; +xmlhttp.open("GET", url, true); +xmlhttp.send(); +} diff --git a/embedded/www/tool.html b/embedded/www/tool.html new file mode 100644 index 00000000..33c5cecd --- /dev/null +++ b/embedded/www/tool.html @@ -0,0 +1,100 @@ + + + + + + + +
+ V1.1 +    +
+
+

It seems you do not have any index.html neither index.html.gz, please upload it or update your firmware if necessary.

+
+ +
+
Flash Filesystem
+
+ +    +

+
+
+ + + + + + + +
+ + +
+ + +
+
+
+
+
 
+
+ + + + + + + + + + + +
TypeNameSize
+
+ +
+
+
+
+
Firmware Update
+
+ + + + + + + +
+
+
+ + + + + + + + diff --git a/esp3d/bridge.cpp b/esp3d/bridge.cpp index 3925d9a8..58d6d34d 100644 --- a/esp3d/bridge.cpp +++ b/esp3d/bridge.cpp @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include "bridge.h" #include "command.h" #include "webinterface.h" @@ -29,92 +30,91 @@ WiFiClient serverClients[MAX_SRV_CLIENTS]; bool BRIDGE::header_sent = false; String BRIDGE::buffer_web = ""; -void BRIDGE::print (const __FlashStringHelper *data, tpipe output){ +void BRIDGE::print (const __FlashStringHelper *data, tpipe output) +{ String tmp = data; BRIDGE::print(tmp.c_str(), output); } -void BRIDGE::print (String & data, tpipe output){ +void BRIDGE::print (String & data, tpipe output) +{ BRIDGE::print(data.c_str(), output); } -void BRIDGE::print (const char * data, tpipe output){ - switch(output){ - case SERIAL_PIPE: - header_sent = false; - Serial.print(data); - break; - case SERIAL1_PIPE: - header_sent = false; - Serial1.print(data); +void BRIDGE::print (const char * data, tpipe output) +{ + switch(output) { + case SERIAL_PIPE: + header_sent = false; + ESP_SERIAL_OUT.print(data); break; #ifdef TCP_IP_DATA_FEATURE - case TCP_PIPE: - header_sent = false; - BRIDGE::send2TCP(data); + case TCP_PIPE: + header_sent = false; + BRIDGE::send2TCP(data); break; #endif - case WEB_PIPE: - if (!header_sent){ - web_interface->WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->WebServer.sendHeader("Content-Type","text/html"); - web_interface->WebServer.sendHeader("Cache-Control","no-cache"); - web_interface->WebServer.send(200); - header_sent = true; - } - buffer_web+=data; - if (buffer_web.length() > 1200) - { - //send data - web_interface->WebServer.sendContent(buffer_web); - //reset buffer - buffer_web=""; - } + case WEB_PIPE: + if (!header_sent) { + web_interface->web_server.setContentLength(CONTENT_LENGTH_UNKNOWN); + web_interface->web_server.sendHeader("Content-Type","text/html"); + web_interface->web_server.sendHeader("Cache-Control","no-cache"); + web_interface->web_server.send(200); + header_sent = true; + } + buffer_web+=data; + if (buffer_web.length() > 1200) { + //send data + web_interface->web_server.sendContent(buffer_web); + //reset buffer + buffer_web=""; + } break; - default: + default: break; } } -void BRIDGE::println (const __FlashStringHelper *data, tpipe output){ +void BRIDGE::println (const __FlashStringHelper *data, tpipe output) +{ BRIDGE::print(data,output); #ifdef TCP_IP_DATA_FEATURE BRIDGE::print("\r",output); #endif BRIDGE::print("\n",output); } -void BRIDGE::println (String & data, tpipe output){ +void BRIDGE::println (String & data, tpipe output) +{ BRIDGE::print(data,output); #ifdef TCP_IP_DATA_FEATURE BRIDGE::print("\r",output); #endif BRIDGE::print("\n",output); } -void BRIDGE::println (const char * data, tpipe output){ +void BRIDGE::println (const char * data, tpipe output) +{ BRIDGE::print(data,output); #ifdef TCP_IP_DATA_FEATURE BRIDGE::print("\r",output); #endif BRIDGE::print("\n",output); } -void BRIDGE::flush (tpipe output){ - switch(output){ - case SERIAL_PIPE: - Serial.flush(); - break; - case SERIAL1_PIPE: - Serial1.flush(); +void BRIDGE::flush (tpipe output) +{ + switch(output) { + case SERIAL_PIPE: + ESP_SERIAL_OUT.flush(); break; #ifdef TCP_IP_DATA_FEATURE - case TCP_PIPE: + case TCP_PIPE: break; #endif - case WEB_PIPE: - if(header_sent){ - //send data - web_interface->WebServer.sendContent(buffer_web); - //close line - web_interface->WebServer.sendContent(""); - } + case WEB_PIPE: + if(header_sent) { + //send data + web_interface->web_server.sendContent(buffer_web); + //close line + web_interface->web_server.sendContent(""); + } break; - default: + default: break; } header_sent = false; @@ -123,36 +123,42 @@ void BRIDGE::flush (tpipe output){ #ifdef TCP_IP_DATA_FEATURE -void BRIDGE::send2TCP(const __FlashStringHelper *data){ +void BRIDGE::send2TCP(const __FlashStringHelper *data) +{ String tmp = data; BRIDGE::send2TCP(tmp.c_str()); } -void BRIDGE::send2TCP(String data){ +void BRIDGE::send2TCP(String data) +{ BRIDGE::send2TCP(data.c_str()); } -void BRIDGE::send2TCP(const char * data){ +void BRIDGE::send2TCP(const char * data) +{ for(uint8_t i = 0; i < MAX_SRV_CLIENTS; i++) { - if (serverClients[i] && serverClients[i].connected()) { - serverClients[i].write(data, strlen(data)); - delay(0); - } + if (serverClients[i] && serverClients[i].connected()) { + serverClients[i].write(data, strlen(data)); + delay(0); } + } } #endif + bool BRIDGE::processFromSerial2TCP() { uint8_t i; //check UART for data - if(Serial.available()) { - size_t len = Serial.available(); + if(ESP_SERIAL_OUT.available()) { + size_t len = ESP_SERIAL_OUT.available(); uint8_t sbuf[len]; - Serial.readBytes(sbuf, len); + ESP_SERIAL_OUT.readBytes(sbuf, len); #ifdef TCP_IP_DATA_FEATURE - //push UART data to all connected tcp clients - for(i = 0; i < MAX_SRV_CLIENTS; i++) { - if (serverClients[i] && serverClients[i].connected()) { - serverClients[i].write(sbuf, len); - delay(0); + if (WiFi.getMode()!=WIFI_OFF ) { + //push UART data to all connected tcp clients + for(i = 0; i < MAX_SRV_CLIENTS; i++) { + if (serverClients[i] && serverClients[i].connected()) { + serverClients[i].write(sbuf, len); + delay(0); + } } } #endif @@ -192,7 +198,7 @@ void BRIDGE::processFromTCP2Serial() //get data from the tcp client and push it to the UART while(serverClients[i].available()) { data = serverClients[i].read(); - Serial.write(data); + ESP_SERIAL_OUT.write(data); COMMAND::read_buffer_tcp(data); } } diff --git a/esp3d/command.cpp b/esp3d/command.cpp index 066d5879..a40647a7 100644 --- a/esp3d/command.cpp +++ b/esp3d/command.cpp @@ -17,24 +17,26 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "command.h" #include "config.h" -#include "wifi.h" +#include "command.h" +#include "wificonf.h" #include "webinterface.h" -#ifdef SDCARD_FEATURE #ifndef FS_NO_GLOBALS #define FS_NO_GLOBALS #endif -#endif #include - +#if defined(ARDUINO_ARCH_ESP32) +#include "SPIFFS.h" +#define MAX_GPIO 16 +#else +#define MAX_GPIO 37 +#endif String COMMAND::buffer_serial; String COMMAND::buffer_tcp; -#define ERROR_CMD_MSG F("M117 Cmd Error") -#define INCORRECT_CMD_MSG F("M117 Incorrect Cmd") -#define OK_CMD_MSG F("M117 Cmd Ok") +#define ERROR_CMD_MSG (output == WEB_PIPE)?F("Error: Wrong Command"):F("M117 Cmd Error") +#define INCORRECT_CMD_MSG (output == WEB_PIPE)?F("Error: Incorrect Command"):F("M117 Incorrect Cmd") +#define OK_CMD_MSG (output == WEB_PIPE)?F("ok"):F("M117 Cmd Ok") String COMMAND::get_param(String & cmd_params, const char * id, bool withspace) { @@ -60,10 +62,12 @@ String COMMAND::get_param(String & cmd_params, const char * id, bool withspace) if (!withspace) { end = cmd_params.indexOf(" ",start); } +#ifdef AUTHENTICATION_FEATURE //if space expected only one parameter but additional password may be present - else if (sid!="pwd=") { - end = cmd_params.indexOf("pwd=",start); + else if (sid != " pwd=") { + end = cmd_params.indexOf(" pwd=",start); } +#endif //if no end found - take all if (end == -1) { end = cmd_params.length(); @@ -75,11 +79,12 @@ String COMMAND::get_param(String & cmd_params, const char * id, bool withspace) return parameter; } #ifdef AUTHENTICATION_FEATURE +//check admin password bool COMMAND::isadmin(String & cmd_params) { String adminpassword; String sadminPassword; - if (!CONFIG::read_string(EP_ADMIN_PWD, sadminPassword , MAX_LOCAL_PASSWORD_LENGTH)) { + if (!CONFIG::read_string(EP_ADMIN_PWD, sadminPassword, MAX_LOCAL_PASSWORD_LENGTH)) { LOG("ERROR getting admin\r\n") sadminPassword=FPSTR(DEFAULT_ADMIN_PWD); } @@ -91,9 +96,38 @@ bool COMMAND::isadmin(String & cmd_params) return true; } } -#endif -void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) +//check user password - admin password is also valid +bool COMMAND::isuser(String & cmd_params) { + String userpassword; + String suserPassword; + if (!CONFIG::read_string(EP_USER_PWD, suserPassword, MAX_LOCAL_PASSWORD_LENGTH)) { + LOG("ERROR getting user\r\n") + suserPassword=FPSTR(DEFAULT_USER_PWD); + } + userpassword = get_param(cmd_params,"pwd=", true); + //it is not user password + if (!suserPassword.equals(userpassword)) { + //check admin password + return COMMAND::isadmin(cmd_params); + } else { + return true; + } +} +#endif +bool COMMAND::execute_command(int cmd,String cmd_params, tpipe output, level_authenticate_type auth_level) +{ + bool response = true; +#ifdef AUTHENTICATION_FEATURE + level_authenticate_type auth_type = auth_level; + if (isadmin(cmd_params)) { + auth_type = LEVEL_ADMIN; + } + if (isuser(cmd_params) && (auth_type != LEVEL_ADMIN)) { + auth_type = LEVEL_USER; + } + +#endif //manage parameters byte mode = 254; String parameter; @@ -107,12 +141,13 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) BRIDGE::println(INCORRECT_CMD_MSG, output); } #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); } else #endif if(!CONFIG::write_string(EP_STA_SSID,parameter.c_str())) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -123,14 +158,17 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) parameter = get_param(cmd_params,"", true); if (!CONFIG::isPasswordValid(parameter.c_str())) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_string(EP_STA_PASSWORD,parameter.c_str())) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -141,14 +179,17 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) parameter = get_param(cmd_params,"", true); if (!CONFIG::isHostnameValid(parameter.c_str())) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_string(EP_HOSTNAME,parameter.c_str())) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -163,15 +204,18 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) mode = AP_MODE; } else { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } if ((mode == CLIENT_MODE) || (mode == AP_MODE)) { #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_byte(EP_WIFI_MODE,mode)) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -187,15 +231,18 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) mode = DHCP_MODE; } else { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } if ((mode == STATIC_IP_MODE) || (mode == DHCP_MODE)) { #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_byte(EP_STA_IP_MODE,mode)) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -207,14 +254,17 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) parameter = get_param(cmd_params,"", true); if (!CONFIG::isSSIDValid(parameter.c_str())) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_string(EP_AP_SSID,parameter.c_str())) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -225,14 +275,17 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) parameter = get_param(cmd_params,"", true); if (!CONFIG::isPasswordValid(parameter.c_str())) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_string(EP_AP_PASSWORD,parameter.c_str())) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } @@ -247,20 +300,64 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) mode = DHCP_MODE; } else { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } if ((mode == STATIC_IP_MODE) || (mode == DHCP_MODE)) { #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif if(!CONFIG::write_byte(EP_AP_IP_MODE,mode)) { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } else { BRIDGE::println(OK_CMD_MSG, output); } } break; + // Set wifi on/off + //[ESP110][pwd=] + case 110: + parameter = get_param(cmd_params,"", true); + if (parameter == "on") { + mode = 1; + } else if (parameter == "off") { + mode = 0; + } else if (parameter == "restart") { + mode = 2; + } else { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } + if (response) { + #ifdef AUTHENTICATION_FEATURE + if (auth_type != LEVEL_ADMIN) { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } else + #endif + if (mode == 0) { + if (WiFi.getMode() !=WIFI_OFF) { + //disable wifi + ESP_SERIAL_OUT.println("M117 Disabling Wifi"); + WiFi.mode(WIFI_OFF); + wifi_config.Disable_servers(); + return response; + } else BRIDGE::println("M117 Wifi already off", output); + } + else if (mode == 1) { //restart device is the best way to start everything clean + if (WiFi.getMode() == WIFI_OFF) { + ESP_SERIAL_OUT.println("M117 Enabling Wifi"); + CONFIG::esp_restart(); + } else BRIDGE::println("M117 Wifi already on", output); + } else { //restart wifi and restart is the best way to start everything clean + ESP_SERIAL_OUT.println("M117 Enabling Wifi"); + CONFIG::esp_restart(); + } + } + break; //Get current IP //[ESP111]
case 111: { @@ -281,7 +378,7 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) //[ESP112]
case 112: { String shost ; - if (!CONFIG::read_string(EP_HOSTNAME, shost , MAX_HOSTNAME_LENGTH)) { + if (!CONFIG::read_string(EP_HOSTNAME, shost, MAX_HOSTNAME_LENGTH)) { shost=wifi_config.get_default_hostname(); } BRIDGE::print(cmd_params, output); @@ -291,108 +388,800 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) LOG("\r\n") } break; - #ifdef DIRECT_PIN_FEATURE //Get/Set pin value //[ESP201]P V - case 201: { - //check if have pin - parameter = get_param(cmd_params,"P", false); - LOG("Pin:") - LOG(parameter) - LOG("\r\n") - if (parameter == "") { + case 201: + parameter = get_param(cmd_params,"", true); +#ifdef AUTHENTICATION_FEATURE + if (auth_type == LEVEL_GUEST) { BRIDGE::println(INCORRECT_CMD_MSG, output); - } else { - int pin = parameter.toInt(); - //check pin is valid and not serial used pins - if ((pin >= 0) && (pin <= 16) && !((pin == 1) || (pin == 3))) { - //check if is set or get - parameter = get_param(cmd_params,"V", false); - //it is a get - if (parameter == "") { - //this is to not set pin mode - parameter = get_param(cmd_params,"RAW=", false); - if (parameter !="YES") - { - parameter = get_param(cmd_params,"PULLUP=", false); - if (parameter == "YES"){ - //GPIO16 is different than others - if (pin <16) { - LOG("Set as input pull up\r\n") - pinMode(pin, INPUT_PULLUP); - } else { - LOG("Set as input pull down 16\r\n") - pinMode(pin, INPUT_PULLDOWN_16); - } - }else { - LOG("Set as input\r\n") - pinMode(pin, INPUT); - } - delay(100); - } - int value = digitalRead(pin); - LOG("Read:"); - BRIDGE::println(String(value).c_str(), output); - } else { - //it is a set - int value = parameter.toInt(); - //verify it is a 0 or a 1 - if ((value == 0) || (value == 1)) { - pinMode(pin, OUTPUT); - delay(10); - LOG("Set:") - LOG(String((value == 0)?LOW:HIGH)) - LOG("\r\n") - digitalWrite(pin, (value == 0)?LOW:HIGH); - } else { - BRIDGE::println(INCORRECT_CMD_MSG, output); - } - } - } else { + response = false; + } else +#endif + { + //check if have pin + parameter = get_param(cmd_params,"P", false); + LOG("Pin:") + LOG(parameter) + LOG("\r\n") + if (parameter == "") { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } else { + int pin = parameter.toInt(); + //check pin is valid and not serial used pins + if ((pin >= 0) && (pin <= 16) && !((pin == 1) || (pin == 3))) { + //check if is set or get + parameter = get_param(cmd_params,"V", false); + //it is a get + if (parameter == "") { + //this is to not set pin mode + parameter = get_param(cmd_params,"RAW=", false); + if (parameter !="YES") { + parameter = get_param(cmd_params,"PULLUP=", false); + if (parameter == "YES") { + //GPIO16 is different than others + if (pin < MAX_GPIO) { + LOG("Set as input pull up\r\n") + pinMode(pin, INPUT_PULLUP); + } +#ifdef ARDUINO_ARCH_ESP8266 + else { + LOG("Set as input pull down 16\r\n") + pinMode(pin, INPUT_PULLDOWN_16); + } +#endif + } else { + LOG("Set as input\r\n") + pinMode(pin, INPUT); + } + delay(100); + } + int value = digitalRead(pin); + LOG("Read:"); + LOG(String(value).c_str()) + LOG("\n"); + BRIDGE::println(String(value).c_str(), output); + } else { + //it is a set + int value = parameter.toInt(); + //verify it is a 0 or a 1 + if ((value == 0) || (value == 1)) { + pinMode(pin, OUTPUT); + delay(10); + LOG("Set:") + LOG(String((value == 0)?LOW:HIGH)) + LOG("\r\n") + digitalWrite(pin, (value == 0)?LOW:HIGH); + BRIDGE::println(OK_CMD_MSG, output); + } else { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } + } + } else { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } } } - } - break; + break; #endif - //Get/Set ESP mode - //cmd is RESET, SAFEMODE, CONFIG, RESTART + //Save data string + //[ESP300]pwd= + case 300: + parameter = get_param(cmd_params,"", true); +#ifdef AUTHENTICATION_FEATURE + if (auth_type == LEVEL_GUEST) { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } else +#endif + { + if(!CONFIG::write_string(EP_DATA_STRING,parameter.c_str())) { + BRIDGE::println(ERROR_CMD_MSG, output); + response = false; + } else { + BRIDGE::println(OK_CMD_MSG, output); + } + } + break; + //get data string + //[ESP301] pwd= + case 301: + parameter = get_param(cmd_params,"", true); +#ifdef AUTHENTICATION_FEATURE + if (auth_type == LEVEL_GUEST) { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } else +#endif + { + char sbuf[MAX_DATA_LENGTH+1]; + if (CONFIG::read_string(EP_DATA_STRING, sbuf, MAX_DATA_LENGTH)) { + BRIDGE::println(sbuf, output); + } else { + BRIDGE::println(F("Error reading data"), output); + } + } + break; + //Get full EEPROM settings content + //[ESP400] + case 400: { + char sbuf[MAX_DATA_LENGTH+1]; + uint8_t ipbuf[4]; + byte bbuf=0; + int ibuf=0; + parameter = get_param(cmd_params,"", true); + delay(0); + //Start JSON + BRIDGE::println(F("{\"EEPROM\":["), output); + if (cmd_params == "network" || cmd_params == "") { + + //1- Baud Rate + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_BAUD_RATE), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"Baud Rate\",\"O\":[{\"9600\":\"9600\"},{\"19200\":\"19200\"},{\"38400\":\"38400\"},{\"57600\":\"57600\"},{\"115200\":\"115200\"},{\"230400\":\"230400\"},{\"250000\":\"250000\"}]}"), output); + BRIDGE::println(F(","), output); + + //2-Sleep Mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_SLEEP_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_SLEEP_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Sleep Mode\",\"O\":[{\"None\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_NONE_SLEEP), output); +#ifdef ARDUINO_ARCH_ESP8266 + BRIDGE::print(F("\"},{\"Light\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_LIGHT_SLEEP), output); +#endif + BRIDGE::print(F("\"},{\"Modem\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_MODEM_SLEEP), output); + BRIDGE::print(F("\"}]}"), output); + BRIDGE::println(F(","), output); + + //3-Web Port + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_WEB_PORT), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_WEB_PORT, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"Web Port\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_WEB_PORT), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_WEB_PORT), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //4-Data Port + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_DATA_PORT), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_DATA_PORT, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"Data Port\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_DATA_PORT), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_DATA_PORT), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); +#ifdef AUTHENTICATION_FEATURE + //5-Admin password + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_ADMIN_PWD), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_ADMIN_PWD, sbuf, MAX_LOCAL_PASSWORD_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print("********", output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_LOCAL_PASSWORD_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"Admin Password\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_LOCAL_PASSWORD_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //6-User password + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_USER_PWD), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_USER_PWD, sbuf, MAX_LOCAL_PASSWORD_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print("********", output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_LOCAL_PASSWORD_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"User Password\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_LOCAL_PASSWORD_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); +#endif + //7-Hostname + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_HOSTNAME), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_HOSTNAME, sbuf, MAX_HOSTNAME_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(sbuf, output); + } + BRIDGE::print(F("\",\"H\":\"Hostname\" ,\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_HOSTNAME_LENGTH), output); + BRIDGE::print(F("\", \"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_HOSTNAME_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //8-wifi mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_WIFI_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_WIFI_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Wifi mode\",\"O\":[{\"AP\":\"1\"},{\"STA\":\"2\"}]}"), output); + BRIDGE::println(F(","), output); + + //9-STA SSID + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_SSID), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_STA_SSID, sbuf, MAX_SSID_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(sbuf, output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_SSID_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"Station SSID\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_SSID_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //10-STA password + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_PASSWORD), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_STA_PASSWORD, sbuf, MAX_PASSWORD_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print("********", output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_PASSWORD_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"Station Password\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_PASSWORD_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //11-Station Network Mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_PHY_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_STA_PHY_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Station Network Mode\",\"O\":[{\"11b\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11B), output); + BRIDGE::print(F("\"},{\"11g\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11G), output); + BRIDGE::print(F("\"},{\"11n\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11N), output); + BRIDGE::print(F("\"}]}"), output); + BRIDGE::println(F(","), output); + + //12-STA IP mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_IP_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_STA_IP_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Station IP Mode\",\"O\":[{\"DHCP\":\"1\"},{\"Static\":\"2\"}]}"), output); + BRIDGE::println(F(","), output); + + //13-STA static IP + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_IP_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_STA_IP_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"Station Static IP\"}"), output); + BRIDGE::println(F(","), output); + + //14-STA static Mask + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_MASK_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_STA_MASK_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"Station Static Mask\"}"), output); + BRIDGE::println(F(","), output); + + //15-STA static Gateway + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_STA_GATEWAY_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_STA_GATEWAY_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"Station Static Gateway\"}"), output); + BRIDGE::println(F(","), output); + + //16-AP SSID + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_SSID), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_AP_SSID, sbuf, MAX_SSID_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(sbuf, output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_SSID_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"AP SSID\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_SSID_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //17-AP password + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_PASSWORD), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_AP_PASSWORD, sbuf, MAX_PASSWORD_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print("********", output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_PASSWORD_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"AP Password\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_PASSWORD_LENGTH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //18 - AP Network Mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_PHY_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_AP_PHY_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"AP Network Mode\",\"O\":[{\"11b\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11B), output); + BRIDGE::print(F("\"},{\"11g\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(WIFI_PHY_MODE_11G), output); + BRIDGE::print(F("\"}]}"), output); + BRIDGE::println(F(","), output); + + //19-AP SSID visibility + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_SSID_VISIBLE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_SSID_VISIBLE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"SSID Visible\",\"O\":[{\"No\":\"0\"},{\"Yes\":\"1\"}]}"), output); + BRIDGE::println(F(","), output); + + //20-AP Channel + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_CHANNEL), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_CHANNEL, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"AP Channel\",\"O\":["), output); + for (int i=1; i < 12 ; i++) { + BRIDGE::print(F("{\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(i), output); + BRIDGE::print(F("\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(i), output); + BRIDGE::print(F("\"}"), output); + if (i<11) { + BRIDGE::print(F(","), output); + } + } + BRIDGE::print(F("]}"), output); + BRIDGE::println(F(","), output); + + //21-AP Authentication + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AUTH_TYPE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_AUTH_TYPE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Authentication\",\"O\":[{\"Open\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(AUTH_OPEN), output); + BRIDGE::print(F("\"},{\"WPA\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA_PSK), output); + BRIDGE::print(F("\"},{\"WPA2\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA2_PSK), output); + BRIDGE::print(F("\"},{\"WPA/WPA2\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(AUTH_WPA_WPA2_PSK), output); + BRIDGE::print(F("\"}]}"), output); + BRIDGE::println(F(","), output); + + //22-AP IP mode + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_IP_MODE), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_AP_IP_MODE, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"AP IP Mode\",\"O\":[{\"DHCP\":\"1\"},{\"Static\":\"2\"}]}"), output); + BRIDGE::println(F(","), output); + + //23-AP static IP + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_IP_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_AP_IP_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"AP Static IP\"}"), output); + BRIDGE::println(F(","), output); + + //24-AP static Mask + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_MASK_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_AP_MASK_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"AP Static Mask\"}"), output); + BRIDGE::println(F(","), output); + + //25-AP static Gateway + BRIDGE::print(F("{\"F\":\"network\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_AP_GATEWAY_VALUE), output); + BRIDGE::print(F("\",\"T\":\"A\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_AP_GATEWAY_VALUE,(byte *)ipbuf, IP_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(IPAddress(ipbuf).toString().c_str(), output); + } + BRIDGE::print(F("\",\"H\":\"AP Static Gateway\"}"), output); + delay(0); + } + + if (cmd_params == "printer" || cmd_params == "") { + if (cmd_params == "") { + BRIDGE::println(F(","), output); + } + //Target FW + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_TARGET_FW), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_TARGET_FW, &bbuf )) { + BRIDGE::print("Unknown", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Target FW\",\"O\":[{\"Repetier\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(REPETIER), output); + BRIDGE::print(F("\"},{\"Repetier for Davinci\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(REPETIER4DV), output); + BRIDGE::print(F("\"},{\"Marlin\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MARLIN), output); + BRIDGE::print(F("\"},{\"Marlin Kimbra\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MARLINKIMBRA), output); + BRIDGE::print(F("\"},{\"Smoothieware\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(SMOOTHIEWARE), output); + BRIDGE::print(F("\"},{\"Unknown\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(UNKNOWN_FW), output); + BRIDGE::print(F("\"}]}"), output); + BRIDGE::println(F(","), output); + + //Refresh time 1 + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_REFRESH_PAGE_TIME), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_REFRESH_PAGE_TIME, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Temperature Refresh Time\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_REFRESH), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_REFRESH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //Refresh time 2 + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_REFRESH_PAGE_TIME2), output); + BRIDGE::print(F("\",\"T\":\"B\",\"V\":\""), output); + if (!CONFIG::read_byte(EP_REFRESH_PAGE_TIME2, &bbuf )) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(bbuf), output); + } + BRIDGE::print(F("\",\"H\":\"Position Refresh Time\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_REFRESH), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_REFRESH), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //XY feedrate + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_XY_FEEDRATE), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_XY_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"XY feedrate\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_XY_FEEDRATE), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_XY_FEEDRATE), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //Z feedrate + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_Z_FEEDRATE), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_Z_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"Z feedrate\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_Z_FEEDRATE), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_Z_FEEDRATE), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //E feedrate + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_E_FEEDRATE), output); + BRIDGE::print(F("\",\"T\":\"I\",\"V\":\""), output); + if (!CONFIG::read_buffer(EP_E_FEEDRATE, (byte *)&ibuf, INTEGER_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print((const char *)CONFIG::intTostr(ibuf), output); + } + BRIDGE::print(F("\",\"H\":\"E feedrate\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MAX_E_FEEDRATE), output); + BRIDGE::print(F("\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(DEFAULT_MIN_E_FEEDRATE), output); + BRIDGE::print(F("\"}"), output); + BRIDGE::println(F(","), output); + + //Camera address, data string + BRIDGE::print(F("{\"F\":\"printer\",\"P\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(EP_DATA_STRING), output); + BRIDGE::print(F("\",\"T\":\"S\",\"V\":\""), output); + if (!CONFIG::read_string(EP_DATA_STRING, sbuf, MAX_DATA_LENGTH)) { + BRIDGE::print("???", output); + } else { + BRIDGE::print(sbuf, output); + } + BRIDGE::print(F("\",\"S\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MAX_DATA_LENGTH), output); + BRIDGE::print(F("\",\"H\":\"Camera address\",\"M\":\""), output); + BRIDGE::print((const char *)CONFIG::intTostr(MIN_DATA_LENGTH), output); + BRIDGE::print(F("\"}"), output); + } + + //end JSON + BRIDGE::println(F("\n]}"), output); + delay(0); + } + break; + + //Set EEPROM setting + //[ESP401]P= T= V= pwd= + case 401: { + //check validity of parameters + String spos = get_param(cmd_params,"P=", false); + String styp = get_param(cmd_params,"T=", false); + String sval = get_param(cmd_params,"V=", true); + sval.trim(); + int pos = spos.toInt(); + if ((pos == 0 && spos != "0") || (pos > LAST_EEPROM_ADDRESS || pos < 0)) { + response = false; + } + if (!(styp == "B" || styp == "S" || styp == "A" || styp == "I")) { + response = false; + } + if (sval.length() == 0) { + response = false; + } + + +#ifdef AUTHENTICATION_FEATURE + if (response) { + //check authentication + level_authenticate_type auth_need = LEVEL_ADMIN; + for (int i = 0; i < AUTH_ENTRY_NB; i++) { + if (Setting[i][0] == pos ) { + auth_need = (level_authenticate_type)(Setting[i][1]); + i = AUTH_ENTRY_NB; + } + } + if ((auth_need == LEVEL_ADMIN && auth_type == LEVEL_USER) || (auth_type == LEVEL_GUEST)) { + response = false; + } + } +#endif + if (response) { + if (styp == "B") { + byte bbuf = sval.toInt(); + if(!CONFIG::write_byte(pos,bbuf)) { + response = false; + } else { + //dynamique refresh is better than restart the board + if (pos == EP_TARGET_FW)CONFIG::InitFirmwareTarget(); + if (pos == EP_IS_DIRECT_SD){ + CONFIG::InitDirectSD(); + if (CONFIG::is_direct_sd) CONFIG::InitPins(); + } + } + } + if (styp == "I") { + int ibuf = sval.toInt(); + if(!CONFIG::write_buffer(pos,(const byte *)&ibuf,INTEGER_LENGTH)) { + response = false; + } + } + if (styp == "S") { + if(!CONFIG::write_string(pos,sval.c_str())) { + response = false; + } + } + if (styp == "A") { + byte ipbuf[4]; + if (CONFIG::split_ip(sval.c_str(),ipbuf) < 4) { + response = false; + } else if(!CONFIG::write_buffer(pos,ipbuf,IP_LENGTH)) { + response = false; + } + } + } + if(!response) { + BRIDGE::println(INCORRECT_CMD_MSG, output); + } else { + BRIDGE::println(OK_CMD_MSG, output); + } + + } + break; + + //Get available AP list (limited to 30) + //output is JSON or plain text according parameter + //[ESP410] + case 410: { + parameter = get_param(cmd_params,"", true); + int n = WiFi.scanNetworks(); + bool plain = parameter == "plain"; + if (!plain)BRIDGE::print(F("{\"AP_LIST\":["), output); + for (int i = 0; i < n; ++i) { + if (i>0) { + if (!plain) BRIDGE::print(F(","), output); + else BRIDGE::print(F("\n"), output); + } + if (!plain)BRIDGE::print(F("{\"SSID\":\""), output); + BRIDGE::print(WiFi.SSID(i).c_str(), output); + if (!plain)BRIDGE::print(F("\",\"SIGNAL\":\""), output); + else BRIDGE::print(F("\t"), output); + BRIDGE::print(CONFIG::intTostr(wifi_config.getSignal(WiFi.RSSI(i))), output);; + //BRIDGE::print(F("%"), output); + if (!plain)BRIDGE::print(F("\",\"IS_PROTECTED\":\""), output); + if (WiFi.encryptionType(i) == ENC_TYPE_NONE) { + if (!plain)BRIDGE::print(F("0"), output); + else BRIDGE::print(F("\tOpen"), output); + } else { + if (!plain)BRIDGE::print(F("1"), output); + else BRIDGE::print(F("\tSecure"), output); + } + if (!plain)BRIDGE::print(F("\"}"), output); + } + if (!plain)BRIDGE::print(F("]}"), output); + WiFi.scanDelete(); + } + break; + //Get ESP current status in plain or JSON + //[ESP420] + case 420: { + parameter = get_param(cmd_params,"", true); + CONFIG::print_config(output, (parameter == "plain")); + } + break; + //Set ESP mode + //cmd is RESET, SAFEMODE, RESTART //[ESP444]pwd= case 444: parameter = get_param(cmd_params,"", true); #ifdef AUTHENTICATION_FEATURE - if (!isadmin(cmd_params)) { + if (auth_type != LEVEL_ADMIN) { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } else #endif { if (parameter=="RESET") { CONFIG::reset_config(); - } - if (parameter=="SAFEMODE") { + BRIDGE::println(F("Reset done - restart needed"), output); + } else if (parameter=="SAFEMODE") { wifi_config.Safe_Setup(); - } - if (parameter=="RESTART") { + BRIDGE::println(F("Set Safe Mode - restart needed"), output); + } else if (parameter=="RESTART") { + BRIDGE::println(F("Restart started"), output); + BRIDGE::flush( output); CONFIG::esp_restart(); + } else { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } } - if (parameter=="CONFIG") { - CONFIG::print_config(output); - } break; #ifdef AUTHENTICATION_FEATURE //Change / Reset user password //[ESP555]pwd= case 555: { - if (isadmin(cmd_params)) { + if (auth_type == LEVEL_ADMIN) { parameter = get_param(cmd_params,"", true); if (parameter.length() == 0) { if(CONFIG::write_string(EP_USER_PWD,FPSTR(DEFAULT_USER_PWD))) { BRIDGE::println(OK_CMD_MSG, output); } else { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } } else { if (CONFIG::isLocalPasswordValid(parameter.c_str())) { @@ -400,13 +1189,16 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) BRIDGE::println(OK_CMD_MSG, output); } else { BRIDGE::println(ERROR_CMD_MSG, output); + response = false; } } else { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } } } else { BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } break; } @@ -421,71 +1213,159 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) if ((cmd_params.length() > 0) && (cmd_params[0] != '/')) { cmd_params = "/" + cmd_params; } - FSFILE currentfile = SPIFFS.open(cmd_params, "r"); + FS_FILE currentfile = SPIFFS.open(cmd_params, SPIFFS_FILE_READ); if (currentfile) {//if file open success //flush to be sure send buffer is empty - Serial.flush(); + ESP_SERIAL_OUT.flush(); //read content String currentline = currentfile.readString(); //until no line in file while (currentline.length() >0) { - //send line to serial - Serial.println(currentline); - //flush to be sure send buffer is empty - delay(0); - Serial.flush(); + int ESPpos = currentline.indexOf("[ESP"); + if (ESPpos>-1) { + //is there the second part? + int ESPpos2 = currentline.indexOf("]",ESPpos); + if (ESPpos2>-1) { + //Split in command and parameters + String cmd_part1=currentline.substring(ESPpos+4,ESPpos2); + String cmd_part2=""; + //is there space for parameters? + if (ESPpos2 + case 710: + parameter = get_param(cmd_params,"", true); +#ifdef AUTHENTICATION_FEATURE + if (auth_type != LEVEL_ADMIN) { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } else +#endif + { + if (parameter=="FORMAT") { + BRIDGE::print(F("Formating"), output); + //SPIFFS.end(); + delay(0); + SPIFFS.format(); + //SPIFFS.begin(); + BRIDGE::println(F("...Done"), output); + } else { + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; + } + } + break; + //SPIFFS total size and used size + //[ESP720]
+ case 720: + BRIDGE::print(cmd_params, output); +#ifdef ARDUINO_ARCH_ESP8266 + fs::FSInfo info; + SPIFFS.info(info); + BRIDGE::print("SPIFFS Total:", output); + BRIDGE::print(CONFIG::formatBytes(info.totalBytes).c_str(), output); + BRIDGE::print(" Used:", output); + BRIDGE::println(CONFIG::formatBytes(info.usedBytes).c_str(), output); +#else + BRIDGE::print("SPIFFS Total:", output); + BRIDGE::print(CONFIG::formatBytes(SPIFFS.totalBytes()).c_str(), output); + BRIDGE::print(" Used:", output); + BRIDGE::println(CONFIG::formatBytes(SPIFFS.usedBytes()).c_str(), output); +#endif + break; + //get fw version firmare target and fw version //[ESP800]
case 800: + { + byte sd_dir = 0; BRIDGE::print(cmd_params, output); - BRIDGE::print("FW version:", output); - BRIDGE::println(FW_VERSION, output); + BRIDGE::print(F("FW version:"), output); + BRIDGE::print(FW_VERSION, output); + BRIDGE::print(F(" # FW target:"), output); + BRIDGE::print(CONFIG::GetFirmwareTargetShortName(), output); + BRIDGE::print(F(" # FW HW:"), output); + if (CONFIG::is_direct_sd) BRIDGE::print(F("Direct SD"), output); + else BRIDGE::print(F("Serial SD"), output); + BRIDGE::print(F(" # primary sd:"), output); + if (!CONFIG::read_byte(EP_PRIMARY_SD, &sd_dir )) sd_dir = DEFAULT_PRIMARY_SD; + if (sd_dir == SD_DIRECTORY) BRIDGE::print(F("/sd/"), output); + else if (sd_dir == EXT_DIRECTORY) BRIDGE::print(F("/ext/"), output); + else BRIDGE::print(F("none"), output); + BRIDGE::print(F(" # secondary sd:"), output); + if (!CONFIG::read_byte(EP_SECONDARY_SD, &sd_dir )) sd_dir = DEFAULT_SECONDARY_SD; + if (sd_dir == SD_DIRECTORY) BRIDGE::print(F("/sd/"), output); + else if (sd_dir == EXT_DIRECTORY) BRIDGE::print(F("/ext/"), output); + else BRIDGE::print(F("none"), output); + BRIDGE::print(F(" # authentication:"), output); +#ifdef AUTHENTICATION_FEATURE + BRIDGE::print(F("yes"), output); +#else + BRIDGE::print(F("no"), output); +#endif + BRIDGE::println("", output); + } break; //get fw target //[ESP801]
case 801: BRIDGE::print(cmd_params, output); -#if FIRMWARE_TARGET == REPETIER - BRIDGE::println("Repetier", output); -#endif -#if FIRMWARE_TARGET == REPETIER4DV - BRIDGE::println("Repetier_Davinci", output); -#endif -#if FIRMWARE_TARGET == MARLIN - BRIDGE::println("Marlin", output); -#endif -#if FIRMWARE_TARGET == MARLINKIMBRA - BRIDGE::println("Marlin_Kimbra", output); -#endif -#if FIRMWARE_TARGET == SMOOTHIEWARE - BRIDGE::println("Smoothieware", output); -#endif + BRIDGE::println(CONFIG::GetFirmwareTargetShortName(), output); break; //clear status/error/info list + case 802: + if (CONFIG::check_update_presence( )) BRIDGE::println("yes", output); + else BRIDGE::println("no", output); + break; //[ESP999] case 999: cmd_params.trim(); #ifdef ERROR_MSG_FEATURE if (cmd_params=="ERROR") { web_interface->error_msg.clear(); + BRIDGE::println(OK_CMD_MSG, output); + break; } #endif #ifdef INFO_MSG_FEATURE if (cmd_params=="INFO") { web_interface->info_msg.clear(); + BRIDGE::println(OK_CMD_MSG, output); + break; } #endif #ifdef STATUS_MSG_FEATURE if (cmd_params=="STATUS") { web_interface->status_msg.clear(); + BRIDGE::println(OK_CMD_MSG, output); + break; } #endif if (cmd_params=="ALL") { @@ -498,10 +1378,14 @@ void COMMAND::execute_command(int cmd,String cmd_params, tpipe output) #ifdef INFO_MSG_FEATURE web_interface->info_msg.clear(); #endif + BRIDGE::println(OK_CMD_MSG, output); + break; } - break; - //default: + default: + BRIDGE::println(INCORRECT_CMD_MSG, output); + response = false; } + return response; } bool COMMAND::check_command(String buffer, tpipe output, bool handlelockserial) @@ -511,82 +1395,55 @@ bool COMMAND::check_command(String buffer, tpipe output, bool handlelockserial) LOG(buffer) LOG("\r\n") bool is_temp = false; + if ((buffer.indexOf("T:") > -1 ) || (buffer.indexOf("B:") > -1 )) is_temp = true; //feed the WD for safety delay(0); -#if ((FIRMWARE_TARGET == REPETIER) || (FIRMWARE_TARGET == REPETIER4DV)) - //save time no need to continue - if ((buffer.indexOf("busy:") > -1) || (buffer.startsWith("wait")))return false; - if (buffer.startsWith("ok"))return false; -#endif -//if direct access to SDCard no need to handle the M20 command answer -#ifndef DIRECT_SDCARD_FEATURE - static bool bfileslist=false; - static uint32_t start_list=0; - //if SD list is not on going - if (!bfileslist) { - //check if command is a start of SD File list - LOG("No File list ongoing\r\n") - int filesstart = buffer.indexOf("egin file list"); - //yes it is file list starting to be displayed - if (filesstart>-1) { - LOG("Found start File list\r\n") - //init time out - start_list = millis(); - //set file list started - bfileslist=true; - //clear current list - web_interface->fileslist.clear(); - //block any new output to serial from ESP to avoid pollution - if (handlelockserial)(web_interface->blockserial) = true; - return is_temp; + if (( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER)) { + //save time no need to continue + if ((buffer.indexOf("busy:") > -1) || (buffer.startsWith("wait"))) { + return false; } -#endif - int Tpos = buffer.indexOf("T:"); - if (Tpos > -1 ) is_temp = true; -#ifdef POS_MONITORING_FEATURE - int Xpos = buffer.indexOf("X:"); - int Ypos = buffer.indexOf("Y:"); - int Zpos = buffer.indexOf("Z:"); -#endif -#if FIRMWARE_TARGET == SMOOTHIEWARE - int Bpos = buffer.indexOf("B:"); - if (Bpos > -1 ) is_temp = true; -#ifdef SPEED_MONITORING_FEATURE - int Speedpos = buffer.indexOf("Speed factor at "); -#endif -#ifdef FLOW_MONITORING_FEATURE - int Flowpos = buffer.indexOf("Flow rate at "); -#endif + if (buffer.startsWith("ok")) { + return false; + } + } #ifdef ERROR_MSG_FEATURE - int Errorpos= buffer.indexOf("error:"); + int Errorpos = -1; #endif #ifdef INFO_MSG_FEATURE - int Infopos= buffer.indexOf("info:"); + int Infopos = -1; #endif #ifdef STATUS_MSG_FEATURE - int Statuspos= buffer.indexOf("warning:"); -#endif -#else -#ifdef SPEED_MONITORING_FEATURE - int Speedpos = buffer.indexOf("SpeedMultiply:"); -#endif -#ifdef FLOW_MONITORING_FEATURE - int Flowpos = buffer.indexOf("FlowMultiply:"); + int Statuspos = -1; #endif +if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE) { #ifdef ERROR_MSG_FEATURE - int Errorpos= buffer.indexOf("Error:"); + Errorpos= buffer.indexOf("error:"); #endif #ifdef INFO_MSG_FEATURE - int Infopos= buffer.indexOf("Info:"); + Infopos= buffer.indexOf("info:"); #endif #ifdef STATUS_MSG_FEATURE -#if FIRMWARE_TARGET == MARLIN - int Statuspos= buffer.indexOf("echo:"); -#else - int Statuspos= buffer.indexOf("Status:"); + Statuspos= buffer.indexOf("warning:"); #endif +} else { +#ifdef ERROR_MSG_FEATURE + Errorpos= buffer.indexOf("Error:"); #endif +#ifdef INFO_MSG_FEATURE + Infopos= buffer.indexOf("Info:"); #endif +#ifdef STATUS_MSG_FEATURE + Statuspos= -1; + if (CONFIG::GetFirmwareTarget() == MARLIN){ + Statuspos= buffer.indexOf("echo:"); + } + else { + Statuspos= buffer.indexOf("Status:"); + } + +#endif +} #ifdef SERIAL_COMMAND_FEATURE String ESP_Command; @@ -610,67 +1467,6 @@ bool COMMAND::check_command(String buffer, tpipe output, bool handlelockserial) } } #endif -#ifdef TEMP_MONITORING_FEATURE - //check for temperature - if (Tpos>-1) { - //look for valid temperature answer - int slashpos = buffer.indexOf(" /",Tpos); - int spacepos = buffer.indexOf(" ",slashpos+1); - //if match mask T:xxx.xx /xxx.xx - if(spacepos-Tpos < 17) { - web_interface->answer4M105=buffer; //do not interprete just need when requested so store it - web_interface->last_temp=millis(); - } else { - LOG("Not a T temp") - } - } -#if FIRMWARE_TARGET == SMOOTHIEWARE - else if (Bpos > -1 ){ - //look for valid temperature answer - int slashpos = buffer.indexOf(" /",Bpos); - int spacepos = buffer.indexOf(" ",slashpos+1); - //if match mask B:xxx.xx /xxx.xx - if(spacepos-Bpos < 17) { - web_interface->answer4M105=buffer; //do not interprete just need when requested so store it - web_interface->last_temp=millis(); - } else { - LOG("Not a B temp") - } - } -#endif -#endif -#ifdef POS_MONITORING_FEATURE - //Position of axis - if (Xpos>-1 && Ypos>-1 && Zpos>-1) { - web_interface->answer4M114=buffer; - } -#endif -#ifdef SPEED_MONITORING_FEATURE - //Speed - if (Speedpos>-1) { - //get just the value -#if FIRMWARE_TARGET == SMOOTHIEWARE - buffer2 =buffer.substring(Speedpos+16); - int p2 = buffer2.indexOf("."); - web_interface->answer4M220=buffer2.substring(0,p2); -#else - web_interface->answer4M220=buffer.substring(Speedpos+14); -#endif - } -#endif -#ifdef FLOW_MONITORING_FEATURE - //Flow - if (Flowpos>-1) { - //get just the value -#if FIRMWARE_TARGET == SMOOTHIEWARE - buffer2 =buffer.substring(Flowpos+13); - int p2 = buffer2.indexOf("."); - web_interface->answer4M221=buffer2.substring(0,p2); -#else - web_interface->answer4M221=buffer.substring(Flowpos+13); -#endif - } -#endif #ifdef ERROR_MSG_FEATURE //Error if (Errorpos>-1 && !(buffer.indexOf("Format error")!=-1 || buffer.indexOf("wait")==Errorpos+6) ) { @@ -692,47 +1488,16 @@ bool COMMAND::check_command(String buffer, tpipe output, bool handlelockserial) #ifdef STATUS_MSG_FEATURE //Status if (Statuspos>-1) { -#if FIRMWARE_TARGET == SMOOTHIEWARE - String ss = buffer.substring(Errorpos+8); -#else -#if FIRMWARE_TARGET == MARLIN - String ss = buffer.substring(Errorpos+5); -#else - String ss = buffer.substring(Errorpos+7); -#endif -#endif + String ss ; + if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE)ss = buffer.substring(Errorpos+8); + else if (CONFIG::GetFirmwareTarget() == MARLIN) ss = buffer.substring(Errorpos+5); + else ss = buffer.substring(Errorpos+7); ss.replace("\"",""); ss.replace("'",""); (web_interface->info_msg).add(ss.c_str()); } #endif -#ifndef DIRECT_SDCARD_FEATURE - } else { //listing file is on going - LOG("File list is ongoing\r\n") - //check if we are too long - if ((millis()-start_list)>30000) { //timeout in case of problem - bfileslist=false; - if(handlelockserial)(web_interface->blockserial) = false; //release serial - LOG("Time out\r\n"); - } else { - //check if this is the end - if (buffer.indexOf("nd file list")>-1) { - LOG("End File list detected\r\n") - bfileslist=false; - if(handlelockserial)(web_interface->blockserial) = false; - LOG("End list\r\n"); - } else { - //Serial.print(buffer); - //add list to buffer - web_interface->fileslist.add(buffer); - LOG(String(web_interface->fileslist.size())); - LOG(":"); - LOG(buffer); - LOG("\r\n"); - } - } - } -#endif + return is_temp; } @@ -781,7 +1546,6 @@ void COMMAND::read_buffer_tcp(uint8_t b) } } #endif - //read buffer as char void COMMAND::read_buffer_serial(uint8_t b) { diff --git a/esp3d/command.h b/esp3d/command.h index f6793548..2c055648 100644 --- a/esp3d/command.h +++ b/esp3d/command.h @@ -34,10 +34,10 @@ public: static void read_buffer_tcp(uint8_t b); #endif static bool check_command(String buffer, tpipe output, bool handlelockserial = true); - static void execute_command(int cmd,String cmd_params, tpipe output); + static bool execute_command(int cmd,String cmd_params, tpipe output, level_authenticate_type auth_level = LEVEL_GUEST); static String get_param(String & cmd_params, const char * id, bool withspace = false); static bool isadmin(String & cmd_params); - + static bool isuser(String & cmd_params); }; #endif diff --git a/esp3d/config.cpp b/esp3d/config.cpp index 2a58fd5b..a7733620 100644 --- a/esp3d/config.cpp +++ b/esp3d/config.cpp @@ -19,18 +19,697 @@ */ #include "config.h" #include -#include "wifi.h" +#ifndef FS_NO_GLOBALS +#define FS_NO_GLOBALS +#endif +#include +#include +#include "wificonf.h" +#ifdef ARDUINO_ARCH_ESP8266 extern "C" { #include "user_interface.h" } +#else +#include "Update.h" +#include "esp_wifi.h" +#endif #include "bridge.h" +#ifdef ARDUINO_ARCH_ESP32 +//This is output for ESP32 to avoid garbage +HardwareSerial Serial2(2); +#endif + +uint8_t CONFIG::FirmwareTarget = UNKNOWN_FW; + +bool CONFIG::SetFirmwareTarget(uint8_t fw){ + if ( fw >= 0 && fw <= MAX_FW_ID) { + FirmwareTarget = fw; + return true; + } else return false; +} +uint8_t CONFIG::GetFirmwareTarget() { + return FirmwareTarget; +} +const char* CONFIG::GetFirmwareTargetName() { + static String response; + if ( CONFIG::FirmwareTarget == REPETIER4DV)response = F("Repetier for Davinci"); + else if ( CONFIG::FirmwareTarget == REPETIER)response = F("Repetier"); + else if ( CONFIG::FirmwareTarget == MARLIN) response = F("Marlin"); + else if ( CONFIG::FirmwareTarget == MARLINKIMBRA) response = F("MarlinKimbra"); + else if ( CONFIG::FirmwareTarget == SMOOTHIEWARE) response = F("Smoothieware"); + else response = F("???"); + return response.c_str(); +} + +const char* CONFIG::GetFirmwareTargetShortName() { + static String response; + if ( CONFIG::FirmwareTarget == REPETIER4DV)response = F("repetier4davinci"); + else if ( CONFIG::FirmwareTarget == REPETIER)response = F("repetier"); + else if ( CONFIG::FirmwareTarget == MARLIN) response = F("marlin"); + else if ( CONFIG::FirmwareTarget == MARLINKIMBRA) response = F("marlinkimbra"); + else if ( CONFIG::FirmwareTarget == SMOOTHIEWARE) response = F("smoothieware"); + else response = F("???"); + return response.c_str(); +} + +void CONFIG::InitFirmwareTarget(){ + uint8_t b = UNKNOWN_FW; + if (!CONFIG::read_byte(EP_TARGET_FW, &b )) { + b = UNKNOWN_FW; + } + if (!SetFirmwareTarget(b))SetFirmwareTarget(UNKNOWN_FW) ; +} + +void CONFIG::InitDirectSD(){ + CONFIG::is_direct_sd = false; + +} + +bool CONFIG::InitBaudrate(){ + long baud_rate=0; + if ( !CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&baud_rate, INTEGER_LENGTH)) return false; + if ( ! (baud_rate==9600 || baud_rate==19200 ||baud_rate==38400 ||baud_rate==57600 ||baud_rate==115200 ||baud_rate==230400 ||baud_rate==250000) ) return false; + //setup serial + if (ESP_SERIAL_OUT.baudRate() != baud_rate)ESP_SERIAL_OUT.begin(baud_rate); +#ifdef ARDUINO_ARCH_ESP8266 + ESP_SERIAL_OUT.setRxBufferSize(SERIAL_RX_BUFFER_SIZE); +#endif + wifi_config.baud_rate=baud_rate; + delay(1000); + return true; +} + +bool CONFIG::InitExternalPorts(){ + if (!CONFIG::read_buffer(EP_WEB_PORT, (byte *)&(wifi_config.iweb_port), INTEGER_LENGTH) || !CONFIG::read_buffer(EP_DATA_PORT, (byte *)&(wifi_config.idata_port), INTEGER_LENGTH)) return false; + if (wifi_config.iweb_port < DEFAULT_MIN_WEB_PORT ||wifi_config.iweb_port > DEFAULT_MAX_WEB_PORT || wifi_config.idata_port < DEFAULT_MIN_DATA_PORT || wifi_config.idata_port > DEFAULT_MAX_DATA_PORT) return false; + return true; +} + +#ifdef SDCARD_CONFIG_FEATURE +bool CONFIG::update_settings(){ + String filename = SDCARD_CONFIG_FILENAME; + filename.toLowerCase(); + //there is a config file + LOG("Check ") + LOG(filename) + LOG("\r\n") + bool answer = true; + if(SD.exists((const char *)filename.c_str())) { + bool success = true; + bool localerror = false; + const size_t bufferLen = 250; + char buffer[bufferLen]; + byte ip_sav[4]; + String stmp; + int itmp; + long baud_rate=0; + byte bflag; + LOG("Found config file\r\n") + String newfilename = filename; + IniFile espconfig((char *)filename.c_str()); + //validate file is correct + if (espconfig.open()) { + if (!espconfig.validate(buffer, bufferLen)) { + success = false; + LOG("Invalid config file\r\n") + } else { //file format is correct - let parse the settings + //Section [wifi] + //Hostname + //hostname = myesp + if (espconfig.getValue("network", "hostname", buffer, bufferLen)) { + if (!CONFIG::isHostnameValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_HOSTNAME,buffer)) { + success = false; + } + } + //baudrate = 115200 + if (espconfig.getValue("network", "baudrate", buffer, bufferLen, baud_rate)) { + if(!CONFIG::write_buffer(EP_BAUD_RATE,(const byte *)&baud_rate,INTEGER_LENGTH)) { + success = false; + } + } + //webport = 80 + if (espconfig.getValue("network", "webport", buffer, bufferLen, itmp)) { + if(!CONFIG::write_buffer(EP_WEB_PORT,(const byte *)&itmp,INTEGER_LENGTH)) { + success = false; + } + } + //dataport = 8888 + if (espconfig.getValue("network", "dataport", buffer, bufferLen, itmp)) { + if(!CONFIG::write_buffer(EP_DATA_PORT,(const byte *)&itmp,INTEGER_LENGTH)) { + success = false; + } + } + //adminpwd = admin + if (espconfig.getValue("network", "adminpwd", buffer, bufferLen)) { + if (!CONFIG::isLocalPasswordValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_ADMIN_PWD,buffer)) { + success = false; + } + } + //userpwd = user + if (espconfig.getValue("network", "userpwd", buffer, bufferLen)) { + if (!CONFIG::isLocalPasswordValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_USER_PWD,buffer)) { + success = false; + } + } + //sleep = none + if (espconfig.getValue("network", "sleep", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="none") { + bflag = WIFI_NONE_SLEEP; +#ifdef ARDUINO_ARCH_ESP8266 + } else if (stmp =="light") { + bflag = WIFI_LIGHT_SLEEP; +#endif + } else if (stmp =="modem") { + bflag = WIFI_MODEM_SLEEP; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_SLEEP_MODE,bflag)) { + success = false; + } + } + } + //wifimode = STA + if (espconfig.getValue("network", "wifimode", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="sta") { + bflag = CLIENT_MODE; + } else if (stmp =="ap") { + bflag = AP_MODE; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_WIFI_MODE,bflag)) { + success = false; + } + } + } + //STAssid = NETGEAR_2GEXT_OFFICE2 + if (espconfig.getValue("network", "STAssid", buffer, bufferLen)) { + if (!CONFIG::isSSIDValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_STA_SSID,buffer)) { + success = false; + } + } + //STApassword = mypassword + if (espconfig.getValue("network", "STApassword", buffer, bufferLen)) { + if (!CONFIG::isPasswordValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_STA_PASSWORD,buffer)) { + success = false; + } + } + //STAipmode = DHCP + if (espconfig.getValue("network", "STAipmode", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="dhcp") { + bflag = DHCP_MODE; + } else if (stmp =="static") { + bflag = STATIC_IP_MODE; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_STA_IP_MODE,bflag)) { + success = false; + } + } + } + //STAstatic_ip = 192.168.0.1 + if (espconfig.getValue("network", "STAstatic_ip", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_STA_IP_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //STAstatic_mask = 255.255.255.0 + if (espconfig.getValue("network", "STAstatic_mask", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_STA_MASK_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //STAstatic_gateway = 192.168.0.1 + if (espconfig.getValue("network", "STAstatic_gateway", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_STA_GATEWAY_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //STANetwork_mode = 11g + if (espconfig.getValue("network", "STANetwork_mode", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="11b") { + bflag = WIFI_PHY_MODE_11B; + } else if (stmp =="11g") { + bflag = WIFI_PHY_MODE_11G; + } else if (stmp =="11n") { + bflag = WIFI_PHY_MODE_11N; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_STA_PHY_MODE,bflag)) { + success = false; + } + } + } + //APssid = NETGEAR_2GEXT_OFFICE2 + if (espconfig.getValue("network", "APssid", buffer, bufferLen)) { + if (!CONFIG::isSSIDValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_AP_SSID,buffer)) { + success = false; + } + } + //APpassword = 12345678 + if (espconfig.getValue("network", "APpassword", buffer, bufferLen)) { + if (!CONFIG::isPasswordValid(buffer)) { + success = false; + } else if(!CONFIG::write_string(EP_AP_PASSWORD,buffer)) { + success = false; + } + } + //APipmode = STATIC + if (espconfig.getValue("network", "APipmode", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="dhcp") { + bflag = DHCP_MODE; + } else if (stmp =="static") { + bflag = STATIC_IP_MODE; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_AP_IP_MODE,bflag)) { + success = false; + } + } + } + //APstatic_ip = 192.168.0.1 + if (espconfig.getValue("network", "APstatic_ip", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_AP_IP_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //APstatic_mask = 255.255.255.0 + if (espconfig.getValue("network", "APstatic_mask", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_AP_MASK_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //APstatic_gateway = 192.168.0.1 + if (espconfig.getValue("network", "APstatic_gateway", buffer, bufferLen)) { + if (!CONFIG::isIPValid(buffer)) { + success = false; + } else { + CONFIG::split_ip(buffer,ip_sav); + if(!CONFIG::write_buffer(EP_AP_GATEWAY_VALUE,ip_sav,IP_LENGTH)) { + success = false; + } + } + } + //AP_channel = 1 + if (espconfig.getValue("network", "AP_channel", buffer, bufferLen, itmp)) { + bflag = itmp; + if(!CONFIG::write_byte(EP_CHANNEL,bflag)) { + success = false; + } + } + //AP_visible = yes + if (espconfig.getValue("network", "AP_visible", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="yes") { + bflag = 1; + } else if (stmp =="no") { + bflag = 0; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_SSID_VISIBLE,bflag)) { + success = false; + } + } + } + //AP_auth = WPA + if (espconfig.getValue("network", "AP_auth", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="open") { + bflag = AUTH_OPEN; + } else if (stmp =="wpa") { + bflag = AUTH_WPA_PSK; + } else if (stmp =="wpa2") { + bflag = AUTH_WPA2_PSK; + } else if (stmp =="wpa_wpa2") { + bflag = AUTH_WPA_WPA2_PSK; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_AUTH_TYPE,bflag)) { + success = false; + } + } + } + //APNetwork_mode = 11g + if (espconfig.getValue("network", "APNetwork_mode", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="11b") { + bflag = WIFI_PHY_MODE_11B; + } else if (stmp =="11g") { + bflag = WIFI_PHY_MODE_11G; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_AP_PHY_MODE,bflag)) { + success = false; + } + } + } + + //Timezone + if (espconfig.getValue("network", "time_zone", buffer, bufferLen, itmp)) { + bflag = itmp; + if(!CONFIG::write_byte(EP_TIMEZONE,bflag)) { + success = false; + } + } + + //day saving time + if (espconfig.getValue("network", "day_st", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="yes") { + bflag = 1; + } else if (stmp =="no") { + bflag = 0; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_TIME_ISDST,bflag)) { + success = false; + } + } + } + //time server 1 + if (espconfig.getValue("network", "time_server_1", buffer, bufferLen)) { + if (strlen(buffer) > 128) { + success = false; + } else if(!CONFIG::write_string(EP_TIME_SERVER1,buffer)) { + success = false; + } + } + + //time server 2 + if (espconfig.getValue("network", "time_server_2", buffer, bufferLen)) { + if (strlen(buffer) > 128) { + success = false; + } else if(!CONFIG::write_string(EP_TIME_SERVER2,buffer)) { + success = false; + } + } + + //time server 3 + if (espconfig.getValue("network", "time_server_3", buffer, bufferLen)) { + if (strlen(buffer) > 128) { + success = false; + } else if(!CONFIG::write_string(EP_TIME_SERVER3,buffer)) { + success = false; + } + } + + //Section [printer] + //data = 192.168.1.1/video.cgi?user=luc&pwd=mypassword + if (espconfig.getValue("printer", "data", buffer, bufferLen)) { + if (strlen(buffer) > 128) { + success = false; + } else if(!CONFIG::write_string(EP_DATA_STRING,buffer)) { + success = false; + } + } + //refreshrate = 3 + if (espconfig.getValue("printer", "refreshrate", buffer, bufferLen, itmp)) { + bflag = itmp; + if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME,bflag)) { + success = false; + } + } + //refreshrate2 = 3 + if (espconfig.getValue("printer", "refreshrate2", buffer, bufferLen, itmp)) { + bflag = itmp; + if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME2,bflag)) { + success = false; + } + } + //XY_feedrate = 1000 + if (espconfig.getValue("printer", "XY_feedrate", buffer, bufferLen, itmp)) { + if(!CONFIG::write_buffer(EP_XY_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { + success = false; + } + } + //Z_feedrate = 100 + if (espconfig.getValue("printer", "Z_feedrate", buffer, bufferLen, itmp)) { + if(!CONFIG::write_buffer(EP_Z_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { + success = false; + } + } + //E_feedrate = 400 + if (espconfig.getValue("printer", "E_feedrate", buffer, bufferLen, itmp)) { + if(!CONFIG::write_buffer(EP_E_FEEDRATE,(const byte *)&itmp,INTEGER_LENGTH)) { + success = false; + } + } + + //target_printer= smoothieware + if (espconfig.getValue("printer", "target_printer", buffer, bufferLen)) { + stmp = buffer; + bflag = UNKNOWN_FW; + if ( stmp.equalsIgnoreCase(String(F("repetier"))))bflag = REPETIER; + else if ( stmp.equalsIgnoreCase(String(F("repetier4davinci"))))bflag = REPETIER4DV; + else if ( stmp.equalsIgnoreCase(String(F("marlin"))))bflag = MARLIN; + else if ( stmp.equalsIgnoreCase(String(F("marlinkimbra"))))bflag = MARLINKIMBRA; + else if ( stmp.equalsIgnoreCase(String(F("smoothieware"))))bflag = SMOOTHIEWARE; + else success = false; + if(!(success && CONFIG::write_byte(EP_TARGET_FW,bflag))) { + success = false; + } + } + + //direct sd connection + if (espconfig.getValue("printer", "direct_sd", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="yes") { + bflag = 1; + } else if (stmp =="no") { + bflag = 0; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_IS_DIRECT_SD,bflag)) { + success = false; + } + } + } + //sd check update at boot + if (espconfig.getValue("printer", "sd_check_update", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="yes") { + bflag = 1; + } else if (stmp =="no") { + bflag = 0; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_SD_CHECK_UPDATE_AT_BOOT,bflag)) { + success = false; + } + } + } + //direct sd boot check + if (espconfig.getValue("printer", "direct_sd_boot_check", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="yes") { + bflag = 1; + } else if (stmp =="no") { + bflag = 0; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_DIRECT_SD_CHECK,bflag)) { + success = false; + } + } + } + + //primary sd directory + if (espconfig.getValue("printer", "primary_sd ", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="none") { + bflag = 0; + } else if (stmp =="sd") { + bflag = 1; + } else if (stmp =="ext") { + bflag = 2; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_PRIMARY_SD,bflag)) { + success = false; + } + } + } + + //secondary sd directory + if (espconfig.getValue("printer", "secondary_sd ", buffer, bufferLen)) { + stmp = buffer; + localerror = false; + stmp.toLowerCase(); + bflag = 0; + if (stmp =="none") { + bflag = 0; + } else if (stmp =="sd") { + bflag = 1; + } else if (stmp =="ext") { + bflag = 2; + } else { + localerror = true; + success = false; + } + if (!localerror) { + if(!CONFIG::write_byte(EP_SECONDARY_SD,bflag)) { + success = false; + } + } + } + + } + espconfig.close(); + if(success) { + newfilename.replace(String(".txt"), String(".ok")); + } else { + newfilename.replace(String(".txt"), String(".bad")); + answer = false; + } + //rename if name is already used + if (!CONFIG::renameFile (newfilename)) { + LOG("Failed to rename previous file\r\n") + } + if (SD.rename((const char *)filename.c_str(),(const char *)newfilename.c_str())) { + LOG("File renamed, restarted file\r\n") + } else { + return false; + LOG("Failed to rename file\r\n") + } + } else { + return false; + LOG("Failed to open config file\r\n") + } + } else { + return false; + LOG("No config file\r\n") + } + return answer; +} +#endif void CONFIG::esp_restart() { LOG("Restarting\r\n") - Serial.flush(); + ESP_SERIAL_OUT.flush(); delay(500); - Serial.swap(); +#ifdef ARDUINO_ARCH_ESP8266 + ESP_SERIAL_OUT.swap(); +#endif delay(100); ESP.restart(); while (1) { @@ -38,12 +717,19 @@ void CONFIG::esp_restart() }; } +void CONFIG::InitPins(){ +#ifdef RECOVERY_FEATURE + pinMode(RESET_CONFIG_PIN, INPUT); +#endif +} + +bool CONFIG::is_direct_sd = false; bool CONFIG::isHostnameValid(const char * hostname) { //limited size char c; - if (strlen(hostname)>MAX_HOSTNAME_LENGTH || strlen(hostname) < 1) { + if (strlen(hostname)>MAX_HOSTNAME_LENGTH || strlen(hostname) < MIN_HOSTNAME_LENGTH) { return false; } //only letter and digit @@ -68,11 +754,11 @@ bool CONFIG::isSSIDValid(const char * ssid) } //only letter and digit for (int i=0; i < strlen(ssid); i++) { - c = ssid[i]; + if (!isPrintable(ssid[i]))return false; //if (!(isdigit(c) || isalpha(c))) return false; //if (c==' ') { - // return false; - //} + // return false; + //} } return true; } @@ -88,7 +774,6 @@ bool CONFIG::isPasswordValid(const char * password) if (password[i] == ' ') { return false; } - return true; } @@ -165,7 +850,7 @@ char * CONFIG::intTostr(int value) return result; } -String CONFIG::formatBytes(size_t bytes) +String CONFIG::formatBytes(uint32_t bytes) { if (bytes < 1024) { return String(bytes)+" B"; @@ -320,6 +1005,100 @@ bool CONFIG::write_string(int pos, const __FlashStringHelper *str) return write_string(pos,stmp.c_str()); } +bool CONFIG::check_update_presence( ){ + bool result = false; + if (CONFIG::is_direct_sd) { + long baud_rate=0; + if (!CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&baud_rate, INTEGER_LENGTH)) return false; + if (ESP_SERIAL_OUT.baudRate() != baud_rate)ESP_SERIAL_OUT.begin(baud_rate); + CONFIG::InitFirmwareTarget(); + delay(500); + String cmd = "M20"; + //By default M20 should be applied + //if (CONFIG::FirmwareTarget == UNKNOWN_FW) return false; + if (CONFIG::FirmwareTarget == SMOOTHIEWARE) { + byte sd_dir = 0; + if (!CONFIG::read_byte(EP_PRIMARY_SD, &sd_dir )) sd_dir = DEFAULT_PRIMARY_SD; + if (sd_dir == SD_DIRECTORY) cmd = "ls /sd"; + else if (sd_dir == EXT_DIRECTORY) cmd = "ls /ext"; + else return false; + } + String tmp; + int count ; + //send command to serial as no need to transfer ESP command + //to avoid any pollution if Uploading file to SDCard + //block every query + //empty the serial buffer and incoming data + if(ESP_SERIAL_OUT.available()) { + BRIDGE::processFromSerial2TCP(); + delay(1); + } + //Send command + ESP_SERIAL_OUT.println(cmd); + count = 0; + String current_buffer; + String current_line; + int pos; + int temp_counter = 0; + + //pickup the list + while (count < MAX_TRY) { + //give some time between each buffer + if (ESP_SERIAL_OUT.available()) { + count = 0; + size_t len = ESP_SERIAL_OUT.available(); + uint8_t sbuf[len+1]; + //read buffer + ESP_SERIAL_OUT.readBytes(sbuf, len); + //change buffer as string + sbuf[len]='\0'; + //add buffer to current one if any + current_buffer += (char * ) sbuf; + while (current_buffer.indexOf("\n") !=-1) { + //remove the possible "\r" + current_buffer.replace("\r",""); + pos = current_buffer.indexOf("\n"); + //get line + current_line = current_buffer.substring(0,current_buffer.indexOf("\n")); + //if line is command ack - just exit so save the time out period + if ((current_line == "ok") || (current_line == "wait")) { + count = MAX_TRY; + break; + } + //check line + //save time no need to continue + if (current_line.indexOf("busy:") > -1 || current_line.indexOf("T:") > -1 || current_line.indexOf("B:") > -1) { + temp_counter++; + } else { + + } + if (temp_counter > 5) { + break; + } + //current remove line from buffer + tmp = current_buffer.substring(current_buffer.indexOf("\n")+1,current_buffer.length()); + current_buffer = tmp; + delay(0); + } + delay (0); + } else { + delay(1); + } + //it is sending too many temp status should be heating so let's exit the loop + if (temp_counter > 5) { + count = MAX_TRY; + } + count++; + } + if(ESP_SERIAL_OUT.available()) { + BRIDGE::processFromSerial2TCP(); + delay(1); + } + } + return result; +} + + //write a string (array of byte with a 0x00 at the end) bool CONFIG::write_string(int pos, const char * byte_buffer) { @@ -343,11 +1122,17 @@ bool CONFIG::write_string(int pos, const char * byte_buffer) case EP_HOSTNAME: maxsize = MAX_HOSTNAME_LENGTH; break; + case EP_TIME_SERVER1: + case EP_TIME_SERVER2: + case EP_TIME_SERVER3: + case EP_DATA_STRING: + maxsize = MAX_DATA_LENGTH; + break; default: maxsize = EEPROM_SIZE; break; } - if (size_buffer==0 || pos+size_buffer+1 > EEPROM_SIZE || size_buffer > maxsize || byte_buffer== NULL) { + if ((size_buffer==0 && !(pos == EP_DATA_STRING)) || pos+size_buffer+1 > EEPROM_SIZE || size_buffer > maxsize || byte_buffer== NULL) { LOG("Error write string\r\n") return false; } @@ -399,6 +1184,9 @@ bool CONFIG::write_byte(int pos, const byte value) bool CONFIG::reset_config() { + if(!CONFIG::write_string(EP_DATA_STRING,"")) { + return false; + } if(!CONFIG::write_byte(EP_WIFI_MODE,DEFAULT_WIFI_MODE)) { return false; } @@ -468,6 +1256,9 @@ bool CONFIG::reset_config() if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME,DEFAULT_REFRESH_PAGE_TIME)) { return false; } + if(!CONFIG::write_byte(EP_REFRESH_PAGE_TIME2,DEFAULT_REFRESH_PAGE_TIME)) { + return false; + } if(!CONFIG::write_string(EP_HOSTNAME,wifi_config.get_default_hostname())) { return false; } @@ -486,328 +1277,590 @@ bool CONFIG::reset_config() if(!CONFIG::write_string(EP_USER_PWD,FPSTR(DEFAULT_USER_PWD))) { return false; } + + if(!CONFIG::write_byte(EP_TARGET_FW, UNKNOWN_FW)) { + return false; + } + + if(!CONFIG::write_byte(EP_TIMEZONE, DEFAULT_TIME_ZONE)) { + return false; + } + + if(!CONFIG::write_byte(EP_TIME_ISDST, DEFAULT_TIME_DST)) { + return false; + } + + if(!CONFIG::write_byte(EP_PRIMARY_SD, DEFAULT_PRIMARY_SD)) { + return false; + } + + if(!CONFIG::write_byte(EP_SECONDARY_SD, DEFAULT_SECONDARY_SD)) { + return false; + } + + if(!CONFIG::write_byte(EP_IS_DIRECT_SD, DEFAULT_IS_DIRECT_SD)) { + return false; + } + + if(!CONFIG::write_byte(EP_DIRECT_SD_CHECK, DEFAULT_DIRECT_SD_CHECK)) { + return false; + } + + if(!CONFIG::write_byte(EP_SD_CHECK_UPDATE_AT_BOOT, DEFAULT_SD_CHECK_UPDATE_AT_BOOT)) { + return false; + } + + if(!CONFIG::write_string(EP_TIME_SERVER1,FPSTR(DEFAULT_TIME_SERVER1))) { + return false; + } + + if(!CONFIG::write_string(EP_TIME_SERVER2,FPSTR(DEFAULT_TIME_SERVER2))) { + return false; + } + + if(!CONFIG::write_string(EP_TIME_SERVER3,FPSTR(DEFAULT_TIME_SERVER3))) { + return false; + } return true; } -void CONFIG::print_config(tpipe output) -{ - //use biggest size for buffer - char sbuf[MAX_PASSWORD_LENGTH+1]; - uint8_t ipbuf[4]; - byte bbuf=0; - int ibuf=0; - if (CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::print(F("Baud rate: "), output); - BRIDGE::println(String(ibuf).c_str(), output); - } else { - BRIDGE::println(F("Error reading baud rate"), output); - } - if (CONFIG::read_byte(EP_SLEEP_MODE, &bbuf )) { - BRIDGE::print(F("Sleep mode: "), output); - if (byte(bbuf)==WIFI_NONE_SLEEP) { - BRIDGE::println(F("None"), output); - } else if (byte(bbuf)==WIFI_LIGHT_SLEEP) { - BRIDGE::println(F("Light"), output); - } else if (byte(bbuf)==WIFI_MODEM_SLEEP) { - BRIDGE::println(F("Modem"), output); - } else { - BRIDGE::println(F("???"), output); +void CONFIG::print_config(tpipe output, bool plaintext) +{ + if (!plaintext)BRIDGE::print(F("{\"chip_id\":\""), output); + else BRIDGE::print(F("Chip ID: "), output); +#ifdef ARDUINO_ARCH_ESP8266 + BRIDGE::print(String(ESP.getChipId()).c_str(), output); +#else + BRIDGE::print(String((uint16_t)(ESP.getEfuseMac()>>32)).c_str(), output); +#endif + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"cpu\":\""), output); + else BRIDGE::print(F("CPU Frequency: "), output); + BRIDGE::print(String(ESP.getCpuFreqMHz()).c_str(), output); + if (plaintext)BRIDGE::print(F("Mhz"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#ifdef ARDUINO_ARCH_ESP32 + if (!plaintext)BRIDGE::print(F("\"cpu_temp\":\""), output); + else BRIDGE::print(F("CPU Temperature: "), output); + BRIDGE::print(String(temperatureRead(),1).c_str(), output); + if (plaintext)BRIDGE::print(F("C"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#endif + if (!plaintext)BRIDGE::print(F("\"freemem\":\""), output); + else BRIDGE::print(F("Free memory: "), output); + BRIDGE::print(formatBytes(ESP.getFreeHeap()).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\""), output); + BRIDGE::print(F("SDK"), output); + if (!plaintext)BRIDGE::print(F("\":\""), output); + else BRIDGE::print(F(": "), output); + BRIDGE::print(ESP.getSdkVersion(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"flash_size\":\""), output); + else BRIDGE::print(F("Flash Size: "), output); + BRIDGE::print(formatBytes(ESP.getFlashChipSize()).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#ifdef ARDUINO_ARCH_ESP8266 + if (!plaintext)BRIDGE::print(F("\"update_size\":\""), output); + else BRIDGE::print(F("Available Size for update: "), output); + uint32_t flashsize = ESP.getFlashChipSize(); + if (flashsize > 1024 * 1024) flashsize = 1024 * 1024; + BRIDGE::print(formatBytes(flashsize - ESP.getSketchSize()).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else { + if ((flashsize - ESP.getSketchSize()) > (flashsize / 2)) BRIDGE::println(F("(Ok)"), output); + else BRIDGE::print(F("(Not enough)"), output); } - } else { - BRIDGE::println(F("Error reading sleep mode"), output); - } - if (CONFIG::read_string(EP_HOSTNAME, sbuf , MAX_HOSTNAME_LENGTH)) { - BRIDGE::print(F("Hostname: "), output); - BRIDGE::println(sbuf, output); - } else { - BRIDGE::println(F("Error reading hostname"), output); - } - if (CONFIG::read_byte(EP_WIFI_MODE, &bbuf )) { - BRIDGE::print(F("Mode: "), output); - if (byte(bbuf) == CLIENT_MODE) { - BRIDGE::println(F("Station"), output); - BRIDGE::print(F("Signal: "), output); - BRIDGE::print(String(wifi_config.getSignal(WiFi.RSSI())).c_str(), output); - BRIDGE::println(F("%"), output); - } else if (byte(bbuf)==AP_MODE) { - BRIDGE::println(F("Access Point"), output); - } else { - BRIDGE::println("???", output); + + if (!plaintext)BRIDGE::print(F("\"spiffs_size\":\""), output); + else BRIDGE::print(F("Available Size for SPIFFS: "), output); + fs::FSInfo info; + SPIFFS.info(info); + BRIDGE::print(formatBytes(info.totalBytes).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#else + if (!plaintext)BRIDGE::print(F("\"update_size\":\""), output); + else BRIDGE::print(F("Available Size for update: "), output); + uint32_t flashsize = ESP.getFlashChipSize(); +//Not OTA on 2Mb board per spec + if (flashsize > 0x20000) flashsize = 0x140000; + else flashsize = 0x0; + BRIDGE::print(formatBytes(flashsize).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else { + if (flashsize > 0x0) BRIDGE::println(F("(Ok)"), output); + else BRIDGE::print(F("(Not enough)"), output); } + if (!plaintext)BRIDGE::print(F("\"spiffs_size\":\""), output); + else BRIDGE::print(F("Available Size for SPIFFS: "), output); + BRIDGE::print(formatBytes(SPIFFS.totalBytes()).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#endif + if (!plaintext)BRIDGE::print(F("\"baud_rate\":\""), output); + else BRIDGE::print(F("Baud rate: "), output); + uint32_t br = ESP_SERIAL_OUT.baudRate(); +#ifdef ARDUINO_ARCH_ESP32 + //workaround for ESP32 + if(br == 115201)br = 115200; + if(br == 230423)br = 230400; +#endif + BRIDGE::print(String(br).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"sleep_mode\":\""), output); + else BRIDGE::print(F("Sleep mode: "), output); +#ifdef ARDUINO_ARCH_ESP32 + wifi_ps_type_t ps_type; + esp_wifi_get_ps(&ps_type); +#else + WiFiSleepType_t ps_type; + ps_type = WiFi.getSleepMode(); +#endif + if (ps_type == WIFI_NONE_SLEEP) { + BRIDGE::print(F("None"), output); +#ifdef ARDUINO_ARCH_ESP8266 + } else if (ps_type == WIFI_LIGHT_SLEEP) { + BRIDGE::print(F("Light"), output); +#endif + } else if (ps_type == WIFI_MODEM_SLEEP) { + BRIDGE::print(F("Modem"), output); } else { - BRIDGE::println(F("Error reading mode"), output); + BRIDGE::print(F("???"), output); } - - if (CONFIG::read_string(EP_STA_SSID, sbuf , MAX_SSID_LENGTH)) { - BRIDGE::print(F("Client SSID: "), output); - BRIDGE::println(sbuf, output); - } else { - BRIDGE::println(F("Error reading SSID"), output); - } - - if (CONFIG::read_byte(EP_STA_IP_MODE, &bbuf )) { - BRIDGE::print(F("STA IP Mode: "), output); - if (byte(bbuf)==STATIC_IP_MODE) { - BRIDGE::println(F("Static"), output); - if (CONFIG::read_buffer(EP_STA_IP_VALUE,(byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("IP: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading IP"), output); - } - - if (CONFIG::read_buffer(EP_STA_MASK_VALUE, (byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("Subnet: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading subnet"), output); - } - - if (CONFIG::read_buffer(EP_STA_GATEWAY_VALUE, (byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("Gateway: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading gateway"), output); - } - } else if (byte(bbuf)==DHCP_MODE) { - BRIDGE::println(F("DHCP"), output); - } else { - BRIDGE::println(F("???"), output); - } - } else { - BRIDGE::println(F("Error reading IP mode"), output); - } - - if (CONFIG::read_byte(EP_STA_PHY_MODE, &bbuf )) { - BRIDGE::print(F("STA Phy mode: "), output); - if (byte(bbuf)==WIFI_PHY_MODE_11B) { - BRIDGE::println(F("11b"), output); - } else if (byte(bbuf)==WIFI_PHY_MODE_11G) { - BRIDGE::println(F("11g"), output); - } else if (byte(bbuf)==WIFI_PHY_MODE_11N) { - BRIDGE::println(F("11n"), output); - } else { - BRIDGE::println(F("???"), output); - } - } else { - BRIDGE::println(F("Error reading phy mode"), output); - } - - if (CONFIG::read_string(EP_AP_SSID, sbuf , MAX_SSID_LENGTH)) { - BRIDGE::print(F("AP SSID: "), output); - BRIDGE::println(sbuf, output); - } else { - BRIDGE::println(F("Error reading SSID"), output); - } - - if (CONFIG::read_byte(EP_AP_IP_MODE, &bbuf )) { - BRIDGE::print(F("AP IP Mode: "), output); - if (byte(bbuf)==STATIC_IP_MODE) { - BRIDGE::println(F("Static"), output); - if (CONFIG::read_buffer(EP_AP_IP_VALUE,(byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("IP: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading IP"), output); - } - - if (CONFIG::read_buffer(EP_AP_MASK_VALUE, (byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("Subnet: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading subnet"), output); - } - - if (CONFIG::read_buffer(EP_AP_GATEWAY_VALUE, (byte *)ipbuf , IP_LENGTH)) { - BRIDGE::print(F("Gateway: "), output); - BRIDGE::println(IPAddress(ipbuf).toString().c_str(), output); - } else { - BRIDGE::println(F("Error reading gateway"), output); - } - } else if (byte(bbuf)==DHCP_MODE) { - BRIDGE::println(F("DHCP"), output); - } else { - BRIDGE::println(intTostr(bbuf), output); - BRIDGE::println(F("???"), output); - } - } else { - BRIDGE::println(F("Error reading IP mode"), output); - } - - if (CONFIG::read_byte(EP_AP_PHY_MODE, &bbuf )) { - BRIDGE::print(F("AP Phy mode: "), output); - if (byte(bbuf)==WIFI_PHY_MODE_11B) { - BRIDGE::println(F("11b"), output); - } else if (byte(bbuf)==WIFI_PHY_MODE_11G) { - BRIDGE::println(F("11g"), output); - } else if (byte(bbuf)==WIFI_PHY_MODE_11N) { - BRIDGE::println(F("11n"), output); - } else { - BRIDGE::println(F("???"), output); - } - } else { - BRIDGE::println(F("Error reading phy mode"), output); - } - - if (CONFIG::read_byte(EP_CHANNEL, &bbuf )) { - BRIDGE::print(F("Channel: "), output); - BRIDGE::println(String(byte(bbuf)).c_str(), output); - } else { - BRIDGE::println(F("Error reading channel"), output); - } - - if (CONFIG::read_byte(EP_AUTH_TYPE, &bbuf )) { - BRIDGE::print(F("Authentification: "), output); - if (byte(bbuf)==AUTH_OPEN) { - BRIDGE::println(F("None"), output); - } else if (byte(bbuf)==AUTH_WEP) { - BRIDGE::println(F("WEP"), output); - } else if (byte(bbuf)==AUTH_WPA_PSK) { - BRIDGE::println(F("WPA"), output); - } else if (byte(bbuf)==AUTH_WPA2_PSK) { - BRIDGE::println(F("WPA2"), output); - } else if (byte(bbuf)==AUTH_WPA_WPA2_PSK) { - BRIDGE::println(F("WPA/WPA2"), output); - } else { - BRIDGE::println(F("???"), output); - } - } else { - BRIDGE::println(F("Error reading authentification"), output); - } - - if (CONFIG::read_byte(EP_SSID_VISIBLE, &bbuf )) { - BRIDGE::print(F("SSID visibility: "), output); - if (bbuf==0) { - BRIDGE::println(F("Hidden"), output); - } else if (bbuf==1) { - BRIDGE::println(F("Visible"), output); - } else { - BRIDGE::println(String(bbuf).c_str(), output); - } - } else { - BRIDGE::println(F("Error reading SSID visibility"), output); - } - - if (CONFIG::read_buffer(EP_WEB_PORT, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::print(F("Web port: "), output); - BRIDGE::println(String(ibuf).c_str(), output); - } else { - BRIDGE::println(F("Error reading web port"), output); - } - BRIDGE::print(F("Data port: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"channel\":\""), output); + else BRIDGE::print(F("Channel: "), output); + BRIDGE::print(String(WiFi.channel()).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#ifdef ARDUINO_ARCH_ESP32 + uint8_t PhyMode; + if (WiFi.getMode() == WIFI_STA)esp_wifi_get_protocol(ESP_IF_WIFI_STA, &PhyMode); + else esp_wifi_get_protocol(ESP_IF_WIFI_AP, &PhyMode); +#else + WiFiPhyMode_t PhyMode = WiFi.getPhyMode(); +#endif + if (!plaintext)BRIDGE::print(F("\"phy_mode\":\""), output); + else BRIDGE::print(F("Phy Mode: "), output); + if (PhyMode == WIFI_PHY_MODE_11G )BRIDGE::print(F("11g"), output); + else if (PhyMode == WIFI_PHY_MODE_11B )BRIDGE::print(F("11b"), output); + else if (PhyMode == WIFI_PHY_MODE_11N )BRIDGE::print(F("11n"), output); + else BRIDGE::print(F("???"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"web_port\":\""), output); + else BRIDGE::print(F("Web port: "), output); + BRIDGE::print(String(wifi_config.iweb_port).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"data_port\":\""), output); + else BRIDGE::print(F("Data port: "), output); #ifdef TCP_IP_DATA_FEATURE - if (CONFIG::read_buffer(EP_DATA_PORT, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::println(String(ibuf).c_str(), output); - } else { - BRIDGE::println(F("Error reading data port"), output); - } + BRIDGE::print(String(wifi_config.idata_port).c_str(), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - if (CONFIG::read_byte(EP_REFRESH_PAGE_TIME, &bbuf )) { - BRIDGE::print(F("Web page refresh time: "), output); - BRIDGE::println(String(byte(bbuf)).c_str(), output); - } else { - BRIDGE::println(F("Error reading refresh page"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (WiFi.getMode() == WIFI_STA || WiFi.getMode() == WIFI_AP_STA) { + if (!plaintext)BRIDGE::print(F("\"hostname\":\""), output); + else BRIDGE::print(F("Hostname: "), output); +#ifdef ARDUINO_ARCH_ESP32 + BRIDGE::print(WiFi.getHostname(), output); +#else + BRIDGE::print(WiFi.hostname().c_str(), output); +#endif + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); } - if (CONFIG::read_buffer(EP_XY_FEEDRATE, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::print(F("XY feed rate: "), output); - BRIDGE::println(String(ibuf).c_str(), output); + if (!plaintext)BRIDGE::print(F("\"active_mode\":\""), output); + else BRIDGE::print(F("Active Mode: "), output); + if (WiFi.getMode() == WIFI_STA) { + BRIDGE::print(F("Station ("), output); + BRIDGE::print(WiFi.macAddress().c_str(), output); + BRIDGE::print(F(")"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + if (WiFi.isConnected()) { + if (!plaintext)BRIDGE::print(F("\"connected_ssid\":\""), output); + else BRIDGE::print(F("Connected to: "), output); + BRIDGE::print(WiFi.SSID().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + if (!plaintext)BRIDGE::print(F("\"connected_signal\":\""), output); + else BRIDGE::print(F("Signal: "), output); + BRIDGE::print(String(wifi_config.getSignal(WiFi.RSSI())).c_str(), output); + BRIDGE::print(F("%"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + } + else { + if (!plaintext)BRIDGE::print(F("\"connection_status\":\""), output); + else BRIDGE::print(F("Connection Status: "), output); + BRIDGE::print(F("Connection Status: "), output); + if (WiFi.status() == WL_DISCONNECTED) { + BRIDGE::print(F("Disconnected"), output); + } else if (WiFi.status() == WL_CONNECTION_LOST) { + BRIDGE::print(F("Connection lost"), output); + } else if (WiFi.status() == WL_CONNECT_FAILED) { + BRIDGE::print(F("Connection failed"), output); + } else if (WiFi.status() == WL_NO_SSID_AVAIL) { + BRIDGE::print(F("No connection"), output); + } else if (WiFi.status() == WL_IDLE_STATUS ) { + BRIDGE::print(F("Idle"), output); + } else BRIDGE::print(F("Unknown"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + } + if (!plaintext)BRIDGE::print(F("\"ip_mode\":\""), output); + else BRIDGE::print(F("IP Mode: "), output); +#ifdef ARDUINO_ARCH_ESP32 + tcpip_adapter_dhcp_status_t dhcp_status; + tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &dhcp_status); + if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED) +#else + if (wifi_station_dhcpc_status()==DHCP_STARTED) +#endif + { + BRIDGE::print(F("DHCP"), output); + } + else BRIDGE::print(F("Static"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ip\":\""), output); + else BRIDGE::print(F("IP: "), output); + BRIDGE::print(WiFi.localIP().toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"gw\":\""), output); + else BRIDGE::print(F("Gateway: "), output); + BRIDGE::print(WiFi.gatewayIP().toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"msk\":\""), output); + else BRIDGE::print(F("Mask: "), output); + BRIDGE::print(WiFi.subnetMask().toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"dns\":\""), output); + else BRIDGE::print(F("DNS: "), output); + BRIDGE::print(WiFi.dnsIP().toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"disabled_mode\":\""), output); + else BRIDGE::print(F("Disabled Mode: "), output); + BRIDGE::print(F("Access Point ("), output); + BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); + BRIDGE::print(F(")"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + } else if (WiFi.getMode() == WIFI_AP) { + BRIDGE::print(F("Access Point ("), output); + BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); + BRIDGE::print(F(")"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + //get current config +#ifdef ARDUINO_ARCH_ESP32 + wifi_ap_config_t apconfig; + wifi_config_t conf; + esp_wifi_get_config(ESP_IF_WIFI_AP, &conf); + apconfig.ssid_hidden = conf.ap.ssid_hidden; + apconfig.authmode = conf.ap.authmode; + apconfig.max_connection = conf.ap.max_connection; +#else + struct softap_config apconfig; + wifi_softap_get_config(&apconfig); +#endif + if (!plaintext)BRIDGE::print(F("\"ap_ssid\":\""), output); + else BRIDGE::print(F("SSID: "), output); +#ifdef ARDUINO_ARCH_ESP32 + BRIDGE::print((const char*)conf.ap.ssid, output); +#else + BRIDGE::print((const char*)apconfig.ssid, output); +#endif + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ssid_visible\":\""), output); + else BRIDGE::print(F("Visible: "), output); + BRIDGE::print((apconfig.ssid_hidden == 0)?F("Yes"):F("No"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ssid_authentication\":\""), output); + else BRIDGE::print(F("Authentication: "), output); + if (apconfig.authmode==AUTH_OPEN) { + BRIDGE::print(F("None"), output); + } else if (apconfig.authmode==AUTH_WEP) { + BRIDGE::print(F("WEP"), output); + } else if (apconfig.authmode==AUTH_WPA_PSK) { + BRIDGE::print(F("WPA"), output); + } else if (apconfig.authmode==AUTH_WPA2_PSK) { + BRIDGE::print(F("WPA2"), output); + } else { + BRIDGE::print(F("WPA/WPA2"), output); + } + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ssid_max_connections\":\""), output); + else BRIDGE::print(F("Max Connections: "), output); + BRIDGE::print(String(apconfig.max_connection).c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ssid_dhcp\":\""), output); + else BRIDGE::print(F("DHCP Server: "), output); +#ifdef ARDUINO_ARCH_ESP32 + tcpip_adapter_dhcp_status_t dhcp_status; + tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); + if (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED) +#else + if(wifi_softap_dhcps_status() == DHCP_STARTED) +#endif + { + BRIDGE::print(F("Started"), output); + } + else BRIDGE::print(F("Stopped"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ip\":\""), output); + else BRIDGE::print(F("IP: "), output); + BRIDGE::print(WiFi.softAPIP().toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); +#ifdef ARDUINO_ARCH_ESP32 + tcpip_adapter_ip_info_t ip; + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip); +#else + struct ip_info ip; + wifi_get_ip_info(SOFTAP_IF, &ip); +#endif + if (!plaintext)BRIDGE::print(F("\"gw\":\""), output); + else BRIDGE::print(F("Gateway: "), output); + BRIDGE::print(IPAddress(ip.gw.addr).toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"msk\":\""), output); + else BRIDGE::print(F("Mask: "), output); + BRIDGE::print(IPAddress(ip.netmask.addr).toString().c_str(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + + if (!plaintext)BRIDGE::print(F("\"connected_clients\":["), output); + else BRIDGE::print(F("Connected clients: "), output); + int client_counter=0; +#ifdef ARDUINO_ARCH_ESP32 + wifi_sta_list_t station; + tcpip_adapter_sta_list_t tcpip_sta_list; + esp_wifi_ap_get_sta_list(&station); + tcpip_adapter_get_sta_list(&station, &tcpip_sta_list); +#else + struct station_info * station; + station = wifi_softap_get_station_info(); +#endif + String stmp =""; +#ifdef ARDUINO_ARCH_ESP32 + for (int i=0; i < station.num; i++){ +#else + while(station) { +#endif + if(stmp.length() > 0) { + if (!plaintext)stmp+=F(","); + else stmp+=F("\n"); + + } + if (!plaintext)stmp+=F("{\"bssid\":\""); + //BSSID +#ifdef ARDUINO_ARCH_ESP32 + stmp += CONFIG::mac2str(tcpip_sta_list.sta[i].mac); +#else + stmp += CONFIG::mac2str(station->bssid); +#endif + if (!plaintext)stmp+=F("\",\"ip\":\""); + else stmp += F(" "); + //IP +#ifdef ARDUINO_ARCH_ESP32 + stmp += IPAddress(tcpip_sta_list.sta[i].ip.addr).toString().c_str(); +#else + stmp += IPAddress((const uint8_t *)&station->ip).toString().c_str(); +#endif + if (!plaintext)stmp+=F("\"}"); + //increment counter + client_counter++; +#ifdef ARDUINO_ARCH_ESP32 + } +#else + //go next record + station =STAILQ_NEXT(station, next); + } + wifi_softap_free_station_info(); +#endif + if (!plaintext) { + BRIDGE::print(stmp.c_str(), output); + BRIDGE::print(F("],"), output); + } + else { + //display number of client + BRIDGE::println(String(client_counter).c_str(), output); + //display list if any + if(stmp.length() > 0)BRIDGE::println(stmp.c_str(), output); + } + + if (!plaintext)BRIDGE::print(F("\"disabled_mode\":\""), output); + else BRIDGE::print(F("Disabled Mode: "), output); + BRIDGE::print(F("Station ("), output); + BRIDGE::print(WiFi.macAddress().c_str(), output); + BRIDGE::print(F(") is disabled"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + } else if (WiFi.getMode() == WIFI_AP_STA) { + BRIDGE::print(F("Mixed"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + if (!plaintext)BRIDGE::print(F("\"active_mode\":\""), output); + else BRIDGE::print(F("Active Mode: "), output); + BRIDGE::print(F("Access Point ("), output); + BRIDGE::print(WiFi.softAPmacAddress().c_str(), output); + BRIDGE::println(F(")"), output); + BRIDGE::print(F("Station ("), output); + BRIDGE::print(WiFi.macAddress().c_str(), output); + BRIDGE::print(F(")"), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); } else { - BRIDGE::println(F("Error reading XY feed rate"), output); + BRIDGE::print("Wifi Off", output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); } - if (CONFIG::read_buffer(EP_Z_FEEDRATE, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::print(F("Z feed rate: "), output); - BRIDGE::println(String(ibuf).c_str(), output); - } else { - BRIDGE::println(F("Error reading Z feed rate"), output); - } - - if (CONFIG::read_buffer(EP_E_FEEDRATE, (byte *)&ibuf , INTEGER_LENGTH)) { - BRIDGE::print(F("E feed rate: "), output); - BRIDGE::println(String(ibuf).c_str(), output); - } else { - BRIDGE::println(F("Error reading E feed rate"), output); - } - - BRIDGE::print(F("Free memory: "), output); - BRIDGE::println(formatBytes(ESP.getFreeHeap()).c_str(), output); - - BRIDGE::print(F("Captive portal: "), output); + if (!plaintext)BRIDGE::print(F("\"captive_portal\":\""), output); + else BRIDGE::print(F("Captive portal: "), output); #ifdef CAPTIVE_PORTAL_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("SSDP: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"ssdp\":\""), output); + else BRIDGE::print(F("SSDP: "), output); #ifdef SSDP_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("NetBios: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"netbios\":\""), output); + else BRIDGE::print(F("NetBios: "), output); #ifdef NETBIOS_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("mDNS: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"mdns\":\""), output); + else BRIDGE::print(F("mDNS: "), output); #ifdef MDNS_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("Web update: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"web_update\":\""), output); + else BRIDGE::print(F("Web Update: "), output); #ifdef WEB_UPDATE_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("Pin 2 Recovery: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"pin recovery\":\""), output); + else BRIDGE::print(F("Pin Recovery: "), output); #ifdef RECOVERY_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif - BRIDGE::print(F("Authentication: "), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"autentication\":\""), output); + else BRIDGE::print(F("Authentication: "), output); #ifdef AUTHENTICATION_FEATURE - BRIDGE::println(F("Enabled"), output); + BRIDGE::print(F("Enabled"), output); #else - BRIDGE::println(F("Disabled"), output); -#endif - BRIDGE::print(F("Target Firmware: "), output); -#if FIRMWARE_TARGET == REPETIER - BRIDGE::println(F("Repetier"), output); -#elif FIRMWARE_TARGET == REPETIER4DV - BRIDGE::println(F("Repetier for DaVinci"), output); -#elif FIRMWARE_TARGET == MARLIN - BRIDGE::println(F("Marlin"), output); -#elif FIRMWARE_TARGET == SMOOTHIEWARE - BRIDGE::println(F("Smoothieware"), output); -#else - BRIDGE::println(F("???"), output); -#endif - BRIDGE::print(F("SD Card support: "), output); -#ifdef SDCARD_FEATURE - BRIDGE::println(F("Enabled"), output); -#else - BRIDGE::println(F("Disabled"), output); + BRIDGE::print(F("Disabled"), output); #endif + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); + + if (!plaintext)BRIDGE::print(F("\"target_fw\":\""), output); + else BRIDGE::print(F("Target Firmware: "), output); + BRIDGE::print(CONFIG::GetFirmwareTargetName(), output); + if (!plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); #ifdef DEBUG_ESP3D + if (!plaintext)BRIDGE::print(F("\"debug\":\""), output); + else BRIDGE::print(F("Debug: "), output); BRIDGE::print(F("Debug Enabled :"), output); #ifdef DEBUG_OUTPUT_SPIFFS - BRIDGE::println(F("SPIFFS"), output); + BRIDGE::print(F("SPIFFS"), output); #endif #ifdef DEBUG_OUTPUT_SD - BRIDGE::println(F("SD"), output); + BRIDGE::print(F("SD"), output); #endif #ifdef DEBUG_OUTPUT_SERIAL - BRIDGE::println(F("serial"), output); + BRIDGE::print(F("serial"), output); #endif #ifdef DEBUG_OUTPUT_TCP - BRIDGE::println(F("TCP"), output); + BRIDGE::print(F("TCP"), output); #endif + if (plaintext)BRIDGE::print(F("\","), output); + else BRIDGE::print(F("\n"), output); #endif + if (!plaintext)BRIDGE::print(F("\"fw\":\""), output); + else BRIDGE::print(F("FW version: "), output); + BRIDGE::print(FW_VERSION, output); + if (!plaintext)BRIDGE::print(F("\"}"), output); + else BRIDGE::print(F("\n"), output); } diff --git a/esp3d/config.h b/esp3d/config.h index 81a8d7b9..6b70a55f 100644 --- a/esp3d/config.h +++ b/esp3d/config.h @@ -19,15 +19,47 @@ */ //definition -#define REPETIER 0 -#define REPETIER4DV 1 +#define UNKNOWN_FW 0 +#define REPETIER4DV 1 #define MARLIN 2 #define MARLINKIMBRA 3 -#define SMOOTHIEWARE 4 +#define SMOOTHIEWARE 4 +#define REPETIER 5 -//FIRMWARE_TARGET: the targeted FW, can be REPETIER (Original Repetier)/ REPETIER4DV (Repetier for Davinci) / MARLIN (Marlin)/ SMOOTHIEWARE (Smoothieware) -#define FIRMWARE_TARGET MARLIN +#ifdef ARDUINO_ARCH_ESP32 +#include "FS.h" +#include "SPIFFS.h" +#define WIFI_NONE_SLEEP WIFI_PS_NONE +#define WIFI_MODEM_SLEEP WIFI_PS_MODEM +#define WIFI_PHY_MODE_11B WIFI_PROTOCOL_11B +#define WIFI_PHY_MODE_11G WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G +#define WIFI_PHY_MODE_11N WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N +#define AUTH_OPEN WIFI_AUTH_OPEN +#define AUTH_WEP WIFI_AUTH_WEP +#define AUTH_WPA_PSK WIFI_AUTH_WPA_PSK +#define AUTH_WPA2_PSK WIFI_AUTH_WPA2_PSK +#define AUTH_WPA_WPA2_PSK WIFI_AUTH_WPA_WPA2_PSK +#define ENC_TYPE_NONE AUTH_OPEN +#define FS_FILE File +#define FS_DIR File +#define ESP_SERIAL_OUT Serial +#define SD_FILE_READ FILE_READ +#define SPIFFS_FILE_READ FILE_READ +#define SD_FILE_WRITE FILE_WRITE +#define SPIFFS_FILE_WRITE FILE_WRITE +extern HardwareSerial Serial2; +#else +#define FS_DIR fs::Dir +#define FS_FILE fs::File +#define ESP_SERIAL_OUT Serial +#define SD_FILE_READ FILE_READ +#define SPIFFS_FILE_READ "r" +#define SD_FILE_WRITE FILE_WRITE +#define SPIFFS_FILE_WRITE "w" +#endif + +#define MAX_FW_ID REPETIER //number of clients allowed to use data port at once #define MAX_SRV_CLIENTS 1 @@ -41,7 +73,16 @@ #define SSDP_FEATURE //NETBIOS_FEATURE: this feature is a discovery protocol, supported on Windows out of the box -//#define NETBIOS_FEATURE +#define NETBIOS_FEATURE + +#ifdef ARDUINO_ARCH_ESP32 +#ifdef SSDP_FEATURE +#undef SSDP_FEATURE +#endif +#ifdef NETBIOS_FEATURE +#undef NETBIOS_FEATURE +#endif +#endif //CAPTIVE_PORTAL_FEATURE: In SoftAP redirect all unknow call to main page #define CAPTIVE_PORTAL_FEATURE @@ -78,86 +119,97 @@ //STATUS_MSG_FEATURE: catch the status msg and filter it to specific table #define STATUS_MSG_FEATURE -//TEMP_MONITORING_FEATURE : catch the specific answer and store it to variable -#define TEMP_MONITORING_FEATURE -//SPEED_MONITORING_FEATURE : catch the specific answer and store it to variable -#define SPEED_MONITORING_FEATURE -//POS_MONITORING_FEATURE : catch the specific answer and store it to variable -#define POS_MONITORING_FEATURE -//FLOW_MONITORING_FEATURE : catch the specific answer and store it to variable -#define FLOW_MONITORING_FEATURE - - //Serial rx buffer size is 256 but can be extended #define SERIAL_RX_BUFFER_SIZE 512 -//DEBUG Flag do not do this when connected to printer unless you know what you are doing!!! +#ifdef ARDUINO_ARCH_ESP32 +#ifdef SSDP_FEATURE +#undef SSDP_FEATURE +#endif +#ifdef NETBIOS_FEATURE +#undef NETBIOS_FEATURE +#endif +#endif + + +//DEBUG Flag do not do this when connected to printer !!! +//be noted all upload may failed if enabled //#define DEBUG_ESP3D //#define DEBUG_OUTPUT_SPIFFS -//#define DEBUG_OUTPUT_SD //#define DEBUG_OUTPUT_SERIAL //#define DEBUG_OUTPUT_TCP //store performance result in storestring variable : info_msg / status_msg //#define DEBUG_PERFORMANCE #define DEBUG_PERF_VARIABLE (web_interface->info_msg) +/* +#ifndef FS_NO_GLOBALS +#define FS_NO_GLOBALS +#endif +#include +#define DEBUG_ESP3D(string) { FS_FILE logfile = SPIFFS.open("/log.txt", "a+");logfile.print(string);logfile.close();} +*/ #ifdef DEBUG_ESP3D #ifdef DEBUG_OUTPUT_SPIFFS - /*#ifdef SDCARD_FEATURE - #ifndef FS_NO_GLOBALS - #define FS_NO_GLOBALS - #endif - #endif*/ - #include - #define DEBUG_PIPE NO_PIPE - #define LOG(string) {FSFILE logfile = SPIFFS.open("/log.txt", "a+");logfile.print(string);logfile.close();} +#ifndef FS_NO_GLOBALS +#define FS_NO_GLOBALS +#endif +#include +#define DEBUG_PIPE NO_PIPE +#define LOG(string) { FS_FILE logfile = SPIFFS.open("/log.txt", "a+");logfile.print(string);logfile.close();} #endif #ifdef DEBUG_OUTPUT_SERIAL - #define LOG(string) {Serial.print(string);} - #define DEBUG_PIPE SERIAL_PIPE +#define LOG(string) {ESP_SERIAL_OUT.print(string);} +#define DEBUG_PIPE SERIAL_PIPE #endif #ifdef DEBUG_OUTPUT_TCP - #include "bridge.h" - #define LOG(string) {BRIDGE::send2TCP(string);} - #define DEBUG_PIPE TCP_PIPE +#include "bridge.h" +#define LOG(string) {BRIDGE::send2TCP(string);} +#define DEBUG_PIPE TCP_PIPE #endif #else #define LOG(string) {} #define DEBUG_PIPE NO_PIPE #endif -#ifdef SDCARD_FEATURE -#define FSFILE fs::File -#define FSDIR fs::Dir -#define FSINFO fs::FSInfo -#else -#define FSFILE File -#define FSDIR fs::Dir -#define FSINFO FSInfo -#endif - #ifndef CONFIG_h #define CONFIG_h #include +#ifdef ARDUINO_ARCH_ESP8266 extern "C" { #include "user_interface.h" } -#include "wifi.h" +#else +//Nothing here +#endif +#include "wificonf.h" //version and sources location -#define FW_VERSION "0.9.78" +#define FW_VERSION "0.9.99" #define REPOSITORY "https://github.com/luc-github/ESP3D" typedef enum { - NO_PIPE = 0, - SERIAL_PIPE = 2, + NO_PIPE = 0, + SERIAL_PIPE = 2, SERIAL1_PIPE = 3, #ifdef TCP_IP_DATA_FEATURE - TCP_PIPE = 4, + TCP_PIPE = 4, #endif WEB_PIPE = 5 - } tpipe; +} tpipe; + +typedef enum { + LEVEL_GUEST = 0, + LEVEL_USER = 1, + LEVEL_ADMIN = 2 +} level_authenticate_type; + + +#define NO_SD 0 +#define SD_DIRECTORY 1 +#define EXT_DIRECTORY 2 + //flags #define AP_MODE 1 @@ -196,14 +248,29 @@ typedef enum { #define EP_AP_GATEWAY_VALUE 324 //4 bytes xxx.xxx.xxx.xxx #define EP_AP_IP_MODE 329 //1 byte = flag #define EP_AP_PHY_MODE 330 //1 byte = flag -//next available is 330 -//space left 512 - 330 = 18 +#define EP_DATA_STRING 331 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese +#define EP_REFRESH_PAGE_TIME2 460 //1 bytes = flag +#define EP_TARGET_FW 461 //1 bytes = flag +#define EP_TIMEZONE 462//1 bytes = flag +#define EP_TIME_ISDST 463//1 bytes = flag +#define EP_TIME_SERVER1 464//129 bytes 128+1 = string ; warning does not support multibyte char like chinese +#define EP_TIME_SERVER2 593 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese +#define EP_TIME_SERVER3 722 //129 bytes 128+1 = string ; warning does not support multibyte char like chinese +#define EP_IS_DIRECT_SD 850//1 bytes = flag +#define EP_PRIMARY_SD 851//1 bytes = flag +#define EP_SECONDARY_SD 852//1 bytes = flag +#define EP_DIRECT_SD_CHECK 853//1 bytes = flag +#define EP_SD_CHECK_UPDATE_AT_BOOT 854//1 bytes = flag + +#define LAST_EEPROM_ADDRESS 855 +//next available is 855 +//space left 1024 - 855 = 169 //default values #define DEFAULT_WIFI_MODE AP_MODE -const char DEFAULT_AP_SSID [] PROGMEM = "ESP8266"; +const char DEFAULT_AP_SSID [] PROGMEM = "ESP3D"; const char DEFAULT_AP_PASSWORD [] PROGMEM = "12345678"; -const char DEFAULT_STA_SSID [] PROGMEM = "ESP8266"; +const char DEFAULT_STA_SSID [] PROGMEM = "ESP3D"; const char DEFAULT_STA_PASSWORD [] PROGMEM = "12345678"; const byte DEFAULT_STA_IP_MODE = DHCP_MODE; const byte DEFAULT_AP_IP_MODE = STATIC_IP_MODE; @@ -229,24 +296,105 @@ const char DEFAULT_ADMIN_PWD [] PROGMEM = "admin"; const char DEFAULT_USER_PWD [] PROGMEM = "user"; const char DEFAULT_ADMIN_LOGIN [] PROGMEM = "admin"; const char DEFAULT_USER_LOGIN [] PROGMEM = "user"; +const char DEFAULT_TIME_SERVER1 [] PROGMEM = "time.nist.gov"; +const char DEFAULT_TIME_SERVER2 [] PROGMEM = "0.pool.ntp.org"; +const char DEFAULT_TIME_SERVER3 [] PROGMEM = "1.pool.ntp.org"; +#define DEFAULT_TIME_ZONE 1 +#define DEFAULT_TIME_DST 0 +#define DEFAULT_PRIMARY_SD 1 +#define DEFAULT_SECONDARY_SD 2 +#define DEFAULT_DIRECT_SD_CHECK 0 +#define DEFAULT_SD_CHECK_UPDATE_AT_BOOT 1 +#define DEFAULT_IS_DIRECT_SD 0 + + + + +const uint16_t Setting[][2] = { + {EP_WIFI_MODE, LEVEL_ADMIN},//0 + {EP_STA_SSID, LEVEL_ADMIN},//1 + {EP_STA_PASSWORD, LEVEL_ADMIN},//2 + {EP_STA_IP_MODE, LEVEL_ADMIN},//3 + {EP_STA_IP_VALUE, LEVEL_ADMIN},//4 + {EP_STA_MASK_VALUE, LEVEL_ADMIN},//5 + {EP_STA_GATEWAY_VALUE, LEVEL_ADMIN},//6 + {EP_BAUD_RATE, LEVEL_ADMIN},//7 + {EP_STA_PHY_MODE, LEVEL_ADMIN},//8 + {EP_SLEEP_MODE, LEVEL_ADMIN},//9 + {EP_CHANNEL, LEVEL_ADMIN},//10 + {EP_AUTH_TYPE, LEVEL_ADMIN},//11 + {EP_SSID_VISIBLE, LEVEL_ADMIN},//12 + {EP_WEB_PORT, LEVEL_ADMIN},//13 + {EP_DATA_PORT, LEVEL_ADMIN},//14 + {EP_REFRESH_PAGE_TIME, LEVEL_USER},//15 + {EP_HOSTNAME, LEVEL_ADMIN},//16 + {EP_XY_FEEDRATE, LEVEL_USER},//17 + {EP_Z_FEEDRATE, LEVEL_USER},//18 + {EP_E_FEEDRATE, LEVEL_USER},//19 + {EP_ADMIN_PWD, LEVEL_ADMIN},//20 + {EP_USER_PWD, LEVEL_USER},//21 + {EP_AP_SSID, LEVEL_ADMIN},//22 + {EP_AP_PASSWORD, LEVEL_ADMIN},//23 + {EP_AP_IP_VALUE, LEVEL_ADMIN},//24 + {EP_AP_MASK_VALUE, LEVEL_ADMIN},//25 + {EP_AP_GATEWAY_VALUE, LEVEL_ADMIN},//26 + {EP_AP_IP_MODE, LEVEL_ADMIN},//27 + {EP_AP_PHY_MODE, LEVEL_ADMIN},//28 + {EP_DATA_STRING, LEVEL_USER},//29 + {EP_REFRESH_PAGE_TIME2, LEVEL_USER},//30 + {EP_TARGET_FW, LEVEL_USER},//31 + {EP_TIMEZONE, LEVEL_USER},//32 + {EP_TIME_ISDST, LEVEL_USER},//33 + {EP_TIME_SERVER1, LEVEL_USER},//34 + {EP_TIME_SERVER2, LEVEL_USER},//35 + {EP_TIME_SERVER3, LEVEL_USER},//36 + {EP_IS_DIRECT_SD, LEVEL_USER},//37 + {EP_PRIMARY_SD, LEVEL_USER},//38 + {EP_SECONDARY_SD, LEVEL_USER},//39 + {EP_DIRECT_SD_CHECK, LEVEL_USER}, //40 + {EP_SD_CHECK_UPDATE_AT_BOOT, LEVEL_USER} //41 +}; +#define AUTH_ENTRY_NB 42 +//values +#define DEFAULT_MAX_REFRESH 120 +#define DEFAULT_MIN_REFRESH 0 +#define DEFAULT_MAX_XY_FEEDRATE 9999 +#define DEFAULT_MIN_XY_FEEDRATE 1 +#define DEFAULT_MAX_Z_FEEDRATE 9999 +#define DEFAULT_MIN_Z_FEEDRATE 1 +#define DEFAULT_MAX_E_FEEDRATE 9999 +#define DEFAULT_MIN_E_FEEDRATE 1 +#define DEFAULT_MAX_WEB_PORT 65001 +#define DEFAULT_MIN_WEB_PORT 1 +#define DEFAULT_MAX_DATA_PORT 65001 +#define DEFAULT_MIN_DATA_PORT 1 + +#define MAX_TRY 2000 + //sizes -#define EEPROM_SIZE 512 //max is 512 +#define EEPROM_SIZE 1024 //max is 1024 #define MAX_SSID_LENGTH 32 #define MIN_SSID_LENGTH 1 #define MAX_PASSWORD_LENGTH 64 -#define MIN_PASSWORD_LENGTH 8 +//min size of password is 0 or upper than 8 char +//so let set min is 0 +#define MIN_PASSWORD_LENGTH 0 #define MAX_LOCAL_PASSWORD_LENGTH 16 #define MIN_LOCAL_PASSWORD_LENGTH 1 +#define MAX_DATA_LENGTH 128 +#define MIN_DATA_LENGTH 0 #define IP_LENGTH 4 #define INTEGER_LENGTH 4 #define MAX_HOSTNAME_LENGTH 32 +#define MIN_HOSTNAME_LENGTH 1 #define WL_MAC_ADDR_LENGTH 6 class CONFIG { public: + static bool is_direct_sd; static bool read_string(int pos, char byte_buffer[], int size_max); static bool read_string(int pos, String & sbuffer, int size_max); static bool read_buffer(int pos, byte byte_buffer[], int size_buffer); @@ -256,18 +404,30 @@ public: static bool write_buffer(int pos, const byte * byte_buffer, int size_buffer); static bool write_byte(int pos, const byte value); static bool reset_config(); - static void print_config(tpipe output); + static void print_config(tpipe output, bool plaintext); + static bool SetFirmwareTarget(uint8_t fw); + static void InitFirmwareTarget(); + static void InitDirectSD(); + static void InitPins(); + static bool InitBaudrate(); + static bool InitExternalPorts(); + static bool check_update_presence(); + static uint8_t GetFirmwareTarget(); + static const char* GetFirmwareTargetName(); + static const char* GetFirmwareTargetShortName(); static bool isHostnameValid(const char * hostname); static bool isSSIDValid(const char * ssid); static bool isPasswordValid(const char * password); static bool isLocalPasswordValid(const char * password); static bool isIPValid(const char * IP); static char * intTostr(int value); - static String formatBytes(size_t bytes); + static String formatBytes(uint32_t bytes); static char * mac2str(uint8_t mac [WL_MAC_ADDR_LENGTH]); static byte split_ip (const char * ptr,byte * part); static void esp_restart(); static void flashfromSD(const char * Filename, int flashtype); +private: + static uint8_t FirmwareTarget; }; #endif diff --git a/esp3d/data/404.htm b/esp3d/data/404.htm new file mode 100644 index 00000000..a1dec29a --- /dev/null +++ b/esp3d/data/404.htm @@ -0,0 +1,18 @@ + + +404 page + + +
+

+ + + + +404 Error, unknown page!

+

What are you doing here ?

+You are not supposed to find this location... +
+ + + diff --git a/esp3d/data/404.tpl b/esp3d/data/404.tpl deleted file mode 100644 index 3f3c993f..00000000 --- a/esp3d/data/404.tpl +++ /dev/null @@ -1,30 +0,0 @@ - - -Redirecting... - - -
Unknown page - you will be redirected... -

-if not redirected, click here -

- - - -
- - - diff --git a/esp3d/data/config_ap.tpl b/esp3d/data/config_ap.tpl deleted file mode 100644 index 2c59ec2d..00000000 --- a/esp3d/data/config_ap.tpl +++ /dev/null @@ -1,65 +0,0 @@ -$INCLUDE[header.inc]$ -
-
Access Point
-
-
-

-
-
-
-

-
-
-

-
-

-
-

-
- -
-
-

-
-

-
-

-
-
- -
-
- -
-
- -$INCLUDE[footer.inc]$ - diff --git a/esp3d/data/config_sta.tpl b/esp3d/data/config_sta.tpl deleted file mode 100644 index 19955f02..00000000 --- a/esp3d/data/config_sta.tpl +++ /dev/null @@ -1,66 +0,0 @@ -$INCLUDE[header.inc]$ -
-
Station
-
-
-
- - - -$AVAILABLE_AP[]$ -
$AVAILABLE_AP_NB_ITEMS$ AP(s) available
#SSIDSignalProtected
#$ROW_NUMBER$$AP_SSID$$AP_SIGNAL$$IS_PROTECTED$
-
-

-

-
-

-
-

-
-

-
- -
-
-
-

-
-

-
-

-
-
- -
-
- -
-
- -$INCLUDE[footer.inc]$ diff --git a/esp3d/data/css2.inc b/esp3d/data/css2.inc deleted file mode 100644 index ae0d19b3..00000000 --- a/esp3d/data/css2.inc +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/esp3d/data/footer.inc b/esp3d/data/footer.inc deleted file mode 100644 index 3bdf08d6..00000000 --- a/esp3d/data/footer.inc +++ /dev/null @@ -1,6 +0,0 @@ -$SERVICE_PAGE$ -

-
-
- - diff --git a/esp3d/data/header.inc b/esp3d/data/header.inc deleted file mode 100644 index 3f7c4361..00000000 --- a/esp3d/data/header.inc +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - -$PAGE_TITLE$ - -
ESP3D powered-GPL licensed
- - - - - - - - - - - - - - diff --git a/esp3d/data/home.tpl b/esp3d/data/home.tpl deleted file mode 100644 index 0ad8c982..00000000 --- a/esp3d/data/home.tpl +++ /dev/null @@ -1,55 +0,0 @@ -$INCLUDE[header.inc]$ -
-
System
-

-
-
-
-

-

-

-

-
-
-
-
-
-
-
-
Access Point ($AP_STATUS_ENABLED$)
-

-
-
-
-
-
-
-
-
-
-
- - - -$CONNECTED_STATIONS[]$ -
$CONNECTED_STATIONS_NB_ITEMS$ connected station(s)
#MacIP
#$ROW_NUMBER$$MAC_CONNECTED$$IP_CONNECTED$
-
-
-
-
-
Station ($STA_STATUS_ENABLED$)
-

-
-
-
-
-
-
-
-
-
-
-
-
-$INCLUDE[footer.inc]$ - diff --git a/esp3d/data/index.html.gz b/esp3d/data/index.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..c502eb6459f5f2c9064ba419a07f8ed503991e12 GIT binary patch literal 79433 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

oD=aD1^Z=Bv80O;>47 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

{8V~id#28$KR_-NViYnD_xuI^mHY#1gUjpb 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 -

-
-
-

- -
-

-
- -
-
- -
-
-$INCLUDE[footer.inc]$ diff --git a/esp3d/data/macrocfg.json b/esp3d/data/macrocfg.json new file mode 100644 index 00000000..07b5bd33 --- /dev/null +++ b/esp3d/data/macrocfg.json @@ -0,0 +1,74 @@ +[ + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 0 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 1 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 2 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 3 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 4 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 5 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 6 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 7 + }, + { + "name": "", + "glyph": "", + "filename": "", + "target": "", + "class": "", + "index": 8 + } +] \ No newline at end of file diff --git a/esp3d/data/password.tpl b/esp3d/data/password.tpl deleted file mode 100644 index 6ae1d619..00000000 --- a/esp3d/data/password.tpl +++ /dev/null @@ -1,111 +0,0 @@ -$INCLUDE[header.inc]$ -
-
Change Password
-
-
-

-
-

-
- -
-
- -
-
- -$INCLUDE[footer.inc]$ diff --git a/esp3d/data/printer.tpl b/esp3d/data/printer.tpl deleted file mode 100644 index b7ea3b90..00000000 --- a/esp3d/data/printer.tpl +++ /dev/null @@ -1,870 +0,0 @@ -$INCLUDE[header.inc]$ -$INCLUDE[css2.inc]$ -
-
  Control
-
- - - - - - -
- -
- -
- -
- - - - - - - - - -
0300% -    -
- - - - - - -
Status:
-
-
-
   - - -
-
- - - - - - - - - -
0300% -       
-
-
-
- -
-
  Command
-
- - -
- -
-
- -
-
  Information
-
-
-
-"; - - -
-
-
-
-
-
  Error
-
-
-
-"; - - -
-
-
-
-
-
  Status
-
-
-
-"; - - -
-
-
-
-
-
  Print
-
- - - - - - - - -
- - -   
-
-
-
-
  Jog
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - X - - - - - - - - - - -
- -10
- -1
- -0.1
-
- - Y - - - - - - - - - - - -
- -10 -
- -1 -
- -0.1 -
-
- - - - - - -
- 10 - 1 - 0.1 -
-
- - - - - -
- -0.1 - -1 - - -10 -
-
Z
- - - - - - - - - - - -
- 0.1
- 1
- 10
-
- Z - - - - - - - - - - -
- 0.1
- 1
- 10
-
-
-
-
-
  SD Files
-
- -   -

-
- -
- -
 
-
-
TypeNameSize
-
- -
-
-
- - -$INCLUDE[footer.inc]$ diff --git a/esp3d/data/restart.tpl b/esp3d/data/restart.tpl deleted file mode 100644 index 89e84af9..00000000 --- a/esp3d/data/restart.tpl +++ /dev/null @@ -1,27 +0,0 @@ - - -Restarting... - - -
Restarting, please wait.... -
- -
- - - diff --git a/esp3d/data/system.tpl b/esp3d/data/system.tpl deleted file mode 100644 index a6da1266..00000000 --- a/esp3d/data/system.tpl +++ /dev/null @@ -1,108 +0,0 @@ -$INCLUDE[header.inc]$ -$INCLUDE[css2.inc]$ -
-
System
-
-
-
-
-
-
-
-
-

-
-

-
- -
-
- -
-
-
-
Firmware Update
-
- - - - -
-
- -
- -$INCLUDE[footer.inc]$ diff --git a/esp3d/data/tags.json b/esp3d/data/tags.json deleted file mode 100644 index 5aebc12c..00000000 --- a/esp3d/data/tags.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "WEB_ADDRESS":"localhost", - "PAGE_TITLE":"Testing things..." -} diff --git a/esp3d/esp3d.ino b/esp3d/esp3d.ino index 1337d23f..24bec6aa 100644 --- a/esp3d/esp3d.ino +++ b/esp3d/esp3d.ino @@ -23,71 +23,87 @@ Main author: luc lebosse */ -//be sure correct IDE and settings are used for ESP8266 -#ifndef ARDUINO_ARCH_ESP8266 -#error Oops! Make sure you have 'ESP8266' compatible board selected from the 'Tools -> Boards' menu. +//be sure correct IDE and settings are used for ESP8266 or ESP32 +#if !(defined( ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)) +#error Oops! Make sure you have 'ESP8266 or ESP32' compatible board selected from the 'Tools -> Boards' menu. #endif #include #include "config.h" -#include "wifi.h" +#include "wificonf.h" #include "bridge.h" #include "webinterface.h" #include "command.h" -#include -#include -#include +#ifdef ARDUINO_ARCH_ESP8266 +#include "ESP8266WiFi.h" #ifdef MDNS_FEATURE #include #endif +#include +#else +#include +#ifdef MDNS_FEATURE +#include +#endif +#include "esp_wifi.h" +#include +#include "FS.h" +#include "SPIFFS.h" +#include "Update.h" +#endif +#include + + #ifdef CAPTIVE_PORTAL_FEATURE #include -const byte DNS_PORT = 53; -DNSServer dnsServer; +extern DNSServer dnsServer; #endif #ifdef SSDP_FEATURE +#ifdef ARDUINO_ARCH_ESP8266 #include +#else +//#include +#endif #endif #ifdef NETBIOS_FEATURE +#ifdef ARDUINO_ARCH_ESP8266 #include +#else +//#include #endif +#endif +#ifndef FS_NO_GLOBALS +#define FS_NO_GLOBALS +#endif +#include void setup() { bool breset_config=false; - long baud_rate=0; + bool directsd_check = false; web_interface = NULL; #ifdef TCP_IP_DATA_FEATURE data_server = NULL; #endif // init: #ifdef DEBUG_ESP3D - Serial.begin(DEFAULT_BAUD_RATE); + if (ESP_SERIAL_OUT.baudRate() != DEFAULT_BAUD_RATE)ESP_SERIAL_OUT.begin(DEFAULT_BAUD_RATE); delay(2000); LOG("\r\nDebug Serial set\r\n") #endif //WiFi.disconnect(); WiFi.mode(WIFI_OFF); + delay(8000); + CONFIG::InitDirectSD(); + CONFIG::InitPins(); #ifdef RECOVERY_FEATURE delay(8000); //check if reset config is requested - pinMode(RESET_CONFIG_PIN, INPUT); if (digitalRead(RESET_CONFIG_PIN)==0) { breset_config=true; //if requested =>reset settings } #endif //check if EEPROM has value - if ( CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&baud_rate , INTEGER_LENGTH)&&CONFIG::read_buffer(EP_WEB_PORT, (byte *)&(wifi_config.iweb_port) , INTEGER_LENGTH)&&CONFIG::read_buffer(EP_DATA_PORT, (byte *)&(wifi_config.idata_port) , INTEGER_LENGTH)) { - //check if baud value is one of allowed ones - if ( ! (baud_rate==9600 || baud_rate==19200 ||baud_rate==38400 ||baud_rate==57600 ||baud_rate==115200 ||baud_rate==230400 ||baud_rate==250000) ) { - LOG("Error for EEPROM baud rate\r\n") - breset_config=true; //baud rate is incorrect =>reset settings - } - if (wifi_config.iweb_port<1 ||wifi_config.iweb_port>65001 || wifi_config.idata_port <1 || wifi_config.idata_port >65001) { - breset_config=true; //out of range =>reset settings - LOG("Error for EEPROM port values\r\n") - } - - } else { + if ( !CONFIG::InitBaudrate() || !CONFIG::InitExternalPorts()) { breset_config=true; //cannot access to config settings=> reset settings LOG("Error no EEPROM access\r\n") } @@ -95,114 +111,78 @@ void setup() //reset is requested if(breset_config) { //update EEPROM with default settings - Serial.begin(DEFAULT_BAUD_RATE); - Serial.setRxBufferSize(SERIAL_RX_BUFFER_SIZE); + if (ESP_SERIAL_OUT.baudRate() != DEFAULT_BAUD_RATE)ESP_SERIAL_OUT.begin(DEFAULT_BAUD_RATE); +#ifdef ARDUINO_ARCH_ESP8266 + ESP_SERIAL_OUT.setRxBufferSize(SERIAL_RX_BUFFER_SIZE); +#endif delay(2000); - Serial.println(F("M117 ESP EEPROM reset")); + ESP_SERIAL_OUT.println(F("M117 ESP EEPROM reset")); #ifdef DEBUG_ESP3D - CONFIG::print_config(DEBUG_PIPE); + CONFIG::print_config(DEBUG_PIPE, true); delay(1000); #endif CONFIG::reset_config(); delay(1000); //put some default value to a void some exception at first start WiFi.mode(WIFI_AP); +#ifdef ARDUINO_ARCH_ESP8266 WiFi.setPhyMode(WIFI_PHY_MODE_11G); +#else + esp_wifi_set_protocol(ESP_IF_WIFI_AP, WIFI_PHY_MODE_11G); +#endif CONFIG::esp_restart(); } #if defined(DEBUG_ESP3D) && defined(DEBUG_OUTPUT_SERIAL) LOG("\r\n"); delay(500); - Serial.flush(); + ESP_SERIAL_OUT.flush(); #endif - //setup serial - Serial.begin(baud_rate); - Serial.setRxBufferSize(SERIAL_RX_BUFFER_SIZE); - delay(1000); - LOG("Serial Set\r\n"); - wifi_config.baud_rate=baud_rate; + //get target FW + CONFIG::InitFirmwareTarget(); //Update is done if any so should be Ok - SPIFFS.begin(); - +#ifdef ARDUINO_ARCH_ESP32 + SPIFFS.begin(true); +#else + SPIFFS.begin(); +#endif + //setup wifi according settings if (!wifi_config.Setup()) { - Serial.println(F("M117 Safe mode 1")); + ESP_SERIAL_OUT.println(F("M117 Safe mode 1")); //try again in AP mode - if (!wifi_config.Setup(true)) { - Serial.println(F("M117 Safe mode 2")); + if (!wifi_config.Setup(true)) { + ESP_SERIAL_OUT.println(F("M117 Safe mode 2")); wifi_config.Safe_Setup(); } } delay(1000); - //start web interface - web_interface = new WEBINTERFACE_CLASS(wifi_config.iweb_port); - //here the list of headers to be recorded - const char * headerkeys[] = {"Cookie"} ; - size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*); - //ask server to track these headers - web_interface->WebServer.collectHeaders(headerkeys, headerkeyssize ); -#ifdef CAPTIVE_PORTAL_FEATURE - if (WiFi.getMode()!=WIFI_STA ) { - // if DNSServer is started with "*" for domain name, it will reply with - // provided IP to all DNS request - dnsServer.start(DNS_PORT, "*", WiFi.softAPIP()); + //setup servers + if (!wifi_config.Enable_servers()) { + ESP_SERIAL_OUT.println(F("M117 Error enabling servers")); } -#endif - web_interface->WebServer.begin(); -#ifdef TCP_IP_DATA_FEATURE - //start TCP/IP interface - data_server = new WiFiServer (wifi_config.idata_port); - data_server->begin(); - data_server->setNoDelay(true); -#endif - -#ifdef MDNS_FEATURE - // Check for any mDNS queries and send responses - wifi_config.mdns.addService("http", "tcp", wifi_config.iweb_port); -#endif -#if defined(SSDP_FEATURE) || defined(NETBIOS_FEATURE) - String shost; - if (!CONFIG::read_string(EP_HOSTNAME, shost , MAX_HOSTNAME_LENGTH)) { - shost=wifi_config.get_default_hostname(); - } -#endif -#ifdef SSDP_FEATURE - String stmp; - SSDP.setSchemaURL("description.xml"); - SSDP.setHTTPPort( wifi_config.iweb_port); - SSDP.setName(shost.c_str()); - stmp=String(ESP.getChipId()); - SSDP.setSerialNumber(stmp.c_str()); - SSDP.setURL("/"); - SSDP.setModelName("ESP8266 01"); - SSDP.setModelNumber("01"); - SSDP.setModelURL("http://espressif.com/en/products/esp8266/"); - SSDP.setManufacturer("Espressif Systems"); - SSDP.setManufacturerURL("http://espressif.com"); - SSDP.setDeviceType("upnp:rootdevice"); - SSDP.begin(); -#endif -#ifdef NETBIOS_FEATURE - NBNS.begin(shost.c_str()); -#endif LOG("Setup Done\r\n"); } + //main loop void loop() { + //be sure wifi is on to proceed wifi function + if (WiFi.getMode()!=WIFI_OFF ) { #ifdef CAPTIVE_PORTAL_FEATURE - if (WiFi.getMode()!=WIFI_STA ) { - dnsServer.processNextRequest(); - } + if (WiFi.getMode()!=WIFI_STA ) { + dnsServer.processNextRequest(); + } #endif //web requests - web_interface->WebServer.handleClient(); + web_interface->web_server.handleClient(); #ifdef TCP_IP_DATA_FEATURE - BRIDGE::processFromTCP2Serial(); + BRIDGE::processFromTCP2Serial(); #endif - BRIDGE::processFromSerial2TCP(); + } + BRIDGE::processFromSerial2TCP(); + //in case of restart requested if (web_interface->restartmodule) { CONFIG::esp_restart(); } diff --git a/esp3d/esp3d.ino.nodemcu.bin b/esp3d/esp3d.ino.nodemcu.bin deleted file mode 100644 index 19532b137525531e24c24394f42f6ea3a1e39689..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372592 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 L>A;@yFU5@3i zML-D;NRF63#SVS66XH83|H-j@!az(!eA}{b963?qw>d$Y%nm!eM%Bua{xP?#k4I*= zWp^vm#*>#5tiXikd*DgbXFC%-HoUOePHcE##pcvoz{4D;G?v9;7R2iuQi=AjHt=>k zMX2>t18Klm{R_m@{?Y^K`(HUBmX5F_t95l$PS)$%pg%9QdZpQ?_+}SM;At#0h@ZbW z)F&widx>LGJQ52lcCyAO1c_jNz%vE)X9rHdB3pci z17=dDCHkgyIc`_VPcVlgp(a7O^Mrd^S1vn}8(;bQxvhH5Zpw0PD3{X zF4veez#vPv{Bhg7Cnd+Ieos!cffS^lDTql#6~V_ll%IEqyFM&yHiP@@*cr9H4Mq5c z;JK6ab%Kwyuvp{h4f7PA7?MM>X-Ceu`*+2<7>8T*#xtJ&UEZ8*Yj|rr^vOMMZ6m7( z|1gML8_2DMtr#MeZ;68TkHyzNv2=`8Jr%^9#mUx*i;=W%sXD#sKn+Dom`r^vocT9! z)>b)`lgD|JoG{dFy_dc^E5q5Y=Y?TAryZO zNZE6=32RZG3f82Ng%SQ5^>JWb-jhL?Eu#S%7JlZ@@K=S=0tdKx1od-P?HR}NFCx|1 zH1_?&^eJ{=IND3(E_5vKP7_$j?$FQ4m{5Q=r}mP=ySQq}xc6`Q9H$%L*R7b*i~>_% z@Bs!nfhH04H(|b=#;A1Q64R7bxc5m2={I7Y#-4PjDR^#@w55)`Td}|cu@kLYUz(rH zqa4j6G!-b~G)rAc5S^a~o!=6xa@%nv$>SYreA^~4QGXttCxlMOJe{f5p94pMs#u
#KdrqBfrcNs`1CIQB~6V?ny*O{hjhpvI->ST6ga3e`2V zzd6qVEq7EJJP({h_U1Z5r%pM|T(k$MLOtMU4x_l3%)XEN_7VxryAG^2>E%6K43zHB z2PK{0iSoWr-PQnG?NyfM;IY!JoxIN3 zr?e@wiFE>JkcZdthaKutBJUwbVI9U99HuC?YV)E%;S{29iUUEPK1V_ISq}9n1m&|3 zbfQc_v5?T`Ago@7uv!^~U5yaK>)1?$L1AK)!6uU)LB)9ox>7Pbz@Lm#Un4&91rD4A zf%%ZCGpI1yL`SzRFugiJeeqnt4vUc$s}1!X3dgFcBEWLRXAb|?W4HvWRPID0Chd@Y zj$AZK>^_HDhJ>}hfXN~k4*plr#m7;79OqES0gr_GsNLgGOA(OWgMcCr4t*wN;AYC~ z%_x{gjOVQUQdMLD@*aalIY`$Yj-r~25L3`Mq)XaE@MI-Ko;KPcx&OS57RC;D7xo(N zDI74|mzPP^bm;JWRNRtrV}_3zUow0sD)JR!t`=dk##~vIEgPG$w|p9V$N*I8`Z6mH zxb~Oc6hfH_vT8tBxqZ~k$?%;I+f5UNzl02Qt-Pn78g%WK}r*Md${fVSk z*&a@vQzH8hcJWYrx1&__>l~X^q|LrE(5lD~|JH!N{`dr2R(onJ8W=5bA9rN6<1r5n ziL9LR4b=Lw936@g=4r4s;NdF3YCshL@}whq`@c92D`}2hqa$Zf&b7o&INSumbGoe8 z1|T>)ZNNey5{0ghp3o`FTJC`t)5+_EfgX$q+Ze!c7h=j+fsS#h!?s%CDd+$Ic7V^b zz#pW!YjnCDC3oJ4oI&Q?w}y?{H|x9#HOuB#k9!S1*DSw}15lAjm-!cg$_Jn$0dhVM zc>25eoObBEp?p6i_unC9;_ELa8d5hYdI9nu)RR?!MWVjoUW9a_D-C!}mIn&vaS)B!K0W#6Ag-SuM;70-~b-+c1S|9|g!79sdY>JeubsZ_mx> zIBU181?ArgSsow*@0Zt8?r=zd}F;AP#V@31?F9yu{zLhG{GxnProjW<}1>|Aj(>nB_Gip(isl zxH_=^v9si;zaCJJQ2}qg06i9G}L8^uFeO<5@c4SDIL)Kpl>`x?09Q?Ha z#Dj2oH2@VwVisOD!a=JNY4fW8XWAcKOdF=tB4_ZI1N*NRd4?(A1Sf+i3-$RWvuK|W z;8YSmUko&#$KZ}x!}5TNQ|>ZbE^@8C5K#X~#l-MZM6~c_0WzH->q|{qp8XSAvM|6|$H zlDB~_4)tn+>3y8MzcfmpbK{r11E$fxTZOmwyIeU30sd>$=3&mX4ykKxW`J>K{3CMd zF9B%fU`)Co5c6Avhklq4zhjgJB`RtwJ7@adEPUA^^8J@l+9R6E*~(jmuQtZ?JxIQ9 z7^T-o;upTBP2bUGk`3hhno)XtCur+{pcdh)-(>pkBj1;hUxuXte49*ii-oWDi9Fa?B0=#s1moLebrMum*gm<~F%jjC2@-#trWadf&laq(HCx0V&;RcDRLN}wV7lPB zAyyh>Q`?L|KK%G5i~D=fzrsEg=C=tRi@pGRDgfqVo! zA-jE3#F$^LwqvRZ13{r#Z)mafqwIh1Xu5SLraT$iLAe;~9h%{MOBwr$486jg9gv}P zLzOh%K|;(#%CeRF<+}5~WAH|A&?E(<<8o;|L}LiApOi{HjIP7LFrPug`yLs`#c8dS z4{Ys{7jm|IOnV`Nvg$VA(ofOYO5xKi(7tCUp~jHNJ|j}}Pw|_4z#jN5seW%!%!Zn>zW#lf z=uXOkd5Ej)%lb5wd0Wa-`IoY~9BY8F`WJFt{86#Phs~2{+zBc6P8JEjI(h%Ic$tK) zlR8wsA_KG@{Fl7uc~yfKvFTGe-=B!mp&f!>B5BPzi5~@1*<0kT zzlmR*p>wE@0&61s1U?uQKSn`8X&+uJ1CuVkN}$58(iIkmBs+Ffq6feiMIPEr!J33< zIwbGE7YP#*zE%*$_6nkSwVcp%6xQ0nl%l;y_;MfwPhmeqsuM-hL0NJf#%{`O=Nl1U zdj}e6Xy>~ksh8$ef<W(f%PPyn`b|ILOP^$jvv2;8+vE8 zou!j$#f~f?!@|O%XkKHDVjF~5NRHK#G=M)viB&r*eL%Sd3mNTmG=H!5nR(Vw#qkpV zSoQ_bk457AYrJHz1^CU@pOn?6a}DVvkKoH>AO*U7l*+nD^*Gj6iQ4{9IUYGj<;a$Z za@5z0a@3yyjzo=qQ`i%7!ijiMj@t9Gy4MW;d`Btr52&}CE$`n>SW%t+4s0m$zh5jz zj)59GhlG(o3QuI3zk)&coTy{`87fGM3Nf2mkn9_?AlVBPhdoSG=no+#e@IrNkmYQ& z7ImG-MTLy%t(8?=EKqJBp#C7m)EQoFQM)Y?^=!A{OQqRVaGH@ z{}Alu)8z^mbznjeqgBBPi%3?5ku2TGswFJatiG~j{eIb}B=6~^9>uoASVnCV{7>ZX z%2E%acq&n>J>@JdX)EnP)q+ATl+|A;IDZGeUhQ@2$N9Z@&t~_^ss^@Fq`wK0sigE* zBh>|zNA|TSsV?dqDo@bO9~NcBR*JG>cOhb;K82$5DRRQ~xSA9S$NDUj)!LKt{^=&G z(P2DziP1&6gukkau7 z5C$pU-%;c#4D%POb{pYhx5;WT1=R185f&Kl>nJN4s!(?0MUvy>x?7HdRhS_xl&Ts8 zQtO8pU4MB?F;#*l?7y3bM`5H zsz8^*rVzRzvbXssH}fblKP|zKk&W`7Zz4pNsm1Zd0%10rOTn{csXL{gEtdxD1s;pq z2UKKW1SqZVl!tSj{;7y@KQ*utbJLG6ZWB35;i8i0WFA|aL*+QlD1F|d_9X7>kAXS# z!tg>zz6-TSsp-bDKLkZETTUw<8n(h-vPv1&4=Hqd?ali zG#peJh0y+r1V|j44e>l zC<<~2q4lF?6pi|c6sD)6mN@? zDo&ANt%ofM2xbPs{wdWNh`ebkHH~UTdKU?jG+;LDS z#9hnihjF-$V%$jPhfI zaVE0>vsACWa57Zx!YmO`(7W=AGSFb2X^R~<^SK$~OTN@BLqfa)77}IB{w`hD( zAFFr5@CkilZdCMq(0<9fOCt1N!=V4V33JJV&>h={=Q)4`d)+C3Y=E$D1p7bc66gH; zP;1?@66+WtBhW8ZjvIWK)Bo7votT_Md#cpYX}|T9uX@qo9ISFY zvI>j+GY)I7O7}>khXtAs7;5+tY|L0M{HW())S^{C%nDiAU_(tmh2|BDR*s0hsJ&Tb zuXMqqcXd|I4=G?lOCE0_Z8YV!!&otgD^RcMv45*^G@U16KNY3#!@jt^ruR@7o3PN; zn-)v+sKe#`xLPX|SC`?OPo3Y`?wQNtksq(L+oR{gtwXV`Kt>|!_7<}eDZ3lBzS!cz z^0fSOCJF7HMZ4^$gC@+Z+|=4X^Ve z&HWDJWNi3po$#p?Ck_boxKu^om&BBdiTW#ibVtQKy>~%(isxmc?pkBxN!_ z`&Ok#;*KEgw4~fYpOxtm^ULD3Q&Mx$(b=aiU|+V_&hBkj<~7bf)i!P=uqB5Jc$GrEvUt!nau9`$+r2d`g>vSm`e}?c?3VijFDvWFE4HC&CAT7ESPJfE>$P^98<5lCa>OsN+P)U4*agQaJr_!Z%mYr%Sl&p78xBsS}C5bHRyLDb6g9#|Yo! z0^e7XT8eO9{d>t=XYkgbI+h}w0pb#W;{7N?FXYEF5QjfXaTxu2wJ#-X@#BSWm&8IN zQEv&Vg+x-z6)`njmrdJIL=63U*?LJGLNT#qQLiT=*~uV|DS@UF!TYhjgj7YE`n{B& z2PvjLlVb99lA0+Zd?Tr`6yf(vxn~a$h0{gok0kYK3a8adY9zw3BbUNy_Ypn!Q#k&C zBu*S9vW=3OO!y96;u53O`F#T4dlIa`!uwzl-J_&0fRA>sW2NF&!wbDy;IXk6ie+qYDwkshhnOY@a@RWi~eSiJ=E$@NA4`l1ceQ0$T6E4!C? z#^8GbzGLt`0UK8MybTY0;odx|83E4jcu!t8CW{mL8m`B!H++8bsVyZ7-%l zN!riB`l3zsMKz`xQvFo5K}o6+ml(Dv-ArQ*kSAe(h|YQULgzul*iLg8Q*k+)!pYZpVBT_vmhfEr6c! z5HLgI1+zhZ-oU_kzc;P2#GAcqa)HIN3&*@W4xsPCso~HO^p1;}E}p9;qoHK-ZO>Y- zw9|v^jR;~Ggp$by8Fz}|8-`eLt~RMg&kLoibw;|l{>z(|DYdvF!N@Z&+SqhMN!R`K7cm zp&;vmp6VnvSkA9b!mI_B6`V+3f6#~?g3-AMGDggWWq!o)PDB2ac1^pSj%LtNw`qT) z|J?hb1FdG6K=!vaZ25rD5nl%@#D*{~p8bb}06;c@*zN1Ij1C@I;&#KpFLp zO%sRD*$@bGvmQVjQiJCnsC+)%$v!3>`!pG)`~b`Y;3zuI9Nx-ucljc{t82sYjX+&gGe_FPGGHhep2%#m1syiLZtRa1npn;VHZJ?2;QuRotJ+ z|Bb10lFy&1Jttw|hj-?OH~{gxdbDTAPn(M0Og>doT)*X6TD`WC>UEeecfFa#MOK`! zT577-eCt=YG-0@WOlm2+25GRrq6Xn)X82k%j@^_oi@z(Czy2G<*r<4P*PnyMU}KRI zdj$JBXmBp^naLi8q&F$wp9y45l&n65NZ?Z>oSVBowf|RSnGPh)qF|^l`y@|UCIy%* z`4oC7x7)%8Sg;AC%?t(kMG8`HZHE(`Ow#ffi>qPI19{Il5|G@PcR?`yl?)}mxCUt-M(PnRc`W$9fbUL(_HekFPwrg@N(FILI77fls^*AXOd(-t*5j17HlV}tu zR#d0~_?^z^ced_BK`-p9aC$E5>d{py_^uwVq8p$w6$}w|hyTZ{J6eBHcb4FIAbGRg zj=IBEhZ>WXetF%|-WToVvbv+aXSyu>{U)k9+Pjjv^(08)V9Hi>mf8<(v(Hd*;SyVD zsGzf~Z{sha*U6-MV{A}$N|gW}y)^Lt2W@;&vX_i9a z55?QUM_F(X7jdQo()=$(Mt=248umpu_)*JmzB8qpTSbA3pf;gcG7GL$LkSG@l)!&A!X_~z8dPDR z8=xUU46NNwB0s$(GGlO!ns^f3sRwIweekJ*5kZJTi&%cNH|7xP9BD&h8o(b$7f=KO zILXVCxEc)4ML^}6Qd

jdbd*vO175OZr}slG*^lUZx&FMQvu*p~Vu>S}O*XB-R?O z)}6phqojpP>NdP)vTzjLH3(0+bm%S-`V@uc;x|Wb!~p>0?iy^^kTsGd{T0d@Z^oI| zbzUh$ovX)1Y$BdOwr4ea0-X{~Vkc=fzB8rcnK;nTx)>=FEB*Q&r)Yqh7+Q?tQ z<#?rQg0-D6VO*1}%+-I7t^<|T>+lXa-U!JbeIQ|FQ^6q^su_woi$}S(M#-;N@*0%f z7G=oAIXe`@CPTOJDtn|lFu|c*Xi)uU*dx&}bOV`HZf5c*o~%y~8M_fSQnD}y%BA_x z8R+o<8lgM19WViNs|9!tgHBHho{0bnU;z{&{3t*Zbet*yS&jo--0Po?u2+wxt1~mcp0k#8<0nbjt1*itR1Xu_-hPD7xi(GbXC^@ z`Pg5W9}u7BM@68H9mHbe?Xcz{t>x|l5Sin|WOH1bnhinBR8Wf(2XF;$(5ti^&=1?G zr-qQbt+Wb?#^i|zH@B%bi3m5h)h1X-T0zciY#Zbi2(682D=o6BGeW4ek~Z})cD<*v zk~Weaz7Ylj%W(xZ>M>4m;k3v;&c_ahg0g;7o7$C-^PAd^P4GHKmlK$fsytoZw3QDf1O`Q-Tp{R{d&D5j|f@(d#4acnoZG1!XqB6u=sM0^4ppR6Tv9cyf%c*GTpV@HnmOgC$|j~n#EzN&nWlw z5qR|Li9OikzP_z=j~$1$g{zh$n0Dd}bP|Pp6Wr(7ZEA1Au3tyEVIGCbL?7IyE+pK1 zFckO~sXYz!9@-!(2W>%Exf}h_RJEH?OBbHT|-j%%o5;Bwoe$M;K${v(R8URzwXwAW*s1d-qj{e;9OE{< z^o%xj(g9De7~Xtdl$w^>=5>@P*&RjB?+;-3eIg9fmU53R{AH{GePub?oG_n~gA2!N zpRS3CQ>Yp|<2$f$RUH z?0w*(DzpFbnLBfb8Mwor0mpx+b1$faf^f%wgMz`xMN~*7B{EG1U89yVjW&1J%Ct-F zHf^T0SyF-7pWTmbX>Qx@S|1=UYGEl^N-L%0mX;cl$;|L)e(!VdfY`R*&+F&Q;okfF zInTfIoadbLJkL3A(E;Zt2_1&vfJB8nqz9MI5L7#$ynptW_hl4z)Y|$AlmAC6On#gS zd%V9e#ojeHUDk!sc~F;lBV7DQ)z=`(Z}&s|oFKOLL6lz6AWEAF;^r_!8j3iK=e`di z#>!VB(fTw!Q1@yi?JiX)F*wvO$x+38wm+toE&2F@Y?~s!NF7U~Z>Q1!OdBOw3qXfH zt@XK_&?R2Na!Y-##CM5XDHzlbuTNrqu8<YVc{?V^ugLC=*w5xR78ECS4GtIY9U;g_}g%O zqL9YRHffM0_y-2+-`5Kg71<^5LpAjE_Ets0Os+ZuR+H7=RmA*MhepS}#eLgO_1Y zoJgC}9;B^Usy*8tr2C^4^7lc}MnQxxD7LozX`J zp4FLNB%Cy9u%z!OpZM|>_4*(zV^aZypXY<(%rLI9c!vRLZNWPi3?rqq-6$W{MppSE zNakPE@%mb81h~2Pi~^sI&g`hsWpr%QI&(o((;Mo(YlZSvunHy>sf)9%@;^~M>UH+> zaPQ5F63NUmwf0Pqy<>_}8^-^WL8W-I_^+NG&>zG~U#j&#*)wL@Fzn8bxgml6&Wjd5 z>lu@7#$P*_^G|z}Q$hUI;GLol`kOJE;kh;`%F0%U(X%@_P z;0Bn`M*%(07wanb108;AXu{gUsbC@;rai5P|Trl>3zUz$-fon z5gC3Kn8pS^znPcX_`D8&CUNKQ2=FH@ZSIruFE&shmR^%3xzKK!=hw+p{F@%sk0 zke!HM*baUgzjqLpgXdX1b$5nBx>5Me=nd)CcZaqdHR$}`f&WJQ0X)m`oP>KGiQBM0 zh~I@v;A`>Bz%L8Gh4>k9ZgB(n;ZnS>#B(M1=q}6~#Y(UOW_n%5w=Lcqj7*La9b51YmI__Y@r>_+30-AL4N4 zvcTr@j&uu77tTQmUY>t91@PMG-WS5H1Y?YwdxGCOaCewN-Yaikm&q*yIfpKvv|!2=PF- zno_oxiCLq~U$ejQl`?SVmk34-L!%0UPaHe^ekrkZu3P*)SR&k$42tBWPp%DK-ti^v8d3$%#Ym&nYJ;>Zv*D9W4OO@( z`;0W&F|655Y1k1+vpWrGLLtQJ%tHlK!?;o zUZv-5d^1t@-VwADNZ|ceHXh-dJ?Q2b>REPbgxU=GPf@@C?KOnO0cly7g&^Kq%_hS* z#(-?{L@gT&_5})Ub^N-uY)V(8%1LXbap7#k@@RdPGPG>UPGp;;W>frHHpw5UvdzeL zl5U}eOS4iXl~gU8^kNhtrCQpL;nJ=|LY;uEz9@mSj(uwcxKCAFS7t#7QN761ZiUs71n|T0(Yml*&Nk$WBn*c$7A330?f;vD?x~iAmzW?1~~T8Spj) zkI}v(){KXO*nuQ;c_>Jxf8__&j8nv;=cc*rD~zxtZ8sQ224{WU?{LtzCU0up6RMN3bW{1 zz^?*!kH@7)&)&zb3zTfUA)f^p4F(h>1Y~)j1g?-bo&%D&YA7KoPP`O|QyUl*4ZfC` zy)97U(W%q~V{`1L(^S@7F^EKo0LCr}G{Xw zhrgu@)jg4(`T~0@i+w8bAJ~YJhD8ayn@z!bnHD1tje@yC>`o0u;1nqJ#y%Y(Vk;_! z9fd`WQV*uo(iknZJxcrwMcOgBGUw)byqU#(W-07Ox<4BfY=luE-?u7av1hQ}VIn-m z?E=2)2@h5MGUmf5Fzo>Q9bq0w4|@bJM1$m}NO3zA7#qbI8*Mt@0rBo{(_%1{r5KvZ zV6L^VXthEkvBnySf(#_!P4$Qfn9Rr1fGPhftNO{jkmT(abUUwCQ{tB&Z*+lTtjM5;jbT*2d zGsm!O6z~f%W1otE*+H}+DvG=_$H)excNf=}&zbBtpk7qsZIpq5)Zw1H2>ph5SN*y< zNd?Sjm4QYa{Lj*QP-%)(aY^k#_AGT$Uk^s9J%}s$8iDyc#X-P%CsHh=vb*8dQR}~v z;r{E2r2flAB=u$xb3IeCXe|hU%us~_2&9URLq!1tMC;&r)W4H*4$nKiFbDu?Spa_>J_?{NTVB*BAoEe0mj>@nvbeC{?Ew|(jiY=E> z!qlL4N0%yjOSdz|w_9Dr%pr$g5MVWw&S-Ozc=xF2fsS}Dv>S~=?~$3 za}fL#@iq89j_+SF^ldB_zS_g$HJMc!Eh|vjl>~Mgs>0bM({diJv`%Gr`^1{jK4WNW4O`mWZj>*dIMtqYk|5k%|3u3F)*oP2XO|jCSO4)I2hdcX@9q_Lj;kBa8V`7k>+C(-$VK z2#5LJM+?UBNG6q0kgpZ(#e7Bp>s15pLkH0WUk>D}Lw7F&;ap_Tn+C2(ttNX9;Q*cg zuaKTH0g*8PpcfBe>?`2W7L}5hfCNjNRjT!$*gAqZCc=B=l}MbBB6@Z)Aihi7^o0O7 z0-P>`z;zx}=uVVW3Mkpw(po3~0kF-0jrHKy1Y5dU#jX;XG2oD}{=OY)->P@jVkfF= z*u+AkbkyIpl_LF!lpaSNJZ!bUq**Usffp>)Kz<<-R#d14{|<=NRD-jq0d1CDLTCk5 zp^U14Leq?j&!j0m(W&x0@Bp_6$Mn8MM?$KTDCwf*pQ>%DSKNOAvS7F zQJ##1C1|4CCj;W0Xo_+o+?0LcGUP=A%aDIfWk?saGIF&tSdZGHxmp>y+)HXHW8WGD z&IlbwNbpFcxSNVmjs?W|-LzyJ(+2ICa53z>fyGGoQZdTEwPHM4G4gaOMw+e_<9WMy z1h^w@K;%gAj|3hnKhaGC@}UMDib$;&XRE!aj>ok8;ZJ8>xJTDVioc?|Nbd*4LDZvgGfU`sTNtpM zGZ3)65`f!Pz`zawmeL5Yk_y0C>^cIxQUfgAA1Rg*VENsE7=p5teHVbm*}Z8krc+CV^oF=lr_jerAyJGU7(EYm~G|bMp zcnO~6*jMqDACE7{-(Bo06c@v|Vi32E{Ts!>&0tIpJgKp7Q=A!Jx$uZ4{gvWad?DZc z(msmQ<7+0I(8+I6TrcKpR+@nWIg#E(fGLOoH~hX$6S+M04TMzvs7K|5+MKYU@w(q< ztGcRh{9dnf)h3{Fq)@7H$WN-1Jwc4dWS4J@6v+df87Qkvi*(geMM)sp?r%P(hwMQP z7jf)lyq1`%_xFD4{6VRSPYv4uSGEH6Z}z zxoW9lXvtQ86QD3c5x%oxU8;ce2Y<;%YI}c2hvCr98^-10M85-UgVAUS%5u3@@qHiQ9Xm-vt_R4H!zp z0r`I6mmfm%)SSy3Aev-H6a5_qnaAA2HNwe323*pnk}9QCno4sx&B*5avl%szor3iw zRdjYiZj&ZQ7Nh?b!7?>cjeSau5xTI_Opg?K4G23ivR&NZN}7mVlqFM5G#rU!F>)^U zJ5LUq7*s_df7N)@v+Ha0pVDmsZFd=R;0X_-qQuiek8r@n8UvXnf`Zxe)c?vki|Flv zz>=y7KROa0zxbL2o>FN%RbOOaZH&IgfiRRvnP>`ubplFXD2XT?DP%rUJQ2hT3xvTk#^ieVg|oI=#ZRbCVBgHqU zIfE!rPF4ezgh(+H{U#-7ovBu5)yw}7pZJcAj}&{m2|jJOp*F-UBzhH=VBt+<#-@o_3HTI(i{if9qy?64m$2rHhO9j)K-vl~b&>R$)O;E&^l~&*an8M{)!8k%Xh% zO}PBQnt*4jJy76To`z?NQN^=ztqF<&T~ngiv<4U=#T8UphWe|xeu*Y#E9OY?;=ch+ zuVI=hW*5v)+CXx)ifA3wUE&Sj5sB`#h;L9I%7q{dsVe!v&i?;UkTf@-;?K-gLPDCJ z=KPLsc1}Ru40^7+DoiV&(-+G-rJMk~NvHE4R5cozl9 z5`xacV~&VT_2OE`nUv3~)11)|PE>JZ@d9>xSN>F>DfnG%ywoS#AHi|Mn~PwPUwW~t zB#RSo#tEZjDK{XFQRU`(z%?TV!LI5;?Hw47RYS0Y8(*ok{>i0D5J2M~_so$B}w>u!tRlnW%291=b2E^GE zpiBwi6M~vFC7{l|Vrq!|9Jc7uFsKORoAK(~uL)w~yGTW#18h%y@=`tf4v_&li|)tM zA9)6@%tMtCP^D4j1zLH)@zWC$D{d!a<;6EW6KFN7#tU(eEWJPumUmci+(d^!u{A&m zKCu+n=&+tZU0}M4SQ;?{fLNHt9+Y3+i<)qQOc6S6M1D^QOE(E;OPNNPo7W^A@1n-{ zyE&uByJ*%{#`Ix#zS7O`D)xw+r;9Y{%PadXwnwxElKm-VV_lOKx%JK>%dr1f&;pKK2pigM*a z%fV3-v#k_eiOX4@`btU{BfrIpUYwgLS58@o^C*|rgUD2}>n%Ug1>9K1->Bjs?Zrrw zG<*bRy8GWeUC;$YFW46HKBegb=w#7W5*%eq0Oyy0lz8@>MTenlc34CqaFQwuZ6oa@FvD?+y4T#;YitPWxa-+b;rW?eY5$mH^_94Xj)Yv}(ZdHmwT!6R@6em4^ zxD6Diyo$KSWP>=ji)vdb{}!~lG7a{rSQ7RNVT@i}98w#i{Mv$JK4^)&i&YgXd=jTA~y~v|^u386XdUYqN<*H4jjnf@?cYy>z9Dc5|4g7fY7%1C5 z=)|1OfT%lzv&nzMM}8VUrl$(Z+xUP??c&qnx>orsr5nSzqLbmjU1_AaBz%pAPkTk7 zxKRv>6lzwI{3SO~{BVRM!jC+KNcEHk0(Q-t@JpoI(;N`H^xFhtntH8uO{0n zFR8P^4-Eq5&vJ|Cfo}c+n$H%2oa{$!hE0SBEY)^4web(Nu#z5FRI?v)%3O=9b_~Y= zJo~3k5`AeqPA?RVan(|_Nql{^vrqO-cGXht!4AFBN%AYwjnLUo>@3*|5w=pC z5+oji;_53AC;M>VsvP7?{sVMxgkPwebc2cwiKqd!8OhKMFLaU&TM2$im0=U{4!!5* zzU;q8b`6)L>6DutiuO_eP>(6kbza2esJt*i92}J7a31MV91e z35u^%I(8=l_p8k0AA@3mxFMy+UtBvzl@(VBnoN5+AiwA*nYNu+t~9;4@GHo)?_E)z z_G8H(cUheO6`1=BO-3jr8R2)GBqPjIifDp^94zTnC7D8)dqIp;h`vl##b!j)hTKCG zT5J&?#8aMQDdr2YA4*aJ;Lf**zdKnGBP6RbLM1z% z)*!51mDPF96^(E!Sj(>1YKi4I+YCiOWzXedS`Z7RmFq2IN@8 z#Z=WC1fmWFnv5XlTg0<%fHs42hPUEM!!kml;4S)$WQ168$~l_pSr)NYWjlZGch$yH z-zyIW#hnzy{?4z;2&4ODgslPPQNJo9JQ=7``~Jr^k`b0&VITC1>uC%X8DmI?7jd;Y zD6Uh7{}BWoSA%{X6e}r6+JvA(X?mJL>w+aWikDwGiH3ZlZ}S$7fyZIkysj}wM_{P7 z*jvOIaGE7Xx|`V`=p9Z`@D_?E+Ry?lVK&R|La{si5l7vi%s}6$k;()xd$Ho`9;|{B zfRy=LfRZImLq!oaC})Fax)@f8%^{4GIy9h%;y*4c(=1^CtWh1JuL;+cf1A-gbaFLW zsR&Ze^5HX-SSkV75Awm%K+0cfsX&D9#C{6c`*Qh*zH$_6xE$7H5o<0>llsb$dr(59 z@+Flcec4}*v?^Fc3>S_7{u0!27)IuHD1*w`RpXH~So>I9A(U^wXohLe)@w68iP+^ zB||Fno18>4d@sNT}JznaWqcehsC7z;H@T1JgZ zIEkGJc4S|p*l3H`t|gPL{jUlKt{Vt&3+ltEFvQn?0A7;}6)T?fQ(GccB#K3a6pLl} zCD4M)-6wAT3)5H;@>Nr^mEV9FF$0j2!-)SPp-^7r$F?zWk+su2)k}qblKaq=Aa=lb zr65?$7x{icH_#dOMSTgD>yK3Nve+-?z^b6Uz;9Yj$eN`W52_I7`^7KLr|F6BoaYzo zDNLH@#}%NMPNF7yDB7xD=WqP1xYp>zJ;)n1;dB0i4N`3|Uj!(A*1$NDwdL1>CHo`A z_1{vB=lI3B#PQ?#lnQ*d|5yP6uzg=Bx@{H+^E(V5HHiW-I^$ZBWmAuSDk}YeKX|N z2EL@3U)07g?BH)wrRvupOIMIQ3|ZQNyEX6NUj8}A%_s3Ygx^ZUEy3>!WM9}c(Js;? z_nS5e8#dwnVTqIX*EfE8=2*u`Y&RD`iS}nRiE#zWaU)#-K$!fD`2=K682u-sLa&)U z^$RH_+({V412|++ApdA4PN9H(8Z&#L@{}1T|C+ZQJz5D%Gj?wD^1Cv$kt%{;7YzZG z1=?#7Op^r{G=;oPup)`kLo9no5bjNATm--PRtIJYo{bbB!{S%X!?64$#dkIp^9`X! zOddhM@J&~oV`7~n35S~Eq|;YvW+`?*{F@+;G!l7sp*i4Zti)x#bWZTv1m32!stMTy zKWy4iX~U85H6$dyFiPXmR%%Jvf2m33I6rK>A}Ko*Nq4I-Wi!F7-J&IwPilon`;V>u z6gE}pvdCaFY^u=h9lX4Do@zA6FQ%OVLd%?A?T#Y7G9?IuDo)Nr${%SvA*q~5k_-KT z;*xTW^#8o08%&3F81wlU?=0Yh5oak9@N?joieECqmm}UfR;RlHKihBO{Q#cTcs_;a zW<1?Uw;u0XYwFbV6RBs|Gf-2~>523P?}TP=T8DQ$n8q+7NxhvK=Eyyr_3lrPc{&I& z3UI!=%1pY70(K8!4pyiFw$l8~sL9Y)5a!5_^ka_lno*ogn8P-kRSCO5T0^MA;%|-q zXxp~arwMmP!MqV?Z12tR%&g}|t2lHQ6zqMdBc=7fO%0yvb#e>d4SC-SpI^ueiu+Xr z=|kpVJ6x;@sXi(8>yORi;(N1m)j`2bekDg zbEwJ-mAlQ^RxK&Jjgk`6;T7=0E}^9It!7+7QN<1k}6QcqpY6b9D?{n4MPv<;`!$JrQdk6`=6fopj1m zz_|`O-#}WVn6?XgkcR#hhfetyA2BWbzp` z*>K$Ar(|Q`kDH)9YZm9I(7x;xA0=pCcIIyaX~5>)mMf+Wx{}u+)@%kH(9U0;zG^QU zi8COW@3iZwe2MQ7>Wr?y*B4jq8xvi6A4m;|Nl8Ou{@s{kT7In2L>>-bB@vD&i2%(L z5)!xiff`t2z!+(;wZu}R77kj%_m#maSDV^gwOd@?;Z=IL;mF6P9v-bm96&^;0GZfN zI?=cCHjSPf?o_W}C(FkmK?~AWgcAKY)G2OK<@=)u=9Mj4Fnh35JBp}$gy7-Q6XDcK zCvdlVM403h*RR7=;)5pGPPHG8D0uzo;J?c3+MN${@4?2leI81-p zCUxWCL;PJQrJ7aS6(SFwex1D1%o(B1el&uLH8Q?3C(<38=u<2 zk5|{&L$E!30KWpz#tJ{t#y&g5U7w`s-DHN?^?pvjC1N(;tX{X0b6Ip%vRN|#T_NY0 zi_lS+YIJ(=67WqanP{43PqK&w~hwHy``;r)1dBs?3kL$n{uDJcHHa zRm!}GlCAdqMbuTacfF9!GA~#PwvRMq73`7-C+z-uVCpZAwnfUoK`S=}VXXrH*2A7) za*=_3DNM7aot@$zzN9%k9wV;xx^fcTtah@}7VtJ;AzDxuK7ile7b7>}jf$h~i3#co zwYL*>-iywLe>bZBKDGDX>NJhf!HzoG%odr&dr?-hl57?ye~SCmF0Vtrs)NB+)ptdK zQmk(z)CUOVs1E&s#Y1{H0)~H(Npb-w8*3J)eS>GAxqkGgn#+no;#9JiC>NWZ-Lek+lBn2A#9VPk7aj+edBpk7)gH4fZ{^n#y;T4Zv6IL1>c2l%~y7tcS!x3PtL4| zpOK-23bd3ChxcqL0Sf_cFW;cDR%jLj&I%qb{h;E>vJLBFG7YLS#VFq0j_Bp!t5Ew; z1fr!-L?2sq=1hqH{x}Itqay7M5#e=Nc_ci>>?57w@s$4AH-4-VXzIbh9uIks)7a7u zRC8aX@)x}MURO~--WVXB8Ng8)I<6W+gRN|%2_|jBkSkBqI7?4=;z}C+iNP-rqnOB| zZ&Q!>UPwtJ#DWi|Prj)#=)i?3L(Q1cxre?$Alwt}pz-K{(I+@9huuLgzJVXs%nxnj zhjj3RU7k8y{XLrPN!Uz+`N=+eNk%vo3&7x#B2b+@c6`N*=nk4<%a;{9Z5v6CJ4>(sl%TiX8iAs<_{CNg7)B}6^O;loE zU^_P6q*1~DG?%2~yP9D(3(lD_ncq*g?2#?-|9c9?75)d#SLBcM<~^#pD;;c1sZKi> z_87B-N$KXBJIta`5z9Y)N~nm#QI`rES$it%v-0JDy~=lhLrp3ko#xArXX_7p;dn#P z*9Ssyc;e9;iuJ}aSUKg`C!#)Et0V6toV+V)fUzkIiRwS*OzH8!nrs-qfg11jzmV5V&U!*E&d-gAv8aS6=UiSu6Gh zx(<6H;+jdXYko^Ix^Pw(zb(6P9|}+Y_ET^Tr5VOoqD@fADskV}Pdd&SP+2R0aY@o1 zO!^$0dhyh}#<84T&IXFR2YhEmxN1U0I9JJ;$YSjD2w2yIo1`c++~uMoQD(PTpyy0$ zYmD3=7;KX7h4ghriu#`aGUVdpQff2zq&)1toZ@vJ^VBPQd{(EIEZn7GGNaR?oa@cO|>HAs%ih zB;R6gSQ$4Q@-L69NRy{3+NWN%ckq2_%zbI3QCb@9c+}*p_PwLDG+F{6-G~VH5`J~a z<-Nh3C3t7RC<83JCgQ592j{G6{3$p$gN?jAtUm?lqLuQ6OF$^A3=KID?7K@`64uSf zbXfxX-6b>$tX_QuH;6NFvyf;3C6dlxQd>9&$AZ(Z+IJ2{?_;7@snEW;1ho2Iqy#m; z!p23~Rr}UKG%5(l^+LZ_bH6ek{h1IB^A4r3b@I5Yc3ZrMo6Ip>d`{9PA-A0K2)TEl zIAOtLqKqS4_GSS%HqvD;78>s%nu+RhHg$xCp+93%1#N)vQ5JpX^fA#(1N1SDA<+PR z)IUIOb%4|jgCz7HE?Ch3HKt*JGEkm6K%=h0bD4|F@W9$)tphfS%D9Obpa^6|8f_XAeQ6|COH&RtKA2nuwb{r5j24gNs;Wa_B6w5CU7eDe!eNk{OERjm!( zIFXQ<2n%lpmcfK_)#zkBz?q9{{AD%mY1V0C5jSknuvHJ>rn-*UT`s0-p^h^E`K8~g z{r@q%dy>4oS{=@hE^%z%Al}7tV1w9zI)q2mAyju#*m(3;mpX>*ooeKVmr}P1-ubG@ zHZleot^C817A?kx^5KglioX9&-_{Uul41k}zy^OLoJV=QVSguet+#`!-69^3Z-lfK` zz^4L-KhnW!gK1AFzm@n_1RMcy#-xN+d6=q$A=8H%J9{fgQ(8;|zqpydrHwD`;BO{| zmj4WE7Wwjn?Mltj$p!#{D(z@ETv=)u7_Niu{Zro99M$e5*_=GW?7xW*hNkYNy{U28Ca@|0`Y5s+=InG5YT(@wT zw}?j=ju{(2-NkX7ZU01fB7LO+h>)n$|40CQ9=H$0Y6LGMi3O?sa7)(q3Wdm%p~2TY zw9wkuuG!jj3Kp^2hNS@}F`bD%8#~Mln~8}jsZ^VA>Nl6=fYbS3F%-(}3Gw4Un>HyU zD>swj44Jk}!R6t=hwzVv`-jcJZDeu~vq4AyZ1r{ghUPXem+_SYN74_UAF0$4a|p<9F_RP*ooiR z;rhg?v$v5yH#sRvXuvkk)Ugvk&IV^&fop2)7S&eX4?&bAck#_xlcrnRd(|>1h#wV3nVZDk+YlSk$!Mp%|k|%5b~w2+UTD z#qx*6N`D+?F6bRISpO-kP0+hTrzB^rvL(X_fht4E2SiXIKx7qQU@D`Z_|H11)qOpt zgCU(fGy?}U9SsgpLJZggF8kVcTtQ6ZN`5fb@4+3DE4Vbx$!~$Pxj=8qUK6Q^YR+O? z05@R-KF3va#Zz;kxaRDziMTGih;0oKKZRnJ??*BG&X9mz^0H3TmzaxlF$4|#oMwJ@ z8(+}D&(aP~*;IR@U`dZ)g@+?9_C6P}VbX5XPkFs|#A99q>yH@NjV>}A8%FTc;3I+C zndIz9>oN>lug*TUJa2ZVorEnGf(EnFieP<7d7>f8pLR$;G1 z^!Z5w|Jm~7$uQ%IO1)@$3|BwE$Hhu7nB0jN%%v80>SMgJ#DbL`p-U{zv?d$-RYXB{ zniXv(Q}BBZ)t-D(gpPR+r5CH?d06I@ac-%~`=Uh#r zJvAozk1+x_9`i4)M9{IV5uP+!Z#4KwKQ2O>80xgp=thG8V_$PqAPq(la4-wm zgp9hJN-lnuZ5+_1nXr>j2*Gnuoukq>Q=XDhrPE1MGk~N*jYGfbABcx(Pz*kNN`|Q$ z(L#$T$7Ea&zu8OZa)ik^TB%qwiWr9jy2??$Bd~-u$&ry!3BR&fpVxnt#$`;3Rj!6i zB%x!kVjvaoqq75Gu@-{GhhYiV!TLmn#diD`SXajLSZ7YB8Cw>#8aM-aojYP=r(4oE z+Vh!Y;S##ba^d_ElJindz8Z%$xoIoS2E}cG#Sopg`|En6YwA|Bawr0e65S*)=A+gL zm@URb-jfS#sz(EzZXaYUl!cNQC!_hd>+l+|j!JX&X9A%^(WWR}L8@R(uzQToEPIEc z&Y^SK#@HMtt8UfC80VxWoBU2hY2IA89IIn>hq!O5KPEf)=>AlPpObgTe3&Xt3!rX$ zB96o~c7~irw{`5c_Z!e6R$AubQ3YX|15UmFGxd`80(I4UxX4_^9 znM@1jSITvEvSU->3m~2FsV3V9cf=r{^_ZH2;g&e;pzZHwE+)VQ5)(JFPe-J{F#~N~ zIRZSp-|Vb)^C`S@PiC!KOc4{A%sm0GvK0*uz}5>iAAdKy)0})JpOWUzc8Zx|N;ZEs z)RLRBhW{#*;_Vz6%ehi;yf=341nDo>0~2mc0CiKIhaO9Q-t5NqPDXKkEX0hCkW=qY z6e{%Kl)XB6FwRssq#b7dmJpVeFR&&IPUGOL87`Zz^Vhr*ZL9o$w(U>-ZId1y*fvz> z=i0`~{cU4+{~v9O;YPGX3m+NLJgLUqtTv6^f~F}?3}~8sR&81ehwNv}+*=k{E?+dY zM!*p95vCxwbOHD;4ySu`<)hpQ&OvwRF<@~ejfRqKhTS_cjdgJ30Vc=g(FqguzO^YL z*fK_bHO@I=_g3}8ro0kY6#+K9vEbwaKqm4OclZO0XKR$oT+ncvleW#6|J2vD9;1*!@zkG&&<{bz>Cf!O|zG`_p| zZ$IV?(#vT4sI54;3OpDAbMh)va2-#egI?$dQB}>1|2dvO2O_WX1d47TPw-P1^7o=U z4%A@Gf512md*@;P17)!nMK=%rBl$nl(SnGAuoB51WRUiVZ8QyFLNKP7%UJu62Hd_u zc{noFz!}F*G$G{&STm5;cx}x}(B?kYt-oe)E2i#^fV;+VNm%!2X$voGTWfVH&pMfZ z@#AK1_C5E&=Q7lY-WhG)tPbyV#(TpNBaHbH(>g`o65{6B_r}{Fk0<_Ah=)-2>qxMy zZ!!6^b-w**`nt$M13s%H@PoI5-CP~H+lQ9kA6dk#YK|6a9v#PHX;tE4h=+64-%d;^ z$KDm0uP%%YxsO)g=Bd9O(>?bfY?U4Gax2-G7wi1DII^Sxhc0i& zq;MT@u(w3Q51LEAT+kn!YGd*pI{Q`wVqFKkLOp;;#+cn3aeE5)+N5AQ`2Juz>L=x8 zXy;JsZ>Rl3DFfWWBkurn@H|Wy1k)S#VjbcnAH_XDaWEYamBhV2b|Sn;O;X+#`Baqw z1yfX+j^mlixloTPViAyc2nZkOCJt5b=l>f*CBs8ZfKt4HpV7=`xA9pW{B%M{j4S#c z!>@dO-CV^yXz-3CrvaD&%9rV?DSvsFsSl;E;WPLXwi^72wt|O;S9ct9{V0Br&GapJ zp2Y8S{Oa%vuX{(BmN-a?+u#Pd$Uq_kydUG-cL)B!UWJnxo>#Il#9s={W|}H7-Dfjo zO94)%*LTdC7*UrTH^*~2IZm1a^0$lq&)C*l=3xhv6 zl;P3wUxc`LdbU#EHI=bago#Y~)qf5L2-R)kC!vBYoC744b7`vY-|)D~d1?$`5g>J@ zreqCRx@kUOGSnXoq3fU-_w9rg9`Sv0+`y$6aDf2pGPpRD74DFVDYTv)ZT4D@?GGKU zZLsRjKO9(N*#l!k;Ma0aSC({}_;*57xqp4c#mnB1@^A(hzm#*_w9WT#p`pu>waK@F zKmHL!mA|TffjUEQeNE<559<%dHRPJxaxK!djDxle{^bxhv>U)a;eMqK_XQ8yh*$XQ zMH4h8?8FHES!z8nP^i(EIiaSv&q;W{LRfq<FHFJ>}uGM;6Qj`TNb! z{=elYHvXDiG*FI`9+h7v_uQ5>EeqgLBR=Q!6>@_`-lN=m(P41L z3Z}z0sHqI9h&aM;=^k4vV~5+AOCcd%XJ4xu?(y8D6PCup^H!EaT0B@hPsdc0#e)}| z3uWu!xXLQ8u|Ww{utZaBZtLS;RaP1}Y!Q_N@Ov7P;@gRXvDItcHs4FGc%vXNj-gc!y>SDUhC0)Lv+CB_VaKK;VwSRlWxg^CAif%b{mt=>+~az*6DO`jl#JF)vfG_ zohAAq6z0wC4Dosg5}2wI=`w_`5{=}TSZHnqPNuev?n3UU-q zze)bpMYFhg;VpniGC0y`3#lOB+^?^}&A8(+kVF@xUaYBovjFL+*NCS+f?g}xWe^$? z*>3FHw$=FUE+bCjWDf>5S>^B}OZ^H57HP4{6k7{d#p(n>Z{JDgtd+@waTHdsn++Y= zMOu}k2X=s3CNK@kG03%30gyAu+C!P5ejyOtPX+jUSo#JH>#Hr6CiKHub>3>e+&nD{ z#wE2H+*y`2=W&;B>|4?NYoWrV+^eAluZ8k$7}+H!_S&GCKV@>Krldl{kY-@NFtsdc zOV#7*jdSFQz4{);nd*)%iowwr=g4-UE@h-MIw+(>pBQE3pAO}I61(7?#RIhL{J`bjd zvNH~%s&qpfCI@7J>ok*u3z~d)gt6~sPZmeDHkYv_BUrX8geAki)_|*FqqJcSKSruw ziuNedVx?{pmVF*%Q3lgyV}-6D%eT;3sBVn{^W}p?VHAeA%uF`L!E65~&*Ov*j^l&Z4ZY_B%qNUL8iga`KuPkny zS9B*~%0SkN&veC4ySmBLYMiwfq9+#v#1c|1M=v@~fH1Ty~31}6hdS5e^G9nX! z5DXu%lP;$CGS{PX+HrD}KVmOhRe|xIGkXZ|=oFVuTA*PR2QX{e$%yXcl<> zW-r?;ur%99=Rtm#b}!|)g9%Aa>p|N{=nAA=u(88m2_2r8VhF^ar@geR5T~F+IbtP^ z<4>kgAATNT*l$A4^-XAdiqEFJ_0zEftswvD9HU{EI-cP9x_=r5JxH^lKg@eZuozg7 zR>#7+j74?hlD-}^$Z0)QjN=KeY@@t7&Y382;QUCD-)Pcdp9wQ3GgUfocXH?m*9ca+ zD-IKujg0%Rcn#VbUO1{7oJ%-Efo*C+OhJNMm^P^a)Ha^>VGwK-1TE^rJm+?)<~& ziUVu>Bem`Hr3U+##)eTw=LAPn-NAiK&H)D((`Y4`(lvqc*x0&Lj*L9S=v$2iwlo&Y zkM$P4KDQSOP$~RAe!eIh-x$zR{n4hn&qF1J-Pl`?A+6`Rhx=J6Y>|0hI+sbxj^bP) z1ha~>nF2$KVYUbB1^n9E5IbAQ9UjUoM#N3S^Jd?K8+-jJpaDag*&g>zx$&Xmm(JZH z%w{r+eKW%;W3HvdJnUP0SWVYLQ|@me_tMNIzM0OO;7#i$tO?iYTJD+7=M2e#A4NP< z@dTdXUMQ2=KseU2;CwD;y=YJ#G#z2iGcC3jp~cnWX(?_gYgyZ}QK;3WR5uqofyVH@ z7Oxz$!*@A{hxjeF<77O~hsZk$Ue3{rgqLp+!zCcdx#aLNRA>oI1OYd#q~9Ar-gO)D z^k_~_fk;f{RT51=1c87XFl`QL^8p%0##!95KwE)Y4g2>x4L}MjXvco0kwZe9CU*&p z8q&igZj{#2{AdpyPD(Kxo_YADmiPen%;f_#M}RaOCgr&$9OsNaxb?u#&6ji6&qL}V z%)wTggX3uqj!E2@srPvG$}hw7FkH^i`151|>%IS+i<(B0f1wv`rKJMOHKH}(|5T>w zP+>_TW?3I07%;xTf1<&6V6GBt(U(Gx_92Ca@)Zd(;O0s$7?kxb4=602WU>o?HT=oOk=0vzdYw zzDe1}s-Do{6-U7H9lrZ|jWBfU1LhL@lewg=!v^trzij0kh{XU!~;>uW<)a! z*3S_<@vI}Su4yII_!YEMxzu`MpMI&)m86HS8AlSlexTIz)>6H5{ruLt#X`#Z#i5c1 zy3(S5%2}v*uCA#pX31e5s*({Yr6a};a+GI7Mp{lQmi~wlVv*rah(+vKt26rpAtjrZ zdmJt!vJsv#=p*PIz&kMBsKd3?Rh)6wh^6NqNHdN9+FHqY<+~TtNm+DGR^*EPGTVhMChnLQk(%9lbk%#X(`~XZzv-)_) z(aN+K`46#N!qLKQSO|?jSqKR?Zc=win5LvEC|=Mh_KA!qN$)vuw%BMbGjf74dc&eP zmoaAfB8N_hn=d#vOw>CjIxzoE8foq7qjZ4PM+5X0G27@XW>?u8!J}e2L;A^b?)H_r z_X|xVMPH+!VfqMsK_+OQ3>TTHiL*{7PJJGB`c|^3uo+0pKWA=Q3*||n8SII=h*TKB zq7cDdW+$}YK!+ymd%J}REJWoMu6Wkz!tE8*4?3Ug_F}?yr2UVSL;!>%$3jB4l=UgQ zp&#vmqm9XB)71YU8cJQI$-GYjfJKTr?HLmkv6$F^ie4za>uA6TBb8@Jizf^aRt*blem< zJKoLQ0s*JZ1LvQd?fOB~`W*;K62HCKaMBai+T!Uhax&~in{!DE=UXe^9jlRT>ZFZ2 z`L0-%*UKv1?UP+iaK6b+g2V;QaW@EjKav9X`p1-{1*kz7c^=pV#ji4&DNFi>UiW5! zO54E?qm7V8w9d*neFaExl_Z^|=&v8Zgeu@`!~F%_B963hoVD4jljefcB=rdUwoTI{ zaq;Fgj!!oAu_4;BtXqdQ>?~xYf&5!n2+HgM{F~UR%1>ASf6Gr&zbK^Rzabdf`d`J+ z^1t=xmVfG>K6!FXa?}_&@Jkr!G|*zzOnZe!=`8C?(`AAmfC>Qm2j$-^)>;s;0iFDR z!C+5c4?{llf5S*xl`sbNfY7AYgH!%RFbYOMpiG;MQ#k$gIrX!!K;tlu#W>@N3!m1ZuAxP$+7oU+lnF0P#S$NXmFJ*(zn@I zswn+HBE#@It>$0tqnERAF7Q8=7zoy6zA-OfJ4IX_Mv!I4ss^y5G}a ztj<7ppvnpXQDfq=qaPDkf$eBYQ19RJY+6jq{+6beQ!N)-aEhLt%$nD<_*%k}!?|2y z{rmMg$>z`vyDXz~&L=>fzm(5e{~qL$LYnVyws~VO!trq6GULTYk*(Pq$Bio4YUO{x zS@=|^EoBe5N99>sg-S+npa5^NEnq2|J>~&2%g!T=^oq@0n8M|L9XdQRI5D%(Z7kw4 zYsK$+*+`Iu+%`aS%9S<(^Lm7Hq?2j!c6buGhC?Hzzp&!JLM^sT=Dd)SE4GCAmQd!J z6mJXfYrsY_@1l)i4yHOn?l>o3TAlf1X0>}aDC=&gSnkW@-TPI9QgBfRsk(wBj7=qLlhY1ZH2faoA~t6;o|t3v=U+KoOA086%jwW0OkLtoqCJvC36sGU}XqR5{JyW=b}N0!)51?6il9xGazUJf)#K z3UdYhH}sC1LmwyW&(fFgnqL1m3U;OA`U|@lXD9S~)MTq|h!sAbrhh|=9)@?e)QTh1tK;}%Au53p zY|KTyuq=@)7FNgdM?#rj3Q*lG8<)n8U1}V@X#V`l;le6Uhcgkik`I9G;tqgyywNJW z@rW>w0SISeb_{o*cwU6GGc@%gW16nRG4hWKAokRTJn1$>M=Lcr6zcjok4s={5C*l9 z>*HzCi)vsFm!Q0Wz*q{L#J->gE`;LY`H+xqD^5?~4C59F>2bF%qDL&ZYaG=HBZc}% z`Btt0hJe5U&KsMEKjVZqorFjSI# zrmvFHAJs5aQhB<+k}NI?0}?7JKhhyD`e$NNioJcMEOqz?nhP!5EaVn+a0FSOQAu_iJ<-+J(KXg*Ay zQ2RHBAwYYu9{?IHI_DrCmHb)RD!(e~jpkOW`raZRNIkY4UHemB_6WKAxbAwz|@Xb1O5Pxxzdb63v^4R>{9s z%P7Qft_!(u@TA8>nYpg7GV=Y`D)Xzp%1FNoMOa( z|BeqGum6 z(GEbO{GiFRbH=c|&nH3ozabAK%pu&Q8{fL>^_J#ijPShUGnWX(Hta^N(RYjxgb~T) zntA)z9wz@TJ#_6$M+-~G(19Q5-B@ddSI`Xk-!E!4n|JHPo5tSaNi!~nD0DXN(s9dBFZn)GaZTO);#fyUrTsn(x?E|3VF~+JMtF;E zuWTAsHBawYUg_F75{Yp*xyV%P-BIR!UYZvwxzcvD^N#ap%Zk zo88sIAw8~AZseck;vJhdZS+3dh%;J=%H1Yxp(V<9o7(%D?#Q`X%>NBfmBkWqd|=i9vS@>`vInf%fEG5aDKlW>7Y zDmO(fo8Nw=Bt2B6?nJNJm5sBemqj8VMw|XOBObxB&t2gpHe#76htZt)6=TQR4_DVvoGx1K5 zof3jRfHSO0Nar@9Qd|rG$Tyod?wk|5c|&`_1|d&3JhW=wxqKtxB-C4| z&Gc7rk>LTRVHnM5_Fb+DI(GX!TxttJ&kR(S_83cw$E%+Suu%4<(e4^; z`jZZMaH!tZpa)p?11>7m-d0Y|<-xE>NG0aul%eVI8Qc!n9iES84pHAo6-Uu~5 zic0d;J=sv|?~sBKm>eaxAth%A3pEBfO|Y-l1CXb-7mMgLaZawZ2uHA*c2?c2YwvKN zjU~$l2_yJdilJuaqD`Zr*H2U?_Ter&k?`cX&* zyMbgdlm$Xd{3(bCSjm*Shbg3 z-s&)QhlGYJj!!oM;lD}xfE}GSxQ%H{A>@K=vfJad2@PjGjJ25ITud~ma~l&gKhL3? z7?(5AvEh8>jtLo4H+nrgM;6!iuEQbmZ0nrd#S89= zVdsUa1oWfCo2netp>4Ij@<KyNX>gEK9jQ0CELs^hfV zm|0BKgQ2QBLb`0M0LrcDpr)uXJ4^+1n+iyq4l0obd5e~R?EN;4WDJFD5~@Cx$JBbGMhUQO@N(ANOt2c$xc8vG?8Rs!Xk;lDj`@?{{eju(+#YE zyTk6lO&8>Fj!J)%ge21=j!>fMN@_u;6^J!a&U+K>ygkt-&KIG+lnUl+{7flom0Em( zWN7>S#)f}nmQ?uEOsVh;?x%3a*^A`=PF|Ng@TWHfjz;8vCGwfCVBcXLIRjno7*#Pr zJokdBBb?;=6dZE(2VnC;#ApfSn8X;-b6QgWU^>9rS?QGaPE5$|0wb-IwM*ozAx=o` z!FgN`Pf)*xAA=;d01mIzCOFA7b@;i^%SOJVl-?yB)e085T^OMA{^} z7LiTuN z@zs3H({y!2@A(6o2)7R(cFWIUv3WUErn9w1QY9xBw8g-F$2~-{97r@UPTB zeFUGeojV8)9Pt`kO|y@!Ryh;w8DQBy&IDk>bSaQ#f({`)q??)!X**$-e9$E@rhl|T zDS;Jo5TzDVsvA)})sOgMNPL6N^)LeztfqsK(9ZWuf{a-P*rIOK+u@IdO-PqN!cbo5 z;cH_~r73NZc?gPdtgShH&pvT4qNxQT|KWCaL5~)WB1&UIo1tGDdM2WjL*14@8zwXR zFeP%wl7682j^Jfw)3Mr(WJ+!k)78U5fBpR$40@m2^olIUsMo|SIcsX}t8xXE);TYTSb{M~w%rs*zz}+xVa{pTHh& z<=cTNz<7r$N|d>;Cl~tAqcK}_eA3UzY3I)JqS!*Jz4CZD*uCYj77y*XPI>(dR!ui~ z+1fU|zpNaDSUzxqbdQ_EtUO-IbiD1Fs7qVlhaqjBU~^ED1ML~$k?A#<1z>R~A8yH! zUm`Zt7*koBUX&9>eJYaXO~1|6pkd5x;V^7A(O&41Hn&AWCTA!>rA(6@InW=d%HGqc zGD%b#Dh-tFFZK2f8kp$Vc+d0 zxdraiX3D~yrmkjFTLshkg;g|@5R1V<5~S0zcy&MT>h3)_KJ*s9G`{1|sFcbN9_s*C zv#TmckM#F%UL1XjMaR&X!v$NcX)h_`nYLCo@FCxE$RsOPo(*qxOxZcAR#uda>k83-whj6XNwFp-Uu4%a3xNNvm zaYf?l?oKZ}gX;*cFs>l3J-Bw_T8C>Xt_8Sm#Wf9A4z46z-S7qRDXuqhy@YEAuFbgC z;aZC8R$Oje`WTZ%v)r%^s;n(PVrw4-fyL6%2kJlnli@x z5Uq!XC-BR>49Rbi8+Oq10;8%&>G>9FTFopZdkjB|;c}tjSM+`kQ?nY+zozF~^)$2b z^EZ?Rs%s59>AjDs`2n84qUY}$Wj<-Vr!sHGr+P|H85`*RY^LT8Jby#abCEttZupv> zDdhz`w3IT%^YDC;p6TT!JQUAjP?1w~-J{_3dis*iq)-r|em0C*y-S5;|zDM^ZT1y_?7i%q(=w6|it>0YL_ zjHdfsttEx-w`wid()|{#I!Ko$!Vux^AYEDek3OOEld} zG?09_&(y#l$NeU)g@mlG8RTIRcdyo>+q$@lfppb5DNc;`M;R|-GF z=| zgl#YiDPRv4i2|66Xl(^*2UABDOOiVfJk9l*CeJ#C?p5=yKT&zrJZcrtRWY;vVg}m!|Bogl7UC+_W>;sU(T?k z%YF9X5S)Hs8YRYVrqiadvBRN^D-b@Ma|DDrk?Lnnf}f^LOeq_*Fa+bk6u!0q zJ%Pk+K-;m86-xANe;F{JKB7<=!a{w@_2mwIkFPBS2%yMq9K`gjCeYj$f3B}TthEj~ z*^r7tJbLMTE7#Us82*XuNIBC?x{&gC#^Z>+=ph@}85`7jymtdBYr;8LFcz#RG;ktc z_FLZkC3rbYLY-Q1Gy|ngOh^?o>7Yx!70T)uYxN->die|ClYcwb)V~2TL7^Gx;$0^w zvSGlZuiTK2=3mZ#pMQoO4LbUApx0!JceCD9dn#n6VxCCm0x-;#-1+u=Cp({=5ufJ@ zeP+VpOWfa}lf;-GdNHHB%3L|r7Zc*P+}u{~Yj?(QAE zu8YPm1$G(mfrnDyv6{0vGt&>Xd<|Z1XEu@Iaw^qD=*+8iWo*=eRuu zNLUbSvn=&F*=0pS4DYM2T}p{WcrafOG-EBQXE?>-lpW)<(&Q>99Wch@M~b3Ujn4{q zl)Qd*(`;a`&}jsC8nX$s4X|}3ckQ5&*ii+~&ANWoQ8H?QT6wXc>s%}POY^r{;90_h zfb9^)!Ie6H1AT`7l3U=vgtoD$^RQ!AzvRH|IVD2o&6)C8xyV#Iro+LBCO9-KfLd|N zS2N}az@D7L=be+eO}YNolYh8@&c!~zDd58@^3Ev`O zMFn&c;plHL%`p)aZi%o0{Njf+)lUiJuCtS!3}kX-vNKrw1VIEdRAQ5fiMssbK-m8 zM_K}#z%9UQ;S0_g8wzs})7MtW*-5ntH5b|FbKx;97ucGwG5K?gzh(*qMkrggg5c0z#={sxDOBN8`QAmxcq^6T+M^5 zXgZh;)r3GX4@a3u(uUlSx28k66xo9u7TDjplH(waynY&dl)mj% zKl*|?o*(#_%Ks~u|1LFiB9i%_)1Zkl*4sBJZ|6H>D@`e2p7=sqXbO)caO-=ND)=)8 zw1I!uPm7+b-Uzyvy7Di43H*t3q*1{+{6d&PQDymRzMddI1phm+>Z=@FRa5ej{K-0@ znB0~zu3Gd#Xu*6ehz)i2QXfM5xIJTBH6%oSlRG#I;1Gq=y?RCJd-VNf^fB-DTXdKq?Ucq!N1QZ2Mbtv|)Iv|BO z+F@d8bYDO{!V4URIC&SJzY72j$^7*m|DxBemt| zaogLq&9*O~>xxk0m|DVTNR~rAInK3^@jY}cmX&cSiQU!XLEI)C3+*;(@X@L1}^YK!vrs4Pd|RXjeM<$$V2=nq^+m9wL2dOlv_ zLLt|v;Zdq#&+W)iV6w#kHOE!}@UIX~sL+#&rLhKbjt$hIA{Ge7kTR(7tG{9t#Zq&~ zE39V7A8ZyNS~AB8dvtexfWs(IjXQAwMHcwSKzh6qKRUVXU3lWbIrJ&Lh!taO7DX0; z?I&Lw{0S+v2%hzN&Bu!LXTZh ziE!_CRibXcx{^RO=Yc-}gbKEVGL1E)Zlm?Js&5SiGU(Sz&h=wpS8w2LPD~RgSSM`4 z#t1rF6yL=pguV^nDei)bic@sFO9x@xg!`f5k`5+h;f?DRo=kC&6bd&q`QKy#ZX2Hr z_ls$n6WZ|&b1AT%MiUNU60)VrM6P9-mXQ`$mTNAKr<$O1dau^9gfN|Y7nWvvsFD_F zfd1wSmFV!bju=oph3A4N8_AVW_O;kute!17(_Wf64Qeo>7-S7BrmO<}%?VXdR<(jN zgM$V9>8DQt`kN!r-~7-b&b+wy@WL&J=f>Zbi%HS9;MPIyLdKdyPi_PI`5*v5@J?y> zyg3TA>q+N9(Sqh2`)J?4-rKWFexv&o2f{XIC}Astc?;|m6S$2VU;_stdDpVb!+5|U z6W^ipfT1^28UtPs*uR+GXooO^Hc8ZqeG+op54L>@lDMND({eN%XAvEFJ0U7C%x915 zYqz?JT8VZaoN#blV5Q#Vb7=Ah2 z8Vo#Zpux~hTN0#h>D$L8JP1=^hYayiO%%@5 zIh}V9s1V@iAdW^pza!w|e3F9>Mu7^DxoRPoqRHd4Gqc+qU_h)5{gF$lz-DaLe<6K^ z|9W*FwC^gU>r*^E+ygi<6;^Lrl(x;9X_fsMC<|_7%u860lmSPFh}8^w0%;e1U2u-rR2A65iMOBGhzJ_=74o=OZ|2O07{2hOxdvMmJrl1A()j!H=n6cRwka49$IuR{f2(Cbmc z6ub^W1+!_C`Zvz&cW=f1XVzSHVqiFotf8NvTx7luf0F+e;gWiU>-8_A)EfOuXcSj1 z*~*}=K8;v3_P&n~VI83|e^v-F6s4@Pu__-|EQ3E>A@-&iGOX+7LlGj8P@4+-scAd6ayfPY$ebdA|K#dMp zN9UH^Vr#L&x9!a-aQPsC{Uma2<80^|G&RtP z60jzO*<2}C)&`%RSQ1#yfxEcnKrvagFs@}5!rwkt1rQ+!3S$MtqNuzP=hf%YXvT6*h3sC(>Y+3kZ zF+x)SE}?dolO|ywlBJAh>4r9GVuv)LOUgBriHJvrp~*KG>QJ%30Xpzlx9c)^wW;cV zSnwa9R&fT73%dtw?g8&^m3F;{pj-#-MPXhgy5;XkOoPQED z{t1JhJ|-(Fe5h7019}HJ$E~i9aDX2{+B%n3!DGay?2$vsa0YAB zUx`h&2=JvLTg-AvmTZZTORfhUa!ylHMetaE+zsdJWcPP`6RfX>x*q_XjhGLiA9dTp zY{An(Vg*4Y5gq_-gOlaP!cCP!f>>`7pACRi08t0ZuW51dTEcy>2xd=Y1Pnsy<7 zxA%2-7;h$YLq8TTp5eteFaWrL+b`gjh>uSjzi^{pPx0b3CF}+)RTo0b;ms~yoQl-D z@T`PwaPuC>rdo=+Ni@(eQ_woe(JjdpbbhIbW;UAon>pvAX0+5J=FiTJD=eG<)jVkA zq3zId^O2?qE2tE`SL>G%QOkAy>ETK%9|__M>tFo4Kigdierqd%i843JD?c zyF~02NB07YiRuSX)54mHggF|h1?Y6*$MbCMJpjf@nmjftWlaZ|Zg9zgfqR>(qhae; zUh4yn&LK4Xq3d>(SJ^Ml;=bE{aW)5W11O$B6)DVv&JW{{Bp6oBuNTN1ERl2#Kb?JS zvxvMsH7_4TocbHx3DN7K2fC5EHg#Fs)aT%dqs{YNo98sdA%O+MtSOb>*NvUR<@f zw&2>1Yi+ddhqvw-25uHG(?}^1epX%b)19EFuY+$_m+dduL;{B|QwWco>Zd!E_k`=# ztc{QtkN2O|&_v%Z`^p|Z56Qq$vA8XZ(%j{b#o_YzjC{Mp~{{w`*vowNivQNVWKu3b<N!MinSdOnocg?2051UQg9&~4PQKdEacF(nPkPKJG{y^G07{bX3m`4%UN>1* zk_4EAhZoyS_Ntm_sC>tMvkx|AN;->Ts+th5=ACPK(cR7v;#hg}{Ol#9uElg-%9ceTbGU$645f$MxV(yzEaf-v`aO#H`$E zo`ISD1d*5Dxzn07vT%7t5^i(0h8+3DqQ_s~)oq zK^LuGZi3Kne~uAdi%PXo5)b% zEv{xd<9X}LN!z*NVrEhu*D{Tf-)g}_jfctaz@XO@GAZMMc|M<0tuk3f$~18PYQ6{Q zq4NhGDJ~;j$e55@lgJ>LB{qR*LA=HKJ4s1zfjBuT=3TvguT>A|=|_o#l(8 z80te4ulsUjLN~KR1A1bAu7s|?tXm_*iBq5f!zAyGkl*?;*%u*8ab-S}>&FBH5rlhU z;9pVIQsN#D81~pfIgs3m&@Eg|&EW(z5dfIF$>Wd1dmw!@#~)|LQ7ujJ$DxBt`jFna zM3ZMKgLnWC9hD^G&jPUp%a9jmc|~_p?Kazl>O>*)8m?v|f*~X)Z;WKWATRCibtKMB z6*F`1G>>N3&-Hh;cn8r>=Dt|=1ii4=ifP!dLN8L*qg+c8#vU>7;EHc51CJ1SkTb#V zu&k~Z)}e0kpu?S5w)owex$t}K@yAnxajuAm8uQrVqeGfUJ3QQqFt*y{ic2-eAm2_I z8e2;btfkW@Y8XVHp@oo-wPfhvyK?Qlp;ws!Et5V2WwcLjhMiy`Byfn<(!Yf;p8ALJsZd^Td{X}u)!zfi zxatoK{T6t2=(h$tzQMIh{dy=@zcTQ}(-764$BL@deFI-mUgNU26{ix_Q0NjFQ}{G^kAOQ^8;V@JfiyoB0B&QYLjXtdv61# z4xFPB`NOWHA0l)np*pb8#4e|wLr8(mz@2M1ONA@{4!!w@bQ^deDfmi|>lwK;St|Rh zVF?fAk5DSJoP++=qQZL@m9Lgtmn>SeT0LOeZ%N+CpDKwyce>=vAVfHpKN@o|P#+6qQ|m(jm@I~2q^QpQ78~b^{leZr4mkn| z2^8nf=Gk4PJ`e*dq_UfPaOQ6!+eI6vSVo-oE4uZ)CGaYXXt1YYeg7d@-~UCE{-Rso zpT5HSzCv4CTfWoFy5q^lenxE`?C{-t$mP5Hb+W{Vr9N!%J^si*5d4TZA;{tE2lM;9 z1nitJz6a3>59ngTz^sPty)m&p^_uiX4~AN)|3cUGzl_-<+`~xLCiTvN)rdZ(HX#ws z$R7;TPcdE!ygl@19QOw80Pr44voG5FSA+gLF!qc?n_vP^BQQ{% zf<6o3!f!NBJ)8MA7O{iKIDqKnKE>xqu=R2*L@ypby#X#G;Dj&6(9&s*E&HWO`sZhl zxWtFp_dY|jyEnFTO<$2eYtm#ymma#rUW#X1>02%Q!ka<&*y2;#ACa@d@PLq6@L_W} zZXIV0#~pwdrK``3sJT!Bt4D_`+K2!oMdMl~%Y{mubpEp<@-IWqje~6-wdZ;P+1q?1kA+#lX4ftltN&| z?i(y%^RNQQ)99dv_;;4`#*lIz87${V|GOOceK-T3U`EeSF6n98JVwlkJ+hlq(#+s_ zz;;fAUYo8gLD42~&@+WThn4_H9K(O&z&Q5l>*(dci)^?8s-@pjEG~pnRML19Mhsa| z=)f!;^wtDAA&tOKYoc@DOfm2-H24nZ$a0>nkm)Sh&O1%vx%07%;Y$Su5}u|=NVdx= z7&~i^H=D?W$|LbMzFb-=J6SO8XtsoI?wTnDdb`N_h>T#2iH>rY>gAGkGnIVSJqhq!x(VapE)lsr*1f0>){fF9CZqeb@ zdC)_g4;CyON}LjTZq_+~-j_nxv>VIAdF!KHB3 z00RkqL<)ca=L$F$3%!N@_v0Vwoj>3+PpNYum-(6o^hu5KzPfrZA3C>}xam=$Wos2#cwa=;s~0?1QMa&tL$(h-O{#9lIX%6@=P zFw(-G5{R(AU9=zG%;S1FQ0}1YY`2lq__|$hH}Iz6(*}^`MA2g@N4taL*Eff`kYa*) zOlA1O5u+^)9f5p_n84KhYJG0T;joYZp@u?WeGLiB29tS7w?@ z2_>`T3D8M{|M-FB${7A&6n`qDQrL9m`t?~`H#W_NcNmX9S^T+2O7;1#sql}grl7?o z{KBZ^kq=l5$1!jsv(X=4=Z|aiCv5bOsq>FjmkB*we%Cj9Z%CQq{mn3dLe@Z_5)(W5LE1pi*{CD#kG|mUUVHXVAT;^E(g~+@nnut`0Ox-%FJ#mk`1(7_tMBqBLZS_NiJ}u35pxR< zua=9fXZZ_GuC0DVbJJMyQL@Qb;190}!Z8d;Vc}|Mul7S#$3^%G zm;zo`(VL+wd_N&sE5~M2s1e<5zoKhHzVBm0*RZUeUJrQgKPJD3TKZR(K8FpzA>^5w zwEKHZAkv^zN&MT(n$>50tdYTL@p+&M{LN0_Ok-yr;mf^L>GQWN_We6&_n1f;AOOS%qKf@eI!!SszPdPHxlp zngNogziz}Y;34BvJYa%T@W?zR&y$D!1Gb&;%^$iI6wLq~)sN#*8?bkv6W{a`l!JC! zIC&gE^q_akl|dI%t%RFR$#db|%PeCjs~3`U1?kh*W>2)j&7A55(F-r-72-y@goSVn zB-wlx#6&skD}hdddh_*XTBRee1!ijglAbxM-*6Qj-{9@J`zN#4#7%bJEw9Wa$0PIh zjS@Y`UksKcYFLu_#8zq2ao3GK*4*_HP)V8`8cvH(A*l%WObVjB3!dJ{u zI0`{y-1)YWtTg)qr==!>!9T^pdVsIPHux?>fwF_6uYjTBYKuu-ueIO9E392PRzytf zR@2Eut~i6SDQEd)IjUw1{D#Q0SXfyVHFvC!H#DYUqj0-$e(`JW5@#%|hE$;tPz^VV3ZQ1gY=W3kVKI)UGZO`| zu^7-(SRQIuITN6TuTSdOydq%?w8gyk!0e^O}>= z(0r$*S(4i%$=FwKaDhQsk6=mSDKlNuuc5cON_AI(EZW7?ba^Af!90eYo7?_!-EB3rs{C=}7lIh~l+yHP}aA8h)Z3Oj{KP?aRQcu;T#EA9Bhy=pG%|QL79< zWG2QE@guy>yV+9g@*y0e1_&Rt@w@8#N+aLg>KP5EK_EK^Q&in))ET-S=iV#p>;zMT zaFfjF1IF*H^Nx0>O`2eFBPuIzbJ$^H0NFJgd;)N^iFWwhvX3@iQyU>=9~u-yha2_0 zl%JH4=;o6*G2V3boJM;V*=8TdE;(=rMDvgydyI(!L(Y)l@L>3U0xSz~KvJkv8CT>3 zE*|_&ky(a+@1r3x@&^65yAOnc&nOC$`Y$Yp2n=YmWbR}8pe>X~hra=R5D(zy5Usi@ z^mm;SC+cYk{DX$=P5-n-dMB($K-td0Sb?$y<#B!}UHjkC3x76B|LXsmekoQz%7+#C zkn+Lb1S+j=;n1q}YX+ETO zMTm!z3TYLqA8IWaD*=(cB(fiAli2b12VE8SAZM!8lMc3wFG_Ms9NcZ>m_>>m*pvusmzNy{M&p??2YbErh zUTWa^VWsNp&4u$ zgPl6SNz=>l$($z*^AAOd;`B#HV7)*w;f+nfAXuNn*Jr0!kCQH@hCi+SAyxC{Hl%{2 z2aF#sJQW)aXjRx)(m6JtxT=_Y%>zzc^?7HUKuftv3EAcH(ln8~>(TLI!k$O>n~v}( zhEdm&r6S@Z!j(l}4V_6de+vZ{rp(i8V0~)+5QZ%Jv(U6u_NMiXLSbc46zAQLY~$Wa zhW~@OuX80Q}Ja)B%!Z-YfC@ zxtkn;_{d;$aNU>I{B6ZxU4Dr+!6UnoLoWkKJvv_{)NeY9!cq1>S@T{=+RwT9n;h!M zfud;7{Eo7Wf`G>jdV=`ox?Qz9jkKi5sJh+s`Ym4h^`uD?vZoiY(eIt&)^#Il%>uWYH9BDb0{|ImTy2J1pnUGF#1?03b|cUA$vXOP>|&bOM* z3e*3E|tj|^mJ3y`AaXK1;@12l-v@(HZ6Hgye<7=%u2-TV$V=8V9@fgE#{m; z=-&|+9hbYPh5#G6ki*ognaq^4kKM^^=1a}R$;|Rt@-4=6{xnz+TN>#!-&gdo6gU#G zS#pa%tMEFU=FkTb%Q>3^^mnCg{6**5qTA%l-`K}fk;}+G+XLKES6Rom@NgEZx_C1f zs4$uAT7TQLf=FlVjQC|Py~Ilq-uR`iwMCnyvbLVPlJ2sNnZ8%T0oV6Vz^59V&b_~vfi}8#eDt)Iiy$sNP7YpAZt|=hU(Vi?J3DQC;q;*TQG^XY-7#6? z>@Y{vkBYV!ufr`~mep`X^ejkiuP{f{SJr-@hj3UYPZ;4wlUzdPuvnG}KuUd66L{`) z(J5$789x6J;x9(HD7VIhXTjxzkz9R`E%Rv6+T~u_oVwoDaCQ;iWy?D7%m!x#XE@*b zTYL+!)LVc5qy}pCWZNyg5#hGjoPBL2ygnqv4%!BeJ=Tw0&*<*Qg#AO;7Cx}|{U%6s z?!bDZcdNhS-M!!OZspK-uRq;8W%e_@Q>0$4NDnubKNb9+z=;X;4w3itcMIM?OsR)X zh`<3$UXTix;2X0Wy87n0!gZDX@-HlQHtE-B79?3szj_?TfAF&eX5R&3+2Q^*-D?{W z(SPao$B~Udf0QatZe&0fhc1xB1&5MXHN;d`>K6xAqM!Oe z>1~AzuGwfUdziB9l-d1{;|_lkZk|rBuX9A%^-n$&GwKDv`FYrH0_H#N+Wi8`0B0R_ zqP3x(jL<5!=^HwHHHV?D#{@Y>`bx{(*$L3Y_j>40988&k0tfM|cZ@cr{&}e|4t*B) zNQFo8n8I5D%fl9(&k7m-mzfB}bU{mfGqfW@X?#`WSRAhqxN+5qz}>7QJo!s~#Fm>)JB-J`^7E{%3>l z)q_LcKQ#D0bYSqkPK&kjiY%A1c_oT0&6M*Tiaa)IRbIY>&s#9lCFGqVd2f_09_MEf z@}yMIm;7+LsJR)mH}(F5|G>qdDE#{5(0Q;FFhqwj>egl}Hs3xcZb^dc)J#VpQImF~ z!-MYIXx}s@36iV2|F*vkn^)Km^|&)|Fk%=Zw{o?XBMRL4b%m`3u|U9~^i!e$O5m1l z@V@OUDXIP1ohpZAip+yB@#Sn;br1F?VYq05Ny4~q!9{~pXF?Oo_AxL(FZvd7_U;W$ zIe~$an@1TVbHqrOv)GEH=ouZ?7MjAlAnh)qxO{Rb|AZ}})C{Ltub+IZn#_?(+}L^z zYRM?$@X#_)ou2<=t>`lHXNTN<`PCNy%mPs7IcfWheESF5Xe@hhdeG3rM#k@{6OnPI ztX@Vo!T|1p1r+?Q`ra_I6^C5?^}T(Ph!SgBjx`(dIZVt~2I}jB3D5(dj%=fI3Z@F+iE#9MT}N#0lWnLsA)Y@v1a|9YfO8542q$TwO|l(OqMV?gPTu69?Nc zz7~vc`$@!YheEF7O<`#S@oNF|fe@d2jB-#2CbL{;!lvCQRT?l~61eV!EV^mMfF%Mk zUdg~v(Hb!FNUv#msdnhmcotxjcZ>W%hvQ9bbAEEaM{9&;mDEqggh{VJ zYXeF${V+zE;B}nE3C&=wwDW~;S_9qM&W!*gZV50W5ND1L9XmOwhC$^IaZ(|ky-fx{m3$DlSwr^37@QXBhPb2sheN?8P0P~RMq!_bN`^kI(Z zbKw}2?)eH!2?@AQ7q!9<4utlV%fw}=H7PijT+1p>6Wmh!>Y15oN~={^j?xfzsnMJ# z=B2hIF!{|S5)Z7^?5w-ARw<1MeNNFVq*TulR$Zgj?iCY>8}Is5`%pndnRt8rBhckh zne#TN_z=MD@pd*Z6#{dub5OD{cors~4V=?Nlq`8RA^!XPIX&jUNi8gsv6(ChIFN^8 zSon{&7tQST7J&^AD++;|!8>@rj#tJfNXMVdOeCfl(neH>V7?ONxcekLV>TN6kYX$L zQ79uIQU+MVHzDU^ICsUOZ+_BU3BlgMZ)f56wjHMx*Eb2*N#iwTp~-GJJ-VyZ4PPg* zjyFR$!qtcHZeQoyBu2e!u=h_7>wTcJ^Qzu|(MgiUBk%10(8&3(gmOgo@p z%XP1^uOizVCiH2i&5vJDPPQXDK&7svjs<3oFt@3Pm?IWVS>$4@MIbHjoo4& zjVVWb-r;VnHuvM9{YsQ;Pd;`layVMQ-Rf8$IC~Mc@OTKF!2`_E)iW2daOMtMgI13f z%M6S_;GaAbWH{=r_-^31b$^r!^Zz6ju6<1^48B2nclFKwWJAX6AO}$p@)^=Ti2l^H z2#`Zvj~j!@rp;l69;IUpf{JXAetR^p!M+tya9(CN5b^rSrN=Y>#;I+e zIb$)8*md--l*_#FOs6y6-sEn=N#-4P4ZTf~JLP!qJDE4W6FqJEjo}Y#VIw^AsM8Xd z{~tU7Ls-=L|LK8EaoU+?TT?(q@O8b%kZ?F-Leuo0Te2L&c@iW})qfI%gicNRhvspl z`5fuhj&WUnM)tExQyfHW%VPrOlMpzTf;1Mn!n93SNgnlc^oQ{?+h`APT7cqwASS?L zhy?$2Y#54u;GjTZ3jClmTA7dhvjr}nD61fIG>UmOOl}9<356<O>+H? zs8wKiAy!yG(OlJ-)On(`?t<%wM@7qI_>mdoT5+_kDovMTjK#SDzJsf*AP(B9(qYt$ z@Fi7pTh%yE{py*HkSQXSJHUPzA98}x1B`T1^RlpU==nV`P~r?;Ogo^E;!fyQ;2}C} z_2ZzWpogKufcb{W7J8-AASBnLp$zl4BlH1|QY=`L(z3_MsScs3ygBfiBTUt7bJn$d zuQluJqHx@z-nh5^&i06J{WVMaVDI7Dpc3vTfziYM(9WLC{;*<(T^e)D9iQV0+KM0_ zD2)ttnBRI*I5{P?CY~uTI$RQz4(z>2Md0W=f`P|-a6Tu_5j?Q(1qOsUt*_qHc`hjI z=z)UIzsS5%kp!P)I+hl+j$2>A0yVdrK^TDzd*q!VNT#l_5OSm^IBD`@&Hi7s`G4Nw zukG?b(#qHQAL9JK^!V2YZqVwahtQKt|2Vx!i(B+j+&6z^+hf0Z?R)FGw#*93MT}eo z*Et-#-xNy0nez14xnPM^k=CPx!24$DH+z-0yNw109_~R=;e_Jrm~WooYDNPmuix@y za7*3#E!L#Y2ZD`_Oj(B@{gS%0WrlTOM4+apj1y{N80O~@YyQk_Y-9?ezpkLzrjlajnI*4j1MXac>NtUY}glYLaNi;Rq++1GXR?o$b6We`Yr% zpb;90A3=hN388yQ<-?LnBnkipj{S^5M z2iAVf4tH5eBQnzY8ej=9e>v2OgCZ7Yxr`u^Tgyw~M+2~nuyA%z-m zkg7HZUO6fgB1v;n@7N%P_ut!m=l^W8=fx*PZhD%<^Wq_h?WgZDK~x~eTRKa*$I{qx zS>)#Jvv`v-lOiWi01w&HNo|K1=CN(~IB#E4c|z^ilP5wCYx>AY4{Q+XS;Zp~EYJ_o zo4&q?=KZ~+GmhSO5yb8cFoJ7eDbJlD&sWOR#B@?R8aUe`|Npl%Yx$*#<(xO+K5kh8 z>YdNeNYppwa*AVCekVqAuw`x;VK>u))J6317-Sx9E^1YIqL>6R7NuL&FY_3XtGZ=< ztaftl1qe{v>`kzxWu+7Qyd$r@vip&rMS)(D!$}v-wcOPQG5#swTnymoN3l#mQh~(d(N~t zk0%{v{jYw}_)+H-kFLticq<0mV8H9MVetB2Wx0Jje`rhGsd#gJ3BtT2SW?|2!y`4v z%*eHLuItiaj5N7`T9-Q)fqkbZM%of4EBZw2`)>2qRwEv2u5SH;95&z1E?WYG(f`XJ z3+cQxwg~8MDo?j1MJ$fWQoW|h6QXn7FuDi02PUF7VdoOJ;!6_dB_h`QfZxbr z@bk!{!nZ0F*8uf0c}YseDCCse$YmqyZj%$a^`3aEt;jmf%D|kq5GTyaq$FP=pZREv zFVU3wXe0oWlfDTjJxk~Rwa*IT;trYLQ1B)3pJ;;%ev(qbjoYw!UhaV~ipv}sX%nCl zEkGr@4|;&G+hbs3*ps4&Yi+!@8iG9CA)gH#CB~Cx#t$g>52w+Nkyde7S=R*~wwpt> zxq79Q31?(>V2KfqA-!@P%S;_IXg-dqsIR_jWK2cSkG2+PiCQ+!t zVj72sxtR6(!^HVKsrMw*e(CtbJRG_3Iya9XK;uFf0ClYEs=XK8Q-*er>L1#7-_VbG z-*vcP&Z5^&9{ucti`O%_W`_1*+mJp`er_OmFrChhA!pHx$=>NFx1zOml%L3YH5Pkq; zN$|xA5r%xhx|J>1>>;(>7iHt7CzvKH9+L6uYb<940~s00s(mQuL?UC=CmpE+5_CXd zFfzwl^$&x1f-=%IS+RPoleSY7aBRx6lV&doE;YmX6C)HZn!Od=&E$!_DbrdmK)S?; z0#3V&Rwf}NE7GiqzilHEQMhR3)@m=4GWWK{(;w|X`GVtwIRc4SE=pRoCb%}@aAiDW zE?l{2D>NT&tFD+%Nq;ymi7RXA>2HIFD^Z$3Ccv^>?+<cD?iB3Qs)OJLPj+=Wuo5x`68< zs`J7Bpswkt=S$qX@g7_dZPe!8DV;y1=a;$}rhXm6Y*~l&4v&27OwJ`&iUF4Ob~H z>UV4=!+e7~%Irlurue6>SiJkEZBzE`U-XFWXDw5{z3<7{iPPT2_tZkvfwmnN@x=*K9NHYEwy{%)!87_M$ypQ7wJsOxcDk%%j?2-hi$gAI3zqCp+O z75tOlcXBw)F!Pc24qS_IK@qCZ7AF^Cwlmw2W;L!`aScl|QZ58&wfv=Vg>GEaaHZqY zJ_bm>(KN>xxo|z=b?7y%N4!*gTY~xlrw7sR^_U|dnVy1tuWCSpg5H_Lry&a}8}?35 z7g#pzot{p;b>JO*_k%P@qt$3l!n}sB{=VO-KeVQiga*>Ch5hf8`d{_Egb#j7M;pw> zfpoX@rz@G-|4zqYQ7+$`y^ai^Fn->vkxB{U zaWkZameSa~4G(X9t|7Dm{FRbw_lC_|pKZweEf=x$w&%~h4tM-aK9{*oE?TyI&eH8V z8>-Pif{iC3+_Md}bz(w&V-U{78Y{p87-{3P&K2FUea`JjSzuu!C{-A7c=G8SmExIE z1k`9NI;ni=E|R5dz^)7C2J<*XEq02qodoBuFLW`^qk|d+9uL#bUEk5lJNCZ6iOC5r za)vWC?P@YZZybhbyXMciRK(tQ9CgagIr1z<+y&X|b=&c~d`>GDt$B+w z$Gsmtp}9Gyc`EbcqGFB#O`4J`-^`?(bH+^1?KJb~Y;!mVZ<=pruOA;5PzD|6#S zlf5+0GUJ_^LY$dLS8`^tLf2LBz4-C$`Eezyr#~u$Wii1HHm$?sOz=4qVM*R(gB^KO zx*ep=g9B>N1f_BVE4p(Ui`R+E1VIB>DQ3CJz-s2CcrRyQsa`k z1HD_etOm)4;3>aSY|*);QF80-yasA*yXM|%e`m66FGUF_(%`Q1m?Pl2;m0 zk(82F4E!!8WbVQca1euMrQ1tIz&_djj?6m1SZxDP%bTETXz?^zkKIH42#qJeRdND| z-+h3OWp~FlPSM>|8e3j!-h$uPRB*)&OwALhUqN4Txt40CZ`ihNn^U)q&F{sql~oAt zrlK1uPN1)z4aP7T-0y5#0TfIJClgWes=LYiNjaGJ`lmWEwxabq@K8|?yyS=@EBp!g zP$4B$!eQ1?Ek(0!jg~XBKQ8`Qvo)MZScS4Pscdm1l2Mv>@jl#W+ZwL0St2^P;(tPx zGf)8%)WAf}T-|zI3+M|}0s)m?Nwq)DsHa+rLn?E#mQrbJ0G7+lIMUbatu;P$6{d4w3T=&oILC=PxOn&8e09%6?y`Iz}7R9^~{to}*>*nxU<@N&hwwUjj| zbdeIAl=)893U`BTYi8PLYW*kzlvP{5NDE@nzCoQ`))QmL)d;A|=+lt8+RTrlXPp;z zp>yOBAFOn-)VwfOhs$RzKc|MEw-^Lux}v+qHF|g5TXAylgqB1`Tk%gZ7f+-K0AY*O zC@XdV#`j+d(;sPl1D~{QPSQ5^Z#@|Ja77P?u>@esw-N+XW<}41o{_t${2iz0X`PLB zWpIc?tC{c8@b>EAHv0#MyXHKqB;fY7;ZH5|HTMQv!K6mT$rndMa#PWI?SGjz=2tj2#z%NI5psOn@UU|Pr_JpS* z^I9o`Yw?QWorP)~WfaYo(*)$UR_t>-Y$cN#$u1$QQjBO0(?VjXa>`wbIoMZs1{X+K zb5|yUbX}!lhrOUrUe>==_wXCvn5yuj;3%X1o^}9)A``9nB%5gu;T;}(hRy8GpdF;!hG5;E;wKSD)|RnmNhGCC z-2?-R)J=CS8ArdSr$yM3TVTS#T$R^X#}E!MQVF(X?44JoDd)Dv_lQruKQeCiZ0ynG zByd<&h_Xgi$wndH-9}%+|D_%!c9i&#^2S!NaqCyzh&NL#Gs-M=>-la7UJvJU)WBk?On0#Kz6Q+0Z_#H4@9Tf1c@c1@scZF3sfd$dw#TH1Ak_sv#se zywj*Z6l#?qv_Hq%#Gt3V%CAZ+Kxr`}UjC+fhDMvd2VHRwo=Rzd)(|0>#uEO&@lMF_ z@n#u4q%$>3Fl0*oYD(+E!+rGH#kAbcJS+b6?ve6~4_cp(drnN5n{0-Af#}LS2cn~W zKA~*i$Y(|6_YY#VxWzT_R_|jPUwp7WH!e@C$!CrRjxKSFjk}rpeQ~>gli+#w!9w~X zCe=)2D$}{*@l4|(xFoF4Bj;Grzkhu(glv^b)L1keneQ3QEc%{(5S|8+d5n21vVGg1 zE&RjALp>-VInk1G4#uz84491Zch}^gKNXraK6-n zct3c(_i5&(eQ}LXF}qVDcW)v9CJRx&Iv)9~^kGr`+~9ndQMa#QJ=}z$1;l+}#0kWN zOvhXoZ^SHS#Ge%7&oAUsCZ!#+9T_o*O0dn9*hb-b)H4YqY?1gG311Nm)96@aV+$f@ zteU@-X6nNYk8cQ$V7#l!x6+K=+^}N<45l1q$Nya$z%={4MhHZVo^~O9942{myU%fl zVu8bl(#VG!z|69hY;HguCC|oxF!>X4OwEs&=qKid+*Q+H~L3h zQRA^1MEDYaTCs9>MS3xo;Ly}pH?Q~u&07-fR5&L3|1tOOaZO$6-uT`-SIiEO06`7v z-dmJJp(a5~u+ox102Nvi3xXq45?jO`ok6MvJ9Y-KV5m3;v{P|j>giF=8!md*Ei=M6&7T%C6m0_m7ZO7%+hnf~wj^;vR!&8ye3QNi5h(A-}K z_h%8Q;7*E*4;9{^Vz#imc+6XNa^cA~P;onWk>)SV4qmLIwX?H=+26G-pm!OMTRc{; z(DZX?GsGlGTunbKJXv8}_8rU+6Cn}Ct(CTVsJ5R|#cUQ+Akxi?B{=gACV2GsW%|CV^%ukJ)J!8Tb! zFrdRK(Nbv)Sc*v!I_*0zv9{CUmZG0S@GF?;vIOHs+{3GIHNJN*h7}W302pTo&XASM z)~%`Ugu;DorOpL8E%e8h!k<6mY6*3;aHSqOX#FhZGF3jkhOas!3W#3s`4hOSOAzy& z$tk&8-H}s=5w50ot!}yB&c=0red7D;`|{uFBevBHAO0QOSb?FcyLfv?R3$z5pBR}j z^gI1UlY=sbd}mRA2j`(i<#+ZR1S4mR?00jm@PTSne3$Ql2!mZXSv*0|3Cco58n#Zf8&~u*+PY3TPfp zvnTS2_Gg_@Q0Gd*O+)K&jxTjaRsC9YmJypg8xxhaYfU^no>AcNF#L2h+saSt;q^o# z;QKxx&d__e&=H4oa-bXN&vDTM{V?s2o9t2n{cxgQN)h|x{a_D0&<{!V|Gpm>BL--k z(2ri2oJ^v9?NxNfWS2S6w5JZ^1$-QK>9fw+cJ@#b?T6Xj@%{?7T7Lg~fiVX39RlOi z)6kZZky_!M#_ormA8`B&x2#SfFy1T?s>cw)AR!IF4b+AQs$cVC)l-!WwHbT*?5z!% zhP~XIipLFm4R3BVXa$WqNE`nq^JpN0R@mAwT_cy1r0MsP#%hjBwef@$xtAu^#^(;- zsndb4k8Kz}z*ahMwS#CD=Eu942GKyCYHP!s>;|rE?lgiGi7clawrGtbcXaw-kyFdUH(V%Ms=_wPP?R@dzr&Ga^d9@=N#a?ZN7a@H-`X+`Ae zNY=bzOf2{(R3%}IRnDUt-P*Szmz={ZUTWX36w%X>OizC+S4V^i^WSod=EtYYgBQv} zm&(Iy#+13gA%jO|mb=Z7OH|Y2-J+%PX=QHNBk>^YP{tibS{$=bu3Rctm$|>ao30)GK7I7}?hq8I zyH{!7(v*uMmppzbd zJr;O*>CWbPv?5g_zBB!;Y9cY%`D8Ky-g|QOLizZm^2s%0P}BUk%G_VIpY@@Sq_VU# zJ_0}MK@>_m<$w0W(t2>@k+-D1zI$V=eHu-lzau^F7gFajQCt0tMXQ9WJorgP#i|Vn zjP)R=jbHjounTjWll$~7z ziuA@r3;RXvJF!REtzh4ZsF<1Zvb|F^>N(Oe)Izm#sajIhI!P*_*m2|l3(`);C0Imn zyVB8i;L!~B*x(BfmH@svr4GdK@=0#;9XI%K&zO1IAPo15iV zOf8`s?Vmb#IJJA7Q3ztdd804kfYuz!#9v$m}W{~1-1umq!==W7p#OHV;ep-BnihtpzH=gFA zLwC{KJ`N{&bJk0jIpFhfzPg5bZLfCQw)zv6 z~{+n)HU<`0`Z)SAsOwP!*l?WRu>GYY1x+QcTH-d}`fB{O+lC0of z$@%*HW)Rx~FAtRM=fzb&Lm^m(Ona!IUT?87ppOXPa_0sW1c4zBO)HBwhm63A5rkh6 z4t~b2kJ-ma1**Z)D`6$ux-Ur}Bi2sQ%#=Wg`zX61N-mXAiX}^9SpRSaid4&*KolkD zpeE`W@Ts)%eM`WYImt5Fj@K9clwGg=YT@KS-sGaXWld-^N_1{A$(`)0Gg}H6Z3>zf z(Eu@ZzP>;y9PDDZ#O!n9lGu!jK?bp5y}^miM7l9EG}8gyYWSOIXvuzvs}nelEBvrU z3#X)TKoPqaqVw3Em~dqpq0yy)GQ9s`o;B0`8JIxT@jsm-LTX^<{NuiA!nilUuVF&E z>0p=J!fs1L!-jZIa(tcXKv#xE8;u6Ubm_sal9E+rADpSE^zs*n*_s!b4SH#uDB(>y z4)OO25s8J2;)sQ1a(}64XsOHLY9rEKV06v7gF%`7G2si+1zG0im~a)8rwO+wTn-jd zO!yorM;ZS$EVP79nJ1z+1*ec;ksgjO17cysr#6b64Fth(=& ztn%J1+0O{P7^F8u2r*m68;_7YS#(uAQ{-TIh!Ru*{9eE`9~=gL+Zps4>$3fErlG#8 z$6NQ>`V%eN>Z6#>;Bz}@xcq3M-`fTHh<)X4<|EOeH|E&i8@6`b$WGnkh^FCgj{bTR zzOFz#9=MYNw$gtfxn2C&Qi84sPb*E5(WglsQl1?=C;YOZrDL2lp4mCh5w&FN4zTox#ZBGW9 z7e)W|Zry1U2{WgmW%-U6{dnW1;kvFuL+_ppW!{9iF-Z!#h2)bW=w?HU_m210&9jpT zZ*72^+2}G>q6Y@S-wN7z_il}ArO-mvOo|kmX5QE_iDi4)BTYx@8`i}N`k;m;c1-in zhTj~=R1eYBL?Asd#FK_tWy{Zp!FZ-9+0R*T)}FlZ3^CnAs?_!lT;b2oIQKTg7o)-1 zd--RE3lv=M9(Wd=KsN+h<@1L>5?P$XdxX%KnHw#I!!dsjYJO^X?X9%gsFMHb@U(r1 zJg)gnIWSO2I$vp7Fr1`Fwvy?{5PPO^^oG0LM~5^|D53^$>`>h8yEGaSWRc;qP{H#o z8)VqLWm_}pbIaV}b}{;^u*Oo3SejlqY)0QST2Otip@n7ZxWc;F zeS$N*7yAsdj|*h1;vsv}xV~y=`c%l6`)Q)}Ak&wsstOke3hUMpOxoxSU5PG*?scjp zTN%Akd($JFMz4dqWwr(8{mfmJQytsSX&32l~>mKC8xo5l$ z&1Skz@XqZ$l9R$_8S6T-2^{1IVTcBfW-xD1#FKp2pQ-2J2?cc&PW7wvGS3DqtL;RoohTBAcaBMl}n9On=x8-cIex@|uh{d%-V z+|ZqypOQN*h2Qw*dk~6@q4`ZWjQ{5bSuXKRwUpK^#!i`eR$!_{v~FDz*ihg1Jqhs< zs&YrGI;(z4`W<9$Ar0Mp`J0*};yu>TBt^_C{p(1i~N zXFvIl%kv-Exn3$FnGztWe1d=BM$8sTk(g<}b%$SmgB=6L1pkX0)AmWfqTZ`CT>M8v zGhcM0G10Q>#vW5>!b}BUawB0cQ~fWh+Uhf|Bwd~@81vs;dka?(>2WIWRPE~bs+j7( zQ$UE#e8ihIOmz<)l!4`w(cD;5WrgN*0j59H#H;9E*J34+wb_1{YD>QV%SQ6WvbNU# zi(0{{g&ROR`o_Ig*Lt{mKiCCH$^c|+&oP#jwf2>@ml(rUj?TT8^Q`(;4c)aLoLW|U z@e%g{-YoBm~e5MzZ51W|nqQFNiDvDb7L~VV<4c<|ENnST-s8&*zd9`*G z@|SSNrE}b7=Xk4A?Qn)wrD4(FydqtjMcN3QVFe;Me38XTX%k7a4_+q# zH%tjNif>f%<2Li-WA=^XZ(QHZhsA7@3jyit^LLuBUdN7|NAZK#|FX9_2K_QOYeZ7K zW}Hel=Cr=6r^nkv39hC>_JF9*uDX2on(bq^CtX?Otr;qN$V;)AliNr1n z>R8Q>A>(cL`N&}Te_l87!P90K2E75y2vllIyf+}4bpAfn@omIAI*%sFcru!EpH%Q4 zUe7y4)=>o0uBYPUb&1^GyBo}CH?NXnwEu6QupeR=2K_Dh($IYg?q2}6z>MbBP`QgJ zzG-KS^byO4*X{eS-#?H4Bqc`if(f#`bKSlb-vRvh$+!a_cB&`Av%Y2bb^D+2Z4?1I z?<-g;A$wflL)%}m;LY__VU){`WYV|q`=z=Q+W3m*r zb1h99ljj=(zAcGR=imKX7BGCqb#Sym*+Bge>WQ|P?`_MV)WTcHN0^?GuSa;lpKaR| zSSIy~Bwva;9Fk*qaMt?QF+Gcb>_L6p0peDgcrQA__lgkct?`dtslRi0{v+Au-5DO@ zEZgW^ML)Zc71J+}u?NcD_4Gw_lDv8qA94N2shiE4;HWX^N(OVHJ5Gd9-V%0w4?}57 z|M6tMgofHt?W1wB_FKN#&l9$fnO@oht*MEmUyyff7vpVu>GDA?HuPev-v#y@5jf8Y z+qDiEqz_*jazYocPXM~bQ9Uv`ik)7TM(Fp~xdU5x`$l_BZxY+**b*n1YguEgvFG#j z2a&dI* zlL5D(5;vkc--(^f2FL7^!v|=LkMe4Cl6s*fEE8Fx4q=p}O}#c;9W+tzYyX3^&Ve-O+_; z;|acP)qzmY$=otL$_KioyM^bSX>OwRvFu$=42Nd4Td2^zA?<=5}En#`ND?xI{RWhX6EE` z{-z-3jv-Bf)-W@g&q-6%+e%>am!IH5ivoM29v+;&}qnQ7djQ?ucEe>8&VCjI0%xuk@4 z+gXvWA(7G59~GcJ4V5mI-+0m>gzD?bMgUD@Jv&^_M_d~)g~n`|!9RShl8-j8)603& zwT{<~ir*Q0p~i=<4NP8N$xrPV+b$A07|}-4BUb1@R*#_$uRC6EnfDnGe-VeqP%(t_hyMVlj|zrR?zcTw*8&fuN+AIUE|ZvD{t7R zzg)N?w0}1p$7VmweSLsQNkZCo7eRTqa;6l`VI8MBDtoxJbNY^X;Hsy7hNlLM$i*qCh7DwJ9CYW@IO=6 z?DRD{oIH0zpT1WVc(&XgvX2bWEJ@E|3=4=;HDVz=CXf-?g8apA*Vwjw}j?>|G3~3xg zcahvX)yi@UD_4}Qu~a(4$v!AUcAbiqu;dG!Y6ZYp(# zz2IhLHBD2z&kjsP8H5CHj=!@p;;Bd(!&jj zQEUpY7P!B@?Azmsrov zaTW}LF)dr6&5$~#;wlI-*yYsHn@A29uhn)Cf~%{W-&mBpX@oSF6+G}1M^}^Ygh_;1 zjjiY^+~3R39qLM+$)$oFf#%RwhPdksp8f^Ncq(Nm&Cjn`p~wi%o2c!eSCeE??d9A} zcSui4aqT=OKEH0b-cnR!Us?mFEa(dTEXjAYhjBai%ge8vjbx--(WIrI#=fLR;U?5v zrBhA2NG?)~w&VB}0Nf3nQ3Genfnw_8PNM!RALN7R0+KH)xFCeiAy1af8hh#x{UmvA zNf}zf{PjTYcCjU`#-2Pxss&BWtaZO4eHtnnxA7E8a|zUwN%y{^L*^o2ml(R)F8HmBe1|vm%YwZKS}ZRSKUr7W)E3c3LU58jxr+b07rK*<<8v5nU)XS_I+1jrW{Ov zOsXTjp+6x{$DJd}qgGRUCq+@k>&oj7x5R;CNoHgep8H5H`W^DOm!bbme*N>cn>+y~ z0JZ-XMEIOON~Dq_85n_rA0vi>HL!#`(_b6BaPZTy13DKKYe z)sF=_K-TfYBt3VBU3O`j)JD5oHmJpbjEroaE!wgA1tff_UGKBC!>AP-s^*=a$fsKKIr#q%B1e@ zv%2x6d_?V1(;M-#g=$bHsyRy_jXQqoa5ID`ZfE%^#qnb?lCEQ3shDz~LcFz#IPbKw z6J$$gl{)9)=A%}M>+rHnC9f#u$8he7X=OS)8&=c2rm0FrBY+PMds5vXAL?$Zm|?6C zyhjh`qq>@=Qa*TRqy@`(zkKI}i8?z}%9L#! z>dRP3UfPs!YiP!!?E-aSW%((cy(`^oUfJ=AlxS&S=U$m{s%-*Jd7T|b(2^j!k`L=; zc8(o`!pbbUEsE}CSed(f&8f3GLAS1K^926#4s(4%WduJkn81XP{%FhAG;7^#BstVj z9M>t~Qg^HI7Vq7;Ai~`obpYwp+|$Zxnx}QFX(Cfd zO-)h9iAbezBR{QdntKgC;qYwU8L31Md09z1*EW$BoHBRQ_noYofKFm_-XE!3nWSvf z(MKy8w}p&N;bz}pB{dewzo_ynfRTRX8fWeM1TG}K>LfLSa#G=tkBi}snk4S-o#w|+ z9wI|$pM*Dre*oD@l~t4Jv+AgJ&|=CFB^K1$!3x2kw;XQ4i29ZcJ$klm5yNl0#MhfnlQW_s$UkAX$| zsUZ0agD!w+Cke&mxp=mGo!hBsf4QTiM0})a%{tO0;A@-J=V&#+B?vD|3W44P+z08M z{%H%AMA0w8Pq~91kM(r2RJXDufy0(2iKMd-T$vRJrr$Lh5XIcv=X-{_YYpm;1TM zy)M@+YQO0t2*-v8>TDAs9K3#|ErbrVd{!;)*erWSHfM88L^x{GwmZ_Ob}K-&GhBmq zeiJljv$h?VHR$YhGTNN#8$PPE9e6orjT1RLWgA{)5ERkh1SZkurSvP4LeL&w&i&UI z+b5XRONm7^OKHYeZ)w9Mwbf?biJ(!>54*q2~)GrH}+A^~i12SJPIp5%{|=27O{ zBzf&qnAQ;6+gPtj!EL)KkkkIXE)83Tf3qXFZuX79_IV@jrxW?sM^BwuFB-FT=eW`5+!>b43Ag>WWM{4!EdDWnP zKl#%!s%nIGtOtDH_auK&mz?G4`T{O*E{RN?tB758)tjf_9@|mrnmj!!SrwM=6~zK^b2?M?|L8| zl@mW0gy(dDh6A$W%WEf8t0?|oSJ;XA-4~YkEPuFXc|y-}Gn9kHh$;bvH4&wc#T$O+ z=s;h0WpVKRql;y?^gYhOzn5+f`?}S`NWS)6SPsu*KVVY%?T?Ay=@ABgd-|Q?wktl~ zd*v{rTb}D6CPwgo+3z|2^~J*v=_cZc>1mYi{;0L1SRou0e7ax+6c1rjBo}=8U_jJy zJ~$1sK}zzik8Rb5Ks17XkOBycW!Th(#nPVTT?BJ;%J z6U(t@zGSOnPMkb(v1hruXF0-!V>;}Io!^Hp2>`zBoR6P>#rS`&fU8&an^E9_LqSn| z+7;ugSN!ZE@Km-ia9VVitwOo2*4A*tGkk$~!_I{ULu#_ylU(HKh))t%hf?Lz*dW6; zFKnhuO6unq6^Nmgv`b2jOQzmxDtUohBPo~8&$;_`!^5ZN&srlXS+E7mh{}`BFUp4! zN`Yv@!-HT8CR_Qr)(-Jp2hoEutP&0olX3Qyn3)pOfxa{uB^>xKqBiQ1nhtybDxR_) z_ylf6SmyfE$Z!Jo+5!F*+=W@4bbdX&UoFF#1D9A}WPx`z=nT^vCC|XUg5GZPj^x?( z{In?w0URn;f*_CU@-1d&j(B=JR(2kA6Y?#IbRG=@JqeYrzQhJ&GDm{XZMNuWcpI|v zOw|j_xy`F}JbVEET~JcsL!DC>pP=W6NO>CNu_sX|oS+_%T!kYh#LGRsenbg9wc~U( zMZxhkN>yF)<(i;aK`I2>X*F}wdh%C!{G#3w64OrGi!2B~0hhWgduUQ{*Js|o4i)M@ zPIm^g6Y+5|bXX)NPf5b&m4cE6%Tp}_A5Bm!<CX%=Qde z#H=}0)4i?v_bs+1O!+BycSG~8mi>@=`_{-=*?jkQ843ro>~ONSlfH&#j+os##d=uWmr8JLjePDCak4#MsBA@)S;fV9kBeg7&g-&zVI=|2 zW|CuI?Phc@RT~u1+$_E?-ot9lA|f??z9~VbJu8UWsqJu1ckmAU>{*>k$rqHBS86Kn zunz|+Sk{c#w;A2@IzTVupUXoX+cB2AurbO6Y9&1cI8#fkl-s*MX zdI_;^$XlrozKMdaYA1N}A&R7`zf!raBcP1&FVCro7{Saqcxi6cZFB^UA?#Y9vBgaL zlUP(8zT6^uXLtlI>jVr{?YJ#ubOWLAkJThk;rl>ZGU-s36}Tc~Nn$aQk9<0nx7W+Y z999=M1G~Y#(6oo39jlBXZpnT2tZ^@DmJAXb#j~6vJnz%wk1+!uADS&+yz-e9$q} zgk$xp34lqBF@W%*j&SADazC4w-LpOzuJhWr7w82Mpb)}Yq#$G`e3Kf2< zCM*&wsO+xKz2&El2}dwZP;g*?ad|7_WH%*w^+zN>#=K^$u;GE?jFl(5y?N?#h8mkp zJ=0XUl%vGS+1d5WaCXlZ5=^J>@{bRT^eXQ&JT~6>Q@!3)uWO4=MR>_Q?YI5zBE<;U zq1?s12r79lySGeYUk^dhD?F@(~-Wg0{0hTYKANY1{bDEmZ?74@j`75|IJ0eOBYx+&aqI6FXHop;-v-Xfo^N$TnUwDiyc7LJ{UmVN`d#J&*^VPpFP>z8e7Sk|=iqVOnRrJ)S^Hji8Y z8yvHks-GDrevp9i!{+ej(TIT%>*Yp~zD)7=<+UT~Bf=5ph^h9H?ltoS;=u~M`$T1r z>qlgD-~0LR6kU=WPa&}#O$WkRNx4XyQ^E};3za1$*S;2#%PP6TYcCWP_FaP$Q>sWc zZK@vU|FJ1Y_dleIjftCLj*5fyqv{f@HwwtQp5woh<v`K9YR~uz9oJysr2;{cvuxYp_c2H z@hr5;E8GCka+=89acv43obhe%RC* zZbxIz>jue-q7@QW zF&IhpYiN(JvaW9E>u>+^G4+kA?lo?kbaN!#uVFmfNabH|J5T>*+x)U#Y26+O$j&7k z**0N*>inEy)zUvR)yI8lL{xS*N_xa91sO^~RA82C_T5Q?3ytOnr~EEHURc)&(csOM z$y_)I=?jg&_R9*vVD*3t?iY^W+E(=`0;=`Fp~j=K;l`68Scxg?{ky_V^-bX>bJH~3 zm^Y*2D@0-6vC?+dSHS3J5E=pZWMZi)``M%{Kptr5r12G@8~ycKom5o|{D0=Ddc}RG z_{LxAB)QB;k|awK$L6crPUC#jOKvjKZ%J%D<%6B~ucb~=dFF+6$zSm={PINo3jZL? zVcKK5SS%uKJpBG06K=#w=kgGN(vrOhgfhZxf?M1o;ud&nB-(he2qs_c z`|5S>vIl;=I>M8aQw@S=VR)SX4BRE!9!yl#-fHsXaQVS`Kn+SxPQv+@W8zOuFUud7 zeQXOhd@2K9<_440Aw}+$@k#$i#G~G=H zZWoL5L<`{+K)vwYF#*SL=_Z(21Mx@ib)6Ur{4$A8*hwtrUNJnRTw+d=u+t$`uM^Lz z)(Z|Oi-V2sfT}PVDRzvBoyuOu9ECH^)`VTm(Gh+)3;2D(l>LUs(BUa<4QHhdlJ`Y* z6+_P!1Dm_5y+Am~O)CnGd$xI>-Bwp9<@Uvmp4ERflKzgB}o)Fi)OO?oti(kjh3{D+pf;G# z4T`uv~f(QGWM$!=et|Fa{Hx5IH4UG)Zz zE;cIvr$-(aTDitajz4rRdctg(mO587=ShqVW+&D^{LO5cC+J0d`SxkCgvxg8=};m5 z4HxS*+vQjEqQj@+g75QaJGwsS8-tnyQFeOCwVenmK-AD}Uttq~Ng=$C7iWRlYtA%0 z?A;Tunk_(`(<{)o2CFeRJV3S6ulBU9(hEJDA8cU$Gk^pmh+4(FD~&akhoV`2;U%tP z4;+d{rHLs^Wu@I++1lZw-K2c(Nq@*wKhdLzH{|f9gW(ye+8i#&gFPPLEC!A)1A&(w zKg5dK;phy{3r)iWsc<^ztOgsOE(kGi@L)7F?#qt$6f*=l0s?JQ6RTdjWg?1^)t#N{ z@$WBK&pL63BYoC2g0);7BE6hDw!k^V80e1?0|WhjZ^5IhWqjAebjOgYcC z?%!n2%z&zhWFc*ek_vzL6*oE53M!*Q+5wz`j$)yvY9xGA5= zys&stZ}w&H3ATSZGw>yM>=QT}hTmHgPlFTH=A?D8T`*ve)v^ERIl+S56H#a@lL1|g zMiBA-!N~$n=ZRrm9(|&lU^H>joR2uQBjVapR+4Y*BnHJeF($RoA@IvnzR-WlYq<^k=}jz&5ygutGPoK`+Y>b83~`Xu=;L(C zmn(HMYLs4=ciD{Gw88c^AKDGTsX&S$&(Kc-wEoQ>w8sNGN*EbI#R(_@vm=-q!R!b& zM^J2bImeYc$3qhe+D~P!iMo`No8y$3qN;^`2t=6KQHj11Gs_JWmC5KA$1-fNU>P@u zxnLJ8;}Jg!5Y`q62%y#a&)TqD!8h={cXxULOfBIcnK+(_Dn%IUzx!N#R4EUCMvSxs z9OjbJic+Tpr8I(e?VvXI0)4@#S6$%yEh+s@&6WKZ!CJR^=mEj6$`Rc}JU}?9g!RYfLn8r{Ekf@MEp~_<4f=j{B;W(i`!W;|k$RNkFTKU~r)?INJq}Hpd{; zp#!j2N%-?+y%CSG{V`j9Vv^8kZp$pv47`I_o#UtHq)(Qhp=x5v{Cztne*CD1kXKC< zRt|imR!d`aWg>Pa%6%P*cRMZbt+ENJ_fTEE>WTwni0Y$b#%*zb!j z#=#=io5{Ia3fnTilZuh%yf4kR>pQ`z6?pAbMnNQFTKIvoODlcWD5=?=oCaSpP^L?x zDZnx923*+uczAItFB-cmd^YFgN5idJ@zYDEgd4I~P5n)NhNfL$cGy~ZSPb@dT#qgg0G$MG4sOF0n;h&crGy< zzI?`_j4)%|G1uJVVrdAZ*AvQ>g-+5ww!cT~(0KL~4$U~6451FIUcpwWK{wM$cWc@Gx z|Fr(A{p()}Em;5huf|mU*e0Vowf-BdY-l0+*ME3m{X_K&>mO_oq3JwX{|}9>|25xW z{r3mfzbdf)zxk2%?~1KVi$rtwpM66JC}1vG|MI~4Uv^)bt@uaQe_Ex_k4%bt*l~wo z%2F32eID@<2-ab}ILB8H{x@5~M+|@F>$gSQ#hWBV5YzXfG)VzVp`aCV#wo+?`2j!S zIG9XZWDus&so!{U2Wdrk!-#3|rsWZ7Yib6Pd7HP!$C?PZfxm=f@ z%H2`H!S~4yL}HYoG+_2Cf*%G>T-$?kvAV^CLRbzepNc#ULnwW$ITJjpEg|Sl*^(d- zWT034gsVTg%3W=L|9zW8l_ar=dqJmbo>Sc2!sa5 zJ*$=rv7u)nNKsM6`!!R=EOTC|SMqyWIbZ0&z)mzry{LJ&SI!YjoUsfgiq z%Enel>(^{p_SN+R1FJfICA6MKs1MC!iVI3a5jSE_iju~-f^|{2uIoB^vvA8}#@MfuQ$kr0m8wdNGH1ezymc`mWgU7tsE84n zl^tPN;eclU3QDv7W&qy^0DtEPC<1)=V+f!K21A|C)I5G;nB@%N7jVhx^Lb;o_>l*k zda8Ig=?2kvLr2c4Lx65TqtW{hPKRliVUu`v(y{6ee?;i}B8U3_qGcyy$tRg2Jet$&7C5(N-+nD^j6QEgqhM-i=RLSBuV6mOwRGy;;Mxd zCdWES3W#DyeM&0T!tCM_9G74t)6Gx_`WXlgX8w7CFjg00f`tWq;D$g0X6hCqz`;mB zry?0u;=Hr{-Uk!!fF3pp?+nWKULiOKA{gGWLwi|giFs`YtTqU({%_YRvUd@<3(@07 z#T;To-;k_dA%y$EbTH4hiE=bbEt@VRPYHz}prc2K9haQLC0jYiVySicICKU#N{p}S zGFYPcNDAMDaaGOtFdp4N{Cg$WH^fI=xNoz3QMZDe5mo;h;a3Ib7-s}uibv_;xHNJY z^Cf{P#)b};i&eys9xIix}xggoTjciqxev3dO;L*eYX| zsY-qodNN(ALB)adGoHWh1gRbi0eXNt1gCsk2zR zj4oD<*8A-pK+3d(a>s(dQ9YB|@ChTGMg`a%(ipHiV6(p10LC1jol{rLXFnlX^rSW| z+s@xgO@D_j5Wne~lRb;W3^<_AQvBs6CeP9#5PqB~mfY%*T4QWWC)@rHcpiBcx3PK* z1yf!W&bLScWlvU;t+nl$FG&G-cMF^`xH`8NQ^kBuX8z)5-Gw>c8a6+6Q^_KO)4GQi6=nOp5K}Ls^B>A>yCD6QuUN&78I~4n2;9kRy5P(0)jPRw z(d0(@dX}{6Kd9PLZRtRnSBkT+nASeeLh+9(*~*o@%M`xKkrB9K^A^YKduWk+>n?p3 z!a1#hh_=RP!}4U^#w7M-LC*qk`+Vhgw{e$6V-=@GVYV0Q$GiPoBFUZ=f}U<-$|27^ ztBy_!r?P@bJ==^B_9jsc0NpN2T>y0D_TQqyO+gi9-jk68AZzTH$G82ppR9aaM#foD z>ZwTfQzhiXiN%difXc;*9!f$OqY_pf zsQSlb_}Cxd4~=W(_@AAJSG4crHcCKP4l}u@sj8?u1q|%T*sNf(R;^BPmG%yTFT%JI zQUrE|5>8%=7&&gbN|Wd1MD_>pUBU2u=lpa-f!L5dlmxZFwtEs~iX!yu0*A+!{tld6 zy`0DpDF$41`5B;bB0}eP^*iNUKgXw?XPgQWi~TSIZuiPWI(cBIO?}6Vy$8fXFgn8i z8|RmtpL?=sIH;r__Ro%$=8fkw5Ve;>(4Q~*Sj2Bwj}w4p7#^{YvPmq6Y6-Q-rOhdo zQj3--id<4^X{4kuhWJfN|IJr^*$P$r#k}WS#J`ivhC5zaJo^0Zstf)U>p>q9!R(2A zX7amF{~c+i#N!kE4kavS>w!2tV9=1$U zJb6t-dHk{|rURjCW;xnIH^iS!cv?ZeZH!+gSp#lo%o%y)nF!e#0sZo`qajm?JR_E! zflZ$)jG7+r%Auy`$j;!ZMBkJ$Rg{OhCl@YV zw@lIyUsAqqO+;}@Ma{Yz(sbRc>oz|lLi2CNpGbH*{QHa>0~t5wR1_nY1zQexQvM3& z=d6(ZB|h?uRCb1h>mlv>2Y+|uvNH%XcDFNtK}@`umB2;kyafyQUQ0F<&U4Mqnf)-1 zwRz6~`tz2Qra=N!Bpy%>ELuXQ!-WKGPWo?aX3UW<(szzC^B!gD;{L1r$?|*dn!Qid4i(qE1G$Vyl%x$pUB` zD5eMuZd^V?j#n`S<11iDa1lM2iuhL)u0Z30h~h{D6aWc2AaFz!@A4-uRsRb*&qzo6 z7sE{=$}e(f#q$<8BvfP7JQrGC_^J#MQqbyXKXcEF1mxu?HhRAXkFM2o{K7iIGP}9* zudQq_p|y_3f)6D_F>u)56;#4@8Tf~Zh|1d`EpFhuPdH5>Pt$0g)Bf zz6w()lVP2$q1|pK-5=|0GT9zWwh_kolfx#Rbj* zLzoDuR!HAG7d~;B@qQZYngHGr|&?x$2BCy;vVcUO>~+ z+=zI9ODY#Ed1EYz!A|Z+3_@lHt<*8|!3kpp=vR{<)HLf7GBK?}rifg`!~#4TE|##V zLPsbqI_RaSPh&yFrqY*53<#kEIv;rXCh#)W-(;r$Nz(WeK7^O0*;E8~xNraoFr_K4*z3lkLfr^<*lonZbjZA^n-5 zu1uAwLoIVX${vWLaqzgDlE46xXs8oQ$^_OVWU2*PUThaK!v#7h!y;rx2=thq%rGHS zBhU&{$5+nG(v)ylN`xZ?0Yt{j zuLuXUKeYSZ1$d?-Zp<6_t;7G9;)Ue>^F#0A1*;}<`4je=M%$T*ml)mVTD9#naa)hL zd(bD~-YHPIwG_ZgUnLW#Q?9+Le~rK7Lu_W2|BbKZ8$1atcs{a<$+V$(HCM#(p=ZGs zsz6Y*A`Vc;IfsXgsO0k16;INT@^Y&}E6P;K{x2oCujFtUvB~b$6{~0n-?^7UE8OH` zMHvStZd?qv)Wj})7$Mz&vuR}S$xq`!I=6si^8*Jt*k7r7=m=|#qB zE)`K-zZ(1##VrV}fbq210+Km971lf4z!01!{R*nP+B4~Unf`-~CJzhtH2n-2-oWEr zMKqn9x0=i0_%FXQ{cQ>NbZA8p=}%z}N{0@_bICStZj>Q!bwvt|$L|{;wNDP^qB)S* zO5^;)nKLE-DaO+qK2~g-EdO_YMlI%o#PPv?1Y9C&KLJ5R+ouz;S~vS}$(<?ZoyA~5{cmc3XcaRyh2Ro{ z){-8;K_{XD3TB!BJOHmPUj?R}Ks!DZ(`v}!%u&Dz0;x2PTS6ci_*j_A8B#fOtN}Q& zgoe5%_Z-0qd@L#QgK;Xi&?HHp#kBYOl8Y_bd6tD5ru`p2&TLs4Ms$ag1+NLSz7KA8 zeBJYW=$DedMxt-%q7b|!mJvYp*?cCJT+~^00QjT(i+u+|@OIr5`W$IG4&9$ik~G}S z5a%Ve!>XH!+y2bMGm9r&ya-L8;AM2x85u;T#^3mGm!`XqpcUh0-w`EF9K3gu_hPzN zitV1#`g*0{4&^3&_wIkr(*++^Coz}Ub_sQyg+*>s#?16t;v{l(Ut)1-yv^5m@b@QqxzV=BF?+2c1cmxn065bd!g=0 zxoU(I58P=XpyK~{$6z2busAkwEx*erLHQsfi0-!YlLB)srrJ6&(LcYNF zGrZ^?&-)AiS%SUzM0Y3j0Ssu}`KvBrg} z!4sX3X9ro{>Qo0@$KSk?2#KV`#zNcS_}B zl{kN_)ZyUm&=i*HsXW$fpFf3tI)7zN{kC=VJ7j2iE8TE1*HNlDE+1j5DT-=*KS>^k zi%KbEMI+iVj;@YJrb`lgj0obu@k0Fn82z}x-){! zbjM41&R!Aq7^wv|gPJ)(nhTQQphM#x(LF`f&L06rf>XUucIxvx*js`z z8zE#iM)#IrT0!0bgc zS2^FhgB!dws&W}7gRUfSEXGufFx#c1J%T^AD|9rhgYc9j%~GPLx{y3)%sVRR;Rj)4 z#}A_nf-Z;R<_)6~k97Ww%}zP}vA?ww{?;1Sv8?{Fq@esKjy%OyVx1O~c9NKz%n>z4 zuw6#%-P#`Ebs@Odwf?{bI8`1rh2SC(FMxsl&d{4zdc~UP=~sSnN7xaa6k_#I^a4_4 zC)44Ae#~(??RTI`#TgUyuoEG8Ic=sxL`{RUaYqVN3WiJ*BnhUk&B~KYKyVq)`=-U> zum~eHtYC6CM}rGo9L9>OMbzvxtC(7}SQ~G(fleLDP)=K54VPqR52eSSP8;xHNtrrW zp+&r`zP}@iUPs0}--x?>htF&&{Zr@*&smB`9G(FRkqj4?lo&yN(l4xL7Zlge$=i$| zl`3Mbvq8;nRa@pnr*AeAAX6?01ACO|vq13C`SxY?aHGEx%j6rfblG?|73*MSxwE)F z&koNOf`pzfa5)uav;I8w;qdEelBt@BQaM$W#-tTeQ=cCX24v9!6|eAtXwy`NNT-ll z1kbE!$ygkNrWWirwCx?3QWzf{(Tma+pnYm;{LhP0m}(O>HH>M0oLH45+HH^f<~W2* zSjP~8cu??wxV$ngwk^*GG84xJW7-j&#Yp}N0g|RN6zc5a@~}8DAgFasi$&Xu778}1 z5PI1TuPclIaOtcwW|3wxe9*TK`A8eKj6e&7*1m%1^8QB9g5!Y}+76HwTx0&%Er_K4 z7SMpi>JvP(For-2pymfbWoBL-?Yj-SMU18uXU_kw@3l){pg_#$z~LRStQrvnibU{9 zwFzQjqO8^g#D+IRr44^r7$A%3V6sqt1i`IpHqW7b+T~#9*+3mQQU^v;=Gp8opGI=_ z0tA@3_CWgjyXkqBd+GifOsV9)eG&HooO`YQ;OYHND#&;VLM|+to=8pDSd6%7CT8nT zv_4a_BXVkz3em7}E9gkg5W&v}0*fZHW*oDLi?JD*@dvUIQ?SWoWps3#n`7XIqC~%O`V6WxOs|1_aWRq}))tqiMD>d1qf=y=Xyv?dzHo40d#`|bwqTbn#Nb+w2%fpm)27a0Jm;RJijo9@1()wOF~Soxx{3a3S(8l}sMcf)7HlD` z)MX2G*;FnYst$A6!d#Y!Z@M~L zFf|R)$IDQ;e5J5hdE6csa-U@?;WOTa9o!$>g`MP)QP^So_QOuiMib~E-4DAqm@E0g zCYepZw&Q;WTUF~Q*dz)6FR-war9wUbT@QlZS6J`hVBh$ZzaEi4n7Y@iok4{DX5N*$|kU<^H*; z`UG>+c5HNR*4~>N>+QR9W1Dv0+*C~;otyUaqjSS+pT9dd*Ow@S*UuB5P^Kn`n7^Nu z(*JH&{B-)^$_q3be~HYA@q|hufHCgJ=6yb{YgO)xQZgeZPhuNS#il|f~6O{BYh*g1l5NJ@GQLTcYZv33MLd}jUpX* zMvlTrvPl0ZXAhFWCP>0CNVw@mG2n!a{6rmS^CvE``G2mqsgW3apvwPqTH^n?TBRa6 zuS&=daH1;I|GP#)eq;Bwh2RI}9$2fAq5v??-yv(Y>NSE7?~dZbFkx~9)~faUwQ38x zA0Nit#fPrD_^@^L{|g^3KmXsX(ouXsO!oEuHENX5L{rGr5e<6JCK3y*QVUu{2`eEr zS>vjE+avA2v=TM}sPi7>;Yv-dQg?DHgB3PMXq`wGm7`7Lzsh3%FJ;jAB0<#0ctbwuv%HnCU3(KDZg*8|7uwX5;K3KZxY4@``#Nh0X?i4%IK6b6# z)m3MgX?fk}tj|U*>4l|Sm)b`Q@ha`KGa^%go$vEK>p$#%-_PUQBV^f~oq5lD-tX7n z=j-_*899gysosbrE6!q+&j7bL<85-#LhYaruRACnwM+2yr22Tt3Rr+KJD=}BZWdpY z1Y?I+-T})CGF`}oJl(vA2=^Y?o=Wh)vv+g0|M@St7Phxm*5{i02;%rq zg;Qd8NVzobOloB0T)Ro0X~#<9^!P^s6MBSy4~g3FD39E73Vny;7q)7edo~TL;kV&` z@lk&_T8#F5rg~coevl_qk~n0?qDANcDYBA zBicz6L_2mG2-&n3Jji>s7Z#*Rv=>=?Z1hE04;np@6Z_hcmRrcIIWHJ^AdS7EKdA2u zvbW5|wQlzyzgFq87>uy##UXoRZHH>>Kuk=`3f@1rlD02@iJiZ;e}PGEta$@PJS!G> zg;L^-{DrO_mkS!n`%XLz7P_r(y>RHy8{1~kuWxj%QJ0)py?y;FTi$y9(4HR_IM>!K ze=$Sr*e=sGw+G3CdwpfzUqr`O{S#ii_UL}7Jvz`Rvh63;ak-*&XHYRsY63FgU|$gT z-&CC`)8xy~ugrT?W+q!z?(%BRFNhJ5>46Z`%B5DDWz=lRk0~3*(j-rl2SOQ zD?2|61v)Shz;9IK!sGqfZn}4$W44N1$#LBoru}CWo_|G3Wi8s|)lTv#EI@+lyu@Qa z1KV7S3daF)D*?zwcy&$iyC0#NB&O#pM_ng0t zk~Ezs`)v zo1#lZz!kNmh`+Vu(+$9;cPa*cM~U-Z1n3Z^Ygi>VKGol_jznh>dT4-kyh=pi&hL*y z(X8S&DhB-yos)#~E+74?Ye$nq7bW26`*sOD=ynjqm4a|CT zLzb*q3tUKzh%)B#^Edh%jp661B`4}OPH4i`{YBQKnaC;mHVs3Pzo_zg*mvEdu($SL zj&fjOd0tX`Ccz!7#N;U5qp+*?iL+HD&xzF$ztK=DH0`=UoP1-z-nCAiZdD(_-Dq;<=)0 zPJgkV1UPXA4FrUffZ(v4QMt~`nEXtFn=wOzNK7I=1K1041X2b*g?$r-dk-RZ_Q|>N z;iDwN?X$npj#Aj0T7ze#U~|u41e6rM*8Z~dz`Le&+bn&y0cPKhS{z zpE&dBReAnz{eh&*hHcwp{Qu?;m~m)Z$Jl!df2!S^yI0iwf$_xP%DZf1eAf?+=8=`U4-Xz{&r;KkzzqrcFhxTMHGRrehuZm^E(*#xih) zI6J^%E+xi~bGzrnH<`2DI$@#lU_kcY2a=&xFIAar@{N4cWB}*lF2JEv$ zBl(K4$t?X}zS7|)2H!u_?i|WDTg?6>XF%_OCee0M^UOvD4nR@A_#EQ&$ZnkX`Hg|^H*_+{)N_Z}RIF3-z%(r=;~nvqwtJvVla4}nO* z*gg#c*`gRi*jI*aC$(R0#!y(0Wcx;?#f!MAyu;EuF2qo1c1gL-hCP|F<4WCLLwh!^ zm4&{V6Dfs3`%3@Ymm2O|H{dnY)U5FRUGIN;2!G;rM{>^uswpu+Vhrc~x8ue|m1ugT z=GWas-jgt?+lDs;YudWCA;hDn0$78iHjGHN1^AI5O`&t!u(KbQ0B7+r& zbOB+C5_FvRdLaF)w@QeEYPkr4Oh3SA*60u~Q%71Q?L10?QdKn1e_FDRSGsP4X$Ab& zv89f;Bh`i(-E=J3Tf`pb>>UuA=xN{KCUq}5ouHfX4st@pq)Q3M>+GqPPMw>H$1tR(OD&$C}+dhWq|dxI4B5+GD8M00xs@~;X*yBP`*4PvRz zA-XtkuILz0VKccCQN$L)i#;BueJ=Pp)S9`$nz`rlKHCZTLhRxiATo5t#RcwJoWgK^ zhQ)aTj2`M9|Mo0zhh)cyC&jDwyo^Jks46{c$* z@sB>anw>?e7&jr7h_)`Za&q}D+CI5;yYO?M$^TG@IQT(wGK`_4-96cZJx*ZI^5h+@ zM5?tYL}w#Wf{FiwH15Gk*$wB0eE)sE48a-gXmot!p-H7#GJ@^?tBzoW{~-5m1y#*#_uRjd&)gZMO|D_rJhQ9QE$gx%%Y zZgD(-wfC(whlHTFCsZ@xMzY4u!alPA2`9Wm|NJ{#(s8f)UcHn^jr(endQM)^0)+dZ z2&~_^A&Fo*2CFEkiamG1C71`RXsL>uFm=LL2XyT)U_q|;)r4NjNaa<95S!|72fF)w zt0Kq;;Jps-LZJ-dYjT*hosw$tKTWby6LRREkZF`tf7mO|ASNy%!OJM8>#YN-tye|; z^~shU`msA` zbEu(S0KHKbjdXLCl$xb1C%Gq)5;6e(5OlaPrHTgr1G$+*IHk-u_!KMfu8-jrd@O(= zLyMy6no4qxc^%KG&cu$Ba1F?p03gt5V$YjXx-IO^@epuJh@;?;!J(~U-kZUFq4uCd zZ%*$nJZM~xk(x^}Uq}b%Saw}2$j0Hg>Uk;I^((c4?f9@`w^P^gkn0ynN(U7`&{?RJ zDEZ`*C6z?Bp+@LXn`#?T_cwOuQpm8wsy%ilyqB>XwgnunP&I4`1~7pk2%fM=>`$7z zbQy#nO<3E0MDz>c0NjQ<25p^S4xdp4$%B6s?#xwg9ILjTfNcVL;6C;ATA3k5+ebIf zr%5$muN(TSY#KPs1UApJt{9Q01Ch|**ZG!4NNS$}gAe^`2#;3@s@WNR5cIdQsA;sL z2%<-(8c(aPzeYNFkd@^k;rTe*wS9bmh4;7Pa8scnz_QC84z229mx(K8#!tAr=G=-G zOPgjN=Wn9&N`l3u=UP78={8VJ1wS0sAtF&tNj%DtOD8B&H4E2CffuvXgKb4W5gkBe zfQ$i(irzrp0QB;`+?has(x3bn{uG!mk4x3yu>nV!6dW$Yf)1*CN}jkeN8StjXP*`~ z&oh;aO&V1kBBDmiERQyBj6Zp}wk#1tI63jk(m6wPEcTtDoh~a2Xhw+p##&LQE z3F%xlg{VyJnVnl3QAvXjq5|&=_+voQ3jRgHyRY=Qi;lJ)?dOvsWdDB0z&nqjZX z70&8C7h#8njASVu?!3wN=qPA~g#Ezc6v4AN+!YIzzf4z#{2`2L?6_-}eHC-!P*ppi ztz^7fRR;rQs~?brM8MOa+sgeZ^ZZzgcg*mFFQ4%v0wLg*Ah4RLfo2iXx>5&pd0(@LXN>=3T?J$LU1TQHGotRB;af8@M!R3} zv9PxY5Rot;%!Fx1488PTf4f$zFw^Kx)T8}J@sN9t-uF9J(g~+@O>jtKLC8Rq^B#~S zBIz@G9VD(Lla?~rBD(Dzs}oIgfdw)2z_`LMkhT}Sg+(3;t?>QvQoDwB$Q95a=*HEJ zni1HZ&ucjofLX|>_HRGEc9hLKIFx0M>*&ss%vs9KJy0SXR)N*y4JYBZz=AQ zy0*7dG>b)?nBaZ(Op&#(o)zbY=DkEOGzeyIJqNzcnzNx%K`0br+LNIzDaXr1TLv2G z$87X}lJkN9!nEGj+XY+eOBGVaj^_|?3$1R{Q`rqid{7R)bM%Qv+&K=e4xCa@`K!S`3dKwgh?5|=@7Nt8Xdc3fc?_z4X2#@ zHsPYV&&&3qGd0>#;8yHa?J<Hp6 zxf+T?Kz;WZ@D#?a?V|&XWM-ijp}2!{9C2W>4w3o<0!Ltgw;>4Gi_767`RW_#32H>*i@e{&MTe*G0HbF2dR-B8?-V`GX9ZHX$IxBR%LC&9w z_jIzMx6e0nf$S)vYp|H``w~_futzt{*yVd5JL%%`1I$ug@xdYN5sSoIGI+uGh!GVH z9e*cRo=SS=;Un+~;!lA6V5N;R*>BLJ2Ji!&8~Sn9g8b@uQW#IqBX_Zy{_~+972A1jkcd46W-(+B#aJ9a zeHfReKUj_n;6?TuOgrwakCo~%D5`c4d`$~VD%c8^$4&c_60$A(D++w2>K*w_yFZJH zlIXKN7}ZC3xMH{1*NDKYvx+FDV(^S5>cQ72%qn)XLVoedO+KVazf;%#56&%=w#*6E zadlh|iN*Vq6S6no+2`;tGG+Ur}Kl3zE~_w49|{4X;0cPw=p zEE$y23=cQKc0yGos@so0bwC^dLxQnN!LKnP3f2xU zzKW0=%&(Yif0`{jA~Wz7p+?OKiZ!9|3BCf*(88o6AlK`P*bYZdoKEeT0db&?@m{F-fN#t_A?uZ@WMX6Z_lY(6JGqSO52Y_bP z+eV-!k1|Cw+mI!>9BsOyjnBcKZ&X#UIStsOH`Z?5XpZIW#6Fmsz# zfD+*yu=ES$ey>RkjDr{#Seo5fQX?v^1+v_0&^~-l>I`j5BXDSBw*c!U)GUoO1Hd@zho=-03=b=n7Asdw78?THugxZVOZxd-t<~lp(oiaP+j^ANn zbpul-*}hOe{%YXCN#hE__SEb*nI0Q4{2!bo#qT&DV3CcRy#tZil{BI)_|N@J>gH1T zt?s*1-BZ#nuX5gJQr*vFl~43$N!Ee%OzD}4)K{kdla5JW+4|IQW-1}$n!H`QI}0bh zJ5@=~lhSX26c&qzP$vkTmYycs{vq9+bFRcx-o?1@&Qb2ZC0FC_sHV|%VRn<>3~b@2 zc~e8)U`^p`ocjO`+g*u|5sZb48nOaRlY0Tm>Ob{Pk&(%;o1`iBfhpPIL|{5DeJP>W zS_2VUptiM@?~0vJjqeI+ut}u&mvBIh)Y>n#(DTS4ZW}!SQpH__Ao4C6pOagENtz;V z>r|e}S|ZeanwP%;OCNo63a6s60C~O-iWs1hNUo2I*Xy!(->hAtou!0Lg`EbcAWbpg z6J>ipA~%);EDHO=$3WB!!V_IbiJg!{Q!dM>o!w@XrldGu_NONV(oNOzcihd{Y4?<@ zjyvTC*Q`U4x#NG}$_wnN+vu;!!n{DkbC=?sN_-Kpk8lBJJ5SwKsNk7Q?3?ZEU4eTT zpvs_#+3?S{Ji zT%98n5m-##N91C4wwdvxD01|DGXldg$_LAUNJ6nOa=!1UBV~hXU4GB`8%?z6{?|F- zxV^iHcg_I8Xe{M=F_Nn*VrQ}tnH9>rPmF_CF{4N!vKW#iQ}ne)q(xYO_8Hiw++S6> zD$AUl)oDfoR__;tj65kS5yBs0hvTrSYxeI3*n`?NqjH)^Y|F`U$RV{)LDi|P_Z!E% z5x3QXZQ&%I4mkIeoH!{b#cxdrSWSR3dwW^5@qoS2tvX&AIn)v%<~T3UfH|(mybxE( zsl2->#yP`oC{iF#@-jr&MjfRJIa(klNGAp#IUZ9|`5C zfeJmax79IO8(UNlID8Si4tju0XH0ZDi5_5y9w1@I85k*Ldt?NG-Op7=B^+JI$Odvn zLC6&_M#{Ewq~|*#7sETrN>PFwyqX>iRvWGdRRlmbgBc_kTU15VrNAIi*#&I8hVk2r zzsD#~d=1aR37MFc80Tg((Wn^_Lw6?fWQeRn@Zxk3pDoejqH;VJd>kaG`wu0F^=yM2 z=ZZj9j*TXKRn36KAiAumL6I#9^?&6$k@4DIjCB_T^+jxLFhIwUX6@CLzsepkmXHwCyLl z1dy_}jd+n}@lpu?B4r1?gF2QCY6o^H>$h>M8%cre9kp#Isg8y6a>x_|<>(pJ*23{O zLjNvChi8Z<1{)B3xtM%S;hlqxXse4jB5DOA>u#4UT~R-J3FdMALa8|PA&qC>f7%6O z+_rUuRMi}jzTPoPLXJ?Zjj_w=`n|Xs)=zhg?e@q*!O7T4BTE>#793Uax8kzUyjQ_0 z+Jm)$-KAvcitiMCb0X01-@!-HFqc)APq2%%y*um={uF1($BEYC9N4G$&#g-;zcrzJ znql?dmaPuWE9924U`*5DWWJ0DLEjCkz?^93DvF-V;zjkWJGc{D@u5Ks&(W*e_Kprz zB`NhqL|!oXM<&cn^(oTJEmBpS)HPnJPZQiyeU?-|F{;~xv{G;BtDoLi728)2cjp$* zS=C{PNX<7(%_%4`mYOHXy1pu>{g~}F6l=XCHD}mfRi)-^TXwV5EDN1dv;BJw7jQdx z4pOif&jD`YmFJ+zIWaVpt3zjuXP9kX#XR1ECY)~{L4|Lw@b0S&W)GheYvqcBgwN64 z7zevs2H)nj&{%Q*kWVpL9x}F)+yk<^;&l#ZRXA&89Cln^rSRgvC$Btu}*`bMcc*dp;#eI$!Ik z`yICF(fu5PR?R8sm!M6EZPBQ}Vsh)4${k*qf#j7o*IvwYeIBN{vKJGL&YxZ5+su-^oGldL@i}{+6^74XYuiEj3IWjosf~Xsl!pvplAliK>l+NLZU%d6X$>Q5hC?8*Sh@d*SO(*~)&!@y#bZK|6JP-dAbG7OcL@cU zpBsa}?tOO&qrIs+Sh2!g!W}GL=`P_bcJ!67#Y?o(I-l66965MoWrJ2=w+twR)vkuc z34k2nUc4nS{*u_}UHD7lyd~rO)|7hATOwHTkD=v9rUndPo(NytTVljuye07h*H@zV zmLzyfOx_Z+wAmLexzkn>nDZ0W~N&D_mC8M#9 z7V}u46ya;p#tLtXQ`h;^cquilEA@-5pfinYtkdA+RH%hkLXs&mNZr>5cp)%*(^>8Y<_Id9pX zD?Fu!x3W$fLKM?sp$^$?3yoX0Kfkeure5Nn2ERWVFr%)xvX;+5Q88}f+|&?SfWj}p z;wXF-lma!t@HN7b#W1Rw`D?ds_q-KZiXm9sNw~bzRpE#ZA@9YIY`#=b;ldDJ*m&P^ zI++Y%$?{x2ypgT53F{U_uTO^FWsA+;9oLX0a=Rn^ZP?4++zGhHhG}BW-7UF>rR>)2 zFKqO@4OVP2R!f(mf`$oRJD(|oWlTF=^J_2d-g$1Q!c_j>O#30#QpsLOBNh~ZZ|o$y zbT=!<%AHVQ0;T5C30OqM10mTq zu&_v4INkCrCwnZrIA^0Eq@27@0i6#cMDwJs+1<#NVqz7yfP|*vHt=T9H(pzM9nHA{ zF&wsoSAxPiv^>GU821P&AA>)KAPf(1WsrpjNac+;b^3gpH#hApXPJ1ieIArjVy@6< zGoi|7z?N{~YcpYS(DWAZjV1H+D9|DA;0jo?#BZ?{9X!Ee+WT)cm3J~_A~F2iev3#Q zh+lc&!Ez?R(gSsE{{v#%i)wElVgZ*oNmXV~63q6r-V&*qwCAqSbrj5G+ecxApopRV z2M6<#I!-D%6VR2bd4ggs8kY|Zu3tLNEx`H|wZwI%B+-4=>D)5*poD7g=~9qtCo=uU zR0h$zij)@X*sH@;O0}y{&JwTA0OSXOAw#NEWF9L(j!>K^qNo{3RH?*}%M#rJ!-+db ztjwswZovv6b`hyVm!y=VwFHb)w~{2Txx=x`^W0Zz*5->T7*8A{%}x;IA!)YBE5!MQSnZ?5$T>cUW@BBld|1D8dRp zN)P0urTFJt-ejG#ygJUWW8Hw%==7MH8!%oqfFVTiszob?IfOLRY~EaDOd!SZwkB_l-0{;3ih30zxcfNA z3##Jhq-|j4B@wy$R9U#=n6Hn}WN|EG@y2Ne7MRiklUZMYwXGd?>p9>8y?R#B^HMWe z7Lxw|ADR23kFH@fuOM@kW|N#&ZCGMf%v{6b5R`sHen|0hikW@b+(59uLwqt(+N~$&pi^I1w@+_|gmT)7>%#3}&`84Jg_06bq zMv=SA`w<{B#aC+1kq@hB67jx*$1f%ctdK0;xo$y*Hz(zO1+*IF&oWALilq-;czUI= z*FDgjj_yRx*;r12>y{G~`Sp;&t3Wo#w6V7j&}614W`(@HYaY>Uc2j`3E)@P-GYWQ{>#gL?jom2`olVp0zyjqpNd-9e`=Nwh6R3@}}|boFp<$ zo>0pi8cSxGw#slV97(Q4c0dIU7&jP`;L7zP?eYW5`L2z_gM*)+9Rq_4mBMWk@MD*fMYtOcNz*-t?)3yYzzD-8@OE+JTKM ziuXXKppc2!xXR1HLYCntt399G7|wzGI`}l2GGP56t8j6-U>=283Oo<7W^E5U9y4v# ziuh|j6T@W@7__$4j`gN3w52nCpSdN=1iQ1rFScZBAd!H$0Z>^xEuyX?{CAvEtR!oF z!xk5olejfu!zLVnY9MYy-b(OWv;c4EB-OoQ1v#u`y>^(KAg&WzWZ)lSTf~*{${e#V z)gwuY`PsH1Dj^w}Kg?Dn3w^5U4T*s?33^MACChxHlL5;&pAi=+zFXO4~D4rlq6+ z1Rr{XEy7|?3Pf)>C-U!XVJSV&zTPMTBB!dCYugtuRfKPXbVB_pmv*V(<=?N6`0_wP`D)YEK5tmRexlF}}o z+r_i3JRjio*b3Mp)Ou5Jz1Xsf28wxo$*vgAAH#OVkd4&v7ttScWg|7w!6vcgXY?}c zrJsv6zb6|BlZ>y{tV(EjekHgqTH0yy(R1V@JOc7jQ$oWMz^Fr;d%mmG6~$uM*Tx*p z&%<$m*C0vh@PI7=RET6|54fNvzEPo?6l-4g?pUC^mHM1^C^^yQf@=t6;I`(R%P?jC z4nj8vuP0^PE)j`ee~aKI#&%Wa_4$D)kFAulzj2&&O*5ze{oiV46uzH!4dUr5>H%g) z_Z?^bR`!CKz!+cwhIbg==-OnaNhdN>ciGCb~k3Rn%PDg{^~_SWgO15$dF9-E{D zdw)3~rCEMsgx^ZZX|mbR7#kW2`kPGuY{Ci=cp1;t4M63cdhB~4sit6EUd;+%+T08q zVECxn=VtV%QqEf?wv^JaNb;uU!LC|X3Qj)iJ`*slqf8yW#AI>D95L^hD;W%mK_GiY z5*;5S-k9Jxiho7y5~*4o>+UWsGH6Kq|IH z2+o3pwU3>2WPj(>_0Dl@x#-kw(_xMkKLtNu3O)k!)q@LGW^uwCl5cFJk^kcvDjMPbX*`q z!KJV__S+C|vQ79_5FqsSGmb&kmb0W<06@wC=7}m%+CGG)q>itEvyy`Mw0)^M&XSkE zJrzE!I{r$A0p#at)piPlCSsF8VrZYODB3j^S0MqY-;X*zRq+*E5iLTl1fwwQ=;v(< zX~#!6(>>(#e|-OQ&&*K=(vaIhLrS#`eE)N9;wZOg*rqOayiFhsp8o6Sk6gc%vbo=M z{Dpkj_R00%|EyKxk+J<5xUUlrsr$F%4)!s!G0L1}>EdkPsfTuxg8AMqfXy6lq8SP_ zIf0XIcj7gD_N1w(+l|PD+y$-^WJBotOmrv718SRQ>S!(x z@LbQ}_w?jHU{fE#&xcyhF0|fE0=%S;#>H2_LK;JzMf|(q7R8&&K8ALXroxG)ehH3! z0|2Jb8BgnwbR>ia`$yZGsEudU!CYFhlWf6ONBA`zV!-jV5|5xY*{3Z54Z68Xl;U+t zJahTYD4sK4gvNWAhSOK&u9~{Vk-aH(UJ3whl>AG}U~HY)@@%Y}Y>^Tje^;Hl9{6_i zHr=$I&K^(vvAW+_!g^RvZj&>%urmN=3;-Or#4ceFd=u>nc9(6Rx)6D8p*&aE73^;} zQ(eiig-;c)H$Bhwj<@_5_2kVl>s@~uuUl{0@w`tEy10a8FD3-T>-b#i`Q+Z|y@9gH zRQXd00FXJS7Ac5_-ZvFKwjJ4PWbc!Qdym=vs5;YRhSX#1MIu0o*DLXS^!|{Wa6GTN zo>QTvVMu#}CT=?I+jS<_ux4HOF`dtRW?S?64$JfZl(*IXMqPrIZ*V2SaM@!9&elfz z#(!yh5=Cq0umcI?IM|=PiQ#{%uD9hHlo%>6ui%z^JQh!zF4rLBhd-wHZ7OarZaw|8 zn;HJF%7369;Q0Rmj`IehDY`{f*RE3$4_XrQMhqH;=!FV`!J22D+{wiJ?6FCm9RAJh zOpYzzng$7^1ivXurl{vR%XHPEQ@7|We~vu)6kB#t6;dz@_l|UsqJ8Gfoilk?<&N4@ zY8gwlCdQU;i3Ng~@Hj#bIP(`g+A-d@DB}C(lG__A=n9|I-KW^cMR^;+JBw)6an@~) z-G3s=Qd8u*uXcVT6l%v15WGq-Cj2AafQ?1R7M4Pj*CA3+V!18Cmt#}IV}#m>5!mnx zqlBO#!Re9`!G2B*;I{CnVvXIB)`B{1Afz=lQPC(>Qp5|c1nk_^l1cEm2>$?zTgd>2 zJ6NfcDtW0=F9`{S{_)s)SWK56K%8PUL^bm)0|L-~x%Q4ho=4uc)|pgjHps5Q;HB)} zFl9EXER_n4i2gLTWtyqs3T#=bB=(wA$>G%cfpii&0IztwHF@iD&v@EZci)!fqI;9O zk}s|pa#!ldTw3oHtUQsuP)Z;>f!BjxDAh3Ka*fs$&uSVpUFTMmr-6Va{Hsyzz(Ebf z8-K&&C;mM+q%gHIdVSR#90Es(KiCg|7-DnY-tpp{n{v4#y3!Q8+>=Q!Wt?<{sRKCE zg$B=O#N*XYjTrM7t|rJ;fMfcH$P)xSl5|iyuCtU<$8up8;CUS--?R)ydZ63D-e*vR z1lK@Bn@J}N)AXoypgt~_bSliYjw6XhwP?nEmKYFYQ+7nxx;~8Ha!#n#>`fM@f-*sv z9u@f=E3%*9+>*|{D2o4dd`qgUYKY>!rl)La=N_Z8e1qp^omj?La)TmmibEFESs0QnPR;Ty0O%jphWgv9KkdtNjPm!_kdbpjXF1 zgIukDoNste1f#CRCG`fHws6HQD^RAlx2vP~g7A9spPu215t6V`)F7AKWKNa2j?PuL zr4=` zh!;Xj^5h6YK3r6X{pKI>0U%T{;Ym1FMkJCRa~DAiLb^501aeNe2MM=BFJqo&#{WkSh>6}OuZ33lNEHv@ zoK*%w@CAH8%yO)weT_Hpo@+R}D7cOwhXJB~NCL1;!XPLq1NMswROx)$Q-v0Hb+pe6 zVx(((I`MD00w|!{PLUL0-S!}QF!AHcqav#WFXaw~=?8SMbvf%UIXf#$~EopP{)~FhtjM(LZ zVIcUg!60zF)DA_t3X!J^Z{?a$c9f9-RO}IzSOX{zQb^svgyY@4f@qwzOR&XlzT4oxAdmgs6HtOhlGFPzQ zq+XFQi`8j=0z`@jPR}KO{6`KsnD&y_PFm`L8%_6K}caXn?MXPP=9ZHp1 zC{d~s$-2NJ5h@-O{DCTCD{*{HWR0LzA;FNKj=|V=8*;|&|8@~#e<8m(*ro2&#+X72`j$sGmrP505^ugEf~GcBP} zw693B*n^+8U?*cT-M#q;&;Md>_z;#oS*6>LY`og3wLp8`=pi_Ybo3)=h<$Y9!=@+_ z_&6JubgNCiK%%U72hX88QwjDH+(#v4QOvn|5OTb!ip48h-XTkKwP|y`>0G_(#IeX< zC-zG_6((suEp;dK=99u|wvN``m6)U~GmCoVV+QyydN+Dxo>aw}6%{7Sfq0qzYoLGC zPD!7%M;Z@;&tJ@QyHPIy$dCJj{BW2Y*FF_*WSI>lC#n-r+JWSUQ|C)m%d#o_huuT~ zLbarp7k%7-FeR8P+q*+wzaEjjTEhDASMk_p##{Ux+MKbK%wIkIr8_UMN6p)Qx-?!$ zB1&XJ=~BZH-nUe>^XCg1Z|ppOwz zz0d%21)IS(N@!-G5V6-|@iyCow!sEZgz@Em2OC65WRV<#nD@w|;-KgYK-1yT<-eKjP-7;(`rg{!YIxX-}4Zi9yMr3oR)ayPruaMp<-Lav+!TOZ4I=K|lnY zF1Yvprt-1qa*Kx#$$c0L5KpDr*mhJcgNs{h!X^Wjvo}BdJXx?kkQ#`qkJa6$T;{jH zWv_MC=F(V5)5sflOmU{$8wKWZ z*zd+x8|6mqVST726VbXAok6DWeTz3px6EG$sxq?r9$UM0Iky!F&Sb@y6us2?wOf{F z4T24ZD(ocf70WWgk#{6UK-y2P_0CG_oR!@A0eI6uH@KF*iCoj!D7zr!EaWwjebW0P zZNBmcSc&4v>-B4)MPh_|j>pjBu6*_%lj#`px^6l0ZXnIz!k0#lGaU-L^V~G*p2A~C zVg*3{!8!Za2-F1Lz`#8dMi9~YYJ{-?gO1D>@?X~_zku->Y#av_M(l2_zj{0@p@Rnt z`j49qqPb0NQ6nZyIO+<&$@tufz?7eNGw3NGTj8Q+wK9AKb>e{$XX6pl`^WPU<73e1 z`JA{=b60-NmK9T&c6(1U0Oy9BMa|fmZD#-+&I%{ zr>jwvLjtTR;Wu&H;g3dc@WL?f3z?&b1oLrJn&yU~nc|-|4Gj`>MFUDjxjDQg;mf=u064!_)8%(^rL>L#~06&@cu`wkn-F z-r$WFlz5{QAOHO=X{U)vRZU}*OAQ$39#CR=z&AVATa>lf0O3DGLe2KmU4xDBupUNr z_F91v)>Sj$LyQt5a(x)Kr8RD!Sx%MB_FAhy`x%>@`-^JAnpVXkLLOyJldAND2O7m? zLRk#TT>=7|{me~rt_!}!*duWm4wgRn63gJcbUP`N3{pZo$gl^iVEpKWbwuel#&9Tn zymHHOs`9%h?6mY&g56ZHR&Xn|F?O5sR#L7}NQTO0KYyHkbKyqW8YXl~f-r0I!7Z6cB>=B`6A3mC4i^RjX< zu6~N5@xuVvh8$=S1N1Vx0ppQ`OcknK8C_$;%JLkl3Vco3iDi%v!6(BkJJ*I~G5 z@J~+Y_SAq45ggPO>B^&LmPGKM@5k%?FN9c*fv_{#sWgy@*piJicI)*Qxx^rpV z3wH}RA$$_tYMAxtXz`6&;j$>>z*uZeo|hO$x0v7-^ zpr9}Rbw$f>P1K)EEia0}KZq@RX#6`e9Tl)X!sir+O$q@78ej0QzCo<0HFD%mUSW`POh7mWS9=(13DG43z$j3jc+8wo}bn6~sl2V*2nW{79& zBF`>ujgDSRvA_;QenT)`sUJjz_;KbD9dJ_zjDm%1C9DoP6`(2GeU3mQ6>ebuDv5dD z0>Oxytm(Z3zE1#hl-_R&q13zA)c<)X)GeX`Unn$m#NazS-0{cg2Y456IrTDnoqP*b zGrd489=aV##cwBNAThhZ+cL$3U{o|Tb!qNj!y)lod|^`WmESS1tQibRdAP3|>{(0z z&IhkA>|>OdN%UFFActKik4~d&>HbE7dL@n6aBt}(FhdH&(7JmL6Ovl4-c(+1%e9;N z*O;3*J~H-Z&>U;|d^p0D=X5G6sgAD)9-fqGIH))k3jX`Yn9WV1zZFdm9v zAK(e$vjjlTfh^`~nO?W&+ws}fbjXt#5!>{yk(dDS84m-W)Uyut07I_BVt}5FIQ&JOky3k_}6qDXGu;F^gUok*IU#9KjnXroGn+l&*r%kJ+gd~UNXjJNd@N>F3X(R13nDD*_v3` znV&1*IM2!mpM=xmY0u=_hN&LNMeVg`j@n}&W+4tjT(u2EAaD+G>-amI!yNNoA52Y* zIc-G{BBO1wR!uNt#IXwLAPN;7j=x;A$J=$NqTtadE>;Sf5Or^VLj^qF@fvQ>!hFMr z;6)0|*j-mlQ3cvM+X-O-PK{;D2-H&Zr{G+{Oe(6abj@$PZ|%bf0rZ)2EKiKLEalg9 z!?qBSTkapCZZ*NEgdXaCKZ%QBu+<-7(3}uH+r7{XiY>X?@bE@D<_{s1PHz0-4fw?~ z^&d+IXNBmmKgW9l)8FU)KkDjS}Lg3F}`x-K9W|CU-tTnT^_@-oht(#VVB3aZ1u`+&Jgg# z4{*XR&WM2oxcL5Fk@|}%^cRxz-?>U$wsYvkt^c)k*|Kkc{P6vYCuM!ycYF2pf;^E( z*Gc*KJzZHd2q%9ZZ82B^t&LP`kb2DYm@T>(5KISBg+wne``qB?KfvUIWrmm}MXt)) z*snpy(9pkP*})az9iZ^8sNJU6>4ouVoMn8(;JHNHc%H=nN$h>Bl}>ETombXc)Omle zwwrczRcM+D=Ov739*`kO2cwMpfX=WzU*+fiC$d8_LT59>53_pkZ;)xgxFZ%_C zub~c>w%%Ule&-+%kW|wfbBR6J$iqF17TSvEls-orkwq$ghc!uEiE93Fz zgpxbdo_8Q}q?bR<77X6r@9-E!mTgD+M>&V$^XWW&+-FK+K&&W-Ct*#H|<_XX?zMGRB?$2DWe2Y zV^^L(YYDwLzjC!{ReoumZC?Iu#87J@Ju{%r0i(jum(=cPy2gt0O7B&kScrPkLj^qm zcsycYoUozI|89X{eZka&FA?rn-8Qt@!ICQ2l#8MlttAiTjOx0J%Ns|5nvkLJ2<$2L z6~WNT#O~wI8hR3;USUB0tg}QG4x9CkpIjiO-L%#9g5hw=6uG(f|GRLX=`kcD(QQwU zZj0;b!{+ga(@gRVA=Q4X%nR}M8T-j7(Vbw_cvjdqLw}a>ZMy^)!7x@NR%v6=Fe|cq zeua z@s?&5sef-O^1E_XfZULY5;LQy+vft6_IdINe)z_+sZ!ia1%B?tj~hRA_?dy9V*F@M7jPfn0h1aP_Zl1+0FY?cI{{C5^!+ExAI23hn~!`p=B-_hUTG8r=v|0c67i90y0iE_;ZpPyco70 zoDucT+9Rqrnd(Sxzeu-Q^Sn7XPcK|hSD4JSe~V_&sUKxfW#7=*=+W{uEeUr<3%{!F z+~WpT{uarard2*8>IP#07^I$RY!ard3JNy-%4pf`FcEW7@|4hX;Ft1%4m&e@kzviA zhI~+eWh&MjRJr)AnE~rW&{H-na{Rc-U!Uc-79p%6=rA%=(%e5+u2QOIdFzW5a#8yL zxoA%In|fTjhdcuOo@o@NRyw9Jgw6?*A*-|B1UBjxAssPa*(f!q%W2`?(2~_@>7(jq zc{zjrUJmBHRPXd!r%RJ*FRb!yG%64#h5(v|tDikG0D!LX0eP0=!}qQ(6E9gK#F4^S z0Xb}$OJmw=z;Ssm*|B*m2_O-*6$FhqHvzkMi6M~2H_Q$B8L(b7G$d6s4YN1hzWDyR zpC>bAN7eQq3iYKbXBpWS7_al{c+)W6P5;YyH(ozpE5@5O0!%nPOzp`Z|X~vY-M#^GvHyCm&V<1DG7aej-OOn8}OxaZ93r#|`acJ`{ zxalckQ|NOGQ+8PO=OkEsypm&*N%`+bU7X|R=Ok;UQ%8Zmu*LyUshHsqwav0%4#Xan zVXCQdh@!(=pZQTMl_xfk14V~oomex+2HQ5T!I7sp@}`Bfm4uqJ1rln{FeS|iClu8+ z9Py`7@(w3!+2hUghQ_VjTplwakhdz-uoxqH_|PPECj2YEnVa`qj^7NlV@(qQ0u!@_ z0vb5r1>tHCS4gZiStdO3-tY19#^*7^&MK>uQwH<~ikx)iS}4 zq2x7%p0hCgO>{P%`hQY~A`xM{TP@Yw{Lfbb z#sLfC$7uQ~WFn0v7V{#&8R5uMQKL z7^HC>fvKrUs>#@dx2H?eUBI4;mUyFFO+@Da0$i=zsj?JcqLgOv6bwr_BDxIqOt~yt zbE2Zvt5sV-<>b}5R<)(Hj1{m_DvzGXIJGi`%8f6gABG9j_RX*p!0Yw4QJv)*UY_lG zEYihryBM|;^7cg{ZwdTzt0}k@fCr*D>(~uA>*i2bI=^6RaBJwJqu;e3g`HK6X9sI+ z>|H_%r}CcXhUID@aqKPTq3{9s*etq0ew9W!+38Br4m=AyEO0TvMf-FZUpBKH>l{yO zHN?_VIyx7AgKcXh2f=HIW&EWWj!d(7|-!S=8+yaiqhbS9p6LO~))3)79mW;Peg@}lVq`E#Qqh68)d}n5>Q091it56x zuxa&pDiCrTt_Zn#nQdKf#n2sZNO^IXjmZ0Gs5X_2-Mhd~Qw z38Yla_OhIxWhIses2!Wdbzu~D5Ajh0|2Ll?tYsE`y~Wbd^wQ^&3{W#zDe!#m=Gz_} z9(a&|d63@-|5$B@9$I4P_|d50IN$R&3_dKX&!Le@qXq=i?xt+xBiw;uyTLLTFIT%h z8NE99n0T`3#?HOWVm4r0PM`Z+@|Ein%Yb`i*!IDwbH@?}<@i{C(+lpGpc~sKX${D* zR0G&QN!!^V0Yz@)-4S9XAtnZ6;qS1zz1rdjyUugwiJGu#Uq$#Gs_x_$MYQVP z_JxuA?~RJ7_6)Tw@B0u8%7J^*`E^3WJ+3`Xet*w!f0HTjb`k`Z5~Nz6-95eB%Tig% zF_yV(*2LI$0hi?g52L&+-Q-ccZ|fF6o8x5}H><-_grDSnhtOutd!2DV`>NYZ-H{Jh z!p+hh_rUqe8(N(IN5pq)U?+{3sD{136htvJ(O%=`D*;(IgRFw%JWy!`cHN2RM*9m) z(DE^RR?v9voDVoPJ{d`QEI!JAw*v<#`AN?M84 zxnoHHq!=-qMcSuW);N}UqRyJN|sZo!JyvPmtabRM{)3rLT`JQNb` z+20i#n|GyWVqPhD>cwJGnYF@Q$R(OPOk zokz=hx)}I&z}741;@eRRLg48rG01Z!;8R>}?Yz-qIPaCQ#VAIojH`@6LyFeec%^cj z5{qg9Qy#wUB;U9!@+*yjN(%Wcewf;r?K4NgocydrE)#9#q{JBclIKttVK;(WOa7swS_jHqFc?DpXcXI#nw-J zp3Y?#Oy`GaO23GAEcgm=#J*FsW%6;5I-tw;U>Jr1A7S0Cv$_k2YkU>=X{*aB(|r|s}R|2$(qV`Wf^ zg=XiO74(9F_QQ0_Nv3@P$!a)fH<`Fm>_1V280qB>QYbbnM&?iR_FKd0qtg2`xVKa( zE$xn5J^B&pt~6@~OyXsvr%^{INolm57;c}WlHA|VN6KW?KRKggv;4qJBO>#}=xWFk zf#^jHFZ{tUz5_0b2W({8u5nQ?JvXbizl=y`$|v<4+B0HH9z;9C(@gdvMJ60Swp}Am zMw*-ggly06=(4A2%JyTtBmWUfe6zGfNwc6B_&GDv{xr>RriF=UnkN}EJKk9`%ij~( zlLaO*vF8c8e1Nz8<18i$eUhYEFX6UGJk7IPm1j9?QM6p)Ldj-N2VHwAQgfMr#2qxF zu1gAt}fhifEN-!&N6hq8p%#+%(FQicuuCf8RB( zdz6Qv;IT}cP+AUON~Tc0vawvtgTw>i2G*1Npt~*c5-X0N4glM6N{}0Zi7jVnO*=MYkZ?erfg*+%H$-O8RyO` z2yNcYDU*rM_j#gMaM%6BKC3sm=X2`nHL)nRnXg+7hz#(bLN@0b`_gXl7_s!67B`q# zrMsM%f~M4K_gZGbVUC=UjX5I~y6xW%dvBtgaeh`8VCgQF>0~bt4c5DB?oh37DA*+8 zNpW2xd?HO*9xZj88kYa))Qyv{vdWA!%!BaW5gvInW0=Q=qkv0kkD;&3lQb(+2$U%p z7sruyqgDnO6Ao&OL1 zm$8O(Zy4+0QQCEFtUtOu))i!|;rQdF)=d!)7;TmivvxnIgCI5*gwzhkG(8n|D}3 zUvo76U_tgtMpcT$Kj9mK#2CXj6qWI9%ZZGK{41^?G($}}a2$Sq;>rk+9RS5(cJ2?N_*7M$Kv2C5Wtg@r7XNK`Z^FJCC^e8cw3bBB~+0pz!G zYWIWGyJpt&?4|vwo=53D64NdsaN_yRrFIeu9I%m6`*{a}E~=1(z932Ul|D41;J`FdAWN8w@(4x%+|1R^1QV4nv@}REXuJs2wR? zb1jw3YIC;{9n{29v(#40$TG_dnwl4w^LxI}fVKPifB!s~nfH00_xZfo zCXA@y@*eML{{eRdObhSF5U^bU_vD?*Ihg|33X6q2#)xZwUe>PuKgtrlyh{_bmeONQ z3DM^CVJ6i=%8BJu9gk z*^=@*J=>-HmS?-cc>VuVRKtH2wM==Qs57VMmju`m+9Jldq=9; zviqlwuZzOn%3G@jZ^tL80oq!+%{RIu3n_`yjv~UvAHMqT2VS+0D}iEDy_)2ov^j(0 zx2vbAFl8_mG%-hA+{|nwX-aPwRi4Z559iR_@0jTa>om*m+t-t0tfz2#jTi%A&V#YX zb6`EYc{6yWJkyQ}8E>0Ef~X6`0P|TVE8uEtaqJhU>#da^J7DTWU= zhnwGEyjIPy+vX2o;b|IAvsqq7u2&g%*WM?mJ;$~0{O{|QUmRE=Ep~xMk#FG#7JsK< zWTCoRsKRzwD@#^3q?+PmyM#&SOq>=XIPr1gU(hr0m>3uE-xoA4kt`ax0OMl`3$Fub z{C}p&SJL2~#cOSIYQb?TF20pDr?&X|O~J&_zpyDyI zb^%+QhL#~#(fYVy%#fgp9>A6X1joz;5Yb2L+F9$^GU(A3f82BVb2-V8Ie;Gc60w;BEFEK| zKq7tpRXiD<8DPpZSO(;~3}^cL?uBjAEUOtHTx(U@5t>3YA4S?>_&Tbg$CQi_%LJw! z>wLer9YNUD`$A?kkt3Qb83|ooYQz7i1Kq9$RL z+0%bWS648Thr=O?1{J@xkv1zP54FX$-FYg~HOc54!;Yw&0h+Poy9HM|27`r#p54zx zg{MV4{{uVnA>ex@PDrag)`styCb2m zzURx8P$+?fp6#hq-Ez)^LGV8Lk9@8p1%pCLR2AwHO@(&u+jmV#V4`vr93JjbLv9%A zwF%jYc@#ZOEOv)Yi5*;aB9o=d=bE?kn(@y^SrfClnTRqaj&IVK64DcACgdj;UuF9Q zR%^y5GT}d9<`4n|1iDKm53g(VGtgF%SX@F1{k4YU z1e7S(9xEUJ(718!S`t$SYQc5WsLyJNn5bD~VfJ45cu(pOBtrzKMKC2aLn9`t-LvV) zF_sxHMiScv6YgxLAkSchM(V=i=`z~sw!}w41K$-D+r>O37@f6HVmhA!lT!`bW4pjQ zm=7O4>cUiG2`43}i$h^oygHkEm_@Qqi-8+T-z}0d-6Y!`+huV_#>3)f0|1o4ou>R| zd)d2GSj^T4bJ%vrg?&z{FB zfo)C6PKS!%oO8qtdq%s%@JiRleVcq4cR$RGXa^OPjLfweuR&iDzggF8Mp&aVyiJS{ zy1?Zy*@*ig{*|R2s|U>)UXt)o{19t$p(|^=2F9w`ny&2i zAK!G5Ps~)h%+~at@z3ilDT5;NqGAdpi8NyJAaV8}DP>UcQ7metnKAx(jTLAO)_m@G z_)~DC=jP`YCt}bsCK<8NEeE_l+7h1Bg-^<>;YlUbAN&fTJU!1CHCIR zdsP&x7WY&mG>BCiNu|c1*hHgW#ko}~$os0IVACfOS6O)mciQwgIDF*Ql@A$x9;2q> ziiwvvYQc3kHx7g{2n2}3Nz-uEP|@~8P<)hB8n3?C)byx|c;Y_0u5l0NhI-tOa_-@p z`EK{4c-Ai30jt1TLl1}QTa@YpqOnP-UMzz!TU3iuKO#}NSVo0^$e@MSm7-#+{d;l5 zN;CZ@>x;==KbE+MQ+GRcKT2VBpcE{QN7aU56dgf%$SrJUSwpj~h#BO2zoes3#YVG@ zxkj7qjFmrhChq$&?#O_^i5*Chg=dPdT@n5&yM}AL@x-<$h~7Nxay_bX4Og*W6}TLW z-d5Uw0qzboE~WjTtNdd4V6Fwjhd8vIwP8728)D?@W?ZohC(>~08qNvJnfNFPwVCc5RfylM4SHo)ieD z*n;?+#-|G(F2Adz62!;*W{#?d?G)P#wd?J%J$1Jv~I~AO|!qidx&ue zmt;DQh0~HaPlnrkPPV8gv5JJF^1e8F7YpiWxyX%< z?XrI;^9lL6JZGDdBJBy=l52t9gdkx;Fjpb~qD*@5i&hmvPRbWhr zoMMwN%d(G+O)T3x7?WMwv3T=B!6yoA($rTU;|KFoihd{aBhjj8+TzU6ImOW6Mq>04 zVMlD)dwj84NwZ&MHQVM~hgp{JP z?DpA2ztpmj);1#z9Q4pSxunDXowAIH>r=`RGE?i(4|4MvJJPtk;h^!r{n}WOAK@*? zz`fsNyi3H2Jk7>S4CnwQofbG4q9<8I4Ho4w*{>rl5VjgTa81X_XyGFn*BfcwSo*Kt zR(XcRhyl`ye;cV=csD&Dw;^>>43<-ZXv64)YgFe#xQC?O}ki4b@jMJ zXL=GEcms5QfpQTN5s(nV;q*_~`qz?D((lTo<8Ldrv5RhmvA`rv1{QnqSWV$QMk$%1CIJ@d z#mQEcO$^qp5mx*t*IZ>SS*$BMA8tzbRis+)neT4&1m`bWqAT?Ts!}d><;8iUh|OuQ z%&VO`25IRxa<&g8BPbfD@@d9E;>mtOjcl&LkS(F!-XV)}$0#ZCjHVetK1wYRKhH{A z8S|8}MZMU`PpMpz5=dX^ORG&A5hqm1W-oF-Mcuu*LziTsJxsr3kHVg?`S+`P!OG`K z%>31%1|obA7RA_x_#k%&iYPclG^Ou`bv6>6l4gt(ej}TIgQB0O_w^Rd`U90Nu-g*l`8SgECM2)rwB!uMeXMkJeG3tJt42cG1?3IsXF=2bWorth#q z#egq#M!vHR$k^X1>zwWLRcso#40Tj#v=efT1-u`ZDJ-Qyr5Z~BaKt#GR0Abln+UF# zI=hq|TV5lLje2mSTi%=$SgUVZpf2;X+4HAO_Aj7S zJ{IS?8P=CoE`!j&}-X_(N^otB^-o9)hqwY+jEsanM!0V*(L&bV4|8*2O6YD$kYO8}`1|cLL<*LG&Oj z%L8P53Nr~g%5aFtc?4QT9QCk4+x2}n!@yywD>roA#83yC6CZQ^;V)er*5{u zc)7VA(Z8jOdZP)hY#Hja-<1CJ%_9J`p$|w}{0w?BjJ}H*8hC7!U=41}k`e|o+(uua zC+KdUJz^Z!KAs?k!)c=l_T%7P%35G_=(BRvh6KJ)ZDczwx`6g)BWXIR?DJjZBF$zk zm3TsThda(7e@Ub3Qw@G+2DK_yUPYt3y%4|ig8PKt!JuujaJ#3fO?GV{QSYq5*%&ph zsj8-}q#znnU^u7g&N zN`yc6nA2DFg2WeCi~^SSu%R)XG`KGSCTh21c>~+|7mKWVw+B!>W>N7wKWJW&^WKnQ z!$wDTk_uY&_X_~@zl8D_JM)5Y$x8g1^wyQUaq5`y7Ru{M;X+963tpN2{oky{f%Q9O zVtgMM0PL0n%9YW&_(9J2LCu`d(_;?zNG;dt#TiJ6En632E9XX!`39nYqTlsK6O7li zo_yP}GwSM2oDw!HJc|x$Fp))UA)_~cQZ|(>B;i{e_xbb@;!g9;OP%r{UCz2yb8pYO zr+OCWH?@$!B0acUOY(8my@ZWhinZ;-r!lg|(`j^^a9gI;tmW8HSv?(BK*j|kZ2J{m z#3J)l3|Hn8B}6>VB6{0EFxsg-BKNDM&L59-L1g)XyCbzmx-)(E>8%h*gxam!g;Rl(_x*%IPG~u7P%sM-i za06W4Nm(km>w0FtoLHevreA%ISEpfnAepQGOcwqn(^D*_{u5S~GM{x9?_dphR@Uen ztetL78b|}I9Z>kRyJfh}8)%uqf$I38(zwX(AlotSN;&jlStNo7;+|N~0w}i%fXAbuBs$BX;c+!1s zqAlZcc+w5*ugdJmo{Xb|WR7H~Q;&W;-EtebsuE;g*Az9u4IWC=uNy0B-IGbjdMy5J zV|rQwkGDJ)5@ImuoRm%1v-E%t=j0NO|8e}=ze%TMXXQd?F17_+u%DxB=HjS7SC^v^7%j^gsGBO^&GAu;c_+6b*?(R2?>Rew>Y ze_)SRYTpS3)2WO!2}uD5pTWQ>OFTn|xZd6&_uMj_|{| z7BzvVN{Gwm5>I@3)xPlmW3GO41;qEnY>qssM#f3O!8&af>q1{N`; zz?s@6xUdLx1>VzFF424bl3Um~gMYfP*dBP$7=R$&Or%IVrfCfX-&vhdm^Gv72N^Gc zAF!9x@v<<_K4KxiF}`VV%*G*&&)b`(!n5e#mY+qu=j@k01+Aow0JjfN!PAw#3o3qlg z;x=SO^YI%>aoep2xfxDuak-ca{O}?(GAXq@Mz6V0Jx+OOIhY_+c1;&n|#aX!OlaG2`ej_7F*Ob$WpFL3BTK{qtOkz zn2l2jH+CzD>(@_Lxu3in)6`+y+B$aY`*Hu+wDynm9i^UTQ@k-HHL`(V&c+izD!)0p zVX?ZxSy`nnU9{CZV)Fi|e6^*+XtS$JbGKS%Plgg=ACBk|#|hElCN78HICO1e zXZ5>z^p)NwuVPK!MZ&b1MYQlaF`HTna`<@dCD~(nM*u=K=LBBRrrz{VD;;iRPw*ks z%H3;zN*;P2NbFhf2lmHYf1bud0Q6q%mp`8cf9r#9q~_Zml3-hw&)?-W-B0GNn;WId zjE?Q9++g&r4760-FV1^F@w-=bvWLXm7Ek5}yGPtlO4dD8ugcURoj*{0ljj;=$ZA}r zZ<>3*Sn)t?*Nhast*}s`hegxv@zcd{-($=xZt1ZY^NSrlNGd8xIp!dI z>zm<8o3Df?$peT?ZiFZC(LiNjrOzB42PEZ7Vd5OWBaJ;Fy>-e;EdMH?W zs6!v@wgrQwZ5_i`HFG5oh^hAz9z9(F#qB~qz!@JfQ8cZ(izG4Ec?6o3r}XVzGC*a` z8Gy=Yziz%Ijd-={EUkU-kJ)8k$o_p{x0X~cwExiqCN=+%@5$Oli2|diL4>y$mv>dRR9AC@rQ_puB)tr27gbKqr>?{p zSE$=HBPKruJG1QWH6`j&$Y0O0Bet+`yY0a^7X2^Ts)o)|;TR*Hg!koaaJY%#$fc_H zWSDG#m?*WDg&?i?54O0^mTLL@1mXRrw7?uT+- zm(0cLngZ80pI)ucfCBq|x&8-0#JYWQ{W%$Yc2|H%8EWB3kEA9h7i63vDWtir#z_49 z@__PE>U|j>1BxIa3w{hw$^hI>gb*cLeMQmsb5$qGE@)3_Y?|P=0Zu!T9M}^?(8#1K zU4c_PXa7<5?$$36rkLG(&dj6Io+qcoNjx3()KX(L$CI6nX<0+k3j00O80EQJeSK^- zA3y5(7dwKnDC3xRF!9`dDFUfmIc*Eip~!b$oPzv(eBL$LGx~_m%#lAebeZC;0xZyt zVc_q)AMZ_O@d(H`*2zsnO?1>mn!(<5bRxf!S&N&T$o4O{ujqK$cU3yOGIOIc%==`1 zEEQO4X1-!&-cRVa`PFWq>JEj;I2d!=HH9N2e0kF62%pCJ)rHSdMqlnvN`nVP+X|m@ z_la8!fupAAytXF3(Wl27hQ zac>LF)%gay~^Uoy&$CFP~UF^tA# znf($U-+nJCt{Bi;OIqDGa*Vs!(?7!}ZaF?8L$lY&X~z*SY8}C~k0E|kypgLnlNIy3 zo1zm9Ct~Pw2B*OPusl!F>4eRn-BPt~IsVS(82I`EHyONS%M6lHw|9O2vR$%ex2ZR- znC$weEWNRD@~aH{pGCkpqq~oxB*@Fz_81Lc6X6}k7{n|3PZn>28Y3`1ZRlTjm9@&= zW+H5r$s)F~U1_gC4*{4G3wvI%=XSH}Y$AQK2-#qXch?5olyH16X3v>C$W-j&M4w=f zzc@)r3cK$n=xs2E0@cp8GPPJ1&6TOnmED8`KmOxWs_){>ncd&r&8f5^3`h{#bwv-^ z1u$09Yc}X(>y`~Qr*@Cx2q$n3ZP~i8F4m=eY;Tu_jMf;u@yEKNe(D0loGqaYn$#UN zC(5hO7`n(?nBjSDbZE5f{HMy`)`kwk)PS}qvD+Nq4MGVnE|OCaLn%@Klna{A+6*+k z_)Aqqjpth{gg1_`;n&6HaOBCv;wZ?Gyp3u4`{>Zes%F1wMTw9fXZdJwVQx^`(+wu` z)cd79gEd#V>lwM3{NL||`JvBA#fqHR^gl$1{azT@w;`?jnU zDBK^;7DVo`=s2TMZMbsTv|?KStkR(Cqro|`?)Gj7SIz&uyM1uo0XfEBtm`tZ2vviw zn0Gv~sjmA+(+_UzY+EgH69`8}WYd#D`rr+WoA4eK+)UC0(d14S=yVpP6W9!qhDvLr zRkieS;G&s*cOIhLH5ryb^H@^)ItpzwPHoPB;A4YWI<>xLj+)y$yd5T+-MgX67wGE!>_4vMnAmkIhuiVlImz08c9^?5b zDxQ$i#;n4?l!0BIxCw>7PAg4&Ybg4<5SsI&L|Cfz*iP}py>4)pajWFc_yE`F;L?NfYE+f&Pb)5J1{DO z%p~zZ7+6`zo?gBUhlad*+k>}@4#<=*bZO?V+b${~%=0BM3vIaMLD2 z_Er({;DdyGZN>9QP@0nP3`6hNai3cLG9i2JC!}^PNFRV6_9299OTeu+j*xxN5OM|; zNzg0yCgYwvh>-UXpV^;~6=!ApQrEURR~5KZPw?YF!XIM(O6E;|$2h+u(eD`OcNkh6 zqgxz&izBwh(I3j#qC+D(poX31cHHZBB)J{K+>X0lj)^Wuj?0nfa(I?}y`=oTSKmvX zqFTFqtz$~$u13xZmsez1Q)I*RjFtc+>0H;dT7W>-fU!_}1&V z=yhE8I>N1v8Lf^7TOA8q9Z$468d@FCv^t(|b-d8(=xB8uY;_!Mb$lv0W=W1mBuBO6 z_><&#N^;amjy;ki)KosYseEG5b{Y5vFYyoaYy6G^zhj!;vB2;6o!^n`cR2ly*?z|y zzoXgjc-ilG&F@(6cWm}M-tarN`yFrl9XtJwfBGFK{f<+9#~Hul8^7bc-*Lh3xaxOY z^EtBbTj`-Q}XIJY~g;h{-Bymdjp5%s5xM6=FR0rLt6>D3&MLpOuAY<#kKt zmhvHDxk)Nd6P}m1`DObGdEL{9%#g|_w3f$<<@au@mvLS2mK$5kM^-IGU~J9*%Kq}f z@EPDQhm4?dKjGFr8r7!Jd?iDE-CiN{C75kX%u0R`uWg)LTbjDEbn!}W?ksO^wKsQ$ zn7dHSEf8}Th`G69?(91|1Dh}Px`nw=gh%D_QTKpiZ=4S6^B@9%SFs~mRedG4Yh91r z1OqF&o&L1=neMi*p*_mm)?@f7I!#hlcY?_6U;X@m)i3aYm5u%>dT~k|BQ8w7XE*`F zX>ax=d_qacL%F~GI7_JgP~K6;)$fZWPDA3hy;F1rb^b~>6`q=D=nc+-B)eEBW;tE=)UoJjmwp5rnGc|SU7DD0o6 z&+)>uZ-H7W&`1S~-3x|xE`T-b8}=gwOF9?arSJ@XU}qv1_%l~PxB|)*a9n{Z!eqz6 zhpc6%W!J|>eq+@snP1XWu-Lm`=%M8+{RNss#kH;lLpHq1Y0ZRxvms~4vy^`_hn=C$ zPPv6&6liILwTZ4xjV=8MsCs|9cVtd1EZ4O1i?+5lcD>)&8bi;%KSJbZ!HC(Hawos& zbZ2AN#m3J5R13EOv6?S_83#dxA;Jgp>8^!ca${#(;815Rkpov246Z)_#ue(+{9ESu zMTAr8B#i*?sPnq*US3sq0y^M@mB5KYU;7~X|0rjI!Gux2h^UOXHs1BYw{P{8Q;E?nx`pBnPSjBBx z`)-*ZjEtaGSoRJPkw!fH$0Jbiu7WQU6p~~E{g2Es;>@xOA_YpnayBg6syl_OO)}sjOgnj1kieMwS?0DoVE`X+QVQ*ma0b&D0cnzX* z5P@yS_?XboEY{aS3{$=hZqEdf!$MKplpc*FiMHySWa&EZ?puw^z{>YE>fKT5Ch#dQ z%RZ0ZJy}hMvZA4x0QxZuhXFw2#v2;ZVMFqkRm zrJN7QstC5hTM4>2PrOhxi7y1p;4iVcsS1*(2g3cW~Xz0qwVBVlPH(Z5FlKwMUj6+_()6~1+M=Ii_l8`4ko`K!KD58+MA^Bjn>Eq)%SYu*^|Ardp27pV z=(xWuTMphjJ7#tP$sfSaIc{_n62lwnuO7aIW~_;AY~0?ozZ>6pS{55zriZB`1eY`S zh>K$@E4SMe8c#*+X%CYLMeICAmj@jS?qo8HU%ssyU- zoYYoIkFr!H1E8u@*ZCloLMc<8;PVb&?FJ@|f~<3bcaZWqbZ=nWb8OBw&LMp>{`#C1 z-!bj9Wpf&rvFTXOmdfHehm>VG%i#_|4r<99X-_FXXdZQi;3vYpj=26tC}xq6#RK@q zEtAz{+->9nr$zJx=$pz!dH#x+%bVmYo)(A^Al&9z*SdvGOG}z>>n2uJi^sQS1b&-5 z{$+dd>-W@lPSzmM>3Is@t~B4F2U$9o#}^?--l$>sKM-Ibvui2*!~6In+?7do*op3u zVJ#YIrE(v>#qt{E+s~4+^%PCLe~S`Mu<3A%FGa@K?S5&&HI_wusW6w-Be`EPm%oPq zC%%M>BLcjNbH4=A16P*_NW~|>3sb@!RuCbozh)FhWI92VPzg&}X%=^Vbr&ncy<8KN z>xxL-zva+183Gd9uF6&KvKG)kU283^=h^;k8u0~W23cV47d52;1l%KP0E<~*ZVlW` z@rlZEm7G3wB_@hQ@lgZ^PD7Kqn|0SRo5^6`WtVaJC2ckALbHHpwbC+KRrTL1i})Og5Nh4e;l}BShpQy>nr}5a(#~YSbqzBzRXJ)+RNuHGizKcfy)(9= z{-#{CTeh37HC$nZrL4s<%L20_4HZ*XL+~FF;%uc6_Alk4VZCWn*8)voY3KB&ONn3rZX0u$i>3-NAFVkN$#B1@YHEl)V`z%eXXGJU1YM>H^cx_x`F4LIsy-#5& z3P2u@NF#X~{?8~qgZLItBfhHJ$O)~l3qEIS(`5GeZ(2efIqjb zh?hj4WGA+KyJQCw1>cpdSYs*T5D>*0U5#<{z!8nHCLsq15RGOiQL|SeT%B!x z^Z!s?LB+o%>k?U8PDg|I!f7c;5uU0{DcQ*Qdot^Yb@&wERdG@y8|h zCJps!RM(RY#9+gfenVP9&CH*`*^bin<0s@%Fh5zeAByK|<6d0Wq~UxIv3Z10;=^l8 zivx!qMC>1*K%)bVDgL=Wn=Nsx?<(xpY+XyAhUuD=)61xdzPRk^+$^8kC{o`t`m{Ke z(M-g-3=RofiU(T-?nM(6s zz(Dje&18AFT=iEOykvebkhf*)fVrVa_lVj)C{c@RGSun|bGH^j9^7 zj|%i-eBX0so=kTJUe+it`?Ch6)>KCJwK$j;1=gThj*k{NUT7b<`cc9|i4lfe9X8SP1N}#6thOeHDo;Rho7wuAD zX4!`YMXsBOmr`p=BO7;4jd?j-wu=r1cFBvRlrO(Sa}XkU}^=%1s&**Of(`sXNnea>@yJ1Zu&zON7U zW=IyY)9i5MG~?WdAy7vTv4gw%EZ&rT{-Y~xJ)~$5c6rwKAx6rIfpqg=foG%Q6<_Mb zC2^(iUkeA~?;OzDpYh4P(}gpA=c92;Y{?^*z&q^)_BW**E{*J+*@vsgBf@Q}hx7moRMg|U zrD7EnP7shPlw+sj*%dj;a91$s=N;uMjG)+$u~Bx9@);w8t~^SkYI=d~V{DXLM%5T2 zN7iFCD}Y$B=Cl9_W`T+p*Y3e(`)(lY^3+1;&Y{8D2r_&TcP>JV_8TYcUUS2-7r#Z)0&Y=}#<1S~n|w z7@v@y2_tPed~D>M8yYaN}-T3j?w zu1KBNus@Z~VUJqeLCbq9=%9yxuHYkj@aGCXrXT)X!6CYrJ=DizK>I3aW)&QE$@G3! z=;E9u4f}KGG!}-+pr_Wz+QILkE0uOQS$xf8c}@P>hW+`}!5)7hd(qqGWlGu!?B%+N z^1J=sYuMk9TG^u(B08k;2gn0ppJbhb{_I620|MgSO*=c0P6(ZW(!)38U6A)4er1;S zM03%etC@VsdOqP{aB;7e44hdoC22}V=sUTs!*t}JvGb#=-`@Qx|LkQ5XG2W1@P9TA zz-6K!CW5)XKHz53&5RSxFn>S&z;pavO|!Ji3pC%byjMOhK=zo6-`?HM->;;29B$(x zg|gTm_$LpakZ;(PSGA$9*sBAl*qie|ABI?8M7d9JFvQyvUgaX+ik!1g=Zn2;ME`J) z4T^Cili4#|X$IYK^B>Gkm7F{xDwY0s!M^}k#2u)5^CI+HJG@lU&UU^}dk?)*kBc6m&prD~u^uFG=G&BNLVHSmw zIAAcIc&=^F{gqn5-mK^x7M@C6vf5w6N~IBW9ef1%K`@+nRi$Nhc~&F@0oGvD46^O-r83#|o`7{WojGSHrGv{-@M`{`uLV1L0Ni z8Z;iF!v?>)NMdxrLElUg{wABJ$H})RPkDDkFv$ zRMVi$#*3Q4vX&>F#6ejOqtRl7#W2kvMsTL5K0-~nZibG@Oyl}<_Smaq0@Ewd27&jg zqe>da(7;_Nx(W_2ik6g}g9-ZmHHu$W?GBG7bcp$f?s&_22v&4*cs$kGUnk{9N%>lL3GdC1 z_U8BV=Ep5rykr^hbnue5M&J?3#|;|;!o#K$zn<4RZ!^66@yJ6RI7sn)GWY_{vLEFT zBoH_}rSSK-*Pn)pHu#3gk%SsNc=0epDdH#Q$DXgXNJNb9&nGyihBbfglW!OqO^ERB z-+;vMFSuKXcO9t#a(Gha-)nNjHaU3zbe(^C)RKgG$*$@Br0M;|=>wELLg<2@k>nh4 z4`ZxB)x<@oaZ+Bal*d3w7i7)iZAD?3H%O`3ByF8dGD>r@J&u0fR4Xnh;v8#iSK4$M z+vQKSR{zM{WtjBXG#EQGH19dFJXR#so=uQLsdz+h69eV0h6cb)17}R*p9-Q!U&>Sw(-lrdKohfoL{gv!fjNXk4U>B$9gP5KAkQ<|IfCu0 zKp>XTd`ON=H5_DWJ{_hxF{}?G?^^?Ougn?wsM1*Hv0-!%V4+SI#0nGtA4;or=kJuj zt@`|6ucgS@&lrw+JB5F#yXh~O};}x-Iop`ky=cTcSYnD8 zIAA-2Mex5$JIhp8%G6A(^%ST1QrBzv@-utu*Ha|CK!9>ZSiy?PcYp9#V^7vc+jCN7CbX(@J;*BHLZhAVIu=$ z^}-KwQ*1{Kz@Pz&Gwx{}jen?Rsz!G9J}qf_T1H{pv;*2$X4i_wuu>3!p$?|Ay6uFV z^kU0z2vxIqX0Bs(H*9rG`w*NPYGwrpp8}UrnB1A{u@_ocVm}<8^tmVL@2t%0d3b>U z&_JBHdt`I%QcEGBmsqsmTk34;&ikIhKVe&#ng8h!xeuX9kgNc`?SQ8MNKmfEQF?e| zxUGykk{Q42;H5)HfCq?KB6ZWzH>*RdLMg9p9$-N%DPF3Diwr7VYn=iTHMsm zUSi#Z-eSw;XPs*E_ZOuN1n4Zd!S*LXy2;)HaRvzeVJ=BO20y{~-EWS@Y&y5fho1Dl>!?%=V~sp7%eXxS!KzKQa$^6Dz-n~H<{KrjpD9i*=+^+v{CFK zZRSbgJF2XIV_Qp@5H`PhQP&0%kmWVd`i#+SeW%K7c3w780&anFJVl6vo%_zW?Q1?f z;}WLuNT$!e@}jB39C#U2VO&4bJ2>7_veVENr7KuG>kznWZ%^2ENp1?>WrQ%V}&J zu(R%CzZg&{Bfg|S%t$!&VDMoPK#CUqJith%EP#3l=j!OB-kdp+UrS(~f>v7Dr|c6|c9Yk)|xqYyI`-9h`Y z)(dN88pQ&-4v8PX_w?xVFxciQ$UasYTXsP%Ej7;TaPH`?=SWq?MS#a89d&Pa-#O_B z&Vg%k9+*OCvniR7Lqx%c!C8N&2O6LqP=7ZZib0L^qLWqjq)gAVfcdpnT?Z7wLE9=A zCl!pxbwg>BM@)2XmK)lH?lA3S330X@=mqPK#~5mf^NMWA;9-M<$>jHAofo%+VV9@s z`PPaKJEPXt%&GS;h@ZLBRWM=Zf|&&~XU%Mo79=nopbl4oMc2VEL`_CE0A!~9A$7kM z*Dt`F#@Y_e#%?iVLcj9kN0)&&s;_iow8Qr0D z>yJIw-N(L8a9-%?I06a#byt;T@+N!Ni{wZ4&moLg7d|<6;2t2}uK7LDam?BUMy;5{ zgeq@0#5)(>wg4shn%M+;9S!r-ehmJK3nsuQ5F{r)Jb{zGOU=$|YP=4MJt@eEDTLU*w%daR)yb2jr5Dvbh(rXL$`%!_SyGQDg1aOz8dvj7*#TW>o3l zg+KL}|I{PB`aHdui`;-fdJbnE`kV?pH4Ps<?@{aBrvAKU+JJ}}y)_Qf;VV0Ni#35C0?#-mn!R9xcxz1h ztn30yl9<^qtMF*Y{Zgz707wdiTM8`RSank@a7z7Dc-K>V3q~re`i0G(X4Sqn*=kst zosd`ER#Ax)f;W+_XP=B2s*$K7_z(08rksmH|Va4Ca`6=rlYZ0ZP|nMzzW)mFLt78gI0#!2!(;G)MwR~U zoDNtc(YkgFi1;Ycej)EYJ*;lMto>h^=$`QSG@6yNcCqXVb{DTd5*R3>rN_)dptWIH3g5kAI>CV8^Zn3@E>#Qg-?2nDaL)~^k6TEFH_xqTPAS%E|yQkJuwfz zIk8*#mq8Q;e+uEFo?9a_d5Pd(-3utnG+kDf)F5p;RPd}A_#qKMfp_Ve)^+L>;Y{{fRL!4hGT^?`&F`b#Z zE5Gu6-`RCBh%#UV_GPIP(X$IhcD%=Glz9haD^JZ~v;tW;06VymL%9=tf1x z^M!?a7alEemJMV??<4F_K>%Tt0Z2D;#wQ*-ohi+op{(H9?*V{y@skFH4IbO*b)Cf+aRP|DY#X*ETKNIajGre{8n; zr`f+cND%dlW3J6cN@p8gvDxzudQz3-vt{TjB2nFCSqo7dm0X1b=5u+(c=lFPD8nj^ zA7l8Y3}MTL zG0OJK45F8PD!a6pj-kwqLueGqJCE3j1E5Eq3Gp}JvIq2FKq+&9+wCq3G^&my%}qBm z_3x`kX3aJHQzIr-Txe8>KQeZXxj66>C5&`47}g_B| z0XJc_X za-WLB5n^C##6%}PuArRp?CB25Nz6xYnRaI|19R!S+5Ii!rf7Q&`(;lwAzi9u+g5e5 zEm50nE5YYDJ`LTXEf|w*BUp>(YvAko493eSPt)&TzgJNmC zr7#hsOn$l|2&!KablWVUOSgp+GGFe*ueZm1oG~muXGIGOy3L=mr(?u;^~m`^bu@w+o2nG4;}nEa%wh)>55zY&{o?$PDkHR6GD72Cy)wiyLtJo=yfna zqZ%J=Ke^DYvNjYy!U5!|h&N#{_)&kh8y2Z!wZ_7gE=P7=ENK-qO@gi^2A2Un__r-aBJ z`?DdG=*$jVYYLv?HNWF(KIs-xF8)bpl9toZaaBo;F#8AV3&_GhR!z$KUCB=nMPGV3 z)2mC^_=0uCnj!gBWUXFNhgsDR#mCo?h+o2v7fHt1TSd(#UUX))qktv7y z)Lly4yr?Np6n}j#zb60r0#$Zy`z8i(?BXqjss>ehaLukZis>viRxGv}V?htK&uyg$E}f3gxr=%8#d zq3!w$SNLrU<&3EWb{k0py)uqRg>#B~nDv!0@9E5CP+X8J!_ zp%qqIks|XTQs7FdVU!IakP%<$7z6f<@%(m=9@J7Y^ALTLa0^c(IkcFrGgC?$o45rm z3}z`$;?r;^;O4RL96>K(<$nDl-mhJ|_hO%7`Ds-Y&}h0eWs)Wxz)ps#TqgSls7GJ^ z8ue%~9@exLLG*p*H2_EJefIPYj^w#qN%0t(|KLk2DHPb%#*emn~PgIhdefd||t zxwlzocRfGWXa)1(t+AYM$8x^|`jf$CtHwbKf;EV1)YX2mNW1`6vaWL!$gvI*?T*>j$@lQQ zNHxG;uk@kl8>(lfmt-yW=hyK#1A*n3qWw&jLCqaAo=!i)jB}}P!y!7{%ME|fA`FOk z8t7W1Rd}?d@SU4gz00zHZlSJa*~b$^eYVxNp(~OU7vclwnShx8=x>0+@L2qJJs)|5 z$DyrTUX?ynsrBSPRy)=3UeCs9e;a3NU1N{G4%`zVG9BVBC?h>2&8-#ZKFH?HF2qC6 z{wkzc_Qn=b<&_dAHSTJBQX~<;Aey?_FaP&MS{9aIgAM}3Bja6Tl{QjvQCyRR4VW8U zO;?vex^R}s$d-vKmWwOy5Lf(GTu~~naEdD)2;QlJT&+VCz-bnN`c~3q(OokkD(Bbm z;4B~K#YCNTWu)5*MZ>N^&NzCe>m?=sBa_HK&+q@~OxOEru(;NiK(U|y8EoyGXZfph z_cio&+W9~L`iJ9FxHV9@LZ^((NxnW!xJ~T+S?t`(y%yYw6+{_1E%|!QwdmmXj>Q1n z!ts>=h#dXg5RsdmjR|#8g!-^BkUJ9S0qAhpP~od{mqr3HMG-c{4D~S9FQ~8}P70rZ zM_RceY*l1x@}5Zs5rS7=*wCuTNy&R6^v@^1b_P*mZ?xD6scP_5Eq1PgZ2k{HgC&<} z*rwB!{-McG>8p**_KL=ho9Vnws`tc7AlRc=v6mA&9|@NCtF-jd|21tf_Cgz;GCb9g zW0d1>DIPzbEqHu*n(*KR9XDKH$RyB$|v|^iYPK4ApjhoN* z<1m`CP$x!-t(rLzVAYjc_b!y$X0+X<BQ@N47GVij*$2mkhS^#21IC~_#8KcG>}0q+*bAfa_YmZJ=JR7W z&xQ<~?2;4nkD#+*TR(_&hrvH#B7NV0Gm1Jj!_MelXJn^SyZ`&Zkq^EV1#)iH*`!F` z8qw^Iy3M4AA1+w86OzsAew-rARn!pb1EgWriLU|!;Rgra5A^rn!&RO_y{TnE|94G? zzw-@z&JDc($SDnvlr*1!k$bv>D`!an;e5Z+q#v-f>l{X?Bvwh8%kMj3O-P!5&J}g* zE%QR%ez(@OG?XInT|A+;-D-_^Zs7emcT^^jA7xU+pT&s3z_8CyDi@+lXKo;3D-^{@ zcB{a1@3OwDxpZEb&=&C*LFx0!efL57IOR9f()Yozgxk4^)iIp5zY*xs&~TaP4~VzY zj!=T*RCi;nm>)*NN0$|BSi|^u*49>4bxuA$A%ZU1LRc zVZfmg61k^YwovoopT9&~&GZhNXjw2|4DSM`+!$fCw11NgFvPjBh^^ZmX#R6RoIk%} z@1Sv*F;^U3(x4X<4O@VfeP7vqcdve^X9?613A-2ja83t0%+$I-MHeXByrgY`+PB@_ zwjhLGtJHbIP{$4-LYUmY&(M({(c%+iqAwurpDEgBrW)$Lr&eyJJA>!7q+S8G4%ZcO zQNoBuhtmkJu9`SI&O7`8M{Z=NQQK>b956-=8>6XF6S=<>9JhN}!%Bk<%NWgh>JrYk z?gMNMk|%g!RrS)%bNISDE}NFm;d1uNQ}o`5H5gHqv^RbG{+G;TpTB>fzvI2Zj(j00 zh4S7@U0bzc=j9^Dan(YdO=&e~cPHE}5XIdLqc%Uxnjemi7ky(OUKPH;k);6$61WXF zqg$njHA#t~T}_vm`qEl8h$*XCZGjIe2zT#i2^Kw`%Xu3sKsf4I_z}eUFvBvuEGF!5YToF6RYd!@sr^=X|8HQU< zWt^&|71{ynts&|A1_AVHFrXDVo(r(fXHc=Gy00%#0p!}{*wV@A51z5vG*;OfDL=xU z5F$kK)46Vr;2(0D#$DUw4&z)L!M^Y#o@nd^`cA3Ubw%L8%!3c6pZGbj|ATMlgdbSO zZSF>$#I+eZSET6cnG-IxmT^z8IBL#F(ewDO8EEO7c7K9Uz<^HCFhO@Xv9NqgG`7ifwr1EO^#qnnA;{3X5AMi zu9KxqN_ji`}^v~Q&>|-Gf2=c;2Wa~92b(o{|5kvb74JoEb zUxUHwve5j+9c!aErPOT!UdkM<>mN}Tj(I=hBSWmLaa&VXz!6s%w}Un5KLk3UnSTl% zPvAG*|BaeEunhcua|W`M%+XeJ5_IsTwbAMXokN}JawS9`*%D|`FpqRn>&x8JEJLKu zbg5)5(43Z9UqxRxUyE)0(jt>uUjxIc@k*R3GPA!$#$xv%w*KF-L*udg5LBxt72gxtaoh&qr9(@qog4QyqL%YoK?Geo!U;PMt$xOrM)srZaL~W zS-@{IP+04;PO94(#r_D14&TbIKU@|Z80uv|i0ib%T*wLe&n{TP9!t-8NDgGw!n_j| zGrl>pY|N9~?l?3we`*Ru4Sq{lxf_V=gRUHb+i(+VV+k8q5q*dSYW9E2U{qhe8Z;rHW0#h8gBUL&p8G9}v=0T6U(Ym-p0@gY4v`nKT~iZRbDei4njHKC zGON#T96l|u!2L4g(CIu!CTCrl2!jVl&T19p-O!Nj58!Uz^%M^JtDH23z1Q#rwsf{lljwP(_tqYcj1N)C289Xs^PSqYfKnS{HB%m+vnc!Ze-fCQsFF7^1 zXF81h(p~RvHM)8XB3z_NS-HD(| z!+9AqMc7i~RjV2&?AiKg>)=T?1WxVtKef5+Jr8#nBdKqfGG2~*q4W(l6Rpdrb={rV zv&dtNO!`C=jhf5~@C)9`;LKeZlg44hq~CZH0%a2m7kPf@@EsnKS{*$j$meSn9|iRATpoI9io+PW=c#a)z?Hh? zy4)ylk0Cc7Xra?3*u zi~S68b9rd;3$(r=P-YBu7wtabLH@B}MSGwhjY%xrQ@2Q#TLTP@IEc4F`@`{gm}HEs zdxmsB5LEHLo#khc49L)HMD-#`63G~jby zDZIF~teH2H`rib+J#nT&f0qBTj9G28ercf186~MPSE8l2Yl?n66Q7cv#*iI%yp1|i zV|1G_s>u6o_im;=fp)?ViYFO7IWDbIlXktPGD?L`VHwWdjQQb=ax4MZIYEqM?#d4)_+uF(obnB?6&3XtSK=_7^GM{nqA)47E;66sKia6S5p#!zLGh zMBQx!rzgyXq(M{XSx-%|PRpQ9g>D5W`NK^s9D4Q*QsW!`eYHY|oT}CtOInNAQ@#=_zseHS${~e@9Z=|LsQa+W=3%*>X9JRE=4I#6`|SEZOWYAP!4DK~lRfwfAbalIZ1y9U4xlwVcV;|b zeerP6O~&b9(7yJk^59C*y%L(I>ljU;(#-OIt^##G%9o?s*i3D z^H>rsijgVH6rCT$T_DsSw<*oP&jYVir|xf={#e3HRTk<(yO-e73%2t2a| zpR}h8zS-t-#(7hn)ET>TREV@1r#_JX@-mNclIz_OfGqj3#*MKqV_f@`K~x#{@lIz_ zJx9(mXwG#)>Z6bLprPB)C+`ISkbm;^JV?Af&M97t7CE|0vaIiBh#zP$m0oxYv*k=} z+xz`Rx5o&Y*`Xayef?tM{!S;zJ5!aFXXvWQp=k*QhjF4N-H=nkbsCMmMsdKHFl%(7Dr39XpEmDP~((R+dYyk zk=t5_;X{etsgOJDUXv;bycOFIvH?7vYDUhf~+A=|SgWJ#@DR>H#$UqbIc;3(QvO zFZ!fc?562|xWt|4L=)MPy5&?+?GbCLa?kI146E+#!-XG=xhzS=ylY*eZi(F7nO=6u z-ZRGWY_dVlBEEdHu+oDe`@?GLdB=BOSDs8UIWXV@JqlNc&@phvxiCfV=pLV`(|@IZ-Vs4uzP{2Weh^r*I%uvkfXl5hNyLQviBIMXfKaWJ z7ghRexlQQu}sYFn3B_m;AIWDHBtxN*$-L5S5km3y4^ z=l&bMDtu(D$i7g7b>S#f zE5iy_YL-4i6^X>7;mXTDs?^ck$)q(cTMFlE}gg-3HNkur@2fQT#oax7yQh_c;cX|IRsvY zMmE(ph%mul81n?x!A{%N+R?&e>F454_jZ0n!%|Ls{-v%UhMO@c2$ZyRE=;ldFYCUH zWBWp!)%SFei*))1Hu(+>;(v34^_7>JPX^#s(6yB?!0RNH)I{dNw>rE76!~?34FhKO zs$`lwgS54#uEJhtC9R(Yq!8k1BD%Ljy{~Lf;r3q|tlXXqT#bzrnGWk!P;L zVuR;@*^dId)nw1ML?m4^_v5#LF?$r>y;% zP0i`R9MZ6t-#v@}rD@d;3kzDORf`K#{zH3>vz}DhDCxx-xB4#@%{`fZYCP*&mUZ_J z(9j$*)}uvClZJ5r#kwPRALd1Ia)NCOwHHV$_ z?PzM+;q#^}X#13Fd-su-v@cFja!Em@4U(R8K{RsWicoGJOON-uFok546+I#=+q7{)?OtougTmu6Jw;G~LaKjaLe_*~bCmU|kkMA-GJ#Cpri(tN4{e%KR$p)Qt_{cufTTvHD|+!P9$CRBLEl_BS}}mX!>)f zjC)6W=MwJgEPR4qPG61jqXN(00xPqeKV9Try&z666T%vY?fV0B2)FZ5q~l(?(EGbG zar)}UPS}4Vb{mWB{oQJ0z@{u4C;qxi&=!Oy82?*n&vm&kp1IW?aY~ZkrCg~u9vI^e zvI5us>^#d@OOB*xuOgH@TeokF+ca8BB1{_P;KUXWlf%p_mkV=qDIs_8!pee=HUot7 z>x+QQaj~g_Rp-J~ft}DV9Z?XKT+qVwct(P4*~|o+)kmC{0v?~fW;EdKLVM1d^k6b);v>i>@WxtV_1jY)Z3b_H%)p2BiRG8vFNwob}3Uyg?hLSCG@G=BOBb zh^{K7Jai)o070zgXz@4%y@Q>u$y9m>TEp?gZ94~wNX1##Mjy~#wc~ZX`cFxW#*XD! z%NV1sXk3~C0k)|R!L}6~dYVAs=B$8dNVb8W$jpL+p8|;rjvSUgsacTW5~Dr7YEVrs zS9G_W)a*G~tLn}VNs3c>#b|(8cwNyBnM{&hxtd6hwZQV~kUkxkLCfU$(IcZC>9c}@ z=+e??m(=Hwj!QCy&9+jKJ`bi+5PQ%aF6#%sgkp(_oPbFToMFs0BuAT! zV_#V{v@T+-r}vZaP~*j~tmc{akI(Qw1gLptqbpe>55rw|rV088M~&useNMke1COPH z>5lv_{@o|*e*zBn!%P97|8zRTiDbq~3=g&rZavJ=C{Wa|wN8FWI510?&{j05j`Ax3)@~^No!40gG-$2(!pL_j`{hL5~#*mF@5M1gCcO>*W z&;0epd-+lV&5h_)u24@x?@+a2PbIBg8|@7vZN9!2w{i>mm?bwH0e3(Ze;QC&Ndj-U zd2{kzu^Y>ysc_tW`9`;fPrq{aa5OZfD-5fZUEcz4!W$+# zYMixN-!|^emEGd$sL8QkpV4G9EQC+WSb0^3tF7a zR&msRR(6@L{{h;yDTS2Qh~kvAv|U*hm7ZAhirLb6L*RTGXOZQ8e&vB~l! zPA1i>7Qev6?B|~P2Ns_0Rs}r4g%iowH*Yhy;JaSm!=QUMaDQXsuLsup*S=P|!U$Ic z3Z76~X=%ICJ)K7Mf1;UovPWK3@lLYQ-4oJK*nH1hwWcZ0sG`j3cV3cjcfNC-`ob>Y z$S&&dTyP@3=aZHlzeeT+svpLdVSvkJ$}WT_0>PG549Y(YXwVP{ysu179}5BsVC zOt67#X4Rp-hw};_xTF7$*9vYk-kvSVRj8BA)~;MRX`3E*_)k49<%xK)w0h;nKdXkG zHhAZqKtAt?C*!|U{&~-T=+mJ5aa#x#!o-z*0Bm%vHt_BOG9j}SlHHu#1&B;-*Y%gn{56dv(S++ zNt`}q~fJNq*b`zcaP{GQWS@(w8r`>2ZSFyfZTUGFMOyjni_rCR*t8fSO ztgWgz8<0e+Rh-%QQhUOUZRRRaU~OxwgzI`fs-66BK^d?6SmlFzV3A#XXnD0}uMELm z?J>Jl8}x6z_>;>1IkVLRoo-f^15E$k#j&M@`KoGIMRNLk3{BDf+q8SRj)f#`hvr6$ zAWKQdUb$idA-?0C!HV?pzo(Sm8fl?_3zov{iyCr1maW zikgFIEw-HM4!etfTHO>~D%nd5qDzcRU*fi6#inTWUD)3NCpa&aTc;|mO)UK54V!9~ zMkRo1IdcQw3QgGKE)=J=pT5DGFq8KM?5`jW@=b$$gUMJ{gMO=r3kjSH=8w<-p9C`= ziAxphPG3`^&41hRYLlSQpQ?Se59!ogtwcN$=aQ&HlFd$&BsrD%yTrPa*S=t5)X%I) zj-?+o_Q_z!f7-q+%0A$GND#oB%$MYx&9Jg^<#ox^l7$T;+ym4=Un4SONPv4KC`Qy^ z{=k-kq%pi2aS>Y*@jbK5Z~u=|Sn@HK9yrf%cwjS^9b&4~_p&|~Ei=2eUFLRtE#|`{ zwo|D6q&!Ec7V|m$V4|@esJ&sX(R|KonJHvv%4{}6T6#=ll$6iiWw!Qlj<7yQKDEBp zf7FO`M(ojD^G^Z?AyjcTknGtHXL;WR`))StyV7fYcm7&WTAp| z(BK>gww;bDp(La8DS$CdclnDe!V5iLJEnFny_c5?nKhfa$W;hR zR;DR5NQE+~P~LntKTHGFC?JxPb*$2lpg9Q^?5`~l>#Z15A76S;0OhM6r zJ0Ql8I%NY+MJF%^3c+aS&&qX?Om8R4sB4O`aQY3xll;NUVN@qZH*i%(Sfv+p@prC< zg(sKEiIYhD-1(e17w_>2Q0$znb4=nKb2(`eR~*E2%;DfbN=)H8CeaRwv`wOWxu7xz z*Phd_4{6{$lVqt|wsM|4=n=}QxY9DaYaS>3A(PW@Ohtyr?{G|#JLXbplKj{C4fr_w z=O;Y{Azp*}$oB&d1DCn5IHpQn;P97MFLrbd0_@CD5b8@dY@gr*DrSShwnOvMgyN=6 z>b#is%JOVYDGV%Q{0V-;w9SJ}ARyO&YG{&oq*iB!uV>)kS>X*$Z`@s_8rrJ$jr%25 zxy*?I@6v_kHMQs(ytc0c1BrCo)<3C>=ym zoy}O&FGll)C&7-6a_K{>qVB8t*6n#`_`WFDvQUMR*c$Au{Q<8&w8MYljhZ*2c5M9? z=9r<9O;Kx8QjQ}edZ!^tljAnbGSw_d2haFvRu$`hjj2Xhd6&p}SrE{!SAKnh1z%3T z^5bJH1P4OR2U>%Br>O=XB9FRXrK({eCb z8F*$y?)OVhg~Q2rI@P25kF}m|SJ#}S=Cq@c!;zs!CmoV~8hCk5Rz;RD{6XB|hy9fX znmd9nS+?OmJLhE0GW}Vaq;VXID_Jis<4vM+~`5@DT5HX)O-&SS^ zGmhrVJ>AFeTed2JDh5gW_R+(C@jo6S=uCy&QP?esoxT*K$tf5NNt@xaa#K1D;}(Xc zrpLv)4pYNmiNjh(adWDE2UP>d*m_~ zJ{f0e@#-(OFXRn;EmCHP6 z%=loUF~1zlxq;wdw#0bl%FwMv6Z(Wnz4?pT_Z0z?Rum5z%)GASvtYmc??dKH53JhE z`sH69v!-a{QE9CP*>wMQyc)f7-Yb{Yq8j5eGE}3F$;dD_n2anTC?ku}#r&(+tS$Qc zNBCF);GVAci-td(|7Q2Xfcg1ZQxnbGmL^4omKW{mtqr5zR>F8n%jCJaf!?kUi`E^% zN4azH(Pu?%ho!ZVxwgQz9P`N~wEL#OwmUT^@1^y#1JAq6xVkPD>E5rp zb^hA&2mPLWA$LY#Ta51HRQdd!_2~iNq7-HJcu`KiyxS5ey7#^LE#0Y55UMwl%$-2f z_)^s&<96?(xi}1HOGZn~0M8A}IN|b8pa0Y=U~gc033Zt*5Rf#k@W?o`qH;Ga5Dm&W zxmn#L8dQz?zc!Y35bpeq+)ItrtkHkpV(2BDm5{T%EyJJo{f1M2r)}s(vsS;Vh13$_ zBAl(kUw!WetOrHepOB6ejDVpB7`Uedl`FpJJ7_b%tbi|C2WZ;F}Nru z^wlLc)i5tIz2fnan#V^fBPVT)Olkh-SnF`$naIQ!BV}etd>b=_&pPH3!4)>7+Yk^O z;#{I&8pbGx$%L(posbS5GnF|gC!vgSaVg5c@(POd3la^pB14_`j8xn+vMMs9G7=7` zSS`nMAQ3wW9u5!1Bf}%d!-MDY|5xu>6~lp=;Xq|%!p6wy&F2EG=TPtKUW`m_9}4Wb zR{LJm_-gGJOTVr?s{>k){>A^H{+|RYJ_-EK`VZkA&-9P`)lP?S=BPq-%{60`pDCJbUx-YEOc726~Qf60a zs|u?f)tyO8`b8H3oQ2(XebAfG|6#`#nr~a{Ww@>WWcoY#XMfkOhb(-_5D@xK+ zjL5s`$5mMrx;#KhbVsW97Q()8K~24kn2b39L=+XKLLrSxHDwjW=_Y7$Ef7&c{LHk1 zd%DkJYAD{p^b^2`0|LdkuNKKp4h*P`EiDcvftPK2N=qRqM9&ZdAz1hdAVnN-ob(7e62~_ zPkv0^WoTh+9xmszK<}YTG@^Dv59=5zE~<_H4uk~Gx^0sd3E{nm#vox8A#d%uTB9G; zTHTzV%e4IkKdzcd6`wNn$3FCgQkdsiR09zt!pG4Ma-q0(QO$xLS5)^)}IY}ccq|_s)KaWVRbVn>xaxz zh6!S|id%{R_ZpKqUEINzD2O~nvG6_9@wmlyrtDs(@V)woto za1;?$bC3$u_okl?m}hXWvudZ*6w!-D$f54}Z-mwl!@m`y1Jeh;V7?&5gc7=<1P&4U z0{L<-l*v^K$&bQSzX>F4=t+s`+n_ID6!O^@ho}f-73=z8fOo!m{LRBlVUegRkUD$p2i3Y;{RpY@tIDF7~y5?BLQIEQi zTC`_nNd@89ESyIx25VG>!O5rla16I7ixsjnsne2}O9?R;>fYd0cFZ02F4w(zNz#X< z7<*nk+eGyVcK_ww=|t1JEG*Kf$;x~6hEI@-A|5xYuw z-NOVh-&(ls4bPc9{X)>Cq*r;@e`8vjsq{%2z*m=whP3PLLOlr7GNTV?2~ez+ zrHLC-mX_r;#2$A0OYhp;PQQeG4ygw(RUcN+l(-9CV777~hc?AlrMJv<$H;{x-QdG^ zT^8a6-te0ZNa+AqBUufnn5L-pJS>`-1$$KcyyF7Dg(0vvsBznVV>JwkH>uYjt9qui zTArtb{cuyZrW$v1rBxrM`#~s6FMGO7QMyWAgyI1c>mJ3?lFm)p*by7r78{aM`QJOX z#I}1G%yWa9G-!5>`^-^0XMbsboW*9UOEVbU8(y>2Tqcv>?NyU~V5qUEH`G4g>$V-* z_WSw~YEYwH&|}AI)iYJfP3n!OShsIFKVYWw?vA1st6LL>J3drH>kh&;2>>)*xpG}C zWSO#@!Jl(^%xink=f&xQ^1eD(Vx_gqP@=G|tZeMW)x=;*SNskh^y-07$sb1%_Whq{ zZnmy01fxlqfEib!J(xb~R2#EuP8S}tpH<@O^j6vo4GlXmQe#onS`s%^q;LloRhM&8 zJ}J*jcW@S)7xxce_aA|tjP5HlB0PC|SO|nd# zU$MZUgH^txST6&XziPo_! zRP`5cI2my&S0{D8K#me&+TmS`4}Wa$?=$#tDT6MMZ}G0(cK<$uFX%PqC20Jgc;xe= z_JQyR2W+Zw$X>AYdoo4K)RYQuK9{*4jakY4@fS5}yiy}pUv3i%VA_))|5067Mh`kY zVj?_6pAvMtg+fiBW=nlXRA^gN$d;)8-hp1uR99bhbf2Ye-!o97VzZ)Hy=#f4dI=lp z5_Nh9lXLD>!-*{ZUYim>eSy#~ro<+-t2?7O-zr*5>^;xl$HC&6&-p3<0Y~BQf40Vk zE!{vpoq4N+@m&LfvX%yWnId1k%B}LKICv}YK<_ny%@)j{oUWfCa1&^|?Q=nv)ksq- z+n~-t+U}}6;AHy?s5T)oxGmvig6P?YqwH|6Qw4q1(bm(=2P@9fPBC$W&bPO`+R~Vx zU^44{0RGT#Fr;nHDg+ck*W;I%NeMDx#S|ugKKi(8YNd3@a7-cHS$Ux1Xw6{rNGl@{ z(f^+J^BT;q4>GnCdL1DnQf!%ca9l^&cK~u+7}XHED6UOdWe#ne*s&;%E}8(+WIRd! zBYK{PE;i-DKhHD^G4ocaqzKNCZIHnKh^YDLM5e9mxqe(OW^OLlRrpU;FJWS}o(#|u zm}mMhhnu4o^?-p}FSmWCIjw2G`Liw0q2IALtp6shT;8CDadU8wD0}XW)y0bSN5^w0 zQDAFr`Dn{?Thx`OV}T@)Gj&v4r|be~-M|pE@p4}Mxw|W1iBK?A7y{U50%%Y4V>s9> zl<`;;r<+IHkJVhJy<*}3JpeTys!D!#g7*Pk};jq)xFk=`4bAJy^Rmx#axN+3v$PdW26vN7QKUP6>GllBZLmV-s9|;@Bq$gZ zDx;YXf^ssx{<#|0>;_6V9W&a9|75j1{xIwI$G1(=_u{OHfrTr6Pc`2#BR*qc7$>q8 zrLJ4kqv9;WQR6kCe2^AHe!kDu+VT95+qP=s>?FxQIv-~l=gKFJU`8{a&EPaFn<_4~ z^8Oz1d$m^#b;s)^N!%5YK0PGIrX-QZm8l{pW1qYWs81$xOcjHDfQrVLUyvjMPq)Rt z7ZT>(OIhV*OYfBnxuA5c61@?Z^6`9`KS?0?%KB((hNK7X?fuA5)Pr~XsmSsS=C~_( ze;FE=q94?rrH5qnL(ZCz-|K&~Wv&PZK9LEHZ^4{w+g`x#aKkmogV72;VqI9DF!C=3{zh}r=P(&#MoFXRvRdaim(;ATxX-C>Ke)e5 z-LU`l<6iY9_+2UVZS|kLk8e9T70oigYc)HzZQ{KLFS16evAqUKwJ6eIUT!rn70o63 zzYF2(!VT*-<2QyhH5^5BpH0q;?+sPyZkzmaUx)dDoxg!~QJYiibw=(DrOv39-vIiZ z8l$|%$TnC888r+gZ67NjbR6qu*Yaw3DgM(f_h;XddwX_W5>A}sUep9d$WVkeiU0(Q z)9gV<2$70qB(p-_kmsy*gqZC7mjPyGXrB|oAA{j~ioLE6nlFwNdt*k|NyMYly4y(3 zNm!W3z2*|#e9|Q$8qLvtOQck;@sao&9igha(>#lOpylG;(3X9u?km(}cTbEAst{qr zh3<9e8(iJTNR>Hhcv47S)Gdo_qF-Dd+R9&UfBcc_reo{eB7@H)NO1AGRaQYR*Syk? z*D@ItFrXTP*VVGZ9V{wO20?6p(Dl=NnZfY7{Y;-t)Zzz~41!!kP)W*ESk_wAoG;h& zYS~E5oUl=jcLjup^@_~rD$@J&WW`Z7!(wPE*>deAQG1_*6v{WglgPHmuZI(I%@7Wd z_~wU>ZD*&TH>G-S$olVx_G#V-sd{efnldHMKfs|XRnHZZ$~&z%=xTl3z&fRuD`*oQ zY_qAz1RLCcZL;Ou{4*pKzc4R@ZJ!WUUkBZFQr9tJ7%<@2h2vAG7b{J)aLREZs(6VY zcTKfArbdUlOXqHwcPC$-Z2+Gm`QDI9m(r|2T@iA!CH=!w%u4z{aXv1-IbKm!uB2yN9w{YG_j`wxLud!Y8c zy~FQ*1T9BqdSxd0HBv)TMB+!gVl%ciO;2^?rYx_|J<$O%+%qh9yBn&&pxrUiU<3S%hQSlL@MAG7*e>Nm9XE7 z33C+C^!_m>s?DnC`U}vvGb?gl2rQ(k<`hn4z)%^81`bXRPq4`6gy&qm3^&N(b>U;< zKSS>r%0~EqR#Qa(O$PoVL$gJ)@UavQb#Kh5dkHzRiVqRV!0Da@aFBzjx?bT^xV#!w zv=kiz39ieiDp*_%39h3kwEgc#1x>?q&3ArL6=zxmS@wN#dCv*=W=5}9;5rBAjakwC zqTgWHtYXWgtofSsmW)epNyBq*l>S7snbEkR?rFFNJIHlwVVFzFgGn|%sero6lQElC z7q<8;3W>;4{d0uWY%ZIXqblqa0IHnYbC3&uAo|C2wQ)>yJ0VW;U(mfBi?b-Rg5MY@ zKGzA;xvBjr+^l;eJkz3GK7XY`F(ps$xb478|CRjy~g-|X5WLw&daaMdvnqm>_fw+LM zQYr}TUJ$^hp!1)CAuvWQEz5~f`dGdY*sqDCy&$D z!EDtLB8c!HfHSK*>)(mGUS)|oUKdQ;xh>kNX4kYN{bL=DkaD-*dpoIhgzC1vr%GP` zCDx@nxjr>uN<#$|$FSdvG_KL=j^rB?f^rpbXbEY-e!UC2lhrB+!+~{j2K#pFjN^h5 zTleVx=alN2W35>g2b)i~AEGC~-@Q!?KX%0XDKMf8_h4%|49;LLNBxh`wKE+d4N}Oa z6lX!U-x1QRE(~2#uzADDd*nB+WCIHGtlPFd!b@)l_e%M&rQ~s?exJv3$IxSpGPy#v z=;lo}#SSY~y3R>22RxPsb}rp|WYdY&=Om}5N=cpCmZg3rC=;z@)RdiTII-o3+ankD z)B~-+N5)B$^50gsO^bQ7{FY5?Zh18OmU*}2Kt)%2yD6vT;$>RYDWD_^ZiCEsR>6-s zw}U>A%o#0j=dH9RMz`E1CB|@fv+)6*fXS6<7sVJjY6np=GgFq9HnrvXyo#h~oy#2U z@cCEqaN)!6xI9My5%c%UNM&IQ@R;N$pMWLQTWnl4&K{%C+A^XM~dC~yMRkE!L0)_Lsvc{^1|zG4seeg*FQm<@N-cC zGo_GqqxU1aH)2K-x(*kY!v`zo$dA>ioqcq*9hdP!xLGAonUHKezLsYfEpIpP&*7i#v_{69zG!EiKr zb%;IXLgB}Kc>VP_^s=a5k3-D=90xWElFyG}uwNU7oSkFqLog7gmcrZnGHG69+OEYQ z(!tN3AGxJPFUL?bj`lvo8?<495DrF?a6cHlnluIl9uSIkV?U>?&pAbP!|3;}hV!}q2te=tVf0=9 zX{S2erXGTIEea**R6cbU2Jr!_;Fvj_wl8ruiM<(idQ~GY$jiR z&2K!vCA&)d%%6E{%G6vL$y_`OuL()mlu=vVQcefXQ`D`YTm4(L-h$BDs9WP3YHzzW z)7U}enVXe&C3#*T4Kg8R99{IvN$WP07A!7x+i?x^1vLsvWbLy)HW_QaI1a9e{6X(r zRarLbbzfATcRhbJTF@8tX@q+V`V7aS`>*$>&EDMLMJ?B#OiPm&d#mEWRP+J^r>y3a%^^XD0a4c;OlXS_|zxpVRk;M zkI*}3a$Ox5Bk26Wb)F z1Z+CeHFRNb;f?Q!3n-mtJvhg$F#s(}AxwoUx7)1X0OfOze3>hsy7J|&d|q5G+||QP z{q*2+4{3JChSw5rV}nKD&Rj+v4$&4Xt|5`LMj)|f_Df?{cFvZqXJ)> zQX-~2fZJo|`0Y`kDecv_ZGM(iD>t-sI-D94Wh9j7r;LPh7&XmPjxzeGgJnYt)>j*B z)vlCwnzC%jUA^Y+``v4@gS6ALjZIY=5c-YDw`aec4Kho=p-y@65XAu_bk8MLqg*nE z9A0kF*Sj1cb%&sZK2kWdxk>K2Mi>YO`wexmu=-~wMYW#y z?2mKpH>~Em=8p*vq`w##X|W&vOci08Li!hj9tPJwWy z6H8aT@F<+tR}-bJz}9ZF$!*YAzHW1iWBo-EYa@SZE!YHe`?RK~G-;bQ)aF(P`I!cn z0mZ=BO3jI4I!#JDBuh5LS(B_LAwI+Ew(_6j+ya094PWiOJTJvbm`9LMv}sfpFkwq$Rto8-k1amN(Amn8qrL0{`DP}8|t%eM4=*Hv)Y@Y zK$qA2{Uh{wQ-lAL%$cyr>|^%${+M8En6I(z%G20p+@i68pNwiyCxK~QP|=y+Z~5e`{6IdW zENc_Ro;+^Oy_jRi|J?X@W+CbqX5_px1~m-yHta=lTgd4iYdmB$d?F+OcB5+=2LjJH z=@Xb1^!f~vkMu9xTxa1HfD6wJFuEQF(eTkE=lWUTiV^NnqeWl_Xx#rt*t@_*RjvKw zd+nJ$7uf?dfa3+U*_(@ygE3o6IO%EFI*2)xOo>`r%xEK)7R<4<(n1u|)Lx^r8Der<=^n@3PovLslykF%0Z8o`a=A4cnzQ)m`xVNg^OFpMk zc*?#u-NfXq137ne)k79VnQrmADc~<^tR^?h5@7W9hzK?h7UJSDAEA z`-)*EB17d}$*p`TIO3FfcpM|?pOLbeTK%)N*`!8aQj^WzzVvo~( zM(fbtY8WsxHD8oNg|ON7LhEQm3$VW3CT z2jpiw^0PjH66!t zRo!nX1^4*3&}QR<3Idt|U)sUZ_hP~p&|7*jZwuafuPAxSG2F^YTflkIi-)#2RvZDI z(Y$BzUY!6etJN16$g(4>?OAlq_1OiE_d*k49DyUe7O7RCv*WQFS(&wuB{(Mo`(PRV zf^U$j3q8SQC@|dNLgBI0_}LA!+cUdlc_S1xymp#MM$^7Wcf&RgGkjEdGV{8?2_SJC z^DTNJum~^<1N0zo)-knuV$vvy3(85Uo}`=0Ac+mn5Qgc*w<`)0oQYVk1sL~b_$geJ z;4H%568wN}!rNx5Fxz5u9MAjFdj-1ubLW)~4Imd`n}CHD<>;o>(9s(%@@oC<$E*Pj z$6r0u1)$1gz{ZjOe!S{hG^*Vlq%jEj!3Il;ATCN}7u}4vm+4y^3nnpT5m&jlF64_0 z_sfNI$wyM|me^MK@5dNqK3hMZW!*c__@8NV$6+PqZnZB?)7!GqjN|>IlI9Vf(a(D% z=WhQ*Bz{NMwkO{^liYm_DOmoURI=M9%(~mdwMNXyzc|R((x1O+kg!Jyyz36knMo>l zA{ngXB1-bt4if%LA%CV1cw^<9nKk@7aocO$?;y@v)l8AqaXo;Q34bG=%UVWfhLpGk z=Vy8`e+$$cj&~_4K;wUiuc6Os1^QpRdon*{t!1MXMk&kG7 zdt;5;#XZBEjyfGV+I5?fqHj2v$^jGD`3%>>B6HhlD~TYaa1i&(q$WTVWvyU&i{zO$}VJVhb=(c49OYL~6YvV-6qUI?O|4Gt;>EDgM9$m zeyNiq6KFA;`OQZC!nU&S$r`{zQ`&(|kvtk6py4=uO3v)EP9j|EC+Rf3uovNw=*4e+ zR)KXXP}rAF$*T>kn16KC&pmo__E*PxPv1qpc^AnSofq1VVnVXw7D!d;g>Q@N-=y&i zBJ2cTaMgo8&`#wGW|%$hY%*AFp?J1xJK$IB!y+mcMBg!7 z-mlgcU7q!{XgANSv;Ya0hv3nik(I*MnHU`bo*e$V^04G~IL3XIY}RK?k~FRUu^Bm8 zz2m5D1gyArOgn&$`Z7Ic72XxvO%X8rK|?Om2kMSLA77#Xyyxf>E|&L8RxK;OI+>Rp!GZE9?~66T%CqszX$LZ^t0&Z|1i5q`cJ5lHA$U@DsYC*&4lkHV8z ze&za10wpmY1sR|83eDp%9Tg{m;G<&)BqMM!yd;g!6sB5;?x=ro%0$K{?o1bh6Sa~r z+O82B+*nU(w7a2K5ppbqr(Yr0jtp|QPp+UVcwqH1mn5ip^DZ2*$vdY{4&LXHTos5M zVCwdsIZQv7)tpy<_DEqi%U2faF4>~LC<^E+@}JYGdm-zt^xMwx8tZv&U3!V6smLqa z<4>?ocR|y|NKIoQf3+?ofS}O#!xPURBQQlf>y`%DQPI}v^I#;trKQ6O&)HMD_Vbh8F_7_j4!X| zt@`A{%3f(myWs!;y|-i%Qk~CS387w?^B!zMbSt}1`ED`Fvewe4V zC74qYv;uhg$Bf2a)bE78-?e}kK89o8U(rut)hI{rm#PW%B1`RnzxkdKJd-s`0EVs&qgn~ z?{IT*j%5_yC>yMm~0r1X&`W2@Pc{t z*fd6L_%2K_3_>}Tz6y-QtnkOgvtHKvZ9k%)(z7y*WA~WJ5jxXha3AQCf$kRU9`fA* z!FdFLaZVlFCQF@$0K2o)X)G!lSN9x6I19)-`JwCbN}bwSXG)#iXGzuRhu^$2jjy~p zHa=n}5IY`@ZTzKIxaA1T?nH5*QyF`eBUcq*RPg$1-%Ye#w4Jtfk;n?~Q6;Kdzj7k<8yc%eJVc^r43`xg{24RF#vOW7SBuREw6-m>}%VJiGG2KeB{^OCWGir z_Jx7i*f+wZgy;Qnq3!EK&6f5wA9(Z;6ZvUrQ0P8P2dj!bX3B3t=xDmi2G$r<6xWo^ zH#5!^+CL-IOR(J=>z3u$_OagRF7Mz5Z_HV))N5(c1iWU)0)?!l4;CqGcf#T zTCqkyLSIMMSBPGUwhU9H9`BGYueHI8kPL$XRo(X3S6!m9N7SAk(-Xz8rY#77*nQa% zsxxd986q*PwKCZ{FBz6tHCGU{sK;xW60HTp{36pMm@nTntMBqn)(;G9n%O$t@b)dK zCma8*ZUVp84TMv`l z4gnlrw5{+p0V;C1wSkdDrhFcPb7&ZH%b|d6t@WkBo2zO}ldZ!B*L=}u{Ur8E8_+pZ z&y_{9D;xX!*uehMUQg{&m>brP&Ol`W`8Q=tlrZ>LRQWwx#eguhN@n#dtc*qYxIg0@ zs{Rgrp3j;^fy&f`Xzm{hpa62J(nxq>$+W2uWK=St_v750e+QRxu90E; zSgG1fGT))eR*8`YJ`qB)jC%1dL)T*?)1q9dY+4jO!?+yu;vQU##|6kk8<(kG;G>PV z@6!TmG}8IqgLM(H3w2K~HS$47PF zva?kT%3^fYy@skPv&4|`FYsVk(0lV~N#&JlL|^|cUqM&IqNQriyFiEk3b_biOgqN$&vq$6DG*%nB5t>`X0hToHyWyZ>RfgD>+OOa=m>nf6&z_+dV- zl{X|?5kzTFsjDqxO68<>xM2CX_T<~R~H+-Y4^|nuCN{_LnhRLP- z`>Y=&aKjDoA-I&w?S@a{yG&)vHS4gHnwBfpPextmt0*SV zW&JCTciNUn4G6Lv(;m`xg@(!v{niVKh_P_tDq4^hNqW@3DoWgH?zukx&)HKL6m%(# z>VPm7a*&jj_36ID>1-z~8U||eFoV(|1M&rf_`rhbi1a|6^}~djn1sibwxW*Gw66SF zq%s)QX%JpA>-nGFFth#wEiWQ2DSXz*SM;mXPM{v`^opCu!$5YIucLN!*NL~W!+mrO z=aUw-YNqR$eqV%Znvv&a6dFpd0Y$&XE*%Iamw1(QCBoBWrG6TXR<;F{@RN{svV?z>rk(uP2Zrdl_AjALaE- z8@lFk1tT=Rl5I+0rnlGSuQ-v$cV-B#{R$k8SUccl-~*&3#ny1=xbkO(d8%%jmhvn;;KNW3U`cZ zYW>k%+@dkKJ0Jv^$k`r<4Y_Q#55U)_m~Aj^i8|zA9`+Aro01vppN(BXr6(;BfoCrP za8_gt@doIpnCS(v`Az!DVCz&zrjTm!F{CEg%^&Fe-W+`043xTsSvwvS794u3USzY4 zMBg}`+{pT1Sz*})T1=;wajQCHp>>600W+$ zOkZj)0QRpwGQA`gYdPOw5t)$?yOmE!;HWJHHOJ7x1t0NO{)rE#S7dR_2&RH8~wY5QmwKG-T&jGxB^qSHSd@=C2I zJ$_w$S1m(I5zKFA?DVzf+AsTdrf%G9S+E(PJK~%{wr~uAIT6-pIR9O2_HiZoFKp9M zr6w)W`pU&xfsA^aI$z^BBJJtV|I-D?O~4kU<}H{%ovP4s@?7$je2L5c68=54=7{`X zetl^;3wP15$Grl$}|8)09miQ+>gd=yok~@gzoaHDK%BC>7&lQmwYO{?) z=;YMAoOsxt#M-7`xNmG`ES+5fBMW3!UgHbbHoV+Ek!@kE@)^?GDm<;siuZ}n<_xa7 z6c9`NLx!`q71oNMX4$N+pB_mpjfwbqoV>rM4sN)w)26(6vv<%B`kx-IjT##9Y5v<0 z?OGGmnLq_8>aZ1b)aCb`^0h0zrV^iSqOYkpe|JQ{_;6rfZ~mwVpKZC-`hB6U?VDEX zrtcm}L^vE2eyhBMYtI$hH|7|^RG%w_NBS7x{K zdel6S^RV@aqbb=|@hCo_yI)OG_O`zIkL|n>?*Kxuju=G@V&i|S7Wb+;tPt6*nBqXK*N(%mC)QPSo@ACSFygeRmkAe5Z}3l0k`&amX2|Dbt%`>2;JVVV@nr<6KN zT!Z`8SfGQ%QNLu$LN3`kDcR<%v0MB%JB0jJsQMFK%M}QO(3r-OYt~w7NNpbyW`uo@ zs(p|HY_6SglgrF~`yJG*3de2U5I2A3?x8hW;(W1g^!7JWchqW`xrW*=yLaA8g}QSM zti^oF8L`b~uyR)#JegI6C{BIy*4gBKs@Q{l9wK25 z$)9;exTTeLMp;0?nVa!w08%$|oT{G*Xbh$7jG}^Z3pT4*7;lgD$ula0CBBBC6)%}9 zWj>&R^hz6$^F11fPR4oUnX-n!y-Aj5)oNh6yz~8WwemeR8n#BhciPwml?SLs5}OC~ zSiRt->NX@e1#_!9ZD3UZd{0e^Op%ZhJ2av=l54qKe^HV66*lLRo z-OmEn*S&%@X<7F({#y|-W_kI7OX*rZqtyLO+m8yEhQ`aZKTU{1jUn9=zR7{tk(`() z@z2Pyk#S?4V@vVwbNcRgGU9@tsLZXR#8TJgg*k0pk5>TPJ)$Q_Ua{SK)0|Zua2_(S zJ%Y%3<8wI}GRWTH#JnA)#D9JIrkB=68Lva>@ z;D}PaIhRMchO+!?`K9NtKPWRO^oxJ$83>B;!#P&4mIp)Ss4C<7hQ2J-=t@ep)|~Fj z;JoT}2l3?1JK31Xo;#h0^}cJfqW_d@2+nV~C$gbsC`8uN)S>0&w8RN}FscZCJhmRA zI)y%NdKY-R!KLV@24&wHG|qvTW=ZxKk|oXqk~#RNX=5ZIJ{%}Wqc*r8neTbW|S@B>DXUu_qNfJcYm)G*UzUzL_ z7Vh?;oP}NUS0#Vvw{&39Sso#-@g1eyfuF-7v8l^PNQo8?IzTqUF zP&txMV}Lp2oN6n}RI;B{P$0^OTZDXIXk!H1^pwId?`SE#c8dl(B zn`Sbu$S~zN8s@e0_mquMCi2j_#6p_-k4rdwR3F=Qy8dz-h1&r8LIxj{V@#eH-ueQi z+KkQS8m*MQ9uXnu-+N(N3kLJpuNXB5^y)8T2# zyz|bwQ;949u3__bzN;z78`iDlbM7(pr{n9qSeT z`G9qbrL=jEbu+w9I?^-i@?(IIuv<p|9~*W<8^wdHL(GZSD_vE`FHe_qv; z0tq_4RvE#SMrZ=a5{9}$mY08rTlV}J3Uw80y;t9jJaOSXo(N8g&{QIiinJgh&kPC= z24yFJ7aWsLjenWuiPe4#mxm1>AApc9)%(`T&x{#)PfvUM{$*ZY1BKt>Wq@zJdD1{W z5(+KoD4mw+i-1;Xal{(Ltcbw2Vu~0Yc-s<7F1?r`6lTt&D;oo{B{JWPM)RTY08 z_Bf>E08r1JJS>MGG!cR2az%M5fPjoQ&^aVK1AgShq+HCaiCTH@FD}NI$_s%5To&-O zMXE%DjGx!#GTZ`8*|O@3-bXGVoQ1nB;BNKU$H4~2vuGTsCjRxQvIsKofPsF|3^Fa+ z#=X>I08&y|5t{X@;(?mX+2(P!O15!Sp;<7l(I0`&G`@N<8_0r~^^kKo@iXE10iCVt zJIeAV*aMLt4mPtQWW=!cWSS$y2&7+PYu!ltnlbq$`?S`Min@+qdk1N6S$#A{FBEi9 z?HSX)Xd1ahlcbqk2xxO!ah%4sM!K1=mu6*| zx%^jN(h&v*4ZsTxcS@=`)3(xjV5)PiVfOU3hK1=v3co4CQiiv1BKiS&DF$rYC%_Hd zpKF*1&ES+))OjMCG6MMHh*m!(hHZ>w%I8oGc^%K>q=ohh=MZ0;jC~X7bULPf2hNG4 z`4a5_J|hjBGU z(Gz452ZZk~Bv}`gsXA6J$U^t1oz|{T za56}%Hi&}zHh7`PseiQYtfqr?{JV!|WzA6O(6xxktmbddhK+vnXjxO`k4+M~74ko5C=Up}`T_0QaL0?#jd_(ZaF!y52QYsRh2riHnL#H9e3oSEDZeb;+U2>I(OdCHq zBzc_ehRM`2t@X{x#RUp9leO>u6CT!3O&01^P2)nntG_SntWv%Mr^f_XP5+~B4FNn9 zuW9_uVrk7uAO zK>l!|42%H)Kgg*NFh5uuwajHKSMwDKczr8_e8trYew8C26AkF-BD(v7H+H zEI-7@x?Y1kA5@~;helpf@RZgZgyT0FlcLI{yCpA_tgO*e59~t*r=teDo%={B+p3f= z&macOIMn;b=4j)RoO8nYu&T*BA>kSX)pWuU=?x@I0im!|m10}tV}xxXX>y4=!7BQ_ zJ!r2dyJY3x{_GIxG6^K~!I7e<=pwGAggzmk2Fvsh;rZj^KaN3vHd5s}YTS6;Ft%*3 zvWCKDF+xR1oqz+R_W6F7Ho_mxqLsh3O?WPxh7v^>6|C*&SemBn!tc`HRo0LLsJf_q zm^>Zw%dsd{v@Mq=KU`j#BbQIE(=z1o5E_t}#x$<#Z|oa{B3#|qi%^RW#gzTNPYcjD zX7o`yeh{TH>!FbFDT1z)u->=^Z#;JDoXI%+K|yY0T~pzokngj2&nq6?ig0A=>=phQ zv1z0%bC3_wMXkm(0>&b%plsuyl_$PkYq0L;5XI{>uznAc7`g{Rf>nuG%+IfUx0xUQ z7F#KgrV`$%+wg9h-SLNRyOzv)7&q}ADcHO#E0oLEj$T{qP9&Sx;Heti>oAJ@n#?Q4 zJ;@9ioDEDXqWqk3pRoa_46y*BBeS0GmlD77R69YXrTJeq2=P*|gcaicfP-bSZ3u9q zU61s0XV5zlLWANM(M{gnhSI#6!^LkL!0`GO^l?Ao?LQiX;i~lHrwe!uuKmzO(9+Z4 zo9kTr_w;s6r{Y@3kin>q$h7;VNJmVFkCmP68I!1~PaDhuBA9&fl6QXpEZw4C0dFu{ z2Vo=jAN0GUh7ybLRw!vUVuq6Sv_953I{2*_7+nmdUY;Q1!*KH(9lc+|qcmN0R)?+G z6Uvze^3Fb_7cPCt@*5>_8eD2@OpvWxrjOA(qB{9#aT1di)oFa6yiU{Q-AV0_T$URg zPyNakilrSEGd+TMs4#qQ`c+wtxzUNAk2VhQaoD7rErtq!#s&42Da3jJg-Q02qc+9| zs-0OEl)SILEZjTG1!ts%du8o(+0_oyWE*2WqbFtb!(>5ADN|L+RQNNNTBqu3m<`Fp zA0=8^j7n&HsKqW32G&HHW)Y`FH#`DM^Ttnp%^Go3oE$@*P#gI#g*->QTsW>c-n^E} zlhx|o5ydgRg&!>6v4a-KWU|^oe)dm#Bj; zdD_Z7-{`G|KoF4Yv{oDHzcGGHX3`|po%`!-%&t$AH(z<{Q*xvQk808SIJ4tJg_m-9 zZkAHs12@3$s7znOf%b~oCzZNIHqkyZ?_KDQ7#K#m?pF|egc+yOq*m5zXx@-n+`>Zh zTW=;GzK$|cjG;I`XyAQ~u^0J38Ge!MjKjN$#9`eUJIovR9)7?#u|3D^(iB0JbI}tqHq5O>PVYz>h>4if$bEtkss^> z7xi2w$@KE~e{A_!0I1UK2tzpVJj06^-33Ny7cvoN6Sd3K@snluj{qj~)LqVZT@r(w zT8dggK7aH{%R&^PmdTCR@gAJAub0Ia^2guwBG!Xto#47v2QWBv?_iGYgO-i)K21YJ z(F4Yh4p?64R$R%l?nHDG-bB{*@tSjwv;geu;4`USrX?sxt!S_xDBqjnMd|a&KewT? zcgR>`Fb{a9&s*3Z*D>n9G-ui7JW;m-QJ_XmY;Iy0KJv#rn5-eF4lu6}k7GZ~oFTJh zu#N(K9THU28DV;hh!!qwA#b)p<5B>x2kD<=MO^w&B0w#*5*A|t7(Z$&5P?mWBd~-FwOe9 zE}l6ioOq^(C%}CTDWO&oh)}#X1WX#lnk*lO?ih?c_q5|OyqghOG7aXMHji63&}`I? z){OeKkof)|9Y9_<%kC&TH>Qv0yH5n$(+*UnQMn8HcLD9+@-7nHk3?~yy1FI$3IF0v z6xIhlX}X+6VS{K-t{l|wGpz6!o+*y+TkyfqI9E|pP!taUE!UItj3kcC(7ZHHyWquB z)NFo((&sa-D30#?T(|o+Rf2md*;2G7C>9=&j4OB+4m?v=n7XUB@m!5KvZyR5ryKxM z#T&6v>V~!8#h>XYaCi~-`hxA|qU>OVUrKC|<{yB_V8PA5%#3?qEIbHP8jSBiTdD2T zxs!dET~RCe$Q?{eWLr-!Og36i1jV!icNS zx{?*1rY8^3vLaWso$Rf0@_cJ=P`c&7s2EA@qJ0&=&eV@HHK*_JWa^4I|o}WnqIZ3>r2pNiGWSSuFc# zXk3~G20H1JDoP5}$)8_QFe7;1bgcGCoF6;iV@rLQj{GX_ zq2ErEDo^8&HDd|hIjKZTWVx6zIB)_9%`efAT#XLw9$Q?(fah^!mG$x$j}$ z`x4vv*KGc}f?HSVU(=fCBZ&G#zm_JpkJ_x~6B-|&U<<%6yw0Vm-ztYwz@PlF`axsU z5hOtV6Oe0SxH&htRHOl)8D>$Xy=D;h`6RKBj?hIhD1xkZ3dN@;q2b?FFg=^QiB(a(xo8FqxGGCu0uFU`!$>2ECL%U`vno71Ao-sr`P zj6O)Ks1In_qy5{Wtj=2cA=Z|NK#h!XZT7s?*{NO;zz$gW$j6z~1=GENxT z^&bENR+~S{SjsacFN`ZG8TZm=%3f@cPi{6^QxPw=Ef>lk1g;~?=spU%)Xpblvb8*; zDrw;Pz~n{-gX3ysZM=tQRwGS$EyXdCx4uFSQtedZo#6VUdiJXZd)Jw&`kLnbZk7Lg zxCbx6|J`#Q{9j@C<~slP5WNkrOFB`oHp1;5O_8n9?5(uf+4UeObkhKSK#$kZ?$w2( zH=U&zX)&f_Y*o-T9>SkoxK{b%O>hN-MgxB2D?p?h$6tij)Ae(yDRX=wNNeMpKS6rk zh+nQ1KlMOjxtR1UX0J@dn7(*H-g>%iNwWx_vq62Z#S%q7*-Tp|@uyqI27BiD#Wa6; zyF-JHIzuYyo1VpZwgAuid*!X?$e+W{7KlN}4JqI0nth>d_ccCos)^-wLki&0yL=-L zT#vr#(_zN1Yuu+aEItJO7O@+%mjBSRxV_MR%nPW8h4!9D6ZhwxF1{RQ9aMVS;N|Mw z%@Q_$yVjUx(29wPJL-1Sc-}cPGd{`pZp#AmO;X)hZ^qexeQl}MSyZ&-QbtTJJC}tx zmbh%!Ujc0y8{*Y#m#kg4=ima1{&wH&vkb%OR!cBZ(+hM}bY9Bp&;1u7^@aqrKg z&#uvD0}+0h67bzi{+8erXed0KxX8P&;jNI=oB?x3d6F|lb|4fUa-F5QTsMwk6Obo} zyvPK3*RWiw)GX0FL@0XgTbv|Fa#(hkRiA$ z?`&V|mU7x|@VJt*m9=XnXL~JvPiu3Hz^pzgY(IrUxPSGlLfX^NWjm`F#ymZ(tguli}!pHpICL$Mgu@nsP$E~FX9q

%%Sq_(uI9tHB~jOGS&!qVJ-PPy-^h& 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 +#include #include "GenLinkedList.h" class STORESTRINGS_CLASS { diff --git a/esp3d/webinterface.cpp b/esp3d/webinterface.cpp index 6c60206c..4359e062 100644 --- a/esp3d/webinterface.cpp +++ b/esp3d/webinterface.cpp @@ -21,12 +21,24 @@ #include #include "config.h" #include "webinterface.h" -#include "wifi.h" +#include "wificonf.h" #include #include #include -#include +#ifndef FS_NO_GLOBALS +#define FS_NO_GLOBALS +#endif +#include +#ifdef ARDUINO_ARCH_ESP8266 +#include "ESP8266WiFi.h" #include +#else +#include +#include +#include "SPIFFS.h" +#include "Update.h" +#endif + #include "GenLinkedList.h" #include "storestrings.h" #include "command.h" @@ -36,9 +48,13 @@ #include #endif +//embedded response file if no files on SPIFFS +#include "nofile.h" + #define MAX_AUTH_IP 10 #define HIDDEN_PASSWORD "********" + typedef enum { UPLOAD_STATUS_NONE = 0, UPLOAD_STATUS_FAILED = 1, @@ -47,2545 +63,41 @@ typedef enum { UPLOAD_STATUS_ONGOING =4 } upload_status_type; -const char PAGE_404 [] PROGMEM ="\n\nRedirecting... \n\n\n

Unknown page - you will be redirected...\n

\nif not redirected,
click here\n

\n\n\n\n
\n\n\n\n"; -const char PAGE_RESTART [] PROGMEM ="\n\nRestarting... \n\n\n
Restarting, please wait....\n
\n\n
\n\n\n\n"; -const char RESTARTCMD [] PROGMEM =""; -const char VALUE_11B[] PROGMEM = "11b"; -const char VALUE_11N[] PROGMEM = "11n"; -const char VALUE_11G[] PROGMEM = "11g"; -const char VALUE_NONE[] PROGMEM = "None"; -const char VALUE_LIGHT[] PROGMEM = "Light"; -const char VALUE_MODEM[] PROGMEM = "Modem"; -const char VALUE_ENABLED[] PROGMEM = "Enabled"; -const char VALUE_DISABLED[] PROGMEM = "Disabled"; -const char VALUE_WEP[] PROGMEM = "WEP"; -const char VALUE_WPA[] PROGMEM = "WPA"; -const char VALUE_WPA2[] PROGMEM = "WPA2"; -const char VALUE_WPAWPA2[] PROGMEM = "WPA/WPA2"; -const char VALUE_STARTED[] PROGMEM = "Started"; -const char VALUE_STOPPED[] PROGMEM = "Stopped"; -const char VALUE_NO[] PROGMEM = "No"; -const char VALUE_YES[] PROGMEM = "Yes"; -const char VALUE_CONNECTED[] PROGMEM = "Connected"; -const char VALUE_NO_SSID[] PROGMEM = "SSID not Available!"; -const char VALUE_CONNECTION_FAILED[] PROGMEM = "Connection failed!"; -const char VALUE_CONNECTION_FAILED2[] PROGMEM = "Connection failed! (Wrong Password)"; -const char VALUE_IDLE[] PROGMEM = "Idle"; -const char VALUE_DISCONNECTED[] PROGMEM = "Disconnected"; -const char VALUE_ITEM_VISIBLE[] PROGMEM = "visibility:visible;"; -const char VALUE_ITEM_HIDDEN[] PROGMEM ="visibility:hidden;height:0px;width:0px;padding:0px"; -const char KEY_IP[] PROGMEM ="$IP$"; -const char KEY_WEB_ADDRESS[] PROGMEM ="$WEB_ADDRESS$"; -const char KEY_HOSTNAME[] PROGMEM ="$HOSTNAME$"; -const char KEY_HOSTNAME_VISIBLE[] PROGMEM ="$HOSTNAME_VISIBLE$"; -const char KEY_NOT_APPLICABLE_4_AP[] PROGMEM ="Not applicable for Access Point"; -const char KEY_PAGE_TITLE[] PROGMEM ="$PAGE_TITLE$"; -const char VALUE_HOME[] PROGMEM = "Home"; -const char VALUE_FW_VERSION[] PROGMEM = FW_VERSION; -const char VALUE_NOT_AVAILABLE [] PROGMEM ="Not available"; -const char VALUE_NO_IP [] PROGMEM = "0.0.0.0"; -const char KEY_FILE_NAME [] PROGMEM ="$FILE_NAME$"; -const char KEY_SHORT_FILE_NAME [] PROGMEM ="$SHORT_FILE_NAME$"; -const char KEY_MENU_HOME [] PROGMEM ="$MENU_HOME$"; -const char KEY_MENU_SYSTEM [] PROGMEM ="$MENU_SYSTEM$"; -const char KEY_MENU_AP [] PROGMEM ="$MENU_AP$"; -const char KEY_MENU_STA [] PROGMEM ="$MENU_STA$"; -const char KEY_MENU_PRINTER [] PROGMEM ="$MENU_PRINTER$"; -const char KEY_MENU_SETTINGS [] PROGMEM ="$MENU_SETTINGS$"; -const char KEY_MENU_ADMIN [] PROGMEM ="$MENU_ADMIN$"; -const char KEY_FW_VER [] PROGMEM ="$FW_VER$"; -const char KEY_CHIP_ID [] PROGMEM ="$CHIP_ID$"; -const char KEY_CPU_FREQ [] PROGMEM ="$CPU_FREQ$"; -const char KEY_SDK_VER [] PROGMEM ="$SDK_VER$"; -const char KEY_MDNS_NAME [] PROGMEM = "$MDNS_NAME$"; -const char KEY_MDNS_VISIBLE [] PROGMEM ="$MDNS_VISIBLE$"; -const char KEY_CONNECTED_STATIONS_NB_ITEMS [] PROGMEM = "$CONNECTED_STATIONS_NB_ITEMS$"; -const char KEY_CAPTIVE_PORTAL_STATUS [] PROGMEM = "$CAPTIVE_PORTAL_STATUS$"; -const char KEY_CAPTIVE_PORTAL_VISIBLE [] PROGMEM = "$CAPTIVE_PORTAL_VISIBLE$"; -const char KEY_SSDP_STATUS [] PROGMEM ="$SSDP_STATUS$"; -const char KEY_SSDP_VISIBLE [] PROGMEM ="$SSDP_VISIBLE$"; -const char KEY_NET_PHY [] PROGMEM ="$NET_PHY$"; -const char KEY_SLEEP_MODE [] PROGMEM = "$SLEEP_MODE$"; -const char KEY_BOOT_VER [] PROGMEM = "$BOOT_VER$"; -const char KEY_WEB_PORT [] PROGMEM = "$WEB_PORT$"; -const char KEY_DATA_PORT[] PROGMEM = "$DATA_PORT$"; -const char KEY_BAUD_RATE [] PROGMEM = "$BAUD_RATE$"; -const char KEY_REFRESH_PAGE [] PROGMEM = "$REFRESH_PAGE$"; -const char KEY_AP_STATUS_ENABLED [] PROGMEM = "$AP_STATUS_ENABLED$"; -const char KEY_AP_VISIBILITY [] PROGMEM = "$AP_VISIBILITY$"; -const char KEY_AP_MAC [] PROGMEM = "$AP_MAC$"; -const char KEY_AP_SSID [] PROGMEM = "$AP_SSID$"; -const char KEY_AP_IS_VISIBLE [] PROGMEM = "$AP_IS_VISIBLE$"; -const char KEY_AP_CHANNEL [] PROGMEM = "$AP_CHANNEL$"; -const char KEY_AP_AUTH [] PROGMEM = "$AP_AUTH$"; -const char KEY_AP_MAX_CON [] PROGMEM = "$AP_MAX_CON$"; -const char KEY_AP_DHCP_STATUS [] PROGMEM = "$AP_DHCP_STATUS$"; -const char KEY_AP_IP [] PROGMEM = "$AP_IP$"; -const char KEY_AP_GW [] PROGMEM = "$AP_GW$";; -const char KEY_AP_SUBNET [] PROGMEM = "$AP_SUBNET$";; -const char KEY_STA_STATUS_ENABLED [] PROGMEM = "$STA_STATUS_ENABLED$"; -const char KEY_STA_VISIBILITY [] PROGMEM = "$STA_VISIBILITY$"; -const char VALUE_ACTIVE [] PROGMEM = "active"; -const char KEY_STA_DHCP_STATUS [] PROGMEM = "$STA_DHCP_STATUS$"; -const char KEY_STA_IP [] PROGMEM = "$STA_IP$"; -const char KEY_STA_GW [] PROGMEM = "$STA_GW$"; -const char KEY_STA_SUBNET [] PROGMEM = "$STA_SUBNET$"; -const char KEY_STA_MAC [] PROGMEM = "$STA_MAC$"; -const char KEY_STA_SSID [] PROGMEM = "$STA_SSID$"; -const char KEY_STA_CHANNEL [] PROGMEM = "$STA_CHANNEL$"; -const char KEY_STA_STATUS [] PROGMEM = "$STA_STATUS$"; -const char KEY_FREE_MEM [] PROGMEM = "$FREE_MEM$"; -const char KEY_SERVICE_PAGE [] PROGMEM = "$SERVICE_PAGE$"; -const char ARG_SUBMIT [] PROGMEM = "SUBMIT"; -const char KEY_MODE [] PROGMEM = "$MODE$"; -const char VALUE_AP [] PROGMEM = "AP"; -const char VALUE_STA [] PROGMEM = "STA"; -const char VALUE_AP_STA [] PROGMEM = "AP_STA"; -const char KEY_BAUD_RATE_OPTIONS_LIST [] PROGMEM ="$BAUD_RATE_OPTIONS_LIST$"; -const char KEY_SLEEP_MODE_OPTIONS_LIST [] PROGMEM ="$SLEEP_MODE_OPTIONS_LIST$"; -const char KEY_ERROR_MSG [] PROGMEM ="$ERROR_MSG$"; -const char KEY_SUCCESS_MSG [] PROGMEM ="$SUCCESS_MSG$"; -const char KEY_ERROR_MSG_VISIBILITY [] PROGMEM ="$ERROR_MSG_VISIBILITY$"; -const char KEY_SUCCESS_MSG_VISIBILITY[] PROGMEM ="$SUCCESS_MSG_VISIBILITY$"; -const char KEY_SUBMIT_BUTTON_VISIBILITY [] PROGMEM ="$SUBMIT_BUTTON_VISIBILITY$"; -const char VALUE_CONFIG_AP [] PROGMEM = "Configuration Access Point"; -const char VALUE_CONFIG_STA [] PROGMEM = "Configuration Station Client"; -const char VALUE_PRINTER [] PROGMEM = "Printer Interface"; -const char VALUE_HAS_ERROR [] PROGMEM = "has-error"; -const char VALUE_HAS_SUCCESS [] PROGMEM = "has-success"; -const char KEY_BAUD_RATE_STATUS [] PROGMEM = "$BAUD_RATE_STATUS$"; -const char KEY_SLEEP_MODE_STATUS [] PROGMEM ="$SLEEP_MODE_STATUS$"; -const char KEY_WEB_PORT_STATUS [] PROGMEM = "$WEB_PORT_STATUS$"; -const char KEY_DATA_PORT_STATUS [] PROGMEM ="$DATA_PORT_STATUS$"; -const char KEY_AP_SSID_STATUS [] PROGMEM = "$AP_SSID_STATUS$"; -const char KEY_AP_PASSWORD_STATUS [] PROGMEM = "$AP_PASSWORD_STATUS$"; -const char KEY_NETWORK_OPTION_LIST_STATUS [] PROGMEM = "$NETWORK_OPTION_LIST_STATUS$"; -const char KEY_NETWORK_OPTION_LIST [] PROGMEM = "$NETWORK_OPTION_LIST$"; -const char KEY_CHANNEL_OPTION_LIST_STATUS [] PROGMEM = "$CHANNEL_OPTION_LIST_STATUS$"; -const char KEY_CHANNEL_OPTION_LIST [] PROGMEM = "$CHANNEL_OPTION_LIST$"; -const char KEY_AUTH_OPTION_LIST_STATUS [] PROGMEM = "$AUTH_OPTION_LIST_STATUS$"; -const char KEY_AUTH_OPTION_LIST [] PROGMEM = "$AUTH_OPTION_LIST$"; -const char KEY_AP_IP_STATUS [] PROGMEM = "$AP_IP_STATUS$"; -const char KEY_AP_GW_STATUS [] PROGMEM = "$AP_GW_STATUS$"; -const char KEY_AP_SUBNET_STATUS [] PROGMEM = "$AP_SUBNET_STATUS$"; -const char KEY_AP_PASSWORD [] PROGMEM = "$AP_PASSWORD$"; -const char KEY_IS_SSID_VISIBLE_STATUS [] PROGMEM = "$IS_SSID_VISIBLE_STATUS$"; -const char KEY_IS_SSID_VISIBLE [] PROGMEM = "$IS_SSID_VISIBLE$"; -const char VALUE_CHECKED [] PROGMEM = "checked"; -const char VALUE_SELECTED [] PROGMEM ="selected"; -const char KEY_IS_STATIC_IP [] PROGMEM = "$IS_STATIC_IP$"; -const char KEY_AP_STATIC_IP_STATUS [] PROGMEM = "$AP_STATIC_IP_STATUS$"; -const char KEY_STA_STATIC_IP_STATUS [] PROGMEM = "$STA_STATIC_IP_STATUS$"; -const char KEY_STA_SSID_STATUS [] PROGMEM = "$STA_SSID_STATUS$"; -const char KEY_STA_PASSWORD_STATUS [] PROGMEM = "$STA_PASSWORD_STATUS$"; -const char KEY_STA_IP_STATUS [] PROGMEM = "$STA_IP_STATUS$"; -const char KEY_STA_GW_STATUS [] PROGMEM = "$STA_GW_STATUS$"; -const char KEY_STA_SUBNET_STATUS [] PROGMEM = "$STA_SUBNET_STATUS$"; -const char KEY_STA_PASSWORD [] PROGMEM = "$STA_PASSWORD$"; -const char KEY_AVAILABLE_AP_NB_ITEMS [] PROGMEM = "$AVAILABLE_AP_NB_ITEMS$"; -const char KEY_AP_SCAN_VISIBILITY [] PROGMEM = "$AP_SCAN_VISIBILITY$"; -const char KEY_HOSTNAME_STATUS [] PROGMEM = "$HOSTNAME_STATUS$"; -const char KEY_XY_FEEDRATE [] PROGMEM = "$XY_FEEDRATE$"; -const char KEY_Z_FEEDRATE [] PROGMEM = "$Z_FEEDRATE$"; -const char KEY_E_FEEDRATE [] PROGMEM = "$E_FEEDRATE$"; -const char KEY_XY_FEEDRATE_STATUS [] PROGMEM = "$XY_FEEDRATE_STATUS$"; -const char KEY_Z_FEEDRATE_STATUS [] PROGMEM = "$Z_FEEDRATE_STATUS$"; -const char KEY_E_FEEDRATE_STATUS [] PROGMEM = "$E_FEEDRATE_STATUS$"; -const char VALUE_SETTINGS [] PROGMEM = "Extra Settings"; -const char KEY_REFRESH_PAGE_STATUS [] PROGMEM = "$REFRESH_PAGE_STATUS$"; -const char KEY_DISCONNECT_VISIBILITY [] PROGMEM = "$DISCONNECT_VISIBILITY$"; -const char VALUE_LOGIN [] PROGMEM = "Login page"; -const char KEY_USER_STATUS [] PROGMEM = "$USER_STATUS$"; -const char KEY_USER_PASSWORD_STATUS [] PROGMEM = "$USER_PASSWORD_STATUS$"; -const char KEY_USER_PASSWORD_STATUS2 [] PROGMEM = "$USER_PASSWORD_STATUS2$"; -const char KEY_USER [] PROGMEM = "$USER$"; -const char KEY_USER_PASSWORD [] PROGMEM = "$USER_PASSWORD$"; -const char KEY_USER_PASSWORD2 [] PROGMEM = "$USER_PASSWORD2$"; -const char KEY_RETURN [] PROGMEM = "$RETURN$"; -const char VALUE_CHANGE_PASSWORD [] PROGMEM = "Change Password"; -const char MISSING_DATA [] PROGMEM = "Error: Missing data"; -const char EEPROM_NOWRITE [] PROGMEM = "Error: Cannot write to EEPROM"; -const char KEY_WEB_UPDATE [] PROGMEM = "$WEB_UPDATE_VISIBILITY$"; -const char KEY_STA_SIGNAL [] PROGMEM = "$STA_SIGNAL$"; -const char KEY_DATA_PORT_VISIBILITY [] PROGMEM = "$DATA_PORT_VISIBILITY$"; -const char KEY_LOGIN_ID [] PROGMEM = "$LOGIN_ID$"; -const char KEY_IS_DEFAULT_MODE [] PROGMEM = "$IS_DEFAULT_MODE$"; +const char PAGE_404 [] PROGMEM ="\n\nRedirecting... \n\n\n
Unknown page : $QUERY$- you will be redirected...\n

\nif not redirected, click here\n

\n\n\n\n
\n\n\n\n"; +const char PAGE_CAPTIVE [] PROGMEM ="\n\nCaptive Portal \n\n\n
Captive Portal page : $QUERY$- you will be redirected...\n

\nif not redirected, click here\n

\n\n\n\n
\n\n\n\n"; +const char CONTENT_TYPE_HTML [] PROGMEM ="text/html"; - -bool WEBINTERFACE_CLASS::generateJSON(STORESTRINGS_CLASS & KeysList , STORESTRINGS_CLASS & ValuesList ) -{ - LOG("process JSON\r\n") - if(KeysList.size() != ValuesList.size()) { //Sanity check - Serial.print("M117 Error"); - LOG("Error\r\n") - return false; - } - bool header_sent=false; - String buffer2send="{"; - for (int pos = 0; pos < KeysList.size(); pos++){ - //add current entry to buffer - if (pos > 0)buffer2send+=","; - String keystring = KeysList.get(pos); - keystring.replace(String("$"),String("")); - //this allow to add extra info in array - buffer2send+="\""; - buffer2send+=keystring; - buffer2send+="\":"; - if (ValuesList.get(pos)[0]!='\"')buffer2send+="\""; - buffer2send+=ValuesList.get(pos); - if (ValuesList.get(pos)[0]!='\"')buffer2send+="\""; - - //if buffer limit is reached - if (buffer2send.length()>1200) { - //if header is not send yet - if (!header_sent) { - //send header with calculated size - header_sent=true; - web_interface->WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->WebServer.sendHeader("Content-Type","application/json",true); - web_interface->WebServer.sendHeader("Cache-Control","no-cache"); - web_interface->WebServer.send(200); - } - //send data - web_interface->WebServer.sendContent(buffer2send); - //reset buffer - buffer2send=""; - } - //add a delay for safety for WDT - delay(0); - } - buffer2send+="}"; - //check if something is still in buffer and need to be send - if (buffer2send!="") { - //if header is not send yet - if (!header_sent) { - //send header - web_interface->WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->WebServer.sendHeader("Content-Type","application/json",true); - web_interface->WebServer.sendHeader("Cache-Control","no-cache"); - web_interface->WebServer.send(200); - } - //send data - web_interface->WebServer.sendContent(buffer2send); - } - //close line - web_interface->WebServer.sendContent(""); - LOG("Process template done\r\n") - return true; -} - - -bool WEBINTERFACE_CLASS::processTemplate(const char * filename, STORESTRINGS_CLASS & KeysList , STORESTRINGS_CLASS & ValuesList ) -{ - LOG("process template\r\n") - if(KeysList.size() != ValuesList.size()) { //Sanity check - Serial.print("M117 Error"); - LOG("Error\r\n") - return false; - } - - GenLinkedList myFileList = GenLinkedList(); - String buffer2send; - bool header_sent=false; - - buffer2send=""; - //open template file - FSFILE currentfile = SPIFFS.open(filename, "r"); - //if error display error on web page - if (!currentfile) { - buffer2send = String(F("Error opening: ")) + filename; - web_interface->WebServer.send(200,"text/plain",buffer2send); - return false; - } else { //template is open - int b ; - String sLine; - bool bprocessing=true; - - while (bprocessing) { //read all bytes - b = currentfile.read(); //from current open file - if (b!=-1) { //if not EOF - sLine+=char(b); //add to current line - if (b=='\n') { //end of line is reached - //change all variables by their values - for (int k=0; k-1) { - //get value - nb=atoi(ValuesList.get(ipos)); - ipos=ipos-(nb*3); - } - //do a sanity check data are there - String Last_IP_Key = "$IP_CONNECTED["+String(nb-1)+"]$"; - if (nb>0 && (KeysList.get_index("$ROW_NUMBER[0]$")==ipos) &&(Last_IP_Key==KeysList.get(ipos-1+(nb*3)))) { - for (int j=0; j-1) { - tmppart.replace("$ROW_NUMBER$",ValuesList.get(ipos+0+(j*3))); - tmppart.replace("$MAC_CONNECTED$",ValuesList.get(ipos+1+(j*3))); - tmppart.replace("$IP_CONNECTED$",ValuesList.get(ipos+2+(j*3))); - } - tablepart +=tmppart; - } - } - //now build back - sLine = beforelinetoprocess + tablepart + afterlinetoprocess; - } - - pos_tag=sLine.indexOf("$AVAILABLE_AP["); - if (pos_tag!=-1) { //if yes - //extract line - int pos_tag_end = sLine.indexOf("]$",pos_tag); - int nb = -1; - int ipos = -1; - //part before repetitive section - String beforelinetoprocess=sLine.substring( 0,pos_tag); - //part after repetitive section - String afterlinetoprocess=sLine.substring( pos_tag_end+2); - //repetitive section itself - String linetoprocess =sLine.substring( pos_tag+strlen("$AVAILABLE_AP["),pos_tag_end); - String tablepart; - //get how many items - ipos=KeysList.get_index("$AVAILABLE_AP_NB_ITEMS$"); - if (ipos >-1) { - //get value - nb=atoi(ValuesList.get(ipos)); - ipos=ipos-(nb*4); - } - //do a sanity check data are there - String Last_IP_Key = "$IS_PROTECTED["+String(nb-1)+"]$"; - if (nb>0 && (KeysList.get_index("$ROW_NUMBER[0]$")==ipos) &&(Last_IP_Key==KeysList.get(ipos-1+(nb*4)))) { - for (int j=0; j-1) { - tmppart.replace("$ROW_NUMBER$",ValuesList.get(ipos+0+(j*4))); - tmppart.replace("$AP_SSID$",ValuesList.get(ipos+1+(j*4))); - tmppart.replace("$AP_SIGNAL$",ValuesList.get(ipos+2+(j*4))); - tmppart.replace("$IS_PROTECTED$",ValuesList.get(ipos+3+(j*4))); - } - tablepart +=tmppart; - } - } - //now build back - sLine = beforelinetoprocess + tablepart + afterlinetoprocess; - } - - //add current line to buffer - buffer2send+=sLine; - //if buffer limit is reached - if (buffer2send.length()>1200) { - //if header is not send yet - if (!header_sent) { - //send header with calculated size - header_sent=true; - web_interface->WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->WebServer.sendHeader("Content-Type","text/html",true); - web_interface->WebServer.sendHeader("Cache-Control","no-cache"); - web_interface->WebServer.send(200); - } - //send data - web_interface->WebServer.sendContent(buffer2send); - //reset buffer - buffer2send=""; - } - } - //reset line - sLine=""; - //add a delay for safety for WDT - delay(0); - } - } else { //EOF is reached - //close current file - currentfile.close(); - //if current file is not template file but included one - if (myFileList.size()>0) { - //get level +1 file description and continue - currentfile = myFileList.pop(); - } else { - //we have done template parsing, let's stop reading - bprocessing=false; - } - } - } - } - //check if something is still in buffer and need to be send - if (buffer2send!="") { - //if header is not send yet - if (!header_sent) { - //send header - web_interface->WebServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - web_interface->WebServer.sendHeader("Content-Type","text/html",true); - web_interface->WebServer.sendHeader("Cache-Control","no-cache"); - web_interface->WebServer.send(200); - } - //send data - web_interface->WebServer.sendContent(buffer2send); - } - //close line - web_interface->WebServer.sendContent(""); - LOG("Process template done\r\n") - return true; -} - -// ----------------------------------------------------------------------------- -// Helper for FreeMem and Firmware -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetFreeMem(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList) -{ - //FreeMem - KeysList.add(FPSTR(KEY_FREE_MEM)); - ValuesList.add(CONFIG::intTostr(ESP.getFreeHeap())); - //FW Version - KeysList.add(FPSTR(KEY_FW_VER)); - ValuesList.add(FPSTR(VALUE_FW_VERSION)); -} - -// ----------------------------------------------------------------------------- -// Helper for Login ID -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetLogin(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList,level_authenticate_type auth_level,bool ishtmloutput) -{ - if (ishtmloutput)KeysList.add(FPSTR(KEY_DISCONNECT_VISIBILITY)); -#ifdef AUTHENTICATION_FEATURE - - if (auth_level != LEVEL_GUEST) { - if (ishtmloutput)ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - KeysList.add(FPSTR(KEY_LOGIN_ID)); - if (auth_level == LEVEL_ADMIN) { - ValuesList.add(FPSTR(DEFAULT_ADMIN_LOGIN)); - } else { - ValuesList.add(FPSTR(DEFAULT_USER_LOGIN)); - } - } else -#endif - { - if (ishtmloutput)ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - KeysList.add(FPSTR(KEY_LOGIN_ID)); - ValuesList.add(""); - } -} - -// ----------------------------------------------------------------------------- -// Helper for IP+Web address -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetIpWeb(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList) -{ - String stmp; - - KeysList.add(FPSTR(KEY_IP)); - if (WiFi.getMode() == WIFI_STA ) { - stmp = WiFi.localIP().toString(); - } else { - stmp = WiFi.softAPIP().toString(); - } - ValuesList.add(stmp); - - //Web address = ip + port - KeysList.add(FPSTR(KEY_WEB_ADDRESS)); - if (wifi_config.iweb_port != 80) { - stmp.concat(":"); - stmp.concat(wifi_config.iweb_port); - } - ValuesList.add(stmp); -} -// ----------------------------------------------------------------------------- -// Helper for Wifi Mode -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetMode(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList) -{ - if (WiFi.getMode() == WIFI_STA ) { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_STA)); - } else { - if (WiFi.getMode() == WIFI_AP ) { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_AP)); - } else { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_AP_STA)); - } - } -} -// ----------------------------------------------------------------------------- -// Helper for Web ports -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetPorts(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList, bool ishtmloutput) -{ - //Web port - KeysList.add(FPSTR(KEY_WEB_PORT)); - ValuesList.add(CONFIG::intTostr(wifi_config.iweb_port)); - //Data port - KeysList.add(FPSTR(KEY_DATA_PORT)); - if(ishtmloutput)KeysList.add(FPSTR(KEY_DATA_PORT_VISIBILITY)); -#ifdef TCP_IP_DATA_FEATURE - ValuesList.add(CONFIG::intTostr(wifi_config.idata_port)); - if(ishtmloutput)ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); -#else - ValuesList.add(FPSTR(VALUE_NONE)); - if(ishtmloutput)ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); -#endif -} -// ----------------------------------------------------------------------------- -// Helper for Page properties -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::SetPageProp(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList, - const __FlashStringHelper *title, const __FlashStringHelper *filename) -{ - String fullFilename(filename); - fullFilename.concat(".tpl"); - - //page title - KeysList.add(FPSTR(KEY_PAGE_TITLE)); - ValuesList.add(title); - //tpl file name with extension - KeysList.add(FPSTR(KEY_FILE_NAME)); - ValuesList.add(fullFilename); - //tpl file name without extension - KeysList.add(FPSTR(KEY_SHORT_FILE_NAME)); - ValuesList.add(filename); -} - -// ----------------------------------------------------------------------------- -// Helper for DHCP (APP/STA)tus -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::GetDHCPStatus(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList) -{ - KeysList.add(FPSTR(KEY_AP_DHCP_STATUS)); - if (wifi_softap_dhcps_status() == DHCP_STARTED) { - ValuesList.add(FPSTR(VALUE_STARTED)); - } else { - ValuesList.add(FPSTR(VALUE_STOPPED)); - } - - KeysList.add(FPSTR(KEY_STA_DHCP_STATUS)); - if (wifi_station_dhcpc_status()==DHCP_STARTED) { - ValuesList.add(FPSTR(VALUE_STARTED)); - } else { - ValuesList.add(FPSTR(VALUE_STOPPED)); - } -} - -// ----------------------------------------------------------------------------- -// Helper for Error Msg processing -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::ProcessAlertError(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList, String & smsg, bool ishtmloutput) -{ - KeysList.add(FPSTR(KEY_ERROR_MSG)); - ValuesList.add(smsg); - if (ishtmloutput){ - KeysList.add(FPSTR(KEY_SUCCESS_MSG)); - ValuesList.add(""); - KeysList.add(FPSTR(KEY_ERROR_MSG_VISIBILITY )); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - KeysList.add(FPSTR(KEY_SUCCESS_MSG_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - KeysList.add(FPSTR(KEY_SUBMIT_BUTTON_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - KeysList.add(FPSTR(KEY_SERVICE_PAGE)); - ValuesList.add(""); - } -} - -// ----------------------------------------------------------------------------- -// Helper for Success Msg processing -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::ProcessAlertSuccess(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList, String & smsg, bool ishtmloutput) -{ - KeysList.add(FPSTR(KEY_ERROR_MSG)); - ValuesList.add(""); - if (ishtmloutput){ - KeysList.add(FPSTR(KEY_SUCCESS_MSG)); - ValuesList.add(smsg); - KeysList.add(FPSTR(KEY_ERROR_MSG_VISIBILITY )); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - KeysList.add(FPSTR(KEY_SUCCESS_MSG_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - KeysList.add(FPSTR(KEY_SUBMIT_BUTTON_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } -} - -// ----------------------------------------------------------------------------- -// Helper for No Msg processing -// ----------------------------------------------------------------------------- -void WEBINTERFACE_CLASS::ProcessNoAlert(STORESTRINGS_CLASS & KeysList, STORESTRINGS_CLASS & ValuesList, bool ishtmloutput) -{ - KeysList.add(FPSTR(KEY_ERROR_MSG)); - ValuesList.add(""); - if (ishtmloutput){ - KeysList.add(FPSTR(KEY_SUCCESS_MSG)); - ValuesList.add(""); - KeysList.add(FPSTR(KEY_ERROR_MSG_VISIBILITY )); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - KeysList.add(FPSTR(KEY_SUCCESS_MSG_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - KeysList.add(FPSTR(KEY_SUBMIT_BUTTON_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - KeysList.add(FPSTR(KEY_SERVICE_PAGE)); - ValuesList.add(""); - } -} - -//root insterface void handle_web_interface_root() { - static const char HOME_PAGE [] PROGMEM = "HTTP/1.1 301 OK\r\nLocation: /HOME\r\nCache-Control: no-cache\r\n\r\n"; String path = "/index.html"; String contentType = web_interface->getContentType(path); String pathWithGz = path + ".gz"; //if have a index.html or gzip version this is default root page - if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { - if(SPIFFS.exists(pathWithGz)) { - path = pathWithGz; - } - FSFILE file = SPIFFS.open(path, "r"); - web_interface->WebServer.streamFile(file, contentType); - file.close(); - return; + if((SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) && !web_interface->web_server.hasArg("fallback") && web_interface->web_server.arg("forcefallback")!="yes") { + if(SPIFFS.exists(pathWithGz)) { + path = pathWithGz; } - //if no lets launch the /HOME - web_interface->WebServer.sendContent_P(HOME_PAGE); -} - -//root insterface -void handle_web_interface_home() -{ - String stmp; - //long lstatus; - int istatus; - //byte bbuf; - STORESTRINGS_CLASS KeysList ; - STORESTRINGS_CLASS ValuesList ; - struct softap_config apconfig; - struct ip_info info; - uint8_t mac [WL_MAC_ADDR_LENGTH]; - bool outputjson = false; - if (web_interface->WebServer.hasArg("output")){ - if (web_interface->WebServer.arg("output") == "JSON") - { - outputjson = true; - } - } - LOG("request /HOME\r\n") - //login - web_interface->GetLogin(KeysList, ValuesList,web_interface->is_authenticated(), !outputjson); - - //IP+Web - web_interface->GetIpWeb(KeysList, ValuesList); - - //Hostname - if (WiFi.getMode()==WIFI_STA ) { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_STA)); - KeysList.add(FPSTR(KEY_HOSTNAME)); - ValuesList.add(wifi_config.get_hostname()); - if (!outputjson){ - KeysList.add(FPSTR(KEY_HOSTNAME_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } - } else { - KeysList.add(FPSTR(KEY_HOSTNAME)); - ValuesList.add(FPSTR(KEY_NOT_APPLICABLE_4_AP)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_HOSTNAME_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } - if (WiFi.getMode()==WIFI_AP ) { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_AP)); - } else { - KeysList.add(FPSTR(KEY_MODE)); - ValuesList.add(FPSTR(VALUE_AP_STA)); - } - } - if (!outputjson){ - //page title and filenames - web_interface->SetPageProp(KeysList,ValuesList,FPSTR(VALUE_HOME),F("home")); - //menu item - KeysList.add(FPSTR(KEY_MENU_HOME)); - ValuesList.add(FPSTR(VALUE_ACTIVE)); - } - //Chip ID - KeysList.add(FPSTR(KEY_CHIP_ID)); - ValuesList.add(CONFIG::intTostr(system_get_chip_id())); - //CPU Freq - KeysList.add(FPSTR(KEY_CPU_FREQ)); - ValuesList.add(CONFIG::intTostr(system_get_cpu_freq())); - //SDK Version - KeysList.add(FPSTR(KEY_SDK_VER)); - ValuesList.add(system_get_sdk_version()); - - //MDNS Feature -#ifdef MDNS_FEATURE - KeysList.add(FPSTR(KEY_MDNS_NAME)); - stmp="http://"; - stmp+=wifi_config.get_hostname(); - stmp+=".local"; - ValuesList.add(stmp); - if (!outputjson){ - KeysList.add(FPSTR(KEY_MDNS_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } -#else - if (!outputjson){ - KeysList.add(FPSTR(KEY_MDNS_NAME)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - KeysList.add(FPSTR(KEY_MDNS_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } -#endif - - //SSDP Feature -#ifdef SSDP_FEATURE - KeysList.add(FPSTR(KEY_SSDP_STATUS)); - ValuesList.add(FPSTR(VALUE_ENABLED)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_SSDP_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } -#else - KeysList.add(FPSTR(KEY_SSDP_STATUS)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_SSDP_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } -#endif - - //Captive portal Feature -#ifdef CAPTIVE_PORTAL_FEATURE - if (WiFi.getMode()==WIFI_AP) { - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_STATUS)); - ValuesList.add(FPSTR(VALUE_ENABLED)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } - } else { - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_STATUS)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } - } -#else - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_STATUS)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - if (!outputjson){ - KeysList.add(FPSTR(KEY_CAPTIVE_PORTAL_VISIBLE)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } -#endif - - //network - KeysList.add(FPSTR(KEY_NET_PHY)); - if (WiFi.getPhyMode()==WIFI_PHY_MODE_11B) { - ValuesList.add(FPSTR(VALUE_11B)); - } else if (WiFi.getPhyMode()==WIFI_PHY_MODE_11G) { - ValuesList.add(FPSTR(VALUE_11G)); - } else { - ValuesList.add(FPSTR(VALUE_11N)); - } - //sleep mode - KeysList.add(FPSTR(KEY_SLEEP_MODE)); - if (WiFi.getSleepMode()==WIFI_NONE_SLEEP) { - ValuesList.add(FPSTR(VALUE_NONE)); - } else if (WiFi.getSleepMode()==WIFI_LIGHT_SLEEP) { - ValuesList.add(FPSTR(VALUE_LIGHT)); - } else { - ValuesList.add(FPSTR(VALUE_MODEM)); - } - //Boot version - KeysList.add(FPSTR(KEY_BOOT_VER)); - ValuesList.add(CONFIG::intTostr(system_get_boot_version())); - //Baud rate - KeysList.add(FPSTR(KEY_BAUD_RATE)); - ValuesList.add(CONFIG::intTostr(wifi_config.baud_rate)); - // Web and Data ports - web_interface->GetPorts(KeysList, ValuesList, !outputjson); - - //AP part - if (WiFi.getMode()==WIFI_AP || WiFi.getMode()==WIFI_AP_STA) { - int client_counter=0; - struct station_info * station; - //AP is enabled - KeysList.add(FPSTR(KEY_AP_STATUS_ENABLED)); - ValuesList.add(FPSTR(VALUE_ENABLED)); - //set visible - if (!outputjson){ - KeysList.add(FPSTR(KEY_AP_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } - //list of connected clients - station = wifi_softap_get_station_info(); - while(station) { - //Row number - stmp = "$ROW_NUMBER["+String(client_counter)+"]$"; - KeysList.add(stmp.c_str()); - stmp=String(client_counter+1); - ValuesList.add(stmp); - //BSSID - stmp = "$MAC_CONNECTED["+String(client_counter)+"]$"; - KeysList.add(stmp.c_str()); - ValuesList.add(CONFIG::mac2str(station->bssid)); - //IP - stmp = "$IP_CONNECTED["+String(client_counter)+"]$"; - KeysList.add(stmp.c_str()); - ValuesList.add(IPAddress((const uint8_t *)&station->ip).toString().c_str()); - //increment counter - client_counter++; - //go next record - //removed due to queue.h removed - //station = STAILQ_NEXT(station, next); - station = station->next; - } - wifi_softap_free_station_info(); - //Connected clients - KeysList.add(FPSTR(KEY_CONNECTED_STATIONS_NB_ITEMS)); - ValuesList.add(CONFIG::intTostr(client_counter)); - } else { - //AP is disabled - KeysList.add(FPSTR(KEY_AP_STATUS_ENABLED)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - if (!outputjson){ - //set hide - KeysList.add(FPSTR(KEY_AP_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } - //Connected clients - KeysList.add(FPSTR(KEY_CONNECTED_STATIONS_NB_ITEMS)); - ValuesList.add("0"); - } - //AP mac address - KeysList.add(FPSTR(KEY_AP_MAC)); - ValuesList.add(CONFIG::mac2str(WiFi.softAPmacAddress(mac))); - //AP configuration - if (wifi_softap_get_config(&apconfig)) { - //SSID - KeysList.add(FPSTR(KEY_AP_SSID)); - ValuesList.add((char *)(apconfig.ssid)); - //AP visible or hidden - KeysList.add(FPSTR(KEY_AP_IS_VISIBLE)); - if(apconfig.ssid_hidden==1) { - ValuesList.add(FPSTR(VALUE_NO)); - } else { - ValuesList.add(FPSTR(VALUE_YES)); - } - //Channel - KeysList.add(FPSTR(KEY_AP_CHANNEL)); - ValuesList.add(CONFIG::intTostr(apconfig.channel)); - //Authentification mode - KeysList.add(FPSTR(KEY_AP_AUTH)); - if (apconfig.authmode==AUTH_OPEN) { - ValuesList.add(FPSTR(VALUE_NONE)); - } else if (apconfig.authmode==AUTH_WEP) { - ValuesList.add(FPSTR(VALUE_WEP)); - } else if (apconfig.authmode==AUTH_WPA_PSK) { - ValuesList.add(FPSTR(VALUE_WPA)); - } else if (apconfig.authmode==AUTH_WPA2_PSK) { - ValuesList.add(FPSTR(VALUE_WPA2)); - } else { - ValuesList.add(FPSTR(VALUE_WPAWPA2)); - } - - //Max connections - KeysList.add(FPSTR(KEY_AP_MAX_CON)); - ValuesList.add(CONFIG::intTostr(apconfig.max_connection)); - } else { - //SSID - KeysList.add(FPSTR(KEY_AP_SSID)); - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - //AP visible or hidden - KeysList.add(FPSTR(KEY_AP_IS_VISIBLE)); - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - //Channel - KeysList.add(FPSTR(KEY_AP_CHANNEL)); - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - //Authentification mode - KeysList.add(FPSTR(KEY_AP_AUTH)); - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - //Max connections - KeysList.add(FPSTR(KEY_AP_MAX_CON)); - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - } - //DHCP Status - web_interface->GetDHCPStatus(KeysList, ValuesList); - //IP/GW/MASK - if (wifi_get_ip_info(SOFTAP_IF,&info)) { - //IP address - KeysList.add(FPSTR(KEY_AP_IP)); - ValuesList.add(IPAddress((const uint8_t *)&(info.ip.addr)).toString().c_str()); - //GW address - KeysList.add(FPSTR(KEY_AP_GW)); - ValuesList.add(IPAddress((const uint8_t *)&(info.gw.addr)).toString().c_str()); - //Sub Net Mask - KeysList.add(FPSTR(KEY_AP_SUBNET)); - ValuesList.add(IPAddress((const uint8_t *)&(info.netmask.addr)).toString().c_str()); - } else { - //IP address - KeysList.add(FPSTR(KEY_AP_IP)); - ValuesList.add(FPSTR(VALUE_NO_IP)); - //GW address - KeysList.add(FPSTR(KEY_AP_GW)); - ValuesList.add(FPSTR(VALUE_NO_IP)); - //Sub Net Mask - KeysList.add(FPSTR(KEY_AP_SUBNET)); - ValuesList.add(FPSTR(VALUE_NO_IP)); - } - //STA part - if (WiFi.getMode()==WIFI_STA || WiFi.getMode()==WIFI_AP_STA) { - //STA is enabled - KeysList.add(FPSTR(KEY_STA_STATUS_ENABLED)); - ValuesList.add(FPSTR(VALUE_ENABLED)); - if (!outputjson){ - //set visible - KeysList.add(FPSTR(KEY_STA_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_VISIBLE)); - } - } else { - //STA is disabled - KeysList.add(FPSTR(KEY_STA_STATUS_ENABLED)); - ValuesList.add(FPSTR(VALUE_DISABLED)); - if (!outputjson){ - //set hide - KeysList.add(FPSTR(KEY_STA_VISIBILITY)); - ValuesList.add(FPSTR(VALUE_ITEM_HIDDEN)); - } - } - //STA mac address - KeysList.add(FPSTR(KEY_STA_MAC)); - ValuesList.add(CONFIG::mac2str(WiFi.macAddress(mac))); - //SSID used by STA - KeysList.add(FPSTR(KEY_STA_SSID)); - if (WiFi.SSID().length()==0) { - ValuesList.add(FPSTR(VALUE_NOT_AVAILABLE)); - } else { - ValuesList.add(WiFi.SSID().c_str()); - } - //Channel - KeysList.add(FPSTR(KEY_STA_CHANNEL)); - ValuesList.add(CONFIG::intTostr (wifi_get_channel())); - //Connection status - istatus = wifi_station_get_connect_status(); - KeysList.add(FPSTR(KEY_STA_STATUS)); - if (istatus==STATION_GOT_IP) { - ValuesList.add(FPSTR(VALUE_CONNECTED)); - } else if (istatus==STATION_NO_AP_FOUND) { - ValuesList.add(FPSTR(VALUE_NO_SSID)); - } else if (istatus==STATION_CONNECT_FAIL) { - ValuesList.add(FPSTR(VALUE_CONNECTION_FAILED)); - } else if (istatus==STATION_WRONG_PASSWORD) { - ValuesList.add(FPSTR(VALUE_CONNECTION_FAILED2)); - } else if (istatus==STATION_IDLE) { - ValuesList.add(FPSTR(VALUE_IDLE)); //should not happen - } else { - ValuesList.add(FPSTR(VALUE_DISCONNECTED)); - } - //Signal strength - KeysList.add(FPSTR(KEY_STA_SIGNAL)); - ValuesList.add(CONFIG::intTostr(wifi_config.getSignal(WiFi.RSSI()))); - //DHCP Client status - web_interface->GetDHCPStatus(KeysList, ValuesList); - //IP address - KeysList.add(FPSTR(KEY_STA_IP)); - ValuesList.add(WiFi.localIP().toString().c_str()); - //GW address - KeysList.add(FPSTR(KEY_STA_GW)); - ValuesList.add(WiFi.gatewayIP().toString().c_str()); - //Sub Net Mask - KeysList.add(FPSTR(KEY_STA_SUBNET)); - ValuesList.add(WiFi.subnetMask().toString().c_str()); - if (!outputjson){ - //Service page / no need refresh on this page - KeysList.add(FPSTR(KEY_SERVICE_PAGE)); - ValuesList.add(""); - } - //Firmware & Free Mem, at the end to reflect situation - web_interface->GetFreeMem(KeysList, ValuesList); - //check if need template or do a JSON - if (outputjson){ - web_interface->generateJSON(KeysList , ValuesList); - }//process the template file and provide list of variables - else web_interface->processTemplate("/home.tpl", KeysList , ValuesList); - //need to clean to speed up memory recovery - KeysList.clear(); - ValuesList.clear(); - LOG("request /HOME done\r\n") -} - -void handle_web_interface_configSys() -{ - static const char NOT_AUTH_CS [] PROGMEM = "HTTP/1.1 301 OK\r\nLocation: /LOGIN?return=CONFIGSYS\r\nCache-Control: no-cache\r\n\r\n"; - - String stmp,smsg; - //long lstatus; - int istatus; - //byte bbuf; - long ibaud=DEFAULT_BAUD_RATE; - int iweb_port =DEFAULT_WEB_PORT; - int idata_port =DEFAULT_DATA_PORT; - byte bsleepmode=DEFAULT_SLEEP_MODE; - bool msg_alert_error=false; - bool msg_alert_success=false; - long lbaudlist[] = {9600 ,19200,38400,57600,115200,230400,250000,-1}; - int bmodemvaluelist[] = {WIFI_NONE_SLEEP,WIFI_LIGHT_SLEEP,WIFI_MODEM_SLEEP, -1}; - const __FlashStringHelper *smodemdisplaylist[]= {FPSTR(VALUE_NONE),FPSTR(VALUE_LIGHT),FPSTR(VALUE_MODEM),FPSTR(VALUE_MODEM)}; - STORESTRINGS_CLASS KeysList ; - STORESTRINGS_CLASS ValuesList ; - bool outputjson = false; - if (web_interface->WebServer.hasArg("output")){ - if (web_interface->WebServer.arg("output") == "JSON") - { - outputjson = true; - } - } - level_authenticate_type auth_level= web_interface->is_authenticated(); - if (auth_level != LEVEL_ADMIN) { - web_interface->WebServer.sendContent_P(NOT_AUTH_CS); + FS_FILE file = SPIFFS.open(path, SPIFFS_FILE_READ); + web_interface->web_server.streamFile(file, contentType); + file.close(); return; } - //login - web_interface->GetLogin(KeysList, ValuesList,auth_level, !outputjson); - //IP+Web - web_interface->GetIpWeb(KeysList, ValuesList); - //mode - web_interface->GetMode(KeysList, ValuesList); - if (!outputjson){ - //page title and filenames - web_interface->SetPageProp(KeysList,ValuesList,FPSTR(VALUE_HOME),F("system")); - //menu item - KeysList.add(FPSTR(KEY_MENU_SYSTEM)); - ValuesList.add(FPSTR(VALUE_ACTIVE)); - } - //check is it is a submission or a display - if (web_interface->WebServer.hasArg("SUBMIT")) { - //is there a correct list of values? - if (web_interface->WebServer.hasArg("BAUD_RATE") - && web_interface->WebServer.hasArg("SLEEP_MODE") -#ifdef TCP_IP_DATA_FEATURE - && web_interface->WebServer.hasArg("DATAPORT") -#endif - && web_interface->WebServer.hasArg("WEBPORT")) { - //is each value correct ? - ibaud = web_interface->WebServer.arg("BAUD_RATE").toInt(); - iweb_port = web_interface->WebServer.arg("WEBPORT").toInt(); -#ifdef TCP_IP_DATA_FEATURE - idata_port = web_interface->WebServer.arg("DATAPORT").toInt(); -#endif - bsleepmode = web_interface->WebServer.arg("SLEEP_MODE").toInt(); - - if (!(iweb_port>0 && iweb_port<65001)) { - msg_alert_error=true; - smsg.concat(F("Error: invalid port value for web port
")); - KeysList.add(FPSTR(KEY_WEB_PORT_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - } -#ifdef TCP_IP_DATA_FEATURE - if (!(idata_port>0 && idata_port<65001)) { - msg_alert_error=true; - smsg.concat("Error: invalid port value for data port
"); - KeysList.add(FPSTR(KEY_DATA_PORT_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - } -#endif - if (iweb_port== idata_port) { - msg_alert_error=true; - smsg.concat("Error: web port and data port cannot be identical
"); - KeysList.add(FPSTR(KEY_WEB_PORT_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - KeysList.add(FPSTR(KEY_DATA_PORT_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - } - if (!(ibaud==9600 || ibaud==19200|| ibaud==38400|| ibaud==57600|| ibaud==115200|| ibaud==230400 || ibaud==250000)) { - msg_alert_error=true; - smsg.concat(F("Error: value for baud rate is not correct
")); - KeysList.add(FPSTR(KEY_BAUD_RATE_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - } - if (!(bsleepmode==WIFI_NONE_SLEEP ||bsleepmode==WIFI_LIGHT_SLEEP ||bsleepmode==WIFI_MODEM_SLEEP )) { - msg_alert_error=true; - smsg.concat(F("Error: value for sleeping mode is not correct
")); - KeysList.add(FPSTR(KEY_SLEEP_MODE_STATUS)); - ValuesList.add(FPSTR(VALUE_HAS_ERROR)); - } - } else { - msg_alert_error=true; - smsg = FPSTR(MISSING_DATA); - } - //if no error apply the changes - if (msg_alert_error!=true) { - if(!CONFIG::write_buffer(EP_BAUD_RATE,(const byte *)&ibaud,INTEGER_LENGTH) - ||!CONFIG::write_buffer(EP_WEB_PORT,(const byte *)&iweb_port,INTEGER_LENGTH) -#ifdef TCP_IP_DATA_FEATURE - ||!CONFIG::write_buffer(EP_DATA_PORT,(const byte *)&idata_port,INTEGER_LENGTH) -#endif - ||!CONFIG::write_byte(EP_SLEEP_MODE,bsleepmode)) { - msg_alert_error=true; - smsg = FPSTR(EEPROM_NOWRITE); - } else { - msg_alert_success=true; -#ifdef TCP_IP_DATA_FEATURE - wifi_config.iweb_port=iweb_port; -#endif - wifi_config.idata_port=idata_port; - smsg = F("Changes saved to EEPROM, restarting...."); - } - } - } else { //no submit need to get data from EEPROM - if (!CONFIG::read_buffer(EP_BAUD_RATE, (byte *)&ibaud , INTEGER_LENGTH)) { - ibaud=DEFAULT_BAUD_RATE; - } - if (!CONFIG::read_byte(EP_SLEEP_MODE, &bsleepmode )) { - bsleepmode=DEFAULT_SLEEP_MODE; - } - if (!CONFIG::read_buffer(EP_WEB_PORT, (byte *)&iweb_port , INTEGER_LENGTH)) { - iweb_port=DEFAULT_WEB_PORT; - } - wifi_config.iweb_port=iweb_port; - if (!CONFIG::read_buffer(EP_DATA_PORT, (byte *)&idata_port , INTEGER_LENGTH)) { - idata_port=DEFAULT_DATA_PORT; - } - wifi_config.idata_port=idata_port; - }; - //Baud rate list - istatus = 0; - stmp=""; - if (!outputjson){ - while (lbaudlist[istatus]>-1) { - - stmp+="