xX zu!bi(7O+36@%G00tTw&3{T#FfV)5CpsxrRN@mn1?I}+{e2ZexN6bOvtT`n+(NiGsm zqdLO^i#7z0PE5?9Fc=J!LT5)7^)?10CUEK505>6jnzj;D7oC8aw>ZVvx*0HSDJH{EX^5lf(d0qS93
@mc|nqK!G= zC9_p6IS5v%DL&7@0aC-ms(k|U6PZL A*zeUF zTYd5T=Bt7i7y%V_M8**803df{l1}th$xr8)&xc!XcX!J4PEBQoZa@|^pg3BQZ8TKs z!bh;z?D5vsLS#h^?ogypD2Ir0hKDl3-5N%i8kQaT)>EZ2ChRq1V6B{1b>yqUFiq1@ z&m=|2s;c>wf?|21jaEd&GN-jpXe>wl>%_=%fcv$AWm#zVM$NKoT|InOb#LB^n+4Re z+in_J>$eK6<+`gyCX+JNm;_^l+X~u7z%9ZI-44jf jiQeuI_<)|2f<3I%0*ppWNJA~3wRULn_-pYqO@{ZRPEuo0>Vj$W;Rh&sy) zcdh#zgWXnN=SB_lHeY?UG8f4=tM@)F-KE!yy-unc=k;^Lk=X5y+;Q29b=JRgSA}3N zOmowK>_sg7&cn0cd{p+T*y}eRa{VI(R=;9Q^&;`ye1!F44<9eyx?_h{Z}Mx!V!zsD ztI}Uw|G6hFWzE1R3m-a2*mOK|6lxg}FkSc5w~L#&rn1F~TS`~h?2;nQ$*+7zWs6_u ziZc80+)#Fv8@!;bIc|JE*% *-&vr}eKVn|40J?PPcG5ih6G=B(V^zw@ifoUZp~ zvMTv5CPTc$*b8_s3Ec6otsj$%oQhglwT61^$>}&z9*dap8lC9aCyxYA!>bPc *zab+{|n86 p1s zr`o+zI#q_8G`Mu8>j2p*QlHW(m7vMzJ5MSY%Z^Z4&z7834Lv#gX)i`6;y74l oJ56iE@XvESSyE>h#J(D>E5S&`_Q$|bK0+J<_Sl! z;xKT`q`cdE)|~D4U%Ct^>efqlGlBMnv`_JSM}3W{sWaH<7ZpU17iZHrkc8n%r!- z*X$^L#nh-#W0@&`00G*?g;eejW E&zr8}d+Kg(KTmObpJ!R}wy-E*2R*hAX(2 z1yeM!Al@Je#dX+Ki@WC>$+~E=APF}TKi>Sc*+haxR |tZM#0 (h1V)$%RF{)E0zx)ie2bAd8o{N^jMIsbHX&uase+E zdu|l=$uK+k1o 8=%-=YalG&HJJcgMLjaLnjbvPAA z8gAefVH^9m0`2=Jh(Ni5`TdW)-bWR_M^walt@#)8%EH2Q5~EuAz4Jg%CsLOz3OLB} zA 8ae+!y@TFO!$aFB3ohZUElqF{{A?sSL6kdw~psq1G7zA(>jfiA&R3k`Ljq(Z) zPm(-rg!u^mI!ZzegYhzh7Rz7}H8?g#BU+%7vprEO(h!CkWXn!W&tt;}<`F@^%$Bc1 z2`~hJ;T|U9v88^-lZhxB%VmmlquLe>3&<` a_0W<2o zI?k5JU5@gL*;t3jR7Evr#-_; 4(x_^rCpt!f1@AIY+A;kFXEHY}$=a^CckRED4SQ55atq z9RMPMweMjpQyJ9qv$nAgMTAkPvkHV^`PC3cO#D2{mkK@a2^$I-PLABk0+)TyI6Quw zCyRH Z> zQJyw5 d;62A~i+zGZb!}QY+pO`U}>Ppuvn^%P8HJl0wl6WKlexRh1Uc-OTaZO66zE)0A z@VjxdYrYex#|e7)!U@^G*fR^>%gclcUs6hfLW}-o88}%)SitEQA8@WdDAaZVCUuns zn0_e&<|ht=S7 2jWb^fc;d)9c7CTKQ5OZ_h52mTh z%?4w_6!KB^?#<7GPCxXAGn0vsw@rUo6*ovFRMdjn0~FM5PnUgu*m68-`E*9sE4Jr& z+VIlz#nLd 6tw >C- jZCF+ z3|u?L$_ByUE6fTF47`Xq)Qf}(87FP8ZbJzI;d{V8^rCL36MXv*!bOoiNRbv*bWM8W zpUm>_7Sk=gbofgX)^Dq{aI&sz Ey50ArX~bx=R*F?BOlfZF|j%DtUKdcHQ#q zy1v HsR zZXGYU^gry7Uk**YP=Bh9 fnaA^h&3@N7-4rIv%>B& z!3=u}yH$mEstWH`72c~Vyl-!U>oCS<#$ us_r~cNb$7ZE-f||9bIo!$SLXQ@OSmzQugtSFFK?c%29LOg1TZq$|Gbj_w~?&n zfP#Masu;N{J~kV^w8?3=iMB9u8OP 1G7us!Cng=Ob7TFV+zaiF>K^?3cWnzrjzSoeCDJZ(ofzhTQ;jT{_Ec$B$ z@#gzC4(WzX`;Js1*IiUBa)7bDUq|LCrHx)SsA|bbg%5w6!3m0wf+g|gYB q{=QRfLCYf3N<1TY PLLJdb%JDc0 z?`MnTBzu?C4EG?jbToluPRH?dAKJPH3B=Qf0m$yb>fHGbhX?NW>0yev R&$7jjIr~hRQ3X{@!P=-b zIXFQP5dW?3Z1rlj1M$;{e`;>^I=~PqTYH>pDW@6}a{8d$w@e6ZCAq>Gzk#!Dq#-Gz zeXBW &EvG%-z8p=GCezZ3N@*J^&>(f)p?`T5!aK6e24ywm(*Z2(_50DRGDez`V) zFC75B>@>GJ5(2G_(7aY#!7J)j#_-Ob^E{mt!&kviO*Rz4-(^5a{1v(D^`I3zBQaJ} zIcOZI+MIyqa0cx}+MyCrLU?I{$i&{1GB1~_Qq<5mBwy%KJUHhi J#v_q`-1to7ZcAsOls3MS-Uh%9MN+LvZIEEFPvKt#H%YA%-y<)f zD4(Z?hw7Sh@BQ}a{Ae+nBs)|&9|(2j!D#&B>AW>xr0){oIo`DaPi>H^#EM{`SE}FY zoIiTh>2&rFVP72Y=jl(${?<1Kt?s@1|8TI+^iUWl$#Hk?$3gQh5Mk>eo!us|>vv5b zp=Y$px?azemdB!5o)$h#4+bR=JCQtufR|~WC3pz+4nQvIt2BRV6A5~$3}E>>IRpYc zCJQ#X%;;iIod&mqH#C@_MpF!6b^*<<9;`9F`c5z$&Rl^2zT*{t4qPugPj25te;jCa zXghJKD{B?4%Gno+)}&n%d+U>tV^Sjbqh%1LK!->bXmIwM(S>uw^&MJ6XPI+R)IFkc z(bWBHa C4t0jcZI_y7CK)+cktwVRAUU z`FMK({OEgZDk{K7tbk2A9pvV)BK*h|xl2)%zF=i+t}D~e+k@_1S)GfFdBj}j!B*$? zZTi$&W^Z^m*2U$72};9G*r4K`=n3ZCz_Cz6_}AYI3VSpYY66piCR6|)dx!&GyXC%G z1JpG!4P>W)VZAnD42>`*u=FoLXuuMLaj?Y}y9L5~oMk_z38hMoIflh#bdf9hR(%oa zjVOVUCPv&r6M8e_0oCY>pwL>qLG6Rjg6>`T>wZW6MMF`nKyp4$nSjE+{4xj|1ZtUm z{mom6xxO%21|imH6T;6*k1(d`;23eYhX95R) Bfe&o|wj7RS5t7FVuIucKE!YF>+8Xu1q50|wLvn~O!EmY6A5Vm6Y z$`EyA0_7deW3P*R#qyLjnsWsKzy_t=`%zn4$cL3oA5N!?tz7#DF%ohwUPLBlCtkRz z2RU*{MJ<6QqMUzzmF22LyM+%zMO-s}EaaNoL33+I4oZ5Tb6LH|zY|6KsHrch^X>6z z9CWsVKZ5+T_2uWCpwsEme*utd*e{uYrxUToSTm-!m%Q`JLPCN $q@<(O9g1D;>Ra}Fi^T( zJm0g~^kTc+w#R BT2VSC0!2aD~H#Q}l?!v29w zKyTSz*i`9Sa|Qd;ppCId Z=6efap )nM+OlTx} z!U39WuBJ<6N60eoOH<@aC*FtY$Fi9Qpkj`l0-y1GGU#|joOI%NrzX9W=H=yct4<80 zjeXTPkyqq~ylI#eMfdDB&5}F+vOVZ3)6_zDBsvuPa=+qoa9 xiJep2x?nWS+)}l{^?E(%7Se4JBdaPZ* zlBsa8g-^`hgB%+X*P@=_u~T8XBR!(wD1-WA5YHzdYrv7L65B_xc|Mg)7{Bn7r}<;{ zB&cHb?S8PGvaGa@nsPk@zTs*gM+Kv&!Yt_&!dVt3NFL+Lc!}O=j2Z*uiy3pUfhJdg znYz$@7ag<5n5XQ!IaytujK<_RNi#1H6z4)~igbyFCtK*#T}wf62b&JU20(9w%}~TC zA{RrXOAT1$%k@fy|4CV++~;k%f4SxP0RU2q?xl9RLk(IR?J?j zjWS)D2H2kz{7BfMa8=gG^1?-&k65ZdLisz$)xVp?w2l(t P@X)y8{kcFra7w+u!?>&6?0v0bzIpzp*w8Mpcgub zt&7C{O9FSe(%j0=f{9rS;0LKH9KMJDziI3YFNc>fsuRV;K|O&Ejrakg{Q;Etyr6+y zhEmhuJ7{(Vr`~RtqJg9n72y+xL{3c$g)Ji?ZuI_r)IhVE%S$){kC3WMaAYT&0wT}% z&^i;t23ko Qsgli@K`Xb|Q?7vi|HVpzyJP%IZ- zpNFC>5-AYdZE4oB#&~w%6N^n{0{R+_$JZs8UHCr|%-(SC;}VQF`b=P%rYaQ!?ez2I zKsf|C{K5wV Zj7XGhcMAuGlI_!X zfO8ac6To^+L{BnhKw4vLf4s;}5+NwHGP0=n6VU(pKz-|9sLy}y3r7;*3X{X^{FWjp zXgnQVBn#P=zfe>9$SqIv 1{xUs>}-QwdBcqo|2=qSP0^^v@C=k!dB&5+3= z;qM$cx$cCs={&~<6z%0a4ld$g3;wIO5P*_P38VG*cvdnI1dF4Cx7oAgyfz1cHlFWp z;a}aodR-gXNwF%l8<#r?nI_>3G4Orxu_svHzIk4mV=3!D8fTPRDQ(Io|n z3_lGUzERWh&f<#<+j6OQfJS~YjS0Om>Jbn+VjkpQQn_J(axCO;q|j;|lLeD1;jdg& zT8hbHbVh4Y<3558{b#_8EigD<`8qF#Q?m!YFH{!ANLIG8B$?W+#`3&kRB3CS UvRc6n;4>{c>Or9(8rE zvRoxMq36xh1$y=%s~Y2%Wi}_al`mMRDK_aVdMM{RY?AR|EZa6Hv5Bbo0{w(UDFU+! z-)3{>C4@l+lmuqE=%ufDi1)#HPj&=5uqVM@_RWJ?Z4&!<2K2toULPIQ;Dc#b#ph=G zFQ4wzc1O*_;biZ9_p FEq*{4?&J07w8&;iGbCSC<}? zOYd+gOt4qB6p<0C(`63z=UE<)>Dy!2%1g^)nF2cHy>@#vPg_SR+%X3j2f0nH+9)T% zzm&m+pjCN%uqY=gasmfiU_-uCjB1kryrM}V2JeHwoRS%e*B(MiDw+Fzz?AvCw!|N! zIMM{pz(~i=S_d&Kez)Z=TcgwEakgl&WtQ=jyVYSi(&>w50YW7110_=+ZKs! 3js1!#wv~-D zS%3|xr)K0BAo&!bX0RS^|G)nXJBPt-m+R8|fMLD1)#;Gaj=h=97FB!s!~gy8e?I(= zU;YjJ{og+P?+<_d@K@ z5L_2;o^=r?U+^H^u9d6cDTxn>jR^Avrj7&Bh0Zb}tMO>%mjdI022_+J2MGfREWn zAE^EOEM1O|#evucyjDjOcubNcnE`VXc43-V>(%g_|BjYKobv&Dmc)VKf&pKk+7mR5 z!L#3~_9i6o6Vd4=oCCd;`Nin6c?_oUGIv3lUa#WO zloMH4o**6RJF$jWl4x%EBROE1Hq3YHB7v;e8^oXwIO))bry0Bi;-g-AffGI(#_dP- z-Mcyt6S?IG0DsO-HGrD%-D0_C`_4UqDnFcFr2GgY33MILB5meq&B{F8L lq0;j*ow#hdE&B|rj2&E*OdyLuh>~t~a_jFND*v=|gf^*}F2G_ 4#2U`y&?u>vw=ZOMtiC6>I-GHEXJ z80|4?>PIrqKpS~ Ulb4rF^f;PaEGFP^@A8sb8gVmem^OI`|YL8c$V?|Fffu* w@V{~b6ZZ2wb0PH>MdfT>=|NRsQ_iI2M-E1d0ZDmv1 z)=k=;=F%^APrGaR_@hL~VoZ@byx3M;KgT}MzSzzTKoX=#iAu8FwrBHI7KzJXW-yo= z0JZ;@y`RN|eIss!7c50MU~h$Q#}WHM+=Rl5m?`dh>_3C|iD$R=PTg1x*gTGxgMR<^ z_O=)JQ_r1V_q?0ElfaMdX*^)AKMUBo9bYi5_VjwSgsve1Km78GXM1P2ZXDxy|Nhoq zymv*k_rjivNf2BY2AHYB-ZWVB^WNXO@ps8Ywv3?Zl^f5KNvY9`Fjx%OOFO=C?GF39 z?JZmp+IxTL@9o{#A+z7vcg$k<4@Z0W*u$4u;!k5Y@R`|S_j?SR-Oa b@U*cQ)gyb7E63b%v@hMl3Z26u(d>! zI0Yq=lSKAi4+P3L)u5I|Lyq{j&(HXP^R_H*bKdG8_7YLq%@2j`tfJVC#dL1_S7Lo; z2*0}?H9W o4^5y)s6_>njhcX12qp#I^gz&;CMzBwhJIHxcj zv6}Di03Q*W92bM|<8BO6&pV9U%O$J?8wu#&bwRMZvmjh_fpFnZ14lSqO}Cs|6X&j# z&-ayx*QT4MH=FZ(o^d7smv99=&MyEejKoYVy%sB2oQz--=G3gWOrp6d(fH}@_b0&u z$Oqg_Xx?gbi?=K45XLz)xM(T7GqFV6+NOjI#9hVn5lnhp7Q72w-{g;ZYk9Ax|>V z@e?l =;WwVCzAo@d*t`mieqf;VWCy=zo!b3%AO<@hk;ura*)FHsn=&r0M zeO9B8X-z8Nbs8BJa=BemBl9(l%u5 a8h38;FPvAY1JNEU`5!jy1v QL4YKXv|S<&W;}PJ z4lvkLIN_ATf=K7e3#4U$rDTWGc@GR#MBFzITD=Gi2lxk%jn?`8MVt3z-=m#qM6m@a z&6boGT$%96G=~Sm37*{|f_cy64Q$SHN$%IH?;X?7KpHKrHu`#XW?#Lw7s50=*Jx?F z#|3!%NAPu=51~{el(yTsC3o47eZH^EcS96Hu?TL&$=vlEGXoDyLVC$+?=dOr1!nYI zSX|+EXRltewuPKHs%{p+>i4{}U ;BJ`smr*di7BQ+tqA6d|%KHPK z`!s6;lq@~)b4@P0F<1k)=+&Z(oO3&L64wtn5tc&&g@DVZ!Zp&`ka9+E1Pd5% avBvg@_`% (ODF)JYg9N zJG^rJ!L#KZtal>?WqTrw8U5{IP)H0S5^(U8HKc*0;9p{$^|#YEuX{^71hb+MteeS8 z6l04mM0h2Xxz?*YIymYq7jTsh0A kqx50GVO()XbDjn@Su17Oz+HZ2$Marj1Bwf? z)wzG@WWG)sm?`T^Q;Pl&;-E}wZyt&njGlot2&{oK4C|`sd`ZibLVaZM7p^B>2l0yl zqFqjIWY$_2$_x(#k->ZphS&--KTbuVY5yL`-psv -S4w zB!nJl9QVrK0niQ_6vER?h1v{d%rba;(`>YPrUfUl&*0PbT>sig6=p2%;%*FL9$_9} z;Dg0GqB7e9Dh8gI#Yf;~$D#|vP6adwL02C+E-XxYHE?}^CJYvX-W9QBNRJuy>t>{m z`*ss`f4INT-u$p;#OR-v%u@650&H#ovkq1&BK1VNE3L0u1v*ka(h6^8x%1OvYzQkN zmr8;`nvPO0GdGN4o{Kgs=+sSP<&)1IvZoKTr2h(HQ17o*i^Bgesanqv^(_O1%Shwa z@pG^EosZLQA7y&n)D4Hl%Gjy+N?RUTIJUAN7+XOwM&>aK#8zn_wyvemG35FReH^2G zzPh-`OzY}m4eLV3UfR!U;B6FaNjw)PL2&JgLNGd|BITCwBaLY}b jWr-Eg=Ve$!fV+JeyCR2DAd5XvI|Y+81*w<2C=XP z5G~URKvb>+p@JG9p+IjBllgkKjd&QJ!BddHBxwFI ADNhpT~W72=RQu-|4*sZSxJ`F{&vaaQV$!pt;7Nx_E99OZllz=GJOvGtDpI z^x2>&lB@1ZHfm&VoN|P@GAkAbKBBye@3Ol`KY_`XA`N}K1@a0t8x(?R3fuSML zM_>BlD*82ug+|}@cv2%0gvK)s8Z5GJgwZi*=hSE$(`%!Fy{!tkmF209(1!|PISb4O z!!$#~gt01^;Zjs)fTR>H)duF%s+fdB`pgfc<*R_nrnZmcBBOdR05m e*_8E zGGqvY|3b{MQJX_uUTadIYxU(^XmO&`@1kKnZeUk8`2`?@^}&5J7Zu{w=DxE^7nVI| zfWeA83Tyetjoyth_~O7=%R%O_n`9%i#yjLCvpx^?!);0t76)yZDr_=necG;W$m;Z6 z-dHnMB`ma;^2(>|fZn#i$FGN&yQTcKYGH3fo#WNN~ols=^@PL zcQ$B6F<^$OGY02IUq1Id_eMzY7udF-2yhdHTw;bfc2o&00+YjnnXEzti%MdfL2GEt zHtCsq9fLEWb9^_A8C9}8)6*q}zp_^o!B)VnTN{*m957moQ2?%y D8e1yC9lBKxn3W8P$n`E0#-n^A9?DTX;;9r83$-KR9LD6AzS(RF7 zZG)?-aWUq}A>-c02IyF=cfuB`Ikm#~QTl+Vj -^FsgT1vo@^~BnmHdNK`Q5 zD(v9x%`jzB0CWg1!37-^i_q60tD=$iyoL-2bAe^`<3dZlYid3k^)By%AOI;Ls(UUn zS_?c2i1ilM;>%HPB+@!k^Yc*4Kd7})R_ybTEI4@1YTC8*C~s%;i>17sO;Veev~k7Y z2V{$iWrr1IPb$iuR+K%fDEsSn0(m>_(&isZ>K5UXNinii`e<8OgsJ6>D0HpzN~q0_ z%5I~v336L7as6eYC#&etZl;!6MHR)t#}1}R6eO`_=!cZl`J^!iCqa>vOY VELy*9K2CX#x(Wg2`U)#s9W2w=8kHJZR9_ wFi@O(g zDC~cM2~J7<
z*@=u?Uh#B+K6| zk2Wrr_0>^YKIv;pGZZ!OjdD?LD*IB9rFd=^ Bt8KZZzfxV?G%3{V{F~ z{oaHoODcXeWrohU8X=Tt8H#Rotz=fK$CA8CIZEZD-jP>0!+2~5Kc4W-H;Kx5^EHXu zuaqduFh0Fd?Gx({{)9rMQ`SVN9QP)jc9}%(O0@#U{sy-!OX8+AFSM(uVIh-5OI?C) znUdDB*lpFT3U1y*7fF5OYd@Gom@9{}LWO6qWD=b!^uKadfqzrNVV8(iO1cD?%ll@n z9O7K=;#;W6|GkOpX2U7DD<{}YxjW+WKvvFgi9^{gs=QTtDr|xifhRELPj{IdXw7QX zWFz;sWaA5NY>lFoB2IG*2$ywXZIFqVVM}H@o(sEZr0c>q?A*xTSYyNRSdM}f^wibJ z$&Xx}|HJOS-|v2T(Z6y#yh~FCT|@Xd!{aI7B*KlGS8{Kna1=)EXJM3<0_Y>OK7t+h z2^)Zq$9*Jv__Pap00X 82d+&?7p-W rK{c$c`BJmJ) zelB{eJnkxNxHT&eb*-O#bMw>2Tck$!zhb|86$Z)D$npNS%+{qd+Liv^W|_*e0_ubT zDv?~IK!F^kdz<(J4oJG321Qolt&Iw}CrqBktnmDbGMaeE8QrU@jdA7qmF-fh&nvR5 z!WQPm4UJ5r4UkV~A0 !$%h(ep1Aa|#>TDd#Ph)y&psO)*_4kB zX|c{!^3>!;Glm#^%f0KSaJurqa3`JJzSa>&>2P;uQdPJx$72Ay#yxlu@nPFwb#+hL z#u#Iz`*o`f<$bW1KzlrL#Em-@R&b4t(~I5ktm?Y}muj?=&)F%L)_r~ZhtA xH$-kx>l&dY};NaP3Yu7vI zhlEP1!>CXXQ!hxIb-j?Enx+QYx#_}sn1Z0i*>X76&qV8pZ&NFZ8akLZ*gwMSCIdT( z1F3Kb17oPv`UVo{;in}oQc`@y0}1vN6<}wrLJ4bycFfqlfgKep;3P*wsa193w+Z^+ zs7sk2LO?IZy!j_2B1LAM40SRpUFe%I8m0G4Ej+1Yu Su> z=LQqBofK&Ffy6}Nbe$G? 5sr6G&uJkN-$j^`ajkc4wQ(ftxeCp#CP24MY76PzO zafkwjl)%!7DWpw4j94H-!fdb=0@nAV`Cd;azrSzbHKNnlmA2~PL8U2F&NNr3k#1h` z5HD%)U0{Q5M@Ob*4FCJTfJJhI^+={l;7gaH3Rn&ETtyylmU0zfaxRc^NE|rBcW+ zWkVI5%fqR76q;OthORdeN;0*BKFWT3W7mQ3vOw;a$b;KE#0fiu3Cg>lhie|b{Mmp{ zDth#jeDYPlX18X!aM?8S+sXa!lr0>)Hz*w??PJt79y+oB1QA@~dD~F$%fR(xs7DBN z%n=86qZnffu#5+qY221yN4) xQ7CmFvTvwp G*x~?C@sZ zXUB$Av|K&omB&8HG4Gh~gjt%e)r{j96MQ*m+u)ZQpX%fQi4$HKFxQfmwU#ux`9p~e zZH~|e0zP#C{T-HiX;G_ Fc|plFxYrYj%H_Q zyND}hDK?7Y$?4xU#nyOB2Ctv1yEof({>N>W<-1Yoh}$=spryHsQYO&0qaQ`YyNof5 z)kP6JihtKxb==PT7PBC{Wooyz;-@co`) Z(34q8rb#P>IcfmYem(t*lhL?u<5t*GEa2Wpa53 z8+?-}!E15*@HtKV{1S3iA53~dy9HiY !c+I4(qVWDZ8TK+)q<#>Aq2J9#pPXj z{J>z@iCJ_19QEw42lDF>zMfpP%mI8qyP&ex{o#XAK0&*NA?lu|ZQiTOfT=6MZ9ZW8 zpAYuG96Z_27F;PU{N?^< 3rI_7H^ zlgBl8SMLi~Q>%Y2Zf)TF*5sJWq6^H=%iE9}lG)SiJjGa(ur> !#c}Au`ap!qvy=`jK~~3V z3PdT7#GRE$${GY=m-_5Tu$C04aDdzy{uDqHselrPey*sbY@bzW?Be+vtJ0=D|7Sw0 z%CuVfS(sAK 67|}9V`hSerFm^@Fo3Oe(qx0BmRn?yc z>Lfx9C0h_uG<^s{!w*8}QT24b4&n^(qr#MK7SKWvS}S|BUNpC*B!o}bg)nn43jPCv zESi-Maw$?Jc9?1-(wXZ@t75^|nR&dp-&Fx{(b}guyejTx>4CBdqH_&Kb=IJY*~9;7 z?^~POII_jQ>sO4&8x3F#9)upY0f8)8l5Op^Wkr&&cQ3(ZfxwWQHHpEU0Y%a>tCIT% zZc>%1{ER#*Ta|oB@*#gf{zo~Fe$I3c0FturZrxo=0?^&3yHB6)KIim#I6T-km858i z3_)s*CRy$ky#N{(mrb6_#x-SoB IfAjpV_M43`+96&&&UY2$|R!l8bjAD*pqv4c?XcxIz$XXkwikNfz;!N}igCbSI zJwHSl9m)b}VYrItzh!}EnOFkPZ3+Z^_gzwE4x*NdI&_>BOO%n?j}#}c1|#qRkC1hF ze~C 1aTe}OC4S1BRU1j8zX4Nq2q;_*$ck?0dFN6N4Dz&-hn+qv`qiVZ zROmkFqOR%XU;s90zy-Tp?g1ZELCUq~I{L}uZubb5{@?T;vYc48iBlFrF6|&|-X+?T z%Q6dD!)2HCZzWyd`~UR*FYo`?FaQ3Re|rDl-~Z3|f2po{U*3|)Kvs63?*zRsJ7x-? zaNXfHhh-X&hO=^tR*l_g-Oy;jK6TJMKrAZfPm1joGZH7+zsJf@VYr@=-01|9hOPJh zzrKn|d$DQfHJtFbqBr4mRC%rEa{CHi1#6`lAV;I# uALKY=tIa({9BwFGMW!u@%gmLpwNhT0~r50+z{8os#qs0YDKj z;DMZbkQPBYpJsUuhb&aRa%v!mn~N;{_zG(r)xBY9V}Ug%feR-viCGU(*o0einw@0% z;N!!?!(l0&_cB{ZyYSvnnu)6*-#@h}9O2+|_}_3bnc;H;UWmax5>5>lm9>l~&(p(n zqf^M?vLQLXbXMcpQ@YU&l3T-YpJ4M |p>0n7@d^W =DwNeh&$ zC&CYwvL+ECWLk-VjsmaRH;%Kjyug%GyS=^mG@aAOt-ZKNru4DDx9Tp>j}A6uRWyEq zLpnP>DACilw>D 1xGMN)!dkLEBO_Psk}ZC){Hxh!bqz)}EeepO);Cn;`uv*t+nS-4 zx&G%gvPQIov;1=MWA?U~bYExl?C@~^hxE&Izc^2q)8i-(4VUd^D Npm>b)n+g8O!4$l@xInZg?)JZ2SW2m)V#1$h+R$%LJk9h(dc6)Mi zB6-Iz&M*})iW*4J#5YoD)lRg`Kz`4&xFzmT4NPZWN#|`Ax9&aYEiOttBkHj*f5%Y@ zcj`e0&W~>W{_Kh)rh7UmmPV2nBi$JZ7*(3{Zj0b6>O8=t?=YDH |byICfEa zXlZ|UcSR{Z>WGL}dwUoUrK&V{d!km*sY<+$^J3NVLpUeo$DkYV=itrPTMyye4{7_$ zG |6nSnVkm>ui1d#vI3aTa2vRupz*`&{%2cTUHYfreUW4@L0~=! zzIpbvsBPXZj?+_y@%roM-v*5by$8MSy$Aizy8X}YJ@B{v^W-EuD^l3_zZakU6Gp7G z^DKjo2t(~x@Y!1(9qMBF z@4Bg?v&_E9&XfGfq(~Y~X=3dlLjSd(PYW21p+OcKS2~S36;a6l2B*pLID=kae)sxK zC|vho2J#|J=2KQ`ox(0l7l7R^vCYEs&9hg{havQE@r|E8Ulh`=R(2{5uVc#GKDc)e zjx8A3G+Dqg**Qq(r5=j2gHy+?ZXFG$N*4H@ItdQ&CNl3VbrOs!uJ6{FIF5$S5gHLV z5JPU1>x*hbw{bHw#~uE|L13<|lo2ZG60k^k-HSUE(=2>63g%}gCn(gD4;^|9 z4(OV1Rwguq%FBdJUDH{dE(o|zStA~pqE@ 7K4HAf|a*7)%4O(m^r zbVN@e`%e=b7^leenGFy;PNtb2UN#h%X3VM A;HurVm%#4rn> z=llS0IP_$6!R`N6VY>iy$NbZ8iglGy#Go|QYL^ih?Wq(aI=c_aK9!2Q>E3RX&LYaw z0<)CDkf$ai0BZ~M49!jWSHI%Qj$EaZS-?z7h8=ys%}3w!lsdd4(%R9Ro(5?@>Xo6E zN}X@Cs06jE)03urpB?^ogo?G`z@u|bJ+;-Hk*aoU)Nr4dJJD7&h `sL$laaJ5R-i7Hb9MHrMPqHj;SUC7(iy{xjIFN84hZmEYbt@dO{gZHyh@cv* zFZ?W4IcCq80sb9_yj#M-*41Cn*?4oh_wF?1n~e-njC!A^$aR){vguaU$*Pvfb~H$E zS455NThRu@E7G+IM|Nyp ?}j1ob42isQ7-cp zuCW2kb?}Z1oso$=SP^-%;dQ$-Kz6R)XncG#kxP>#75W985B8Ti<;fCKi~>2%$Mc`Z z^Kt$&{+oA?;&42ND@43x;b$+~CEz-kEu&k!?qyBPHYflO#S U zj1J;xD9zuNQcVPO &!pChD20sRW QLMed+@%Vk*U&sjRB z1BS12I`5g!!fITK#~xKMX+ru30s|VS9D0N G%~fpO|o%5Ox=n`6%p%A0oy&aezi*U}SqcIEL#8P9;``h0GBq{T0e87Y|gvf`I7} z${#kId`hubD|n03I9 mb-Vv!*5)=vTp{b&tOP)0l&qtm zfo0MSlp@7o5kREeN3j7}gla`R=b(n<7zD#$w%f;? 0!v%GyTYzbex}w2Xgz=r!VS*g+N0ZN!Y->Y*W0SEw~m{Y5Qv zg(;YqEbstA{RUc`O&lh-bsi65J6ahT>if7A_W}7Zku4_Eba^@Gb^1foEmh*ZVuLJw z59w(?v<>~GtB2F*SVh`)J(_^v4RR1!9h-`LBFhqif~@ZIvxTO<$k4*m=%R3LMC#s% z8ZG9ZmxNOzUQ;DIyX#0lzHb`_sO2V$L%1c_q&aX`>XtnPYa$odkbsI&>fyE5km6+_ zuq*XEYc{I#qh=fzn;|7xkS~ l8DD>AFzB~{|jL6=dB3eCE@sC#5BB)2+h+FC%;lmx6QAt(-oqd7#fWCSj@ zHV`r&*#r*Qu2zJhjz^=BVpMlz(O_dRS~cOI{oCLwOoI9= %=@etPkQM1NTMWbBf}yXynts>+wOM;c(^x4; z=!W&Fcw`)s^W!8JFF1wb9Bp+K{=#ZL_=R*Ia4m_q_i~&AVS&(WZ4HGQ(N_iUD*`Is zLyaNWe!2H#?kqGREzTAgW}jPb_jjrkPEBRvOh6Abpzs!v{rFkw!bhSv?D5X^B3DE$ z?odQEu10QfMr|;n&>3bV8kQZ9&Qql}RND >g;eL#xRFiqnZ&m=`8iMsh!VpVv8 zfYk)5FsHRn#0p3Kn}n`#fcv##SXgNH2D7khT|cTteQ(~1o5i`X+in{0; yPy88GO)61V?gQrzN; ziKTij+lbJE3G `4b6RprxjV1})&1ced<@qAG>0Pz6@1 zyVo%o9539B?sJSmSAU%wHO$+5_0`IJBj2pv`?PYG-Yg_4j@Ets+;V_ayCZkF)N-Bm z@7z_9QA^X@G)`(6OMl~0Q*S?5YF$Xw+mD3$f#RKBGt_CBcy2%NX}O0F7Y5a_L+dyB zjY6be@3K` C*E8G)%>_tba!ZCq1XzT%eB6*jx1NLTVJ z-%(lq>s(Q0Kb{-Pu5ybPlr_hV? -Dt$^<>k|2e_T=4nE-JRN0)hyZdka zYBHzmy_u{^zKh8aFVTAx? JO2dg$vb3HqoCd%^y^H8EQ0Q(k@;AwaV zpuPXWpXuX}N(eMpAek -WTuj?To_iaY@83Ad_Y=T$qw7OCI=&C~U z+BrKYmU*KWTfZucePK+`+g*aVdsjl!6=@u7*B{vG$kwQmC7|A>QY|`7(6FqOooXK^ z>Dd%=BFYLwqJyrg=uc|9SD?w)W>0zn%a})*uvI+9j7J{!mCPrnVh1g=m3xL52B-(4 zn#{hNpP-|ZhBF#Pgp;TgO@U0|2y0cZ?x;mwnLai~#%3?8vZ|TK8@z50M=jS(szx#c z>p_g!q2@-Ob}P3$-*!mTYD8q{#A7n7j@H #SRcBTF1+i2I?YI3vTUb7=VmDBA- zt!1W+as_A?3thWEn16 i#tcxZKlCb6W !mJxjX8Uc(6Y^ zu>u# )gVgb(?z|A=Yqwbq*}1 zceSi @+pctVEGYn>+ekjR8i9Io z=p<(`$GVPD96_tt!@;lXn8K;XRR?evIo<+a?DxtR_91^`geVV+H5~rSO(Y?BDWzO- zO^Wd}uh5XQ-a1rO(}6qCz^_DNte`?}Xdk&DatquSu{P @~*j=8%)Y%f;ruX-bd2tS4;mTtlLE;w4?cnSV9=#z7a0TV{c$o z&T>~>{pw>>CCgMtWz#NER2LE2^u(%`{6ZqB23bbCZorAKF0%5nI+3Ev>VrL%Q<^$q znZ@gY<1CdGOQ!%C+WkoGP?WXsdF}idFZBinrw}W})OJas_-YV>YwExVEo$qs1~00{ zM%bx?TdlMKrc@h0zOEQ$KiMezNuVst8Dl@K!Wa;?3t>Rnt)J@fB`R!&E znykcCYU3&uxWbJoTyGd#=COlYv3l@O=rGU8LuKxx$AWB~6Q*6E3wXKMbEB~HklDdU z$QN-$YCjQBO^i^a&f3w)M8HmjDxzp${>Jf4%)ZR!F>K6eylQ}~!>Kvaa09Q1nl`*6 z5=0tApp@! e{znE7R7N)ZpHL>rU2YNb_T38v)^PN~DslC;!!k1=) z!b8DScA^NQz*W@hLe{lfDZG}Wu-ssDFbLo%S`o?Qs78>g8s(Z9o+d@u3X2K+b(DnY zi~b^m7Rw-yTI`_Sit=O@l_qM1`@nc#Y?h2EA8h!*JR;~9+45B=0fqoD+{5G!w$#sf zG7)8Cxk_ xywm$IiKnX zb*iYr%-Bh?L}u;u>0~((K6zh?uM}ww%NGJv(m^2#Q=_nwnrd|>i$wwgTu1?iW3Eik zn)xM79w8vlGdZ86&{wjY9ycNi>mS9zJC0^N2soT^9AHGCfdbBf2+<2TJ4rex*-<0< z`puh{%0G=ls}G_$?_fx@vw}m$O()ogU^eZ>XT=hbaGnImfQMj_X9s{tVC@GON>E0Y z`=o2ELm6QdZ>R=gSbjZ(5fi`2ilsu&JHm!ShLa -{7}bLdP#BnVrn`87kD{59$yxzoI;CXvS6PzRbAZ zkg*0=q1J~%tO%0nL1UMvw+D1ZTK_>niQc-b#JOt5LD&sja`FhW+cnVM5NI&maK$gI zdy}hz-L6=bI}(R*{U-B {t^uy(JE+u#^iTe7+1(fOVkaCzva1Du)I$|V5+r&uG3~@kuB}B;z*Jf;I zM#-ihJ~9KDG?lJdHm?bdY52bqB=JZ9{J?d5T^-k?^g!(t6ok4TxBKQhfqI;vhcBFv z{fj-b;GMiosPF|v1TVE1UR8mUIgbULe(?e4>Z4L^7hqCXS%B%6GT=KZgrDqUIXU9d z!$I-<#mn#CnElHmq&A+V(Oq+RRo}zY=YJmsKmY71dW;2utK{n~e^K9GbkARO-(U2= zU-ZyKjqRDg8G7{kv2sxdiAOeHFBq<;q++qtWKtS8=l$p;b@_;4V1`nTlfi? )*Z@P41)GDX+sCo1S;gGlaq?=tnN;{&3VJaXdDCAjsa^yF!&NPjRFHN z!hQ@QVgJa9fa}{((kb{J@DGEi-|Ge6{hjcyWrt^^MHS+X-uP$p;`{t$OD`S%(uVch zsw|wW>smPl$67l1t93|3)d&O?+Z|FGt99F6v!Y4}Tbf !_04PE+E`ct z&qr(8{Z-R;f@s0YRZCuG`O=4!n}D%UX0bC-q?nm?xtm+$TW}~PMx_@AVsUnN^%Y)a z9c43d=31e3O&)BhZ)kHE!M2X;7ibaB8F9O4s(#8bd{;G;t@OB1!67lYicz~3r=~hs z&8uCDS<~=q*|i(+Yt&SC<7C-HO^wcLFmD3J)yiI9Kl|p{6RTTK(sVj5_~p>V3-zb! zIG(Gxi2?s+QQK=nvg`glVc9LD7zlR8W?vJ7f)REXGAryZ6U?xuuwPerudeWZUEzbe z!iV-IxCvuyX5n=A_U7>y-#m*-n-W<>MJf~@7-jE d=CxbdzH%f#Sv3;*0A5&yvp#!5$LBidTG+6Z42I9>RuN~5jOrIi?1MZ?? zkz?WQ{W>yFB^BwaLDfq}Du(Zq3{Fsd6s(9Z*TY!>V?Wu( DqJCsI z_=ZF$n)`8&IaKub8QNn*DqBv{dC^cVYG$qi>WI!#_H8P?pykPF_BLr4-fd>-WCjPF z_K9*I+qwq{#M6fX$nL@F-1!oRNA3^lVT!op+RtYNVoN@Z24xFm%RF&nY#+n#46~Yc zis@u7d<0h;T;UkJ>T6k{Gf$T1S^i_eE`MeaOcesNG3m?>PEiQNf15j7gGS>({50X8 z+FOGjutdt*9;aGKZN!9}KC1RD=-JLSgEM{&r`tqBQfB*Bb0TRR%_wMNwwO}OUi)D$ z8eXl{{Gp@$!(RK-wE=wU0PtzA{n^?8K63#0tk?d0Z2+G;0DRtSZ}lVuS{tEzt+#_$ z)T_+lojn&tIx9zCgP+=LDuTbu$fx)#^4IG@D>?RJsIh94LsGUm0WIJR+KIG3FrtL; z(gvZ4oq=U~99N~NrEy5E{FMNP&TGgsD_9-qXZFRZx}qrd*@3S e Wp1L4ei4{TDOse1MU3~FHuh-i@gne RL&3dNn7#7X)wD4(qG^&8u ziR2*!yiEI?6GR_?WHeOSw$vsP^imsf^;L2R1b9p~Y;u_~LIiah+znpSV1fosF@V_x zG`nW7#`Kyy!FW7(#j*IFSNu8fz3e`@eH;DBtmKv(m%6f6(W;z%sc22wHL Te*#IikuId1bacA>Iy=h?Vb1dueWoew52mHSy59k9!g1g1KJ0zc-Wm!!Nd)x| zP#VPw0(Nb^(x!{p4#J7x0Jla1bA)+<2D+Fd>KIGo({vse$yC{N!P>web&{w^rB@t~ z_(rYJft0PepgDcn+M{tz=}TXJVS&4W@F~g@N8+DukANS2hfPHV_=pv-Nw0_899D!M zxgvKds?ry%jLmgr`gwcQzb~tEkui^$>pa@(-MvenI?L=e@5ZLMoG?#d*b7@!JP zyjwUHY6$=On?d1#W Vx3^1(MMvS2q#srrB1qdxz zf-nxY*k-pxcu%tI$26ggr7?$KnN2PWCEuzqBFhNn5z)kmJ7`9)W;~z X(A*vHE+|+{{xul|&Koe2UKfcTgRiYikN1-CF zIX@S2&F!GQwIc^5{m;3qIpE)kqJ7jfl+^j=_$&^3Tfy%^{@MEc(_YZ)4d}lB$Tb{R zjKI^G*kY_1Q`<}4c~v1HK_Q`OnXv$W4ug7;%@VCrs;Xg1ds>#o_Z~iwy;sJ^zNDn` zBu8H9;Aaj?t#e7kWz?@rUpjPo8wmbi$t_`5C|-r3sT_x2j4|G;S3g!Mq7c1&lg^Wu z>D=+F`3`hS2GQL=bv|h{bQX{1&%bMSk4|0wdIlUrXfb}JcS=owecs^Rt`ba2qv;cg zmz(pZlA#yMZSEQGxYm~2l3PxLcUdx&VVPfv3o`*|vjs~ +$X2G~S=c0prJ7jTy;DE4yAoD<5))zKay4GC5{y6Aj^bvXE1ZCxH z*{qQJWgM0f2i(1fHd*HAH$NIh9|zG+D6kKV3eIQSMkEXwm^)*d!FtpO?VR*i+A|D( zG>Tq5`{wZ<4buhZl*=vCy&cqR`Qis+5C}^594yj#J5MmqK1(TF(uWc}T&yC(Tq+Vp za;0nz*gIQrv^@&rLDGx>4zQsq!olVYYaGQo1A@*_T_R?Fu^Ms|!Kfve+R7XS9$WVS z1Z^!H_i&dJ^}> b2B?J`qJk5eB~PfY;GdrCNmgyL%l# z?K3#fJJZR@NyFU;WYb3Uv9MmiApxuMNz{zB6IgO0Tx{VJv-cp!M#QzKCwS~s81G1* zXgJEC{uIRX8OR!NB&+<=5p151B@@Ok{N!u?gnbF>Sbe)6Y^Q81t)r$|&wy_@+s9GK z?5Q+MI)!kSr3sSHxH4a&cN(L{$oOJL9c-b|6=0?*bl+vy>?tPJ`+h-oSErLHxlYo| zO9XXD>fH8H7-nf-w$P`$mV)9AHXVg6fZht*p@>vOPKHRA8Zgsd(<@2((qlTI$T-D? zh>g^WL{`gH8Rg(hvh2H~X;axfdVpxYb0xs+!iWK1%bgh~sLy`19w9|(8(?w@O{F8$ z?vL+$wXfnnJM~`;{fcT@&Zi V4Rf-}Up^{%lCVwTswAh?g@Z*i z)gPh!9pvi2nZ>k@65-}g52$nX7M_aL{b+S$T(-`ojYhAo^xY M6UvTQ(ZY3T_I#V$|VMyfGlq+l* z`J1D6@1ho()m&Y{5qN}DU4bJz*%T1@zK7PC7`D(#QUbJnO7ECf p-zwczqs ~^JD%Npa^fln+pRSD=TG#_7= zV0PjENHBZjy$?$;-uN?tWtyr~47AfPmLug7 SvB|Oum2h{7H5Sw3dj(LCXKVxi;`O&;Ib{@vCQ#0T&18_-_v1g$Fxq zjjCV2x5hvi<6YigV<3<5p4?*qx@jog^ `O}#FTi^o=;qXCT zx6hwS3xxC(bItEJqE6JJR>%b(pPe3H35-HK6-?%DCk0phSXZ1Dszy$EFDjt;XH{#F z11kiRFIN-4L%j>SaAI}uz)3 3T(;#e)RaDQ%d;YRLfC3B z(qb5HY;bgU_;>^!3MMi+O7L}kBCp&9JriRyWU@&3y8uqEKjUOj?i;d%1{%%Q)DA z|C${HpyX1*X!9MOl}rRdesu6A`#QO3EI^=*7rR^dSAVbB)CRVaP)dBP0ML-+V;zz^ zk!f7QdOdwEDu|jfhcDct66*27W)I8`$`WXFNueUckHeO4)O5VF_#y+hT 7ZHw~qh>G8!r;sQ`U{>LqY{9&QFvx(Cz$_QN3^fn&F1Q%T zj$j84B-pE=c`&O@Vjs_d-Z$B+qk{%~Fzu@N-0c48 sb4zEE=3}7`WnH^OriHBZmLC;m{P3X@SxLULQ$r26e^*3owuYVz< zdb5IQTJNA+?%g0;{Ua|PT#GqI_(PimpiI1`m;KK_W2f;Im6tGs%gK+~+hU?r+Hwp` z($**#1{D-a#&C^^tL)N0Y`RO`!3HQwaTN^9y%3Ar9KX^81`-Z>xyc-rMpy!-B!*fF zdx8!&4&TUGTATtwq^N{4y(J&9Z=tbYF+;qvaV86}G4<4r90MeuBGe2v!|ng~pJC@P zxb13PdLJ;X*S2~+a@w&sv)Q6 mP#a;?1)z;^Ye+rQ3~a6+9*JA+Z%< zy35pYK)TRbMPxl5&3HX{3K}P%v0J;ZvpMiF`{)C;U!14Q>9IHvyMWjFcmhvIk|Z-= zZo)21i+a5pp7Y<+l8AFYV9$~`FkCR;3sifGrZIT-JJsHV1b!kq+k|tVx3YqLW$I4- zHGQK#kaJYYL8K>6KRCY_T{e%wG+yN{C{gisJemq33(FIvCw(W@@JbTREq^2jEYpVh zepBQ>_IiUD^Z_Rw`tY=a7eIW}%OG&VXT!MtsJVMzM`9wk90A~u*_j5=5WZV1_iW#L zAW-FpGl-NQVI+aB<5{H59IaWIr<(`@AkH>%P{0N&Wj#{%7FXt`vG-hB{Qcx4o&6q$ zg$l?x jm3iTm(f1V+=5) zwAF|A3MO*}JcAR9<76MwT>WtmQDQAHeKjos4QrJ07AA1|i#(uw6VR+&mW@zKvbo2Y zy~xh;DZi(Sdct;A!4jMsS2Vab{-JX`DZV?Ozs$1*pyCom5aklaBa_)@xqdb2hn^-? zubB2fIcT7VgrRP*)l)bY8MqdCugljIYYn)w`%N)eRnBpx@$BjYmqMkMQ3F)PzJS{+ zmd}OpeuTCWkAf|!gT)HSkaZ;|0+(3wD$As~%oDW7Xs92_JOgdy(bY(*X7R*Ay_2j( zp^T;W)Y90B-e^=N(-1hvDd7{hn@m({6hfe3udj6H4XkC1(NMJ9YZ3@+R;Aif!)43} zYw+Nl%3wPZ{c-_kM6%?!Tg30mP}Mq+GA%Wk)UfFW+UyXq5Uk-f;!oqC!#I%b?U2t; rpMCS}&9e{}suIX9oP=G5?f*Z#MABSzJ^=s#T+@H5 diff --git a/data/mqtt.json b/data/mqtt.json index e24ccac6..da2a8476 100644 --- a/data/mqtt.json +++ b/data/mqtt.json @@ -1,96 +1,106 @@ { - "configs": [ -"/config.setup.json" - ], - "class":"col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{SSDP}}", - "class":"alert-warning" - }, - { - "type": "h4", - "title": "Server name:" - }, -{ - "type": "input", - "title": "", - "name":"1", - "state": "{{mqttServer}}" - }, -{ - "type": "h4", - "title": "Port:" - }, -{ - "type": "input", - "title": "", - "name":"2", - "state": "{{mqttPort}}" - }, -{ - "type": "h4", - "title": "Prefix:" - }, -{ - "type": "input", - "title": "", - "name":"3", - "state": "{{mqttPrefix}}" - }, -{ - "type": "h4", - "title": "User name:" - }, -{ - "type": "input", - "title": "", - "name":"4", - "state": "{{mqttUser}}" - }, -{ - "type": "h4", - "title": "Password:" - }, -{ - "type": "input", - "title": "", - "name":"5", - "state": "{{mqttPass}}" - }, -{ - "type":"h3", - "name":"my-block", -"style":"position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", - "class":"hidden" - }, -{ - "type": "button", - "title":"Сохранить", - "action": "mqttSave?mqttServer=[[1]]&mqttPort=[[2]]&mqttPrefix=[[3]]&mqttUser=[[4]]&mqttPass=[[5]]", - "class": "btn btn-block btn-success", - "style": "width:100%;display:inline" - }, -{ - "type": "button", - "title":"Проверить соединение с MQTT", - "action": "mqttCheck", - "response":"[[my-block]]", - "class": "btn btn-block btn-success", - "style": "width:100%;display:inline" - }, - { - "type": "link", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", - "class": "btn btn-block btn-warning" - }, - { - "type": "link", - "title": "Главная", - "action": "/page.htm?index", - "class": "btn btn-block btn-danger btn-sm" - } - ] -} + "configs": [ + "/config.setup.json" + ], + "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", + "content": [ + { + "type": "h5", + "title": "{{name}}", + "class": "alert-warning" + }, + { + "type": "h4", + "title": "Server name:" + }, + { + "type": "input", + "title": "", + "name": "1", + "state": "{{mqttServer}}" + }, + { + "type": "h4", + "title": "Port:" + }, + { + "type": "input", + "title": "", + "name": "2", + "state": "{{mqttPort}}" + }, + { + "type": "h4", + "title": "Prefix:" + }, + { + "type": "input", + "title": "", + "name": "3", + "state": "{{mqttPrefix}}" + }, + { + "type": "h4", + "title": "User name:" + }, + { + "type": "input", + "title": "", + "name": "4", + "state": "{{mqttUser}}" + }, + { + "type": "h4", + "title": "Password:" + }, + { + "type": "input", + "title": "", + "name": "5", + "state": "{{mqttPass}}" + }, + { + "type": "h3", + "name": "my-block", + "style": "position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", + "class": "hidden" + }, + { + "type": "text", + "class": "alert alert-warning", + "title": "Прежде чем нажимать на кнопку 'Отправить настройки MQTT' сохрание их, если Вы их меняли. Настройки получат и перезапишут все устройства в локальной сети" + }, + { + "type": "button", + "title": "Сохранить", + "action": "mqttSave?mqttServer=[[1]]&mqttPort=[[2]]&mqttPrefix=[[3]]&mqttUser=[[4]]&mqttPass=[[5]]", + "class": "btn btn-block btn-success" + }, + { + "type": "button", + "title": "Отправить настройки MQTT с этого устройства на все остальные", + "action": "udp?arg=1", + "class": "btn btn-block btn-success" + }, + + { + "type": "button", + "title": "Проверить соединение с MQTT", + "action": "mqttCheck", + "response": "[[my-block]]", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Перезагрузить устройство", + "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", + "class": "btn btn-block btn-success" + }, + { + "type": "link", + "title": "Главная", + "action": "/", + "class": "btn btn-block btn-danger btn-sm" + } + ] +} \ No newline at end of file diff --git a/data/pushingbox.json b/data/pushingbox.json index 0679489a..eac5a080 100644 --- a/data/pushingbox.json +++ b/data/pushingbox.json @@ -6,7 +6,7 @@ "content": [ { "type": "h5", - "title": "{{SSDP}}", + "title": "{{name}}", "class":"alert-warning" }, { @@ -39,7 +39,7 @@ { "type": "link", "title": "Главная", - "action": "/page.htm?index", + "action": "/", "class": "btn btn-block btn-danger btn-sm" } ] diff --git a/data/setup.json b/data/setup.json index 2b998ff4..7425c4d9 100644 --- a/data/setup.json +++ b/data/setup.json @@ -7,7 +7,7 @@ "content": [ { "type": "h5", - "title": "{{SSDP}}", + "title": "{{name}}", "class":"alert-warning" }, { @@ -26,14 +26,14 @@ { "type": "input", "title": "Имя устройства", - "name":"ssdp", - "state": "{{SSDP}}", + "name":"dev_name", + "state": "{{name}}", "pattern": "[0-9a-zA-Zа-яА-Я.\\- ]{1,20}" }, { "type": "button", "title": "Сохранить", - "action": "ssdp?ssdp=[[ssdp]]", + "action": "name?arg=[[dev_name]]", "class": "btn btn-block btn-success" }, { diff --git a/date_excess/favicon.ico b/date_excess/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..198474d246359b14553a1d0eac6b208cd8fe6160 GIT binary patch literal 1150 zcmZQzU<5(|0R|wcz>vYhz#zuJz@P!dKp~(AL>x%b3`hubNaqE~Hu_nK#=vljw{%%U zywY^%yv*t1zH!Ndo-r{XEaVjzCz;;b#v&vk0dr76xKYc^rJ?_CEVRPF2B-f2N5_T- z{{9z_tgMFV4|32-xVfs}|IKA#|8KAGgyUPw-TvF1`~Tko2^$0T8gBpdU&tvs23`N% zO|}1#!S^>e{@?tHEb{-q
zCB7Z86IJ@ZY%U zGb(QW@ZW1!BL;Te)A?5^#;Xbz{_H$5a+20njlzb}2{0^bk&vkxQ#D7oC}56ioMVHG zn_&VBtHwCgvkUP_!t_%@|Nqaxa1WT18kiXv4xr%%MxZzlV~7LQ-Lq$40O getParam("mqttPass")->value()); } saveConfig(); - start_connecting_to_mqtt = true; + mqtt_connection = true; request->send(200, "text/text", "ok"); }); @@ -49,11 +49,20 @@ void MQTT_init() { jsonWriteStr(tmp, "class", "pop-up"); request->send(200, "text/text", tmp); }); + + } -void handle_connection() { - if (start_connecting_to_mqtt) { - start_connecting_to_mqtt = false; +void do_mqtt_send_settings_to_udp() { + if (mqtt_send_settings_to_udp) { + mqtt_send_settings_to_udp = false; + send_mqtt_to_udp(); + } +} + +void do_mqtt_connection() { + if (mqtt_connection) { + mqtt_connection = false; client.disconnect(); MQTT_Connecting(); } @@ -76,14 +85,14 @@ boolean MQTT_Connecting() { //ssl//espClient.setCACert(local_root_ca1); client.setServer(mqtt_server.c_str(), jsonReadtoInt(configSetup, "mqttPort")); if (WiFi.status() == WL_CONNECTED) { - if (!client.connected()) { + if (!client.connected()) { Serial.println("[V] Connecting to MQTT server commenced"); - if (client.connect(chipID.c_str(), jsonRead(configSetup, "mqttUser").c_str(), jsonRead(configSetup, "mqttPass").c_str())) { + if (client.connect(chipID.c_str(), jsonRead(configSetup, "mqttUser").c_str(), jsonRead(configSetup, "mqttPass").c_str())) { Serial.println("[V] MQTT connected"); client.setCallback(callback); client.subscribe(jsonRead(configSetup, "mqttPrefix").c_str()); // Для приема получения HELLOW и подтверждения связи client.subscribe((jsonRead(configSetup, "mqttPrefix") + "/" + chipID + "/+/control").c_str()); // Подписываемся на топики control - client.subscribe((jsonRead(configSetup, "mqttPrefix") + "/" + chipID + "/order").c_str()); // Подписываемся на топики order + client.subscribe((jsonRead(configSetup, "mqttPrefix") + "/" + chipID + "/order").c_str()); // Подписываемся на топики order Serial.println("[V] Callback set, subscribe done"); return true; } else { @@ -99,7 +108,7 @@ boolean MQTT_Connecting() { } //=====================================================ВХОДЯЩИЕ ДАННЫЕ======================================================== -void callback(char* topic, byte* payload, unsigned int length) { +void callback(char* topic, byte * payload, unsigned int length) { Serial.print("[MQTT] "); Serial.print(topic); String topic_str = String(topic); @@ -228,7 +237,7 @@ void sendAllData() { //берет строку json и ключи превра topic.replace("\"", ""); String state = selectToMarkerLast (tmp, ":"); state.replace("\"", ""); - if (topic != ssdpS && topic != "lang" && topic != "ip" && topic.indexOf("_in") < 0) { + if (topic != "name" && topic != "lang" && topic != "ip" && topic.indexOf("_in") < 0) { sendSTATUS(topic, state); //Serial.println("-->" + topic + " " + state); } diff --git a/set.h b/set.h index bf10a2b1..76630a71 100644 --- a/set.h +++ b/set.h @@ -1,7 +1,8 @@ -String firmware_version = "2.3.2"; +String firmware_version = "2.3.1"; //----------------------------------------------------------------- +boolean mb_4_of_memory = true; String last_version; -boolean start_check_version = false; + //#define OTA_enable //#define MDNS_enable @@ -79,11 +80,14 @@ AsyncEventSource events("/events"); //--------------------------------------------------------------- #include TickerScheduler ts(30); -enum {ROUTER_SEARCHING, WIFI_MQTT_CONNECTION_CHECK, LEVEL, ANALOG_, DALLAS, DHTT, DHTH, DHTC, DHTP, DHTD, STEPPER1, STEPPER2, ANALOG_LOG, LEVEL_LOG, DALLAS_LOG, dhtT_LOG, dhtH_LOG, CMD, TIMER_COUNTDOWN, TIMERS, TIME, TIME_SYNC, STATISTICS, TEST}; +enum {ROUTER_SEARCHING, WIFI_MQTT_CONNECTION_CHECK, LEVEL, ANALOG_, DALLAS, DHTT, DHTH, DHTC, DHTP, DHTD, STEPPER1, STEPPER2, ANALOG_LOG, LEVEL_LOG, DALLAS_LOG, dhtT_LOG, dhtH_LOG, CMD, TIMER_COUNTDOWN, TIMERS, TIME, TIME_SYNC, STATISTICS, UDP, UDP_DB, TEST}; //--------------------------------------------------------------- //ssl//#include "dependencies/WiFiClientSecure/WiFiClientSecure.h" //using older WiFiClientSecure //#include "Ticker_for_TickerScheduler/Ticker/Ticker.h" //--------------------------------------------------------------- +#include +WiFiUDP Udp; +//--------------------------------------------------------------- #include WiFiClient espClient; //ssl//WiFiClientSecure espClient; @@ -145,7 +149,6 @@ const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 3600; const int daylightOffset_sec = 3600; -const String ssdpS = "SSDP"; String current_time; int scenario_line_status [] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; @@ -154,11 +157,25 @@ int wifi_lost_error = 0; int mqtt_lost_error = 0; String var; -boolean upgrade_flag = false; -boolean get_url_flag = false; -boolean start_connecting_to_mqtt = false; +//flags for not async actions +boolean upgrade_url = false; +boolean upgrade = false; +boolean mqtt_connection = false; +boolean udp_data_parse = false; +boolean mqtt_send_settings_to_udp = false; + +boolean udp_busy = false; + String test; boolean chart_data_in_solid_array; + + +unsigned int udp_port = 4210; +char udp_incomingPacket[255]; +//char udp_replyPacket[] = "Multicast packet 1"; +IPAddress udp_multicastIP (255, 255, 255, 255); +String received_ip; +String received_udp_line; diff --git a/udp.ino b/udp.ino new file mode 100644 index 00000000..a85052f1 --- /dev/null +++ b/udp.ino @@ -0,0 +1,122 @@ +void UDP_init() { + server.on("/udp", HTTP_GET, [](AsyncWebServerRequest * request) { + String value; + if (request->hasArg("arg")) { + value = request->getParam("arg")->value(); + } + if (value == "1") { + mqtt_send_settings_to_udp = true; + request->send(200, "text/text", "ok"); + } + if (value == "2") { + SPIFFS.remove("/dev.csv"); + request->redirect("/?dev"); + } + if (value == "3") { + request->redirect("/?dev"); + } + }); + server.on("/name", HTTP_GET, [](AsyncWebServerRequest * request) { + if (request->hasArg("arg")) { + jsonWriteStr(configSetup, "name", request->getParam("arg")->value()); + jsonWriteStr(configJson, "name", request->getParam("arg")->value()); + saveConfig(); + } + request->send(200, "text/text", "OK"); + }); + + SPIFFS.remove("/dev.csv"); + + Udp.begin(udp_port); + + ts.add(UDP, 30000, [&](void*) { + if (WiFi.status() == WL_CONNECTED) { + if (!udp_busy) { + String line_to_send = chipID + ";" + jsonRead(configSetup, "SSDP"); +#ifdef ESP8266 + Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP()); + Udp.write(line_to_send.c_str()); +#endif +#ifdef ESP32 + Udp.beginMulticast(udp_multicastIP, udp_port); +#endif + Udp.endPacket(); + Serial.println("[UDP<=] dev info send"); + } + } + }, nullptr, false); +} + +void add_dev_in_list(String fileName, String id, String dev_name, String ip) { + File configFile = SPIFFS.open("/" + fileName, "r"); + if (!configFile) { + addFile(fileName, "device id;device name;ip adress"); + } + if (!configFile.find(id.c_str())) { + addFile(fileName, id + ";" + dev_name + "; " + ip + ""); + } +} + +void handleUdp() { + if (WiFi.status() == WL_CONNECTED) { + int packetSize = Udp.parsePacket(); + if (packetSize) { + //Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort()); + received_ip = Udp.remoteIP().toString(); + int len = Udp.read(udp_incomingPacket, 255); + if (len > 0) { + udp_incomingPacket[len] = 0; + } + received_udp_line = String(udp_incomingPacket); + udp_data_parse = true; + } + } +} + +void do_udp_data_parse() { + if (udp_data_parse) { + udp_data_parse = false; + Serial.print("[UDP=>] " + received_ip); + Serial.print(" "); + Serial.println(received_udp_line); + if (received_udp_line.indexOf("mqttServer") > 0) { + jsonWriteStr(configSetup, "mqttServer", jsonRead(received_udp_line, "mqttServer")); + jsonWriteInt(configSetup, "mqttPort", jsonReadtoInt(received_udp_line, "mqttPort")); + jsonWriteStr(configSetup, "mqttPrefix", jsonRead(received_udp_line, "mqttPrefix")); + jsonWriteStr(configSetup, "mqttUser", jsonRead(received_udp_line, "mqttUser")); + jsonWriteStr(configSetup, "mqttPass", jsonRead(received_udp_line, "mqttPass")); + saveConfig(); + Serial.println("[V] new mqtt setting received from udp and saved"); + mqtt_connection = true; + } else { + add_dev_in_list("dev.csv", selectFromMarkerToMarker(received_udp_line, ";", 0), selectFromMarkerToMarker(received_udp_line, ";", 1), received_ip); + } + } +} + +void send_mqtt_to_udp() { + if (WiFi.status() == WL_CONNECTED) { + udp_busy = true; + String mqtt_data = "{}"; + jsonWriteStr(mqtt_data, "mqttServer", jsonRead(configSetup, "mqttServer")); + jsonWriteInt(mqtt_data, "mqttPort", jsonReadtoInt(configSetup, "mqttPort")); + jsonWriteStr(mqtt_data, "mqttPrefix", jsonRead(configSetup, "mqttPrefix")); + jsonWriteStr(mqtt_data, "mqttUser", jsonRead(configSetup, "mqttUser")); + jsonWriteStr(mqtt_data, "mqttPass", jsonRead(configSetup, "mqttPass")); + Serial.println(mqtt_data); +#ifdef ESP8266 + Udp.beginPacketMulticast(udp_multicastIP, udp_port, WiFi.localIP()); + Udp.write(mqtt_data.c_str()); +#endif +#ifdef ESP32 + Udp.beginMulticast(udp_multicastIP, udp_port); + int size_of = sizeof(mqtt_data); + uint8_t msg[10] = (uint8_t)atoi(mqtt_data.c_str()); + //Udp.write(msg, sizeof(mqtt_data)); + //Udp.write(mqtt_data.c_str(), strlen(mqtt_data.c_str())); +#endif + Udp.endPacket(); + Serial.println("[UDP<=] mqtt info send"); + udp_busy = false; + } +}