From 817296e4f9ed3db6bba009d34de639c3136f5c4b Mon Sep 17 00:00:00 2001 From: jmgiacalone Date: Sun, 11 Feb 2024 21:51:59 +0000 Subject: [PATCH] Initial commit --- .gitignore | 5 + .vscode/extensions.json | 10 + data/css/style.css | 9 + data/eMAKER.png | Bin 0 -> 5064 bytes data/edit.htm | 629 ++++++++++++++++++++++++++++++++++++++++ data/emaker.ico | Bin 0 -> 370070 bytes data/index.htm | 36 +++ data/js/scripts.js | 84 ++++++ data/network.htm | 77 +++++ data/settings.json | 1 + data/wifimanager.html | 32 ++ include/README | 39 +++ include/SPIFFSEditor.h | 24 ++ lib/README | 46 +++ partitions.csv | 6 + platformio.ini | 34 +++ src/SPIFFSEditor.cpp | 554 +++++++++++++++++++++++++++++++++++ src/main.cpp | 432 +++++++++++++++++++++++++++ test/README | 11 + 19 files changed, 2029 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 data/css/style.css create mode 100644 data/eMAKER.png create mode 100644 data/edit.htm create mode 100644 data/emaker.ico create mode 100644 data/index.htm create mode 100644 data/js/scripts.js create mode 100644 data/network.htm create mode 100644 data/settings.json create mode 100644 data/wifimanager.html create mode 100644 include/README create mode 100644 include/SPIFFSEditor.h create mode 100644 lib/README create mode 100644 partitions.csv create mode 100644 platformio.ini create mode 100644 src/SPIFFSEditor.cpp create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/data/css/style.css b/data/css/style.css new file mode 100644 index 0000000..5c2146f --- /dev/null +++ b/data/css/style.css @@ -0,0 +1,9 @@ +#header { + padding-top:20px; +} +.logo img { + width:200px; +} +input[type=number] { + width:200px; +} \ No newline at end of file diff --git a/data/eMAKER.png b/data/eMAKER.png new file mode 100644 index 0000000000000000000000000000000000000000..c3a1240c2a69ac76ab74c46071494a073363ff68 GIT binary patch literal 5064 zcmV;(6F2OMP) zK~#9!?VWp^Tt$_~zdd;)2_mA)YKDg>=qk^VRe1=V3MinskQxwOA0(;x2nHCGNetO_ zg%BRCA`g=?2!gm_Dujn1LMkIZBANsdWLJExFu-S5NO*;Wgv?CuA9Z`ubZ&RgWcqgB znK|FjXFk)P?)$2`b$@m0)Twhb)R09T>u7InVNu7r46r}&L!gD>#b)42U_pCpOLucy zCtbNLf*=UBCR2-pT-vdgJeh(x?+Ua5Uj@btv-k+p8r+go50OL_o9wJfFbUY)*11O>EO4qc8$l3KCD03RSxZxg313$v{Dz zCllN+`%9A%1R*s7T_VgA7j>-r9B^3;uVGY*>SHUgsJ*r2LV$h0+}YIA%Zb44DZ5TV z5JtK{m-w2G1uh0YFih)WJussvgl-`haD+4wK@d_Q&mzaA zj}TUOfHVg|5K<@5nS5qaepG$|pn%oGxU9cvZ*7@V_@cS3^AzAaz+Tc61VKopKoeH< zEd;(kjLVv7Z*6%2;IIpS#`?`YR}$PWMAc#PxlU{)4woa)DK@dcs8_Y|Dtaq=WE0>j;5d=X5x`F%! z_#)v&1A-t34MipixAR-zIKr#0@=_gwAPg6Q-V(V6GAS+Ri&cKVrz@8|5kj^*X%>PY z3@3qJ37iW|NNG7YR{8x`(i8+i7_I{Sym$7mX)dVJ2JdXr^&kj>P%~;ZNtj7{K`V%} zAPB;+7HB~b1VIE^5ClO4S`Y+55P=p1K@dcs1wjx-m_VogEh9=Bx!Zyu3@K_A|9i61 zW=)DM@?Uso&z0LP2*OAd=slvpwDPRnYC#Z&8Y9IA-6OYJ5CjouVc1g-e|~??k>qvs z_xwrMMWf4D%9Lrdq)pfH{E~x0DA!ot0sLdhPkG=W@9axea+?eq?<`82F~H%#_>!MD zM%U4s@cG9AN0%9aZS>AQnDo7fu47N&J;YDOKLb2A(7GtTe@dIf2x)dJF$(ydcS|<( z_Z-b_onwJRfL-d`gfqY^z}l`{wr2qKoB@uYK1tttqicM|JNra*elmGjx!j6C3sw07 za8`*ZXRYf>FlRK70*3!(?9l)o!&PVvq@R)>3W z6!62C@-_i3x>s9wqI@WA76CJ=Xu<1%`M@s+c-?ORt^y9EzB$&LfWJlcwsC;_E&=wb z!!_oCZNSS)o2P**y|c@eHks_{Cf|9B6@eBiG69$v^Sx2ptOAzP+l0S$aqY#i!=kj= z2lxiCd(39Ll2C%Kf_N!y-UM6}eLXg2)7^j>N}CISo`jQejfqAP<70l?rT=A{g?CE| z<=Yil6vz)?z@Z;~MWw3$@!oz++zZvMZGHuOh2SD8$0NW28Mw|nyLAYQ^VlIO6MHLdb}3eDp>7sT zexlN5f8a>qfM^ImhT8d4dx6cs)4*Eb_ez_`y|ej*9<-@SoAbT1R}AL(MXrs*fq9K+ zmqpib6!77gO}eAHjq|5oskFJwEv{~bw{rS#_bdfMl0KP|qR-_h%S$(I>CQBkwxh&?le*oIpKB<@jt9c1Zo2Ez% z=2AIy?2o`)@9b@*E|CPuL}E0Qc-cF%prsyzNJjPj5rs^E{!~S)Y#kV zEY1LL0_I1SX;O?Q_@npO8Gm$<5ZnnI)F^8+;$q@MtX>4pBlvC~kNLfc5Z&_DG%R?C z#CbR1C&0f~5$8LB57t?nhbpzw%U6Ks`maKvuCB+f^D6N@Az&bFX1x{I`12S zBa}7|*5JX*15W{yOTM27+^@7b)H~a~6QVL7P$gf#3an?x#WFQz%61EWAK?5lo3(jo zUj_c6w7Cs9haKHglYuXIXXiCSk<)hP7|Y3cAVtsZrq$f zJ?KTQjbjK4 zLP~j(5T~1{NxI5erfQSP2TOBI%q9;5w-*WECBSEa*T-x-S84No@9ZDzEz(6RFJ}We zD$i^D5;(^@`=HV@fu_C?JYjeWbn5Xdu4&}y_bT)KL%>JN2*W_x7FnTpBzT|mzzX10 z;=|z127cz9y|t1+ouH?4@Ai1->v`?OTRsw(xxlgYxH)+^3^*;WTL-@Do!tPSrWw4m z&nj*HgRqDuj%C21b+$yiqq;o$K2#x+Q4mh;At#crYkuty* z;P?H_v5_Wb@^)n18%9vqnwSmrU_*U40dYj0v z>PS=&E3F88nlSNst9N$WFp1FENPQD86&qt$DQ&jxC%V042$O<) z$839>clHW(hQTkhNnbZgoBe=Km)XPuPlV9Siq~=jAp+%HF~3dBIEF+}n zEah3k0*_bfAsUgWzM1&gYk=k6*+6SDu^ zQRR6)1o*Mi=4$Wk`6;lX*GKK)j{~$|3vVJBZrlxg$~*f)@pDisfgVrDN03%tKZt!_ z6X~-0oFK|WOq>(xIEx}OAWTNRkNAZ$?~ndU=>aYe3nuDn(Op}i?ax%&%&g(4@lfCl z;O2zNmo0L+Cl`jIrMHgr)TFqkK4R zFYp*)6>fpglc~|ZTy|Ys)w6D(s-zI(@sEM$UY=L+7H~lesVy#1A2d)P`p5XBx0zN{> ze_V^dk448T{`)W?6I)^t9{0JWg~s&&Azf&H%YIh9EV!bKdASC(qr)PLHL-b`s1CP8 z0(}%=seC0S151@Q%at}0eM<9LrwOIa#2vqzh0@dU&R!3+0xy->{a|2~(&j4z7=4Ka zUB(^I3tZBb%g#&qT-yejzA#lxIc)~s*{hW{AEf-^4+!zjXB1+jlNRTq4qyf$FG(Z# zw$kQ?q?TBh#A^RqX>$-^>GyFJ46!kUCGPK4+MEy#!^N5&P`xiHZe#Z-Z8RaODK3NN z>wrt6^#il}6Pqp;^p5lZr+4MD^P1Z{&261hBmHF5m_8TWnS>eo*r6gJi`t*+X|XA7 z_9UzftVftuzQTwsQSmDr+dKP$cUBP+TfIjFKR(DmO<06eZcgDOrOokm>W~V;aUsFg^+-Qkd5aYnN7WXS+3u#Tu`u@x z(9#;xmPGV_jnd{aU{R4^J?@=7v!27~=%Lx2kR~*awcgoFPX6?4UfnXd@Y?%sS&Y)= zF2X9xxD1BlfiEd-Rs)-owxo-4JpWQ@^8rHci<7JDdJOOD;@anFPZbfm`sPhO#tI)1sgCmgJ_ zxhdh1%xFUR)s5cSx}Zqf2RXFmOL1KTEle#6=69EbwX)anM7R9>U^^8Sa0SBcnY^%=Do$n=SUvJ{GQN z@u1In?+Oc$k3#CcMEO^ET?4$WUK4S}K4tH0PHFRV!phGhs_Z(Q@HU?L-q}0rIr6EY z8>L|*$*8WLi#ocSh<_PzfvbQcl{RNbdVzO#MEjs$0S@oVWtVp4vb{-(vuf>g{@>of zvUWGHfo}HBUhAD*UC&o4MdzOgoLgpuvOW^ZBqAy{M8_^SV%bk=b5TL?>Qx^_?x(ec zP`s=9vFm$)WlEc?ls1`Aud`&#J+NnB17Uu`SJ~wZLMYx_3j2-}fzFils*eKucIC1U zCmp3xlx*kXNEAj?18oFTruB*5aX`7n1-E-=A5F0A7WhkrP39_X_H9JOL}WB<^Ui*W zFu7Un1*Q`S`8-xBZJLWi%Y=T5^d|4@RD!#)5(feQt+YAJJIiQ7%-(QkUD4;KfaAMz z*}vB-pGI_p9*So0&jbzt_9eVcWEW}1wPn?E%amzm3?V8Zj+aSr!Ag-E;FE+zP;oQ? z7b|W4HNiX`)r + + + +ESP Editor... + + + + + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/data/emaker.ico b/data/emaker.ico new file mode 100644 index 0000000000000000000000000000000000000000..a09ebac6085fba3159ef64ff0664fc63d235ce5a GIT binary patch literal 370070 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 + + + eMAKER Printer Climate Control + + + + + + + + + +
+ + + +
+
+
+ WiFi +
+ +
+
+
+ + + diff --git a/data/js/scripts.js b/data/js/scripts.js new file mode 100644 index 0000000..b1b00ed --- /dev/null +++ b/data/js/scripts.js @@ -0,0 +1,84 @@ +var _elapsedTime = 0; + + function getParams() { + const url = '/paraams'; + fetch(url) + .then((respone)=>{ + return respone.json(); + }) + .then((data)=>{ + document.getElementById('Iim').value = data.Iim || -1; + document.getElementById('Imp').value = data.Imp || -1; + document.getElementById('Tu').value = data.Tu || -1; + document.getElementById('Tl').value = data.Tl || -1; + M.updateTextFields(); + }) + } + +function setParams() { + + const data = new URLSearchParams(); + + data.append('Iim',document.getElementById('Iim').value); + data.append('Imp',document.getElementById('Imp').value); + data.append('Tu',document.getElementById('Tu').value); + data.append('Tl',document.getElementById('Tl').value); + + fetch('/params', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: data + }) + } + +function joinNetwork() { + + const data = new URLSearchParams(); + + data.append('ssid', document.getElementById("ssid").value); + data.append('pass', document.getElementById("pass").value); + data.append('gateway', document.getElementById("gateway").value); + data.append('ip', document.getElementById("ip").value); + + fetch('/setWiFi', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: data + }) +} + +async function scanNetworks() { + let raw = await fetch("/scanNetworks"); + let data = await raw.json(); + var listHTML = ""; + data.forEach((network)=>{ + listHTML += ''+network.ssid+''+network.channel+''+network.rssi+''; + }); + document.getElementById("networks").innerHTML = listHTML; +} + +setInterval(function () { + aja() + .url('/sensors') + .on('success', function (data) { + document.getElementById("tempinfo").value = data.temperature || -1; + document.getElementById("humidityinfo").value = data.humidity || -1; + document.getElementById("pressureinfo").value = data.pressure || -1; + //document.getElementById("targetinfo").value = data.target.toFixed(2) || -1; + _run = data.runProfile || 0; + _elapsedTime = data.elapsedTime || 0; + M.updateTextFields(); + }) + .go(); +}, 4000); + +document.addEventListener('DOMContentLoaded', function() { + M.AutoInit(); + getParams(); + // var elems = document.querySelectorAll('.tooltipped'); +// var instances = M.Tooltip.init(elems, ttOptions); +}); diff --git a/data/network.htm b/data/network.htm new file mode 100644 index 0000000..d2b9352 --- /dev/null +++ b/data/network.htm @@ -0,0 +1,77 @@ + + + + Network + + + + + + + + + + + + +
+ + + +
+
+
+
+
+
+
+ Network +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ Submit +
+
+
+
+
+
+
+ Networks + +
+
+ Scan +
+
+
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/data/settings.json b/data/settings.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/data/settings.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/data/wifimanager.html b/data/wifimanager.html new file mode 100644 index 0000000..d22f4dd --- /dev/null +++ b/data/wifimanager.html @@ -0,0 +1,32 @@ + + + + ESP Wi-Fi Manager + + + + + +
+

ESP Wi-Fi Manager

+
+
+
+
+

+ +
+ +
+ +
+ +
+

+
+
+ + + \ No newline at end of file diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/include/SPIFFSEditor.h b/include/SPIFFSEditor.h new file mode 100644 index 0000000..3586429 --- /dev/null +++ b/include/SPIFFSEditor.h @@ -0,0 +1,24 @@ +#ifndef SPIFFSEditor_H_ +#define SPIFFSEditor_H_ +#include + +class SPIFFSEditor: public AsyncWebHandler { + private: + fs::FS _fs; + String _username; + String _password; + bool _authenticated; + uint32_t _startTime; + public: +#ifdef ESP32 + SPIFFSEditor(const fs::FS& fs, const String& username=String(), const String& password=String()); +#else + SPIFFSEditor(const String& username=String(), const String& password=String(), const fs::FS& fs=SPIFFS); +#endif + virtual bool canHandle(AsyncWebServerRequest *request) override final; + virtual void handleRequest(AsyncWebServerRequest *request) override final; + virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final; + virtual bool isRequestHandlerTrivial() override final {return false;} +}; + +#endif diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..51480d7 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 36K, 20K, +otadata, data, ota, 56K, 8K, +app0, app, ota_0, 64K, 1M, +app1, app, ota_1, , 1M, +spiffs, data, spiffs, , 1800K, \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..9dc7afd --- /dev/null +++ b/platformio.ini @@ -0,0 +1,34 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env] +platform = espressif32 +framework = arduino +lib_deps = + https://github.com/me-no-dev/ESPAsyncWebServer.git + me-no-dev/AsyncTCP@^1.1.1 + ayushsharma82/AsyncElegantOTA@^2.2.7 + arduino-libraries/Arduino_JSON@^0.1.0 +build_flags = + '-D ELEGANTOTA_USE_ASYNC_WEBSERVER=1' +monitor_speed = 115200 + +[env:esp32cam] +board = esp32cam + +[env:lolin32] +board = lolin32 + +[env:odyssey] +board = seeed_xiao_esp32s3 +platform_packages = toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 +build_flags = + '-D ARDUINO_USB_CDC_ON_BOOT=1' + '-D ARDUINO_USB_MODE=0' diff --git a/src/SPIFFSEditor.cpp b/src/SPIFFSEditor.cpp new file mode 100644 index 0000000..1b115d2 --- /dev/null +++ b/src/SPIFFSEditor.cpp @@ -0,0 +1,554 @@ +#include "SPIFFSEditor.h" +#include + +//File: edit.htm.gz, Size: 4151 +// #define edit_htm_gz_len 4151 +// const uint8_t edit_htm_gz[] PROGMEM = { +// 0x1F, 0x8B, 0x08, 0x08, 0xB8, 0x94, 0xB1, 0x59, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68, +// 0x74, 0x6D, 0x00, 0xB5, 0x3A, 0x0B, 0x7B, 0xDA, 0xB8, 0xB2, 0x7F, 0xC5, 0x71, 0xCF, 0x66, 0xED, +// 0x83, 0x31, 0x90, 0xA4, 0xD9, 0xD6, 0xC4, 0xC9, 0x42, 0x92, 0x36, 0x6D, 0xF3, 0x6A, 0x80, 0xB6, +// 0x69, 0x4F, 0xEE, 0x7E, 0xC2, 0x16, 0xA0, 0xC6, 0x96, 0x5D, 0x5B, 0x0E, 0x49, 0x59, 0xFE, 0xFB, +// 0x9D, 0x91, 0x6C, 0xB0, 0x09, 0x69, 0x77, 0xCF, 0xBD, 0xBB, 0xDD, 0x2D, 0x92, 0x46, 0x33, 0x9A, +// 0x19, 0xCD, 0x53, 0xDE, 0xBD, 0x8D, 0xA3, 0x8B, 0xC3, 0xFE, 0xF5, 0xE5, 0xB1, 0x36, 0x11, 0x61, +// 0xB0, 0xBF, 0x87, 0x7F, 0x6B, 0x01, 0xE1, 0x63, 0x97, 0xF2, 0xFD, 0x3D, 0xC1, 0x44, 0x40, 0xF7, +// 0x8F, 0x7B, 0x97, 0xDA, 0xB1, 0xCF, 0x44, 0x94, 0xEC, 0x35, 0xD4, 0xCA, 0x5E, 0x2A, 0x1E, 0x02, +// 0xAA, 0x85, 0xD4, 0x67, 0xC4, 0x4D, 0xBD, 0x84, 0xC2, 0x66, 0xDB, 0x0B, 0x67, 0xDF, 0xEB, 0x8C, +// 0xFB, 0xF4, 0xDE, 0xD9, 0x6E, 0x36, 0xDB, 0x71, 0x94, 0x32, 0xC1, 0x22, 0xEE, 0x90, 0x61, 0x1A, +// 0x05, 0x99, 0xA0, 0xED, 0x80, 0x8E, 0x84, 0xF3, 0x3C, 0xBE, 0x6F, 0x0F, 0xA3, 0xC4, 0xA7, 0x89, +// 0xD3, 0x8A, 0xEF, 0x35, 0x00, 0x31, 0x5F, 0x7B, 0xB6, 0xB3, 0xB3, 0xD3, 0x1E, 0x12, 0xEF, 0x76, +// 0x9C, 0x44, 0x19, 0xF7, 0xEB, 0x5E, 0x14, 0x44, 0x89, 0xF3, 0x6C, 0xF4, 0x1C, 0xFF, 0xB4, 0x7D, +// 0x96, 0xC6, 0x01, 0x79, 0x70, 0x78, 0xC4, 0x29, 0xE0, 0xDE, 0xD7, 0xD3, 0x09, 0xF1, 0xA3, 0xA9, +// 0xD3, 0xD4, 0x9A, 0x5A, 0xAB, 0x09, 0x44, 0x92, 0xF1, 0x90, 0x18, 0x4D, 0x0B, 0xFF, 0xD8, 0x3B, +// 0x66, 0x7B, 0x14, 0x71, 0x51, 0x4F, 0xD9, 0x77, 0xEA, 0xB4, 0xB6, 0xE0, 0x34, 0x39, 0x1D, 0x91, +// 0x90, 0x05, 0x0F, 0x4E, 0x4A, 0x78, 0x5A, 0x4F, 0x69, 0xC2, 0x46, 0x6A, 0x79, 0x4A, 0xD9, 0x78, +// 0x22, 0x9C, 0xDF, 0x9A, 0xCD, 0x39, 0xF0, 0xAF, 0x65, 0xC1, 0x2C, 0x60, 0x29, 0x20, 0xA3, 0x78, +// 0xEA, 0x3C, 0x11, 0xC5, 0x4E, 0x53, 0xB1, 0xDE, 0x6C, 0x87, 0x24, 0x19, 0x33, 0x0E, 0x83, 0x98, +// 0xF8, 0x3E, 0xE3, 0x63, 0x47, 0xA1, 0x05, 0x6C, 0xB6, 0x90, 0x36, 0xA1, 0x01, 0x11, 0xEC, 0x8E, +// 0xB6, 0x43, 0xC6, 0xEB, 0x53, 0xE6, 0x8B, 0x89, 0xB3, 0x0B, 0x3C, 0xB6, 0xBD, 0x2C, 0x49, 0x41, +// 0xA6, 0x38, 0x62, 0x5C, 0xD0, 0x44, 0xA2, 0xA5, 0x31, 0xE1, 0xB3, 0x5C, 0x54, 0x54, 0x40, 0x21, +// 0x27, 0xE3, 0x01, 0xE3, 0xB4, 0x3E, 0x0C, 0x22, 0xEF, 0x76, 0x71, 0xD2, 0x6E, 0x7C, 0x9F, 0x9F, +// 0xE5, 0x4C, 0xA2, 0x3B, 0x9A, 0xCC, 0x96, 0xEA, 0x92, 0xD8, 0x15, 0x60, 0x85, 0x34, 0xA5, 0x74, +// 0x6E, 0x8B, 0xBB, 0x0C, 0xA0, 0x96, 0xFC, 0x05, 0x29, 0x17, 0xFC, 0x2F, 0x45, 0x5A, 0x11, 0x5C, +// 0xA1, 0x30, 0x1E, 0x67, 0x62, 0xF6, 0xF8, 0x2A, 0xA3, 0x98, 0x78, 0x4C, 0x3C, 0xA0, 0xFC, 0xB0, +// 0x6D, 0x86, 0xBA, 0x04, 0xAC, 0x24, 0x24, 0x81, 0x86, 0x3A, 0xD7, 0x3E, 0xD0, 0xC4, 0x27, 0x9C, +// 0x58, 0x9D, 0x84, 0x91, 0xC0, 0xEA, 0x2D, 0xB5, 0x5E, 0x0F, 0xA3, 0xEF, 0xF5, 0x0C, 0xC6, 0x30, +// 0x0F, 0xA8, 0x27, 0x94, 0x92, 0xE1, 0x1E, 0x86, 0xB7, 0x4C, 0x3C, 0x06, 0x3C, 0x5A, 0x28, 0xA9, +// 0x4B, 0x2A, 0x69, 0xA2, 0x2E, 0xB0, 0x25, 0xD5, 0x83, 0x1C, 0x4B, 0xC9, 0x95, 0x50, 0xF5, 0x61, +// 0x24, 0x44, 0x14, 0x4A, 0x93, 0x5B, 0x08, 0xAC, 0x49, 0xAB, 0x79, 0xF1, 0xE8, 0x46, 0xD6, 0x6B, +// 0xBF, 0x44, 0xBE, 0x0D, 0x7A, 0x15, 0xCC, 0x23, 0x41, 0x9D, 0x04, 0x6C, 0xCC, 0x9D, 0x90, 0xF9, +// 0x7E, 0x40, 0x4B, 0x56, 0xEB, 0x64, 0x49, 0x60, 0xF8, 0x44, 0x10, 0x87, 0x85, 0x64, 0x4C, 0x1B, +// 0x31, 0x1F, 0x03, 0x34, 0xA5, 0xBB, 0x3B, 0x16, 0xFB, 0xD0, 0xBD, 0xB8, 0x9A, 0x36, 0xDF, 0xBD, +// 0x1E, 0x47, 0x1D, 0xF8, 0xE7, 0xBC, 0x37, 0x98, 0x1C, 0x0F, 0xC6, 0x30, 0xEA, 0xE2, 0xB4, 0xF3, +// 0xFE, 0xB0, 0xF3, 0x1E, 0x7E, 0x0E, 0x5B, 0xB5, 0xAF, 0xA3, 0x6F, 0xB8, 0xD0, 0x7D, 0xED, 0x77, +// 0xFB, 0x83, 0xE3, 0x4E, 0xE7, 0x5D, 0xE3, 0xCD, 0xF9, 0xF4, 0xE3, 0xBB, 0x5D, 0x04, 0x77, 0x83, +// 0xE6, 0xD5, 0x87, 0x49, 0x73, 0xB0, 0xF5, 0x32, 0xF4, 0x4F, 0xFC, 0x89, 0x17, 0x0E, 0x3A, 0xEF, +// 0x3F, 0x5E, 0xDD, 0x5D, 0x87, 0x83, 0x71, 0xEF, 0x63, 0x6B, 0xF2, 0x79, 0xEB, 0x43, 0xEF, 0xF3, +// 0xC7, 0x57, 0xB7, 0xF4, 0xD3, 0xC9, 0xDB, 0xCF, 0xFD, 0x29, 0x20, 0x1C, 0x45, 0xBD, 0xC1, 0x55, +// 0xF7, 0x43, 0x77, 0xFC, 0xB9, 0xEB, 0x1D, 0xDF, 0x0F, 0x83, 0xF3, 0xEE, 0xEB, 0xCE, 0xB0, 0xB3, +// 0xE5, 0x51, 0x3A, 0xEE, 0x5F, 0x75, 0xB3, 0x37, 0xEF, 0x2E, 0xC6, 0x8C, 0x4D, 0x7A, 0x9F, 0xCF, +// 0xFB, 0xDE, 0xE1, 0xF3, 0xD3, 0xC1, 0x49, 0x87, 0x4D, 0xCE, 0xDF, 0x5E, 0x35, 0x6F, 0x5F, 0xBF, +// 0x3B, 0x3C, 0xF2, 0xAE, 0xDF, 0x5E, 0xEF, 0x1E, 0x6D, 0x37, 0x7E, 0xFB, 0xED, 0xCC, 0xBF, 0x60, +// 0xBC, 0x7F, 0xF7, 0xBD, 0x33, 0x3E, 0x9C, 0xBE, 0x78, 0x48, 0xFB, 0x93, 0x37, 0x77, 0xBC, 0xF1, +// 0x21, 0xFA, 0xFA, 0xE6, 0xE1, 0x0C, 0xFE, 0xBB, 0xBC, 0xAC, 0x0D, 0x7B, 0xAD, 0x74, 0xF0, 0xFE, +// 0xCD, 0x87, 0xAD, 0xF4, 0xE5, 0xF3, 0xB8, 0x7B, 0x74, 0x74, 0x17, 0x0E, 0x2F, 0x1B, 0xA1, 0x7F, +// 0x3B, 0x12, 0x2F, 0xB6, 0x45, 0x7C, 0x3D, 0xCE, 0x3E, 0x7F, 0x7B, 0xFE, 0x76, 0xD2, 0xB8, 0xA0, +// 0xE4, 0x7A, 0x52, 0x7B, 0xF8, 0xFE, 0xF0, 0x62, 0xD2, 0x3F, 0xB9, 0x3B, 0x0F, 0xC8, 0xFD, 0xF9, +// 0xB9, 0xF7, 0x3D, 0xAC, 0x05, 0xE4, 0xE5, 0x45, 0x3F, 0x20, 0x49, 0x6B, 0xE0, 0x77, 0x1A, 0xB5, +// 0xC3, 0xAD, 0xCE, 0x8E, 0x48, 0xAE, 0x0E, 0xF9, 0xD1, 0xF6, 0xD7, 0xDE, 0x8B, 0x6E, 0xB7, 0x15, +// 0x0D, 0xBF, 0x6D, 0xBD, 0xBE, 0xDD, 0x7D, 0x3D, 0xD8, 0x7D, 0x3F, 0x7C, 0xDF, 0xE9, 0xED, 0x74, +// 0x07, 0xE4, 0xBA, 0xF7, 0xBE, 0x33, 0xDA, 0x19, 0x4E, 0x26, 0xEF, 0xDE, 0xF5, 0x5F, 0xF9, 0x9D, +// 0xEF, 0x49, 0xE7, 0x62, 0xDA, 0xB9, 0x3F, 0x1E, 0x74, 0x4E, 0x6A, 0xEF, 0x8E, 0xCF, 0x9A, 0xAD, +// 0xDE, 0xF5, 0xF6, 0xF8, 0x6C, 0x77, 0xDA, 0x4D, 0x8F, 0x3B, 0xEF, 0xBB, 0xCD, 0xF1, 0xDB, 0x5A, +// 0x48, 0x3E, 0x47, 0x87, 0xDB, 0xE3, 0x37, 0xBB, 0xEC, 0xF2, 0x9A, 0x74, 0xDE, 0x74, 0xDF, 0xA6, +// 0xEC, 0x2A, 0x3C, 0x19, 0x34, 0x3B, 0x9D, 0xD3, 0x0B, 0xFA, 0xEA, 0x70, 0x9B, 0xBC, 0xDB, 0xF2, +// 0x3E, 0x82, 0xFE, 0x07, 0x9F, 0xE8, 0x6F, 0xB5, 0xCE, 0xF4, 0xA2, 0x19, 0x78, 0x2F, 0x69, 0xFF, +// 0xE4, 0xBA, 0x2F, 0x6F, 0xE7, 0x38, 0x78, 0xD5, 0xBF, 0xED, 0x65, 0xEF, 0xC3, 0xC3, 0x43, 0x53, +// 0xE3, 0x51, 0x3D, 0xA1, 0x31, 0x25, 0xA2, 0x1C, 0xAE, 0x16, 0xFE, 0x01, 0xB6, 0xB5, 0xB4, 0xC2, +// 0xDC, 0x4F, 0x05, 0xBD, 0x17, 0x75, 0x9F, 0x7A, 0x51, 0x42, 0xE4, 0x1E, 0x40, 0xA0, 0x09, 0x9A, +// 0xD8, 0xFC, 0x77, 0x19, 0x3F, 0x35, 0x15, 0x3F, 0x35, 0xC2, 0x7D, 0xCD, 0x28, 0x1C, 0x01, 0x83, +// 0x87, 0x4F, 0xEF, 0x98, 0x47, 0xEB, 0x31, 0xBB, 0xA7, 0x41, 0x5D, 0x22, 0x3B, 0x4D, 0x73, 0x26, +// 0xFD, 0xAD, 0xD8, 0x46, 0x38, 0x98, 0x9A, 0xA4, 0x5A, 0x2C, 0xF8, 0x5F, 0x89, 0x47, 0x21, 0xB0, +// 0x81, 0xCB, 0x84, 0xF8, 0xAB, 0x7C, 0x27, 0x4A, 0xEA, 0xC3, 0x6C, 0x3C, 0x62, 0xF7, 0xE0, 0xD0, +// 0x23, 0xC6, 0x99, 0xA0, 0x5A, 0x2B, 0x9D, 0xFF, 0x5E, 0x90, 0xB9, 0xA5, 0x0F, 0xA3, 0x84, 0x84, +// 0x34, 0xD5, 0xFE, 0x22, 0x99, 0xD9, 0x28, 0x89, 0xC2, 0x65, 0x10, 0x99, 0x8B, 0xA8, 0x34, 0x99, +// 0xCF, 0x9F, 0x65, 0x71, 0x10, 0x11, 0x10, 0x73, 0x4D, 0xE4, 0x50, 0xF1, 0x34, 0x91, 0x6E, 0xB5, +// 0x88, 0xAB, 0xB9, 0x9B, 0x6D, 0xA1, 0x5B, 0x96, 0xDD, 0x7A, 0x6B, 0x67, 0xE9, 0xBA, 0x75, 0xB9, +// 0x17, 0xE3, 0xFD, 0x9A, 0x4C, 0x81, 0xF1, 0xA0, 0x14, 0xEE, 0x9E, 0x09, 0x50, 0xE9, 0x13, 0x87, +// 0xCB, 0x43, 0xF2, 0xC8, 0xB0, 0x60, 0x40, 0x05, 0xEA, 0x96, 0x8C, 0xD4, 0x85, 0x24, 0xB0, 0x6F, +// 0xFE, 0x8C, 0xCA, 0xBC, 0x67, 0x3D, 0x8B, 0x13, 0xB8, 0x0D, 0x3A, 0xFD, 0x11, 0xCD, 0x42, 0xA6, +// 0x2A, 0x6D, 0x45, 0x53, 0x65, 0xBC, 0x5C, 0x84, 0x65, 0xDA, 0x93, 0xBC, 0x16, 0xA4, 0x1F, 0x4B, +// 0x05, 0xE0, 0x05, 0x37, 0xCF, 0x91, 0x9B, 0x1F, 0x6A, 0x75, 0x7B, 0xF7, 0x97, 0x9C, 0x87, 0x9D, +// 0xE6, 0x2F, 0x73, 0x3B, 0xDF, 0x5B, 0xA4, 0xE4, 0x56, 0x13, 0xFE, 0x29, 0x32, 0xEF, 0x8B, 0x25, +// 0x0B, 0xC3, 0xE7, 0xF8, 0xA7, 0x60, 0x10, 0xE9, 0x94, 0x80, 0xDB, 0x3B, 0x2F, 0x5F, 0xF8, 0xC3, +// 0x02, 0x98, 0x0B, 0xF6, 0x24, 0x3C, 0x21, 0x3E, 0xCB, 0x52, 0xE7, 0x79, 0xF3, 0x97, 0x5C, 0x9F, +// 0x5B, 0x3B, 0x28, 0xFB, 0xE2, 0x2E, 0x71, 0xB2, 0xB4, 0xD8, 0x34, 0x66, 0x5C, 0xDB, 0x4A, 0x35, +// 0xBC, 0x6F, 0x92, 0x2C, 0x0C, 0xB3, 0x92, 0xED, 0xE7, 0xBF, 0x2F, 0x4D, 0x13, 0xF7, 0xCF, 0x9A, +// 0xBF, 0xCC, 0x44, 0x02, 0xD9, 0x64, 0x04, 0xB9, 0xC6, 0x49, 0x22, 0x41, 0x04, 0x35, 0x9A, 0xE6, +// 0x1C, 0x84, 0x5B, 0x03, 0xD8, 0xDE, 0x6D, 0xFA, 0x74, 0x6C, 0xCE, 0xE7, 0x7B, 0x0D, 0x99, 0xD7, +// 0xA0, 0x6C, 0xF1, 0x12, 0x16, 0x8B, 0xFD, 0x51, 0xC6, 0x3D, 0xE4, 0x41, 0x1B, 0x53, 0x83, 0x9A, +// 0xB3, 0x84, 0x8A, 0x2C, 0xE1, 0x9A, 0x1F, 0x79, 0x19, 0x1A, 0xBB, 0x3D, 0xA6, 0xE2, 0x58, 0xD9, +// 0x7D, 0xF7, 0xE1, 0x8D, 0x0F, 0x3B, 0xE6, 0x0B, 0x04, 0x6F, 0x2D, 0x02, 0x38, 0x30, 0x9C, 0x97, +// 0xE3, 0x54, 0xF6, 0x43, 0x82, 0x01, 0x22, 0xEF, 0xE8, 0x83, 0x41, 0x2D, 0xB1, 0x40, 0xA4, 0x36, +// 0xAE, 0x1B, 0xC5, 0x2E, 0x80, 0x71, 0x73, 0x76, 0x07, 0x4A, 0x20, 0x2E, 0xFD, 0x22, 0x6E, 0x2C, +// 0xE6, 0x72, 0xF8, 0x69, 0xE7, 0xBB, 0xC9, 0x1E, 0x3B, 0xA8, 0xB7, 0x1C, 0xB2, 0xCF, 0x0E, 0x5A, +// 0xE0, 0x5E, 0x65, 0x6E, 0xE4, 0xB9, 0xAF, 0x58, 0x40, 0x07, 0xB9, 0xC3, 0xE1, 0x31, 0x48, 0x6C, +// 0xB1, 0x85, 0x28, 0xE2, 0x5B, 0xCD, 0xE6, 0x86, 0x4B, 0x0F, 0x48, 0x00, 0x39, 0xCC, 0xD0, 0x8F, +// 0xAF, 0xAE, 0x2E, 0xAE, 0xBE, 0xE8, 0x35, 0x5A, 0xD3, 0x6F, 0x1C, 0x4D, 0xAF, 0x71, 0xD3, 0x11, +// 0x76, 0x42, 0x47, 0x09, 0x4D, 0x27, 0x97, 0x44, 0x4C, 0x8C, 0xD4, 0xBE, 0x23, 0x41, 0x56, 0x16, +// 0x84, 0xA1, 0xDC, 0xC8, 0xA2, 0x70, 0x39, 0x9D, 0x6A, 0xAF, 0x40, 0xCD, 0x47, 0x90, 0xEA, 0xDA, +// 0xC2, 0x26, 0x71, 0x4C, 0xB9, 0x6F, 0xE8, 0x31, 0x20, 0xEA, 0x16, 0x35, 0xAD, 0x84, 0x7E, 0xCB, +// 0x68, 0x2A, 0x52, 0x1B, 0x2C, 0xD7, 0xD0, 0x2F, 0x07, 0x7D, 0xDD, 0xD2, 0x1B, 0xE8, 0x47, 0x3A, +// 0xF0, 0x46, 0xCC, 0x39, 0x52, 0x89, 0x5C, 0xD0, 0xA4, 0x3E, 0xCC, 0xC0, 0xA0, 0xB8, 0x6E, 0xB6, +// 0x23, 0x9B, 0x71, 0x4E, 0x93, 0x93, 0xFE, 0xD9, 0xA9, 0xAB, 0x5F, 0x29, 0x46, 0xB4, 0x53, 0x28, +// 0x48, 0x74, 0x4B, 0x5E, 0x51, 0x7E, 0xC8, 0xE1, 0x84, 0x05, 0xBE, 0x11, 0x99, 0x6D, 0x24, 0xE1, +// 0x49, 0x12, 0xB2, 0x40, 0x01, 0x0A, 0x9E, 0x2D, 0x1E, 0x62, 0xEA, 0xEA, 0x23, 0x50, 0x86, 0x6E, +// 0x79, 0x76, 0x98, 0x05, 0x82, 0xC5, 0x01, 0x75, 0x37, 0x5A, 0x30, 0xE3, 0x60, 0x41, 0xAE, 0x8E, +// 0xB9, 0x19, 0x61, 0xCC, 0x77, 0x75, 0x15, 0xA1, 0xF2, 0xB8, 0xB6, 0xEE, 0x14, 0x4F, 0x9D, 0x92, +// 0x56, 0x4E, 0x49, 0xCB, 0xB8, 0x4A, 0xE0, 0x34, 0x3F, 0x18, 0xC3, 0x3C, 0xCE, 0xD4, 0x51, 0x05, +// 0xCC, 0xA7, 0x23, 0x02, 0x9C, 0x7C, 0x40, 0x6D, 0xBA, 0x7A, 0x63, 0xDD, 0x41, 0xA9, 0x3A, 0xC8, +// 0xAF, 0x6A, 0xC4, 0x2F, 0x6B, 0x44, 0xDD, 0xEE, 0x3A, 0x64, 0x5F, 0x21, 0x07, 0x55, 0xE4, 0xA0, +// 0x8C, 0x7C, 0x28, 0x8D, 0x64, 0x1D, 0x72, 0xA0, 0x90, 0x93, 0x8A, 0x88, 0x89, 0x14, 0x51, 0x85, +// 0xBD, 0x3A, 0x6A, 0x13, 0x05, 0xD2, 0xAD, 0xA4, 0x22, 0x66, 0x62, 0x83, 0x97, 0x92, 0x61, 0x40, +// 0x7D, 0x77, 0xA3, 0x09, 0x33, 0x2C, 0xB6, 0xDD, 0xAD, 0xE6, 0x9A, 0x33, 0x12, 0x75, 0x46, 0x56, +// 0x65, 0x30, 0x2B, 0x33, 0xA8, 0xF5, 0xC8, 0x1D, 0xD5, 0xD6, 0x31, 0x98, 0x99, 0x56, 0x60, 0x47, +// 0xDC, 0x0B, 0x98, 0x77, 0xEB, 0x2E, 0xBD, 0xC5, 0x9C, 0xB1, 0x85, 0x85, 0x5A, 0x5C, 0x06, 0xBA, +// 0x01, 0x94, 0x5E, 0x8B, 0xA5, 0x7C, 0x80, 0xFA, 0x9E, 0x5B, 0xD9, 0x5A, 0x02, 0xDC, 0xA6, 0xF7, +// 0xD4, 0x3B, 0x8C, 0xC2, 0x90, 0xA0, 0xED, 0xA6, 0xC0, 0x41, 0x3E, 0xD1, 0xCD, 0xB9, 0x15, 0xAD, +// 0xC5, 0x79, 0xC2, 0x45, 0x2C, 0x7F, 0x3D, 0x8B, 0x23, 0x03, 0x5C, 0xCE, 0xF5, 0x6C, 0xD4, 0x61, +// 0x6A, 0x83, 0x1E, 0xC7, 0x62, 0xF2, 0x13, 0x17, 0x2A, 0x0C, 0x54, 0xA2, 0x7C, 0x69, 0xDE, 0x58, +// 0x0B, 0x91, 0x56, 0x7C, 0xEA, 0xA2, 0xB7, 0xE2, 0x54, 0xA8, 0xBC, 0x8A, 0x5D, 0x9A, 0x4B, 0x1D, +// 0x94, 0x61, 0xB9, 0xBD, 0x2F, 0xA0, 0xFA, 0x7C, 0x0E, 0xE7, 0x01, 0xFF, 0x13, 0x68, 0xF9, 0xE8, +// 0x5F, 0x17, 0x60, 0xC9, 0xA3, 0x34, 0x78, 0x8B, 0xBB, 0x0D, 0xE3, 0xC0, 0xF9, 0x8F, 0x6D, 0x7C, +// 0xF9, 0x1F, 0xFB, 0xA6, 0x66, 0x9A, 0x07, 0xFF, 0x6A, 0x48, 0x0D, 0x1B, 0xC2, 0xFC, 0xD2, 0xBA, +// 0xB1, 0x08, 0x80, 0xED, 0x7F, 0x9B, 0xFF, 0xB1, 0x25, 0xB8, 0x02, 0x6B, 0xDF, 0x45, 0x90, 0x49, +// 0xF0, 0x24, 0x34, 0xB0, 0x68, 0xA4, 0x91, 0xCD, 0x4D, 0x43, 0xB8, 0xA4, 0x72, 0x8D, 0x35, 0x51, +// 0xD3, 0x6D, 0x88, 0x53, 0x50, 0x5B, 0xAC, 0x04, 0xBF, 0x3E, 0x24, 0x7A, 0x15, 0x5B, 0x17, 0x00, +// 0xC9, 0x3D, 0xCA, 0x0C, 0x3D, 0x22, 0x97, 0x52, 0xCB, 0x0C, 0x02, 0x42, 0xA7, 0x89, 0xE7, 0x2A, +// 0xAD, 0x1D, 0x14, 0x30, 0x17, 0xA2, 0xE0, 0xBC, 0x1C, 0x2D, 0x15, 0xEA, 0xAA, 0xFD, 0x17, 0x0A, +// 0xA3, 0xD6, 0x12, 0x8A, 0x04, 0x31, 0xAD, 0xD8, 0x79, 0xC6, 0x72, 0x75, 0x4C, 0x59, 0xBA, 0x35, +// 0x59, 0x5D, 0x96, 0xAD, 0x04, 0xAE, 0x2F, 0x8D, 0xFE, 0xD7, 0x3D, 0x16, 0x8E, 0xB5, 0x12, 0x3F, +// 0xF8, 0x97, 0xFB, 0x2B, 0x46, 0xE4, 0xCD, 0x3F, 0xBC, 0x21, 0x70, 0x05, 0xA6, 0x41, 0x6D, 0x1E, +// 0x4D, 0x0D, 0xB3, 0xF6, 0xAB, 0xAE, 0x49, 0x8A, 0xAE, 0x1E, 0x92, 0xFB, 0xBC, 0xA7, 0xC4, 0x8C, +// 0xD7, 0xD6, 0x70, 0x5E, 0xB4, 0x28, 0xF9, 0x82, 0xEC, 0xE6, 0x48, 0x26, 0xA2, 0xB6, 0x56, 0x64, +// 0x52, 0xD5, 0xCA, 0xE8, 0x5A, 0x63, 0xFF, 0xD7, 0x4A, 0x40, 0xB7, 0x98, 0xBA, 0x4E, 0x15, 0x8C, +// 0xB3, 0x00, 0x1C, 0x93, 0x3E, 0x1D, 0x69, 0x03, 0x26, 0x03, 0x75, 0x35, 0x46, 0x5A, 0x81, 0xC1, +// 0xCC, 0x03, 0xC3, 0x2B, 0xFB, 0xF3, 0x1E, 0x16, 0xBF, 0xFB, 0x97, 0xAA, 0xAA, 0x81, 0xD4, 0x8B, +// 0x33, 0x5D, 0x59, 0x59, 0xD5, 0x4B, 0xE0, 0xD2, 0x08, 0xA0, 0x5B, 0x8B, 0x3C, 0x3A, 0x8C, 0xFC, +// 0x87, 0x52, 0xF6, 0x4D, 0xBB, 0x0F, 0x87, 0x01, 0x49, 0xD3, 0x73, 0xB8, 0x01, 0x43, 0xF7, 0x42, +// 0x50, 0xB8, 0xB2, 0xC2, 0xFD, 0xE6, 0xE6, 0x66, 0x15, 0x29, 0xA1, 0x21, 0x14, 0xDB, 0x8A, 0x2B, +// 0xF0, 0x49, 0xD3, 0xF1, 0x81, 0x30, 0x18, 0xD2, 0x1A, 0xC6, 0xF0, 0x25, 0xE3, 0x47, 0x5C, 0x71, +// 0xF4, 0xF4, 0x22, 0xA6, 0xFC, 0x33, 0xDC, 0x95, 0x32, 0xCB, 0x1A, 0xAD, 0xA6, 0x68, 0xFA, 0x8F, +// 0xD8, 0x3E, 0xCA, 0x0D, 0x76, 0xC1, 0x7A, 0xBA, 0x56, 0xA1, 0xFC, 0x9F, 0x61, 0xB9, 0x94, 0x28, +// 0xD6, 0x70, 0x9C, 0x40, 0x80, 0x5A, 0xC3, 0x31, 0xC4, 0x1A, 0x41, 0x17, 0xFC, 0x26, 0x6B, 0xF9, +// 0xCD, 0xFE, 0x19, 0x7E, 0x97, 0x76, 0x1E, 0x15, 0x25, 0x91, 0xAA, 0xAF, 0x50, 0x02, 0x9F, 0xDD, +// 0xE9, 0xA6, 0x15, 0xB9, 0x55, 0x0A, 0x50, 0x1B, 0x46, 0x41, 0xD0, 0x8F, 0xE2, 0x83, 0x27, 0xD6, +// 0x9D, 0xC5, 0x7A, 0x31, 0xC8, 0xD9, 0x5C, 0x6E, 0xB1, 0xBC, 0xB5, 0x44, 0x4F, 0xA1, 0xEC, 0x5F, +// 0x4B, 0x15, 0x01, 0x3F, 0x23, 0x8B, 0x7B, 0xAC, 0xD4, 0xA5, 0x36, 0x28, 0x0F, 0x56, 0x3F, 0xD5, +// 0x3C, 0xCB, 0x5F, 0xCC, 0xAE, 0x6B, 0x51, 0x9B, 0xC0, 0x38, 0x57, 0x92, 0x8B, 0x4A, 0xB2, 0xC8, +// 0x13, 0x01, 0xA8, 0x58, 0xC7, 0x2E, 0xC4, 0x4D, 0x6B, 0x7A, 0x7C, 0xBF, 0x5C, 0x83, 0xC2, 0xDF, +// 0xF5, 0xD5, 0x12, 0x33, 0x08, 0xC4, 0xD3, 0x95, 0x4B, 0x29, 0x5F, 0x37, 0x29, 0x8A, 0x0E, 0x62, +// 0x47, 0xA3, 0x51, 0x4A, 0xC5, 0x47, 0x0C, 0x49, 0x56, 0xB2, 0x98, 0x9F, 0xC8, 0x90, 0x04, 0x8C, +// 0x45, 0x3C, 0x8C, 0xB2, 0x94, 0x46, 0x99, 0xA8, 0xA4, 0x16, 0x63, 0x21, 0xCC, 0x5E, 0xFA, 0xE7, +// 0x9F, 0x8B, 0xC9, 0x7E, 0x5A, 0x0B, 0x96, 0xD3, 0xEB, 0x3D, 0xBF, 0x34, 0xD9, 0xF7, 0x6B, 0x89, +// 0xB9, 0x7A, 0xE9, 0xFF, 0x67, 0x4B, 0x21, 0x65, 0x4B, 0xF1, 0xB0, 0x54, 0x2E, 0x62, 0x62, 0x29, +// 0xE6, 0xC9, 0x82, 0x91, 0x97, 0x7C, 0x16, 0x0D, 0x1A, 0x2B, 0x25, 0x55, 0x9E, 0x97, 0x7D, 0x95, +// 0x43, 0x40, 0x59, 0x71, 0xE5, 0x35, 0x11, 0x06, 0x34, 0xE0, 0x63, 0x64, 0xF2, 0x41, 0xEB, 0xA7, +// 0xD1, 0x94, 0x26, 0x87, 0x24, 0xA5, 0x06, 0x24, 0xCD, 0x65, 0xDC, 0x41, 0xA8, 0xE9, 0x04, 0xEB, +// 0x76, 0x6D, 0x6E, 0x12, 0x05, 0xCE, 0x33, 0x77, 0xC4, 0xB1, 0x26, 0x03, 0xF9, 0xB2, 0xCA, 0x09, +// 0xD4, 0xC6, 0xBE, 0x12, 0xA4, 0x3E, 0x52, 0x25, 0xA8, 0x61, 0x5A, 0xD0, 0x76, 0xC0, 0x35, 0x5F, +// 0x26, 0x51, 0x4C, 0xC6, 0xB2, 0x07, 0x83, 0x35, 0x74, 0x0F, 0xA4, 0x66, 0x6D, 0x34, 0x91, 0x60, +// 0xA9, 0x73, 0x29, 0xFC, 0x66, 0xD9, 0xC2, 0x70, 0x4B, 0x57, 0xC9, 0xB0, 0xBD, 0xF4, 0xA5, 0x35, +// 0x59, 0x83, 0xE0, 0x0B, 0x6C, 0x62, 0xE0, 0x1E, 0x68, 0x64, 0xF2, 0x7B, 0x00, 0x77, 0x6B, 0xB6, +// 0xA3, 0x3D, 0xD6, 0x8E, 0x6A, 0x35, 0x53, 0x55, 0xE9, 0xAE, 0x0B, 0x6D, 0x4E, 0x74, 0x23, 0x0B, +// 0x4B, 0x10, 0xAA, 0x9A, 0x59, 0x0C, 0x38, 0x1B, 0x81, 0xAA, 0xBA, 0xC0, 0x11, 0xD6, 0x98, 0x66, +// 0xA9, 0x23, 0xF1, 0x97, 0x1D, 0xC9, 0x13, 0xB5, 0x07, 0x95, 0xF5, 0x05, 0xD4, 0x31, 0xAB, 0x25, +// 0x86, 0x30, 0xD3, 0x29, 0x13, 0xDE, 0x04, 0x03, 0x90, 0x07, 0x5A, 0xD5, 0x05, 0x14, 0xB5, 0x8E, +// 0x1C, 0x4D, 0x44, 0xB8, 0x1C, 0x05, 0xF9, 0xF0, 0x6B, 0x9A, 0x0F, 0xBC, 0xB4, 0x18, 0xDD, 0x97, +// 0x80, 0x50, 0xD2, 0xE6, 0xE0, 0x88, 0x8F, 0xF2, 0x21, 0xF4, 0xB2, 0x05, 0x9D, 0x02, 0x58, 0xFC, +// 0xC6, 0x71, 0x3E, 0x8A, 0x27, 0xC5, 0x68, 0x42, 0xEF, 0x17, 0x78, 0x51, 0x01, 0xF5, 0xA9, 0xEE, +// 0x28, 0x1B, 0xDB, 0x68, 0xCE, 0xF3, 0x41, 0x6B, 0x29, 0x7F, 0xF0, 0xFF, 0x28, 0x7F, 0xCC, 0xC7, +// 0x85, 0x34, 0x71, 0x31, 0x1A, 0xB3, 0x42, 0x96, 0x61, 0x18, 0xFF, 0x90, 0x93, 0xA4, 0xD4, 0x13, +// 0x97, 0x7A, 0x5A, 0xF1, 0xB3, 0xB6, 0x53, 0x98, 0x8E, 0x31, 0xAA, 0xF8, 0xE3, 0xC8, 0xF6, 0xF0, +// 0xF7, 0x3C, 0xF2, 0x65, 0x6D, 0x69, 0x5A, 0xA1, 0x31, 0x82, 0x3A, 0x57, 0x37, 0xCB, 0x7E, 0x9A, +// 0xFD, 0xB7, 0xAD, 0xE8, 0xD1, 0xF1, 0xE9, 0x71, 0xFF, 0xB8, 0x5C, 0x38, 0x23, 0xE7, 0x25, 0x93, +// 0x8A, 0x2B, 0x5D, 0xFA, 0xB2, 0x22, 0x80, 0x02, 0x1B, 0x45, 0x01, 0x7B, 0xDD, 0xDC, 0x54, 0x7E, +// 0xF1, 0xB6, 0x77, 0x71, 0x6E, 0xC7, 0x24, 0x01, 0x8F, 0x24, 0x15, 0xE6, 0xC2, 0x82, 0x44, 0xF9, +// 0xE0, 0xD7, 0xC7, 0xA5, 0x72, 0x5D, 0x7E, 0x61, 0x70, 0xC4, 0xDC, 0x52, 0xA7, 0xA9, 0x7E, 0x78, +// 0xE2, 0x62, 0x5D, 0x99, 0xBF, 0x04, 0x41, 0x72, 0x1A, 0x2D, 0x13, 0x55, 0x11, 0x67, 0x46, 0xE5, +// 0x30, 0x2F, 0xEE, 0xB2, 0x75, 0x0D, 0xD3, 0xC8, 0xB4, 0xC4, 0x84, 0xA5, 0xE5, 0x46, 0xA5, 0x12, +// 0x14, 0xFE, 0xA2, 0xB6, 0xE7, 0x8B, 0x91, 0x24, 0xB7, 0x5A, 0x73, 0xAB, 0x6F, 0x41, 0x2A, 0x3E, +// 0x58, 0x04, 0x23, 0x66, 0x39, 0xDB, 0x16, 0x77, 0xA3, 0x43, 0xEE, 0x61, 0x5C, 0x7F, 0xBA, 0x35, +// 0x78, 0xD2, 0x3C, 0x79, 0x61, 0x9E, 0xFC, 0xB1, 0x7B, 0x2E, 0x1C, 0x45, 0xF9, 0xDA, 0xE2, 0x98, +// 0xF6, 0x10, 0x58, 0xBB, 0x6D, 0x2F, 0x7D, 0x18, 0x20, 0xD2, 0x83, 0xCB, 0x00, 0xF4, 0x63, 0x58, +// 0xFF, 0x4A, 0xEE, 0x88, 0x7A, 0x09, 0xAA, 0xA2, 0xAD, 0x73, 0x54, 0xD8, 0xEE, 0xFD, 0x81, 0xA3, +// 0xF2, 0xCE, 0x65, 0x18, 0x48, 0x97, 0xC3, 0x92, 0x37, 0x8B, 0x75, 0xC1, 0x61, 0x19, 0x31, 0x64, +// 0x6C, 0x00, 0xE3, 0xCD, 0x5D, 0x49, 0x13, 0xD5, 0x1C, 0xB4, 0xF0, 0x1B, 0x08, 0x8A, 0x4F, 0x39, +// 0xCE, 0x9A, 0x38, 0xAD, 0x62, 0x72, 0xC5, 0x23, 0xC8, 0x4A, 0x67, 0x89, 0xC0, 0x6E, 0x10, 0x0D, +// 0x0D, 0x7C, 0x64, 0x9A, 0xA1, 0xB6, 0x1D, 0x3E, 0x37, 0xD7, 0xBC, 0xD9, 0x54, 0xFA, 0x4B, 0x62, +// 0x79, 0xD5, 0xB0, 0x8B, 0x1C, 0x56, 0xCC, 0x75, 0x7D, 0x1F, 0xF4, 0xA3, 0x4E, 0x29, 0xAF, 0x48, +// 0xA4, 0x53, 0xD1, 0x83, 0xC4, 0x86, 0xA2, 0x41, 0xBE, 0x91, 0x40, 0x44, 0x72, 0x4A, 0x33, 0x5D, +// 0xC7, 0xCA, 0xD2, 0x0B, 0x28, 0x49, 0x7A, 0xB2, 0x73, 0x95, 0x49, 0x6B, 0x25, 0x06, 0xFE, 0xC8, +// 0xD7, 0xF0, 0xC7, 0xA1, 0xD0, 0xA3, 0x83, 0x9B, 0x49, 0x2B, 0x83, 0xA4, 0x23, 0x64, 0x83, 0xA9, +// 0x37, 0xE4, 0xBB, 0xA8, 0x2D, 0x2F, 0xCB, 0xB4, 0x16, 0x50, 0x70, 0x71, 0x83, 0xBB, 0x11, 0x30, +// 0x52, 0x5A, 0xC4, 0x9E, 0x94, 0xA8, 0xC7, 0x8F, 0x10, 0x1F, 0x53, 0x4A, 0x20, 0x06, 0x20, 0xA6, +// 0x40, 0xD0, 0xA7, 0x42, 0x8A, 0x54, 0xE6, 0x92, 0x53, 0x2A, 0x20, 0xCA, 0x48, 0xCD, 0xE2, 0xC1, +// 0x85, 0x78, 0xD4, 0x46, 0xD6, 0x80, 0xFD, 0xDC, 0xBD, 0x73, 0x33, 0xDE, 0x90, 0x68, 0x09, 0x56, +// 0x36, 0x3D, 0x9A, 0xA6, 0x52, 0x5C, 0x54, 0xC7, 0x19, 0xF8, 0xA8, 0xA1, 0x03, 0x5A, 0x23, 0x84, +// 0x11, 0x1E, 0x84, 0x8A, 0x01, 0x40, 0x7F, 0x42, 0xC3, 0x1C, 0x22, 0x70, 0x08, 0x20, 0x82, 0xA0, +// 0x7F, 0x49, 0x0D, 0xF7, 0x64, 0x05, 0xC9, 0xF8, 0xD8, 0x6D, 0x35, 0xF0, 0x9D, 0x66, 0x95, 0xEC, +// 0x20, 0xA5, 0xBD, 0x68, 0x24, 0xFA, 0x64, 0x98, 0x1A, 0x50, 0x00, 0xAC, 0xD9, 0x01, 0xA0, 0x1E, +// 0x24, 0x5E, 0x63, 0x2B, 0x3F, 0xEF, 0x04, 0x2A, 0xBB, 0x00, 0xAB, 0xBB, 0x8E, 0x87, 0x5F, 0x39, +// 0x4F, 0x19, 0xA7, 0x39, 0x26, 0x00, 0x7B, 0x93, 0x68, 0x7A, 0x99, 0x30, 0x2E, 0xCE, 0x64, 0x1B, +// 0x6A, 0x6C, 0xB4, 0xE4, 0xF5, 0xA9, 0x87, 0x15, 0x79, 0x3F, 0xC5, 0x8B, 0xCB, 0x0C, 0xF3, 0xBA, +// 0x53, 0x79, 0x77, 0xB1, 0x86, 0x70, 0x21, 0x50, 0x66, 0x38, 0xB3, 0x29, 0x74, 0xB0, 0xFA, 0xA1, +// 0x48, 0x82, 0x7A, 0x4F, 0xB7, 0x42, 0xE2, 0xC1, 0x44, 0xED, 0x81, 0xF9, 0xDC, 0xC2, 0xD8, 0xE1, +// 0x94, 0x83, 0x5A, 0x0A, 0xB5, 0x02, 0x45, 0xC6, 0x95, 0xCD, 0x98, 0x35, 0x1D, 0x6A, 0x58, 0x88, +// 0x61, 0xE0, 0xAF, 0xFE, 0x05, 0x0F, 0x1E, 0x1C, 0xC8, 0x55, 0x3F, 0xE1, 0x23, 0xE3, 0x7E, 0xF4, +// 0x23, 0x3E, 0x3E, 0xAF, 0xF0, 0xF1, 0x79, 0x1D, 0x1F, 0xB4, 0xAA, 0x3C, 0x98, 0x0C, 0x80, 0xEC, +// 0x19, 0xE1, 0x64, 0x4C, 0x13, 0x58, 0xC0, 0x43, 0x50, 0x25, 0x7F, 0x8B, 0xB3, 0x84, 0xFE, 0x98, +// 0xB3, 0xDE, 0x84, 0x8D, 0xC4, 0x23, 0xFE, 0x8A, 0xD5, 0xFF, 0x82, 0x4B, 0x3C, 0x70, 0x3D, 0x97, +// 0x79, 0x6D, 0x5A, 0x49, 0x28, 0x3F, 0x7E, 0x2B, 0x91, 0x7E, 0xE4, 0x42, 0x78, 0xA9, 0x38, 0xC8, +// 0xDF, 0xB7, 0xF4, 0x00, 0xBC, 0x11, 0xF8, 0x29, 0x35, 0x75, 0xBC, 0x0B, 0xA5, 0xFC, 0x29, 0x30, +// 0x64, 0xA8, 0xC0, 0x47, 0xDD, 0xD9, 0xDC, 0x12, 0xAE, 0x01, 0x8A, 0xF1, 0xA3, 0x29, 0xB0, 0xEA, +// 0xC9, 0x02, 0xD7, 0x9E, 0x40, 0x26, 0x04, 0x91, 0xE0, 0x48, 0xC8, 0xA7, 0x8D, 0x2F, 0x07, 0x9B, +// 0x37, 0x35, 0xC8, 0x43, 0x2E, 0xFC, 0x98, 0x2E, 0x0C, 0x36, 0x6F, 0xFE, 0x6D, 0x36, 0xC6, 0xCC, +// 0x5A, 0x76, 0xA4, 0x96, 0x4C, 0xF6, 0xF4, 0x0B, 0xBF, 0x71, 0x09, 0x48, 0x5D, 0x49, 0x78, 0x45, +// 0x34, 0x03, 0x6B, 0x43, 0x61, 0xE1, 0x07, 0xFF, 0x47, 0x09, 0xF8, 0x91, 0x9E, 0x07, 0xCE, 0xBD, +// 0xE6, 0x3D, 0x5E, 0x2F, 0x3E, 0x85, 0xE9, 0x56, 0xE9, 0xC1, 0x4A, 0xC7, 0xEF, 0x53, 0x3A, 0x76, +// 0x59, 0xA2, 0x14, 0x4A, 0x14, 0x59, 0x88, 0x1A, 0x6A, 0x50, 0x0E, 0x51, 0x98, 0x89, 0x17, 0xCD, +// 0x81, 0x02, 0x9B, 0x73, 0x34, 0x5B, 0x3A, 0x02, 0x0F, 0xF4, 0xF5, 0x45, 0xEE, 0xFC, 0x74, 0x76, +// 0x7A, 0x22, 0x44, 0x7C, 0xA5, 0x62, 0x22, 0xD0, 0xAA, 0x2E, 0x2C, 0x2F, 0xCF, 0x9C, 0x89, 0xE4, +// 0xA1, 0x28, 0x75, 0x30, 0x31, 0x28, 0x87, 0xFE, 0x74, 0x31, 0xFC, 0x0A, 0x71, 0xD6, 0xD0, 0xCF, +// 0x52, 0x48, 0x58, 0x5B, 0x36, 0xA2, 0xF7, 0xFB, 0x97, 0xF6, 0xAE, 0xDD, 0x84, 0xBA, 0x00, 0xB4, +// 0x0A, 0x69, 0x19, 0xEE, 0x7D, 0xFE, 0xB7, 0x90, 0xB7, 0xFF, 0x1E, 0x32, 0x83, 0xA8, 0x95, 0x42, +// 0x58, 0x2A, 0xF0, 0xAB, 0xB8, 0x93, 0x24, 0x9A, 0x4A, 0xB4, 0xE3, 0x24, 0xC1, 0x4B, 0xE9, 0x43, +// 0x85, 0xA2, 0x0D, 0x61, 0x31, 0xA5, 0x89, 0xE6, 0x47, 0x34, 0xD5, 0x78, 0x24, 0xB4, 0x34, 0x8B, +// 0x63, 0x68, 0x5C, 0x56, 0xF4, 0x61, 0xEB, 0xC5, 0xEB, 0xCB, 0xFB, 0x8C, 0x66, 0xD4, 0xCF, 0x97, +// 0x69, 0x52, 0xD1, 0x0B, 0x56, 0x50, 0xDF, 0x10, 0xEE, 0x7E, 0xB9, 0xC9, 0xEB, 0xA9, 0x8C, 0x73, +// 0x8C, 0xA2, 0x1B, 0x2D, 0x35, 0x07, 0xE9, 0x26, 0x40, 0xD5, 0xE5, 0x59, 0x10, 0xCC, 0xDB, 0x2B, +// 0xB4, 0xA0, 0xF1, 0x8A, 0x44, 0x24, 0x9F, 0xCB, 0x67, 0x7F, 0xE4, 0xC9, 0xA9, 0xE2, 0x82, 0x50, +// 0xF2, 0x54, 0xA9, 0x36, 0xAD, 0x0D, 0x63, 0x83, 0x6A, 0x8C, 0xA7, 0x82, 0x70, 0x0F, 0xAF, 0x51, +// 0xE9, 0xC2, 0x2C, 0x6A, 0x29, 0xDC, 0xDE, 0x46, 0x5F, 0xCB, 0x6D, 0xE9, 0x89, 0x7C, 0x2A, 0x25, +// 0xE3, 0xAE, 0xAE, 0x63, 0x55, 0x45, 0xB1, 0x3E, 0x25, 0x61, 0x5A, 0x26, 0x5B, 0x54, 0x06, 0x26, +// 0x77, 0x0B, 0x70, 0x9B, 0x06, 0x29, 0x1C, 0xBD, 0x7E, 0x7F, 0xCE, 0x46, 0xD1, 0xCE, 0x11, 0x80, +// 0x69, 0xC5, 0x3E, 0x93, 0xD7, 0xE0, 0x24, 0xCC, 0x73, 0x07, 0x32, 0xE9, 0x4A, 0x03, 0x0E, 0xA9, +// 0x98, 0x44, 0xFE, 0x81, 0x7E, 0xA0, 0x3B, 0x3A, 0xFC, 0xBB, 0x09, 0x35, 0x47, 0xCD, 0xA5, 0xD0, +// 0xA4, 0xFA, 0x74, 0x70, 0xF5, 0x06, 0xC2, 0x53, 0x0C, 0xA5, 0x01, 0x17, 0x50, 0x34, 0xD7, 0x74, +// 0x7C, 0x7A, 0x7D, 0x0C, 0x29, 0xC8, 0x7F, 0x21, 0x37, 0x66, 0xBB, 0xAA, 0x6C, 0xB8, 0xF3, 0xEA, +// 0x75, 0x56, 0x2E, 0x03, 0x7A, 0x61, 0x8C, 0x58, 0x0F, 0x29, 0x7E, 0xFB, 0x7B, 0xF4, 0x9E, 0x8D, +// 0x15, 0xD2, 0x6A, 0x5D, 0x6F, 0xCE, 0x76, 0x90, 0x67, 0x89, 0xD5, 0x43, 0x2C, 0x70, 0x97, 0x1F, +// 0x29, 0x59, 0x95, 0x35, 0xDC, 0xF6, 0x48, 0x10, 0xE0, 0xC7, 0x5A, 0x03, 0x1B, 0x6A, 0x22, 0xB2, +// 0xD4, 0x42, 0x22, 0x29, 0x08, 0x90, 0xD2, 0x3E, 0x84, 0x39, 0xD3, 0x92, 0x65, 0x86, 0xB2, 0xA1, +// 0xBC, 0xFF, 0xC5, 0x9A, 0xA3, 0x64, 0x46, 0xE8, 0xCE, 0xF9, 0x6C, 0x73, 0x53, 0xD8, 0x85, 0x99, +// 0x18, 0x05, 0x52, 0x8A, 0x01, 0x1C, 0x9A, 0x7D, 0x68, 0x2D, 0x8C, 0xB2, 0x90, 0x58, 0xAB, 0x3D, +// 0xD2, 0xB6, 0x51, 0x55, 0x03, 0x54, 0x7C, 0x46, 0x01, 0x03, 0xCE, 0xB2, 0x24, 0x80, 0xA8, 0x8B, +// 0x39, 0xBA, 0xB2, 0x2D, 0xC5, 0xBA, 0xD0, 0x84, 0x0E, 0xEC, 0x67, 0xC8, 0x12, 0x95, 0x97, 0xAD, +// 0xA2, 0x27, 0x12, 0xC5, 0x77, 0x95, 0x9E, 0xC8, 0x6F, 0xE5, 0x84, 0xAA, 0xC8, 0x77, 0x88, 0x2F, +// 0x13, 0x5C, 0xD4, 0xD1, 0x13, 0xA0, 0x24, 0x83, 0x52, 0x34, 0x60, 0x2A, 0x2C, 0x37, 0xEE, 0xEB, +// 0xD3, 0xE9, 0xB4, 0x8E, 0xDF, 0x6A, 0xEB, 0x70, 0x82, 0xB2, 0x02, 0x5F, 0x5F, 0xC7, 0x21, 0x47, +// 0x15, 0x58, 0xF8, 0x6E, 0xE1, 0xAC, 0xBA, 0xE8, 0x42, 0x7F, 0x2B, 0xDE, 0xD4, 0xAA, 0xD2, 0x59, +// 0xE1, 0x73, 0x79, 0xDB, 0x7B, 0x3B, 0x2B, 0x20, 0x32, 0xC4, 0xAF, 0xB2, 0x90, 0x69, 0x20, 0x0D, +// 0x3B, 0xE5, 0x46, 0x56, 0x25, 0x85, 0x65, 0x5C, 0xB0, 0xE3, 0x2C, 0x9D, 0x18, 0x33, 0x60, 0xDD, +// 0x11, 0x96, 0xD2, 0x95, 0x43, 0x2D, 0x65, 0xB7, 0x0E, 0xB7, 0x0A, 0xFB, 0x70, 0x30, 0x83, 0x94, +// 0x79, 0xFB, 0xF3, 0x4F, 0x39, 0x5B, 0xDE, 0xF6, 0x92, 0x62, 0x71, 0xE1, 0xF3, 0xFC, 0xA9, 0x35, +// 0xAF, 0x69, 0xA5, 0xD1, 0xAF, 0xC4, 0x97, 0xBD, 0x46, 0xFE, 0x19, 0x3B, 0xFF, 0x9C, 0xAD, 0x81, +// 0xB1, 0x43, 0x23, 0x2A, 0xDC, 0x4C, 0x8C, 0xEA, 0x2F, 0x34, 0xE6, 0x63, 0x79, 0x29, 0xBF, 0x2D, +// 0xA0, 0x54, 0xA9, 0xD3, 0x68, 0x78, 0x3E, 0xFF, 0x9A, 0x42, 0x19, 0x1D, 0x65, 0xFE, 0x28, 0x20, +// 0x09, 0xC5, 0x82, 0xA3, 0x41, 0xBE, 0x92, 0xFB, 0x46, 0xC0, 0x86, 0x69, 0x03, 0x93, 0x6D, 0xCB, +// 0xDE, 0xB2, 0x77, 0x71, 0x64, 0x7F, 0x4D, 0xF7, 0x57, 0x4F, 0xD8, 0x5F, 0x34, 0x69, 0x58, 0x0B, +// 0xE7, 0xB5, 0xAB, 0x8A, 0x4D, 0x6A, 0x83, 0xFB, 0xC4, 0xA7, 0x70, 0x3D, 0x6F, 0xB3, 0xCC, 0xB6, +// 0x1A, 0xE4, 0x5F, 0x60, 0xD4, 0x31, 0xBA, 0x95, 0x2F, 0x92, 0xF4, 0x81, 0x7B, 0x18, 0x5B, 0x17, +// 0x54, 0x26, 0x70, 0x49, 0xD5, 0x87, 0x34, 0xB9, 0xD3, 0x9C, 0x2F, 0x39, 0xC3, 0xB7, 0x3C, 0xA8, +// 0x03, 0xE4, 0x37, 0x9C, 0x72, 0x39, 0xB0, 0xBF, 0x07, 0x5D, 0x33, 0x2A, 0x41, 0x79, 0xB1, 0x26, +// 0x9B, 0xE6, 0x7C, 0x02, 0x82, 0x01, 0x70, 0xB1, 0xA3, 0x48, 0xCD, 0x2B, 0xCB, 0x98, 0x9B, 0x57, +// 0x96, 0x54, 0xE2, 0x5F, 0x59, 0xCC, 0xDB, 0x9F, 0xFC, 0xDB, 0x4C, 0xF9, 0x7F, 0x5B, 0x28, 0x36, +// 0x32, 0xF9, 0xE1, 0x09, 0xF7, 0x56, 0x3F, 0x45, 0xAD, 0x47, 0x51, 0xBB, 0xF7, 0xFF, 0x17, 0x53, +// 0xE8, 0x9D, 0x36, 0x92, 0x29, 0x00, 0x00 +// }; + +#define SPIFFS_MAXLENGTH_FILEPATH 32 +const char *excludeListFile = "/.exclude.files"; + +typedef struct ExcludeListS { + char *item; + ExcludeListS *next; +} ExcludeList; + +static ExcludeList *excludes = NULL; + +static bool matchWild(const char *pattern, const char *testee) { + const char *nxPat = NULL, *nxTst = NULL; + + while (*testee) { + if (( *pattern == '?' ) || (*pattern == *testee)){ + pattern++;testee++; + continue; + } + if (*pattern=='*'){ + nxPat=pattern++; nxTst=testee; + continue; + } + if (nxPat){ + pattern = nxPat+1; testee=++nxTst; + continue; + } + return false; + } + while (*pattern=='*'){pattern++;} + return (*pattern == 0); +} + +static bool addExclude(const char *item){ + size_t len = strlen(item); + if(!len){ + return false; + } + ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList)); + if(!e){ + return false; + } + e->item = (char *)malloc(len+1); + if(!e->item){ + free(e); + return false; + } + memcpy(e->item, item, len+1); + e->next = excludes; + excludes = e; + return true; +} + +static void loadExcludeList(fs::FS &_fs, const char *filename){ + static char linebuf[SPIFFS_MAXLENGTH_FILEPATH]; + fs::File excludeFile=_fs.open(filename, "r"); + if(!excludeFile){ + //addExclude("/*.js.gz"); + return; + } +#ifdef ESP32 + if(excludeFile.isDirectory()){ + excludeFile.close(); + return; + } +#endif + if (excludeFile.size() > 0){ + uint8_t idx; + bool isOverflowed = false; + while (excludeFile.available()){ + linebuf[0] = '\0'; + idx = 0; + int lastChar; + do { + lastChar = excludeFile.read(); + if(lastChar != '\r'){ + linebuf[idx++] = (char) lastChar; + } + } while ((lastChar >= 0) && (lastChar != '\n') && (idx < SPIFFS_MAXLENGTH_FILEPATH)); + + if(isOverflowed){ + isOverflowed = (lastChar != '\n'); + continue; + } + isOverflowed = (idx >= SPIFFS_MAXLENGTH_FILEPATH); + linebuf[idx-1] = '\0'; + if(!addExclude(linebuf)){ + excludeFile.close(); + return; + } + } + } + excludeFile.close(); +} + +static bool isExcluded(fs::FS &_fs, const char *filename) { + if(excludes == NULL){ + loadExcludeList(_fs, excludeListFile); + } + ExcludeList *e = excludes; + while(e){ + if (matchWild(e->item, filename)){ + return true; + } + e = e->next; + } + return false; +} + +// WEB HANDLER IMPLEMENTATION + +#ifdef ESP32 +SPIFFSEditor::SPIFFSEditor(const fs::FS& fs, const String& username, const String& password) +#else +SPIFFSEditor::SPIFFSEditor(const String& username, const String& password, const fs::FS& fs) +#endif +:_fs(fs) +,_username(username) +,_password(password) +,_authenticated(false) +,_startTime(0) +{} + +bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request){ + if(request->url().equalsIgnoreCase("/edit")){ + if(request->method() == HTTP_GET){ + if(request->hasParam("list")) + return true; + if(request->hasParam("edit")){ + //String fname = "/" + request->arg("edit"); + request->_tempFile = _fs.open(request->arg("edit"), "r"); + if(!request->_tempFile){ + return false; + } +#ifdef ESP32 + if(request->_tempFile.isDirectory()){ + request->_tempFile.close(); + return false; + } +#endif + } + if(request->hasParam("download")){ + request->_tempFile = _fs.open(request->arg("download"), "r"); + if(!request->_tempFile){ + return false; + } +#ifdef ESP32 + if(request->_tempFile.isDirectory()){ + request->_tempFile.close(); + return false; + } +#endif + } + request->addInterestingHeader("If-Modified-Since"); + return true; + } + else if(request->method() == HTTP_POST) + return true; + else if(request->method() == HTTP_DELETE) + return true; + else if(request->method() == HTTP_PUT) + return true; + + } + return false; +} + + +void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ + if(_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str())) + return request->requestAuthentication(); + + if(request->method() == HTTP_GET){ + if(request->hasParam("list")){ + String path = request->getParam("list")->value(); +#ifdef ESP32 + File dir = _fs.open(path); +#else + Dir dir = _fs.openDir(path); +#endif + path = String(); + String output = "["; +#ifdef ESP32 + File entry = dir.openNextFile(); + while(entry){ +#else + while(dir.next()){ + fs::File entry = dir.openFile("r"); +#endif + if (isExcluded(_fs, entry.name())) { +#ifdef ESP32 + entry = dir.openNextFile(); +#endif + continue; + } + if (output != "[") output += ','; + output += "{\"type\":\""; + output += "file"; + output += "\",\"name\":\""; + output += String(entry.path()); + output += "\",\"size\":"; + output += String(entry.size()); + output += "}"; +#ifdef ESP32 + entry = dir.openNextFile(); +#else + entry.close(); +#endif + } +#ifdef ESP32 + dir.close(); +#endif + output += "]"; + request->send(200, "application/json", output); + output = String(); + } + else if(request->hasParam("edit") || request->hasParam("download")){ + request->send(request->_tempFile, request->_tempFile.name(), String(), request->hasParam("download")); + } + else { + const char * buildTime = __DATE__ " " __TIME__ " GMT"; + if (request->header("If-Modified-Since").equals(buildTime)) { + request->send(304); + } else { + // AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len); + // response->addHeader("Content-Encoding", "gzip"); + // response->addHeader("Last-Modified", buildTime); + // request->send(response); + fs::File f = _fs.open("/edit.htm"); + // String fileContent; + // while (file.available()) + // { + // fileContent = file.readString(); + // break; + // } + request->send(200,"text/html",f.readString()); + // request->send("/edit.htm"); + } + } + } else if(request->method() == HTTP_DELETE){ + if(request->hasParam("path", true)){ + _fs.remove(request->getParam("path", true)->value()); + request->send(200, "", "DELETE: "+request->getParam("path", true)->value()); + } else + request->send(404); + } else if(request->method() == HTTP_POST){ + if(request->hasParam("data", true, true) && _fs.exists(request->getParam("data", true, true)->value())) + request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value()); + else + request->send(500); + } else if(request->method() == HTTP_PUT){ + if(request->hasParam("path", true)){ + String filename = request->getParam("path", true)->value(); + if(_fs.exists(filename)){ + request->send(200); + } else { + fs::File f = _fs.open(filename, "w"); + if(f){ + f.write((uint8_t)0x00); + f.close(); + request->send(200, "", "CREATE: "+filename); + } else { + request->send(500); + } + } + } else + request->send(400); + } +} + +void SPIFFSEditor::handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ + if(!index){ + if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str())){ + _authenticated = true; + request->_tempFile = _fs.open(filename, "w"); + _startTime = millis(); + } + } + if(_authenticated && request->_tempFile){ + if(len){ + request->_tempFile.write(data,len); + } + if(final){ + request->_tempFile.close(); + } + } +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..79060aa --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,432 @@ +#include + +//Peripherals includes +#include +#include + +//Web server includes +#include +#include +#include "SPIFFS.h" +// #include +#include +#include +#include +#include +#include + +#include +Preferences settings; + +#define LED_PIN 5 + +//********************************************************* +// Web server variable declarations +//********************************************************* + +// Create AsyncWebServer object on port 80 +AsyncWebServer server(80); +// AsyncWebSocket ws("/ws"); +// AsyncEventSource events("/events"); + +//Variables to save values from HTML form +JSONVar scannedSSIDs; +String ssid; +String pass; +String ip; +String gateway; +int timesConnected = 0; + +const String http_username = "admin"; +const String http_password = "admin"; + +IPAddress localIP; +//IPAddress localIP(192, 168, 1, 200); // hardcoded + +// Set your Gateway IP address +IPAddress localGateway; +//IPAddress localGateway(192, 168, 1, 1); //hardcoded +IPAddress subnet(255, 255, 0, 0); + +// Timer variables +unsigned long previousMillis = 0; +const long interval = 10000; // interval to wait for Wi-Fi connection (milliseconds) +#define WIFI_TIMEOUT 10000 + +// Stores LED state +String ledState; + + +// --------- function declarations -------------- +// void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); +void initSPIFFS(); +bool initWiFi(); +String getLEDState(); +// ---------------------------------------------- + +void setup() { + pinMode(LED_PIN, OUTPUT); + + Serial.begin(115200); + delay(2000); + // while (!Serial) + // delay(10); // will pause Zero, Leonardo, etc until serial console opens + +//***************************************** + + +//Init OTA + AsyncElegantOTA.begin(&server); // Start AsyncElegantOTA + +//***************************************** +//Init SPIFFS +// MDNS.addService("http","tcp",80); + initSPIFFS(); +// ws.onEvent(onWsEvent); +// server.addHandler(&ws); + +// events.onConnect([](AsyncEventSourceClient *client){ +// client->send("hola!",NULL,millis(),1000); +// }); +// server.addHandler(&events); +server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password)); + +//***************************************** +//Init webserver + + if(initWiFi()){ + //connected to known network + + }else{ + //softAP + + } + + + server.on("/scanNetworks", HTTP_GET, [](AsyncWebServerRequest *request){ + String json = "["; + int n = WiFi.scanComplete(); + if(n == -2){ + WiFi.scanNetworks(true); + } else if(n){ + for (int i = 0; i < n; ++i){ + if(i) json += ","; + json += "{"; + json += "\"rssi\":"+String(WiFi.RSSI(i)); + json += ",\"ssid\":\""+WiFi.SSID(i)+"\""; + json += ",\"channel\":"+String(WiFi.channel(i)); + json += "}"; + } + WiFi.scanDelete(); + if(WiFi.scanComplete() == -2){ + WiFi.scanNetworks(true); + } + } + json += "]"; + request->send(200, "application/json", json); + json = String(); + }); + + server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); + server.onNotFound([](AsyncWebServerRequest *request){ + Serial.printf("NOT_FOUND: "); + if(request->method() == HTTP_GET) + Serial.printf("GET"); + else if(request->method() == HTTP_POST) + Serial.printf("POST"); + else if(request->method() == HTTP_DELETE) + Serial.printf("DELETE"); + else if(request->method() == HTTP_PUT) + Serial.printf("PUT"); + else if(request->method() == HTTP_PATCH) + Serial.printf("PATCH"); + else if(request->method() == HTTP_HEAD) + Serial.printf("HEAD"); + else if(request->method() == HTTP_OPTIONS) + Serial.printf("OPTIONS"); + else + Serial.printf("UNKNOWN"); + Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); + + if(request->contentLength()){ + Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); + Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); + } + + int headers = request->headers(); + int i; + for(i=0;igetHeader(i); + Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); + } + + int params = request->params(); + for(i=0;igetParam(i); + if(p->isFile()){ + Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); + } else if(p->isPost()){ + Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } else { + Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } + } + + request->send(404); + }); + server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ + if(!index) + Serial.printf("UploadStart: %s\n", filename.c_str()); + Serial.printf("%s", (const char*)data); + if(final) + Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len); + }); + server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ + if(!index) + Serial.printf("BodyStart: %u\n", total); + Serial.printf("%s", (const char*)data); + if(index + len == total) + Serial.printf("BodyEnd: %u\n", total); + }); + + server.on("/setWiFi", HTTP_POST, [](AsyncWebServerRequest *request) { + int params = request->params(); + settings.begin("WiFi"); + if(params = 4){ + for(int i=0;igetParam(i); + if(p->isPost()){ + // HTTP POST ssid value + if (p->name() == "ssid") { + ssid = p->value().c_str(); + Serial.print("SSID set to: "); + Serial.println(ssid); + // Write file to save value + // writeFile(SPIFFS, ssidPath, ssid.c_str()); + // settings.putString("ssid",ssid); + } + // HTTP POST pass value + if (p->name() == "pass") { + pass = p->value().c_str(); + Serial.print("Password set to: "); + Serial.println(pass); + // Write file to save value + // writeFile(SPIFFS, passPath, pass.c_str()); + // settings.putString("pass",pass); + } + // HTTP POST ip value + if (p->name() == "ip") { + ip = p->value().c_str(); + Serial.print("IP Address set to: "); + Serial.println(ip); + // Write file to save value + // writeFile(SPIFFS, ipPath, ip.c_str()); + // settings.putString("ip",ip); + } + // HTTP POST gateway value + if (p->name() == "gateway") { + gateway = p->value().c_str(); + Serial.print("Gateway set to: "); + Serial.println(gateway); + // Write file to save value + // writeFile(SPIFFS, gatewayPath, gateway.c_str()); + // settings.putString("gateway",gateway); + } + //Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } + } + settings.putString(ssid.c_str(),(pass+","+ip+","+gateway+",1")); + settings.end(); + request->send(200, "text/plain", "Done. ESP will restart, connect to your router and go to IP address: " + ip); + delay(3000); + ESP.restart(); + } + }); + + server.begin(); + +} + + +void loop() { + digitalWrite(LED_PIN,HIGH); + delay(500); + digitalWrite(LED_PIN,LOW); + delay(500); +} + +// functions +// void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ +// if(type == WS_EVT_CONNECT){ +// Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); +// client->printf("Hello Client %u :)", client->id()); +// client->ping(); +// } else if(type == WS_EVT_DISCONNECT){ +// Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); +// } else if(type == WS_EVT_ERROR){ +// Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); +// } else if(type == WS_EVT_PONG){ +// Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); +// } else if(type == WS_EVT_DATA){ +// AwsFrameInfo * info = (AwsFrameInfo*)arg; +// String msg = ""; +// if(info->final && info->index == 0 && info->len == len){ +// //the whole message is in a single frame and we got all of it's data +// Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); + +// if(info->opcode == WS_TEXT){ +// for(size_t i=0; i < info->len; i++) { +// msg += (char) data[i]; +// } +// } else { +// char buff[3]; +// for(size_t i=0; i < info->len; i++) { +// sprintf(buff, "%02x ", (uint8_t) data[i]); +// msg += buff ; +// } +// } +// Serial.printf("%s\n",msg.c_str()); + +// if(info->opcode == WS_TEXT) +// client->text("I got your text message"); +// else +// client->binary("I got your binary message"); +// } else { +// //message is comprised of multiple frames or the frame is split into multiple packets +// if(info->index == 0){ +// if(info->num == 0) +// Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); +// Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); +// } + +// Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len); + +// if(info->opcode == WS_TEXT){ +// for(size_t i=0; i < len; i++) { +// msg += (char) data[i]; +// } +// } else { +// char buff[3]; +// for(size_t i=0; i < len; i++) { +// sprintf(buff, "%02x ", (uint8_t) data[i]); +// msg += buff ; +// } +// } +// Serial.printf("%s\n",msg.c_str()); + +// if((info->index + len) == info->len){ +// Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); +// if(info->final){ +// Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); +// if(info->message_opcode == WS_TEXT) +// client->text("I got your text message"); +// else +// client->binary("I got your binary message"); +// } +// } +// } +// } +// } + +// Initialize SPIFFS +void initSPIFFS() { + if (!SPIFFS.begin(true)) { + Serial.println("An error has occurred while mounting SPIFFS"); + } + Serial.println("SPIFFS mounted successfully"); +} + +// Initialize WiFi +bool initWiFi() { + +//scan nearby networks +WiFi.mode(WIFI_STA); +int n = WiFi.scanNetworks(); +if(n){ + //networks found, try to connect + String availableNetworkParams = ""; + settings.begin("WiFi"); + for(int i=0;i 1){ + //known network + ssid = WiFi.SSID(i).c_str(); + String netparams[4]; + int s=0; + for(int j=0;j<4;j++){ + int e = availableNetworkParams.indexOf(",",s); + netparams[j]=availableNetworkParams.substring(s,e); + s=e+1; + } + pass = netparams[0]; + ip = netparams[1]; + localIP.fromString(ip); + gateway = netparams[2]; + localGateway.fromString(gateway); + timesConnected = netparams[3].toInt(); + + if (WiFi.config(localIP, localGateway, subnet)){ + WiFi.begin(ssid.c_str(), pass.c_str()); + Serial.println("Connecting to WiFi..."); + + unsigned long currentMillis = millis(); + previousMillis = currentMillis; + + bool res = true; + + while(WiFi.status() != WL_CONNECTED) { + currentMillis = millis(); + if (currentMillis - previousMillis >= WIFI_TIMEOUT) { + Serial.println("Failed to connect."); + // return false; + res = false; + } + if(!res) break; + } + // Serial.println(WiFi.localIP()); + // return true; + if(res){ + //save connection + settings.putString(ssid.c_str(),(pass + "," + localIP.toString() + "," + localGateway.toString() + "," + String(timesConnected + 1)).c_str()); + //initWiFi() true + return true; + } + }else{ + Serial.println("STA Failed to configure."); + //return false; + } + } + } + settings.end(); +} + //no networks found + Serial.println("Setting AP (Access Point)"); + // NULL sets an open Access Point + WiFi.mode(WIFI_AP); + WiFi.softAP("ESP-WIFI", NULL); + + localIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(localIP); + return false; + +} + +// Replaces placeholder with LED state value +String getLEDState(const String& var) { + if(var == "STATE") { + if(digitalRead(LED_PIN)) { + ledState = "ON"; + } + else { + ledState = "OFF"; + } + return ledState; + } + return String(); +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html