From 473d6654dc71dc98c1e38c3ba0fe7f741e8d6f4e Mon Sep 17 00:00:00 2001 From: vados-dev Date: Sun, 5 Apr 2026 04:02:50 +0300 Subject: [PATCH] Backup for MikroMaster sucessfully creatd at Apr 05 04:02:50. --- .../20260405/20260405040243-Binary.backup | Bin 0 -> 311950 bytes .../20260405/20260405040243-Config.rsc | 4518 ++++++++++++++++ .../20260405/20260405040243-Diff-Config.rsc | 4519 +++++++++++++++++ MikroNUC/20260405/20260405035444-Config.rsc | 2916 +++++++++++ MikroNUC/tmp/Config.rsc | 0 5 files changed, 11953 insertions(+) create mode 100644 MikroMaster/20260405/20260405040243-Binary.backup create mode 100644 MikroMaster/20260405/20260405040243-Config.rsc create mode 100644 MikroMaster/history/20260405/20260405040243-Diff-Config.rsc create mode 100644 MikroNUC/20260405/20260405035444-Config.rsc delete mode 100644 MikroNUC/tmp/Config.rsc diff --git a/MikroMaster/20260405/20260405040243-Binary.backup b/MikroMaster/20260405/20260405040243-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..2bb5f180a0547da64605a21e1c0191c4e8366949 GIT binary patch literal 311950 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%0DVuf+zxO-F#S9 zJ9evDb7rk{7ZddV@eN$oAXFyAIqa`iNrD(H|_<&c#E`b6coMgX#R$oU6=ig0m%*p1uyFtRPyHr z^y1?m;k7@I*TO`!&u-Wl7Bs|dnzfCxs2>BlNHUG}v zO5nOdoCXe1al9Fp*0H8UOyO{Faoe|rDtF&)x;ewRA{p_x)O9`_tj9dtGOYhx6GsCbn)7KyP#1gwzX?XDd~%iMt_yH*LNmX zH6?+}HjL3Tc@js+CrKOOcOOW1z*|;+8xzh!1N;UoQ%Zj2px9R%2`q00`}=RylJH(# z4KeFb-U_wZd1ev5KktXT=sjJ_uJ))84V#;ers8GQq-AQ9^l6>i5fTK8$FR}p&$8@I zp^}&~gRd6St_O@7pZ347sc${lb8KXe2?hUA7+S_aejG>}*vFT5Bv%vnU!AmYeF?#- zx~tUNI-#wu5-9y!e&O$#WwP0M-IHdaZJ1EJFaQnQ2G@YyP8eF$a4do5{BA%VRR$9y zKTntgg(V@Vwt?-mU|JIB)dd4Xd1=4+Vhyb9>iHW%?$rGthmR|Dc)MDIo17xG;hSQH zNW6L_VL0o-@<8Ls(*<>#O(4)wj*lZ}#4s~J8FsmafEyN8I|#5WN6b*SDlRcZ*?~h= zkHaf3wo10;m6%QvulOy%^Je(oykI6K)RT62!O}D!h@xZCgY?6;5NgMVbr9I(#>+#C z;-jYGHt7$LR({?_fQ&h%Djk9xhX7Rb^dhNO&()M*>spi)Y!oG?j7z_kZCr>kU}ZvU zoL`e_*tU$32E<$xLPH;mGgYAVrZR4}hJ{U24a{!S-;BRRq9gOyJhys3d=59jfysqm z$opaLqc%l{{GbLx{vP^0Wx18xhop;!*xj+c%SbgU79 z8mJe2&4I6Ivl1Iy5KnaP@feLWhJj@pq; z2FQv;0MvQM%r|rpzwP;|YgW$2jfiQ9N#ha|vy6uhM>yvfh2Xd2fJG-)y=w2<+TcQf)-yEe=ZPdwT8o!zmbgV&jryuDVzzIWvk+lTN2$1kJWK0=2 zJ_SYJJB)RhZEngr6%iNMk4xY_qP+Tq5Zq}4rzy<+Im0rbNqY`dwkNvgA6}%!s03ry zPg`481%HG-H62#(eLvigaKL>68SH)2i0KMxPr=R)&KD`udb3T7QxxUXhld`T=b3Rc z3F&<%OuVp88^9>D$o+}&`*{ujGSB=;qN}2`{@G{!pRM)%n-8CZwB=NCxbgF=j-J}_KYU@Y%ZfEgAaV^gG=kc%FhwoaJd zx(X7|vQuxcF1`Sn{lqIy4&}X|>DWG9N+Q(563ErU`}f0YUEK%}-xuD4AD$<&z6A{i zwAPEHfVT9t=`QkRSIZ&c0s#1N&UY()vs!c_k(R532EK@MidRAgIw0hcuHWt~tyuIq z9~{>=d^;tWGa_T5%0Rb2C!*F7ji9PEZWwR zJ5!|ca$_q^USrk|OgKq4xu})eHT_K|7O?)s)pGCc;M_yue5_{%Ty5e*p(C99Fkf!V zk!f671|FIbmn(oNF&CXg&Y?UzecAj@Y)L?&YM(>O7z-R`-pejFy600>xt1ObjR)!e z?=3l+%RlywFWA%mY9P8FxsCJ!iGsRstJDA)iJYbu^V$<+w?oV@Ei~AurjLdij3u%? z!4h>Z+AMXhFs(#bP%aYLy(n*3LkIv~Z85zs(_#p0%pqNq%bZ&o z(8#20Kgh{EsOjtJax`u;HqkJ@d3?|xaZ4c#ktJJxwPP6a0~<1Z?$|x=?k(PhYd4WG zq%uDCk9$gFbn0ZSutC^6#M9}|1#Y`1t7O)v8I=hzeh^fJ>7*bFtRj_}+1wtC%QvD= z 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�QyL#G1){h+?ooWz0~Ic`LOf%Ijpe|D-tZa3?@rX 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

)#Qa%Z&3Yr$cBwO3&xUR}` zw(~*&Lw+ek{%sRiol-eQk{+@h*ZBx_E2Gq!%B zeFdMO8~tZGle?1%UJ~e1g1GBb5~nm+EiNxbz*%Iy#{hA+YyQjso7)lOm?ecHjCx~x&x_d-5L(dPV zll*6pAOOGo{@g4bucCiCj1n=k=Ygt z9(s4g7ca6%wwe#E!$}DEizf|0Ab>xnWPDEXeS^uYo?J^=G**C>!_sP>?-tj;|25|+ z;nR3^Jr~`mJ%oQ|NRlLAIASG~UEar_ha^as zosfXXcL2Y5BDV)*Jmz=hB>SQB;~=isHgPq6JIiT$?4_a#zMuX)j6BuakXgw;44N7A zURgq*rN}n+@rIerz^wzhb;JCsGVBY~f&`TACf=%z;%b^D0O=pcewd#q{{wAao92UW{9jQK`<)H1(a^Wx16K9O(`p zdjq(73z&m;NS5jAy2nhs6?dmpFz{DBlh3f^5{!+BQJ;H)Cr1vQpNwHRVzW000*q-T z+ebh{JsWdRZ%EX{g1>yE(E?M$@=qi!A7WHCdTcwfF5uf8_R=g2s}POShe7tVYmFkb zh77%%f5Dum?^+>hUhb|seZ}8IzXN$a z2_n63*3i^=qgVO+T2GK_-pLg6)y^_r@Bf?UGbrfFQFi+#OJ^K5PXm}utNo_z#Bnp% zTdVYwG=)1V7(rc#%X(+M^T0TNyZ9KmOv8XY6x}k;6NFJQHW3}SkaavV_XrdH@f?exlPCgOcc+sLM)=l8qyjG8D z`hc9MV2dN)cwaksl&HVmhMzq^*WZqL#X8b1=?gU84tzS>wZc z^!`kj$hzMfKE1)dM{G((MvnFaw*A|w6^eEp3_TEvY9PAHaxg{%=(<5xN z_ul+oC-oNf<5y?mh)r*XKTUhzt1-DlMJiU?cNcBOwlgAp9E=^{-2rL*&oiMmT}bYM zKXt-T(ihi;AGcsl=siOAWEufYsH99rk{qe9>(P~zp36%Phw7B#{Ghzlt~>-%1_DHN z8Qxb0OD?5{Q^M|>phSpZ+Zw(oQd%c>KN6Eaae^dkzTF%HBJ-%02J$x!w78MS2UVae zO9XS#*%$UKQ>U;6P%SmClqm`Yp^`ep{mxv(FsNHlx4&?t9idn?g01#RYlgPCKUe>& z41CQ&_iKsGe7ljF3V!3!lfE_9ZCoo(LaU(VOa&m|5Z7F`XirMkFktgdNydCC>nu@d z%(5xdoFYZ|3~`Fdpy>o5k$PzjA+lp+6l;^lA^m@BV+ZY_^@CtD*y4Mc z^cJK_U%s_qEp*X+4Cg8srQT)f438zaVK@(3T9%$r5PNku``8d%JR6_Vx5mid&P(R7 zUr~x*`~<^r^?e(x)i3AfMPrmi5gKw?a;LjwY8nXt@W%bRxfjWHYJ z2Tb-@O-+Ga)}FK_%gzftiN|j70?Ut=&e5#{!FW{k)s&BQw0)8-QVX;$ZC%`ErmaI- zdu0e^fo6s)my}+N@FjJ+HEHf+K{n*I?MS6NuI`gcFwmzc>el!ezhYty%5(0j?d>_^ zFEK9!xE1_Qg^rrC^b7aHJb&&6t0Ww!3+rlKUw!;zBa?B+0)q5dG2t9!2*=J;emZB4 zU$n=VT>gv(?1S`ebN!?`xZpbyznqd}?kN;>54jvWXV!;aY{DqhyJNrPo_BA@84cAAsJqs&tK0|UndaqZUo>;e5DCks#DA>FIvy1BrBwau0J z$#n7u?Zql-T)0aDzV+rGEsYbtRdYHRgjP(j(n_08AXC1w_zrh8<~{}k(nIm?GScVi z4INUkW5iwXK^_Ru{8D4cie^9*VgN|acDAND@6&>$;cK6C0oLqek4Rp7@%!4axk0sI z_gBPwd#N8K0m-k?r6->wm~|-)d@hl%ldQp0Y@#PJ-e}<4DCP2?hEbUhvM=pog4@N> zm8hp{c0&B%-Lo1VW}S5BRs^sQr5+&^ZG29H1aUQX2EKw)c(1zlDT8>WP>0>{pX&L; zD$vGP&_KA7q-eUWOwJ(YR$I+V=(3_-tX{)~5|VNR?$y!g8TPo~Z@WWUqcL~*M34sZEvHyHD%U$iUDKe%w7_MqW zurSYp_+>Ff2*2lIv(dz$qt4U@yM}a8i3%&|9(dQrnda6s|JKxJP{C(FUMw!+;zA~z z0<|%*(E_8+A!m55DK*MF*0sbbQaue(u?d#l;@qwIlBH-aq^*IQCQtTRTOb{DuTNz| z6)zLE=?-}+YkgMtI8&wg4H5(!wJ$f0{+CtWjD|Mi6OWrmf2|Z&xd(@^@lXT59G1M{ zSmGr6xXR0vO!o_NA zGb#x9$W!n=nPW1DK+FJv(EPRs&HHus!$5*)BkKP+t<;!_GD?B_qomE8c>c_BL(z`CqzN?$i7Y5wodFosb7{mN?@RH<&~pqO#c2?32)m&w{$<>;zt3Sx0y;{ z3vY-Uc$#FGuedi9zJmZO`qfMy^)<0XqH1gQW?OaMySHDFpn}a6qVovYaauui%hA4a z)|~U&7DnH$)isWD%9hkAp-$B|rTma9tFJQ@3*kXH@HO4-gP|{M z`PL`JVzW#7u1@ofJWGOMjfCr^h162J3R(BfYcmdq-jy?3=X!{p9a;7jl8Jhh1OBO* z9}(nQ`NH`g%%YRV-eiM16_D+#aQ@H&;z){-+kV?GjoXsCoPzy(&s`@zK7b7j8UQa^ z!ib|J?g@BzR5 zdzlXbcv1nO$ey|4)Kl(sD<>i%h|7rJ=H!oR?=TF?u(xX5v)?Pj@g=ob(eEP=*bUo; z+lTt;c-!Zd7AZj+)Pc!6&x2!gED%2mBB^j;Le23&o9=6u@N(5*=bo!?R?2coa?jXa zaRa4@G(Wv1NzP1)BkspyB^+Q+mH|xbKXl;3HUABS zoWEe1XqwL1wP6gKT{=`$YMrB3L>r(fI#1TX9NG+ggmVwPDe44iAR0^#M~roKH29*y z;XBYgWD4bp{uE&LDx1r03v8Vi8(;1mdlSF^Q~jqQg{c)e7}{?K0pqaqo&k_kB?zIf znjxd9>?}x&+_sT8``A?-Sp(-*NQ4izHo{~zL_I%f`l?}P(YU(!6zp&6X3;5tzH(UU z!Dr(C*+Uq|V7##k$7NU^hoLK@>%M~-B2Iqn#zZm{7~<;q#tfEwr+#RVX}9B9km=)g&BP83;ZG)r8s&$jx|CZV3dmnmhO!c(#A5*eKLEfRjW~3-svU*wJA`LKUH4GbKodX3{Aw_J z1!;bnDetCNwlZY<5CSbYzFX%dTF8MXaK9G!|HBda8Gs6b0K{XBG1In(&$KD+!akp- ziSB>m#^YFi<8RrY9n!}3seq(1oZkd3ahA<11E9@l*2Zflq~ZaEhOXy~l~kLx{5AG7 z&pUK?fY3h0<3R5=rdn)d4&56Rh5Bl!PUN)vJ4g^RwTW51L<6gTCdiu~C1LJg<$(%) z$;4!lp0d}l0l;0Ev22p!U_Alg411UKj|4CNeSyQ0sD3c5mg69kry(%H{^TjF zt;7!F8@8OZ{EpKkBieONesE6pab1m6{9`=0QpAg3vHkDwX!OsaaMV}VaNB#JT z2CeR!Vr|zhZSsod3Jj1pQ1b&$#(pi?%vQC=VF*D+OMxosyq&K&VJl>Ht&rNfVjDIx zt7|ZCg!$rh1{UpX+%#tn=`ejbJpa&vF;>2A4da7I)vI+#>Iuv(|5UzFnSP4VGn77% z-BhFdZgFBKM!u3x(e@YUN!Kmj=5T)iW(mM~eN%@e3bdG(szsv9K3GKQUB>xthS?XK zZ7cpF-WbIaS2pBW`WE62tN{_-6+l%NzKOF%D~4OQLig6-@V$`&RBYFP&X6E` zvtLA(=Z{_^#GS7vL{PLaHM@J`UlgtTzN@I^M9?ee-_$Xs%Zof4o0nIa9z(W9x=|?# zH4{@oq2}O->VNeca~D}L8*hEzdc_jyhYWhxi@qvveia$H7-*9R@PFV!WO=t(m9 z^YJ@qJ@4L(WjZ7BUZA6nE(vv4IwD+6>ZQUf+-U4C26mu*EdC*#3=vgX6q2pgxQkTc zL+xql5Gu#it6M(EKx|oywVA6r!x9~2I|#51y-fRc>> zVUYMa5zjG-hh1Ijh6MlIwzI+FN#lEJYM8uUlxTv9ajr*8y?Wvv*?mwc&=Po&!65ka zcJpDe7C&~Mqp=N2$_eo<74^h1Yd%pOk-9sBF1z%aW*Qxu)~uG6LJ!=lXMP_08y)hbeREvFXI>m(4bkQ5 z{+ZNZ-r=?rBS(Ybee@ZsM5?@Zdnys>hJOESC{yW@USA@6ckY?iRikW|QG2s6Demyl zz5O7-*-vew2Y)qzpP$^NK{KA+&cE?C z3lVmPPZ|`YKsfehX^t`#e9JkUKFZ_G9#_Z)zh7S%TXSk6ND8$FR16bplIVV*VJm6F<9N+UZmR#gDTWcJy zzI9Ay&yDHoW1fL=F9UcferXRAv_yE*oa5?V{j|W9ug(4Hbt|w)A58P1sQg-}Y?MU& z2Rr|8ZNokuUwnBd%qm(!$mdZea0V{UC^W3z_@U|>|MatI_=JAu_a0n_vKM;v1-?yh zBxN^i-(^Xe@8kUy*gioJ@+zr~w8%i09LJq%-DUh6?X~NT3Nf}U%L8a8Sv&4`&-+y* z$r`HGQ!)2_@+QS5;nk)y!1Z$Yz^`bkn{UjRiSGlfq%=4JWJBzZ#$VZ(EOZ!w&a$M8p^CPmdHTQp53Z6^3QMED;& zngYeKcc}O4u=XT%7SBi-P{8jB5IA6ym$Jegmh>9n;JFgL-){R>I?m&4QPGG+0lpJo zzncM95?5_(W?qR$L;=rEl;lHH?CD5N>Rt1yJsI;)U0TU8yg@TdVbS2jkyqlnEe$=s zZW}Jp)@r$yJy^VMZGeuPMe2)tq6~q=2{UPw^)hqAE;n;XJSvFDOflrs zE0?qWbAz`6U^;aRfgvObX+c9!_(Q^XDzsh`eX@(&QCeLI9U8l&UT+7Qaj;D(G1XrT zprBqRSUO~d>4b<^qR0jx_O}bzA}zRV^+kg18e?otE|0lNM3{M;+lUsZJbB-XQGxP1 z+M=!7CS->+xJzL&m?ZFl8c-s+#2(-bd_q6#?e=!U>(OUiL{cXoWGD8DqU(#y~)yZGr9T2I0R3 zKy?X+fQN%XZ{tgJOkcDk3L|)0Z<`$`0Xp&Ho5dzZdpMc&>k3}Is0t)i; z#@AU25Z~JVs!oS9z<#uj*t4^}AECubdlT2E78thbFJG@)BA0?7h%;wuDGz@vitLWR z^*Eus`YKd_M~Q9sPk1PVzFXTJbN_oZtHMBu)M^#@n@uoHv#d0|rNDk$9s$ePZm?H% z;GUe;HS53==ei%B_}ZzUoEPEM~r%>PmW_Gmnl7L~*3&ks9&~?LLT(Vp4s7#-H8hvLUuv9@axm3_}`z(IR7RVffY zDhZUr+RU@IAaF7m-FHViF$;2KSHR~3coygI3(5&eDc5zLal!xFa4zjvhOG?aYq+); z{*;Z&%CgR5Nav>w4(wUdoqAGvU$$ve0M@FZMZP6(Ae&9tD2!{+v6@0bNxd^x3sxsV z_orHoBu#cBeVPiG_s&s;zNwjP z%9LUmG0u|7XL*76(9for2q3*BFXwTrMKLu<0NW?|%ywE2$7Hv2;m ztNh>sTBet~e9AUu?d*!j{8pdhLTqJZH^-*N%^2TTR_1}vd6%lj1B!UuyjR6cgdQoE zAFF(deBPNn!2eZvF|hMyGm|6qT7HXjajk7aR2Dj=$idWlI*t~W79rZ>jGcm_#08qZ zj`E-uWJ znFi;NM<4=w9*foQyX(p*4K6<0&j>#$bhr^xc=cTn#00aa-nZ`CyY9}(xk<#cON}tU z9+bKY%1?hf;VLes1d-|VdoXOjn;G;%FA^-4nI&uG&irJ*ro4>gjJZBC1{SgMwk&gf zLAuDSK4yJ;3?7Ju$6-pn3N;hN`SUXuj9=-=Z|*0Z&%LbA3erJ#q@^6&hW zxJIvjA|umC^Tl>=%Cev!5MoHw!NCtKns$4v3Xn zZQQ?yR60SAk!v(n(kBxhX^(=bQ3wkl#uWlirr93O#QN}%O5v6-I@L%qgG<94?J<@{ zo23CKt?_ct84AX&+!G%C!VHc$uTONvR*$aTlK<;wq^}Sc6GSJ&LdsYd7(VrG32gK zGE@kpF#cs2;|D__?x)nhtFWR9R3DEE9MjL*IUKlm4Sa-Eom8_La;D%Q_^gEe8QiV# zR`dM0wVSFkUhoeRq^ECq3}Dp@5<+_Z*%jK{RDQJ3{}4Gy3;_9bB%U6CyMv|u;8!MK zh{3}tpEhkdOcgJM)!jC$n#h;04bgiWn>9>lP_n82t@jaWj4vdfL?^cz_1RRE(;p+5 z7qirCmpM+~YTJ4c0ASqIT|gGXNN-{G)&ufS&n7B>mjzmU(`43jpd&|1W9}3NB-H+V zW-5KS(82Ucpg~mw=$785$um&Brx3gF;uh)oBTq;BAZyqWCju=S#K2gj!=RPPaMI;{ zZ)b>jK@vXccc?hANlJEzn|*rdBHnF^{ZEdvpWf;CyMAY83)kkPlNkgJi*(6neQr*u zaxo9{zca$-9>t)(li)yMrvfV(;JuyK=BOj3({F9BiKrjO)epmKxBrm38$+Z^m5@Kk zKid|WRNvv*q8!*Fi%X5PR%*6lP|M}qnNcrU>MKw$=K~!RX-TZZTBzV^g}0TSYfMud zj}N|R1CPc1kQ3jKl6enoxN=8mt2*%u)mh(T%YbE16gdO{e=HIF^o@^^AnC59cN|e_ zp~>&1?_o7M)Q+pK(mvi~m)LfXzVtii3J0ZHBr1{*=^u`*y?T7d*4Glp2&R-DFft!D zm_%b8lbGF{6D3_P!i*;Kt*{HODwbECpcCi;(az&xn&*^fc}8Lv*O)X0L88Gtz|oZ| zz!6)Yu@ZOB%*qbEm91K)^^|{ zEe{`GX#552QoteZz%h(VAZ*HC+t{Eq9{z1j>0*c5E)a~+29kA4YOx9UX1i?2fWgZEtUq26 zRdxe?0p=iwNPDP)-xtL*^3I0eq3FL}m|=UXf#4Po=-&Ict^#PO-->s*QTscyJyoSX zyQ&nIl`n_1Wrw5^oK<8KQMwF4AkJs+l`-DV7B4=)58~qBAPYy$Pfc=Ez?P!%wHG<2 zhV1CY(}RZiv16Sq)rQ4K!zPQ($b|DvqDKITC9v|pX=x?$d!+p+X$5qMp}dlgo;c9M zlvz1Gn4Q5e(#xeE0gDzF^m>j-y;#O7`lM{xfv^Y6ZF=fe?WZ*JN>;Hk=~plP4meH* z{SqYA9n4A!&%^>2(CN$j_KO!9zJe!w#Kc^MH$`Ltf0|*VM{Ur&C`!5J&FU} zD$p6=JMhU%+`qUTQva~L%MRbTaKCuRxGt@?$fD-Mm+(#_E~t~=LAd6qZpNu*3}@(h zB|849{JyDP1l4`R0*Pdt$K|voqxTXQ<{{N+Ipo;>^^V-6;mouL0FVXyA_Y~s`dlY# z&n=O8(-O>7jN12dTD$G9sN{7|aNNr7_5SL^;q2x(PJr&Gk1~ueW9Ka$z9pxf_od@P zl-RgYubn{8Q#zgi0Y17{`{PG7eF=373fm}0O3jeI=ENzTh?enq{xU00_yn(wIaH}Fd3mYq} z%~1xZmf!RwVBWF$LhN(oVmEr1K@Ns)`4D3OWaczsA{Rh#d zGh&x9;qTf)ur4t~c1S41bD)tU5CAcV!qo?35^tWATCfcm5rNLQJ~T zi!Ki5B0gYWun-+mPl7uMn>xuJ0ZaBke7MhC9FC#JPDin03D#5{zRmlUAypZ9F?6*| ze`am<*>{E*cSe=wxt?x+0zh9SiBi`PI2Lf%Z{w$Apm@bW<BlVLGk~mAq|sX^XH6Lhq4lnxCFX;dbwbFD;yZ=KMm&Lq9sNIg+D`AHggT?@Sx8K1^jI zqz~^#ZE+>#YU1DZ+7c|yl(*kO0*zp&1WF?I)C51?zt_NV;)^B7>issj;-(>iA1>T# zuirtq2m#HAV1L_#GEhoA_Si**>)%0ce6WnFWln5+3@z7_MezS-N+*fNIo}VcVra7g&r%UnH2~i0!UopHA zfbb57@s@;06$DOud&bVGFl$dlY( zbB(|AavWBlp_*t??841Z0;fI#j;@pg{hu<4oFfY%qxhULqC#fWVzRDG$P$Xt${bcy zwzT=0ZT*6*&CMyZK(!)m%i50dv&_*`KM65F=Un$@a!O99*+p!6E-qvZx9A=!kFYXz4$CeZlZ@rLe z2S)gFTBu}qL4%_KWO^5#e`L22T|W`FldF5hngR-milhAd=XJI96DB|627d~|+ z0Sb)|g=Lt>$`3`av2YO0o-^ByMf(zUFIr|St$R9qOwbDqgdg#_8Qg6*>jk=B>@gkU z)s1KHtcXqtLkUeaU)`&o=yD)mp&x&8ggzXyxGqlq=L7-FgUr6mqEpl3Jw#-4-{000T?4Qh3I6J%c|MPXr@DJd} z5!;HI5TU!*`!+B1cA9*3FO1|)XuU1V8vEqkCRkFm?&Or_f=>a}YyvaFh zj$=%^ELtnPNYN^OG-#9@5<>M-P2t)gA^I1}{v6!5l6kj*aI%i0rmNYsP#jp|1P_t*VQc zd`ASjriE>!k6eqZ;G)I0%j2)SlE^$eFM`7LxQmHIP@ihg@9Jh=m%I$ld zgkTK>pj{{F;CJEsu!nSV>%@vh!bI@45(ji_A~G3YV{lS866b|T zucZ}FS|Q{0Ip0S@Li?(D&xxDeP=E*FO;RVb{&ahZTpZkYqF)PqwJd89$5;x+ zsm!qWA4Bt5J@l`n2}9VD0)9?Ns3JP=gn4Aw5c*wcz0;%X)ww|HNP)mx>IosZL(pJWy&;^G$ApCV@C!1toV*yDmxj(`NO+_Fi2H6WZLAgJ1E z`~B4%YFt-2bviU~kJftDpj_%Yp%Q|qUuai;?{|4kbIbqYi*Zu@4(Dwi{I9W63VyG) zjP$TBD}ODtF>1+-EOTQ^PogU^SQkIDW4oDDov>4y1+y_M@3~*SO5h>paq9tGUyYAy zP`g`_61 zTO$f=x0-stk?yj@w%x&J?TFOZW3?O(o)A^q(vHmw9+O@L2z$fXT&0 zRK)VjLth(vxt%3KTShKwx`OSum`i|83D0c!uZ`Q@kbXmHuBu(_ZPfQ%}USz*pbPpeDWw!t1I<6 zvgEWPeP|@1dGc!9)v|-N8K3Gg6*k5m|KKU)CrFE$m6D}Lo#K+0`&Io*#uOIRJQE61 z$nb#~bZU4N*)-S&s$tfy! zR2_#B8RAk;qbVI5B~3R?QN_jt>s(%DVN$T(!P1|cH5gC$xKLBh%}}`FH62YusEKJz zhFH`?3xU5(_X?dHh-Rl6C;2pP#hRMt{ET$hBP5bV((MEf7~Pg|dZ^3K5T>EWfS54z zbTMD=?3{ginblY$WT^>}s)7u69OVBvlw0vAXn067>&K+9WzsZh-cB+8waIz+enZb@ zV0hTFl>bLT9vd!;2enKZcGJ#~G!P|BrZZgF+kptn{<@xDM|hh*yPMGqTsdzJoRns> zeH)1a=8R`Y!mP5!Vi7JO&Cmz!Q!@7;9Jj&4y$Cn=&#$#T*0S9FLZ<4s+vc8USa^^f z^UF;)xiPG2oc>O3!m>v5)TTJh=u*nNIBKThA`hp1p#$g&sOwJmyY6@lu`&PC6y2@P zosyK1^RbKuJ5RwQ+u1`U7@dXU?N^ z?S6Z;a7xCeSigq^Dw3Fa;LusGW(%TV5{| zy=Dd$|K1KDC+^0z$_Ef(R%N`ftxtfT%H2sXk_V+y>%ftlV%G9NJnh!|n8lq3+KT(T zx+4OCJs3FskOI6eh`d3_YReJWg(!$f=c;>Dm}`KCg1WZaQE|95`)SuAAVg4i6|{Eg z;eFhsd)DEgF+q@pvj6_my+qMN48(-ay=Jv8?f#kOO?wGhnwYx$yhlLXLsn8pm0ePc zZ!CjWo{iDK6yh)V74uw={JO3WQY!!bz6{37H-OY57fzwA}Wrumx_?@;rsqH zjz?Z&*GUK@u}-=-hR8lHcFXNIn=eeiDHgAtKHB#ASp%2Lgc~Awi7dU{E@U#}msks* z9^#mGnn}UFjgi_w`TdJ$@=w03=6Sks;F3ps`aoNi2LUq;f3KU%7dNc^MYS4MqO*06 zc(mABe}UWNXy@Y2qSIDc+Tds-F%Td+KvGt2S|72PGR2nPr8jpwdu++Yv85b+lCVVoEDTJQ!d#<*JJWOp*z4}s zk4h3xCj;TUmEn+0W{A+MS9h7Bsi41Iz~)t!_(BE_=qgYKT}iK!@Nz{N7F z<N!xa%GiKacdR?#})oY~=Cd8?XbvI#Yk5%;Hxk|157QX;_ zm4q$b!7$Z%k=lQCLCEo%mEd8H-t_X7N!GjE<>zaxv>@A{jEbt%wtn$3Y!15p1_1cO`~r-N^~ra|BD#vd%xb(sw~7e+O$)#U#ez}|l;G>pfqsu>5i*yj(HJQ1 zGdrX1?MHv61e-b&M8|k1rAU4^iB@5hUi&gb=F?zS@M;#fqF%96cEIk zc?|(9K=p1YBnd)e;GCAh2|g+!H%k@Zscg10a|ARtsBaW%1qLm&HCWK8IAb;CwLY&vy!a245%KPl$vT z7&(H~g}enfv8CQx0cTtWc>*BJ!Pk=Q*_g5kM$kLbH94BGvtJ;IUIwY!q!VI!Yau$( z0>B5%4$2^EN+=2Xx|RH{w(oxK4c|;Kddd=2JD(zYCicN3mF2*k96tu&uN?%#rOm-y%?oJwwQvUKEt!9-vtJ* zKh4x~vSWmjkh#1(a~TC3=i?%qU*KUftqa7Rqho!RH(K}7hV?F*O|Ft4RPv>~8Qomu z$+1{w1);;+=0>e|OPW`!TL9MQUWJDF=ahdwIV~v~KK&&9b}q-Wi)hvTZ&iTpCXKe{ zA3};o6Ks@%9)*W=E}<2Ef?32vJM%XS{-9VN*6aJyeCS`P?Wy!f@fmEH*poB>B-TB} zS#J38(-O4H=OG05{{ZMsuFzcCQu%DcatSgGws$zJ?_D`MVoA=g+YrRTHa=bBgJ2kJ zDF>EfxFl+_{8x-hI~?}fm_y!s96o_e1SAgo-KbqymOcF{eYYpT!ouk=4nLwdeME$S z{i0RstyN2U2D{ffcjWWL!Z$X(O5wpV4t|Fx;4J?SqAnFA5$eX+ScO!50K&fO5 zl$%KOvt#acm!c9NwNql&H5I(q#DLPc5l}YIHrP$*P7VJ885lE2#M}M-bn~dpHoCGU zj8Z^j)N{Y!G`ue+p(+cDTln%#XPA3kyjnJxwB{t8V!E=L>$BIcWXCEJB{F8l&qFy1WNUw}^vtWS61J?!1^=Wy1$lTjB+ zqS37~?))O4%ILRWS^Kc9!(2`13pB_`^>ii5v;!7hFRXj>IamgE_LMbb_5?NH(3{m7 zlWyD5o-m?q(r66g?e8GEG3Pm}^-2WWL{$nv4shNU)vt$GR@&VIN?Y8rPs#X=Xw3xW zs-sjc*AI%XEedx2HqWD}?Hy7Udf@1=v+KtL0A9%Fe7i{6ck1e+ize_;EuqOwfrq7= zVN^$8Q5cwqJE@o-jYQX`-_%BB>O9TFF1%i=s>T^AWX#X)ofI%&Z%GOTB)3wufNSB{ z!!Pmh!42m-^M4(Kd8x@xmQxLUY}QMm9H9FN8(UdXFx*WSf2Rd8izLp`a0&>J?ZAMt zg$+0)P#Drj3amG26wkgHNFkY+RU1&>8(@+v@J7Sagu_ta){Xs=Ei;5GIKK!zL%aTF z(piU5cg`@#O&v|=9c%jNP&zDJsl9Z*0h7{o7qmo{e*nn?*_x+7MB_TA@Yo3o4;V>pGz1gfKf|WD!cSh#hjL<$CD9k}SS3Tn5n_~nYGkHxS&(LWz$15?5TNGO zaFuE#3%%ee=PK4Y+6BY<6tc+VrO zom3S)LU~EK&?HoXO{^%rELzc18+zVp5OR0uTP8!1+a03(KD6sAJFmoB)UFAkL#SPj z3r-_X?GC$_QCR*t8t)J*9M<)S3y8h^bSPayYt*7BM%jY(vCYNo1sG)B>oKs7&@?&^1@YNWAVev|f z!m1AS&da7?Jxp)yd0^=E!TfvO>#15zKa-^eZj?Hz3X5tOK3Gr_;SGG^z?WMN0cAd2 zEbSXiV~%(6J~LCp>KumBhO*62UV5Ks5wpK(3BqF^h?Ls;L)Ei4@y^XR1aS7x4>j<1 z&>X>;_n|4hOH+93kAGck2bAB0&e%&ZDhSl;XT3CP2-fcu_vXeOI09B6QL%6BKorYt zulGS>JjYS20PS-FRTe`opPCO2CuZd#77#h|Xt*bfkIW0*7r5*2~KHqPX* z0Z^x!KD&aK0H8%5@R+EDD1#&I&~ux-u0n1o9zlSx{=r%INXqz|=fz4dgm3u4on32c z#tn=T*#1{R)e-AE`zkv={`9Us=u)o}X1uCojoQ|%j}A$PJv0p>*7es+gKZQse_U#QN(iT`QE&b zHB=rH|5d_;m3qu)goK&`eCDs@l3vR7%VC!tm z#hPuKlx*Cp9`;twBJN+`mMZ-3k@R7ayDAcW~& z6X?a95|!2#amYho~$xpvc{E6l7hftHn`rrvB zCyf%ujXSR*e4lFblrok*JQ{!K6g`xaZR2QIC%@ikcj-xQkr_;@GNiedB|j79`DmxW z?C|n&4N~*Qnw%k$jgfMJ-F1<|#(}|d&9&x{m7gTkfGiVH@Dam#_YF;SR_UR8s;RD+ zsUCFz|1j`kc=*vl6ewwQ%SNw@|ML51OgLIT>R)t1sR?HvJV{k$at{=T=#L%TN`*QkPHRgPTvMS7jE9OHL zoIPQwFPKC86sA^k)lef1)Z*PezXx+Ckp zL%rDD_;HcwPg=khkb}Vfp#ZvwErM%O(ny8#=8orQ>grQeP6WK8;+_-L4d^LdP6OGv z7l6mg9eJ;icHp%0DgHJ!w=U&hQaJdWF6wfTQ(K3N`$X+H&CQ<2Nf&R6v$=1)VqS?FGxd-A+Jpo#- zi72iMC}jlPkuaxk>? zI7}@S9o6b**ia86VU!a1o~$Bh{te#0F6DNSqiCbPpysr~htE5G;0zf+L#2IUK;4`K z=x6!a)P9pPPJ(As-&Wf$?s1>7aM8m?`dRx=n%VeE@PKr4Wc}?81Z>F>4-_jrNnXZ% zE-0w`L<~|(W|}%rx=_umcQKdUylNBD+YFU0X+kH~faAR`CF=_#SU4?KEcJcuf;9@t z`kt=82TN;1@tP6D-^6Fgd;+4oX^inkMkTPJ5hdQ^6?txDp+hUKDVQrS z1QuABMraHi~!39SF^?yyB64qo{_z+<8g!*vQfyt%=qjYV4qX8X#$ z!C0tKnn)wL=TCxNJF?4Bigdn|Mc@?!%|sVpaWL&R#t`k!AZ_AEXV-B4Crm!K07|5X z7<9#yAR+Nz{zqCS5<>NNn}K2B7Rs2>So1|x_QPM`E@lPAg0^eVdC?!e5Ke31WyCq= z3+y3JEgorRkK1wOUS#SN%2{Q3?SEPk5W`sqi9I^*BRJ>SE+YM9zz7%HXm*7amRyf| znZIImBcsTbK7p5E_}Zj*kN#d&F+oN}#Ly=ig@`|Jgl|5!J1?ucLV?pFTRcb>BH13Q zSUN!kFE@HEa3s1PagrE-B@O={eKrnpWkp?s?h=*(xhSDu3ESE}vCEGP!uCcXjx4O| zoaiPON`wOr15Li>1YiO&{Z|wzLoW4PGS)H@*fDZYRV)^w{m6^bUXd9rBzQ#`2$eR# zwbJJRgF6c~Y)#fYp^|Rs88N3<(FM^{7+!}^+%x|CN!M{^i%Dg^oOEhpr6^+y0)jNe zC0hMLS@sjQ6Fg27C5N!*6HtfxEvvc1&^~Oc5z+SREN}zpfC0wX?bA6T-zv1qamP_@ z&S+I+UOFe#ivi=88&I`d6#)UXN-;yx($AbiSx>r#FV;ByDJY@hFHO2r6?%3|YC_dJ zuwfR={2mZ*qr2R*x?RLEq^vWy&05E%Gfdy}mteZ#$?XX@!QW~4nT|cU8xoH3ayHrXQb=vN>aML zq5#(Pq2HL|q`%+MMNR0#fia;2n{eemAiDofHl;^iKc)zn=ch+I+k)+6-arpIZE<1$ zjfH;V3?hN}5_W&8q#c+Asc4_+yJ8JbAon1!W29cgG9jO?T+5(0_Xu~pXWmN3Ru+pj zh0^fy#^*>%vJY&^YM!yAJ5GUgwArz`(r9=H?bEL1#W~t03K{?@h3nAhK-9^%AkPIO zNlU`=xWEJrGj)7I++^3w0B=|ymH%P-V)YaEd;Yqld5#}kgQ^HNh)h$rcfjglu;lSI z;Q0H`=MAT8VDf80A71y}GmsXL7^*C>y_pEYx`WuyCqhBUKMu_e@~d1}8SUoj<`gxA@mOi9;{Zk2vTqbT zr&>$*Hq|hJgfD#@&u$&(YOiompXEzDO8^7~y_XV*)sFo)ob`1c7B`+6UtBI`pZcmjb!0O83r&rZX|skCtbv~n zvu7pc?%na;@qYnQdGdoZjY+lSGiW%&LjqQ)7F%ny0vcbEHc{A7_5-TCb!puRNoRT0 z7Chb1$GrONv+8{Y1$_*wpYYKyYxIw@z=2nYJQQCb;|LnslgBJgPY}NXBt;4}%VLA) z7yfxRP^qwn$BM{ugW<{1h@OCL`#-g7$SniVQ4+vx15}(>EOE03Llg^!6W%Pp0YK$= z$bO~%)Hi&DlUhvJ6uEae?qOzM;KwgOa>w1LlF%*rShNs5SI(Vx6!C`5_e-bJ9%5fq z8*QqggIj3M$*|nmya(PN1FlE>bXbvke+TVSMsgEw##47W)x+TEzM+9M%*Rp*Q=XCJ z4itDVnU|Vrz-ogU1hKGYw)^~VI?AfjR}Xj+`p?=|biEU(e>G!cwnU(a!Cc%IPQt}u zg`ePGY-;ZcV{?Ij`xw}n!bL+=qh4WXs%Sbj<<*2F-Q8`n;_S$O7*?3*;$9gD0&aBl znL=Az(wuCvg8$eUD=cz1!MaIJ$uzk9Jl4{0E*-m150*ZLSv1d+Yx)h+*gt zlgg=XqXDp{27&_it1Z`bP@Afk??G={bp9%>`qAJ!5hZ3QpAArEwb8Hn^&)jKj5weJ zZPRy7bZjkj&D}R*QB+HPDhe0l>n1#q5r6$kAHQFR8(j!QK6s*bmY*so&1uvX@S^`e zKlM5JEI4_l1f?%u`km6J_(i%VTe`4^1f)VD&md>EV9^?R>ZiK>n|Pmk$B1h3U#Yz2 zebOu?_@ClX1IrNd3~Y2j?$9}($1qyzv-~7h$>nW$i*J{@vf`Hs=11+Y`uYrT{*3>Z z{=eQD+$wjmO(|d?!;zXxQjnih?Q+KB-?MI6&tp(Vsl&h7kk=cs zL^luUVFceckJ3-99&U|dI5zsj#v-}9+_3P;RmV zi9qQMWUN%-fw<-ei=qj-9U7&0*D-2LKVs3qzq3y4fu*a6t%^%HWZirG0)pYj0j52# zi}_6Qfn3-4t3h^lW0adbT1v}TP`84$s;zo;`5(TIAN?=Tpe*^u8|sAA_)8Z!csp7n zNbh}%88oYUoh79oLhau>5!3Ivcd>GAr*R6f);TS%<52jMKXSiNo`bS2a}LnRs99%r z_^&OJJFCiNPg73bc_#^3v9T0uaWv&y`A}$mROAM5Y||$aU~w=hq&CV+C*T*b=OYEq z?rQoiZ(4pVaG*-p9tAbFM+rI6H#bn+@! zgH8Fy9pwB!HD@aqmT_Kmc_%cVlov0vRSaa|`ayswgWNqAe`ygN-FC#|31 ztV-HSJ)Td9THXd1DMEn>AHtMlk>HSafruFoz1RT=~S&{M%rEaPqr=&$79! zKrx_qdWi08%g_td$|E@(50<0BpZQNt1)YQB=9i= zTEo5!i;yjv0`gKgx`el>A4_*;D!|@)nd1|L zCv68HhAhSlhuu3oR-`fg4c|n-9Hhvo1=!-WPKbsfRC_#~T0b~ZLwgzKKWr0kQ2yHk z`hm7o74T?LGZN6@3ZHTR-4qF`j;g9a7RR&P%L=v7S1}2P*+Rd?Q@2X z%t?)1x+O%bprg1OArH`mTI-N@r~;Rymj~x#i6XMSjUm5=;eVe84iHywc;biAi9Y)b zX|chbccB@(rqaQhaKDbTiUlXKOsU64rkLxC9{i zeq?TfLX%zSJ>b@7pADCvzuResYW@^Yv@2Dk8^o>qDy!~gpJ5wDT`+$+%QjqOuT#Sx z>cu!nry^m<>nnVLMAGTIBx7lBD--1)uQ;&Ei)13{9a3)1$3(zo_h3$Uxj9vjF9~?o z2EjeOd72tmegh-u>}cLjEzI;x0+gb*;3$J~lp|;@h}Ny-lB>YnV1-x2x*1~17rJOE z6M2ezf6b_E?cup!^2*i2V9=~fXTf#40Ei|dWCvVWE$MTenyZhrW@Sn(DKwDYjaJyCs~Sh z^m+SXE4L@wAvelj(%ZQFy)!LdG5qeBs(Y&O9G}J1gndtc8OVf>s!ED~5=+z`JHyE7 z+crtkm;L#vZvm=W7%i^0%(fm;8L|cAIGR!Kd)%CJ`ltS89ng<$m>6u+y=|X^Zbuv4 z`w7+&cg%-8#oX0kaL@nBM8PChAMzYv3jt7#k@N3?w;r|skUF$$Lq9#j$A0S1F=Lly zSohfU<|GD%1pC%A7m z3gs=BqV!`z5~(DB-$m&>`~~di?QXJSXmorW zW>W3^ilY}eiF(WqQLWWXDRVj?IQJ;LN@Tkg(+MtCoCJu0UTd=G+PUWx396%PJlz$9 z2V4RJJA}8aC5%D~$P*4nU)*&`u{xg~_v4@I4KmqjC0o3fK%_iC|qD{6&h35JeI74dS4gIR&=o*_zZ9P9kSQxZEV#STn|WT`fH zUB7lo89|+uQLCZEZ8+leBo=hmRcc*w>--Z zS|2oSSqo&q8hc%xn2->ef@?oTS+ri$s$3!uV}JJ6-ZT>SWdx+yI!I~+*F!p^_h(D+ zwcnfcNry(ehuX95P86v2b5c>0zE8%zPzeefnOa$iqrN&}WWQnXql3#?sMlrq-qJSg z4r6{a4e_!K{^W5ElCPdi&Xtz$Xhi9f+7B)i>YzBq$ZHSA4Qb`8G>xORQE;5K&Xdt2 zkhs2c{-HYg!c32gm zd^O&&hcEirSfOk~YISd8(7o+7MetyG1=}PH6TlFtx^H*w`Zw47si z%u!%F*#bNqjQ0`ChQ<~>sYPfh@niykS&bM!U)~lb(woAF_X(f)RDA0e>|rheu?c)# z%QKqK?qp%7b4||1D10s64tYSmRW46cZ{jmnV91Ju1^FZbg{^;L1c{Q=-yb2%nhuS{ zalxaea+Wp~LK{}vnM|lsm6n#lfgHRVkH>#&RU&$2O%hOd_|_?r^7L?NBw<;wW>x=4 zYQQ9Hhkzvx0uWQNGa+5%1+u+xDbyxOP{|E=^AR3-?BGI9uM5P*X&u=uC{oz<*v)Mk z9Oo2MwHxG|zbaa?PPSvfN)~K3-v_}o_t$EP*%5!a$k*Zmm&g`}r!@t`jV2RBS79|$ z>Ly9r>JSb*!DH9Gts8caU=gIVq?ZnPX#nL?9qaBO@2FVS=Uo)GL<$)10TRnJ4%~lh z0U>P(myL4%`d{@(QI%NzYuA!}!)pH6ZZ(0U15SH-f}Zs)lMer-Vi@=TdpL#Cx){qc znTZCi7xDDWNSl!5F7KCu-ew=xt5$~9Bok0j)f&iRm8da;(sgu`*`4~p;Pr|KgB-b1 z@~Zun!a#S90WyAUv42!3s?QsH_zLRk@!-m=@$*iyGDNI)=I^z6?P>4^3?;R7bPfYe z3DaJ7>rIj5WBt}Dxq#<0q0^qJUbVN4 z%Gd+X2lb3f%TfamRaji3j^gNIm!WiiVI|H`OUFx3GvrCREizP4YxvY8&ZUTMW>Ht* z0xhZ}MROm5MmjcC0i}bT&fUzX%Ft|p{p*)SE3bV`$A&WOK(LpDwYlMAd|AIJA@0JS z)*(UjSq5wD^+fd}1NJ3O0K5~}q!$%HLJGAU9I#?SDnn{XpoR**{ z$%RI^;-e9H*ntu+PFKhQMJZ>cx)vWm8l#R^-N7f^{`#gp_zaX6QAL@#6MTj2F})D# zBGowYp36n<6($0>{z4IVnO9Mz@=brQ*aEuD9hm4O`}ebaKo99D3E{ILv(YljNjg2t z&U^H&J>_SERX2Yw^mQUl<ufO3=9!ew_kL!{_*VcU@X8qbdHV6-9ph8`cxHSA0qs1*3R#^ zq@qVOvARz*)NCbZv36gB2fnC93ZiXvdX^0@k7Z&G_*vaajnyIZ!|{3*X_X%spQb?2 zj5BeAU13waG#d?^Z_^8M4}sp&!BJ*K_$FkNtL|DZ{#78cIpXe37`YVXEj(l53%03X zt_kY-LZg0s?sMwbi5#r2xR~;1r~Bg z2pzPJ&#BQ$)GAMz<9_(;cSHm99YSR7HlIC(`EeIHBe9i(PYUsVcdzFmHWup=n0~%_ zX=DbAH6+-1Pn5p&PH44lP&?e;?{btH0H>aN6w$$q`kYU$=jv6pm!S?qhN5rU8JBkC zmwbH#VnOqi2v@@QW%&g(#PK5j-vDP|9I}J*ph{Tz*rkW-WXe8cC0`~qGHPuXoVNQrCdO%*XGRqBi}Qt5AYGDZTme$HgW(2UnN z8bV*02~qDVB;+3Mfj+okglYBu<)T?b${Ijbkx|TU4!S|6UUn?oMIkZ6K&(99q8*Fo zOr#SXEr8hz7Dbjp@k_JR7~t@I{f9-NT;w&)K?nM~vYSlw>sNCfXr>GFtHbJ9`>V1c zL&#rSz96ry9vQvM^dYV?QSgNa9WB_m6C|&|iBC(Qc?913UX=?G8WC*3?lBA3oQE{?mGewkc$JYr_$UkE5+n zq)iKdH3GF{egps8d2{IX(D!Af%F3topK`B}B3#6l6!NOwtj`A6$WHinV0!J&>OQ&_ zPJn(yorZcWvPj#KSa+CfsMWNMOGEW7)T<~_1xmg~{ygPk$l=uMx7h2xgG;G2*q7ar zsB(jAJy~KA+iAtF1=z35m-@r3l)bDX=?E`sROz_u=HV4yUOJ>>Bu@~s1iA2tC ziZTgtHGRekBtoiMim}-ey%wG!kWam(h2G;NikqLEZ8-)7<*ga)kvE<_EU(W$-MIcK znDZ2>a2RUz)VlAMpa86oJ7=2P_4R=e=-1J(<4|{&S%l^y#{OlcH8c+QZXda_4<# zd?q+m1E@&D-EJ{f%@vlCFI0Ji9BR4bd{u{s+lZv6DF$2W>n-uOo(n%j!E=`~IJm*q zq7IlXr24ULJpMfTur+MW?#s~#)$jrj)&UDgx}cT)*|ocB)Iwt=de^0aI0Dv9ksl=k zm4bkj`k21*lDt26ly)BZr_RPqb`d7Z*L|n| zHbaHB%b)%;K;u&aph8^KJy$*AlWb`a(Y4!+rMTYX)p*s(A~o(-00=zF$VW|itFT3H zYquS!-TItC<@-%$SD{QP+(HxTHg^1oI4R-9l}l}2VKy-Q(1@#e3j3=pS-9k(=u-so zm=4yAz5GmF`#2epJn;F0^X`H0FbIB#o|_R!QSQRIZZcQI2ePOY%o|TE#yo5`Hu^{i zn%q9#H~4%JqlG<5PsaELD#>!)k$D)1G!a-aqXH0DQxj<3ZIY!d{MTvaASsW zu*;t;7w`UPXpkXScCSD4^S0;S*Q*hSrZpeYL8@(8qqNOvMIf29n2=Qn?J|#OKDCJK zuizF7+R`zuCOqC+&VZc={xktB;U|0fFn^o?qzuDRqr#RjjfvFX==1J&8WjOE5riL+pGj zxtVh}@Gkj~Gtajp6L1K;d5XGQ^y-h0Ew*{N`CrD1r70{_%hIQWiDBV=M0)sXbwAH}TrKdt zpgJ^V!g#`#S*cXP>J(l1xDaZwdqI>Br)dXal3(_5B;Mpd0i8=NZ zi1;bj52Si_{{|^0B&T>kb2#=GvUP>OjO|?{rY9vnAnBZ)gury3?Tgjme{n8Me)q6V zU4?FguhZrjrGhxEqHpUlZ8H_A#!EEeK_MzR<3PV`!S(lJd0| zIl!!s+c#mPty(9RS-M{@e0qP^PL%veXueaU&VT&kz@*CNOnoNSZKm0i?8yXR*$ZPS zY^cv%mH&(3no$b{u4HJtjNNWz=m=KepNhaQtzI<#GOr~t@kG8Pq`fczAl?|<63sVe zV0QtI+)az}Dph5 zrFD)AMDlf%S+&ef8FPj9_3c9Z)g8voX)P5muqfxV?5$$;-x(BsyAH_5%YB3Ns_2IG z4s=0XrynSAYXv-QVEp`>@A=jS!HC<=$tl9Y9++B~e|ggRvl&Ks+F=<<(E5liGSD_= zK{hbOto@Uqy(wG}zKGRYMbo|ZA=MgnM4msY%)b1)dCXU8n|mo;WliwS+)ID;#(B04 zZqrN=b;Wk>YZ9wNh8wAm9VAaN?YJKMcqJnm@OrRYE`x^zIM#dluB0V`#0L-+_n6}aj$l+0uB>qjaAvKfvHW2-Js@F z&1Xh9S#!1$R2u*KXl5pBA`L{G8E#xc0hAX?0Hrm4FZEKTMJF5f{pl_=nEZ|VIw-}+ zlSs#xuTdfcF?C}iA0ZzX#8l)y&Le2WnXpULth}zM=4#5Cb^CF?c&H3PtBkN5|4|Ja z@`j81Ggl=`ywVrz2o?;UK5=)kj55ha%rOFqPg&r#YlTc+^UuyH1LB1Roo%j}m$DQD zvKIKpB%Gmf&H$4n6W=OS#(@ubdy1|tImGz}N@P%>z_LnFMUm{D-6}su-6oS!Kb?xW+?$jPA(rC(4j7M*vKkG80gJF(#VZg5a zw^YN!h&33PoA7*xzT@}sR4`$0yq{-Xn**f{eZH_nzmgU9TDH9L6i$&Rl3o|tLxG?S zz-PP2Y4#;7cI-f;dQbt2Psw86(ZQUOJ#)ht{kJHd@Y-z2c_)eYw9Mb`btzOxW+UH;42B0sO#!dCnT^aBV#M@;mwzH!G)`mm||G15fMF z2A^&$Y4vi|fK*l@b>u;djJ=2!S~F+DX!?2N>WWZ+g2f^@=m})ZjC7Ouw=+(z8O^k0 zYd(|#RNh|0s$V;|UEx0l$b?Knf&QbGB0#8-i6R^ydu3j& zi(GD&nyXbmh`dTRUGGVyk>7}~EZM@={G>{Tc*8WsvxrUEqD;xEO_`MyP8`x5Hw{YE z;DqVxTzeejPm`lK)7|Ij)!at_Gj3WY5MU9t3w8yj&RBOId9>a*ZI_fF)*4~WE}1OB zvPA6(rBpu^k&uf26Upag-erTN`a@@~jY8^-bDt3`w%41+Pe%o-O$?*cDft(;`yB3E zX)%U()txN(Z<;4W#5Uaw?LDtLfm&RUKWOy`OKwU`XUyx{7+669D$dusX>0OV*&fU{ z^6&O0EBIhT0w0Cr7s*K@piP_n*TjX+%=Q~2@iAfvX>@Jzo4Ka2@kQtbxDpNPLfgAv zZz}8fzvd(P{}d-4`vN!EYR;Ku!Xa{NPuWTEVsj~hIOtx_k>W1wA{QFvqfyZ1r9S0r zTBKqG3_cdYfqQ)Dt3s-VH0Pq5%_Pdf8*HZzrthlziJ%50SbSbuAuW&^AWdB9f3b&` zWj=ne^!(E=U7r$xl-Ak#poeS8#$={ZFc=RGNEsBuneCbfHglu}rRMR0JQV`p*FTEN z1Hd#MEe1xK`F4UBGEyc2_`pE}tISCI7;*MB)CzGpFrEt1Rn-s(y8IC0e3DEK0!damv0~lKbxmp% zz23bbfU8J}Z~xu$AAN_MWJ+t(L~Lf1gyRWpQrga?K^BtI>fDH_CLi4FULpU+2b;_< zq;EU2SA_ffLT;HS3_}AWXJ-C&U6l>NN$S~AfT2t+67s+2rt9_!t8 zRdNQz1b;uo2tmu862wuENQ~DbUtikgai=fFA0q{cy(SKH%_V9GUHBDwNYXWSG(STX zK=G`J%gmrU`SrmM!JN@310`0x&#BymUBE=2BBQRb?%&-VW=`g~w{TqBMj&k74zE;> zML&yzyHt#j2D4oBaQk(jjW=&JUgFq--ZdA2FIj=^*)ESuD0jWD3jp1?aI7hL!gsA< za18SdCWrK&@uV~lluzrC!K1COx5&SggA%0p2l9nNF{!xpBB`M^SNiuDE%)5=Z-C*t z0?<-I);n`HIzg`i{y=kisTQLZmQHnxLM^Ic7+zdja%Zq_WfeTueYqpMci3#>Vuywt z>8Brg$yDJHIKQq0P1ItRF#DLWfzpqT+)htsvfMt@!Qpqy6rMN6)QHv{cs#~Z@Eux6=-jG3QTyy-9K;KAAG*-J&2uR}LVDKc(Ern=U zcGt^80DS*#cX~JT_SXZ>SQpbv4xNqq2G-^SqZs2y|a84fQAtjNgz_; zCf3J@Ug^sgVEs9!8P3NvbO|V3)`;zz%#u)V*y zZIr2G?H8u>3pzI=XkNvr<`9_yGESl68m3dr>=8O!f4T&!E?phWElKZ9p!q6l#*?Sf zCK8C#YD*t)lcDDD*8?bHl6dKPnqlJV{TH&d0q$)1J~;&lRnX z!7H%Lkc!gE@s^eJ8&?p&YY^Yj*oO}q@$S%Y1 z)}414q`$;=6og~fa)TUL&y@mT+@b>O_ir>fgJIM10b|&JqT5_Wf#CbkDqS6D&|g?> zqoXi*#0TtYTv~*`c2`{b&#QEtl{{H>_{d?!8zKHn-O5g1eB1V`*v^@?8@=;1S-%tY zS_`zHEPMr87d{zBxv+r$fvkdCDz3wL#A&2nhFQC#ceGn_1X;b7=P1=u@LdW?zL}FS zqh#I~10+@|nCb7DhUL{%^Oycw6px!4)JFesi>y}_V=j2Hq_EN{&p?On;SX+R1a&ds zxQX?1e}tv=)kKWi8g*p_t8K0IKENE{Q}C01DyaAjg#b0T-atU+&R#m3vxMnYV_JvH zcp#fag&nV$*oh+yC6uhSH4Z8J|Ft9D(9SDdKB4=!#`*Vo9{)OK9ARtktS@fgUaT5s z_>Y@Y@d*2BHH`}3p~juO!*qcU*UZAfG9Q1s-0HxaDXqtK_*ePK_Ede{7e(`AWNMu2 zFeHy>OwR+pydwQ`asH(+O8(mB&FgOixauX_f3wLh~ zhiL`NzX5NEV_}PFPV-M{p3oR?kZ5bLX_gAYS?P7DadWbNb=Ah_U78}t3csd#Ue_Dc(FY&vWT@KABO`b)T6>7U z2-|YyBt*_$noG=1w@ZgM$Rmy^kI`V!OETKK#f;>0nYV{-F67DCYIxN7=XI$5VZ~3@ z0x`yCkV#9PZ<>n-$*u!XLIyFJWnU^!bQYl{dv26kT#~LG?ZVeA>;Xdg-ojWhip1v?4&bF=lCR3jWC^6}- z!nL`qpNB#IH&ou{cQUhpP5*klvUQ2t(y`U$kbRYhsN+P4A%t$Li$+I4A$S0ms()5H89dka)HvA!hQcL{ zx~&COJed+54*%&yjW?>&%W{|LZG)HUe0}>TBJaBtT(nBE!g;WC4S(HYL7;;G5#oJ4 z`4cq8yXx5L~VpCwKYO7M{o+%Qn7kA3>$J=(_UZ{ddjKhyn2R1|FicYpA-W8qa zeaDs_I2lruuB9y?#EU+kKD|s_7FuIL4R}TG=Bgm&;*Amasu2JoZck)H!S><&A9We= z$ziX%1UQlI8WD#yA_cnP*L{wS?(}+EgKsl(>UJ9=dJePJQTTI^Iegu^ycc=-`Ya~* z@Ukz-M>U=XuJn<@-WB4?x^Cz)YUO(n$rFF1YXhDjaBhl)jUo;OPtzI_0Sw9HUXE+y zfI)?;*YL^aS0A6H;j!Ckv{#{{067prws|HVSH2RmApW_@*ef&frXd^{8e)(4# z$P)T6a%^sBM3&6IV1h`<7XK<2Dc)ZI2U%oLXn2#vb3PX)Pm=X*?AdhtwCr~V3-^z> z21YYf+P~x0H;N?+t2y?u-(0l)GMZklA*T7dXfj$@i4aPTV6OahPOZco)4Qd{CxXj# zoE)D^wgl!PU21y@A!X5fZGL38mDrEQ={@_X*FtFUrNlTFX}s=&>p1Q!G?Y~#!P1iv zVS8p0hkyFP6XMOJ#1;Dtvi?WW(aSaB*V1svhw|1TQiokc;V)LNbOm?gfyrpYM-c}@ z*QURVb~aN&B4mW$4&9a}^v~RimRjG2<4E`p&^ZjW?YPrn6vG%UocOJ+k$k=f`myf#i=jN4dLmw*Pra)6!TvL zVdA1>HU;6(ak{;EsyR>3^ZPMe#W=NSOeqcBpOl!kzq^uRlHqfMs|_KfFr3Zd@DW)` zpg4f5$iNMYQyr;jr7hHy|3z8GT^3lP_c1Lz?vTx%7Mu1uJh=UN-}ZJv9OpP!##(SR zY1vtNU0I15;nFZZGNN1k6#Q)v`I7+JYmDNJIQ?Q=0sH_#zi;O#rGxxK$k0;Dme$u( z>#W`qyMm7y>;vmgH-^+Uvzg;nFp-xXIVjKOCCWbsA=fdgplRYlbak+lc4Mee+5R|) zPqFm=#4XV}b(oQ0?Wcf^jZxznf%TTQ6EP5y7&i+RXUV7byCyv6pR5)Vn5HAkZ%&Pv zN9(WBJCE3z;z}Je+7|NbFR34pkc8sIy^Xh;GlYHO6JZIfobmDL2``luqWE90RJoF+ z>Iz8Hz8Bd}Q?qe))_PSG*%lAhnJTOauyx1#LZ>u(v|D5@B?LxY=R4}944226Y;aF*6bfLX^!8V^_w)WbeN zuh85G1R95y5H6fAI^)A6lCdGoav+~Uxv!r3ba=2mlJ1BU(N>l}5&AUvd;?LZn8ZEp zwNJJPq_Rcy43dkYU||TTeXAT!0`4W^zMSEeF7Bh)!9umlBu&(Pq|irV=>w(9+e6?U zvLRWx=W4UN{`Gc&?|R-)0J)$t4a-1hO?w|*cpswq1P$^aT1G?=VW*}UY*1DjT4BAEqn5Euok zfY}{`$A9T%W`wNYC0h)SMgeU$D*#GcvBx{v(5}D4%U?4 z7x3k*PsRmLkvW8*V#^?iXyY}}NMm^`8f!Og&O-PhRkFOrUw|N4vv zr(PjLkgo82!2qEp1TzRmui|>t0%g$V9R@}I8VjClI^*Kh%8lZirRi@*+sKSk#ftR$ z-6?F&Ai*mS#;01?%B4p(s7#OZBvBIK#5RT2n{Y69?|;Mn0~qnXupA-F9(Sr^nRLH) zn`%~Gadx|GToy`+3ICDZ5z7DODOy%+8wfStwOSBprs_?=4o}sxHpBh_aw_pi<=Ar# z?E+L|ms-nBLPv=P)LYU%Ck8ESar3X_*guJ2WX7q}OFsE$Vou#N1eM3UCRaMT?dwlS(4=dhxrgkv zota62>0p6)p%!d>zlNR8%X#f8R=dyZXTY|QJKKyPa8o6|Lpv$mpcI*2!ct8tE9+L7 z+v=xhMTN!Io9QYd(EV*4XBe#sn(o%SaQKZ|P62#QqfXH2!RfVo2=ybiBTXf{_FiZ(gxT9SY{!nm@o%mkG&+c}-nF;;$!waOPH?*G+VXDx0C zrB|(zDrCGGwV-0fcD7$oQHS;n0XF8SE% zlUlt4T#Cer6Sz37ZTqxKe~Z?(%XZNpmRqSBbYKAq&hB1idt2?6CMCALQ{N6&7=4Gt5H9NAL}2iu0##N6*j+ zBfLgrJnmEBt|+_YL}k(AxWmY7b4rn_1>8k!le+L;{Rs$SnN;_q7w>T4zkDZcz0aV#G{D)#^evB6LNekD47No$-s5uEQdjUmv&NAhLz zmxdQ)Ml{y>>4sCXy#KYE5b*0AW~9M*&)_9?=VYSJ@#`9!e(gz=uC(Xn^p&N z>3TKWoixm9YcoXfSh>vY=J=J;hGRBS_LUstZ=8x0*D@RYl=QG8tBnrJmYmA`%rd+B zYfpLzK)-@lNa+|m(>8`8cx8ZVYwl@HQ6mKW&r9OIRe{}OTz73*fuwJCqf@rLPwmf{ zvIoXSC@=!tY4!p};FsqZJ1SSU(69d#V;hoUp;);jtsybwODI=5i8|{?GbHUEO&{3^ zwmn12XK3OfI=>8=H)<-F=VZ^d{DzpZ2*)zsMJ7p$!Rl~JzUrMw1R*>W@VZ9hhsO|6 zNgVIA*dX?#h#w8!9DHfOp+>^or1;of4PS9|WBUFu?%NnU3zT(~dlo9_snAKbc_*?I z05^29$YvQob7~63Q~TdpltW)7P+{qlwkd;QCu}?F4$w9h#uS0TMAlQ!u0LVTjUcWS z?t9Tv3Xhv8Z}HcnQjKpQBou#vU-_Hx2)XhY;MBisfRUq;9|-0X+x7w1Z>CEk2k6KW z7jzsl3P9BYX*o?{TbLouuMw8JaL*mTKcS+LtnYAg3X69*X(&||;Z7JDfN6zx=16Jb z`?1T_`|t#ZGlEm-3Ldkc>~jOksVdj;R!j+}vrN(VvRZoU5Q<{J8Fx0C(Q3=%S*q7L zA94X=&e z0~V0@1ff)yGn`$fB~e=4rMwBiBBYho{(Ai$vN6=9o^Z^PMd%PT7lr~HijuRahDG>} z{6uBc&iP-OfByKE)ouB~s^r@@zS%sp!e2!WZ8{gmJtGdQu~fV%Iw=DzTMP=r+yuB{ z74~6d_fArNVfZt($MuRWIf>Tcj{-Jih6Q&V?s5G z${>sDf-ak2AOE9azM)$vLId#oP!|T&)>kx!<{E6IG^}MEc8G$xfNbSW-cjr9zPq?w zJRq(%34+J$KS=SPB!a3Ez3~HG8u0%92jlH2lO-2%H1 z=J~U2J0m_C*~0sa9L%+(4D1SSxxe5Ieql76B@`D`&P&DMZ3nxejD`g47a2w@8M8)d ztii^k@y;nOY(w7D-5FWJh6S9oqH2UL8rG8NZrcjov9J<*IAw*5;1Sz$*G2 zEjOGBIGeq*eJR~PeFn}Sq|ceMvFGf|xL49nE{}&&GbFAM>5S$0oFQY1(d@(@!O{o% zi@sNn)R{mvOh zMyZET9B~lHer7>^wz7={D!g;ITc2lXks4x{pnpw^qk!VFUF0s?#LxnsAge~7b-&nI z;k!o0i0+gHyXXcQqou)sWK+5*o19F3=T5G|T%uW8Djyw{U z+ofICsS`}dfu{+FAl(1QmTx6%2p9yZG%pvnuv64^$vN6B6$J-~>uQ7p={&ljHBkR|Gv*&$1;hbUv;S0Gf8u32;bN;b{-*^(e}1C) zxE86!6S5*hCRNF!4t{8?FyZS?HF#2)eTA_4YaoF0PvYLWgHHM ziy6w#W1Kl39PnMV!I|^CBg@%IqQ^f%_`V)w*!Tl$ zAQl9{T3ST2l>5rnbHC=~vAJ3p>6tF~zI$=psL9cgH2cwOAR?$)KKCa!rskFIhdUvxcfV?HRy`H(pp&?_QpI5i@nMQBRpDpV+{j70vVWKTriDM&0eM5pujN?k zd|e}97A)&NtKUvSfGgI9zlQS>X-BuD>WDF55VcmnqN#Yr-Hct(D5v@*D2;m%@#x|YBt{rfv*d_?* zRWkqtjnIwW)W3ZWWAK88mtIJoNGQwD8kvn_y1HbwgeIaJ&VY8{1sia2`|?lXa|D@J zq@Zq|`uP)Zr{yZ`#93mER?`msXedn0nZr9cgzW&6z=&%B3oMyxL2Z@wULm78SUszZ zb70~bL?!Du4kT0moMyDz4xwVdjlE!U?^k(}*2tWf3qQlz&d3rj`p-VCJRB9GmanIvDIATJW%In+GPd3D~~k<>N@5Y;XgOR-X*; znh4(JvncO;*kSXkoY#fC^rMhILXpoEu9ywip)=-ox)-smZ>4aEa!yyT=3I^NAn=SG zti3`UACnR8K!2jsswKbcCzt4hT|zl+C}N+-!Cd^my=ju%x-H40M|XQqi>g zN=BmZhA7X;;v#<-lp4BQ}8L77862_hLx zo=;ISpZ{KVzNZS#!pW?mSI|O7GfCs6@$|%ft`#|F7$T0ilk)sXEFn1vORf!vk?+S2 zU!ADNFyZoqkHGN!GU4_0SslS7dpIqN88*WV-XkzDt8@7g@6R&Yjyw-ro|`}-J9!lA z=ZPawnSFoirq&7?NPQK{UAq98qv!8SsY2a>#?G zMgQHIn(5etev2>5>;->%4QgX7WIFs_r@zXcU8iLXy@v4bb+Pu%AY-BG6Jl??XdP0xGmIaM?~vHNc5Mxhy~N}FSw0uyZTO#^2?ar}6IB)r zBt+v%_v@2-YfwCbG8$v!4ep5P+(Ohdcftaau+~V2a>4Zs_*d;p960tQ^OfwzjE|x}?|7rX z9KRAJ5ZC@+o`SYr-4T5LF9L+Lc*m;%9d{{{?ng!5+++slc{F%wAOBD{rkl#pYpeE& z_NC=PrqAL81k=HTQKFpZwiDy==`lA`fw!L%pY%FMhU=tQ!>(UM9AxT`JO=_kDiz(i zp>y0eVi7M40tsU6_c5p{>Ak-BDJUUjfPh*Zk zP~@^fxU`_mc-Gp-j8~bv;x?2~dcIrIA!rWjB;G3S8&UJlBjEu5KLEgK3C%1NSJ;@z zDsDKBqAD&<%I^@B<`tOVC!`1yYiBqJ>Uved;c*AwotetCjf~$Z>z-l>&^mGO)kO}8 z7Il7V6%%&@ESXdN5Zt3Kn#K_=F>xz+v?0O3?B=KJF8Q{ud|BcbPLgDt5=SmsXn}M) z31T2XZ9aaeS*!wR5MRcwILfap!7<(bV*bzdu9@A2rr7AW^Z7gX1VahMDy#n|rWs0PIWM1O1gkwCY{)tnVuPE5VRh1~sPp=ED0Pdc@DLT7Jh zI|=DWJ8gbdgw*gQUE)!6{!wb6^I$S_T!VqN@v}vuB3l=eLCb;(oGE%P_(k&eBAd0E z^%ooC_*SM>ilCKcWrfF<1H-Il5~mE{?2D=%ObBq6IR02OLIEm@UU|tw)_{S}MboL0 zKUn2)=-+IW3ihqf;re^jAHuv&4!Mg4voI`kojkp9)&=WlDBdUM7~H zM}l$-FXlWv>#C`OA{&n<2^K{U{sRK*zK9P;3yRj+J@XM$D9;^%&}egu!d&gW1hY*p zWl@M!0^8cA9XO(5oi}ej{JrBm25j5ENmFEfh+KFvUmCN^Azcoc7~Wfeb7_Nd z(~y=KUg-=MWjsTm#b{>>YN4%kyE%CZaVu5`gb4Lc92}2c4xK?yBLc>#c#pfkTL^Sv93;owZEAcy>-tH;eu2X|0qX*!_8-EaQj_rbl zRNM*#UW5-jU20NK-_1)1b^746TWV0V)Iuv4=P zo^|mzFgpu@Bescby5$v|No2@t15llH*KT%aC5c)wnv=*dhUg3MzX^+}{iX(23v%iP zs*!9v)F5q@e+~QYggixlkYs|D5_r+8jvd$(PYr6_KZZ1&r|wqJpevAAH@s^fx*+ zsgfM*<%#7nG?PXtdls;L`Ku!Ce&A$PWu*=z#f0PvvYGKDKXeO*jIGI@N#QjYi{J+0 zS^hg4t9bx+%lAS0+)m4~?=J$+-f|zy>~i(({%NBw)r5%Qz1Dxd7H;gR5^m`lo!~`D z_!VQeC6(yH;vX!d*6QCc=L-lCoZ3#IRMp>`wQlP~&v}JeZ3z2>P(&ndL=By*<)0`6 zQ8jPrO%X#>5sl}v{pet9hH@pOUVX|yl5YB&Q>BB}>#6_*yxF|u3KNKaji;6FmV9~~ z5VrOr^KGCBcPcAiLTt)-uDZ`zX5Y2r;enYSSXw6r7Qc$~^}0YtQL0Epy>5%Sh47#Vr=D<3 zpox{GAqpgIjy3gWjWE6cigCZ0aozs;r5AV~tmhSYdq3Jz1_aIxyH{c1% zTNae0?;o?_ESwsR~XKa3+lnsVygVRF zt+ku>77v8a0iu$xHjwR0bh#(u2@k)`+ftjC+30g|xZjW5bSqs*g8n3CHoHkZ^eLLv z-Ss#|qiR?(a7x87xY9E6MJd<2uJHe)Cy|7^?oq{+oTMo)`Mg$94u$r8ojtMcQ4-81 z8I^`j<+tLHovB@ywVoT`9AOQPmXG{(fac7#7wUwjX*sl0mc|qvXViuDa4FD?cj0W! zS@3_#sCfXzYYXV64r_TLP?D9$*s|08daZR4dY>04Sl1S|;H>AjlaHM4cx7$q*Vnt` zt9~tP`<302+aSp=m(n?!1XlL%?!kQ4%gG~rA9pGef4X#R`+7&D6GtbethE6#hIpC| z(cN=4_``J+_c9BbEC>Usr2Y)0$F;qroIPo2gB=>Q=mj6VU&C9a@LAAt0*rFLt~#B( z;C>jro64^GG3OST{5|CcL_)TVmF|D(@CDL}qlK8?ygX;1OzpeHL$CSa zmWk9VH(GzEbo35FG7T&AZ{?ULTJ)Npb6|PNk8UyZLBs*$C&q?qpxRmP!hcA@qjbNWFdZ$|7r$E8e| znupee_C(N+W?KLrpo8a`MQ{l+2fA#l&FhT{zJ;Fel#G(ArH~(&ocwE_Y(3;x7ZN| zH)44?3pEa2ARNn%6m|pyv|#Hwr8uV{ndd8kdjIT-Gu!kF%vJ{F#fH<>~Z;H!=mXd67u5!jG0oK`CsI ze9H^tw$?SqwbyJ#=p_HTjdRJ!t<+8}L_8^**#xR)A3ls;W)xX#AyQSCxkk@`61~1V z5gy0om8%NirLM6*TPd)xoo_0!YI6thT!%p-5N11j;59dACWqP^!)R|;Pi@ZlOs!bpJBfMt~;jv?CTOK(@mYG%{axC zI6Hg@a<@D*+KmzJ^qLovy)vtpDQRTEADA7^fCFYbn>10PDte*AY!>K=7L_U zD5qF9thT+G8&3M3R%s0LL$V2m$uls4r5G&ikF-2OM+5*604@+eqiS>a{s4jW)ypJO*zZ%s*a>$nhi5g=CA8|^Ju%x2nKHW_*xp1unZA-s28@K|h%7zh&Ebk+N zkHfbn2oO+!s#h4P@~&{L+U@s;_M#l#huG2C$x>Tfh@fI^i$;=cbEB9s=`QDg*t3`L zs5$3SFTct#BzR??w&aG{kSL1yYJ>s7(Dc7YODL7z2zygZ4+vn$F1Kai|8s*8DD+PD zk?PFGmX8h$T#SO~*C$b}*S06i--&Ft{V7ahgwWwf{xvOHx49}h(|Wo|y+DYi(BObv z!=tnma`)b*c}(2=9vk)CP44s=HpLcf0^*4UWg&b3k5dUiQ+)9_U{4TtYoW5DkF^T}`kqz8{uZ}-s>#EV-8w>PMX6>4CRzcp^v3N|<8Kxv@5!0WW zjh>rx9k(D^OcL?ug4ZroszKUe9#9FmHedvTgk}Xm(SlFKmgj+u$99`G&tmchBT7aI zel}CbGnG8Dh(vsBUy3s2`S1u1+R+PD0Ad`;Qn9Om+tt&w8$!5|2)owU? zv5nd4(QNmhCS*7!@29A3krKoPYUyHH<&w)=ljqQis(slHob4)OPFUxY?D=canMS&X zD218B7GY9T)`eg_b=S-sLthSCb+*Rg8(+D!5#ED|CByC{s`+$=`p`5Fjb%gGeFgrc zR!L&;QN%X9l-MQXuY0BS1GGoiGIojxYuGmo>L_s==Y_!R-}#f(`G&B>wy!z?=uX~T zCych=JZwmCfO;cVPk#Ev{Y@m5;iSfQ$vD#rswRHS0E{nbz?_Jj0)=mDjL79GaSrX9 zy!}FHWX%DuEj@EYK8@r;5L^?-yhf0!DtiX3gD4%-v4Io|+A#22IlNo#Drx}DVIdVK zzd7qzsH~kj9t;_eJRxiip2YokJFcSD7!88T{`e22eh)E{W@+6Z@>N6^jW{&lQ$?13 z?j?W#*|H}h%QlYGYvi5i$3i%DhKaPKs^G1ZB>?m-=XOGlu>)S7bM=aBJ%+8WDJn>B zvBLh=&NKdun$aD^eUW|_!)uRM8U>|Tw{ptDk6t7UeH^(=%)ShVSWaVc2ULf1e3k=E zUNxSQ+&=Z%2!C(3gi+F##A(w(K_r)C`K1=vX7UpKT&cvu?1Ke0uNVe~9Z^N!H=NI_ zF~6n8J5WU`LYkyhazO0zFAah?7)ez|qk5>ib`X#H)(}zyLE|p25=- z0u~E4c0VNTU4JhL_+-9Y$4%j3zUV-2Qu8CM(JWQ9GR-d}^00o|H(8ErYX2rT+SFMk zWv5#oJjkvdXv#Hbm<``70`7Ip z2i17;sH2Bl!!NO_&n%%gPqr>j*Se*_K^^e~QzCX*^9%OHEe%wHJs3=t>z3$ zl`4Hdlw^xKCg0Cp4&ufy?4ncSZ>X%ka}f_?oxtty z4EVEy*y;9;Bm+^H&9|@SObv*H4ET58++b{0z?8)++SS-VeBaJNO^z>#XP2n>K_XsX zrMW^n8G>WA!9?n`<&W!9W4-0;4n@r5Oq_BeW#%=#FR<=-)Y_WU*%F@eAG}v~+2QXD z(8s~X@MGEW`2Q;xSPC>=o}PklS9Z$LWT8#dVn`bVTL^d=z1Z18l$EJUQkfYsc@`1@ z(M;#wGD)dR@eFmMG^X=1E6i3x67Ttg!r7#xCmv#_u<_1nBF2hWpTCa?8$D;0*!tT_ zg=DV+n3@?E;>1BMEp`>Hu<1}tdIq6UtYMiQL{57Trgi;r-E=1u<^nSt|8^nq7T^vK zFgkLX5_3s#(}PrTaZwN+(%KG-#qzy{`O>otzcW{<_fvfB&q=Eu4*EPdip zQxix=dIY6*7MPS=+gP<`f*fWB$(YKa3zjhO+ij{$riqNnqrtLP-{&8kH)AbdYh70( z7Kn?V@>hmq5m~q!lWwH9bO(vr#D35c|?9;*?uE8Z^Je1$xaxI^! z*dY5%DEOv50$khQdXSqoov=jSkjs=^$Q@)n{IDPHCvdlo$yYF$nD))T6sWnwP!TD- za{d`=lq8es;>XcUlC&K^Y*@NMIcjl_=U9U5#{S?t9rOtaWx-k11T`+tKJG z$edzm+6fQVTjhZWAWKXWT`*G+goX8K55TP&OmVQV|4ko~cMuqWgDhJs-x!;}8?gOg zqBOuRNjUmbsx+pQmFB51C zH@gvl&;vz3Ks#Zj0@+*S4%Udj>WCq1)sO;Efj<0II5N-_a1`*F2#%eIT-6Hvoutf=XZSYn3MnZf&!Y z6$24YvZ54Td#044Z_>+q4?PU_5;@ga=gu}@hq+~*U9R_(@%l0^KYeuzH+aX0USEZSw+aPp$ zo!PEcaor%NY7{Y|c)tLF2H?|SG|M-FojFueIEmiV1IIa6#7Q^;aV&mhCF_!QaikbQ z|5V?$AaHa&38yJCpQq@?)Mhzm*hcgR(RCjr!Zcz=>wY$h!~d#V{uQJz-K=$)LFJ{v zS%J4@R$_(+PQITY^+$e)yq$5Knu3sQD|TTeyV4_q0tW(j>)$C|OyTv@L+wsN5T4$P z#*j~P3g5nlw^&c;-r*m zb7?WG7mJf&b0uAI*q5`k4`XHSL%_t|u(soe<-+tyEvslGF^vgRG+1s!oQ{oj%&0E9 z+_3(ZVBgp)Rllzl->?NNtPZ!@0T@OwnCSK3@b>%3M2KI>>?~Rgy-gi@DynV);rWGe z;Nn#Hu`-TxP3`M|yCueRyD&)Oq>F0`;t0y~d@R`{ow9`Dx>S~!nxHJlUD6tH<>Xg0 z$*Br#)bsON5j72o@IG3yg(!}O`>lIIjXXs8$a_)-g#mKyP#SmEFL2%(==PMI}PFygxQ-s(F{08?zk~am6p{nPN*@Qdk6_2<~7-~ zk7Y}R0m-hemhMYhf3K?EhpBlhLHi9kyhyUwc_hd4lg&nOAOy2xYMxVcg8zopO_&bH z=>bSO21lw_T9$`RnRpGKFZuNf-ie*?-WFM!w3(l;*%V@9LFF$5 zB&#s06h~zCSV{DX{)xyZC#Q79o@Zrwf~{=;q|kwDJg}Tv2XHV4tDjN$a0IL}AaqPv zB~uVf{EGWAvU0q6D=EYuOQ*v~B6xt!U@R9M+6`d(&YvvBo%$wI2e-XS_`qlR>-u`m(RM05Wsy zYdvFRI3703AQ<4Qbc!iwr?!e^Q`P&`7I{=r?~C&xkq)DKS<)V#K1NL6gSr`gMYp_aIT^FpbGCyTCd)O+%2ZX~tm zRh#XG%HHSX%m@_*a%1_us-{VaUXM-(8rPB`?~WsfM|OtYI%AGM(`1`!j9~}D$AC%KSVjZE_X)QFG^eMS}i45c~<(B@v8@n?Q$0jU>A7C z<#F!bh@KQKexCN;XuTwW8_$~aQS4G2`TCHgkZp(7lmJO2O5vem` zc&;ra5K`dSj)tJiKrkKE^qt1~iqfC$Vyg1AuYWDJy+a{n4<&;|$#^Q6V0!!4zSn_x z=$v0C&x&e;xv00H@epHlHmE=;#RCdPb+iSplV$rBf2W51gC`iZx{1j?J=@4A=P2~RsU=Z* z;$6JzB(~AG(bUxi?;%({j;Cif!O34Nv_T)JisH|pc8zDrBcq{l5F1l=PqMLOmm&bV{gnArBEw6C4zUt7o}JtvC)^H>r;|7@M|0`GbSEEH zpje{pGER+91VeOw?4UNOZeq>6$DBf4Ug}z)fM!jQRbq$t)P7l*qfEvDt&ZF-1@%{& zyUd5nN1DcoDefo4pwpL6Psld}+@^-6v=N$>3HXPa;CGOGG}%vY|ADj^j&EpB*w2)5 zz1nt~DPZM14NBngJ3kAQt>ryr6r2CzS#H6_CzO6!o#18KW`l;>_q~2Jx}jB2*--55 znRA3CSpyWAfJ#w;$|rNiA`BooCoIAtD{3|tYzi2eK z__;1n^vvmT_}8Gn1N{ihf)wZo z$AITC8pvU#mX7q-HE=%RZ;%nWXp%1=>^Jju=V4Jc-duc&S^a!23+#IYx*MjP^*%-{ ziyd=Vy)npBrC!R>Se(;5gMd&lyW*{uC4=yRJK_38feDKdEa!Ss*dBJsQ=nS)=T_KR z-o}J%WObQ5$;!gtcn+I-o=I@Ba2Ae+^R`aaRF)lxpaQG}mL*?>ySY=YGYJ?A8nb|* z!#Znt%D}}B<&_V>L0qo=cM%cgqvs+Kd4Lhkl3gha1OM1K3o@bk!L-+*@;HXa%eo2 z#QGu16^ z?{Hl>krocF_2md&I-CIMT;6DLq=WnnLA-xr)LN^Lh-jfh>W=Aj)C z^~rM9$pSj5qJpI9`1u&HYxR$kpv{f^8V(2f%cb8~yBq_Bzgce1ZJDMA{nVB8-+?wA z>#$Hs2D>2==a9;^@~orH>~8kQ@4!pejoFo6UBiC=cjw4WC>w)xUlJf#pnP!k%kXD5 z6>y~7iNb^;MJ#AX65F!i>vz|eKY?C#TC^ms*0|9aTzsa~zWPH!$_hDq|}Oh!BF+ah&G%KWxp za>dq)P~LpL$feyUvP+eUU0t4%8Jc!pZ$*Q$zj;P-&5AgcS%Q<>c;~9=;4!7Tuqk(k zrELc0Gl&I(Kn>gSq0nfpzrP>V!afH;_+T&cHpEezhs&ytnCyEGR9>X(@~CDOzpNdj zkS)o%U>&*zQ>tOL1syKjX4(-_;{sE|s2n#09bAUT!Rs(36Fed57Au51?%}K2ikbgC zO<2r)PqeUCH`gavk7N_Sm4?la1?gk<9Sje-`}Ephqd>LIKltFr1hnIt@;4HzF96B~ z6@zP}wQ}C_ClvQE*DoL6gIZ9sZN3auxY2;0?bxwgk7VnY=Nx`31^^xX4gV=PeqhXl z9qx_}_pTxaD~&f~_7zHsh+?6wYBSS+h&O7W=u;+Tkj_2@pyfKOQn%Tt2AOsuu(6Vm z?x|7VEa0j74yw|aIc`_gF97=|U&zs_)6lXnu$hyu-8 zH84bq7FaX{I>*%wJ$8{KW>QNfuuc;K>Lt?Xwk4nN_`vM!6w za+}gZsZKFxnHsLM>R(ddhEqhY%C567WO2o>C3gPb776r9c@0cS(E!fho1MoI#dhB! zMIL!D`5$;M2GruEX+zw4y;6kBT^#u_NY1G>T;C+|Gbl0YPsVr^SEZD9^l61JMc#B1 zl#*d$sL`l#7w~-WR+40s&lymnJK0|(I0OR3S0gXoFjxFmJL^SDZMG_fCSq;#*hFpx zOQTmKe^!(3dTZphPB6}?D~tlEjTOWl0SnPepQ^^y>Hiu{l+BjCiTMuo*2&7)rQNck z6vnbt{>CjrI$CGQbguIEdb$9{XdUKDa?@HfcoDziV;@l%dBytUtPh8Kg4Zj3jJq<~ zU$fbSqCdA^ocVjis*=TUOwP+F^f8gmlgC~a66Cg5ZlSzf+p0VmvgAUsFfz`>wqm`M zunG_psy5r45Nz1`J$RnDtghx9S4z9U18lHV4cNB53234^lGu}~#i@o4U7skls%tBu zeDWY1++|}QRE?rWp)p%2<1#i9+wKd7anL8q^&6JUH(5_s-0cJ0Kl$fCl4lyp+3!=1 zqGW=v&0ujw?3dQDJ9jBZRL-MPQz-$OWuT649lOR>kObc)HQ#e+zK6b${ zabE_&ut~eL2%~=0|9VdRS^ljK*{?LuME{F@@c5GyztfmC`k*_K8iPAT;$5tC4Eo9) zEO~V{7yf9WddDqscS#Q5YuHU?-zz%VI!?6>N>@2p!=9bA@lon?LDv8`&OFA1n&-6y zmcGr3o01n3xl3q6{j;6K5=vj=y+-Sj_iF6H_$-t{Y=juq4Dy<(WEdCLV)dVU{g)Ob z$bq7JL=Hz-y8G5OAQcIUuM5jp_haU|*yr+fAnHM2E{cwEW5)LlwsJCt?5#6B0bwqL zUBvVzg30vC=m1XnKN_Jt<~!W;llwj^f2ho67_$ZSLC@XSM{<;&6&16A%o<&Y@^;xJ zm0eq?ji%IL8$DYV*i6?dOD$H`%iIZZuXIP@>_88+;26KLWsZ)J^_IQHX`GUd2yN?& zTFHg!nj}g@mj(ZvBydJLB7^v_%#~4GH*JCW^j_Rw+^q$zd#~TVWfubBWLS1d#93ZF zxA=*Unz^$8Ia}J@5iA?nESa*EGVMe_uaQH>;`_?K4K$#6+bG-`urVr{GmT#Y?~@Ju zSUpGJ0?eQ3BX;6ar<=mC z*L-O9#5YOOiYgB)er* zw}%xL9&&YOC#*ju5MxM@ku|70Q8ek&{zlvv3-H$>x-v`j?-)HzN#XzdMc8yoa4{l$ zdcvdx-}mfrTVZTAF~v*CRc_>AzgE} z8oU+lr=YrGEkZdRh6;RN6Fi$%5SDi}KI^DKg{C&`?S~w16LcQax}h4KFYFJz=e!KD zCaEra%USgmnYcm+oO+ATEm3vAfWdB z6n>V-^FQB*!htIm&zy# zF4{G04~g}k^U|j8NI-mrD#jEDs=)Xq^elYEoSczWuzt;F1xd@*EWOCt#z~XLAY9W6LrDsawvQEt zs5c6+sv>|EHX!un9Ao#>%EU-D*o*rvalv9fOwo2wZ0canS1$;~J#g&yJ2k=x?6I`vT zGWXMEq5fiv*q6oKvx8?uxfRU3YC6(c5tO;m2#2$CrDNigR}jp_j;qmBN+9-gGFGD< zf)8+4vd|ren`ElQ=<@9bwvaY0K&jP$J4ScDH>S)Vix7cFv9G3Kq?X)szBua#Bwp?P zc{W~mrw>@FPN{&*iA)AAWXMEcY!L=RK;+D01LKfrCA!4Dt|KmU~Xp(^ba$>Z#ocOS$YWX4LyZcZ#DN_#6);A@jckcdwCnv4% zC8Dl{^&GXcDeD4Iz`7zM{lCi2_T{0sZ4$4i1cX2eoli;E!x{8gf~-!2U_0t5r{S;o z(UiF_4tDCM2B!dA01l-4mZ3wm{KuylG81qmwNJH=Z4M9qk3PdOf2yXVS+Q(?vgpZR zgT@G4$bf0cZ`p;{L^tfBfOaNS7<+F@xiId3wDn7MW2+G>3;&MK0ra0JV{d;vZ^Ex{nc>WU0t|clE8>yM5sub@q@0EE6$)MFQ6B4E zF;6g?`=E_SxEZWSs&$@X8L}B%yc9p&ergPzt<)xs)CF(jecUkl_GZy|KM9VkwE;!l z%5}VaQt;Xy7a{t;kvjXt9Vca%_lzKftl(E)GzSLdD_se9qL|<*kk+d1Ym-g*!k&V1 zCdRy0h(@?{cMf`&Zs9P6e=f4Gb%QrN52k`6rzK>Ub4_b3JWqq&5@TlqXeWBfB=@0C zuQ3Yu=JIVCHkT38GQc0l9v^eUFMP>2-^U-tJ_#>`>a;cn5 zKBs1vKYLxojdPR^cdfiM*+*>69hEQjKGzJjb$D&}hRB!`5;A1~IZ!M2k{(J!WHHc| zk+STd5}Ph0Jkxp$)h;9A!v!3eZ;|*i+w)c(dSnBmtH%79@z`76g!ZA*fB~W60i~5; zp9l6GIW7h-fk`c~f)9T)H)(yuMB6w*cpVx_&B>Powp8%j{S+sqRCsv5${!Rr#-A81 z&233ysM;dz1bP6bik&`f#?-S9L&y7w@iXX5r1PuE(qlH2ds5qrH(C6pzzTSHI&lkCIcppyZhD}b#V}XhI1iUrC3~RvM=KlU$a(8( z?R>$6f+Mu6s(#KHt-Yu2?%D{lLG<1?3ejZVFuNFE+P3eH!kViJD(!dX3NEY-Rl=M_ zq6M{HD}EEiOayIMvHN_B)R>Op*>z-VX^rxT;-GJ;IRQdKf$K>$7Qv+Ljrio3$67%0 zB6A}mgoUGe={1OdTQ~qbR%fJs;)Kn;?9=M=+iE`jjRNgX?-R0^{~_NetCn!rP zmr!cP&68Al5s`8R*_K3&SI1-{d!p@V!MkYK!IYyhyn~F`b;h#b#?fIwFnt3q(SRCi z+RDyTeE)Rieb2+1S3MScVFlwTGCmp0cORgo`cZg&Mw*davcP(~92i_Q8O=QuDk!+o zFwQsh9NDu{v6qmP&b}NOiW&eumU6avI7~ASiq&s*)Q+LEB4o;kC}7g2#|oI9nGO;JcZUFYwfFnR+WdMs3S6o2D zaO*|ZH>GQoU)2Cnoi0*E#^1V&=#YC^F(bweZQ)(e_zmP<-_FL6p)`_6Jr9jH9iott zzBWVk>aJN`K=iBs1s6K7kWykBH(C(qf-?q6AsJIc@yyHpV+k})d|3R5xvZi4|4&ZMdJW&xL2e}w=zM{q@I%m77Xgqud?bEpn7un*x$cT~uz zI0CM`Zdcr;1}EYp5y?INhJCctR@g8Zh4M}-2FFYg4RpK>?sM)yuVxk4+0nHS9pj_J z0+u;>-BvfG58wdR;-k9^tOjkBnmWz%Jfh`*n={U zu%6CNTY39r4Jx9U&d_XWqeCmxNY}9h?C*elBA>ng&A(M^5Mz4FeffT0gv00Qt$3tFC%lwvylzToWzDYQ!cdlneg2os(NMXZk0oy zdI6YJQcWID$I#h*|&61(GUDNfN#Jk{cIrUYSC_F25qw+T~(= zgjuRVMxlUn!-;O(Imf2dIa_#`=BtWjku5PCP}as(itba=+4)A#+*<%#Rp=~*Z6bZ; zh^Q~L$J8pPM`RLp9MVq1i6KHO?d2v8B_Q#4zM5YKq?pZC{|it_9Z)< z8zwQ1mOk17Oy?|I*mL2u4aKP#WG5{Tzi#)WNa}YfLAoKB@N5H_C_JFP0{H}~_E~_; zupf%sG1ilELb1$l+mtDIWuUJVoQ1mw9 zX@VZwjTf+yW>D^@u+}&K!B=S^)1zU%}xUKWzPN8OZ1On0CETu+2ni!Ju({1pD zL_n{W1emsWx@2Lx`z)>HMvVVca5KjC%D|$fp#S3;{J7e1hFM3*gq&U%o_%~KnkK}3 z5kxXaHRbRnQ@K$JWTJ1kuO?)hXAtLu;eO7WEla)UFD^VT%EZ z_DVH|NITnIbk#eHFE2ne4HFrl6S}|p45mJL$h z{n>MH#&7ljSq?pYLfWA@MjO&)inE=i61r%xTK(vl%NqmomI+M%PI~}#G@@i|yJ1?( zZQFi!JKRcmsXIH$+MT~p%EZJ)tJ$Qt`ll6*A8$1XHy>?3yWBGv#WK(fxkxfQwbu#Q zTea$ap8yJVc;hM>sHLC_u6yw7RIJiqXk(y@F1r)k>IKuN`$$EO1KKj@8ycmzg@{<@C_ER$yMbKTEM3y@kM1O& zKS4fvWaq{JGxFP`j&*&;IbdP8O7h0%h-czb22dJpAP45iPfc!+cNJetxXN;Smh?`` zn=8Z#r+$z~=HGcy7dwv&`|8{qjoZGJtW{c^m41T44@8J%=@gNB29&bX9Y#t$hDIv_ zD`ZYIPQLG%$!wlK*IPjJPW?oH&n$a^9{6jkfg;KUQVk9~>gUr%2LF=*@O`I|H>JP& zJ0?gO;_%2dNogKU@ns>|Ri*1t>IIVi!Qe2dRsfI~*lh01nmZKKDsK(WX@{nCOPv|L zUu(+|C%-D&4@K6h?1;~sb!#7*Ee=aBXL5JCf6rc0!tA5Ao|km5U;-gQ6lGz!QHEak zyS@a!Dm?lp2-R>FF(Qh-u8D>{Rs%^()=8R17h0e8T;(n6M_;uV>=TT=saXSqb`ePJ zS&azYG=;n4BA!~ygdm7!6Ucb&-=%7a6P=ymxK zO00XxOrUQU_DM2bNWA^GX`rn{+~m%N<4NbA)_l}iQO~?jetkjVwcxU;a4km}7(V6H zh{Ynh#Crccjba|)ZlI2+PIUIOv~5EJqPRXX#9Sw~uCjP?1a>J<&@#MrU2Xe^I(@16 zD$`m`V)8qE0Bk9(Q)GJ^rF~S9X0D}~YcAT2Pp{aAb+)0BMPvqfmKwkRdc4O_459Pi zp?+B!MCH&nkQ*AL&%S0+K3FExkF8cCR8^o3a7Oj?yQ6a6LT0;UJn5jTsR9HcyzNwk zuzaYQU2XwebVw=CFc!HLMFOS!BW&}&-<+b)?5LEB`fy$9mDtg8`Jsv3&>5QGd#Vb7 zB(Agk#%Er@P2wu+j3w=DEJFvV`}q-L;J{FE7?Ps0CD`MpxI{`DW2|cP=(rI z7B1sde?6hjKR?6Q=Yp+7MRqnf&i`OLhpg)OM$MEq@f%|*$`BPOvHIyh+fZKAm4yxL zw9(|~P52&VFnRCQn)sK_6=pINcw4*>NMpebXcJ4m;yY8gpa_$VQT^lVj4%3V!_*QLMH(MaWI?KM(7%dpfOtk~RVM7VwMgl4~ zem9tCI|UH0BhgM;l?9vxSvmi~PV`Fjx7?q;U(PZE)A~Y2(aAc5h|Ep5n6y={&6u0w z^J?!XbXkw}B0fCPf>8+h>)fv-tSdc3MP@7`wMLahr-X(EOCtLXmc@o%2=hD=U4@n6 zyUkT;pWX&Gi{b5vA`*|?cSYOyh!;dC8v?m;G+{z?m`ta${mrs?=o{n`92s}KXG`=) zWhIY&_LI~=P*lokN2$kV|N2wK`1>=8IFp(*;J<9OUu@OiSy@3jFgt=E73U1d%1_%K z*oGJWd1?;gbJ@tAc1fJhT1z1GQ%<@>Zrt7*+h+d(ImEP_7ZprPL~t4V8sWXO(?7(T z-Hly#)Apf<-Kd=|D(>z@dge*owBA;-BNkcCNzirkA3B`w;MK6#VII9sH`@twx!v&u z2;edX9Z?ucR!wI0m^KSu_`uV_8Oopd`u>BvcE=F;ng17tL5bw;o>k)Hwc)U7F9!?y z88@hYe2ft5pbwV;pxGiWJ_MB>|FNIL^W7zXsT zw=BVHqzAlKwCVX+jL_~ux?2WBv6)y6?Tzn7X^yj?1YOU+2o7WG-nEIV^nB%*a!H>S zw+y?Q@|#x397G=VI-DU{;aV^(S3{L#<+P)qUnYs;XNdI5AH}%wTd<@-$d)d zcJ99dI}(NC1jJ=>o8ugz3mcg;sJm_#iMw6RBkJN@b;6%xa5|KE2`48KRJH*BKLEgr zQp1J4bp+rn3j;hHL#?7a+w3ABgzM20lu0U2cK{f0OjB_oPy${dM$ zy2;)P`XjRZGeFV9%eLSTK%U3vp9ZY`XcDsQ;zGaj@~Ji}<3HCwI~44f4~LY*KmTGm zwP{%sB3zjxG5fpY`OQOWO>9!y?>6HVjA%}A3bfA;FRH^@os9&Umtwcgn&g8$+ay{G zg{j2^E9>&4^It7%&xm1`jZt@gpK%c+vipytVSp-N3Q!bc+~%Hg_$8TSH(-JGNP5Km z4YQu{g-aOR!tj=1NIWCS5$*zIfG=Fy0d!r_ivcI7@0ywmA)g;=(Mj~QSvqishYjJ` z_-Hw25ie@hSQnzg;(V%&ts#vNq|j(-)-#H3&yw&9O0N7UFjXno!ac!FYgqHw7-y>< zv)3=z1Fgl_;8Atck>ZXTkzv&fj$3oGq^F;nDYydlc+f%+oxskkn8G347J(!dw@&9w zdVQzB)2r+36QA+Cm6UrW&j}_HTDBsCyn_PIXgJweq)SNGL)hm^o7ca1i{-A>PEBd` zgkQcVt_`%9VIVERP8AUTy1Z4Q;XKUV8tA1NCwDXWPcs4O_T*YG{K(&L0V^{@H*R}+ z!}HII3G`zw60ed6pUpwAmuK64I;PNm^5-;X?D4*=jUJ&+pMRfwjQEb)--Mx}Ign^O zM~84}!qaYiMP&R?DOx}x;-rodZPo89yg7k;9R)oBXEsE^?dOw!eq=#?0Cia1i##&k zmrBG`mHl7w>kU&bMk34`c2jpZn=i>9!2YXNMGG%Souf5bbq zce~q^+1P(B7R@DV{j3@ade{Bx3#KAQaH`+nRW~q)XQP&Pi?&H@K1R`XjTQs4bxTG& zEj`Gz%-L(S9%Js4x6wv_B@RZ250J=C?|>~&px9DBaKnT(Vfd8+_v5RRM7+sMq(vwY z=4M8kaQt+KdOPk2?B&8n(7I$F3hW{7a^h#fKHEOr^K>hjXqwdZ=ByH{{#eVFea~^A zVGkhSqt00~3z=5?deOo`ZqA}B&UYrv!S=#Q>b@+8tqVg5CwDFkMn5%B>SBLe;ADKO z7&#HrdRNOX=8SAK+U~XekyH*zf|ZuWBxMnm!t%tuaq!HOlVpi8zd@Yz3U}Zj@2EbX zC!Wmq7w!N2iZJXOJl)}wm;dwjfD`H}Gew2b3E*wc(mAi+1)9Rzir$twyG_z1l9TXV zQ@_?y#mhr^2x^`GGPXcnO-?N)^4VttV6RF601%zYQ<}-4nmld0hm#oB>YT78w6zo2 z!50xAk#f*Pr3in5)SF6n5LtfR6s?4(;)Y%(!yQ#yUloBVjQcC28i)t*uW#3wD19${ zFyW8ozvRJ)i7(kef76lAXFl6E#&J&X*_Pgaz0A$LB*BI$TkV@>Y=kzurb2l1v&XKc zrzp0VWK8-&d!VyKK|6p&ZT1yO6Y_k7F&~a!;lIj8uaur1J~-XTa~oJ1vw~EA5#(JE`qwpiLn%9y-ZN*15I4G$V^06*EKAXUlLrQ#XhIPM4@x+* zWK=B&nRMVrsFLj_y%C?^Jz9~K8ohiawq8j| zh?a$o5)E=yUZ-kb8omk3}(YHtr8fZOuPJtXq7kJGxcNz8z^J&s@{n>6V+ z^@?#2N&kR5`U2T*!t(I$PY~ABo2l&hlZ2yr8JQIDk(|8C8LU0Mb=Y^9t?Hv8@wO)k zhWCwM?IajsNs9XOS!BBk(M5~KM@p^+my(R=KM#}8_?*7M>MoIz8N%1#gZe?6bKO@! z^d2{~mc&GByU;)*Ejg*Pz?p~ShBN`TMGU|+IEFv_k59H*uI}ZKEC=#GghuF|ErUJs zHfp&R2Zf*NAAL%P!OF~}4Mdg8eMw^sA_*H0fTC`crdnMgqB=PU$J!bTMxYwM)IE_3 z?bHNse@q#Q)t-F@^J(bRGiVN}DylPH02a5eo)KXkDSubz5V}Eg1yfd$Qir!XZ^UqR zi5}M@iuZFA@vXB=TIG6>GmuaZB+S;nMzX-|OTInfQOqq`J63EqFoX=P`*V^bkFMW6 zT6xN6KlHS;NND5eZB~*S!SccUm2#=8ASsZgfkC+~iNS=zTP~uLX5eA;>_7H0{UoP)41xMPLcdLEf-T zH~E^oMvjn68_{?hKFDcBwzEr5$c{bzh=X~RzB5?9$1@rFB#|E(l;P!Q02IkzzE+s+ zJ+6>RG~iWvfjJ2ygnk#_@^sK(ei$GUu&!2!NTw&L(N3wCgJ*Xvg3;VJGF1M z#+}k)t11ZrO1C^IvLWrj9fo&Iw=~{NO7v>TKFVn7I%d7a2`12<-41O+#v9 zLF)&NvFT*0dZO}8viN|mYB{fRq_EZnR~Ab_?;Hl=Cnf_Yl-%9JPKCYdHUo`=PZ^X# zFYSEphs10li)^hK0uwS4A~%od&SM@-Fnt`mw9(`W(lIiDgK2#hE?nhYX-@Igk-6QF4@CUAqW;o-~XgcR5YjC_BAM#Bch4OB}9y`=8MiBBa=>AG&~ zY}uHM0bvwh8li3R5=PZODLVkWWuQ(4%*FT+YaS8+2%AC2i}xbdkd{=l0R;>WJ$$EsFFx8_g*rT=7B+kY-dy>j9Gw#>PYlMI+m7fZv!$7 ziiUV|nJ#{$o>D00<+sHs>0+TZ3jI#Td}1_yP)O@!VKM-=#+pgv4j!~aKqy6+d3 zLqZQRgxAbS2o@{k;|OJ|zp#YFIiF$Yp&OyPjgj-K2ITBXEzgqZ2xeG_Jlk^P*m+QR zTalqmPk)aj)dSqT1Xq0V;-$Nmwfl@t;TBtLAlbq0w3YpfigP$3wAk_9EX5WyE>*#9 zDSCz^iRWd`Ve@cgZ`;r>^zea9G>Y6$hOvuAIc8xGoo4fD7&Xg<#N=R7BH&t-ZD~9I z$ANOBupzum3H&rxP0q57RDi+9{;T3HUGLeJ1*deF<6Nx2 zl2p+?s=t%$hv#76b9{1%dAEh*&n2!t;^fKus$!F|8J}O99LVWmSVpK(;~6d_brVJI zCBB+Ze61t-YxpyX+|Y@8+31hpl#O`xD~!N7J~=ty0xEN5*C@pli=+&JGEg3`2*7d$j=L0X!VmCDg>m;uH^KNb z>AIXb%bCz1er$gy-MVDHVFy;e#>+SARvB6PJ63~hhx1<)4L-Nb|Cp?0DDZB3-umQKXI?LOv#2S1AB!K0(wYyNsTEPAN z9*MUT@M&WVZ&CEK)ZL>&Iizx2$Jn=pmnOLn|j+iQoIv-92SJj4S zX>3QInV$!0k(ORxM-tbbb+smzd4N&>os$~QRxq1MfNWx?qFTn@kCQU=qx5jY#X6{I}W*w&R-v%ZeuS*-ZrA(ejtBeDf#X%o)E zAwhmb(Qgiet)RYeT?i>9gxP#uMZ54@NyI1^0v!rz?@xYS?lCzAVaadE5oN~E4_w#& zoY|Nv%&dYqua;XhDUPL6sDhJK;MVN8=Y!1rPJaV5!s!w8EN%S)u0}bIl-9C-=1QIspumg_pcG`Wx>^H; zWUhTIULlkYw!CwL{3z2E1fpN_%8`SR;SQ+pqklZsaDTo^UF)~N2AS=XM>CD^C}ffBplNn#4MXX#3pC?* zB7B@yNKyz=d6~p{{~QMR_)&`t-0kjWJ-!88+5klk*`u77qF&Ge4#kPIG;#xp4%qi|RBg{C+2Wf+p_Jd;CcLQQKH zvhPRdv%kDI`hG<*9Bn?jeQoPMcZ}!A%9ofBbmSdHPQq(aunM=M+>V8;Rlk{C!vm;m z?B(>OjINU&{lc_1Y`pIx39BZKJdi%Sf`8?T(#>BgnHQEicZyRNO2&^rOoAJnlg66e zb={njup<3pBXG=qH}c@b@aF9QH+=N7@>pCm&LduOCG50$ud5R(vpXxwl3cxVb+fE| zhAsJmY<6X)%FcnYMq!7a*E&Wh+PrODbbcLB-*_6lgsgI*2WbHTxF5$n1*5Hc(HWA( z8(^s`{zeJ5Z!%375kLT>%q3*XnLG5bRIfG)5-7FmhRXh)M4%{3trQsGJoQEsCe)b$7X4ufTfWBR|DPo^*bH?Du~-r_Tm%I(I|2e-XEiw|*}M zb<+$367Kz1uFMDFq8XDyM6(u~u0gq~B;IN(|HA4l2E5APN69l8DxIxlm+fgVL1kV5 z^XOY;=j5+o;sVRYmf#?~yHfa{A>dsoSFC~nAq?H>qNS^RdgT-aP)Ft+Z{|wL0G1~v zvzEhWESu=xKNqS&-(?l`^GjQ*mnkTHOC&wj%A5Ni$>+@!GbUZHD0l=0m|BIlkSB5P zc|R*2ydZ}&Gyc-|T`LGzsJ1!u z;!(6uQcHD~H=0Pz36AUbqx?tj(efj4m4U+(R_t*IFp)6^hB*?R%ylLfV|=73%cOmN zLIi`HuNI(TZK>^fKZLlonyGasPX)KsPW)17YcgiBc4jU4Rb>8ro7}yBbgx*PYgugB z_-cof(JkQ6y-LLds?^5@)R>LMJd^{wmt+y&NLUEnlam;;%G3Ff8^bJr%u1NeQk`Gj zzI$FUX4JgHBC3PSH~lA>+e0&Rz>FSfq7cL)r+#zB#Ej1yB7C?d`g$`(3%bIAmahvQ z)6LGJ-kD{lCkXL+f0;65^40Zxu5BZ{X9s$+^YPbUyzk@H4CpfX72u-`x@c2;L;Xgm zTn*y7SOOWh5ONDA&Wt(SR?E8?w%hP_rb@z&;qD-ed|-t7>gWE1lAM|*4Sg|i3~I%+ zscgh%>)ifr-0l$b2!>`3eUr&s5Ah*EeFgf#wv;CjpTN%I;u*$2P2s5M5-*X=LD$4N z+Dq%T{vOQOJ^oW0=H#hZ{)lvR3_65IJ>cN?Nx71=0>M4UcX(gx?zVev_f_O=JTdJ6 zwisYmXofxMEnMl@ZF0ogQUFdrF!7{1P2nx^bwasqKj1*&Hg510>o|?efq&Uool85> zD1~!)tw;(XR`AGWU{OuYg)?Av5O{}F6M@)fTprekYy_oq*AXXq(=ZhKG2Jl5ml%FR zR?arnoYP-O*~yOrJc@UPlD8@7zDfCIn1Q3eYW>Xh2=@Q&I+ais>F!^0OGY(K{!pi( z{#x35Zi(Y8_QC~WsajH8e;@8jo}7W8O7}vuv=NxEyZad|;uw1GGHI5ezIcosmw`w7 zx*>aR_qO7b8;5^a$tKuL!j|eq;&euOsUEr{#2s}1G*UQ!@`;}%L~L)7&VRF8Cd-2o zsquJ0S4T+Cr#{3E!Bg7n0u-^`?xM6>*-xQo{gs-1&P@@9LyY+aM5l10UMu*1 z$z>Bn6H1{AhI9k!J zA&GVyOZ?c7NnkznFCs9)u5}$VUr{4Vpua)oAK*i*EZMh4rXwt1#sTUv5ui;?y%$hi zV{Sw{+-N9q|9>zPQ=p@6Ms}TAkRB~WBr_@S-Y$@oVYA*=(Y>dG3ri8rsKuW8*zNK( zS+PWnc-;5|e!a|r@AA1sP12|DcevWbPFl;o-@PwSCiplOL8Qa63L_eocu-^?n5rm<@W4yz~|@66CK^;-U-by&e0LZXFbY4 z=vWDIcSYC}M;`*wMRh@qHU+a2{Y|7v-)>LRQN|Y|X6fKVUZl0aokFwOkVFB0i$I?# zeD~v97&K03LK>ub?5V*aq%HyFMnVeGgP;cpsJ_&5u38w%l!Rfz1U_9$U2w5 zUpHP#&aOTEn;(qE8$L%T5FNLHJC2us@7Pi!`{atmV+}W9Cel%G;|BW%NCw*7g~I}; zM_utkpo)YLd;sx`VogAKUcxJR_rbP2DQ&M`7pa z+J%la0-(WD59gXQoa)exje=JQJ(!tfb%|`T#QbrhH@1y!IXq>rmjP+T#F@qQ z59NB9J`Un0)`-2i{oU{+3TChTBO--nxj97Qv%cAIQU9_YtXJNeI$fKMmcuO*-B(%wj+fpl_IG3X|DpJauD*JesQdVV=`@Ew`EpG zROJx<0#VGit#7bA5T)6s%w)-jt5t@nBwIF5>S{O6R$g4zdf>*GaBH}EGS)Z|Zl<3t zeC!nW^`+;<{lM$=1TMt1%zjD(&bqqQuy%i`ku3)|XuKA~mUKk-W+$eUDxhF9qfCp# zB0BOVx0vsj2H`-zfox$~=eYHa`f~W0syq1t79f}wrIK1*UqBUk!)Y&@|EM&=pOt%9 zzMe|xFZPl7>uwKMN=VE_DKuvATH!w>_JNhcK9Gd;kL0USVcS7d1FI9gS;3?H2#@lQ z@iZjkcT>^-V4c_=-!!m%V84u`@8RfjGkb&%Yt?tC)8UDa*b0{?F$*^zwXM*;g&ZkJ z$&|RD7wCc!$Rekm{CQ5)?>EJK{l#8|mF*cy9L78I64}EUPN3>Qcll=c!EYtgpVz=^ zhf7p<)-W2va>>5Z2;JDKMgALbc$CsHZG99{5G5tbh{@j3lpAWCh5eTdLoq0fd&0cm z0Mbiyz8VPU2pn~}JXT(O)ANGfR9LJvwRsfw8Igtu{p)w)Tdwe2m&Q+r2sbE-x%j^!9&P z8!ub8YuRC;n4W~@d2W%~*YTzF3N|m3smI-HYo~nBkg)Ah?7`rS|CGr?L){%F-FB?$ z3g)L3*?Kc^0R=FL(-rQ=&mg5{b#*+}c-&j0g~PYjAeDic zj`xZ(AF8PrcsQY*pBo2|ARIta7wu@)ZSekb>O}Qu<2n!Sq1oJd(p?GSwvRp&<-r3> zdc+2guQ9ogPt@)g=9)mdWmtarABE8iy9@E?qmJ-(n4C}NUq;X}La4g1&FOp1p1z=S zFmsxNzBn5$Z~~=~XkI-N1wMxRGDb!YFy%8;RUtBK76?O3L&rVlXUFB96mP1Uh$Fqo z;r&{4GV*sfFNF1zz6X6Dy*sm~!Bt6i2!7vk&Ggbw1v)vefWaPVkw_297B@|nH1*_# z&6FD{M8;>`UhBNxUHZj3qFV-Zwb~j5fpo;j;6*}3A!i0a?k5>WF+;tY|UI zaQl}2mWy&6yUL(b=bB!ak)2H?oSi80ejC;9cZOsP2Xb9+V1-(165!vKHcQUAC15@0 zwwvnMjlfYs!f?jR->|R`=R7=vT!kv}Z;{#VIc5a&y4V--XuQT{no1Vn@B&mx)pR08 z-zD!*m)xL=sxmBn4J?8UKk`q6vuRJ|c&W)4Ra#47$)&@m3%nc-Mx_{O(r?%?MKX0VIQH7a^RwY+)q|V4i6mfXJ5Cmr%B$tUSlSw*|geW|gjt-0TQ6zMh}R1WU9LZDp|p!Ih5+a^bBSzb)YB6rop3L&D} zX?cDkE!Hm6d6_Np0Iv2=IDj4&JlG^pz$!XbXoa8oCiXp&b@3Sux%%TqbspR}(;l0N z+aQ_6u?y<0kx$2oHMI%AZ+P2#R+B8QakS3tbJ#DZRj$fc89#nZ)10NH*AKuDHJJtGNt zfdwGIJE_>SNCA7C0jtgPEdrL}V&vT5VtH8fw^J9_fT{O@)hFxP5a<}Eo{{Swq+NL1 zX`jD~T%g5~@-qvXe*Cs)DKJ%dYM~NGYILq+Q0D)et>A48{;UTl4anbTg*XEi|28yy zrc!5C`G1BvX~0eW6Wh5mHOV8@Py-7Ay*5dS> zqS^zFvEY zRrq5$UAGO}MzpQvOuht;c{k9X>^h)nI5b|{>fu#qy$7CS(`2XC!WX>w8X5f$-s=t- zCg~%!T{t0&BW;K(ORhH&RtiV+_xg*?RGmVNv6ElY(h+YotnLZ+6%qp?{NTf>%ytU?hBHp<7O0COH>~^Q zFdx%WD>;t%SUtY+p>s@T7mm{)WOvKc#IcozVp%1+U0mTHqxbKdfz8AHuU<%^;CnNUIc@^4Iu9a z@W`g(-jw#FW2f3XK3T?Q$d=B_>%NZth)X~I$(WNyTYJO+H6zhrt(pJ23ENIR>YC!@ zl3V&MPda&0|6)(01kL;sfu;2KaQGxg4SwK6B_1EO4b5VXQ`|X;rf7& zIB0u5KchJ)P?)uJ(g(EFpvs$GzoKao1h9@^QAh31EU;Jtz}a(CkIdtWi455-Zw*sM z)D-Zdlxepe$0xGSn{)9`>u7h(kaV_!vZqizO!^*rgHM_xIfGoO+7Cr;yPlB(%s6By ztNa#7(LV2<+e`(5Z9fnR5yFseEK>5KfxH#OJX3AjATj?xTb^SGartxKn~;O(1& z(R)nv<&rHEB7EYVMd4)*G@ll?zZ!-(Yb_E%5Y{DFjhks@ zTD1SKD{{7j0aV5yI;4anYv-X=CY)zb3yGQgk}D6%jb$@6OT|@_@PIa_E9pagDo|4+ z5UgSQQba~yA1>nxL`@G0M4l}eGk^|AO+W=SAUQdNJ2tV%8$uquT~dRNTI`cuWWhR{ zWE$Yb7Y+5_rsDhrA%w4+=FmdPeqRfa(*hLsN~h$NzgPRtS6TSHkh(Un`vPnitMyGJo4f=ph1DdnAdaI zfNT0cWPJsYSqGvld!PP7RY!O2<=Dd4p-65OQzz)z1AgjHLet4MPdirwcXbyn_?mwK zqrgc#Bwb0z@85x@XtbCxHe+u_E5JTLS6fd-1QQt#P@&-i);6aRrhct+BEst~dH_1v zIgpSj^n6hZIwqk=iw1Cua{}q_fy1INn04s#?b(~rmDnvYJr9gZ!)&S6NS`Cd9I6~b zc{uxw)!;u8i?9Nbh4z<(&d>4gD3LHX=ZLf8K_n(dcsCKzd5eD|{ z)1W#5t+iC%3-47x3FH^tM2o^uwS4{r!M@O)%lm%x~))%#04)PBLrwDxfDGn61RCZMj*g9`A2QPxYyFO-i0`HIN_nM&xo zDNf=jM<^e-YB8=@jwaobOhdEz5hgO1Nxxtd{S~sfp2Lhi0}&O(-=ek&c_4TOijF)B zBPO)<%w!z1{Uk@7TWmk>D-n?nRL&*i|MGhO;(UnXgdGS3nK;jKvHXLui}W)!##pl8 z9!6>>dgZR=~T*m*P?nb|B{b7vatCAiBkIY=iGv|3gn!h@5W3+hW8H5Z zmD4c|>B^V&3A-%D7jQPS%C1v z;E|#^5eY5HM#2Cz_l3Q4-z>^uqlPK;LMj#4PA$8^`Yt;5qrOLC#$#A-qc*h7AXtM zCxBzTXWE@=$v=yw#p_v;2<~?p-3|mXK+}WN+hRii2H)yM)?BW*!dDd#^TZpYaRO8! z)OM-r^AkG|y6(_dInxd!@i4MsmFaBw&{#Kl?Tx(q~o$RFFk8f(LE3UHlo$cVc}^!zYrV)sitnyqr=O^hm@ zxG`7siSVUroo%F#TWvMlB@U|f8I!h{858?pCNF)694sfXI=VV*kF}JXaIfJ3(23O* z^MeJp+#^QkTIlKfLt}}LIvO@waZoF@A`#*0B6hVtJMJJ$x5$G=dNE|&p!78#a0RR! z#HiRAqjCE$*#r57qR~Is3ps)b!4K;70Ixs>`DDreq-Dh(32){YZv~aMzD^r#Tqh9p zW%{cokJ+j(C?GYyOjp62k_V{pPsOlA5_<^G-xm9@J6W-h{NXoza_v4kTlXJ3;QdP$M$pq9$4~x=I_a zwqt>EJHkh_bH@}FQ0{CnM$2+iTo5Mc-tUQGP){g}HS3io6Qu-BW>@Qd^j?x?^gFB3 z)xa(vhGvPrk9m@DzE!f9jKXBgU0~u&nebb6o_R&dj{~d3|JQoJE&~bWEvprDm_^Zs zoz`@Cx9X8uv;jmv#k9Rc{nf}^PI5cT-2Y|-H0s!y>Gsa72c#0aJ>gW|l|iIfdirjw z9B^;2-xGj|j=-9YepjfDfdu?P*#;q3LDq0Io$&d#(qyy-mUZ$oYAme8Vc3*W$yvuZ znT^`q+$JO^@-nN-6xriKRnBH!v!9gmS^%vEZ7r7(F9@3@cjQ$o%P7L3Mmt8pSpSKO zo;Y60EKt9!zgxqfQs=;C%ZBPfb644xpS0O)pcQwJbTOiDdj>87z9`v7oCqkoBMKqQ+p#ld9mDc4{1BpopdJ(hti;411Nh-*HZ5#tF5I6{Dz4> z?uL^dTCFkM))@7l06uRHN|2J?qdD)lf3VSx3oW>@d21FiNH8=F8@q3^4GqV4}h+8X7YuqQ) zZ?77GbykV%6i3kQaz%Ekk&%12X4q}rXmZ(eaBNI9QqVk?7%>$*QG@uo4msegYk^#p z&8~Z?U3OEDmJkrU3nn)ILrmlOtW!)_~jegY50OorUs~ooN7)DAVhS0y&Y& zyXDsm9Yi%GmIV4)rprtV*xHcC-!i}+%~;#bQ?VG3sp}!vs31S$fg~cKA#xeV1VhBs z|Ehj1X;{LfLl=~DHg!)4pooS;0OgsfW4HW7|{r8m7vY@nD zbqspvKCmmC3>4=d8RAMgjfykr8sm{Rk_LkfVawPO48Vlfq{ugCUXu0IUG#JMaW@eq znF)jrPr%58@>r>vrM&{4a0ke2bC4qK=`~FxzXCxpI4~EaR(dRnyw1f#{`oepesc-N zo}IOF;Z<~;5Xgh41gg$es=r#4wrehf8rZ2aUlGkv=Dtgk@W!6#NJ)E)hJtj~IXBy( zE%6p^DamD6%(K2X6~B$caKE4Yr5{PemfSYgP>ERsG#&Fkra=dLZHSzOtbDr7m&p+y zqda+tj$SUAGun3D#$W0vKh~5WT5^(y47pmlI5^CZqnGv@jhOTo0q-#r6WBldU6xy; zwe~lmgN$>_5`EzRK&>{wY5Yw*XPu8DJ|-N5rAh{g^K)uwIy&*3Yp zU^=YRuZ=?v^om`x2UTJlz;%5W;TGw9E#7M=*3Q65lW2wyH+GNe6I=ANt5NIbqDL(- z`{j34kZIpMhXEEUtQmT<%Il(W4sdbF!8UVo7&SGzyC=ecOqcM;%UVU#psoIX7(B)L zr5nUMi^MLDnD;WacrdD?QE&!0HkuBJHY$cQ2yso&Fu2hv2L8p_)Th7C{VObN*yada zW%?XPX%selAhXW-9yQvTelatp{}susRfeh^n2eFy+$p)jg?GT6V^$ulzxW9EFOdAHiiyEFI!fH*W9X)0}VojL*r~dOrNojaFdU=23dW0 zGP4H)6?o1#`-~HEkK=v_4OI;r4xFJiG0_&Ohinp?bBUtcmUp?IOg50fkEQf|l5*D! z{Ai8JsmElVvo64)H;7Hq1N6c@tB99@kGbCu^3*PAPL$(;BF=Zars7G5EOEtRv$ZvA z$Xbb4Ht+DEs2&=b`@NS7RuS^REnqyx;?Zg2F)+r9ejgNLH;!FC0yMomrF))C2{oS& zjKLzfC_sDJaVaTP4ak@_{URuY5V+*3zQDP#D-LgO&yM&fsg6pLG4+^+(Qp4?ID^c~ zIR3nVyWiEY7D!JheZ1qZ4QV=;v0*%Ci&42qbzW;`FEnxyiz%v)V|8ALsWH>z3*!Z_ zP`P3wS?6tZ#{~w%vAOwb*2J@% zlKGA)bQo;*^TA51xSNq=#~OsM-(Bj^Zbe(ck);h z#^G48{w*suSmk5~^=A4;(ME82QwgxavN(fXZF zg7`*^2tnQG_M-l0dgu0}o=FaEcHC?9F}oqdvvaV-Gi`Kr6}LQ!w|+67ZrCVt5R0NS8U&^RdhlzvoO z)iUsC6argJ_Lo=x6+$Yy(ttH(=_1`QAujojKD5!92}PczE!#b1(l zh3c^X*FZ*6ZA~XYJ|^#1Oc}d%!vsHV9~B$n1cXo-AUJg|#Ca2WZa&Ol;^c(n9zsoZ z$mSUr{O1kD#;wp#*)gmwte7_%kkG0W%RPiM1fRRl!X>Ax3zj`G8Rtk!{KE*S_b)ns zI215Gicg)i9~$6#-FxA;UGF2XwMfiJoT%O!j|57KMe?A^0Tv=Edi~-IseFSq%>Y*M*ma*pEF-R~&j1GEeP9@mMo^4ZThB`=ehpB-l)?+$T^j;*p|k&5gdHT31jB z);zZ@z(P=l|Ls+3>G?d|nWmhBl9pl=!w(YKMf)nd=r9JXx8ycDSV&a8 zq4p;FMg%rWq`Of$5jZ_wFYBxIc0b3JeufbcpUlqpUZHC6+Yoasul7Y<@ojHC@{QNv z{1VM|@RdcA5h ztnnns=de{Z_6#6Iml})KGPVn%D?#LoC>#l>=}~8~TV-=elqqOad)e(H zq83SD@UORcLb|QGPh51Zr-&;cBVuyA(^LHUnA7MTHUkr1oj*D#C|aV<$5BHtIM|BSO8kx$nq@eL9kseU=HGN$1hot$4O` zajMCS(2bz2Fsd>%!uAIzAZ9G%3Er1pO}BQ42fha+A)jw`TF)I&`|c-N?q9q@7M{M0 zfs)8xQ^YobfBnciq4TdaP)fMW+n;JJrAPtNf)xD^Zm9dy9_ocE&od5 zRgbHn37p`B-1a`EA1=C(ifOnd7@Nwz>(xuZ%Yg-9L$eCKVtSA{y(2Ib{6LoL!-nJq zUOk!fah@m{MU~N4+|P;|me}!~Qom@*vslDr{A+ zGk?s#x1HmNeUhtJ1%U)VZLE=5S2*9nj5D*u6*fWFnRc+=8$ZPWb~VK@G^ZKcY2vQ6 z>Hk-Ui^~g*hp&V!Jn7ux>Gzem@lEbm`mv(OUAo;@#d6nm((b{a6AYtr&5DT>dss>) z?`R8(&n~fF>YB3s&^`_x!M57Y2t`)Gj*nHo6yQpiCv=H85YA+wlbYs#ywQmq#oWhB z7Bfua>f0VTHCV*w0?W4P7xN>4j#v*A;Jx;|ln@6|>uzh$J{U{K|qkAq#fu&jy4Xtl+V%VY&G90xJA?u9Um6w&QTX zD||N|uJ4H_BtlRvTl@A=JoXvaF$foLp3k3?+X06%3&pq+q~dGjQmZZ#(4_IHt#||} zg|A~D3Q~!#G`aiuZbQsbNc~VzTgBUjJVY=qh|+nqxd#8-hpCsD6Qw zq)7Lzmz`4w{xz9#`S|+-<8q<=T`Gvr%heq1@P?>SLzdzsOiSXJD(jNkEB)ljp`hi! z?7*M)*LEDd8;nu~ax9P+di3Swtr&&u+?s8yPN+3G;q~wrg^P;m-%=&eS|@4xT(Rye z`|*V(!*|UDROg>JK!bwD0wA63_?iz^xI%;9u^}#dG>%y5b$^=NFPjMfEYd+KvJ!wLRgkmasBmV4P{%h|Z(~@HpG(^6@v1EZo1} zH!b}8XI||LUt53*VVp8Cbn?2SG}0~^srbu^QbfmjA471R{}ZvQn(+!8`NvWr)5nY> zI*4LleLuHt;aY`+L$B3Vg!m^kt*R#o&H9Yz)lJaIR{gY2Vc)BJLb5sk)78M1Ef4e3 z{VXYm=~Dan(CLs~!GfS4*pL=6h%qY>QAC>YDY{I&7GU;2hgx zn}OhGd$+*8fII&hKrfg_QmbFzQ24p^UamQzmqK8$b{=Gqj26C5=RJf=L3uDaMbs5d@(9niAF zk6LDWqWcyCqRJ~Sc{_Z!+_TOjeZ0whM}gS<^n%=KT>e^#dg5vQ4<({Hd59e!FWQM1 ziD+#?%Scr4z$CnBk?tU*Kn+6k%vjr_ckB7TT%M6;9kO5LB{b0}Up)swn^YtXPbj(0 zBm8722KxE%=8ow1OQ=gMlL}t*KG|NR8Y4QQ+b-!ujMKVTcTz!^%WK=lsqr1+aM^)# z(-gJGcFvLzn{xvue9n-#dZWQVKT<$JNTgyOJ{DJA3CzOUcPW$^LNl#e?JZo1g#lTG zEw>u48*m)rGRkI7UpzDpnT*Ing16cOU$b>_W)QVg?YIC@Yjtxe*e010i zqanBWJ#k&^yiy1~9nm1Na?Hi79T21-TRcIFbkX=naPnmKEiYdx+EvyIxy(c4!if-_ zv7DPM*%?so>wGn#$ZpQ3>5<3R#>6I=(iw43p2B<#^ddtg?r&c z+R0eDcq!iBqu-^GDwG_Bt<*86rnGdtl+E>h=Y_TAW`8-#V>Y*?yN~N%T6<2V9g$xoU27|J;BGN-`B(>j93C zF*jya<VzTA-Ck!>5bA46AC)23>q*tOKZ4Kzd#oH zAy(5(2=RMHh~8huHY-lVn=BM%@AbN{|A+UYVwPr=P>n9c4>&?kYu|z5mtK za;i9D;$^AuWmnFw_Te(zVYCKY)IR<;$V;J$z?4qPE}3pc?iGC>Nunjrn!pqk1py^W zogL#^bPcS%h7DI4gFrP{;Nf#}AH4G6okZuHhL^wEeN>--32g$l*0*l<6c6lpf}g0h zlcMDI<}@U$G3_ul`ew%{o3&jRfm$+Kzq4dU(mf-Ij6|^JWX<<8;mk1>)k{RvEjM8$ z)w@ZyR2<}$Ym7X5CpCyb;gD{{K0md1=`U!=0NGi^N=S&?Y&Ftb+PO$SglQO&k4#*s z+y$PT{at2}(@@=giK56ieNVJRxLLgb0dlXpm?(ssjJ`o#ZThX5Z=a60!I%ZMt83Lx zN0K=4P$vu?kVC&i01 zc8G=_Ti+zOp{`3D5FSE~*q|~yuS#)Msf4%%m*Oku*)*5bZ63V3)ALQ^2%=b|*SDKt zGZ<)67b|bj=nzTuqR}Tox$8#)bpFY8_q>X_+@hUn$VXd~?#Ov9Z*;Z{)knFne{X8; zCYY&86KEsudi79Qq~0G5pO=#g4Zj=G^o%!#S|NZlgCXJ;G=DtO8B#z*k7rf(Hex@P z4ad?AL40@SFg%-{_->gmM(?v;qR)T#yxk=DBjSJw;t01;a48$`2WDA3%LE5|_?FH1 zR?O~O5MwoY*g4^E37+`(w5ffw^pz{{I$l77pvbWQ`kK+gRDYQt#v(iHig5KB+(BY^ zs+2eoeg>unHuxJ#YtPFXBg2l8M$8M2Qq;!fe7L6}A3zFPU$vsY({qYC0IwUfZD`z9 zI~mYEPS5bb{RbLjzvS`B{4(1V)_GmCHniGOH<2K5OwKAAMe5Wz{L}G-r2Eb@>-v2) z;)V;EgT`dCV3kvqVtOP_Z6TBMA0a1h`V*Oxnk**Yj0}i8)71fgyFBZ~M+!khwSujd zd}%z{?s3ec(zqtz8UcLwEZ>nw6Y@^_@x>OVx5Rx6@LP07L`RB3TQ4yLw@l0q1maJ6d0>} zU<2qYh%Lr*95fF2?s*KyC@;6H>WiHKmxgFRKusL<06SiZZY6IP4Oj1OFWd)3KL#dLB7 zBv3Qfc^SevB?XT*|@&B@*D61=i&F{04To4 z?J5Yi^yKF)WgEe5f1$%mtqe&@`5Ymc-4d}zEe!@8mnK#&NBcCNTAyf<6>xhwmym{P z$ch|3Ys=^FZI}$b%iA$*Kw_vKCLRn-7*sVfGn$I)%RB3~9p>y*&MJW$#;O2T zgzN|Yx}=|3AyqiY*;fiI5Gb;FVzN(xx$q5=*P)u?9xK+j^6zXSs+;n5BC+FB*2k!t zKHhL7RBmYC$l>@k{<&BLXAY}b{;s8EAff%I)_}jeiNv?A-W|MG>>n6~ONaFdxGnl- zKG>;{S?DGOYAXK7Tx%o*$u;k}=OB)umBsnFKkJ*tEtMmgrm4V?GGIL?6x^8j=i7V` z4|xr<8=}!^(deb42*S5v(kSZ6Nnei zpZ(FN#3bc(5fVMQyV83GDS(sd(l5O zMtW{1;gWJ4>scr=dHf6h9@6$}rxwX<47B1ykUi~{{@1EvfD^UX!kFo1ORtYtwmR#Z z^8fIA%xv;~hyxnZDh(N4QTelqq;$uZ!%%6`eatg_Mew)s|J1i+?VJITou{k8ULxXp zq^aBS?H2RAk{f$;io{G#9g1E%4cJCk2dg%uwwv%Q|{jMqG_GMthMF;X?$_?GE3u=p*icCFW5X9vz z9C3TVC8O&kA9}J^q}Mhv+MZ{C@a;BT1nf5*RlPxzN9vCWi^~|p(V;KFD(fNy5UAXq z|H7&hTy@qqoW=*HN;Z{JlCC)ETOQI~>mjPf5IRKqQENjgr&`|#VS=R1*Vzmx~IdrM8 zM+7Hw!Tp*f^Y|%|apyX?(cBDIBOxc|MMAHX_#iPc>8%={D434&8b4ts*a@RGE;j!- z&qTihWl9!2IjnubFAlL)`Z_GyU|4rKkdkfV9~69dC^@^7rnj|X>9XfjnO&hn$Y1qg zDMALCO4~I<+c!1c*=ca04y|Ny1M~AmuorL3cNuWe`#CZL*U&X(9QHyflBvzVy9|znt*URs(9uc2peL zU;w-ale;kTWIq7@zHz++ZViK!kEj2#s_N)WC38@B*=Mq2D6{R9Vd5Im?rwi*|A9QRI|xq1Tcds+R#z$G@*s z^jGTCq+?3k;41N&QZdd2%gwO)y{b%x+k_i&=6?Sp`ESe3e*^mxLTBnE)`sk=ia3JD zL*!t1>-4_FOOC4l?|sDY>>eSg*pMD2Ehdi#H&ZlKu9BS+H=x{ zLeuc4w+T*u3l`_ElgNl75Vsmo1)vZZO<#e1)QlN#IctPU4E-P;M?jC13b(si_L#RG z<7GeJohu)H)It~;y4B*2JxSMx(O#Jw}e|Zf- z54I_73G;j;49X&ewUB#Rf1;o<1pNakH>IQ__HJ4DMpj zNEH*$H-b|iG&FzT2`%c56e`ROcwx;^AfAUtW~{EwI8LpNZ{}IR5arm{<7(SE(K;A1%sbiF&W}U!vht#% zeIy&W%w)+}jhwXp8+;&jOSz<9w_=>J_4KQpe|u8D3v#-O11I>+(52vrZO~4t<^lJ- zcj0$hR4Q-l6%|fky~h{QPW;~j4;#IJnSA+lv`pU_FMfKO<1?9b&wO~-FDV*yWj{hC zUyYo-_u#js89&99RBLQ)8vOyR7tHKQNkcJwR+t4U3~a z;z467;EgvSTo`1n{{|OB zX-C2Y63+vY5mY26wR`cys6T*wsRo!@*#|21{JN*cIfALhOF1{UON+fDr)^3j284KW z2`>K|ubNIb5f@BjIbfrxnLVS3PoUrs#BQFzGZD1}^4s%De5ymrnYVw*#vBNP$Nr%9 zf1|W*m!5`te^=9~Vp4}jtB~@@DJ~aR%X=8mXJ_tNl@(6=6kF*C04L58lc6Ctwr1ZQ zw;jyn2+rQW1;`In6A0gX1YcDYR)7Vd8@#x{`M}In#5-wk$oH8zbU1(E)zFR7JFf1$w>0?RNz56 zF%;Q^_W)%wyqh0+5KaM|B$6}5m-Dr+F71LSqJjy_7XDZCvzm;T^Pv_%EA}20lAd^t zB8S~1)Lh$fVi{aM3aG*RHn!LbFSH)%Yp=ABY#hsK9%5^K<%@VRf|;YLa{(svtHdCJ z&uQw?Rb>d}Rh>u@UFaxlB!>!g-=)Q)RJp&S(E{CWd!n!Ow_F0(Ck1iKcZhXcZ7T?J zJ$|SHU=o_UQ&uBh$$RLiz!S+7R@@F_@i1^H(lo*8bN zJsffvK@8VUOmyns^aa#C7?(=TU%`~`X{~EFRoY}mkRm_#+l~&;rM$THD4I-`sG{Ol zl(!cXDF7l-1}&4naKwT@zeJj93JdX||Cw`VbjtBH7e3EqO|Y*mhU0oFVETdhjWpAW zFIR)l*8QLIw}|)G6ao5;2s}q}6%9)iF?-Lior(*G&APU-DJugLYzlCr>`abVoL_uT>?;~8&wQXtQgv?)O?29(r48VL?XUbLALbvE(!W++)0n>xJ(Q8kZo~j0?$of#?+xVFt^mZNku2n9ZJvPy? zv)Qa7z9tXux%dpkdk5Z$LRRt9Yke%cSNy6G)I{{+Nf<=dWHwSG5fa}~!VbMN%C;^W}}`2I_I3OK>>OpkZQ7-!VglEn96XY?b& z&<^|%_r2M;duaO-0Uu}m0oxap63y`6?2uI~`VArJBJIj>X*E=P7VM-#FUktw%2kW# zF8=C@P@z}>;4V*WXK$Uef>!aQz*qI^1D{YuY0$6lmG67@d*BHZGD zj8T$CkHmt*k}qZnT)BIMarCaU)pT{Q?%=!-(G%x%WFKn9DgR^M_tSYCi3Z9V9#)xd z^yeQXRYurJqc9&JmmS92Qr{>WR8!Zv9c61j@Il)rm$N;bIfKq6EALnc9f-+ zXt~#x5Tac$KnIAn6kxYCGI5mU}rcEy9E^CuQsV-BaT*RYAu$ApSV@U`4>yrJ;Qc z(c+G>_-Pf~K}W1KYKm^i=PD?f>~HIDu=u|-0#JPGfc!R>x?w!PExN|b>9?r(gA(kG z5!IH8$FDWLp!RNNV!khn4d*0xMxUBhYZJq7jZ%HfmvGUEzFj-lCB-_IslmKkuuMLpYg6!-;c%DOSB^(PEEH|Ofjl=T}Q#R z$t0MJ#rV?48>C)ec4Zg=6Zt_M75&4TM|C0TdTtP*yvYBVw={q*0|h-*JxmE9pE#Od zN>dmgu2w zfZ-UqCC%|t{6~sFCdv`jT_gC)EeF|7iq~R$Fj#~{9hduEf`#GK+CTpjj|02VX-S3Y z7Je#tPVnP&Jz*cZuGz94Eu^@gzDCd?)y7clD``|L=E4*dt_UNui)e%+atSjYDnK@i zACFQb!*E2Qss^4YznpLw`AWO%gv zv<_MwQ|qV0(7N2HPp%kiFfuLCD_wtEZpV06_DLl$p;3nTcEB0dT>s&3zz@;lV~d*r zY>kv=#abMw$Q{~Ec!tp>8P={DrfLidW?e>_H~4dLp@fE#;qN|986ztUi6x=fRpMeb zKZ65E_ya{E+F11XotWhva!ilol0B-XPy#spW4f08AX_r!2W;&;CvIw>8`L%7B6nvn z_3!75VBhLFxF{kJG3Xl(+^&`#3IuEQHO2t%OgNB&-7ECH_+76CykAL z^(6&ZedHgJpsg;5dq+qlg?^Is4!5(7(QMQ!Iw4!jhlksXLGQhes=F|jy#xACM%#a4 zE~W_Wi>1IlpUZNotg$1JEGneCd-Uco{7!!}o>iLwosWbA zz6dYTPKhII>wgr7< zy&#e8gQ+O&U}$MKkMK5nayJy%QXhM72Zw=1oy7g%{0#>HG_cjW1Q!Ma>Yr2Fosg(C z_jqqv?Cgh*gYG;gVQ**F@#Iik?1<9?TEOlgGWcmjxd6Qjfa|?j%IplQ4cyl}Q{1LL zJYs26Q?&*Q$y9@%r3ujP$Dy`d)pggAnu~MCpa8Yu`L-C;3pk!BS%G6YcYTb9Ygo7i zE3Bft)#WW+BZ1u5n54ylRWl^J^d^`xV-E!J;2HHXMQSL5k&7#XGG5We^M zNjt2^E9n&W)mxx+7}lQ&MnkfSD?!kDp+X&(b^H>IV-Zc{yinK7+w1{;ly_rJM1$?V z43@!jJzcT*+f}nL5E3ods;yAQYMF7e{MI;}ws|`9&HQP%1lGEX@Rg44OB~egSq$7uTZ&5;I5&)a+X2Il$ z!Iio3^p*Tz9Dc>bwcM;4EBt8gIB=1A;|}X=fcD$I$0gPbsX15R9TCj7OL%C-b}V$r zCU{CAO?1&p*pyDs4{&K_z1iArysqS{SQ+B#B(QM1MaIf+Wa+u;c#OF+?9kraN~e** zo+0A{>Zraa7V6R`yH$rO(X~F3=sD?#osw!XHwbd?HP4sc!Jfv=>G1cPXAM|g$WXhG z9Ge_<5uuv(gy(Qm-pIe&c5z4cfv5RL{^ZFn3njqZG}fw)ykZsDCV15ArNHH3Ph>;5xfZ5^;CK6CJ-XLRD@j!QWoIk3!43x;1)@J zYQx0s1xy>P*!cdH`6TB?8sL7YZ}d=~@7Azagixr>A<>^UTjG{DCPWDD5pMb1JR(SU zTrH-q?8?|nuoSM}N5^dtsRQG+EFBYofEFkngRD4BibngY3ICWCidWufsF48vGT`ST zlr%jFC?G-~F}WE9cMZM73p6U&G6rW;w?1}BF0$sTp6e30xWkIKGy$LrH{jJ;ONKS8 z4~@P-H`H{S_$SkEZvvritveMzuQ%|XRso*V?k;~t<|m>-A;PX61xFoKo>0ck*I&i2 zWl9aIhr(pTBIdjgD-EQ+UuWlDC`x7up*93zS+oFqjjlC)JPSv00!t@Yk@izKX7@s| zU*SvK>IR>;F+e zC{{(CUT)M-HLz0{LujcKy0a{RnG{LxFYY5a$;X|O?&hC7Cgfr&=BptT0W#p?qe9Zq z$8>k0bvro)=9fDpOb6i4&})XV@_63GFBy-vuy}_}5`2C<&0&#SK?VmIaoZUE`K^DG za7k`S1s{#iD3go*N#X?Jwoc*|?45C8cLvqbjFRsm) zxAX1ov~To{B-!Rq$0q8+R*$~B_;3kqwORNVy*d=NM1p8Mkr$)KDapaaG^FY!IUJ*H z>^MS$Jo2$WMIxj`iMDlS0&3%tBIw)9uSN8n2I$skcHhH;Y|%i)nh-K4?*1vBT9K7I z)8H|GAUFH&3Fm4){$A@F)|HD#PP#O+gT!Jln;Sf(!)^iTMfwIp@4jaSyR)8^xF<1H zVig<}Df{6Ym+P1ZleQ!$c@afgFO&(SD@yXOFCkofGThkHkM-%3sO(Z-D zDLb!UV~j{uZa<1(gsfOu^p*%;4T5C}bPgE~bzgqhf6gNBPmyP~LfbA?{BSvtXx;-F znp8^84b8lcKvz2xn;mVkG05@iux6N5bcC|eIHf7Vqy|P{^uw|aACFP+960}OVYfo~ zWPA7mfig_mzM+@{6Qbchem%Mn+w1j`+AH5=K}#h05aoTrU(Sz%FQ@6EO~G7C3GV7x z^XAC|_n3VPoZ(G}60PDNQL^= zoYrPo1{}(OEnJPR^%dKmXBNN6m=ZG8gLJ86o~)RSVej04WWl(HAa|M1?El;1T_vsU zbv9|-g%S0|(~pWYky;Pe&0gnd2{UVL@?v_v2Kab!0T=4kGQxs{K3}j5ch|h;TpR?m z*WoYB)+Bx8q^pem4n58^w&E#7%DA5w#w3f|sg3 z!Av0rSoVmd%3aY92CMOx)(S#iduE>cPPL4AQ!6rhVqnw+ACN#*qd3RRb%w?~;&<>> zBPmtZ&1I|*@@P;|t8Bq=wVGD(>V@dT;M)ub`=s-cnS%Eqws81u zfLV-YY%(x)p7lHqfXD?z)|T|cBTv;7?Uyz6OBz*N(1!oX89j4ey&d6t1yNk(l~WHZ zovvOE;J@JfuhS9-iH!iD($$v4&y>6RLm#C5pgk4*zzH8aynL1wVSsCdlS4{h+{s#c9+_iTcu*j?iS!jLw!q}c~N4I+YF=X8* zc#0Ts3_XNV!yy4XAk*Q>zV~)BZzof1WpqIHc{WF(=+}*U5b3A|2s}12_EPNyfEC|R$`MZb>SS=X1?V^9HD+cd;6c+v+8Z;*oNWg}vABRb% z*ToZb2Pn|FBjrH2`ZrT);}GK+Su?nr3GeW=k;|>V64)eMx)SeHgoH_4a0?%%?wDPJ z5^B0ta}DSj@ML98B?y?Tl+Q2xL+;@?T3Rp(7NHcQTVb~W0xp3nFB#%O2DYS505@6G z&H*^S?B$n%0uK(EQj9tr{mt&`U)feIV&t?N?pz0gY0LL&`$qCL+JgqGZ!Sv;Zl~)^ z>6O)&)ZcgvdEvS{tGo1Nfa>{e1Iv-? z@~(bGKguOQ!sv}Zudd_S{)b~Ff`02&!4El{1GhErDAIo$=*?fH}t*!_=DQbX%i>_smeU#!Ub7gp0^ZF71zWy4rl6v<$BlBh~6%cBAak5L|oV` z-O^Y~0?vtOMpqEGZBW^`)P`ct7|tYk>kTA5Q$C%JoI;wLj1!Bd=Wsst+wNhKLJB`ec%p%RRfv&oz;Rm_jmI?(Hm zZQP!1HZLatkXtFbC!FNYz!%g2r|X(_DGM`~5Vrvee#U`-p;KFB0=u-23~OckP04)>%!y z*^^%riFI4ft3(fsGcVP3f2)51oTXoeyeDX5h?tg6O?eFYpc{xl0UkCJmt5ZFdN1MK z7G-mDN-ch(FX!ei2KX@?g}d@%3hp#-yFP8WpAh@3YJ7E@Mg%ECb6aR?VIUQ$H#fYP z!Y?9XFI)nQyu+z{_52d+!E}rFuWRRv7y3115_>EpiObMM@~|ftS`_w9@-t3-QU^Ps zIbYMIh1+keNz`;XlrA&Lwf2Je_6S`A280yLD;}6Cf$;aR*z3 zfwQl^W6d-~eV8I?8UxhCmL_7oSy`i*jNa0*s^A{dk2Ro1xr)K1z}$zBW?D@{^eg4_ z&b$Wz#U_MQv~ zLIS9W9^?#i4e+4*?;A643d%`-2J;FLwHen|SRl3f%a5PmUJ#wLgcW0Ol@%Tf2EV~# zTp`=&cnRkI2Q#YMpyX-zqNV5DXcad!xJF};@};MQ2maLC?Y8&vtt{6I&?_iDN}M7O zF4yl>7pG{Bog5r`#Nu1&L*0xZ=igO2@5p~Fy~}wU!{lQhH3Dty#9BrMS?v$0Pq4!iA-@T zQRE1I#78m0Vj5l&|sZ_%C zziRnnTtE*?U39IzJQjK_&+!ayV!m@mq<25lVEBVo?eL?{&s;xW%v+1DYv!M_7e5w@+u zd22>#4tt1%9~SR8t9MDlQmqolC@yn!;96q|&MH_BT>9z0NBI2X=LJQed(C=Jp(IYn zp+vNg2w?Ol?JIcCZVCe^79xrDNb%a>78z+}GkK`32e4->L}mfuPm1va1wG)jU>WX0 z9`4rc1u#AiPd<-uk~{#qFcabI}X+vdV^$|Aqcmul1j}*rOX!U9+}P;T6QJZ zwLHsVWCqPkS~l&q`4a@Gv;4g)c==sBz$9Cls8s3)L~lZcf4qh~d0p^mN#Lt*fu^%K zdA*S7J23CfM8F@`Hlb>TVwY~~IF2^IxV%Zh>Ql;}?(_L6*k<#Lp z9E5r%Os-qfco%5_l=7flss>bwm_lyQvKPx4SXdottJJhfNJr**$TW}S#GAX>Kbsgv z=&uddvvVp#np%1I&b@V617OcHCcH~Avo#~`^V54z6Su2mGSth!R*{g+lAPp8`=q%R zEXd1uovbuAO8&%rZZBrSXqBn!Ts1OwMA(|ZEzr{k-XSea*TCvDr)F0qa#i3Rfu(?+ znt2Pq!r_A)O$)#+suplGFWc5E)s>MV$@0{9_>1yZb>vI@xWf{7Kvz(EyVn&yW~0-3 zs0aN4B$p(6w?41tmEB7m2Rngd#*Ki)F@WvM&^}ytEyfhf$}V@Y%!R0Y`4(!1ukn=7 zf5plb;eP_WY#2boZ6xYVC&Wzb?&j=4t0~nCHj(V4%yiSG;3FFRH?dAri@bOSr{Ch_ zxm4xDyXa-v%7C*q7uV#S?zrz#YL!bElILdoRuR^QE0k^*FiYe-)1V`*u%iXfuEe9# z@lB}1zvzsT_9>Sevb;SA7=z3}!TPqE5xBWum25lZx-bx70-$nxpaxla?j-5eD!>|b zOvF+$(~H=q6w5-imSc$1Q99)+(EiJvj5)}F`KJdxo*2-l~gV1C^CQmET!8ULzYEm(N)~56QcKi~>bWc&qFmpg3p9APn`~Ujp zn^6~$DJkK8?;y%%gxN_@RScn`#3JyU30bd-&#Mn~ChulPpe8lAf7$M(DATS?KI=8A zZqPGnJtgo^jBZo{v}KI7;^s}MIswBi zZB%lmh~7gk`$?E#AR}1N%28Fj9^xZM{6yjA>hsimJFsKI*6e*jDwtg+q+h#!I;`cY z1i0MU6d+@E?fN?6=QFJO2TH*rty2(EmxCS2>%r>ZYsQX{%ioq}lcwC6^G$NI2N;bsMKs!H07<=@$qqmCbqrYzllBOu1+X4FKS9~Cu83u%-6^Pv zkelTJT;?PV@}TrWw%k{kEtnfGYrV*OeouOP!-nUTbw&D9!lA~B`TzS|K~3##+bc@| z6)0wgu|X$+sRQuuGuTlios=4YJVF;Ak7!R076FNUrHN|XP(PKBIn|z1S`X?yhj2jzaA}I@B{2_C>4<9L(9cV`LthwpErjS0RBO?<&s^;in8sF~M zOhQjbX61GX27lN8%4E7gptzY)Oxhal2?I%i#|vg>+1P zPW?fx-p$msl{73ZS-2D_({`X4);z0Jbpth0@pM%8W&2{3#80vnp#kpBCt6X~L}cvafJ>RfLPL#8{*-xPU5? zH92i3+l#^bd$T?^;!|VITT&1CDpD122fT@i;8_;wj>j9*mX!Q&YjH}HK9c6yBZZtUhvxP?^#e)trQlZ?}qbhP5G z{}6rg2ABP(xKR*s>h%YMRBPmK-`GHnE$si=&$~xTj{}`w90m*gJYUSuG-LfW)Bj`W8*JC#8TB-%JA#55jHZI2`67)-ki}sM?mB%C`MfT&e(fa4x zAd3ic!;-^Q)SnPgaNwF1HAMojwIzavHJ-d zH?hXOgjn2G9BnJp(Kh!dj@br~LJ8HW^sI`oAdI?A&x|Gww1BMj0}a0BrzHzvwh5$K zf^QQ*Hb3(F@dpT4fmfbXCo*9`%^;dk?dNZ*!$9~>B1&=LqjQ2^(#k3iRp6%%X}kS_ z%cK)o3yCs)EUy;f+hr+E6c#PruBXjR=S_jWWc3Kyj-dpsxVs9j+#UqG*pHdZ@O*uj z)eM6v(gC+2D_kBl8U<=9j5s%gOjU})6^g3M;19^>Aviw9f#_OjmA69J3)^HUFomuM zq)^B{5mKv*=1l{LZ!ZD9ioixbP#B8*^XYx8cmYy(b)9caY3T>a1$-Q+#k>z08!)X5 zAj{%I(`g8{7`Y&>I)$MY=+zllSY-PIt76lB5?|sP-v^}dOJ!K={b&s$3s4`0efc51 z@8ixSH~^o{^c^wi1$N%%!m3jbg#trGKeD5`Sh@~r4G_(_<#Yr6tVf0MEk%sPN_ro% zmdr$FUn5n(O<6&@8utB}yfG8&ww+5F`%S;Yk`B6Fc0R;x)+vxInhCy}rzXfglAldU zPB@0U5n`A3SRhoM9d41-&0eBEX%uZ~+bF+cq=usfNTEw~HGMAB;J$52=|C>M!(Gfb zZa}etn%CtsMRsW&9f_1pxI7s0M;<^+^HeHdV8iWU51^06HQ5_z&Z(9Rf6m~4oKv$u8S0s`w!M1 zk=^Pfcma6i$rwndG+-kTD{%*KnQk0Ss$}B#O=OZd^didhF#eB0_|4xwTb?(JoMq+z zfCQF;`GHtR%dN;GA|J!&K@$^Fy(bsFX0)4Loi2x+PAwe{Q^^vRbeEhC#YNDsj=Drf z1td_zOkv2Cc@Dlo4Mkw^0z*=5K69L#v7H?+5W;srekUxm83P-B=;#Zb z6P(xW#Szi5Q6J)`wjy&SE8_3;+os>r?Q~gFEb@3UxBCY>*}(e_droKm`?cd#W^rR5 zXH-Cf^F=GeSLw;^tT2LGJR7^vRmfxlm3J7oAD_VgjdF`5o%&b8_^)_V{9s!)4)OF% zwkkJtMwEkZ*t>aWY`n3aX)}696Or-#X2D`EDLwIPed{UR*b zh;Ku2k)lxIkNk_ZPBy!Cr#HiQ;n)Vnc$U9fZ*>OYZqBE)^2yI zLt~^)Toh*0;PBYv+MCKr-m?%YD$M)_V&C+SS2YR6K(?lFvR0IX1>O-1mLt!sD1k{V18c&Dm`THZlY zr8BygpvPxt&~S-)KM#4JdZ3(!C$9liNZv9A2q!k#{g_ur^|gK~+xBD&At>t|-2or5 ztW?2KgrBSwcv&ILfYZd-3^SYP0~Pd{E;A;-Ds?u?GWln7m8yfOP-tI;V+4whPWiI} z74q)F(TrgAbr;;9Zi3KvPQV`=PDf>v4n6mlH!2vCxAc!&h@%h2hW<>FdawKyRG?~RfxE>n4TkjFehkOs8dC|{bByZdrahS`8bmL^7ZZ!peq>W(=KeQ9BgMYlzrHK!N0p}51) zI5Q9Qo)f|w_+|eLU_2wLvWoJ!8hcWyFw*yNH=fd~6LO#^U5`Rl&uBp>IapH{nyE%f z--GWKPI5eRMEGri57e-07-|*F9?F$boIMQ6Uaj0gsN7hvPY$wBG#@C5gPefERieAj zxQv9Ay{$!#$1{IQ-82oBv!tN8*WP$SyXYQRn)tEb5mkGyGmsdV5*(%^4N7VnF>Aj? zi$;QL%=uvWGs_whz-h+5?<<7>SbPMaR}}ev5b9LO}PG)f#S1Xr+2d_zdY1=S8gu$OF446N96Urf2A{?^-5$- zc%(PH?AiYif*@%AsNMN4*z)o#=XtZy;b$KMakoNjp z|M#Mq*3B4V5FSuI%n9{spZ%U(g6zvQ?3!O|%HRU^yQ3G!MZ1%u-Kstw=o<1UdQssQ zv@)OdMA&2E;GviGA$U-gDtlbmAYfEc%-o%ki1&!|ajOF;v;wrz(w#;lvIZo$312Mu zaGWG=Mw)o+O?*qAq%14;JWRwryG(OKl#mSV*w9_Jif^VBsOMHnh`V9=s81235KJZ> zN!buKA}Xq!{Dl8D&PnV*!E<02-R@{g;T6+-y`Y9cBa*mK8>CCH_k)fq270=)^usle zo%8Ro=0@jn^A`9kB`8J~uXaEWDQGBY4NP|ok|METq-E7S)&)~>$YA~5+ux$m$olDt zr_;Zo>p=zTAc#@0U*jrz>mz||8XU+%cPgko2{l@?o>%@y<1Emw2JX`J362S*?R!N+ zj$Yp3UVy~1Eg9r-_F=T)=HJ>~fH)!z9>h`t)OAaob-T772Bg(LNvNe=OJJeDcvDV( zh(Sz2B&DD`%shaAQ*9u$vpz8Kh(&+PIMCNT&+0*0jG!gxAEYoXdo50Kkbze%G)@>tSTOEt8txxJWP0=0+s+!?b ze(y84e_abB?a|-+vNO2n+8z1evFiI|)VfC3wP>fRe- zG?)w7BTrAQWorQcKLEgqn83QqLq7SmS~Uh#qq z)oJF(X-Z|zBZOh-v2x$hOQ2>-qM(r<47RDf0hW*M@V=*xTRQYFXkN}5HIda!%=P$3 z)PSz2cgVHUO?^qG5lH|-lFx;EQMk?DASYDz#|Wi91GZE8uJzATmGw5?mNAPyc2#8B zOS>thOUA(l%?b(ccXlT z5^K=|ck_QX0oFE-(r%+8JQ}y@JF&(*y8nd}0QrZo3djrQ7le5r4h?KaLk8a=A>@~< zt?&8_h9r4$_v&vt6O1jN=#+xKIX8+@o%@qA9;oX3OXUe{HSK9~4y3cZq4Y+9eJrxz zmr=s(M@h3VFVOu)B}yt-%#7Cx{Anhj=sA*NvewIdnU;0kCrtQd1w==?U^y|Gr{|}& zj*-L-xxIkWA_1?+K3&a*@JIx-Ogribyb%(6N<>8?oObv4HETIjRQtdIav2s6*Q!nQ za$kbSVQc5=Ao!_>dpmd_R;{|xe+f;L%tm6-ty)c?erqsUqKc=l*wRW4Pr8j6f zn~i%*#q;P0;?z_en22UPNt2ATtM!t5A|k0;tr)PgJX^R2Ssrf~)}ZuBo($8s<=?X7LY0wKS!CHrLxe6IBT z)>sScX-pBzpozOWp6?8!9apOQ zl&;_?Gey!yS5LQQm|mYUO>{)o{Y(!WkCG|?yrr4n2Q)4|q5C^Jldf?aMpmNBR3PL8 zg8Nt%IBW$L(HA?R>BrZ%1k!Eyt(7D|=#nX+;j}mz(T?H-#wdUED3<1nW&H+}OrIS{ zF+M{vD~K!Rv5HV4pldu3cuzkL%L>o!XEzM0J|e(qZ4gD&DPg(rdtfW#>wh1`2D#)B zYx3VKn9uT;dXry4f*&UDDNkK?_L9s&0hN${NBzy&&LroY_c7ullNYH99DWW(q&fbqNF$m%nW&R$Cv9SH_=c%8fEGAcnv7~^2* zF1Qgp3rU2ea;$^qg<$s7oCQXRj>MH;)dVH68}7cAzphyKFP!uk9wxnM4`F&nu>D1a|PNk`GC5rz7-X7xz<{v5nE&s43=+b<94of`d6I2!U{RaYz8p6AO3D z+tgU2nj1hCL$LFUS*KMHpiIH;KUP@b+y2TFoVXL~rqZ9Y7wg04^qeq*I$Ny5ollQ% z3k6)d4gTrQc0OMwklKKC5Tnl@cRisr`iy2jzlI&+`E{0$+SlnxvN{+E>7{3?Rq za1Z1C^%HXH108TLoI`QFX4>0=FhU_X_%0&~4N@zEuV=3~tZtH<`!T|te4S1cAaV>O zafZ4l3CpeE`P=kSD3!KFL7kmP;bzkm(Kk6{Du-8|5aH2Vc|%~aPuvglArJ7o7kVJy zuFh<d?On-40q%(o`ybZ*?javGG>Vwh{v4vp3^s(gOP6L^nht0D008KM&%xdMi_F`P4`sl~rxjP7ZAW*q2Bg$3Hgey8H3(z!mA$DxF$R0kFH5!+cp`gjOpwKBh z_s7E0)|VbFfuIZzl*?Ls1_ZoJ*jYM)vjEK|n6u_@ydJQ&<#d-zwSWv-T1WH)MK>%r z=cGZLd;4mF{F|M}_Ue)fqsws#XmYm#7V*3JY0Dv|Hv{br*No7Pixmu?p!NW=hUO6P zMbilZKr_86wvu|uM16`g%!=&vzqNRqmsX$d{soY}yu<7y6Qb=tb$Jf(1@rT`gWxWd z+Hn8vd2zY=z;!d_Q%_?subWl(R2@=!<&%9uhl#&_)*_TRyB(83(3fdIQ3Hz=a0dT9DhC+2!K zAfk3j2Hu7$VgR*}i!$2YPG@ih(d*F%GHHJwNTDNZGxycQgl`Yr6dN%GVitoOAR_+| zF2snggHm&+Lh_gdOM-+=0do~7PL4oAGZa{Jn}sjw;V$w{23s-0K7gY4Or&du5SUy0W{Yy~vZ}R{to;zbIJ-bFFbz+~P14%Te zv@$Q7$MTY{9C02Mg6!+?d5+$#&ZN8RPc*b)=S}Fj&C6<(@~Fi*ZrwrmemV~FvKX7f zBnXT*+`>k!mt59mb%v zPV-U~)Y6uPk1L<0Q6v5N0o~8UdSx8;N6$Qdq)15!tk2T}1p`R;uO4E~T=NDv5_$nU zD5JD~MD~`33wX2?<}`t`13;M}N{sanzmFHjy+H?gs>+Vf=%MnHQ83l3B@)TY0)bcM zO^unUu(F-AjfuR|raEXCQEDMpCl<;F&3F;U#u5%G&obk6$x}086tD)U?NZ=gw5&{SSDqSz#^^W0Q4n>h`@*Y=6j{{?JH zjb~VYypR=+D2PX+Yixj$e7aIeUg&DukD&VUMg*kfj0TEOM_U>E94QMju!BN4(q*3~ zPCyxBCFgyIb(xn@-*UW~2E{+2cLsq|kk~G>`G8f~dx!a!ruVayW1NNBx=!8W9qo=s zYWMfTd)uC5ZyyxJh5Qj;y6Qcn^5Bdzep`6Z!UX*7MW3L%?5y@#U{|-jj z3@@hM6npq2+55POzh--5*X7<}=q$YQjzRbr7pYNkUb&EE85avfNmnKLAOuVg>`r>O zAJ?itOF!~~C-clV*m;GO#Gs%NzMt4|tb_5>ic@V> zT+yXb$i`KfBml~3y~mW|XKI|FyK6a@&aW=-ceQiUHo6Z^)oF(K+`(gw|jmQ6I zeA~COQ7$t4;n|Lk?3fj)q_RKx(fSeYEB5{jxa&#fZTjbFfX7dE7+lVpA2L(&Y{aW> zaHDu1aM>gC3M)#GDU>bpWc2Hub?G!cr*U#L zNIFUWPao^O3sEG-a}vz~guKJ%gO{qF2P=rYu_D(s$I9?QwK-kj7ScX?$K;dxLCjq~ zM-lSxnmao@o{%Mr8Qo5)_J2s{fCudt7#B7?h_8CE0~dG2yo@j2U`_4>gXbTVvLxpE zU%XX$b$HwZhow|wg!K_ljJR*5m5kIb?F$(C9C1Q+xLti!A~Zn2!EsOItJ!%LO)Ppc z6fs-@ua3SNZBt&6rQgzmp-acoJs%m!Z4QyX*A;Ox?h3pR2ig0zSs?P}3GU3nFI06; z!}4*N$!QP)VDvsyrG#b6)Tfh9NXnW^#pTAsuiLHesW*ZJcRhby<=5&^W*z--=~eRgozA|HE3ZJHh1nuM84wkfa-di$@kk7oA!tW*+9gf7{+Xy} zP+f<*=ADUVaroFP*H>D&*)N&xLe&QC_DLOI1$053)w?!1Nyb!leytMwJCA{Zd*xob zgrE{CNm@du64>xh@El;*qE0xw{0B~r6J3B2f!=P)7T@KPyDCz^&ijIgTTq?+Q7Udz zZ`rtDonxjc4kp)MvJA2)${~BdrB56+vl>b8V6g66tnTxn+xfym(`@e{#aK5u&C8cm z*w$4dr?wSA;y56)ibGEtUqu24Md$e~On55s{=Ti!++WFhENpMaPmTA>&&1DdabEkA zOd%@K`4%^AeZq%jjI9&%-ngf_{+a#)wN}cFV_}?Jt^t#@Kv{fTq_b4u<>u{ZV6Huy z#Rl#x*}o9DTYu#!9>6mZdvO1T`bI(aM<0%I$!v-!eT+nBX+}(ECA4uhMQ-FBzVM83 zP5r;%mXC;(6trt1zHOjPziHZ)Tx=a4tJf)s>hhWXB|M8Sj)}ueGoR~$qP{bFV)wOd z3hCL*#I!epcQ}|M>aZR5Ki03NL@zOrLPQYstC3Q{R#l;^;--^8=0+oz&_GZzc32J?x5Ua7x!Z7I_6Z-1upaTSuV2HH8IC zgi|g$b(5vts9gt&Lh5F^*Y zGz?PgqpWTeQ`QV1EvL+86(*627knOytzh_Ly-;+A9_{MZm5>t=1g-eDBHR%bB(Gi) z^EgCbJfYULq0#EPGwUBAkeMziW0|aiFbeeK?PK$7C6ZBX;~M8a0GGmX zYZD_W>5RrubbG-}Nv6;>N5Oe-_ouEhll5vd(8j`0U^F&-lkOYF?)`SkSL@>b=>fyd ze$S`Bqq(mh8n4-?=w_88lCY+g*nGr6-<7;rfTrg}z;AM5%1#ZWLyWGIR(wtQ!Guit+ret_wgsY+LNGG7n}X4+lYm4`a< zeAT_YZm5kg0ky)ZGvOLehJtcT2jvL>$=Vub#_CZJsh(1%JI5j&Mh)`YUm|R}-@wO} zM{fyh60+bzsjO_UZSe;J_Lukt#Y{G=R|9)zZts>#E*i}pg-*7O<#b>P;Xetmfq1HU zW%#oSjVr8%*IqkGuE*Ex%Ws@xYKs;;js-P#ZR})j@Up)pl&uL#Wk?<07^b`r4o=O` z_?g^Q*!*DI-v+Gduujv`p$*A~LumXXwD6)bKd5VyFXY;vc=+8_db5&#u49QpvU8G8 zDL_IqDlPzcY6_^;-i5R{e6iie1k5C$M|E6ZDr#|P(6pyQ z8}yYG_Z%7JQfT}18>4HcXXE=skAup!EC>}_pLC*79DK)tWlVOCe(PNf1!pzST|?w0 z5~#=um;JnSOb*S)v1QTzCqPUi6|srb048mJ?}|G)6an`?uJY08DTGbofNoJWYdx(Y zy;=w~i5ukv-b5~f@s%tuZcV-XwP)Z17>gYcGo790xO9#F^EszF0lt2#F7F_txEm>; z7ZkI^=^N0dHdFn&0M1TIH{1I7j5yU2u%iU+Q?iqHhU&3cN-FFBUK7RzA4G1;r@8V0 zXjHh#0sKe{Ih?cq$Y{{RFkGLFM{ zL_Rz{!gh|2?ea&{Q%V5Q*=-_hoN%w>AQSC!4g;=DSC~nghG+-~HYxcM`^EGX5rrZD z$wKgA-b|u*k8+6*OuM7K(B`335%j`ESmOKR)}jXCpRMCtrP?3c0>`l0Z-1jKpsLr; zSIvkhmEL8MF(h19#N7Ai2>BtXyMCw~ng{(60;xlTA6@E(g4V5dC70#=Ox#{ctGk^= z#>l&tLhYsthH*x;$#XH&b2)6Ay8kxZ z4&^_$=T^ll64#|sVCY%?2?I*At1={$1>-gjN@8Z|?CTvt!p3zm31PgAV|h(8wck&A zgNOh(IM1*)Pu{*9<>{XJElgx9QR16;sHtq9h6=3fZidC_wFkcHiR6IuD9)87S3lVb zYW^=~6#ZatKQFH;Ho(EqqRkw!!gSx6U5U=TQEjTv-%db5l~)wdiBdL;$u1z4tHS>N zao*f;GxTdq$A_iu@1@fS;64z+kH?olX#S-MuKJHZg&-+-Qo zXvFWh?X)3Yh&B#CJ1QKOiWkC%H#RKV@lU8N0@+3Udg22m;+y)y{Y3f8qcXpOIBU4< zZ$zQtEdAu%Zgc}-iTa$}D12~vES|<|y%RSdS2FK<@rCT~UUZ>$0KFA5VxyzLzwGsy z5i9^XT1FNXI@OKe)PILFjgBe(8s^h^?t_fL6axH+1y3DD7LM^7ktDL#8XK#_k2~b6 zoptMv8B`Uj`u((Z2y={(Ii<*6ERsS6lSvm@R&L<6_2O5TF8|yR>7D zi-FpveZ4%dP4-osm$N3jyc?w~34KY94ZJRO2GN1De(I>r7K&BL5jeCyoobWmSkC`cUO3nZ3+04_%1p%O4>5fs!d@URv~FI zvfjpmO=>|P=v;Q=v{8j1tk*fTixXZ5z|#@E)CxY?y9lsPQofQk^gME*`IRc56Brys z`23-=CIqr_W`(z;=ijYq{qK1pvb7rS24d_ou9gO>=k$~Hi0XlA#gm5wtHALHawS!vd0XG^Mdah~2yT|ZBQo^q!pvDl zg-_t$Ls=*g9<8epySUtQod4|xGwy4C-(7Ed8P_47o+4o~`E;#oHN&_2K=$R!P@Ox1Ni2W^>f&DlM6A(zP+(-)Tjj6akb5{164hhCO= zM>K3~1yNQBU_=N}Yg0F}f64lz_WuP~GZoTp&Q~Bq>;_Q;?Vn;7Lv625Klfg=LzGqb zTyT^}_bcvW0$2$rJOHe&xVx8wzuy|4`a=N38pb2ybG5 zsUvzNr2urt8PSaCJO%hh31yYMoVjn1wNN;Hc&uc$s2U2Kul{Ai0f6lK6!_t#7dzAl zZ2DrYFJwAwNAXahjI!GiyiT)DM>Tn=Vy;v|$1lrlEwU{3AtL(H)vS%q#Gp)QF2uAE zO@+S>6~}+0O`~O7MCH>d#?0*s1o_e0-lW=zA@XRs2$_uAjIgXGVW@-da^AvR0*tki z5?&!j{u^>Ej*CpAFdhcF{=T3l4vt7w8-kN}pO?owb<0}`sDu$oQU^BQ3V++Q8>o;x zP1{3%%afKh{c19bk%n(PhChh_kMyfzT5cVy zo{o-cA-rva`GpwNf%p{f2-NnKr~OIeKBr`8B?sF5YcsyDVp zCG`^BdcGm{NHB236j0^vk(Xs3I7?{Y^O3^xpvdCT!vCA4xtY~3`p`$SJUBa;NLQh? zMuBV1EMu%52bDbC`efIAt@dT(*GD;%i++-mCWI0wE9XBnEzH*nkNMM4Dr};DUs`LG zh{4lU8M2J%9pe%2DuP$Oo=s?{eG-M;5Taiw2gZ{;uuRNezAlc9o=@z}Dna0Kx=EGT z<)$yQ4?SzdZC}{wVZuh|R5`rjbmgW_B%%{^q7iMc72J8F>O9q8cAMqf>ry(TZH{K; zZr#%?#)7V8ax(qr>O}U3CSP*xb~u@S3o>ijVBq}gfYm}CM1zoXG3d=&e8X?9Gi#>9 zR!_f=h=WrZPCJmD{kUY8{)Fyo$4R}U4xc=oaF@L@Kzm{pIHq%Z-C7m#z%(H7l6rVq zrgZ=pn}Zpq4Wvg2YevYO`xDf5Q6w%@n|oq~2a*T9)Khpvpb_PjbN?VY^7qT#DI~Rw zG)-0Mtr+?Cnd39Dnk8+9!UWqD5&;;+-hQlMKaXz@Mo4Ay z8IzH-$r9x@5me)huA5+4pNv_JgaUn9dVR zp&P|U>PcX1s*eQqlRnZu$KR!h^_kci)uyXADV}?T>%Q^A|F=Q+Z!f9|VM(OL&Kygox4f7MP> zs`>ff-&icdx6Bm~NkQdgTq2aOn?+VRBB+5@X0IocRLEAfyKgz!=U z4ooN8Axyxb9&p$O^RZB(b>bw4!8vF&mU5>h3MF$l`%-X#Egx71Jmg%>U#8RgzDNQv zFRpy>k!IjU>Ud1)J|?LRU3?x&IZ-KseX40m^vb0Q+>q&G13{itoB09R`{;{i>C2xO zu#6D-p>!kEn?i}(%r*BJiDIS46-6qB=xJFD29+?DLlibL*a6K4_#TfijxGKq%1&G& z$U=29e)SDvyFX?~1V39i#buLn)m-qx8INo-%|daEE2d@$C&mZEhsr-)F29E=Oy>6B zIUx3bT1Bd>X9|DWwT94z5jMCr6@mISRl92up3$(EW*afR&iriy5UOLiCamGb+P=pR zCHIIFf5Q>Uyk|z}m!@kb2a~qfGA82}ytd}-vTBlFulZ-Y`6wptnDeWnA3EUcgPq|I zkw9yfxu4oyxt#LR+)hQRk`{d~AgW-)w0pK5aVBbQ_{lvkS=ra0nw{rNcu z4uJQtuumFP1|J_i!-0#*Cj2;z#$+p%+*ZtWCt!8CX~}#uGWFL?IP84ueY_?5!X%!= z^67=34id0QidM4$K3C*Db50gL!KEH!!pb5q4Pz(zH6HVo5PKr>)yT6*ZqMd}+ICN| z-&ph|5y`19(V4$^8!GWpvPGWSZw&=DaHSN3q-7Ud)l?UxA=y;M1w%Q8M*+%5(Zv{H zen+i#+XXMRrczPXE6(Yw?(Tk$bi6;2AEXC_zdxS`K9T*vhvZp8>$TxC8}RW!-9ZJa zq`#B1l8yW(8`b~J`+&6eAaxTLNJDWMmp9fSrnaDcV&a;n7%{M`Kf)Cild7vI9DTAw z>!o)X$5@z_g9%?C4X+7k;6XFH65BQ;rf1kjx7VEKo)gA2FV1>4i$n|S{H`5D2@|}%vJ#kv@11qnE>9Ga749ZR zKHy$Gk-KHD#3NKP{xp~I6t^PCD$U2s3}kO~vbN-(jIRAx417bm87Z4^&aLaLEqdjY zbB+qw`gmv-%LGmrMlNI2>zx*JoOgE{+|}d|REF1PMcjdD)JM`Ck!c)6-MTOJhERu0 zGj*5xvKU@dT$T!Gupt+;VCQV1a10_F*~+FVde~&Ve^-_n6_0HljfE5<*v!Y_x4-pD zv`u`EQdnjhS?57I9(8!`(}$M9<#<$Yn%-5@qE^E~LhP@~2Lgq&60(>$XCXGbmYCTa?51%}uM6{b~; zj2sM^uV$F#B1%1jetvodfLjZO_O+YWVNjEDP8|vvNQz%hq|V+bdHV+VKm|i7Q1GM& z6*z7xCrh^Yq>?>2kxJNRj*e4nbZtJS)-MdO4}xHCj58V2s%>qhKPz2HudI3JT@)W) zXwCJm`^q6aBn_;5bku{%RA8538>4F91YYex5ADhEGU$0_T94nGZvB~%jl@hGbnp2; z7&>kw@5#U=5rMCT`%yJ$n|Xe4db`S-GbIQ6Bxf#KlXf}NfFZ2-T1a>KPF165+*>zO z*ak+OB~I$>mhWvDfPC!@KVxh_`xE3O`NKbB6V0;E;iP?7hW(Q?Y}IfT74a5ptu}*5 zsJM>DlsF~id!3KKWlojP3eU#p*qeyE2I=Oo(Qcohcx!6?rb5eU>>i_8J>Z@AHk)T| z`+PUBX&_mPZ05QR8~f(+^M&OW)I)L?$CyBksP<*pnyfi0V`BvVtzCwVFZiW4^-k{0 zK0Ut&?la7%Smutac_0&$U2{(9(LxTW;ZT27a+Tj-x9j5R)up8hWm z_v8F*9fmdx)KwjjJ*ZS3;vE8?J&=SOOZf*D+3Q0ic$bYztNTBun+ZVecMtoxqoHnr z@|}b9?ZonM;<&1?1r5n|@XM_u=WhlJCBI6Puq)q*tcQ`_lN+%+vox3!5nf8Vb>Hh> zrWVQ*c(yv6>n83$MD2fk8WhZ8(uz}nht z1`TCMt`xXUwRunsubf}?=Z?iz>#59j605L;hl$$c5k&%LCVPT-0L!l-uPuVj9LImQ zx;M6|8tjJ9KT++s>smllcg5%!C45^hRzkP#RA)ZrBcFiJ{|LhHL!iZm#q^?r;{ho$ z7rqg{z*>D>;#t41MX;NQ3{wrsL~qu(VQshwKcCAd z(t!(WHK@Oc^+J2H#hNeK*5Nn~07U9L@j8+NZZDrX@J`C&X6sn{8}PVimZHvzW%>k) z{S30szy#qgW{n8T?H0uQ?V`ma3jC$-bw&QzGC6Sfown@N%PsD@97^VO2?Ldy_5^D- z7?q&UZ!SWaz|>^b{u;e3&^!d&WYn-ILf!Bl{_QvZ{~zO6x*(;?#DUC^2`DBaP!)el zW~3vXI>DCAf{)z0j9JR{s};P7gI{}=?qkcfkE6_i?tj&)c_$Aw0!Qv7U}A0nm+q zRh(s0m26-au@&x^!qftR8yRsX2r}C>V%3Z9E;0>91)dA`-^B82uMqX~yr22Tu`_Pk z{q$G?Ct^&h;C(L~u9gbJd>C*9>rvLcsJ5^^{uv;Usk>DsA?e>7>$L9~4ddClU~49_ zD*m7OK2-mT>sZS}xicL}$$gI4mQ2oSUc0~w+URyCRDo}I1ea4e5()zu9}?-5^H}-D z1YZ9N+(L{jT|6QO&-8rnp?u9TgPu5OCzq=dFU#Nk^ckq&bP=r6A4#SH;YWo(E(ON- z>I(E)GRG58F4uU{Iv7^yC}lri3-!T^5HJ&ALy6@ym!)FlzZM#0NZ6Q zvL=QPY&LOgeMW}nohOU}sn!;?_j9H10W{wW3$}?cnPDi=+ZGT{wO&P`dq!LLqeV(5 zh(G_FCBcH(yFUs`g=H44XC91LZrl+j`<^1os?8@B42(~_H zqJhwTOSY(|Y?yR;#+W5ubJEAoJnRd9;k~{u9-Tq$XJ@T0`18?8%qQ_JJs9N5zI@{dhk2Bixdsn2jH7A`5%i@v6b~|{xr<-jWtOVJz8z{5}K0kN=SKq zrKWX~SURhnxpghY-=;aj5{qxrZ6~q!p+O9>E%kAXdW-2?)DYrOX9B>dOp4G53fjs% z2E12bQLE;>Z@^+|I9Rl`p^MzkLMPc*`ISFPq}|JswzzEi4%Lt*?En}ccwfg zzhO;C)F{iI4B2`VWHF(TiQBD?#&H;y1#wgQbqLT`y<_O6445UZ6pleEb0!1DUUfyb zGb>eaaG~1X0KG402&6x5a)w!af(F$L+*_t5@ATQsA8g9IFYS7PDv)CIyT-kk>#9i4 z18WO%3pn5i5LtF5&=w={R+JSab54-%oE}?1DDK^DNz%Sc?)$gsK)a_41)2xq*lu44 zfnSG3&_zel7xNN`hx214DWD@ghE=s+ReOzvJ>T2nRD0~M?B<&=${U#lA>G(iTvVJt z&$niXCsqs|)9;TL=cq#msy(}}p1q68Mf_Yac@`t6M!3~NC(%GJRQWn0y(0>peN(}C z&alFI>?K`XdxX!-Y!tsY{!k6o{>rU`pk<0L2V4*B$YjPV2CRTZF1_Zuz!L5>k;V@T zW`G=rD~&%0y9nm~IHxeorJE3~QKViQ-gEo70hrQkeVd?Vv(*7M`CVzvx7Gc6I_$r> zyfRfMe-^YRH9W$cPcWa-Sk5erp{*<~*C2E+lumZ)2sYjnr}C(u4q|It)>1pZnyWIE z-PLON>a`p@>;AM+rE}U~ca>g~R)NCcGzs`27SCUUcuu!|8Irjz98FrcVFO+TZZ z@%*1w=y;-}QRoqrYbT=$`Vw(DRL#X1337I@V?Rq8y3x819f^JlN29gnaRipG=EbU> zRQ{Ibohe5;x;Gx+tk;7;Hh=kx#}F9s;)(~P%+dRks=`?jW)}^Kg733sG0^^TWzK# z=dx`r%hTSQDOwOPru0LJMc((P%*2lmES~?tXA{_9b3x0L&Z1n5?a?NxVN8Pm>~br) zVf^pYP$NV%HCrfx%3u-sE$;MI5`T#H(<;DdtSf|~+RyAh;74&8dEMltt5K$cC`|Sw zMpQ60 z-0E5sWNfByBl?RK?yx?YGhF9gk+!|iX*b%!%QHw1nN>d`o`^69doekWN4OFZj(QFL zB>r$kl8DtGO;4V4nxyLkiR%KjQ!T(Y`sp$LYAEZW6D8nRWljk3Zb87@RqI+r6#qgf z`X&d%x)7^C>2O?Szg@TlWMTwelSGKnlJgUno7=R?QBPd>^_u~H<&1{;B!A61vOXJ- z_<)N&!ja#NYID?@3muq4S>_&23&2@Rf z7y6tl)0NNm>{awGah@l@AFi{zf`!i69BP*0`dk{BeTPQ4ew?k;q?_1^p_dHvT#ClF z69P!>q-1YE(OsB7!D)+0b*PfX%^B_aQ6XP1Jcm{M?_=rhTttnC^BjGxuUHvxZCdQA z=JKz#K#{9~ARr@Wu8X79ZLFN4K%s(Q?tEu{CjYE5*Y-@(IlZf+VSKAL8?mjxOpW=8 zTEbGR?ElZeV<%8`{XJ8tJnV5QH;Q4z&xPM9!RjK;7)Agh{L#aMv6e_T+K~y5%!?mj z(H*)rO{260yB=^YLh2zj$xM@CSluAfnDOnjNc=Dx>&rxKqWK)9VBkZpsh`QT%VJBa zAN9;>6QGW$2E8F#xdWWk1&!51Ip7rN)=BRj zQ<&ILv&S^Y4OaBeb}05K%N^xlNTDaBvgD36nzXn|rpM#*-{zQ5++U{quzpJmixYl% z1Cyv!wbdl&a0VXe`U+7M=HKpB^OT&9a*riNUjQyXX$Zx|cH77F5t6OlBmY?2_qAK; zN~D>r+`beJ|0mMxl8sxzzBRl}NkXD|;-Qn?u_FPn6RKi>Mi4-Fh@G`Yil*dhj#w8j z$|at4Vup7O154Z}oqUAjFT{yN20CL2XsGaC0LahiGc*wn7n8j3sjeP73z7fZVNFA# zaJ#9vEC07T!y@umb@C9r;9)Xic3=ISHq6-CR23&`i#MP*dPw%-#vM6tI=7&qm+mqS zl=spd9X1Ha$4o*32*0H6)u_I@c&q0j)#_4_=NqJ^K#YYgB2&Mz8>OvUxt9=cG~q@K@9?}lk|4Cn{Go7}-K~Lq-J(|GGk-b#0cW#>+O6z%iz~uMaML8tD%N#8}{bSxE~AJw{>h z+0II2ajZEDM?@2xQFS5(b^;){eU=DQN3~j`5J?&{WG)rq>>mg4%M1W`0QZfYDXI6o zJXpfYQ-s|eLuDNOz?dzyaM?ye5V2>F)zbgz79IkGDx#t^&*|%siB`KX<9k9jETcoA^V84Q>yM*0a{i^F9O)H zq$YCe*k zYhiac5pPLej_2+J$a9c~Q1KxTGHbP{a=d%MOL-zNY-R0x8p2-_hosn#oS&uyQpqbo z%`(2N%1&N(M_Z7v>&~rj)NtN3L&gF+*=(0>Es*bn;0eP?uJoohvD?GUlqV&ee>zGX zRADnzW))nK*5N3n=z+>%@74QfD#ta+SKb*!2PjIRblY6z=-ACoj<PV?gsWLEQt)uQ|}tjP@+edXX!UxHN&FbA zd}ifWu|XExp{G1F0`{m3nTVJW=Yk!-EX*kepH<+qW9cgbGMs^nEXq1TFl$TRjGY%1 zae9Jg(EfSl1X2&-pKr)g9``;sQX035lUd*C!xN9n#sIy?@*^Ej=n-q)MgLwi>mEcd z_0XOQ)}Lhy^~)1}42*xriL1imQFj&dZ>2(p(TR@R;|l-_AgGnWpEf4Wt)H2=LhQ(F z=4bR^5>>6N^5Ok6KE?9`S|&uYhU!w`#OF13MIsC|s4okPRN8+v@_`A$T)?XK&;6<8 zYSDx02KzL!@-&Ul3PcU{<;%n0V-`!Af(|Z_$L>0x$DgU1b`#vJiv$XclbDH_V6X*Y z<&bE08Wn^YnH2QM6F|eS8xICXQs;2F77Z7O-57VCA{2TmcgCA51rz>L@5T~J*Q;Pf zj&~$cgje1}K}xX9H5g1b=PFL?aM(axtUV6$Nu!}rTq)vSAI^g9d2q8IMViC@`u`O- zT#gtdXk;BJ(1$XE^2qdsS(57DCq|#Ru=0X6Jn=7&crY>fIUJS`130mhAb`F77q6GW zZoZzRXb$k!w+WSJK?7&5P+@>VM!GCS6ut}M2jO0Trd(mOfHr#m_4ei;A1IO%6h>u; zT$&vxEB<{HO8Zas>@Z{(O5gT<7O$YiR=rU*nR6p6bj6Gq=;EU;2@eu#1PD_jcI+gAJF%D0RKZSc|#>d{6l zx;RZ7MmCwKr2!`J6ZTj7VKGPHtrlinKFDTY<;Ck`07qJq_)P1w1&;4ahs5CbLj}4Dd+DUyfw7 zY)2F8y$u^VmW`rQKT+lnY5pS-GxGLps74gK$qXBdt7$eL`_(PQSi06h(wCgtonvh% zuO6RjC4|j>VvD5~&c$F-ny0U|!8dJ>)U{XZc3Yc+VH^Kj-LnPF8gH$8os*0QmXDL3 zZ;2D0LY&s(#!tIuBLN1D2ngtiXCLBHes2)i5qwT}s`IW8i$6dYC5*yUWv>2uL`isWBWb6 z8@bXve>_`OqXNZQq>p+lv}KN=tU7HJ;eOx!pBhJe*nT!{WtasE)p|E9n3DM7#nFi7Bj+nMDu zc!YYYPTI1cXZeI5CUfPg=mHXI{^c1a!D&>uZCWt z&aD5K_ib{W+F)fG9Lz8Uy zp>u7dI8M*DLBDcyb=sjT|C;;m_4f}>D5WcMI^mbTBI@IOwSjj@$&yzJfD8)Zy^F8m z&~1;Bsv7tP6?ccyK81J&`3qE=(S2EslMd6~SY~N;6Llcc1bQElqUi|tlp+5-u4x?I z=!VkGRRM197aZUgqK%0cRmwccd(=}E-$y4^eY2dJA%>n%4iN`V=MO4&N-3rcn)=VzTu z8%_nYsGifv1ReWfIH){nsT8Xh(f`5iJ21+d%ao{d8;j}<7NVicIqjPik z3gfKy^C$bD!#SD@RMN@HeTK+}Rf&60aJ3!#LHS>5aYSovEO8r9`71efqYT~n0?S`F zu)j--^DQ>kx)XxFyP5Qj5FsHqEgdQBQ5*Ts9)jj8jwKH0kI4(8e6W=)8la-YPC1;* zeu!;ocGImPX9tigo_cx=CRzahKLEgYsHK7NIWQT^TZu6^UR8VIRfG|fcDL46rzou5x+8r%)(cm zZ|D(fJu;uW^a~|Y%&dPZB2GF$L(N}w>Lph6>&1=s?#7h`a%7$oi1ba1FnNd0I}`~k zdt048JhE($@RgSB)SUUQg_;ZWG}T9iGW9jNU!Fmujv7Po_d} ze%}6oiO{iU=+?y#uj)Du3&evqm4wysuF(~wrz4M-d8U+64t2}uC;ZxY3p7M~ds3pf zLF3aW!CJ6AKh6~02L0RX2VTE&xvGyPe-86DioA9DOF^ zZL9xbHQZg)vF%kL6fUK`Ju4R`d3v@reF|2v{-KXlQi|LP-rhj3<4ZY{>(6=c zZ0x+J86L&H9r z)$lCR{Z+_wjR!%|po9ALNe+B861v^r4^iZ-Q*uxh(gl45Nn%vb%RNmON==CVE1=_R zaTPmvWaAtV^h0y<-+X=djC8v@6}> zg0x*$!L{fpcd}61;=KkdL~_aFWe4iL{+m2pB?RfxuC;w;%T~CH`*=BH$SF*4eHK`= zPZ|_l16KA^y>G>Z#9^@3k1$M`D^@fmGoL#^7{uGGyA4+wRm;uSIel4WViWu)Gem5x zbvX-(7guZbYaCwCJ2E>RdgwbOHgSA5V^|rsyAu2BOK|g6 zZT=x4xq1_V_6~m45)ku`>~xI$1UQ)$Lfx)qH4VFfxTU0V765I~Dx?jWk{u_plN*X> zt1l4>_`vMPIO58Qeop-NH(nBz?yUcK&Pw*-Ji_`bOWP(7(Mm3iJ^TZq;S9jGU0jrE zJ1h&{_OKUQTt6jfTdgXP<{H{*1ZVD4z9ki=!6;G#bjnR4QD64?!1K+J9=phprcmlQ zl;C`YEpF2-9yod65#mj=u*<$Y$xk=ItJQBjUH%|fzK<7Eu9%&CcVJDs9XMw7MyZ(^ zc)R7S^sfANM&l6g=IUxXm~4>0s1)$o=nWBSBOh~Q8ejrJ$5$J9E({=UF@i6g)q_%w zH>ZFv%0LVKU4>i$z>*F>`ev4-oROta^{-6h3b@l@;=1$=Nn;uGUP}fU&@Ikt5)mLr z;JHwV&sf05YhAxZPb>iG>2#Moo_B*wjM%%`RJR_Tw)`IdcEMT!3yrd>P{m}cJF0CZ z(T0eh2WCT7;!-W@9k$~)*MA2Nf)aM%n?7G0ZjZ2is+Ef|U3t%FPwy^OZ1spr>$xE- zXy9WEl^NE9tBUf!7c8|`Lstk8)|jO3GbD;1)sM2fhjOZ<2VxxokU`ThMM=ZMOg%BA zk1pr^jTxwqT_xX@Yfoq%f&>+wmiEDL0MZkhiunIF!p_2GhO6fgM8cB>Y{Os>93&A6 zDVw1nezVL!_k(Lo5(QayLR2wBJD~s~{>-og<$;LynE*hEgq;f>Xe2rUh|XN zErv2UdpQND--k`<=Isc9*T@u9QQdh33}vZSXoxC8q3SMVJSTgW0L2I?CGLUB6A8v( zW{T_NdGpjEE9r9C8>87XO7$3?MoBe+X5F-eWT}7z(KuQ398lqOh`lmTkHNYJYJ6$!Ya|(N3L! z5SwdW@3RM83>r^@hul@x=e<0O$LU_dq3P(&;H4is6?+c>R~%8&%9#06Y1+>(=?>?{ zq$+GJIv;Qy%<9z9&NaBS?7n~$b_5jDm*DY*V5c%Ys$01_t^Tu46(#W^IBP^Bu=OEI zwRV#~DeF2H$wt5vc*gX~t$W_Qw^swAH#JI?K5P4|4j}?xHvb)L$L97`w}(fNu?02( zgI1r97rF|21cSK)Be=05s7VTsv6pL&BSjM&j^`VEk@D_OB>jKcT$>i3NWpvc^?ql|r z34jluir75otCL-?`?ts7MI*oy?aGdo0}%=oqZyNbaBQY3c^tqFSRmD?Na zfq(6X9c}ZxO9VB}x*0~k-Neb`FS^R7- z$8se_OR^SphlR2EgFQisH!$W}{*L>cuyW?9&Uu7bBi{g1R*jfT4C5?22j_(>ULW-t zRlv8(z$Djm?UiupdqZ3Lrma;zQ0yl{MU9KBjl}-@*xQY}P9O{Sv-!0}aw+|UX_hn{ zvcvA-Hi#=#vNQ1e9SYF4)^F9HynpmAHV4D?U#_dK^*b;M{d;b(0W1`}Ry zX7GPo;AuGHmC$ZhvjXXH{QOEAZLFOq?dpYjTr`41!R1Ipki=@6e72XHY%cyNR>ck8 z{7D);arUoF2(UU$jEu@tdmV^xbyLGlnFn+Nb~1-I@523#R${{K;}$__@Tsp#2BX## zE=T=R6v?LIJ>HojW})pG2J*7#V8;0KH60C<@1&(c`|KQvAHX!bcaynY(s=5%4Uscb zJ=HgSctUraK2PE@G&Mh7?O5kMG;gK}M%rG^H$_z-CfGcsoKS7wP7TY5Ba=l^yC*1; z$<0!juVmg_2&u&t!WxJ^fHHwkI8DkylyspM&;MbLPs_ZFVhdPN0htZpbJb65wo2f& zKW|~Y;rW8a8UrolRC2Pe)rDx2YLnD0ct(nXyD)w%Ofj+7)ne3bZUS%r5~-bzARA0` z6qQoR9Xs&v)_t!Ed42{j8V10DuMRqMxTYPC?TZgCG7BYUjQG7)IZSK()j*8rwYT?;ENBOWY`KG}YH}(;`;sG7x3!lA9r&}K1vKO5-vqOEt`cFX3>I$IF;|~W z|BWh@w1mjnefoByxHYax9xx|hYnc~;*cgMC|7LX(|F`wy*v|844wA)sa2XWBfgmx3 z4xnaX;RdPdL4&|3c*Bqr=UZoIF7QT*h$I1u@_8C`c@maa0oW>RCv2t9XGH*HSHKI9_;?|Z{eILK6Z8hIB|6QB_2OooE%+Q|& zNtJIf0Mb~1QoNVwz(6lF?=Z9)?jnZ9c<~j52e0qKlWNU&neX2F`BqWuvv5E!g+4c0 z>8F0Op}zzGEdSe|=cZC$_J6xlf7NA*g+rzWyOq1sORbmeZYT0yHGS9C$CD8vvz*H5 zmyGW7-5q?*?)k~Ao|v0%&eFn=%SkgTR~pu1IF@>LRTA?AlHNa?dej?eFT+6`*j>Rj z+@|eFbgo+w1}XtT8nf!f?CVMiS9`{knyL!9^#oCeHO3!xL>D zDe%+6G}vMX?q^O$lED+v%cXJDMW751&TLD>$@!cU|6cy*9t;cJS^%VpLk-4jMKbo5 zOjzv}J!#*rYCxGsT&HdyB_~ANI{UiPMZme zK{Ri{EVYk_o(?g8^Q*qyZrG9r{hGKO0@tpE;hkp4J3S3gO0tssgFQF=N%6ZuutlOd zKaoEsr~Mw!mI7A`%eC8EfM?Aa1SyJ-l#A=DpjO`FD53tX@_9ajGc=jH11AV*`z=k| zPPL{U3&qD~%D>$d^ZGu!s9q+4fmY zkUW5xg?o)>0?0F=ZBJ@i`Jd^DB|BR$?l$(Wek6FWyR^R3a5+f61?)k!6TtFDc#2t6 ztz#F)HtJHR$4F}1gZloBg`7YN5H0xm?~Yral=4$60M#W-6-W}xoQ$Rosg;!iq;GY$ zRX=CX6Xb)HsCImHM`J+*OHHwd3&)_5lQFJHlKZBlGF4_^_A=zy8V<2cxj*WHEaNs9 zuG%giPxA0^BIToVkj&=56VEv2-FACcB^3UpkM=H+|rl&`en|BWk=mgwz(mnNp*K+97#XW@{KWaEjTXUTfdN)<239V5S;Q7 zX+s)6ZAfHXc_NR;2@-(=I62pFO{E>R;7C^+FqE=+Gy*qml$KZ_jm%CkPk5jceeyzz zDDr7!cv4x5Ls4>G{f_z^afw8Q4OjGcavS%^C7{vcpdmuGuA9Vesgu*YL}+|tO(&Pw zQIz@SA5hmHWJrpn9;ypZV4Pr)tf=;XMTb0$9NF9E%5VdWkx<^cQq83H_MX6*Ch%gI z84Os^#SA>!cpubHAR6##WkEyKk8zMNtkYgE^rJHbD7#foapaJ^%g*(KmyVo@eQhI3 zKrdB0KKJcL$6WOJJd~;YnX-alh}&;4J00)p;LclCF+?^j8=_NfL}V4m6`%;SFn_>S zvq6~&i7p;VeLW^bNU8QBci)zqZ=;(b1A0ClpEz67SWWE{$!`rB7S&zS1FQ!u21J^W zrwty#qq=><>8>bnJSb`?Wi}%^^g)=;afY}i$1VAGfakeQOU?JS3m({kKL}E2YM3-i zjsiUchX|c9ra@4-UEL13En#)=QChs^wGdJFeaB!8RpD(%&RPRMLTg%SXeU>pW2!eH zAB)j5_JA=uq@4Af>5=pOQVKfF;fTDwQY1$OGBA!4-8GienN6;RwX`ud=Fc{l2A9)YVhZqnh|-;vGT#5s;|JZ`A&RutdyGw|K{!aFg)Kwu52 z!!Bpxj~?A_6AeJUp@(uL)e9efb@>9dp#Jp%ZYM99m0rFd>n)!k^WDeG$_~ED$$tTv z_|;qPVrB0b8O2=Fx*PY1(h_ z!~YF1<;I&}b#`)SbX`V*kf`g3^NsN{gh~da`bQWgVP)a2A92ZM+mRtp zw0KfNYJ55mb3O~J4$Hel63-SC|7)#OTu|7h3_3muo4yAVemJ;a)_uDFmv=%|=6v5s z*@o+lNpN(oF+W%G7KrsR;ua;MhxpHmVVbGd%>>aYFL9DI+$|sp3_NhzD|vxkrCrlu z0DSWU)>9nVWMR34tfj_}0^4Xw$A1QIBn^86;O;0 zXK?vSLed8r=D2x*_!*t%(FBH}C8vO7Aq|r-Z?Fum76rJ^QAwMbXI40l3IXlMk(@ws z%S;C#V+E17$nsa1R51YW{3mSTK=Usyv=Y)39^5hFSDHnu!M0F`$*_n_BwkT_;!?9V z-5MyaveiPxmodeP2RZkdjdEP$93Xt^#AEp^c;q@twmCKk`2gLy*75APGbeC$9LnX| zXV-e*&5U)qI^U#aLXJI8@gLT83(Q_77nkt$-1_X4U|qO4o2)}a#W3$)drZ-4+0;{G zJ>FQE+#{?Vf}CfgH;9EyypF9|P)?Rtrz!y;LtsM-0UgB-kv8pMXfKadjqL9%khkzb z=CbUst9(%AX4h3gvj^vUwIP?Wt&QbWuM>j82{Gph4ibV?LF2%QU6z`6GU|e<)mUkF z&a(AW2eWc_4~Ek5JX6|H$_;|J8g&>(j?vi~vgQc(<7wJNEkyOgSkSkpS;j}hMQ;ND zZTZXu$>W`>MFtQ&W;m5I2>saTtJ$LqT5rlp;pGMRWu~SCyN1{HkIc5x5YJhWUd1qX zi)BT;gD5;{2z9f&wKqeMBu6^cui-@?$Q@PSW|s5pAX*%Z#a|prLu@ZpCxkI7Oayhw z7MV4wUt|Lu3hMByYA_z^Q7H1ZYsBs6D+Ij@o&BcDhj(wT;+&q>zQ#C$ZkkGeBj3bJ z3^23;awbKj?zzAiFvQV6_!HQ>m7%2UV)?A|xFql1ZBMs^4x}eiTp1@|eTPBVU4-w_ zmYYIMP^t>B9)K?5NT}xqJg(XXLyY;>(n}LUdU%X=uHr&%JoesQl0L?RGZM$&c8@OI zJPBNO2*eiurplLKppXO>Hh8OI4f-t>9LzD59F-Ezc*T@nJM;PbA%GE5)O=TKD|_Ea zroAe*()+&%O$W`g`XU6Z<%uc4C|2VBE<8ewcBKij9r5qZOf3p0tw#y8ghIO1(m4tqFjhn23b9bjay8XH%mFeXrEFR63CHhf5XF+6}$qYmIh@^c@PP8e|GnX`dd=vj6f?^ z%-u*tTpxXiXeT{VO>exgm029Ovbnuz6#krFs(AOm>#9zjHSy%Zzg*g;skQ<9b` z?S1V!9X$pqj`r24z$NnMTrO9;L6_r!-I0>O?#!S#smMS1q*R3~E)jeakH|`V-w(wUv&j$odaF zF37jHO-&^sL{jV{Ue$)-5zii*g`C6SzxP6?(Vo%k?Rh%e2<4c=tt51CKX-GFD9*L@ zr#N}x2Fb}WT)Z$$@O_e4z5zdjobN3i(R_7zO;qx|KK~G3=UBgwdLSuCsJ8wI+cnrP zHECoDrsnEvLJtiO%0cKwV#PGO4f#$~BRA;-uOEhH&dNNn#Y&f%5rBvqctqebM4_Z# zSHWCz7(PNzO8K~CC&@V%at9p}vNJfZCM*Tgo;^5OVdzefxW>-yD?{!mRS%P=p?~LJ z-xJK_>-M>&i?aY*dTL~rHBuO)JjoU*AF?<;u3Jh&L=@lh($X*P#ElIaJd7MGv`S0v zdTl1HKuXtfjRZDB-H0Ukj*?U_kH4M?aITM=CChIC0AI(j=28^ z4hu6q{d{2wa6xKzGa(Rw5qv!Lu8r2}W#2g@2q_V`CS^zGrYN~}?$gs|J|5)&`{l1sb zUPPhm;=nNtwosxFo}EcbBeFJFK^foa{xc0z+hZ9r$k#bgMUZPGdGX6~BEJ*LHHo=) z9^Cb3OQ5$2+M^#+iiWFLnZ%*K!(FhMU@<^9W4oo!@2 zNUzTI7lOLKDYf8B7iN9!QIanWnxCSbHS%jes-n^1w?ew_LgsYlJ4~}NA$5{;b_Rnn!0Pq?3nn5JqGVnl;*cw-W z;2DdNoDc70^+Fhj0UI4&;9PN&sO8$bed=Puy)L>Nx}Bb``2Lc>`iRcLDiPrT66om} z8r+{eOTCNJ`?|UUj%TbMr*!Q3RE$*Hjixy!)+|R%$2{GC*zq&scGx(325)#9YLnlOPJ$}F=FS4YoMlg*bKrx)`E&qoQ6jz zFsDM8GjgWs!^Whz7?Q<$T9n1``vmTE#I{p}Tw+x(L*lYzysQA9t2zUz;o75G%tvgC z1ScY6ar<tPaWMYtHa=A zwGpXV0Dv+DId6RXtv!t{*BQR&e0>3cH)u`g$QB&Svd)~>ZnmVlt#%$DoNTcB3@>EP z&8E0Y=(H#UJn=Z&1_R@#pgd&xM0(w!0MZW@h$dqrf0h}-;`)SOk(5?YyTe-_Nnzb(8Gh4;jhz{3uLoKO zq((wS>1*P!ET53%_&PD6?`1eAAL;5y@J}sxHVF|I%zFeAJn4$tfvhGdg-zGJG_4wU zGS-)zNvd|8-O4caNG$_Yh#p96vtxkD6J3nYG5XvH(gr$N6pQTESnE@o!{+y;0c7wM zcCne9u8cpcGq&5T&jf#8j}96Yv|2s@bej#6;+n&622L_|4`ILxvEQm6=W#GZUGk-H zN28Vg?Eu(qxl(76T7B~}@81RWBOgP%UI(tlW3<*lDs9VN7_!}jZNDX#5Z3h@D|`8f zZFfJ5vL{lc;4;LGan&lVpforzxpmCZiXj5O*7z{!7w$p}){d;vrsmj<_5EHRvh~#; zVbIdX7NtkhJiDHmPBYpD@q-_9P$f-_Bkixtj6H#-d&GyRN!zaDKpjTQv~ZSq1S7j~ zm|0VOM_0=@*k+3cbL|lVTe@YST)H&UutZjR`qw4iaVpLOrT>$1go0Az^t^wT5VJd8 zxR<_vYh^n1b`c^G6MLHMaSJw?Pe?W}v*^b*-$JFMg3#_5qmhk%`}iH`uhl$={8MmN z`#m(>{5R&5gYI4<)a;gUQz?u^poQPA1Wn)I`w$z-Sxt49=qIaJN5CmBa1i)(cffs< z68UoBEoi0kz*nHfEw`m<`Fho}Ru_pR3oG(p1QPbhVj6_pwG7F^G9EFcU1wB{NvI*H zo*sru{cH!s?2$0QN3Q$6oGH0)nijOwv^-SDauf4h|KAe3-I{Hpy@FvXuG_|`uYsEq zRv9Y|jW?sgbbM`8LKuGreM3bE4N_vlxKtGV1D}Q|?6SFtHynY2%Pj9h%k1_k$po7& zJJLGp8ZhtM$6=O4l-6Nb#qVH@fK`bh-NfKYCL$b&Bn-X*Zf6R##6gEj8<=_dYmw)J zHlr(^G`W$L)DU+6IGLLl|M(Gq<*fweg8W?bg3Y$%p)IcHoF<22_Yu<_yVptXdoO~= zKYM&grq7H4-s4zYS7>TsjPrfkheQM*uFFPda*`qQ z^u!PB79!$hi9qE1F!qe-AQkkD%Nw6p@6HKlUewMS^_b}H%%CHan?ICd+nl)bQ#!5Ov!>hT5 z8Q(+*`e`vMj&&i@n5`GFZ%oy$cDi`A4IBVD;?G~%c=ZuMZaSc}m%OW^^)GT?YQW{m zPf^oUhdeH>8RQ!f<5~P=zZA-})13}y7D}ygGidrd>xx&RKd9V(oC)4oyp{4OOZqD# z4+9$1-QfjXfuj^IV>@x-QUDF+hbmTY=L$o2c1#q$Fw^ZfVfdzZ6#MP^d;NwD>V5N6-3j9aIcV&jaBwJTS}e)RPp0xsJ2XU z+28dI4LGGY662tScXB}&t34fyaM5swK+WGq96y(@J>hZ#vnCFx(i@BvBNLby|YpVH6aRY%%72e&0J_@arF zr8Pjon)6nWo^Y~fxYRuY{%w4#KZMFSJiTw<*i0KNk!_2Bw{aDFrhdVmeTp~>uw0wH zmYf4>2k~caYO+RxhQ9@-=pTO>qp?VM4#D8%C@Y^ymtQ8inbYFxHnsm#aRwEKea4VJQc3}H66(aV&MhWd z<*?C+6}QUUJWkM@z_^z810J_(?412-;6Z%<*F5fPY68m%ctzH(&!g@Op1nGW8lH(3 zGOPn+NNS0zd!tmKu8$8jUW2)7VepLsKVNe*(zWvSxqUm~MYCjvB&q~OeL!Fwm{4cF zM}hs-b-F5*Om_<|poxlo6*X|ci>1v4P>sF9Ky1wgR3)HNXJ#@}$NY%Q8E_)g!U4AN9 z@txSCl6`MaI|#`!>3jcg6)Z915IOF#wE{-aq_U<~J&Q5h># zyv1dnfTL)r@2#P z8;uB!_aV$*w(nFpx4W2C8TY|Y*+j0V%Q`D(BXeRIK$ihwN^E8bwqWOzb;jKQDo{+G z)M)nIJ@*=iY$Kp9<)41wr}`UE&?dM0xMcm&Ob46Mx|n8nYK?|_By2OM`a+KM)r>r< zOoDKS=Moudb3{1O;_4E0?F5`M$ky+p`8J#SUSp{PCtL8b3z3*9PTn25@CwcaN?y}g z8dWX~)>299;P+NLP^i;So!@3I3HHvoW1iBC*(1$Y$YkPdvgKu?XKwBOse-fki{O^~ zJ!Z4UIaQ_lM%3z?LmNf&6@Hf_wy2IAKncE)C8nMA5Qbz%S-elmv8RDVU{ zX=ihp*`ew6bQBOP{YJj;^vE8LC)58}G~m4nGOo~=)jD=L(K;ydev=NYxp2zatLbSL z#pv9Y3cU!tH_5)9g-s4h60y#a$cDudYY(z5EsyAbzo!WlWh3@`a}%e~Zt_W1%Xd=~ zU?_@dpdqt0ZBQSD!U=6T&0W{xkKvN*KA&k2;n(aaM_d%g&>~S0@m?)3hAdjsN_Wn1 zBu)VLiU~pcK6)%yfH>XoMA;^A09_3M9c`QH9r5Kb)yuSFiJp)9&Z+of+TFd|(2>$p z{OYk{Fv@F|XM(w;Tx^WytaiBorO*_1hSWss)ZUrEP}pFs+jLkNh0zV{4cG%D^R8qh z?A9|YM0mHpwUNSsY1*^N;zwqtZOIVYM+mDb>=qIrbh_H(z@!I#3^dEvFbf0hBw*dg zdA~Rlo-e7Q2*EunaN7lu1Tgy8(a>BtXBoU-BCe63&K%*Lgq1u-xpwGC1#xxjig_rv zKQ`>y&b#e2kF>&o2=I|UmCutbYKQl)4mkH|=M+?AElhGred>Pwc(>yGl&P$$3~70b zetVGe#SM<`Xt<6uLHC7fd5?a3uwv)mk0tqOV4>$8b`XSOrY2|BCz3t35V%Mr)1mXc%z6*i=NTrb`3c`eblgPZF$U+KJQS z=($^TO-!QQ=W`U_B2fDr5vyzH6seSHFyd!W*O9=hZ!9->f-+E6n5NF{!H# z%cRrTo6G^a=q0gvSB>YabK5q8y=h?&+sSw><{4j3GZ!e55S7ypTT6+MYSklg_*iHC zNlt`TP56pZ$>Y5ZSs`e&TrS*zsQyuJo=z0jwn6y2S;Wzg2g5&J{%LWcI|s^LT_oXBEEyW74V?Hi2I@H`oi%jrKo27?9*j!Wmi#8=XmLH6 z=+zZtr&tAF6c67IYZ_9r@7=*R(f|7~rR^T4xyAqx*ohX=KT27ol0%!C|PjU9<8nNehAOB?$B!IVVHHY*F zU{%y8+-14~!b~mo8tk3-k~3Ly+l z>)|m=MtHVO@iOaQ*8o2xAeY}-4g}KWq?D(j>LI6$qD?^ui_EM4$f(pGlc5Ilgn_FO z73q7WilP(dv%NPb!9Sd_%E5Fk_>n%fbh_rI4CV-ucvSJuaKd2sO>=o!{1qU1rlDvy zKe+Fm)le3=f~ZH3A1It{V2LWFXDl^Z)PCXWQJg7|^La^xZBo7pGUU>qocUh&XKlNd zv*!NA{$BW;MMDf>3?-Nw>dL*)xkep%3FxZ2#yEqn|7WTa0L<(-k%+<%Z}M2BT|48KetK7`E1;9&$AbPU4rx(>RCL1)8CNrBJy7a$RCJr#F8Bi@Fz zqxSv3}*ME_)i<03`ZDL%9smZncDxje1R&p50z zYiq7{9>et3;Lkboqw9@!A7SM8qpImOYA| z3A?4k@gf=o@-{@ziloQl_6b5eULJ@!Zr+rZz z{vw*LndJ;8=?uC;jj1vV2;tSNZrHKkal*2eNLT-QmU~10d*sh&6^fg&%>BvU-=o+n z>BS9_ex}A6wW~~Upb}IsVpN#}n%!6mIY$>pRFcO&6$UWy7(wUAK5!!LDe?INg@VVd zW^OBN7XwdmXz`E8M8_aRc;++4m&>$|T)H@ZK#wqW)dTRP=5*=9`>)>1X|;KF6-aY+ z#8cd$I7fRX+BM*NAci$`jm-e@yNY%KZQqXDnBU5NfPVL~Df9m>KB2}`i5)#C1|g}v zX>||H{$COU=!zdH7$wt6VyQ4yat2e=$Wr`%Jc6pran3n`LKu#4rb-T2U;Q&0t4-v~ zdj$c$TvE}UZY%;KjO-OUYr1^&(?p6ODZsB2DY8AI-bM@lw@R`vYk4wxAD9BV`wtbK6qWy;vLjI8-qxLQ9^*XfX6 zPa=Z=kf|6C^w8GbCVGzj+6PLSk8%~ww_<1{vN$(3bGPg*p6?q6>sDk9^a+AA*}+4a z93j1N@*+zGG^K5-N&q4i;_YftDsn*bGiIe9VvzuFa!<IPg+Q$xU6#uE1}NZQE5HtsOiv*N$?}Q^G@0K zN`I;#q0AuDj*jYQm)lARfmuIV@J__~1)JedN9iJ9#Q6>P|GIrx<-)^uPli*LYlps)~JK4Q^_en)hJ^KEPi^bJfD9 zyH3?KK#rzLE(BEdayGGUVP^&9EJ;)Ne}tNcA}7HIaXxi(7>?aGQ44u%{-##y02)2E zTqX2$7^@q%*EFwGOcIz1-C54F*3IR~?jyYTfOL_qvfnw+g09290lu+U&@~*O8mKuf}zsn7;iZwNhm0N%|dJqdvPYvDjuWx5>9kVX?Bs zoAA^~p&{Q?)qfUMAYU{|X*-Hh!Ru1wWSt^#{DG2Jti39U$@={gg$Lj_phsfTWC^(E z;#Wwa*--7p-Q9?m<`8~)vO00qDbUJ2_lLQ#|eQo^*ILQU-(BmVio4WVV z+Z326Q|1$%uo|2s=O?sPydkxM0DLA(qJEd2@5_X~g4Ka{7sue+ofXC#oL3TXXR~oQ z{v3a!(H!fUrBcSZr3iYU9&DbpiBmJd95Pi-)!2az&6(W_i%b!eAg z2NDqecBIhTXhPL2AIfeSdjao7o-6Xflon=ZZ^bjo)3^_e}SE;qQi zG}bn!4PZS5%NPrciBfCiiCrTB-IscbUD4xlEOD%xxTw=Tvf& z1&6>iQNe5hHxe{JZ_wEItM>+tz2qAuR+#ICZg87W zFWvPIzH*(m`_(5s;Bbn5A>+?KtZ*rpFs$S*z*G=$rgxeczeP;4&aiNhvO{szrJ=|I z{)ZnEE3YEc=YTLq>WctJcT|>VIQ>O*5k47eK0AS?Ygd>?WR-j>KnBz@_d>(M8QKeaVVjaagXuFpK%uIk5lRZ{($gSV=Ja@NCsqP= z?lCrmk$A9#V+YgcV1yPp$ZzH2QBE&Er&21NbPH!#XzB^m{181YP?djzW#ClTmfvqR z{Se9Ib(`wL8#_-a1LFC*^$xt6E0+&;5!Gd**>`Bdi791Wop%}p&qJ z7ct|elQLwT8IEB5x1S)7sL%B76Zt?N7T<3k#w$&UR?6BhYeTcBx2OSv67AB{&wb%F z87)=y~v+{Fd zNslt*{=Pkk@M%n?c0Rp4xm3Z!qUj_lzkF>A0-E{q-*h0hp0^xX=%){g@hX$)c0;#y`5WN zq*`qRCB0ZS?*m`n^SWh)NT!GP^HYO%57J@%^i|WLotyZTfQM@Bw(LtI-OoD0`Imw& zjq{|(%z*KcNbhSI*@>O3i7pi2&;-k$KvnXxpn2i7a8?4E9pZmx7wSM(ne|b_ZP$1= zY^5KvDc3g6qn<)&LmUp{j~dAxnxxfTUL@gFG`{JhdEfxB!Od_K1!;L>OykWraUT5L zc>Ri5n%{aCFWi1ds}K7iv4MGBWWz4~%5>)5c`c<|3F&tBK&v-WJOLZ(?hiw2?p$*c zad$gp&_VGQ=xhERnlrF{v6H{8-X7XBQhxlt!6ZS+AsY8Ab4NoIOk~-#$p2r#OKfyI z-ib|x@Xm$CO;i#Bw6I3EL+@`Q`gb(5&geKG4*rlmUk@4k({1#hO#Eg(nmtkRV4COqj#R8~jc_ zxKR~OCLYk253`vh z+0Ha)r9^UfSseEMGl6GZEKK{Vvkkqu31UCtun*z4_+)L4$k|=$(>rVr@=U{0?8Z`% z`cR^miNQ$tEDNp!d~9{K)nCqfj5jLozl^`P<{sxaRG*|J4ka6-@%N+IY)_RwF}SdN<~=Bko_ z*fcsx8p!KblN^ien_{APLKf+Z+&nCfxX*7X8d$s8-@n|n86dDCphMKd zcsM=sDU2M%%4c8VWik#gWzKze%zT^?_OfI5!<1=fQZP2H&0) zUXQ$5Ijl0&_9f;$a`1l)U0{}!JRkYxNs50G_Pz0tt4Qr+*bjbk37Ws$9AD$P2yI#j ziSn`T*OBaNEELQr=HgRm%Pre1Q2C zjJDc}%x>53;15%(8>%M=VPoX!rDh{Mjpd-2mI$)mk1ce2ns{lh1*OIyuPsdFY15LG z%^&>CA2rOAVwRXQfc%qjEasKtHixrvZcrjwlZUEi0T+C$Su%P11z9MmquWe>Ph`wp zA7Nh|-mliv)!2$YLL|Kf2PtoStdF}NQ_|=_=pmOhdd{v_JiByvO3p{l^8c!Z4dz(P z$Ln^huJL{lBBZIy;kZngS$D6!7H8D#pZX(uo&2u>hr$68w|NV8V1K8^gj zG(!LRCY`h+d7$A!d?qmw;pa1|s0Rni>qNUN`w(t4mA#UDhH4MLBB}$a6l*PI$f(Q7 zFs~qshcSFDwAx`o1=A1+`$9ryll{y0nOH6a3DS?VNLRtkz)8;EC{gtID-$p45uNSJ zu=~FW9m>Zdtiq2WQsbeR9>MO=>F%6vkrAf}O351r2pZc8LW~5ZO+2$yedi&w(2i;W zxPz~!RZtWPZi_|Uh9|b5h{i)xG(Up?DAxR~w*GMKr+huNZj9t*c@N$)a#AW_kU?#x z;!6v7qdXE%LSmQ8nY$mk);xY1Vyc!REkFSOKLEfid%06tdvc&v+wkhMR;4Yz=bv+V=e!gB+a5+WA_{5kMsk8nqx6vg@gq$ExK9Ek%6uq78*p1CW5b&ks1i<`h8?*FK7g_nB`Tn4>(se!k+xRRMR3t*mhog7d%W$DzcEv;QG9e z=G>x%Hsmpq6*uGAC=3ig(rhIFU4on4rfo%Hyo=5%bqet(a+WB_!Xx3ogdKpUz|AUu zl3GP-5AzaY>dAAV`Ux8ZXtye9#ad0JHCdrPWdhCNgAN16QJ293Hj?v==wFEOZbqhr zAi0+Ldgp+hIZ9(2+G#(tO!p}8Gy+?kiVT)`kYM7(djds2H`c@lx-S9i(bnzp7;qli z9Kzu(5t z0zCfVSq5xt!bKH&a4JfU_Oo2jr1#*!amOn+mlzls*My_M_BhKy`@9PoJRpD5b!W~+ z0E`$H-DLVs4@E{xQOc6;PQ}XrYUFb@ypS67QX>bJTGEo`QS}fD;PVHo?J{^dVCGMX z1$|Bw8p$1uP}03>S^zS0u~V$13W*gUu?asb-(Ed+HdY=C|-6vk5!NvbDE1Kc<;n5cljEHfpd;HgVJDK-B|q|;_3p~XV9O7o66 zTM6~V`FW<#4Nyt74b+I#9YLN9tVHh87ke~4`eKc+5d0;As;~<$8^;Ri?cZC$Nq~qn zskFL`gUbCsMYgV}c!-x#39sjX#^1s~CKdpd{HKDHhEEcRX+vxo*f<5?f{&aQ6@pxW z805=jWgtF8#)dQr+{n{-*ogtX(Z`^n#TxI##3^a zj!jFgwgPi44mWoSN{!NuOp$Jk8nifAA^-!E!M;X&z4nXe**qyvtUE<0wMiMrGo`Fj zl0-_9v+CCsY%*Zl|B+)3lzuSe`KjidND=Ua=Fw+x5OW*IH>nxeH-$SL8Z8M~CE}$f zU$m4#q2jsZJi~1bRc_pKuM-w}WGw1?j20R$vye(L+YD^vLvwdHP>~RN9{4s2mKV?d zUSBhojFk+I(*w!7PW1C{l^Mic_#lOluo|GP62N4fp$JdtJ7O(s%~4g9FjCg!^^kRF zyuRZu!5Q6_XW-7~bX0|irh4xfKo1vzjaATmkb2nVTarj8I*1ikJ zOyoJts|}LZGxr4p7J@q*hHFfMu^J_*oLx+b! zg28Jd8p(QWw(l%`Re>&zEQdJW>+6PSjT*6f%w{BTS}ZagyZAaCLId4N8tXMzkV-m`iWWZqRxkVJY+R_olNy= ziR{~6Ca0o3-`28-8+I9vti|IX&%d=^-vib*yd#dUFRRk2Xiw3d2TTos;Ed?D2!i6_ zp1f*}=f%aO^s`4W*3EN?(zj#As^<#J+Sc8N{oN55oiTN!u)*Oufu|`C=PslOJo)7^ zd@xu6j^qtQxlOmbkfWQE7OeN12Ht1-&|>!wZzlk>%N&}x$b8-dojCL{+?!lw!2D~O zt%Oh(=051)yW&)SGtGqob}0Caus5y?%SmmbqMB;)=W?N>?p@08^Pyy;?W~56$y8@&pI_WB07^-e_rgyWqW1F{S!GBD-zl7i_e3_9-|L8l%Zgy* z5ogq(4nPpV)MGCJCcpgiOHN_wf^}I6mLysB-Jm)K@H^M)l4YvHQWnvo#B+$sGt#Eg zb+;K5_+CJw-lUSdlMS(B-dCl}*Azc}E+_|$)VdzK~EqyST(p`44!e(PgM9X?{h7qdrL*P{-DR$Co ze+%_%j@&Ty6cp&A%1Qo)T%9o)Fl|vMbZkTevFv?XpZD2OQZkSdiffb;AbZq}8SfRv zf}VEVgM)Pa)0c9U=J4g`b6w)-4#2jT6UY27OWB#kV?|1A!8;#p#A>0KND&1kKvVkw zpj^!Lm;zl9TEDRY5%1!B83Wk*C>dUEgO*DAaxHs-QA*R2Stjnf`*t~JuYwtURobH7 ziJ1u4QqM1J0y@>{7yWZ+yhlCaX`ph?_hPWk;AsAq61ew?e{c-TT&fmOaAl zz)++4k!+3F1$I)zzhmklM0yp}Ef1CoX9g^o?P<4XJs9b^;eWw`7H2YgeKu^A(Kc2+_QDiIt5EYjz50JItm$2{3ZMGc! z<^i}BjMr-ASu7HYb*{ZBu8ZW%OuX9Z!0YF=I>9%-Z?x{5S+M#E%-2K|1@X7J(-u{^ zuO*YXX=j(FC;0G)XxqxQKIb!p+CSthuK{akmQa|=`wMqV0ecCvP|eX9({ZeQ!i$jo zULxg3zzKZ14i!TLl{P}3-I?rs#F7|F=yc%q^*_cZ4Es1UiS)scJ8nb(Kg0%q;z?b)XYbJHG9Pg)3FIsji(Gs+TB z@F#F-C9uzsMAJ7QjC`V*O@X_?B$>yT4T9>=ymQ159t`wA5>+FE4k34;zj| z;u>8sP%rt6?3-ofJg8+n$lRT;-`^nb41_bq{M*%QHlN#3UfmSeUL`o#II9C6NHA7? z9Egh51#B)(kkXW)NjQCN(1^#uk!O9;q1@Hlcg3}wI4G)s^Zu#q-1O@|UFf1Wry!FIYbeR_7ZdJcZP$FfnEQlGEPvY!=nvO%Z;<_4tvKbKk%w(H?wt&#%gsqjN zKMRu}KX9n*S&L~uaCXxg7HdA%^%4m?mN=dHR1XLd89mriuwwNQpz2a#urs=G>VJhC zGVYXFeVxUBAqXnsB;TO09TsXHD7L3bTRhwZglVz6DImA_>Hza(Epd*qDfy^kn?s9i zJpOxwX(pjWJ0J7mi4b=x*>B*xZ2X)N>zH`~JpM2)#+|G<*EG2%?Yx~p>gLge24WTz zeRTwC8Q9;KpK7I9k(q>Lnjrm|f86a`oj_jjwN;-{vDo!gq=&*@nyK2r8iZmP0rJ$q zV;p}OD52Z*n=94F`M+Hcx-B=SG<%pp>hkI- zG7xt4(~oOa+JIt?>J3^0I!T}z)H4K2x+l5W%+uGB{!GZ&hUV=Ix0IrUy=3Oj*iqKLEBm&asrzRFa-m1LT2dv&{3>OTR8-Z=NUlk<13*Q+2QO*V2+!Rmt0I?_y zk^?;5o1GYrPrvWuvASK3>ZmQ#C@b=(_05oATQV94Bxr>%n3P+6@_j!Dqrrc4crt-m zHlTX8CisFn$utFM=YH_nFkQ2R>hT$QM3r0>DcSk z0b*6WQtcA2B5%rGBG+fX&shR}V?dz=5e!P~?(0xCfpWW894db*F`>|+%wo&OVwKe# zoiA>G3+rD92LBaxp3mTq_PT6(D^jHPBg5}RW`JEcE`gUb`&@o)d~An~tC{*^xecK_ zbt<^@1YPDFh?s%REVW=7n7L;^bi`+c;l;OW&{2nhC-^o>&mv2r7@DH~zZ-BY$i7Wa z%^-`Fb45G5Uk7I85ElRR&yectjJIL0o#PRi6$7t<>z%>5=PYe9|KY;! zv`oEL{1RE`2~}s8HIM@F+y1K6HR({8e%T`Kp#F59ApU3>IuZwdf-@R+^d1|fN+A26 z+3X7^vfRkL#%GB^~?H-V#;@PM)@JVCZct~14z(S>V_7?PE=5scRf>5$)t zKA`8n;za9|P962$ntCqp9tHL)j+(HZPABeECDtjB4ku*yp9DfxYFt+xV_DLM;pMTx z;a@X3Um4^6Lqa!=y0Z$-X$-HG%>?|*>ojC&1)EYw-M@xEs;PIG6MKgYe1xn|)txHf z*?;pf)QICNjZrbqWp&-xEdIfy=}08gY=>HxriqP35uz6%k!B9sq_w)MyU0fOr@$z1 zma|!`hqBLWkS-hACm&(AJ~UfAd@tRf@;+kD2H%L#Kp>m>X0U**+094iN}lW|g(fJ~ z5Sj(Y(LEMpk)~h0qZmF!c@c^-x`qFBST2Wk{w&dsfqLg^=l0oQ=DYn@kzHtG1Gd3L z(AROcZ)WT<#M^GzlSEX}R0%LTn^AKH2HO}NqGMAf?>y=qOGj&`a-xL|3O&*Xpncv2 zd^aAVHTEjad+WBh+}`G@jthQLVE`>irw-13w@+BYYBFYyajK63Nx=tC9e0Q<6F}`a zk;xEZ8P~^}`BGZR?5fOn9?B`Q*P51a&*60s6LO|2HN#+1OGR5!X2G9r5w#O-@M?CwU7;ZrS z>qoc1M%j&4{0$4h+fMo0@C~N<6+=jb{S$~QU;0UFJqHsr^nmZ;KA`Y%h)(QTw%8R)yp1qQ+uCh&;x^dET|C)GZpcSCFeqV%S6U79BQU{-*!1H;zm^@UQ> z91a^O3NxDir^NQZ2^)IlyZ4`YK!*j22To>FMM4>N-PmX^;rugLy_;q!qR@LQex;;| zwG0_fH5Kk7-K9fsgPxvWFYAx_dxqOBnqPFYetEdn7FhJOH)?U(kt#|UhTfekB?Anoizi>RYjY&oN1459r&T?AP zd@CJ)9kQfLG=j1Ig9^ZF)jHIC0HVwIN6``xsH*pKmlk$9%L{?ck?^cS}4<7nrDifEgD4-KUaGa@lS^qahEXLclhkrAaMu+AzDpvsns^I@< zt=~Nh!Pt8i{Md~l!v@3?(W$pBQ9;9|5vPKlug{Ty$u0=b&euyE#{y!30$g$028dJ7 z|3)bmGMvXwmfgbP3k0o}G`|GHFUI1(r}7S1C$Xr`p%O0VtM zfz~VC=ej=ssSJitNV+NK2KoR%I|c}jsD#x)Y-VJ{Yoi!$*tLl!q=ex!rY>$|DpmxLi9y$F;KU2&@)s&P*qb_67aM#`gqf)z3lDLXCw0TM z6a*3GIy>=W(X9r6bCkbJSPGN?^g+BXYFcvXhY60PHp3>6vZPML#i>2a-xBNq)%2Sl z@HAQHCN3_v?K~zzR1_Qf3h;5yF=uEdR*+KSB^-=QTQrOvlAXG}HSi~Pu_PNW>1CwN zU(RNJ8~@Y+53TE{CKKa?YvZR2^y5Y)7DeCa$nq^1zd}BsFil!n5n{Z7Cj9?EMtd`D z#!SXde^^89M`dLBnUH1z(A7*E|K=ONKqw~%r?8_;_s3CL0bShrN@^G336Yw!i1-6x zpJN>&ZQdoLY_A-*krrpta zur(1!8@!-E=Q;a2@;~GZxoPJ43;zg2{TmO_N{4)iLYa1sw3w~Tgo5f++5Fbv%g+J8 z=BFfJi8d()K$Xk(r%<;r-MeLw@CRm%WX|OqQ%>@Uq0U`MA1ym;;3`27B;q@jd5!w5 z5bQoJnp&T+6kRWM#W%DaPVp;wCaJ4Myh!1_cqt|`hYokFvJ`6W&cqdz<9K1WolL6> zQYIVucnm>fE*=}4+@}ycY}CTvHuP)3b!q&?0Y>|2ya;svW3|&vKmcxC+zy8?vYC3Dz^JsEm+GU5uCmE0 zakzZ}0JaLmjg-;b*TgCziIPs$-Oeh)q!G)A{DijoU?Lc$dhm|c)C zT_JBu#E8eYJDCMsM650$nTIGxXyH?3voN8zu1|r)kU(HaG9dXi#({ie`2NZZoP&Di zYinf!>4nObWv9WRDS8{Oa$`!6U36L0605*T5w;am*G|aM< zzd%;Won}J(`76nA2Q7)WAFPX*1(p#`{yy%DW?!u6`D>s0Mb20&FI9$uefuJ7cH%PK zTIxaD`q7|UejT?8Iuk7z-G`c^VM%pMT*60KoKRlytDh+u`bE@4N{Nvw1%#LDQC7$)L3<_L?PZ4z49_`&ys~lE$E2}6 ziL&~m5VY%T)#-L%`%cqYr+fQWBj6OU%5}a84bEEgZ#}0{)DDT^hks_tHwpwL=`<>) zcF4^ygV7z*Jc<_|A2=r_92F1_ca3uV?9U(pby2;dxn+xP=>Q|Ot&AsW(>abbLeyMr z14Q{7JY8dCF57q=KIc$vR)sMwhGR8{c*-)eq^Frky8p8GRNTEg@Z*haHWCIx%!VWH zShMx{WjAzJ$Bp41ryoL0;#rzYBTPyIh#Vrmv7h=xGT%(@P@4G3*v<@UR!drY%xkN@ zQ(J|clpHTKFnp*6q8~F4OQ(*d=K~E%L*nA^Ca@ISjpaV3w7KTGTittzNdY zU)=EyH)gB6dl*yZ;`0YH-xoIXc4%N7I}{9jq~Ab2)H2-EY)q0iwBH|Axo*oNjJ9P2 zpBafBhNbnHv2t`L#iq6%kcvcd^ROmZS5({wzOEE`c_Q(2r|d@>Cp=>|`P4$xWFs+) z8JoB#YAu?clAZnVtSnax=$ZV!RPT_~uI!ifwnX%_)*SyBotp13`29qp`kTh6IA|QK z9#{ov|0IoivWefNw>lifs;)NU)0ZIU^{E|!ug|Zf25^rF;2Zg!VI%z-`8;tZo(^aX z%%oTRq)QU%lX$sSFbYW3QCH0K)S*@I`aDUL9ZXm_UUBaicQ0cmiK1?A3eZ%Dk*ch& z`RlQfVK^H1B5T;Aw2EITQrGq2!@s#9w}PxST&5>nt-sgN(qbekv)Wf1fx9&%km+X+ zwbHdnoPD`_>xe|rn?|HpNWrmofbLn@RN{OWD%eI3&5r`=z*5fSDyI_FA#zyvf{C1v zYRi4gyT-6k)7qq3 zLMlqn5dpwqj1USay*7s-~I?P>Oee*O`P^*AF?$zK$*A48PsL|4JO#a^4pU zlG&OM*wx6h&fIjXy=2r42eA_53qxSAS4@TGQ`AqGVrKpQ$qJUv7Mp$k4}od0%|2)? z@KLnb&Z=6XfbrklBaDu!8W)20q5mG*o;&;nm`YrJX0HC1N~ES3YF0&55)B5%s|(?d zkVOr~jcX)a2+bWH$UhN}$OOdw0Hzz0nwG&6ZP?{>q(mMEci#Ha3t8VeR+Y}WjUm_l zT>q>3{Dgixek0eg6k@LY>`?l;iYCw{x9`VP>KFn5u9|BU1Qcc=oj@xWFcIpjg5dRu z^P_*YhQsl6s!K|ShSM+j(x0UI_Vx}J zB!zc#2KltfNj&}G)S#uixAt%4+k^K+yA^q5AZ4gY&luzJ6_r&QAj;K(fA|oJ_;$TO zgE_WK(M2j=e5h(roADo__5G#(=J%nIne3|kx6dMCk0>@iMY(H*QX=cK!3)>u4?J}c ze91P3b6G|k;#!(N*|G-_Py0GV0_|@&VE6S9j>V{^fx)L1kD-9|$+;IGwFb)Ay4q$< z(9kny`aWkIpu6TIjGr#1AKPseibqZVoW0vPM9q4df#(-JyIQ8)+$);0^M7Go?B!^W z$ImC3=PJ?_gtuZp)dTh#6=4=n)r3*< zjeq_dTqM?(>KjSvvecaU;u96DNypB?W8++rOOHFCO!q2Q?bvpW&j>K36<9{rzZ zMxqcoLCJ1?IQ{KKkP$Z-QeJmskB?L_Hh1;?xF(T@>ut?95q#9Irk39=UhUmcrBTLe z9usL3E+Zi<~fSWJ5SH{)`!Bq&G>Y3JnKRk$bbPCF*AZ z{6Z9lN%7zqyXrZfW}v7T8K!l zlz6eog2j0W{}ih~DnO@P7QSE=$n&@`a-w;cDj%smWU?y_C-(f>^$kn!GqL00q2fVF zFzoVlwdzzk6ga&ad$avK`d-}UdAWaXGQI38bZ`e)tS*_i1gXQAUkT4mZUALe+=R`J za^`56U<01p<$0EKLTIzcjx)&4<$wa|W$1Q_Z{c07_DO_b9 zKIIo+hooNfg$;D2ThBH{uwq9HHFwBK)*G4&8N8EBykkuUDo?f*aXwZ`jla=f;ah37mspP4+W`kzMuwaO(+a_rrHypqGxS_hi=1HxC|_s_2;$JamEds}G_53}XdRr=AdM)f}O! zEFMLq5cL?(i?Mp&rRAQTr~y1lqG+0Mtjf|`d_cbR*X2s{~wLM=*8=+>FNDx(2VE7zlmW(J>{Yf>z^yPLdPX zXULOeJpEid{570M=Ob<}bs8kfc5k5_vtU7WXu9;MEBAPLDxh{!=^#ehw{@?PmLmjd zm6#CmcjhH}3Sr$pqCFDi92ED^-?e#yVA7!F5K^BVm$B5^z}mkg{g3?fixh~BWn<_t z1e5;?Han7#GEaA!9cOX%M-d=B5WY z#C7@k>~tMfOMKYen{=;XGdF>S(B5E3gu9rn~Mz{4T>c^9#$77u)kh5ko1zlRS}5lOUFZ~C&vCjF zeFnZiUX8K>7;CaywB}ZBhO5kP$c+UfM80KhCDukZiTkvKjVwxSxQcpy8*-^qBvjy_ zQh|sYoc4F9smD*H0}W@SDoPLb1zC3_AiImw+GI=S`jn>C>0C%czEt!MX(H$@LgpyE zdl!c|&S~^vHF=i?GF`XHt@PyTtd=Rzu})J050G`6vp+(XQf_FQ?fy@-uozy8tCc#e z7zG#N-l}q(5d4KEFKxlz<~Z*`m(aQw5_eD@l?ce6F&wb$tfo9kkFES~d8U5P82b|}`yq40Og)KH(*8Drke_^#hv=NRgy^!MHzP_kMUAs?)s zWR5i&2C*IRD8T|N2OdWM-S$=X4720klHQ@sav6jtH-90^vd?xbA#EK}=c7%Y9M5Mf zJ<&Wkh5?tSEo>$5P#QT0AT9;ymwIbZ*WA4TTBM&$N!M|qW(~ygq{mRs_}w=3`szYK z!nXi;+H`ZRM(*g*qVK;%;tS9@cflO%Uyo`&hb9P*j3kP zgsdzv77Z#b)WnUh(8i2HBFPEb2&ep)P^K!eMDWQVk5!~nou5@Y)B|m^vBg}crB&$C z;0iUe;(uezsZ4KnJ|A!)%+iyZx7B;hNVRfAm_(?M3ngA3I>TxSP-yv{p=l84Eq{rd^7T%}o|Nk$ny^7=peETpX7P}LY)$6eV~(J+E40^A=q=OLB7xvUqw`YJ~Xj19#995QjFy8h1ul`QfF6*XpRxNPEnh;TY+yTQO8} zBBEFIFg${SGP@2_v{8S^AZR|HD-T#UEMq?6Yv%+S!@f-S_AnWA{oScF_67f8Was}F zE67`2B1mypmgL8Uj%f2uM+2m07zB)E?y!LNv!-Ziq+wrNu^(az2&1X0x^4HG=nX)Y zNVU-eX-YRwWzbI0OSI5s4BIinn(_S4SzMAIMz8I}fSSqJ@9h!Cm9$XZ#s$Va~uF7M(XjGRP1AUi7*9qbSdXv6CXq z*3}g zql%kTv~IiuA%}RI1)`~Kbk56dnxlnVr^#QG?X@5q|JK)7d&{^EjP)(ib+mv^AD+kJ z-GVCUvVGNoBem8IwNFO!fX+y*pvp_iu!z=}^1^pnTBK39 zBE${sBG^yDK^tm%>OQekHDctPhgk%vgyYY+B#em=Zk}H@^D(PQdUV)RK^T~`o~o~P z2Z?o2yoEORQL1FptcrHU%aEwE)Q zD#|$brwDa=0Gk|I{^qCk&`Q)u8u5QiaThX+;<0)gmgE%6mSGSZEj|^&HREi@vw#!Y zM|_c$K1hTB62O5j89Pb04DQNd05a-5*tnr)Ee)E!@JeSd;KQmtn7~(JRITvZR%LTV zcglHOUr&MWKpgZn?ALt2%-@)21dHMi%r?f`dA72>rA@0X- z>SZ;16zvp|96m*D^{ilY^5lzoek4`wdd!Z~R)|h@W zuqZAt%6M+}$FdRx4%^>I|9@FGd;p7L@wP}jiAjNyvu_MFw(_@{BzIA5-!J~ho<{ng z{bbG~-et54*n?UY0^gt=f1*LtWCTTuRjqavEA2)N@9REb0d{5~)=y&0 zAv*CtQ4XJ74wWOyP9roX$jHV1kj0i@+fgV?n5=`o0?#tKt0B$R?s%|w3kn6wXtV)% z`-kdtPhGmGgDa0tAH3h8PrIjDAs-IIT50IyMo@n%M@( zkN|laZlY?|s<4!TVhU0ddDu4^S6YYbQz#QPh)UJ?1M>Hk2>S>qN2o}@*u~PjQ&pn zA0;OT6|D0P`Put*>I@2(#b{6c->yvC^WuA<>_69ZO>4CuLTx;eb6MkH*`Lyvxs!hX zwTP@U2v=88m){G5oY9HJ?2}N6NL)iY6bv~=MmX0-K)sBFx%Uk2-&H~YORRyW=1l{% zoD+L5H9NTiTt6o|ftu~g6Fc5&5aPvptN=k1E9}}6uAGCJ(ioW}4#6e0ho4?hR06RL z{2t5+b6qVB?GdWuoK+^KB>iScf%9=D-Pn9f+Z*I3#@M%<<%I42BVd3(C}4iQ2g*-+ zXG}9PYL|W#w5C7Iu??|=wO71A7yGfcjfmrDlYv`4*nyzo5%Y(qcB;|`< z@KoszE}7dMA1zJ)D1@q6`*cIGrQ&$CGtH_bbH2y2lg44T`9%s7!M^P`&|W~w!x_2`QuL&Lnt8P0n=d4thYx~em$=I^X8IQkjIJS zCJVH+RLXh&C_w|n@47xz}$QwA|gM{@3=v7soZpI1JQ6YOiK_CH*4 zIyzZ)BliHJ%-bQUHQUnkbA|2@?LfHlP((~%Kjq$5*jkL3Uu!kDN*EBCH<|TbK|A7@ ze(?mUJ$`owkqtWV4!8KtL}J1nt26}k>GT0BT?}{$6d5eV(F^jd<>5U;OizmhnH9Vs zEfBpG>bv3wr%VIOq2p)mV>B#|5X@bSWcR8)_-M=Qm8;Wft4W9l*o>_?0akO_L0=UV zZ8%FT^d;n4H}tO}=lobt7%x7^r(@bENL91m?on zD`!_8)MtTZS39Wsbn8Db+y3kA9uQedDpm>?43OX;QH5_<=^C*mA6~*Ir;lZUn%n5P7b`Dt&!9BCRPzQT~HhhPLJ(FL3aP*jxUc$akY5)8u;-4%B=j z0rlJar(`C!e!AVYTWDuod}hcMEe)p3L5jDbxaE^-vbtZ~3Zs3QEX7fXB2{FJA(;;; zJrHm%bWuc~29Uy1OQ~;JU~P1^qC6@Iir~otiPeFyCM_hVvYA)9Yd>#I@=XfIvXtQa zfSK3v=du*A>A)Lg;pr#i1)Mk$k||`kyTXPVHKE?sL%&tXe9Cv(wU3!TH;6r4+Ej)C zxIF#HqUI7a8DA+^HJ8{6DC7!oOgqiWAv^6g^78wp-_@~nm7aZ%0a5aAZs zYtiW;Z!yDICVN>t!-^-{i&mAQp_U}bKb@M8|4I0PIpKa9>jpnVv&I07<51I*zTRE3Aw;R~ z17T##xo)gectA*b}0*R9y8e#Ym7T=KMdt0ooN4muNPq+Pq0 zd0wREe+*6^wM25^sd_!pyAU4<#xv z2biB;3<=N*eH|11>H?XiiAtNfT?m-S*jks&%>a8u%TY#vw1RQ+ZSrweAwA4Zxt*;e za;%!pG(muuO7YmHC7G~vgrXbHYN*cWZ z+6tAzpMS(ShzN&&E+Dc8MI)g&r1wQiPJQ;3MrQM;>|Z3_a1KvZe$_}NT7bv=4TEE$XY1G`?8T4@kH<$LP4d0 z&iouIXe0`lnH=~9-_t13{B6WjHj`s6uiXiLN|O(}62X65o|&s1eBTZ~8x5B)J!5TC zbpZTSG#ETKiVj+MeYEYQ+@hdlI@MODgu>4(nvb_4W1S7Fndzkxu;?he{!8~WX7mvE z(>WB>IB~jk%9cwQ0tH+iJ;$a938(MUA&y=T`Ef=-S$kTpPeWd!RKaAkwceaM$F*I4 zK}dl`rKyiwY&@VFN7B-dMx9zJ?dNts=AV8r6?TBRsM51javX9Ft+=bawE2g7H;KzD z^Gka^Wocg2M)4f5`hBPS_fPB2-R|C@r>7?U>Xc?d9)0_3Zdm8-q%xQcwv!bvFYVio zZ78LR=-+8d_=gwOkng}N4`}J?uq*}3>x2v)qhAW%PA9%*e+V}gfVZ|OeNyA)U=pN# zxJ9fM2}yf3V`;oki~xVh^Dsy0oZb0spbgka8`5;<4e*|!AH8qCC`eF+7?CqGa zBR<|uS|{_`==<+G^@N89mnZCmwX5v} zrmou^6!bqi_jp4hq?4gyHv?I)j6_{aZ2oW|ft0!+B=nflSK2B6k}5vL2{ngtBOGtv zs2@v)4N54U@G{eKFJhsT(dqycRF!gjbmeOYG4TB+ki!&|{FO+VQ}y`_>;FCyDn^2h zyc6#V$y@oc&5;UFz;BiA)F5Icp4&Xa7m-J68x7NU@EqiPSeDYo@PuSI9CV?-+@13Z zI(Mi=nJ58Gw$Z;}0zzNf2gvpi4`|jf8-b~>sPC4$Ro{iYvBM?mAu~j*!S3%z2}`5T zVcu%pDiZ;(EWf1hXKaO+k*SDThOSMUr{Z>C%8Q;CfvtwZP!M%tLz-wioHqI7qkKL^ zxZ=grlk$tI1&O!nW-#IB*I{E?o3@GMY;HbmBo^8XS0Wb2;{P5oKcXqDm=89IJhbYE zGkHSUpACzX9tqp>yQ77&xfG5s)`Ukm@sNi}1uyS1>EE)(T{&e45=g!2 zozb4)WZke^<4wV(Rro)3q#)ee50r@(MFOpAAM5|F0+Oqlk}m^JPy9t%9q^6WW{n8& zx%PnuZ(-S~QEH$1UxiR;dyODB)fFAbN|I4sRD+BWqJ^QwrGX^kmF@PFnZ%{PU2$=EIGPgxHk&`_$(NKN;;zoHJOvNNl&^IN8$U&PoKND6mog;|&^L4rWXK}gt;aUus zNaR6JY>{|O$12VWx=$g4Cs610w&*B_9Ce0&>8X@4oq&sIu94m>kj2us6y=gZS7-A` z6H`;_e0UZZ#WpE#l_A~ho!G^sfKY>>kz&?ub0Ik%^f+NB0{JcG222~v8Fq>ol#WUikg!OUt^@O%cZ0Z9mPbxQ&H16oQx#mS=^EA5o7@YV~*Dvmttq zoVq%}ofq%}976#0(PA07T96KbJhoVD@F_(__)3dWgKwoBXSdVQmiVoLIAvlM!@Y-+ zzOwr<}9BZx?8a*TjtIP$0rSVtLrx%5KzwQ(X+3T(0e`Bbf9k zJwF5G%GkH;H5`Ae*2K{WRFB$E-l0>RwI|BN9Q~~l~`sWWC`KcfzN?}yH4aYqfc1U+ZVHU+{!LDI^G9@<=IhRVj#Js ziE@Hk3@w4s1o^VX(hs&4h{l^YdqF9Wo}DYm_b$>>9Ip;4p43C;Zf}+Q(fF&c;Z)p^ z4@;+$zQ-e)Qi|Mg?<0F5_dP;~{pD@wzu)QkX0975nMHAR#VLsJ4Ab2_X3gz^!fuwu zmwdyK7>m!#NiE`>0QT^__!&?y}R#=c6sW=~?3F0~#r%~MRRcO_YX-${or2R4#8 zY3Fb`m0TJ|FTu@LhOj7kAgea;4gMgXaGw{vyh$){CbsvY^>aIO6b{Pokf)f1VG-7l zjNErUcr$Insf^+c|Bau7U#2#}A)7KKfF-E)r)W0o&9Rscv?>YX9P`x6&LISjaYu?g z@g2mBhXpHgFZX4JOv^${IuuG1l|H*k$0nnb`GQz_^BAt1?LdlG=%3*t-Y+*6*_AU~ z_if=0RSLUM4AF5UyMuzYe#8T+fEJe*yHaHw%*K?l- zJ@0nCAH8xg*LYe|OOBqdD=qv^?<*8$xvB>kPmOLn zx8q|n9q!9h{BhD*{8x2R#ahCCSlS)Xvwu9#D_vUbj4bbM)|h_ie584^iiq6~U+xN<<45Pqt%vSE2vOeu@nZF?KV=)ke0E3{L zWtKn4LzVqY{PenTRx%ZgVL7i5b}VR8yK?5VM`eb%$Sm)Q7EA!W<)@g=r%~pN7dQbm z!@cef7zGypehqXaQ7@mw*jXc3v~(>dfBIg*MBOeY&{hN|xEC?L!@1;t0dTT9^%>FE zi#d_&@`R$kea#JK7Ve#jU1nAcQ=Z4aj7R(S4{5Df3h0EY0Wkf4XBTy=fK2Sh?)SE} zZKo)mp@;|sJSGTOE4y|am_RxTBf1D44~0%~=Q6tLNrnLbKLEg@Va1;ZOInmnYMAux z5iR&Yz?8m^D5!)aw{{kt#$2Ln|Ax&_|LA?kvN@uvioK^^`Rea}l%IKyT+L+cilRj1)g@vFug*fE z21ObCBv^iF+@|+lwDTe^*Z67L^EbioW6XyrkHgDzkF4R%=u9qpC$;yvzk5%T&zg4$ zAr`_B73})|7?OXW?IPhbEmlzFQ;@T$E=C-C$otoS#I5#_+zyAi0u~`Ac*-t0_2*Q? zASd%Y>4azv6LSw8uzq3ktlpDJzi`YZ!kDyg9(7O4JoHf3$!UmMxu z<|?>>HnK?5hEeVY0Pq2D(Gq{NKxCfrwdLT6%_I)RgQMg1i6d#rUAHBs;fbHDGczmH z=1s2Y5&3YgF!jj1&F+PgyLK(3m*kQr}+?F>_RvzYo|6>q|4j=3l#x!e;;=}o@JtxD`rHI!|`-4*Ni zIGE#92|SnYcbbLmnzhNAE^+X15X40^^OmUGYw4#sTRyPK76j_0!|g!Het98x@>D=C zW@QIqk_H$=;Vb&A$yqd~S&W=z-45H+`r`>)Ppe}SLAQ3>M?C zY$dW8ajFUDK+|sD>uLW)f0Nv{A<>hayCu?tEmYO`a{hI! z%~rY8$%hnv*`q2Ws9VJli^|?@^vYs*XI+z|#KrW?GR`hy2=7j2cWXkFJ78F56RKwT z72eUfoJKEix=(?)%gRRI+eqz*ooIHOojv8^f{&}kN7GTAhp9>?;S-<=oo(x@7iah6Ec_3X30 zqEf)F#BIOYu%X$aA$IY?$6i^j3vIiWNyYx84(0u>Aue-Z09Q(xX%6q!?)-bFIVbHl zzeEW?gq9Q7>ZAX0HvkQc@9%)+wztkcHl^Ef*ZGbL)yoRINxw))cuH5Uz$1IOaAc_$ z*zES24U$alfmUBLErT$&sQ?2bIlER^QDSv(0-16Cgi$aW*EXK1Z&m zHJN2Augjn0^5KXxvgRd$wyXp=$`mDtbJ9dz>E>KPn^>hG^Q;6EVz6BpTZ$g72f5#l z2)LAhrbEmIHKgJ^WL(lmKNBK@wb|EG!J|sC8rVW8%ZB`7_WM>RDr|Y+qdqa4pdkpJ zicC_>@%NWhF$#&u-R%EaQRxcQ^6|P@ehg_7HL?5H##>-&DopxW1}aZJ97kM%PE87f#U;6|rx9+!HUlhshSa~b zz6gVN*lAqpR|WQ<<9<0kRKUIp=W|X%i>mloAP2L2f7(dr9&Y~UOszqfI2_L2?iSJD<(>AA z1v>^!mMdL}miu;Jx&R{>ohpkIOHMBQ!ot1?2}^Lto+O_gR(pic2p=|ua6H!-*1D)L zsVo74{nzRS0cjW9Zo4k5IIgv;YSSWPp;5ILQLFXan`Zbovcwb^xR~e~niNo%TYtHZ zL^)g`M85MQ^dGia7~W8GN$4V;oL9H(*R+apcd(Weiu;s6!pqUuLDP!Qf9^MJatcH@ zf^)5;*Nnk2AO9Ubw5LmyO-(t;(Cg9j57K{&!|S_wD0k@;LnQSbi*es_d==Su&-n>g zAR-4b-uvIn4NcOuK~y%sObgty7#oT!@SOK37qtHM-&zKNIl-0Rtz*1PCjkb zP4&M70!#Z{4nVdctb*yrz@nnd2OUg&4%U>kq&Q$H(up;4L}z%xoK z>e0e^IOkWK z-M-!L9z5zni3K2pPH(w(xvIXAC&o0QT5x#{EYxD313Mrh<};L&vgA^WPAoMHDP#!S zA(y7fGssCGm@gO5g0eZqIZYXZnRwH_A0#zRr()MM-X!!>nqowuJ4KJJZT;ce*4v}L zki_!KVkN=<)%&nq-0qeD)ea;F35^RBxdgw%CQ8L7*%;ulwp+wN$f^)lo!_7V?0Ctk z7grK#WQN!5G*g~UiH{?tboB54*{IL$yyt&9O)t#NX7c@)qO7w3&D`B&Q;QHzPBt3# z{F5ffn`Y`MHzxetq7ID_@*D)Mq|9M7K<@`xUNt4-ZZGA`Zo4e!1zm$LWfP{=dpj)hX~cNZ*bsz7yuFhd1aI(J za5{Kc$~`z~VyT(&ag|zu?b-L1F!A%b033BBw`MI!kl&D8e`kw@rpOU9N(MDCci% zAp==ocuW{Ojf4O}3Vp!3!Ls9K&1B;@4JtmCiX;+4Q8Oq;Y-?+&ONl%@f99x-D*>Qi6v(qS8WvEsitwG-4pT~vacbQd|r zO`k{HS|%Wf^R>(+F^Ac!L6#w^TCKH)a4yT~utkp;+7Oz0+MsJii=|=8Co&BDl2su| zcr9AS#K2d##P+B1x|NYO(-@amQG~%OvQW4z5w39p`zW`Ss(;Qt`~?+XQ%jFr{$&&R zsAwt+C2p&*X^H+Qj-C>{?8}$+*vm2FBY=)$IOZ?EaA#5Lsz!k3bUR#Dpc(Xp-15%w zLf7NC6;7=uldxK9jBdwk6@!YnC6G+^oFMT>%ThuC)N(UM1agdvh()J+_)6Bnml{^N zm7sTBCnue&vX$h@R+QKsQH4uXCqTv0v0zI~b26re0z|AiCz0@ZN5U}siv?fG&ZS#W zQ`mBM6#@CY{JljqG4{G|ax7a!Q;GTF;lU&>~dTmz|h zomPdYA){KZDvrr-CD7_}G*K7RV%^PYcS`3#P)%jVc^>O^d-;NR7I9rw+R#GUa2d5qzw%;E+U;z? zLNRb?X4vq8&nO^GBWf7~iFD?@uc(7kZY1I%iMcqad`q)2Sb{=L8@t<`#?clzV`u-@ z^_&bg`)*~c;1mLmQmtsVfpj>x9JwIZ7zWYjf4Zbw$39s(WqdjS5kZt$Rb9%mt_&;G z5o8G_id%L1^v{bMF$K|P@gY7Z)W!zvfsE9}B31aIjU|{#l8b zAhy`fnR~Daw+qtSAJ_`n?adK)XnsxKN?u+hrcclv?08#!N|vg)N5DPCXP)56H^2!! zrn4WYpHvEkF+je$gETkn%3<1Ay0{|dUXRo^&D@jUlIxC)tq}T?z=$M_Tv#M&7TCo; zk$Fa60!PuhdUWuC&_q|c94YUYnl6(zl4T@Ri6arPRS7roUIC;c-j_43vX!9i!#aMpABFf-?z&-d-qwpO_!{Mp z0tSe7F=q=4A;~VXEtK|9VNPnx>W*2)h2A-TdM3!kJOvKb6D5A5Gn|kBmRo)WuNQfvR2@Qt;#l53Z{Dtq5{LInSjn+ zX>-+$(y#p>_iufocKPU97CB!o%PjVoly%yFKiFT|pa~HMm)GJ}SHxcUW;$>&t!D2< z$=qoM9-x6KtnzUzMwvc4Blm04c*410SD`bgp#Uh8JiuxW>;$F$1^A&AXbg}s1NN=g zVp)t31zHikp3a7fi*x+dC-Rq@B-?v33yTZex%0_8ojusXLK!39Iuninm4kw6mH(H| z`%Ufw^DTY}92at9e_?Jy9FW^10?m{`+JI27DqOlE>l(d6VrUEw)L-be@ZYn9wi#F0 zj(&KHKs5~h_|w5?BGSStvYD7ZHb;i$mARk7bLqj&X)(|2#B1m1AOy#Fe-I#f|9}Q} zhE$o{`~j|1-gFBZjWiSFnc4=Wh`rT=9g3hu+JJl3t``wdz;H%uta4Xx0uqrRcUjYZ z&u`D}E)@dJ9VEZ{`}X^_$HB}%R>Y$*UE|4wWGOtZ*ogD{+a2EhcMl=-VLG*pGCbrd zqnA>BKX5Xmtb>qyaW8%NijgMBpwpIE9T7-WQtEVTW`(e6joE6%?{R483B$A|92vyQ zKmFo1bUH}Z2Txaj;QU|bkl~u1;q!P)YGZo3G~bhO6t=v*1I%9$UY2ib78ur4WNm@u zo-u&;@?{TdO;DoHBp~yTTb0p{m&}FAA;X*alhr3x;{mlz?)8>9QD5{n*$G3Nbgy1S zhq(OwFNqrH4VuaT4H<1*7&!sSV>nkp*-G#lY{#-m@c?_9BIvEWzzY^29p@WJD8vc? z4~z4d5;((w6~K%xD-baKlOZ-|+`HPV;Lw|9n%=ZzewwONrPUd2wa%4PdmH1zATy{% z-Tb#a@?(tWq=PlPbz_fmY09qc#yl)AZ_Q9Wte2va9AwhJ4v+OF-9_vyWkkQpX-_S} z(ZU*jw+myM0kMvtAdUHm6CWitTYLZlIbhPI?^=yse1ifd)1VToIPtbY-vZ)Xm`#eY z!EBVL9V^IARKk0cIl{HgZzr&9yC-D~&YhOSVUS6~E8v=RkjYqtRTDuuU)8a8-DRrp z6zsjSsXM}X5U>5gV|<+@*^`1p|FP;aHx`%9vp4LQG|ODL0AXdJ{idI*c8J5c_7!Bs z!ki&2I_l@$R4#2Nk3cS{nlq5QuaJ?ogzH^CUQMJIUu}R_kyXVFe4_0P&5olv+Z3IWnvcWt1b&oyRNi|n>3KHMjDheTda6NU zSv@UOkAjKR17ydAiK0187L2i+b2tms>6;BwR?0lPt*;)BMg70BGTmO zgJ4EKVV{2_7Acq144mDwW!%uar^xu7VFV6!ajN9JHTtDo4mnxdxna4D!A*aqPfgI)6Q`9Dr)xGJ#w+&T;|2K{zYoLLetSJ{B{F(Dx>4GOGMbUhae2VTp`Nx$B zIL*@lc$`uoXZMo~&n+mHfb%4>Q-RRmbgk;8I!#1O5X5=O>%`7UTTAZmVIU2i-XLbb zx_yjn?g5~+mjE2(zecWpheo(vzbypG{PBTG5HeaE9Dy-gQ@xp}liZiP&3yt6siI3Mez2+<%7+{zVyuifDsD7J@_t0vM_6O}5R+a{&j7u8k*)|D}IM@y- zT7V!7l}-r&`|Z(>)3NG!CK)MyZ==%JclM&=s4!Rq&>cZU@P>dUOopg+wypqiCI=ZH z4@Jjy%q%t;P;5mrEbf5k74jLR>W&g8Y?P<6HP$ZCwsXRS=gCx6H$ z)YM;E<(Y|cSfk=rSQ{Yoqj+~NW%4q5!8lDgIuEvs!-f zK=M}mx&(WkRHKvice!>Bcb%#m$O?2~W3?@^34iWv>zdOiBbIgu_CFj6twq2lkPvBJ zwqCWi1Qq6`Uy$ z!P76Z9hjJKw8hYFM`I+=Q$NM1HQg><+$D&cMU>GaGN3_vR`B*1`@g^=v# z&3FHhgUTqnNs}zx%$XR#YLbs9HrRZzok9| zB5$#tDPT5Q;X%iV0z?Dq%h;2?=|n{MnR0m}cp0V%!o%qvt_<<%M-H|kPFPO66%=dP z`fSuc{Ar(GML;w1Y8(LNB@=uh!lqHD+21~Bx&=2acstychW6nyl9@&JI&MJaVMVLK zm?c+%%>FnBuy(>{TKB}C+WdnnF(yp{$huZztG2KPW-e=xS+ z6nCYQX%XZq0OP_nl+LuqciOp{5T)9f^nnysVJgi`K}wwn zCt>FtA<4tVN}pfz@rJbuKiq<}4KVdNdTJn_0WR$Dg91NY0(fR$+b%#DDKhM29_cYT z`9LMMTR#&V3puGaWKH=1%1xMdP-UPtse)dGj@VI4ATB5(WRg&h~HwKOru4VnR+=qWdmIX5d7Y_trOH% zssq>$4e|1D(Jao_Fi+@NTL&fqs#V@tYa$VEV;XSrS9Wa3di!@W3I%Izg76u8FyN>( z*f0)zv<#(S!;D%*XuSp6go^YDS?5VZHDx`J53}c9pgn{7z z^>e3?c?piiLy};S-&l&bcm#oNd-OVZRc#jd{?=EDne7VhFUDpZ%x3u68U_V04tXnP zl@g$)*$g|S@;isSqFRykxv8;KJ0S7gy>puYV3`oNNohDhF#ojTu4<)xyL2X@u*bIs znMsX+|09JuzR3;QPCHHXBzs6avnsEl%mCgI?#HONs^(Q?dW%vF-`B{Lf3Jw3$-7Kr z2j={kkc<2vAf=wJpV(D{#1j0kk-vaIb55#Jbf2^&f!yy{&;yNB?8Rh-se~$BOMsKr z;;C3O7hWS;+g*CyJ<>CcCLENKq@YUZy6MiF60l+19MTH=pQN^^#YDjh(O3dl80AV# z#?-pu0`LOu!~-rO zE6gRo#Rw3y3^n5EJSaBmW~@x>d(|)X^YX`2$>-U!^B`D-+PMUHqEejOqLcO%?HR*( z8?8>MZefX-*AG&@3qdUZpdBH0w2M|JytpBH8zDoPlE&^}sXzIoXx0>N$4v;x!vang z$oNQ@185|m)k1%6cl+4m&Hj5yT!Svo;gVv44#y}SFk3q|Tn9M-{6aXa1lnxYV( z8s{pm*-^<;v-Gpb=<|%{2}(6Yvda+=R49xeI7nr83|E1_eivZ{d8Gi7thFC)ROvoASNIA4x2G0E!69A1N!F$tdBhlNP=(VN^tL;G`A#8PoU7 z9&Gng@m}kvw5)Hp2(=-u2o3e9c$}ZK*y$K6V7%G zloPVdz(a`uoK=_#MP59SU?~l3#0BkJEV#v#eGGJ+HoOlP06ogLaO6M-J9T}9?RE4v zJH1fzxTQ$3Mi82a7`=Ey^lEO~e`v^RoT4$b1S!`O6ELNX*(JB#{=oEy%vRBM@sq?M z9b5CJQ{I$@=;k0Xpz7z>;|GYisV)bP_zc*FYS&e{E2_L0`y#??uxqi8_l6|F0^igZ z3090C%e+sY)aR%bu5$Cr7_znZ@~<62H|74u%dCDsBTBR)`LP>+c#pI5g!l$u$i5aK z{Yle`WN2z$3BaaN^y-;IHaIVF2?Z~uch&so1O@aEgdw0U++#VN z9&xu27`1nSHm5^NLj80=8#O@h=q4Nx`>Ou~VV6S7TU=L}j;Hh$kBiOgad2Lfx5-@=Gr`F7!Ec~bgQ#=(m$M<=9)^YlJ{@@99Wc70;{bfYAy_H~Z(<F*#)?-Hez_$te_JSwC!Jo9J`;WMCHWdw(;(1*lX8OL||uVXxBZdseFaAd2S zyZlHPo9TljzAp5>QR#0303#S;1gl;zfUA%$+x~O)w9&bT-~0?yX((kb!&A)&f#Acs zsPg!(MLMKEw!(rL=m-9{IwHWQpE^eHA<#q5ImWuP2R&}wUA`vBozC~6vCf%EMw!5m z8EQIPXQR@FKr-sfz~Q}CVdqk`(Xe}9QRMTFI1A`zM^mZ?DppE2IL8L2epJWw_v@0t z9Ld9+>6--T+^O>j;;}Mkg^Ul%nJ&cJWuk~G8}vM9=;@e-bHdtwqm92$ibwyn1Gr7-Fe?A$(-2?@&W19Q@{6` zI;-v=heD{t;4NL|iF}}R*t4_e`AWLwo$RF4hbj$SWwko9ugX4m3lshY?DSh9bNN+Fn zC@?)(%S|P9a8!HM$?r)-DOE_`GryJuX7;2Z0+yQ*IjP&1p!`L-i08ZxvI}E@E=(>! zIU1PF%2dM#B${PjQUylnoVv{}ZFhM!l*zR_pn+ih#lqRo-(y8V;x$L=g}5mHFs`W0pXLj;oT0YF0f9#fObUtvWM1 z=BAqneZ(O{L(GT9g2Zcva^@Kk#QM#eSXZU`>;BP1xjac!1xBNAg2#eFao&ozdAF-OU0N%E9%b%B)QA@M>|OuVdN3m$HUuKmEIy0g@2c4S z;}>K(pj}Uk6L@KA|cpJ)CL?E7JxhArqJaOfMFbEf`U5VVCeMn=9ro z&k@IUr+Qp3kDg^>a7=Pl9@?DH zo7DGD8WXN<=6@!UO8PzD#`j!%)^e^0#Ev|ZLcX;Y=cb4!_rnPU2$xbVjL0mmx>~G| z@Rh}zkVK6lMcYyJMXc8B4padb7I4@xfHI=*{*HUpU2iNe)f}1?lQG(?m;kP z^X%Vtv{>OTSY(0Rt2R!8BKAMl0FgW*b{#fK^$%N60HDf>X;caAEkSM#>jy%0L%_Em zX!SUR84>eD?VlJ%dZ2NExiZl?d`Q{cI9chgqjhW^RK^>Fv}i9zc?AW~t{TQ%k z3t>OuLdes{ZjYdBwY0Ei?ea7C;wXZm=R`JAB;oH{4@)aXQa#hK04T2eh%BE%!{KX4 zdB4e+X))FWKnuVzk1~=m6(@}kYNRbTPE#hGI-gT-#Mzkl#WQullHeCF2lAjb-t6sS z(kVcqJ%GZ+wzTGs;|QI}mO|F+s$?zFTk$tkoU1ep_^lh|?d?4G%ZG$T!A~65+D6fX z+4h3r2Ea+4Mi3>7wga|1vrx3xS!@QjP^Dm2)#h2fquBGzjjpq+TTkvY{C0PsU~)5l zg$GZ9uE89Rr$H)k5$N^$sp6e|zBTlxmI=oxGmH}(fCgzi>4ROMT|goMp6<`|Y_Ry2 zc2#pR>~N#AV87ejAvaWsA(i(shcyoI8Ri!jSV8p7Ad|!to_w0DsI}7i;UaT<3}7k4 z6!GD9IjTKP)+hq6=$JhWgm2zIR)CL+jS@)RJGr@VI$mX=6vWD;%z3FI$sFgmDSFGm z0w9!?XO`nPia_?*m~MR^pZxR9^nzaTBSADK2pTdQCtKNBzBIa9#7%!%x4ouP4_Lvt zh7T5PG>~#-c+YSsX>|}*2u$>rfBMzeU1B0c?t#r*lk_e4A-)8}`PPnV1#R@0_4u!t9UpP&8C;87YN;9FlmXUsH0)!}12eJ`zF~mm6 z?ZxboS~~Nsf=43`N<$t zhb(M@8dFx6m}A~sQH`2kqqRDcO!!E|4;TSMGiS?b-@Zovel4Z+>Y0OlDBgwq)nMhSdt$YvUjR z661bVVOh91J97XKv$5a%g?)!1?vq*u#cKOW`N7xN81P+xFvhIi@@;OZEt)vWQpLjI zISSl9Zr!hDGtQ5kltNH4q@_^`-kLsV6HJa_Ej1n$sYZa~!S3)o8%8(5X&licFNK2j zr1^{->}y%!fPLE(fBkcJp=XFVpTxH=|McZ|^DDbEA1H=X7&ZFR+nE(#k;|?Xp{7fd zk5cr2e9;N~*f(5U(PA^mCCpJ?`EkxxF=Pw(YHDo=DwPLU|F=Q8wJ((cDSm8?X=&bQ z8%{hWjM~dNo;e8p$R^;WIuZXQbPr)=6#-Pv%|50V%lKs%{oxb^d0dhEtf=>uJId-H zp53Wd;+z~!Az`RB0V+cwFqinmzj@DFd9wyyXkXanQ)W=;C`sn%2(4>21fKSTJCzL+HJ0kWrzLbnwKenTl1$3!0J`AUc^x?gd;`<(c4l__cMpZl%(m-Dv>sVA!Q z=RKsA;+JNHk;bGmU7uSADUD!OsJ$(wfbQ$l*Cx%XCV_{)h4g_cyKkLpg$QTMTFL3H z*xP?F_x~W^WX#G3!%K0*MQ&m@35aXw8`B&vf#s)Jw6f6j)axv^tDvfJJixkjM{w=2 z8pzg{-H|jXbXI_Ws&-U68e|`KA+|LutF&BV2#;|{D5Gx$?UbOpTRX6g&zQT7l`6>4 z*;;r8x5-Hiqxr$|a^jg7iC_~owC?D~J*{NV%wb<-A5vJ+s#Q;+59L_R8egJo(?6XN zrZ~h+B>^RNXf&>R9$=&S9AJuWJ?OoEq8wkb3;^z+I9bqNIjm?pK1W1uW(CwOWVD9> zK7#1LUtm5P1pyWKK;m^R1bn^xBX)+ji!W$bXhu3!8R`G45WE4fyc^cFc~GYu@Xq)f z{N=EuM|UO3)JHC_;GMz44A`x3XS!zib)>fUTZx=gx7Z-RG}>}~F>zgd)XmrzTw zW-JgBy?OX#yX23cNU_R!Y=)o|PSSqcO!WcZ%NR!!K=;6hF=4Nystj6oV4lHWmzay0 z*jym2YLVDTvC()(3f@DpCLv(J%jDwmojMY`xP*a9hGil+9< z$kC_&fwL<_uN+6z)u3)S-4J&p=wIvR>KU(UoU|9b%C=nLeUZ7gX6&e>nyZTuFWp`y z?t~6kUAagj!to9BH!wbSQRYjq9*5oZ1|1offgmISqYE$1+00ALBRUG<VyS-@&K(`^tPy`U7bz47UwL6o(5(6 zh*Hv*6ji#U9QZF_FzzdFB5~4qLs)q3z-WW$m}NyEIFuml35rL8hjQj`tfm~pq!#G? zu+X_vj86rzp7ywFA2(%jo*^-mjyyodn!rK+02v71$;vVjF2krk;tHvENWVXflP|J% z{ySYZld+Q*-n%mp6kOg2v%mwwGZMU#{@=9+IIJokO4yLRlr|a6zZU( zHpZvG-YXQ|H2!JTykQ!(TRaGRG$R@oj#i+fwaw&-)!z@N#EwwiQ^UnYL1^Z%RAO}S z?cu7c_=!ahOZbi?g||cUTC~l7O@zw+#_L0nJ&dWfJ%dO}&m4%f`*H0E-KT`^!^}Kx za<*PBbssbc*kDOPo-S-f`Ok$8!C6ez@D*vdq~%X*9Z1(n{gDx}54@(Vf&MO1w-9~; zJY{6r%?uZ6Im@z}z378#>{)X)~EH@rX@#- z9>lxG?}5|Xy57N;H7^HnA1<)&x8 z(eZ!RU;tS?!5=|!Tir8aYE|?Vs5iYNDO)XiJ*`DN>&H0vL25FqFStWQEM1j`C2>Qo z)zWL$o25s1wrSoB-pMb6PC)-zWB(_u&`R!41iLW#L#_GciqHU55y z7xT7^;uxw*CrtNwwAt`C41YQRB^KK`R9DX+g%3JE7<{sA>abR1U)~qRYe;L3ld{GD zz`r7hfTCU`O#RC|{+^~pzS>CKzdMh9<7k+v_0IxveX`$;#1=vma+pZGd9dH!#5iFNoMH+1&{z#4I zaKBojH^=GOHrx>Z)tuxZAA&@{bXF>SL0Ge)zlUVN&YW4S53O(!+!*bpSYJ zLFw^waK+v#pofa8nkH(ViL>br!1ltY9-}y(ae=X!-z>NN8X3TE91Osa=3TV@$i$-{ zqnyXodmSY<$1S8{g#nPI^E3DB1nR%K)8`eMBvS>xm49C5QuY#;(vX7L3ya8Ko3<6U zZKJPog<#stpRZL^WpvvRs{;z307l})JaxCv!=?iNY zew5Uh%OI?9hBmHpIM#lNH_N}Tmc1V8Zyz*!9T=vmfs)E^7G?6%H>r2^8<7I5-)8+x zla%Y{WNp8Rf5Jx{T7{z6?R)Z`ryG4$`;gDNSz}QyV@a}MWyZklwJv4{KkfS5a4>up zWIthdECt3a8XBD0Q&|#%DJMLP&-}hcudle4PQ`+Pk-SPVN{nRSv?6bK!n+PCoJ%z@DpHyx}0 z$P4MjqWw!sZY0U450KAYkKuXV1T7~Tzw$2^6I?AcG}@#h6g1rYRYum)aPw0WTH}>9 zz$-MDRAWn7k$8KnncvDC

nDrMQdtMn#B}u4#d&HqhcISy+9ny`E%0N-pu}OXaeC z*iJK+{LB-W4v0Myj_`%`Y~AP+%%_o2RgM*w==|_kFRx1G?DGB$ET=C$la;CJRM@_V z1PT}bqrrsk-(*SHY1L_^StKKz#@^EbJTmL-u=L6ZE@H=P2-60$MSckV9Yp^pJqv24 zr?d%zfQcQ0h{)-rucq*>K*xuh5TreZMy7D_+v@RKv5Q7fLEML<;u;r~*x>2W1?+B? zE?-aGfNDfoXZJCg!|uY80W#L&GMBDwf2PMPR>KG{Aqr_&jRVhS!a>{9+9Xf~culI} zm+LBJyq7{tuB>w@6rmUFi1x%TAJ!(OwFj`t_!(yw3emUk;KLNa49sIS{)-8f6|~Bh zC&0V;^;6uFrXMyF08u@3`6@BGhTz!uJ{TRAXG@*Z5jIp;YKnRj&A_fJ%(ZLwsFBV2 z=1kTQY{%Dp@d|r!-=!iq(bfA`V%|Hmgj;2KS^MVv>c7m9*FHU6Cn2Rx!8?7Zz~~XL zv4-W8brL^ZZ6l4fGGkEzvF}=zQCs}Y15F(=r#NQwRvW_ES(fU+U%qoxfJmWHh#_ZzTZ{JQzNhvqE`QLBcp4c zI}ru5=p;mMPF|!MNIU{SFF~jZ;?0Ca;p(na37uof`hxUdUW45Sx(7RlJ*MM-MYJ&M zEhoVeCWV&7T{6gw)+c+62yfDi9f7!rVPjh9aUyY~J3-+^m}ZtYUvHprRa&+X;8A&d z;>f9{bD=fEpZU?J?^=rY-Ja@-?!vBUq+hV?P*)ug^cdPlZX7(TKSBx%X3Ep@>Zo2kWCggr!pe#KVoW2Fi(tuF?hIlP>`q zH3`K#WCjhnS;v&e7{j{=g!)UtB>iz7cd4$o6IJn}Z)Vh?N_m`%TTS0b2tq)8=iq0%-@VDpDun>5xZKc0J<(a)qrNOy&Uu3e#dN(kBsx^NIhG{-$S znf>lBm{z)Sg2wraYI5C&MO8i(2NO7#eCtTz6HEO*h9bNI4y;FIj$N^>rrZWv0Aj1Q z01LFG`%K=>a_)44!uN;b!W5OSj)mT^IGPW7c-g{bJx7GD2Tfq47YHR?O3m5596@`4 zGfd_z8)<1x6Pz!wzZivGkQn8+*hN1C!Iu8;f5jn;aO35jG;-ckyw+SrthPt+N0eok zn|(j?1UtyeoHLzbpO_pP+&LX34{8DtyCregs&I+a>-+zp1^Xy{pBx28x9P&4EDU@0 zU_p=paEKe#5>SSSw9|%6e?06DPOx%GB+td@-z{^#rX$5yo}Nuo=+T9!9rw`6E70`O zUQ_bo(k-Hoh%j_E(9q-7Cvp!;)tmLywTm7##N5Ud1qqotdAnl)GW^USdQ#>El4kPcuePrwx@*2B1?Z^4wAk_Iv#%3^`olv9(wbqN?;jrjG(|WAyH&Ic=qrEq?YUi*T)&ycmPU`E zJ+j@Tc0kwn@3LWe)gt8DjcSuTKoqf{R`$!(qHaHm%#I#mLilt8_E6&2J--~rR3s?x zwN2w}FFvlTi}rxS81I!541jD~+6(^kNYe>Ipu3ASX-Re`19wEYxD<+=+st21zpWSH zeqMa{ za|mJ)J6(VDx7q(rM$EgW?T&?XN?~6-Z<(h|k&JQ7amg!G}awM#~IO5*>3s zdz*i9+m-q!xhx(q*#85g@S2NnYy5JC8#M|w?E^3{9(Yu_$ZtPuxj>845^fv(V-N8WR8n+zJss%pId2p zX^`z46@J7Ejv6{*vtFrb=k+Qnd4kuwaWLE0Ma>x-QyWOk-Ht)&AVevrVX1e6{w-s) z1Y3Rdn&ln9o5HXag*bU@9c~-1{EHf6RDPizugykl2E0R#KHYOcuOyMk3S%jMO$`Q} zVjB*&V%AsrtH&DB_B)vxDiP<{t6b;VEAmhtT2OuIdF#ftgLYiTWU*L3s>lhd<`ino zdcAf_r%~XalQB&0c%m1yY8XgasRqXvTvJDZ>Wod3*asIdc zNPY`RG*9U+j*Wn=8PTSqtN{yC)07foU=s3K7R_ z`3k-B2YJi_C5q@1a8!7~1A|5d9dwPz>TJCK^nDX+^uCM6WH-$B4!sf@#t67w+ z0OuDY3IOiDT4$NgK}ztkggz1z*9DI$r*$($@aw{o8-MN|R{*|m^PzT|ra9(F`b$>Y zO$`Tn$KKf_;t_bNW6y%X9F4Vy{gIO*iFRWl6p>#slM?S>>E%@DPB#=!Dx20KG-|&m zLU68m?x0cMmLE*ug~W!RKNH{^WRht1Tm58TOJHJRd8-PJU^dQ0HHYli#F>O*5)vQA z?_|!*yI$Qfm>wH}>bK3cBWpAWA94~SyG(^)ZYGmij5#BWwLq0opcshFv;Knp5-N0r zXgDqFeR$+RC<|0YY2($6e`}OkXX$Mj|53Sw=?__AM_*HfzGk?2=^LV~-)aatzxiYg zIVe6z$gXy1`HpFjh+5&b*l_j9J{{b~>N&08k{~^vDxZ^bQh6fBgS!J-p4ZB9AN31* zXHaYbNt&Vf(vpEMNCyEEkBS1+8Fp3br_1-9>UghjX_s_6%ie1gHho?`dBXGxr<#5B37V)zSxHEl${VLz?SaS{3K?v=i;s z*>L55(}Z^_lJ4Tuj^h1ux+=Hkl_ z`GdohTeM7I7ED?2zs{=}q#=j`Ns(b+lfK77Bw#LZ-Dr`XXql0jJKjfB7qb-FdE<=R z`sE)Bdb+eTLvqlZ0c-TAWy1X4K#&`%IEtFLYCQ`{$r~>%@X=}_CLgx|smW>2Kc&iH zuuq8C@?=bTr8t71Ia$dBuUj%Rnxtk`fhF1VL=zVgFqj}SQl9=6yX_vvxQtKR`+bac z9xk5AG=DNHNt-ugeqU>DYAggmOm=c$mcA5uNsi~;J8xh3ahrE}=5PT2KLEhNDTl9eHu-^W+fj`@Gq|2sqC9_~5kTAB6@-sDzKZ(Bl!9 zDy?n1|JoPN1+2=}azh1t@swSdTY5tYV)r>8y%>TH=U%mj=17 zhplaA)R4Y2c1(EP3*9w25V`b4;yICN2Yjh=TMGffb)_%NTL!RB*=mWJ$o*!(95&V4 zpqHMSHrd(#xVw-;fK@{_=qw^|-CrIqyL^If9};k_wKm64CU_%^YWPJAI4KMRx_7DL z!mDWAB=sB~bWQ)`9XFqt;;putZsx3kSET^mXoZ$-nF{su*+0KYCx(2mM#B7_H;e>Iu;jsUY4N)f$lLN=EqfBfAn*}Lgozqc^V?Rh zAiL#`K#9RJFzAc~U&0X^0*M}nh@z<^qQ*LnPLE4lUW|Er`Xb9bgHz4ql>d>h`$;6! z5D8Lg^|z)zJ5o*SF9q7%u)QQfj`Rbsq%VM;sO+-9r@InP(~b*+=u(n|*Pl2<2%&<0G4cLK1ctM&VKOd2uhw;4fa@}%e&@rxcPdLNqvfN@;b8rQ&~-|kxR@v zXX8!#k<+O!iW;%Xr}@y@4qJZKk%A7|DWX7bB`wLOWD{blfKU}Vw>_&s+C)bR*IVQ} zk2r`avPq9#8WN-FK&xn$O9#wqJ>FLn8 z+n0+H?;9@7zk#%f_>GMB5z*=KRRfVyp_#`K#xqzCV&NGxDesblMF0%a}BnwqNM+cQEh1R9H@$s|7G&(VSgO-*N?kR?D3XZ~SmkG%35z z&g;ddv@ET5NlvaK9g(Q&EL{QDUkFSE*x%F)Jz~~nFiZSCWLmHm%MwuiuBi78w z{@r*2^WXBtuJaOnVi=<;+073T+O%2|XRGEmH-A0uwf1f_fxR~fbNMBdN>hn50lBvi z?m(LTiv)~m-BTAPKIXpcLqKh>J@PkQ#S5rmCYaiJ00=MG-bdkz&W#U&rUMRa>LX!OL( z`8rI^oB`?)d=(g!%A##~wG7vAftwHpJ)wJqROB~Au?%Pjeykr?)YxghiKjd=Qn9&^ z1nb;CK6OkVZUxBQ$VSbAWIqo0Zb;suf`g&2(Rmy5F~yU0(F+kjvUK*KBUlSRoxy$f zJE?8`WZtwqXt3rkW8**fStFkl$V@J=M7t6~>pbsSkif{d_s)0GDhUZjds|#B)qQ>L zSVedMvPpMK;Wo2ZGRYx#{}Trnm~);I2*UEr#(f3<)lGbVa1a!(mP!Qx(?OFy7@u~l zH!cm1tGUJdgqWkTn1?{1&RpRtX*Um~-w0Y0qX zMw>;Md*T@%sn0AxA-trOj(>Bz*Hr4)tFy)J^-8NTpJN-NG4WH=Vc8R;zlR_7U(6x| zhkHwFW}+Ratnax-smo{q$IXwzMF^ZxQ>odKPLCdPCZ~4aIj54AF@!rQ6KnQ;7Lj$J z3p8ng&puFnB`4In#Ml{PIaoDa$tDbhspHQU)uW}Ke@US{zR|$ zdu<`bZB2b_TkVe;3u=<$Rsa$~Q3IZ@PHP}QllanQH=U9`xxd7(k5rma|5{E*!OFgR zfe`ox@QCERAfa=kuQd|2BV&r%M}C8~`mbqmmRzBw_6QO#CRWhdA5Ch(4TdNQIachW z3KMJ>Ufr2p@YN`l>3c3-7~p8N;aN0B$xQ1(YaP-c#()P2k3vAp5ng2-p@8wNlRVO7 zC+4VB*f^mWw~LrG-p~(29vOnKRIlG8*e>51ZJvBpFFv5#5CjvD8}|`MP)+9BsrmbB zZwEM<)YJ~<#;(zV&0bGRDDA*)B&Kg2h{0NSf;$@7)O_IY&1eWcY%iHqg=1rymVw!79I zPaeNPI@r{h)hH+9=|ovT6-YgeeG>B%4fk45NtS@GEnkgW)YyZL;T~NHXhJql(=u>} zxSDsyMycm-=~b*_HrcHboXzUHs?!HXGO|UIaS-(BWH6VaqwGaPnn!6#6HoFCP{o2m zr(D6N+?B^JosEgPE()S`m3@l$o#B`R8F=&ekjfTtWm6I&O_e^YlNynKCfk*ykS zj1qF0E8hvAl6D_un(=3ll91=6pHeZ)QZVXXY{PWPXMtkpKW8t4SWVYqvrI^(u^$); z@@-!@575rtXwpwsvpHnqSf~Co@0*CTV#7=1E0L!m0>Ur%HbbE9@0^r%lH(=I?3(j* zf_(}M8r#3t3!l#Z>Oe$+-lx@CDab^aRx_>|e+{CKW5xjit}@A9gbXdH4(j?;&~a&S z4fkMc?asW0Un_mnZF?xFi+zt$L7;nd<8y53H%#G%FH=yOE+_WGxC?!$@*1_SZ&#>F zTJL=_FSc9^n`7yBupf@CVGug7Ioeq<$tKUHSP5!)x_wayCRVFM$XEmmH`x3_LB_== z5Hcz~*9dp3;zo%z1W^9FiULtqiaV|3a%B~5Hy8qjs z(~TXGy|%;IMA7N+_@?fj2iKLG$mrI`c~60;-Y!z;rar6kM$P0RmRL;EFH4-%VlyVm z#+WqBoeUBmGROE+yzv%%d?MCIwL$)Bcm{7dTM+lbK&bz z?PLpH-uJ_RM8ss$sGS~>>m-lTlqPpxEXbXC>jo7IlnPpaHUbOOM8buQw$l1^$PM#Fj;Powh^ZBU=zF`Vw_KhcX=OtDy!vV zAIO2g%>T=^sy)peBxc6L+)QFKZ^Wb2s2_Gw)sN`)t5;l=2&~e0*3J6G{AgE}yCuJc z82YGwDD{!{&enZ;djlI=aW}a*F>(zMaSsH|0OoX@MRnc@#QmR5Fe;|>`F<~uAGF-^ zsH(DFJM5rA%6c#tIN5B-$p2=9M5r0`x!C`jDY5V9Ek^Z25a|8qn0!w@!d_s50jiTQt`UAv+ zGR)VpJdCyJI)*nwG_mCI-_~77O;WHM<1^_++=G^zzbJuMOi>#Y_+9i!$YI-6xSbB} zjby(jw`*XSL>*#YP<(~&vljh+g1;C8ZHKI1FJ{JLW(X{macElOv3by(x^l`Wf19wAAHgC(5s|Ey z;jI6PPi4tduzh=|60P~#4`s9t2Kms6xd>*}bCJaelY$vpeKYw-jVz6h?{HlvkvP{n z-TEc_3y6$C3>=v8qO}qq+c3N}b{Qxb!66}mhQ$Xz5HMsH2*DO8;dUKn3><8WpZ!PE zr#uJ{`-$35{ObsZqHSEe+|9B+oi81^X6gYOxAgq*@_;XkrnLxm4L2n5N28v#^A*mo z^6bCDAN{5F(4=%r@@Pou0%+A|aKWbSg<-wv*#D z+-ATY-l9np4j<^(BsaLd-K2Hwp zl*e)Y1J*mugx@K4O87k&1~wIbl-cM^0%{H9ZznJ(A5jEpO?6a23=?wZZd)Yr{#1`f z9fu~;8>{>$t#X(tf}R^Dplyh9+;Cwg1w`$vfpHql_Ab3(CE=cMXsLxQ36=d(aGj3K z>i1P3t2H6p%ilggkD_a&1ZnAc@BD0u3tC{^n`(H&s9Zr$z!We+Fxwjm-$nc<2BQI* zgxQB9jcVY$eLS55zZELZF6S677O>~j$62-r~F$?m!a+0bIfU^kN}`eE3lW7 z#OxQ`6jk{T00vp8?jk~8Yo7L!4d~$HwNIp)SN@P_M+uSZAYy}%wZS1kn-kIE6shrxg*Si@*duNeDo_$PTdhj zm-2Jwn(l3C?yy9ls`XU3vMinA7`0u$L?-iRWdisnsxQ+{^}n7rElw6_Kv?Yh_Y%fE zYnXOj88&e0Sn2wFu=jp+k?J`jX&49q*PJr~9VN~`Y`GDPy}v}eMG(==gg&6%s&^Y* zL9ohtHxJh_ze_mMS&{A`c-^xmoS_UINm&SLEV14w-J+w(zQ#9|4Y;uVQHzB-fe|M! zQGQ+K`Ytgf^2BjV72-1HX|*yzm8oeDNkk5y?mHi@7l8bM@=))y;lYj=^HrCYKWU6U z9y5$T-`yFczPQ?%1m?2J;Nd%_W-BE*1%b5#^AO)p8HG@GwB;uB1A=Lti)R12#tlhS zGKAn?B`OI8!VxVZ@zFS&s5UNyC@GaP_L%D_2L#>Qe-~Rzj<@OVIb$4sLl)&^_JHdt z3E6_#7pbf)Z-Sw4?}IFL^8z&^CqDAdTvzmOKg*xU*>U>x( z^vR0ECP|r|r+)s(7PG>*{`YNXcyB#+s;5W?XH;z|015y@VD1I(&QQLmu*`y3nB}<$ znj;4GH{%!J$Z!F4ZQ=!WD3_Wsm4^!DFY3fJ=}>9WIJ!a1_ZylCmSN;pt)$RMVAz>Q ze4o(ooOYL4DsZX`<7LD-lhfrM`XI);QyZy`axh3_1m1XF$F8WKIbZOcUhlg5V&*k; z7$Lzl^*X>105@VAm>BaTsS#YIb%*Qr8-MTxFOH~F7-7c4K*{a<<3l}(;Sbws3PA=Q zyD~Eh!jbGO63h-L$&BTHdlr7C)E{ENQby04qEZ-kswQ9dV+(-YCO_oK1WPDJ#2m<6 zWp}B?5IzJwP08}#_bcZ4qT0*>#tX)C<_@v(=lgrv#=lom%NuFDo`}wtPd7-ju%w=?DyMH zse=7iM@AxurmDK%-$Yh^775IMXR?z2JEM@Z=O!ojI4~M;LaJgjfuU)J3~P>|gEr_w zZJ8<0nVlR_!K;Y+j~P`czsX#%lL7n^IyYlW{-%f?Lpavb_ojdFzLxNZy6+d*y6M2; z!YTU7PzC^-`@}*4o*GG;CYE3^dCrV_P0r8djM2SsBfOWYvq>1wJ8H6AcafLytuOXRwoXlD z%&9$}I`bRA=QyBK%EHv$SDObwK<*z)5B?u=*^=EK2k2PeV!y%%_vPrt0O6&VBbJIo zoyDeXuZI_}kpY2o+P&zR;c%zFsq$%0>efV z_Qxv2IiYU}_Y|Vru1xFnx$Z&OYy2~I%1kT|<$1}kUPX z%xLKEOgLYFxYDu=*+M0aZfF_t&houVq_?Gq3VfVF+!<-(d5J7)Sn!pH6?lAX45%b+BAtm}l5BK@13QF8>l zm~AHbYy34yRflsq92n+r?W5&w_$`dLR}e%1aO%3JP+=dji;T;>Y7#U(DDO>3V110`AP3MC-c?+XY-1Bs1HLEPhLn#s%uhtgqcX{y=vd8DPVa6_CGdK9H;*vPP35^R(=#8XWQaV5!7%w{iy)rY;=#mNe0<4TK^ zk}@Bb%9nfT?_zFbU2byS^3(>O@GudZZSRxRqRbJ+MvL(a9r&kA31&Gib4x_b<1#Tu z@=4`$m35enz16s}NhDKgbG(v;;O>T%FukKYu}!+weUB25477G|>2lDIn50A-KzHnc z#NpEO@7^+uO-DWXoSHQuMmD&JAH-SBPpC;wfTp0CDF5Mq!qFaN_yL5ke7TCQn&!SZ zjPB(*EhlsRcIs#l=W+|MHJtJlW9$)}rs4!Z6M@%#NM)7&#!BZ&oqP(k4X~#!wb)N#Xx%ezx)DMB`ZH@cyO&pBNCO*Er?4``n!4{>vs2(#8yGN)sNz`k8?2CYWlivsVvr%z{~U zTdgrrHUYW9jPJw^!&i_7GSCKLX)&brB~4U~v=x-BP-;q#(y9v=;vSDr+h!GEJ3d{D z3$OdUiTzEQPM{Q0G?a&;7RhXYg?ne*P>Yp2BJunu`fWvLdh*C%Wj0^k1?hnRbeC>s z!n1<5PnL$wPqyvtsYxW%Ndz%BL8hC3HBb z2LJqWdXCpLv?XRG*#T)+kLf$yU^i#l%LmHxq)1lvbyy5eW!2L9x7x?LnxuFVMuZBM zz$|`3N|ouqicD-a>V$FTh6Thk+^QO z2yq}^B27}gRoto^CdJGZ`@+bfGt*CiW2Kz+m=4y%c%1FaP)oN*lWYnuV?}{*nvN+G zaHf`w9~eX}Pz@ zF#27GWCX*-zr;)f>{^XRDWF!`nB>d|l>5dvZS!b4u;C3xhw)3d-iv44HraQob;^y;z#sly^R(QYTL*AX9> zT2K?#vYR7Ymm(ByoU*MHYwOwu%iK(OZ{B5u*GTHld2$`+8yo%9!%LG|fA!ZLS&CcyL#23m3^ZYynrQ&OXzFZ)RO&l+9;@|kkJ5@k|l z8lJss?;MiXuB8Fz(6?mZ25=i4*urGAQ*yXzEB@d$`u+L^tpyZs1qX1bFuH34Zo$zW z)|LWPupuX4$@d_Y85@NZ8(XMCeXdZ@m^j^n8OgMI-G5|hx+Z&r6gm`{W=S$%_ zeeGmqtf%FMjuJ&qlbY<^5Q}F-Xxp=QJH#pBtL-e;LAG#)KZsBuU}TYbrwEQ2KpLtB zdnh!uQ2Q@P?cd`*Vc=f)K+?1(e>TpkdE0&1&#FOqs0rNKZX^cz2Az%wLDUeR_!zxoIBChUlGLHimr%kUi?f;itRrQluo2nBBh5u zy~SK(}et{R6$`u9p_1e#$jDS19*w+?Th;()6OkR2yLVM3v1erM~w zB#r~Y3P<%4rdmQo->ZbQI#gYbAXB3@1Z-0ViXVg?53PI~j?Nm5SAG^@?>t~;#yLRB^>RtE`?**b zsYS+{It4x0#u}&?$YU1pras4w0)f2lgAplqGF|z^hU`Ap>0@A$qunu%#)$3=Q9FX2 z>2c?Bi(%q|4p1bmhVb#111x_#^ZN~+yjQ#jrj)_`h`#)Uxs}A`9CU%?o|5IIkVfQe zlg*f2YO!C{G=p-aEABbngjJE!vvT7p_oF6DyX6z5;C8H-f}%7z(PiLx@ICEBED1_! zQERUZdt8hNh_U)Z)i~d40me2&Y7VUA9C2GJd6qLPRWkSeO>+;dZXe_wt9D30eHXQO zda6Itfc{&#tdjDC6&Wb0NOye)TMyz$nxe<_`pbDlRuG&<|2PDm0bmN0(4eiZBU#rwJ&YrGmc zcJVvcST3{YdRstD+wo%3rS)H$EUH!%!n-1_DX0(=SRF|NVf@&fCOUQ2Dq9vzM3 z{*731kCt=dIcruI2<9#}vF$$!ef+ha$uP7V z9{sIr?pL^Ipzq9SGW<7G6Xuo4)^-Sbq!hs6f%T#%u&1xv;lMi%xaync=wH2Uuc%~n zr8WC}8%)8(tv#d)0tx_{8@`9yVSSt!2eM;x^v=e$eg^>alpt&jER6lqoO>iZFWXi3 zlSjn#yRm+5MRd}I@O#|~DMx4Vm81G&4MGUM@rOO7n9^)@!S2;ghxUS*?P%Uf;1~#a z-&7M1VRo`SB%4%WB0nen(k83+j8eHA>;>K5y-_*Sh8}$IeC2ar9V#VOg$(Z2$s47r|!+Zt^f4<7(nQ z@8#;H)W1vUXwj(+fkJr32xs%`GmD%h0Ha_KfkBzso7>YACYL$R*|> zDbQ7l{j)5I7`jkdu-W7dI6)~S-W9-v#f8aHY$I)Q!zsvVMK^Y}l}LncFYx zP>K8}-c;*v?2I^VGr~O)BmDt=zsfZ)@Nj2scu+mAgo=N_)JQ!|nwOMw18a}h&Iu9t z8nXz|9CFz+O8o^=Hp=hgc|Z=giL*()U`1A7tjrkyfVn$%MQt9K%Aj;~y1ZmPX~{J% z+Wm{)qt{<5RE^#6&34WT>m1+;h0T0O$iX*~w%GDxdT{b79o-_15|^C+I?e)(-)SCM zJD9_Y+3E<3tQL*eJ@rq>)e-qBuj5T?gv@j(oMJxQvwv)v7Lh2#7#<^159$A+5Ndk0 z$>;{y`zJ$Rm-~wsObqEKhYh*3KBK?UMH@Krl{>$xyX-9tmBd5AGRIl_wo$AENg#IU zWvuxr6t<8f#iJlEAH~G7isicP#nDMQ&;5Pf=h-JpiU2?Rb8aN3zJ~x>k&g^ zD^td13?hd1NL+1@&F+m~7XlXn0Ypx7Tf;sb4h4GeZ~f?a1DQHp&}ak1a=Y8P49<3C z5IgTUipBM@jR5?96JKUPyTWbMv^1zT`kDR;L zJMspUHZl{gGey{k;uOX26Fw(2*<`{ai3we(;Il>Ij)+OAUtAiog2`3nX*@<}W33-C zlcUajIA2qdp%gMWs0y5eN4gbwqvL%fD%Tvw%SRk@iv_$2xJLuW)1Zwc#DSRs?2d z|8i&)NAXIwGyvc^u6|<(DlIb5f}6bGpb1;4uuq*~6)i4s;aH>9*E7Tyz85u^`Ifq! zpR&vy)Wl8|O)h@?;A3i!xV}k+k)ga13jw8C9LLghQ6R1@zFvc0!8jG=arc=^>Mq2tHm9Kg8(A4uQ5VCDr3ztEJ7} zba{FEN>h68p%u_zmQ>{^J07r?!Kvx>NK^E8n%Ek1-8e#qL}a0Po7~)arXT0o6KKkD zmVvH2YUh7py_0u%K7C(zVZzxTTRN_b@vWsD{(7F6sWo}_f#NkJM^YinY8Efb7&#yx z7+-}0k)`*6uQ&^JC`?-3h!n@8$tv|b|GBv{yK}s!xp{PfeL)d>Kn=ptnc6SblA2Sl z>DU&9PB!R{a%1r$4UP`vTi%I-NKW&g35vp`m1Fuq1T#d@^w-#C%{Zh%FC~oNYZw4= zyD6=+-ITu)R?^YbB3NHwAnVX4JE0Mf_znPO+=dR z&+FdmZ8KE=!;Vlb9ki*KnwYxNTo7c|#3nBz^Et4(C-L6#%3t*6-9s%RO?v;L0%0Av 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 50) do={\r\ + \n # after 50 * 0.1s delays, it's been 5 seconds, which should \ + be long enough\r\ + \n :set errorMsg \"New folder could not be created at \$newFold\ + er\";\r\ + \n :log error \"mkdir: \$errorMsg\"\r\ + \n :error \$errorMsg\r\ + \n }\r\ + \n :delay 0.1s;\r\ + \n :set count (\$count + 1);\r\ + \n }\r\ + \n\r\ + \n :return \$newFolder;\r\ + \n}\r\ + \n\r\ + \n:log info \"Created function \\\$mkdir\"\r\ + \n" +add comment="Certificates CloudFlare, Quad9 " dont-require-permissions=no \ + name=Update-Certificates owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \_CloudFlare\r\ + \n/tool/fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalRo\ + otCA.crt.pem;\r\ + \n/certificate/import file-name=DigiCertGlobalRootCA.crt.pem passphrase=\"\ + \";\r\ + \n/tool/ fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalG\ + 2TLSRSASHA2562020CA1-1.crt.pem;\r\ + \n/certificate/import file-name=DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt.\ + pem passphrase=\"\";\r\ + \n# Quad9\r\ + \n/tool/fetch mode=https url=\"https://cacerts.digicert.com/DigiCertGlobal\ + G3TLSECCSHA3842020CA1-1.crt.pem\"\r\ + \n/certificate/import file-name=DigiCertGlobalG3TLSECCSHA3842020CA1-1.crt.\ + pem passphrase=\"\";\r\ + \n\r\ + \n#:global AmScriptsUrl;\r\ + \n#google\r\ + \n#:local CertName \"GTS-Root-R1.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"GTS-Root-R4.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"GTS-Root-RX.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#internet\r\ + \n#:set CertName \"ISRG-Root-X1.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"ISRG-Root-X2.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n#:set CertName \"Starfield-Root-Certificate-Authority-G2.pem\";\r\ + \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ + \r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n\r\ + \n#/ip/dns/set allow-remote-requests=yes doh-max-concurrent-queries=100 do\ + h-max-server-connections=20 use-doh-server=https://security.cloudflare-dns\ + .com/dns-query verify-doh-cert=yes;\r\ + \n#/ip/dns/static remove [find where address=1.1.1.1];\r\ + \n#/ip/dns/static add address=1.1.1.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 1\";\r\ + \n#/ip/dns/static remove [find where address=1.0.0.1];\r\ + \n#/ip/dns/static add address=1.0.0.1 name=security.cloudflare-dns.com com\ + ment=\"cloudflare-dns IPv4 2\"\r\ + \n#/ip dns static add address=2606:4700:4700::1111 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip dns static add address=2606:4700:4700::1001 name=security.cloudflar\ + e-dns.com type=AAAA\r\ + \n#/ip/dns set servers=\"1.0.0.1, 8.8.4.4\";\r\ + \n#/ip/dns set servers=\"\";" +add dont-require-permissions=no name=script1 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + tool/netwatch/add comment=\"doh-fallback, doh-url=https://security.cloudfl\ + are-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Clou\ + dFlare-doh IPv4 1\" host=1.1.1.1;\r\ + \n/tool/netwatch/add comment=\"doh, doh-url=https://security.cloudflare-dn\ + s.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=CloudFlare\ + -doh IPv4 2\" host=1.0.0.1;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ + le-doh IPv4 1\" host=8.8.8.8;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ + le-doh IPv4 2\" host=8.8.4.4;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ + uad9-doh IPv4 1\" host=9.9.9.9;\r\ + \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ + /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ + uad9-doh IPv4 2\" host=149.112.112.112;\r\ + \n\r\ + \n/tool/netwatch/add comment=\"dns, notify, name=ns1.unet.ws\" host=91.192\ + .189.2;" +add dont-require-permissions=no name=script2 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n\r\ + \n:global InspectVar;\r\ + \n#:global RouterBoard;\r\ + \n#:do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on-erro\ + r={}\r\ + \n#:global Resources;\r\ + \n#:do {:set Resources [[ :parse \"/system/resource/get\" ]]} on-error={}\ + \r\ + \n\r\ + \n#:global Updates;\r\ + \n#:do {:set Updates [[ :parse \"/system/package/update/get\" ]]} on-error\ + ={}\r\ + \n\r\ + \n#:global PkgUpdStatus \"undefined\";\r\ + \n#:local Update [/system/package/update/get];\r\ + \n#:retry command={:set PkgUpdStatus (\$Update->\"status\")} delay=200ms m\ + ax=5 on-error={};\r\ + \n\r\ + \n#:log warning [\$InspectVar \$RouterBoard];\r\ + \n#:put [\$InspectVar \$RouterBoard];\r\ + \n\r\ + \n#:retry command={/system/package/update check-for-updates without-paging\ + \_as-value} delay=300ms max=5 on-error={};\r\ + \n\r\ + \n#:global arrDeviceInfo ({});\r\ + \n#:local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};});\ + \r\ + \n#:set (\$arrDeviceInfo->\"RouterBoard\") [[ :parse \"/system/routerboard\ + /get\" ]];\r\ + \n#:retry command={:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system\ + /package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"Error\ + \")};\r\ + \n# [:toarray {\"section\"={\"key\"=\"\"; \"value\"=\"\";} }];\r\ + \n# [:toarray \"\"];\r\ + \n:local arrDeviceInfo ({});\r\ + \n\r\ + \n:set (\$arrDeviceInfo->\"devUpdates\") {\"channel\"; \"stable\";};\r\ + \n#:do {:set (arrDeviceInfo->\"Updates\") [[ :parse \"/system/package/upda\ + te/get\" ]]} on-error={:log error (\$error)}\r\ + \n\$InspectVar \$arrDeviceInfo;\r\ + \n" +add dont-require-permissions=no name=AM-setup owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \_RouterOS Setup Script: AM-setup\r\ + \n# \r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n\r\ + \n## Additional commands:\r\ + \n#\r\ + \n# For scripts:\r\ + \n#:if ([ :len [ /system/script/find where name=\$ScriptName ]] = 0 ) do={\ + \r\ + \n# :local ScriptName [ :jobname ];\r\ + \n# :global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n# /system/script/add name=\$ScriptName owner=\$ScriptName source=([ /too\ + l/fetch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptNa\ + me . \".rsc\") output=user as-value ]->\"data\");\r\ + \n#}\r\ + \n# For run from terminal:\r\ + \n# /system/script/add name=AM-setup owner=AM-Setup source=([ /tool/fetch \ + check-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" ou\ + tput=user as-value ]->\"data\");\r\ + \n#\r\ + \n# /system/script/set source=[ :tocrlf [ get \$ScriptName source ] ] \$Sc\ + riptName;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:local RemoveThisScript false;\r\ + \n\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n{\r\ + \n :local ScriptName;\r\ + \n :local RemoveThisScript;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :local AllDone;\r\ + \n :local CertCommonName \"Root YE\";\r\ + \n :local CertFileName \"Root-YE.pem\";\r\ + \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ + f852f02a708aa5d5666\";\r\ + \n\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ + onName ] ] > 0)) do={\r\ + \n :put \"Importing certificate...\";\r\ + \n:log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n /tool/fetch (\$GlobalScriptsUrl . \"certs/\" . \$CertFileName) dst-p\ + ath=\$CertFileName as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint \ + ] ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\r\ + \n };\r\ + \n :delay 1s;\r\ + \n };\r\ + \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ + \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ + . [ /system/clock/get time ] . \".rsc\");\r\ + \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ + fig\" ];\r\ + \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ + h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n };\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] > 0) do={\r\ + \n :put \"Renaming certificate by its common-name...\";\r\ + \n :global CertificateNameByCN;\r\ + \n \$CertificateNameByCN \$CertFingerprint;\r\ + \n };\r\ + \n\r\ + \n :put \"Add Schedulers...\";\r\ + \n :delay 1;\r\ + \n :put \"Add Global scheduler...\";\r\ + \n :local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFu\ + nc; }\";\r\ + \n :local Comment \"Setup Global Environment for scripts\";\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] \ + ] = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-\ + event=\$OnEvent start-time=startup;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Commen\ + t) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n }\r\ + \n :if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEve\ + nt) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n }\r\ + \n :delay 1;\r\ + \n :put \"Add Update Script scheduler\";\r\ + \n :set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\"\ + ;\r\ + \n :set Comment \"Every Day Check For Update Scripts\";\r\ + \n :if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpda\ + te\" ] ] = 0) do={\r\ + \n /system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Commen\ + t start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n }\r\ + \n\r\ + \n :delay 1;\r\ + \n :put \"Loading configuration and functions...\";\r\ + \n :do { \r\ + \n /system/script { run AM-GlobalConfig; run AM-GlobalFunc; };\r\ + \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n :set AllDone true;\r\ + \n } on-error={\r\ + \n :set AllDone false;\r\ + \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ + \n :log error (\$ScriptName . \$ErrorMsg . :error);\r\ + \n :error \$ErrorMsg;\r\ + \n }\r\ + \n\r\ + \n :delay 5s;\r\ + \n :if (\$AllDone = true && \$RemoveThisScript = true) do={\r\ + \n :put \"Add Scheduler for remove this script...\";\r\ + \n :set OnEvent \":delay 30s; /system/script/remove [ find where name=\$S\ + criptName ]; :delay5s; /system/scheduler/remove [ find where name=\\\"_Rem\ + oveSetup\\\" ];\";\r\ + \n :set Comment \"_RemoveSetup tmp scheduler for remove setup script.\";\ + \r\ + \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-ti\ + me=startup interval=30s on-event=\$OnEvent;\r\ + \n :log warning (\$ScriptName . \"\\nI've done everything, and now I'm ti\ + red... I'm leaving. ))\\nThere will be an error below, this is normal.\");\ + \r\ + \n }\r\ + \n};\r\ + \n" +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n#root.mnuc.backuper\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n:local Script AM-GlobalConfig\r\ + \n/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch ch\ + eck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".rs\ + c\") output=user as-value ]->\"data\");\r\ + \n#/usb1/mikro_bak_rsa.pub" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/226/e1cd7257\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 09:45:02 01.04.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 138;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global GlobalEnvRemove;\r\ + \n:global MiniDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n#:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global ExitError;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global WaitDNSResolving;\r\ + \n:global WaitFullyConnected;\r\ + \n:global WaitTimeSync;\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global FetchLargeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global LogPrint;\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n \$LogPrint debug \$0 (\"\\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if (\$CurrentChannel != \$updateChannel) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n \$LogPrint debug \$0 (\"Set updates channel to: \$updateChannel\");\ + \r\ + \n }\r\ + \n\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel (\$Update->\"channel\");\r\ + \n \$LogPrint debug \$0 (\"Update Channel: \" . \$Channel . \".\");\r\ + \n\r\ + \n :local StatusPkg \"undefined\";\r\ + \n \$LogPrint debug \$0 (\"Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n \$LogPrint debug \$0 (\"\\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([:len \$arrDeviceInfo] = 0) do={\r\ + \n :global arrDeviceInfo ({});\r\ + \n :local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};}\ + );\r\ + \n }\r\ + \n # else={:local arrDeviceInfo ({})}\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [[ :parse \"/\ + system/package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"\ + Error\")};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannel\"; \$Cu\ + rrentChannel;};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentVersion\"; (\$U\ + pdate->\"installed-version\");};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannelVersion\ + \"; [/system/resource/get version];};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateChannel\"; [\$up\ + dateChannel];};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateVersion\"; (\$Up\ + date->\"latest-version\");};\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n\r\ + \n :global arrDeviceInfo [:toarray {\"section\"={\"key\"=\"\"; \"value\"\ + =\"\";} }];\r\ + \n #:do {:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system/package\ + /update/get\" ]]} on-error={}\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devRbCurrentFw;\r\ + \n :global devRbUpgradeFw;\r\ + \n\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global ROsVerCurrent;\r\ + \n :global ROsChannelCurrent;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :global ParseCustom;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global devBuildTime;\r\ + \n :global GetPubIp;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Resource [/system/resource/get];\r\ + \n :set devBuildTime (\$Resource->\"build-time\");\r\ + \n :set runningChannelVersion (\$Resource->\"version\");\r\ + \n :set runningChannel [\$ParseCustom \$runningChannelVersion \"(\" \")\ + \" 1];\r\ + \n :set runningVersion [\$ParseCustom \$runningChannelVersion \" \"];\r\ + \n\r\ + \n :do {\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :local RouterBoard;\r\ + \n :do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on\ + -error={}\r\ + \n :set devModel (\$RouterBoard->\"model\");\r\ + \n :set devRbRevision (\$RouterBoard->\"revision\");\r\ + \n :set devRbSerialNumber (\$RouterBoard->\"serial-number\");\r\ + \n #:set devRbCurrentFw (\$RouterBoard->\"current-firmware\");\r\ + \n #:set devRbUpgradeFw (\$RouterBoard->\"upgrade-firmware\");\r\ + \n :if (\$devCurArch = \"mipsbe\" || \$devCurArch = \"arm\") do={\r\ + \n :global devRunning [ /system/device-mode/get mode ];\r\ + \n } else={\r\ + \n :global devRunning [/system/device-mode/get running];}\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n \r\ + \n :set devRbRevision false;\r\ + \n :set devRbSerialNumber false;\r\ + \n# :set devRbCurrentFw false;\r\ + \n# :set devRbUpgradeFw false;\r\ + \n #:set devCurrentFw \$runningVersion;#:set devUpgradeFw \$ROsVerAvail\ + ;\r\ + \n :set devRunning [/system/device-mode/get running];\r\ + \n }\r\ + \n } on-error={\r\ + \n \$LogPrint error \$0 (\"Error in Function getDevice!\");\r\ + \n :return false;\r\ + \n }\r\ + \n:return true;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global WaitArrDeviceInfo;\r\ + \n # \$WaitDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devCurArch;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global PiblicIpAddress;\r\ + \n\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :local Return;\r\ + \n :local License [/system/license/get];\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n\r\ + \n :set Return ([ \$FormatLine \"Hostname:\" \$Identity ] . \"\\n\" . \\\ + \r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location:\" (\$Snmp->\"location\") ] . \"\\n\") \ + ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact:\" (\$Snmp->\"contact\") ] . \"\\n\") ] \ + . \\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board:\" . \$devBoardName ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Arch:\" . \$devCurArch ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Model:\" \$devModel ] . \\\r\ + \n [ \$IfThenElse ([ :len \$devRbRevision ] > 0) \\\r\ + \n (\" \" . \$devRbRevision) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len \$devRbSerialNumber ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial:\" . \$devRbSerialNumber ] . \"\\n\"\ + ) ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"nleve\ + l\")) ] . \"\\n\") ] . \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \"Running Channel\" \$runningChannel ] . \"\\n\" . \\\ + \r\ + \n [ \$FormatLine \" Installed:\" (\$Update->\"installed-version\") \ + ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :typeof (\$Update->\"latest-version\") ] != \"noth\ + ing\" && \\\r\ + \n \$Update->\"installed-version\" != \$Update->\"latest-version\")\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Update->\"latest-version\") ]\ + \_. \"\\n\") ] . \\\r\ + \n [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true && \\\r\ + \n \$RouterBoard->\"current-firmware\" != \$RouterBoard->\"upgrade-\ + firmware\") \\\r\ + \n ([ \$FormatLine \" Firmware\" (\$RouterBoard->\"current-firmwar\ + e\") ] . \"\\n\") ] . \\ \r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n# !!! The function is not ready !!!\r\ + \n:global FetchHttpInfo do={\r\ + \n :local Mac [ :tostr \$1 ];\r\ + \n :global CertificateAvailable;\r\ + \n :global IsMacLocallyAdministered;\r\ + \n :global LogPrint;\r\ + \n :local Url \"https://api.macvendors.com/\";\r\ + \n :if ([ \$IsMacLocallyAdministered \$Mac ] = true) do={:return \"locall\ + y administered\";}\r\ + \n :do {\r\ + \n :if ([ \$CertificateAvailable \"GTS Root R4\" \"fetch\" ] = false) d\ + o={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ + \");\r\ + \n :error false;\r\ + \n }\r\ + \n :local Vendor ([ /tool/fetch \r\ + \n (\$Url . [ :pick \$Mac 0 8 ]) output=user as-value ]->\"data\");\r\ + \n :return \$Vendor;\r\ + \n } on-error={\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=yes-without-crl (\$Url) output=none \ + as-value;\r\ + \n \$LogPrint debug \$0 (\"The mac vendor is not known in database.\"\ + );\r\ + \n } do={ \$LogPrint warning \$0 (\"Failed getting mac vendor: \" . \$E\ + rr); }\r\ + \n :return \"unknown vendor\";\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n :global LogPrint;\r\ + \n \r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n\r\ + \n# :retry command={abc} delay=1 max=2 on-error={:put \"got error\"} \r\ + \n :do {\r\ + \n \$LogPrint debug \$0 (\"Trying to detect public IP using default s\ + ervice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fail\ + ed to detect public IP using default service: \" . \$Url . \".\")}\r\ + \n #:error \"Failed to detect public IP using default service: \$Url\ + .\"};\r\ + \n } on-error={\r\ + \n \$LogPrint error \$0 (\"Failed to detect public IP using default s\ + ervice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n \$LogPrint debug \$0 (\"Trying to detect public IP using fallback \ + service: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fai\ + led to detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :if (\$PubIpAddr = false) do={\r\ + \n :set PubIpAddr \"not-detected\";\r\ + \n } else={\r\ + \n :set PubIpAddr [ :pick \$PubIpAddr 0 15];\r\ + \n }\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n :global CertificateDownload;\r\ + \n :global EitherOr;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :set UseFor [ \$EitherOr \$UseFor \"undefined\" ];\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n \$LogPrint warning \$0 (\"This system has low free flash space but \ + \" . \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n \$LogPrint info \$0 (\"Certificate with CommonName '\" . \$CommonNam\ + e . \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={:return fal\ + se}\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n \$LogPrint info \$0 (\"There are \" . \$CertCount . \" Certificates \ + with CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n \$LogPrint info \$0 (\"Certificate chain for '\" . \$CommonName . \ + \"' is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={:return fal\ + se}\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global LogPrint;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n \r\ + \n \$LogPrint info \$0 (\"Downloading and importing certificate with Comm\ + onName '\" . \$CommonName . \"'.\");\r\ + \n \r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl http-header-field=({ [\ + \_\$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$GlobalScriptsUrl . \"certs/\" . \$FileName . \$GlobalScriptsUrl\ + Suffix) dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n \$LogPrint warning \$0 (\"Failed downloading certificate with Common\ + Name '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"Required certificate is not available.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl http-header-field=({\ + \_[ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n \"https://mkcert.org/generate/\" http-data=[ :serialize to=json \ + ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n \$LogPrint warning \$0 (\"Failed downloading certificate with Comm\ + onName '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n \$LogPrint warning \$0 (\"Certificate with CommonName '\" . \$Common\ + Name . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :global LogPrint;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (https://amster.vados.ru/; main/3419/3ee\ + 19780)\");\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetRandomNumber do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndnum from=0 to=[ \$EitherOr [ :tonum \$1 ] 4294967295 ] ]\ + \r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n \$LogPrint error \$Name ([ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\ + \$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={:return false}\r\ + \n :local FileVal false;\r\ + \n :do {:set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :global LogPrint;\r\ + \n \$LogPrint debug \$0 (\"Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\$LogPrint debug \$0 (\"... which does not \ + exist.\"); :return true};\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\$LogPrint error \$0 (\"\ + Directory '\" . \$DirName . \"' is not a directory.\"); :return false};\r\ + \n :onerror Err {/file/remove \$DirName} do={\$LogPrint error \$0 (\"Remo\ + ving directory '\" . \$DirName . \"' failed: \" . \$Err); :return false};\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :global LogPrint;\r\ + \n \$LogPrint debug \$0 (\"Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\$LogPrint debug \$0 (\"... which does not\ + \_exist.\"); :return true}\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n \$LogPrint error \$0 (\"File '\" . \$FileName . \"' is not a file.\"\ + ); :return false}\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\$LogPrint error \$0 (\"Removing file '\" . \$FileName . \"' fai\ + led: \" . \$Err); :return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n :global LogPrint;\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n \$LogPrint info \$0 (\"The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n \$LogPrint info \$0 (\"Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Creating disk of type tmpfs failed: \" .\ + \_\$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n \$LogPrint debug \$0 (\"... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Making directory '\" . \$Path . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={:set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]};\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={:set Path [ :pick \$Path 1 [ :len\ + \_\$Path ] ]};\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={:set Path [ :\ + pick \$Path 0 ([ :len \$Path ] - 1) ]};\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n \$LogPrint error \$0 (\"No valid RouterOS version: \" . \$Required);\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n \$LogPrint warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \$Call\ + er 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"A script named '\" . \$Script . \"' does not\ + \_exist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n \$LogPrint error \$0 (\"More tickets than running scripts '\" . \$Sc\ + ript . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global LogPrint;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No symbol available for name '\" . \$Name \ + . \"'!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n# read parts of a large file\r\ + \n:set FetchLargeFiles do={\r\ + \n :local ScriptName [:tostr \$1];\r\ + \n :local fetchUrl [:tostr \$2];\r\ + \n :local CheckCert [:tostr \$3];\r\ + \n :local fetchMode [:tostr \$4];\r\ + \n :local fetchMethod [:tostr \$5];\r\ + \n :local FetchString \"undefined\";\r\ + \n \r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n #:set fetchMode [ \$IfThenElse (\$fetchMode != \"false\") [:tostr (\"m\ + ode=\" . \$fetchMode)] ];\r\ + \n #:set fetchMethod [\$IfThenElse (\$fetchMethod != \"false\") [:tostr (\ + \"http-method=\\\"\" . \$fetchMethod . \"\\\"\") ]];\r\ + \n \r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n #/tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName h\ + ttp-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-value;\r\ + \n #:log warning (\"\\\$fUrl =\" . \$2 . ({[ \$fMode ]}));\r\ + \n :onerror Err {\r\ + \n :set FetchString (\"/tool/fetch \" . \\\r\ + \n [\$IfThenElse ([\$fetchMethod] != \"false\") (\"http-method=\\\"\"\ + \_. \$fetchMethod . \"\\\" \")] . \\\r\ + \n \"check-certificate=\" . \$CheckCert . \" url=(\\\"\" . \$fetchUrl\ + \_. \"\\\") \" . \\\r\ + \n [\$IfThenElse ([\$fetchMode] != \"false\") (\"mode=\" . \$fetchMod\ + e . \" \")] . \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue);\r\ + \n :log warning (\"\\\$FetchSring = \" . \$FetchString);\r\ + \n :put [\$FetchString];\r\ + \n #:put [/tool/fetch \$fetchMode check-certificate=\$CheckCert url=(\$\ + fetchUrl) dst-path=(\$FileName) http-header-field=({ [ \$FetchUserAgentStr\ + \_\$ScriptName ] }) as-value];\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$fetchUrl . \"\ + \_- \" . \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$fetchUrl . \ + \" did not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={:set NotificationMessage (\$NotificationMessage . \"\\n\\nNe\ + ws and changes are not available.\")}\r\ + \n\r\ + \n :set GlobalConfChanges;\r\ + \n :set GlobalConfMigration;\r\ + \n }\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n# Global Environment clear. Use: \"\$GlobalEnvRemove True;\".\r\ + \n:set GlobalEnvRemove do={\r\ + \n :local doRmEnv [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :local ScriptsUrl;\r\ + \n :global LogPrint;\r\ + \n :if (\$doRmEnv != \"True\") do={\r\ + \n \$LogPrint error \"GlobalEnvRemove\" (\"This script is needed \\\"T\ + rue\\\" for confirm to remove global environment variables!\");\r\ + \n :return [];\r\ + \n :error true; \r\ + \n } else={\r\ + \n :set ScriptsUrl \$GlobalScriptsUrl;\r\ + \n :delay 5;\r\ + \n :foreach var in=[/system/script/environment print as-value] do={/sy\ + stem/script/environment remove (\$var->\".id\")}\r\ + \n :delay 5;\r\ + \n :global GlobalScriptsUrl \$ScriptsUrl;\r\ + \n \$LogPrint warning \"GlobalEnvRemove\" (\"Done!\");\r\ + \n :return [];\r\ + \n :error false;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Setup Global Environment for scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n#:local Resource [ /system/resource/get ];\r\ + \n#:log info (\$ScriptName . \" Loaded on \" . \$Resource->\"board-name\" \ + . \" with RouterOS \" . \$Resource->\"version\" . \" and Architecture \" .\ + \".\");\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err;}\r\ + \n\r\ + \n#} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ + \n# log the successful load of the script, or an error if it failed\r\ + \n#:if ([\$GlobalFuncReady] = true && [\$GlobalConfReady] = true) do={\r\ + \n" +add comment="Import ssh keys for public key authentication" \ + dont-require-permissions=no name=AM-SshKeysImport owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-SshKeysImport\r\ + \n# Script comment: Import ssh keys for public key authentication\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n#\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global configs or functions not ready.\"); }; } del\ + ay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global SSHKeysImport;\r\ + \n:global SSHKeysImportFile;\r\ + \n\r\ + \n# import single key passed as string\r\ + \n:set SSHKeysImport do={ :onerror Err {\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local User [ :tostr \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n :if ([ :len \$Key ] = 0 || [ :len \$User ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Missing argument(s), please pass key and u\ + ser!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ :len [ /user/find where name=\$User ] ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"User '\" . \$User . \"' does not exist.\")\ + ;\r\ + \n :return false;\r\ + \n }\r\ + \n :local KeyVal ([ :deserialize \$Key delimiter=\" \" from=dsv options=d\ + sv.plain ]->0);\r\ + \n :if (!(\$KeyVal->0 = \"ssh-ed25519\" || \$KeyVal->0 = \"ssh-rsa\")) do\ + ={\r\ + \n \$LogPrint warning \$0 (\"SSH key of type '\" . \$KeyVal->0 . \"' is\ + \_not supported.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex (\$K\ + eyVal->1) ];\r\ + \n :local RegEx (\"\\\\bmd5=\" . \$FingerPrintMD5 . \"\\\\b\");\r\ + \n :if ([ :len [ /user/ssh-keys/find where user=\$User \\\r\ + \n (key-owner~\$RegEx or info~\$RegEx) ] ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The ssh public key (MD5:\" . \$FingerPrint\ + MD5 . \\\r\ + \n \") is already available for user '\" . \$User . \"'.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$MkDir \"tmpfs/ssh-keys-import\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Creating directory 'tmpfs/ssh-keys-import'\ + \_failed!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileName (\"tmpfs/ssh-keys-import/key-\" . [ \$GetRandom20CharA\ + lNum 6 ] . \".pub\");\r\ + \n /file/add name=\$FileName contents=(\$Key . \", md5=\" . \$FingerPrint\ + MD5);\r\ + \n \$WaitForFile \$FileName;\r\ + \n :onerror Err {\r\ + \n /user/ssh-keys/import public-key-file=\$FileName user=\$User;\r\ + \n \$LogPrint info \$0 (\"Imported ssh public key (\" . \$KeyVal->2 . \ + \", \" . \$KeyVal->0 . \", \" . \\\r\ + \n \"MD5:\" . \$FingerPrintMD5 . \") for user '\" . \$User . \"'.\");\ + \r\ + \n \$RmDir \"tmpfs/ssh-keys-import\";\r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed importing key: \" . \$Err);\r\ + \n \$RmDir \"tmpfs/ssh-keys-import\";\r\ + \n :return false;\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# import keys from a file\r\ + \n:set SSHKeysImportFile do={ :onerror Err {\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local User [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global FileExists;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global SSHKeysImport;\r\ + \n :if ([ :len \$FileName ] = 0 || [ :len \$User ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Missing argument(s), please pass file name\ + \_and user!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$FileExists \$FileName ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"File '\" . \$FileName . \"' does not exist\ + .\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local Keys [ :tolf [ /file/get \$FileName contents ] ];\r\ + \n :foreach KeyVal in=[ :deserialize \$Keys delimiter=\" \" from=dsv opti\ + ons=dsv.plain ] do={\r\ + \n :local Continue false;\r\ + \n :if (\$KeyVal->0 = \"ssh-ed25519\" || \$KeyVal->0 = \"ssh-rsa\") do=\ + {\r\ + \n :if ([ \$SSHKeysImport (\$KeyVal->0 . \" \" . \$KeyVal->1 . \" \" \ + . \$KeyVal->2) \$User ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Failed importing key for user '\" . \$\ + User . \"'.\");\r\ + \n }\r\ + \n :set Continue true;\r\ + \n }\r\ + \n :if (\$Continue = false && \$KeyVal->0 = \"#\") do={\r\ + \n :set User [ \$EitherOr ([ \$ParseKeyValueStore (\$KeyVal->1) ]->\"\ + user\") \$User ];\r\ + \n :set Continue true;\r\ + \n }\r\ + \n :if (\$Continue = false && [ :len (\$KeyVal->0) ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"SSH key of type '\" . \$KeyVal->0 . \"' \ + is not supported.\");\r\ + \n }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ + \n" +add comment="Enable or disable ip addresses based on bridge port state" \ + dont-require-permissions=no name=mod/AM-IPbridge owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: mod/AM-IPbridge\r\ + \n# Script comment: Enable or disable ip addresses based on bridge port st\ + ate\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"SystemScheduler for script: \" . \$ScriptName . \" is NO\ + T SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Fake Bridges\";\r\ + \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ + rtup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:foreach Bridge in=[ /interface/bridge/find ] do={\r\ + \n :local BrName [ /interface/bridge/get \$Bridge name ];\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName ] ] > \ + 0) do={\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName and \ + inactive=no ] ] = 0) do={\r\ + \n /ip/address/disable [ find where !dynamic interface=\$BrName ];\r\ + \n } else={\r\ + \n /ip/address/enable [ find where !dynamic interface=\$BrName ];\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Check for certificates validity" dont-require-permissions=no \ + name=AM-CheckCerts owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-CheckCerts\r\ + \n# Script comment: Check for certificates validity\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global CertRenewTime;\r\ + \n :global CertRenewUrl;\r\ + \n :global CertWarnTime;\r\ + \n :global Identity;\r\ + \n\r\ + \n :global CertificateAvailable;\r\ + \n :global EscapeForRegEx;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global ScriptLock;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global UrlEncode;\r\ + \n# :global WaitFullyConnected;\r\ + \n\r\ + \n# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"System Scheduler for script: \" . \$ScriptName . \" is N\ + OT SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Renew Certificates\";\r\ + \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ + rtup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n\r\ + \n :local CheckCertificatesDownloadImport do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local CertName [ :tostr \$2 ];\r\ + \n :local FetchName [ :tostr \$3 ];\r\ + \n\r\ + \n :global CertRenewUrl;\r\ + \n :global CertRenewPass;\r\ + \n\r\ + \n :global CertificateNameByCN;\r\ + \n :global EscapeForRegEx;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global LogPrint;\r\ + \n :global RmFile;\r\ + \n :global UrlEncode;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :foreach Type in={ \"p12\"; \"pem\" } do={\r\ + \n :local CertFileName ([ \$UrlEncode \$FetchName ] . \".\" . \$Type)\ + ;\r\ + \n \$LogPrint debug \$ScriptName (\"Trying type '\" . \$Type . \"' fo\ + r '\" . \$CertName . \\\r\ + \n \"' (file '\" . \$CertFileName . \"')...\");\r\ + \n\r\ + \n :do {\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] \ + }) \\\r\ + \n (\$CertRenewUrl . \$CertFileName) dst-path=\$CertFileName \ + as-value;\r\ + \n } do={\r\ + \n :if (!(\$Err ~ \"[Ss]tatus 404\")) do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching certificate: \" . \ + \$Err);\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n \$WaitForFile \$CertFileName; \r\ + \n\r\ + \n :local DecryptionFailed true;\r\ + \n :foreach I,PassPhrase in=\$CertRenewPass do={\r\ + \n :do {\r\ + \n \$LogPrint debug \$ScriptName (\"Trying \" . \$I . \". passp\ + hrase... \");\r\ + \n :local Result [ /certificate/import file-name=\$CertFileName\ + \_passphrase=\$PassPhrase as-value ];\r\ + \n :if (\$Result->\"decryption-failures\" = 0) do={\r\ + \n \$LogPrint debug \$ScriptName (\"Success!\");\r\ + \n :set DecryptionFailed false;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n \$RmFile \$CertFileName;\r\ + \n\r\ + \n :if (\$DecryptionFailed = true) do={\r\ + \n \$LogPrint warning \$ScriptName (\"Decryption failed for certi\ + ficate file '\" . \$CertFileName . \"'.\");\r\ + \n }\r\ + \n\r\ + \n :foreach CertInChain in=[ /certificate/find where common-name!=\ + \$CertName !private-key \\\r\ + \n name~(\"^\" . [ \$EscapeForRegEx \$CertFileName ] . \"_[0-9]\ + +\\\$\") \\\r\ + \n !(subject-alt-name~(\"(^|\\\\W)(DNS|IP):\" . [ \$EscapeForRe\ + gEx \$CertName ] . \"(\\\\W|\\\$)\")) \\\r\ + \n !(common-name=[]) ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$CertInChain common-\ + name ];\r\ + \n }\r\ + \n\r\ + \n :return true;\r\ + \n } on-error={\r\ + \n \$LogPrint debug \$ScriptName (\"Could not download certificate \ + file '\" . \$CertFileName . \"'.\");\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :local FormatInfo do={\r\ + \n :local Cert \$1;\r\ + \n\r\ + \n :global FormatLine;\r\ + \n :global FormatMultiLines;\r\ + \n :global IfThenElse;\r\ + \n\r\ + \n :local FormatExpire do={\r\ + \n :global CharacterReplace;\r\ + \n :return [ \$CharacterReplace [ \$CharacterReplace [ :tostr \$1 ] \ + \"w\" \"w \" ] \"d\" \"d \" ];\r\ + \n }\r\ + \n\r\ + \n :local FormatCertChain do={\r\ + \n :local Cert \$1;\r\ + \n\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :local CertVal [ /certificate/get \$Cert ];\r\ + \n\r\ + \n :if ([ :typeof (\$CertVal->\"issuer\") ] = \"nothing\") do={\r\ + \n :return \"self-signed\";\r\ + \n }\r\ + \n\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=5 do={\r\ + \n :set Return (\$Return . [ \$ParseKeyValueStore (\$CertVal->\"iss\ + uer\") ]->\"CN\");\r\ + \n :if ([ :len [ /certificate/builtin/find where skid=(\$CertVal->\ + \"akid\") ] ] > 0) do={\r\ + \n :return \$Return;\r\ + \n }\r\ + \n :do {\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\ + \"akid\") ] ];\r\ + \n } on-error={\r\ + \n :return (\$Return . \" (possibly incomplete!)\");\r\ + \n }\r\ + \n :if ((\$CertVal->\"akid\") = \"\" || (\$CertVal->\"akid\") = (\$\ + CertVal->\"skid\")) do={\r\ + \n :return \$Return;\r\ + \n }\r\ + \n :set Return (\$Return . \" -> \");\r\ + \n }\r\ + \n :return (\$Return . \"...\");\r\ + \n }\r\ + \n\r\ + \n :local CertVal [ /certificate/get \$Cert ];\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$FormatLine \"Name\" (\$CertVal->\"name\") ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$CertVal->\"common-name\") ] > 0) ([ \$Fo\ + rmatLine \"CommonName\" (\$CertVal->\"common-name\") ] . \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$CertVal->\"subject-alt-name\") ] > 0) ([\ + \_\$FormatMultiLines \"SubjectAltNames\" (\$CertVal->\"subject-alt-name\")\ + \_] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \"Private key\" [ \$IfThenElse ((\$CertVal->\"priva\ + te-key\") = true) \"available\" \"missing\" ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \"Fingerprint\" (\$CertVal->\"fingerprint\") ] . \"\ + \\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$CertVal->\"ca\") ] > 0) [ \$FormatLine \ + \"Issuer\" (\$CertVal->\"ca\") ] [ \$FormatLine \"Issuer chain\" [ \$Forma\ + tCertChain \$Cert ] ] ] . \"\\n\" . \\\r\ + \n \"Validity:\\n\" . \\\r\ + \n [ \$FormatLine \" days\" (\$CertVal->\"days-valid\") ] . \"\\n\ + \" . \\\r\ + \n [ \$FormatLine \" from\" (\$CertVal->\"invalid-before\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" to\" (\$CertVal->\"invalid-after\") ] . \"\\n\ + \" . \\\r\ + \n [ \$FormatLine \" time left\" [ \$IfThenElse ((\$CertVal->\"exp\ + ired\") = true) \"expired\" [ \$FormatExpire (\$CertVal->\"expires-after\"\ + ) ] ] ]);\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n# \$WaitFullyConnected;\r\ + \n\r\ + \n :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expi\ + res-after<\$CertRenewTime ] do={\r\ + \n :local CertVal [ /certificate/get \$Cert ];\r\ + \n :local LastName;\r\ + \n :local FetchName;\r\ + \n\r\ + \n :do {\r\ + \n :if ([ :len \$CertRenewUrl ] = 0) do={\r\ + \n \$LogPrint info \$ScriptName (\"No CertRenewUrl given.\");\r\ + \n :error false;\r\ + \n }\r\ + \n \$LogPrint info \$ScriptName (\"Attempting to renew certificate '\ + \" . (\$CertVal->\"name\") . \"'.\");\r\ + \n\r\ + \n :local ImportSuccess false;\r\ + \n :if ([ :len (\$CertVal->\"common-name\") ] > 0) do={\r\ + \n :set LastName (\$CertVal->\"common-name\");\r\ + \n :set FetchName \$LastName;\r\ + \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$ScriptN\ + ame \$LastName \$FetchName ];\r\ + \n }\r\ + \n :foreach SAN in=(\$CertVal->\"subject-alt-name\") do={\r\ + \n :if (\$ImportSuccess = false) do={\r\ + \n :set LastName [ :pick \$SAN ([ :find \$SAN \":\" ] + 1) [ :len\ + \_\$SAN ] ];\r\ + \n :set FetchName \$LastName;\r\ + \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$Scrip\ + tName \$LastName \$FetchName ];\r\ + \n :if (\$ImportSuccess = false && [ :pick \$LastName 0 2 ] = \"*\ + .\") do={\r\ + \n :set FetchName (\"star.\" . [ :pick \$LastName 2 [ :len \$La\ + stName ] ]);\r\ + \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$Scr\ + iptName \$LastName \$FetchName ];\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :if (\$ImportSuccess = false) do={ :error false; }\r\ + \n\r\ + \n :if ([ :len (\$CertVal->\"fingerprint\") ] > 0 && \$CertVal->\"fin\ + gerprint\" != [ /certificate/get \$Cert fingerprint ]) do={\r\ + \n \$LogPrint debug \$ScriptName (\"Certificate '\" . \$CertVal->\"\ + name\" . \"' was updated in place.\");\r\ + \n :set CertVal [ /certificate/get \$Cert ];\r\ + \n } else={\r\ + \n \$LogPrint debug \$ScriptName (\"Certificate '\" . \$CertVal->\"\ + name\" . \"' was not updated, but replaced.\");\r\ + \n\r\ + \n :local CertNew [ /certificate/find where name~(\"^\" . [ \$Escap\ + eForRegEx [ \$UrlEncode \$FetchName ] ] . \"\\\\.(p12|pem)_[0-9]+\\\$\") \ + \\\r\ + \n (common-name=(\$CertVal->\"common-name\") or subject-alt-name~\ + (\"(^|\\\\W)(DNS|IP):\" . [ \$EscapeForRegEx \$LastName ] . \"(\\\\W|\\\$)\ + \")) \\\r\ + \n fingerprint!=[ :tostr (\$CertVal->\"fingerprint\") ] ];\r\ + \n :local CertNewVal [ /certificate/get \$CertNew ];\r\ + \n\r\ + \n :if ((\$CertVal->\"expires-after\") > (\$CertNewVal->\"expires-a\ + fter\")) do={\r\ + \n /certificate/remove \$CertNew;\r\ + \n \$LogPrint warning \$ScriptName (\"Old certificate is newer th\ + an the new one. Aborting renew.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ((\$CertVal->\"private-key\") = true && (\$CertVal->\"privat\ + e-key\") != (\$CertNewVal->\"private-key\")) do={\r\ + \n /certificate/remove \$CertNew;\r\ + \n \$LogPrint warning \$ScriptName (\"Old certificate '\" . (\$Ce\ + rtVal->\"name\") . \"' has a private key, new certificate does not. Aborti\ + ng renew.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$CertificateAvailable ([ \$ParseKeyValueStore (\$CertNew\ + Val->\"issuer\") ]->\"CN\") \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$ScriptName (\"The certificate chain is no\ + t available!\");\r\ + \n }\r\ + \n\r\ + \n /ip/service/set certificate=(\$CertNewVal->\"name\") [ find wher\ + e certificate=(\$CertVal->\"name\") ];\r\ + \n\r\ + \n /ip/ipsec/identity/set certificate=(\$CertNewVal->\"name\") [ fi\ + nd where certificate=(\$CertVal->\"name\") ];\r\ + \n /ip/ipsec/identity/set remote-certificate=(\$CertNewVal->\"name\ + \") [ find where remote-certificate=(\$CertVal->\"name\") ];\r\ + \n\r\ + \n /ip/hotspot/profile/set ssl-certificate=(\$CertNewVal->\"name\")\ + \_[ find where ssl-certificate=(\$CertVal->\"name\") ];\r\ + \n\r\ + \n /certificate/remove \$Cert;\r\ + \n /certificate/set \$CertNew name=(\$CertVal->\"name\");\r\ + \n :set Cert \$CertNew;\r\ + \n :set CertVal [ /certificate/get \$CertNew ];\r\ + \n }\r\ + \n\r\ + \n \$SendNotification2 ({ origin=\$ScriptName; silent=true; \\\r\ + \n subject=([ \$SymbolForNotification \"lock-with-ink-pen\" ] . \"C\ + ertificate renewed: \" . (\$CertVal->\"name\")); \\\r\ + \n message=(\"A certificate on \" . \$Identity . \" has been renewe\ + d.\\n\\n\" . [ \$FormatInfo \$Cert ]) });\r\ + \n \$LogPrint info \$ScriptName (\"The certificate '\" . (\$CertVal->\ + \"name\") . \"' has been renewed.\");\r\ + \n } on-error={\r\ + \n \$LogPrint debug \$ScriptName (\"Could not renew certificate '\" .\ + \_(\$CertVal->\"name\") . \"'.\");\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :foreach Cert in=[ /certificate/find where !revoked !scep-url !(expire\ + s-after=[]) \\\r\ + \n expires-after<\$CertWarnTime !(fingerprint=[]) ] do\ + ={\r\ + \n :local CertVal [ /certificate/get \$Cert ];\r\ + \n\r\ + \n :if ([ :len [ /certificate/scep-server/find where ca-cert=(\$CertVal\ + ->\"ca\") ] ] > 0) do={\r\ + \n \$LogPrint debug \$ScriptName (\"Certificate '\" . (\$CertVal->\"n\ + ame\") . \"' is handled by SCEP, skipping.\");\r\ + \n } else={\r\ + \n :local State [ \$IfThenElse ((\$CertVal->\"expired\") = true) \"ex\ + pired\" \"is about to expire\" ];\r\ + \n\r\ + \n \$SendNotification2 ({ origin=\$ScriptName; \\\r\ + \n subject=([ \$SymbolForNotification \"lock-with-ink-pen,warning-s\ + ign\" ] . \"Certificate warning: \" . (\$CertVal->\"name\")); \\\r\ + \n message=(\"A certificate on \" . \$Identity . \" \" . \$State . \ + \".\\n\\n\" . [ \$FormatInfo \$Cert ]) });\r\ + \n \$LogPrint info \$ScriptName (\"The certificate '\" . (\$CertVal->\ + \"name\") . \"' \" . \$State . \\\r\ + \n \", it is invalid after \" . (\$CertVal->\"invalid-after\") . \ + \".\");\r\ + \n }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\ + \n# RouterOS script: AM-GlobalConfig\ + \n# Script comment: Global Config Script\ + \n# Copyright (c) 2007-2026 Vados \ + \n#\ + \n#\ + \n# Warning: Dont touch this line!\ + \n:global GlobalConfReady false;\ + \n#\ + \n#\ + \n# Global Url For Amster scripts to fetch\ + \n# most be defined in AM-Init-Script or AM-setup scripts\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\ + \n:global ScriptsUrlSuffix \"\";\ + \n:global CheckSumsVerify true;\ + \n\ + \n:global ScriptUpdatesCRLF true;\ + \n:global CommentsInScripts true;\ + \n\ + \n# Debug output:\ + \n:global PrintDebug true; #false;\ + \n\ + \n# Debug output for specific script:\ + \n:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\ + \n\ + \n# Debug logs\ + \n# Other actions (disk, email, remote or support) can be used as well.\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\ + \n#/system/logging/add topics=script,debug action=memory;\ + \n\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\ + \n:global Domain \"WORKGROUP\";\ + \n\ + \n:global EmailGeneralTo \"vados@vados.ru\";\ + \n#:global EmailGeneralCc \"\";\ + \n\ + \n# \$ScriptInstallUpdate mod/notification-telegram\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\ + \n# Use this to send notifications to a specific topic in group.\ + \n#:global TelegramThreadId \"30\";\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\ + \n# or user names. Groups allow to chat with devices simultaneously.\ + \n:global TelegramChatIdsTrusted {\ + \n \"454403445\"\ + \n \"-1003631309063\"\ + \n \"-5124482807\"\ + \n \"1087968824\";\ + \n};\ + \n# \"-5294757340\";\ + \n\ + \n:global TelegramChatGroups \"(all)\";\ + \n#:global TelegramChatGroups \"(all|home|office)\";\ + \n\ + \n:global NotificationFunctions {\ + \n \"email\"\ + \n \"telegram\";\ + \n};\ + \n# Toggle this to disable symbols in notifications.\ + \n:global NotificationsWithSymbols true;\ + \n:global TerminalColorOutput true;\ + \n\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\ + \n\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\ + \n:global updateChannel \"stable\";\ + \n\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\");\ + \n:global CertRenewTime 2w;\ + \n:global CertRenewPass {\ + \n \"\";\ + \n# \"v3ry-s3cr3t\";\ + \n# \"4n0th3r-s3cr3t\";\ + \n};\ + \n:global CertWarnTime 1w;\ + \n:global CertIssuedExportPass {\ + \n \"\";\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\ + \n};\ + \n\ + \n# Script BackupAndUpdate mode, possible values: backup,\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\ + \n# osnotify - Set `forceBackup` to always create backups on every run\ + \n:global DevInfoIncludeIP true;\ + \n:global BackupAndUpdateMode \"osnotify\"\ + \n\ + \n:global forceBackup true;\ + \n:global BackupPassword \"Peskar55\";\ + \n\ + \n# SFTP Backup Variables\ + \n:global BackupRandomDelay 0;\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\ + \n:global BackupUploadUser \$Identity;\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\ + \n\ + \n:global BackupSendBinary true;\ + \n:global BackupSendExport true;\ + \n:global BackupSendGlobalConfig true;\ + \n:global BackupSendScripts true;\ + \n\ + \n# Remove local file after uploading if no errors\ + \n:global BackupRmLocal true;\ + \n\ + \n# Local Backups Root Directory \ + \n:global BackupLocalRoot \"tmpfs\";\ + \n\ + \n# Encrypt Backup\ + \n:global BackupEncrypt true;\ + \n\ + \n# Sensitive information in Backups\ + \n:global BackupSens true;\ + \n\ + \n# User Export\ + \n:global BackupUser true;\ + \n\ + \n# License Export (not for CHR, will silently skip)\ + \n:global BackupLicense false;\ + \n\ + \n# SSH Keys\ + \n:global BackupSshKeys true;\ + \n\ + \n# Certificate Export\ + \n:global BackupCerts true;\ + \n\ + \n# Certificate Password\ + \n:global BackupCertsPasswd \"\";\ + \n\ + \n# User-Manager Export\ + \n:global BackupUserMan false;\ + \n\ + \n# The Dude Export\ + \n:global BackupDude false;\ + \n\ + \n# User Files to export, comma-separated string or array of strings\ + \n# User Files are not removed on backup\ + \n# Any directory paths will be removed (/ -> _) on remote file\ + \n# Nonpresent files are silently skipped\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\ + \n\ + \n# load functions and any custom scripts\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\ + \n#\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \n# :onerror Err {\ + \n# /system/script/run \$Script;\ + \n# } do={\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\ + \n# }\ + \n#}\ + \n#:log info \"\\ndevMode = \$devMode\";\ + \n#:log info \"\\ndevRunning = \$devRunning\";\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\ + \n :onerror Err {\ + \n /system/script/run \$Script;\ + \n } do={\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\ + \n }\ + \n}\ + \n\ + \n# signal we are ready\ + \n:set GlobalConfReady true;\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\ + \n" +add comment="Renew locally issued certificates" dont-require-permissions=no \ + name=AM-CertsRenew owner=AM-CertsRenew policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-CertsRenew\r\ + \n# Script comment: Renew locally issued certificates\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n#\r\ + \n:local ExitOK false;\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady; :global GlobalFuncReady;\r\ + \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ + \\\r\ + \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ + delay=500ms max=50;\r\ + \n :local ScriptName [ :jobname ];\r\ + \n\r\ + \n :global CertIssuedExportPass;\r\ + \n\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global ScriptLock;\r\ + \n\r\ + \n# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"System Scheduler for script: \" . \$ScriptName . \" is N\ + OT SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Update Local Issued Certificates.\"\ + ;\r\ + \n#/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=st\ + artup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ + \n :set ExitOK true;\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :foreach Cert in=[ /certificate/find where issued expires-after<3w ] d\ + o={\r\ + \n :local CertVal [ /certificate/get \$Cert ];\r\ + \n /certificate/issued-revoke \$Cert;\r\ + \n /certificate/set name=(\$CertVal->\"name\" . \"-revoked-\" . [ /syst\ + em/clock/get date ]) \$Cert;\r\ + \n /certificate/add name=(\$CertVal->\"name\") common-name=(\$CertVal->\ + \"common-name\") \\\r\ + \n key-usage=(\$CertVal->\"key-usage\") subject-alt-name=(\$CertVal\ + ->\"subject-alt-name\");\r\ + \n /certificate/sign (\$CertVal->\"name\") ca=(\$CertVal->\"ca\");\r\ + \n :if ([ :typeof (\$CertIssuedExportPass->(\$CertVal->\"common-name\")\ + ) ] = \"str\") do={\r\ + \n :if ([ \$MkDir \"cert-issued\" ] = true) do={\r\ + \n /certificate/export-certificate (\$CertVal->\"name\") type=pkcs1\ + 2 \\\r\ + \n file-name=(\"cert-issued/\" . \$CertVal->\"common-name\") \\\ + \r\ + \n export-passphrase=(\$CertIssuedExportPass->(\$CertVal->\"com\ + mon-name\"));\r\ + \n \$LogPrint info \$ScriptName (\"Issued a new certificate for '\"\ + \_. \$CertVal->\"common-name\" . \\\r\ + \n \"', exported to 'cert-issued/\" . \$CertVal->\"common-name\" \ + . \".p12'.\");\r\ + \n } else={\r\ + \n \$LogPrint warning \$ScriptName (\"Failed creating directory, no\ + t exporting certificate.\");\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint info \$ScriptName (\"Issued a new certificate for '\" .\ + \_\$CertVal->\"common-name\" . \"'.\");\r\ + \n }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ + \n}\r\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/caps-man provisioning +add action=create-dynamic-enabled hw-supported-modes=gn master-configuration=\ + cfg-2ghz name-format=prefix-identity name-prefix=2ghz +add action=create-dynamic-enabled hw-supported-modes=ac master-configuration=\ + cfg-5ghz-ac name-format=prefix-identity name-prefix=5ghz-ac +add action=create-dynamic-enabled hw-supported-modes=an master-configuration=\ + cfg-5ghz-an name-format=prefix-identity name-prefix=5ghz-an +/certificate settings +set builtin-trust-store=fetch +/disk settings +set auto-media-interface=lo default-mount-point-template="[tmpfs]" +/ip smb +set comment=MikroVados domain=WORKGROUP enabled=yes interfaces=Bridge-LAN +/interface bridge port +add bridge=Bridge-LAN ingress-filtering=no interface=ether2 \ + internal-path-cost=10 path-cost=10 +add bridge=Bridge-LAN comment=LEN ingress-filtering=no interface=ether3 \ + internal-path-cost=10 path-cost=10 +add bridge=Bridge-LAN comment=NUC ingress-filtering=no interface=ether4 \ + internal-path-cost=10 path-cost=10 +add bridge=Bridge-LAN ingress-filtering=no interface=ether5 \ + internal-path-cost=10 path-cost=10 +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN +/ip settings +set max-neighbor-entries=8192 secure-redirects=no +/ipv6 settings +set disable-ipv6=yes max-neighbor-entries=8192 +/interface detect-internet +set detect-interface-list=WAN internet-interface-list=WAN lan-interface-list=\ + LAN wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add comment=WAN interface="ether1 - Unet" list=WAN +add interface=Bridge-LAN list=LAN +/interface ovpn-server server +add auth=sha1,md5 mac-address=FE:82:A5:78:8E:84 name=ovpn-server1 +/interface wifi cap +set caps-man-addresses=10.30.30.10 certificate=request discovery-interfaces=\ + wlan1,wlan2 lock-to-caps-man=no slaves-static=no +/interface wifi capsman +set package-path="" require-peer-certificate=no upgrade-policy=none +/interface wifi provisioning +add action=create-dynamic-enabled disabled=no master-configuration=2G-N \ + name-format=2G-%I slave-configurations=2G-G supported-bands=\ + 2ghz-n,2ghz-g,2ghz-g +add action=create-dynamic-enabled disabled=no master-configuration=5G-AC \ + name-format=5G-%I supported-bands=5ghz-ac,5ghz-ac +/interface wireguard peers +add allowed-address=10.8.0.2/32,0.0.0.0/0 client-allowed-address=0.0.0.0/0 \ + endpoint-address=89.110.101.17 endpoint-port=29185 interface=WG name=\ + MikroVados persistent-keepalive=10s public-key=\ + "64Y25EUZQQt8EIeAJYD8qWt+te8qvGEepnswdBgmzlY=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan1,wlan2 lock-to-caps-man=yes +/interface wireless sniffer +set file-name=24g +/ip address +add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.8.0.2/24 interface=WG network=10.8.0.0 +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main interface="ether1 - Unet" name="ether1 - Unet" \ + use-peer-dns=no +/ip dhcp-server config +set accounting=no +/ip dhcp-server lease +add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ + 48:8F:5A:8E:EE:A8 server=masterDHCP +add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ + F0:DE:F1:91:0D:1E server=masterDHCP +add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ + 00:80:77:EC:43:86 server=masterDHCP +add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ + dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ + 04:7C:16:36:F5:37 server=masterDHCP +add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ + 10:2D:41:2C:20:C2 server=masterDHCP +add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ + 10:08:C1:81:59:5F server=masterDHCP +add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ + 10:38:1F:D2:5F:13 server=masterDHCP +add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ + 10:B1:DF:E9:D0:D5 server=masterDHCP +add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ + FE:02:52:BE:3F:16 server=masterDHCP +add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ + CC:42:10:12:46:94 server=masterDHCP +add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ + 50:CC:F8:85:96:0A server=masterDHCP +add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ + E4:18:6B:58:34:AB server=masterDHCP +add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ + mac-address=C4:82:E1:03:49:10 server=masterDHCP +add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ + 10:38:1F:82:81:F2 server=masterDHCP +add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ + dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ + dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ + server=masterDHCP +add address=10.30.30.74 client-id=1:20:72:a9:d3:34:36 dhcp-option=HostName \ + dhcp-option-set=MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP \ + use-src-mac=yes +add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ + mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ + dhcp-option-set="=\"Client ID\"" mac-address=DE:4D:72:F3:1A:9F server=\ + masterDHCP +add address=10.30.30.86 dhcp-option=HostName dhcp-option-set=MikroYellow \ + mac-address=48:8F:5A:8E:1A:C2 server=masterDHCP +/ip dhcp-server network +add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ + domain-search-list dhcp-option-set=domain-search-set dns-server=\ + 10.30.30.81 domain=WORKGROUP gateway=10.30.30.81 netmask=24 ntp-server=\ + 10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +/ip dns +set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=8.8.8.8,8.8.4.4 verify-doh-cert=yes +/ip dns static +add address=10.30.30.33 name=amster-nuc type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=amster type=A +add address=10.30.30.33 name=amster-reg type=A +add address=10.30.30.33 name=mng.vados.ru type=A +add address=10.30.30.33 name=mgr.vados.ru type=A +add address=10.30.30.33 name=prt.vados.ru type=A +add address=10.30.30.33 name=git.vados.ru type=A +add address=10.30.30.33 name=reg.vados.ru type=A +add address=10.30.30.33 match-subdomain=yes name=ros.vados.ru type=A +add address=10.30.30.33 match-subdomain=yes name=mikrots.vados.ru type=A +add address=10.30.30.33 name=oxidized.vados.ru type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" name=dns.google type=A +add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +add address=10.30.30.30 name=MILLER-LEN type=A +add address=10.30.30.30 name=miller type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" name=\ + security.cloudflare-dns.com type=A +add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" name=\ + security.cloudflare-dns.com type=A +add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ + dns.quad9.net type=A +add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ + dns.quad9.net type=A +add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +add address=10.30.30.10 name=MikroNUC type=A +add address=10.30.30.86 name=MikroYellow type=A +add address=10.30.30.85 name=MikroMic type=A +add address=10.30.30.95 name=VADOS-NUC type=A +add address=10.30.30.98 name=VADOS-LEN type=A +add address=10.30.30.20 name=garage type=A +add address=2606:4700:4700::1111 disabled=yes name=\ + security.cloudflare-dns.com type=AAAA +add address=2606:4700:4700::1001 disabled=yes name=\ + security.cloudflare-dns.com type=AAAA +/ip firewall address-list +add address=91.215.120.206 list=TRUSTED +add address=185.71.70.78 disabled=yes list=TRUSTED +add address=176.53.203.171 disabled=yes list=TRUSTED +add address=176.53.203.170 disabled=yes list=TRUSTED +add address=176.53.202.194 disabled=yes list=TRUSTED +add address=10.30.30.100-255 list=KIDS +add address=8.8.4.0/24 list=YouTube +add address=8.8.8.0/24 list=YouTube +add address=8.34.208.0/20 list=YouTube +add address=8.35.192.0/20 list=YouTube +add address=23.236.48.0/20 list=YouTube +add address=23.251.128.0/19 list=YouTube +add address=34.0.0.0/15 list=YouTube +add address=34.2.0.0/16 list=YouTube +add address=34.3.0.0/23 list=YouTube +add address=34.3.3.0/24 list=YouTube +add address=34.3.4.0/24 list=YouTube +add address=34.3.8.0/21 list=YouTube +add address=34.3.16.0/20 list=YouTube +add address=34.3.32.0/19 list=YouTube +add address=34.3.64.0/18 list=YouTube +add address=34.4.0.0/14 list=YouTube +add address=34.8.0.0/13 list=YouTube +add address=34.16.0.0/12 list=YouTube +add address=34.32.0.0/11 list=YouTube +add address=34.64.0.0/10 list=YouTube +add address=34.128.0.0/10 list=YouTube +add address=35.184.0.0/13 list=YouTube +add address=35.192.0.0/14 list=YouTube +add address=35.196.0.0/15 list=YouTube +add address=35.198.0.0/16 list=YouTube +add address=35.199.0.0/17 list=YouTube +add address=35.199.128.0/18 list=YouTube +add address=35.200.0.0/13 list=YouTube +add address=35.208.0.0/12 list=YouTube +add address=35.224.0.0/12 list=YouTube +add address=35.240.0.0/13 list=YouTube +add address=57.140.192.0/18 list=YouTube +add address=64.15.112.0/20 list=YouTube +add address=64.233.160.0/19 list=YouTube +add address=66.22.228.0/23 list=YouTube +add address=66.102.0.0/20 list=YouTube +add address=66.249.64.0/19 list=YouTube +add address=70.32.128.0/19 list=YouTube +add address=72.14.192.0/18 list=YouTube +add address=74.125.0.0/16 list=YouTube +add address=104.154.0.0/15 list=YouTube +add address=104.196.0.0/14 list=YouTube +add address=104.237.160.0/19 list=YouTube +add address=107.167.160.0/19 list=YouTube +add address=107.178.192.0/18 list=YouTube +add address=108.59.80.0/20 list=YouTube +add address=108.170.192.0/18 list=YouTube +add address=108.177.0.0/17 list=YouTube +add address=130.211.0.0/16 list=YouTube +add address=136.22.160.0/20 list=YouTube +add address=136.22.176.0/21 list=YouTube +add address=136.22.184.0/23 list=YouTube +add address=136.22.186.0/24 list=YouTube +add address=142.250.0.0/15 list=YouTube +add address=146.148.0.0/17 list=YouTube +add address=152.65.208.0/22 list=YouTube +add address=152.65.214.0/23 list=YouTube +add address=152.65.218.0/23 list=YouTube +add address=152.65.222.0/23 list=YouTube +add address=152.65.224.0/19 list=YouTube +add address=162.120.128.0/17 list=YouTube +add address=162.216.148.0/22 list=YouTube +add address=162.222.176.0/21 list=YouTube +add address=172.110.32.0/21 list=YouTube +add address=172.217.0.0/16 list=YouTube +add address=172.253.0.0/16 list=YouTube +add address=173.194.0.0/16 list=YouTube +add address=173.255.112.0/20 list=YouTube +add address=192.158.28.0/22 list=YouTube +add address=192.178.0.0/15 list=YouTube +add address=193.186.4.0/24 list=YouTube +add address=199.36.154.0/23 list=YouTube +add address=199.36.156.0/24 list=YouTube +add address=199.192.112.0/22 list=YouTube +add address=199.223.232.0/21 list=YouTube +add address=207.223.160.0/20 list=YouTube +add address=208.65.152.0/22 list=YouTube +add address=208.68.108.0/22 list=YouTube +add address=208.81.188.0/22 list=YouTube +add address=208.117.224.0/19 list=YouTube +add address=209.85.128.0/17 list=YouTube +add address=216.58.192.0/19 list=YouTube +add address=216.73.80.0/20 list=YouTube +add address=216.239.32.0/19 list=YouTube +add address=2ip.ru list=Test +add address=157.240.247.174 list=Instagram +add address=46.53.178.107 list=Instagram +add address=179.60.195.174 list=Instagram +add address=157.240.205.174 list=Instagram +add address=31.13.24.0/21 list=Instagram +add address=31.13.64.0/18 list=Instagram +add address=45.64.40.0/22 list=Instagram +add address=66.220.144.0/20 list=Instagram +add address=69.63.176.0/20 list=Instagram +add address=69.171.224.0/19 list=Instagram +add address=74.119.76.0/22 list=Instagram +add address=103.4.96.0/22 list=Instagram +add address=129.134.0.0/16 list=Instagram +add address=157.240.0.0/16 list=Instagram +add address=173.252.64.0/18 list=Instagram +add address=179.60.192.0/22 list=Instagram +add address=185.60.216.0/22 list=Instagram +add address=204.15.20.0/22 list=Instagram +add address=157.240.200.63 list=Instagram +add address=185.60.219.63 list=Instagram +add address=129.134.31.12 list=Instagram +add address=66.81.203.132 list=Instagram +add address=185.89.218.12 list=Instagram +add address=31.13.66.63 list=Instagram +add address=84.15.65.162 list=Instagram +add address=68.66.224.28 list=Instagram +add address=157.240.253.63 list=Instagram +add address=83.174.11.224 list=Instagram +add address=157.240.9.52 list=Instagram +add address=157.240.252.174 list=Instagram +add address=157.240.195.63 list=Instagram +add address=31.13.71.52 list=Instagram +add address=57.144.110.192 list=Instagram +add address=157.240.252.17 list=Instagram +add address=84.15.66.97 list=Instagram +add address=217.168.6.33 list=Instagram +add address=31.13.83.52 list=Instagram +add address=157.240.241.63 list=Instagram +add address=129.134.30.12 list=Instagram +add address=185.89.219.12 list=Instagram +add address=157.240.252.10 list=Instagram +add address=157.240.201.63 list=Instagram +add address=66.81.203.197 list=Instagram +add address=179.60.195.52 list=Instagram +add address=66.81.203.7 list=Instagram +add address=216.40.34.41 list=Instagram +add address=157.240.202.63 list=Instagram +add address=157.240.229.63 list=Instagram +add address=157.240.252.63 list=Instagram +add address=31.13.72.53 list=Instagram +add address=124.108.16.224 list=Instagram +add address=157.240.205.63 list=Instagram +add address=92.46.37.96 list=Instagram +add address=157.240.247.63 list=Instagram +add address=157.240.234.63 list=Instagram +add address=157.240.235.63 list=Instagram +add address=87.245.208.97 list=Instagram +add address=216.58.192.0/19 list=Instagram +add address=209.85.128.0/17 list=Instagram +add address=198.105.240.0/20 list=Instagram +add address=173.194.0.0/16 list=Instagram +add address=172.217.0.0/16 list=Instagram +add address=142.250.0.0/15 list=Instagram +add address=108.177.0.0/17 list=Instagram +add address=87.245.197.140 list=Instagram +add address=74.125.0.0/16 list=Instagram +add address=64.233.160.0/19 list=Instagram +add address=157.240.0.1 list=Instagram +add address=157.240.238.63 list=Instagram +add address=157.240.238.174 list=Instagram +add address=157.240.0.63 list=Instagram +add address=157.240.224.63 list=Instagram +add address=157.240.224.174 list=Instagram +add address=157.240.251.36 list=Instagram +add address=157.240.253.12 list=Instagram +add address=157.240.253.35 list=Instagram +add address=157.240.238.13 list=Instagram +add address=157.240.238.56 list=Instagram +add address=157.240.238.175 list=Instagram +add address=57.144.112.141 list=Instagram +add address=157.240.251.60 list=Instagram +add address=157.240.251.128 list=Instagram +add address=157.240.238.5 list=Instagram +add address=157.240.253.13 list=Instagram +add address=157.240.253.5 list=Instagram +add address=157.240.238.2 list=Instagram +add address=157.240.238.37 list=Instagram +add address=157.240.251.5 list=Instagram +add address=157.240.251.34 list=Instagram +add address=57.144.112.1 list=Instagram +add address=157.240.238.54 list=Instagram +add address=129.134.26.123 list=Instagram +add address=157.240.252.3 list=Instagram +add address=31.13.84.4 list=Instagram +add address=157.240.224.12 list=Instagram +add address=157.240.238.4 list=Instagram +add address=157.240.0.13 list=Instagram +add address=3.33.139.32 list=Instagram +add address=157.240.0.35 list=Instagram +add address=157.240.238.14 list=Instagram +add address=157.240.238.60 list=Instagram +add address=57.144.112.145 list=Instagram +add address=157.240.251.35 list=Instagram +add address=151.101.84.159 list=Twitter +add address=pbs.twimg.com list=Twitter +add address=89.110.101.17 comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" list=TRUSTED +add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +add address=love.ru comment=love.ru list=NoVdsina +add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +add address=pochta.ru comment=pochta.ru list=NoVdsina +add address=vdsina.com list=NoVdsina +add address=vdsina.ru list=NoVdsina +add address=youla.ru list=NoVdsina +add address=kupiprodai.ru list=NoVdsina +add address=myip.ru list=Test +add address=geoip.co list=NoVdsina +add address=x.com list=Twitter +add address=facebook.com list=facebook +add address=fbcd.net list=facebook +add address=comp-lenta.ru list=NoVdsina +add address=128.85.102.70 comment=update.microsoft.com list=\ + windowsupdateslist +add address=wu-b-net.trafficmanager.net. comment=\ + ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ + ctldl.windowsupdate.com list=windowsupdateslist +add address=redir.update.msft.com.trafficmanager.net. comment=\ + update.microsoft.com list=windowsupdateslist +add address=geo.prod.do.dsp.trafficmanager.net. comment=\ + geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12437.d.akamaiedge.net. comment=\ + kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ + comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ + list=windowsupdateslist +add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ + sls.update.microsoft.com list=windowsupdateslist +add address=fe3.delivery.mp.microsoft.com. comment=\ + fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ + fe3.delivery.mp.microsoft.com list=windowsupdateslist +add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ + fe2cr.update.microsoft.com list=windowsupdateslist +add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ + download.windowsupdate.com list=windowsupdateslist +add address=wu-f-net.trafficmanager.net. comment=\ + download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +add address=tsfe.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ + comment=9.au.download.windowsupdate.com list=windowsupdateslist +add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dspw65.akamai.net. comment=\ + download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ + comment=licensing.mp.microsoft.com list=windowsupdateslist +add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-nlu-net.trafficmanager.net. comment=\ + star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-tlu-net.trafficmanager.net. comment=\ + star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=storeedgefd.xbetservices.akadns.net. comment=\ + storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ + comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ + windowsupdateslist +add address=e16646.dscg.akamaiedge.net. comment=\ + storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ + windowsupdateslist +add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=bg.microsoft.map.fastly.net. comment=\ + 3.au.download.windowsupdate.com list=windowsupdateslist +add list=windowsupdateslist +add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ + star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a2033.dscd.akamai.net. comment=\ + star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-nlu-net.trafficmanager.net. comment=\ + dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-b-tlu-net.trafficmanager.net. comment=\ + 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a122.dscg3.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e10370.d.akamaiedge.net. comment=\ + geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=a1683.dscd.akamai.net. comment=\ + dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ + comment=collections.mp.microsoft.com list=windowsupdateslist +add address=a1847.dscd.akamai.net. comment=\ + wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=au.download.windowsupdate.com.edgesuite.net. comment=\ + 2.au.download.windowsupdate.com list=windowsupdateslist +add address=a767.dscg3.akamai.net. comment=\ + au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ + 4.au.download.windowsupdate.com list=windowsupdateslist +add address=cl-glcb907925.gcdn.co. comment=\ + 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ + comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +add address=ts-frontend.trafficmanager.net. comment=\ + tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ + list=windowsupdateslist +add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ + windowsupdateslist +add address=e12671.dscd.akamaiedge.net. comment=\ + download.microsoft.com.edgekey.net list=windowsupdateslist +add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=e12358.d.akamaiedge.net. comment=\ + kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ + tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=dcat-f-tlu-net.trafficmanager.net. comment=\ + tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=a1856.dspw65.akamai.net. comment=\ + tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ + consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ + windowsupdateslist +add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=82.202.162.184 comment=comp-lenta.ru list=NoWG +add address=smtp.mail.me.com.akadns.net. comment=smtp.mail.me.com list=NoWG +add address=17.57.155.37 comment=smtp.mail.me.com.akadns.net list=NoWG +add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ + list=windowsupdateslist +add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ + purchase.mp.microsoft.com list=windowsupdateslist +add address=e110219.a.akamaiedge.net. comment=\ + purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.141 list=windowsupdateslist +add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=storesdk.xbetservices.akadns.net. comment=\ + storesdk.dsx.mp.microsoft.com list=windowsupdateslist +add address=e16646.g.akamaiedge.net. comment=\ + storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ + software-download.microsoft.com list=windowsupdateslist +add address=download.prss.microsoft.com.akamaized.net. comment=\ + software-download.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ + windowsupdateslist +add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +add address=87.250.250.50 comment=YandexDisk list=NoVdsina +add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ + displaycatalog.mp.microsoft.com list=windowsupdateslist +add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ + purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ + purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ + cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=a1996.dscd.akamai.net. comment=\ + wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ + windowsupdateslist +add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.sls.update.microsoft.com list=windowsupdateslist +add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ + windowsupdateslist +add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ + comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ + star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ + windowsupdateslist +add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ + paymentinstruments.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.33 comment=amster-nuc list=NoWG +add address=10.30.30.11 comment=MikroNUC list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! list=NoWG +add address=89.110.101.17 list=VPN-Server +add address=80.85.244.9 list=TRUSTED +add address=8.8.8.8 list=TRUSTED +add address=8.8.4.4 list=TRUSTED +add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ + disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +add address=10.30.30.95 comment=NUC list=NoWG +add address=glb.tas02.cws-prod.dcat.dsp.mp.microsoft.com. comment=\ + tas02.cws.update.microsoft.com list=windowsupdateslist +/ip firewall filter +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=12h chain=input comment="block honeypot DNS" \ + connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment=\ + "block honeypot ssh rdp winbox" connection-state=new dst-port=\ + 22,8291,2222 in-interface="ether1 - Unet" protocol=tcp src-address-list=\ + !TRUSTED +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ + connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ + udp +add action=add-src-to-address-list address-list="Honeypot Hacker" \ + address-list-timeout=5d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp src-address=!10.30.30.0/24 +add action=accept chain=input comment=\ + "accept NTP clients on local area network" dst-port=123 in-interface=\ + Bridge-LAN in-interface-list=LAN protocol=udp +add action=accept chain=input comment="accept WireGuard" dst-port=13231 \ + in-interface="ether1 - Unet" protocol=udp src-address-list=VPN-Server +add action=accept chain=input disabled=yes dst-port=443 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=fasttrack-connection chain=forward comment=\ + "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ + connection-state=established,related,new disabled=yes +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMP" disabled=yes \ + protocol=icmp +add action=accept chain=input comment=\ + "defconf: accept to local loopback (for CAPsMAN)" disabled=yes \ + dst-address=127.0.0.1 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + ipsec-policy=out,ipsec +add action=accept chain=forward comment=\ + "defconf: accept established,related, untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid disabled=yes +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +add action=drop chain=input disabled=yes in-interface-list=!LAN +add action=drop chain=forward comment=\ + "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ + facebook +add action=drop chain=forward comment=\ + "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ + dst-address-list=YouTube +/ip firewall mangle +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" in-interface=WG \ + log-prefix=Mark-VPN-FT new-connection-mark=VPN_No_FastTrack +add action=mark-routing chain=prerouting comment="Test sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test new-routing-mark=To-VPN \ + passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=Instagram dst-address=\ + !10.30.30.0/24 dst-address-list=Instagram new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=Twitter dst-address=\ + !10.30.30.0/24 dst-address-list=Twitter new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=YouTube dst-address=\ + !10.30.30.0/24 dst-address-list=YouTube new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment=facebook dst-address=\ + !10.30.30.0/24 dst-address-list=facebook new-routing-mark=To-VPN \ + src-address=10.30.30.0/24 src-address-list=!NoWG +add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ + dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina log-prefix=VPN-all \ + new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp tcp-flags=syn tcp-mss=1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 dst-address-list=!NoVdsina log=yes log-prefix=VPN-Net \ + new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +/ip firewall nat +add action=redirect chain=dstnat comment=\ + "FORCE DNS TO LOCAL MIKROTIK DNS SERVER" dst-port=53 protocol=tcp \ + src-address=10.30.30.0/24 to-ports=53 +add action=redirect chain=dstnat dst-port=53 protocol=udp src-address=\ + 10.30.30.0/24 to-ports=53 +add action=masquerade chain=srcnat comment="masquerade Default" ipsec-policy=\ + out,none out-interface="ether1 - Unet" routing-mark=!To-VPN +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + in-interface=Bridge-LAN log-prefix=WG-nat out-interface=WG routing-mark=\ + To-VPN +add action=dst-nat chain=dstnat comment=npm disabled=yes dst-port=81 \ + in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps disabled=yes \ + dst-port=443 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + disabled=yes dst-port=80 in-interface="ether1 - Unet" protocol=tcp \ + to-addresses=10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat disabled=yes dst-port=80 in-interface=\ + "ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 to-ports=80 +add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ + dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ + time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ + Bridge-LAN protocol=tcp src-address-list=KIDS time=\ + 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +add action=dst-nat chain=dstnat dst-address=146.120.64.211 dst-port=32000 \ + in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.95 \ + to-ports=32000 +add action=dst-nat chain=dstnat dst-address=146.120.64.211 dst-port=32000 \ + in-interface="ether1 - Unet" protocol=udp to-addresses=10.30.30.95 \ + to-ports=32000 +add action=dst-nat chain=dstnat dst-port=32000 protocol=tcp routing-mark=\ + To-VPN to-addresses=10.30.30.95 to-ports=32000 +add action=dst-nat chain=dstnat dst-port=32000 protocol=udp routing-mark=\ + To-VPN to-addresses=10.30.30.95 to-ports=32000 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ + content=linux.duke.edu disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=vk.com \ + content=vk.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=ok.ru content=\ + ok.ru +add action=add-dst-to-address-list address-list=Instagram \ + address-list-timeout=none-dynamic chain=prerouting comment=Instagram \ + content=instagram.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting comment=Twitter content=twimg.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting content=x.com +add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ + none-dynamic chain=prerouting content=twitter.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting comment=YouTube content=youtube.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googleapis.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=ggpht.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=youtu.be +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=ytimg.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googlevideo.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=gstatic.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=googleusercontent.com +add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ + none-dynamic chain=prerouting content=nhacmp3youtube.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=me.com \ + content=me.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=icloud.com \ + content=icloud.com +add action=add-dst-to-address-list address-list=facebook \ + address-list-timeout=none-dynamic chain=prerouting comment=facebook \ + content=fbcd.net +add action=add-dst-to-address-list address-list=facebook \ + address-list-timeout=none-dynamic chain=prerouting content=facebook.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=comp-lenta.ru \ + content=comp-lenta.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + smtp.mail.me.com content=smtp.mail.me.com log=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gov.ru \ + content=gov.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + r78.fssp.gov.ru content=r78.fssp.gov.ru +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=api.db-ip.com \ + content=api.db-ip.com +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + api.telegram.org content=api.telegram.org +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set irc disabled=no +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip hotspot walled-garden +add server=*1 +/ip ipsec settings +set accounting=no +/ip ipsec policy +set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +/ip ipsec profile +set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +/ip proxy +set cache-administrator="" max-cache-size=none port=80,443 src-address=\ + 0.0.0.0 +/ip route +add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=WG routing-table=\ + To-VPN scope=30 target-scope=10 +add disabled=yes distance=2 dst-address=0.0.0.0/0 gateway=146.120.64.209 \ + routing-table=main scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set ssh address=10.30.30.0/24 port=2222 +set winbox address=10.30.30.0/24 +set api address=10.30.30.0/24 disabled=yes +set api-ssl address=10.30.30.0/24 +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ + webfig-plain=no webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required \ + strong-crypto=yes +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add interface="ether1 - Unet" type=external +/ipv6 firewall address-list +add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +add address=::1/128 comment="defconf: lo" list=bad_ipv6 +add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +/ipv6 firewall filter +add action=add-src-to-address-list address-list=bad_ipv6 \ + address-list-timeout=none-dynamic chain=input comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked in-interface=WG in-interface-list=WAN \ + src-address-list="" +add action=drop chain=input comment="defconf: drop invalid" connection-state=\ + invalid +add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=input comment="defconf: accept UDP traceroute" \ + dst-port=33434-33534 protocol=udp +add action=accept chain=input comment=\ + "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ + udp src-address=fe80::/10 +add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ + protocol=udp +add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=input comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=input comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +add action=accept chain=forward comment=\ + "defconf: accept established,related,untracked" connection-state=\ + established,related,untracked +add action=drop chain=forward comment="defconf: drop invalid" \ + connection-state=invalid +add action=drop chain=forward comment=\ + "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +add action=drop chain=forward comment=\ + "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ + hop-limit=equal:1 protocol=icmpv6 +add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ + icmpv6 +add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ + 500,4500 protocol=udp +add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ + ipsec-ah +add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ + ipsec-esp +add action=accept chain=forward comment=\ + "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +add action=drop chain=forward comment=\ + "defconf: drop everything else not coming from LAN" in-interface-list=\ + !LAN +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/ppp secret +add local-address=192.168.60.1 name=vados remote-address=192.168.60.2 \ + service=l2tp +/routing bfd configuration +add disabled=no +/snmp +set contact=@AmsterNL enabled=yes engine-id-suffix=MikroMaster location=NL \ + src-address=10.30.30.81 trap-interfaces=Bridge-LAN,WG trap-target=\ + 10.30.30.10 +/system clock +set time-zone-autodetect=no time-zone-name=Europe/Moscow +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroMaster +/system logging +add action=email disabled=yes regex="* added|changed|removed *" topics=\ + system,info +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes use-local-clock=yes +/system ntp client servers +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +add address=time.google.com disabled=yes +/system scheduler +add comment="Windows Update script" interval=2d5m name=WU-script-run-schedule \ + on-event=WU-add-to-list policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2014-02-11 start-time=00:00:00 +add comment="Backup Every Week" disabled=yes interval=1w name=BackupEveryWeek \ + on-event=BackupAndUpdate policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2025-07-07 start-time=03:41:27 +add comment="DoH Cache Flush" interval=1d name="DNS Cache Flush" on-event=\ + DNS_Flush_Cache policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2019-12-06 start-time=05:30:00 +add comment="Create mkdir function on startup" name=\ + create_mkdir_function_on_startup on-event=\ + "/system script run create_mkdir_function;" policy=read,write,policy,test \ + start-time=startup +add comment="Scheduler for Update Certificates CloudFlare Quad9" interval=1w \ + name="Update Certificates CloudFlare Quad9" on-event=\ + "/system/script { run Update-Certificates; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2025-11-28 start-time=05:45:40 +add comment="Scheduler for Amster-Backup-UpdateEmail" disabled=yes interval=\ + 1w name=Amster-Backup-UpdateEmail on-event=\ + "/system/script { run Amster-Backup-UpdateEmail; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-02-13 start-time=03:41:27 +add comment="Setup Global Environment for scripts" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Fake Bridges" interval=1d name=\ + mod/AM-IPbridge on-event="/system/script/run mod/AM-IPbridge;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Renew Certificates" interval=1d name=\ + AM-CheckCerts on-event="/system/script/run AM-CheckCerts;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/system watchdog +set watchdog-timer=no +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool mac-server +set allowed-interface-list=LAN +/tool mac-server mac-winbox +set allowed-interface-list=LAN +/tool netwatch +add comment="doh, doh-url=https://security.cloudflare-dns.com/dns-query, notif\ + y, name=CloudFlare-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 \ + http-codes="" test-script="" type=simple up-script="" +add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ + flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ + oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ + port=443 test-script="" type=simple up-script="" +add comment="dns-fallback, notify, name=Google-DNS IPv4" disabled=yes \ + down-script="" host=8.8.8.8 http-codes="" test-script="" type=simple \ + up-script="" +add comment="doh-fallback, doh-url=https://dns.google/dns-query, doh-cert=GTS \ + Root R1, notify, name=Google-DOH IPv4" disabled=yes down-script="" host=\ + 8.8.4.4 http-codes="" test-script="" type=simple up-script="" +add comment="dns, notify, name=Cuad9-DOH IPv4" disabled=yes down-script="" \ + host=9.9.9.9 http-codes="" test-script="" type=simple up-script="" +add comment="doh-fallback, doh-url=https://dns.quad9.net/dns-query, name=Cuad9\ + -DOH IPv4" disabled=yes down-script="" host=149.112.112.112 http-codes="" \ + test-script="" type=simple up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" test-script="" type=simple \ + up-script="" +/tool sniffer +set filter-interface=Bridge-LAN filter-src-ip-address=10.30.30.50/32 +/user aaa +set accounting=no diff --git a/MikroMaster/history/20260405/20260405040243-Diff-Config.rsc b/MikroMaster/history/20260405/20260405040243-Diff-Config.rsc new file mode 100644 index 0000000..6788892 --- /dev/null +++ b/MikroMaster/history/20260405/20260405040243-Diff-Config.rsc @@ -0,0 +1,4519 @@ +1,4518d0 +< # 2026-04-05 04:02:43 by RouterOS 7.22 +< # software id = 2961-C4ZZ +< # +< # model = RBD52G-5HacD2HnD +< # serial number = HCX084RAVFA +< /interface bridge +< add admin-mac=48:8F:5A:60:A1:0B auto-mac=no name=Bridge-LAN port-cost-mode=\ +< short +< /interface ethernet +< set [ find default-name=ether1 ] comment="WAN - Unet" mac-address=\ +< F6:BE:9D:85:53:F5 name="ether1 - Unet" +< set [ find default-name=ether3 ] comment=LEN +< set [ find default-name=ether4 ] comment=NUC +< /interface l2tp-server +< add comment=Server disabled=yes name=l2tp-in1 user=vados +< /interface l2tp-client +< add comment="Starless 2 MikroSPb" connect-to=176.53.203.171 name=l2tp-EoIP \ +< user=vados +< add allow=mschap2 allow-fast-path=yes comment=Starless connect-to=\ +< vpn.starless.ru max-mru=1280 name=l2tp-vpn use-ipsec=yes use-peer-dns=yes \ +< user=vados +< /interface wireless +< # managed by CAPsMAN +< # channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding +< set [ find default-name=wlan1 ] ampdu-priorities=0,1,2,3,4,5,6,7 band=\ +< 2ghz-b/g/n basic-rates-a/g=\ +< 6Mbps,9Mbps,12Mbps,18Mbps,24Mbps,36Mbps,48Mbps,54Mbps basic-rates-b=\ +< 1Mbps,2Mbps,5.5Mbps,11Mbps channel-width=20/40mhz-XX country=belarus \ +< disabled=no frequency=auto hw-protection-mode=rts-cts mode=ap-bridge \ +< rate-set=configured skip-dfs-channels=10min-cac ssid=vados \ +< station-roaming=enabled wds-default-bridge=Bridge-LAN wds-mode=\ +< dynamic-mesh wireless-protocol=802.11 wmm-support=enabled wps-mode=\ +< disabled +< # managed by CAPsMAN +< # channel: 5260/20-Ceee/ac/DP(17dBm), SSID: vados5g, local forwarding +< set [ find default-name=wlan2 ] ampdu-priorities=0,1,2,3,4,5,6,7 band=\ +< 5ghz-a/n/ac basic-rates-a/g=\ +< 6Mbps,9Mbps,12Mbps,18Mbps,24Mbps,36Mbps,48Mbps,54Mbps channel-width=\ +< 20/40/80mhz-XXXX country=belarus disabled=no frequency=auto \ +< hw-protection-mode=rts-cts mode=ap-bridge rate-set=configured \ +< skip-dfs-channels=10min-cac ssid=vados5g station-roaming=enabled \ +< wds-default-bridge=Bridge-LAN wds-mode=dynamic-mesh wireless-protocol=\ +< 802.11 wmm-support=enabled wps-mode=disabled +< /interface wireguard +< add listen-port=13231 mtu=1280 name=WG +< /interface wireless nstreme +< # managed by CAPsMAN +< # channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding +< set wlan1 enable-nstreme=yes +< # managed by CAPsMAN +< # channel: 5260/20-Ceee/ac/DP(17dBm), SSID: vados5g, local forwarding +< set wlan2 enable-nstreme=yes +< /caps-man security +< add authentication-types=wpa-psk,wpa2-psk encryption=aes-ccm \ +< group-encryption=aes-ccm name=security +< /caps-man configuration +< add channel.band=2ghz-b/g/n .control-channel-width=20mhz .extension-channel=\ +< XX country=belarus datapath.client-to-client-forwarding=yes \ +< .local-forwarding=yes name=cfg-2ghz security=security ssid=vados +< add channel.band=5ghz-a/n/ac .control-channel-width=20mhz .extension-channel=\ +< XXXX country=belarus datapath.client-to-client-forwarding=yes \ +< .local-forwarding=yes name=cfg-5ghz-ac security=security ssid=vados5g +< add channel.band=5ghz-a/n .control-channel-width=20mhz .extension-channel=XX \ +< country=belarus datapath.client-to-client-forwarding=yes \ +< .local-forwarding=yes name=cfg-5ghz-an security=security ssid=vados5g +< /disk +< add media-interface=lo slot=tmpfs tmpfs-max-size=44739242 type=tmpfs +< # mountpoint [tmpfs] taken by tmpfs +< set usb1 mount-point-template="[tmpfs]" +< /interface list +< add comment=defconf name=WAN +< add comment=defconf name=LAN +< /interface lte apn +< set [ find default=yes ] ip-type=ipv4 use-network-apn=no +< /interface wifi channel +< add band=5ghz-ax disabled=no frequency=5180,5200,5220,5240 name=5G-AX +< add band=5ghz-ac disabled=no frequency=5180,5200,5220,5240 name=5G-AC +< add band=2ghz-n disabled=no frequency=2422,2442,2462 name=2G-N +< add band=2ghz-ax disabled=no frequency=2422,2442,2462 name=2G-AX +< add band=2ghz-g disabled=no frequency=2422,2442,2462 name=2G-G +< add band=5ghz-n disabled=no frequency=5180,5200,5220,5240 name=5G-AN +< /interface wifi datapath +< add bridge=Bridge-LAN disabled=no interface-list=all name=xs-DataPath +< /interface wifi security +< add authentication-types=wpa2-psk,wpa3-psk disabled=no group-encryption=ccmp \ +< group-key-update=1h management-protection=allowed name=sec2g +< add authentication-types=wpa3-psk disable-pmkid=yes disabled=no \ +< group-encryption=ccmp group-key-update=5m management-encryption=cmac \ +< management-protection=required name=sec5G +< /interface wifi configuration +< add channel=2G-AX datapath=xs-DataPath disabled=no mode=ap name=2G-AX \ +< security=sec2g security.ft=yes .ft-over-ds=yes ssid=vados +< add channel=2G-N datapath=xs-DataPath disabled=no mode=ap name=2G-N security=\ +< sec2g security.ft=yes .ft-over-ds=yes ssid=vados +< add channel=5G-AX disabled=no mode=ap name=5G-AX security=sec5G security.ft=\ +< yes .ft-over-ds=yes ssid=vados +< add channel=5G-AC datapath=xs-DataPath disabled=no mode=ap name=5G-AC \ +< security=sec5G security.authentication-types="" .ft=yes .ft-over-ds=yes \ +< ssid=vados +< add channel=2G-G datapath=xs-DataPath disabled=no mode=ap name=2G-G security=\ +< sec2g security.authentication-types="" .ft=yes .ft-over-ds=yes ssid=vados +< add channel=5G-AN disabled=no mode=ap name=5G-AN security=sec5G ssid=vados +< /interface wireless security-profiles +< set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ +< dynamic-keys supplicant-identity=MikroTik +< /ip dhcp-server option +< add code=12 name=HostName +< add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +< /ip dhcp-server option sets +< add name=HP1505n options=HostName +< add name=StartLife1 options=HostName +< add name=amsterDev options=HostName +< add name=MiTV options=HostName +< add name=miller options=HostName +< add name=amster options=HostName +< add name=garage options=HostName +< add name=domain-search-set options=domain-search-list +< add name=VADOS-LEN options=HostName +< add name=VADOS-NUC options=HostName +< add name=MikroNUC options=HostName +< add name=master options=HostName +< add name=MikroYellow options=HostName +< add name="=\"Client ID\"" options=HostName +< add name=mVados options=HostName +< /ip dns forwarders +< add dns-servers=1.1.1.1,1.0.0.1 name=blsp.at verify-doh-cert=no +< add comment=Kra dns-servers=1.0.0.1,1.1.1.1 name=slon2.to verify-doh-cert=no +< add dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +< add dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +< add dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=no +< add dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=no +< add dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +< add dns-servers=1.0.0.1,1.1.1.1 name=m.blsp.at verify-doh-cert=no +< /ip ipsec proposal +< set [ find default=yes ] disabled=yes +< /ip pool +< add name=dhcp ranges=10.30.30.150-10.30.30.200 +< /ip dhcp-server +< add add-arp=yes address-pool=dhcp dhcp-option-set=domain-search-set \ +< dynamic-lease-identifiers=client-mac,client-id,opt-82 interface=\ +< Bridge-LAN lease-time=10m name=masterDHCP server-address=10.30.30.81 \ +< use-reconfigure=yes +< /ip hotspot user profile +< set [ find default=yes ] address-pool=dhcp +< /ip smb users +< set [ find default=yes ] disabled=yes +< add disabled=yes name=vados +< /ppp profile +< set *FFFFFFFE use-upnp=no +< /routing bgp template +< set default disabled=no output.network=bgp-networks +< /routing table +< add disabled=no fib name=To-VPN +< /snmp community +< set [ find default=yes ] addresses=10.30.30.0/24 read-access=no security=\ +< private +< /system logging action +< add email-start-tls=yes email-to=vados@vados.ru name=email target=email +< /system script +< add comment="Example add WU servers to AddrList" dont-require-permissions=no \ +< name=WU-add-to-list owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< \_Script to add target web sites DNS IP addresses into address list\r\ +< \n# Tested with Mikrotik 6.4x\r\ +< \n# Syed Jahanzaib / aacable@hotmail.com\r\ +< \n# List name\r\ +< \n:local LISTNAME \"windowsupdateslist\"\r\ +< \n# Web site names which will be added in address list\r\ +< \n:local TARGET1 \"update.microsoft.com\"\r\ +< \n:local TARGET2 \"download.windowsupdate.com\"\r\ +< \n:local TARGET3 \"download.microsoft.com\"\r\ +< \n:local TARGET4 \"windowsupdate.com\"\r\ +< \n:local TARGET5 \"ntservicepack.microsoft.com\"\r\ +< \n:local TARGET6 \"wustat.windows.com\"\r\ +< \n:local TARGET7 \"stats.microsoft.com\"\r\ +< \n:local TARGET8 \"mp.microsoft.com\"\r\ +< \n:local TARGET9 \"ws.microsoft.com\"\r\ +< \n:local TARGET10 \"sls.update.microsoft.com.akadns.net\"\r\ +< \n:local TARGET11 \"vortex.data.microsoft.com\"\r\ +< \n:local TARGET12 \"vortex-win.data.microsoft.com\"\r\ +< \n:local TARGET13 \"fe2.update.microsoft.com.akadns.net\"\r\ +< \n:local TARGET14 \"statsfe2.update.microsoft.com.akadns.net\"\r\ +< \n \r\ +< \n# 1st time runner, check if address list is not created previously and a\ +< dd entries in it for 1st time usage\r\ +< \n:if ( [/ip firewall address-list find where list=\$LISTNAME] = \"\") do=\ +< {\r\ +< \n:log warning \"No address list for \$TARGET1 found ! creating and adding\ +< \_resolved entry for 1st time usage ... zaib\"\r\ +< \n \r\ +< \n:local FirstAddr [resolve \$TARGET1];\r\ +< \n\r\ +< \n/ip firewall address-list add address=\$FirstAddr list=\$LISTNAME commen\ +< t=\$TARGET1;\r\ +< \n} else={\r\ +< \n:log warning \"Previous List for \$LISTNAME found ! moving forward and c\ +< hecking if DNS entries can be added in it ...\"\r\ +< \n}\r\ +< \n \r\ +< \n# Check DNS entries and collect matching names\r\ +< \n:foreach i in=[/ip dns cache find name~\"(\$TARGET1|\$TARGET2|\$TARGET3|\ +< \$TARGET4|\$TARGET5|\$TARGET6|\$TARGET7|\$TARGET8|\$TARGET9|\$TARGET10|\$T\ +< ARGET11|\$TARGET12|\$TARGET13|\$TARGET14)\" && \$type ~ \"^(A|CNAME)\\\$\"\ +< \_] do={\r\ +< \n \r\ +< \n# Get IP Address from the names and hold it in temporary buffer\r\ +< \n:local Buffer [/ip dns cache get \$i data];\r\ +< \ndelay delay-time=10ms\r\ +< \n \r\ +< \n# Check if entry is already not exists, then OK, otherwise ignore duplic\ +< ation\r\ +< \n:if ( [/ip firewall address-list find where address=\$Buffer] = \"\") do\ +< ={\r\ +< \n \r\ +< \n# Fetch DNS names for the entries\r\ +< \n:local sitednsname [/ip dns cache get \$i name] ;\r\ +< \n \r\ +< \n# Print name in LOG window\r\ +< \n:log info (\"added entry: \$sitednsname \$Buffer\");\r\ +< \n \r\ +< \n# Add IP addresses and there names to the address list\r\ +< \n/ip firewall address-list add address=\$Buffer list=\$LISTNAME comment=\ +< \$sitednsname;\r\ +< \n}\r\ +< \n}" +< add comment="Add Hosts DNS names to NoWG addres list" \ +< dont-require-permissions=no name=Add2vdsina owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< \_Script to add target web sites DNS IP addresses into address list\r\ +< \n# Tested with Mikrotik 6.4x\r\ +< \n# \r\ +< \n# List name\r\ +< \n:local LISTNAME \"NoWG\"\r\ +< \n#\r\ +< \n# Web site names which will be added in address list\r\ +< \n:local TARGET1 \"comp-lenta.ru\"\r\ +< \n:local TARGET2 \"ok.ru\"\r\ +< \n:local TARGET3 \"vk.com\"\r\ +< \n#:local TARGET4 \"smtp.mail.me.com\"\r\ +< \n#:local TARGET4 \"windowsupdate.com\"\r\ +< \n#:local TARGET5 \"ntservicepack.microsoft.com\"\r\ +< \n#:local TARGET6 \"wustat.windows.com\"\r\ +< \n#:local TARGET7 \"stats.microsoft.com\"\r\ +< \n#:local TARGET8 \"mp.microsoft.com\"\r\ +< \n#:local TARGET9 \"ws.microsoft.com\"\r\ +< \n#:local TARGET10 \"sls.update.microsoft.com.akadns.net\"\r\ +< \n#:local TARGET11 \"vortex.data.microsoft.com\"\r\ +< \n#:local TARGET12 \"vortex-win.data.microsoft.com\"\r\ +< \n#:local TARGET13 \"fe2.update.microsoft.com.akadns.net\"\r\ +< \n#:local TARGET14 \"statsfe2.update.microsoft.com.akadns.net\"\r\ +< \n \r\ +< \n# 1st time runner, check if address list is not created previously and a\ +< dd entries in it for 1st time usage\r\ +< \n:if ( [/ip firewall address-list find where list=\$LISTNAME] = \"\") do=\ +< {\r\ +< \n:log warning \"No address list for \$TARGET1 found ! creating and adding\ +< \_resolved entry for 1st time usage ... zaib\"\r\ +< \n\r\ +< \n:local FirstAddr [resolve \$TARGET1];\r\ +< \n\r\ +< \n/ip firewall address-list add address=\$FirstAddr list=\$LISTNAME commen\ +< t=\$TARGET1;\r\ +< \n\r\ +< \n} else={\r\ +< \n:log warning \"Previous List for \$LISTNAME found ! moving forward and c\ +< hecking if DNS entries can be added in it ...\"\r\ +< \n}\r\ +< \n\r\ +< \n# Check DNS entries and collect matching names\r\ +< \n:foreach i in=[/ip dns cache find name~\"(\$TARGET1|\$TARGET2|\$TARGET3|\ +< \$TARGET4)\" && \$type ~ \"^(A|CNAME)\\\$\" ] do={\r\ +< \n\r\ +< \n:log info (\"start entry: \$c \$sitednsname \$Buffer\");\r\ +< \n\r\ +< \n# Get IP Address from the names and hold it in temporary buffer\r\ +< \n:local Buffer [/ip dns cache get \$i data];\r\ +< \ndelay delay-time=10ms\r\ +< \n:log info (\"1: \$Buffer\"); \r\ +< \n\r\ +< \n# Check if entry is already not exists, then OK, otherwise ignore duplic\ +< ation\r\ +< \n:if ( [/ip firewall address-list find where address=\$Buffer] = \"\") do\ +< ={\r\ +< \n\r\ +< \n:log info (\"2: \$Buffer\"); \r\ +< \n \r\ +< \n# Fetch DNS names for the entries\r\ +< \n:local sitednsname [/ip dns cache get \$i name] ;\r\ +< \n \r\ +< \n# Print name in LOG window\r\ +< \n:log info (\"added entry: \$i \$sitednsname \$Buffer\");\r\ +< \n \r\ +< \n# Add IP addresses and there names to the address list\r\ +< \n/ip firewall address-list add address=\$Buffer list=\$LISTNAME comment=\ +< \$sitednsname;\r\ +< \n}\r\ +< \n}" +< add comment="Flush DNS Cache" dont-require-permissions=no name=\ +< DNS_Flush_Cache owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=\ +< "/ip dns cache flush" +< add dont-require-permissions=no name=create_mkdir_function owner=vados \ +< policy=read,write source="# Written by Phillip Stromberg in 2019\r\ +< \n# Distributed under the MIT license\r\ +< \n# \r\ +< \n# \r\ +< \n# this creates a function called \$mkdir\r\ +< \n# from the command line you will be able to just type \"\$mkdir some/new\ +< /folder\"\r\ +< \n# and all the folders that need to be created will be\r\ +< \n# if the folder already existed, it is ignored\r\ +< \n\r\ +< \n:log info \"Creating \\\$mkdir function...\"\r\ +< \n\r\ +< \n:global mkdir do={\r\ +< \n # \$1 refers to the input variable the user passed in to us\r\ +< \n :local newFolder \$1;\r\ +< \n\r\ +< \n # we'll use this variable to report error messages that may arise\r\ +< \n :local errorMsg;\r\ +< \n\r\ +< \n # if the user put a slash on the end of the new folder name, remove \ +< it\r\ +< \n # i.e. \"some/test/\" becomes \"some/test\"\r\ +< \n :while (([:pick \$newFolder ([:len \$newFolder] - 1)]) = \"/\") do={\ +< \r\ +< \n :set newFolder [:pick \$newFolder 0 ([:len \$newFolder] - 1)]\r\ +< \n }\r\ +< \n\r\ +< \n # if the user put a slash at the beginning of the new folder name, r\ +< emove it\r\ +< \n # i.e. \"/some/test\" becomes \"some/test\"\r\ +< \n :while ([:pick \$newFolder 0] = \"/\") do={\r\ +< \n :set newFolder [:pick \$newFolder 1 [:len \$newFolder]]\r\ +< \n }\r\ +< \n\r\ +< \n :if ([/file find name=\$newFolder] != \"\") do={\r\ +< \n :set errorMsg \"'\$newFolder' already exists.\";\r\ +< \n :log debug \"mkdir: \$errorMsg\";\r\ +< \n :return \$newFolder;\r\ +< \n }\r\ +< \n\r\ +< \n # the name of the temp file to create\r\ +< \n :local tempfile \"mkdir_temp_file.txt\";\r\ +< \n\r\ +< \n # port 0 is unlikely to be open to HTTP requests...\r\ +< \n :local fakeURL \"http://127.0.0.1:0/should-not-exist.txt\";\r\ +< \n\r\ +< \n :local fullTempPath (\$newFolder . \"/\" . \$tempfile);\r\ +< \n\r\ +< \n # this is where the folder creation happens\r\ +< \n # `as-value` prevents status messages from printing\r\ +< \n # wrapping in a `:do {...} on-error` prevents error messages from pr\ +< inting.\r\ +< \n :do {\r\ +< \n /tool fetch dst-path=\"\$fullTempPath\" url=\"\$fakeURL\" durati\ +< on=0.001s as-value;\r\ +< \n } on-error={}\r\ +< \n\r\ +< \n # this waits for the temporary dir to show up so there isn't a race \ +< \r\ +< \n # condition where you call mkdir and then try to do something before\ +< \_the \r\ +< \n # folder is actually created\r\ +< \n :local count 0;\r\ +< \n :while ([/file find name=\"\$newFolder\"] = \"\") do={\r\ +< \n :if (\$count >= 50) do={\r\ +< \n # after 50 * 0.1s delays, it's been 5 seconds, which should \ +< be long enough\r\ +< \n :set errorMsg \"New folder could not be created at \$newFold\ +< er\";\r\ +< \n :log error \"mkdir: \$errorMsg\"\r\ +< \n :error \$errorMsg\r\ +< \n }\r\ +< \n :delay 0.1s;\r\ +< \n :set count (\$count + 1);\r\ +< \n }\r\ +< \n\r\ +< \n :return \$newFolder;\r\ +< \n}\r\ +< \n\r\ +< \n:log info \"Created function \\\$mkdir\"\r\ +< \n" +< add comment="Certificates CloudFlare, Quad9 " dont-require-permissions=no \ +< name=Update-Certificates owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< \_CloudFlare\r\ +< \n/tool/fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalRo\ +< otCA.crt.pem;\r\ +< \n/certificate/import file-name=DigiCertGlobalRootCA.crt.pem passphrase=\"\ +< \";\r\ +< \n/tool/ fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalG\ +< 2TLSRSASHA2562020CA1-1.crt.pem;\r\ +< \n/certificate/import file-name=DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt.\ +< pem passphrase=\"\";\r\ +< \n# Quad9\r\ +< \n/tool/fetch mode=https url=\"https://cacerts.digicert.com/DigiCertGlobal\ +< G3TLSECCSHA3842020CA1-1.crt.pem\"\r\ +< \n/certificate/import file-name=DigiCertGlobalG3TLSECCSHA3842020CA1-1.crt.\ +< pem passphrase=\"\";\r\ +< \n\r\ +< \n#:global AmScriptsUrl;\r\ +< \n#google\r\ +< \n#:local CertName \"GTS-Root-R1.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n#:set CertName \"GTS-Root-R4.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n#:set CertName \"GTS-Root-RX.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n#internet\r\ +< \n#:set CertName \"ISRG-Root-X1.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n#:set CertName \"ISRG-Root-X2.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n#:set CertName \"Starfield-Root-Certificate-Authority-G2.pem\";\r\ +< \n#/tool/fetch mode=https url=(\$AmScriptsUrl . \"certs/\" . \$CertName);\ +< \r\ +< \n#/certificate/import file-name=\$CertName passphrase=\"\";\r\ +< \n\r\ +< \n#/ip/dns/set allow-remote-requests=yes doh-max-concurrent-queries=100 do\ +< h-max-server-connections=20 use-doh-server=https://security.cloudflare-dns\ +< .com/dns-query verify-doh-cert=yes;\r\ +< \n#/ip/dns/static remove [find where address=1.1.1.1];\r\ +< \n#/ip/dns/static add address=1.1.1.1 name=security.cloudflare-dns.com com\ +< ment=\"cloudflare-dns IPv4 1\";\r\ +< \n#/ip/dns/static remove [find where address=1.0.0.1];\r\ +< \n#/ip/dns/static add address=1.0.0.1 name=security.cloudflare-dns.com com\ +< ment=\"cloudflare-dns IPv4 2\"\r\ +< \n#/ip dns static add address=2606:4700:4700::1111 name=security.cloudflar\ +< e-dns.com type=AAAA\r\ +< \n#/ip dns static add address=2606:4700:4700::1001 name=security.cloudflar\ +< e-dns.com type=AAAA\r\ +< \n#/ip/dns set servers=\"1.0.0.1, 8.8.4.4\";\r\ +< \n#/ip/dns set servers=\"\";" +< add dont-require-permissions=no name=script1 owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ +< tool/netwatch/add comment=\"doh-fallback, doh-url=https://security.cloudfl\ +< are-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Clou\ +< dFlare-doh IPv4 1\" host=1.1.1.1;\r\ +< \n/tool/netwatch/add comment=\"doh, doh-url=https://security.cloudflare-dn\ +< s.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=CloudFlare\ +< -doh IPv4 2\" host=1.0.0.1;\r\ +< \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ +< /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ +< le-doh IPv4 1\" host=8.8.8.8;\r\ +< \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ +< /dns.google/dns-query, doh-cert=DigiCert Global Root G2, notify, name=Goog\ +< le-doh IPv4 2\" host=8.8.4.4;\r\ +< \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ +< /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ +< uad9-doh IPv4 1\" host=9.9.9.9;\r\ +< \n/tool/netwatch/add comment=\"doh-fallback, dns-fallback, doh-url=https:/\ +< /dns.quad9.net/dns-query, doh-cert=DigiCert Global Root G3, notify, name=C\ +< uad9-doh IPv4 2\" host=149.112.112.112;\r\ +< \n\r\ +< \n/tool/netwatch/add comment=\"dns, notify, name=ns1.unet.ws\" host=91.192\ +< .189.2;" +< add dont-require-permissions=no name=script2 owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< \r\ +< \n\r\ +< \n:global InspectVar;\r\ +< \n#:global RouterBoard;\r\ +< \n#:do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on-erro\ +< r={}\r\ +< \n#:global Resources;\r\ +< \n#:do {:set Resources [[ :parse \"/system/resource/get\" ]]} on-error={}\ +< \r\ +< \n\r\ +< \n#:global Updates;\r\ +< \n#:do {:set Updates [[ :parse \"/system/package/update/get\" ]]} on-error\ +< ={}\r\ +< \n\r\ +< \n#:global PkgUpdStatus \"undefined\";\r\ +< \n#:local Update [/system/package/update/get];\r\ +< \n#:retry command={:set PkgUpdStatus (\$Update->\"status\")} delay=200ms m\ +< ax=5 on-error={};\r\ +< \n\r\ +< \n#:log warning [\$InspectVar \$RouterBoard];\r\ +< \n#:put [\$InspectVar \$RouterBoard];\r\ +< \n\r\ +< \n#:retry command={/system/package/update check-for-updates without-paging\ +< \_as-value} delay=300ms max=5 on-error={};\r\ +< \n\r\ +< \n#:global arrDeviceInfo ({});\r\ +< \n#:local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};});\ +< \r\ +< \n#:set (\$arrDeviceInfo->\"RouterBoard\") [[ :parse \"/system/routerboard\ +< /get\" ]];\r\ +< \n#:retry command={:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system\ +< /package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"Error\ +< \")};\r\ +< \n# [:toarray {\"section\"={\"key\"=\"\"; \"value\"=\"\";} }];\r\ +< \n# [:toarray \"\"];\r\ +< \n:local arrDeviceInfo ({});\r\ +< \n\r\ +< \n:set (\$arrDeviceInfo->\"devUpdates\") {\"channel\"; \"stable\";};\r\ +< \n#:do {:set (arrDeviceInfo->\"Updates\") [[ :parse \"/system/package/upda\ +< te/get\" ]]} on-error={:log error (\$error)}\r\ +< \n\$InspectVar \$arrDeviceInfo;\r\ +< \n" +< add dont-require-permissions=no name=AM-setup owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< \_RouterOS Setup Script: AM-setup\r\ +< \n# \r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n# requires device-mode, fetch\r\ +< \n\r\ +< \n## Additional commands:\r\ +< \n#\r\ +< \n# For scripts:\r\ +< \n#:if ([ :len [ /system/script/find where name=\$ScriptName ]] = 0 ) do={\ +< \r\ +< \n# :local ScriptName [ :jobname ];\r\ +< \n# :global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ +< \n# /system/script/add name=\$ScriptName owner=\$ScriptName source=([ /too\ +< l/fetch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptNa\ +< me . \".rsc\") output=user as-value ]->\"data\");\r\ +< \n#}\r\ +< \n# For run from terminal:\r\ +< \n# /system/script/add name=AM-setup owner=AM-Setup source=([ /tool/fetch \ +< check-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" ou\ +< tput=user as-value ]->\"data\");\r\ +< \n#\r\ +< \n# /system/script/set source=[ :tocrlf [ get \$ScriptName source ] ] \$Sc\ +< riptName;\r\ +< \n:local ScriptName [ :jobname ];\r\ +< \n\r\ +< \n:local RemoveThisScript false;\r\ +< \n\r\ +< \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ +< \n\r\ +< \n{\r\ +< \n :local ScriptName;\r\ +< \n :local RemoveThisScript;\r\ +< \n :global GlobalScriptsUrl;\r\ +< \n :local AllDone;\r\ +< \n :local CertCommonName \"Root YE\";\r\ +< \n :local CertFileName \"Root-YE.pem\";\r\ +< \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ +< f852f02a708aa5d5666\";\r\ +< \n\r\ +< \n :local CertSettings [ /certificate/settings/get ];\r\ +< \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \ +< \\\r\ +< \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ +< \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ +< \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ +< onName ] ] > 0)) do={\r\ +< \n :put \"Importing certificate...\";\r\ +< \n:log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ +< \n /tool/fetch (\$GlobalScriptsUrl . \"certs/\" . \$CertFileName) dst-p\ +< ath=\$CertFileName as-value;\r\ +< \n :delay 1s;\r\ +< \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ +< \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint \ +< ] ] != 1) do={\r\ +< \n :error \"Something is wrong with your certificates!\";\r\ +< \n };\r\ +< \n :delay 1s;\r\ +< \n };\r\ +< \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ +< \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ +< . [ /system/clock/get time ] . \".rsc\");\r\ +< \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ +< fig\" ];\r\ +< \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ +< \n :put \"Installing \$Script...\";\r\ +< \n /system/script/remove [ find where name=\$Script ];\r\ +< \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ +< h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ +< \".rsc\") output=user as-value ]->\"data\");\r\ +< \n };\r\ +< \n\r\ +< \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ +< ] > 0) do={\r\ +< \n :put \"Renaming certificate by its common-name...\";\r\ +< \n :global CertificateNameByCN;\r\ +< \n \$CertificateNameByCN \$CertFingerprint;\r\ +< \n };\r\ +< \n\r\ +< \n :put \"Add Schedulers...\";\r\ +< \n :delay 1;\r\ +< \n :put \"Add Global scheduler...\";\r\ +< \n :local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFu\ +< nc; }\";\r\ +< \n :local Comment \"Setup Global Environment for scripts\";\r\ +< \n :if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] \ +< ] = 0) do={\r\ +< \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-\ +< event=\$OnEvent start-time=startup;\r\ +< \n }\r\ +< \n :if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Commen\ +< t) do={\r\ +< \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ +< \n }\r\ +< \n :if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEve\ +< nt) do={\r\ +< \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ +< \n }\r\ +< \n :delay 1;\r\ +< \n :put \"Add Update Script scheduler\";\r\ +< \n :set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\"\ +< ;\r\ +< \n :set Comment \"Every Day Check For Update Scripts\";\r\ +< \n :if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpda\ +< te\" ] ] = 0) do={\r\ +< \n /system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Commen\ +< t start-time=startup interval=1d on-event=\$OnEvent;\r\ +< \n }\r\ +< \n\r\ +< \n :delay 1;\r\ +< \n :put \"Loading configuration and functions...\";\r\ +< \n :do { \r\ +< \n /system/script { run AM-GlobalConfig; run AM-GlobalFunc; };\r\ +< \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ +< \n :set AllDone true;\r\ +< \n } on-error={\r\ +< \n :set AllDone false;\r\ +< \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ +< \n :log error (\$ScriptName . \$ErrorMsg . :error);\r\ +< \n :error \$ErrorMsg;\r\ +< \n }\r\ +< \n\r\ +< \n :delay 5s;\r\ +< \n :if (\$AllDone = true && \$RemoveThisScript = true) do={\r\ +< \n :put \"Add Scheduler for remove this script...\";\r\ +< \n :set OnEvent \":delay 30s; /system/script/remove [ find where name=\$S\ +< criptName ]; :delay5s; /system/scheduler/remove [ find where name=\\\"_Rem\ +< oveSetup\\\" ];\";\r\ +< \n :set Comment \"_RemoveSetup tmp scheduler for remove setup script.\";\ +< \r\ +< \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-ti\ +< me=startup interval=30s on-event=\$OnEvent;\r\ +< \n :log warning (\$ScriptName . \"\\nI've done everything, and now I'm ti\ +< red... I'm leaving. ))\\nThere will be an error below, this is normal.\");\ +< \r\ +< \n }\r\ +< \n};\r\ +< \n" +< add dont-require-permissions=no name=fetchCustom owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ +< \r\ +< \n#root.mnuc.backuper\r\ +< \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ +< \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ +< 0.30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ +< \n:local Script AM-GlobalConfig\r\ +< \n/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch ch\ +< eck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".rs\ +< c\") output=user as-value ]->\"data\");\r\ +< \n#/usb1/mikro_bak_rsa.pub" +< add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ +< owner=AM-GlobalFunc policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\r\ +< \n# RouterOS script: AM-GglobalFunc\r\ +< \n# Script comment: Global functions\r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n# requires device-mode, fetch, scheduler\r\ +< \n:local ExitOK false;\r\ +< \n:local ScriptName [ :jobname ];\r\ +< \n#:global checkRunJob \$SriptName;\r\ +< \n#:global fixCRLF;\r\ +< \n#:if (\$fixCRLF != false) do={\r\ +< \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ +< ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ +< }\r\ +< \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ +< et \$fixScript source ] ] \$fixScript};};\r\ +< \n#}\r\ +< \n:global GlobalFuncReady false;\r\ +< \n\r\ +< \n# Git commit id & info, expected configuration version\r\ +< \n:global CommitId \"main/226/e1cd7257\";\r\ +< \n:global CommitTAG \"unknown\";\r\ +< \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ +< r: root, in 09:45:02 01.04.2026.\";\r\ +< \n\r\ +< \n# The variables are received right here.\r\ +< \n:global GlobalConfVersion 138;\r\ +< \n\r\ +< \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ +< \n\r\ +< \n:global Identity [/system/identity/get name];\r\ +< \n:global IdentityShort [:pick \$Identity 0 18];\r\ +< \n\r\ +< \n:global devBoardName [/system/resource/get board-name];\r\ +< \n:global devMode [/system/device-mode/get mode];\r\ +< \n:global devCurArch [/system/resource/get architecture-name];\r\ +< \n:global devCurVersion [/system/resource/get version];\r\ +< \n\r\ +< \n# Variables defined in AM-GlobalConfig.rsc\r\ +< \n:global TerminalColorOutput;\r\ +< \n:global CommentsInScripts;\r\ +< \n:global DetectIpAddrDefault;\r\ +< \n:global DetectIpAddrFallback;\r\ +< \n:global updateChannel;\r\ +< \n:global Domain;\r\ +< \n:global EmailGeneralTo;\r\ +< \n:global BackupAndUpdateMode;\r\ +< \n\r\ +< \n# Single functions, without nested functions.\r\ +< \n:global GlobalEnvRemove;\r\ +< \n:global MiniDateTimeStamp;\r\ +< \n\r\ +< \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ +< \n:global LogPrint;\r\ +< \n\r\ +< \n# DeviceInfo and Updates\r\ +< \n:global IsCheckUpdates;\r\ +< \n:global WaitCheckUpdates;\r\ +< \n:global GetPubIp;\r\ +< \n\r\ +< \n:global GetArrDeviceInfo;\r\ +< \n:global WaitArrDeviceInfo;\r\ +< \n\r\ +< \n:global devModel;\r\ +< \n:global devRunningMode;\r\ +< \n\r\ +< \n:global devRbRevision;\r\ +< \n:global devRbSerialNumber;\r\ +< \n:global devRbVerAvail;\r\ +< \n\r\ +< \n:global runningChannelVersion;\r\ +< \n:global runningChannel;\r\ +< \n:global runningVersion;\r\ +< \n\r\ +< \n:global devBuildTime;\r\ +< \n#:global ROsVerAvail;\r\ +< \n:global PkgUpdStatus;\r\ +< \n:global currentUpdateChannel;\r\ +< \n\r\ +< \n:global ScriptInstallUpdate;\r\ +< \n\r\ +< \n:global DeviceInfo;\r\ +< \n\r\ +< \n:global OldMode;\r\ +< \n\r\ +< \n:global ParseKeyValueStore;\r\ +< \n:global RandomDelay;\r\ +< \n:global GetRandomNumber;\r\ +< \n:global EscapeForRegEx;\r\ +< \n:global ExitError;\r\ +< \n:global CharacterMultiply;\r\ +< \n:global CharacterReplace;\r\ +< \n:global CleanFilePath;\r\ +< \n:global CleanName;\r\ +< \n\r\ +< \n:global CommitBrief;\r\ +< \n\r\ +< \n:global EitherOr;\r\ +< \n:global FormatLine;\r\ +< \n:global GetRandom20CharAlNum;\r\ +< \n:global Grep;\r\ +< \n:global IfThenElse;\r\ +< \n:global MAX;\r\ +< \n:global MIN;\r\ +< \n:global HumanReadableNum;\r\ +< \n\r\ +< \n:global IsFullyConnected;\r\ +< \n:global IsDNSResolving;\r\ +< \n:global IsTimeSync;\r\ +< \n:global IsTimeSyncCached;\r\ +< \n:global IsTimeSyncResetNtp;\r\ +< \n\r\ +< \n:global WaitDNSResolving;\r\ +< \n:global WaitFullyConnected;\r\ +< \n:global WaitTimeSync;\r\ +< \n:global MkDir;\r\ +< \n:global RmDir;\r\ +< \n:global RmFile;\r\ +< \n:global FileGet;\r\ +< \n:global Unix2Dos;\r\ +< \n:global UrlEncode;\r\ +< \n:global WaitForFile;\r\ +< \n:global ScriptLock;\r\ +< \n:global SendTelegram;\r\ +< \n:global NotificationFunctions;\r\ +< \n:global SendNotification;\r\ +< \n:global SendNotification2;\r\ +< \n:global SymbolForNotification;\r\ +< \n:global SymbolByUnicodeName;\r\ +< \n:global ValidateSyntax;\r\ +< \n:global CheckSumsVerify;\r\ +< \n:global GlobalConfChanges;\r\ +< \n:global GlobalConfMigration;\r\ +< \n:global VersionToNum;\r\ +< \n:global RequiredRouterOS;\r\ +< \n:global FetchLargeFiles;\r\ +< \n:global FetchUserAgentStr;\r\ +< \n:global CertificateAvailable;\r\ +< \n:global CertificateDownload;\r\ +< \n:global CertificateNameByCN;\r\ +< \n:global CharacterMultiply;\r\ +< \n\r\ +< \n:global InspectVar;\r\ +< \n:global InspectVarRet;\r\ +< \n:global ParseCustom;\r\ +< \n\r\ +< \n:set IsCheckUpdates do={\r\ +< \n :local isInfo [:tobool \$1];\r\ +< \n :global LogPrint;\r\ +< \n :global updateChannel;\r\ +< \n :global PkgUpdStatus;\r\ +< \n \$LogPrint debug \$0 (\"\\\$isInfo = \" . \$isInfo); \r\ +< \n :local CurrentChannel [ /system/package/update/get channel ];\r\ +< \n :if (\$CurrentChannel != \$updateChannel) do={\r\ +< \n :retry command={/system/package/update set channel=\$updateChannel} \ +< \_delay=300ms max=5 on-error={};\r\ +< \n \$LogPrint debug \$0 (\"Set updates channel to: \$updateChannel\");\ +< \r\ +< \n }\r\ +< \n\r\ +< \n :local Update [ /system/package/update/get ];\r\ +< \n :local Channel (\$Update->\"channel\");\r\ +< \n \$LogPrint debug \$0 (\"Update Channel: \" . \$Channel . \".\");\r\ +< \n\r\ +< \n :local StatusPkg \"undefined\";\r\ +< \n \$LogPrint debug \$0 (\"Checking for updates...\");\r\ +< \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ +< dates without-paging as-value]->\"status\")} \\\r\ +< \n delay=300ms max=5 on-error={};\r\ +< \n \$LogPrint debug \$0 (\"\\\$StatusPkg = \" . \$StatusPkg);\r\ +< \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ +< s true; } else={ :set PkgUpdStatus false; }\r\ +< \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ +< \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ +< \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ +< \n :if ([:len \$arrDeviceInfo] = 0) do={\r\ +< \n :global arrDeviceInfo ({});\r\ +< \n :local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};}\ +< );\r\ +< \n }\r\ +< \n # else={:local arrDeviceInfo ({})}\r\ +< \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [[ :parse \"/\ +< system/package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"\ +< Error\")};\r\ +< \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannel\"; \$Cu\ +< rrentChannel;};\r\ +< \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentVersion\"; (\$U\ +< pdate->\"installed-version\");};\r\ +< \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannelVersion\ +< \"; [/system/resource/get version];};\r\ +< \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateChannel\"; [\$up\ +< dateChannel];};\r\ +< \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateVersion\"; (\$Up\ +< date->\"latest-version\");};\r\ +< \n } else={\r\ +< \n :return \$PkgUpdStatus;\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n:set WaitArrDeviceInfo do={\r\ +< \n :global GetArrDeviceInfo;\r\ +< \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ +< \n :delay 1s;\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n:set GetArrDeviceInfo do={\r\ +< \n :global LogPrint;\r\ +< \n\r\ +< \n :global devBoardName;\r\ +< \n :global devModel;\r\ +< \n\r\ +< \n :global arrDeviceInfo [:toarray {\"section\"={\"key\"=\"\"; \"value\"\ +< =\"\";} }];\r\ +< \n #:do {:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system/package\ +< /update/get\" ]]} on-error={}\r\ +< \n :global devRbRevision;\r\ +< \n :global devRbSerialNumber;\r\ +< \n :global devRbCurrentFw;\r\ +< \n :global devRbUpgradeFw;\r\ +< \n\r\ +< \n :global devRunning;\r\ +< \n :global devCurArch;\r\ +< \n :global ROsVerCurrent;\r\ +< \n :global ROsChannelCurrent;\r\ +< \n :global ROsVerAvail;\r\ +< \n\r\ +< \n :global ParseCustom;\r\ +< \n :global runningChannelVersion;\r\ +< \n :global runningChannel;\r\ +< \n :global runningVersion;\r\ +< \n :global devBuildTime;\r\ +< \n :global GetPubIp;\r\ +< \n\r\ +< \n :local License [/system/license/get];\r\ +< \n :local Resource [/system/resource/get];\r\ +< \n :set devBuildTime (\$Resource->\"build-time\");\r\ +< \n :set runningChannelVersion (\$Resource->\"version\");\r\ +< \n :set runningChannel [\$ParseCustom \$runningChannelVersion \"(\" \")\ +< \" 1];\r\ +< \n :set runningVersion [\$ParseCustom \$runningChannelVersion \" \"];\r\ +< \n\r\ +< \n :do {\r\ +< \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ +< \_3] != \"x86\") do={\r\ +< \n :local RouterBoard;\r\ +< \n :do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on\ +< -error={}\r\ +< \n :set devModel (\$RouterBoard->\"model\");\r\ +< \n :set devRbRevision (\$RouterBoard->\"revision\");\r\ +< \n :set devRbSerialNumber (\$RouterBoard->\"serial-number\");\r\ +< \n #:set devRbCurrentFw (\$RouterBoard->\"current-firmware\");\r\ +< \n #:set devRbUpgradeFw (\$RouterBoard->\"upgrade-firmware\");\r\ +< \n :if (\$devCurArch = \"mipsbe\" || \$devCurArch = \"arm\") do={\r\ +< \n :global devRunning [ /system/device-mode/get mode ];\r\ +< \n } else={\r\ +< \n :global devRunning [/system/device-mode/get running];}\r\ +< \n } else={\r\ +< \n :set devModel \$devBoardName;\r\ +< \n \r\ +< \n :set devRbRevision false;\r\ +< \n :set devRbSerialNumber false;\r\ +< \n# :set devRbCurrentFw false;\r\ +< \n# :set devRbUpgradeFw false;\r\ +< \n #:set devCurrentFw \$runningVersion;#:set devUpgradeFw \$ROsVerAvail\ +< ;\r\ +< \n :set devRunning [/system/device-mode/get running];\r\ +< \n }\r\ +< \n } on-error={\r\ +< \n \$LogPrint error \$0 (\"Error in Function getDevice!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n:return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set DeviceInfo do={\r\ +< \n :global WaitArrDeviceInfo;\r\ +< \n # \$WaitDeviceInfo;\r\ +< \n :global devBoardName;\r\ +< \n :global devCurArch;\r\ +< \n :global devModel;\r\ +< \n :global devRunning;\r\ +< \n :global devRbRevision;\r\ +< \n :global devRbSerialNumber;\r\ +< \n :global PiblicIpAddress;\r\ +< \n\r\ +< \n :global GlobalConfVersion;\r\ +< \n :global Identity;\r\ +< \n :global IfThenElse;\r\ +< \n :global FormatLine;\r\ +< \n :local Return;\r\ +< \n :local License [/system/license/get];\r\ +< \n :local Resource [/system/resource/get];\r\ +< \n :local Snmp [ /snmp/get ];\r\ +< \n :local Update [ /system/package/update/get ];\r\ +< \n\r\ +< \n :set Return ([ \$FormatLine \"Hostname:\" \$Identity ] . \"\\n\" . \\\ +< \r\ +< \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ +< \n ([ \$FormatLine \"Location:\" (\$Snmp->\"location\") ] . \"\\n\") \ +< ] . \\\r\ +< \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ +< \n ([ \$FormatLine \"Contact:\" (\$Snmp->\"contact\") ] . \"\\n\") ] \ +< . \\\r\ +< \n \"Hardware:\\n\" . \\\r\ +< \n [ \$FormatLine \" Board:\" . \$devBoardName ] . \"\\n\" . \\\r\ +< \n [ \$FormatLine \" Arch:\" . \$devCurArch ] . \"\\n\" . \\\r\ +< \n [ \$FormatLine \" Model:\" \$devModel ] . \\\r\ +< \n [ \$IfThenElse ([ :len \$devRbRevision ] > 0) \\\r\ +< \n (\" \" . \$devRbRevision) ] . \"\\n\" . \\\r\ +< \n [ \$IfThenElse ([ :len \$devRbSerialNumber ] > 0) \\\r\ +< \n ([ \$FormatLine \" Serial:\" . \$devRbSerialNumber ] . \"\\n\"\ +< ) ] . \\\r\ +< \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ +< \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"nleve\ +< l\")) ] . \"\\n\") ] . \"RouterOS:\\n\" . \\\r\ +< \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ +< \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"level\ +< \")) ] . \"\\n\") ] . \\\r\ +< \n [ \$FormatLine \"Running Channel\" \$runningChannel ] . \"\\n\" . \\\ +< \r\ +< \n [ \$FormatLine \" Installed:\" (\$Update->\"installed-version\") \ +< ] . \"\\n\" . \\\r\ +< \n [ \$IfThenElse ([ :typeof (\$Update->\"latest-version\") ] != \"noth\ +< ing\" && \\\r\ +< \n \$Update->\"installed-version\" != \$Update->\"latest-version\")\ +< \_\\\r\ +< \n ([ \$FormatLine \" Available\" (\$Update->\"latest-version\") ]\ +< \_. \"\\n\") ] . \\\r\ +< \n [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true && \\\r\ +< \n \$RouterBoard->\"current-firmware\" != \$RouterBoard->\"upgrade-\ +< firmware\") \\\r\ +< \n ([ \$FormatLine \" Firmware\" (\$RouterBoard->\"current-firmwar\ +< e\") ] . \"\\n\") ] . \\ \r\ +< \n \"RouterOS-Scripts:\\n\" . \\\r\ +< \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ +< \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ +< \n}\r\ +< \n\r\ +< \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ +< tionFunctions ({})}\r\ +< \n:set GetRandom20CharAlNum do={\r\ +< \n :global EitherOr;\r\ +< \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ +< FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ +< \n}\r\ +< \n\r\ +< \n:global checkRunJob;\r\ +< \n:set checkRunJob do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :global ScriptLock; \r\ +< \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ +< \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ +< :set Job [ /system/script/job/get \$Job ];\r\ +< \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ +< stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ +< \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ +< lse; \r\ +< \n}\r\ +< \n\r\ +< \n:set InspectVar do={\r\ +< \n :global InspectVarRet;\r\ +< \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ +< \n}\r\ +< \n\r\ +< \n:set CommitBrief do={\r\ +< \n :global CommitId;\r\ +< \n :global CommitInfo;\r\ +< \n :if (\$CommitId = \"unknown\") do={\r\ +< \n :return \"unknown\";\r\ +< \n }\r\ +< \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ +< \n}\r\ +< \n\r\ +< \n:set InspectVarRet do={\r\ +< \n :local Input \$1;\r\ +< \n :local Level (0 + [ :tonum \$2 ]);\r\ +< \n :global CharacterReplace;\r\ +< \n :global IfThenElse;\r\ +< \n :global InspectVarRet;\r\ +< \n :local IndentReturn do={\r\ +< \n :local Prefix [ :tostr \$1 ];\r\ +< \n :local Value [ :tostr \$2 ];\r\ +< \n :local Level [ :tonum \$3 ];\r\ +< \n :global CharacterMultiply;\r\ +< \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ +< fix . \"-> \" . \$Value);\r\ +< \n }\r\ +< \n :local TypeOf [ :typeof \$Input ];\r\ +< \n :local Len [ :len \$Input ];\r\ +< \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ +< \n :if (\$TypeOf = \"array\") do={\r\ +< \n :foreach Key,Value in=\$Input do={\r\ +< \n :set \$Return (\$Return . \"\\n\" . \\\r\ +< \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ +< \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ +< \n }\r\ +< \n } else={\r\ +< \n :if (\$TypeOf = \"str\") do={\r\ +< \n :set \$Return (\$Return . \"\\n\" . \\\r\ +< \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ +< \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ +< \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ +< \n }\r\ +< \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ +< \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ +< \n }\r\ +< \n }\r\ +< \n :if (\$TypeOf != \"nothing\") do={\r\ +< \n :set \$Return (\$Return . \"\\n\" . \\\r\ +< \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ +< \_\\\r\ +< \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ +< \n }\r\ +< \n }\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n# !!! The function is not ready !!!\r\ +< \n:global FetchHttpInfo do={\r\ +< \n :local Mac [ :tostr \$1 ];\r\ +< \n :global CertificateAvailable;\r\ +< \n :global IsMacLocallyAdministered;\r\ +< \n :global LogPrint;\r\ +< \n :local Url \"https://api.macvendors.com/\";\r\ +< \n :if ([ \$IsMacLocallyAdministered \$Mac ] = true) do={:return \"locall\ +< y administered\";}\r\ +< \n :do {\r\ +< \n :if ([ \$CertificateAvailable \"GTS Root R4\" \"fetch\" ] = false) d\ +< o={\r\ +< \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ +< \");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :local Vendor ([ /tool/fetch \r\ +< \n (\$Url . [ :pick \$Mac 0 8 ]) output=user as-value ]->\"data\");\r\ +< \n :return \$Vendor;\r\ +< \n } on-error={\r\ +< \n :onerror Err {\r\ +< \n /tool/fetch check-certificate=yes-without-crl (\$Url) output=none \ +< as-value;\r\ +< \n \$LogPrint debug \$0 (\"The mac vendor is not known in database.\"\ +< );\r\ +< \n } do={ \$LogPrint warning \$0 (\"Failed getting mac vendor: \" . \$E\ +< rr); }\r\ +< \n :return \"unknown vendor\";\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n:set GetPubIp do={\r\ +< \n :global DetectIpAddrDefault;\r\ +< \n :global DetectIpAddrFallback;\r\ +< \n :global LogPrint;\r\ +< \n \r\ +< \n :local PubIpAddr false;\r\ +< \n :local Url \$DetectIpAddrDefault;\r\ +< \n\r\ +< \n# :retry command={abc} delay=1 max=2 on-error={:put \"got error\"} \r\ +< \n :do {\r\ +< \n \$LogPrint debug \$0 (\"Trying to detect public IP using default s\ +< ervice: \" . \$Url . \"...\");\r\ +< \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ +< \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ +< )} \\\r\ +< \n delay=50ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fail\ +< ed to detect public IP using default service: \" . \$Url . \".\")}\r\ +< \n #:error \"Failed to detect public IP using default service: \$Url\ +< .\"};\r\ +< \n } on-error={\r\ +< \n \$LogPrint error \$0 (\"Failed to detect public IP using default s\ +< ervice: \" . \$Url . \".\");\r\ +< \n :set Url \$DetectIpAddrFallBack;\r\ +< \n \$LogPrint debug \$0 (\"Trying to detect public IP using fallback \ +< service: \" . \$Url . \"...\");\r\ +< \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ +< \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ +< )} \\\r\ +< \n delay=200ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fai\ +< led to detect public IP using fallback service: \" . \$Url . \".\")}\r\ +< \n };\r\ +< \n :if (\$PubIpAddr = false) do={\r\ +< \n :set PubIpAddr \"not-detected\";\r\ +< \n } else={\r\ +< \n :set PubIpAddr [ :pick \$PubIpAddr 0 15];\r\ +< \n }\r\ +< \n :return \$PubIpAddr;\r\ +< \n}\r\ +< \n\r\ +< \n:set FormatLine do={\r\ +< \n :local Key [ :tostr \$1 ];\r\ +< \n :local Value [ :tostr \$2 ];\r\ +< \n :local Indent [ :tonum \$3 ];\r\ +< \n :local Spaces;\r\ +< \n :local Return \"\";\r\ +< \n :global CharacterMultiply;\r\ +< \n :global EitherOr;\r\ +< \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ +< \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ +< \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ +< \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ +< n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ +< \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ +< \$Return ]) ] . \$Value)}\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set ParseCustom do={\r\ +< \n :local Str [ :tostr \$1 ];\r\ +< \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ +< \n :local End [ :tostr \$3 ];\r\ +< \n :local Num [ :tonum \$4 ];\r\ +< \n :local Return;\r\ +< \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ +< \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ +< \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ +< lse={\r\ +< \n :set End [:find \$rest \$End];\r\ +< \n :set Return [:pick \$rest 0 \$End];\r\ +< \n }\r\ +< \n:return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set LogPrint do={\r\ +< \n :local Severity [ :tostr \$1 ];\r\ +< \n :local Name [ :tostr \$2 ];\r\ +< \n :local Message [ :tostr \$3 ];\r\ +< \n :global PrintDebug;\r\ +< \n :global PrintDebugOverride;\r\ +< \n :global EitherOr;\r\ +< \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ +< ];\r\ +< \n :local PrintSeverity do={\r\ +< \n :global TerminalColorOutput;\r\ +< \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ +< \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ +< \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ +< \n}\r\ +< \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ +< \r\ +< \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ +< \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ +< \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ +< \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ +< \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ +< \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ +< erity \$Severity ] . \": \" . \$Message)}\r\ +< \n}\r\ +< \n\r\ +< \n:set CertificateAvailable do={\r\ +< \n :local CommonName [ :tostr \$1 ];\r\ +< \n :local UseFor [ :tostr \$2 ];\r\ +< \n :global CertificateDownload;\r\ +< \n :global EitherOr;\r\ +< \n :global LogPrint;\r\ +< \n :global ParseKeyValueStore;\r\ +< \n :set UseFor [ \$EitherOr \$UseFor \"undefined\" ];\r\ +< \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ +< \n [ /certificate/settings/get crl-download ] = true && \\\r\ +< \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ +< \n \$LogPrint warning \$0 (\"This system has low free flash space but \ +< \" . \\\r\ +< \n \"is configured to download certificate CRLs to system!\");\r\ +< \n }\r\ +< \n :if ([ :len \$CommonName ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"No CommonName given!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local CertSettings [ /certificate/settings/get ];\r\ +< \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ +< \r\ +< \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ +< \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ +< \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ +< \_] ] > 0) do={\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ +< ) do={\r\ +< \n \$LogPrint info \$0 (\"Certificate with CommonName '\" . \$CommonNam\ +< e . \"' not available.\");\r\ +< \n :if ([ \$CertificateDownload \$CommonName ] = false) do={:return fal\ +< se}\r\ +< \n }\r\ +< \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ +< ) do={\r\ +< \n \$LogPrint info \$0 (\"There are \" . \$CertCount . \" Certificates \ +< with CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ +< e ] ];\r\ +< \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ +< ertVal->\"skid\")) do={\r\ +< \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ +< \_= 0) do={\r\ +< \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ +< >\"CN\");\r\ +< \n \$LogPrint info \$0 (\"Certificate chain for '\" . \$CommonName . \ +< \"' is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ +< \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={:return fal\ +< se}\r\ +< \n }\r\ +< \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ +< \") ] ];\r\ +< \n }\r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set CertificateDownload do={\r\ +< \n :local CommonName [ :tostr \$1 ];\r\ +< \n :global GlobalScriptsUrl;\r\ +< \n :global GlobalScriptsUrlSuffix;\r\ +< \n :global CertificateNameByCN;\r\ +< \n :global CleanName;\r\ +< \n :global FetchUserAgentStr;\r\ +< \n :global LogPrint;\r\ +< \n :global RmFile;\r\ +< \n :global WaitForFile;\r\ +< \n \r\ +< \n \$LogPrint info \$0 (\"Downloading and importing certificate with Comm\ +< onName '\" . \$CommonName . \"'.\");\r\ +< \n \r\ +< \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ +< \n :do {\r\ +< \n /tool/fetch check-certificate=yes-without-crl http-header-field=({ [\ +< \_\$FetchUserAgentStr \$0 ] }) \\\r\ +< \n (\$GlobalScriptsUrl . \"certs/\" . \$FileName . \$GlobalScriptsUrl\ +< Suffix) dst-path=\$FileName as-value;\r\ +< \n \$WaitForFile \$FileName;\r\ +< \n } on-error={\r\ +< \n \$LogPrint warning \$0 (\"Failed downloading certificate with Common\ +< Name '\" . \$CommonName . \\\r\ +< \n \"' from repository! Trying fallback to mkcert.org...\");\r\ +< \n :do {\r\ +< \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ +< \_] ] = 0) do={\r\ +< \n \$LogPrint error \$0 (\"Required certificate is not available.\"\ +< );\r\ +< \n :return false;\r\ +< \n }\r\ +< \n /tool/fetch check-certificate=yes-without-crl http-header-field=({\ +< \_[ \$FetchUserAgentStr \$0 ] }) \\\r\ +< \n \"https://mkcert.org/generate/\" http-data=[ :serialize to=json \ +< ({ \$CommonName }) ] \\\r\ +< \n dst-path=\$FileName as-value;\r\ +< \n \$WaitForFile \$FileName;\r\ +< \n :if ([ /file/get \$FileName size ] = 0) do={\r\ +< \n \$RmFile \$FileName;\r\ +< \n :error false;\r\ +< \n }\r\ +< \n } on-error={\r\ +< \n \$LogPrint warning \$0 (\"Failed downloading certificate with Comm\ +< onName '\" . \$CommonName . \"'!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n }\r\ +< \n\r\ +< \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ +< \n :delay 1s;\r\ +< \n \$RmFile \$FileName;\r\ +< \n\r\ +< \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ +< ) do={\r\ +< \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ +< +\\\$\") ];\r\ +< \n \$LogPrint warning \$0 (\"Certificate with CommonName '\" . \$Common\ +< Name . \"' still unavailable!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ +< \"_[0-9]+\\\$\") ] do={\r\ +< \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ +< \n }\r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set CertificateNameByCN do={\r\ +< \n :local Match [ :tostr \$1 ];\r\ +< \n :global CleanName;\r\ +< \n :global LogPrint;\r\ +< \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ +< rint=\$Match or name=\$Match) ]->0);\r\ +< \n :if ([ :len \$Cert ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"No matching certificate found.\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ +< \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set CharacterMultiply do={\r\ +< \n :local Str [ :tostr \$1 ];\r\ +< \n :local Num [ :tonum \$2 ];\r\ +< \n :if (\$Num = 0) do={:return \"\"}\r\ +< \n :local Return \"\";\r\ +< \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set FetchUserAgentStr do={\r\ +< \n :local Caller [ :tostr \$1 ];\r\ +< \n :global IfThenElse;\r\ +< \n :local Resource [ /system/resource/get ];\r\ +< \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ +< \_\$Resource->\"architecture-name\" . \\\r\ +< \n \" \" . \$Caller . \"/Fetch (https://amster.vados.ru/; main/3419/3ee\ +< 19780)\");\r\ +< \n}\r\ +< \n\r\ +< \n:set Grep do={\r\ +< \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ +< \n :local Pattern [ :tostr \$2 ];\r\ +< \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ +< }\r\ +< \n :do {\r\ +< \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ +< \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ +< \$Line}\r\ +< \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ +< Input ] ];\r\ +< \n } while=([ :len \$Input ] > 0);\r\ +< \n :return [];\r\ +< \n}\r\ +< \n\r\ +< \n:set HumanReadableNum do={\r\ +< \n :local Input [ :tonum \$1 ];\r\ +< \n :local Base [ :tonum \$2 ];\r\ +< \n :global EitherOr;\r\ +< \n :global IfThenElse;\r\ +< \n :local Prefix \"kMGTPE\";\r\ +< \n :local Pow 1;\r\ +< \n :set Base [ \$EitherOr \$Base 1024 ];\r\ +< \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ +< \n :if (\$Input < \$Base) do={:return \$Input}\r\ +< \n :for I from=0 to=[ :len \$Prefix ] do={\r\ +< \n :set Pow (\$Pow * \$Base);\r\ +< \n :if (\$Input / \$Base < \$Pow) do={\r\ +< \n :set Prefix [ :pick \$Prefix \$I ];\r\ +< \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ +< \n :local Tmp2 (\$Tmp1 / 100);\r\ +< \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ +< \n :return (\$Tmp2 . \".\" . \\\r\ +< \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ +< 2 ] + 1) ] . \\\r\ +< \n \$Prefix . \$Bin);\r\ +< \n }\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n:set CleanName do={\r\ +< \n :local Input [ :tostr \$1 ];\r\ +< \n :local Return \"\";\r\ +< \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +< \n :local Char [ :pick \$Input \$I ];\r\ +< \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ +< stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ +< \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ +< \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ +< ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ +< \n };\r\ +< \n :set Return (\$Return . \$Char)};\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set GetRandomNumber do={\r\ +< \n :global EitherOr;\r\ +< \n :return [ :rndnum from=0 to=[ \$EitherOr [ :tonum \$1 ] 4294967295 ] ]\ +< \r\ +< \n}\r\ +< \n\r\ +< \n:set RandomDelay do={\r\ +< \n :local Time [ :tonum \$1 ];\r\ +< \n :local Unit [ :tostr \$2 ];\r\ +< \n :global EitherOr;\r\ +< \n :global GetRandomNumber;\r\ +< \n :global MAX;\r\ +< \n :if (\$Time = 0) do={:return false}\r\ +< \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ +< [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ +< \n}\r\ +< \n\r\ +< \n:set EscapeForRegEx do={\r\ +< \n :local Input [ :tostr \$1 ];\r\ +< \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ +< \n :local Return \"\";\r\ +< \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ +< \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +< \n :local Char [ :pick \$Input \$I ];\r\ +< \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ +< \n :set Return (\$Return . \$Char);\r\ +< \n }\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n:set ExitError do={\r\ +< \n :local ExitOK [ :tostr \$1 ];\r\ +< \n :local Name [ :tostr \$2 ];\r\ +< \n :local Error [ :tostr \$3 ];\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :if (\$ExitOK = \"false\") do={\r\ +< \n \$LogPrint error \$Name ([ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\ +< \$\") \\\r\ +< \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ +< ror\" . \\\r\ +< \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ +< \$Error) \".\" ]);\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n:set MiniDateTimeStamp do={\r\ +< \n /system/clock;\r\ +< \n :local vdate [get date];\r\ +< \n :local vtime [get time];\r\ +< \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ +< \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ +< \n :local M [:tonum \$MM];\r\ +< \n :if (\$vdate ~ \".../../....\") do={\r\ +< \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ +< \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ +< PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ +< \n :if (\$M>12) do={:set M (\$M - 12)}\r\ +< \n :set MM [:pick (100 + \$M) 1 3];\r\ +< \n }\r\ +< \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ +< \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ +< \n :local HH [:pick \$vtime 0 2];\r\ +< \n :local mm [:pick \$vtime 3 5];\r\ +< \n :local ss [:pick \$vtime 6 8];\r\ +< \n :return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\r\ +< \n}\r\ +< \n\r\ +< \n:set WaitForFile do={\r\ +< \n :local FileName [ :tostr \$1 ];\r\ +< \n :local WaitTime [ :totime \$2 ];\r\ +< \n :global CleanFilePath;\r\ +< \n :global EitherOr;\r\ +< \n :global MAX;\r\ +< \n :set FileName [ \$CleanFilePath \$FileName ];\r\ +< \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ +< \n :do {\r\ +< \n :retry {\r\ +< \n /file/get \$FileName;\r\ +< \n :return true;\r\ +< \n } delay=\$Delay max=10;\r\ +< \n } on-error={ }\r\ +< \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ +< \n :do {\r\ +< \n /file/get \$FileName;\r\ +< \n :return true;\r\ +< \n } on-error={ }\r\ +< \n :delay \$Delay;\r\ +< \n :set Delay (\$Delay * 3 / 2);\r\ +< \n }\r\ +< \n :return false;\r\ +< \n}\r\ +< \n\r\ +< \n:set FileGet do={\r\ +< \n :local FileName [ :tostr \$1 ];\r\ +< \n :global WaitForFile;\r\ +< \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={:return false}\r\ +< \n :local FileVal false;\r\ +< \n :do {:set FileVal [ /file/get \$FileName ];\r\ +< \n } on-error={ }\r\ +< \n :return \$FileVal;\r\ +< \n}\r\ +< \n\r\ +< \n:set RmDir do={\r\ +< \n :local DirName [ :tostr \$1 ];\r\ +< \n :global FileGet;\r\ +< \n :global LogPrint;\r\ +< \n \$LogPrint debug \$0 (\"Removing directory: \". \$DirName);\r\ +< \n :local DirVal [ \$FileGet \$DirName ];\r\ +< \n :if (\$DirVal = false) do={\$LogPrint debug \$0 (\"... which does not \ +< exist.\"); :return true};\r\ +< \n :if (\$DirVal->\"type\" != \"directory\") do={\$LogPrint error \$0 (\"\ +< Directory '\" . \$DirName . \"' is not a directory.\"); :return false};\r\ +< \n :onerror Err {/file/remove \$DirName} do={\$LogPrint error \$0 (\"Remo\ +< ving directory '\" . \$DirName . \"' failed: \" . \$Err); :return false};\ +< \r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set RmFile do={\r\ +< \n :local FileName [ :tostr \$1 ];\r\ +< \n :global FileGet;\r\ +< \n :global LogPrint;\r\ +< \n \$LogPrint debug \$0 (\"Removing file: \". \$FileName);\r\ +< \n :local FileVal [ \$FileGet \$FileName ];\r\ +< \n :if (\$FileVal = false) do={\$LogPrint debug \$0 (\"... which does not\ +< \_exist.\"); :return true}\r\ +< \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ +< sk\") do={\r\ +< \n \$LogPrint error \$0 (\"File '\" . \$FileName . \"' is not a file.\"\ +< ); :return false}\r\ +< \n :onerror Err {\r\ +< \n /file/remove \$FileName;\r\ +< \n } do={\$LogPrint error \$0 (\"Removing file '\" . \$FileName . \"' fai\ +< led: \" . \$Err); :return false}\r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set MkDir do={\r\ +< \n :local Path [ :tostr \$1 ];\r\ +< \n :global CleanFilePath;\r\ +< \n :global FileGet;\r\ +< \n :global RmDir;\r\ +< \n :global WaitForFile;\r\ +< \n :global LogPrint;\r\ +< \n :local MkTmpfs do={\r\ +< \n :global WaitForFile;\r\ +< \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ +< \n :if ([ :len \$TmpFs ] = 1) do={\r\ +< \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ +< \n \$LogPrint info \$0 (\"The tmpfs is disabled, enabling.\");\r\ +< \n /disk/enable \$TmpFs;\r\ +< \n }\r\ +< \n :return true;\r\ +< \n }\r\ +< \n \$LogPrint info \$0 (\"Creating disk of type tmpfs.\");\r\ +< \n \$RmDir \"tmpfs\";\r\ +< \n :onerror Err {\r\ +< \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ +< /get total-memory ] / 3);\r\ +< \n \$WaitForFile \"tmpfs\";\r\ +< \n } do={\r\ +< \n \$LogPrint warning \$0 (\"Creating disk of type tmpfs failed: \" .\ +< \_\$Err);\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :set Path [ \$CleanFilePath \$Path ];\r\ +< \n :if (\$Path = \"\") do={\r\ +< \n :return true;\r\ +< \n }\r\ +< \n \$LogPrint debug \$0 (\"Making directory: \" . \$Path);\r\ +< \n :local PathVal [ \$FileGet \$Path ];\r\ +< \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ +< \n \$LogPrint debug \$0 (\"... which already exists.\");\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ +< \n :if ([ \$MkTmpfs ] = false) do={\r\ +< \n :return false;\r\ +< \n }\r\ +< \n }\r\ +< \n :onerror Err {\r\ +< \n /file/add type=\"directory\" name=\$Path;\r\ +< \n \$WaitForFile \$Path;\r\ +< \n } do={\r\ +< \n \$LogPrint warning \$0 (\"Making directory '\" . \$Path . \"' failed\ +< : \" . \$Err);\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ +< \n :return \$2;\r\ +< \n}\r\ +< \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ +< \n :return \$2;\r\ +< \n}\r\ +< \n\r\ +< \n:set CharacterMultiply do={\r\ +< \n :local Str [ :tostr \$1 ];\r\ +< \n :local Num [ :tonum \$2 ];\r\ +< \n :if (\$Num = 0) do={:return \"\"}\r\ +< \n :local Return \"\";\r\ +< \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set CharacterReplace do={\r\ +< \n :local String [ :tostr \$1 ];\r\ +< \n :local ReplaceFrom [ :tostr \$2 ];\r\ +< \n :local ReplaceWith [ :tostr \$3 ];\r\ +< \n :local Return \"\";\r\ +< \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ +< \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ +< \r\ +< \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ +< \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ +< \r\ +< \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ +< \_\$String ] ];\r\ +< \n }\r\ +< \n :return (\$Return . \$String);\r\ +< \n}\r\ +< \n\r\ +< \n:set CleanFilePath do={\r\ +< \n :local Path [ :tostr \$1 ];\r\ +< \n :global CharacterReplace;\r\ +< \n :while (\$Path ~ \"//\") do={:set \$Path [ \$CharacterReplace \$Path \ +< \"//\" \"/\" ]};\r\ +< \n :if ([ :pick \$Path 0 ] = \"/\") do={:set Path [ :pick \$Path 1 [ :len\ +< \_\$Path ] ]};\r\ +< \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={:set Path [ :\ +< pick \$Path 0 ([ :len \$Path ] - 1) ]};\r\ +< \n :return \$Path;\r\ +< \n}\r\ +< \n\r\ +< \n:set IfThenElse do={\r\ +< \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ +< \$2};\r\ +< \n :return \$3;\r\ +< \n}\r\ +< \n\r\ +< \n:set EitherOr do={\r\ +< \n :global IfThenElse;\r\ +< \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ +< \$1 \$2 ]}\r\ +< \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ +< \_\$1 \$2 ]}\r\ +< \n# this works for boolean values, literal ones with parentheses\r\ +< \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ +< \n}\r\ +< \n\r\ +< \n:set ParseKeyValueStore do={\r\ +< \n :local Source \$1;\r\ +< \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ +< \n :do {\r\ +< \n :return [ :deserialize from=json \$Source ];\r\ +< \n } on-error={ }\r\ +< \n } \r\ +< \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ +< }\r\ +< \n :local Result ({});\r\ +< \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ +< \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ +< \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ +< \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ +< \_:len \$KeyValue ] ];\r\ +< \n :if (\$Value=\"true\") do={:set Value true}\r\ +< \n :if (\$Value=\"false\") do={:set Value false}\r\ +< \n :set (\$Result->\$Key) \$Value;\r\ +< \n } else={:set (\$Result->\$KeyValue) true}\r\ +< \n }\r\ +< \n :return \$Result;\r\ +< \n}\r\ +< \n:set RequiredRouterOS do={\r\ +< \n :local Caller [ :tostr \$1 ];\r\ +< \n :local Required [ :tostr \$2 ];\r\ +< \n :local Warn [ :tostr \$3 ];\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :global VersionToNum;\r\ +< \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ +< \\\$\")) do={\r\ +< \n \$LogPrint error \$0 (\"No valid RouterOS version: \" . \$Required);\ +< \r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ +< e/update/get installed-version ] ]) do={\r\ +< \n :if (\$Warn = \"true\") do={\r\ +< \n \$LogPrint warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \$Call\ +< er 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ +< \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ +< es RouterOS \" . \$Required . \". Please update!\");\r\ +< \n }\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :return true;\r\ +< \n}\r\ +< \n:set VersionToNum do={\r\ +< \n :local Input [ :tostr \$1 ];\r\ +< \n :local Multi 0x1000000;\r\ +< \n :local Return 0;\r\ +< \n :global CharacterReplace;\r\ +< \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ +< \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ +< \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ +< \r\ +< \n }\r\ +< \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ +< \n :local Num [ :tonum \$Value ];\r\ +< \n :if (\$Multi = 0x100) do={\r\ +< \n :if ([ :typeof \$Num ] = \"num\") do={\r\ +< \n :set Return (\$Return + 0xff00);\r\ +< \n :set Multi (\$Multi / 0x100);\r\ +< \n } else={\r\ +< \n :if (\$Value = \"zero\") do={ }\r\ +< \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ +< }\r\ +< \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ +< \r\ +< \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ +< \n }\r\ +< \n }\r\ +< \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ +< lue * \$Multi)); }\r\ +< \n :set Multi (\$Multi / 0x100);\r\ +< \n }\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n:set ScriptLock do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :local WaitMax [ :totime \$2 ];\r\ +< \n :global GetRandom20CharAlNum;\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :global ScriptLockOrder;\r\ +< \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ +< \n :set ScriptLockOrder ({});\r\ +< \n }\r\ +< \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ +< \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +< \n }\r\ +< \n :local JobCount do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ +< \r\ +< \n }\r\ +< \n :local TicketCount do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :global ScriptLockOrder;\r\ +< \n :local Count 0;\r\ +< \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +< \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ +< + 1)}\r\ +< \n }\r\ +< \n :return \$Count;\r\ +< \n }\r\ +< \n :local IsFirstTicket do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :local Check [ :tostr \$2 ];\r\ +< \n :global ScriptLockOrder;\r\ +< \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +< \n :if (\$Ticket = \$Check) do={:return true}\r\ +< \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ +< o={:return false}\r\ +< \n }\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local AddTicket do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :local Add [ :tostr \$2 ];\r\ +< \n :global ScriptLockOrder;\r\ +< \n :while (true) do={\r\ +< \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ +< \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ +< \n :delay 10ms;\r\ +< \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ +< e}\r\ +< \n }\r\ +< \n }\r\ +< \n :local RemoveTicket do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :local Remove [ :tostr \$2 ];\r\ +< \n :global ScriptLockOrder;\r\ +< \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +< \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ +< \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ +< \n :delay 10ms;\r\ +< \n }\r\ +< \n }\r\ +< \n }\r\ +< \n :local CleanupTickets do={\r\ +< \n :local Script [ :tostr \$1 ];\r\ +< \n :global ScriptLockOrder;\r\ +< \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ +< \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ +< \n }\r\ +< \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +< \n }\r\ +< \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ +< \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ +< \n \$LogPrint error \$0 (\"A script named '\" . \$Script . \"' does not\ +< \_exist!\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :if ([ \$JobCount \$Script ] = 0) do={\r\ +< \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ +< );\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ +< \n \$LogPrint error \$0 (\"More tickets than running scripts '\" . \$Sc\ +< ript . \"', resetting!\");\r\ +< \n :set (\$ScriptLockOrder->\$Script) ({});\r\ +< \n /system/script/job/remove [ find where script=\$Script ];\r\ +< \n }\r\ +< \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ +< \n \$AddTicket \$Script \$MyTicket;\r\ +< \n :local WaitInterval (\$WaitMax / 20);\r\ +< \n :local WaitTime \$WaitMax;\r\ +< \n :while (\$WaitTime > 0 && \\\r\ +< \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ +< \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ +< \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ +< \n :delay \$WaitInterval;\r\ +< \n }\r\ +< \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ +< \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ +< \n \$RemoveTicket \$Script \$MyTicket;\r\ +< \n \$CleanupTickets \$Script;\r\ +< \n :return true;\r\ +< \n }\r\ +< \n \$RemoveTicket \$Script \$MyTicket;\r\ +< \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ +< once\" . \\\r\ +< \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ +< \_lock\" \"\" ] . \"...\");\r\ +< \n :return false;\r\ +< \n}\r\ +< \n:set SendNotification do={ :onerror Err {\r\ +< \n :global SendNotification2;\r\ +< \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ +< \_silent=\$4 });\r\ +< \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ +< \n}\r\ +< \n:set SendNotification2 do={\r\ +< \n :local Notification \$1;\r\ +< \n :global NotificationFunctions;\r\ +< \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ +< \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ +< ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ +< \n }\r\ +< \n}\r\ +< \n:set SymbolByUnicodeName do={\r\ +< \n :local Name [ :tostr \$1 ];\r\ +< \n :global EitherOr;\r\ +< \n :global LogPrint;\r\ +< \n :global SymbolsExtra;\r\ +< \n :local Symbols ({\r\ +< \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ +< \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ +< \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ +< \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ +< \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ +< \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ +< \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ +< \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ +< \n \"cloud\"=\"\\E2\\98\\81\";\r\ +< \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ +< \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ +< \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ +< \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ +< \n \"gear\"=\"\\E2\\9A\\99\";\r\ +< \n \"heart\"=\"\\E2\\99\\A5\";\r\ +< \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ +< \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ +< \n \"information\"=\"\\E2\\84\\B9\";\r\ +< \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ +< \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ +< \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ +< \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ +< \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ +< \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ +< \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ +< \n \"scissors\"=\"\\E2\\9C\\82\";\r\ +< \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ +< \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ +< \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ +< \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ +< \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ +< \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ +< \n \"star\"=\"\\E2\\AD\\90\";\r\ +< \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ +< \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ +< \n }, \$SymbolsExtra);\r\ +< \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ +< \n :local Special {\r\ +< \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ +< \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ +< \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ +< \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ +< \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"No symbol available for name '\" . \$Name \ +< . \"'!\");\r\ +< \n :return \"\";\r\ +< \n }\r\ +< \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ +< me) ] . \"\\EF\\B8\\8F\");\r\ +< \n}\r\ +< \n:set SymbolForNotification do={\r\ +< \n :global NotificationsWithSymbols;\r\ +< \n :global SymbolByUnicodeName;\r\ +< \n :global IfThenElse;\r\ +< \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ +< \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ +< \n :local Return \"\";\r\ +< \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ +< mbolByUnicodeName \$Symbol ])}\r\ +< \n :return (\$Return . \" \");\r\ +< \n}\r\ +< \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ +< \n:set UrlEncode do={\r\ +< \n :local Input [ :tostr \$1 ];\r\ +< \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ +< \n :local Return \"\";\r\ +< \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ +< \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ +< %24\"; \"%25\"; \"%26\"; \"%27\";\r\ +< \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ +< \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ +< \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ +< \"%7C\"; \"%7D\"; \"%7E\" };\r\ +< \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ +< \n :local Char [ :pick \$Input \$I ];\r\ +< \n :local Replace [ :find \$Chars \$Char ];\r\ +< \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ +< ce)}\r\ +< \n :set Return (\$Return . \$Char);\r\ +< \n }\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n:set ValidateSyntax do={\r\ +< \n :local Code [ :tostr \$1 ];\r\ +< \n :global LogPrint;\r\ +< \n :onerror Err {\r\ +< \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ +< \n } do={\r\ +< \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :return true;\r\ +< \n}\r\ +< \n:set IsDNSResolving do={\r\ +< \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ +< \n :return true;\r\ +< \n}\r\ +< \n:set IsFullyConnected do={\r\ +< \n :global IsDNSResolving;\r\ +< \n :global IsTimeSync;\r\ +< \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ +< \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ +< \n :return true;\r\ +< \n}\r\ +< \n:set IsTimeSync do={\r\ +< \n :global IsTimeSyncCached;\r\ +< \n :global IsTimeSyncResetNtp;\r\ +< \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ +< \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ +< \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ +< \n :set IsTimeSyncCached true;\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :local Uptime [ /system/resource/get uptime ];\r\ +< \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ +< \n :set IsTimeSyncResetNtp \$Uptime;\r\ +< \n }\r\ +< \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ +< \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ +< ;\r\ +< \n :set IsTimeSyncResetNtp \$Uptime;\r\ +< \n /system/ntp/client/set enabled=no;\r\ +< \n :delay 20ms;\r\ +< \n /system/ntp/client/set enabled=yes;\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ +< \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ +< \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ +< ee license and x86.\";\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ +< \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ +< \n :set IsTimeSyncCached true;\r\ +< \n :return true;\r\ +< \n }\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ +< \r\ +< \n :return true;\r\ +< \n}\r\ +< \n\r\ +< \n# read parts of a large file\r\ +< \n:set FetchLargeFiles do={\r\ +< \n :local ScriptName [:tostr \$1];\r\ +< \n :local fetchUrl [:tostr \$2];\r\ +< \n :local CheckCert [:tostr \$3];\r\ +< \n :local fetchMode [:tostr \$4];\r\ +< \n :local fetchMethod [:tostr \$5];\r\ +< \n :local FetchString \"undefined\";\r\ +< \n \r\ +< \n :global CleanName;\r\ +< \n :global FetchUserAgentStr;\r\ +< \n :global GetRandom20CharAlNum;\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :global MkDir;\r\ +< \n :global RmDir;\r\ +< \n :global RmFile;\r\ +< \n :global WaitForFile;\r\ +< \n\r\ +< \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ +< ithout-crl\" ];\r\ +< \n #:set fetchMode [ \$IfThenElse (\$fetchMode != \"false\") [:tostr (\"m\ +< ode=\" . \$fetchMode)] ];\r\ +< \n #:set fetchMethod [\$IfThenElse (\$fetchMethod != \"false\") [:tostr (\ +< \"http-method=\\\"\" . \$fetchMethod . \"\\\"\") ]];\r\ +< \n \r\ +< \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ +< \n :if ([ \$MkDir \$DirName ] = false) do={\r\ +< \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ +< \$GetRandom20CharAlNum ]);\r\ +< \n #/tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName h\ +< ttp-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-value;\r\ +< \n #:log warning (\"\\\$fUrl =\" . \$2 . ({[ \$fMode ]}));\r\ +< \n :onerror Err {\r\ +< \n :set FetchString (\"/tool/fetch \" . \\\r\ +< \n [\$IfThenElse ([\$fetchMethod] != \"false\") (\"http-method=\\\"\"\ +< \_. \$fetchMethod . \"\\\" \")] . \\\r\ +< \n \"check-certificate=\" . \$CheckCert . \" url=(\\\"\" . \$fetchUrl\ +< \_. \"\\\") \" . \\\r\ +< \n [\$IfThenElse ([\$fetchMode] != \"false\") (\"mode=\" . \$fetchMod\ +< e . \" \")] . \\\r\ +< \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ +< lue);\r\ +< \n :log warning (\"\\\$FetchSring = \" . \$FetchString);\r\ +< \n :put [\$FetchString];\r\ +< \n #:put [/tool/fetch \$fetchMode check-certificate=\$CheckCert url=(\$\ +< fetchUrl) dst-path=(\$FileName) http-header-field=({ [ \$FetchUserAgentStr\ +< \_\$ScriptName ] }) as-value];\r\ +< \n } do={\r\ +< \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ +< \n \$RmFile \$FileName;\r\ +< \n }\r\ +< \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$fetchUrl . \"\ +< \_- \" . \$Err);\r\ +< \n \$RmDir \$DirName;\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ +< \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$fetchUrl . \ +< \" did not show up.\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local FileSize [ /file/get \$FileName size ];\r\ +< \n :local Return \"\";\r\ +< \n :local VarSize 0;\r\ +< \n :while (\$VarSize != \$FileSize) do={\r\ +< \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ +< 768 file=\$FileName as-value ]->\"data\"));\r\ +< \n :set FileSize [ /file/get \$FileName size ];\r\ +< \n :set VarSize [ :len \$Return ];\r\ +< \n :if (\$VarSize > \$FileSize) do={\r\ +< \n :delay 100ms;\r\ +< \n }\r\ +< \n }\r\ +< \n \$RmDir \$DirName;\r\ +< \n :return \$Return;\r\ +< \n}\r\ +< \n\r\ +< \n:set ScriptInstallUpdate do={ :onerror Err {\r\ +< \n :local Scripts [ :toarray \$1 ];\r\ +< \n :local NewComment [ :tostr \$2 ];\r\ +< \n :global InitSetup;\r\ +< \n\r\ +< \n :global CommitId;\r\ +< \n :global ScriptUpdatesCRLF;\r\ +< \n :global GlobalConfVersion;\r\ +< \n :global Identity;\r\ +< \n :global CertificateAvailable;\r\ +< \n :global CheckSumsVerify;\r\ +< \n :global GlobalScriptsUrl;\r\ +< \n :global SumsDirAndFileName;\r\ +< \n :global GlobalScriptsUrlSuffix;\r\ +< \n :global EitherOr;\r\ +< \n :global FetchUserAgentStr;\r\ +< \n :global Grep;\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :global ParseKeyValueStore;\r\ +< \n :global RequiredRouterOS;\r\ +< \n :global SendNotification2;\r\ +< \n :global SymbolForNotification;\r\ +< \n :global ValidateSyntax;\r\ +< \n :global CommentsInScripts;\r\ +< \n\r\ +< \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ +< hout.\");\r\ +< \n }\r\ +< \n\r\ +< \n :foreach Script in=\$Scripts do={\r\ +< \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ +< \r\ +< \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ +< \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ +< Vados\\n\" comment=\$NewComment;\r\ +< \n }\r\ +< \n }\r\ +< \n\r\ +< \n :local CommitIdBefore \$CommitId;\r\ +< \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ +< \n :local ReloadGlobal false;\r\ +< \n :local DeviceMode [ /system/device-mode/get ];\r\ +< \n\r\ +< \n :if (\$CheckSumsVerify = true) do={\r\ +< \n :local CheckSums ({});\r\ +< \n :do {\r\ +< \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ +< iptsUrlSuffix);\r\ +< \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ +< \r\ +< \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ +< ficate=yes-without-crl \\\r\ +< \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ +< =user as-value ]->\"data\") ];\r\ +< \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ +< \n }\r\ +< \n\r\ +< \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ +< s\" ] do={\r\ +< \n :local ScriptVal [ /system/script/get \$Script ];\r\ +< \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ +< ];\r\ +< \n :local SourceNew;\r\ +< \n\r\ +< \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ +< \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ +< \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ +< \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ +< \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ +< iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ +< \"'!\");\r\ +< \n }\r\ +< \n }\r\ +< \n :do {\r\ +< \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ +< \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ +< e\" . \"', as requested.\");\r\ +< \n :error true;\r\ +< \n }\r\ +< \n :if (\$CheckSumsVerify = true) do={\r\ +< \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ +< \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ +< ptInfo->\"url-suffix\") ] = 0 && \\\r\ +< \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ +< rce\") ] ] = \$CheckSum) do={\r\ +< \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ +< >\"name\" . \"' matches, ignoring.\");\r\ +< \n :error true;\r\ +< \n }\r\ +< \n }\r\ +< \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ +< \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ +< fetch\" ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ +< ng without.\");\r\ +< \n }\r\ +< \n }\r\ +< \n :onerror Err {\r\ +< \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ +< lScriptsUrl ];\r\ +< \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ +< lobalScriptsUrlSuffix ];\r\ +< \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ +< Suffix);\r\ +< \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ +< name\") . \"' from url: \" . \$Url);\r\ +< \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ +< \r\ +< \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ +< ut=user as-value ];\r\ +< \n :if (\$Result->\"status\" = \"finished\") do={\r\ +< \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ +< \n } \r\ +< \n } do={\r\ +< \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ +< al->\"name\" . \"': \" . \$Err);\r\ +< \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ +< \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ +< \?\");\r\ +< \n /system/script/remove \$Script;\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :if (\$CheckSumsVerify = true) do={\r\ +< \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ +< riptInfo->\"url-suffix\") ] = 0 && \\\r\ +< \n [ :len \$CheckSum ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ +< pdates with 'ignore=true' in comment.\");\r\ +< \n }\r\ +< \n }\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :if ([ :len \$SourceNew ] = 0) do={\r\ +< \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ +< >\"name\") . \"'.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ +< \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ +< lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ +< \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ +< \$ScriptVal->\"source\")) do={\r\ +< \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ +< . \"' source did not change. End of lines set to CRLF.\");\r\ +< \n if (\$ScriptUpdatesCRLF = false) do={\r\ +< \n :put [ :tolf \$SourceNew ];\r\ +< \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ +< ) . \"' source update end of lines to LF.\");\r\ +< \n }\r\ +< \n :error false;\r\ +< \n }\r\ +< \n }\r\ +< \n\r\ +< \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ +< \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ +< l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ +< );\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :if (\$CommentsInScripts = true) do={\r\ +< \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ +< \_\") ];\r\ +< \n :if ([ :len \$CommentLine ] = 0) do={\r\ +< \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ +< iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ +< noring!\");\r\ +< \n :error false;\r\ +< \n } else={\r\ +< \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ +< ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ +< ] + 2) [ :len \$CommentLine] ]) do={\r\ +< \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ +< \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ +< ;\r\ +< \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ +< ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ +< \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ +< omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ +< ded!\");\r\ +< \n } else={\r\ +< \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ +< al->\"name\") . \"' did not change.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n } \r\ +< \n }\r\ +< \n\r\ +< \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ +< \"\\23 requires RouterOS, \") ] ]->version);\r\ +< \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ +< \_false ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ +< \") . \"' requires RouterOS \" . \\\r\ +< \n \$RequiredROS . \", which is not met by your installation. I\ +< gnoring!\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ +< \\23 requires device-mode, \") ] ];\r\ +< \n :local MissingDM ({});\r\ +< \n :foreach Feature,Value in=\$RequiredDM do={\r\ +< \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ +< ceMode->\$Feature) = false) do={\r\ +< \n :set MissingDM (\$MissingDM, \$Feature);\r\ +< \n }\r\ +< \n }\r\ +< \n :if ([ :len \$MissingDM ] > 0) do={\r\ +< \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ +< \") . \"' requires disabled \" . \\\r\ +< \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ +< gnoring!\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ +< ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n \r\ +< \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ +< ript comment: \" . (\$ScriptVal->\"comment\"));\r\ +< \n\r\ +< \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ +< Val->\"comment\") \\\r\ +< \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ +< F \$SourceNew ] \$Script;\r\ +< \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ +< \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ +< \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ +< o={\r\ +< \n :set ReloadGlobal true;\r\ +< \n }\r\ +< \n } on-error={ }\r\ +< \n }\r\ +< \n :if (\$ReloadGlobal = true) do={\r\ +< \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ +< \");\r\ +< \n :onerror Err {\r\ +< \n :global InitSetup (a);\r\ +< \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ +< \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ +< ctions failed! \" . \$Err)}\r\ +< \n }\r\ +< \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ +< \n \$LogPrint warning \$0 (\"The configuration version decreased from \ +< \" . \\\r\ +< \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ +< \n \". Installed an older version\?\");\r\ +< \n }\r\ +< \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ +< \n :global GlobalConfChanges;\r\ +< \n :global GlobalConfMigration;\r\ +< \n :local ChangeLogCode;\r\ +< \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ +< \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ +< \n :onerror Err {\r\ +< \n [ :parse \$ChangeLogCode ];\r\ +< \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ +< . \$Err)}\r\ +< \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ +< dation!\")}\r\ +< \n }\r\ +< \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ +< \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ +< \_do={\r\ +< \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ +< \n :do {\r\ +< \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ +< \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ +< \_\" is not available.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ +< \_. \" failed syntax validation!\");\r\ +< \n :error false}\r\ +< \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ +< . \": \" . \$Migration);\r\ +< \n :onerror Err {\r\ +< \n [ :parse \$Migration ];\r\ +< \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ +< \_\$I . \" failed to run: \" . \$Err)}\r\ +< \n } on-error={ }\r\ +< \n }\r\ +< \n }\r\ +< \n :local NotificationMessage (\"The configuration version on \" . \$Id\ +< entity . \" increased \" . \\\r\ +< \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ +< d modification. \" . \\\r\ +< \n \"Please review and update global-config-overlay, then re-run glo\ +< bal-config.\");\r\ +< \n \$LogPrint info \$0 (\$NotificationMessage);\r\ +< \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ +< \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ +< \");\r\ +< \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ +< \_do={\r\ +< \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ +< \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ +< \r\ +< \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ +< \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ +< \n }\r\ +< \n } else={:set NotificationMessage (\$NotificationMessage . \"\\n\\nNe\ +< ws and changes are not available.\")}\r\ +< \n\r\ +< \n :set GlobalConfChanges;\r\ +< \n :set GlobalConfMigration;\r\ +< \n }\r\ +< \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ +< \n}\r\ +< \n\r\ +< \n# Global Environment clear. Use: \"\$GlobalEnvRemove True;\".\r\ +< \n:set GlobalEnvRemove do={\r\ +< \n :local doRmEnv [ :tostr \$1 ];\r\ +< \n :global GlobalScriptsUrl;\r\ +< \n :local ScriptsUrl;\r\ +< \n :global LogPrint;\r\ +< \n :if (\$doRmEnv != \"True\") do={\r\ +< \n \$LogPrint error \"GlobalEnvRemove\" (\"This script is needed \\\"T\ +< rue\\\" for confirm to remove global environment variables!\");\r\ +< \n :return [];\r\ +< \n :error true; \r\ +< \n } else={\r\ +< \n :set ScriptsUrl \$GlobalScriptsUrl;\r\ +< \n :delay 5;\r\ +< \n :foreach var in=[/system/script/environment print as-value] do={/sy\ +< stem/script/environment remove (\$var->\".id\")}\r\ +< \n :delay 5;\r\ +< \n :global GlobalScriptsUrl \$ScriptsUrl;\r\ +< \n \$LogPrint warning \"GlobalEnvRemove\" (\"Done!\");\r\ +< \n :return [];\r\ +< \n :error false;\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n# Add and fix global scheduler\r\ +< \n:put \"Add or/and fix Global scheduler...\";\r\ +< \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ +< ; }\";\r\ +< \n:local Comment \"Setup Global Environment for scripts\";\r\ +< \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ +< = 0) do={\r\ +< \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ +< ent=\$OnEvent start-time=startup;\r\ +< \n}\r\ +< \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ +< \_do={\r\ +< \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ +< \n}\r\ +< \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ +< ) do={\r\ +< \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ +< \n}\r\ +< \n# Add Update Script scheduler\r\ +< \n:put \"Add or/and fix Update Script scheduler\";\r\ +< \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ +< \r\ +< \n:set Comment \"Every Day Check For Update Scripts\";\r\ +< \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ +< \" ] ] = 0) do={\r\ +< \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ +< start-time=startup interval=1d on-event=\$OnEvent;\r\ +< \n}\r\ +< \n\r\ +< \n#:local Resource [ /system/resource/get ];\r\ +< \n#:log info (\$ScriptName . \" Loaded on \" . \$Resource->\"board-name\" \ +< . \" with RouterOS \" . \$Resource->\"version\" . \" and Architecture \" .\ +< \".\");\r\ +< \n\r\ +< \n:onerror Err {\r\ +< \n :global GlobalConfReady;\r\ +< \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ +< \_not ready.\"); }; } delay=100ms max=5;\r\ +< \n\r\ +< \n# signal we are ready\r\ +< \n:set GlobalFuncReady true;\r\ +< \n:set ExitOK true;\r\ +< \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ +< \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ +< \") ] . \\\r\ +< \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ +< \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ +< \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err;}\r\ +< \n\r\ +< \n#} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ +< \n# log the successful load of the script, or an error if it failed\r\ +< \n#:if ([\$GlobalFuncReady] = true && [\$GlobalConfReady] = true) do={\r\ +< \n" +< add comment="Import ssh keys for public key authentication" \ +< dont-require-permissions=no name=AM-SshKeysImport owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\r\ +< \n# RouterOS script: AM-SshKeysImport\r\ +< \n# Script comment: Import ssh keys for public key authentication\r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n#\r\ +< \n:local ExitOK false;\r\ +< \n:onerror Err {\r\ +< \n :global GlobalConfReady; :global GlobalFuncReady;\r\ +< \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ +< \\\r\ +< \n do={ :error (\"Global configs or functions not ready.\"); }; } del\ +< ay=500ms max=50;\r\ +< \n :local ScriptName [ :jobname ];\r\ +< \n\r\ +< \n:global SSHKeysImport;\r\ +< \n:global SSHKeysImportFile;\r\ +< \n\r\ +< \n# import single key passed as string\r\ +< \n:set SSHKeysImport do={ :onerror Err {\r\ +< \n :local Key [ :tostr \$1 ];\r\ +< \n :local User [ :tostr \$2 ];\r\ +< \n :global GetRandom20CharAlNum;\r\ +< \n :global LogPrint;\r\ +< \n :global MkDir;\r\ +< \n :global RmDir;\r\ +< \n :global WaitForFile;\r\ +< \n :if ([ :len \$Key ] = 0 || [ :len \$User ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"Missing argument(s), please pass key and u\ +< ser!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ :len [ /user/find where name=\$User ] ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"User '\" . \$User . \"' does not exist.\")\ +< ;\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local KeyVal ([ :deserialize \$Key delimiter=\" \" from=dsv options=d\ +< sv.plain ]->0);\r\ +< \n :if (!(\$KeyVal->0 = \"ssh-ed25519\" || \$KeyVal->0 = \"ssh-rsa\")) do\ +< ={\r\ +< \n \$LogPrint warning \$0 (\"SSH key of type '\" . \$KeyVal->0 . \"' is\ +< \_not supported.\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local FingerPrintMD5 [ :convert from=base64 transform=md5 to=hex (\$K\ +< eyVal->1) ];\r\ +< \n :local RegEx (\"\\\\bmd5=\" . \$FingerPrintMD5 . \"\\\\b\");\r\ +< \n :if ([ :len [ /user/ssh-keys/find where user=\$User \\\r\ +< \n (key-owner~\$RegEx or info~\$RegEx) ] ] > 0) do={\r\ +< \n \$LogPrint warning \$0 (\"The ssh public key (MD5:\" . \$FingerPrint\ +< MD5 . \\\r\ +< \n \") is already available for user '\" . \$User . \"'.\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ \$MkDir \"tmpfs/ssh-keys-import\" ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Creating directory 'tmpfs/ssh-keys-import'\ +< \_failed!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local FileName (\"tmpfs/ssh-keys-import/key-\" . [ \$GetRandom20CharA\ +< lNum 6 ] . \".pub\");\r\ +< \n /file/add name=\$FileName contents=(\$Key . \", md5=\" . \$FingerPrint\ +< MD5);\r\ +< \n \$WaitForFile \$FileName;\r\ +< \n :onerror Err {\r\ +< \n /user/ssh-keys/import public-key-file=\$FileName user=\$User;\r\ +< \n \$LogPrint info \$0 (\"Imported ssh public key (\" . \$KeyVal->2 . \ +< \", \" . \$KeyVal->0 . \", \" . \\\r\ +< \n \"MD5:\" . \$FingerPrintMD5 . \") for user '\" . \$User . \"'.\");\ +< \r\ +< \n \$RmDir \"tmpfs/ssh-keys-import\";\r\ +< \n } do={\r\ +< \n \$LogPrint warning \$0 (\"Failed importing key: \" . \$Err);\r\ +< \n \$RmDir \"tmpfs/ssh-keys-import\";\r\ +< \n :return false;\r\ +< \n }\r\ +< \n} do={\r\ +< \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ +< \n} }\r\ +< \n\r\ +< \n# import keys from a file\r\ +< \n:set SSHKeysImportFile do={ :onerror Err {\r\ +< \n :local FileName [ :tostr \$1 ];\r\ +< \n :local User [ :tostr \$2 ];\r\ +< \n :global EitherOr;\r\ +< \n :global FileExists;\r\ +< \n :global LogPrint;\r\ +< \n :global ParseKeyValueStore;\r\ +< \n :global SSHKeysImport;\r\ +< \n :if ([ :len \$FileName ] = 0 || [ :len \$User ] = 0) do={\r\ +< \n \$LogPrint warning \$0 (\"Missing argument(s), please pass file name\ +< \_and user!\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :if ([ \$FileExists \$FileName ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"File '\" . \$FileName . \"' does not exist\ +< .\");\r\ +< \n :return false;\r\ +< \n }\r\ +< \n :local Keys [ :tolf [ /file/get \$FileName contents ] ];\r\ +< \n :foreach KeyVal in=[ :deserialize \$Keys delimiter=\" \" from=dsv opti\ +< ons=dsv.plain ] do={\r\ +< \n :local Continue false;\r\ +< \n :if (\$KeyVal->0 = \"ssh-ed25519\" || \$KeyVal->0 = \"ssh-rsa\") do=\ +< {\r\ +< \n :if ([ \$SSHKeysImport (\$KeyVal->0 . \" \" . \$KeyVal->1 . \" \" \ +< . \$KeyVal->2) \$User ] = false) do={\r\ +< \n \$LogPrint warning \$0 (\"Failed importing key for user '\" . \$\ +< User . \"'.\");\r\ +< \n }\r\ +< \n :set Continue true;\r\ +< \n }\r\ +< \n :if (\$Continue = false && \$KeyVal->0 = \"#\") do={\r\ +< \n :set User [ \$EitherOr ([ \$ParseKeyValueStore (\$KeyVal->1) ]->\"\ +< user\") \$User ];\r\ +< \n :set Continue true;\r\ +< \n }\r\ +< \n :if (\$Continue = false && [ :len (\$KeyVal->0) ] > 0) do={\r\ +< \n \$LogPrint warning \$0 (\"SSH key of type '\" . \$KeyVal->0 . \"' \ +< is not supported.\");\r\ +< \n }\r\ +< \n }\r\ +< \n} do={\r\ +< \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ +< \n} }\r\ +< \n} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ +< \n" +< add comment="Enable or disable ip addresses based on bridge port state" \ +< dont-require-permissions=no name=mod/AM-IPbridge owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\r\ +< \n# RouterOS script: mod/AM-IPbridge\r\ +< \n# Script comment: Enable or disable ip addresses based on bridge port st\ +< ate\r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n# requires device-mode, fetch\r\ +< \n#\r\ +< \n:local ScriptName [ :jobname ];\r\ +< \n\r\ +< \n# Add this Script scheduler\r\ +< \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ +< ={\r\ +< \n:log warning (\"SystemScheduler for script: \" . \$ScriptName . \" is NO\ +< T SET! Fix It Now!\");\r\ +< \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ +< \n:local Comment \"Every Day Check For Fake Bridges\";\r\ +< \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ +< rtup interval=1d on-event=\$OnEvent;\r\ +< \n}\r\ +< \n\r\ +< \n:foreach Bridge in=[ /interface/bridge/find ] do={\r\ +< \n :local BrName [ /interface/bridge/get \$Bridge name ];\r\ +< \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName ] ] > \ +< 0) do={\r\ +< \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName and \ +< inactive=no ] ] = 0) do={\r\ +< \n /ip/address/disable [ find where !dynamic interface=\$BrName ];\r\ +< \n } else={\r\ +< \n /ip/address/enable [ find where !dynamic interface=\$BrName ];\r\ +< \n }\r\ +< \n }\r\ +< \n}\r\ +< \n" +< add comment="Check for certificates validity" dont-require-permissions=no \ +< name=AM-CheckCerts owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\r\ +< \n# RouterOS script: AM-CheckCerts\r\ +< \n# Script comment: Check for certificates validity\r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n# requires device-mode, fetch\r\ +< \n\r\ +< \n:local ExitOK false;\r\ +< \n:onerror Err {\r\ +< \n :global GlobalConfReady; :global GlobalFuncReady;\r\ +< \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ +< \\\r\ +< \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ +< delay=500ms max=50;\r\ +< \n :local ScriptName [ :jobname ];\r\ +< \n\r\ +< \n :global CertRenewTime;\r\ +< \n :global CertRenewUrl;\r\ +< \n :global CertWarnTime;\r\ +< \n :global Identity;\r\ +< \n\r\ +< \n :global CertificateAvailable;\r\ +< \n :global EscapeForRegEx;\r\ +< \n :global IfThenElse;\r\ +< \n :global LogPrint;\r\ +< \n :global ParseKeyValueStore;\r\ +< \n :global ScriptLock;\r\ +< \n :global SendNotification2;\r\ +< \n :global SymbolForNotification;\r\ +< \n :global UrlEncode;\r\ +< \n# :global WaitFullyConnected;\r\ +< \n\r\ +< \n# Add this Script scheduler\r\ +< \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ +< ={\r\ +< \n:log warning (\"System Scheduler for script: \" . \$ScriptName . \" is N\ +< OT SET! Fix It Now!\");\r\ +< \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ +< \n:local Comment \"Every Day Check For Renew Certificates\";\r\ +< \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ +< rtup interval=1d on-event=\$OnEvent;\r\ +< \n}\r\ +< \n\r\ +< \n\r\ +< \n :local CheckCertificatesDownloadImport do={\r\ +< \n :local ScriptName [ :tostr \$1 ];\r\ +< \n :local CertName [ :tostr \$2 ];\r\ +< \n :local FetchName [ :tostr \$3 ];\r\ +< \n\r\ +< \n :global CertRenewUrl;\r\ +< \n :global CertRenewPass;\r\ +< \n\r\ +< \n :global CertificateNameByCN;\r\ +< \n :global EscapeForRegEx;\r\ +< \n :global FetchUserAgentStr;\r\ +< \n :global LogPrint;\r\ +< \n :global RmFile;\r\ +< \n :global UrlEncode;\r\ +< \n :global WaitForFile;\r\ +< \n\r\ +< \n :foreach Type in={ \"p12\"; \"pem\" } do={\r\ +< \n :local CertFileName ([ \$UrlEncode \$FetchName ] . \".\" . \$Type)\ +< ;\r\ +< \n \$LogPrint debug \$ScriptName (\"Trying type '\" . \$Type . \"' fo\ +< r '\" . \$CertName . \\\r\ +< \n \"' (file '\" . \$CertFileName . \"')...\");\r\ +< \n\r\ +< \n :do {\r\ +< \n :onerror Err {\r\ +< \n /tool/fetch check-certificate=yes-without-crl \\\r\ +< \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] \ +< }) \\\r\ +< \n (\$CertRenewUrl . \$CertFileName) dst-path=\$CertFileName \ +< as-value;\r\ +< \n } do={\r\ +< \n :if (!(\$Err ~ \"[Ss]tatus 404\")) do={\r\ +< \n \$LogPrint warning \$0 (\"Failed fetching certificate: \" . \ +< \$Err);\r\ +< \n }\r\ +< \n :error false;\r\ +< \n }\r\ +< \n \$WaitForFile \$CertFileName; \r\ +< \n\r\ +< \n :local DecryptionFailed true;\r\ +< \n :foreach I,PassPhrase in=\$CertRenewPass do={\r\ +< \n :do {\r\ +< \n \$LogPrint debug \$ScriptName (\"Trying \" . \$I . \". passp\ +< hrase... \");\r\ +< \n :local Result [ /certificate/import file-name=\$CertFileName\ +< \_passphrase=\$PassPhrase as-value ];\r\ +< \n :if (\$Result->\"decryption-failures\" = 0) do={\r\ +< \n \$LogPrint debug \$ScriptName (\"Success!\");\r\ +< \n :set DecryptionFailed false;\r\ +< \n }\r\ +< \n } on-error={ }\r\ +< \n }\r\ +< \n \$RmFile \$CertFileName;\r\ +< \n\r\ +< \n :if (\$DecryptionFailed = true) do={\r\ +< \n \$LogPrint warning \$ScriptName (\"Decryption failed for certi\ +< ficate file '\" . \$CertFileName . \"'.\");\r\ +< \n }\r\ +< \n\r\ +< \n :foreach CertInChain in=[ /certificate/find where common-name!=\ +< \$CertName !private-key \\\r\ +< \n name~(\"^\" . [ \$EscapeForRegEx \$CertFileName ] . \"_[0-9]\ +< +\\\$\") \\\r\ +< \n !(subject-alt-name~(\"(^|\\\\W)(DNS|IP):\" . [ \$EscapeForRe\ +< gEx \$CertName ] . \"(\\\\W|\\\$)\")) \\\r\ +< \n !(common-name=[]) ] do={\r\ +< \n \$CertificateNameByCN [ /certificate/get \$CertInChain common-\ +< name ];\r\ +< \n }\r\ +< \n\r\ +< \n :return true;\r\ +< \n } on-error={\r\ +< \n \$LogPrint debug \$ScriptName (\"Could not download certificate \ +< file '\" . \$CertFileName . \"'.\");\r\ +< \n }\r\ +< \n }\r\ +< \n\r\ +< \n :return false;\r\ +< \n }\r\ +< \n\r\ +< \n :local FormatInfo do={\r\ +< \n :local Cert \$1;\r\ +< \n\r\ +< \n :global FormatLine;\r\ +< \n :global FormatMultiLines;\r\ +< \n :global IfThenElse;\r\ +< \n\r\ +< \n :local FormatExpire do={\r\ +< \n :global CharacterReplace;\r\ +< \n :return [ \$CharacterReplace [ \$CharacterReplace [ :tostr \$1 ] \ +< \"w\" \"w \" ] \"d\" \"d \" ];\r\ +< \n }\r\ +< \n\r\ +< \n :local FormatCertChain do={\r\ +< \n :local Cert \$1;\r\ +< \n\r\ +< \n :global ParseKeyValueStore;\r\ +< \n\r\ +< \n :local CertVal [ /certificate/get \$Cert ];\r\ +< \n\r\ +< \n :if ([ :typeof (\$CertVal->\"issuer\") ] = \"nothing\") do={\r\ +< \n :return \"self-signed\";\r\ +< \n }\r\ +< \n\r\ +< \n :local Return \"\";\r\ +< \n :for I from=0 to=5 do={\r\ +< \n :set Return (\$Return . [ \$ParseKeyValueStore (\$CertVal->\"iss\ +< uer\") ]->\"CN\");\r\ +< \n :if ([ :len [ /certificate/builtin/find where skid=(\$CertVal->\ +< \"akid\") ] ] > 0) do={\r\ +< \n :return \$Return;\r\ +< \n }\r\ +< \n :do {\r\ +< \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\ +< \"akid\") ] ];\r\ +< \n } on-error={\r\ +< \n :return (\$Return . \" (possibly incomplete!)\");\r\ +< \n }\r\ +< \n :if ((\$CertVal->\"akid\") = \"\" || (\$CertVal->\"akid\") = (\$\ +< CertVal->\"skid\")) do={\r\ +< \n :return \$Return;\r\ +< \n }\r\ +< \n :set Return (\$Return . \" -> \");\r\ +< \n }\r\ +< \n :return (\$Return . \"...\");\r\ +< \n }\r\ +< \n\r\ +< \n :local CertVal [ /certificate/get \$Cert ];\r\ +< \n\r\ +< \n :return ( \\\r\ +< \n [ \$FormatLine \"Name\" (\$CertVal->\"name\") ] . \"\\n\" . \\\r\ +< \n [ \$IfThenElse ([ :len (\$CertVal->\"common-name\") ] > 0) ([ \$Fo\ +< rmatLine \"CommonName\" (\$CertVal->\"common-name\") ] . \"\\n\") ] . \\\r\ +< \n [ \$IfThenElse ([ :len (\$CertVal->\"subject-alt-name\") ] > 0) ([\ +< \_\$FormatMultiLines \"SubjectAltNames\" (\$CertVal->\"subject-alt-name\")\ +< \_] . \"\\n\") ] . \\\r\ +< \n [ \$FormatLine \"Private key\" [ \$IfThenElse ((\$CertVal->\"priva\ +< te-key\") = true) \"available\" \"missing\" ] ] . \"\\n\" . \\\r\ +< \n [ \$FormatLine \"Fingerprint\" (\$CertVal->\"fingerprint\") ] . \"\ +< \\n\" . \\\r\ +< \n [ \$IfThenElse ([ :len (\$CertVal->\"ca\") ] > 0) [ \$FormatLine \ +< \"Issuer\" (\$CertVal->\"ca\") ] [ \$FormatLine \"Issuer chain\" [ \$Forma\ +< tCertChain \$Cert ] ] ] . \"\\n\" . \\\r\ +< \n \"Validity:\\n\" . \\\r\ +< \n [ \$FormatLine \" days\" (\$CertVal->\"days-valid\") ] . \"\\n\ +< \" . \\\r\ +< \n [ \$FormatLine \" from\" (\$CertVal->\"invalid-before\") ] . \"\ +< \\n\" . \\\r\ +< \n [ \$FormatLine \" to\" (\$CertVal->\"invalid-after\") ] . \"\\n\ +< \" . \\\r\ +< \n [ \$FormatLine \" time left\" [ \$IfThenElse ((\$CertVal->\"exp\ +< ired\") = true) \"expired\" [ \$FormatExpire (\$CertVal->\"expires-after\"\ +< ) ] ] ]);\r\ +< \n }\r\ +< \n\r\ +< \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ +< \n :set ExitOK true;\r\ +< \n :error false;\r\ +< \n }\r\ +< \n# \$WaitFullyConnected;\r\ +< \n\r\ +< \n :foreach Cert in=[ /certificate/find where !revoked !ca !scep-url expi\ +< res-after<\$CertRenewTime ] do={\r\ +< \n :local CertVal [ /certificate/get \$Cert ];\r\ +< \n :local LastName;\r\ +< \n :local FetchName;\r\ +< \n\r\ +< \n :do {\r\ +< \n :if ([ :len \$CertRenewUrl ] = 0) do={\r\ +< \n \$LogPrint info \$ScriptName (\"No CertRenewUrl given.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n \$LogPrint info \$ScriptName (\"Attempting to renew certificate '\ +< \" . (\$CertVal->\"name\") . \"'.\");\r\ +< \n\r\ +< \n :local ImportSuccess false;\r\ +< \n :if ([ :len (\$CertVal->\"common-name\") ] > 0) do={\r\ +< \n :set LastName (\$CertVal->\"common-name\");\r\ +< \n :set FetchName \$LastName;\r\ +< \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$ScriptN\ +< ame \$LastName \$FetchName ];\r\ +< \n }\r\ +< \n :foreach SAN in=(\$CertVal->\"subject-alt-name\") do={\r\ +< \n :if (\$ImportSuccess = false) do={\r\ +< \n :set LastName [ :pick \$SAN ([ :find \$SAN \":\" ] + 1) [ :len\ +< \_\$SAN ] ];\r\ +< \n :set FetchName \$LastName;\r\ +< \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$Scrip\ +< tName \$LastName \$FetchName ];\r\ +< \n :if (\$ImportSuccess = false && [ :pick \$LastName 0 2 ] = \"*\ +< .\") do={\r\ +< \n :set FetchName (\"star.\" . [ :pick \$LastName 2 [ :len \$La\ +< stName ] ]);\r\ +< \n :set ImportSuccess [ \$CheckCertificatesDownloadImport \$Scr\ +< iptName \$LastName \$FetchName ];\r\ +< \n }\r\ +< \n }\r\ +< \n }\r\ +< \n :if (\$ImportSuccess = false) do={ :error false; }\r\ +< \n\r\ +< \n :if ([ :len (\$CertVal->\"fingerprint\") ] > 0 && \$CertVal->\"fin\ +< gerprint\" != [ /certificate/get \$Cert fingerprint ]) do={\r\ +< \n \$LogPrint debug \$ScriptName (\"Certificate '\" . \$CertVal->\"\ +< name\" . \"' was updated in place.\");\r\ +< \n :set CertVal [ /certificate/get \$Cert ];\r\ +< \n } else={\r\ +< \n \$LogPrint debug \$ScriptName (\"Certificate '\" . \$CertVal->\"\ +< name\" . \"' was not updated, but replaced.\");\r\ +< \n\r\ +< \n :local CertNew [ /certificate/find where name~(\"^\" . [ \$Escap\ +< eForRegEx [ \$UrlEncode \$FetchName ] ] . \"\\\\.(p12|pem)_[0-9]+\\\$\") \ +< \\\r\ +< \n (common-name=(\$CertVal->\"common-name\") or subject-alt-name~\ +< (\"(^|\\\\W)(DNS|IP):\" . [ \$EscapeForRegEx \$LastName ] . \"(\\\\W|\\\$)\ +< \")) \\\r\ +< \n fingerprint!=[ :tostr (\$CertVal->\"fingerprint\") ] ];\r\ +< \n :local CertNewVal [ /certificate/get \$CertNew ];\r\ +< \n\r\ +< \n :if ((\$CertVal->\"expires-after\") > (\$CertNewVal->\"expires-a\ +< fter\")) do={\r\ +< \n /certificate/remove \$CertNew;\r\ +< \n \$LogPrint warning \$ScriptName (\"Old certificate is newer th\ +< an the new one. Aborting renew.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :if ((\$CertVal->\"private-key\") = true && (\$CertVal->\"privat\ +< e-key\") != (\$CertNewVal->\"private-key\")) do={\r\ +< \n /certificate/remove \$CertNew;\r\ +< \n \$LogPrint warning \$ScriptName (\"Old certificate '\" . (\$Ce\ +< rtVal->\"name\") . \"' has a private key, new certificate does not. Aborti\ +< ng renew.\");\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :if ([ \$CertificateAvailable ([ \$ParseKeyValueStore (\$CertNew\ +< Val->\"issuer\") ]->\"CN\") \"fetch\" ] = false) do={\r\ +< \n \$LogPrint warning \$ScriptName (\"The certificate chain is no\ +< t available!\");\r\ +< \n }\r\ +< \n\r\ +< \n /ip/service/set certificate=(\$CertNewVal->\"name\") [ find wher\ +< e certificate=(\$CertVal->\"name\") ];\r\ +< \n\r\ +< \n /ip/ipsec/identity/set certificate=(\$CertNewVal->\"name\") [ fi\ +< nd where certificate=(\$CertVal->\"name\") ];\r\ +< \n /ip/ipsec/identity/set remote-certificate=(\$CertNewVal->\"name\ +< \") [ find where remote-certificate=(\$CertVal->\"name\") ];\r\ +< \n\r\ +< \n /ip/hotspot/profile/set ssl-certificate=(\$CertNewVal->\"name\")\ +< \_[ find where ssl-certificate=(\$CertVal->\"name\") ];\r\ +< \n\r\ +< \n /certificate/remove \$Cert;\r\ +< \n /certificate/set \$CertNew name=(\$CertVal->\"name\");\r\ +< \n :set Cert \$CertNew;\r\ +< \n :set CertVal [ /certificate/get \$CertNew ];\r\ +< \n }\r\ +< \n\r\ +< \n \$SendNotification2 ({ origin=\$ScriptName; silent=true; \\\r\ +< \n subject=([ \$SymbolForNotification \"lock-with-ink-pen\" ] . \"C\ +< ertificate renewed: \" . (\$CertVal->\"name\")); \\\r\ +< \n message=(\"A certificate on \" . \$Identity . \" has been renewe\ +< d.\\n\\n\" . [ \$FormatInfo \$Cert ]) });\r\ +< \n \$LogPrint info \$ScriptName (\"The certificate '\" . (\$CertVal->\ +< \"name\") . \"' has been renewed.\");\r\ +< \n } on-error={\r\ +< \n \$LogPrint debug \$ScriptName (\"Could not renew certificate '\" .\ +< \_(\$CertVal->\"name\") . \"'.\");\r\ +< \n }\r\ +< \n }\r\ +< \n\r\ +< \n :foreach Cert in=[ /certificate/find where !revoked !scep-url !(expire\ +< s-after=[]) \\\r\ +< \n expires-after<\$CertWarnTime !(fingerprint=[]) ] do\ +< ={\r\ +< \n :local CertVal [ /certificate/get \$Cert ];\r\ +< \n\r\ +< \n :if ([ :len [ /certificate/scep-server/find where ca-cert=(\$CertVal\ +< ->\"ca\") ] ] > 0) do={\r\ +< \n \$LogPrint debug \$ScriptName (\"Certificate '\" . (\$CertVal->\"n\ +< ame\") . \"' is handled by SCEP, skipping.\");\r\ +< \n } else={\r\ +< \n :local State [ \$IfThenElse ((\$CertVal->\"expired\") = true) \"ex\ +< pired\" \"is about to expire\" ];\r\ +< \n\r\ +< \n \$SendNotification2 ({ origin=\$ScriptName; \\\r\ +< \n subject=([ \$SymbolForNotification \"lock-with-ink-pen,warning-s\ +< ign\" ] . \"Certificate warning: \" . (\$CertVal->\"name\")); \\\r\ +< \n message=(\"A certificate on \" . \$Identity . \" \" . \$State . \ +< \".\\n\\n\" . [ \$FormatInfo \$Cert ]) });\r\ +< \n \$LogPrint info \$ScriptName (\"The certificate '\" . (\$CertVal->\ +< \"name\") . \"' \" . \$State . \\\r\ +< \n \", it is invalid after \" . (\$CertVal->\"invalid-after\") . \ +< \".\");\r\ +< \n }\r\ +< \n }\r\ +< \n} do={\r\ +< \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ +< \n}\r\ +< \n" +< add comment="Global Config Script" dont-require-permissions=no name=\ +< AM-GlobalConfig owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\ +< \n# RouterOS script: AM-GlobalConfig\ +< \n# Script comment: Global Config Script\ +< \n# Copyright (c) 2007-2026 Vados \ +< \n#\ +< \n#\ +< \n# Warning: Dont touch this line!\ +< \n:global GlobalConfReady false;\ +< \n#\ +< \n#\ +< \n# Global Url For Amster scripts to fetch\ +< \n# most be defined in AM-Init-Script or AM-setup scripts\ +< \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\ +< \n:global ScriptsUrlSuffix \"\";\ +< \n:global CheckSumsVerify true;\ +< \n\ +< \n:global ScriptUpdatesCRLF true;\ +< \n:global CommentsInScripts true;\ +< \n\ +< \n# Debug output:\ +< \n:global PrintDebug true; #false;\ +< \n\ +< \n# Debug output for specific script:\ +< \n:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\ +< \n\ +< \n# Debug logs\ +< \n# Other actions (disk, email, remote or support) can be used as well.\ +< \n# I do not recommend using echo - use debug output instead (https://rsc.\ +< eworm.de/main/DEBUG.html#debug-output).\ +< \n#/system/logging/add topics=script,debug action=memory;\ +< \n\ +< \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\ +< \n:global Domain \"WORKGROUP\";\ +< \n\ +< \n:global EmailGeneralTo \"vados@vados.ru\";\ +< \n#:global EmailGeneralCc \"\";\ +< \n\ +< \n# \$ScriptInstallUpdate mod/notification-telegram\ +< \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ +< \";\ +< \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\ +< \n# Use this to send notifications to a specific topic in group.\ +< \n#:global TelegramThreadId \"30\";\ +< \n# Using telegram-chat you have to define trusted chat ids (not group ids\ +< !)\ +< \n# or user names. Groups allow to chat with devices simultaneously.\ +< \n:global TelegramChatIdsTrusted {\ +< \n \"454403445\"\ +< \n \"-1003631309063\"\ +< \n \"-5124482807\"\ +< \n \"1087968824\";\ +< \n};\ +< \n# \"-5294757340\";\ +< \n\ +< \n:global TelegramChatGroups \"(all)\";\ +< \n#:global TelegramChatGroups \"(all|home|office)\";\ +< \n\ +< \n:global NotificationFunctions {\ +< \n \"email\"\ +< \n \"telegram\";\ +< \n};\ +< \n# Toggle this to disable symbols in notifications.\ +< \n:global NotificationsWithSymbols true;\ +< \n:global TerminalColorOutput true;\ +< \n\ +< \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\ +< \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\ +< \n\ +< \n## Update channel. Possible values: stable, long-term, testing, developm\ +< ent\ +< \n:global updateChannel \"stable\";\ +< \n\ +< \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\");\ +< \n:global CertRenewTime 2w;\ +< \n:global CertRenewPass {\ +< \n \"\";\ +< \n# \"v3ry-s3cr3t\";\ +< \n# \"4n0th3r-s3cr3t\";\ +< \n};\ +< \n:global CertWarnTime 1w;\ +< \n:global CertIssuedExportPass {\ +< \n \"\";\ +< \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\ +< \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\ +< \n};\ +< \n\ +< \n# Script BackupAndUpdate mode, possible values: backup,\ +< \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ +< n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \ +< \n# osupdate - Update if available and creates backups before/after update\ +< \_(ignores `forceBackup`)\ +< \n# Set `forceBackup` to true to always create backups, even\ +< \_without updates\ +< \n# osnotify - Set `forceBackup` to always create backups on every run\ +< \n:global DevInfoIncludeIP true;\ +< \n:global BackupAndUpdateMode \"osnotify\"\ +< \n\ +< \n:global forceBackup true;\ +< \n:global BackupPassword \"Peskar55\";\ +< \n\ +< \n# SFTP Backup Variables\ +< \n:global BackupRandomDelay 0;\ +< \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\ +< \n:global BackupUploadUser \$Identity;\ +< \n:global BackupUploadPass \"root.mnuc.backuper\";\ +< \n\ +< \n:global BackupSendBinary true;\ +< \n:global BackupSendExport true;\ +< \n:global BackupSendGlobalConfig true;\ +< \n:global BackupSendScripts true;\ +< \n\ +< \n# Remove local file after uploading if no errors\ +< \n:global BackupRmLocal true;\ +< \n\ +< \n# Local Backups Root Directory \ +< \n:global BackupLocalRoot \"tmpfs\";\ +< \n\ +< \n# Encrypt Backup\ +< \n:global BackupEncrypt true;\ +< \n\ +< \n# Sensitive information in Backups\ +< \n:global BackupSens true;\ +< \n\ +< \n# User Export\ +< \n:global BackupUser true;\ +< \n\ +< \n# License Export (not for CHR, will silently skip)\ +< \n:global BackupLicense false;\ +< \n\ +< \n# SSH Keys\ +< \n:global BackupSshKeys true;\ +< \n\ +< \n# Certificate Export\ +< \n:global BackupCerts true;\ +< \n\ +< \n# Certificate Password\ +< \n:global BackupCertsPasswd \"\";\ +< \n\ +< \n# User-Manager Export\ +< \n:global BackupUserMan false;\ +< \n\ +< \n# The Dude Export\ +< \n:global BackupDude false;\ +< \n\ +< \n# User Files to export, comma-separated string or array of strings\ +< \n# User Files are not removed on backup\ +< \n# Any directory paths will be removed (/ -> _) on remote file\ +< \n# Nonpresent files are silently skipped\ +< \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\ +< \n\ +< \n# load functions and any custom scripts\ +< \n# [ /system/script/find where name=\"global-config-ov\ +< erlay\" ], \\\ +< \n# [ /system/script/find where name~\"^global-config-o\ +< verlay\\\\.d/.\" ]\ +< \n#\ +< \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ +< ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ +< \n# :onerror Err {\ +< \n# /system/script/run \$Script;\ +< \n# } do={\ +< \n# :log error (\"Loading configuration from configs and functions\"\ +< \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\ +< \n# }\ +< \n#}\ +< \n#:log info \"\\ndevMode = \$devMode\";\ +< \n#:log info \"\\ndevRunning = \$devRunning\";\ +< \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ +< GlobalRUN\\r\?\\n\" ] do={\ +< \n :onerror Err {\ +< \n /system/script/run \$Script;\ +< \n } do={\ +< \n :log error (\"Run script \" . [ /system/script/get \$Script name \ +< ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\ +< \n }\ +< \n}\ +< \n\ +< \n# signal we are ready\ +< \n:set GlobalConfReady true;\ +< \n:while (\$GlobalConfReady != true) do={:delay 500ms};\ +< \n" +< add comment="Renew locally issued certificates" dont-require-permissions=no \ +< name=AM-CertsRenew owner=AM-CertsRenew policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ +< !rsc by Vados\r\ +< \n# RouterOS script: AM-CertsRenew\r\ +< \n# Script comment: Renew locally issued certificates\r\ +< \n# Copyright (c) 2005-2026 Vados \r\ +< \n#\r\ +< \n#\r\ +< \n# requires RouterOS, version=7.19\r\ +< \n#\r\ +< \n:local ExitOK false;\r\ +< \n:onerror Err {\r\ +< \n :global GlobalConfReady; :global GlobalFuncReady;\r\ +< \n :retry { :if (\$GlobalConfReady != true || \$GlobalFuncReady != true) \ +< \\\r\ +< \n do={ :error (\"Global config and/or functions not ready.\"); }; } \ +< delay=500ms max=50;\r\ +< \n :local ScriptName [ :jobname ];\r\ +< \n\r\ +< \n :global CertIssuedExportPass;\r\ +< \n\r\ +< \n :global LogPrint;\r\ +< \n :global MkDir;\r\ +< \n :global ScriptLock;\r\ +< \n\r\ +< \n# Add this Script scheduler\r\ +< \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ +< ={\r\ +< \n:log warning (\"System Scheduler for script: \" . \$ScriptName . \" is N\ +< OT SET! Fix It Now!\");\r\ +< \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ +< \n:local Comment \"Every Day Check For Update Local Issued Certificates.\"\ +< ;\r\ +< \n#/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=st\ +< artup interval=1d on-event=\$OnEvent;\r\ +< \n}\r\ +< \n\r\ +< \n :if ([ \$ScriptLock \$ScriptName ] = false) do={\r\ +< \n :set ExitOK true;\r\ +< \n :error false;\r\ +< \n }\r\ +< \n\r\ +< \n :foreach Cert in=[ /certificate/find where issued expires-after<3w ] d\ +< o={\r\ +< \n :local CertVal [ /certificate/get \$Cert ];\r\ +< \n /certificate/issued-revoke \$Cert;\r\ +< \n /certificate/set name=(\$CertVal->\"name\" . \"-revoked-\" . [ /syst\ +< em/clock/get date ]) \$Cert;\r\ +< \n /certificate/add name=(\$CertVal->\"name\") common-name=(\$CertVal->\ +< \"common-name\") \\\r\ +< \n key-usage=(\$CertVal->\"key-usage\") subject-alt-name=(\$CertVal\ +< ->\"subject-alt-name\");\r\ +< \n /certificate/sign (\$CertVal->\"name\") ca=(\$CertVal->\"ca\");\r\ +< \n :if ([ :typeof (\$CertIssuedExportPass->(\$CertVal->\"common-name\")\ +< ) ] = \"str\") do={\r\ +< \n :if ([ \$MkDir \"cert-issued\" ] = true) do={\r\ +< \n /certificate/export-certificate (\$CertVal->\"name\") type=pkcs1\ +< 2 \\\r\ +< \n file-name=(\"cert-issued/\" . \$CertVal->\"common-name\") \\\ +< \r\ +< \n export-passphrase=(\$CertIssuedExportPass->(\$CertVal->\"com\ +< mon-name\"));\r\ +< \n \$LogPrint info \$ScriptName (\"Issued a new certificate for '\"\ +< \_. \$CertVal->\"common-name\" . \\\r\ +< \n \"', exported to 'cert-issued/\" . \$CertVal->\"common-name\" \ +< . \".p12'.\");\r\ +< \n } else={\r\ +< \n \$LogPrint warning \$ScriptName (\"Failed creating directory, no\ +< t exporting certificate.\");\r\ +< \n }\r\ +< \n } else={\r\ +< \n \$LogPrint info \$ScriptName (\"Issued a new certificate for '\" .\ +< \_\$CertVal->\"common-name\" . \"'.\");\r\ +< \n }\r\ +< \n }\r\ +< \n} do={\r\ +< \n :global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err;\r\ +< \n}\r\ +< \n" +< /user group +< add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ +< !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +< /caps-man provisioning +< add action=create-dynamic-enabled hw-supported-modes=gn master-configuration=\ +< cfg-2ghz name-format=prefix-identity name-prefix=2ghz +< add action=create-dynamic-enabled hw-supported-modes=ac master-configuration=\ +< cfg-5ghz-ac name-format=prefix-identity name-prefix=5ghz-ac +< add action=create-dynamic-enabled hw-supported-modes=an master-configuration=\ +< cfg-5ghz-an name-format=prefix-identity name-prefix=5ghz-an +< /certificate settings +< set builtin-trust-store=fetch +< /disk settings +< set auto-media-interface=lo default-mount-point-template="[tmpfs]" +< /ip smb +< set comment=MikroVados domain=WORKGROUP enabled=yes interfaces=Bridge-LAN +< /interface bridge port +< add bridge=Bridge-LAN ingress-filtering=no interface=ether2 \ +< internal-path-cost=10 path-cost=10 +< add bridge=Bridge-LAN comment=LEN ingress-filtering=no interface=ether3 \ +< internal-path-cost=10 path-cost=10 +< add bridge=Bridge-LAN comment=NUC ingress-filtering=no interface=ether4 \ +< internal-path-cost=10 path-cost=10 +< add bridge=Bridge-LAN ingress-filtering=no interface=ether5 \ +< internal-path-cost=10 path-cost=10 +< /ip firewall connection tracking +< set udp-timeout=10s +< /ip neighbor discovery-settings +< set discover-interface-list=LAN +< /ip settings +< set max-neighbor-entries=8192 secure-redirects=no +< /ipv6 settings +< set disable-ipv6=yes max-neighbor-entries=8192 +< /interface detect-internet +< set detect-interface-list=WAN internet-interface-list=WAN lan-interface-list=\ +< LAN wan-interface-list=WAN +< /interface l2tp-server server +< set authentication=mschap2 use-ipsec=yes +< /interface list member +< add comment=WAN interface="ether1 - Unet" list=WAN +< add interface=Bridge-LAN list=LAN +< /interface ovpn-server server +< add auth=sha1,md5 mac-address=FE:82:A5:78:8E:84 name=ovpn-server1 +< /interface wifi cap +< set caps-man-addresses=10.30.30.10 certificate=request discovery-interfaces=\ +< wlan1,wlan2 lock-to-caps-man=no slaves-static=no +< /interface wifi capsman +< set package-path="" require-peer-certificate=no upgrade-policy=none +< /interface wifi provisioning +< add action=create-dynamic-enabled disabled=no master-configuration=2G-N \ +< name-format=2G-%I slave-configurations=2G-G supported-bands=\ +< 2ghz-n,2ghz-g,2ghz-g +< add action=create-dynamic-enabled disabled=no master-configuration=5G-AC \ +< name-format=5G-%I supported-bands=5ghz-ac,5ghz-ac +< /interface wireguard peers +< add allowed-address=10.8.0.2/32,0.0.0.0/0 client-allowed-address=0.0.0.0/0 \ +< endpoint-address=89.110.101.17 endpoint-port=29185 interface=WG name=\ +< MikroVados persistent-keepalive=10s public-key=\ +< "64Y25EUZQQt8EIeAJYD8qWt+te8qvGEepnswdBgmzlY=" +< /interface wireless cap +< # +< set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ +< caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ +< CAP-18FD746E5814 discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ +< wlan1,wlan2 lock-to-caps-man=yes +< /interface wireless sniffer +< set file-name=24g +< /ip address +< add address=10.30.30.81/24 interface=Bridge-LAN network=10.30.30.0 +< add address=10.8.0.2/24 interface=WG network=10.8.0.0 +< /ip dhcp-client +< add add-default-route=special-classless default-route-distance=2 \ +< default-route-tables=main interface="ether1 - Unet" name="ether1 - Unet" \ +< use-peer-dns=no +< /ip dhcp-server config +< set accounting=no +< /ip dhcp-server lease +< add address=10.30.30.101 client-id=1:48:8f:5a:8e:ee:a8 mac-address=\ +< 48:8F:5A:8E:EE:A8 server=masterDHCP +< add address=10.30.30.107 client-id=1:f0:de:f1:91:d:1e mac-address=\ +< F0:DE:F1:91:0D:1E server=masterDHCP +< add address=10.30.30.83 client-id=1:0:80:77:ec:43:86 mac-address=\ +< 00:80:77:EC:43:86 server=masterDHCP +< add address=10.30.30.70 dhcp-option=domain-search-list,HostName \ +< dhcp-option-set=HP1505n mac-address=00:1E:0B:1A:88:8D server=masterDHCP +< add address=10.30.30.50 client-id=1:4:7c:16:36:f5:37 mac-address=\ +< 04:7C:16:36:F5:37 server=masterDHCP +< add address=10.30.30.71 client-id=1:10:2d:41:2c:20:c2 mac-address=\ +< 10:2D:41:2C:20:C2 server=masterDHCP +< add address=10.30.30.61 client-id=1:10:8:c1:81:59:5f mac-address=\ +< 10:08:C1:81:59:5F server=masterDHCP +< add address=10.30.30.72 client-id=1:10:38:1f:d2:5f:13 mac-address=\ +< 10:38:1F:D2:5F:13 server=masterDHCP +< add address=10.30.30.99 client-id=1:10:b1:df:e9:d0:d5 mac-address=\ +< 10:B1:DF:E9:D0:D5 server=masterDHCP +< add address=10.30.30.111 client-id=1:fe:2:52:be:3f:16 mac-address=\ +< FE:02:52:BE:3F:16 server=masterDHCP +< add address=10.30.30.93 client-id=1:7e:8b:1e:cb:b8:cb mac-address=\ +< CC:42:10:12:46:94 server=masterDHCP +< add address=10.30.30.94 client-id=1:50:cc:f8:85:96:a mac-address=\ +< 50:CC:F8:85:96:0A server=masterDHCP +< add address=10.30.30.82 client-id=1:e4:18:6b:58:34:ab mac-address=\ +< E4:18:6B:58:34:AB server=masterDHCP +< add address=10.30.30.77 dhcp-option=HostName dhcp-option-set=StartLife1 \ +< mac-address=C4:82:E1:03:49:10 server=masterDHCP +< add address=10.30.30.73 client-id=1:10:38:1f:82:81:f2 mac-address=\ +< 10:38:1F:82:81:F2 server=masterDHCP +< add address=10.30.30.95 client-id=1:88:ae:dd:60:39:54 dhcp-option=HostName \ +< dhcp-option-set=VADOS-NUC mac-address=88:AE:DD:60:39:54 server=masterDHCP +< add address=10.30.30.98 client-id=1:c8:5b:76:d8:cc:bf dhcp-option=HostName \ +< dhcp-option-set=VADOS-LEN mac-address=C8:5B:76:D8:CC:BF server=masterDHCP +< add address=10.30.30.96 client-id=iPhone mac-address=4A:91:ED:0E:1F:39 \ +< server=masterDHCP +< add address=10.30.30.74 client-id=1:20:72:a9:d3:34:36 dhcp-option=HostName \ +< dhcp-option-set=MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP \ +< use-src-mac=yes +< add address=10.30.30.30 dhcp-option=HostName dhcp-option-set=miller \ +< mac-address=F0:75:5D:1E:5F:71 server=masterDHCP +< add address=10.30.30.100 client-id=iVados dhcp-option=HostName \ +< dhcp-option-set="=\"Client ID\"" mac-address=DE:4D:72:F3:1A:9F server=\ +< masterDHCP +< add address=10.30.30.86 dhcp-option=HostName dhcp-option-set=MikroYellow \ +< mac-address=48:8F:5A:8E:1A:C2 server=masterDHCP +< /ip dhcp-server network +< add address=10.30.30.0/24 caps-manager=10.30.30.10 dhcp-option=\ +< domain-search-list dhcp-option-set=domain-search-set dns-server=\ +< 10.30.30.81 domain=WORKGROUP gateway=10.30.30.81 netmask=24 ntp-server=\ +< 10.30.30.81,10.30.30.10 wins-server=10.30.30.95,10.30.30.98 +< /ip dns +< set allow-remote-requests=yes cache-max-ttl=1d doh-max-concurrent-queries=100 \ +< doh-max-server-connections=20 servers=8.8.8.8,8.8.4.4 verify-doh-cert=yes +< /ip dns static +< add address=10.30.30.33 name=amster-nuc type=A +< add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +< add address=10.30.30.33 name=amster type=A +< add address=10.30.30.33 name=amster-reg type=A +< add address=10.30.30.33 name=mng.vados.ru type=A +< add address=10.30.30.33 name=mgr.vados.ru type=A +< add address=10.30.30.33 name=prt.vados.ru type=A +< add address=10.30.30.33 name=git.vados.ru type=A +< add address=10.30.30.33 name=reg.vados.ru type=A +< add address=10.30.30.33 match-subdomain=yes name=ros.vados.ru type=A +< add address=10.30.30.33 match-subdomain=yes name=mikrots.vados.ru type=A +< add address=10.30.30.33 name=oxidized.vados.ru type=A +< add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +< add address=8.8.8.8 comment="Google-dns IPv4 1" name=dns.google type=A +< add address=10.30.30.30 comment=MILLER name=miller.vados.ru type=A +< add address=10.30.30.30 name=MILLER-LEN type=A +< add address=10.30.30.30 name=miller type=A +< add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" name=\ +< security.cloudflare-dns.com type=A +< add address=1.0.0.1 comment="CloudFlare-doh IPv4 2" name=\ +< security.cloudflare-dns.com type=A +< add address=9.9.9.9 comment="Cuad9-dns IPv4 1" disabled=yes name=\ +< dns.quad9.net type=A +< add address=149.112.112.112 comment="Cuad9-dns IPv4 2" disabled=yes name=\ +< dns.quad9.net type=A +< add address=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ +< A +< add address=10.30.30.81 comment=LocalNet name=MikroVados type=A +< add address=10.30.30.10 name=MikroNUC type=A +< add address=10.30.30.86 name=MikroYellow type=A +< add address=10.30.30.85 name=MikroMic type=A +< add address=10.30.30.95 name=VADOS-NUC type=A +< add address=10.30.30.98 name=VADOS-LEN type=A +< add address=10.30.30.20 name=garage type=A +< add address=2606:4700:4700::1111 disabled=yes name=\ +< security.cloudflare-dns.com type=AAAA +< add address=2606:4700:4700::1001 disabled=yes name=\ +< security.cloudflare-dns.com type=AAAA +< /ip firewall address-list +< add address=91.215.120.206 list=TRUSTED +< add address=185.71.70.78 disabled=yes list=TRUSTED +< add address=176.53.203.171 disabled=yes list=TRUSTED +< add address=176.53.203.170 disabled=yes list=TRUSTED +< add address=176.53.202.194 disabled=yes list=TRUSTED +< add address=10.30.30.100-255 list=KIDS +< add address=8.8.4.0/24 list=YouTube +< add address=8.8.8.0/24 list=YouTube +< add address=8.34.208.0/20 list=YouTube +< add address=8.35.192.0/20 list=YouTube +< add address=23.236.48.0/20 list=YouTube +< add address=23.251.128.0/19 list=YouTube +< add address=34.0.0.0/15 list=YouTube +< add address=34.2.0.0/16 list=YouTube +< add address=34.3.0.0/23 list=YouTube +< add address=34.3.3.0/24 list=YouTube +< add address=34.3.4.0/24 list=YouTube +< add address=34.3.8.0/21 list=YouTube +< add address=34.3.16.0/20 list=YouTube +< add address=34.3.32.0/19 list=YouTube +< add address=34.3.64.0/18 list=YouTube +< add address=34.4.0.0/14 list=YouTube +< add address=34.8.0.0/13 list=YouTube +< add address=34.16.0.0/12 list=YouTube +< add address=34.32.0.0/11 list=YouTube +< add address=34.64.0.0/10 list=YouTube +< add address=34.128.0.0/10 list=YouTube +< add address=35.184.0.0/13 list=YouTube +< add address=35.192.0.0/14 list=YouTube +< add address=35.196.0.0/15 list=YouTube +< add address=35.198.0.0/16 list=YouTube +< add address=35.199.0.0/17 list=YouTube +< add address=35.199.128.0/18 list=YouTube +< add address=35.200.0.0/13 list=YouTube +< add address=35.208.0.0/12 list=YouTube +< add address=35.224.0.0/12 list=YouTube +< add address=35.240.0.0/13 list=YouTube +< add address=57.140.192.0/18 list=YouTube +< add address=64.15.112.0/20 list=YouTube +< add address=64.233.160.0/19 list=YouTube +< add address=66.22.228.0/23 list=YouTube +< add address=66.102.0.0/20 list=YouTube +< add address=66.249.64.0/19 list=YouTube +< add address=70.32.128.0/19 list=YouTube +< add address=72.14.192.0/18 list=YouTube +< add address=74.125.0.0/16 list=YouTube +< add address=104.154.0.0/15 list=YouTube +< add address=104.196.0.0/14 list=YouTube +< add address=104.237.160.0/19 list=YouTube +< add address=107.167.160.0/19 list=YouTube +< add address=107.178.192.0/18 list=YouTube +< add address=108.59.80.0/20 list=YouTube +< add address=108.170.192.0/18 list=YouTube +< add address=108.177.0.0/17 list=YouTube +< add address=130.211.0.0/16 list=YouTube +< add address=136.22.160.0/20 list=YouTube +< add address=136.22.176.0/21 list=YouTube +< add address=136.22.184.0/23 list=YouTube +< add address=136.22.186.0/24 list=YouTube +< add address=142.250.0.0/15 list=YouTube +< add address=146.148.0.0/17 list=YouTube +< add address=152.65.208.0/22 list=YouTube +< add address=152.65.214.0/23 list=YouTube +< add address=152.65.218.0/23 list=YouTube +< add address=152.65.222.0/23 list=YouTube +< add address=152.65.224.0/19 list=YouTube +< add address=162.120.128.0/17 list=YouTube +< add address=162.216.148.0/22 list=YouTube +< add address=162.222.176.0/21 list=YouTube +< add address=172.110.32.0/21 list=YouTube +< add address=172.217.0.0/16 list=YouTube +< add address=172.253.0.0/16 list=YouTube +< add address=173.194.0.0/16 list=YouTube +< add address=173.255.112.0/20 list=YouTube +< add address=192.158.28.0/22 list=YouTube +< add address=192.178.0.0/15 list=YouTube +< add address=193.186.4.0/24 list=YouTube +< add address=199.36.154.0/23 list=YouTube +< add address=199.36.156.0/24 list=YouTube +< add address=199.192.112.0/22 list=YouTube +< add address=199.223.232.0/21 list=YouTube +< add address=207.223.160.0/20 list=YouTube +< add address=208.65.152.0/22 list=YouTube +< add address=208.68.108.0/22 list=YouTube +< add address=208.81.188.0/22 list=YouTube +< add address=208.117.224.0/19 list=YouTube +< add address=209.85.128.0/17 list=YouTube +< add address=216.58.192.0/19 list=YouTube +< add address=216.73.80.0/20 list=YouTube +< add address=216.239.32.0/19 list=YouTube +< add address=2ip.ru list=Test +< add address=157.240.247.174 list=Instagram +< add address=46.53.178.107 list=Instagram +< add address=179.60.195.174 list=Instagram +< add address=157.240.205.174 list=Instagram +< add address=31.13.24.0/21 list=Instagram +< add address=31.13.64.0/18 list=Instagram +< add address=45.64.40.0/22 list=Instagram +< add address=66.220.144.0/20 list=Instagram +< add address=69.63.176.0/20 list=Instagram +< add address=69.171.224.0/19 list=Instagram +< add address=74.119.76.0/22 list=Instagram +< add address=103.4.96.0/22 list=Instagram +< add address=129.134.0.0/16 list=Instagram +< add address=157.240.0.0/16 list=Instagram +< add address=173.252.64.0/18 list=Instagram +< add address=179.60.192.0/22 list=Instagram +< add address=185.60.216.0/22 list=Instagram +< add address=204.15.20.0/22 list=Instagram +< add address=157.240.200.63 list=Instagram +< add address=185.60.219.63 list=Instagram +< add address=129.134.31.12 list=Instagram +< add address=66.81.203.132 list=Instagram +< add address=185.89.218.12 list=Instagram +< add address=31.13.66.63 list=Instagram +< add address=84.15.65.162 list=Instagram +< add address=68.66.224.28 list=Instagram +< add address=157.240.253.63 list=Instagram +< add address=83.174.11.224 list=Instagram +< add address=157.240.9.52 list=Instagram +< add address=157.240.252.174 list=Instagram +< add address=157.240.195.63 list=Instagram +< add address=31.13.71.52 list=Instagram +< add address=57.144.110.192 list=Instagram +< add address=157.240.252.17 list=Instagram +< add address=84.15.66.97 list=Instagram +< add address=217.168.6.33 list=Instagram +< add address=31.13.83.52 list=Instagram +< add address=157.240.241.63 list=Instagram +< add address=129.134.30.12 list=Instagram +< add address=185.89.219.12 list=Instagram +< add address=157.240.252.10 list=Instagram +< add address=157.240.201.63 list=Instagram +< add address=66.81.203.197 list=Instagram +< add address=179.60.195.52 list=Instagram +< add address=66.81.203.7 list=Instagram +< add address=216.40.34.41 list=Instagram +< add address=157.240.202.63 list=Instagram +< add address=157.240.229.63 list=Instagram +< add address=157.240.252.63 list=Instagram +< add address=31.13.72.53 list=Instagram +< add address=124.108.16.224 list=Instagram +< add address=157.240.205.63 list=Instagram +< add address=92.46.37.96 list=Instagram +< add address=157.240.247.63 list=Instagram +< add address=157.240.234.63 list=Instagram +< add address=157.240.235.63 list=Instagram +< add address=87.245.208.97 list=Instagram +< add address=216.58.192.0/19 list=Instagram +< add address=209.85.128.0/17 list=Instagram +< add address=198.105.240.0/20 list=Instagram +< add address=173.194.0.0/16 list=Instagram +< add address=172.217.0.0/16 list=Instagram +< add address=142.250.0.0/15 list=Instagram +< add address=108.177.0.0/17 list=Instagram +< add address=87.245.197.140 list=Instagram +< add address=74.125.0.0/16 list=Instagram +< add address=64.233.160.0/19 list=Instagram +< add address=157.240.0.1 list=Instagram +< add address=157.240.238.63 list=Instagram +< add address=157.240.238.174 list=Instagram +< add address=157.240.0.63 list=Instagram +< add address=157.240.224.63 list=Instagram +< add address=157.240.224.174 list=Instagram +< add address=157.240.251.36 list=Instagram +< add address=157.240.253.12 list=Instagram +< add address=157.240.253.35 list=Instagram +< add address=157.240.238.13 list=Instagram +< add address=157.240.238.56 list=Instagram +< add address=157.240.238.175 list=Instagram +< add address=57.144.112.141 list=Instagram +< add address=157.240.251.60 list=Instagram +< add address=157.240.251.128 list=Instagram +< add address=157.240.238.5 list=Instagram +< add address=157.240.253.13 list=Instagram +< add address=157.240.253.5 list=Instagram +< add address=157.240.238.2 list=Instagram +< add address=157.240.238.37 list=Instagram +< add address=157.240.251.5 list=Instagram +< add address=157.240.251.34 list=Instagram +< add address=57.144.112.1 list=Instagram +< add address=157.240.238.54 list=Instagram +< add address=129.134.26.123 list=Instagram +< add address=157.240.252.3 list=Instagram +< add address=31.13.84.4 list=Instagram +< add address=157.240.224.12 list=Instagram +< add address=157.240.238.4 list=Instagram +< add address=157.240.0.13 list=Instagram +< add address=3.33.139.32 list=Instagram +< add address=157.240.0.35 list=Instagram +< add address=157.240.238.14 list=Instagram +< add address=157.240.238.60 list=Instagram +< add address=57.144.112.145 list=Instagram +< add address=157.240.251.35 list=Instagram +< add address=151.101.84.159 list=Twitter +< add address=pbs.twimg.com list=Twitter +< add address=89.110.101.17 comment=VDSIna list=TRUSTED +< add address=10.8.0.0/24 comment="WG VDSIna" list=TRUSTED +< add address=ikus.pesc.ru comment=ikus.pesc.ru list=NoVdsina +< add address=love.ru comment=love.ru list=NoVdsina +< add address=gosuslugi.ru comment=gosuslugi.ru list=NoVdsina +< add address=pochta.ru comment=pochta.ru list=NoVdsina +< add address=vdsina.com list=NoVdsina +< add address=vdsina.ru list=NoVdsina +< add address=youla.ru list=NoVdsina +< add address=kupiprodai.ru list=NoVdsina +< add address=myip.ru list=Test +< add address=geoip.co list=NoVdsina +< add address=x.com list=Twitter +< add address=facebook.com list=facebook +< add address=fbcd.net list=facebook +< add address=comp-lenta.ru list=NoVdsina +< add address=128.85.102.70 comment=update.microsoft.com list=\ +< windowsupdateslist +< add address=wu-b-net.trafficmanager.net. comment=\ +< ctldl.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +< add address=ctldl.windowsupdate.com.delivery.microsoft.com. comment=\ +< ctldl.windowsupdate.com list=windowsupdateslist +< add address=redir.update.msft.com.trafficmanager.net. comment=\ +< update.microsoft.com list=windowsupdateslist +< add address=geo.prod.do.dsp.trafficmanager.net. comment=\ +< geo.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=13.74.139.29 comment=array605.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=kv801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< kv801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=e12437.d.akamaiedge.net. comment=\ +< kv801.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +< add address=displaycatalog-rp.md.mp.microsoft.com.akadns.net. comment=\ +< displaycatalog.mp.microsoft.com list=windowsupdateslist +< add address=rp-consumer-prod-displaycatalog-geomap.trafficmanager.net. \ +< comment=displaycatalog-rp.md.mp.microsoft.com.akadns.net list=\ +< windowsupdateslist +< add address=sls.update.microsoft.com. comment=slscr.update.microsoft.com \ +< list=windowsupdateslist +< add address=glb.sls.prod.dcat.dsp.trafficmanager.net. comment=\ +< sls.update.microsoft.com list=windowsupdateslist +< add address=fe3.delivery.mp.microsoft.com. comment=\ +< fe3cr.delivery.mp.microsoft.com list=windowsupdateslist +< add address=glb.cws.prod.dcat.dsp.trafficmanager.net. comment=\ +< fe3.delivery.mp.microsoft.com list=windowsupdateslist +< add address=fe2cr.update.msft.com.trafficmanager.net. comment=\ +< fe2cr.update.microsoft.com list=windowsupdateslist +< add address=download.windowsupdate.com.delivery.microsoft.com. comment=\ +< download.windowsupdate.com list=windowsupdateslist +< add address=wu-f-net.trafficmanager.net. comment=\ +< download.windowsupdate.com.delivery.microsoft.com list=windowsupdateslist +< add address=tsfe.trafficmanager.net. comment=\ +< tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +< add address=edge.ds-c7110-microsoft.global.dns.qwilted-cds.cqloud.com. \ +< comment=9.au.download.windowsupdate.com list=windowsupdateslist +< add address=52.158.227.125 comment=array812.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=au.download.windowsupdate.com.delivery.microsoft.com. comment=\ +< au.download.windowsupdate.com list=windowsupdateslist +< add address=a767.dspw65.akamai.net. comment=\ +< download.windowsupdate.com.edgesuite.net list=windowsupdateslist +< add address=52.151.58.88 comment=array810.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net. \ +< comment=licensing.mp.microsoft.com list=windowsupdateslist +< add address=licensing-prod-frontdoor-geomap.trafficmanager.net. comment=\ +< consumer-licensing-aks2aks.md.mp.microsoft.com.akadns.net list=\ +< windowsupdateslist +< add address=star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedge.f.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=cdp-f-nlu-net.trafficmanager.net. comment=\ +< star.f.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedge.b.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=cdp-f-tlu-net.trafficmanager.net. comment=\ +< star.b.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=storeedgefd.xbetservices.akadns.net. comment=\ +< storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +< add address=\ +< storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net. \ +< comment=storeedgefd.dsx.mp.microsoft.com.edgekey.net list=\ +< windowsupdateslist +< add address=e16646.dscg.akamaiedge.net. comment=\ +< storeedgefd.dsx.mp.microsoft.com.edgekey.net.globalredir.akadns.net list=\ +< windowsupdateslist +< add address=40.69.76.189 comment=array621.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=bg.microsoft.map.fastly.net. comment=\ +< 3.au.download.windowsupdate.com list=windowsupdateslist +< add list=windowsupdateslist +< add address=40.69.75.33 comment=array613.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedgeextensions.sf.tlu.dl.delivery.mp.microsoft.com list=\ +< windowsupdateslist +< add address=cdp-f-ssl-tlu-net.trafficmanager.net. comment=\ +< star.sf.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=a2033.dscd.akamai.net. comment=\ +< star.sb.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ +< windowsupdateslist +< add address=13.74.138.242 comment=array602.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ +< dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=dcat-f-nlu-net.trafficmanager.net. comment=\ +< dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=1D.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=dcat-b-tlu-net.trafficmanager.net. comment=\ +< 1d.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=a122.dscg3.akamai.net. comment=\ +< tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=windowsupdateslist +< add address=geover.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< geover.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=e10370.d.akamaiedge.net. comment=\ +< geover.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +< add address=52.232.182.21 comment=array511.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.70.77.95 comment=array519.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=a1683.dscd.akamai.net. comment=\ +< dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +< add address=consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net. \ +< comment=collections.mp.microsoft.com list=windowsupdateslist +< add address=a1847.dscd.akamai.net. comment=\ +< wildcard.f.tlu.dl.delivery.mp.microsoft.com.edgesuite.net list=\ +< windowsupdateslist +< add address=13.74.142.6 comment=array607.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=au.download.windowsupdate.com.edgesuite.net. comment=\ +< 2.au.download.windowsupdate.com list=windowsupdateslist +< add address=a767.dscg3.akamai.net. comment=\ +< au.download.windowsupdate.com.edgesuite.net list=windowsupdateslist +< add address=52.156.123.84 comment=array818.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.69.78.254 comment=array610.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=4.au.download.windowsupdate.com.delivery.microsoft.com. comment=\ +< 4.au.download.windowsupdate.com list=windowsupdateslist +< add address=cl-glcb907925.gcdn.co. comment=\ +< 4.au.download.windowsupdate.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.167.111 comment=array510.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=40.69.70.43 comment=array623.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com. \ +< comment=tsfe.trafficshaping.dsp.mp.microsoft.com list=windowsupdateslist +< add address=ts-frontend.trafficmanager.net. comment=\ +< tsfe.trafficshaping.dsp.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=40.69.75.248 comment=array616.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.69.74.84 comment=array615.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=sds.trafficmanager.net. comment=software-download.microsoft.com \ +< list=windowsupdateslist +< add address=40.69.74.80 comment=array611.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.175.242.182 comment=array804.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=dlc-shim.trafficmanager.net. comment=download.microsoft.com list=\ +< windowsupdateslist +< add address=e12671.dscd.akamaiedge.net. comment=\ +< download.microsoft.com.edgekey.net list=windowsupdateslist +< add address=20.187.55.34 comment=array808.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.167.231 comment=array513.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=52.167.222.13 comment=array518.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=kv601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< kv601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=e12358.d.akamaiedge.net. comment=\ +< kv601.prod.do.dsp.mp.microsoft.com.edgekey.net list=windowsupdateslist +< add address=tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. comment=\ +< tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=dcat-f-tlu-net.trafficmanager.net. comment=\ +< tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=a1856.dspw65.akamai.net. comment=\ +< tlu.dl.delivery.mp.microsoft.com-c.edgesuite.net list=windowsupdateslist +< add address=52.167.164.252 comment=array506.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=13.74.137.54 comment=array601.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=kv501.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< kv501.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=collections-prod-frontdoor-geomap.trafficmanager.net. comment=\ +< consumer-collections-aks2eap.md.mp.microsoft.com.akadns.net list=\ +< windowsupdateslist +< add address=52.167.160.173 comment=array509.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=40.70.77.148 comment=array516.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.200.126 comment=array507.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=52.167.167.59 comment=array508.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.69.76.172 comment=array620.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=82.202.162.184 comment=comp-lenta.ru list=NoWG +< add address=smtp.mail.me.com.akadns.net. comment=smtp.mail.me.com list=NoWG +< add address=17.57.155.37 comment=smtp.mail.me.com.akadns.net list=NoWG +< add address=smtp.mail.me.com comment=smtp.mail.me.com list=NoVdsina +< add address=40.70.76.5 comment=array514.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=13.74.186.119 comment=array618.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.177.176.186 comment=array520.prod.do.dsp.mp.microsoft.com \ +< list=windowsupdateslist +< add address=40.70.76.27 comment=array515.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.160.43 comment=array503.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.110 comment=array817.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=13.74.142.8 comment=array614.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=13.74.138.254 comment=array603.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.167.96 comment=array501.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.69.76.215 comment=array622.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=13.74.143.200 comment=array606.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.111 comment=array818.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.112 comment=array819.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=13.74.137.53 comment=array608.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.98 comment=array805.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.96 comment=array803.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.104 comment=array811.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.101 comment=array808.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.99 comment=array806.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.17 comment=array802.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.97 comment=array804.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.103 comment=array810.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.16 comment=array801.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=40.70.77.177 comment=array517.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.164.84 comment=array512.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.105 comment=array812.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.107 comment=array814.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.232.161.82 comment=array502.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.108 comment=array815.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=52.167.161.91 comment=array505.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.102 comment=array809.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.109 comment=array816.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.106 comment=array813.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.117 comment=array622.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.107 comment=array612.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.108 comment=array613.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.105 comment=array610.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.113 comment=array618.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.116 comment=array621.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.98 comment=array603.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.114 comment=array619.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.111 comment=array616.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.97 comment=array602.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.106 comment=array611.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.110 comment=array615.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.119 comment=array624.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.135 comment=array514.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.97 comment=array503.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.99 comment=array604.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.61 comment=array504.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.131 comment=array510.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.132 comment=array511.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.96 comment=array601.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.104 comment=array609.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.138 comment=array517.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.60 comment=array501.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.139 comment=array518.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.118 comment=array623.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.113 comment=array820.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.103 comment=array608.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.154.7.100 comment=array807.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.129 comment=array508.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.134 comment=array513.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.62 comment=array505.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.137 comment=array516.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.101 comment=array606.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.96 comment=array502.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.130 comment=array509.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.112 comment=array617.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.100 comment=array605.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.115 comment=array620.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.136 comment=array515.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=purchase.md.mp.microsoft.com.akadns.net. comment=\ +< purchase.mp.microsoft.com list=windowsupdateslist +< add address=e110219.a.akamaiedge.net. comment=\ +< purchase.mp.microsoft.com.edgekey.net list=windowsupdateslist +< add address=72.153.5.140 comment=array519.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.141 list=windowsupdateslist +< add address=72.153.5.63 comment=array506.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.128 comment=array507.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.102 comment=array607.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=storesdk.xbetservices.akadns.net. comment=\ +< storesdk.dsx.mp.microsoft.com list=windowsupdateslist +< add address=e16646.g.akamaiedge.net. comment=\ +< storesdk.dsx.mp.microsoft.com.edgekey.net list=windowsupdateslist +< add address=software-download.microsoft.com.delivery.microsoft.com. comment=\ +< software-download.microsoft.com list=windowsupdateslist +< add address=download.prss.microsoft.com.akamaized.net. comment=\ +< software-download.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=72.145.35.109 comment=array614.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=72.153.5.133 comment=array512.prod.do.dsp.mp.microsoft.com list=\ +< windowsupdateslist +< add address=213.180.192.0/19 comment=YandexDisk list=NoVdsina +< add address=87.250.250.50 comment=YandexDisk list=NoVdsina +< add address=consumer-prod-bcfd-v7-afd.trafficmanager.net. comment=\ +< displaycatalog.mp.microsoft.com list=windowsupdateslist +< add address=purchase-europeeap.md.mp.microsoft.com.akadns.net. comment=\ +< purchase.md.mp.microsoft.com.akadns.net list=windowsupdateslist +< add address=ne-az-conspurchase-mp.trafficmanager.net. comment=\ +< purchase-europeeap.md.mp.microsoft.com.akadns.net list=windowsupdateslist +< add address=storeedgefd.dsx.mp.microsoft.com.edgekey.net. comment=\ +< cdn.storeedgefd.dsx.mp.microsoft.com list=windowsupdateslist +< add address=star.f.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedge.f.tlu.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=a1996.dscd.akamai.net. comment=\ +< wildcard.f.dl.delivery.mp.microsoft.com.edgesuite.net list=\ +< windowsupdateslist +< add address=cp801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< cp801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=glb.tas02.sls-prod.dcat.dsp.mp.microsoft.com. comment=\ +< tas02.sls.update.microsoft.com list=windowsupdateslist +< add address=cp601.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< cp601.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=star.sb.tlu.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedgeextensions.sb.tlu.dl.delivery.mp.microsoft.com list=\ +< windowsupdateslist +< add address=star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com. \ +< comment=msedge.sf.dl.delivery.mp.microsoft.com list=windowsupdateslist +< add address=cdp-f-ssl-nlu-net.trafficmanager.net. comment=\ +< star.sf.dl.delivery.mp.microsoft.com.delivery.microsoft.com list=\ +< windowsupdateslist +< add address=tm-pifd-prod-gbl-weight.trafficmanager.net. comment=\ +< paymentinstruments.mp.microsoft.com list=windowsupdateslist +< add address=10.30.30.33 comment=amster-nuc list=NoWG +< add address=10.30.30.11 comment=MikroNUC list=NoWG +< add address=89.110.101.17 comment=!!!VDSINA!!!! list=NoWG +< add address=89.110.101.17 list=VPN-Server +< add address=80.85.244.9 list=TRUSTED +< add address=8.8.8.8 list=TRUSTED +< add address=8.8.4.4 list=TRUSTED +< add address=disc801.prod.do.dsp.mp.microsoft.com.edgekey.net. comment=\ +< disc801.prod.do.dsp.mp.microsoft.com list=windowsupdateslist +< add address=10.30.30.95 comment=NUC list=NoWG +< add address=glb.tas02.cws-prod.dcat.dsp.mp.microsoft.com. comment=\ +< tas02.cws.update.microsoft.com list=windowsupdateslist +< /ip firewall filter +< add action=add-src-to-address-list address-list="Honeypot Hacker" \ +< address-list-timeout=12h chain=input comment="block honeypot DNS" \ +< connection-state=new dst-port=53 in-interface="ether1 - Unet" protocol=\ +< udp +< add action=add-src-to-address-list address-list="Honeypot Hacker" \ +< address-list-timeout=4w2d chain=input connection-state=new dst-port=53 \ +< in-interface="ether1 - Unet" protocol=tcp +< add action=add-src-to-address-list address-list="Honeypot Hacker" \ +< address-list-timeout=4w2d chain=input comment=\ +< "block honeypot ssh rdp winbox" connection-state=new dst-port=\ +< 22,8291,2222 in-interface="ether1 - Unet" protocol=tcp src-address-list=\ +< !TRUSTED +< add action=add-src-to-address-list address-list="Honeypot Hacker" \ +< address-list-timeout=4w2d chain=input comment="block honeypot asterisk" \ +< connection-state=new dst-port=5060 in-interface="ether1 - Unet" protocol=\ +< udp +< add action=add-src-to-address-list address-list="Honeypot Hacker" \ +< address-list-timeout=5d chain=input comment="block honeypot NTP" \ +< connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ +< udp src-address=!10.30.30.0/24 +< add action=accept chain=input comment=\ +< "accept NTP clients on local area network" dst-port=123 in-interface=\ +< Bridge-LAN in-interface-list=LAN protocol=udp +< add action=accept chain=input comment="accept WireGuard" dst-port=13231 \ +< in-interface="ether1 - Unet" protocol=udp src-address-list=VPN-Server +< add action=accept chain=input disabled=yes dst-port=443 in-interface=\ +< "ether1 - Unet" protocol=tcp +< add action=accept chain=output disabled=yes protocol=tcp src-port=443 +< add action=fasttrack-connection chain=forward comment=\ +< "FastTrack for non-VPN connections" connection-mark=!VPN_No_FastTrack \ +< connection-state=established,related,new disabled=yes +< add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ +< connection-state=established,related,new disabled=yes routing-mark=\ +< !To-VPN +< add action=accept chain=input comment=\ +< "defconf: accept established,related,untracked" connection-state=\ +< established,related,untracked +< add action=drop chain=input comment="defconf: drop invalid" connection-state=\ +< invalid +< add action=accept chain=input comment="defconf: accept ICMP" disabled=yes \ +< protocol=icmp +< add action=accept chain=input comment=\ +< "defconf: accept to local loopback (for CAPsMAN)" disabled=yes \ +< dst-address=127.0.0.1 +< add action=accept chain=output disabled=yes src-address=127.0.0.1 +< add action=accept chain=forward comment="defconf: accept in ipsec policy" \ +< ipsec-policy=in,ipsec +< add action=accept chain=forward comment="defconf: accept out ipsec policy" \ +< ipsec-policy=out,ipsec +< add action=accept chain=forward comment=\ +< "defconf: accept established,related, untracked" connection-state=\ +< established,related,untracked +< add action=drop chain=forward comment="defconf: drop invalid" \ +< connection-state=invalid disabled=yes +< add action=drop chain=forward comment=\ +< "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ +< connection-state=new in-interface="ether1 - Unet" +< add action=accept chain=input connection-state=established disabled=yes +< add action=accept chain=input connection-state=related disabled=yes +< add action=drop chain=input disabled=yes in-interface-list=!LAN +< add action=drop chain=forward comment=\ +< "Filter Rule to block FB address LIST : )" disabled=yes dst-address-list=\ +< facebook +< add action=drop chain=forward comment=\ +< "Filter Rule to block YOUTUBE address LIST : )" disabled=yes \ +< dst-address-list=YouTube +< /ip firewall mangle +< add action=mark-connection chain=prerouting comment=\ +< "Mark VPN connections to exclude from FastTrack" in-interface=WG \ +< log-prefix=Mark-VPN-FT new-connection-mark=VPN_No_FastTrack +< add action=mark-routing chain=prerouting comment="Test sites" disabled=yes \ +< dst-address=!10.30.30.0/24 dst-address-list=Test new-routing-mark=To-VPN \ +< passthrough=no src-address=10.30.30.0/24 +< add action=mark-routing chain=prerouting comment=Instagram dst-address=\ +< !10.30.30.0/24 dst-address-list=Instagram new-routing-mark=To-VPN \ +< src-address=10.30.30.0/24 src-address-list=!NoWG +< add action=mark-routing chain=prerouting comment=Twitter dst-address=\ +< !10.30.30.0/24 dst-address-list=Twitter new-routing-mark=To-VPN \ +< src-address=10.30.30.0/24 src-address-list=!NoWG +< add action=mark-routing chain=prerouting comment=YouTube dst-address=\ +< !10.30.30.0/24 dst-address-list=YouTube new-routing-mark=To-VPN \ +< src-address=10.30.30.0/24 src-address-list=!NoWG +< add action=mark-routing chain=prerouting comment=facebook dst-address=\ +< !10.30.30.0/24 dst-address-list=facebook new-routing-mark=To-VPN \ +< src-address=10.30.30.0/24 src-address-list=!NoWG +< add action=mark-routing chain=prerouting comment="VDSIna for All sites" \ +< dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina log-prefix=VPN-all \ +< new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +< add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ +< out-interface=WG protocol=tcp tcp-flags=syn tcp-mss=1381-65535 +< add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ +< 10.8.0.0/24 dst-address-list=!NoVdsina log=yes log-prefix=VPN-Net \ +< new-routing-mark=To-VPN src-address=10.30.30.0/24 src-address-list=!NoWG +< /ip firewall nat +< add action=redirect chain=dstnat comment=\ +< "FORCE DNS TO LOCAL MIKROTIK DNS SERVER" dst-port=53 protocol=tcp \ +< src-address=10.30.30.0/24 to-ports=53 +< add action=redirect chain=dstnat dst-port=53 protocol=udp src-address=\ +< 10.30.30.0/24 to-ports=53 +< add action=masquerade chain=srcnat comment="masquerade Default" ipsec-policy=\ +< out,none out-interface="ether1 - Unet" routing-mark=!To-VPN +< add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ +< in-interface=Bridge-LAN log-prefix=WG-nat out-interface=WG routing-mark=\ +< To-VPN +< add action=dst-nat chain=dstnat comment=npm disabled=yes dst-port=81 \ +< in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ +< to-ports=81 +< add action=dst-nat chain=dstnat comment=amster.vados.ruhttps disabled=yes \ +< dst-port=443 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ +< 10.30.30.33 to-ports=443 +< add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ +< disabled=yes dst-port=80 in-interface="ether1 - Unet" protocol=tcp \ +< to-addresses=10.30.30.33 to-ports=80 +< add action=dst-nat chain=dstnat disabled=yes dst-port=80 in-interface=\ +< "ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 to-ports=80 +< add action=dst-nat chain=dstnat comment="Yandex.DNS Family" disabled=yes \ +< dst-port=53 in-interface=Bridge-LAN protocol=udp src-address-list=KIDS \ +< time=6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +< add action=dst-nat chain=dstnat disabled=yes dst-port=53 in-interface=\ +< Bridge-LAN protocol=tcp src-address-list=KIDS time=\ +< 6h-15m,sun,mon,tue,wed,thu,fri,sat to-addresses=77.88.8.3 +< add action=dst-nat chain=dstnat dst-address=146.120.64.211 dst-port=32000 \ +< in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.95 \ +< to-ports=32000 +< add action=dst-nat chain=dstnat dst-address=146.120.64.211 dst-port=32000 \ +< in-interface="ether1 - Unet" protocol=udp to-addresses=10.30.30.95 \ +< to-ports=32000 +< add action=dst-nat chain=dstnat dst-port=32000 protocol=tcp routing-mark=\ +< To-VPN to-addresses=10.30.30.95 to-ports=32000 +< add action=dst-nat chain=dstnat dst-port=32000 protocol=udp routing-mark=\ +< To-VPN to-addresses=10.30.30.95 to-ports=32000 +< /ip firewall raw +< add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ +< in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=\ +< extras.getpagespeed.com content=extras.getpagespeed.com disabled=yes +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=linux.duke.edu \ +< content=linux.duke.edu disabled=yes +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=vk.com \ +< content=vk.com +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=ok.ru content=\ +< ok.ru +< add action=add-dst-to-address-list address-list=Instagram \ +< address-list-timeout=none-dynamic chain=prerouting comment=Instagram \ +< content=instagram.com +< add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ +< none-dynamic chain=prerouting comment=Twitter content=twimg.com +< add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ +< none-dynamic chain=prerouting content=x.com +< add action=add-dst-to-address-list address-list=Twitter address-list-timeout=\ +< none-dynamic chain=prerouting content=twitter.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting comment=YouTube content=youtube.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=googleapis.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=ggpht.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=youtu.be +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=ytimg.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=googlevideo.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=gstatic.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=googleusercontent.com +< add action=add-dst-to-address-list address-list=YouTube address-list-timeout=\ +< none-dynamic chain=prerouting content=nhacmp3youtube.com +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ +< content=rutube.ru +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=me.com \ +< content=me.com +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=icloud.com \ +< content=icloud.com +< add action=add-dst-to-address-list address-list=facebook \ +< address-list-timeout=none-dynamic chain=prerouting comment=facebook \ +< content=fbcd.net +< add action=add-dst-to-address-list address-list=facebook \ +< address-list-timeout=none-dynamic chain=prerouting content=facebook.com +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=comp-lenta.ru \ +< content=comp-lenta.ru +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=\ +< smtp.mail.me.com content=smtp.mail.me.com log=yes +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=gov.ru \ +< content=gov.ru +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=\ +< r78.fssp.gov.ru content=r78.fssp.gov.ru +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=api.db-ip.com \ +< content=api.db-ip.com +< add action=add-dst-to-address-list address-list=NoVdsina \ +< address-list-timeout=none-dynamic chain=prerouting comment=\ +< api.telegram.org content=api.telegram.org +< /ip firewall service-port +< set ftp disabled=yes +< set tftp disabled=yes +< set irc disabled=no +< set sip disabled=yes +< set pptp disabled=yes +< set rtsp disabled=no +< /ip hotspot walled-garden +< add server=*1 +< /ip ipsec settings +< set accounting=no +< /ip ipsec policy +< set 0 disabled=yes dst-address=0.0.0.0/0 src-address=0.0.0.0/0 +< /ip ipsec profile +< set [ find default=yes ] dpd-interval=2m dpd-maximum-failures=5 +< /ip proxy +< set cache-administrator="" max-cache-size=none port=80,443 src-address=\ +< 0.0.0.0 +< /ip route +< add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +< add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +< add disabled=no distance=3 dst-address=192.168.0.0/24 gateway=l2tp-vpn +< add disabled=no distance=4 dst-address=192.168.5.0/24 gateway=l2tp-vpn +< add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=WG routing-table=\ +< To-VPN scope=30 target-scope=10 +< add disabled=yes distance=2 dst-address=0.0.0.0/0 gateway=146.120.64.209 \ +< routing-table=main scope=30 target-scope=10 +< /ip service +< set ftp disabled=yes +< set telnet disabled=yes +< set ssh address=10.30.30.0/24 port=2222 +< set winbox address=10.30.30.0/24 +< set api address=10.30.30.0/24 disabled=yes +< set api-ssl address=10.30.30.0/24 +< set www-ssl port=18443 +< set www address=10.30.30.0/24 disabled=yes port=18880 +< /ip service webserver +< set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ +< no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ +< webfig-plain=no webfig-secure=no +< /ip ssh +< set forwarding-enabled=both publickey-authentication-options=verify-required \ +< strong-crypto=yes +< /ip upnp +< set enabled=yes +< /ip upnp interfaces +< add interface=Bridge-LAN type=internal +< add interface="ether1 - Unet" type=external +< /ipv6 firewall address-list +< add address=::/128 comment="defconf: unspecified address" list=bad_ipv6 +< add address=::1/128 comment="defconf: lo" list=bad_ipv6 +< add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6 +< add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6 +< add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6 +< add address=100::/64 comment="defconf: discard only " list=bad_ipv6 +< add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6 +< add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6 +< add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6 +< /ipv6 firewall filter +< add action=add-src-to-address-list address-list=bad_ipv6 \ +< address-list-timeout=none-dynamic chain=input comment=\ +< "defconf: accept established,related,untracked" connection-state=\ +< established,related,untracked in-interface=WG in-interface-list=WAN \ +< src-address-list="" +< add action=drop chain=input comment="defconf: drop invalid" connection-state=\ +< invalid +< add action=accept chain=input comment="defconf: accept ICMPv6" protocol=\ +< icmpv6 +< add action=accept chain=input comment="defconf: accept UDP traceroute" \ +< dst-port=33434-33534 protocol=udp +< add action=accept chain=input comment=\ +< "defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=\ +< udp src-address=fe80::/10 +< add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 \ +< protocol=udp +< add action=accept chain=input comment="defconf: accept ipsec AH" protocol=\ +< ipsec-ah +< add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=\ +< ipsec-esp +< add action=accept chain=input comment=\ +< "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +< add action=drop chain=input comment=\ +< "defconf: drop everything else not coming from LAN" in-interface-list=\ +< !LAN +< add action=accept chain=forward comment=\ +< "defconf: accept established,related,untracked" connection-state=\ +< established,related,untracked +< add action=drop chain=forward comment="defconf: drop invalid" \ +< connection-state=invalid +< add action=drop chain=forward comment=\ +< "defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6 +< add action=drop chain=forward comment=\ +< "defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6 +< add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" \ +< hop-limit=equal:1 protocol=icmpv6 +< add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=\ +< icmpv6 +< add action=accept chain=forward comment="defconf: accept HIP" protocol=139 +< add action=accept chain=forward comment="defconf: accept IKE" dst-port=\ +< 500,4500 protocol=udp +< add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=\ +< ipsec-ah +< add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=\ +< ipsec-esp +< add action=accept chain=forward comment=\ +< "defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec +< add action=drop chain=forward comment=\ +< "defconf: drop everything else not coming from LAN" in-interface-list=\ +< !LAN +< /ipv6 nd +< set [ find default=yes ] advertise-dns=yes +< /ppp secret +< add local-address=192.168.60.1 name=vados remote-address=192.168.60.2 \ +< service=l2tp +< /routing bfd configuration +< add disabled=no +< /snmp +< set contact=@AmsterNL enabled=yes engine-id-suffix=MikroMaster location=NL \ +< src-address=10.30.30.81 trap-interfaces=Bridge-LAN,WG trap-target=\ +< 10.30.30.10 +< /system clock +< set time-zone-autodetect=no time-zone-name=Europe/Moscow +< /system clock manual +< set time-zone=+03:00 +< /system identity +< set name=MikroMaster +< /system logging +< add action=email disabled=yes regex="* added|changed|removed *" topics=\ +< system,info +< /system ntp client +< set enabled=yes +< /system ntp server +< set enabled=yes manycast=yes multicast=yes use-local-clock=yes +< /system ntp client servers +< add address=0.ru.pool.ntp.org +< add address=1.ru.pool.ntp.org +< add address=2.ru.pool.ntp.org +< add address=3.ru.pool.ntp.org +< add address=time.google.com disabled=yes +< /system scheduler +< add comment="Windows Update script" interval=2d5m name=WU-script-run-schedule \ +< on-event=WU-add-to-list policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2014-02-11 start-time=00:00:00 +< add comment="Backup Every Week" disabled=yes interval=1w name=BackupEveryWeek \ +< on-event=BackupAndUpdate policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2025-07-07 start-time=03:41:27 +< add comment="DoH Cache Flush" interval=1d name="DNS Cache Flush" on-event=\ +< DNS_Flush_Cache policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2019-12-06 start-time=05:30:00 +< add comment="Create mkdir function on startup" name=\ +< create_mkdir_function_on_startup on-event=\ +< "/system script run create_mkdir_function;" policy=read,write,policy,test \ +< start-time=startup +< add comment="Scheduler for Update Certificates CloudFlare Quad9" interval=1w \ +< name="Update Certificates CloudFlare Quad9" on-event=\ +< "/system/script { run Update-Certificates; }" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2025-11-28 start-time=05:45:40 +< add comment="Scheduler for Amster-Backup-UpdateEmail" disabled=yes interval=\ +< 1w name=Amster-Backup-UpdateEmail on-event=\ +< "/system/script { run Amster-Backup-UpdateEmail; }" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2026-02-13 start-time=03:41:27 +< add comment="Setup Global Environment for scripts" name=AM-SetGlobalEnv \ +< on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ +< policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-time=startup +< add comment="Every Day Check For Update Scripts" interval=1d name=\ +< AM-ScriptInstallUpdate on-event=\ +< ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-time=startup +< add comment="Every Day Check For Fake Bridges" interval=1d name=\ +< mod/AM-IPbridge on-event="/system/script/run mod/AM-IPbridge;" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-time=startup +< add comment="Every Day Check For Renew Certificates" interval=1d name=\ +< AM-CheckCerts on-event="/system/script/run AM-CheckCerts;" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-time=startup +< /system watchdog +< set watchdog-timer=no +< /tool e-mail +< set certificate-verification=no from=MikroVados port=587 \ +< server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +< /tool mac-server +< set allowed-interface-list=LAN +< /tool mac-server mac-winbox +< set allowed-interface-list=LAN +< /tool netwatch +< add comment="doh, doh-url=https://security.cloudflare-dns.com/dns-query, notif\ +< y, name=CloudFlare-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 \ +< http-codes="" test-script="" type=simple up-script="" +< add check-certificate=no comment="doh-fallback, doh-url=https://security.cloud\ +< flare-dns.com/dns-query, doh-cert=DigiCert Global Root CA, notify, name=Cl\ +< oudFlare-doh IPv4" disabled=yes down-script="" host=1.0.0.1 http-codes="" \ +< port=443 test-script="" type=simple up-script="" +< add comment="dns-fallback, notify, name=Google-DNS IPv4" disabled=yes \ +< down-script="" host=8.8.8.8 http-codes="" test-script="" type=simple \ +< up-script="" +< add comment="doh-fallback, doh-url=https://dns.google/dns-query, doh-cert=GTS \ +< Root R1, notify, name=Google-DOH IPv4" disabled=yes down-script="" host=\ +< 8.8.4.4 http-codes="" test-script="" type=simple up-script="" +< add comment="dns, notify, name=Cuad9-DOH IPv4" disabled=yes down-script="" \ +< host=9.9.9.9 http-codes="" test-script="" type=simple up-script="" +< add comment="doh-fallback, doh-url=https://dns.quad9.net/dns-query, name=Cuad9\ +< -DOH IPv4" disabled=yes down-script="" host=149.112.112.112 http-codes="" \ +< test-script="" type=simple up-script="" +< add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ +< down-script="" host=91.192.189.2 http-codes="" test-script="" type=simple \ +< up-script="" +< /tool sniffer +< set filter-interface=Bridge-LAN filter-src-ip-address=10.30.30.50/32 +< /user aaa +< set accounting=no diff --git a/MikroNUC/20260405/20260405035444-Config.rsc b/MikroNUC/20260405/20260405035444-Config.rsc new file mode 100644 index 0000000..77fef34 --- /dev/null +++ b/MikroNUC/20260405/20260405035444-Config.rsc @@ -0,0 +1,2916 @@ +# 2026-04-05 03:54:44 by RouterOS 7.22.1 +# system id = NmJcEM+8XAP +# +/caps-man channel +add band=2ghz-g/n extension-channel=disabled frequency=2422 name=2G-3 \ + reselect-interval=20m save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXX frequency=5660 name=5G-5660 \ + save-selected=yes +add band=5ghz-a/n/ac extension-channel=XXXXXXXX frequency=5160,5200,5280 \ + name=5G-5160-5280 reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5180 name=5G-36 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5200 name=5G-40 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5220 name=5G-44 \ + reselect-interval=30m save-selected=yes +add band=5ghz-n/ac extension-channel=XXXX frequency=5240 name=5G-48 \ + reselect-interval=30m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2442 name=2G-7 \ + reselect-interval=20m save-selected=yes +add band=2ghz-g/n extension-channel=disabled frequency=2462 name=2G-11 \ + reselect-interval=20m save-selected=yes +/interface bridge +add name=Bridge-DOC +add name=Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] disable-running-check=no name=ether2 +/interface veth +add address=172.18.20.6/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.18.20.5 gateway6="" name=docker-xray-vless-veth +add address=10.10.10.10/24 container-mac-address=5C:26:FE:05:6F:12 dhcp=no \ + gateway=10.10.10.1 gateway6="" mac-address=5C:26:FE:05:6F:11 name=veth1 +/caps-man datapath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=xs-DataPath +add bridge=Bridge-LAN client-to-client-forwarding=yes local-forwarding=yes \ + name=DataPath +/caps-man security +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=xs-Sec +add authentication-types=wpa2-psk encryption=aes-ccm group-encryption=aes-ccm \ + group-key-update=30m name=WPA2 +/caps-man configuration +add channel.band=2ghz-b/g/n country=no_country_set datapath=xs-DataPath mode=\ + ap name=xs-2G rx-chains=0,1,2,3 security=xs-Sec ssid=vados tx-chains=\ + 0,1,2,3 +add channel.band=5ghz-a/n/ac country=no_country_set datapath=xs-DataPath \ + installation=any mode=ap name=xs-5G rx-chains=0,1,2,3 security=xs-Sec \ + ssid=vados5g tx-chains=0,1,2,3 +add channel.band=2ghz-b/g/n .control-channel-width=20mhz .extension-channel=\ + XX .frequency=2422,2442,2462 .reselect-interval=20m country=belarus \ + datapath=DataPath datapath.client-to-client-forwarding=yes \ + .local-forwarding=yes hw-protection-mode=rts-cts installation=any name=2G \ + rx-chains=0,1,2,3 security=WPA2 ssid=vados tx-chains=0,1,2,3 +add channel.band=5ghz-a/n/ac .control-channel-width=20mhz .extension-channel=\ + XXXX .frequency=5180,5200,5220,5240,5260 .reselect-interval=20m \ + .skip-dfs-channels=yes country=belarus datapath=DataPath \ + datapath.client-to-client-forwarding=yes .local-forwarding=yes \ + hw-protection-mode=rts-cts installation=any name=5G security=WPA2 ssid=\ + vados5g +/disk +add slot=tmpfs tmpfs-max-size=715827882 type=tmpfs +/interface list +add include=dynamic,static name=LAN +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroMIC +/ip dhcp-server option +add code=12 name=HostName +add code=119 force=yes name=domain-search-list value="0x03'WORKGROUP'0x00" +/ip dhcp-server option sets +add name=P1505n options=HostName +add name=StartLife1 options=HostName +add name=amsterDev options=HostName +add name=MiTV options=HostName +add name=miller options=HostName +add name=amster options=HostName +add name=garage options=HostName +add name=domain-search-set options=domain-search-list +/ip pool +add name=dhcp ranges=10.30.30.150-10.30.30.200 +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add dont-require-permissions=no name=test owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + \r\ + \n#:local ScriptName [ :jobname ];\r\ + \n:local expSrc;\r\ + \n:local FileName;\r\ + \n:local FilePath;\r\ + \n:local DirPath \"tmpfs/\";\r\ + \n:global WaitForFile;\r\ + \n:global IfThenElse;\r\ + \n\r\ + \n:foreach Script in=([ /system/script find where name~\"Amster-GlobalConf\ + *\" ]) do={\r\ + \n:local ScriptVal [ /system/script/get \$Script ];\r\ + \n\r\ + \n:local expName [ (\$ScriptVal->\"name\") ];\r\ + \n#[/system/script get \$expScript name];\r\ + \n:delay 2s;\r\ + \n\r\ + \n:set expSrc [/system/script print where name=\$expName];\r\ + \n/system/script print where name=\$expName;\r\ + \n#[:put [/system/script get \$expScript source]];\r\ + \n:put [\$expSrc];\r\ + \n:delay 2s;\r\ + \n:set FileName \$expName;\r\ + \n:set FilePath (\$DirPath . \$FileName);\r\ + \n\r\ + \n#:log warning \"\\n----------------------\\n\\\$expSrc = \$expSrc\\n____\ + ______________________________\";\r\ + \n:log info \"\\n\\\$FileName = '\$FileName'\";\r\ + \n:log info \"\\n\\\$FilePath = \$FilePath\";\r\ + \n#:log warning {/system/script/get source=[/system/script/get \$expScript\ + \_source];};\r\ + \n\r\ + \n#\$[/system script get [/system script find name=\"\$FileName\"] source]\ + \r\ + \n\r\ + \n#:local gettingScript \"\$FileName\";\r\ + \n#:execute script=\"[[:parse \\\"[:parse { :put (\"\$[/system script get \ + [/system script find name=\$FileName] source]\"); } \\\"]]\"; \\\r\ + \n\r\ + \n#:execute script={:put \"[:parse \\\"[:parse [/system/script get [/syste\ + m/script find name=\$gettingScript] source];\\\"]]\";} \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n:do {\r\ + \n:local fName (\$FilePath . \".rsc\");\r\ + \n#:delay 3s;\r\ + \n#/file add name=\$fName;\r\ + \n:put [:tostr [\$expSrc]];\r\ + \n/file set \$fName contents=[:put [\$expSrc]];\r\ + \n:delay 3s;\r\ + \n\$WaitForFile \$fName;\r\ + \n(\$FilePath . \".rsc\");\r\ + \n#:delay 2s;\r\ + \n\r\ + \n} on-error={\r\ + \n:log error \"\\nERROR \\\$FilePath = \$FilePath\";\r\ + \n}\r\ + \n#\$WaitForFile (\$FilePath . \".rsc\");\r\ + \n#:execute script={ :put [/system/script get [:put \$FileName] source]; }\ + ;\r\ + \n#/system/script export \$Sscript file=\$FilePath;\r\ + \n#/system/script/export [:put [/system/script/get \$expScript source]] fi\ + le=\$FilePath;\r\ + \n#:execute script={ :put [/system/script/get \$expScript source]; } \\\r\ + \n\r\ + \n#:log warning \"\\n\\\$expScript = \$expScript\";\r\ + \n# \\\r\ + \n# file=(\$FilePath . \".rsc\\00\");\r\ + \n#script={:put [/system/script/get \$FileName source];} file=(\$FilePath\ + \_. \".rsc\\00\");\r\ + \n#/system script export \$src file=(\$FilePath . \$FileName);\r\ + \n}\r\ + \n\r\ + \n:log warning \"\\nComplete!\";\r\ + \n\r\ + \n # :execute script={ :put [ /system/script/get Amster-GlobalConfig sou\ + rce ]; } \\\r\ + \n # file=(\$FilePath . \".conf\\00\");\r\ + \n # \$WaitForFile (\$FilePath . \".conf\");\r\ + \n # :onerror Err {\r\ + \n # /tool/fetch upload=yes url=(\$BackupUploadUrl . \"/\" . \$FileName\ + \_. \".conf\") \\\r\ + \n # user=\$BackupUploadUser password=\$BackupUploadPass src-path=(\ + \$FilePath . \".conf\");\r\ + \n # :set ConfigFile [ /file/get (\$FilePath . \".conf\") ];\r\ + \n # :set (\$ConfigFile->\"name\") (\$FileName . \".conf\");\r\ + \n " +add dont-require-permissions=no name=test1 owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n#:local runningVer [:find [/system/resource/get version] \"(\"];\r\ + \n\r\ + \n:local runningChannel;\r\ + \n:local runningVersion;\r\ + \n:local ParseCustom;\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n \r\ + \n:global runningChannel [\$ParseCustom [/system/resource/get version] \"(\ + \" \")\" 1];\r\ + \n:log warning [\$runningChannel];\r\ + \n:set runningVersion [\$ParseCustom [/system/resource/get version] \" \" \ + \")\" 2];\r\ + \n:log warning [\$runningVersion];\r\ + \n\r\ + \n\r\ + \n\r\ + \n# :if ([:len \$open] = 0) do={\r\ + \n# :log error \"\$SMP Could not extract installed OS channel from vers\ + ion string: `\$runningOsAndChannel`.\";\r\ + \n# :error \"\$SMP error, check logs\";\r\ + \n# }\r\ + \n# :local rest [:pick \$runningOsAndChannel (\$open+1) [:len \$runningOs\ + AndChannel]];\r\ + \n# :local close [:find \$rest \")\"];\r\ + \n# :local channel [:pick \$rest 0 \$close];\r\ + \n# :return \$channel;\r\ + \n#}" +add dont-require-permissions=no name=01-Amster-Init-Script owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# Amster Initial Script\r\ + \n#\r\ + \n#:global GlobalEnvRemove true; /system/script {run Amster-GlobalEnvRemov\ + e; };\r\ + \n#:delay 1s;\r\ + \n:#global ReloadGlobal true; \r\ + \n\r\ + \n:global AmScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global defOwner \"vados\";\r\ + \n:global AmFirstRun;\r\ + \n\r\ + \n:set AmFirstRun do={\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n #:global ParseKeyValueStore;\r\ + \n #:local AmUpdCRLF true;\r\ + \n #:local IfThenElse;\r\ + \n #:set IfThenElse do={:if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1\ + \_] = true) do={:return \$2}; :return \$3}\r\ + \n #/certificate/settings/set builtin-trust-store=fetch;\r\ + \n #/tool/fetch \"\$scriptsUrl/certs/Root-YE.pem\" dst-path=\"root-ye.p\ + em\";\r\ + \n #/certificate/import file-name=\"root-ye.pem\" passphrase=\"\";\r\ + \n # For basic verification we rename the certificate and print it by f\ + ingerprint. Make sure exactly this one certificate (\"Root-YE\") is shown.\ + \r\ + \n #/certificate/set name=\"Root-YE\" [ find where common-name=\"Root Y\ + E\" ];\r\ + \n #/certificate/print proplist=name,fingerprint where fingerprint=\"e1\ + 4ffcad5b0025731006caa43a121a22d8e9700f4fb9cf852f02a708aa5d5666\";\r\ + \n #:log info \"\\nAmScriptsUrl = \$AmScriptsUrl\";\r\ + \n :local Scripts {\r\ + \n \"Amster-GlobalConfig\"\r\ + \n \"Amster-GlobalFunc\";\r\ + \n# \"Amster-SFTP-backup\"\r\ + \n# \"Amster-BkpEmail-and-upd\";\r\ + \n };\r\ + \n# /system/script/set owner=(\$ScriptVal->\"name\") \\\r\ + \n# source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRLF \$S\ + ourceNew ] \$Script;\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n /system/script { run Amster-GlobalConfig; run Amster-GlobalFunc; }\r\ + \n}\r\ + \n:global AmUpdRun;\r\ + \n:set AmUpdRun do={\r\ + \n #:local UpdScript [ :tostr \$1 ];\r\ + \n #:global ParseKeyValueStore;\r\ + \n :global AmScriptsUrl;\r\ + \n :global defOwner;\r\ + \n :local Scripts {\r\ + \n# \"Amster-GlobalConfig\"\r\ + \n# \"Amster-GlobalFunc\"\r\ + \n# \"Amster-GlobalRemove\"\r\ + \n \"Amster-backup-SFTP\"\r\ + \n \"Amster-SFTP-backup\"\r\ + \n \"Amster-BkpEmail-and-upd\"\r\ + \n \"Amster-TG-Bot\"\r\ + \n \"Amster-TG-Notification\";\r\ + \n };\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :put \"updating \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$defOwner source=([ /too\ + l/fetch (\"\$AmScriptsUrl\" . \$Script . \".rsc\") output=user as-value ]-\ + >\"data\");\r\ + \n /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$\ + Script;\r\ + \n };\r\ + \n# /system/script/add name=\$Script owner=\$AmOwner source=([ /tool/fe\ + tch check-certificate=yes-without-crl (\"\$AmScriptsUrl\" . \$Script . \".\ + rsc\") output=user as-value ]->\"data\"); };\r\ + \n}\r\ + \n\r\ + \n\$AmFirstRun;\r\ + \n#\$AmUpdRun;\r\ + \n\r\ + \n#\$setUpdExist;\r\ + \n#:global setUpdExist;\r\ + \n#:global ParseKeyValueStore;\r\ + \n#:set setUpdExist do={\r\ + \n#:do {\r\ + \n#:global ParseKeyValueStore;\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\\r\?\\n#comment=*\" ] do={\r\ + \n# :local ScriptVal [ /system/script/get \$Script ];\r\ + \n# :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"#comment\"\ + ) ];\r\ + \n# :local scriptName (\$ScriptVal->\"name\");\r\ + \n#:log warning (\"\\n\\\$scriptName = \". \$scriptName);\r\ + \n#: log warning (\"\\n\\\$ScriptInfo = \". \$ScriptInfo);\r\ + \n# }\r\ + \n#} on-error={}\r\ + \n#}\r\ + \n#\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run\ + -count;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;\r\ + \n#;(evl / (evl /docommand=;(evl / (evl /foreachcounter=\$Script;do=;(evl \ + / (evl /localname=\$ScriptVal;value=(evl (evl /system/script/getnumber=\$S\ + cript))) (evl /localname=\$ScriptInfo;value=(evl (<%% \$ParseKeyValueStore\ + \_(> \$ParseKeyValueStore);(-> \$ScriptVal comment)))) (evl /localname=\$s\ + criptName) (evl /setname=\$scriptName;value=(-> #\$ScriptVal name)) (evl /\ + log/errormessage=(. \r\ + \n# \$ ScriptInfo = \$ScriptInfo)));in=(evl (evl /system/script/findwhere\ + =\$name;\$owner;\$policy;\$dont-require-permissions;\$last-started;\$run-c\ + ount;\$source;\$invalid;\$comment;\$.id;\$.nextid;\$.dead;\$.about;(~ \$so\ + urce (. ^#!rsc by Vados \r\ + \n# \? \r\ + \n#));5))));on-error=;(evl /)))\r\ + \n" +add dont-require-permissions=no name="Download cAP's Packages" owner=vados \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="# +------------------------------+\r\ + \n# | |\r\ + \n# | Mikrotik RouterOS Scripts |\r\ + \n# | _Download cAP's Packages_ |\r\ + \n# | |\r\ + \n# +------------------------------+\r\ + \n# https://github.com/sebastian13/mikrotik-routeros-scripts\r\ + \n#\r\ + \n\r\ + \n# Set a directory path providing the required space\r\ + \n# Add a microSD card https://wiki.mikrotik.com/wiki/Manual:System/Disks\ + \r\ + \n# or setup a RAM-Disk via '/disk/add type=tmpfs tmpfs-max-size=20M slot=\ + ram'\r\ + \n:local dir \"/tmpfs/capsman-packages\";\r\ + \n\r\ + \n\r\ + \n# Set Package Path if required, set policy to none if using 'upgrade-cap\ + s' script\r\ + \n/interface/wifi/capsman/set package-path=\$dir upgrade-policy=none;\r\ + \n/caps-man/manager/set package-path=\$dir upgrade-policy=none;\r\ + \n#require-same-version;\r\ + \n\r\ + \n:local installed [/system package get value-name=version [find where nam\ + e=\"routeros\"]]\r\ + \n\r\ + \n# Delete old downloads\r\ + \n# /file/remove [ find type=package name~\"capsman*\" ]\r\ + \n\r\ + \n# Starting from RouterOS version 7.13, drivers for older wireless and 60\ + GHz interfaces are\r\ + \n# part of the separate \"wireless\" package. The existing \"wifiwave2\" \ + package has been divided\r\ + \n# into distinct packages: \"wifi-qcom\" and \"wifi-qcom-ac\".\r\ + \n# RouterOS >=7.12 is required to upgrade to 7.13.\r\ + \n# https://forum.mikrotik.com/viewtopic.php\?t=202423\r\ + \n\r\ + \n:foreach architecture in={ \"arm\";\r\ + \n# \"arm64\";\r\ + \n \"x86_64\";\r\ + \n \"mipsbe\"} do={\r\ + \n :foreach package in={ \"routeros\";\r\ + \n# \"wifi-qcom-ac\";\r\ + \n# \"wifi-qcom\";\r\ + \n \"wireless\"} do={ :do {\r\ + \n :put \"\"\r\ + \n :put \"Download \$package \$installed for \$architecture\"\r\ + \n /tool fetch mode=https \\\r\ + \n url=\"https://download.mikrotik.com/routeros/\$installed/\$packa\ + ge-\$installed-\$architecture.npk\" \\\r\ + \n dst-path=\"\$dir/\$package-\$installed-\$architecture.npk\"\r\ + \n } on-error={ :put \"Error downloading the file. On a 404, note t\ + hat the package may not exist for the specified architecture!\" }\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Script for setup routeros scrypt system" \ + dont-require-permissions=no name=AM-setup owner=AM-setup policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-setup\r\ + \n# Script comment: Script for setup routeros scrypt system\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# :local ScriptName [ :jobname ];\r\ + \n# Additional commands:\r\ + \n#\r\ + \n# For scripts:\r\ + \n#:global NewScript \"script_name\"; \r\ + \n#:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n#/system/script/add name=\$NewScript owner=\$NewScript source=([/tool/fe\ + tch check-certificate=yes-without-crl (\$GlobalScriptsUrl . \$ScriptAdd . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n#:global NewScript (a);\r\ + \n#:global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n#\r\ + \n# For run from terminal:\r\ + \n#/system/script/add name=AM-setup owner=AM-Setup source=([/tool/fetch ch\ + eck-certificate=yes-without-crl \"https://ros.vados.ru/AM-setup.rsc\" outp\ + ut=user as-value ]->\"data\");\r\ + \n#\r\ + \n\r\ + \n:global ScriptUpdatesCRLF \"LF\";\r\ + \n#:if (\$ScriptUpdatesCRLF != false) do={\r\ + \n# :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vad\ + os\" ] do={\r\ + \n# if (\$ScriptUpdatesCRLF = true) do={\r\ + \n# /system/script/set source=[ :tocrlf [ get \$Script source ] ] \$S\ + cript;\r\ + \n# } else={\r\ + \n# /system/script/set source=[ :tolf [ get \$Script source ] ] \$Scr\ + ipt;\r\ + \n# }\r\ + \n# }\r\ + \n#}\r\ + \n\r\ + \n# /import verbose=no \$ScriptName\r\ + \n:global SetupScript [ :jobname ];\r\ + \n:global RemoveMe;\r\ + \n:global RunOnce;\r\ + \n:global InitSetup true;\r\ + \n:global tmpfs true;\r\ + \n\r\ + \n{\r\ + \n :local RmMe [:tobool \$1];\r\ + \n\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SetupScript;\r\ + \n :global RemoveMe;\r\ + \n :global InitSetup;\r\ + \n :global tmpfs;\r\ + \n \r\ + \n :local CertCommonName \"Root YE\";\r\ + \n :local CertFileName \"Root-YE.pem\";\r\ + \n :local CertFingerprint \"e14ffcad5b0025731006caa43a121a22d8e9700f4fb9c\ + f852f02a708aa5d5666\";\r\ + \n\r\ + \n :if (\$SetupScript = false) do={\r\ + \n :global SetupScript \"AM-setup\";\r\ + \n }\r\ + \n :if (\$RemoveMe != false) do={\r\ + \n :set RemoveMe true;\r\ + \n }\r\ + \n\r\ + \n :log warning (\"\\n\\\$GlobalScriptsUrl = \" . \$GlobalScriptsUrl);\r\ + \n \r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (!(((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \ + \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \"fetch\" || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CertComm\ + onName ] ] > 0)) do={\r\ + \n :put \"Importing certificate...\";\r\ + \n \r\ + \n /tool/fetch (\$GlobalScriptsUrl . \"certs/\" . \$CertFileName) dst-p\ + ath=\$CertFileName as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint \ + ] ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\r\ + \n };\r\ + \n :delay 1s;\r\ + \n };\r\ + \n\r\ + \n:local MkTmpfs do={\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n :log info (\"The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log info (\"Try to removing directory 'tmpfs'.\");\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/remove tmpfs;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n# \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource/g\ + et total-memory ] / 3);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get tmpfs;\r\ + \n :return true;\r\ + \n } delay=222ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\"Creating disk of type tmpfs failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n}\r\ + \n:if (\$tmpfs = true) do={\r\ + \n :put \"Tmpfs variable is true. Checking for tmpfs/scripts directory...\ + \";\r\ + \n :if ([/file find name=\"tmpfs/scripts\"] != \"\") do={\r\ + \n :log info (\$0 . \"Directory tmpfs/scripts exsist.\");\r\ + \n :return \$true;\r\ + \n } else={\r\ + \n :log warning (\$0 . \"Directory tmpfs/scripts does't exsist.\");\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :log error (\$0 . \"Directory tmpfs is not created!\");\r\ + \n :return false;\r\ + \n } else={\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=/tmpfs/scripts;\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get /tmpfs/scripts;\r\ + \n :return true;\r\ + \n } delay=100ms max=10;\r\ + \n } on-error={ }\r\ + \n } do={\r\ + \n :log warning (\$0 . \"Making directory 'scripts' failed: \" . \$\ + Err);\r\ + \n :return false;\r\ + \n }\r\ + \n# :return true;\r\ + \n# [ /file/get \$FileName ]\r\ + \n }\r\ + \n# :log error (\$0 . \"Directory tmpfs/scripts does not exsist. Remove\ + \_global variable tmpfs!\");\r\ + \n# :global tmpfs (a);\r\ + \n# return false;\r\ + \n }\r\ + \n}\r\ + \n :put \"Renaming AM-GlobalConfig, if exists...\";\r\ + \n :local ConfOldName (\"AM-GlobalConfig-\" . [ /system/clock/get date ] \ + . [ /system/clock/get time ] . \".rsc\");\r\ + \n /system/script/set name=\$ConfOldName [ find where name=\"AM-GlobalCon\ + fig\" ];\r\ + \n :foreach Script in={ \"AM-GlobalConfig\"; \"AM-GlobalFunc\" } do={\r\ + \n :put \"Installing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\r\ + \n /system/script/add name=\$Script owner=\$Script source=([ /tool/fetc\ + h check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \ + \".rsc\") output=user as-value ]->\"data\");\r\ + \n \r\ + \n /system/script run \$Script;\r\ + \n :delay 2s;\r\ + \n };\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] > 0) do={\r\ + \n :put \"Renaming certificate by its common-name...\";\r\ + \n :global CertificateNameByCN;\r\ + \n \$CertificateNameByCN \$CertFingerprint;\r\ + \n };\r\ + \n\r\ + \n :if (\$RemoveMe = true) do={\r\ + \n :put \"Add Scheduler for remove this script...\";\r\ + \n :local OnEvent (\":delay 30s;\\n\" . \"/system/script/remove [ find \ + where name=\\\"\$SetupScript\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \"/system/scheduler/remove [ find where name=\\\ + \"_RemoveSetup\\\" ];\\n\" . \\\r\ + \n \":delay 2s;\\n\" . \":global RemoveMe (a);\\n\");\r\ + \n :local Comment \"_RemoveSetup tmp scheduler for remove setup script.\ + \";\r\ + \n /system/scheduler/add name=\"_RemoveSetup\" comment=\$Comment start-\ + time=startup interval=30s on-event=\$OnEvent;\r\ + \n :log warning (\$0 . \"\\nI've done everything, and now I'm tired..\ + . I'm leaving.\\nThere will be an error below, this is normal.\");\r\ + \n }\r\ + \n :delay 1;\r\ + \n :put \"Loading configuration and functions...\";\r\ + \n :do { \r\ + \n :global ScriptInstallUpdate; \$ScriptInstallUpdate;\r\ + \n :put \"Normal removing temporary global environment variables.\";\ + \r\ + \n :global SetupScript (a);\r\ + \n :global InitSetup (a);\r\ + \n :global RemoveMe (a);\r\ + \n } on-error={\r\ + \n :local ErrorMsg \"Loading configuration and functions error!\";\r\ + \n :log error (\$0 . \$ErrorMsg . :error);\r\ + \n :error \$ErrorMsg;\r\ + \n }\r\ + \n}\r\ + \n" +add comment="Global Config Script" dont-require-permissions=no name=\ + AM-GlobalConfig owner=AM-GlobalConfig policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GlobalConfig\r\ + \n# Script comment: Global Config Script\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# Warning: Dont touch this line!\r\ + \n:global GlobalConfReady false;\r\ + \n#\r\ + \n#\r\ + \n# Global Url For Amster scripts to fetch\r\ + \n# most be defined in AM-Init-Script or AM-setup scripts\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n:global ScriptsUrlSuffix \"\";\r\ + \n:global CheckSumsVerify true;\r\ + \n\r\ + \n:global ScriptUpdatesCRLF true;\r\ + \n:global CommentsInScripts true;\r\ + \n\r\ + \n# Debug output:\r\ + \n:global PrintDebug true; #false;\r\ + \n\r\ + \n# Debug output for specific script:\r\ + \n:set (\$PrintDebugOverride->\"AM-GlobalFunc\") true;\r\ + \n\r\ + \n# Debug logs\r\ + \n# Other actions (disk, email, remote or support) can be used as well.\r\ + \n# I do not recommend using echo - use debug output instead (https://rsc.\ + eworm.de/main/DEBUG.html#debug-output).\r\ + \n#/system/logging/add topics=script,debug action=memory;\r\ + \n\r\ + \n:global MikrotikUpgradeUrl \"https://upgrade.mikrotik.com/routeros\";\r\ + \n:global Domain \"WORKGROUP\";\r\ + \n\r\ + \n:global EmailGeneralTo \"vados@vados.ru\";\r\ + \n#:global EmailGeneralCc \"\";\r\ + \n\r\ + \n# \$ScriptInstallUpdate mod/notification-telegram\r\ + \n:global TelegramTokenId \"8390868324:AAG3_d1hfVR2M6pGAgDK6ZvhOe4J97nyopw\ + \";\r\ + \n:global TelegramChatId \"-1003631309063\"; #\"454403445\";\r\ + \n# Use this to send notifications to a specific topic in group.\r\ + \n#:global TelegramThreadId \"30\";\r\ + \n# Using telegram-chat you have to define trusted chat ids (not group ids\ + !)\r\ + \n# or user names. Groups allow to chat with devices simultaneously.\r\ + \n:global TelegramChatIdsTrusted {\r\ + \n \"454403445\"\r\ + \n \"-1003631309063\"\r\ + \n \"-5124482807\"\r\ + \n \"1087968824\";\r\ + \n};\r\ + \n# \"-5294757340\";\r\ + \n\r\ + \n:global TelegramChatGroups \"(all)\";\r\ + \n#:global TelegramChatGroups \"(all|home|office)\";\r\ + \n\r\ + \n:global NotificationFunctions {\r\ + \n \"email\"\r\ + \n \"telegram\";\r\ + \n};\r\ + \n# Toggle this to disable symbols in notifications.\r\ + \n:global NotificationsWithSymbols true;\r\ + \n:global TerminalColorOutput true;\r\ + \n\r\ + \n:global DetectIpAddrDefault \"https://ipv4.mikrotik.ovh/\";\r\ + \n:global DetectIpAddrFallback \"https://api.ipify.org/\";\r\ + \n\r\ + \n## Update channel. Possible values: stable, long-term, testing, developm\ + ent\r\ + \n:global updateChannel \"stable\";\r\ + \n\r\ + \n:global CertRenewUrl (\$GlobalScriptsUrl . \"certs/\");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass {\r\ + \n \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass {\r\ + \n \"\";\r\ + \n# \"cert1-cn\"=\"v3ry-s3cr3t\";\r\ + \n# \"cert2-cn\"=\"4n0th3r-s3cr3t\";\r\ + \n};\r\ + \n\r\ + \n# Script BackupAndUpdate mode, possible values: backup,\r\ + \n# updateOnce - Update once as \"osnotify\" and back \"osnotify\" mode (i\ + n terminal run :set OSUpdateMode updateOnce; \$OSUpdateMode;). \r\ + \n# osupdate - Update if available and creates backups before/after update\ + \_(ignores `forceBackup`)\r\ + \n# Set `forceBackup` to true to always create backups, even\ + \_without updates\r\ + \n# osnotify - Set `forceBackup` to always create backups on every run\r\ + \n:global DevInfoIncludeIP true;\r\ + \n:global BackupAndUpdateMode \"osnotify\"\r\ + \n\r\ + \n:global forceBackup true;\r\ + \n:global BackupPassword \"Peskar55\";\r\ + \n\r\ + \n# SFTP Backup Variables\r\ + \n:global BackupRandomDelay 0;\r\ + \n:global BackupUploadUrl \"sftp://amster.vados.ru/upload/\";\r\ + \n:global BackupUploadUser \$Identity;\r\ + \n:global BackupUploadPass \"root.mnuc.backuper\";\r\ + \n\r\ + \n:global BackupSendBinary true;\r\ + \n:global BackupSendExport true;\r\ + \n:global BackupSendGlobalConfig true;\r\ + \n:global BackupSendScripts true;\r\ + \n\r\ + \n# Remove local file after uploading if no errors\r\ + \n:global BackupRmLocal true;\r\ + \n\r\ + \n# Local Backups Root Directory \r\ + \n:global BackupLocalRoot \"tmpfs\";\r\ + \n\r\ + \n# Encrypt Backup\r\ + \n:global BackupEncrypt true;\r\ + \n\r\ + \n# Sensitive information in Backups\r\ + \n:global BackupSens true;\r\ + \n\r\ + \n# User Export\r\ + \n:global BackupUser true;\r\ + \n\r\ + \n# License Export (not for CHR, will silently skip)\r\ + \n:global BackupLicense false;\r\ + \n\r\ + \n# SSH Keys\r\ + \n:global BackupSshKeys true;\r\ + \n\r\ + \n# Certificate Export\r\ + \n:global BackupCerts true;\r\ + \n\r\ + \n# Certificate Password\r\ + \n:global BackupCertsPasswd \"\";\r\ + \n\r\ + \n# User-Manager Export\r\ + \n:global BackupUserMan false;\r\ + \n\r\ + \n# The Dude Export\r\ + \n:global BackupDude false;\r\ + \n\r\ + \n# User Files to export, comma-separated string or array of strings\r\ + \n# User Files are not removed on backup\r\ + \n# Any directory paths will be removed (/ -> _) on remote file\r\ + \n# Nonpresent files are silently skipped\r\ + \n:global BackupUserList \"autosupout.rif,autosupout.old.rif\";\r\ + \n\r\ + \n# load functions and any custom scripts\r\ + \n# [ /system/script/find where name=\"global-config-ov\ + erlay\" ], \\\r\ + \n# [ /system/script/find where name~\"^global-config-o\ + verlay\\\\.d/.\" ]\r\ + \n#\r\ + \n#:foreach Script in=([ /system/script/find where name=\"Amster-TGglobalV\ + ars\" ], [ /system/script/find where name=\"Amster-TGglobalFunc\" ]) do={\ + \r\ + \n# :onerror Err {\r\ + \n# /system/script/run \$Script;\r\ + \n# } do={\r\ + \n# :log error (\"Loading configuration from configs and functions\"\ + \_. [ /system/script/get \$Script name ] . \" failed: \" . \$Err);\r\ + \n# }\r\ + \n#}\r\ + \n#:log info \"\\ndevMode = \$devMode\";\r\ + \n#:log info \"\\ndevRunning = \$devRunning\";\r\ + \n:foreach Script in=[ /system/script/find where source~\"^#!rsc by Vados \ + GlobalRUN\\r\?\\n\" ] do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n :log error (\"Run script \" . [ /system/script/get \$Script name \ + ] . \" width marker \\\" GlobalRUN\\\" failed: \" . \$Err);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalConfReady true;\r\ + \n:while (\$GlobalConfReady != true) do={:delay 500ms};\r\ + \n" +add comment="Global functions" dont-require-permissions=no name=AM-GlobalFunc \ + owner=AM-GlobalFunc policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-GglobalFunc\r\ + \n# Script comment: Global functions\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch, scheduler\r\ + \n:local ExitOK false;\r\ + \n:local ScriptName [ :jobname ];\r\ + \n#:global checkRunJob \$SriptName;\r\ + \n#:global fixCRLF;\r\ + \n#:if (\$fixCRLF != false) do={\r\ + \n#:foreach fixScript in=([ /system/script/find where name~\"*\" ]) do={/s\ + ystem/script/set source=[ :tocrlf [ get \$fixScript source ] ] \$fixScript\ + }\r\ + \n#:if (\$fixCRLF != \"LF\") do={ /system/script/set source=[ :tocrlf [ g\ + et \$fixScript source ] ] \$fixScript};};\r\ + \n#}\r\ + \n:global GlobalFuncReady false;\r\ + \n\r\ + \n# Git commit id & info, expected configuration version\r\ + \n:global CommitId \"main/226/e1cd7257\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 09:45:02 01.04.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 138;\r\ + \n\r\ + \n:global SumsDirAndFileName \"tmp/checksums.json\";\r\ + \n\r\ + \n:global Identity [/system/identity/get name];\r\ + \n:global IdentityShort [:pick \$Identity 0 18];\r\ + \n\r\ + \n:global devBoardName [/system/resource/get board-name];\r\ + \n:global devMode [/system/device-mode/get mode];\r\ + \n:global devCurArch [/system/resource/get architecture-name];\r\ + \n:global devCurVersion [/system/resource/get version];\r\ + \n\r\ + \n# Variables defined in AM-GlobalConfig.rsc\r\ + \n:global TerminalColorOutput;\r\ + \n:global CommentsInScripts;\r\ + \n:global DetectIpAddrDefault;\r\ + \n:global DetectIpAddrFallback;\r\ + \n:global updateChannel;\r\ + \n:global Domain;\r\ + \n:global EmailGeneralTo;\r\ + \n:global BackupAndUpdateMode;\r\ + \n\r\ + \n# Single functions, without nested functions.\r\ + \n:global GlobalEnvRemove;\r\ + \n:global MiniDateTimeStamp;\r\ + \n\r\ + \n# Include globals \$PrintDebug and \$PrintDebugOverride\r\ + \n:global LogPrint;\r\ + \n\r\ + \n# DeviceInfo and Updates\r\ + \n:global IsCheckUpdates;\r\ + \n:global WaitCheckUpdates;\r\ + \n:global GetPubIp;\r\ + \n\r\ + \n:global GetArrDeviceInfo;\r\ + \n:global WaitArrDeviceInfo;\r\ + \n\r\ + \n:global devModel;\r\ + \n:global devRunningMode;\r\ + \n\r\ + \n:global devRbRevision;\r\ + \n:global devRbSerialNumber;\r\ + \n:global devRbVerAvail;\r\ + \n\r\ + \n:global runningChannelVersion;\r\ + \n:global runningChannel;\r\ + \n:global runningVersion;\r\ + \n\r\ + \n:global devBuildTime;\r\ + \n#:global ROsVerAvail;\r\ + \n:global PkgUpdStatus;\r\ + \n:global currentUpdateChannel;\r\ + \n\r\ + \n:global ScriptInstallUpdate;\r\ + \n\r\ + \n:global DeviceInfo;\r\ + \n\r\ + \n:global OldMode;\r\ + \n\r\ + \n:global ParseKeyValueStore;\r\ + \n:global RandomDelay;\r\ + \n:global GetRandomNumber;\r\ + \n:global EscapeForRegEx;\r\ + \n:global ExitError;\r\ + \n:global CharacterMultiply;\r\ + \n:global CharacterReplace;\r\ + \n:global CleanFilePath;\r\ + \n:global CleanName;\r\ + \n\r\ + \n:global CommitBrief;\r\ + \n\r\ + \n:global EitherOr;\r\ + \n:global FormatLine;\r\ + \n:global GetRandom20CharAlNum;\r\ + \n:global Grep;\r\ + \n:global IfThenElse;\r\ + \n:global MAX;\r\ + \n:global MIN;\r\ + \n:global HumanReadableNum;\r\ + \n\r\ + \n:global IsFullyConnected;\r\ + \n:global IsDNSResolving;\r\ + \n:global IsTimeSync;\r\ + \n:global IsTimeSyncCached;\r\ + \n:global IsTimeSyncResetNtp;\r\ + \n\r\ + \n:global WaitDNSResolving;\r\ + \n:global WaitFullyConnected;\r\ + \n:global WaitTimeSync;\r\ + \n:global MkDir;\r\ + \n:global RmDir;\r\ + \n:global RmFile;\r\ + \n:global FileGet;\r\ + \n:global Unix2Dos;\r\ + \n:global UrlEncode;\r\ + \n:global WaitForFile;\r\ + \n:global ScriptLock;\r\ + \n:global SendTelegram;\r\ + \n:global NotificationFunctions;\r\ + \n:global SendNotification;\r\ + \n:global SendNotification2;\r\ + \n:global SymbolForNotification;\r\ + \n:global SymbolByUnicodeName;\r\ + \n:global ValidateSyntax;\r\ + \n:global CheckSumsVerify;\r\ + \n:global GlobalConfChanges;\r\ + \n:global GlobalConfMigration;\r\ + \n:global VersionToNum;\r\ + \n:global RequiredRouterOS;\r\ + \n:global FetchLargeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global CertificateAvailable;\r\ + \n:global CertificateDownload;\r\ + \n:global CertificateNameByCN;\r\ + \n:global CharacterMultiply;\r\ + \n\r\ + \n:global InspectVar;\r\ + \n:global InspectVarRet;\r\ + \n:global ParseCustom;\r\ + \n\r\ + \n:set IsCheckUpdates do={\r\ + \n :local isInfo [:tobool \$1];\r\ + \n :global LogPrint;\r\ + \n :global updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n \$LogPrint debug \$0 (\"\\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if (\$CurrentChannel != \$updateChannel) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n \$LogPrint debug \$0 (\"Set updates channel to: \$updateChannel\");\ + \r\ + \n }\r\ + \n\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel (\$Update->\"channel\");\r\ + \n \$LogPrint debug \$0 (\"Update Channel: \" . \$Channel . \".\");\r\ + \n\r\ + \n :local StatusPkg \"undefined\";\r\ + \n \$LogPrint debug \$0 (\"Checking for updates...\");\r\ + \n :retry command={:set \$StatusPkg ([/system/package/update/check-for-up\ + dates without-paging as-value]->\"status\")} \\\r\ + \n delay=300ms max=5 on-error={};\r\ + \n \$LogPrint debug \$0 (\"\\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n \$LogPrint debug \$0 (\"\\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([:len \$arrDeviceInfo] = 0) do={\r\ + \n :global arrDeviceInfo ({});\r\ + \n :local arrDeviceInfo ({\"section\":{\"key\":\"\"; \"value\":\"\";};}\ + );\r\ + \n }\r\ + \n # else={:local arrDeviceInfo ({})}\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [[ :parse \"/\ + system/package/update/get\" ]]} delay=500ms max=5 on-error={:log error (\"\ + Error\")};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannel\"; \$Cu\ + rrentChannel;};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentVersion\"; (\$U\ + pdate->\"installed-version\");};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devCurrentChannelVersion\ + \"; [/system/resource/get version];};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateChannel\"; [\$up\ + dateChannel];};\r\ + \n #:set (\$arrDeviceInfo->\"devUpdates\") {\"devUpdateVersion\"; (\$Up\ + date->\"latest-version\");};\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitArrDeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :while ([ \$GetArrDeviceInfo ] = false) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetArrDeviceInfo do={\r\ + \n :global LogPrint;\r\ + \n\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n\r\ + \n :global arrDeviceInfo [:toarray {\"section\"={\"key\"=\"\"; \"value\"\ + =\"\";} }];\r\ + \n #:do {:set (\$arrDeviceInfo->\"Updates\") [[ :parse \"/system/package\ + /update/get\" ]]} on-error={}\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devRbCurrentFw;\r\ + \n :global devRbUpgradeFw;\r\ + \n\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global ROsVerCurrent;\r\ + \n :global ROsChannelCurrent;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :global ParseCustom;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global devBuildTime;\r\ + \n :global GetPubIp;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Resource [/system/resource/get];\r\ + \n :set devBuildTime (\$Resource->\"build-time\");\r\ + \n :set runningChannelVersion (\$Resource->\"version\");\r\ + \n :set runningChannel [\$ParseCustom \$runningChannelVersion \"(\" \")\ + \" 1];\r\ + \n :set runningVersion [\$ParseCustom \$runningChannelVersion \" \"];\r\ + \n\r\ + \n :do {\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :local RouterBoard;\r\ + \n :do {:set RouterBoard [[ :parse \"/system/routerboard/get\" ]]} on\ + -error={}\r\ + \n :set devModel (\$RouterBoard->\"model\");\r\ + \n :set devRbRevision (\$RouterBoard->\"revision\");\r\ + \n :set devRbSerialNumber (\$RouterBoard->\"serial-number\");\r\ + \n #:set devRbCurrentFw (\$RouterBoard->\"current-firmware\");\r\ + \n #:set devRbUpgradeFw (\$RouterBoard->\"upgrade-firmware\");\r\ + \n :if (\$devCurArch = \"mipsbe\" || \$devCurArch = \"arm\") do={\r\ + \n :global devRunning [ /system/device-mode/get mode ];\r\ + \n } else={\r\ + \n :global devRunning [/system/device-mode/get running];}\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n \r\ + \n :set devRbRevision false;\r\ + \n :set devRbSerialNumber false;\r\ + \n# :set devRbCurrentFw false;\r\ + \n# :set devRbUpgradeFw false;\r\ + \n #:set devCurrentFw \$runningVersion;#:set devUpgradeFw \$ROsVerAvail\ + ;\r\ + \n :set devRunning [/system/device-mode/get running];\r\ + \n }\r\ + \n } on-error={\r\ + \n \$LogPrint error \$0 (\"Error in Function getDevice!\");\r\ + \n :return false;\r\ + \n }\r\ + \n:return true;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global WaitArrDeviceInfo;\r\ + \n # \$WaitDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devCurArch;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global PiblicIpAddress;\r\ + \n\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :local Return;\r\ + \n :local License [/system/license/get];\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n\r\ + \n :set Return ([ \$FormatLine \"Hostname:\" \$Identity ] . \"\\n\" . \\\ + \r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"location\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Location:\" (\$Snmp->\"location\") ] . \"\\n\") \ + ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Snmp->\"contact\") ] > 0) \\\r\ + \n ([ \$FormatLine \"Contact:\" (\$Snmp->\"contact\") ] . \"\\n\") ] \ + . \\\r\ + \n \"Hardware:\\n\" . \\\r\ + \n [ \$FormatLine \" Board:\" . \$devBoardName ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Arch:\" . \$devCurArch ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Model:\" \$devModel ] . \\\r\ + \n [ \$IfThenElse ([ :len \$devRbRevision ] > 0) \\\r\ + \n (\" \" . \$devRbRevision) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len \$devRbSerialNumber ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial:\" . \$devRbSerialNumber ] . \"\\n\"\ + ) ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"nleve\ + l\")) ] . \"\\n\") ] . \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License:\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \"Running Channel\" \$runningChannel ] . \"\\n\" . \\\ + \r\ + \n [ \$FormatLine \" Installed:\" (\$Update->\"installed-version\") \ + ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :typeof (\$Update->\"latest-version\") ] != \"noth\ + ing\" && \\\r\ + \n \$Update->\"installed-version\" != \$Update->\"latest-version\")\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Update->\"latest-version\") ]\ + \_. \"\\n\") ] . \\\r\ + \n [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true && \\\r\ + \n \$RouterBoard->\"current-firmware\" != \$RouterBoard->\"upgrade-\ + firmware\") \\\r\ + \n ([ \$FormatLine \" Firmware\" (\$RouterBoard->\"current-firmwar\ + e\") ] . \"\\n\") ] . \\ \r\ + \n \"RouterOS-Scripts:\\n\" . \\\r\ + \n [ \$FormatLine \" Commit\" [ \$CommitBrief ] ] . \"\\n\" . \\\r\ + \n [ \$FormatLine \" Version\" \$GlobalConfVersion ]);\r\ + \n}\r\ + \n\r\ + \n:if ([ :typeof \$NotificationFunctions ] != \"array\") do={:set Notifica\ + tionFunctions ({})}\r\ + \n:set GetRandom20CharAlNum do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndstr length=[ \$EitherOr [ :tonum \$1 ] 20 ] from=\"ABCDE\ + FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\" ];\r\ + \n}\r\ + \n\r\ + \n:global checkRunJob;\r\ + \n:set checkRunJob do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLock; \r\ + \n :if ([ \$ScriptLock \$Script ] = false) do={:return false}\r\ + \n :foreach Job in=[ /system/script/job/find where script=\$Script ] do={\ + :set Job [ /system/script/job/get \$Job ];\r\ + \n :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={:set Job [ /sy\ + stem/script/job/get [ find where .id=(\$Job->\"parent\") ] ]}\r\ + \n :if ((\$Job->\"type\") = \"login\") do={:return true};}; :return fa\ + lse; \r\ + \n}\r\ + \n\r\ + \n:set InspectVar do={\r\ + \n :global InspectVarRet;\r\ + \n :put [ :tocrlf [ \$InspectVarRet \$1 ] ];\r\ + \n}\r\ + \n\r\ + \n:set CommitBrief do={\r\ + \n :global CommitId;\r\ + \n :global CommitInfo;\r\ + \n :if (\$CommitId = \"unknown\") do={\r\ + \n :return \"unknown\";\r\ + \n }\r\ + \n :return (\$CommitInfo . \"/\" . [ :pick \$CommitId 0 8 ]);\r\ + \n}\r\ + \n\r\ + \n:set InspectVarRet do={\r\ + \n :local Input \$1;\r\ + \n :local Level (0 + [ :tonum \$2 ]);\r\ + \n :global CharacterReplace;\r\ + \n :global IfThenElse;\r\ + \n :global InspectVarRet;\r\ + \n :local IndentReturn do={\r\ + \n :local Prefix [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Level [ :tonum \$3 ];\r\ + \n :global CharacterMultiply;\r\ + \n :return ([ \$CharacterMultiply \" \" (\$Level * 2) ] . \"-\" . \$Pre\ + fix . \"-> \" . \$Value);\r\ + \n }\r\ + \n :local TypeOf [ :typeof \$Input ];\r\ + \n :local Len [ :len \$Input ];\r\ + \n :local Return [ \$IndentReturn \"type\" \$TypeOf \$Level ];\r\ + \n :if (\$TypeOf = \"array\") do={\r\ + \n :foreach Key,Value in=\$Input do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"key\" \$Key (\$Level + 1) ] . \"\\n\" . \\\r\ + \n [ \$InspectVarRet \$Value (\$Level + 2) ]);\r\ + \n }\r\ + \n } else={\r\ + \n :if (\$TypeOf = \"str\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"len\" \$Len \$Level ]);\r\ + \n :if ([ :typeof [ :find \$Input (\"\\r\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\r\") \"\" ];\r\ + \n }\r\ + \n :if ([ :typeof [ :find \$Input (\"\\n\") ] ] = \"num\") do={\r\ + \n :set Input [ \$CharacterReplace \$Input (\"\\n\") \" \" ];\r\ + \n }\r\ + \n }\r\ + \n :if (\$TypeOf != \"nothing\") do={\r\ + \n :set \$Return (\$Return . \"\\n\" . \\\r\ + \n [ \$IndentReturn \"value\" [ \$IfThenElse ([ :len \$Input ] > 80)\ + \_\\\r\ + \n ([ :pick \$Input 0 77 ] . \"...\") \$Input ] \$Level ]);\r\ + \n }\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n# !!! The function is not ready !!!\r\ + \n:global FetchHttpInfo do={\r\ + \n :local Mac [ :tostr \$1 ];\r\ + \n :global CertificateAvailable;\r\ + \n :global IsMacLocallyAdministered;\r\ + \n :global LogPrint;\r\ + \n :local Url \"https://api.macvendors.com/\";\r\ + \n :if ([ \$IsMacLocallyAdministered \$Mac ] = true) do={:return \"locall\ + y administered\";}\r\ + \n :do {\r\ + \n :if ([ \$CertificateAvailable \"GTS Root R4\" \"fetch\" ] = false) d\ + o={\r\ + \n \$LogPrint warning \$0 (\"Downloading required certificate failed.\ + \");\r\ + \n :error false;\r\ + \n }\r\ + \n :local Vendor ([ /tool/fetch \r\ + \n (\$Url . [ :pick \$Mac 0 8 ]) output=user as-value ]->\"data\");\r\ + \n :return \$Vendor;\r\ + \n } on-error={\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=yes-without-crl (\$Url) output=none \ + as-value;\r\ + \n \$LogPrint debug \$0 (\"The mac vendor is not known in database.\"\ + );\r\ + \n } do={ \$LogPrint warning \$0 (\"Failed getting mac vendor: \" . \$E\ + rr); }\r\ + \n :return \"unknown vendor\";\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n :global LogPrint;\r\ + \n \r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n\r\ + \n# :retry command={abc} delay=1 max=2 on-error={:put \"got error\"} \r\ + \n :do {\r\ + \n \$LogPrint debug \$0 (\"Trying to detect public IP using default s\ + ervice: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=50ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fail\ + ed to detect public IP using default service: \" . \$Url . \".\")}\r\ + \n #:error \"Failed to detect public IP using default service: \$Url\ + .\"};\r\ + \n } on-error={\r\ + \n \$LogPrint error \$0 (\"Failed to detect public IP using default s\ + ervice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n \$LogPrint debug \$0 (\"Trying to detect public IP using fallback \ + service: \" . \$Url . \"...\");\r\ + \n :retry command={:set PubIpAddr ([ /tool/fetch http-method=\"get\"\ + \_check-certificate=yes-without-crl \$Url output=user as-value ]->\"data\"\ + )} \\\r\ + \n delay=200ms max=5 on-error={\$LogPrint error [ :jobname ] (\"Fai\ + led to detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :if (\$PubIpAddr = false) do={\r\ + \n :set PubIpAddr \"not-detected\";\r\ + \n } else={\r\ + \n :set PubIpAddr [ :pick \$PubIpAddr 0 15];\r\ + \n }\r\ + \n :return \$PubIpAddr;\r\ + \n}\r\ + \n\r\ + \n:set FormatLine do={\r\ + \n :local Key [ :tostr \$1 ];\r\ + \n :local Value [ :tostr \$2 ];\r\ + \n :local Indent [ :tonum \$3 ];\r\ + \n :local Spaces;\r\ + \n :local Return \"\";\r\ + \n :global CharacterMultiply;\r\ + \n :global EitherOr;\r\ + \n :set Indent [ \$EitherOr \$Indent 16 ];\r\ + \n :local Spaces [ \$CharacterMultiply \" \" \$Indent ];\r\ + \n :if ([ :len \$Key ] > 0) do={ :set Return (\$Key . \":\")}\r\ + \n :if ([ :len \$Key ] > (\$Indent - 2)) do={:set Return (\$Return . \"\\\ + n\" . [ :pick \$Spaces 0 \$Indent ] . \$Value);\r\ + \n } else={:set Return (\$Return . [ :pick \$Spaces 0 (\$Indent - [ :len \ + \$Return ]) ] . \$Value)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ParseCustom do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Start [:find [ \$Str ] [:tostr \$2]];\r\ + \n :local End [ :tostr \$3 ];\r\ + \n :local Num [ :tonum \$4 ];\r\ + \n :local Return;\r\ + \n :if ([:len \$Num] = 0) do={:set Num \"0\"}\r\ + \n :local rest [:pick \$Str (\$Start+\$Num) [:len \$Str]]; \r\ + \n :if ([:len \$End ] = 0) do={:set Return [:pick \$Str \$Num \$Start]} e\ + lse={\r\ + \n :set End [:find \$rest \$End];\r\ + \n :set Return [:pick \$rest 0 \$End];\r\ + \n }\r\ + \n:return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set LogPrint do={\r\ + \n :local Severity [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Message [ :tostr \$3 ];\r\ + \n :global PrintDebug;\r\ + \n :global PrintDebugOverride;\r\ + \n :global EitherOr;\r\ + \n :local Debug [ \$EitherOr (\$PrintDebugOverride->\$Name) \$PrintDebug \ + ];\r\ + \n :local PrintSeverity do={\r\ + \n :global TerminalColorOutput;\r\ + \n :if (\$TerminalColorOutput != true) do={:return \$1}\r\ + \n :local Color { debug=96; info=97; warning=93; error=91 };\r\ + \n :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\r\ + \n}\r\ + \n :local Log ([ \$EitherOr \$Name \"\" ] . \": \" . \$Message);\ + \r\ + \n :if (\$Severity ~ (\"^(custom|debug|error|info)\\\$\")) do={\r\ + \n :if (\$Severity = \"debug\") do={:log debug \$Log}\r\ + \n :if (\$Severity = \"error\") do={:log error \$Log}\r\ + \n :if (\$Severity = \"info\" ) do={:log info \$Log}\r\ + \n } else={:log warning \$Log; :set Severity \"warning\"}\r\ + \n :if (\$Severity != \"debug\" || \$Debug = true) do={:put ([ \$PrintSev\ + erity \$Severity ] . \": \" . \$Message)}\r\ + \n}\r\ + \n\r\ + \n:set CertificateAvailable do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :local UseFor [ :tostr \$2 ];\r\ + \n :global CertificateDownload;\r\ + \n :global EitherOr;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :set UseFor [ \$EitherOr \$UseFor \"undefined\" ];\r\ + \n :if ([ /system/resource/get free-hdd-space ] < 8388608 && \\\r\ + \n [ /certificate/settings/get crl-download ] = true && \\\r\ + \n [ /certificate/settings/get crl-store ] = \"system\") do={\r\ + \n \$LogPrint warning \$0 (\"This system has low free flash space but \ + \" . \\\r\ + \n \"is configured to download certificate CRLs to system!\");\r\ + \n }\r\ + \n :if ([ :len \$CommonName ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No CommonName given!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if (((\$CertSettings->\"builtin-trust-anchors\") = \"trusted\" || \\\ + \r\ + \n (\$CertSettings->\"builtin-trust-store\") ~ \$UseFor || \\\r\ + \n (\$CertSettings->\"builtin-trust-store\") = \"all\") && \\\r\ + \n [ :len [ /certificate/builtin/find where common-name=\$CommonName\ + \_] ] > 0) do={\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n \$LogPrint info \$0 (\"Certificate with CommonName '\" . \$CommonNam\ + e . \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={:return fal\ + se}\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n \$LogPrint info \$0 (\"There are \" . \$CertCount . \" Certificates \ + with CommonName '\" . \$CommonName . \"'. Should be ok.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :local CertVal [ /certificate/get [ find where common-name=\$CommonNam\ + e ] ];\r\ + \n :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\ + ertVal->\"skid\")) do={\r\ + \n :if ([ :len [ /certificate/find where skid=(\$CertVal->\"akid\") ] ]\ + \_= 0) do={\r\ + \n :local IssuerCN ([ \$ParseKeyValueStore (\$CertVal->\"issuer\") ]-\ + >\"CN\");\r\ + \n \$LogPrint info \$0 (\"Certificate chain for '\" . \$CommonName . \ + \"' is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={:return fal\ + se}\r\ + \n }\r\ + \n :set CertVal [ /certificate/get [ find where skid=(\$CertVal->\"akid\ + \") ] ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateDownload do={\r\ + \n :local CommonName [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global LogPrint;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n \r\ + \n \$LogPrint info \$0 (\"Downloading and importing certificate with Comm\ + onName '\" . \$CommonName . \"'.\");\r\ + \n \r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl http-header-field=({ [\ + \_\$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$GlobalScriptsUrl . \"certs/\" . \$FileName . \$GlobalScriptsUrl\ + Suffix) dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n \$LogPrint warning \$0 (\"Failed downloading certificate with Common\ + Name '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"Required certificate is not available.\"\ + );\r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl http-header-field=({\ + \_[ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n \"https://mkcert.org/generate/\" http-data=[ :serialize to=json \ + ({ \$CommonName }) ] \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n :if ([ /file/get \$FileName size ] = 0) do={\r\ + \n \$RmFile \$FileName;\r\ + \n :error false;\r\ + \n }\r\ + \n } on-error={\r\ + \n \$LogPrint warning \$0 (\"Failed downloading certificate with Comm\ + onName '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n \$LogPrint warning \$0 (\"Certificate with CommonName '\" . \$Common\ + Name . \"' still unavailable!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :foreach Cert in=[ /certificate/find where name~(\"^\" . \$FileName . \ + \"_[0-9]+\\\$\") ] do={\r\ + \n \$CertificateNameByCN [ /certificate/get \$Cert common-name ];\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CertificateNameByCN do={\r\ + \n :local Match [ :tostr \$1 ];\r\ + \n :global CleanName;\r\ + \n :global LogPrint;\r\ + \n :local Cert ([ /certificate/find where (common-name=\$Match or fingerp\ + rint=\$Match or name=\$Match) ]->0);\r\ + \n :if ([ :len \$Cert ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No matching certificate found.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local CommonName [ /certificate/get \$Cert common-name ];\r\ + \n /certificate/set \$Cert name=[ \$CleanName \$CommonName ];\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global IfThenElse;\r\ + \n :local Resource [ /system/resource/get ];\r\ + \n :return (\"User-Agent: Mikrotik/\" . \$Resource->\"version\" . \" \" .\ + \_\$Resource->\"architecture-name\" . \\\r\ + \n \" \" . \$Caller . \"/Fetch (https://amster.vados.ru/; main/3419/3ee\ + 19780)\");\r\ + \n}\r\ + \n\r\ + \n:set Grep do={\r\ + \n :local Input ([ :tostr \$1 ] . \"\\n\");\r\ + \n :local Pattern [ :tostr \$2 ];\r\ + \n :if ([ :typeof [ :find \$Input \$Pattern ] ] = \"nil\") do={:return []\ + }\r\ + \n :do {\r\ + \n :local Line [ :pick \$Input 0 [ :find \$Input \"\\n\" ] ];\r\ + \n :if ([ :typeof [ :find \$Line \$Pattern ] ] = \"num\") do={:return \ + \$Line}\r\ + \n :set Input [ :pick \$Input ([ :find \$Input \"\\n\" ] + 1) [ :len \$\ + Input ] ];\r\ + \n } while=([ :len \$Input ] > 0);\r\ + \n :return [];\r\ + \n}\r\ + \n\r\ + \n:set HumanReadableNum do={\r\ + \n :local Input [ :tonum \$1 ];\r\ + \n :local Base [ :tonum \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global IfThenElse;\r\ + \n :local Prefix \"kMGTPE\";\r\ + \n :local Pow 1;\r\ + \n :set Base [ \$EitherOr \$Base 1024 ];\r\ + \n :local Bin [ \$IfThenElse (\$Base = 1024) \"i\" \"\" ];\r\ + \n :if (\$Input < \$Base) do={:return \$Input}\r\ + \n :for I from=0 to=[ :len \$Prefix ] do={\r\ + \n :set Pow (\$Pow * \$Base);\r\ + \n :if (\$Input / \$Base < \$Pow) do={\r\ + \n :set Prefix [ :pick \$Prefix \$I ];\r\ + \n :local Tmp1 (\$Input * 100 / \$Pow);\r\ + \n :local Tmp2 (\$Tmp1 / 100);\r\ + \n :if (\$Tmp2 >= 100) do={:return (\$Tmp2 . \$Prefix . \$Bin)}\r\ + \n :return (\$Tmp2 . \".\" . \\\r\ + \n [ :pick \$Tmp1 [ :len \$Tmp2 ] ([ :len \$Tmp1 ] - [ :len \$Tmp\ + 2 ] + 1) ] . \\\r\ + \n \$Prefix . \$Bin);\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set CleanName do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Return \"\";\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :typeof [ find \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr\ + stuvwxyz0123456789\" \$Char ] ] = \"nil\") do={\r\ + \n :do {:if ([ :len \$Return ] = 0) do={:error true};\r\ + \n :if ([ :pick \$Return ([ :len \$Return ] - 1) ] = \"-\") do={:er\ + ror true}; :set Char \"-\"} on-error={:set Char \"\"}; \r\ + \n };\r\ + \n :set Return (\$Return . \$Char)};\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set GetRandomNumber do={\r\ + \n :global EitherOr;\r\ + \n :return [ :rndnum from=0 to=[ \$EitherOr [ :tonum \$1 ] 4294967295 ] ]\ + \r\ + \n}\r\ + \n\r\ + \n:set RandomDelay do={\r\ + \n :local Time [ :tonum \$1 ];\r\ + \n :local Unit [ :tostr \$2 ];\r\ + \n :global EitherOr;\r\ + \n :global GetRandomNumber;\r\ + \n :global MAX;\r\ + \n :if (\$Time = 0) do={:return false}\r\ + \n :delay ([ \$MAX 10 [ \$GetRandomNumber ([ :tonsec [ :totime (\$Time . \ + [ \$EitherOr \$Unit \"s\" ]) ] ] / 1000000) ] ] . \"ms\");\r\ + \n}\r\ + \n\r\ + \n:set EscapeForRegEx do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"^.[]\\\$()|*+\?{}\\\\\");\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :if ([ :find \$Chars \$Char ]) do={:set Char (\"\\\\\" . \$Char)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ExitError do={\r\ + \n :local ExitOK [ :tostr \$1 ];\r\ + \n :local Name [ :tostr \$2 ];\r\ + \n :local Error [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :if (\$ExitOK = \"false\") do={\r\ + \n \$LogPrint error \$Name ([ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\\\ + \$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with er\ + ror\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \ + \$Error) \".\" ]);\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n /system/clock;\r\ + \n :local vdate [get date];\r\ + \n :local vtime [get time];\r\ + \n :local vdoff [:toarray \"0,4,5,7,8,10\"];\r\ + \n :local MM [:pick \$vdate (\$vdoff->2) (\$vdoff->3)];\r\ + \n :local M [:tonum \$MM];\r\ + \n :if (\$vdate ~ \".../../....\") do={\r\ + \n :set vdoff [:toarray \"7,11,1,3,4,6\"];\r\ + \n :set M ([:find \"xxanebarprayunulugepctovecANEBARPRAYUNULUGE\ + PCTOVEC\" [:pick \$vdate (\$vdoff->2) (\$vdoff->3)] -1] / 2);\r\ + \n :if (\$M>12) do={:set M (\$M - 12)}\r\ + \n :set MM [:pick (100 + \$M) 1 3];\r\ + \n }\r\ + \n :local yyyy [:pick \$vdate (\$vdoff->0) (\$vdoff->1)];\r\ + \n :local dd [:pick \$vdate (\$vdoff->4) (\$vdoff->5)];\r\ + \n :local HH [:pick \$vtime 0 2];\r\ + \n :local mm [:pick \$vtime 3 5];\r\ + \n :local ss [:pick \$vtime 6 8];\r\ + \n :return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\r\ + \n}\r\ + \n\r\ + \n:set WaitForFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local WaitTime [ :totime \$2 ];\r\ + \n :global CleanFilePath;\r\ + \n :global EitherOr;\r\ + \n :global MAX;\r\ + \n :set FileName [ \$CleanFilePath \$FileName ];\r\ + \n :local Delay ([ \$MAX [ \$EitherOr \$WaitTime 2s ] 100ms ] / 9);\r\ + \n :do {\r\ + \n :retry {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } delay=\$Delay max=10;\r\ + \n } on-error={ }\r\ + \n :while ([ :len [ /file/find where name=\$FileName ] ] > 0) do={\r\ + \n :do {\r\ + \n /file/get \$FileName;\r\ + \n :return true;\r\ + \n } on-error={ }\r\ + \n :delay \$Delay;\r\ + \n :set Delay (\$Delay * 3 / 2);\r\ + \n }\r\ + \n :return false;\r\ + \n}\r\ + \n\r\ + \n:set FileGet do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global WaitForFile;\r\ + \n :if ([ \$WaitForFile \$FileName 0s ] = false) do={:return false}\r\ + \n :local FileVal false;\r\ + \n :do {:set FileVal [ /file/get \$FileName ];\r\ + \n } on-error={ }\r\ + \n :return \$FileVal;\r\ + \n}\r\ + \n\r\ + \n:set RmDir do={\r\ + \n :local DirName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :global LogPrint;\r\ + \n \$LogPrint debug \$0 (\"Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\$LogPrint debug \$0 (\"... which does not \ + exist.\"); :return true};\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\$LogPrint error \$0 (\"\ + Directory '\" . \$DirName . \"' is not a directory.\"); :return false};\r\ + \n :onerror Err {/file/remove \$DirName} do={\$LogPrint error \$0 (\"Remo\ + ving directory '\" . \$DirName . \"' failed: \" . \$Err); :return false};\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set RmFile do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :global FileGet;\r\ + \n :global LogPrint;\r\ + \n \$LogPrint debug \$0 (\"Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\$LogPrint debug \$0 (\"... which does not\ + \_exist.\"); :return true}\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n \$LogPrint error \$0 (\"File '\" . \$FileName . \"' is not a file.\"\ + ); :return false}\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\$LogPrint error \$0 (\"Removing file '\" . \$FileName . \"' fai\ + led: \" . \$Err); :return false}\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MkDir do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CleanFilePath;\r\ + \n :global FileGet;\r\ + \n :global RmDir;\r\ + \n :global WaitForFile;\r\ + \n :global LogPrint;\r\ + \n :local MkTmpfs do={\r\ + \n :global WaitForFile;\r\ + \n :local TmpFs [ /disk/find where slot=tmpfs type=tmpfs ];\r\ + \n :if ([ :len \$TmpFs ] = 1) do={\r\ + \n :if ([ /disk/get \$TmpFs disabled ] = true) do={\r\ + \n \$LogPrint info \$0 (\"The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n \$LogPrint info \$0 (\"Creating disk of type tmpfs.\");\r\ + \n \$RmDir \"tmpfs\";\r\ + \n :onerror Err {\r\ + \n /disk/add slot=tmpfs type=tmpfs tmpfs-max-size=([ /system/resource\ + /get total-memory ] / 3);\r\ + \n \$WaitForFile \"tmpfs\";\r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Creating disk of type tmpfs failed: \" .\ + \_\$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :set Path [ \$CleanFilePath \$Path ];\r\ + \n :if (\$Path = \"\") do={\r\ + \n :return true;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n \$LogPrint debug \$0 (\"... which already exists.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ :pick \$Path 0 5 ] = \"tmpfs\") do={\r\ + \n :if ([ \$MkTmpfs ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/add type=\"directory\" name=\$Path;\r\ + \n \$WaitForFile \$Path;\r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Making directory '\" . \$Path . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n:set MAX do={:if (\$1 > \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n:set MIN do={:if (\$1 < \$2) do={:return \$1}\r\ + \n :return \$2;\r\ + \n}\r\ + \n\r\ + \n:set CharacterMultiply do={\r\ + \n :local Str [ :tostr \$1 ];\r\ + \n :local Num [ :tonum \$2 ];\r\ + \n :if (\$Num = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :for I from=1 to=\$Num do={:set Return (\$Return . \$Str)}\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set CharacterReplace do={\r\ + \n :local String [ :tostr \$1 ];\r\ + \n :local ReplaceFrom [ :tostr \$2 ];\r\ + \n :local ReplaceWith [ :tostr \$3 ];\r\ + \n :local Return \"\";\r\ + \n :if (\$ReplaceFrom = \"\") do={:return \$String}\r\ + \n :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\ + \r\ + \n :local Pos [ :find \$String \$ReplaceFrom ];\r\ + \n :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\ + \r\ + \n :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\ + \_\$String ] ];\r\ + \n }\r\ + \n :return (\$Return . \$String);\r\ + \n}\r\ + \n\r\ + \n:set CleanFilePath do={\r\ + \n :local Path [ :tostr \$1 ];\r\ + \n :global CharacterReplace;\r\ + \n :while (\$Path ~ \"//\") do={:set \$Path [ \$CharacterReplace \$Path \ + \"//\" \"/\" ]};\r\ + \n :if ([ :pick \$Path 0 ] = \"/\") do={:set Path [ :pick \$Path 1 [ :len\ + \_\$Path ] ]};\r\ + \n :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={:set Path [ :\ + pick \$Path 0 ([ :len \$Path ] - 1) ]};\r\ + \n :return \$Path;\r\ + \n}\r\ + \n\r\ + \n:set IfThenElse do={\r\ + \n :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={:return \ + \$2};\r\ + \n :return \$3;\r\ + \n}\r\ + \n\r\ + \n:set EitherOr do={\r\ + \n :global IfThenElse;\r\ + \n :if ([ :typeof \$1 ] = \"num\") do={:return [ \$IfThenElse (\$1 != 0) \ + \$1 \$2 ]}\r\ + \n :if ([ :typeof \$1 ] = \"time\") do={:return [ \$IfThenElse (\$1 > 0s)\ + \_\$1 \$2 ]}\r\ + \n# this works for boolean values, literal ones with parentheses\r\ + \n :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\r\ + \n}\r\ + \n\r\ + \n:set ParseKeyValueStore do={\r\ + \n :local Source \$1;\r\ + \n :if ([ :pick \$Source 0 1 ] = \"{\") do={\r\ + \n :do {\r\ + \n :return [ :deserialize from=json \$Source ];\r\ + \n } on-error={ }\r\ + \n } \r\ + \n :if ([ :typeof \$Source ] != \"array\") do={:set Source [ :tostr \$1 ]\ + }\r\ + \n :local Result ({});\r\ + \n :foreach KeyValue in=[ :toarray \$Source ] do={\r\ + \n :if ([ :find \$KeyValue \"=\" ]) do={\r\ + \n :local Key [ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ];\r\ + \n :local Value [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [\ + \_:len \$KeyValue ] ];\r\ + \n :if (\$Value=\"true\") do={:set Value true}\r\ + \n :if (\$Value=\"false\") do={:set Value false}\r\ + \n :set (\$Result->\$Key) \$Value;\r\ + \n } else={:set (\$Result->\$KeyValue) true}\r\ + \n }\r\ + \n :return \$Result;\r\ + \n}\r\ + \n:set RequiredRouterOS do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :local Required [ :tostr \$2 ];\r\ + \n :local Warn [ :tostr \$3 ];\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n \$LogPrint error \$0 (\"No valid RouterOS version: \" . \$Required);\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ /system/packag\ + e/update/get installed-version ] ]) do={\r\ + \n :if (\$Warn = \"true\") do={\r\ + \n \$LogPrint warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \$Call\ + er 0 ] = (\"\\\$\")) \"function\" \"script\" ] . \\\r\ + \n \" '\" . \$Caller . \"' (at least specific functionality) requir\ + es RouterOS \" . \$Required . \". Please update!\");\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n:set VersionToNum do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :local Multi 0x1000000;\r\ + \n :local Return 0;\r\ + \n :global CharacterReplace;\r\ + \n :set Input [ \$CharacterReplace \$Input \".\" \",\" ];\r\ + \n :foreach I in={ \"zero\"; \"alpha\"; \"beta\"; \"rc\" } do={\r\ + \n :set Input [ \$CharacterReplace \$Input \$I (\",\" . \$I . \",\") ];\ + \r\ + \n }\r\ + \n :foreach Value in=([ :toarray \$Input ], 0) do={\r\ + \n :local Num [ :tonum \$Value ];\r\ + \n :if (\$Multi = 0x100) do={\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={\r\ + \n :set Return (\$Return + 0xff00);\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n } else={\r\ + \n :if (\$Value = \"zero\") do={ }\r\ + \n :if (\$Value = \"alpha\") do={ :set Return (\$Return + 0x3f00); \ + }\r\ + \n :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x5f00); }\ + \r\ + \n :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\r\ + \n }\r\ + \n }\r\ + \n :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\ + lue * \$Multi)); }\r\ + \n :set Multi (\$Multi / 0x100);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ScriptLock do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local WaitMax [ :totime \$2 ];\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ScriptLockOrder;\r\ + \n :if ([ :typeof \$ScriptLockOrder ] = \"nothing\") do={\r\ + \n :set ScriptLockOrder ({});\r\ + \n }\r\ + \n :if ([ :typeof (\$ScriptLockOrder->\$Script) ] = \"nothing\") do={\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :local JobCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :return [ :len [ /system/script/job/find where script=\$Script ] ];\ + \r\ + \n }\r\ + \n :local TicketCount do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :local Count 0;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:set Count (\$Count \ + + 1)}\r\ + \n }\r\ + \n :return \$Count;\r\ + \n }\r\ + \n :local IsFirstTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Check [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if (\$Ticket = \$Check) do={:return true}\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\" && \$Ticket != \$Check) d\ + o={:return false}\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :local AddTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Add [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :while (true) do={\r\ + \n :local Pos [ :len (\$ScriptLockOrder->\$Script) ];\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Pos) \$Add;\r\ + \n :delay 10ms;\r\ + \n :if ((\$ScriptLockOrder->\$Script->\$Pos) = \$Add) do={:return tru\ + e}\r\ + \n }\r\ + \n }\r\ + \n :local RemoveTicket do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :local Remove [ :tostr \$2 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Id,Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :while ((\$ScriptLockOrder->\$Script->\$Id) = \$Remove) do={\r\ + \n :set (\$ScriptLockOrder->\$Script->\$Id);\r\ + \n :delay 10ms;\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n :local CleanupTickets do={\r\ + \n :local Script [ :tostr \$1 ];\r\ + \n :global ScriptLockOrder;\r\ + \n :foreach Ticket in=(\$ScriptLockOrder->\$Script) do={\r\ + \n :if ([ :typeof \$Ticket ] != \"nothing\") do={:return false}\r\ + \n }\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n }\r\ + \n :if ([ :typeof \$WaitMax ] = \"nil\" ) do={:set WaitMax 0s}\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"A script named '\" . \$Script . \"' does not\ + \_exist!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$JobCount \$Script ] = 0) do={\r\ + \n \$LogPrint error \$0 (\"No script '\" . \$Script . \"' is running!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$TicketCount \$Script ] >= [ \$JobCount \$Script ]) do={\r\ + \n \$LogPrint error \$0 (\"More tickets than running scripts '\" . \$Sc\ + ript . \"', resetting!\");\r\ + \n :set (\$ScriptLockOrder->\$Script) ({});\r\ + \n /system/script/job/remove [ find where script=\$Script ];\r\ + \n }\r\ + \n :local MyTicket [ \$GetRandom20CharAlNum 6 ];\r\ + \n \$AddTicket \$Script \$MyTicket;\r\ + \n :local WaitInterval (\$WaitMax / 20);\r\ + \n :local WaitTime \$WaitMax;\r\ + \n :while (\$WaitTime > 0 && \\\r\ + \n ([ \$IsFirstTicket \$Script \$MyTicket ] = false || \\\r\ + \n [ \$TicketCount \$Script ] < [ \$JobCount \$Script ])) do={\r\ + \n :set WaitTime (\$WaitTime - \$WaitInterval);\r\ + \n :delay \$WaitInterval;\r\ + \n }\r\ + \n :if ([ \$IsFirstTicket \$Script \$MyTicket ] = true && \\\r\ + \n [ \$TicketCount \$Script ] = [ \$JobCount \$Script ]) do={\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$CleanupTickets \$Script;\r\ + \n :return true;\r\ + \n }\r\ + \n \$RemoveTicket \$Script \$MyTicket;\r\ + \n \$LogPrint debug \$0 (\"Script '\" . \$Script . \"' started more than \ + once\" . \\\r\ + \n [ \$IfThenElse (\$WaitTime < \$WaitMax) \" and timed out waiting for\ + \_lock\" \"\" ] . \"...\");\r\ + \n :return false;\r\ + \n}\r\ + \n:set SendNotification do={ :onerror Err {\r\ + \n :global SendNotification2;\r\ + \n \$SendNotification2 ({ origin=\$0; subject=\$1; message=\$2; link=\$3;\ + \_silent=\$4 });\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n:set SendNotification2 do={\r\ + \n :local Notification \$1;\r\ + \n :global NotificationFunctions;\r\ + \n :foreach FunctionName,Discard in=\$NotificationFunctions do={\r\ + \n (\$NotificationFunctions->\$FunctionName) (\"\\\$NotificationFunctio\ + ns->\\\"\" . \$FunctionName . \"\\\"\") \$Notification;\r\ + \n }\r\ + \n}\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\r\ + \n :global LogPrint;\r\ + \n :global SymbolsExtra;\r\ + \n :local Symbols ({\r\ + \n \"abacus\"=\"\\F0\\9F\\A7\\AE\";\r\ + \n \"alarm-clock\"=\"\\E2\\8F\\B0\";\r\ + \n \"arrow-down\"=\"\\E2\\AC\\87\";\r\ + \n \"arrow-up\"=\"\\E2\\AC\\86\";\r\ + \n \"calendar\"=\"\\F0\\9F\\93\\85\";\r\ + \n \"card-file-box\"=\"\\F0\\9F\\97\\83\";\r\ + \n \"chart-decreasing\"=\"\\F0\\9F\\93\\89\";\r\ + \n \"chart-increasing\"=\"\\F0\\9F\\93\\88\";\r\ + \n \"cloud\"=\"\\E2\\98\\81\";\r\ + \n \"cross-mark\"=\"\\E2\\9D\\8C\";\r\ + \n \"earth\"=\"\\F0\\9F\\8C\\8D\";\r\ + \n \"fire\"=\"\\F0\\9F\\94\\A5\";\r\ + \n \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\r\ + \n \"gear\"=\"\\E2\\9A\\99\";\r\ + \n \"heart\"=\"\\E2\\99\\A5\";\r\ + \n \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\r\ + \n \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\r\ + \n \"information\"=\"\\E2\\84\\B9\";\r\ + \n \"large-orange-circle\"=\"\\F0\\9F\\9F\\A0\";\r\ + \n \"large-red-circle\"=\"\\F0\\9F\\94\\B4\";\r\ + \n \"link\"=\"\\F0\\9F\\94\\97\";\r\ + \n \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\r\ + \n \"memo\"=\"\\F0\\9F\\93\\9D\";\r\ + \n \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\r\ + \n \"pushpin\"=\"\\F0\\9F\\93\\8C\";\r\ + \n \"scissors\"=\"\\E2\\9C\\82\";\r\ + \n \"scroll\"=\"\\F0\\9F\\93\\9C\";\r\ + \n \"smiley-partying-face\"=\"\\F0\\9F\\A5\\B3\";\r\ + \n \"smiley-smiling-face\"=\"\\E2\\98\\BA\";\r\ + \n \"smiley-winking-face-with-tongue\"=\"\\F0\\9F\\98\\9C\";\r\ + \n \"sparkles\"=\"\\E2\\9C\\A8\";\r\ + \n \"speech-balloon\"=\"\\F0\\9F\\92\\AC\";\r\ + \n \"star\"=\"\\E2\\AD\\90\";\r\ + \n \"warning-sign\"=\"\\E2\\9A\\A0\";\r\ + \n \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\r\ + \n }, \$SymbolsExtra);\r\ + \n :local Magic [ :pick [ /system/clock/get date ] 4 10 ];\r\ + \n :local Special {\r\ + \n \"information-04-01\"=\"\\F0\\9F\\9A\\BB\";\r\ + \n \"large-orange-circle-04-01\"=\"\\F0\\9F\\8D\\8A\";\r\ + \n \"large-orange-circle-10-31\"=\"\\F0\\9F\\8E\\83\";\r\ + \n \"large-red-circle-04-01\"=\"\\F0\\9F\\8D\\92\" };\r\ + \n :if ([ :len (\$Symbols->\$Name) ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"No symbol available for name '\" . \$Name \ + . \"'!\");\r\ + \n :return \"\";\r\ + \n }\r\ + \n :return ([ \$EitherOr (\$Special->(\$Name . \$Magic)) (\$Symbols->\$Na\ + me) ] . \"\\EF\\B8\\8F\");\r\ + \n}\r\ + \n:set SymbolForNotification do={\r\ + \n :global NotificationsWithSymbols;\r\ + \n :global SymbolByUnicodeName;\r\ + \n :global IfThenElse;\r\ + \n :if (\$NotificationsWithSymbols != true) do={:return [ \$IfThenElse ([\ + \_:len \$2 ] > 0) ([ :tostr \$2 ] . \" \") \"\" ]}\r\ + \n :local Return \"\";\r\ + \n :foreach Symbol in=[ :toarray \$1 ] do={:set Return (\$Return . [ \$Sy\ + mbolByUnicodeName \$Symbol ])}\r\ + \n :return (\$Return . \" \");\r\ + \n}\r\ + \n:set Unix2Dos do={:return [ :tocrlf [ :tostr \$1 ] ]}\r\ + \n:set UrlEncode do={\r\ + \n :local Input [ :tostr \$1 ];\r\ + \n :if ([ :len \$Input ] = 0) do={:return \"\"}\r\ + \n :local Return \"\";\r\ + \n :local Chars (\"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\?@[\\\\]^`{|}~\");\r\ + \n :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\ + %24\"; \"%25\"; \"%26\"; \"%27\";\r\ + \n \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \ + \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\r\ + \n \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \ + \"%7C\"; \"%7D\"; \"%7E\" };\r\ + \n :for I from=0 to=([ :len \$Input ] - 1) do={\r\ + \n :local Char [ :pick \$Input \$I ];\r\ + \n :local Replace [ :find \$Chars \$Char ];\r\ + \n :if ([ :typeof \$Replace ] = \"num\") do={:set Char (\$Subs->\$Repla\ + ce)}\r\ + \n :set Return (\$Return . \$Char);\r\ + \n }\r\ + \n :return \$Return;\r\ + \n}\r\ + \n:set ValidateSyntax do={\r\ + \n :local Code [ :tostr \$1 ];\r\ + \n :global LogPrint;\r\ + \n :onerror Err {\r\ + \n [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\r\ + \n } do={\r\ + \n \$LogPrint debug \$0 (\"Valdation failed: \" . \$Err);\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsFullyConnected do={\r\ + \n :global IsDNSResolving;\r\ + \n :global IsTimeSync;\r\ + \n :if ([ \$IsDNSResolving ] = false) do={:return false};\r\ + \n :if ([ \$IsTimeSync ] = false) do={:return false};\r\ + \n :return true;\r\ + \n}\r\ + \n:set IsTimeSync do={\r\ + \n :global IsTimeSyncCached;\r\ + \n :global IsTimeSyncResetNtp;\r\ + \n :if (\$IsTimeSyncCached = true) do={:return true}\r\ + \n :if ([ /system/ntp/client/get enabled ] = true) do={\r\ + \n :if ([ /system/ntp/client/get status ] = \"synchronized\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :local Uptime [ /system/resource/get uptime ];\r\ + \n :if ([ :typeof \$IsTimeSyncResetNtp ] = \"nothing\") do={\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n }\r\ + \n :if (\$Uptime - \$IsTimeSyncResetNtp < 3m) do={:return false}\r\ + \n :log warning \"\$0 The ntp client is configured, but did not sync.\"\ + ;\r\ + \n :set IsTimeSyncResetNtp \$Uptime;\r\ + \n /system/ntp/client/set enabled=no;\r\ + \n :delay 20ms;\r\ + \n /system/ntp/client/set enabled=yes;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ /system/license/get ]->\"level\" = \"free\" || \\\r\ + \n [ /system/resource/get ]->\"board-name\" = \"x86\") do={\r\ + \n :log debug \"\$0 No ntp client configured, relying on RTC for CHR fr\ + ee license and x86.\";\r\ + \n :return true;\r\ + \n }\r\ + \n :if ([ /ip/cloud/get update-time ] = true) do={\r\ + \n :if ([ :typeof [ /ip/cloud/get public-address ] ] = \"ip\") do={\r\ + \n :set IsTimeSyncCached true;\r\ + \n :return true;\r\ + \n }\r\ + \n :return false;\r\ + \n }\r\ + \n :log debug \"\$0 No time source configured! Returning gracefully...\";\ + \r\ + \n :return true;\r\ + \n}\r\ + \n\r\ + \n# read parts of a large file\r\ + \n:set FetchLargeFiles do={\r\ + \n :local ScriptName [:tostr \$1];\r\ + \n :local fetchUrl [:tostr \$2];\r\ + \n :local CheckCert [:tostr \$3];\r\ + \n :local fetchMode [:tostr \$4];\r\ + \n :local fetchMethod [:tostr \$5];\r\ + \n :local FetchString \"undefined\";\r\ + \n \r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global GetRandom20CharAlNum;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global MkDir;\r\ + \n :global RmDir;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :set CheckCert [ \$IfThenElse (\$CheckCert = \"false\") \"no\" \"yes-w\ + ithout-crl\" ];\r\ + \n #:set fetchMode [ \$IfThenElse (\$fetchMode != \"false\") [:tostr (\"m\ + ode=\" . \$fetchMode)] ];\r\ + \n #:set fetchMethod [\$IfThenElse (\$fetchMethod != \"false\") [:tostr (\ + \"http-method=\\\"\" . \$fetchMethod . \"\\\"\") ]];\r\ + \n \r\ + \n :local DirName (\"tmpfs/\" . [ \$CleanName \$ScriptName ]);\r\ + \n :if ([ \$MkDir \$DirName ] = false) do={\r\ + \n \$LogPrint error \$0 (\"Failed creating directory!\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n #/tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName h\ + ttp-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-value;\r\ + \n #:log warning (\"\\\$fUrl =\" . \$2 . ({[ \$fMode ]}));\r\ + \n :onerror Err {\r\ + \n :set FetchString (\"/tool/fetch \" . \\\r\ + \n [\$IfThenElse ([\$fetchMethod] != \"false\") (\"http-method=\\\"\"\ + \_. \$fetchMethod . \"\\\" \")] . \\\r\ + \n \"check-certificate=\" . \$CheckCert . \" url=(\\\"\" . \$fetchUrl\ + \_. \"\\\") \" . \\\r\ + \n [\$IfThenElse ([\$fetchMode] != \"false\") (\"mode=\" . \$fetchMod\ + e . \" \")] . \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue);\r\ + \n :log warning (\"\\\$FetchSring = \" . \$FetchString);\r\ + \n :put [\$FetchString];\r\ + \n #:put [/tool/fetch \$fetchMode check-certificate=\$CheckCert url=(\$\ + fetchUrl) dst-path=(\$FileName) http-header-field=({ [ \$FetchUserAgentStr\ + \_\$ScriptName ] }) as-value];\r\ + \n } do={\r\ + \n :if ([ \$WaitForFile \$FileName 500ms ] = true) do={\r\ + \n \$RmFile \$FileName;\r\ + \n }\r\ + \n \$LogPrint debug \$0 (\"Failed downloading from \" . \$fetchUrl . \"\ + \_- \" . \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$fetchUrl . \ + \" did not show up.\");\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileSize [ /file/get \$FileName size ];\r\ + \n :local Return \"\";\r\ + \n :local VarSize 0;\r\ + \n :while (\$VarSize != \$FileSize) do={\r\ + \n :set Return (\$Return . ([ /file/read offset=\$VarSize chunk-size=32\ + 768 file=\$FileName as-value ]->\"data\"));\r\ + \n :set FileSize [ /file/get \$FileName size ];\r\ + \n :set VarSize [ :len \$Return ];\r\ + \n :if (\$VarSize > \$FileSize) do={\r\ + \n :delay 100ms;\r\ + \n }\r\ + \n }\r\ + \n \$RmDir \$DirName;\r\ + \n :return \$Return;\r\ + \n}\r\ + \n\r\ + \n:set ScriptInstallUpdate do={ :onerror Err {\r\ + \n :local Scripts [ :toarray \$1 ];\r\ + \n :local NewComment [ :tostr \$2 ];\r\ + \n :global InitSetup;\r\ + \n\r\ + \n :global CommitId;\r\ + \n :global ScriptUpdatesCRLF;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global CertificateAvailable;\r\ + \n :global CheckSumsVerify;\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global SumsDirAndFileName;\r\ + \n :global GlobalScriptsUrlSuffix;\r\ + \n :global EitherOr;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global Grep;\r\ + \n :global IfThenElse;\r\ + \n :global LogPrint;\r\ + \n :global ParseKeyValueStore;\r\ + \n :global RequiredRouterOS;\r\ + \n :global SendNotification2;\r\ + \n :global SymbolForNotification;\r\ + \n :global ValidateSyntax;\r\ + \n :global CommentsInScripts;\r\ + \n\r\ + \n :if ([ \$CertificateAvailable \"Root YE\" \"fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, trying wit\ + hout.\");\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=\$Scripts do={\r\ + \n :if ([ :len [ /system/script/find where name=\$Script ] ] = 0) do={\ + \r\ + \n \$LogPrint info \$0 (\"Adding new script: \" . \$Script);\r\ + \n /system/script/add name=\$Script owner=\$Script source=\"#!rsc by \ + Vados\\n\" comment=\$NewComment;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :local CommitIdBefore \$CommitId;\r\ + \n :local GlobalConfVersionBefore \$GlobalConfVersion;\r\ + \n :local ReloadGlobal false;\r\ + \n :local DeviceMode [ /system/device-mode/get ];\r\ + \n\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSums ({});\r\ + \n :do {\r\ + \n :local Url (\$GlobalScriptsUrl . \$SumsDirAndFileName . \$GlobalScr\ + iptsUrlSuffix);\r\ + \n \$LogPrint debug \$0 (\"Fetching checksums from url: \" . \$Url);\ + \r\ + \n :set CheckSums [ :deserialize from=json ([ /tool/fetch check-certi\ + ficate=yes-without-crl \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url output\ + =user as-value ]->\"data\") ];\r\ + \n } on-error={ \$LogPrint warning \$0 (\"Err = \" . \$Err); }\r\ + \n }\r\ + \n\r\ + \n :foreach Script in=[ /system/script/find where source~\"^#!rsc by Vado\ + s\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :local ScriptInfo [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") \ + ];\r\ + \n :local SourceNew;\r\ + \n\r\ + \n :foreach Scheduler in=[ /system/scheduler/find where on-event~(\"\\\ + \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\r\ + \n :local SchedulerVal [ /system/scheduler/get \$Scheduler ];\r\ + \n :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\r\ + \n \$LogPrint warning \$0 (\"Policies differ for script '\" . \$Scr\ + iptVal->\"name\" . \"' and its scheduler '\" . \$SchedulerVal->\"name\" . \ + \"'!\");\r\ + \n }\r\ + \n }\r\ + \n :do {\r\ + \n :if (\$ScriptInfo->\"ignore\" = true) do={\r\ + \n \$LogPrint debug \$0 (\"Ignoring script '\" . \$ScriptVal->\"nam\ + e\" . \"', as requested.\");\r\ + \n :error true;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :local CheckSum (\$CheckSums->(\$ScriptVal->\"name\"));\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Scri\ + ptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :convert transform=md5 to=hex [ :tolf (\$ScriptVal->\"sou\ + rce\") ] ] = \$CheckSum) do={\r\ + \n \$LogPrint debug \$0 (\"Checksum for script '\" . \$ScriptVal-\ + >\"name\" . \"' matches, ignoring.\");\r\ + \n :error true;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len (\$ScriptInfo->\"certificate\") ] > 0) do={\r\ + \n :if ([ \$CertificateAvailable (\$ScriptInfo->\"certificate\") \"\ + fetch\" ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Downloading certificate failed, tryi\ + ng without.\");\r\ + \n }\r\ + \n }\r\ + \n :onerror Err {\r\ + \n :local BaseUrl [ \$EitherOr (\$ScriptInfo->\"base-url\") \$Globa\ + lScriptsUrl ];\r\ + \n :local UrlSuffix [ \$EitherOr (\$ScriptInfo->\"url-suffix\") \$G\ + lobalScriptsUrlSuffix ];\r\ + \n :local Url (\$BaseUrl . \$ScriptVal->\"name\" . \".rsc\" . \$Url\ + Suffix);\r\ + \n \$LogPrint warning \$0 (\"Fetching script '\" . (\$ScriptVal->\"\ + name\") . \"' from url: \" . \$Url);\r\ + \n :local Result [ /tool/fetch check-certificate=yes-without-crl \\\ + \r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$0 ] }) \$Url outp\ + ut=user as-value ];\r\ + \n :if (\$Result->\"status\" = \"finished\") do={\r\ + \n :set SourceNew [ :tolf (\$Result->\"data\") ];\r\ + \n } \r\ + \n } do={\r\ + \n \$LogPrint warning \$0 (\"Failed fetching script '\" . \$ScriptV\ + al->\"name\" . \"': \" . \$Err);\r\ + \n :if (\$Err != \"Fetch failed with status 404\") do={\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$ScriptVal->\"source\" = \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Removing dummy. Typo on installation\ + \?\");\r\ + \n /system/script/remove \$Script;\r\ + \n :error false;\r\ + \n }\r\ + \n :if (\$CheckSumsVerify = true) do={\r\ + \n :if ([ :len (\$ScriptInfo->\"base-url\") ] = 0 && [ :len (\$Sc\ + riptInfo->\"url-suffix\") ] = 0 && \\\r\ + \n [ :len \$CheckSum ] = 0) do={\r\ + \n \$LogPrint warning \$0 (\"Added the script manually\? Skip u\ + pdates with 'ignore=true' in comment.\");\r\ + \n }\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$SourceNew ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"No update for script '\" . (\$ScriptVal-\ + >\"name\") . \"'.\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :local SourceCRLF [ :tocrlf \$SourceNew ];\r\ + \n :if (\$InitSetup != true && ((\$ScriptVal->\"name\") != \"AM-Globa\ + lConfig\" || (\$ScriptVal->\"name\") != \"AM-GlobalFunc\")) do={\r\ + \n :if (\$SourceNew = (\$ScriptVal->\"source\") || \$SourceCRLF = (\ + \$ScriptVal->\"source\")) do={\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\") \ + . \"' source did not change. End of lines set to CRLF.\");\r\ + \n if (\$ScriptUpdatesCRLF = false) do={\r\ + \n :put [ :tolf \$SourceNew ];\r\ + \n \$LogPrint debug \$0 (\"Script '\" . (\$ScriptVal->\"name\"\ + ) . \"' source update end of lines to LF.\");\r\ + \n }\r\ + \n :error false;\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([ :pick \$SourceNew 0 14 ] != \"#!rsc by Vados\") do={\r\ + \n \$LogPrint warning \$0 (\"Looks like new script '\" . \$ScriptVa\ + l->\"name\" . \"' is not valid (missing shebang = '\$shebang') Ignoring!\"\ + );\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if (\$CommentsInScripts = true) do={\r\ + \n :local CommentLine [ \$Grep \$SourceNew (\"\\23 Script comment:\ + \_\") ];\r\ + \n :if ([ :len \$CommentLine ] = 0) do={\r\ + \n \$LogPrint debug \$0 (\"The search in new script '\" . (\$Scr\ + iptVal->\"name\") . \"' for comment in script body, is not found result Ig\ + noring!\");\r\ + \n :error false;\r\ + \n } else={\r\ + \n :if ([ :len (\$ScriptVal->\"comment\")] = 0 || [ :len (\$Scri\ + ptVal->\"comment\")] != [ :pick \$CommentLine ([ :find \$CommentLine \":\"\ + ] + 2) [ :len \$CommentLine] ]) do={\r\ + \n \$LogPrint debug \$0 (\"Exsiting comment for script '\" . (\ + \$ScriptVal->\"name\") . \"' is '\" . (\$ScriptVal->\"comment\") . \"'.\")\ + ;\r\ + \n :set (\$ScriptVal->\"comment\") [ :pick \$CommentLine ([ :f\ + ind \$CommentLine \":\"] + 2) [ :len \$CommentLine] ];\r\ + \n \$LogPrint debug \$0 (\"New comment (\" . (\$ScriptVal->\"c\ + omment\") . \") for script '\" . (\$ScriptVal->\"name\") . \"' has been ad\ + ded!\");\r\ + \n } else={\r\ + \n \$LogPrint debug \$0 (\"Comment for script '\" . (\$ScriptV\ + al->\"name\") . \"' did not change.\");\r\ + \n :error false;\r\ + \n }\r\ + \n } \r\ + \n }\r\ + \n\r\ + \n :local RequiredROS ([ \$ParseKeyValueStore [ \$Grep \$SourceNew (\ + \"\\23 requires RouterOS, \") ] ]->version);\r\ + \n :if ([ \$RequiredRouterOS \$0 [ \$EitherOr \$RequiredROS \"0.0\" ]\ + \_false ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires RouterOS \" . \\\r\ + \n \$RequiredROS . \", which is not met by your installation. I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n :local RequiredDM [ \$ParseKeyValueStore [ \$Grep \$SourceNew (\"\ + \\23 requires device-mode, \") ] ];\r\ + \n :local MissingDM ({});\r\ + \n :foreach Feature,Value in=\$RequiredDM do={\r\ + \n :if ([ :typeof (\$DeviceMode->\$Feature) ] = \"bool\" && (\$Devi\ + ceMode->\$Feature) = false) do={\r\ + \n :set MissingDM (\$MissingDM, \$Feature);\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len \$MissingDM ] > 0) do={\r\ + \n \$LogPrint warning \$0 (\"The script '\" . (\$ScriptVal->\"name\ + \") . \"' requires disabled \" . \\\r\ + \n \"device-mode features (\" . [ :tostr \$MissingDM ] . \"). I\ + gnoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$ValidateSyntax \$SourceNew ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Syntax validation for script '\" . (\$\ + ScriptVal->\"name\") . \"' failed! Ignoring!\");\r\ + \n :error false;\r\ + \n }\r\ + \n \r\ + \n :log info (\"Updating script: \" . (\$ScriptVal->\"name\") . \" Sc\ + ript comment: \" . (\$ScriptVal->\"comment\"));\r\ + \n\r\ + \n /system/script/set owner=(\$ScriptVal->\"name\") comment=(\$Script\ + Val->\"comment\") \\\r\ + \n source=[ \$IfThenElse (\$ScriptUpdatesCRLF = true) \$SourceCRL\ + F \$SourceNew ] \$Script;\r\ + \n :if (\$ScriptVal->\"name\" = \"AM-GlobalConfig\" || \\\r\ + \n \$ScriptVal->\"name\" = \"AM-GlobalFunc\" || \\\r\ + \n \$ScriptVal->\"name\" ~ (\"^(AM-GlobalFunc\\\\.d|mod)/.\")) d\ + o={\r\ + \n :set ReloadGlobal true;\r\ + \n }\r\ + \n } on-error={ }\r\ + \n }\r\ + \n :if (\$ReloadGlobal = true) do={\r\ + \n \$LogPrint info \$0 (\"Reloading global configuration and functions.\ + \");\r\ + \n :onerror Err {\r\ + \n :global InitSetup (a);\r\ + \n /system/script {run AM-GlobalConfig; run AM-GlobalFunc;};\r\ + \n } do={\$LogPrint error \$0 (\"Reloading global configuration and fun\ + ctions failed! \" . \$Err)}\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore > \$GlobalConfVersion) do={\r\ + \n \$LogPrint warning \$0 (\"The configuration version decreased from \ + \" . \\\r\ + \n \$GlobalConfVersionBefore . \" to \" . \$GlobalConfVersion . \\\r\ + \n \". Installed an older version\?\");\r\ + \n }\r\ + \n :if (\$GlobalConfVersionBefore < \$GlobalConfVersion) do={\r\ + \n :global GlobalConfChanges;\r\ + \n :global GlobalConfMigration;\r\ + \n :local ChangeLogCode;\r\ + \n :if ([ :len \$ChangeLogCode ] > 0) do={\r\ + \n :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\r\ + \n :onerror Err {\r\ + \n [ :parse \$ChangeLogCode ];\r\ + \n } do={\$LogPrint warning \$0 (\"The changelog failed to run: \" \ + . \$Err)}\r\ + \n } else={\$LogPrint warning \$0 (\"The changelog failed syntax vali\ + dation!\")}\r\ + \n }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Migration (\$GlobalConfMigration->[ :tostr \$I ]);\r\ + \n :do {\r\ + \n :if ([ :typeof \$Migration ] != \"str\") do={\r\ + \n \$LogPrint debug \$0 (\"Migration code for change \" . \$I .\ + \_\" is not available.\");\r\ + \n :error false;\r\ + \n }\r\ + \n :if ([ \$ValidateSyntax \$Migration ] = false) do={\r\ + \n \$LogPrint warning \$0 (\"Migration code for change \" . \$I\ + \_. \" failed syntax validation!\");\r\ + \n :error false}\r\ + \n \$LogPrint info \$0 (\"Applying migration for change \" . \$I \ + . \": \" . \$Migration);\r\ + \n :onerror Err {\r\ + \n [ :parse \$Migration ];\r\ + \n } do={\$LogPrint warning \$0 (\"Migration code for change \" .\ + \_\$I . \" failed to run: \" . \$Err)}\r\ + \n } on-error={ }\r\ + \n }\r\ + \n }\r\ + \n :local NotificationMessage (\"The configuration version on \" . \$Id\ + entity . \" increased \" . \\\r\ + \n \"to \" . \$GlobalConfVersion . \", current configuration may nee\ + d modification. \" . \\\r\ + \n \"Please review and update global-config-overlay, then re-run glo\ + bal-config.\");\r\ + \n \$LogPrint info \$0 (\$NotificationMessage);\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nChanges:\ + \");\r\ + \n :for I from=(\$GlobalConfVersionBefore + 1) to=\$GlobalConfVersion\ + \_do={\r\ + \n :local Change (\$GlobalConfChanges->[ :tostr \$I ]);\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n \" . \\\ + \r\ + \n [ \$SymbolForNotification \"pushpin\" \"*\" ] . \$Change);\r\ + \n \$LogPrint info \$0 (\"Change \" . \$I . \": \" . \$Change);\r\ + \n }\r\ + \n } else={:set NotificationMessage (\$NotificationMessage . \"\\n\\nNe\ + ws and changes are not available.\")}\r\ + \n\r\ + \n :set GlobalConfChanges;\r\ + \n :set GlobalConfMigration;\r\ + \n }\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err}\r\ + \n}\r\ + \n\r\ + \n# Global Environment clear. Use: \"\$GlobalEnvRemove True;\".\r\ + \n:set GlobalEnvRemove do={\r\ + \n :local doRmEnv [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :local ScriptsUrl;\r\ + \n :global LogPrint;\r\ + \n :if (\$doRmEnv != \"True\") do={\r\ + \n \$LogPrint error \"GlobalEnvRemove\" (\"This script is needed \\\"T\ + rue\\\" for confirm to remove global environment variables!\");\r\ + \n :return [];\r\ + \n :error true; \r\ + \n } else={\r\ + \n :set ScriptsUrl \$GlobalScriptsUrl;\r\ + \n :delay 5;\r\ + \n :foreach var in=[/system/script/environment print as-value] do={/sy\ + stem/script/environment remove (\$var->\".id\")}\r\ + \n :delay 5;\r\ + \n :global GlobalScriptsUrl \$ScriptsUrl;\r\ + \n \$LogPrint warning \"GlobalEnvRemove\" (\"Done!\");\r\ + \n :return [];\r\ + \n :error false;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# Add and fix global scheduler\r\ + \n:put \"Add or/and fix Global scheduler...\";\r\ + \n:local OnEvent \"/system/script { run AM-GlobalConfig; run AM-GlobalFunc\ + ; }\";\r\ + \n:local Comment \"Setup Global Environment for scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-SetGlobalEnv\" ] ] \ + = 0) do={\r\ + \n /system/scheduler/add name=\"AM-SetGlobalEnv\" comment=\$Comment on-ev\ + ent=\$OnEvent start-time=startup;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" comment ] != \$Comment)\ + \_do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" comment=\$Comment;\r\ + \n}\r\ + \n:if ([ /system/scheduler/get \"AM-SetGlobalEnv\" on-event ] != \$OnEvent\ + ) do={\r\ + \n /system/scheduler/set \"AM-SetGlobalEnv\" on-event=\$OnEvent;\r\ + \n}\r\ + \n# Add Update Script scheduler\r\ + \n:put \"Add or/and fix Update Script scheduler\";\r\ + \n:set OnEvent \":global ScriptInstallUpdate; \\\$ScriptInstallUpdate;\";\ + \r\ + \n:set Comment \"Every Day Check For Update Scripts\";\r\ + \n:if ([ :len [ /system/scheduler/find where name=\"AM-ScriptInstallUpdate\ + \" ] ] = 0) do={\r\ + \n/system/scheduler/add name=\"AM-ScriptInstallUpdate\" comment=\$Comment \ + start-time=startup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n#:local Resource [ /system/resource/get ];\r\ + \n#:log info (\$ScriptName . \" Loaded on \" . \$Resource->\"board-name\" \ + . \" with RouterOS \" . \$Resource->\"version\" . \" and Architecture \" .\ + \".\");\r\ + \n\r\ + \n:onerror Err {\r\ + \n :global GlobalConfReady;\r\ + \n :retry { :if (\$GlobalConfReady != true) do={ :error (\"Global configs\ + \_not ready.\"); }; } delay=100ms max=5;\r\ + \n\r\ + \n# signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n} do={:global ExitOnError; \$ExitOnError \$0 \$Err;}\r\ + \n\r\ + \n#} do={:global ExitError; \$ExitError \$ExitOK [ :jobname ] \$Err}\r\ + \n# log the successful load of the script, or an error if it failed\r\ + \n#:if ([\$GlobalFuncReady] = true && [\$GlobalConfReady] = true) do={\r\ + \n" +add dont-require-permissions=no name=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n\r\ + \n#root.mnuc.backuper\r\ + \n:global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\r\ + \n#/usb1/mikro_bak_rsa.pub" +add dont-require-permissions=yes name=MkTmpfs owner=vados policy=\ + ftp,read,write,policy,test,sniff,sensitive source=\ + ":global MkDir;\r\ + \n\r\ + \n\$MkDir /usb1/tmpfs;" +add dont-require-permissions=no name=CreateContainer owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local contIF \"veth1\";\r\ + \n:local contIP \"10.10.10.10/24\";\r\ + \n:local contGW \"10.10.10.1\";\r\ + \n#/interface/veth/add name=\$contIF address=\$contIP gateway=\$contGW;\r\ + \n:local contBridgeIF \"Bridge-DOC\";\r\ + \n:local contBridgeIP \"10.10.10.1/24\";\r\ + \n/interface/bridge/add name=\$contBridgeIF;\r\ + \n/ip/address/add address=\$contBridgeIP interface=\$contBridgeIF;\r\ + \n/interface/bridge/port/add bridge=\$contBridgeIF interface=\$contIF;\r\ + \n/container/config/set ram-high=768M registry-url=https://registry-1.dock\ + er.io tmpdir=sata1/tmp\r\ + \n" +add dont-require-permissions=no name=carkeeperbot owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/\ + container/mounts/add list=carkeeper_configs/.profile src=sata1/carkeeper/c\ + onfigs/.profile dst=/root/.ashrc;\r\ + \n/container/mounts/add list=carkeeper_configs/php.ini src=sata1/carkeeper\ + /configs/php.ini dst=/etc/php82/php.ini;\r\ + \n#/container/mounts/add list=carkeeper_configs src=sata1/carkeeper/config\ + s dst=/configs;\r\ + \n/container/mounts/add list=carkeeper_app src=sata1/carkeeper/app dst=/ap\ + p;\r\ + \n/container/mounts/add list=carkeeper_scripts src=sata1/carkeeper/scripts\ + \_dst=/scripts;\r\ + \n/container/mounts/add list=carkeeper_configs/sshd_config src=sata1/carke\ + eper/configs/sshd_config dst=/etc/ssh/sshd_config;\r\ + \n\r\ + \n/container/mounts/add list=carkeeper_tmp src=sata1/carkeeper/tmp dst=/va\ + r/tmp;\r\ + \n/container/mounts/add list=carkeeper_sync src=sata1/carkeeper/sync dst=/\ + var/sync;\r\ + \n" +add comment="Enable or disable ip addresses based on bridge port state" \ + dont-require-permissions=no name=mod/AM-IPbridge owner=mod/AM-IPbridge \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: mod/AM-IPbridge\r\ + \n# Script comment: Enable or disable ip addresses based on bridge port st\ + ate\r\ + \n# Copyright (c) 2005-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n# Add this Script scheduler\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n:log warning (\"SystemScheduler for script: \" . \$ScriptName . \" is NO\ + T SET! Fix It Now!\");\r\ + \n:local OnEvent \"/system/script/run \$ScriptName;\";\r\ + \n:local Comment \"Every Day Check For Fake Bridges\";\r\ + \n/system/scheduler/add name=\$ScriptName comment=\$Comment start-time=sta\ + rtup interval=1d on-event=\$OnEvent;\r\ + \n}\r\ + \n\r\ + \n:foreach Bridge in=[ /interface/bridge/find ] do={\r\ + \n :local BrName [ /interface/bridge/get \$Bridge name ];\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName ] ] > \ + 0) do={\r\ + \n :if ([ :len [ /interface/bridge/port/find where bridge=\$BrName and \ + inactive=no ] ] = 0) do={\r\ + \n /ip/address/disable [ find where !dynamic interface=\$BrName ];\r\ + \n } else={\r\ + \n /ip/address/enable [ find where !dynamic interface=\$BrName ];\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n" +/user group +add name=backup policy="telnet,ssh,ftp,read,write,policy,test,sniff,sensitive,\ + !local,!reboot,!winbox,!password,!web,!api,!romon,!rest-api" +/app settings +set auto-update=yes disk=sata1 lan-bridge=Bridge-LAN registry-mirrors="https:/\ + /reg.vados.ru:5000/:https://reg.vados.ru/,https://registry-1.docker.io" +/caps-man aaa +set called-format=ssid +/caps-man access-list +add action=reject allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-120..-80 ssid-regexp="" +add action=accept allow-signal-out-of-range=10s disabled=no interface=all \ + signal-range=-79..120 ssid-regexp="" +/caps-man manager +# bad package path +set ca-certificate=CAPsMAN-CA-51B25E507D07 certificate=CAPsMAN-51B25E507D07 \ + enabled=yes package-path=/tmpfs/capsman-packages +/caps-man manager interface +set [ find default=yes ] forbid=yes +add disabled=no interface=Bridge-LAN +/caps-man provisioning +add action=create-dynamic-enabled hw-supported-modes=g,gn,b \ + master-configuration=2G name-format=prefix-identity name-prefix=2G +add action=create-dynamic-enabled hw-supported-modes=an,ac,a \ + master-configuration=5G name-format=prefix-identity name-prefix=5G +add action=create-dynamic-enabled disabled=yes hw-supported-modes=ac,an,a \ + master-configuration=2G name-format=prefix-identity name-prefix=5ghz-ac +add action=create-dynamic-enabled disabled=yes hw-supported-modes=an \ + master-configuration=5G name-format=prefix-identity name-prefix=5ghz-an +/certificate settings +set builtin-trust-store=fetch crl-download=yes crl-use=yes +/container config +set layer-dir=/sata1 registry-url=https://reg.vados.ru tmpdir=/ramstorage \ + username=amster-dev +/container envs +add key=ENV list=carkeeperbot_envs value=/root/.ashrc +add key=PATH list=carkeeperbot_envs value=\ + /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +add key=PORT list=carkeeperbot_envs value="\${SSH_PORT}" +add key=SSH_PORT list=carkeeperbot_envs value=8222 +/container mounts +add dst=/app list=carkeeper_app src=/sata1/carkeeper/app +add dst=/configs list=carkeeper_configs src=/sata1/carkeeper/configs +add dst=/root/.ashrc list=carkeeper_configs/.profile src=\ + /sata1/carkeeper/configs/.profile +add dst=/etc/php82/php.ini list=carkeeper_configs/php.ini src=\ + /sata1/carkeeper/configs/php.ini +add dst=/etc/ssh/sshd_config list=carkeeper_configs/sshd_config src=\ + /sata1/carkeeper/configs/sshd_config +add dst=/scripts list=carkeeper_scripts src=/sata1/carkeeper/scripts +add dst=/var/sync list=carkeeper_sync src=/sata1/carkeeper/sync +add dst=/var/tmp list=carkeeper_tmp src=/sata1/carkeeper/tmp +/interface bridge port +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-DOC interface=veth1 +add bridge=Bridge-LAN interface=LAN +add bridge=Bridge-LAN interface=dynamic +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes +/interface detect-internet +set detect-interface-list=LAN internet-interface-list=LAN lan-interface-list=\ + LAN wan-interface-list=LAN +/interface wifi capsman +set package-path=/tmpfs/capsman-packages upgrade-policy=none +/ip address +add address=10.30.30.10/24 interface=Bridge-LAN network=10.30.30.0 +add address=10.10.10.1/24 disabled=yes interface=Bridge-DOC network=\ + 10.10.10.0 +add address=172.18.20.5/30 disabled=yes interface=docker-xray-vless-veth \ + network=172.18.20.4 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set disabled=yes interface=Bridge-LAN \ + lease-script=lease-script lease-time=10m name=nucDHCP server-address=\ + 10.30.30.10 +/ip dns +set allow-remote-requests=yes doh-max-concurrent-queries=100 \ + doh-max-server-connections=20 servers=10.30.30.81 verify-doh-cert=yes +/ip firewall filter +add action=accept chain=input +add action=accept chain=output +add action=accept chain=forward comment="Comment of the rule" disabled=yes +/ip firewall mangle +# docker-xray-vless-veth not ready +add action=change-mss chain=forward new-mss=1360 out-interface=\ + docker-xray-vless-veth protocol=tcp tcp-flags=syn tcp-mss=1420-65535 +/ip firewall nat +# docker-xray-vless-veth not ready +add action=masquerade chain=srcnat out-interface=docker-xray-vless-veth +/ip firewall service-port +set ftp disabled=yes +set tftp disabled=yes +set sip disabled=yes +set pptp disabled=yes +set rtsp disabled=no +/ip route +add disabled=no dst-address=0.0.0.0/0 gateway=10.30.30.81 routing-table=main +/ip service +set ftp disabled=yes +set www disabled=yes +set ssh port=2222 +set www-ssl port=4443 +set api disabled=yes +set api-ssl disabled=yes +/ip service webserver +set acme-plain=no crl-plain=no graphs-plain=no graphs-secure=no index-plain=\ + no index-secure=no rest-plain=no rest-secure=no scep-plain=no \ + webfig-plain=no webfig-secure=no +/ip ssh +set forwarding-enabled=both password-authentication=no \ + publickey-authentication-options=verify-required strong-crypto=yes +/ip upnp +set allow-disable-external-interface=yes enabled=yes +/ipv6 firewall address-list +add address=2400:cb00::/32 list=CLOUDFLARE-IP-Address +add address=2606:4700::/32 list=CLOUDFLARE-IP-Address +add address=2803:f800::/32 list=CLOUDFLARE-IP-Address +add address=2405:b500::/32 list=CLOUDFLARE-IP-Address +add address=2405:8100::/32 list=CLOUDFLARE-IP-Address +add address=2a06:98c0::/29 list=CLOUDFLARE-IP-Address +add address=2c0f:f248::/32 list=CLOUDFLARE-IP-Address +/system clock +set time-zone-autodetect=no time-zone-name=Europe/Moscow +/system gps +set set-system-time=yes +/system identity +set name=MikroNUC +/system note +set show-at-login=no +/system ntp client +set enabled=yes +/system ntp server +set enabled=yes manycast=yes multicast=yes +/system ntp client servers +add address=10.30.30.81 +add address=0.ru.pool.ntp.org +add address=1.ru.pool.ntp.org +add address=2.ru.pool.ntp.org +add address=3.ru.pool.ntp.org +/system scheduler +add comment="Backup Every Week" interval=1w name=BackupEveryWeek on-event=\ + "/system/script { run BackupAndUpdate; }" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2025-07-07 start-time=04:41:27 +add comment="Setup Global Environment for scripts" name=Amster-SetGlobalEnv \ + on-event=\ + "/system/script { run Amster-GlobalConfig; run Amster-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + Amster-GetInstallUpdate on-event=":global getInstUpd; \$getInstUpd;" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Setup Global Environment for scripts" name=AM-SetGlobalEnv \ + on-event="/system/script { run AM-GlobalConfig; run AM-GlobalFunc; }" \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Update Scripts" interval=1d name=\ + AM-ScriptInstallUpdate on-event=\ + ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +add comment="Every Day Check For Fake Bridges" interval=1d name=\ + mod/AM-IPbridge on-event="/system/script/run mod/AM-IPbridge;" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-time=startup +/tool e-mail +set certificate-verification=no from=MikroNUC port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com +/tool netwatch +add disabled=yes down-script=\ + ":local msg \"Host MikroYellow is DOWN\";\r\ + \n\$TGSendMessage \$msg;" host=10.30.30.86 http-codes="" interval=10s \ + test-script="" type=simple up-script=\ + ":global TGSendMessage;\r\ + \n\$TGSendMessage \"Host MikroYellow is UP\";" +/user aaa +set accounting=no diff --git a/MikroNUC/tmp/Config.rsc b/MikroNUC/tmp/Config.rsc deleted file mode 100644 index e69de29..0000000 -- 2.52.0

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