From da80d692ebe8f4734852a25c977bc9e804030a57 Mon Sep 17 00:00:00 2001 From: vados-dev Date: Thu, 2 Jul 2026 19:03:09 +0300 Subject: [PATCH] Backup for MikroGig created successfully at Jul 02 19:03:09. --- .../20260702/20260702190305-Binary.backup | Bin 0 -> 184584 bytes MikroGig/20260702/20260702190305-Config.rsc | 3155 ++++++++++++++ .../20260702/20260702190305-Diff-Config.rsc | 449 ++ .../20260702/20260702180002-Config.rsc | 3695 ++++++++++++++++ .../20260702/20260702182002-Config.rsc | 3696 +++++++++++++++++ .../20260702/20260702184001-Config.rsc | 3695 ++++++++++++++++ MikroMaster/tmp/Config.rsc | 0 MikroMaster/tmp/Diff-Config.rsc | 8 - 8 files changed, 14690 insertions(+), 8 deletions(-) create mode 100644 MikroGig/20260702/20260702190305-Binary.backup create mode 100644 MikroGig/20260702/20260702190305-Config.rsc create mode 100644 MikroGig/history/20260702/20260702190305-Diff-Config.rsc create mode 100644 MikroMaster/20260702/20260702180002-Config.rsc create mode 100644 MikroMaster/20260702/20260702182002-Config.rsc create mode 100644 MikroMaster/20260702/20260702184001-Config.rsc delete mode 100644 MikroMaster/tmp/Config.rsc delete mode 100644 MikroMaster/tmp/Diff-Config.rsc diff --git a/MikroGig/20260702/20260702190305-Binary.backup b/MikroGig/20260702/20260702190305-Binary.backup new file mode 100644 index 0000000000000000000000000000000000000000..f8063cffeb44a0c0c15b8c85b5eaf91f0eb575f2 GIT binary patch literal 184584 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 z zagEmqr#?U7*sj#bs(mqJ)Y>C*F7a^Q9xI^~BJ`ReThE^bxUe6MGl$pJRNDaQ$*;l_ zkO^LkodcC82qncp-R{V7J%hX$HPsp>`)5joRb)B`G4{(_R1sdJG1?L$RAw zAf_fuRC~p9csDA)wa8u>vbmM#o;K-Bi6tCv&hJ%AaYN|>yW`!keRco88KT37`vxUb zOLJ&T1I+5L;I}$FzXdtMzH@vJtHzGoMU-^&+FauuaSP3e&uax55e2C>2mN%e;Z4dR zH)6FkrCICMI9ymxgMWD+C`JNuQBr>ysJ6tD;R0Bm;F$3_x^vm7Mh<)VronrNoC8Ze z#xWH#PF9PACP-P=#*ySX5pA4Z5x?~hB{`#!;U26J;LJdC(e>Q(NvObg8Egt(fwIdQ zDijeE=A=`h} z<^PQ*FOW+Cb()otk<-m|?swf~)K?^zZE7>Pa4P^I69~o(MKo zo8oW_ZK$f~Zr+Btd26y4I)mBzr}D9sbGf{DXNLyba33P>>ikDzG!42Q@T^2;c(|DV z?@sg^qt6{}be#i!=VJ&`yFlIAS2p69@~fHCll1F;&C?P{aYq8S4KYZMTa76}TpSJd z;~UQN4zOz8enw_zP_Tb$@#ljdAM!AXJrk&?A$IKjgTTu140VOGF~W86d&mMpd$}*5 zFMXZUuJz#fmp?Lu^22SrE)r>%P~f#agj#8Tzw#yxcl|2JNqYEaFO8tl`LBLBeL7>> z$*w!PibU?QW2TsN6B$p>p1J|Z*1%ExLw9%o^mPF>7X%oz=irt+Pu;l6dz`KpcGJ-v zo%$kSjVb47zh?#>)PIod$9^%^gG6Ybf&l!bq8l7gV&^gLxCJ8l$BmjjnbEge;ZO~T zu#|ztc<+i?dr(qMG~+`)ibDe)^rVt3N$lvH0Ah85Y$rz?Y_qKFIKG3V076yz_06GA5$Veus@PM{k+kj=A51Yc?9{d68ewF!e%3e+MmLFc1``yCzQw}F zjR7ePnRD7VTDA07&32AAzr0cuGf+=j^@emB)Id5NEr^0R7p8FtzGm6X4Vc^|6;^}w z7a!^nnK&Nj8HbK%i84PbTfJyzKj&_b9Gr)-=)OW|N4p0E5_J7qt#gQM8JAhvV2qVQ zvI~sS38_fkV-+ip6b6|k6Oo@_tXFo$q%n`h>wj0B+V;NdVq_6pOoU#l6AB1h{v~;6 z>w`Yff4!px$YdtbUpyK% zbwxeQnBggMOIgktL2GVi4&Tx=l!MVJTc={#@h{s^BO+kD6q!M^l5qX2k# zbYZE2kg>Rz6bTBB&I?Er^$CJF^W@L=iY(iz*NMHAXHddAGTG|}%d5@^h9b{Aw^!a9 zr(M51iW%L;#jFph=cgcw-HvPvwJsWnJo;Nrl&3;?9Kf?VV_G^KAPDDV3Pr~VbG{+{ zk#@1DbYh7ar#U;?ppmiP44S=YH#PHlxx$w>#(t^uXdAEVgn=|(!*xtB2NT!HD{%TpK!h0#nbpwR*!+{eRouZ_eusIGk z9yA_z{HXEr#$-b>sBAR4N}}_X)f2jT+)1oGD#_DWciAulBtMBA70=`{ z1mYu6fl~jvGpOgw^~h4h>$?zD-8!4ds{BPG>0vzjOcgC~Ws^ZvM5N3PP2Q`(gS6fs z6TcrMP%mOBbB6jS9_+(7qICZCPVoR7h3-2ia_5#eZy=l&>0-%&4`qli2M?ugy#zJ0 zp7~J^&)Q9N9>t`9)PJb>dVHX+Dy^*DG+cxbXJDux5(0Bf!r0*WTc41#%#)j%)=n8J!#J$;Z6!- zu?Wf;0k|K&fd9U&3ZHlO;hj!z(_AwzmOiXE&Mea!^3{_A$%Ok57IOknxhon-udP2H zv{zELw`N!tRtM*QLlP5*JZMH7GX3FSoa|!@s5~YR04Wga)$?`ItScXmS@Lg0%G-GP zO_#2xv{f9VT8-cEL5L|wsNcdg`>qI-a2dBvNdYcXRWl&W%>f}=zVc#;s?UMlZa1wr zsrVN{{F+P{E83?0G}5LOkJMfed{4-fp*5tHA=138>wXcCAkUQd2dQNSVs`O!zSs)L zu4P7W7I{&si>xP^u%;hHtAaYDm)1odL0EOx;UkA;&4}z_zqGBCI$<5ZBx=iM5DK-j z45tL30HXLYfLC}Of)WI748>TJgP2j|ZI}}I4OUA~XAE#rtobI%d|9xwopyw-+tUw4+3x{rG7b%)TkU@NjEw$n zRx(zidr3oJ;MevYB6wQa6Uf%>(wd8rtqq3+Kz4H&tEi31o zg6zDVvp4RU$2mDXHdBwRpVihP+PtZRWSnIZsJ{;MB_49}=#H|4QS{y5hy7wPt?D;Z zV|Nc?Dj>qaw&)pvuS{$pxRNrdZmLJlw;A1ST%V_6<@6@&72Uq80GgU#2ayBakDw3A5GMXiXh7NL@O1tOmmcsteC$;Z9H+=eAe=5} zN)x9l#=zkTu=}hrz800AV!s8l+#2C2ltwRW>j(oi^`m_iuj+duvt#4xVM)a^;<8*5 zM~s#${W{M3Jn{`g`Zz5g-PwCEl&Xr6XG8sr2zM(BTfG)jTc4k`WjHS@mabm)!IHH) zdyz6jI5QWg;O1c($nNQ-?f;3#c|#hV)Z88~pG>|KZ*P)}_vNi@p_AaKZt?DxHGOXq z9;)l%g&&QQ*`RMvEO5{`H%&6?hR(pXsNiXY^QWzlC6XeKR7+*h)Gh4BtA_4LvH7i9dYDf44|S zKa%4BLCcGY=(N8Yf$tw|pxJ1;myEOY$UhYAFAb4}ak4|ci=%o{jH#u}++EHKAe5by zzvX!?O@SJzQ{B42qogG&o1-6@+#~{G0z>ZQFRHN8w*ylQ)W)hqB&V{%l7Ris`CRk_(fM9oqgDX@QJ-*`$#KZsskS4$fj)mpdTC9%%{e8&T1CA( z3>tK?SE5aV@kf0+aa;Rm-R4WEVbYyb=_o;xH`kWDCtW&HfS5O}{YMJ(hV$X=TRGL@ zPYYWh?&-k&O?PY}rWL#L%`nS=68Wy`B723z*5OB)n7D~A&>-W`2=%FJjf+(8pIT6_s#wwsY$RRU)w}{i1 zO#zU7bEdGWYh@mQnBTqw9a*e&6-&rH>P>9L(^z;<=yp$<_*(pWEga6|j{<)9I z2BZ}@7+J3i8QJz~h1VAD5=@IFHz~00&e*`ki&IUjc8M(R1Lo@8t);U;KE7o^eelL_ zk^IwJug||HtO0FH;Y(Cq?tvwTgO<4a->I`wM5|cGQ^e6hog-WF19>?tSPGUC+q??g zep|gEX=l9wI=P%%BmiQEMoQ(!$`z+H)7Gxpc&SgysIJB@ONOBJ!TX%|6E>z{GJuOh zz^j-kna{#dp46fkg|Xbj2;uZvp#i9=^MSm8zCA7@_|0Hq0vNU*SMXi$wO88Wtr*`r zw~udWtSq(I@_7X~2pE0D@lWC*S$A76#D_9nm2Y=iQm+M&^glBuJ|cl$C|^iZ9HA=NLHAC&Sg zG{~$qC2lT;d<)3Hf85*dh!jaw`-~wdA+eD${7cxIqI$uFR;>fU5s1~kQ)V7RA1gGB zYFjFEY}uh$h_dKYlX2(!+YAy`SX^ZVa+_q}?rq#7$!@%cuxgbELvIB^9|Mc1SWp-p z%s@S_{qx{WnA_6%eO7Ib%SuP`DBik0snqy-Z#15S9vfXiM|&kio`FJ+X6jXA58t4P z7AQi7X*0+R4L{!_WyBI>dC!_ttj6bF)o2Q4>g?UCs6FV$xvieHBb-O3`-6A{6)q9k zU{@aq0Nj=<)HzVinEh0{dI_M~dffki1f++>;WucOTG-r?8(5Z`L#Tl^eA6j(qLJ;a zsF4HRM}DkB5!Jz`Q;6h(drP8q3A=G;*bU`uiqXcgTNmt>ttEIkR$pw?h3if^GJ{w$ z=%-OiTh=~R0+7HKCNe1sKhQHdj{cV1^ z9G7bzPReguT7NRb$)`+Zbrw(|AI>XRmIF%jnaAl?E>`aL+O253H?-+??vP?`lDIbv z6ZDogZL%RDPm8ORtrqP~aa*UKg8=re#|;AMpVQ#9$hdW(Pyz~+Jtu+&3O{1&it~A}Q$e53 zhlb?LZfM>?jWryo>`Wlw7=ALwgQrz?rKkY^KLEhgFS)f5ke2LlrL(_ z*v<;>;V_Y-Y#+`cOgVOZ6~ZbBmowMM#y;mG zLa(fLiOcWK$`dL#mRI(p^EShpnpB;8xtOCPwD}m9$xMGduFz-rR9MK&YxqAFYTsJ| zQhC{lgdEy_WJ|Sm3O!X)45%*IR&mucSj;e&q7FcrXwKxG_|i}2WGPhQ>8&XM>nT$1 zL?FYD<9H}Cn*QYMk^fi`E~do*iDzdKNOo1R{z*11BphsCy&4SCL(}jlxF4A0&SJam zxm9T#*PoS@c8R3;XyPisttr-es{s)ArtPmrDc0yhr?fAx+vDzbw)l92*u-%C%;KJ{ z`5xN@FjQQpBACi?D)UBwHA3qk&`VEnl?(>eFS^X6j^e6T75~SoGg=t-(gJaS(+4 z_2;(9yL)%SZTQ+BN?Y^*1=e6DKZqRH=k=TO{x5 ze6Kcf16nF#eEXZg)>6^m)TD$xSTFQ3E{vZ%#L?+vpJ3aoyPi`kWnz+T8x7 z59{EGT=Y7L4R{$zT3tkxz_XKvsH2k{mW4=UIAtb-L4G8)y6O+3x+a1rGWQLS$sKaU zV>ahWTgXZB)R^rq9G`*ieS&;nX0blLWF(aPTV^A5tG*R<^%bHNeh_5YvciJlD=Yf-I6&lO5C+!%((6NRE^&|UxPX4{hrRt%o_z&ERCgnr~A z=ZQ)>QlLF42l=nZM+u6#!V&eWFGO)Y5kY9fX|(&$ii35R_I(=9PqOcRc5&v?P0g3* zKd^d~()QG0_TJv!GN0&sRhQn59JFRt4tsw!>AF=#BW*z4$Pm6u z7yLbJMuXKI{HCQZ8efI(U9|#-DR|wcfuSIJR$zF5>;KK)1(^|n!XKe^F?2kzJ3s7S z^UtDor!ld1#QX?sqo2R%ZE@q7BBk95Z&)Ajw&OM$-dnoihL^|nz@qE*k&NadfH0-> zuGUh`NC=f6+#tlR`IbMXxH zDKZZc`gthXRuo-u;*9{sFgbNujn=#@Sg`oOo(1B~Qm9!Alo*KJ;vlMX=@wyw zc$qZs!boM%xu7YI^Uk2a+ZLF9q}7FSv*SDjMG9D{3cY0$7NMlKG3D1K`%$m8;)f zrkEw_{D*A45y<3LPu-;{H)9m3v&NI$RXw_7)J_S4)A%0F2O7oL%^yyG#g#=W)6?n9 zTyfD}Q7MP8k7^yXqDDWAfB#1hMx89}zPZk!AJjD0j zYu?+4%68Dl4;a|37&m+n$Nxlve z*#hQNyKEQde-2~g0Rhx*b_2{ce~CkRyGzim%TWn5R&!UEO#TYn=iULO?>Q(AsY3q98ktWzkx7u5bAw+TyW(_{YVNaFnEU9CPrJ#!H8My=#(HM1VjiiYD%H6 zbY-i>9f5}lxOP|2O+Y)co2(OQI0Mqv(U3Y%u39}0PA*PF$T8ulo)>rpc1YGr-wXT2 zMaQnFc}8XL%84Y8|e<|VSdN%Tbg(1J6oss>t{ftbjKYL(Uv5r6Jy_hG`~U2`-6kN6<)A&j6mx*?R5`bEkO+ znOG5ppm!OZK?229p&YS`$7THxy9bF>!KW?is*_c3h2qsy0}#Vo)&1HaFXb*wyO+em z($(6ZTvER^5c|2XqIwU4Bvd{}hjV&A@=!@yZ9J4E14md5qG7u9yro91}K?8t0T zU5nI@%7;woZY>CgmY7?FWBMe=kCnF7ecyaK#mFs|>IRTP7~IdVYb1dE`$5Z~bXh(n zl$z4`uYG<}%mD;WrybAwb$2+_XDS7V92sWr*-0g?WZ?2OP@2WUh?xGVggU_As{{g}oH<7HFyH{98Z6W^Dcw+j@D_x<6L ztEDg~=?@HCQU;wt2$6b|1zpp|XdTx{PcRMW86otl*VZ7K=#W4>>uaL-Tr^Z0qkDfx z|9g~$u`2|1QLcKRo+TLN$8Ad!llwDtPbKJ0vle&1{x*j8zQSP(O!`S&p+)#(CJtYp zl3kjJO)xuPi(}N!!U0!v4rV$07#OgaY{tA;a{*TR<`)ghp?PBJ>&xzh9gmd+ud3P!&~9y|%8g0U;m&_}8ET;Pw!PmQ0wIA!c6uplMjG=0&VVZ9+x zyP}4aKN5e4BY$vsbUpW9Wa8^CFoBRI;YSzb*$Gd$=h_12YE=&04NViJVj4&~{ZNeA zY>*J&=4iCMfk_$O3l9G5Lz=O40}MJ~Fe&NS@l3`rt~nm(lLYTp4!}0rvT^f%a0?0e zwz6!V6KVu*R?)D1pZyMfTJkdlxMpXCIUl-C(W!h6pn2$d?qJG+njy)?UJoWnxl~+x zW8h;tq-XHiNRd41D`vll#oKGK$Flu0k{$Qj;9h1WOo=Ftqxrmv^K|Ts+PA>O>}2+j z&2GHgrLTy#0H&wvzaOOa8sFB9?%5ElhNAn~t?MYqyZlj}Qs)Ocm9_ggWH7HH-D@7b zDnx~t{qKVlHtBE};Td+!Q`D8~F5srKt~*ib(xEKJzQPs?*z@!lbIE)qf4Y3L8@Rvu zM(d9ZDgx?}o4N#sEqwj_Qyg$f3B z1;?QAUy3>~a@JR?w7$9rXHH%3`O1e1BdmW|{35~!L>|~v#KkN4mhG5vBvd~hxC`v4 zzb}Z{K~5`()SoO3B+A~zDEm-JD~9D>bP&>^&fh8|=JRZ}%PbA-rfLU({R)Ss_a090RshEloZvNz)^Eq&tG@5`#b#@bkSeS%KKxjn-Z$!X{=Y`9Tu9i zlaaSv&U5KNYQgh!5SzhQ(+bV_QZ=gsV9Ofc_hIno1mc}oRsah)3=Y$dDORJ(7oKP4 zKr%?j8v`kQkknVg;`s0KjXFkRZBkBv4Ta;E1g7yFZ!hm*BKkbKJ^AoSXJ?D_=)=t2 zVNvL~Ysq+57M3v>KKbKsXEa8upK~WwP9nUAYLB1VtstZ|OfsA0N+# zQc%^Pw&%DiG>V%e^O5eqTR z--(iUPO-MA*jnR?d5x&ruCKJNSKNhny|aq8IrQ{#v54)jfQ8wGqS*~|=hIk&g#=p< zpZ`&)4kiOS*P^`vuz3g-?B2h(kg%Hz7PTEG@bpBd8?zi6lB`I%=A=v;fawsAYygV} z!wcbu)RjZNa&IXO3i$=vpc9s=b`>f(z@PAFEji`H#s?TNL0ulLAvjM=)J4oJjg=%_ z?|yc_=_y3e#Qic(kM)m6iBCM+LD5P#W0$!|AP>iY?39V0VukCTQ}HB%Qj8}8A;fen={dgB1-wa1NSck~d*puhFSAJO zXK)UDLQ#P@_iZj9F02qKy67p~Km`Cz@g#N@XdtJr(yLrJt zHD_9Jd0SG61?&PiyS)iPR{j-qziF|CIS>BLvwDmO@aLvAt++5zTU0T%9o^z`x{djP zDqHMBiq$h&-^&wo)LCY=TjoFGoup`o(-IFNh!pMW=5Fg7Q;$RgG>;pSwRD~7$u4zH zODZCqYl3)hL$oe50C!1yE0;gBWLSFFYU>Y#q7>f4b$4K$H!2XFv6tbwVBCH7)icHI| z{lb2E$nzjayNo0h!J>7IgbFPRZNu?|{cnndf3TtrccsC*7a)~ZFm}6hX zTbLlEu<5l}2mq0}(NC=Yq4J?33xJa@?Q>NMLIYvGSjPtr4ESn}O+BQtw|^r5VSA=z9Kl&H`Hw)zJJdcvkY&1$6} z>NutKxL2mh9d`lijSiKf*>=Ix3UVnR^X;@qct%Dq(4YmD4IWD@Y|CdZB3Vwir z4mn9g7C#&r7Nk7R2{oG^!2fN|d$iT2<5)RqkAl#n3`Jz5lAkK5e0hYoo)uYfc~7aI;H~1fZwK;G_)#*J+y)d=h?2y}+y|djNh;&NUu&;4^tOAGe)SdWT=_e5 zQJ|L#7XhJ0wQ}sAFV#D~Rxpl!-rAcA;Zc$O5p!w&`asw;vlxVjTy$6gSu*JPpOVIJ zR7<$vp7ZK~-FRUsDT{J$DR7@Tsz=X@GjYTsh=`R8%0~;eJPM&l*vh6QOED`F_*k9s z%{(MG4_NA}z_32GrQo5yVM&$YlwcZVvT}tV^_w{6&U-L!V2wL>UO+8rT#}T zn66y_NLbDENveUVym5O!=RQzadzIYwtXNLrJPW^mf$DrJP#Wr%jB>gqJ^XKOeemF zm|(oC`2o)c)*|7Q)PH=SQeTvPeWy%;warG@#bb?9x4rIr{?80Ua5<{gxH10rue0vn z0C*#t&SxXO`ysqf@2YvQ!FiO~0M_Vrjwc5EW{=5??_Z&;2=JIFH%ayyc;5zGK3Z}{ zNWN-gcZv5Coe-9NM~|Oe3Yknm5PXs{Ebw)}=yZBR4A|;&z-pvVw)BAAIYrXr+I#}< z&V;lid=klO0p#%t#R#w5d<+QS3ge)WUK#WDKG-r+)yXz6Y&wtki}FUCD zCPH=5E4k5vL$(K=(@?>zIn#-GI_Ts~heHY<@!k*p790J|3p=zoEYwPdar|ouJP$`} z|BK`jgE&M6@17#s>PA|sGFwuhVgA;>{kZdZx=crNcewJozMlVV{bn^@Zaq;Yl|%bk z6?jWSzX+XX8`!vS8l_?^PB_UsEVj3l!33HmOv_SJS6jznGm%I_Y~zJ|I$_)3MDvbR zDeHPq7eT<>8(8LIu(mcrV-t?Q;Qchj?0zak2)Zo?nZUP0i=GWE>9#nK)U!cT+<9%_ z9_emU!6eJ5?VtU{%ryX>xTpVIoD+M+s~#eS+NlCzaVUR{DeGrwFUf54R9w@;j^k5r zlwRh1n4K{0-y8UJsu6jp(1$`N8Mvw+To@eda!<^dbkwRV?F6c%EFOhG(lj)1x}^8bvL2-M#moK z7ILqn!aql|q_cuVk%BN9md&}hrn*2OT<56hN+(gPb%r7mm{6zXTo6(S33g49X5-_F zGsV?9_K6?g2jU;Zt$}nhu%K1uLWVDqN2uXuIozH-tRf2uveb|fWL_|M5k-4+)Mb_F zIG2OY966H{n@0AiAWSp)1(#{~)J+ts=`e!!nsXg|Qj35wdjDR$oYRIwj%?3M`#USj zfHn?}hQOgq&SN38NSY?UDcruV1G2c|pOld2FW+RV)qjky7wpI^78dt_fZ==Ou_9p( zCEkB%CDUyYxm1EKG2V1jBo~6au7S^*O-OajbmU^;nO(-GU#`?dur+nZxR4#PmdhOd zJ=dGC={3vkzw;&TYPoOog(gMe{dPqLBy#XBGL>5xl=X$WU+q@TE&{98@5fuOQf*Taeq*~|o zP>yr%c<$uds*0R~i)@Q3^gKv+8_VA~H%)Q{&ygJ{D_Bf1o7b zZo4Q;K^*h~vdT?^GBoCj&5~XBvgo1Iw1;@ zI6hysm)`voT9T`=*CJfn+iEiI4?vGtRZJrX_98*^Fo6x^V?1#pH@j*Vtz$|7e1WEz zJ%?!)%h<9)i#)$ijJI{+gTFC^CshHk#`4=UX^5dq*PQgfZ>0GGjc0br4&l+F2)X^> z3Awlb6gnwJ;boio_{7V2M6xx5rJdh0rfcJO_DaCW7#=aWg`ZE6&?YNv_)LS=)_Xj@ zxy#;$f0TXTl2B3AK;bF87MCVy%jsl{GiP`FP+&1{MfeBp&dQcuqpSSeE*kUK)q^tE z;o1U!-|qc7T$AK0AeZ<%Qp%%3)7~B&DT4zzv#Qs(e=s3R7N%p@KT0&A+Qz~^sS zHG~zeUg#Q&k_3L-=xo6UO8amcZ>f}J+Cz1Y(1oR7$&!;_Lluj+jNEfyeY8vwu-GCO z&{i*Dy*Z2~GNl1&U+l$N8EctQkkG7Wz6GTu$o@46_S|oW2yQ6H1&UR-C&M%^dgy#* zvH1ec3THZ>bJ!|(33(coe)0x@R1&Nj@AX8QfB1rfc2IcrXthgkMpq%+r6{}vErf=} zeRk~rWLdzt@o69%%D|ujHx;8bB`?1XWm4UGn^}t#MC25;0<%@2Xz&vhizk&Z{4SG@n-}~ zuRKyTtG&*nXVGjc4-NZgxTFO0s_?I1aCC9Qi@!;n<@x`-4p zD8FN(_uT*Rp$BN*?}&vvAqV;A+?CXZ=wv-KqXX{hT}8^60sMV(9@QNWo3NL3N)2?@ zil4_p3)M@~%hc#2(dJ;OqyfN*<+ij#TvD39akz2W{qAA0I_ZZ@@>+=YmtUHmRu{IgD>TR3kB51hs03VB9=1U9)4kE? zTh!)oK~M&*6_9z(rX?t=8)^Yf9({n4Njq&oX2xnTK;Cm#@*6VueXZ48uA=$Q#1*T! z6QTNW;y^ljhr8LR08K_?RZKWgH6y+gDqqc!cML8L<3Z^)KGGDR$n#$QRy+9$+#&$% zm^+WHt=Dat9{fbzK)n;E+Nse{x;qehtOVPI$CrDExzb+;$mU0vL2H7lv|T#c{QGpK zQtu&4h%6hpMX{2geIW;Uy-cGcEyyU#X5dHcg<-Yno*R}|UvU^{sJ|9d`mUkAp9a5@ zX`(Pp{gv`WLZQKM9a|zjQ$g^J9!(?M=YlgXsu*`YjP!v)8(Mog`B_h{&B11T7V`k5@Lf3H7*@IM8Il z9nnozEJ%GHx_uQ1 z6e(8$9oh3|a;!%hy1U)1IMXz`(Ux)tH~;j+a>Vk^I-sO)ecUp~@i)Y3U|;?xa3ae2 zf!m3iV?j9j0sCVntwsW*spmtB_1zgVUI`nAIKGp(mu|>w;dUDCp+(o7TK?LxqYp8E zn8O8uXX%fs9KS{=@YAs|EkKxBZAe6--haj9bag(Mxi0YpY$dboX-oC?)b}U_sGFf< zt+)M%V`>TI+1&ci>?JZ5#G6Xahn@5^5VUnMQ+OuDTgEMl66PCsZlzBC-I3U&%J9Wv za7d4b^iCJhBz%hL0uKr*9zILexNL+z$9ObHF8$PU9`KxAuO&$>cAC5hib^UT zL6!9hC*|`b!KLGns!@Y3w1ftpnEj9bM=wLN(fV{4jiI4QkK?oU1*lq@EmPJ@Xs0?; zL#ivSPNBrBP{3tyJ?DJQ#DVeS?CWs6ZW0d9EsF5L*rS|4+2?KZ1dA}=OVxJA2Io^+ zLP&d`K#>jr*hq!(9GWuhq)%$zLj?PraObU#r%m+s3XihFuT#WOJHx!Ypr(6we9uZJ zx zCkp<0o8LQUDkpx(ipYJ4HC<%SZ4zRZBx5-8C35fX z>oXp@2k4Ds8;nlZS(u*RmX0_w7y><^yi+n9Ce?X11%26hZpAAEAL65ll>_JN(wUnjM@;tYZL1BJq=sb;P=7E-d&Q| z(r#3`!^+CJ7(+j6{;A3DS4nE;?+-tWo+ul+pByD-F1CAAaQ0Ty<;QY6ahH1=&R(x3 z$xClM6+0}2y8TB&YS&e*Ow41fgygXvJO!$b9xAA4u3IIwgqhJ2Zed&gZ`~q+j^pi!erh@_T;HDtD>Fms>=S)j zI>2l$*S^upi5XJk%D;Pkpgk!0rFBxm!K=-TooqJ%0oQy-`1?-0-aXN}B|KJz$h$q5 z1mu0###67RO@1$T5@kn3s|)3us4eYuS2|yv4pj|)+l_MbgD+*_|G;CN2XULfz72xJ zKs|HL2@lI&M#J#^2{u9?tb~MgJ0f!=LZ)l4BjWQLItiS_?jz=vt-cRLxc2c7zfGSt zn_X|-i=$Z_6X7i$or$nR-%iE!kT z4oj~84mMy9@FFm{+ml%JI6R#N1Cy>>uAdxa-Y=+>!#417D19FRd{7!FRy;uOll%`U z+W9L^A7-0?k@5&%MY`+$9p**DIk<|%)kD|*1~aEKKZc;3HSwdHSKJE5*_dmAD`HU-$9hv0{ih31We8-=A zkDVb&&b_*C(XHGVa#8Yc3opJA6p<2TURvmbSK+vxEHS*i57EG2DR@S2Pu#hNLCN@3 z1~B5}e)*9i7!Ey-yLzGFu*6s4yLD{UODMvl!Dnnb&klmVu4LfrPjKOaGD|H`6P6~M zrB=HuS4|@Elu65QH6+YrHPoz+Mm6_<2!Y4Ny->1=U4yXWF9j=7qU|;rDqDvc6WF7-n^6JD za@Lx{(`PtizYlBdZ~HrOxkC+A&5M2(a&d+a3Raov@XzQY_ji(IQT+&%^NyE)45T2c zwC)xdGyl~Phm==F6We9#0?;g`)r&p}CB`q`@=y9K1Kt6Bl<9Y5t&LfJdOr4Li&~)X zW-Z4-R9m+{Ds(=iCZdc!D{4yKVF%ax&aqTywftvNo&JHl)Awy;8SV&s{g3786zSrr z=Ov;NtLro{7iVWp=HC`XGfOH|NI-)RWa(ka9}O}M3{vB8?+(BgOrz30aGIiNs@aF4 z43C%&ptF%YQQ=IgWGRF6USrH&vE+{_IY3abcFgZhmwJSUE>)MVpJN2qfL*tX4b%W{ zgxduM=_40Y7+MtR!FllNxFvsxyYi5U|91lHVoR2N+*l?uN6FSpBVN;9ha{6})20 zi3ysrUke?&K4QWcp+aP2SG5U%)B@BjaPnFy69KqoBr_`Fn0kP`thuN3UofF98`0qd zn%;RU4o}^8WxN2%t*302`nxfwdg;#VkutPo=T zr^;qMK(szRd}&xuziL5PV>{dTVizZ_+aaS>osPM%gkKr6!Ww>32871P~`n1Gs}DBezc$ZT1s9 z$8|(*$N^WPUSEJkSEj+Qs9|D$WUoBeLOdhRQPF={gUKPJ^goCBDcl##oAUBk5Jd|M zD(9O>^Ke;zUd8=7^H5Bh!U-47m2cHD18bG?fhj6rz!QIYNn3ZaRNC1gA?8w{*5CNB zo>oqYj&*S7ITW}hUQAM7S2I99f=jn7o!!-Nl@djOeD)w@vq?FgF}wx)Lh9|2wA7%& z8c!zinY%NlYpIc6A4oN(PxZ{s)bv@_v?D5hF&VX=ss07))1O~b{*q)Eu7)HuOl0WF zWpHcGZ=%2>vAU%7EFWI`Dt|y>FQSi|mx5>i+!s8!FH6UHm?}msS!U6HTbZx0 zmr9H#kywhY5mgLj;WXjcW~1KmoYCX*n9pXw$;+@ilBE_)rWBD-SzpFLjIAndrvVSh zD~v%JJ^UD@W`MDQDAsBZx)iQ67Cr%d&`Iv%91A@fPA=C-%CPTiCDm(LZq3FjpkgK- z$*sOj0)}gG?4r_YPM($JY&JdPL%9=wFyQO zpe&5i@5nU#dU;C7irWBL^!dddP)vT`B#o}H!%CndPe-uN{PL$^_3^hBK;IEud-m1} zwcq|C$h$9?u2gAA%<59G!WyY1q){=8nEbw^FEe%VoKNUxUE597u#>Qh3X5zSjGn8U zCWic#A+|XaA7+V*)}v5`F*ysWblqrw;sm6yWPzwvuW^Up8s>#^)c2R6Z_3{tFjW$$qirQT7fSByMP@7&~-OKozi4dEDhyqghe@k7PU*nz|G+PHn-uz8}7d z>3Q?Lb~8Gx&f75|numg5J)haNy6l>@_xHw$+;@p&J$b6;PTCs7%b$qf%;ZGKEhi_!sYq-xIUCYEon*NHur$F8+>( zLwszifFvOf1{jf@lHy2@JZ0PZd=IveRMDDHP<*n+U!A+Iju-#yCkFdFU-U~|JgCaAX5qpG#(+xYe(i)Mn=6uB9X_!CA%|cm0a3UH7#_lWS_;^@|QzI56e{=vZ z)e&ab5*Yl~qA`ajP4Ao2(Y+9;)<0Ort3xclcp3KPZx-g${1%vv z@qUuZ+ww8>hTBJw1V2O6tIv5o^~&VGVF%e=kL7wZxq>sb^3B~8FBXLaV|f2bwI8`v)ngE;y`PlA@i>gg8A5M(UnEquC(7!_05FiXmQ> zcuPmuX(da3-2# zV!%eD>ATscaHRFsPA^mlX-9i0V5s#aC{)Yh&MVi`|p7;ip_yPX!eck4|?&MY?Ls z`BW!i(O&}1%F99F>IFs^x&QQ2YJEZ7;5AF3oSLODo8N;ySo2z~tP?6pqprgh1(h=% z5~VaT0EG=TL4 z5EDp4{ye|unU*XpLlY259>I*CL&h*0uu)rV?(ILVAzEj_uTR~XA*v9CxcM%eovsc| zRr;By-D5|&h8tLoi}^BQ9nu0hfOE4X5qRcARuLoCawfj_8Kt%5mt&msEFbf4Y+}HK zCX)Yy0*yWq{ElJzxVR(nf2)e@J0=>`T z6@fhR2K!NrRQj!h2Q1rz3Qnp@7W`V6al2cv@#G5*{4%7_4%2uh?|ngD+TH8~q_M#3 z8P?4gp}#J3zkFhAB(-RcEk0D&>@@b~F8oNGb758%+vffrcE`)~fo2B)Y3a7o5e#Ot zv-`!M8yUir)tAu8n-$DHNEsgd-@GEAH@NI4-{U8f;p@TFtJQ+m)Vdcd)$8fL6Ja+7 z&6>K+SvnwS_TQxR;oC%`6JLbpVycBtK*B+GN&R^FnC2%>Dof~9NjE8hg}eUlfj#dG z;|I2*|8uGnkIKP#@=bAE>O(rJF2io=`-XjX_OvR8^^H2P@~x9@SJa70W>#Bwn}O{x zUSicC8!`&%q>3-e=9OVH*k*vt4AzFAb=1&a%6ViQpb9MK-fYVeBu57N&*M?9c748& z8|=g%lAr73#$mw%vD)F1IADA_H-M6>sFaq0MmNdR zS0%zPfK|fX%gRq-BiN6?_REmel9T4f2fvx^1VX2fBs8tP#F!y(dYw69J)CV1m!oox z$$qQx2IJs-OtXvZqA=~Ef95NdI!I$RfLwha_t-0%8@X7+GWq+4*xu2iK7Gt|5a)|Y zu7I>eyl=(75#DBo?m-qJM`db4-|IgUT#}DeB0c4x)?qT0d9c9c$OEDezUP0W6%8ke zn!>u?h@ec~*c2HpWMS=^U65}{{FcXJkD)9QQ~2LcsnV!sWNCM?(H&(SF;r=r_6QQ) zFSl$DJRxXSPqHK(Tircl1NR*HETUm6m0850zQBQ)=Jlkve&54bX{Fo!*_;qBpT!cbc^VP zj5()1^}7hfbNFE#Vqk@6;iq(kWh2`@(kE$D*!Z;^&jY7gy0-Q^ZTA146kI&11dXVt zH$G6#*XmO8dquk3P#k%CMYG138OKJzl#)0(0WO%Mysksb@II^p;Qvi~@F)DYll6J3 zyU%A9DQ=g&l>$fGGKniy1LiO;cdaL<(eCZ zL37?ma_^G`_LGaC_3B)j7ucMd^fIITo@kdVE&M-lN;^bZ;6gCph>}&C1X@lmU$}Q8E%`~ zPOhz7yr^?Hi+r*p?^8)2t)mwd6%e-{cV^4FyhdFDqfS)bMo$p$e}%7~M{D9OK|R`Z z`$d5?DDJuU?aux?szTeLqe%~>A@4x6qw2bRQy$Cbw^?h6kg%;I%KuOuLUQ1;Lz|I% zaG42D;o3Ivnm;V3@ZvO%@=})M6V8i%zyE#Dae56e^GPdzvd!h~8uvg{ z0bWjp3~MCm<%i0pl3~VB99OKbo%XT)V>8CRdR{P)h0Ildpiwugd=l3d;(7tGX+H%! zp%dp`T(B-J^Lry@);`_9|fM!e?F~1=@{T44bTHQOApF%?h!w~O> zq|Gu}itf?c(<*7@_9JJ%cqr1eXbr{aS_dtfG)2-p z5A7H;w));8;_-fa$6RH60z|Q71OAif@p@mDke!*JhKo^v`R2(_P^J!E`*rJzf7O{d z3Iqm)#n06_i(3&WnD65Y7OG#AF4V7MK83nAQ~6$`gianvz4aX>0U{k|L^@MbE90a! z%x3H~l!O`{dfD2gq3vx|Pjh}mRH+-^^}AA_V~>OjHT&=4NT_JnWkBJtA;q@?>7m|~ zN-lGTmW(c}3Pl<dllGawh=E0NN(#)j)|KHIO%G*{Krn3)ZPDC>ZI3Aq^E%6(D*o7yn-Fj1}rhCu9#N|jrtfn^p9dv zp}SmZfQIx5uZ+g{a&`0XtB}ypT#y^k<1WIA9)cf|Ju4-V%R0ZzbK9a+M?3BNs5 zcJh1uY6l+*Az{nsQ&6Y(dbzMcHUY6X0wvXF7NsmRfrm#hXCKMdYy92(BF9kITPv@b z;;<-6U+1)V4uE#++K$3pSKjG1#8WUZ`jWyY5lB!$`WDRvMOU9B%15aCvuf*fmL6P$ z79bDc9_&}GvmVM=7|yjqT^Y%)Zt4Eq0F8S1`b#P~4aSd*9*%sL+<^u^xXRZI? z)c&uVi5q(-c+YA#pgov<&+kMUbgnp-y{oSF_y!B%B)%kEHdcjR#<1tEXSnoHZ3F750dDa80S|UQv>?|Oh z8=QH1;d7iVrZLZ00)jkx+Im}uMKLM2Nm?ZYYAw&5CE{{1e2$J~dbR^+Iv_d%)~HIa z0x$nC5#&@U$j`Gf+APpAX~H|*g8}OXDgY}K*=hbvrxc!D#>-Ru-kFrz|3{mHtqD?V z!2qYLCbf}6)kzu76F9wdlcYn&C+I#-*`yCw0Rvq4S@za}I|hR)dRFEb zsoqIl{VcBXwpnX4G${x&c$4~2o2R@-eIzt*k+)W<@uP>eQjlY0MDShTC8LPuXtp#v zO63kFgC+;6=zn+tXioWn2LM_PppWHrnQwsAK!(G&|=o9FJ z>cC`4&Yi`3BUy&h9TBnb2&(QQKs)=kKT`1%CU@*$xHF9qYRWpJ(^YZJrN%lmlh$;0!_q&!dsiWB*qe+w7gbPT1yb~Kz@Ovs7$HT-;nA4>V^m zW+elK+$HhFlCen1*0NYmalXnSJTJ3J5@@0C4r4xIL}nnkis9Dqq2#ZTxL>3xdxOIi zZSE%(#C`roeyP`(QVr;Js@~J5@2mon>%v%R9ifrHq#(=w7emel2f3ABXZt}4p|{>n zYCs~Sf-U4}1>VhP?QloWZY{cZDx^EgRnFbA7^5TPy>Dg4qP-X}_kTqfYQ);c=x5Bj zq*4YEzyyibL;_rH#}}42Sdd3=nCCCR%#V0yiG;?-rwDR@(;-tt(b}8|PBpr;*Ygi} z%zX4|$P~$(j9Ub~at`wM?yFiFf!|nUcs~WYko>V0?z0`5w!Ma)t+Q|1Ba==uN*;e< zQIQ6-C+yg+#X2>wLXN!cF-@I8ENS%NKCxHa9Q)YCEUqmE4{NC#lhhioouF36fXq~7 z{B61`JiLRwFn4*%7(vG^@$tF;lw8jD+;`aPgX%cM+aEyZr5sFMZGFbpp(QrY`O ziGXyM;=)QfOE|OIeZ#YU4?%yEkjcH9;D!8b`j}uGWs$igf~I7ZsNp+wqFTe}Xe)u{ z)4#6n>~ek2-0%*tpS-gP#ZfJ^P?1dU$~2?K37E30gw`{!>&qzNxt{AA?hY?_C?)Uk z#@_n;)Mmj+xiy8buolSZ5YNp&9Za{YvC9y-_tKyi`!A~$+J92?ZvM6b7vX+w*iZva z-~Bu@D_ap~9*`Sy!mK8ZKcN${_)k^KyD#ptSrB5VnRe_O!d!-gW z5QM4w%ympGalO*27tz6%$Xo3P@p&chIq;9nyw+_olP@x&>)e6DHCyrtRcVF*4&gaQ z{H`n|0DJ+?fZ@N+{;zqhhjm{giyTbZ5m$fc9eS>eH{1ES+(i3l$#%I)E7f|P{i!>? z>vZV-gOL}t)arR2vIX378p0mQKa4i8sz#dUMS?^IS9Wo`_FE!BRZQ7li~}|?j<`Dn zQQsJUQHhu7ZDKbBt8FjKt^jda^%RB;(p0DAZ;H6nwrS#Ya<0tCD3IA1qZ}0?5nw2S zq%#0sGEEr@*9TBv4a%%bIX7Aqn&Mm@t1&q?Dym+RTw7BuqQZl){6X!P$qP<0lAXWK zWfHlK+(PLi$KkT@rH9gR{s9*t>}}h8J$w7?$QXKGkX(}lD$qN&Ed;!9F|0f=?t8%#p6CTLo9ORvZ$-9 zi|AJj99Ayk3^>&cLW#0WP@eFb0tstrQdY1nZ=Sc1|KI*v%VQ%_Up)-jD$c%o9C8gT z9&w<&P13c-p20qdhFdtz=7DX_wI;7egY8U zHE~a`-k)DHYRb6GTNC{}=yVtiuzR|lAFb`AG1I#WLj1(*W@wO~0G+^Mp0w%Pxk{jp z7#vlabw`dNa(VQ)AOy%i54k6}JEzM;ENrN7RmvqVqUbDS1>syxijzARHd z(AS~xN3M4}>Csy-cizx^SMNUJiAl^ak#K!_M5%0KV{%nXIE2>v?%BH-gn>WB{zyEX zV%5Xf4S1FAEo`qF% z%3>aIvSqHBdjKPwEVn+V$-ns}?8N~ydBk-<8LL{Ldc|(6B;M`m(rnMFe4lUZK*(}~ zg$9!m(fPHBKOt@P2aa9Nxs|LXSiF546IOkw@(ZQDGkhBnAA_+tF1a)_sumRoTT6Ss z4j~U!uvH}++8bQCTL_>{)?7!y=vhBKou6EpxO&!NC*FbRgs#5VHS5?CEZ>4n`{k~& zn=Z}QngT3(Y2yUb=+LkRM-H)4R4LF8yW(+EM`C!*)O$mycPedE424PfH>~mM%4`%vV@|ivj2&aA|jmq9n9PtA$f`*ffq?Zm)-rvfgcd@DZFt;Nm=@lX9r`ArM5RW^u_A1;N{BJ39ieh5ycKm z-l|s}x|1{3TOTvPFwbT~jI{0?WCPgAbK(16ti{dYR6%n5l)s24(3>{LqDR7<2duC* z8^=Z)+dwy>obKzpp93(%wV*IZI*`u;aa|F>JZ_`IG1OXfc4v3?ClsG>G1GWciU?0^ z!t4E;Ze(T&BgqQ)o*i(+voP=sZxrK^;WU;qElUYTaKWpw+;>fOQ=|=6Pc2&&@ zBTcdepRywo{6)a}GE5p{M$VEn?;TSFjVad7@bOkOAdhW>ZZ|S-cgbD^;_njWvaZg= zL*W!*qkiq^SGBEa_G6f*+PqJ&9ixgafoM@@H;(W|PRL}uez=WVMj{?$_0VGWg`ygx znYHk%f8NXXEw8#IFJo$#b{$;Z<(j=5H>LaJ|C7@quI9nZr%(GGJ$) zF!Vwrb>g=CSSYnXT_8mU0BBUtgK6XH_0{5U*HOeRQfXRxte)U-v#;Y9#L^U-<2Kq@ z&_@(j^aHoW(*dossYudOeG5}-ik?(rjXBXQ)ZjzC0C9yAeSPDu8}HJtVgNdXaJ^%M z1I|wc=W0gP$@6j@$lt6sESM-3#>(#J2q%B7fySs$sgivo#S2=)M6fdzkg$JjN%3n} zE=!|8xOlkIVCT1Qd=tyuv^*=yYopp1Up9Mf7n8FH9n2}~rxq(wPST+UP4who z0RJyECC##1#m@!Yv4pGub$O&tPo@P@JvM8x%i77I!HT@=6YEr=ryQzZ<`6@(J?Hbb z%D%b&;t%+UxmuY6vQ^FKE+N%z0g~haj3{>$OFK`~>|Q&g-Ktp##)w3OzO~E03dyX2 z)}=u?C-rAn8u#J24yG7%pS2|OVoY*it(m`?@)DVOu}xT9Z)M}=%n z1Y*Jh=z-EH%39?vHLUWHz>E1yYQf_ku6%H!0MBZIAf~FAoeF z*L&0^T8V8TGc&wsbfip$FIRZ-(3*ljy5BD2f}@{p9haGqZ{w`KRE^*4H+ATTwq|VO zLTP#$qX9J%Y38FeHs82Cfs|6|A^A0oxq;5fmCF;SrM6Gkl{BGCJ?6bC6$Miq8I(Jl zaRC3cPS1y%UvLn*hgEzp0ShkL5_l?Bz$efWcPv8g!gK!RX4>vQV;ab>j8fEwkxS~x z-e`vI0p1J^sSQVBonveO^|S#f!>{B9hXsj=eeRR7+GZE^9FD^o0#9LH-)aBwL#A)} z-DVoK<%2SvRKuX*hgp(zBIE}mZ*A{zYYRuVM>j)`;(yHdn2Tj4J)CjI$LCLczB?p* zl}3mLC^*n;Y=AlnJ{43MN6Qoen?k9J;&D+Qc!fd%l&;c49i1b-THPU#oma;%({k(_ z-e&EqvCQ*_ZBlVZK6JQL;d6LC0D_lb*wM|aUOLcEKbNtFH|H zruFCc0=4?9lm+64dTM3}@aPiD!bdlG-ec*R7^z{q=N=*=KE09un3~%N3OT4It`Of+ z1g^<;>v?lyytjzdDnE$fjMGDyL=V(Pqjc}E zY}-uIsrTV}mrrYpYOAf5Z3AEtCOS1<>?3|!%v&ws#jz`DYOlku<3SZ1^Yt|a&&)$G zDJ6GnFindbxB(VAYd-kRiAqQ z^g%?0FHkg`Rupx8ZvSeF358>AHT6m=S^&LamJuZ^L))zZVHpM+CD@5xvIU-QA>cjW z?`&Gg8Sniwk}P|84f8<~H|uei8foNnFYC*A>lt+ZeY+TdBvVEj&UV`=tXMX?0N8@B zUbqbP=5%R@QCN4%on?F!cMC3SHt7?&0Kt86HBgTJCB-aF5#f$Fa|z12q?M0=tpVXaHK5 z%U~k*x*ra$fl<;%&a#x8$>j&&HzhWq8Ki+2XMHVS{JhI znOD@(P5!FPqtC^kze3@!##ORZyBN;bAK_dMEMAe0orMk? z6I-0*x{fnuHmjwf8kJQ2h{_M5m9{k%5&Jdi3n7zs+p{|Qzvh8kWOOmAdiQ>pcjHJcKN-d&4U(yLx9L$?m0C z6mT<{O3}`ncwKn6E};+_rx(kda{O1y|J2(zx*K0Q9bj{{owR31u+r*$&p^4F!_x`n z_yv@I>{>F(a=q@C0qJ{Og)fThIf;`8#zd z0V%J?(*-Z?+yc<^YLpJ#^vkfo6I6aDgyV`-3doqkq-HWk8~=Jwb&G{}RUkElRktcN zz!{#pg8omGD?8)s)K9Xo$~oTr)m*PY0xG0iM?57?!_X4YRI~`dH-wEkB0^j$c%&R^ zN5+B`T`E4&O+T-lU*-?iT)lkt1uyAXlLq0PIE1^RNc(FiCrLtXd5=V4sZ%mT>DNwX z-vXEdhKcy++~oDofxW1*<)|z^#QI)obG>S@Q!&LNnf!5a3!@yU*i&)Y$4PMixrYY~}oI)6dbB05F@@Zt@bw4vALIXD()-1uc_h1JSRt z0ig)vPuI|79Mmh~wFVGr>QnRC=YdIYScsl_@NnRMhExKcCK>v0D%jhr{v%qex6T(P^JwjbtV-{QwE zHW&f!&~q@DM+)OGQfioq=08g0SB57Ans-Wz2!(wvBX~)q!HSxhUPL5U2?~fXm#Q}I z>H!@-r2-E1oLHBgLH0}kM2<>f*<^+-7+bJY$$BVl>q_Ja4vAY7?nds3wmq}hLhobX z&;IOU)`PpX`-pH6$x&x+-V6IcfF-|lxl%!-=J4PYVk=UOu%XbuX;kL? zNx9i-ydq8GH*{7#PH1wz5CR6s%RVnGNRha(OeS>cVKhocg==vL=XaoD4`B3pl5zYl zUn|r__G-Jn9ex*0BOTPN%P51THbqVTxj3mAUy$u7@ZuHM1dKzK<*sXUv+WCxYTSf(mvUj9Nz!#A@?BAO>4~ zHt)~(ZtVQ19fW{yTnE$xLftrt6Ks82?nilpQ( z=}Gi8=}7`cdc=}P22dI$sCkrXFKFVo*{35W2W1(#!R5c$0h!75!Vq_ zr9QD=+XpeEl^o>o?xnv~E-L!&SWLLs0~}3(bp)LAjm+!+gYc+1p@Rls;A8aOVQR)D z70}-vqy)YC^a-wfh;5X zbJZv9z3`6wJ;QFbKpX(@l|4^RbX0=4HVzIeGZ+b{0R0P>P%Hq@wFsG0zux(Tw z3AYM*RM+pD+Zq}OH@~BqfP{2gHVB(*qV-kmI(yL%6);|O)nXw_O&>*-bqrX&YJ{5o zs1|VeiZDM!YQ~^?n*YcgAgATUFTA~!xS<<`@*{aZ)?Z@>mEq%eZ0m7IPXc1aj66o{ zh^KpUP4#DvLH?l6YnycT$tkK%!^z@SrtdUbKEpleE8h^qP6`HE@GEAXjX;sjgEoVU zJy}983Ku4<6<~i7>ip)~UL`-Y+~a@oZyZjY?8PJF4@uE}kCJj@dixPfg4lBf>2`^6 zw=tnKz{A)6G3lxANTOZCoxG-Zi`3w-poVs)pGlQLOb8Kwo_v9Vo&+bNzRmKEKB1S( z-wVd{9yiP=DXvF>^w$4;JoAMO8`OtAZ`$5w@ruy9q`GyVjAL@XsIu3tH^7`RCD3&e z%uQTJqrz%bcqN$e3djx38$j`jN36O+Y_zFDyjBfTHz^=nkR7=9Z`VVMjFNaA|{jn3bu89qfYdBw( zDuPXpNo*4Up+n}TM$SNj`feOfPnL2LzY&-PpC5+#0c&k4OMSp$uvCU$n@t<-!1eZ@ z;ovq^Lu7=pLc{2urJAZw3aUa|ty8~2s%Td+R>H#G_l6_soxCTBz#X~k?BCs`bW_dU zM9&}7VL9suwkO4{QvLeG&hAC79*5T*ih7RYtPZEA^iui5Kpl}J7o_x{lMtpqdrdR_ zS}X#Z`?Ip41;z4BCY&~mBZu>ptZh_T-)`iA{8u&ifCGb1qZSTjbt*Y4-b%XhLz#ZX zz|0Q7f0rm@C56OlP1w##wI8Zcr`&3?scK!fI76)sn&!}l5E|JL?ZyH+n~K7S`RgEDc=Pr!1Y3PRT=6Y+iA11~UT*|~IOjSZCA$qvW$AO67 zI8O{p5BP>>rNqQ3|1D<*>EtmuNB(ltbT(`u4EgO1!*^~{g`huOUYxJ!v5J&*F!3)k z92lGB6s<8a7E95kv#Zej|0>1MYqr9985JtQ)Sk8Aj$t%nK-`LluKC16jxxlI?>4ag z;xB&Vo3XW0^?;nZ%v+R=JgsWf0a+mvo3&>595aniQy`e(joeib~r+l&Ejl7(--{*8ri7@i*Iw8a7LtoWQOogK@bgl{$#P?~)QL7^b$a)q z%bM)!)3)EPJ-2Wr%p_d;mISWf+zKx%JE8yCR)_9cLUq~OCULd~hO_QC42O4@Ots6u zFBmF)B$E>(4muF@gY1>NGm`A1;x{C;q9sn^&pR0nda8S$j8s~D56If((fD#4A%D#M zf0(p=pai3bfDadJ0@ltWUKsiUJUbmpx^G<47Q@Y^ExRec^v> zcMzkB^=7})_dsBT)hLHWzxU3-pp_#Nj*6L*$7^x6|FH}ejKr=2OBl?4gNcN{!so&l zN_9rCJe*v%qvqAPy8tw9wbh#09Y@v1$T=3|9v5peLb?LAp;j)Izp|5nB(I zzyQ|rZWDfVD$o5nM9KdeF_P087X*JIK0hqj8y1Q2fYx-N2P0i9FNCS0E zAM2c*v<2W)l8;qbpHMj1XJ7Ju>?=t4jeO*#I>JJPr5Oi1OtrkNZE9+*eE$@jOsT!X zCqw`RA>G<{_zDPE7v5;_VIdrm7C2-K7IttEfmGAMadB!}pJq9fj$DK(IIK_}hce$c z6k1@FA0DQO?)tB{gs7odH8}ccA~!=!qwyoFTE@q&7{B( zBj?j(HCTJ!&Ph}dJ7#xpj!ql`EW7%>$$QT@FrC*%?>&>%vW4IluQ+X~yE8U^0#>zO zqG#_tVX4jhmxA*p4QjvTNkZLfX?(n4cAU!uipz29ciYJBb5q@3>2852>^R_~Lb%4> zN}~rxbB(kf)EHd_2!h*3fQM4l@v+RIF9HoNR!W6R=i&%Lu=-{H;uvMQ(0`M9OswvG z)F>-&;>+fM7TB>B1jrpslbb4OEw^>DqMJvJ(2TNB4}O91vO`h@E)j3Pg3R<`@=-X= z`To=G8Oi$cc$TebJNin&&3R-^>2hUI4)QZB)XI@k#b;>L0 z$9834b}(!HVGSJhU?3oOIcm`ff2o#T_9+w3=#)=2!w&q0N!5x7BrsWmAZN^}+xUMv z1DlO^iO8aO4iXq6QT{;aLKX0;^q$Zd|B6giB)PPfc~=g&6`L;a`jf<;l`$}^LV9Yr z6{~NJg?=a`*>%KrWJbmf9}w$ILp6FJx%91bO5GN>y$Qo#pJz@MpJq?66&0xbl=*g! z4I23a$r1x_c*+WRj7<834>`H`oC%HN1h9uIE);qXO|_iEDhh${Jj1stE;)DqY}{WU zTBQ_joNK}~m8-Q&t$3HcW)!S)3r}XQ8-tCF6g-`n&>R+LB0iBIF!RglU-u-G(qprC z30ZL~FVWo%Gwdod{RdSPn4mWX)n@gzW6d#~&AZkG_iVtZ3)>duWu*Dq%qkqNEsU?i>8iT|bSvArnA($8X7jVH< zIh!RprwgwMq}PIi0uni}ax5$-BgWKn-9Wp^>rXC?JEl=mp2QFCYW>7e;^k+nk64Lb z4?W{03Icy3OihBi(Gt_Tws*F=R+3+anbT+!C1Q8wGfflWB2M2#yCY?8#Si5V;Cyo@ z$Ikc8{e!4?QCD4;VwjY7Cz8%rb8G>Nxi^9?pU3x>da67&k^7lCPgE1H6mP1Z999`$ zL8DkUTf(Vq{8JM-oE@RT!&xK|-MyUb!LpxfDbLT@f^|a_osS;}0U|dGI+RYFlA< zq1#2bsd&j;HZg~M2Q-nEuCy|JnXu<4XpS2Wq@&bVh%cM7o!@Ew{~AXrZIds*#8u>e zf7j)d{ISOO3r~hA9;B8_e<2xTI#1`s@=pwe*@qhD4+?#2f&@Ko{`eDPrDZr7t%V{+ z)j2uCShu;JR0S#EY%&}j6!9>6YWKX^qs`7oz4sTswmM}7{M>2^jq}r zdo7geWrOAo-83sZ4dZeXN$j_G3jS?JSf{noYA*Vj_ra~*xU=t>+-8ij_M=ERyr(&a z8aPBES-%~~@_D+Wb5~*A!aNi>x1w>{^TLw_W{#%C%+V_wL>B-YB%AfCDyPFtC#hjL z*Q5X}Z?Y_xI9c;`g*rSEaI;VPDQT0b64K~VQ&cG6OxZIkL7{rD3cI2uptbQ<+9^%5 zJ6+k(vxyS5>{4tY@SH!*Zs^F#Xhx9NMSCj3ZoyTR%GsMM5o+Z0 zPROMjUJQO)A8CrAWEvoMYxwui1)>*7#O0;tIVHv9GoS(yphb+FQQRn0)%6CEU-^vG zOCVShaKH9X@uZqClayy}#glQ2!kB?25tzhT@03%nPp=2RRLmvr+#!S$#AEWZ<{)g} zCD5{J8cr$?T^E&cFAwVL=AG&>$y%8&c94szd1O#3FQ54%7zeJD%OZsK{KqBj4NEK; zyIZZVAMf4rX{SIQ@3O}hc#kt9t&wtw>{C@u!6dg^WD3KIt&4yYRXZ6de?`uqv4_ao zgH#6MRThTX|H4a%)5FL|Jt7OCR``Upof7KMO9N(uvPqlMu|3!vKZ&VQ1Y8LpcN^N| zHf*I^{du>P?^=N{CFityGnI15mgYuyZV0k=fQZX<+UWQ<(|~ekL&S?^^54o`IS?zG zyNnUabrNOa!J~gVEBG%;MgN_lGpjn`PZ<~v2H+a4_X{(L9QCP-b zo~iPP<4&d$9Sjzjs2KbFef?`H&pz>HWyojvbo0>t<($Lw2r2MH@APmWI}FZ5Ard0T zy;WAX?5=`b|56SJEOuW)lm?xMt>G$5!8p`VoyM1{F zOBLQC(opFdr4HunZ8vJlpRsD^QirR$Sdryj$;5>T1Jd}17-Xh+F{ z+M6b;b5iQXkc>m*k-r)7OAr`&l?%}1`?1ED|)2Jgdn#)a3sq~mxi}$X=iKrK8 ztDW=FoVg*~^(MF2u2Z|!m9 ziZ=$@3xB<4&5i8OA<*nkK@`vAOKF0%As z$skSFOZOdQ*o6CeXRJ!vR?oV@X~$zwyBcySxRCE6k>!$qPN}gyi#8?--4MrsrK+^< ztCI2s`by=GhTSNwl5q;rlX^G=h(s>%o|LRU5^6=B8Bc#qQZQvr7$A#Kq|akd4ko&0{U4^LrOyuD{~UT@*XPD zf)#x`<%JI6{qXg`J|Mf_(#49RUO=dw%O2uzwqqfnJh#rY^(ywJGd`D{_~Nd@R53NT zulYExikTzS!ok|?5`ya3-$NsF4AJGX-#OxcS!sxfZ=dYzay*#Kv0OolJ*H4V^ucH& z)2K}8{PO3<^R+sG?)F_ZuSiXAgwyB$6UMWp_^uhQ+FdbS|PUX#4G+nCaT2S1B?nc9Szjo2I)ht}dwZ+JttD zEv_x5s-S290_zoVA*krlP__+lJ>e}dD%tNxc50$mmA=(19(HsD1;d;5&_iB6_MS%) z2}0JwmGi|0&EeEktABm}eUqx}GXRs_pqbOWk120rWq`m!t@QT7!%>8IFVII>8PA)Z zd?1r;bR7<^IYTuI-bUU+QXL4k3bsKNjG)JDv!K;Q3)>EB)2E>j^cma-5?Wh}3!o%t z;04qy;sTIZ&;)GW@Pq$~I;(&7rO~98c?R`0f&HT{3TJ3l=273<-G5*kDE^UrJz&B# z1yRdftiJipTx9`Hu4AxoI@!p*!#n6UsESl4fAT-W*j;eKtkDDxrl3QHq@y~KvtZJ- zBs9U)q%N_4Wrn*jKO5Z`$@kA8AJayK2#L%4$T?ZNvgTL*F;k7)x8w-GqA8>CLw&fS zK^tZByjcXE7*4H_mrdl z8wc7WTl&3H1o0@UbW!O3>}f))sU>^YMEu^^YBB9*Gq{n+{<0^7<2F}JP`s+~skrDb z?gOyl1{-wPrjku9V{Ba@TGCI!j1YCH{^E%dUQ->xOlsQkIIx=dtY)NpxGV;c-gzp4 z!tX9et_~Oj<1&;)sf0=TU2IvWYca8FuKA2~Ne+WVD zPPNe%BVw)Is~xHg64Z2n!pyMZ^BQ*LC}DNZx^2%ucLi*mivtds@vIhnWWN1!z^8E8nzS; zR*urIS~wW+xyH~8mDLd9cvp|pGMBC-8%IRhnCP^aewg?>Juwj#yk<{=DayO}XT5}Z z^<--so)^=Ka&Pyt_K*|#^In;pG_f(7$F$ucOUU#TgHel~^ne8lFqMePi9|3_>3?s` ztE+6ySMZWj7~_xi|7+G3xz^Ui;z>d?K<`0%=?13VDV5yD>kDYf8zu0tMbJ(9r1^r> zw;$H!e5+b;MpPmvM?vt@?1|4D9FMRr_)`7Mm1)9J(d8GhAMys*aQVosWWxl6^MNd* z{*1?C{>47yHS3`wahF^ugQBs)G{o3zb*C546)kj{x0)&ZbG@4OLt0>#iuWxzG~MUq z4(i5;2-w!4WwmUMncLzpz>Hb9sg<9fLPxY2+OOPa%k&{d)o#LZE%1eiZK|?M05>fI zkI@QI3qVv^=bonx_jS4bEqgX4XQiT8($@?fFm1&n`~(wR38Wl1H=^&F9MQC8Esy_6 zx=RO7h;or5C>$I={-d_W!B8R%8YQ7R)z$wYUmr9Ph9^Cwqpd9-Di=j};FCNn zWHfTr=&Yd@*)Q;4x8_RI4WjjdXk^`C^~FbMzfE|v&9|6A)A>61>LI-AYn3U=AJ)&s z0dM&tDGKQ~fF;$@Lg5_>wHrYZ-^<5TRDsBt=g|=t?wLk`aTHq9t9)>-9D}o`E?TJM zn8O)}c`S_1U8FX+z$M)(7=Gj=u2K=j)Q$mm>mYa&_F z4sJ10Mek{%UJO6svOt-?A`6@yZ^}mcy7m$9yL3$|L6L+|q6{A{On(&eVSm#L$s|l-<$EWb*0N`!6BG z`K@p_u{rqzK9|;gcK1oC8@5KJ9I0_F#o-|>#9GO&`M#@HbA9?8O1XoJ|2I0Cqcd+` z>=wfk9ug(I?zu^7Cujp-tZ)$}t`y)HNOc8#&UBS1nIKFM7|Yc99&Z~Y%>o>pu3FBa zBpCY9n$~mRjFZfyWjZLsBYM4j-MOi%KE;FOc|V}u8mrHDllN!Wux7QJM(~|TO*OMp zO*V)urE{@esthR@Bt~uYJ5Tja%JYB*;Z77ajCfR4WtQ7mR&jcK8D?6?Ej0H`hk7p& zxj-)93|9^9>s+rut#Oiq&+v8JKy(~z`z*4Ky5wYg5F&9cQ6@l&<-}7;t|`;LP@N_h zr;H)na-QXI&=G@aw;1rV26PEFtmNILO6nBLE-kzl;Co(MR1-W&I}OiFm+Pa;;r`a^ z8R8}1zvQpLmt7u~*m(eYp?yB!50uTB`~8wFAxeDob&!Lwsh^v_d2Q6%y}%5De3|Y! zmhJ9MDS}vWe}+<}Fgq#m1kKEG*cvZ*J@r}!j4X|T^zL_>FnBBk|tX4${%tv zJqI|D!p8N=BN|1}3V@RJh!Qr<3JKTy9<)5DtRAX&?eedAP1$PS6eDm=jtm z`-&eda-oVYeUYKGV4gu3&6ujM{JQj|{hi`19)i24ge@Z1C*B+i1ujj)KGZLjFI%=2 zcw1q*&N>2QYwB4Hk5AQf)dh*9634kwzgsz(IXV=y@Hz_;KIN&5f4_+_z|B-%)y+TO z+#Hzl9gf=)t>EnExcMiAC8&AVPGB7AA{}Cd>n0nzclA2Oko%7R5PoOFeKq3zh565o zg-`fmx|GrkTHL$i+TFB9#17|Sfu^lBe@66##AO&1>Mw;-9;j|Z zn^eP-80wbxo-x-qtOr0Csg+}zlCF3CkQvXB&E&N5$UH zb(R|3{#Kxj^pR9}Z3`IGO=zu6G`F*lv7rvAJ|Y$8y@E|2+(r>E zB>IY!wNeymG)Wv40y{l?GTOHc7Ck1`w=lnUkUu<;jy0JFc~;i`qf-Z*@#C2r5&kPs z>2HJCdpU*o8rQ}f7yC9!nSj89@3d2e$nh^UjFO-8KqWiVD;vxXHX<+28vUaN>^Y`M z0jwgc0`jXB5N>EEM)^YIu|JhRzb=F?Ob-EHB1#vUK8GSsw>heuQ!w%I(9VY)@Y??% zjte_8LI4+%>>kOEHPFd9je%QR-cjbXVcDzszq1DIF@>@7`a*RoFan;iYmv`8kfHW` zRlO2(E83z5*xy-6dJcyhU-H1^0AD~>c{f$*Y3N%1)=?la*K{erJt>Rzof{uyK<_gV zm2qCP@P%#Q33N&hl-=0dcwDKlayt!$TM%58y{(7$?7mLg2w(BXZfE@+E@i{YP0EX6 zjP&?P*@bZM-L57IND)1lCOR5V-w-aN1GAWL0|LEw_nWZF*^B?*aQ0`mQB=<^hLl{j{cwg{1FBcrg-MMfGtG^pE9T zIget8F*j}YMILY$D)VK-4v93M9lUd?_|{b*2esE4gE()qGfar!K%(aCE4E7s)TK`q z$1)7+%EHFT9ct)w>t|ayQJ!JuH@Kg?1I6bEKeM)tnLRyc&kmsqSzA4>4As^U0R1>8 z;i6J2szG{UTGm^n(Ar39s3Z&*3dzr54ng_%i^8Zv;;Ye5yh zvXVDQYR9P|Ihfk!iTon6@(?cP$c&F;JKVJUKA@Auq=1UbEa09D22dztv$@Q%jZ~V2 zo++wbCpC!ZIg5E&x5D2oZ*$O=>l@H_U6n56+M44Xgr|d<#6J4nEU>7|Dp{nG!NJ65T^ zCjCSdkmh-sr#QW5z#Eu+oZL6%hU|r}SYbMkE8-A_4zL-$*O@1)7J(@ojGaJgsY~_q z>NPVVaVBE(xv2z*P@NGzjjd+X zdQQ9(IpiYjhp6*}i||XzCQ-NaBy)tPUt@2wdElRcIcv_EU=6@b-fi`7gt={-7CYfj zL7h(u1*h)s-ugR6PGE(|KGtFeijkK9wkE=sPL_|+)wGh!Wkj?lfso1)(|yI{hxV4P z3^(_CKHg!Z%!0Bc;?)05oOX2?Ee)~+-4~ZX#X%|*`!(9P!eE~*zpO?0iG(2pIwSs1 z?Ei6%T5?F3|Dpaqu}L=epXD)03u7!_@fqM80@0pUyyc1^G3r|Wp-C2T0*@5-YwV~R6>QvUa07_`Mv^P^8ANs-G92>7+Yb5`P{j^;MhPd)# z?T6%cDriId-VxvOB?Ra+kW2Lk7%yxzw5ptwjtDu*OV!ai4uN3Y76CV_R7ctU9TPXB zFviLjT)v-q7iPD?X`{pyi(pI0R$Xl>i_fvo0!**`i#scQLF_*GDA`Eq$-(DVF067Z$O5=D+tN_t001l68-?n6f5Ar zE6&`85MVh^5}lAyr;Yov_cIKItG9*P6fZNUIl~#XjQpY;2{%J<(Us?=&L;^yoPf}< zGSsoGbhSP&S2Y%~!b@e$n~MKk8pdaE{o9#uC6ugeP~0A%eSTF}7X;BH=6sO+<}gM@ zz}<<~>@vj+;daq;qd)hkFyCYK>uic&qfS}JyLC3Em`~*rhCYNctC(NMV)vx42P(M`ZX%K8%~I>C1gmI9G8- zS`IAnK3HiJ9?gF!Q>EZOzC~Q`E4i~s81O~V5whZLaf5@? zkPry{_ho)EY(zCb)t6;YF@6Rn{tWw6ZflXa`rnrctdtfx4o=8R(z$W(Mf!02hBK`u zjm`1_OeVXnKcRd;%F2MK!PFcVd*;hnhFLYWxaQ~MF`P)3=9HY28?WjYGMEVuPBP#8 zxNB&+TgFZ_1KH5&PP>u7d(*{()TPZPXx1lA%f?ng5&$^zfzfm&E7Gwki3MjkAj&xX zSqvOJRt~2b7yc?o_Jz1@A+Y6ARvyA=ke$A8yZJkmwu60IKY#=%ADW{^zRM!0I&u_EE910rUP5+!<|j0$fH9R+a4$EQ30}Y zxKJ4R-1rn=O`^Y*z^Tc->vob}q8KvdlKX+o`7WecttTzKVZ0KCr2jr3)^11`ll%~E z^`V6s*rCg&s91xta?(p?Sx&GxmJHNDc!vczvIqS5cl>xwKPpVHg>j5VDxXniHp7^- zh;n}$S9zhpe5YQ>R>V*k3J*-(&;yx>JwK0jy2KYGObjA#juXUb=0N}Ip`=dD{UmOz z4Wu8MaYgA(BSM;lI}mKA>Zb&5&(7tV7&1TWXp2FDuYYA)Pl5X$FJWb2F>Fu!y&Q8w zUIIfHw>C(1GGISE7D5uiShGF>G03H**5S@?8qsi@^B!@lkhw=36j?gVsqyoVnvLK^ zMmWStRhR^XrJDw@;bq>)>D$LOxOR-|45=M;=FgFLQEXygS2}gJE^ihYkR3q6O5;PO z@(qXkD-89ByVu{K=#}Hqkf{Cr*I$DEGrkhos4Jt~J$$aQ@}bO|!8U)cDp!IPuCgD6cc%|L_MB zE=&laT;3O4ZaEXwfQVT6hYnBjQWnkNT=3gq5YG!pf{*Lm-Wg~Z2C z6pT(MesJU3HZP!s*9obg3n^SR=^Z;d^8rJNiws0A#f?@oyv|~{5eg1vCZA*rg`njz zZi{&OG$r)6AtgTGig-A7Oq~V3xx27W)0NjSDCR0^7DRb$d`6?M^CI9773tU!2Zfd( zRji8TQ06fIMX@T$lHu5%`Guy9{c3!fpID{>mEA8SugJ49RXX64@>G(={CRmwrc}S4 z0Ejwd(3nYiL^MV=i2_-P&RNpsw61IV^u#ncO$rHvzj%i%IiU3z}I~Is|NGGyNYugI6V1oKUrnVDxJcplKnHTH)62~ zhv$QOYTuQsBQDxg_!{MnDRkLY(uS<5W1KgEz#;2>doU5l1ujlrp+VDAsRm~AXW$ER zg{Z+_eCOQdu{nPw+-L|5K>7S46L{Pa!((Q1>jCJE&GK%?^kRFg$njspRR(1zucPky zjQI{$D)WHmi3&i>!mh@I5?AyE^=hbIW(hidu=)*7+)nFUS5upgx$LR}%u^j)5c~!pCAix0L+*iH|cJrKsgK#Q|EsU7TQC629 z>90#O#u}_ny5jXJc?>Hk;mO~{INQse7>Zr3R{5NP3_m?=aX}O(U&|U9sM7X z)^uA=rdp?im{ItlfK6(EWdxAHGzjY-n8{gv!SxPrDRFGaK#{}}_rclhWU&|(m) znKNVlL!yhB%?MBd-%&%g(E>{s;7)2=_71J^)9pKx3>67rfx12A+Tn-Zg2-p!qzIek_gt@m}e=#vd{hg$9J82M47>h^$1THL(_b3+Ypwn}@N^gE;pK`^IzK}bY z?$2=DDiAC!P_WrV!du#&R(ICK z#fgdWvPEmPTw+*`$sa$x(-XmP9d!lZNV@UN*P}4On}pR};>EQiXb7_TmeVYtTV(Mp zvPla+@+OyoeF`5!^ZSq-P2-dV9iX3DaNuqG#9{dEtl$#D>cC!f(asz43plxf19s)d z8Sz~PnVA-3C$>ohE&|R*ow)jn?G%ECO2z$RidnbfTC;VE;!Dr)mHybAP3W|skGr%y^u^`Fb1D zl`?UnB=w;8>BeY$P>7RcqFQNwOc*KfD8^eh7ul`Ic)lD9#t9nAm`;1da6crpz&iiZ zejJu)=LFTfDQj=erwLmTJS(<0)^A__9r(oz&%wuWDu6#2paCWVzygA5ERIkvDYgoX&{Z> zXFy1BJ|3EAwn3!wQoJa=?$SLO;mqunA(CWn{dPXZ0=ATr*9$YEdc7TtYUQN^sgx04SM)bIKlb6yq-xdCiXA zArMzvL8SfFk&a>_SKwgN1&R0_kD=kVqix)n6FfM#HyaqqYVC63V@*E38&91S-c|JL zVw;>_R(vOMRW@5KpcsCWv&jftXf)FV9bpUqdzf#&ny-IF8F%ClyDKkkR#SMon0h9PBp* zf6fOHB@n8o0KIgyPqBDG?w+xM?NlOV8mW_JB6e%J5MQ41#&k9rd(1n2O{`Xn7o?ai za~FjLtf4CM6-E1$KvC4B6Z?WV-4nv}e_W~S!-k78y{^I$jaA_`^}1ar&X zO~MIMr*6}lC;FnB8~^cYb4j9;55#|L6FRrYnRgz8BCs)^6Q_A6l@x~;v zbm7DIcAyjd=Y`MeuEb4EAHK4zzqP$@8bM#1WWKrqLFA>j>XQN_5%d$)iZda*@ zc~MlGV<;2N54<+GLN@SB!+%8!f#>-*KWTZ!`0y60TVGd@1_2=v1%;zS(?E!LHsH|Ovz@>I zl5HR$qaeCcfx~f)PUP?{5%uT<2A}o|@mU>%A()O{kbT}g!cW+C!Fg&F-8K%LNm!GP z|8Yz>;7@FBK~){LeTx}p$1>$a2U)1gx)T>e(mn8 zIIKA7$0^;00D7(MFaK7JCsE3e!Z{{^a;_GJy!@izz-ZY~a9lVej9Vm$T-dpIyW|a9_tOFBfi#$TQ{t_&uTo&DLsuo(?P4#{`j3u4%!?D zGLD;AybdCbimSZZU2t)T-U>SC^2TB)Min~(C6&)407mSwCky^d4jjbMTLge?#@%?Z z;OZB0^bsrb_MQ51BlO4((q<7~5*icw1lDVC5$fS-oCPoW@*`w!V4#kh<)78inVx_g z{8!8Sak|$LH0BRoq=Q1dtSp5{86Q1#-p7#s)BY0TpGHOgQ9B?Gd|jx1*NzcWl74nbw$~=%5uh|)`ff|tJ-bEnC;_W^3L?9F zF}TZy8>yHvs%Q2hlGHIS$m#kc&^t@R*6e&Cc&tD$D0*?vf3oDg)i$oCepl`i=^nrD zzpbH&-ZH~{xDbR)3048TRUD- zJZBZARJSJWeaH7%pEIWrs}*1M>NYyDt;S` zg(+ICKf5|{9JY0&&ueD3u$LDY9*fmm8Z5l0Tm4JPBwQ1Z^91QZx|~BgV^EMA;#vmQ zn}c#1Ju}xTghO0OIb&nR(8hozyiC@a z!+Oe=%XIc`W_@L6bqv>(K-|jfel;A3>Q0tcdKNzfJtce()WQn7P7(z^@Tvm*qmE(epR_0KeER>8A_h& zM3}KuPFLuy1T>$yTvqed9v#<8ujRHFTdEBVmD&fsDp1(_Q%(VZD=7Z+D|3i^_fTlZ zPtJDyvr=*xucIquY`G+PI+eX(9i1sMohZHhc`uW-9~dPa&m~TE%Rm*wsCkm;77P4c-h#Gq7XEzKP`+C0rwy7bfyMnvC77+KPoS)1oUo=ON)h9y=>;l0JQbeu~|va4Mr6?9PUD7k-)*-J|z`web}XL63&^0 z=Y7*CuUhbd^&A#9G9=EIb?l^%9G^t{8ObYK?|*$PoOc?*4JnhHCTrQ$GJEgy!0c5b zxn(HwOdTcyJ(tWstv+XAsz1`N5@fmwaIZ+mgsFIfN8^&*kUAGB_HT1Pix#lq0MO`6 z4*m`;<)cl{L~IAh?;G<>v*69RXf(^*lQ2c^{*Ykn<%t+nNiAA8kDwr zIL1|V(S*77y%b~cKvjUYwXenJ zYjY6h@o|0FXmdo)9N09f%0Uw&JW3lAt?Q27|0*!6Fi#?7kD0>gLqbP{xQ+m%NCd42 zVfk;PrV`)IEv`o(r#AftZeT<0dq}K-p^TPiTe7Dwf9qD~7zh7oC#pCNIsWD^bIGwa zW=i;HA{PfuZRde4aRl@4a1lFel`q*w{Px!e{=24s#pry>7cL5c5}&X!wBoIr82C}a@P+3dqwq!u>I0&j zVk1QprT>dkhMWn<)hW+M!X+x}?WQ&DVlDX;Rjx}8j{*#2M{DH`BO;|?E4MiU8Kfjd zl4}TR@PHj9v9joj!=-4r=GL@9Oo7P58$1M1{|PQ1g$>Q6F7uyjl$+AQ?nJHONRT0c zo9eD|))+TzRIQh|{)T{sRXD{Y@N(LoMdEAQ_=bLm5iF!ze>(9XI6+Hx#dpSsfNCqs zmi?4aO~47*VKZJnk^^qX2W^Wz=+Q85zTsaJvxPD>R&{lzUQOWhnsy^`FG%EkNWha| zV#TRtBsoV(JTBe4IK>*|YRw4eU-N?qHU!iD+FjD(#k zrP6@oYUXmgp8y8WoxCt!5OcZWo9U)}7Ou9$819HW z4nKPkpwTl`*7*&4E9r&r6EVmbFhxjlvM236N#~L-hkpGwY4$c$-9Fo8K;dm2nrF*P zXQHRT_l!|Ys*GbqpqRzqGL~~#yNIU5?C?%@@v#Mdj6$J8gJ-pqTy3=hk|((od@7^G zLxnr9;sZ*OE0()qVRFEdwz&Oo897Ac?fOqt_viGO2tO;z8>G5OYgpy|byV)iIlaKn zdLutLcsMH%AL6Gf!bagGdyxY#F-0o`U#D8IUM+u;yy^$fs2$38Rw_16>v!LKvPBR+ zuf}2|awT2-#z?Fp-xp5+zXHe@%8HfGcNJqD3nL#wWN;X=K4`3C1*?Q$p`_)OU&Ute zxd`G-#q0!^)tSr=Q-{RB?eVM&2pC|T#8py(#8TUS}Ik{ zXsw5r=N-~!(7P1C%yr--0X%0D9RqQ)oY3)=Tx(pv!$4$})icX+mt7WVkhN9{g#M70imyAua&GC0%}lKC zR@aQ(=CSpHpR2Vytq=hBTMha?-M^wU71qABp}j!KRZWp!bk0iBv-~(R>cMq_HmV{iYm1;5w*-)qL_O6=8lWH$X0ZYDzY^C$?tx zw`-<2J-6!Y`Q+pEE%Yev|BpTf;OTRHzG0g4Ci{qpkM&2LA|-l4@f$rJ{=|nOhvrw! zLsi^zV49n$)aXei0I@$-3IU2_eBX`(kF$$Y{-7mXjt)^WYhX5oo%mx+UXOuDmhpp} zy30{tTn?c~p-}Tpb|b^S{?UJ;Y0~$y5+mz~4BaS`X@&8v(^k^@IQtOb+(`7V- z-a01;(r1#af}G6$C;aKk11zl^?djl#; zBDLPxM->AXN}bv5jwgfSk)grhO@%GcH~-VZIhNyK_c8S49z$_HgGbU)LtO9Jtj;mn zvK)=+&6`!xCwP~jUHqsys)3>sC594P1;_+EYZX1Ca+i`swrK|XZnY05HHRWKja5bw z5KQ@w*Q!^3SWsS&mo>M_W)lCX*IQfRUTe3)Ea{cvs&*{AKeehc$jRp)Xi#kmbq02` z8Q#EBlL5VQlqU1ywS%xgB-gwcD&SfsUngCB?lI|(6q?Ov^-CH>y)|?Au#S`0cYuK4 zb!F^`86xQIn?79A1EmeERddat1K9lg%CxZm?Bi-Lx*bHhCo+C2(@93!MU~Fz9JUqR zs=AVnDz<#p_I1W$3t%LtQ#rYwHGN53fX{rUH7VYI@AgMNI0v}LBQuq$O!#-F;A(_n zyqq2qTQc41rl6k%@Ewl^!rY4lo08t>2556;Bq9<1q~>_Zp%(N=C{*@2@Z@%-fz4-> zeU)UW4yD_PA_yFN_e=Q6`w8ji&7r?X|%QNgh!8Dtz@ zcDSa$cj_l8GickkeU~rJ%eTWO7H0d4Djht5B#P=W2G>uR09?$F+fK1>_%Y*AQ61`!x#xWC!caK2><@y=v*=RS`M7AQw)XdoXhutSqTI~o z25f0FqRRES^r-bv9-Cq-TZsQq zWY*=2Pf7=Q(Z?WD-`F1eSWS(MVSvA$OTd(YpGAN*1_twA5>GQpwqx{py* zR|pmWO$M4hv>-SP;n|;(nWo)>+$D0ga!ejU#&P_9br3n0zFPV{Esrjjl@N<>Gp8V> z$p5G%=_GK-J1jy*_c8un(9sD!^)SqZrbA}sGk>D97N(dM(!=C=5MLkJSB4OFWt9Is z*d6p@ctp-6qp=P4QA4o9HM|n@JRpn)jL4E1X8HCfzgTy%cVg{7yiCp?7vdEhzP8k; zbv-6qCM(jbhGe?z5-3@PT+h4lWMjCM8{x7H7QMRgvLJJbFwv>g5IlpW;xn!n8Lb+x z>!*C#3+Q|fWs0Kx4^C^m?|k0UZJ(-Xl*9qiq&S4G4OwUy#M0i-g(Bjogw>Q8cohd- zwQXbmv*8Gc(kVZtU|p1G%npB;><&DN6O4FjA;y<><~ozokW4iOI;5LnQNKaC zqYADrGc*Zg@b1(nk!UX7xwzI}k-k;Hki#DV_>)kg5h~u_v+2>@G-J0Xoar6U zO5~!N(glK|PTKa%0Q*Je(>fKg8!=1rd3F1=V==fnMKQ6Rd~g=?lW}k-9dbQh=oS_6 z&SMg)^Y!@2TrSgQp8&$rMP`i2egObDVMoRfav?V-OEM(x^&?=OU7~;=>TpZS5**ls~s#m&!JrhkDJA!u` zd_VS?2~#1Qyju?R2?4($)YM~gYLk?}8uOA2ckc0YhY#cv^QnJmZ1)6Rx1`8ar+?BT z!>XjM^+?{BGsNy`AoqM+#}_z%Oq-;Fqt1S8#26c0!avgoxn`*OuE?Vs zn)MPYv0TG4yt`6#PxY`b#uR24ICIm2;{*mNm}WBc6XN)MPg71u8} zO^In4-gXoNR0<~Y)IU?iOu+xA1PH~*CW8(9`x?~?`e0u&5o4ZBV8QEW>aTkqid^lK z+5BWxai!&q4hAI80)`+Wu+Ri6qXVj(Sg)!!{^2_$djWg8e{@dKru?K0+T(t zmLctTXrM9mSw~xxAxp95ceg&p$^LN<4If=YnxiF-JJAKQKS-9IKq4Ng#^?#mQeWpr7OZrNIH(Idr)$XrX4|E33v8fVnG zivaoS`4N-4$)$7$$OT_4DGGqlHLH3}iDV+_c!6n&6lMYhfXJXP`=H4r3tMclI2 zMp}h-@`CU~J4`ybBKyt%1p&pg-}V7X*H9UL@X!MM8lJSf0~&Dk=^2|mbphbD+OHRV#xWC-&6k+2Ic&$5^m6qx>vN4I|)HQRxgqNm>l+OK0$i zh`??TKc3bB9v950xQJf_R4ng;L-6)?k)$khytWV-ha;1RG+NEw)E$hD&&mUA!@f`E6O)OUcqbr?WJHzhi2Xao$8IN` z3wt1}EXYA7CKzn3_lG_-la68S{lMO-pKe)#l@u8L=i#CJa7rMt4h z4z=Q&u2pMn5g||wYA-2hWkMB0ywi*!Yayq7nt%E}4YMX))}#V6VITa&SPNnv|4OJG zucbYz-vell-&$4jWfZAsq(!{v#gYOSQLDD=+;d*!1knkizf8^@Uwyihm~_bH`TWdxcjq&w zY0YBY!R~1q33%bHy8_ZR^!j`z7;`;adLmU=$RGd?1o8-Mb?GAhDz6pqU~QS_eZJsQ zTTM3~VLu+uZ5A>I7$y1^{p2C`{_}-QXXZegxm8l+0s9iUSiz5ccX+2UZ$p%n)kH8L z!aX7rS)0qlhnqIIu4~~PvDrI<)`Whi3jgoeT&0vH24RUp)X#LIthNIahm6u^lx@N{ zDMxrR(3(QNBMV5dBmW;8^c`uW0`$oxwSBkqhTWeOc>#@LPiE;Llp{hHJcjsFbn++m z&;}iJzPn<-cPP8%QW(9!(`&IJ?3dONJ%=ra9=1=xBq?v*Fd2q@%MTebVM!fPM=EL@ znojSxvf>ObDD9$V*hv{G*BN>MuD@rk9OVNgoE`r&zhYGSG<}Qo*{G~1EN^tL(WL^! zOPzSMa^JMWT@u|kosVh&zaIonp&{ACEHK5AFEN{lk=T0%ERmkQbA&vas+ou#sDBPd zx@uA~-tcNqfIx~_{r*qJfY#?;JHSm2xIb0DvXA>E75g zal=|Bc4mMdL=%n3>8{I_?V4%x4YOy)q(3X2TT}B1AcS_l2>}4}hg%QD)3ek991a)? z!bs2!NklCl3{g z|4n9{Vl;vm)8CMs(7Af#*n5?YGnNp}SqzObxV;qy>l+~F`GA<~iIvI>q8I*KDc=kB z2c6ls{z63*DoeIq#5z>kdHXZBgs4M`L(bqA^ztFLQmtHKnRgk^vitrS{XY2vU${G) zD}fOG`kD~qH~FvhQR*2taT|Hj-d%Ws^au{iU{hzAsjf$^T%OWB1qpd+cf!2R2~T+p2mHrfrbF2Ba$mt2H>&`dyJe8 zR3rkHqmNUe?Qb4*)o##5Xlq@PHLLwOjVwxLV%+Wb43p{Svw+p$Z6l7K`CW#PE5-Vl z!Bik++~!zUZ2&`j`7p_9>#Z8#CPuU(zymC92_2CrZkSJb|8x6-oNu9$f%vH7bL+fl z3}m}R((Y9;`C)zB6sw93EHFH}HJ|9wIy%h~i-9o_(&Ee1w&f1p6>A(fGwibiUQ}v8 z$4rZW?3m7Lw1xLxVa^yuY`O>KpoM>+a4(FDQb?=Djf8!9RGHNRpzZ>=MV@aq^@Cjs zOKubIV>kyyY@fegf}*kHS%Q2ru;Zo%MqvMkm3uf4cuQM+!_LSVEX0gLkLl&j_PKAa zifPrUpW4RX<12BSOb;oBjlNM*Pr!L0NMX}H06LXLOjnrOX7#?af<9u$X zOz)>pO>@%N*#76~@dN|du+BDCe*LeA_4j4ntrB+Iy|>0by%56=Sq`3Ou2@wl37zL} zwQAh0(o3z*pi;p^VH0c^fqT3!zJYnpLAr7FgPvzt?oPkk$qqv*J)zMPeTe~E*U*v zH%}>SR3MZX;lH|w3{;P$JUqAs+o(HaFVdE_SmqFe5Pf3u~ae-^XJy?G~ zjQ#1~XP6Uo->;+^GHVBBJ3Mup^$4we>obu62pJHGgVlfmJxE$sbV(d7reQs{HqmG% zmKClH6cz)}k!Oi31;~U$L8{$#QhPuj7?!%Qr+1Jtr9!-SZZKW>nM00~#)?>6mI|S7 z0B2>=SpY$Ctw&#=@rMxk?WA2JASR@W$$=3?x;hj7jQvWkc%+)E5EFXoX{B5*2mH;0 zJ{G*cDe!dah4;=wa4PWvJn9gG|LBfasQ+9uL|Vtjcwuj;9+u*(=9eaplnb9osJxQS zNM3qscnkA*r7STaM9$LAVWke?n#``N8t` zxixn<<(1;>+`d)2Kl;pk=OPwNZP*v^-BT|>!_zmSzQUgUWS#7b9XG|!AD5=W3#8H< z_&a!Y>r|xy2&gLvhRd~eX@|vatnp2b`i)~F%Y3=<2L!*v-u4^SKY|rCU{9Z#%2HUE zW>D}^@30!1rw6-amlOAA&na7Mkk0lPFgVmsti8f{O;&cq#8)T`M*TkcR|_TZ!E7Jz z^cd#eIxtHr!u-FnbXHrVHP(I@R3!ey9Gx9d^ABLc^}j!6SW`N?nX6cH3l%y#^v`NN z;8WLVO?J0PLA4L@^(-cmGgI90Y5{*r;WTb@RI1p(mkd*e4gJQ;hwhlq4oa*eg%qYm zZP)MA-ha>kIBfvroh;~fE}vj|1RUeCt-828z97y%)@9wkk_g|E=x1+ukH!b zqxi;i3Aq8rk&QEhBZs&Ane52oBl{J<%H4asHXiaP_wIvwv-A&1~Os3fhsoitjK%Os)~-GrrUZ8y5?9QS5W9@9G zr{8f7t|5Ue&y+Mn27GaOgW=B`gAwb~q2giHMV&db3Mm3NkBY9$KS>y%A9NpB1G|+9 z5vpj!3J-UN)7KP=l3d#KT#~)dY&c~Qzzv1e8|0kC=Dp>q!h>i`$mdi^HR$)dTB~dq zocQrtskcUvoTMIFi0bZ>aI&pKmwIr;Cm)%-ZYGthlJp4p{g|tBKCD+k_uy*7G>M*q zUVjH87Z~ja{S`8D#gBKiAL|C_26-jy+nwKyDE5fL;$l;2`1jQxQ#Y2XoBb02y40&k zm8p+kJd%SEsgzN7WwfTX-&%s}O^FoI;z2TW=d*{nHK5T->i-%0be)*a-rPS}*cNIv z`-q4?SNElKH$`NA88J(CNf96|((jt|HCbbrdIk>5#mv~`SE2)XCiM=tVi%L;22a`(ODsmy?yW|LhO0#XxI zGU)%4;}6zP@Bfi&vvo3awg|wBdV!R>3ViHHm^hPU3f}rj4zWd7nepsC5|~^%dq5d6 zUAaXQDuLAb(-6D?NL?YoPC`J#m@M@o2{@4`-1fj_i5DJvuD~58H8S%3n&R9W>w(fW zTfj9S+gha~iK7T(OXW9LJ_fGYYVyDK#bZ^x`O0|9z(1BciCk|y8Crsgx$>pJSong{x2O;6l9YQFm z6Wbv^IA9tiCO$>+UBi^?!LqJP8VBrZ9`HTWDf3>SQSbxcJtU>u_7ux+JZIFZG<4u%rv4 zHyLTFIx$$;mHwx3WIxW}`Z32Jw>OKinhObGI%N9~Lc+_;d=59|!C6cN>$E**mmq)C zcq7 zN@cDbaC*3^m3EJ(vYh-I^d$n)%nysSLI_6SzK#?>Z=a_ye$`M5qr)w^rfw-;CYCne zCa7;4!@DN$mUwe-6+U<{Uw(gj*M9?Xz8yxqck~tbU}63plgTg8pkH#vv8CMUsmGE;Et1YguU)|C7b5*X1-9UhnjQv=Eg+Tq#jR4Rf5O)x(SC zG@rrue8hs0T(eJ}tf((XV_aPm&gX#cO|_Vr)*!#3$V3r_5?-pAh{`{POICwhX?{C0Aoa@r(09|{ioqIc)iBctJDk%n^J)ER(pUb~o(gvaWhhf-WwFTz6{tHiT zAOjc^jUC!rth{p!@}u(wzC2NC?u_CoC;_bEvzdmQ2<-krF2W_j#o?q)TFylX(o^!W zh3n--lZ<6sfk5xL`RQILCieMh%K-R;m^QoTwi$u9bw-%8ia>*<&aBw%y7GgQ*~{up z$m{??iV0W-COXi$D(N|YC!Z%De}6;q_%S;|Qj8PXIa8KRJUz-c_Jwbl=8+OIscKw3 zE#CiT0uG8O#>NJg?1K4KO{N!beHRN=d7U;a5Y%+Wn{LTO76I&1{J=XKMRSDm*cbME zsfY0aCMSLr>wSqvQRWj5w-2$CoF&S|L*E(=lSig+Is8|ZW2tjx9-K~kh^Sj9XF{Z> zc0Lp!51rM%ah$SB-yJABgyXUv$G#|KS#2mjb{)?ixP*$%4}@vJkU1H4yFoWKu7^21 zF$`X#7a29 zX_5=Rp2EGLrNga92ZxKHi)hWL+G_tVuD%MiWZxZHt0Z)$FR-jJj8OgxViW5n7RG&p z9*P>Ul<38d9ggdPaIA@J%+2yzfgsrN0n-H1nX(5V^7ug)BimRRUA2h`Y!SOi7V`Lo zbYxxJZmeb)8Os#7y<=wKIROkx)|0RyRWc+w!M8Ep`tb}7iGWz-o+KrzGPsP7$&l8n zme~#Qi($$Q%56LYbj+{*nNH0)SDOh7UD4Zj{yP7^k3AuedThXvyp`B)?v+&~Fu!^z zb15Btd=i;*R?cvckn;#w%(e?) z$E(6-M{+Ck=;;J4crkBkaE4S+S_#LszT&bQ9qomRT+t#n8WQIvb9QYjeOHw)z9M8t zD->h5dnJ|&EZq~WP~7b$h7^M@WMZUJr(}{^NjQG2yM;qX(}`qjR0!mh%7d-P$6LSe zaw1z20%D$3(2pgGq1Nk`CBo+BIBL+$&v;BHS*7b_mj!vZWU=<$MA*BA^2p@g@xX5Q z-WofH#aHwWXunNe`frRb{%UGxc6~T@ntKPOEzzz)gL9=h9j6%ko4JOT69~q* zE~77HTJ{n00s5VDRD%rv#+lw=(=L%j?G2N<)U-KOdnbY8m8HEBz~*oQ1%n5@4g^fN zR)H1~mwHubeqi{w-?ytTZG=ovE@7=>zJTBi6$}jcbx_){eUQz66!>!1lt)sHn_2L| zP_;90pjJDt5JMIEI!ncJU&w^%+>JxVTdKcp92R~$m(XpR1>>2m)a)ozR%HYXIvoD{ zZd9Lo8L2^R_M$Lkv`P2`hfKlb2;-Fovk^#XoWByv7Ggw` z9~4E25Nv9Nzb_n-Qu}{_QvTtAnY`N#8H~}+=8xxK5w6X5eht%7R8`Lg#@MK}Nc)Pz zNt{DgRp3~RbHCqK?dxp?IcDfN`X4q5$Zgv{Dm1>%RNQLNBg;Cu%f4(uy@Teasq(tC z(VP{@Y1;Snlv^nc+WX4|xs%t2!WE$B#ST&*moiYrPHp}J+k`wejJmbB#c=H7^Cq>_ zc-d}Ci!?Iyv+`6WPnuC&r}(Czgxxqn$W30ABta8(Kf5aQyF<(&5rtjYu(z(ek8){48(MQN)HbXA6=ZQGhi{lZkd%1f>PDN1#M_6^-Z`jyT@CX@8V5msvL#K#_}ZFBgAqa5*kkv*>W9r+n>uR5WO2^3mI;h zh|U!Qjm>V6_pL=GwN9Iax#-oh1sZe2l>+L9-#7>~MFzu@CHj{KZd@K5EP1@5d4hHm z0{1i0{g~r_LHbz8dk<>BqX3MNg9PWsh(Y9+?I=~3%&1vtkSb)31a@u~m#dNGxY;CH&aF?z80-m7S>1 z+vn6UoOtAp5Lc0~Y5#^^KCs_FR)mgO2fyotm>&!M*Ils-C<)!w3GfsbTFb=z)wJwL z`$n^)m6?r#3a0PNgnH^#VYb1q?UK5p(__|(D9qX0Ng$U%p1R(|Mi4TBYhYgBuz*y4 z|L&BUs=uugrCC}#o$-LDsU@g}9!f0!6l21%a#foR+kU`3} zEEf|UE#+oB)g}5>8VXrq?IWrvY&TnnQhc{fS>S>##sQlng}KmosPW%1Maw6v<>5TT zrho@6amu9f^SdV@rWrgiSBie)3q|5`lEo+1dGITTMK6wZrH*{|bT3hA)h2|v?M z@$d}b2;Z~|`&&qJ9Ix?W0^qa;;`-r?ySmeRR~`IzklKVCnrIIcEt~Yn(sGpWC7x5{ z7VhlSDteKdq14-*oP!2$|Bn_@%sZ5|%F3BnnOM+lY(l1Z$gnjT(`PrOx@kukXDKor_=GJk@RMH$n*QffpVTj0VR;G>*ZPz97O67-YJ4khDc! z6wNGy!^U`)fGzl9B$P=+ zQr!%~7Vf(ZmE269VU82!w5UDW#My~CY7zRB?4;|Zl!X+CBk8hafe>|07a!A(k(bsM z1hP05sNhPMH`a=5>8*iQ@y@0WEZEdwL*^5Y`)upXR?R2GuVtRlJD4p>KNgSANva{J zyEs0iWBzYBB@nJ*!7m_)2a?AW)&n|oSLCdyouUew9~{Q|zakvG&)=p@*=U5k+QYfx z1e*ITR%p^%0Nu-RJsm9BOl|$b4RZ~fa{c7T^(WbVA17re)f#754OyrVtKDz>PLojg z025wPag^Q3C)W&G$WaPV@5S1;;NPazj^c%+2SB)rtq13dRzd+SA*2+ieoa391b?6z z2h91;OT&v;XD(T055+5w-sa83bqdCafE6ro3Or|mk;{N20R-o>V6Dee4Mms7c~)PBoYAs zKLEgPxqua`vW4%T`u&SYOy&mmGV!BOLAgq!Jp{N7L{MN$R6ex=w6}Yb(+>_Lc!-s-~doI(Q-xrWRS4u8QVlxJqtTUr?LUuI|)BQ9(G5}`}5Ef`l{Jckw z1|I1Ei^2x01#jnr0c` z-%VvIh_Lcr*6f)kIY81Vw=Z;x;vJk|Mk~u4^2u&6BoB00o;h|Gy+8=~Dau<3mycC%`JPl$-S3%fng4 zI!d)Epr2@LJoi{6JvZ0-oaN{4KL2cTfn(HA<&i9dW@ptMw-NYeAx)B8_7^XGJ z(2{%&=NQ=Z*AK_!Y!VmQE9McM{6&T+UDw3_=p|7ZinT-?M(y5$Fy>`;8Q^bgP$wjE zGHBi`g7RNfpAMerq4zYsS|h|7$CG_;vz2iP*fceQ{VWt&s8s+eod31O%3o-FW@QYh zJarQbjNv_T>j3=g%h8&qI+E*mE{8oWR|P}e8lQo@&X`n)3zFap#xv05qKb33dSTg1 z6v-L0kNcMP4o8Jw;pr{vVyRP@(b<*OZ>Z((CFOm~0cmPDy%bUd>lp|h{o9$p%J%L# zTOos1)Z?!E@C@pPMcS$WUEK%?MHA6ELJr&~@Sh!j7W3z=COZmyz3B8k#dusiW0`?j(#h(?(?= z@LrsKzY6rnpt$eImx9WtRS?_4Q2K)eUT*Qg)0NVzNuCgM@LIUn#lKreaAmUU^zMr9 zWLK0H2Zk-6IEYGra%Y*7y>Gvn03Ult`?duKTl=+_e9s_{6cq`Ff`Ed)xcP2_;OB~N zn{PX-AbzIA5tm^cY;IdyyM>KTauW)6h!Ll?gGY6u;Pt|}=rcmx76%!rW11!B7^%QG zCx0p7Qv8I9yY0keOkPtx7_rc+$X(FOL^=hqdQFV*c|W8{rx{@{+#v~eOTMQIK;a%3 zl91)iGiD8T)%riKQW|eDx^(DzsQ*o&xT)`yBu#J+Tdbwf<{>d+ef*kt#(;h+U)YUN z+h-zxkJw9ygv+s!(9q#8%=ZM$mPx`q@QRG1T%@3I zJW-56lzY)-CXM*fWa{e+#+~2`66*P4XAGqjEDjv}#?nf3m~{iSF+SBbVUj{+j> zJCaP8%9dx)?#LwnC-4xnuu#Xc+-v4iSva%cL=ru%iyo+nitiISeLW9@s#Ml)o%rY=-{y;0>M}AV6f-0s8TsL0nFxc*oXi zEe=~KUDV#HI3rZ8Ymr_5-WI|2PmrLpLu^@DF=1>5Mw0Tjd*b1Im7kevb-V(cgnzAE zKt)Y!^Upq0RrM{b_AV39lCnl>L9Tkm!M-Jiw;x3!Pjy8R12=Ba1g~p%2b%O8?<2q_2T{D!z$f^jBflr*M1azIMp$g3-nj^R;j+?PN1Y<8*}-v-St-dRb=mouC4?5p!ba8LP|AO~q5?nLKLKko z*ffe=Di=0YJIhx!vampn%6?XNq$WC*Lbw8-Q_?6rAVX zl0z{D0w51=+h8Ts>)XKY)t&hpjv!!o9l^RYI`i%bl&+px5qbdM(4aq6J z7Nlp6nN|}ym3FL-xX9V9#nGC1lQyw5l>NKVeCI&Q#f7BQxgnJ{m+Bd2wrudxD3xB% zRHiEuW(FcI(N2r^&mn@ELANjXF|E!OlGRz5`f{O^!~crZe2?J%iJz^F(h{N_+Py_~ zmJG5>kShoIMKBwBo+0!3fWWO_+DOASq4R6*Es;LtF6*nzaA@r4z$PD&l`J8baTJhJIj9_=FWo}aO3AW79CDkl9(5+s0a zXr}&ud?sgZM7FvCT7j)-CN0sCHC5~rM`-c0JQK2#fP|Ro^*7hS#3Y*c*%k=}Dn+)u zKsZ1gsR1qa_XEOED^Z(lt${`~C+~4*RK#dJ!3IsJr{_LWzd8B@dthOjCir8n75YbCvVA&%(&PLe$(Z7vWdh=^9IK3FQQV{L>RzfG0VAbI7`V8&-Xu7Mj#nGx%{O+g8dBO5(#^L% zf9EQmt!5Z*et~pn;w;#BW5a>*s?KwxF^b4pY(Wm(xrT*xOpc*l0#k0;lt^<{;Q9(m zUE=ehv96pRFdas1JnD=4C)*lsa$MbySLwwmZ2q^B?be&x~pZt0UK}F?o&B*aH<>-VC!W|Ir*|zn=T4IqHPtt1EV+mvYC;Wnn^;E@=k+Vv8B__Z9+jF5HdWP% zCljtRh+ABsCcHvZc*i(Av~I+yCxg?W7yQ<9bjk9xG=kTuRfoH2sA+3ft$#oZh+@_P;Q3csR z?Vjnycfb?bUv{t6i#yjGc%#kXhf#d@;th;kzzN?9C5?HAuuV*l+mS-L?NL=3>Uk|9hdC-mt^u8v9u4CRXzyb_>p$P`(qaNwQ zOc8GZCjgYQGra@piWEi3&>sJ6<5{dgaegQ&);;XSXqzG%hrd!##sou2AApTauH^bK zs`iR*-~;=fsyqf;&pIo#9EqTv&w&4uFwCkPQ}vI{`kAUDegmGb(3d)zM8~#8$ta3=?*uT?umfQ#W6G|EceLH3vIL#JU>Q_c-p0 zm~wG`X7HYmj${Lq(;~&N&=Y$PrAs6TGrO+Cw224# z;#NJNm8vPV(FG~1F|o__jkyGxiIfl>2k0cC#VXO}x&KuCdtscH-8-VF z%d{bXAA~t9Kpj!B*Kt=9y`T5vV_8Z6O!D^>1guN5ffQ7Xq`AZBxsBSOxowhOyBE*) zorSOS9&1%7G{xtP5cmP!e1vkZYgEQ%4!iQ3MNIGZBy%M#Z21 z*U!u>!jn^_+XUpmgB^;1licENDPf@nFHf9OmaIA)>S_ntyE8BDPmK1)pFn1Z^?kc< zXq(Jre_|4P$mO8Va9+*xCG6-N=bKvcKL_@)YI-jmbOL3M@OxEtpa#U(_XNdR!%`N7 z=6}=%$t?Z(K!wH>9ngO7i(`f{|59Hef{;k>hT$v`e;G3n$XA||n_`)ctAkj+F)C`y zT^uAZksNn7D#Wi!1xy_TTIoT1`*h86aGGxbE$qjf@`NAp0sXvsDQ}@cislVr$x|}f zcfR{hUa4?7A+B=hPuZ(xJleaWVJA}?81bgBs}k3Fe|#4$H+gbr9(v5=dpT0c%m&wO z=Mxy+>hRhJCt_$M5VRfHgo5!jInnT(>-V+{Yxiedloj9H32n}S3^dAtsB9aGQDZfe zi7sfJFyppQATJ0?6%qQQ?VS~wTQVJqX@Mf2yM@M3(HR zpExnp_2opRWjw#}!#@#t%98du5El9R$JT?L1tz0LOVpj!oZ~fC*O;tP=B4(Q!ZRKd zo6v3CQ(d!>fI}-wOoy~L)M4g#5u)7DyVpcJ^BT|;s_j!HQ7c4Z!4Ei=g2Ch?GcmBx zx-@HOUrCcJ99k%HdA`&Y;-2wyKTpAx_YcZ!ai*sd$o*Ld3h4zQ7hjlVJ6Z8vQR}6S zP&!3;yV$LG+*JL0c&Nt#gwfla3*duAJg^@kvy~ngiu^=*dyDV)6XT_0!*lp z2xeCc3tvps)f0rYqgxY3qXE~}A6c`Y$dh5J;)s)q!-J`(#;6AZI_^ zW5vGZD>#*2Kn755wQXVE;?nL0DUAKu{oZPOWhFY`9#JJdg1qYj>LJ$yH6mbV*-S6t z{ylU>Bhi5yw9oT2J128;VDY^7$$8|G zOn|?<2N56{UeZ)gt$1vMvruJ_KjaIxvY4}db!O%7rlh1{xwxS2U?@SoIyBG(Og`)z zyv9t`tm7Tec45625Tj#*FKCH3wM&FjOb>*K#tVw)^GzZN%Po#xzL0gr=V(uXV>`Kb zs|W@qWU!w9o+p#N)QgaRB7!AsxbOu(y=s&-(pM#ct*vtGMuF@$_;01D;n*m16La{) zF~8%RLFfkV?|idl#r*VSH81wQM(e7K|c>sh6A zf^BYMpFayC4(gDf{hoX`m=ZXmJ`^H}9+W7!@3k{mrIat}wh;D#LmdmRH>aDT=Uk8+ zTOTH0bteC`Rs68x=OWcni|Lou47*M?UworxE34Y#renQ-)ZhJVYjgSZv3Q6;soC8- zy0{5k=_tvA&l2+lyILoB!D?xUfF7a?UL&ZP1!_BW{cR*BG`6!D%Of^Jfl~>-y^^R@GEdiOGe!PX75>!!ulgVL(P?311|N@6 zV=S5&6q2|(+Sxk^u5kW#gV@TMTlG-jm|c5zTLtnk_24uf5{mUC2&`CWNz0y~q#5a=(*lZ?ppe`~4 zjj5adv`23f^EvFBYCXFFuUsQ0*zPLhugb0!2U7*9B=W=LqoE-9toX2m>$pz!30#)( z1*cU5R$i?@v!grD`@qsS!@t$yqwsQd>R1p_Ju$@cfMEFg7=rTR50vImTHPP(g?K0- zJ}ZPp1HjKHh>II5DLSmH# zeB7A&uhfLlO{VO;{n-$Gb{Q)CGy2JhgOpnD5-=0urW>u}y09%zE_Rdb008<7j#sL{9UXmFu)T0dn(r@MnBx{QeW6l0h4~vn30_dY37w7d$cDUv&(5;oud~J8-Gu7FpaRk z+1}Px2UvGxXS!!QnirG?>{`bJGv9Rwa+M;J@*CoQr2sva%v*t7_8$NrI{vcoX=Gzl z=lTMxVBO$5i5bFD>pB`xymm0-@zsN{@88AfC(-hoL-_ar`&mmAjsBxPDTN$QE=zC6 z!f-?3XI?B6^falos7ff7H=Q!!dwmQ9-5-Kpb8s19aki9UZ`IX$(h_2V%ykMM3vAi9 z*91}GJ)Y6~`p~c`Y8n&@X#5n2 zL#F2Xc(GRMt&}73b;04(n|~KkZ)@^a!h$434x7P!L!gvR?s9DoEuPxjGvvXZl3X&Pt*^NQzv(xkIXM?8J;y6Zm3V_WW;CVnD}y1CR%QM==V&ca{LKLn9~}PFte7`i=NAgWi?DiqrRWN4o9ZK z%!@KF1~q)fz=rLC&v(S+x4z@7djQI?W^@Mq;lrAbJzB&J)9fTF{0hGYtG@n6(NN@&eL{i}>yT%|hiWbZurlBuF~|KXHJW)} zLcUnx(l}h*t&f9Yhc!E|Qa*0mB7xqPs{$zqrr>f|~^LiGbcW65&fSSuzI9Sjbfl&J2}eIPR~n zpinxA$%@fXgdSf*AIs47DN?Ujw+IF`JL#BzRyV~qeshI;woXYA*+Paxx~t1D!Mma~ zo?F+lnW%pb#W{H~a1j|Bm2o-f&*@BGC3ru=y0uHYh7W>nmJ2g0!f;~C*lCGbo)djH zgIb}|jgHS;*hx+MzvV{iguc{V0)Oekp}E+qb&}G?!fnY)1&7^vGFmiu3dIWC*CKTb zn0R_(qZ~9y6NmAmAWo9~y&#;;CsO-ZCfw7`RPCZ^ET3ez6tZE`2=uhH88BU`9NP&x zR(*3l%P_);;bb;tw0Sha7A%Lwpqw`N^@+wxc&)7ZY!BbcGo+QR>;X!hwNV(P+k5-9 z;onXv@cBSS%BAD)CWh|JXCVG5_6H$hU0F^n@fklDk?tgN;35Eo%0l%+Exq=*`hv8t zJPYrpi1Nb30A#TNR#=cQFlJ6D%zas0>nO4+>^*_gX*?RB3j&TKL*0e(k$Ioak{3(e zP3_3rm3Csvyp@4lc=LWo-I&oF)U}03*7S*(!f-9!mGh3ECx-3X=C%|c?qMF2`hr9@ z-{Q#cX&8clkC11o5}8X>%YEyfME|w{vbTerEs;UqaRXDsuLi>rsw7$j_*i`D*+L(Q zYHv5qB<);loBR|m1%{-mbY*$~2p@7Q$q6x_S7O+&AzdD%`s`} zGr_3elfw$RTSz5y)SVMwz+Ua(bQ9F_;CjUi`Aoh_H6YF40Prs@0nN7Lb8=Yy27jx- zc$D#s;(cHMY{PZwXjN`*4`95<|3|_(U%lG~j(BAC-5#>5D`1eah^u3_^Zs5?V931$ z@&H(P=u`!4VE?E<(`1Yg*>p5;*-^#9YWVtOy5nzj z95#O_fMWedTMu~86sNL;(Egyvs=GxzmD*7KOwSW48 zl@60~PD1f1K(U-WtRKSSH}=2UwrZh`b#=Jt#$8OvUmY?V5u7XA{O2wXaFHq()W)%xnj~*j&Z@7MJ0C@(qF-tx7 zZX96QJkzlO&TSw?=s6zgqpayVup`};Y57fJL2eon6KygrFaUNXQ@IjqTi`c#gk^bI zdRvPI(XdcY3J-#tO%02>ZigHm@t z9ww$eKG*(Gn!|?zW_uvsJ6^?`0S%kT3#^>Jy17<&h;IVByYPZ%guC(~#ASld^`!beq z#LeCUm5yqmIB1{p7D+g~eNFzR0x5dIqbJ%2$tw?QLuPFF^;)>2z(9EF^{!+G+!1m<7h<21KqTNt5=x^^aKcx7+b!Te zB99}^fJnWVKTIvo9#Smm0rizRR3ExbRY0lyOVr|TO>n!_A=VLzZM~pwP%>?Sc6xz8sn!!g!xe<4yoO<6r=SDRV~gxt0)v<^7B(w3(>UD{q>(Ut!`- zviwr2>RC)d!0HChgFLjH7*qX0HW<1dSJ5b_=+QXJFo@; z21Gq1Oh(j@tyoG9Xmj&Au!yWF(rH~ouu9kEWFRbGFTa|K4goRyz}`y|+g+5~j15yT z6b?6bjw+B~N7xvF6onvZm^N>~7A{|C;P@f(QiGYO2h=6tt~e=2^UE53sLqERL!=wA4yKN53+N^J;2>n<^V<7uLrWT6?SqMj&04Y#m*rz))UV88m9eewgMQ z5V)DE%nrR{?De;_P?#*$!(!}CbbD#%Vn^h-(gw79K~Plt({Ex4?O0?UG*NKz7@(tPay1FKazwvm>Je|Es`hnrznKsoDBej?Mx$;vwkvTfJx_w4dn?X-5-(=A zrG$A0Pdvwae)$xuXHfPm7%1_xm;b|tKsH^*2bj2-9ClNjmSbd$)~h!R=*}qXtbN8Y zgMh<;M#2GLf*J&$NmF`3#4o@q1t=~AOH}OE24R}Mr+2P>`q(~5$w=1&HG$raF{bsU z&g`CSB(ANs9BmLI%p9eIbq0hjYGIOk&2^`-;o3r~OmP%7FqGCEm=XU%L?#68&-t&$ zIHE?G;NE*OpcEnuhlT1-wE+Ashq8NCs1!84pui1B$L?jQKIwmys6#xy<~^J zG;kR;QUFJnW`g_u^9+{~%+18orCjvQ*YN8VISGcxBOt)|JHNF$;r+Sl51=zVw=u|_ zU~$NxfpWL}A&-;z*qHL@F;WWz@I98Y^s~ho%i6ZV1hE{X7p$QQ`uPGl+d*|Y>F`wJ z&62)_y~Z~wJh`v14{w*%?9YhTCD|s$exNj?9YoOPFYnA0Rv8=uApTzDOoGbh-Pw$EfUYryK-Np_0Iup={|M|K*C(S}O~Y z%0x(U1wGK`k)TJqxb?o0O&ufr_VKkj#4Leibqvz?tt*e|=#M^m6jQEn4F4AbK?S%0 zuO0H*|EJ7%#{l><w7AuZQQS36V#M~u!Pn2RlFjJtI)lsKI3y$HHOuasOg&T5V zNPENO4bBECiX>|_WN#}Qs=8JJEt_GAX*h9oeMqm*)Wo~41;Z?+ivox%(X&|9nE`Tr z3hI5>Bfbr%rhb6P*tNr2=!#i3S^mNy;+Jx1$NsaFQ&#ZJy(pDGkrN~Oot|-yEwz42 zpYJ}&jtz6r-8SY(xeb4fWfYmcs67L2H$de8*nm#GPB?)X1cf35_K(xrsd|=K;`Hm$ z%*^quSJs$D?|2TJDg4j!%zr{u77=?#gabW}?dL<} z;4A=BIz#@)AX&{8bmkk1JF762Q6g#S42yyZTalry_oU$fOL*@hM4I)M_zB~{?P zbRxD(lBKgR@A8NPA?5ewB}^lb?ewu4LK=WP8kB^)>}nov#LiA#n(I_h=gr`+0Pfn; z@PQF}WCE0R43^T#`yXS+6E0t#+Mau_eT&2vZ?e7NwH z4@xZ8eJmxM(?=I_MDh*QH+GUcn2{m}##xQ{)MahA;?9h{10zFGoCmLrVyYkPRnW2l zF#*avy4d@3i?vzI%_AY!6pw#isw;Js+?e*CIu6@RAdUQsaV!9Q24}`x;tb^AK@luA zUeNwGeL1!n8F{eu`1JHV>kJmBAb&D(+{Is&ntiz(e0%nQF#D^>|b6u47!+RFgU?zN5*;61C56&Krx?5VY))xZ5 z)A2C|PGLVyIzI15G8*YYp9Pc|y8lf4i3E#+feWKnbcbMmne{a4I19C{!C>7tM`78GQ9cg2x^$py=mm+@Kr& zZSFu9nr)MvI<~D`!P7@FW2iVlK!YlIk%v^%fEI;G!MpRoXyz_a&1c{jT%BqBNN*EH z0Kk0G`)|ktSQ>)kkHOI67B(fLzIFbo&6_?9Ug~EcA~cDsW=Ep&9ON!rOMBM$y25*} zq~b%?lQ%4t95jzz^gHYE@ZW3MOcH+xcLM9XG`t&6x*euOf)bNbG8WG?4 z(W0tyhr@r!2Zx-eyD`Se_K<=I(mq;NMxkYk|8l6M0o$=|b*YJY34BZPNeQdmtiptrf-Xn})E_uVdELLAt`NkM&7&3L8g>GYwm6x~6P`%nPZ zjImiz$kzxecuQ4oREKbGD6;2l4g+#JyUmpml{3pet1ov>x1S2TS?2pnxx5!)skx7h z`W`_aMgQ&Cw(%Tq53m)K0cT5_orv^aj2eq7tQ-{~|SraHj@veZk1`d52bXd@5* zmP(6U^ifpc=C7|qwcL;iZ~lb)ST=grNwz`}YHc}}vXlYC6KMjd10m+Ryi1E_DM94I zfUStiKJY8n*Sr@`s@2ZjR^iDgDIN#bLu2ah_OJTGb*>P^JhDT!>`ykJs5}3N)Y9AP2_O|)jQwo{$>!PN9t=*cE+nV+gF@LF zyPY_9S>IsNa`fL=tLP^_u-m0R+PP1ND$oHB?9L`&tk3p21G6%NfizE>AGUBw);V=DbTR6wCk2<`Q;qUo+2(?UB|)Ry zRAkl2dZ^ECNU;Qn$$AmCwmI+H^yJ1F?{5k!)MK`I-+>k? z?0jCiTBlnq=S(eHk1SOdbi0}BH=M4o!w$DO+SJbMGtT0ETS`JEXi^t?4GRP~;X;+E zn)*e$uv61@e0)U8T>)jUrqVQ1Iq==tIa5U@!mgR^qsEibFEEmH%P?JL`Ka3S?SjUw zG{~W~zIp5D$pkEh+!LzZ7`O@9f=@ zD~gH95F~w961@%(BA?w`e)$OWu8;32 zw0ig41waSqo5{jgRY{VBR;e#HPy}Zk>bE1Kpq|{vQm{S()&D$z-dNv5ie_2arrTz+E{4^QG6xB<3*10G&Rz2zdWt3j&ra53WTXS z2Ki7f4QD!M0bffjs4`*Ybv+ZC?2AL60-evQaOK^4*WUZO9nP41?DeT$n|u4H$Lhc} zk~rq#LVZe;3fOzH_C|Ksp2|!IOscs&hPM6K96Y1z#^UNM&KI^p6N0ybK@~-!jMnAv zV!=){Uf*&D__`Z)nuKEd#$V;V_S1InGEKB@pYxj{6D4a~#CTe{&m2S~Yi3tO`l=*K zm0}){M*!Q$s|ge<4vR-adt!jnURsvxI64v3;;3v}7Cs$$7qA;k>?~f{qZ{uqE#pzu zDCj^J(%yyX$;7&zOyq?Nyf(y|izQDw6?o(Be7z)=P##V1f=3lGExK8xYn*#ae~;;Lx9SmXpbrwpoCz$F=#cPw$Xk8(zcOMZd8! zlZ9$yPAc*67H~bgzQ(s&IW!RYPr^gfJ^SuAa{FGCqc5R~(L)C%|Mw%yB^jmMKD~P_ zj3@&r@^YWp!RG#45Q;*ysl-8L|wfVl&tIvpAiJVjZTUby+nHV9D2Ot%3!aX z(97r2>}E&XRpx?80b$o0Vo4sLfj=!RF_a}1XTogkn98IY+!sS7lj6^VlRoZ)x9JfO z4*nsgpt&Y0c#{FgQ22$@2^fjfM*kG%i zfToO~Jo(>riZ#_er-GkiFk_t59Bi+3m&mC(Clf-ekWX_G9JM7-S#zBV-$hChGv}Nm zeOSxKXIcnw&}tec?{!S+wyvl(O+!+%iylJ|tJ@_$=y05UVexL|M} z^s>Pc1$5iG$i}_Lw~xP&Nyn43Cr?TnZYAzS=_I;0ST+=%S?0HJz2~*Nw;59jzDXA^ zPeIM}n#uf_`qBuFKlvEDjl+zcXcrYB*%aWnN#t5J#ddwQ+K`)Ty`EA+9wsBCm`?6bSg@&(hpxDLnQ^GISibKgwt%qZvj3iiV%_-sQ@~IpL1sa z?47aw=|hcyc6Wj_0(G){902DQLnNDnV@c4AZvQAnJZ96Y&I0O(d*qb*(~V}cK}pog z*Kp1amcA)kuH83fU9e18s?3LrGSz+~x=A`hKTVah;UHlVd+FK(2)OZNI3^G^3|?VX zgJ0H^d*hC!-sUT%BY?=}YHq@?XkrEYuQ<7)y2=ju65_9GZ`JMIDbKnD>zG@~O61S) z7~4J7(xzHvAepwu^9b3n` zEvy=j#`XJe%3vZd3PqadK7F93U7K)hdkAU6M-RkyFan)^nU@X?y0R3mq=|h(!EZ@a zHISmB9GEb=Vz~m5C7$BtT7>1;QpUuG0oeyC-%>D~o#P{D1qXeH`;vp0Jr385SOhVd zxn&RGIt@(|=ZA&Hl45uHk*ASGa$Ql1$S7|Ok!BT|%y3uNjc)eag%S)tQbr|x&wIWr zfyyUWEZp5ztIjMS#~7c6%r8%r-9|8TH6Fv_%MbxmbWU6qDwsO1Ygp4$;N3RfmdM1Ba@%_GC5}_m=Q+$w{z~^I0mK7I@P6yX_JyVDn-NLJL zAAG*oyunBLWzo@4Wh@hTP*hc59qGEJ_mz@1IB2IfDN|pzLV_ER09JJ1 zZuOx+i2nqt!Io915j8GwJ^l{#x?t7jSNA{PN@`v-=Gm2!i71|JYIj!A8p(b*95$%ywIBtl$| z3KBmh$Hu8SsS64zplf{V&Y4tcj`%$gbY<<)0l3uJH7>&B5vQklc>0L0m*2Pz7o+TW zS7B1(^x1^YFQr!iOZD{vsBl#!RY&!oEQJS@NDPMV@tQ@!#9>XCP>1OwjDKyv7<3_6 zdAm`wHkd*&&VE3^OKqiR~Qz?&J*kes)bSNyJM?#g&5(2DNQ=DRBqEvh7 zdkD%a95F&VRPI;ltn4F`t*0D<@9p(gJ|+?MNkKozskK?z&I)xcJ9y~z_V3_52Z2Zu z$}7F$<5)5x3w!H4*T;^KupS-K+ltxK=+(PTA=4~qY0ijUIzNH9+O-=TXIBN!MaqGh zJX@rDv1Bl%#+%4Bfn!8h3QAC^K@p?L8OJ3tNAwvA089je_hr)bP8DX_rI+*|p22ZN zSm^O|VW9avNdLMWW^M+~aHjop|1+KSdp8Asqk^{_3UUQmZoLh7?p0$^;w(MN6wFV% zT}+WUnAIGMb5}r&4vHM_%n+>my|s_%Ic#1RLBcCxe|r+k#$ zq*f~Cnuj(}?Y<<6zCSKiV%<4|bXLt!KYbD30Y_phvsZYh_%#1Oee!6(sMFx`0kZ0r z<+0WFxo5U`I}ZMih1hi89KUJAO!lr>(PIm7Mid7t9gO}$be`u%gkB@FaHA7(*zDNE zJ_Cs&zoB-~94pE&Rd@J_!$?r&`%-VpB}#92Gd{GsyTdVo8ELbR=JusXkn9rCss zT^Mt`i-KYRQv`%w&lsPJ8<8+pMaY|0^010D{zLkAHDp+#M265z^{1O{5@D)_RIzwG zB0Vy&%)I;Xj3M=NKv^Efhxua!KXt1a*y><{_!bV5qt+OMXTjLxUV%fM*vvSK~*OJp_coMq54<_D_o4^A^G3?G$o-St-hofn@XMrIC-*S zbx#oBFl_+;KLEfZR*`1??dbiXB`H~h2fu_v^{=VEUs=75C{T?YiL6*gKL-_kSRO%- z2_uJcjbP#jy*N!EOsw*<6EW9#&W;e^sK`mG#{fu|^{p#Zdi;jm2!s#FK4_?o&g0bw zZc{*?`pxe0@?C56w>bZiMx*;CzRsNIZ0a-EWs3u?0>qIALDHKqrZ43(rx;?Ue|Tbo zNvKzz&{Xy-pcJE!U!eiAUC2NeHVJv(E zr6#DL&30t^x&R;4GbQ{rcf7G$@--+8TD7M&*`PlVA$riZ6Vs5_+_k55!q{%}X<9cH zGxX)$aZPGWy1U!cq6?i{Eim8f30ycWgJ7qrCCdP@%!zZ3j*P?v^ao7BU>Pgieu$`~ zYM)DZo%sMnwFWU^!*zbVBUAN0lt!aM(KH=zKT7sLuM_>>3F&x~?*89&?}L#fNDjrZMoi%s=XC{9IzR3dA){-n3z{R?1is3p-x-K3OU4_H3cPp+-1z zl=SfV$GI*$Df7F)DS75x5o-U|;p{Dm-p24$E)9U(pm}v7=Wc8<{uD}YOo(L7A*@9ihc;} zU*#n`WY3@P;Exn?l{qOXn}s`}YTpHq8AJD*w10MyQ)t(8|AT_zt5dp6C_J*S@I?%l zG~9G@vlpwG+Hy_Q6qP4+Y>XD=dPYTJs1{CAszQYe@`p~2gcl3p3zO5f!LG`=1{=u= zL$E;mab}N`x0p1yneM~;z);qhV{0rrb)Q!#T&=)@+~UGW;mkwX0`6Xb%ac< zJ8pH-K*xDmX;}^^We&ko;HHb$iVTGYm*CR*!gMyJGC3PF{`fFs>JRWit>{15 zx`|T4@-p{T2G}ga5tSvE-dr#@Q+k}9e*o~(Gclu*8FGW|9;}{+0p|aHJ9oH9yC5`- z`J1UV^29}A2qL$xcXkdX^PRBq2ktPR_H5}^%M4qplDtgud(mODYHRFeuTqh5#N=Wb zpe%@gvaalO59Fq=Q(QbV?GKQ~tJMQuc8}?Ai9laytf6HXq#r8@8}bu@v(Q1e_L^zX zfYxxqRGK;^`v?}u+kf%o=#wFVQeSe)a{9^%a4!*}c`En35tz;DfML--n39E0vR7q0 z#w$iLT_exHIpe}#v*lFkjV&K+;emUq57r9ATD(=Mv;nDx*Ui%0x0-y{S-Wic95wFZe`0Gl9+Xe%SXwc!!k`b6mq%jp~ z6$mU4o~6ryApRja7K`A&F`IkOyz?6>>fOY4g!XfYY=6(168r15#Bk1LkUF*#$I%sZ zO>jSN)Y?D`ooS(W!xqtL)sk+6?RQcjbcbM+LBRhry8UX8t1V;^a#_bHr6HHB+VG;k z(@YPTp#wr%4+Yo&K<3bqC7dA#5;9Fn^zr-aIL7lLpyAwt64fAOx(~K>g5qR`cD4S| zT@n+_m%bRipvCNcBW=Hd%eXMNFh;V`;9(NZ*k~GfO{Y6JRgWAauSUPMhX%n=&u_4p znq;1Uq=|zLsUwyDp2Zfhtqu~&r8d5qc#xA|Obfo7H|c2l{kv{f&2cJKZlmcRk6W|8Q*_pWoxLQP_S;t@`ISM!h zg8&f2r#bmE#)#|PA|0MN2L+tLJq&eRMvt^TL)e{JOw4(YVMPaLU2){HJHt>M zU|Yd_(iGXt3gxABG2A@Tbl z2XDp6q4dZcSnL~38%u1mc4B`k6+r@Ek_#VE_uHL?cc<|vFwf*aVs&WPH*gj{Z2L4O zXzc={dBs4Oi0Gd-nKcT# z@@@=#4mT7WVh;Y-Zhct0BCUqFMLB!^n;a>sB@j_i#wLnl{D{%a!?-vm+~2C1Q(S>* z&d4H^rjT)PCPwu0F@^C3B2(9X5#X(sd^?SM3}_D4@~SpA5z!ScOZ z<{Gz+Q|*@WJC|btF#JWyagd7ROGRnn7VQI}A()$L7%o8N-ATN4v=U=4^Q8d(Eh_qf zYK-ra6s%7z&_e_!6KWDB76aq^->nnjx_|r3O%xHv)08copzN;tjJEvx@&A#-(H&81 zb^fNqUe2mvd(e=>^WTtDbZYM^8)nY#_p4shKrGMN>=0UE@a;jH-)B8`qdF}2LNTK~ zC&s4Yk-qeSYXuDHs9%>ws^?Ho8AY(b%j|pCEVV93QP%A{-d?UNqk6ypr<=`p0+(PI z3!!Z#*N7A8b_<5;Vky9ds_a`@#WnM^$qwbx{D)>FNn(Ky?sveHzU9~`z1h4?PRzME zPTfSg)M5l^WduA4{yGbRZNj^FV(8C;G;+&PPOvAx{r>dPs#&(%r}>u4rdB3+g|mNg z5Ck!&qtiqF|FWH21k;#|d6@w?uW}B=r*;iN*;!|Y40g=+wt7a7j&7r~UjjLH8ahPT zK)?A{kROg+$u@TV#w@?T^+(`SfLzAXM~D8}d|I|&93=7EXlhTlV0^Oxo*zcd4ggVC zVbW_D@dNlwew@eR*||ST6X8k9;vGp$=KqY9*{D#D79uO>3A*-K#=}5U>Wnr`Keu_% zOJC@EV|SxBp?WT;mrejqGU)&d@iuB9La5!f!n_{-54=dwvk7m2Z4Jb>)I)+1jcN1# z!^fQoY2idIvh0E7h+x7OS(Soi?X8C%dLRW_Jx42vZgOuSsfvL%y^D`8Qaxy0E!SjI zy{#c=X-?{bPT@V$_a`hp4gxUA|Hyfjg&xJaNMJ-2jbz64TF$N(Ln%4NcNH_`{R|`_ z{mlOp47#tJ?$$y5+rA2%YEXS>+GM~T{hU5J@c%I+xJrM~dKbivuNj*>iYh;)I3&4R09+~_ z)nk+Wts^lIN0uA$LiE_XH?9>Y(TQ$X40?t-OE1(DQjz+q00$aKc&A!g62O6~Mqpeq z{a}q6vEiSCt*V|kl;}xzQ<*LWx}HBnGxk1!wKmr6HVLd7d@QZHexUzyoSF;TYBX#M z&JefP7K@=KYBxV*)dE=RG{Ei)p6Xi6QK7=c?B&^LT7tR9rTCO+=#e~2!*zZEZW&!1 zQI>~MJ!O@tOr$X=cY#=`J}1fT8|r%~0Y3#&hDzg=i@Q>Od_6%UVf4Kb+h_wB_^EKp zZA%J;WX#HgOLH{_TJAD~QMmQbQy75$tTQx@L^Iy@$hjZYM#pIFsYOcjzAV)Mj7mza z-M|k4mXiDNt{le>xIIskbo!+}mAw*RVRY~X;N$*-bStnv4!v4$&hlk6sbK~CWs0{;#yr@^M~zsQR3pKmZ6YhVungHupWs&o2$H{L6-hEfe={r+LE z=w#J>{p9ovyuge<$-C=9cy{G}yD%hO0O_(^H3_5OS=L`nu4xH(us35Sj6KS!AGe}3 z;*-*@*eu?$G(AGRP#C7HF%}PvW$p0X{XuurH0J$-SidMX)K43N1gWpidx3 zo{Zh5q1)Rw)4Y>9p6zMWO$KSHJ-y?knB~zyKi_yh<;;y}s)fG)*hF)LKPk&B8=F>; zA8kZFs`*fKsYuhuMM`a*pErgc`$y_B=05P{ZV4x#=QD<58u*i|>I^f)`eyYsz$aS0 zz4he-Zher6Hsy($yAe`Eaj%`R7cABehlD| zw50~57wS_sqaq+x!VqcaMrKx{i=~>k4t_Cm_8)q?-s}2ITa&^$Cih<}CjVj{FZ2u2 z%Lk(S3mYe8^&c$uB*=_LFU*7Vg;UJb?wfMyU zhDwzxMKZ>Z^|$FzG$wJIQO zQr_jf;0idaWrd4V5vfvmy~^c3hv=N-S%O;bM01bZob}a$-*Ku|34uxcY~Z|W`6fCO z<+nn^0A+mt|CWZ*wVaFKnmy+aPBX0R#&j*EzK9-n`9>Pl*G!vL#UfZ-bBp7dpjYN_ z`$_tv$(SMNb+NFhT+p8KD@G!-mutmO_qnwC_6^=i7Y~YEbl*Op$SB8>^z*QNMOFx% zE|TJ4Kt4o)E`(bpZO}$GB0VvC#m8yoE50Y$Q>W}bU5GZ`1vlmLJy3Kc8T}UG?Cxg) zS53MqPGX0jPh!soxfM;_GSq}r6y!~?=VDP$<`|e5i?7Ht9A=@SKGLMNkhb}{U=~Sf zZe5gduSWr&i;29%z*PWMh5eWHDfURA4KZ$P*3zFM$xr{cY>UFi2Tb25Ub zL8$^6Ubnn%izFqY6DS+6?6!J7)jSLmM1+5EsM97%O>GeaS0?65q_S|H!L!zA-&fSL z4tKs+R|EEOv!!;yR5LB;XIiQLeNAIH7CaCUynp=;!3ZxbY7~;)OWXK^mEVej!PzvB+9?ca1GEMRu4Wgly^W+X`5?9JN6kh{E;(lhwe4VXVLZ zNGlf07Qkb|%T{AUT%{}tQBOoIOizt%R|7$Xwi34VJ8;fws%R#`fs zEA40u^oa!wPll2&DJ|2HLjTFa0iJ3n)-q&@Q?{CiT&(ZY@Kr*5e0hS8d{>cY*SF-~ZD;i@5wY5{hq|MN-W}vmG`z1ldkorme@1L~Kx=1uE4* z(Pt3gDw>^V!Tp>gE|b0+N5nwz^9JZ#+gySY*FhM&vQfDiB?_oPv<8@{XHWg37Nudc zGa1@>x2|96LzUzt-u_6obn9T|P~EjuxIlI)dt=PZ6yKhQVElpI(iHID;{2x$;nT+u zbg`Tau!Z~ZD1t@VQDPAx-G&ZDrd3B^Ry$V^nDpa)&p$wVTKAR<&mQf>1qEYiUTXxI zF%s3pFZwQs@|IJ`lb5yv0zd9!oq99YY~7avf6#P0p(|rck!i?}>k*4=(1G+f*Dl^b zjagaUaToct@X!}=AR@YzBltee_lcHmN{=rV!e2}}7Kg@*Pyg9x($$XV{dfXyfeys}7v z<@w_?7YYw}ZilQ~P&58q$h_s99W{6@NrbtEp34jKPg+{f5st+KbW_@b7L_SMZai-2 zlN~h9LxQ0cRio&8mj8E6*`viIy5_PT^^H065}<8HWbZ=$-{`@CZGgAFl{e;8qQxTh ze!pO$p&y{?G2KC)gwUta(kano(>(M?yIGvAkK7G(An zA)Xa`c?Src3<1o|6jy}!(mS=w_+Xu@tJ_V|=Y~*Z5hZY6ovEno+M5 z+KhHgp3JC`q5hz*#5~||gv;6Dq~#6QA>{?OT9ZJEX6;R+KD4C#SY@xR4`k5ZJbx408Rz@xOReJuo$2b6!X1SM*udROXgC-dyQLU_y!U zN;Sw_#`m!I(78^e%4%Kgdu$?aTHyUeG)xQ;FA=TdG5F!EpD;MAlW8ue-(~8&EDnG5 zSBVyOR0j>ASLf!=nasT=Im!POmD^23nzX6*Qp9PnnAE*UVVlq~K^;1;;--1w4N4iT zW%E7j_INfE9k{0;dYxg5RDaDrl}FfMogz0(;o2!qThcbeqb4xQtZ(kjk2)v^0PA6?RY1;yNdNjh4)5MYgdZNo=VA9ltMuTOhsZ}b z00HRS#wceW`^xWM88P6I8S{K7Am$7!938tvl7F%;a^%}69j{_ue`}Ct3qDr|gJ#)! zcWPHMDEs@`gXtNfinpPuwXgu}~8u?a?43kJ322_4`Q7VmXstlYS~(x+?vigxqH zbKY?fA-)_af}w)jkV}dUUm*@%25<16U>*V>TwF@!N;(>L{E?8~1w^14q&IsB_@8-9pazfg3Z+jETY(|SDpu?#cAgMcQz2F!D07%|) zY2%?Fo?#0p_T6m>AkaFVBvPZkPVcpuuJ6|3ZWctJ1n!bOlV!4`1x3x0D!ZPVf$wpV z05=4SaY!zux*DrQC~EGFbc?A&Ny{_X^wZn;o$e$3*#h(4<>nS|ylo#n+V4bxi_OOf z|5g8)_tSiI{nE2KtUsiZ+9`4Qe8LCZR{T%3Vs%M{So$r9vu{!+b@e5^R6T<;zA|kC zbdt-hS8leco%=O9?_3{7Xu z?3>qtaHvfHtloG(NF5409Oa^m5GZII*2t?}9y}v!=y;%qTk4{QMp@A;e}%Jy5quFi z;^06k^RfrHH77Rwnn&vJ@!cbet5*r9au~ThcJ_c&_2&$1nA`?MeWn{+2apS=k6D3d zfs6HFh?CwuEXDNh=YZ8Q0-r^%N;&!txs_8LrYTY$$y+S0ZLeWKZXu7C=Ta@qvZSJ1%mipGVwj{xLL@>Q3=@$9ozD(%W3A?b)$h z`f(&>&|*ep76$|?{Z0m%8iG%_RVg+z@NIVT*#3FMSgV*8W97d-h>m!3q(vAbo&WKo zt8tr+_8TISyx7}2!jbz)A|IZT68f($Var^b7wGsmUKhFxTU^bH+UdK@2K`M zDb()o?yXG^;HBx0-cIRliX+ZV?n{+7X4vio@TKLH(q=2`r+2?I7;7G?^#q}g6uq*lEvypIV+nGy|+30LSv=F*&H#2>_7;C+T51_h;Si2-IJeG z3J34e4@~A$P)nwr_Ve#d!Q?igRJ`3)MAg4mo^-#O)ja%!)X0Veben;{346`Zs~`-H zRf-B5X=>L+r=#*e4osT)%1VplEUA?{k$bcju?kwyuxgO+wxlXoHJU@tlt=v8o9Y-8 z4^cPPBss3iy{v@0mm=PEb0Ej zz|eu)dUg6LTyPL~cLcdkwMLkSl6qa5&xKUHx;=sJKPYx;L+!){>NtCI7rB3C8h-KAmyDVM_AWSy2sa zLDcTyN*|Q5R#CL1>Z;-xNpX<)EWHAm!^HACTHYVJBlQ8gY`NI7aVJwUTQX#gwtgf# z>KN;}6yEee9sAz!SfNG&_gPPxuJr8Ze3Gk}51)2_naJ>Fj`-3IZbc~O?gEER4wOvD zr71)) zEc#ZVstW zQR?#ibc&qorbyx;jCjfY!Vu;7h%|O=K|6vmqLMv2}@Z5vzQF1qxC`awz2U4FL+aywy&` z{Em-Wf*IFoT`pWG2! z2mWIPV6u)0R&pNe%ln#n9!=`{JQIZ&q{XKV}`cWY>0vN+hga?RkJzg zC-?6(6fg8$J>0LU*|Toie?pswsFAnS0LS$u29xobE-o=NNZM^^3nHE}ZXwYflf1cn z`BEkO*fvbeZ{rqC=c&t-5&8O=Q_S*ACxTagYY1;wqoEeU8}N@(*pqt^LOfI|!+LD= z+34}(1P1chRICFR+3v{|&T4d2KYq>ZE&_^CaD$^%yC)YIjGxFFkxhu{Gf**yc~RGA z@knVi?R-8AICe4($zX0;Ex4V$+Xyloi{>h*zdALXCKdC8p{*VoRKPe$!@R~V0N&=Q z$iQdEYBvy=oKrz8$fd@wNyYMeZlR@TrWVaXu(ptIUEoBxrZuRIoHIUTBr7x7#*tVH z{c^b}`fQ=ZtCy@Hm zc5PL;200Xm5nGwcDN2aaASk=19n=Uutv4f z(B*KQRHudquUC%Wf3N+oGMUaEh@b?9ry&JU7_>cgeZtSXtrlZ9g7nOWh?uMB+~IO$ z61IZU45yE>4z0)ydb%Ff)~{_om=BsCUei=scG*~PD*uUeYqiZ1rj$mki$)>Pw)|ZK zj^56SIc1yjRd0pgo}$s}TqV&+wIU%40CoLCTck$P6QX`nz-gWwN-~6W7~(m4#y}te zt{55#^uuy@bFM(xIA<2AYXZV7A5LTDQxJy(xXc=Jg(8GfDI|S#*mqe{bb&Z6EDoJ6 zR%(br5{q;5PA-R^HMjr*vNZ3G&UF1e;C@1#=deOs}Y$$nd zk2{;EfK$)Fp(?&4Eb&NAC(QYk%Ym4GD5$Im0Xs+&TZbYy z<{sN~*y;Eqz?`S0<8JlRztD0Wm9xTA8~~E`-W?4^TM%_FX)6R^6omy@ zpGnU(Ue~n#3Q8+;Gt@E4+BzT{TWO46!|e1H*BTc)3t|imBW^1>^poa#^6axMx*_vD z7%Gyd2-@yn((lge39Uy#&V8Q8H*zptDJsp|ZKf`3OZC>0c=Zt&aq%(;Fi6{CM;vU( zhKd-#^1F}xuYLsU27tJt6<;jp8HEeqpc!Ui)KZMkkOhOiFE&#lby;TPB#PRwa%Ub!%oO3KfQSNx~4@bB~Wh@|?` zVKbbsIC!bti6idWWrTq9*XCW97NTjw9TL30zrY)RZOkdxSPV8mE@y^w3&;{D`}f!;Yvy-k|?F}TLZ z4RwAN%evwVk>c40gWU`7Rg?$KGWhjkE}FV#`%XK&5|T>iInoq=Uu$dP!p)>2((nCo zo?&!YmH~f4z%H6wAc2*s-R2n3U;Bg{lo9sKDn#L!@5s2pZgxUb-?Wd_oEB}9 z_SeJE#HDlez-revAG2^iRvR8$4fc+F)xRxMtorg)5CKjf+yO>%`$pFyC1?j&WWNk= z&}oNYPyRENCEI-L2%+d*eFasUc3mdzJ~L{#FRJb>9U0??!ndOU?5SXjtWuSb2 zk|FTkWe3;_c^LC`F?-Hv8=>h{bGsAq%&&#nQgy6>)SZhadW0ZUk`k)?NhUsAjacjP zDzcuPp$)A@EWx{%2kA@4)N1FQa;XGGWc$r>qoMXdW`8QZv<3lAyheJMc~wjDoiYJj zthL=y`5opcjOUMnd8xifn#3?zWsH9?N)OFF*LgjIn^V4iV;l*53JOf!@iz62egee> znwEYkpp+*e#1*Qo*8Nl(7641i*><8nb1(K)hXKx}&9le3|AtKv4RR~&X;L#GhN#y8 zSCK#G@HCVvrJptx(=n=}BTX(r(hF7*!;v40aggVDN}eS@+k3B|Cb-sxaa zhe3Y;x+$F&Zy&&!2u<{%E|r2MW&ZfUn%EGU0sw#8@EnE)fY#c;n*03dIgDC3c9IcLVHAYqI1&@BZTINZ)@930^6o@TfTr&dN3c=%KAO7B{*@o{H3ASlkefShtKAJM(Q5#;JS{1 zw-hx5sf0N5?Ic?iBpNbCq1R%ah{2y5IxezzkVBQv)F+;%CzImjOw_fm^9Li}Psg9DVq+#UX?*Wo;pXd~qNkEws{n_k zF)1P{sAaxvO*W@5oRJ z@16IZkOyY1P+Dk%%pek#9h_4fEx?Y0Tfc_`@z4uCq@%NcWM=c9cnd7Cxi1&gbdV6C zLVq$ba?v#2iZDStL4SZsw(S8jRK0&_2(as@?I^sRRxd2@{Ffs=4t1X?6oz_p*#jj; zjfXU_KE&38ToUTf6RCsE%*5%~)SkDby!#>$O{hZb4@8RF%2ro~tn6V@8kVa~aVIAz zipP!Q9Hgf)i|A2I$#ZSwlO|D6#yLUs*+iNxhR0!mqv>RB=G78UnmTHZ1> zXy@eE{f*96M_ajTs+z^8doLZr))|!tTcDSeg?RfRslKuoa?rECYY#6GH85YtU>E_E zC|=Zqy)hov;Vu_l#=8Of&h+^i^7_n5W&(Pn@Z?5N0ktLfWJ?UWD|DHIHDgt^2&j0+ z#!qh%PkN_K3SM@2utWh-eHx0bd`}j)z8dS51MMu*=@JYdt^<KfoZXFO{eRZGeUo?&hF1$GOX+R>$QfBXVl?jUW{%dEpzo*JH6=$34ASV}_CY zGYDh%1_>NCS7bxBX{=8Mu09NCs$*nkLnXu2Hxm zDcbnabZ|ww7Qk6b#A02&MErue`UY>CInqOC**}yxH6~jJqi&k)~MJI14R5wrCvP76Kc*?;cSd(LjQ*xsY~em~1ON+%juvJc>K?E(JOID~ zd%AAZart#UA~SP1>N*2DC-l=O*XEE2u}4tk0dMMr0OhbmRhrurlP7KM@Qos6a&bxt zlS&g3=@$sVyn>Hy$^85u@E`)j@DQaK8jb|un~cg}b47DJv%@l0!g%IDPgmgX-l~2w z(#-M{tm1DiwY$(h#GwVCj2GWe2=ijsm!5V5MI`NvwT;unAe~GK)+B+udoaKhP7Jk~ z?Wu+{g!B>M7W(&mJQHe^ncjhU2oW+8qQh}05&4HZJ&bZi1g&kCs`*s=Z#i~UKA-id z!Z7#d@hYkGyUlE36ioR8cZg1l2oyULA0jX9sT18i$fMs?5*X{F z+Z6!%ycD5zc9_`>w+g>2_z!xfao^0Y6C;;VdCvSSxS8-_o{vcM3v(=i)x#yT>$6g1 zy?e~0^f&=Np@lGnk%r9q+(j2EE(YIyqh@%QHHL9XWUC!*symuWZD@#pEp#jSU&$=$N80@L z9Tm=Vgl>ZB&WH|riq>-W+ni$=quyYCcw@t9r#es)oE9^JpWP)<6PWd~xLLwxNtv~{ zu-UE@Nj-Nv{z%_NUPE@o{*n(LLal|tCf3@U4SFjT4&T202K$SRbN#xhIZalm<2K8V zqL^8cN>`7;sUZto!f%rccHTI10e+p(>3e{q##Ur96&2~xAS?xVd>J*mw$1}<=-l}A z%i41b7%QSeUpGTl8TDCIf)59 z51gvRd1c!4DLh)|=zTfR4+PfZjJ~lH?NzS_DpZ~LxK20T*9%BykZO^)6?#V_#deh?xaoakkxEBXrVdcxrD$2H4B;cmWOf(tY^ zl7+7z+t_l2KN5%)(0!o;upwOG9%3~C0%*z%!%#;-Vs8DLn{YQ4zT7 zpgeA11eTL?WV24i6Ir+p5|^!J6#OTuqeD8N5VTUE3TQBNtJ?`m0wpkClgED|3#)#+ z>+@|vo>?hm&xmSua{fYlpYQd!^epDpD&v zXTqvN183*HD_3Jo1WjJ4=d2nWO4zxJ5{Uv4uAVbz6CBLeD<{2?jFO?n%e1BhedK@~ z%6uA!&n~aF9604Hr*l~~wuK8bbm@G|nu;Ayj}ofWdfZMMQaM&~=i}?TQE8lp88{-t z+T<;uusdm4Rxitxj^f-7PHo=^LJTehvSMTB?mhoSuASVx0LByG7a{?&D?9|#%h7NO zwi0@ji+6a)`q>J7ggeJjw~fYRiqH6ulw6|@I?>>g-aa?f{Ix58Yh7sHKQ#(S_s@zO z&$j&+rketD9ukp1Z)obdt6aT6$Rf)`3$ChU(#f+hx~-1PWka)-YD`I{WX!3ASMwWw z4||ho5z=^SqIU*$+C9uI<{e^V`s====*l52;@S`s1FeIZdNejb0+){ZQI%I(#rB|w zo}P#QbKHzA*@{|nzrHGXV}*bkMJ*I+!kM~KHPI{M<)3+#2C#=yL8iqoWvW;#+h+;o zICTC+0#Y$YkQHzw$eGLB&O`1F7lswZ`A|!PlIqK=Coa*K_ARMwW3_J%IyIm5S8Fql zgT2M)y%TZ?@4-09Pu)xoTRH&#olk@zpd`o_Z7CLF?fv;AxsuZNF(8O0U<2hDJ{3_5 z@+ru#S^e)~Ghyw7cug8BJ|qI^)Q$V_8GyX(6zVP$3uvnUG1#+j(vTJJRNo#5>1!wf zEqD9HDeq)-h}c)v(d!v$^o~26bu0I1NLRs z;soC{T{jZ(lFUDl!C<8ilH)b4iDQ=oV?_ckM?Ienw%c~k4YFtpmr;1h=Gu}E70y4c zVI$m-iCR7}0an7Fcx8SO2^R87NB!>q!&zp*Df<#bJh|>cme>p)9KY%5njd1P5&yGN zeRQ5=!9zb!r($&CBO&fOGp*NmKIK20m>0U+}{eKVcjOLT#Af4*~exNZN* zJ_ennE5`O0hpxZM5^r z^?7ob{D~09hW}hdKX5R!g*Sfq;MGAvXvXVdw?2@h2^qAlKcFLzrOr{vc>F++hY?NZ z;$2DdM$}_PvK?Xx)qFbOZ3C5X%s|4VmA=$M8UEk8b$6`}pf=6?r?8?UG#B_i*Tz+Z zDBXPTZVDu=>eb-59g0+QjyXjUX)|wZRZ{RFMr`0%E%cslrWCz?f&0!{twQ!LPo4p+YK+>{)ZzHRVIRG?aEov{uK;=kF}h4yOzg=YNwv;^Z<68DM_?miH;QoFT7Ae9 zto?^=zkr-!i`&fVAKQ;X--wKf)yegz3|s;Vc>pG9jfW@3kV;K1uQR=F*W*6?p<$<6 zITC!;KyQ~BQ8l>aE=Yn`&l-O-AA?;pl#8W$7~G!@n`GmRovno9jFlmDLI6T_0(>hG zq-$_IGnM6$?Y6Y){`vGJ)`i79#$KpSPP(NlMcjZ}YY(`2M?6cXnx}U|omCD^tBxO| zh#laWgHpUmLeo^iv^--hQ~TL_>X-f0IPE_GycevPW3i7ilgde^bbYgAm|cP+60qde z4i2Z{T+thPfo-3E3)^q;-0=>}TPn6JK#!$39o&N%DbF4Q!utl!!5D5*0HZbjn!=pZ*O#U_ zmqV>fmwR#XkH(7W1^2Lw)$rX@FBv#X5-;(ux(`&*hJOcmpR)0`jTOxMoqwVVs$ycY zzO`Pi^`UzxbuhRz5rmrNCD^k>Z&$Xzd<0@X(c^2ig`H4L_^B?mxwyo^=80F$is6z>Q_$ z*nli9$RI9izS)$AW(nVXdpgS$kff(6_-#7b%A$RsU}FT#uLoLe6N@iLQ^lhg)6_@1 z(qKa@nsq0oU+FBhR{i*2nM`kBQFkTWIA=>`Umi2L$GwZpl=^IT z7#S8B8vdnvVhY)4gF8xf-7Cv%U3mUzWt@z7opW=djvQ0--NkoKBlN8dbITP_&x)cf zbki3v3XV3&B=uj`0=i=LsUd!nuY;xCeKr@4<1lPVCBeGXPv!*GreUCsv8Osk^Mz_m(`|cjGw(PooM@K*fHCdQR)AVHR3CHGN4Qej` zf59-JWuS(h^gQl2ojC|`D&apTU^$mr#;IyAmN%6{30EmH$z2t67s#Ud4H@T{bIerX z6A5qoe9*v+&yAZGy|#s+w3_@P<-Qf~c^nAZXY_g$p2OOp!dAdP$7GaN!sfpdRp=t_ z__3a;>Au;htPU}Sw?94d8?!#!Pef}5Q<3C#w7$$$fGt?K!!Yh-hKtLg6Rb-E^OLk; z<6PqbdQgo3bn3$ZfT+=9W!;JV&gG$yhhnJ)i4bMo&KwU@{`CVm{?Cz`o| zo$)Q!wfgcjMyZdYqs&B%k78mXjCf{~Ox$kp1>_L3(;j%(YQclv zl%4lcfQLX*d$0h_y%-BDIIxMz6MZ%)ygyz8a4Y=W7T-IlQR`)O-z5twRY=VW={*X6 zp@saWYMtD*)62QHEW@(+Hgw$!M^X%hqC_3}m68w|-l;|gXACXaj*7fj)ggZ@4fSV~ zd$0lXQ7XC3vackuO*m)oZ3kTMG6tZR3HrrspfXFRBVPvinpHrFHP`kUj|i=sgVRA? zz2cVzT)R7I)i+t;4Ue{6SlwEkeP^8!<}I3~XOhW(Yk}R?BqXeVYtD}*iY#ZP$?e9a z2JT`X;PrTb``!38NZPiPKTe6jV68c^h`9?QG&88QGek18l#jOYVFF#6+ts73ZFD z82;;P`R-aD#^qdiGRcTuhV@~rM?$no8DTp@fsO^Y-9k9l`k2*yt9=PBoDM|WbjNX~ zHh-sXlnnlJ45b}`)XJ~Fz*)#BTpfErX;K@F^K6CYOd1U-xp!*Q#44ZfC&fvJNMM|{ zJM5vo2_}v7T3OSR%d+N*%lrdu(#0q=@d69ey$odiLk(|~T;5d%FTcqZV;ZqSpHl3* zKgry`b)&usu(zw_)o2Y=jRzNBSWWnB>LDow-GS6hY7BK0 z;qK`OFSdLi4a4kzrmGpqh?h9j?j;iv#oUV`!@3aMKg-09T8rJ94{d-)H;Kc#50af- zT1QO40{>Tb2>M+BZr>r{#SfNdCx}29>gE3GkTROb)gm;O1EvRB zL)ZKe9FnHsC3^nn_D4_E2(35dhOISI0ol<*QxehTd*RbGbt*Wb1&Si%uk$Shx-)pH z8w1TM(qJ=+d=tDBRo9;3c87MFst99Wp8r5{SoI6dhGiH1OPM@+ZG@7g;R^FjS#a8_ zt=+VIn#;8}^AZ`@2P3PB3`etgo}!-K9FdB#BsFc8CFqMsXZ9M$h4wa{T<GhVhn z3eLr+%^`z8DiXUcT~*=H9)!2Kf{DUbuXHxRcFDDcByApGA54>u@K`B5FC!y-=3tD1 zMaC4NJr^y>0kDOq{!W|MDcvyO)H73LwI1SZjKZB6*>yAgvC9Q@gvqGN!2|qe$4FO) ztkqZNPmt14M}WJtg9!ltKLEf94IaESg56}#i%MOwooH+R0qCWsT~#EXy3O-6xCJ-7 zq7ghpu}G4%`&YX^G0y(DTRcp_(P}3<7&Hz_R*N&Z;&x`9_xBg233Whz_!@Yq2yj-# zlw>O#nGomrc{n%ZEiZ0>ViFb=-9C_5w&M5)n`q zI`IK>(DqELj1UV#W&m=V$I0VKi-pSkzLn)6ktP3Mlk`h%a%55xA^Fs z5~Aljc^jU9FzgN~n{4zU2K5jaR+*bIgn;-}cszCxMV@a%y99E0F*o@dP|#r zLOXt-rEwtK`5N6p?b`Ial6_IjTP7sgx0x01a@Z}Jt2u$CV3D-sRC)x;;=Duq^|dIk zz&xYPg^0?$l-+_xgd!u+bk>I_X#!dtzE1s+@4R5=y&XR@{8z?2%6b&63Bkq-h>&a7 z!m0UlJ)uwNv+Wt?{fk!Pw{0SO)kmcY|ZHg!c09fF5z96J2 zZ=~Bzj?LA6k6473Fnb~BG_rz@!?YMp55h*p`%3TjiU)D6Jh<8{IPvB|1u8OcjrF+=VgTAr0ipr(LTb0y}SaLooQH`;F zl2e{N)1aRC7AR&m#|pWr=R;waa1dQ68-HVABenof%zVkz+lq$|VHWNGQp=XCA~r8( zs)IWTaHtoZJG6C=e3!UqvCLeBL!Z7F5Pi-Zr_uf<{@swlAxuBtVaF5sAQED6~*<~gb6@A%5#Gl5nTelSF)^Osd4i} zx;xKiUe`()o%e;Qqx7WEw*W8*RAJ@NVQb+GNHTZW&36Jd!Au?&K6u=Ls*O~Voqn@# zic&=y--oz1*mA^gm>D$JX%UDx?Eh81+m?0ljpDf~j)K;xpOzh?FM8bN2A;IAQ`4cc zytPl_ac~)x5<(3Xf^a41Iq;RGN)O(5&7|*c8M48e0FxwU-6p^mCm5F0jM}7@R#z|+QzEJXhTgfmoRh-`7Q2#8>f0Po9>1N%=))q4E#GrO{dMm_O2S??)o3wg zmCuOAU)tj}agH4AU{+`fPH;U-Kj6EdMiY>BYew>dKVKzylf zwSi;4|J6d#-FV{vJHn>rJuUp!LIIQI>tETYLKFRb(OS1r?Gij2yqg&2Os};wdOJsk z^$rqID&|_48yqwb*FGgzWyYefTlWxY9T!|0dg?)$6Jh_14HomscQ|BNTztUd^NysD zb5g#=m-}a*Rw(3W_QIq}Xs^#7B+`*c=&^s0|81Cc;6NT#K7&e#v4cN2XEGA(Tljj5A zFBpxt@4Ib}uciNV4g!`E;kAksmvLaay*$+Cr_TF^b}EXd8w5U)jt@9cYW)KTHDIc4PIFqC>Vcn{CR-OFFsr zJVzO(M6mWe1j%V?$0M7szc8ou_k4r|a!Y8I`|RNn7Qv%gAFlb!;-FEtayPisSaayT zH`#);_7SSl)CbbklfxQYG4+07bL(V)YJs3*CW15KgAlvlj>rSpxC`NeI1We=%ncS4 zUD5Fjr&cdT7BG4=YC}?YhLVCIU}@aE(XlF9Ms{e(5^lDh93o^!P`*Vo#ixJ1KmWOo z-x}Q;SQ={fZC|s{k~9J;rZ-+}ja!8GCcq1ouQ=@j(Wh(U)! zl}Tfo$v(B_aUk6U^ED40l}p6?rSpY-U5C<+v=xmI6yNzmLHOx^#FTiua^wv6rEzXN--$AC~gH@oy#Eu|E(4GH(F3LaqiT(GAqqN4#sAB?`HMp>F;5FPF8$#D#vOyE-TcCifN8cccN> zwbp;CnKU~`*xruTrz2`-p6fSJrXc@IA=#*@MLWSlJfqrb@h{pOG+k=I^8TFWznfl; z=LcJl0I)3i2U%n#6nxP1SIE`OMY0Wi#dX&)&j+}YrC6o^$}zL)@a@QZ`mw3l>rf`~ z9CO)#%lA!XD-|MY*27kaNcyw2IHpManbG$pX+@M*ZR^+Kjc=WclBxx5U$8pw{Bu_g zKjWsRI79Nw(A9b$k_$be#@{tJjksY004-dEFS$)~#OE+d=acgAx>o0(=xlOcxSzTdzRz9Yv#}4~QRD~qjVfJa`Ct;SG!K>z- zD7>C%tGUYoVj=Z->;yppNqhwLBRmxREz?HYvN}N`A^{8BaWlVLWU&hWJ_6D_xt66h#Y}2pjM;Q%szBK=8153zk(v>iV_qb-*UJ?eyBh;QSvH>uWG|^JPSzV zi*?Nr5Jd&CX5yeB9pl3N!Gt~B*ve3hjVUNaV;*gLJg+&Sx@TEK{tnt>UmuDq9vEib zWZ6%N<>$@HKfWIvAknr?g)Hxn2cTal*1wGMdA4kRp}{mefJ)(c1nYbvVtfwf(Y zYCp$tsb#}es7W7ld|wE3QnZ`k!)WHLiqPpgkZm^CLc=4!uA@8lrDx!R=WHi}2rUKM zfl}$MzWyYVEE!2?@TZMyCpFO^olJ+_@?> zTGeA-x6-SX3|Ep&)XZ~vM&e=xc7rt=33i-Qy0&+sj0dz}+1|-X_gvCzm_p70sKGM5 ziTfkNqSG^P1(fPN?Ksp15X%LDN6a^L)c6H5xvUC|bQ?;{cBlJw;(!r_5S~iG_>t)C zwA&p?MvC!8ftVIhj3*|@N-)|IecFB z;vuU#d-@!nf^Cs058P$uYcrKRQ&z7%Tf;#sqRcY7WZxd8I#aQfeb~4_mGE=)zSp#H zSr@f`wC_zIK&q|YF&Ol)Qe0ZKbyD+Omj@s5p)&^`zXZJF6lVqfkRGSTioB)&th|vv z_Q(O;FwkWB2eo`lAzBU(Tu1JzU$d_k=jmx$ob`YaFPT>_YYAYu6foc^yU(pV%?S{d z^?GT+|JCqbw*xkTtYOqPo#aK7-?yz4Pd6?*Nr~1JRl}wB&09uO)lWpJ{px5_dj^nE zV)^=jYz6|w+k}}T9rEv0m$i|vZob|l7x^A64GObGxRW-hFVl~M^ZxB}e$j-c#)tWL zHG6R?f=xxhDYtCtL-^r_w9>+M^?Cb;lRdcr!hMr)TOs3KVQU+KL$ zMw6^s5+5E}_S#vu;WUL;Bj;^)qBVdCQ+O(@A@`Us46ivS*MY1*nYx_}{vC?WSG9K7I=^H2ZQ>T}pkk zZQr4@Cl%NTxOw8h@E(iY5b=EQ8zZs%8@TJncuT|epo?$;%IE*fE1|ubvXtBZp}&<#tLHZ^Y+LVMl=m@GKia@ z<8k3a%Pw#T;dv$o-5vai!b#i7aT5dHRDus$s_1xyOikLv>XetUaHs|5l&logXEgRu zc#ESg0>+-fUv@)VK=;(kII7; z0uk80Cs-%XN+FH4oKkNvf_v4o3#bdnnAeL;d4ipE<`<6~X95l|Ns(@lPbTLj%)2lgZHZr8E%pjM#bk`}t$c>)EddndiL!ssUS?Y2EW zokd?1nU~K@XPf_UVGtS9RwUfn!5a+MpBVbL_(dTN=bOLQS>E{wQ8UDf=vdl41x*w# z+7h9=&VDS#=8sczQ$ezlO411wPgZ~O`RY-M{1!icQ;iykiQvMpwk{%2JDNHMgKE`2 zR`g8>QVpgyqcSr&+5HwD1zn70jvUf5Lu<-(|up_M*Xh+m8zfrQmA5Zj5a53;uN zzy>WlEIsZ>j}dN+FitpuqGb8hoo#f;6Tqx79O@d}jkKPl9MKy(0@UtqlHvxalo9G% zX=Il8Pn-#*5by0DfGa4%j)diR!e$G+%HFx3ULfI*1bxEvP<6T%x+3u4vfeh`b!Ai4kk~#b{ z6I+`PguogOPumIGZoZ7*stW#?v~V&kN*J{kpNm1_nW}&}FijN(kZn;PEQh9>izC?~ zifjmTWi_pgRiAmo`5vO8!f9-LC!G9_3ihf9BeJfbtMTSk>)dZnD3NN$V>HGOe`9?C z1KjZL%<*4Qa2SIDq9tENeD+eKE*lUtS~>A^kt1J-*xR@BeOjPO(s?Ne*n2$X3Mjr!=9Lu}F1$j28-feKXW$PPmID zAq)m z+6c0k!-jNHWV>h8xPg5c?Xg$2z?lGuhc>z;nE9T`Sv=|> zd(*b-eoqDN_bR0E7s~>fl+E=FwI$N6`;zopPAZ_uNMe2LKcUors;Ihs6lWn#5M(`e z(zueGC(RM=Ym7>3AZCT5h?;lZ*5QhSO!iGjo}I)EdjS_eHMF{W9N}SoW(c&tpN^ju zr1K;#>I-K?XiSY@i4Ti87N-6^f>ro*wuDrPb^jfn@Ab7#)xJF*jo8 z09b%{`3xG;?qoW@XZ^M0;^}C^pyrEX zxzQ(}47np+f`aq%w$v@or)%u?7 zdK#2s@h?|i>oO8&Pa`(zP#0Ui5?^(`^h3LS{j*>B!EBozQh#w}Q4B42AIRe-V{ew^ zWp>wa8GVK<`F;mEVDTwW)FK~^>FuF2Vw)Lz%n8hl|5__K<|YROS)zaXWR=snFSdq- z&UkximK<&BF6rYGI!dyuHJRCm*Ix4@ly{*wbjyT{>5f(m!fEWr+oylmY{5L-I3X(^*dRo!Rp8JmM(v&LD@+i{t*DQ1?oRKC*s8lag1#$YYo*Hhb z;BbfK`-5K3RT6Hp{Lg8)LulBNOG(Zx)2~)x7tHs~kPH7UHr(WV;zUM9iEWw|{tF_6 zvl2U&B7J#W5ghKA|I6bK0^bjYo05uaSNcDDeVSP$4Zs)O0hSGCILo=U9c4*n6FqN) z)}i!<1G6)%Hr(7X0(Go5j;QsmoTdO~js2#6N(^r!2GF|Lrc7d^K54rvo}Vv7wa6t> zl~3_fI*MG}GD*7|&ECnslH?C*!6z=3wURML>OqvwbDaK{YIigyPvKiLU4FJt?@Qd?Ofngs~O`E{ygsW zP#}Zbi3mYYB%+_v?iXD&01hW4#-b`W1hD=?TZ#*J!&|3+KM|DFZ5Z^@$g-vj9PVa?K8+LdS`j3Yt?^u*ua-`$0ur&?Zu0 zfTvbcJxUriT7f$id_*B!TbLlhWw+pXA0TVA4{D$pU1lRo6X@gLAN*$?0^LDzeCWQ9 zsL4@}oD%@dI+adJWsJF8?YI9Kxc*E(`W^ySqDz$$7-tDEFOZXWFsx!3W0z-g^{&Qz z#x$iQyR%m~nM&>}gUIg0xlO`=<_CfTpbZ(ep4!=X1-QUy_aeFfS{f?FuCVVKd=sS% zWw2lFbk@7v<)0#nSzuD+p2EER(4=27tw!O9jv{*{{y8oZHa<};bg&ykgP)59^|lw$ zIpi{khej>by(5?l-$jNslc<&)mii(VZQ}efqubAD)tfVS`KbH? zUni}O2q>T+>G)E;$lG;G3KK;-X!8&=(Q*El-}Z#3iVaa#)3j77X%=YKbk3)Ly-?Ch z{tjgMpajB=vq5-IgkGZrr6V`U!Xc;5!lhnzhLR3UyMm;!j=0K9!m)%?VVp%Kj`pJj zsUFcH^>`V?s?z*-A)PDp+KRtPtLRx z+)MYG#xX!IjTo!BeJ`EIKp+dvw&hxD=s@Gh1&J^NuO3<_?CDbQAOE6lMe6E4o%Qi$ zley(rlrjlb`DP4C0!c4Lw4p0je85j=9bV+4#(_)>`L)f7*tHPHvSZENmD>#y>{oDV z>o34&$t&`78BeB775Q~_=M$GvNw=}+Z>XZ`gGyTJoAPa$h60|6OnVTH4s= zv!?3YTcz006DPaR`Ky|x)?!SPDWupq{auRLo+!v}^x^$WkZ&lG(+gsYiyGJXXE_h? zDD7YBq|Y@@CshjPGYbj9KcUi;nx>-PvI3$0phbBu>!8x_FV?h@M2QF7>~){(B_#UvIX{y8rOcbWA#3-sId)f3(@rL%so=>IG# z7_C7m*`gW88Db703|mK3)%O~amBwOi?gqY`G6AJBn=Fp10bIs4(WDXJTChCLo1n#?czeC+wgu0ZSLz)~bUCpXB42Ijg(!VZ`b zfWvbD*1@-t4ydFNjM`u)ttmC8VnMtC^`wi+Lf{r0yXGhKeu5ce3-_t0)$obHcDgjHnQy&w=@ zO|%*D*&vEfs=`}ma}b=IC0INF11V9Fz8SDVS%yX9zpanOjF1Vn;ba}GmpBbolXUN- zImUN)`vr9Nh7-QUu`dr}J%AQy74--el(71cL+~4_wl`CZA>f}C(#xSnt>_P0TR>Ie9y~9{&%9*<8XN=o?;xSPUAg0 zufd5Yo=`uD^$0_ZKFJ-%7TbgTr>#Oj2#+}wi~W+2TtM$@J^L$Fysm<0N?r#r>`)6f zrl)+1RiPh+%_}(VlWWLWz}YQ}b>xmi4Vn-;H-VeK+JSphD^v7}=+au_gbZUF-(IC2 zsKwJdXpi0rLd@kC^^CDh4>aiUsgRi7ERS8DwtXT~r`91$A->Y}0`aef6W5Sb(-;a5 zbYfO=p;{OU?OAHRj(%OWdgTw${AjHtgngZbUZq-}-^LdQ-9j|QFCL5fFyo!Yi%saC zjMZ7vqdPZI-UOe~1jJI4-hYr{rV9C~rvZJ{$=bmn3=^#+<-a#+x1Nx z#7(ac1EPBAX2i^W?JI`3pVLchWOIZE%=3J&%7L}pKNwDxC6wAB)I1SdE*VgMB62?5 zN}^g8yO+B<3-8w#TC#n(A2Vu{4inB=a`o|+L_+S0gfZ7bRTLt*W}??od-;*3TvGI` z4z?`85bt{?SC(l-^6p8JNegr*%D#d2WFVfjh9#7|F(R*Ls^hS}?m6~{ zuw66aV-U()KtuLJNmIpB*!Viu!HMEh?gNe5U-q%R9ysDB_vzP+k?Z(Yj**_>h`3p| zCgZ8cnU6XlwwPe#wY5``!fClF*NnSAQIVRMTSy=RIUtTj27d>N3bfq?^GUYQyF;1a zUq#B~geh=MvB(7X6D1~(=nsx}X7?(qA z$zYgk+dz(R=Fx>tuEWzi{1-qo=x{<;>wfcq=j#bewL8FVQ#7bA6LI1j9^@lNlAq>M z=h5Ony6)6-hcjew$`|IKQ7;9;sVUwz2({nNRu!_}a%>3&iff$$x@D(FAsr z#D05)0W>dn3$2Akj-e7xbL&`zIXOHU7Caa0Lj>~jP;)M4E>xDvT}rUI{W5GGf76#j z>zmmu;KsTDRi`%%aQ#8%o40U7jU=3v1fSsy#s{ho_uE6qxF%?*kVpxwy>&p9N)w^t ziTBQR$Ec0hXrh>NoCdAw||PFV<-)8*xulMRKhY0VVDWyeHW69JI=rO8*bQOYYj^)I**R z6m*ac#w{uP)oy(%og27AG4xo*%L!+OH+X_I#joHewrzzsS~a;cI$!m}=pP{3qOSQC zU0%7-n$lw-(OUYP93)4EXxId2r7k2gG?&PrO8Ym{yuhw&=`o>Y`3cH@5aIb;^rkgd zrS*pag9DI{CaEY37i8ZK>e%=EW+Qz?j&bCuvOVArjOUGavA9PCTasLa^lj;#TPjalkUl=h$<835fa^R^qdVQ zRv9|-U%OR49n^n0Kfj5I)M|MgIj9`@nlZo2WGpEf8;Sv-{;#&SoSY@P4z-9#buQE> z0*vN3#jpO(YwqfaOh%px+5n&~=w4>EeafWDFHTC$DGeuDc5?v6XHaF@Y?gVejpX(_ zOZ&_?Oz&evnHH>MTw;QRuB~}5>T=;`;0E4VS%qRVqxu*H27Z)Kwses$pOiyQ?8T_eT!5@$q={b+*x>()gzo_Z;ef} zxFY(L>i>KuHtuvRS1uhwDxzEYDpYJVGaY9JNFWKgpr((d?Wg7f!3k?ihNqUCOQq21@b8eQD&=&o-ana^@7r-GLP1jR$KV)qN7`7&DsXviwZ)XaAw}4lBh|V}Yz;BU(aB|EkKUOsb#TnDIYxJoL2 zu$*zV5){QDG|@QkF{|uj6?$9-DKZiQM0&%!KNg9A77xyUkpVTL}&;57wkR{Mcw5;&1X{c!u3$RE;)MqmjN}TaT>| zRhmm?_1PyLzN&~DB-?P{ze{1PffVx$y46k`R- zW3zuD_kqNs_Tx#`dFcpGKby4C;>wRIY+)%~uN^`#cGcyjM>?I431M_tnhb8OL} zORVo)H^6C?mQ@Y#fM=X)^MCHGm*RQ0&&bM-q!DKdH)&d13=ns53$61z<5n_x*&~XC zXG({Y0L&q}75PC-Q6dsG?pH;-lSrAn;VIDd#UBy>enxH3!ZmiQ@m@Rh{NTb3$;40^ zzBiR4Rn*r~>`=`9R~mNGg6cWxox<*%{4Bl8=c`*+im$68m6O6v%Ki6bfQP z=oOU9fZgx&xnzuaqIMI=InQ!jd>%*%P{N=ShI+ITRZ4(j^Z?@_yW3jR)qQ#@_Xv*q zL~UqiN$ONpKFO{rCrq20EzFR>58xR8O#6=vs62|lTh$t+=V*kFt!qgRbdpPVz?GWm zp-6lM8<+#>muaWd<(v&(0;HpM#tmwai_tU}2U*m7+@Bx{7Uh-+D3kFDN_62{MRWK= zh~o-%3&6*b-Qf^x8qe;02Xs#!%(a%H2puIL7GX~QsP)8D@PlL%_dbHwye>ZyH6#&J(FPW|+P0RABJu?tsprCR2@pUMjW}gmhD7K;rjA? zvrCL(PTty^Pk}4M1h?#*hxE8u+JDnEJuTFAl{3GbwFIr!=pNNgXm6%oWFEqF0VE-1 z5^K+nRMcNa6Zry9KI|QC)e_%PX7WO8rs{|CuQgCKgR$%ikdJ0V!k&7%kq!7Q{wjag zJn>C1%b5*L&O~8w$n?;YWrI5|;zzV>HzVQIlGGpB`1ysm(^|v2Lfr=-LtkM`i=y7B zxV_j@Tp=ex&4N>%fn?Gsh0aXnc@<%nG*RX6y?+Q?xhq902!SbfM(?HbB^M{c+W8`v z)zoqwChF^vPzv$awbSRhyvo*!q>k8!UpdX=nEXK|-MSem!1gLYhNMnP5+}n zt0O1|7}^00a%Aa@q=m^6!P(D`A1X5g!DFw~4`EP}jAQ6P@l=US_bd@4X;nnrnw_mCWMnJ(sfE-A!C!tOks575wq5)L7v z;Sg}&`BqFh!_p>BEpQ{IfW|FW8&BBM@Vx1Ae^%G!4s}QO*eVi{D?<0c%Lm9~xNW0p zk3!+lY>f&H&UtuZVzTXX!$q+gq-H#Y&E!|O0N$Kqs>;%K3{wGVpA zyxe4neMZ5&qYhxec03s+V`fwep1)yBgS-MO<2O;I{Qb+I>T2I`nnd#V-jjqoRr7DL zej~7P5kq<94-@6<@jU%$EsZJ2fM`^Xhi>@y3fqtl^`@Fty(~A zzt;p6m**U>ofgh)k}-kvWP8S)36&!0d?Ko;L}Fz=Y73slN_2!kSk*CI@!u>hL3fBO zx7zggKHUet9pC>QgPzERHvz)D*l9n9)cxf+L#@Nhh$e&8{YP2Mi-hg7b-NlztF=6V zW%)E1Q#CY7GY=tDY%i7fTwlq3KPbBU0r?%_WiM8VkXe^TOLzKyXaBiYjP?)+>GR=Sj{?ZMS*wEPqSolWJD|$ z%SbFi;r`hS4SeuqP;n1-oSLy(BfC z{{Zr>3MNinRVFA!7kk$`diN+D^NP@nN?ZUz^MLC4`kg@}eeYmm=@`thvJ9MKRT*+7 z;K<+PN}UUt8TL%Pu>SU?;eB_yH#nZ-|yoqr%0#Y%ssfI7&y zExk&?Uzq2Igs_a_YgAteJtsu0crtO`d@ge4K*5fpenXe2sQ&7SCTv|52GhI{P&kD# zP$IK04t#-XW?%7FK@*+sKgM7yiK(O69TcMWei>VxH6xTvAlUN??ZkjB--HJ(OKKX> z>Lz{$BY!u)S>%d*t9T*-r%+Jr5_!FwoUoF9%<3>oaZciz)<{P`GOpVPqsDgdA==IV zotz+yT;%!&ga`a+cTQCi0_HI7LTU~3AT0#_M`E^52T7^a8-d&fsT8Z&3osTRQk3os z=&$v2CLoHD^a5RF2;gnh{;LZRChC)K{CaS|Nqtw)VmF<%ARDT!F%dw^Tf=l5dR=7A zWyK!ai_99&C|c6peR592ziz{2)f9k#%3~0*o8B-y_S)VPE zk&e=zTx{QDQ(&SX^=Vj#kY=m{?1>bl-FujcCJ{ZmPswH}Cx_Htij=nN-Y+=#VGsQosM3!Y?TFp!s(`A06=J~LFZ$2Z z`Ssm7g$8$A03tWY;q9AZl4^WBM7mE?gG!}=C?pxcMy7;54tU?+rBy2ZT%Olnc8aTK z2gBX+TPOk~Oe|kj72B-J9EqvD=K7U(c5&6T{JS)2%JdMKapuHFrmXq!RCeovf=S2m z;`fYRUg$@o>Es{n>O8FfQ!Fv=pWx*}i&?0sm*cDC3vU3;yNEXo;JiOUhL zfj%zN=FV(xk#Wl4{Sconh(-l%oYt{gHoaW8@Dn+_!qu-=i2SR42+zWO#Q<=90G&L- zS)@7XyIx0y^*)n^N>RsqY%4l*Fzl$9tx0koLNV-#IeNzxH<93RsWn~hQ79G-6XaoJ?ITq*v1d`u|M0qk@^NkD<+Q2E{;&IO>$K9ZvycTq>r1O`s0@@cZp(a%-R z4HRBPv8*X!2zl0Qwm@uuX84g2>Fq<^?wY(`t@g4DAiBUM4KDlLcYQdDvn^Pvu+vnO z@q(y&zUM@s&QR)#)7Ff3mG4*7DRlB7E{MXG+!I8Qu)*g8Av+YMTH$OJc;O!?L;@`J zJpD*3_&?NTj>VrO>1BdX5xKO*rlEdLn$K>(w((@_R zxdybGD6uUnUQ5Rpj{%e#2)q~SLY4?LKsx$I6T8Sn(9qo)rJNbM?@Hg6OvOJ( ziqFXM)*f+gx$0ZjnsfeTYawCe4$VWc3*2K15vHZ%3FGMZ8JI=M9k$F^VXo*=2Q`*| zRCW@O@S#5v1Qy4+J`?a2Y|?RaZ=JDv?l3jj{M{nNm;NaCe55B!B z4hMSUBVHXcjbsaVWLE_Hh5Dc$`XfCZQ0vhd0i8JXoaVw8VG0_*2m!S^*j}Qh+V-KH zp`7T59kAk{@xU~$%PZX|nL&V*5yFCU0Y4AnP>*c)?Nx;(rn$VlYNC0Yr{5VZh^dpO zLW2zUu?|d>UcB)7mqBqu;9{y5sWS4*@vLdnHuB}{bxCVlfPLK607J^8=q98$WL<3O zTF)9>$zz%vhr!l7IC%I;yw?5_1$3f^O|lAbrlmht18D*NTk+3`-aGNmoy(TsbAWm1*W%PpfnMb)}LcDi) z0lP$>L9s4lmHZ;WQwjYrZcM={MMIB#MN#fNUE<(hc{I8A@(RS<8$&Ze|DWy zsNc~%>GwS*b>s_97;HG?1Hhvvi*#MCN+f+Gr!|KfW0cyANbski6sGeQ>s$E$Oe2jt zmVRWmP)uj$D?8jsGEpU1Yy%KsZa*==(0G<)A&jepwSn9_&A_m~(;iq-Zdy;+X)0hf zK)xMznxp04$e_*#wN3F4Rakaf+T~!I3mHliBKaoZQ79q?O}_I*+}wJrtzsmT$IVtn z8XVs5%Ga7D%Xz|i>1aD+{P7bm#<(UU8aA+--aq$78b)`F8N1XWN19v@=?KVpPu zPjQFj{SCO$dgFC*-~>V>plx^J0{;!QE5^aWD5o`5%819CG%uyLu@kbepbuEoG^$5g zGV}?4GCAip-jAPnCj~1~#tz$w>Y16Idl{WacZ{zp{KbCPKlUp9MGQ&lMkWO6Aoyp3e`5Iq zSw444K6JI=(Q6d#>GfXJ%qfsIIaRSua6fYN#xwnsr z)lf4!ohzo(}^R^^ppvnP? zdSiPIrkaKuI8B6X7g6(l_3Z?hF4yPKC7EvTCuPa*$8^~Z(GD$2hep%3-ZVj@Iuc2d zinxN5+TL}csH>%jJ`lM4Kp=x(Z$8#(tnD9@m?5mGQ!92}>{7Hp6TzgJgWdVS)LA6W z&W9=Bz8c7#3;J&GQVCqsO3dN;x#!`8Kp-@pEbJGr+Y+rOTeA~$STJI58&~_7xGVkPu26N#6(iFU*^Am}a*MQ_|#G zSIzKR=X2G4cKuawb3XgHb-iN+rCbga8uOHX?C~{*gG6~xxol@qOqQCBDsxkWg5-Eq z{V}&)T_+IzkBmu}ur8vkGH(>Wzy&`7XnLgo7E&$YgE&BQ*^}%AmK#4@0+ZRV7_aEs zXb5^PMA4(rfPg0Hl-|xOyT{3`qn_L*x8} z+<|JCHTV_%Z4W)-a`qA?K3q4f;9xwFFx_T`5i;01d}nCg_6}*%Uob*^8@*O9F}`1N)YK=_;VP~o;KsOO-_JIFo3SJnEjSrswEifb!j;}pSYw<(SMdV|ESS$fU*gk?cbJk4e zaGe0`_JI9_wu{UugC$P&@4$H48u9X&oo4j;TJ7tnM~WnmQb*E)n`?io3%3$onD7wS!qvn+9Df=9LLmd*&nl8qM_|2` z4xVKZ>&jeeNEU)PAsWSK9vlIT9_}~LbgQ0VefwOzD7WTP>8hu0Y$J{OK;{_3Dc-8k zez`q?2DzRAUWkAZ;Jtm~W2GfcN0r}#R_>t=2c{gkf(h36i(s?OmR{mqn)~zQxV5&) z_IUd=Jz!Z(+S3`oK0GZP(`G9KDKTeqntr0#Fo{-gnV6IjR$Eo9HX$OOkLrAKAepi2)V2i7UK|Ah@YqBo%0ZvvG8=5$_&cRTB0mz2@Pb;*-X;y+CQcl^s@Z=13<4s`Z5yA}`XzD07Mgj*M z6{S)1EL|wACmzZh9rS#^!^hSMCQ$(YKLEh=*H~QIL7#}QA7q~FJ@&LD*hUi<()x5)+>9}LuL9~ zwz1V30=KqQeQ=|z+LQ~2wM&qB8i#Jal?wrvu?5)zyT<(txl44*>CO}zr3K`v)5WlL zY(v9zL4B&fPUF*EhjpJk2fY#mL|Z7c%uA$FYh3*;pOKz|%@GpKwd7q!lPJV}f2ofd zPj=@T8ck$|12V#$8My z@NmdRS>yGkvs*+>0vYT_ps<--_ZG#oP0rw6XzE{nYywh2qzshBJBnqvD3n7+r;IaQ z2;y_Lq!|sP=bqls*G58to|2mJzK^!0t9ila-(oe zgn~>(_x)fY*w0B2IK{Ly+yI{WbPGoYo=kEE2g;V%e45*QKW+3+2Km+0)GekQN8}mi z1{KA=eG&T(m;ncxkIJ~l)))Nk1X3EJ;V;kQRR?{P0>LMjC$>NhJKxBZ_YR;AH(XL_ zlu;-}#tIBQI|HziryM=LtSDJP^)B6eEL?%OfB0aJmL*ozh(oWMEJhK>gc2d16(E$w z7^CxzTr`3Te4Qp@#udegK@$`QV?tFm&-yzCTc3NQ)~MALy9z24$%Upv>wrdSUtc4q zXKiqX%d@?ry`>NLc^1o+QiGruGtzx?3Zz?IQ4wI`XWoiF6yEA(P!XGB7|Yy$Mp2yB zE&E^~$zKFhur~QY}zw2$K`izkFU6AL7fTtZ&^p>Tz1>>@+;C(52i+ ztZ{&{gF&5;;N?nXFmM9+9!2Q4hqZYTc1MT)0+?@JcyVyYArM&@eP2@ub&GCzl*t+H zfKK&DpEd*DbqN551usz<%p|KK(inslj;+YxrD{Xrjt}W6GV%C6s8k93lewA#3zyB1 z@b1fcYW&+YrEF6%ri}smA+$WhhaSOiZQQ2(yI;9oNsOJ;KK^pBwLvS_knAz3SP%RP zpGG$IFQF8~=iOuXUU3^0&LtZYa7$PBTrIacZv@5SMKl|~7rFpUsdh@AJ zVE3~xqth6Scm)wAkkrFbe+}{u?fS%EFQr;odE}rLJTa|B*G#5zYP!NER89L zFYdXp3Zy!Zs3@_`X%a%9oOsFS+#(Q4OGK7eXE81O_dhl!zL8B7@F#S!68c_UuybUm z6=jXJWOoY@J~9!8m|b%C`P8PGAJa{KoFZn zx%Jpt1W)UX6u4J_DRk};fzTNNy;X_e^x05{zIiYQST5K%$2j_D<3OQ;-2-MCC^2e1 zFsBA{w7RaTPvMIej9;1Ep7=x58N~mZW+=w7l<#uF+m$fV4iAxs=z?y2Z8^EwuTJ2( zxbe(1u{bcnF+o-cXsKz}H^rZxl4|drnEq}^)la!?W&pY;gd5^5Uvd}FV3l@lemPKZ zrDyYC9CSFtii7q)y8zStl8-Kj)-y|r7PcM&I_GN}(1LHXa9Yurj|FzJrL#G`+=t!w zCe~mAYXBu%oZ?x+_^(dx*jJP<&W85tlm*Dg{T_`|Z(n=#UX*bTXnfe~ATE}$1c}ZA zV=y)V3+p^0@R@^MD{w{s{xys4f;b>+UEA} zy9?&U_)*Oz3=@+_$}`^q7(^%bh_lF#SV0FOp*Ah*^GD@&C%0tU@-)m%Kt`c;#I4lM zgk$Dm0GQP4^AEtGY@;Tvw7k4$TBd%qQca}5D>T;Qif|+0Dm)m`uHAN(5?w6eL!%D; zofs<%aP+AlK0+ zS+AN@QoAJ!d1_?sn%oO6YJeJbTil*U(rI!w#bRd)hrrug$0^#}qeqZGfFl z?P3QN&F_1>uVH2Bn;z|{lHAwuuzdsz5(OB^hf6^B!u`jSeFQ@=R3ro?v2U=sTI+G1 z2i;8#vpy;*)$phqGj!%1inxFWcEt4}7h!dW3a#*2erO-VA&AB;HkO&)QDR1imSZ_i zfPxG^W$GkP7pN1>NQ{kY37Bh3Va1#_WLgiR)lUVGAb^6Bd3-fAdYyhS`mJQxyFnT+j5G~9QDJn`?)+q~7}XARv=f>GMc>OjR}PmnSDyO=Ni7^@oP zcjK%3)Js>GkYPjCL(MuYX-5XB=sD9$AkFh(HsX*6)knIcq9PamqB~$8i@{6)M%ZxgKW;JQsS17pn5xl?z2hGhH;(2#=7huN~XrjxD* z#r!rxU+gj`b57h2t$ga7{tII#;J)z0 zw4)=0#Dlm=U@?=_y8Kpb?7SSoe)l5hb-J`~d$xZkoDgMRQ4b_HgD|yiZ#jtpIMBUIs{1 zOm?!e7esTUbT@f>vH$D-0u=nW9ET(r8MInd$wUUXU)`ph@5}G}97jVscZmdjPPjCC zdJGGq02L0G36Pn5{b}GvdVY&6LeOyc#;P;|ucL*3avvz85UV{2W7ZFnw2@^h-g1wF z*NrIwV}DU+e!Zkjlph>6Vqpj!_q2hWWqiOqFZ|AJBytHx48`C#$7G;!`?G^FSR$iO zmkW}+o2}Fj`B;JJuz#o&yCVDeqD`?@JTMYA}PuV zkG$2|+b5r|vwGJy8f&%p!^xMBZ$ve~q2UO9i4ZV7AK2^EeA}23p3r)cM1uKL0R}gE zeGOCj%T4;tcI?y}1;5n-;1igK{~o!R-e3Z@x96CjE%Qdx=9rM4N-K45n1GRvsL=n+ zER%R{=Ax-H+Ux2PhoKXW$?L-Zt>WHn#qtl&#-jwSQ6iC?7eb#@bMA_iB2A1X5peuHwx$>?HZIFe8yOle^-UQ5KP8M8g%hvhJm>bH z0VJGNvl0rku(X`|LXNL2JpR7iDay= z1GmmC3dTbN@cYS)$4aq8<(6T5eHdR%{CZ30tmywRUu!Z?rol|sujXyXl`B}NtoUy} z#N9^szOa?l`TU*pGyotK}6h-VFLW6g?mTbh2+s<6d2^&NEy#znU&!%rpuV z7nNjIf7WxDiWPP7XpZwfZ>$%LsH_^FM3-fVYEk*>a$lo?|Aj(xFw*0@df_QKXd^vD0?X5x89ystc9>vbiEn zERkNv!*0#p8fE+W;wDaQc98W&>Zu#!Q+FDF$`hoBC9(3 z4eDbxC#Zp7K+MCq043lZhnWEO&3?Nb{ao7(T>^Kt3%G4D2;SbmFa%kMGuAU&6by;J z3L%ndU%EQq2~!n}ulaK*V11bpV+blZy*q(=);CA@0bMcuVLra;Z<~!p{ajcX5@Z7F z))s3(J6T_!Sy8zPCGR0eK%Ao8h7*gIHEAjC$;=W5ow#w|rDBhsI}9&(V$ z%?x?`KF^Tu*9e;D!1m=rsMw?cYZ}QCF^P0h`e@p>lV$FyAq)+E9kA#LQYi;2V!vs1 zulDces`OqPJ?l0h6Qb3Quyg}9s9H3dT=Y2FVuO~j*z?UAAI0J6yvU4^sdz0Ei>Yo` zI$o;jBBME68WTQ1`bdu;fNL`wC zQw~{g55kA+*C78#zzxj+^E68x6aXZrXru4aFijqf+b&(1c}Kp7mwlw-E!cH=)8JVS z_2dV>IS&~xsEjL@{8jvCen!35VK~fs7fA(G+cDajSIAx`K*8;=K8_IiQxD(!QY;lz zpnm5=Kzd7EV*R9Je;~*_9^)Nsl-Htfo!urW`dK7KIqzkK`9tj!SZfZPfAV3jC_VzG z;25)Ye|h7BG);HFX7T<)7VKSh@ZsmWtOIMyo;;)0K^+{GluZaAx3D6Y5Y|tYBKz2M z)%a@c`0C8I9R{|h1SR~eL?`oE$G*;OaGO8eNFiIbI=mWj!}NM-0;vc*e+B7!tAVc? zAB5ZAfeOnr4MwHv!_W#RvE>US3Z2`0nEPgyt4RBD`(^0-A_GV%WLY@5HvNLP_u3oo z=uo~-Qgev5QPgEjrmk~Lrs{72mu$tGxOaS4cCX;rzs{Z$9t5cmIWBntUXfxh!?#|)ta`zqAA3&q#aRpi*c zz)FQAw=$YW5V#z97Lu8WmvSx;9TPq|kT4`qv2#q-h1?#$87^=!kDOWh^+oK-jo3in z^GyvIi1l$z7Myv}%5Rcrk55V{lpmK4Rd3R9y-O2<>M;;5e0(CMQ}QDGK0hab`>%N*#7e)`gpF4 z9+B2X!({J1i&{y3mf3ajr`vUm61#qM+MZ+I!7y;59hyyNBh>@!Kyv2qMT@iDBzMlm z_cqL2F-n<=?{5Y147~28-q!M0wp8Gy@>HyTxYR|Vh4W2OAQy&hrr?fz3g_75vC~~h z`;kzwt=Hxs9-}s1l29`9&I^-P46eZ(s#LHE%Rn=NQ+2w&P*&m7FFx6y@&8zlnt7?B zp*{LJr9!Y_J;?bQ;S&d1kvKyw@oM|o=lM?xx+S8!pVk69qWsAn5hWDd{F^~eOwxrS zENX1bFgGC!3%$~Q|GAts+3YUoPTWiO50jq#i(u85Wso%|sb>IakAE(duu%Kc@u4f6 zm2EioEl6~wF#uqGp?(X+E+l#%cy$QXOV9nKT4u;*^0Pm&s>Gh(KA!s;ekEIOm^3nm zj&N;|G3@l_c{VjrSRg%%<`&l&5sy1cs$ZO$-_uyC>-XFQ1*I;eQ+LAz zfc0-}Y?)CZ@;wC*x8sbES|VsZYl~L4i^Qvjlx-r}9h{-7d7s`E>oyrrkkikCs*PC* zIdyzb!q%%XSg3X{f4?seij;E3p~onG@7L8cE0Zl>ut0tRQ&o;-h%@UQq_rIjBGRPH z5UiVAv8aIc>p0Bmi_p!Ah?{Kj*{ozb1utT}G*=`c7?U3{iN5^t+q;#Q{#+j6Ubc6M z92tB^AHR*Ev^pSIJU7d$C}B)QrK1_qyIp{SE%YaCTz(I;9gs&89!0O#$nGgW5IJ`h z+DJbmyGXb%224~1#agv+pJ z*t&$kPNyh$jXJWjyiZH&L`tZ#IBM8pX1>VkXBKCL?G;;|J%Fb^j}X{P-x~@7wtNqASh6z zjP%l#=LX6qr&q>vwTyXf%8Ntk+oFLIDkX8RD~)IrnIk3I)x*-n??+fat}WmPU%mRy ztH>PAbP=LpxVqMwo22b($^mfyf4fAgKtbLaXtev_F-01?u14HXVb&kiv+Ja-=^oj83mjDW&fGL1PgF?ob&NPYFvw`@EmVgczEAvB!@4l_Omp<;R17%&N4reBVDYY*ilfI#iR5 zUdrsAoNUzE+rU59O5>_b?IT9U3eTYH?v}+{)cCyX<1rIzK6_N_8<8ewKI9FbVV!J{ z->UE}eo1rmq4&)Y%rpq8OYo>*NdDq6bkCvyOFWW4vOl=jA3s2(VmJw%LU=8(4mQDx zWqraqn(gYD1wQ84r)@F}3^#z7AL}4{fa1 z0yxyBucono79Rm_kevl!kv-s9#yNN;9P$M;MSkR`U?jnR`g#y}pWSOrJ>Z*t(>7aTT-{b1Kb2u!9Gr*WsjVfu4$eop`c)Oc36z|6KRWCc zB|slmRH^@1;!1n!(F3PCnJN*Xt?kWyd`)nKUWL24cqWz~EXTkzJzrM}#o(W3+d#LY zbPt^s@q;Nl{Iqkr;IJ}gHIaBczf0+__u6YYXxs9O+x5ZphQCzpV>E=H@2bEC%TI4! zm<{vh?L)?!uzwazps%i%od*|;r7@tE!R@lXV4=jJ`E;g?x{W5bj1jFK-)Z+b^t->C zPm=Y>{<_S&hh7@fuXx+X{mHWht!KKVT+u>bbx%;vWZAF_y?w@Ah?SD?&{m`FEwU@U z^td3^8AG@nfVaQIAL&G@kMwqGh;{XE#I1X?(Q{Yo6wmO!yI1snYB!#KxnY>oKXLCA z-tU?Ju0^J@fkYu7P>U@$VAprQr}xm8r1AHN1t(^a9=!|uHna7pPVN8sl26^svY_iL z)W=*1F#sU4SJI@@rSyIHt$g}>l2Bi4c>h1EgB<{{tjf#8INkIU{=01ot(zuJfrMUg zyl4<$U$i)=>pDFec79qtzG#ZA&0$S(?&-vrQsXGgAQ@>`rRlqed;zD>&T}@vbg^1z z*P6P@B4n8B8}e4dK^01{6`;D5*Ae5>^5=) zh?~%M0RC^t*JY%)76%PZ)Tf2_@e4_4^J`DFUThZ?8YkRwmIV;u)X<)T@!}`Nf{41A zD3A&XdKj$)QFTEf2spRWj!}ciLM}b|adz|qVeNP?OFwBaH8xP1B z8{Qq(K*G_5R}LN1@t@=}o?XyZ4TkVkU|IZg>I2hodV*KTOlHRX<}~nqHEr$LdAa!V z)&2!8d^z`*d-=F<(#Lu|nDJgDldujEcU3?cm|_+h)-;=+FFz*O3Ag7@PGQTZM@}9T@|hFHg5ngis;hI5Ab2<&e4dH!ejKM;=xVK?_TQv{u7BlT z;ggvJ#{#JrH8xLV5L<(QTX3li>zv-}1$o;vICRr;lWq8hAFy1(z{uray}Pqtc2^f$ zJ)*p)nna|^=!p*z4!|NbM%*xO@AeO?9?!n`Gu8OWtRIi*4q8S2a$)YHB1;~f_j8z1 ze<4Os&_x-e_kVKTkZ|okK@3ep8wtH1?X`{gu9nC-y+Q6#pW8_#aXF(VA&*kYMF(H7 zy$mK9w3_KYDKBlN>#!sg+*8!f+^Ivy>;-HoE_g{uMMrO*_I8iksX$7I*m0FjkmAf!p?R|C3UH516xapBhjY zQ3Ji^iDQO>rCOTkB>X$92E-s#A1!ahMF-e+5$O)%?FsR+};# zE!V>eAJaJVOI0BgMUK0GuDL4P8~QM6!-EpnHTyiT!jm!f3D#*qNVda9CBRS$V`IvD zY0-qiL!fK1Uhr6CWkYhTZaL}~l-tL6!2;jZOFES8$%dk%Lb}huMDSo6YCQfccNFrA zIE=}?)N{}ftx>z2KZjj-OW?V%j_d*z<-S5aQ8(08%svz-3SnJ3`VzbFP!ION)PeA2U^h}l*Mr7 zN^k@?juT^cJ;Do2_i5w=Yje;x2Gdl)P;+wkV^c4otF+nM=Bh6VUbM7eD$<5+vbd-MO0xUd(&0AVTpp_xyMFsKdbIAo16$!|92Ggo(Se*Bg;Q@`i41g=uVtjed-^dbOEY}TbH~;=S`tfjR#iyS z53==Cdg#ACyUW^+xNIGA0iPYR`g903oU=RWiA^=L$hNFzb6wQAo~UhORj6yD1=g$zg)oM8J0AU> zWe7m>FLj8uC2i!oQLY=Beq%D2_CMKzA+<`pDwaGtRZp@fc;elgptL3W!%j;icFab5 z7shn2e&_j$Rg$oqS^3&aq=28z)qQ&%4HitRR$=005s2D?V(7o33WWIS{3GSQn@gu@ zKbGM1M(aT$N_Baj!l7950Fpr$T;TQ|QT$!15;zBZ0^}&Gd$r=l$^Ih9q9}o$$p|Zj zl7qoHZoE(kTeW6Vk3th9z73e})Tb8mb7z&A0t@r%B=rEkpFs2=W$$8;HP)@dJLKEv z!4oqC#QM|ofGWB@|8^o1!0;n0*07DUKze{+`;c~p==hjQ{<(_YX2RLCSkB?i)*T<( zH@(>o<9d(maHssQPrb}B4^CARI!?vTM4vQqP46w)MKS_PZDSgLP(@Ix6|2kl+*Uq5 z=P&+oUT>@5p`i2uIfvIE>pLFUOgRcLoGWlOM*F*1>mOdmO+lUSpJaAt5U58rH_86e?ouuse&Et+!e8c+aKdL}=BK zIbc#LVjM~o|I7K=erR~Iy4&f4B`=sT-oLp%-Ww<)H(;`Rtti}Qw*RLX5H-hR>iQRQ zX%`v-{MI+()i(G-9~$G`zh#mE$&UAk_w5fZWi*(ya+G@EIvwts#R0@pjoqE-)!7!; zz&4hMKzw|j2nrAMUWfXdz9FzghdWN9A5CwL3h}9OiLW_2F}ytAKfh!yt=}g8+U5u+ zxytYb;Y=qoXhd0WpXvt3t2z9KpJH~hnEXHj^I9Q!I8BI!mXjtv^cejY9siborXB5* zv@%6qP>7Ast01VFL5EF7uJ^Axrcxp7YdOn26M*E#0?kidiv7_aEolIw);z)0r@g$d>Gt$y`bQrFMhWwkcwR zme;@OrffC71f$%ANWcnTM!L7>t4A{z09*9mqY&4_CAILrQT@|5rkI1|)`=_H zE~~c_d@rhh`#zwJ)l2?wX~=c=`44}y+HrZ|NFCO63pZl6J%+VDVMVf5DTAbce-HAV z*#9$T3dy6rn&*F#&b1s8;9lHIO-?roU>Jzp{OH^$(yz98uRQ6CZ47U`s)-l?sQ~z? zz0KXBs{Dt1P@F03!wl#b@lS%ziCiBCX+pwBnxTd^KRYHZ#mQI&w9zjG9?KmfyXz=@ ziNE|{`qFeDzcn@rA*5Z;Uvsb7>-AI9EU(y_yoj=I!3fpJ`?x^ribZvfaOz}nI^>pH z**=9D#`n17O1{(pWKej(l!vuZYLboQWg*0$!+em55Tr?W6AWwj-)7!D*bkt0G+7~& zX@fhFI%Zo(P~hV1<415>(^nZp9kB=aPKnk!Uc#ZiLG4GoXbfTv0`%J*a$Yi>J!fv* zO|5Rrjl{2eV0lXb`=1;t9fNesTtAS_{$sp5{WLISJOcG$7BASK|ND^QNlhi@WRbWc zWVqS^N_-z>hz%K85z!FKG5iwtE^YT!lTA)TlJD?ey||h3muAZRX1H_#2PN@=jCv@3>d;Q ztFYw-zM9S1kg%Lvl>8u%o1D-E#YC7?JBX0J9|#e`HSP- z`3db)dBv__4s8RvUCsKmivJcz)BUQ0EECb_vR^eXoC3Xx4~2|;3+VD>VSNYTg(Qo` zXVlvC2ZE@GImRnQX5EOB;^9y|4UvH|^IgYi;Wg7L$oxBhpCC>V<%W2x#w(JQT}mRb zP*dFk_J6{1H~IUv7&_&bCipm>7^7_q7I+6>0T|cGP`z9RJ^nQBkYRa55?(6@Y9GyV zt$pgTx^KJd5SMq(0hq10!4Ndoci2dojo72xP8wB_^d`$cD#P@9syoFC6_KtdN|Rvf z$ERt@^p>3Di-EA+_y!cUNUSCp?|)3L&fzy*I^bVbj*5&unNC|qV%}$=s_~vUOj%YO z9M`T>r(JoHx=gz6VbXL&+~6wHPWt0+74 zkD6%Mlzek`-4vb-xdj=m%6M#SYOy*d%K_Wc%V`4U;yAnF(0UU{li$^zk`vh=8U^N2 z^}{$Ff0~$twA?&$K0xc1!Q*+UceYLiNrt-7K^k%lX8%LHnkGi9>R7wI6_g{Xd&p!C zIYAI%dJ%uv7xI@$P*ypBF^6DWK8az9pvjh2Z^Ux140K zP64Yt!#ZYB3oP%`2a{n%vVNyxeu|1ZEu*WI+rUhA>V5*91D_&g4E#7eiKVvxFS9I%R)43DxTmOzF5?k3CW#->@z5>q5cV)?bV_f$BYb=}>OAW&C zBviFiC`3v{9xf%T;^`|`+B#Kh`MJY9!mVd@*lCSopB|LWVfl6N0PfIvi*x(|F2HpU z#PIJ&(R2uOVU$Gi)msBa~c3iZ_Z6zu!!D$yY zwAeAzchAEhCi_V)hCmz9;={9jK1>nvV+!Pq+c{D@od>*&Q)mUck&*uj+zA6Vpe?=l zwHtj<6n!f_py?j`)wtuzQq1@OU0X}-z&^dJ3R_vk&WBE-N8cD$T zu9X-9T?SX1ELwgyg#LM##ufI8t8>&Pu{v8gYF^L9Ymign4rPFb72GBet;VwzZZb>$ z-%^QyiNZfkJX8{yNF+6zel?&rfm(?o;TJi~`V^DLQ3?0q|{qo+eTjx4Wxa8ByKCruC}F%@*_0mxKDLMvGXR1$_9fE@i#>usLYo9q&t&{HN88fH72N1 zYu>K@fRG5N*O=>7I0#Bt7<+Lt_H5nrRzMs>>ORckI${jY8l>h_=kl3KA}R2BOv;dF<{Ps{pL z7?e1}d;9qgVTy;C%7cGua#6FJTc@viXR?a(c8!x*-$403CIgdos%(~1Brm1dm@sbs z{`XcoF3u6{Wr0+eV-obLnlP<-48B>2J$x{;M}bjvdwUD7JYOXwB3g&F zB_KpQ_cg$mh>waLt$iZo%|kwj4-XLCf*XKFwan&JLOCVD!rra@wn4KEbm7VJZSQs& z5}Z_c{u>1(+N1dHb@fHo8QMXdY+$T)Q*gV4wk99s8Gfh*c`S$az;7y*L7Nmnuf43C z9%s2g$FUk}<#sN2y3u0V^}a?GN>;xb0k9>Tb3n$4mBw}FOr`Ij6J4_Pr50I-z_Qw? z|9N%eN%qR9fmwvE{RS&*hwQmy%B)X&*F!Q113TtX9$jbXzT6zb4Y^`A#OgkFkkmBr z)K~}1w~v-IAVlr?s+2-30q$8c2O;9u6WHS;C*{C`aaIg_WJA%(+`9fvufSw9lB7cD z%ncb)>AJG4~>5an4vJICt(~H)Py{FKB;$O zS6OfmNJ`HwLBS#uQfr7pT{?M?j1Bc&W+%x- zfhRIOlR7A!rzd~9_oB?(0gP{BA!f88nnh#~pc+`=ks)J`*qb}xNuD{Jag1E^DXo2l zX7|cA<5_+&9C@g6_$x`;-fLS1D9&Lyx$A$My)jA{;k(rtEfRk4LzZ}@B->5D&wu*J zFc)zov@6kN1$<8nwtp$R`_74qaO5X^mcac z=55V?AuxeMbm5LAX`uFmS3yh4yPim19zT3jycxZwuvZj3b9#-=!Cm;+rMs5Nx37yd zAVNvx&Z%LO{rZT#WrN~!!9d9ttg>6(Emn?bhq%`?J3wU?!m+|PSGu>Y{nDqbM+>0{ zcAqyQN`5_DIww>i_+>j=_DU+WxVXP;Y~>&*mu5yDgMx(cA?GlTV1uhDEmFE&?j9#e zEC=P1XpL&A&5&_D9=go`i^DYM;66`C7RkfKo|H_Vx%P`L@$WU-fJH~wE4)v!!C=S; z249E7HC(`JsD|nE>r*c7ta;p;Uk%-0Hg%*`$B1hN{!LfUn)tS^4?@7cqpGbnjqMj4 z7O7jyljeONg zrtHrinhyaOL;=64#CgVp%OM|$!*tN+x~m>}vZ1@N+mX3x=FF2BvTYvA6atFO`Lu=P z=3w^?4UF`?W^y-XZy_gvxl=d8V8G6ogut8m%&LBjLq`ImE&`5pS< zT|{y>Hz`S}Q5L}5w%WeRk63qEfSW|EQ9tLmug@CRnsV0>uLN=yyANX|!>@C%2m@(di(ID9g3S{Z&gvOP*f2CvtkJ z*({W*6S0JclGnH8<;53TsvOnHA8-|C-{dKzaJV^S#6Fhza73C(;K}P(_~~(G@d1GU z?UYz@*1hD_xmzF@8qwLceW~jE{p10vqee|0;g2>K*#sGYn)GI`^Bvzh&}X)Fzcip5 zO1PIuuKz054Y4PRTFsZpani~ly&7euyLL4#%!W@SWHe@W#K+rr0t_7p;HtS(V#qR? zGWMcgH;ol2o%0Cz%-oWj8+J0wW`pF_e?&p0S2-hkpmuL$8u-tqVEol_HDAGM+}p3( zD?7i@Yny!OQueoAkINqUb%(wNn=Z51yw-j5GFP=7n~*=HJ!2Q8Xpyqkxsbz_$EM95 zlcpHwWkoyk+qOgnGCxFHRPYfFDnYXioniK=b)z}eCfUW(|C-=l@=)bOC2>7LXVC)C z7-NcVMhD{~(<-|cj1i|wmMh&cDF!M++PGVIJuh-?=P*Jr_!BD0t0R%*Zx*`ctS|fH zX@;cu*R&YF{C!Vp*&cVR`!`1=(LjWO?uA#FRi+X5L0no$oS%cgL-y^H`svN*)X)Mb z^$3F6FE933bqO!B0K22~ElHpf`q}ki#`3L691KwHfnA{WlE!}O1oThjz=%2BNbCCj zpy=eb`#bPrL422ti69-dl-qau!Uq6tlyFym!8~D{wdrC`t$7m6YGrfM(rm}nDW#)< zI){yVn_8Xj2f3DiHThDDq3T*!Rj1O1{8{Cmh40H_Ew@@z|GqKsH4}g0$RWfkT^Wn9 ztH5tBUf8r!C|cgZ#cX3+)jEG2sG!Zl z-dE%2wIUoJQd^Y0h?(tloST;VyMVm1wVXghTE`b=2Th}&Nu>|W&+SYv-&23@fs z9t>6deOMvBDU0Be01%+ha*AiZc>Ad+8lEbIU^J~56n52VYLLN!p8ibz!?lM#8xI;Q zbUMj}X`QbcSBRiO$fdi3gN(UzJZvcGZ8&#Ym3f!VL6Cs6E;>UZh-tjhr0sKE=*Ype zxae=uwz{!(qqjwOhEcr4=^U2~QdivBKc^;CqVY`8^wWFHlI6sJ6pC47+iZc`;@-Z+ zd0t*xrMu=0wjQRcWTPT@+yLT;Gw~OP9;DZwZk1bdEEVE<)R#zuE5?XN{;`ZN^c)^N zS$Ec9y{njy>!Gi#H+-D0b?NQ^Rhhp=l<}D2CJgU;Fp!*QYePBJyLt zuNC8x@uz4IzTFx#5)a#b)1LbCtGm?Jn7kzE^Ixgl5jldrC3m3X`U{XF@g4P)*iiO1 z(Skz{9NTgfp-(p`|*?;O*Rd!TIzA2XUs8gWgmTSP5bUpb?= zyt1-%HZZ$@-|6Ycs0|!sf5~}-kq5X6&>}r%Fg{L4s^&kA=F>K>it(1?DFDyEa z2z{C4N~CsR5b9dR&iq7TWcwasd3cSMc~6`5os_gt^anv1_8%y-Tj&5}S58H(jr5B_ z4?ULohL9h56#`*u&Q3a--vC$g%CKcCq#52+Tmx$c8kB|WF@T20A)p!>6-YpR`I?)sx$nzxIq^p_J)@0+2Ls~ZQIkEmaN zi0833b(azlhtg@e(^EtOHVTv!%Zz3~wdrcrfPgy9C?f9j>!W0iY={8K5Z()C+byMR zW;;={gbKU959UFg1s@9O?yhPJ^P^|d;88zWu)MjD{(T`&Xgc6grL*WUwV+i%q1ae3 zC+^jFsM+UvYAl`J68db>lEL?-HY{R`+`tgw;*fkdCYqdX#scq~`{ILZb}>GGdXzLC zsZGbGPc`(nuBXE@YyC|_A!d+^;pRR2mS3jFAU}xQd1^F(qU)rhnE~!+Cv`N!Cb0s; z3b=>MEfJs7K+yzGG(&k#R|f4k(oG9lCc!0qnM0{vMgvM8ffDIdWaEo!_SNl;RMNG}PpWq{)&RMi)e8-axKMiBtdb z1&+9x|10jAjw#;lus+0RL!5D^dox_xUDNbL%vAj~E+2FT3so_wx+Squ!ed@OcO!YF z8c{!SvxK#Qj+DaxBB~94DOXzkT#bc-B2Df_R-?x z5hX=N{}MSJkbKsa*$xnC7pAy$$t2N@Y5ddTV#4|8wrAW{vLRl2uRA4 z+6?$4t+WmP1{-N(Owfq*h6orT-nLId6i9FIGW9u(31(0x3)jOE-Fx9pD-|9i7bL97 zP?4M5Npw2oCk-N;{Z5%FZ@l@9)eHc|R*C#oe1bctZ?90iv05@+;(UYo(tn@@XQr>} zMBVjyf9V&DRTa@l5e5>lp5RJnMex?^Hzp z2=e9hAAs4A!+mt>XkG=5_6&xY9-(gelZZU(TxNy) zN570q=AvT=G%F&C2z~s;2vrWC+_9-ftQwIhk1bgK`DNBE8EXyx|9%zjPUP`>^AIi-59s{WLbz8BHsPP-erO8%ch6axxrhWF1EzYAM zuMhF&!e6BnLpfHHoL&zNW&Mm+J?bhxX3q})vtkYZu6`SWM0k=ZdFkd9l>1OoOUnnqzGh?`VWPyD`nNUB1nc z)doRTrDTV*o?m-WVWYP4Z%oMT0V2;KtC~Bmgc-t7hvhl_Ctrt+R>9n10#&C zuG7aBKt-+|B)-y10T83;<6hui=VmPlAjj!grPE`XsFm$-6r{bw;!(K+6yBxvq%haZ zD{V`!9`YCXEPMd_7rzwUWUFvoEoJ`YbFp$RyQV=FLAKT&q^>1V_TMm!;F}1AcnN63 z)%7Zt<)2EKo%9uVc9mxL{2(r8W3KK+_iQ{mN82bUvSmM3CAXj?T_mhtJ11pGg|pso zDg#KjA{q4}((HPiO>~YYEONd{a*EaaY5*p<#24Pu>ice+i3R3IY*$5*9?Mip|9VRM zMuX`77Gfv7`iAOvHKTJa!38uewtw}^TVlo~+AFWII)`3E zIMTPG{7p@yE%HAEA$xY18PWmYmc*i_S!mS5T#L9h3LI2nzy~G84n-SgJXW~#zgt=M zfNfbEHRa+=9iFG`Jcib#336uY2DNGSl6v2WFLER&Bph7@d=MG$3TiB~raZ2J2_ID; zp<#z-$8~vr!19NRCycK|?w4MPy(PR=Gy=m}obg)aWiZ^#E%Cq$0j?1)FniI8_UrjA zrLJWWh6w=t)To=i6jauf=Yjrk@4Zrw<;k2Y$V$if4gFMv3+1}h4yw%T*bSs*LLOZD zP0d-q?kjv!uqAC1IGy(@$+=zYW(>PFs^E@m$85C+^NSv7{sEAatQ2sW!9oGZPb8fY zg2p?oaOSD-wz@Y;uX+$yOMPv@Rd`rVKx_wVl>ZWrNvCqTYX4V^;M1*9;Btpg&!#ko zwD!>!rWs94j-g4c37bbF_q#VjqJw9OtO0+aD8}u=@wgU+DhR!n{U=8=7s+HdMikA$ zK~CpIKa9W&o|z=wHkdxfesM<xb@AxlCl8!J1TJjNs&>~kqz5%zju3+=MP}dcb z-}U-nIy_Yg*Zml9#$=Li)w!CC{#%afmdK0hsNzw(*XYb5ED>=PYY^CDkEuSs8!mL= zVr6SDXpK!`{9@NonRDc}2a+e!Na<*Uoy>_5!X6D;3KkC8Hxw6{>vQ>{K_LzQmA#IS z-y{(}>RH$p@QI>~*C8O;4AeTG)%^&dTlx|h-4#oG^dCcCUw-nUvoV(Bof~5bY&0jk zHwAP?$k(_!^%ql<>qOAfaw6RIq(x9u{TMJj8y zG(bwQV@}H$Vd$`--uXv-v3R*)D6{r%DU>wh(O3$Yo+t(O2lPc3DD+64*z=le6a`BP z!dC-ZCq1PrLUH?)ZPm2oY8)YwRz*F4_Bv6)mPpT)M}>pQyA=c~>o`aRdZobxN!FP5 z6M5MD{sZ0;NM>}^Sup|eqK)&9zLs}=RxhfGRSb^#N_#3FpS)PK>hQA{&P-R zZ7S6V>OmWwZC= zT~@4+*#hbDhIg%YEu?kXS;rH)KMO{L+~TH&6p5diQ1BjL*R%j(O0=qWKuLdfzvogon3pKq1PCOXt=N?h|jb%nHG< zIZgVjp?%LnX01&+@*@(O^vJ__M(}RQCMaOv`&Gzp^N}Kj+ z64Oskd$$Pv<%;Ok95{t}MxRSiEBz30!3HBeOWvYYlURXdz*2DCAEDHq&dw}2h*b&n zBYR=bZJ544!1(WU4W20?dVwyBMrAkI5t6s~tk8~dEbVq}79BCE1o+Mrntx{kHSg?m z;5LdLVZa41WAOAj2d|Td4RqO|GQuH)hEg2YxZ$eP5U|M(R~Ky9!LW<*aM-hT*N0n5 zPxp-iEyoo82k%K3f0U|m?(3=qUk+TZ?>3I1 zSSh+Rj}+grXRk{Ti9;)In)hcy#@CZHRfA1W!t5IFv0ZDX?m~ub%?cBz3&|ML@J?Hd zthMIrT8-a;Xw;F?hd1lE%_iPktpj-lu>}Ru0G{aZxx+d)6zbf1K*2O&K@{G(K1ELV zS(p&>gW`<{pA&!U{O2TvhpEBNDyib^qeR|DOobX5(1 z>jYUr{%)stpmN^LZlNEq6uUX9Hg1IRbUft+0!gf6hMV#+(kM{8R)qHpMc_p)@TofF zRii&+{;|J#Nc&Bp|73cP?GrYQ2uw?@L&p{;ElIdwOTF}qF&M4{&kZ7ZFsmO$Q4ti& zSki!bU&6|CILysekqKQn*;4;&;@L0Z#No`UD(xHoTTeUKrOwjJH%*F31M0$pRM9jIv8 zeVy=*GPwwl7JDAG1%ktGLt>raOU0_$7QW^m9~stug}Rtbu3GR#JwVX{G|^|qu3rmf zZ8~CJXgaOt4kCMKp{w={%J~x5%j$fco;}Rj(2!;VR>p93zi4lSNeqk3IeNRs2;1?> z8Iy+*<`^_{jWzn@Z-VerJDo-j(w=dlkYiQwxsdi-c$ruYapD*xpQqo3di!b%4(gZL zQ~!{~t&#Z^6A@W(_B7>q8wqpxaeNk_MVVD9(LUSL&b2fTCJW1Qh{{6L5oY(ha~guA zL-&-VXF<3LaGHt^&I(9S&~zGm>HuZs(xw6@CYqc5HNGadg=U5zNobJijNCm@#(IJ& zo;~U(R;%1&$j`?vnq-eN%LUEM6pdq)=1CFb82dq!m@li_BD-pflg{8C{FAT%e0UQh z445}iof0L8tLHV~2O@#y?a2+<#U&#E3VfTvMOlXrbNomE223p4RuzdKg}zdIpfO2H za|osZoi8DdSwIa;xou`EHuQ5Vno;rl{V&WuhlU{9z_1Yg3Ribm@?wr&-UBLCj_uQC<7B>`!@RG_Drk=0m3TV>u^AtnNo-F!+rm@Ib;8xdU~m z(tk5Sk15djUjYkaQ1<;L0*Lr@AHIf;GE#dAQIX&dePmIg71dMSz#L_(yLMKs2t>WU zG|nWsmpx2AAYZ;mkFpbABO#1+?VaAl!I|mf4Nx-7=-(^lpsXcwFXCn?;Ak-sgckw# z!iBOUvinqM$DjW0df!yG2QB{IeLt*1`s_fRF}w(s>0L~1-LMA4F9|yV-y49|D1xUI z)Q6I31%{)vD6fuq@ISs~^9Mk0I?`Kii-$v(BO*W_ACqN0-G5@l?(S^cvacxvv}&R^ z_B^d1KUhY^l{QaEc;BB)2yYMY*r3KVDhB<}-|i{kDdL@YEF}pGq2L3Q(6~`kW3|qGn*Ni0`)}wVPWH z+JxQt6eL2uW6VvB{)IDqJAV2^Q9YLM(vX~7Og9?6Th!R<70l}z1rkrrm-0eheeg9I z)$5+C+x@w#hAcjRsSGzFxR&@$Kf$FXv3Ps&oD(zEw(! z5*cn7Al16GF(p;}$3BE-Jg27XT;Z?&mgDJ>4UXy%rp_WbL;oemg&C1b)V(N|6C657l(ba3uD^QsI~7)X zFIa9>NVUKq0tWWzyg!hxNYo<3Ha0bGXDT~arX}j)qY>U-WVygdScnA2tH8Zb)R6Sl zxiiwYDMN+$LEVg(zWj8+lsr$O^bVzWOFEubTE-nEM8y15D4YouHtJNJ`23|X6oSBP3o}w`OnswwP_JtK(g&WbSfB)k%PJ6eo1LA~7 zM#H>?P0`c}Ci6Q`0p{@>vOc#zN@HvtBV{pYa0q&{=g(#KZoj?MF%|6RN ze$c}^bP>$-=O8s3y;95SpMJCiNR0RRc4>kJGCB~fn7*?-t*Hw@d#M-bt+<-gL{9ehWK{v_K5gm}>D6mNYl>koIi{RnTUZ0YVItztNwBSQa ztWg6{zyeQmBz%m!z6z2w4@x(&&Jc#5s=rS6F?;~-07uD%rJ*T;lv{JqpC94d0tc+i zGwMij2hh8n3cainqm=c;r4F$oXVE_&{-?d#5=S107x#&>dS<0OoU41dksaM3K_yq% zt^6Na`r()!xpd!47E{qnyT$ke6zAUc@^>54DAG%OV^>^FXgI9=B=f0lJu1NP*~8)6 zzo=N}s1bfkPfLQRG&$k5Rp&6f>{OEqK5I(Rg|XR0y5eh$=+4RZ-W@No(;t(-aU}2` zSte^bhKVN#?sloosOuJO#;lv~OJ|+`@=2<+^H@~Gc2AmNcynWYj#VkZDk?|;Tim5- zmBArcy+#vLo}RVg%|L>V-U`_!*6)L69BjWUS)&QASFmp62JcPaNo@q1fCCRc(rFz> z&9Lu5q7pcD373V9TVZ0^1!%6A(N-wBM-iaR_-a7b-Y22vyx{0P~X2 z)yz$9{WX{#08>~)0apDPTnx<)m^hf`#E-Enk+tNiZtvJXQ=`Fgb6D&Oc> zAO>I%w%J2>UZ$JiG=0OR+HcCw5qR)=b;x@fjq>OxjV8;&D=WJM@eby_+>Y5nsGL`f`t+oQU9?_62T8OMI`ZdH$VZzI6L}HjWM>w=vP(#>q0`EC>`+N4X{iOBXKx-${YS%$cnWpYASl@$;IKv&WRGv4w|;8<8G zdLZlYl*~9eYe623T64k#+Apz^1O*vA%rD zPZ-T!HroUr9hA1dF|(G-<6K6fUgYw0ZPF3jktKM56^^45ML5vdre}hoxil}ciS0!s zUO-1q87D4J&&}QCb_;&Sot)iAcAUd+qE#izx5*uU9yuG)pyC<6<_run#ii zK}bOEL0QKBW!n$(XV*@NHMU+_8deJpFm%pqHh`~P7qQI5(bXeTN-Cngz*^j>Rrh3G zE7eTs>6Am*h%`t!@r$Y4{{d1Ut?@n7(^q9_ z3f%xngcDEyjWEXvHLL+%eIA0QYkan=>b8^ zu*h3W{_6(4-Ng&WQ)%SI+jjX1cM~U%$4f@r&EwbREhDmu-j`X+Sy$#jb%N1vroke& zRWyD`g}(Yr+lpA~!3Jq#yRq z2x$ndVkq}nBo`H&YPFA65d_ZfZXiQLM+#WKf%kANBQ&2HV|HHJ~bq{fibL$+rdKQ;@)p)!>*lSkVHYo=(7a1#;^( zKq_@L5Qu{q980w5HPVxX(%z*)liGOXXu7gem}r{F(BM^a#3Q z&JoWxGwG1^)s^kwLt2$HUcb$<+EKWovUr#$nsP;fb|&oTYL z*5U~;$Lu@h!J;DQ$yBpWFSBXaYxm8X`5wab-@QnbFo(-HYiC~5Zo!h=FA6xqY&ySN za1l)fR^K;QKk)mkpws0sQ}9TxHz8Tv zTBKm8pxZqo3--Impb0K=EPRq2U0Y#f^9ZRP^mPt1AYOf0LZdXZ-=+0X1<;~rX9%kk zLZA4^@*^lLdl^`xKH+TiA71uZ>?1(4rioygvWQ1JBT zt*9a8`C(SdoE0Md9B`C&cFJRy6!hWAM;KvXbZeFFtP`8hZ)e*gDCGm!k!9nfjr!w( z^~4KD8sLSQA{U{Uz>V5yh88>I3{*OA^5S-zu1my4IbS3xL=WQI@!JXi!U+!-wfVMp zl;fEwFd?{GZaxt?M3Z2S!^UeoP~=)pjiwd_k^tfQ6kdUpwrTZYg&3+v^EroBp@zJw z`X+I)NG`S}*4RnNob8f$(ofO;$&b`8QJRKL)0gG9`W=f3xjHfaYV#3qN~}x3IU2wr zaI7Gwp@Jk|CE6uAew>IF5=q3JT~&Fou+VWBHkXa@fY^lse&fMZ#PYVC1~C}Lu#1`& zfyO^wfp-!mn)S3V#}0)NfIskC4LAPN`<4jOFE1HD)yWo4r&D&@^Q^MymQ6`l0AM8j z%Bq%4^h9KwFdMRqtsp*1lM1NhFl78ec~~w&kF<_ev5=)Dd?_{L0Kv$$3j*q!#7Dw?Lkz(iwwNz^r^79fe5HGM>2hNyoutH zQ-7NRn1j{G((r5BOw&bdR;F+$tL9i4K)W2>7?DN^MREq*oIv_QHr`F1{*NdK8(i@= z{>`*!fDrrd^!e35wL|&LHcM!;n=aRTgV$S|;<}5Y+Y+t^8iN_kNH&q6#!MU^IZ0YLUOGvh}3(~yE)K(})$hvzKwX6JtVq`Kkv`H_N;1s!#{ z7uZQb1fD&Y4Is~Xe+LI|(=ECBOzd-1%GU{$!Up~njh+WT^W52tk{Qb=v}*4^@n(gu zdu>G)U&`Qp7vl|@Jd+u04rIYeQ~SHSWJi|^&!I|lc0hvWXS?i1{$)c$Q88@tGyl>o zuNmB8swAd_PqF8iTlUwgIiQr1@8tLFtnn5WQEft>Su)fyAs)<(L56nr8EQxEkhC5M@n5~GsVgvL$MFc z`2ifoXT&|!$!ffC+39;>*?t`#!q=t$Xc?Zbc*U|?DP_j3znz(7F5aSBc4FMFnKO^0 zH{^<{_=B)p1MzY|vpRt#4aB&i#+gq7KCY^34D~a0gO^R@QI--_#%#8t)h9ml={d8( z&GXs%=8^xIISRuysUa4t>=Kk!gF2>5sT4gXaIM=IiF1lIvKye@a0CmrsAIzlB0^IB zKuj8*DGl&Xe3yDUYtXZ0pac5gslqgj$-tXiv}!BuZp$=*=Rnuaaz0f8h2RaNdOpAJ zWol-F`KnD#cr;t)G@T0-!o%;&N1^;#e?za_GPTM42y;zlO|qcT1H*qvD2QO0T6!k) z9bh|3iZD6)?up{pb|squ_Wu+NrgJF0N&~-*gMa0m&4;tml*>U5RE{uGzSz^;y!wV|9qcx{f4BuvK*OiyTWMwY6f1qH z8fBVI1k#rENx1S=9?e*@CY}~er&49#os&Y=-g`Q@h1orpl-&tKyj8`sI^Q|kAbfsC zJ*hLLyuQMO*FiigRyhjS^4 z-QbGMpgnvb|22U>)*Odq=Ko>sHV-sj!+jmC01F#g(Z4U9$#L9jTjZWULlclbH&F*o{P`HNy~r=?vCRu zKU(aXDihkn(V&$vb&$%{@$o^`DM1J>1?G}OkaY<4LZzd8!J#)0cE?azayL z!fuhHjN0t;l03$B-^T6A>j(o6w9YCI4|f)rm`< z1e9lfp zOn=|YJ!iwVMUYi`S-5Rlq5()fio<)jAP-`lfYdcp&So_V<_|sEgpw7L=`RO$s`6Ip zlo643d+w0uSO#*}JVXW}Q^rr_XyIjShqIwFkwqv~rQ=IMr*~;?y?~*DvI!EQAHDn0 z^n(Ha`I}VDp!i)lNu_Vj+G0F@*5+4nXz4-tJ9_B?w1}_OhiA}?&MG*A9p^UdEj1Aq zYfW&0+^Kxc7ZFQVkiPdAWV&!;xL+>7&8Vy^2>7hah9jLITHpF|YuI|dyNyi`7fcZH z&4~K`GhuZ*s53-UOeBNN&4A=lmP$C%6V%7!)<$0g2Y9HjFAw`3E9}Pwqv+4cFEr*8+*R{399QI%Y}$p$8Kte%d8zsbm(zOuR}Is2z7|I)Q$lcjqZMeDv%B2@DYvFL8-m)L)CxN$&1k` z0?t=+Y*l|2C?8bNUO=9tf=2ihB+-l+rEu(>7e+KX_XQ$B)U6pY8;umBwyy{)#i+ z?C|_1BUM+oTdltK3LRUxI3k8-kL>V$Cv8`Qf8D1T^_2uQ!!DrCFMZ>;fVrdOkm8L3 z#kiSx>PosEi{JebEYtpgyqL4uS#1`y(8#bh#LzmP74x?!726ufZ7~a?Ze~qFyrGt?$Og7vzYcnB-on~ zaIIH!7$*6JECQ*JRfWJGrMDp<9!mO1U!ExRKMunBG)0?WS5uq^+NZN?%KE?2`qM9F z&4n-<3Q`8c-8Tm=O!9?k?{&C<>CI9&>oes^KJjo9wm`P_>eBj|ycZ?>vQSt$$;wvL zQ2DUA1rB`oNnFm3JEEwuq)rVjxSweKI<|ukDC9QZqiPGP%rrDtBJTw3sy8BSBuG&rU9~2W!0Q!`=8+Fd@6OMYgH|qBQjlTkBf;#O9-nxMXfOc;t@w3 zz0vqAuF{4ff0fI!YOE!!Ku=s=OX@vcCv#HRan_Pg+J}#1J^@fdki1W`w5v@b;S?{- zuxR1R`!o5T*ky|Bk5h}%GORl3Y52iJwMvl-3uQ9%`J(&3QfSG;l6>&M&m zKvEK0HPcV0Sj0Q5bKJt`wLwn|Avx-idu9MbU@?}>t-b;CgF!CM`8WG8|#h+GR!b_qHKOEN;P^lG{b z$KTDmPKR;Hbtvu5KdTznQqBWoSyNJZ@X!L?4)}M}}Pxr&P z{y1?o(J-)2G1oG1*!KJ)&OBwY7Wt{S71%H^S6xny1cc~P2cj+anliG+wH>6}!=U=` zw>F(KC{`J@TxqW>9BC1L4*e}5ACTuPfvzr~PMAwEkH6s1ZAv`WtZeqLK2rukT6$q? zPDytX-x8zfT$)aJ#koSesKyVHk6PDm`_KG7di|K%-UA>8?jOzJI4rb^nI+ggswN`v z`0?y$se{+GlZY4iqq%#?k0)*}<`97n%V$^-@C4~J(`=5id+US<=04jgHGY=Qr*LyA zz7+hud2w|s?CXD5L~7k4}fSp1{xb_@O-&6l3HPg@>D~dI5(?J`^o9W zzbeJR+W3SpGHr`gqEv-*>I+6Uw&JIiywy@)WTQ8$R!|VN(Y?(puVyh!kJkWvO2xkT$>aVhe~V9N@LBi?UP~OTE#m&z zx{E04A|3%j(c~aqj&1vlp(#2-h15GIn`u>OAW(k40P)ZBxA->Cc~f*_9f&Y7En(bL577Gt>zoyn+w|8Nq}(4 zEB=ll#*Pwz^$U8Q({8jpc|iW{z^iB&{^Aq1HC~;0LPRd4;>cU* z;WCsu%ka=(N!)(6P#@#luG*WUp$`eN>XUSTp-^ifB^Zp3KId%!pBIF?fg+FxDu{t7 z?Q~mcX68PyN^5Z(2r*2#W=YHgKR3PRe|9R<lDx6i+GZSgnH^Gx}9 z9nJJnPAliAF^$$-+U06)v`l`F?dklv3P%wkI2b%8G4vG=@VV9ATubvDC*QAyygfEg zo;VcYZRC5AZWCpda}P^y>J4R|O^t0W7Dg&NVPXVuMTtFAi53y@_XM-Z?=tn*BauC# zLT4N91GErxReK+$u|KQKTs0Dld(sA}EDj+4pG2iZ+D#&%pz0vQbT1buj};e#Y3o>N zOaDKd6ax}mZB=6j+UI)WK&3R}8U#C|n#!C2^*TnOITo! ztZW)Ui!CDAJ)6Gj>Ay@qpDTtY3<|~T_lu5x~xcM%A#3foh{#*hQgvagcyJ1 zPZEGnA+(QsADGYO#0|&MZpB5BiYOY5-+5RjyJPYI1tTF9;_NHWX_P;0pZ@k}QDMt8 zuS)$+uyu_+F{?+E%Q$O|0Gx0+-jhnCT*v{~*_R49u3!67@-%W%GQ6*Yo zbCe^e)W0E0!VS;J7YygZEntLZ&^m!OkJy*QFx z3U}Ds%t?tBsygdAkcIV=#m#mUZI;>Tx`hP9#YydE1g-QiB!RVR>~1OHU8W4WY}(k+ zC$^jQ?d)ydntOayfCU}6TvK78^(PQ=o{=yxK7LoAF^LWkDa$L0_`h+CnL$TO6?Pl$ zh)Hl0SOv-rzFjOcNtNa(b*Pyz9>@)A7;SGU?(pt|Ke)yMOH17uBXKr(^Z!HO05p#z zRXU{DdQ2eV}sYaU&Qbuuwfvl1bHNA~7y8omMO}#nXI@+_sX0-|xm+y&N zjbDYCaWt=fh%fC6COHw?VWS%T?vRYccsGc7I^CMic972-Z~!Vg0j=5`VJszQ+K*M} zfYL)6M?>3D8C)-=>I>%xw95~=p8)f4q>jJcZXyPo@VUl>Ll;J3rUnz0Vl$Gv5DNFVJQE9g=NoAt zQ4-I6A)W_Csh`8#+)a`S6(wHLFV1&6PqiRu8*ht{l_Y`xk zP2R^ARjZs)^E|4MIPVYC|M?<^>gC!jR4H@~LM1!$uO@X^EOMZ+N|#PRW)M4}W`3v}ME&02_zC_qexSQi@eK8k z(uS8Ixz^IImwaAJzm{KzaE~{eYNp7r~8e z-+;qc2ofs3cxm#ff!t-q!qLZt0vB@QyWNcC9i3e_p^nVl1Ed|Og0ayT;q$t1!vKT* z3>0I)Y?(Z$YNBqqR2=pzm(l5N^}#IaK!F*8L(h)PQfnH??nz^A@+6NK{$Mz*$n`6i zq4NaSse9~XW@nKJJe{aXg09yagp{YW#w{GRZd#UaIC{<-42N$4=80`nuk`m}b#(Br z*EiZUQbJ{YdnR7;2!Auon*cllI2mX+JoW6NoGrGvn7oi%=@@L zZ5g2yQ8tnMPAV=m?Ke|d8#*axSOfZBtI(`-y3ox$CKF#ZX1t~OFUQ#MESVp7tphkd zZ;r_^7(DvDzRjv*KOpkhQ)X`kS!NmIWLy1SqC+g^=d z&VXK(8$X8a3bh>KmVW7=gUUrY&OST96jd-Pk^F|VYF(A1?w_fpQoD^#O?qHd{ef>b zlyG(@@5qVZ5MC0~S2Adioi*mi{sc|D4qS-2yPH(AH~Q|1&%{Mj z(w)^b#|pDr6GLcKmZls$ZzhN_yvzQLU zh&cv%Mj*B!77L^z7sC~sa?0_dDseoL;qCy=$hhixiuQk`f;5fx74I zG7CA?3M^*bE#?gMulU5Zdkw4lI5VJVOT|ADG;|4u_8VKLYOh?Vm<)N(9FGl89!(Rk z4Wr;X-xF;FIIdt$WZJizYTgYdA>!d<3y^0RHBf;VbNmEo|M_b&-)xL2uskgar)akp zq`NW;8L|r{k&8@CHT|%WAaK@)`?mwp0jO3o&4~Y~ZAeqJrUJ1H0nYQ1Ja2v_1AV&# zxu~4HL$a-1!A4~Hn&1;tA(l0>${5k=R^5TC~q0nKb7!Co0tP?p5;MrvJ zl)_BLyi9QNU2@4aC3S)O`KTwLF+#V@171%i^s*W;Z#HFp2SBX$WSkTu~F*l8gTB0CQX z7psUG1xjmP>z+8pFsD^kd87|}kq&8FWL`laLoLkhkhI`kvIb=ox-Q}o#Q?IO!w*&K zkdioTR*lG@Es|#mF@TEDPS9_d`H|mN^Au`TQkV@)bx4}P#K3u7Q8}y;)&U3lU*+i6 zf42!w@p%ak`tCG+>RhEWjN~spjH8c<&3xdk%%7uau)Y2)ub7Bkv+cs#wie(hDAS|? z$}b$iU)PKYFqq~Amy28Asgt`d4g*W7pr|99Ec2#1++osJ5OrJI<`!%Jj1-O}XGO?e zf!iQLN7ZHdf;RF2&^;%-4*c34mgUc`h=J~iy}PC-$=%bZpuq#9i0lo4|HRL;Zd{?? zF_V@0y$|spu-RD<_&OKH0ZlK7%M2{PZzr4kcS1d~GCf7rvm2^8WuDfd7a|?0VUV0-p&TK0M z9FlS89X)=Si^*U&9!b^UB#HS~G|V%acN7a?q~#zy4_5N>aCCnkEFL|NbHyn3YQjlc zBIDLH1T%64yEVAImZYMW2%8-ahaTyQr714}RuF@&-YcX4ZAEBlEz${<2QV3d3J=hG zO(UTu`d@2Ju=FGTmm*FT=|oAA>J~5_n=RM#EeO5NP z=j)A3+y}YN)2HCt2Q5&kd(>{co?mvpWf>=^{*H!Ic_V4 z6RSciqB#%-!!iFmZ^^;@+%fnb?Sx<87_#BWee;0PG>(h zTv#X`UY>fuPDlm-0G35tL9 z+q+`819k5-%aW$GIF>qWAA+h0qbim~WtBK{>-|XT*766p*+#@k$jX}4>;0JJceMqy zz9+lilEp4G_?8#1!~t@EO~5fj4YM4vm~UGqLXCIo8A*9YXjkU6!GX+?V~x;RY?U== zuXSDB7(#!8QcnZxeBTbeF*l>BMe}Zvj3d$&umBYTkTd$U&1?CV z%lpbE<+#36t*ou&JRP{Wzl3nd)G{0$;jkgRj2X#ohbjPlz*65nHouR4sSDtzD6aAC zQPz7opFLdn^+*PNID%^Xu*am*!GR+fqVD+?bo}xOqYj(kL8nTsyer6mkHTS3V2xtB z9y*=fXo=m56Ow{6lEl0ZdGNPa@+wpb;7S@Sa7oopvjgNK12fcWG%MqGxpn+oXXa5|IT?h13h zBfayeB{KTsi$l$550U^;^T+NhaT3B*`d~5ik+?@RdgP~waU!WzTdKBzP`&lBBIMyu z=55I(Av~7GIx9b3lnWR4)pjIjMp!$rpdn-x19xorwyoPeAVPn@mt5ha|41J0w$Mu4 zr^=6k6coQ1In`a!oJ60s;^cB7^x|w>w?$OUUWQOw62hi~IFo<2Z7h4kbOT_l4$hX1 zMsU|maNBmT5`VSmXwU`gQyKe}1vo6_t$4gE?{Sdkoxs0qqXy7d4Z}`~u42jiPs&-> zwC2$Mp5fspvv?zGo-+n4eWLd;9uSc~?1x3v<(v`TH|Y;>Te2{Mg$lK^Sk>ye1z;H{ zz7NEHAc|yhPX|_Qfc)sXr z8cZg>XgrSGHghnjeoPpz+@ZaYK1Sw4|FY$ee#BthW|%nyEkZ^IOBIMF<^oz-`*g@! zLkhJ1mw>Vv1BWHm*gNmC;!sr!6z4my0R=PAJhC;F5tWRw9-0M2C-ecH+ z0QJfW|KpJ6hBIL>5Kx(iX@jEJ3dm8O?}_Mf+aD!5js{PqF$!4(^gh!v%vt~`^FM2=^W$Qtum3!g%!5=Xu<`VYq)#{yNdndPG|LI85qQ zI+kw+VXH?{m=byD)%+pJHpdC}WKQPRhTP?gxO|3FG^Y$F7J-Ud=`_*$_Sc4B-#r%6 zwHa^L#KCtI?FuAgi{S>VJ4#V_0=iob)G|-402KR4Vm4znOtkN9BzFW0K4^NWyfEuD zW6@e42GXi-%A!tT#%JTkU-c11cgvN*YT9>6`oTeOXI?x)tmXoeKO&0PN83d&2A&M= zdv1T6Hy)a2s#AuYfsIw~xjF%wmMJMKGAN#aQ}uFzoUd!fgiu{=PgJgq*~BT0=FU2+ zxwYn!0qpHmdJmul91p(Eyx#i7s6h>ub-I6=oTm}tMowzTA&f5=R>Yzq@^pGqfyLY6 zaElAL(a*Hu+*FAY^>v{UjtY@(Gp!5&G78Seq<@iZ7x9 z!mfbN=vZG(d{*8L?jImI_k;C+Bx=AOTPuRv@L_Avk{n*~6sL0!k>{MTU7sv?1v5cl zZlH>T;#RVF;H;D@KUeMc8SZnd>)Q85Kv6dmYuV|hw4WDsdF*#aK$oi(m}2P#!ffpd zypZqTBKR!)&4g=C_xWLihcRy`Y=-}?nz}LI>&75H!G(01jZ~!-ksp+_Ie8* z9kHg=_ZsLh`fd1-kVi`ts2BYVxHe9Kdv}R!${E3e@!SFELR7N-(!p!Ox;Y-HY}IZw zi!1F`5~R13Pw(z|qccYIV7q$-fVkHztw6`P9U#eWXtKeGC!(=Dv!&Kv4R?A_r7=N) z0*q*t0=0L zA~5C@_$+*#*crF9v{}#vz^qv!vO;{_$~<(qrTI?0$cdLtp(u3EZYQ?OdIwm!j0sz! zfhF(M;q%#QW;j)S^hY~nL|P)zdBmxl3eTOJgmW$ATZ>{oI4=Pc5$x_*B@WU5?oy03 z2`|qmUJxxX7JC$JeQ6|}Ossw3FjPG0i+a`;2%OR#mmkLQvai3+s&`bBDm;P;{}5Qm zbLSJ$AOze{P~sWbU=N8D#3IY71o-*_>E2__Z@ReO6HL!Jnhaq`BQ3SRp-b_PPlyjc z=$algKO*|tQ|)&YtVFPtH#yZIbya!&)j+D$Pi8?P86$b%AP0y~J@U2ou=P0*BYKa3 z?$=)Js2v;K($3DS%CqNKp>da@$^|*u7x~vMUSWirQdmoSw&81OZUc9weHFJW$8vuzWI$0Grlu>tb{^T^XsrX;={;Tp;Fuc@gDkV=0zNdzuYZ6P<4$hzNflh zhx&Lhm~6F+)b4CWZE&wE@p+YW27c60*bgm`lC#iUj}l2_OFSCozK%~og@O6P>t(c; zh?_x3?+WvS{$a~^Z?!5BeP3@6{Yk|R$Dh>S@-)$r{sGJF2!#`ROMUup1op~lYq}+4 zEJs(|@#&3S7Cb(Mm52zYCR;_eq{=pB>vwbJyR>C+R7gB~=vp$-4*M>~4K|XjTg+kB z^5~Pd1eq9Tj%zPtFz;R+wLbMF-E%=}s8b@?0>P7|ahPtL0h5?M%UUk7D$t#zV$)m= zlvHHR3;*n*i#glz7QEn{zBcBnG~Jvy2`Gvp@!HajUAa7HSNlw?jnS%u6o@KOHpj8e z24J+(mHjcXzUv=XZ&7O;FnpDJX7x~CcA7ygJz&Z*;i_aqqU|D!e`#Qev@Xi!y{?wR z$PAB?CQWPW0#yaFdodtclbtq;ZtZa}@a)mI-&q&WS*4Q#kEt)DWXqVZ4R35s75SvG zk9>x+6>!NvUM@n`03Nd!V+P}bSTv~bb;b`Q>UOfw@2>TzJ5Pk8tfD}yp*LyS27R{j z+;w*t2*+@<7FpOa*ZdEjR40~bH;@R$2(k=Dc6|0K#dJu&6%^fhDS=cdbucT1evM53 zi&>#JS>j*|Bq|yLPjAqirtw1exo%OfpY-wVcK(V3w5+t&R^3??J+C?q(FnDel}RK` zn}e8`={)bW+F;_Jgiu>Q(xRtF`Ykj>Q|$z1)}uy^sI(#2QG{jdo4~lgt|l4&Y)4#T z->Tpfk*_c-MB>KI41o={mw1|@F7~ThFk5@l@>mRsYUpZfBUCw^?w#;K5xucUv2VN- z#Fwdqfg@QPdyefM%Mo0q!K^&PL@DXhwW;DmAZdq_2d8q<$?%5r!a6I)lumDK`FBl$ z_o*&VJFN=qq5`<+xY%`eO89D%$1&DFfwG1iLOHxN(nQ809Cifg3@B?3GDG-L;(d(j6jc{bQBtkU zhF|5fv-8lb>D(L7<3%`Ph{)Gn_1F+*!)x8=#wE75XwGbLz$H~Jw!_7_bt!sJ%0EqfcU!hu8Ch>T#A+e%XAjz{%pdvpU3#FvZK_m z5*p15P+#nVl53lvm~r-@BdMwds^cYEji>ULi707JP2zi$CB9k{Lx_fz!~^?ql(-zA z;nw+*VtYX@&skiSEB&VzGhEjy64*Er+!fWuSu$z6?6JrCf2?$P75>86eIp;y3qH(& z%^WslN3?|Wq8~Z>5$H5ch_6)5W__;8HuKpzTqqpi5S5D|}aUgwNlct;T7{5rEJ z!7tE^Su??j`asLKYCYRioF#y@R7dWG zx(dmc-_xs`Wb>F2PNaSs{x0P_FW&EPVq;lDf_~Xgj%-jdM>)Q;QdM$>34K+t)Y&^2 z*XiBh-B)clVoPR53$lSc$B;@;w{`a9Z9Omf@nIm~lGY6ooE)SVD4+ur{lRMKc&>ca z{{^0N2mC=u<2T&syxt-457Jp9iqQhN90f|sFO*gyQ9B)%D!u$yTWrBvhK&jN68qV@ zyeI{zP6)fav!txVo7ivtjVPU00g^b=k2w&ne7^bEHpnG;vrHQoT2 z%u~V^PWAL3Vc=OK2`cR>*sQ81u481Tg;%%NF2>E^piXXGe+p~so;zE`1 zNRY79aOm%+S$%~o@``Z7np~UA$OG1lxy9s|Vgy*G8B(<2$#`7jcQ|elWhLsdc7KKQ zJgElqwO~56`}?JAcW57$ZC}Y-W1;)vvpyE|H&q~0_esKK%UbPNo7K%O8aXHxY#w^k zAdDHpQ;6V5n_wfCtc_4Rk;3!!@hput2Ly%Cu@~srwk|~p-oJ%*_{T1 z7pcmGM?ypb3B8S>io1^B9^jf^t5LYW@CIQa!2m!z+sb3DG&x|+t8lTNzG1a{2E_$W94*F;nVA74qc};gAl8I~9PO?S?FJnuX>z^_jn*0i|CEBv~Do3sz-2 zKhNl8TKU^UUua|5{0mPNZ3Ou^{n3is9v6d<-GSM_ZB5)5?|sc3FJO&vZ&D)LT{$No z{Zd-(?l4LvAXel&lM?}(H{jj!3_>}&rg)*Jk>T<1E&qvK@{a9dN4a)|7!{0Tze`U{ z^~c8{1LbAFfW7r|DDykTDtUI)lq~oI47+x6{pfFS@WPZYN(VY3{4=fa&pFJWQKfBJ z*$t6u7%^;mg^%xg(5iYbK#z7x9Y#Gvd%-z@qG%%H3Slcv*Ci1AJKlSN)hDM7EIQao zxv>9ZoLvlV5T-BR2m*H*dKEQ{m{e;D*w$(@rN%yr-S(NJy?Xx6cd(DQ*|V zm`{IR8%JY4{h3+fWQ^a&@vZ7>`MILvnyXpFOGjj;K3+*Lt~$zrpdS76RtarX^^Sxe z9v8a_Z-0WNP=Z*=6#X7Swq-kmTtO`W`)d{8)Q6_&x%R$UITUCJC2&H=Mx~Ib*yrLi zAyL#r`t{~#-xCI_WoO8hOt@~DLX4=2(KEuLxIqk0f{6pbROl$+$#l=dLPaBo;^rzW z&DTHB2I;Xw42#PzdzGOM74wk*F02b&&4vQu+I!A%>uOe`l;&YhfjaFflzg8M>yh&DI5Uvv%7mF2EDcjgKGp2T^@w<55grHkWh zWOrM`&eaZ_g0_xqw2aKBl>fsYYHmjh_+dJl{>%se=K9{9Ek*;qp1N}G0sD143yfQ~ zls-)TZaMg4qHHLxzf={-@p-#@VGQC1{kih>HLt+daKe9+!=S&0*{dSkH{Q0RAnRVOEozWY+$ zGxz|;FqxtpF@I+}N=oNO-7{!w2~pnJ>}|cZS_@jHF*~pZ6Dk&fusZIdx#&d^;ama% zOt*~zAI+iI*#1sYEw-DsOiy;y`}!-siY0+N=S(xywx7P zAdXNZ0A=5S1QfS0g+nZ%#c@Z)WdckR>PQIM*|)$q|A0nVBY4Czs$z^0g0!s^RQ|eP;g24k1$WnzLN?_Nm1XHf;p8N+RDG6%X?h zM~ks8-{BwVpaZFs+l}~;30qK)RoBNiw=d;>f5UAXZ6R_d|@RkNR;9~9< z_Nq!VE|3$Uum0{;rGUMpvcjDTV6QV=Z5e36OzeSK?eLqRg(%p6Xx$&M->Yvm_sy1egR-3Yvp48bR8P4&*Xa-&d4+ln7-IkFJyhJ2+g+*t^y|2`s-D$?dyrWIW%-RH zLGKMc4zX!qNVQ2{9!>Cq#J(ia$!GFqtMN9_LdX(PbM9HQ%kbEi4?m00qa#WlPO{=_h}A)WZVL!iqQ0^z)pIdEOJlHNG8o3P+nQpn79YE%7A4Nj4(0h)C{C z^E&RK`SFZ-O^(8uX%lI98cEHl$u<%h{{d24V^+S5$q_mCdq7R7)2#|||Efkb3m8xo zXh8l+;YfjkP)xf7bY%ZTCi^NC)_7JFfwJdrf7K&FD3_WV1A-riuhkXGu(k0czL!Bj zWYN8NQ6L8)8@GCbf3$b!yBgy6*&m72Uf= zK$sBmuxyHUIcqqM>-8YMPWIzN7pcdL?2Enw`h~V1&FC3K1W3MQ)x#e(iRFd*@A9<` zL>Zk_fV~*zv}jMlUc7bQ8f2po-88qZ)f8C#MWU$-xcnXx3*PAPZ#&xta?iwb^#b3G zB^4diDJ~G!lV|P!8L>8374ldfVZ?6-OeE5* z>pB@FbW)YhAR|Lv;8e?ZJ~&-KSn!)Ht4GadRI;y*Af^9&AAXg3f9hsZ7uos@ns@^q zIgAAaktcfWl1)UFFv&dC;VL1~NH!fx5=hAB_G-z{l|N?^uSbI+nU?AYyOBq|ciR4k z)jEL1&j$iN5!|xef{B%e(0^CVCq#;LjH_w@5AgwRY1=bTf;IVsLmddgquK x^zA+g4HIZlH=At%?nPslt%HMSG&kQ8Gp&%RvyWnajl%3Z##M8H#Vj0m-Qzv$#R~uc literal 0 HcmV?d00001 diff --git a/MikroGig/20260702/20260702190305-Config.rsc b/MikroGig/20260702/20260702190305-Config.rsc new file mode 100644 index 0000000..de192e5 --- /dev/null +++ b/MikroGig/20260702/20260702190305-Config.rsc @@ -0,0 +1,3155 @@ +# 2026-07-02 18:03:06 by RouterOS 7.23.1 +# software id = 2961-C4ZZ +# +# model = RBD52G-5HacD2HnD +# serial number = HCX084RAVFA +/interface bridge +add admin-mac=18:FD:74:6E:58:14 auto-mac=no name=Bridge-LAN port-cost-mode=\ + short +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + name=wlan1 ssid=vados wps-mode=disabled +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(20dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + name=wlan2 ssid=vados5g wps-mode=disabled +/interface ethernet +set [ find default-name=ether1 ] mac-address=48:8F:5A:8E:1A:BC +/interface veth +add address=172.19.75.210/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ + gateway=172.19.75.209 gateway6="" name=veth-awg-VDSina +/interface wireguard +add disabled=yes listen-port=14710 mtu=1420 name=wg-awg-VDSina +/disk +add mount-point-template="[tmpfs]" slot=ram tmpfs-max-size=64 type=tmpfs +/interface list +add name=WAN +add name=LAN +add exclude=LAN include=WAN name=Internet +/interface wireless security-profiles +set [ find default=yes ] supplicant-identity=MikroTik +/routing table +add disabled=no fib name=r_to_vpn +/system logging action +add email-start-tls=yes email-to=vados@vados.ru name=email target=email +/system script +add comment="Script for setup routeros script 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 script 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 Identity [/system/identity/get name];\r\ + \n:global SetupScript [ :jobname ];\r\ + \n:global RemoveMe true;\r\ + \n:global RunOnce (a);\r\ + \n:global InitSetup true;\r\ + \n:global tmpfs false;\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 UrlSuffix \$Identity;\r\ + \n :local UrlDir \"certs/\";\r\ + \n :local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\"); \ + \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\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 /tool/fetch (\$CertUrl . \$CertFileName) dst-path=\$CertFileName\ + \_as-value;\r\ + \n :delay 1s;\r\ + \n /certificate/import file-name=\$CertFileName passphrase=\"\";\r\ + \n /certificate/set name=\"Root-YE\" [ find where common-name=\"Roo\ + t YE\" ];\r\ + \n :delay 1s;\r\ + \n };\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where fingerprint=\$CertFingerprint ] \ + ] != 1) do={\r\ + \n :error \"Something is wrong with your certificates!\";\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 :local Script \"mod/AM-Certs-By-Ident\";\r\ + \n \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/fetch \ + check-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".\ + rsc\") output=user as-value ]->\"data\");\r\ + \n /system/script run \$Script;\r\ + \n :global tmpAddCerts;\r\ + \n :while ([ \$tmpAddCerts ] = true) do={\r\ + \n :delay 1s;\r\ + \n }\r\ + \n :delay 1s;\r\ + \n :put \"Removing \$Script...\";\r\ + \n /system/script/remove [ find where name=\$Script ];\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 Identity [/system/identity/get name];\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 (a);\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/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/728/bebacfc7\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 11:00:05 30.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\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 :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$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\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$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={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$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={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\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\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\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 :log 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 :log 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 :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log 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 :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\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 ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$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=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' 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 :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 :log 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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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\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 :if (\$ExitOK = \"false\") do={\r\ + \n :log 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment="Download custom Certificates By Routers Identity " \ + dont-require-permissions=no name=mod/AM-Certs-By-Ident owner=\ + mod/AM-Certs-By-Ident policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + !rsc by Vados\r\ + \n# RouterOS script: AM-Certs-By-Ident\r\ + \n# Script comment: Download custom Certificates By Routers Identity \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# CloudFlare\r\ + \n#/tool/fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobalR\ + ootCA.crt.pem;\r\ + \n#/certificate/import file-name=DigiCertGlobalRootCA.crt.pem passphrase=\ + \"\";\r\ + \n#/tool/ fetch mode=https url=https://cacerts.digicert.com/DigiCertGlobal\ + G2TLSRSASHA2562020CA1-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/DigiCertGloba\ + lG3TLSECCSHA3842020CA1-1.crt.pem\"\r\ + \n#/certificate/import file-name=DigiCertGlobalG3TLSECCSHA3842020CA1-1.crt\ + .pem passphrase=\"\";\r\ + \n:global tmpAddCerts true; \r\ + \n\r\ + \n:global GlobalScriptsUrl;\r\ + \n:local UrlSuffix [/system/identity/get name];\r\ + \n:local UrlDir \"certs/\";\r\ + \n:local CertUrl (\$GlobalScriptsUrl . \$UrlDir . \$UrlSuffix .\"/\");\r\ + \n\r\ + \n:log error \$CertUrl;\r\ + \n\r\ + \n:local CertName \"DigiCert-Global-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-CA\" [ find where common-na\ + me=\"DigiCert Global Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-CA.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-CA\" [ find where commo\ + n-name=\"DigiCert Assured ID Root CA\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G2\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Assured-ID-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Assured-ID-Root-G3\" [ find where commo\ + n-name=\"DigiCert Assured ID Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G2-TLS-RSA-SHA256-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G2 TLS RSA SHA256 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-G3-TLS-ECC-SHA384-2020-CA1\" [ f\ + ind where common-name=\"DigiCert Global G3 TLS ECC SHA384 2020 CA1\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G2\" [ find where common-na\ + me=\"DigiCert Global Root G2\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Global-Root-G3.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Global-Root-G3\" [ find where common-na\ + me=\"DigiCert Global Root G3\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-ECC-P384-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-ECC-P384-Root-G5\" [ find where com\ + mon-name=\"DigiCert TLS ECC P384 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-TLS-RSA4096-Root-G5.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-TLS-RSA4096-Root-G5\" [ find where comm\ + on-name=\"DigiCert TLS RSA4096 Root G5\" ];\r\ + \n\r\ + \n:set CertName \"DigiCert-Trusted-Root-G4.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"DigiCert-Trusted-Root-G4\" [ find where common-n\ + ame=\"DigiCert Trusted Root G4\" ];\r\ + \n\r\ + \n:set CertName \"GTS-Root-R4.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"GTS-Root-R4\" [ find where common-name=\"GTS Roo\ + t R4\" ];\r\ + \n\r\ + \n:set CertName \"Go-Daddy-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Go-Daddy-Root-Certificate-Authority-G2\" [ find \ + where common-name=\"Go Daddy Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"ISRG-Root-X1.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"ISRG-Root-X1\" [ find where common-name=\"ISRG R\ + oot X1\" ];\r\ + \n\r\ + \n:set CertName \"Root-YE.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Root-YE\" [ find where common-name=\"Root YE\" ]\ + ;\r\ + \n\r\ + \n:set CertName \"Starfield-Root-Certificate-Authority-G2.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"Starfield-Root-Certificate-Authority-G2\" [ find\ + \_where common-name=\"Starfield Root Certificate Authority - G2\" ];\r\ + \n\r\ + \n:set CertName \"USERTrust-RSA-Certification-Authority.pem\";\r\ + \n/tool/fetch mode=https url=(\$CertUrl . \$CertName);\r\ + \n/certificate/import file-name=\$CertName passphrase=\"\";\r\ + \n/certificate/set name=\"USERTrust-RSA-Certification-Authority\" [ find w\ + here common-name=\"USERTrust RSA Certification Authority\" ];\r\ + \n\r\ + \n:global tmpAddCerts (a);\r\ + \n\r\ + \n#/certificate/import file-name=\$CertName passphrase=\"\";\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#/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\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=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \r\ + \n:global GlobalScriptsUrl;\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n" +add dont-require-permissions=no name=awg2-webui owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + :put \"Download image, and save him to usb1/tmp\"\ + \n#/tool/fetch url=\"https://ros.vados.ru/docker/awg2-webui-arm.tar\" dst-\ + path=usb1/tmp/awg2-webui.tar\ + \n\ + \n:put \"1. Create veth interface\"\ + \n/interface veth add name=veth-awg address=10.9.9.2/24 gateway=10.9.9.1\ + \n\ + \n:put \"2. Create bridge and add veth\"\ + \n/interface bridge add name=br-awg\ + \n/interface bridge port add bridge=br-awg interface=veth-awg\ + \n\ + \n:put \"3. Assign IP to bridge\"\ + \n/ip address add address=10.9.9.1/24 interface=br-awg\ + \n\ + \n:put \"4. NAT: masquerade container traffic\"\ + \n/ip firewall nat add chain=srcnat src-address=10.9.9.0/24 action=masquer\ + ade\ + \n\ + \n:put \"5. Port forward: UDP 443 \? container (AmneziaWG QUIC mimicry)\"\ + \n/ip firewall nat add chain=dstnat protocol=udp dst-port=443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=55055 in-interface=eth\ + er1\ + \n\ + \n:put \"6. Port forward: HTTPS 9443 \? container Web UI\"\ + \n/ip firewall nat add chain=dstnat protocol=tcp dst-port=9443 \\\ + \n action=dst-nat to-addresses=10.9.9.2 to-ports=443 in-interface=ether\ + 1\ + \n\ + \n:put \"Create environment list..\"\ + \n/container envs add list=awgui-env key=WEB_USER value=vados\ + \n/container envs add list=awgui-env key=WEB_PASS value=zoomzoomrulezz\ + \n/container envs add list=awgui-env key=SECRET_KEY value=RanDomSecret32Sy\ + mboLs2325272931q\ + \n/container envs add list=awgui-env key=AWG_ENDPOINT value=10.30.30.10:44\ + 3\ + \n\ + \n:put \"Load and start container...\"\ + \n/container add file=usb1/tmp/awg2-webui.tar interface=veth-awg hostname=\ + awg2-webui \\\ + \nroot-dir=usb1/awg2-webui envlist=awgui-env start-on-boot=yes logging=yes\ + \_shm-size=4M\ + \n\ + \n:put \"Start...\"\ + \n/container start 0\ + \n\ + \n:put \"Verify...\"\ + \n/container print\ + \n\ + \n:put \"Should show: status=running\"\ + \n\ + \n/log print where topics~\"container\"\ + \n\ + \n:put \"Should show: AWG started, nginx running\"\ + \n" +add comment=awg-VDSina dont-require-permissions=no name=awg-VDSina-uninstall \ + owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ + \n\ + \n :put \"Uninstallimg AmneziaWG...\"\ + \n\ + \n :log info \"Uninstallimg AmneziaWG...\"\ + \n\ + \n :local prevDNS \"\"\ + \n\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\ + \n\ + \n :local storageDisk \"disk1\"\ + \n\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\ + \n\ + \n :local prevTmpdir \"\"\ + \n\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\ + \n\ + \n }\ + \n\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\ + \n\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\ + \n\ + \n /container/stop [find where interface=veth-awg-VDSina]\ + \n\ + \n :delay 7s\ + \n\ + \n /container/remove [find where interface=veth-awg-VDSina]\ + \n\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\ + \n\ + \n :if (\$prevDNS != \"\") do={\ + \n\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\ + \n\ + \n :put (\"DNS restored to: \$prevDNS\")\ + \n\ + \n }\ + \n\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n\ + \n /container/config set tmpdir=\$prevTmpdir\ + \n\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\ + \n\ + \n }\ + \n\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\ + \n\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \n\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\ + \n\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\ + \n\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\ + \n\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\ + \n\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\ + \n\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \n\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\ + \n\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\ + \n\ + \n :if (\$storageDisk != \"disk1\") do={\ + \n\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\ + \n\ + \n }\ + \n\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\ + \n\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\ + \n\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\ + \n\ + \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" +/container config +set layer-dir=/usb1/docker memory-high=200.0MiB memory-max=2048.0KiB \ + registry-url=https://registry-1.docker.io tmpdir=/usb1/pull username=\ + amsternl +/container envs +add key=AWG_CLIENT_PUB list=awg-VDSina-env value=\ + "pEKNAHuN+yRImhmL0pISjPy/kts2vE4e2TRpFa7Kdkk=" +add key=AWG_H1 list=awg-VDSina-env value=472437748-472438637 +add key=AWG_H2 list=awg-VDSina-env value=707808381-707809250 +add key=AWG_H3 list=awg-VDSina-env value=1609078552-1609079495 +add key=AWG_H4 list=awg-VDSina-env value=1012329484-1012329741 +add key=AWG_I1 list=awg-VDSina-env value=\ + "" +add key=AWG_I2 list=awg-VDSina-env value="" +add key=AWG_I3 list=awg-VDSina-env value="" +add key=AWG_I4 list=awg-VDSina-env value="" +add key=AWG_I5 list=awg-VDSina-env value="" +add key=AWG_JC list=awg-VDSina-env value=9 +add key=AWG_JMAX list=awg-VDSina-env value=920 +add key=AWG_JMIN list=awg-VDSina-env value=105 +add key=AWG_LISTEN list=awg-VDSina-env value=:51820 +add key=AWG_PREV_DNS list=awg-VDSina-env value=10.30.30.33,109.107.177.79 +add key=AWG_PREV_TMPDIR list=awg-VDSina-env value=/tmp +add key=AWG_REMOTE list=awg-VDSina-env value=109.107.177.79:55055 +add key=AWG_S1 list=awg-VDSina-env value=90 +add key=AWG_S2 list=awg-VDSina-env value=136 +add key=AWG_S3 list=awg-VDSina-env value=45 +add key=AWG_S4 list=awg-VDSina-env value=27 +add key=AWG_SERVER_PUB list=awg-VDSina-env value=\ + "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +add key=AWG_STORAGE list=awg-VDSina-env value=usb1 +/disk settings +set auto-media-interface=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether1 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=ether4 +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/ip neighbor discovery-settings +set discover-interface-list=Internet +/ipv6 settings +set allow-fast-path=no disable-ipv6=yes disable-link-local-address=yes \ + forward=no +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN wan-interface-list=WAN +/interface list member +add interface=ether2 list=LAN +add interface=ether3 list=LAN +add interface=ether4 list=LAN +add interface=ether5 list=LAN +add interface=wlan2 list=LAN +add interface=wlan1 list=LAN +add interface=ether1 list=Internet +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 endpoint-address=172.19.75.210 endpoint-port=\ + 51820 interface=wg-awg-VDSina name=peer4 persistent-keepalive=10s \ + public-key="o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +/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 +/ip address +add address=10.30.30.86/24 interface=ether1 network=10.30.30.0 +add address=172.19.75.209/30 interface=veth-awg-VDSina network=172.19.75.208 +add address=10.9.0.2 interface=wg-awg-VDSina network=10.9.0.2 +/ip dns +set allow-remote-requests=yes servers=109.107.177.79 +/ip firewall nat +add action=masquerade chain=srcnat src-address=10.9.9.0/24 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=443 in-interface=ether1 protocol=udp \ + to-addresses=10.9.9.2 to-ports=55055 +# in/out-interface matcher not possible when interface (ether1) is slave - use master instead (Bridge-LAN) +add action=dst-nat chain=dstnat dst-port=9443 in-interface=ether1 protocol=\ + tcp to-addresses=10.9.9.2 to-ports=443 +add action=masquerade chain=srcnat src-address=172.19.75.208/30 +/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 +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 check-gateway=ping disabled=no distance=2 dst-address=0.0.0.0/0 gateway=\ + ether1 routing-table=main scope=30 target-scope=10 +add comment=awg-VDSina-dns distance=1 dst-address=109.107.177.79/32 gateway=\ + wg-awg-VDSina +/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 disabled=yes +set www-ssl port=18443 +set www address=10.30.30.0/24 disabled=yes port=18880 +/ip service webserver +set graphs-plain=no rest-plain=no webfig-plain=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 forced-ip=109.107.177.79 interface=*A type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 nd +set [ find default=yes ] advertise-dns=yes +/system clock +set time-zone-name=Europe/Amsterdam +/system clock manual +set time-zone=+03:00 +/system identity +set name=MikroGig +/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=10.30.30.81 +add address=10.30.30.10 +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="Every Day Set Global Environment Variables" 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=Generator name=awg-VDSina on-event="# ============================\ + ================================\r\ + \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ + \n# 2026-07-01 00:03:43\r\ + \n# ============================================================\r\ + \n\r\ + \n# 0. Check prerequisites\r\ + \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ + = 0) do={\r\ + \n :put \"Container package is not installed or disabled. Install it and \ + reboot.\"\r\ + \n :error \"Usage: /system/device-mode/update container=yes\"\r\ + \n}\r\ + \n\r\ + \n# Auto-detect storage\r\ + \n:global awgDisk \"disk1\"\r\ + \n{\r\ + \n :local usbFree 0\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ + } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ + \r\ + \n } else={\r\ + \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ + \n :put \"USB found but not mounted. Format as ext4\?\"\r\ + \n :put \"Press 'y' to confirm:\"\r\ + \n :local key [/terminal/inkey timeout=30]\r\ + \n :if (\$key = 121 || \$key = 89) do={\r\ + \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ + \n :delay 3s\r\ + \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ + free] } on-error={}\r\ + \n :if (\$usbFree > 0) do={\r\ + \n :set awgDisk \"usb1\"\r\ + \n } else={ :put \"Format failed, using disk1\" }\r\ + \n } else={ :put \"Using disk1\" }\r\ + \n } else={ :put \"No USB, using disk1\" }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n# 1. Uninstall script\r\ + \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ + \r\ + \n :put \"Uninstallimg AmneziaWG...\"\r\ + \n :log info \"Uninstallimg AmneziaWG...\"\r\ + \n :local prevDNS \"\"\r\ + \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ + env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ + \n :local storageDisk \"disk1\"\r\ + \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ + ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ + \n :local prevTmpdir \"\"\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ + Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ + \n }\r\ + \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ + \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ + \n /container/stop [find where interface=veth-awg-VDSina]\r\ + \n :delay 7s\r\ + \n /container/remove [find where interface=veth-awg-VDSina]\r\ + \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ + \n :if (\$prevDNS != \"\") do={\r\ + \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ + \n :put (\"DNS restored to: \$prevDNS\")\r\ + \n }\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n /container/config set tmpdir=\$prevTmpdir\r\ + \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ + \n }\r\ + \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ + \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ + \r\ + \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ + \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ + \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ + a\"]\r\ + \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ + \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ + \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ + \r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ + \_} on-error={}\r\ + \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ + out.rsc\")] } on-error={}\r\ + \n :if (\$storageDisk != \"disk1\") do={\r\ + \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ + n-error={}\r\ + \n }\r\ + \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ + \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ + \n}\r\ + \n\r\ + \n# 2. Network infrastructure\r\ + \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ + y=172.19.75.209\r\ + \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ + \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ + 5.208/30\r\ + \n\r\ + \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ + \r\ + \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"QCMsDU98Gm+nhn\ + kYRcAN/dyczDYHOLsX3PfBRFjWBF4=\" listen-port=14710 disabled=yes\r\ + \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ + Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"b39T9K2/LR8vNtY\ + AZw+sLRze6yGlS3EaZhAa7wiFB20=\" endpoint-address=172.19.75.210 endpoint-po\ + rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ + \n/ip/address/add address=10.9.0.2/32 interface=wg-awg-VDSina\r\ + \n\r\ + \n# 4. Container environment variables\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ + 77.79:55055\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ + 438637\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ + 809250\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ + 09079495\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ + 12329741\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ + l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ + face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ + \"\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ + \r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ + \n\r\ + \n# 5. DNS\r\ + \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ + n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ + \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ + g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ + \n# NOTE: replaces existing DNS configuration\r\ + \n/ip/dns/set servers=109.107.177.79\r\ + \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ + ce=1 comment=awg-VDSina-dns\r\ + \n\r\ + \n# 6. Download, create and start container\r\ + \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ + \r\ + \n:if (\$awgDisk != \"disk1\") do={\r\ + \n :local tmpPath (\$awgDisk . \"/pull\")\r\ + \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ + ntainer/config/get tmpdir]\r\ + \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ + \n}\r\ + \n{\r\ + \n :local arch [/system/resource/get architecture-name]\r\ + \n :local ver [/system/resource/get version]\r\ + \n :local dotPos [:find \$ver \".\"]\r\ + \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ + \n :local endPos [:find \$rest \".\"]\r\ + \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ + \"] }\r\ + \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ + \n :local suffix \"\"\r\ + \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ + \n :local file \"\"\r\ + \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ + x . \".tar.gz\") }\r\ + \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ + \".tar.gz\") }\r\ + \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ + . \".tar.gz\") }\r\ + \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ + \r\ + \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ + atest/download/\$file\"\r\ + \n :local filePath \$file\r\ + \n :if (\$awgDisk != \"disk1\") do={\r\ + \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ + \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ + \n }\r\ + \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ + \n :local freeStorage 0\r\ + \n :if (\$awgDisk = \"disk1\") do={\r\ + \n :set freeStorage [/system/resource/get free-hdd-space]\r\ + \n } else={\r\ + \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ + k] free] } on-error={}\r\ + \n }\r\ + \n :if (\$freeStorage < 262144) do={\r\ + \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ + B free). Need at least 256KB.\")\r\ + \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ + cient-disk-space\"\r\ + \n :error \"Insufficient disk space\"\r\ + \n }\r\ + \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ + \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ + \r\ + \n } else={\r\ + \n :put (\"File already exists: \" . \$filePath)\r\ + \n }\r\ + \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ + \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ + DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ + yes comment=awg-VDSina\r\ + \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ + =veth-awg-VDSina] shm-size=4M\"] }\r\ + \n /file/remove \$filePath\r\ + \n :local freeMem [/system/resource/get free-memory]\r\ + \n :if (\$freeMem < 16777216) do={\r\ + \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ + . 16MB+ recommended.\")\r\ + \n }\r\ + \n /container/start [find where interface=veth-awg-VDSina]\r\ + \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ + }\r\ + \n :put \"Waiting for container to start...\"\r\ + \n :delay 5s\r\ + \n /interface/wireguard/enable wg-awg-VDSina\r\ + \n :put \"WireGuard interface enabled\"\r\ + \n :put \"Installation complete!\"\r\ + \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ + \"\r\ + \n /ping 109.107.177.79 count=10 interval=1\r\ + \n :put \"\"\r\ + \n :put \"======= NEXT STEPS =======\"\r\ + \n :put \"\"\r\ + \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ + \n :put \"\"\r\ + \n :put \" Route a single host:\"\r\ + \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ + comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Route a subnet:\"\r\ + \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ + \_comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Remove a route:\"\r\ + \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ + address=8.8.8.8/32]\"\r\ + \n :put \"\"\r\ + \n :put \" Show all tunnel routes:\"\r\ + \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ + \n :put \"\"\r\ + \n :put \" Uninstall:\"\r\ + \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ + \n :put \"=========================\"\r\ + \n}\r\ + \n\r\ + \n# 7. Verification\r\ + \n# /container/print\r\ + \n# /interface/wireguard/print\r\ + \n# /interface/wireguard/peers/print\r\ + \n" policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + start-date=2026-07-01 start-time=02:03:59 +/tool e-mail +set certificate-verification=no from=MikroVados port=587 \ + server=smtp.mail.me.com tls=starttls user=vadossio@icloud.com diff --git a/MikroGig/history/20260702/20260702190305-Diff-Config.rsc b/MikroGig/history/20260702/20260702190305-Diff-Config.rsc new file mode 100644 index 0000000..219d997 --- /dev/null +++ b/MikroGig/history/20260702/20260702190305-Diff-Config.rsc @@ -0,0 +1,449 @@ +8a9 +> add name=br-awg +11c12 +< # channel: 2422/20-Ce/gn(17dBm), SSID: vados, local forwarding +--- +> # channel: 2442/20-Ce/gn(17dBm), SSID: vados, local forwarding +21,24c22,23 +< add address=172.19.75.210/30 container-mac-address=00:00:00:00:00:00 dhcp=no \ +< gateway=172.19.75.209 gateway6="" name=veth-awg-VDSina +< /interface wireguard +< add disabled=yes listen-port=14710 mtu=1420 name=wg-awg-VDSina +--- +> add address=10.9.9.2/24 container-mac-address=78:60:DB:55:90:E3 dhcp=no \ +> gateway=10.9.9.1 gateway6="" mac-address=78:60:DB:55:90:E2 name=veth-awg +2628,2719d2626 +< add comment=awg-VDSina dont-require-permissions=no name=awg-VDSina-uninstall \ +< owner=vados policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="\ +< \n\ +< \n :put \"Uninstallimg AmneziaWG...\"\ +< \n\ +< \n :log info \"Uninstallimg AmneziaWG...\"\ +< \n\ +< \n :local prevDNS \"\"\ +< \n\ +< \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ +< env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\ +< \n\ +< \n :local storageDisk \"disk1\"\ +< \n\ +< \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ +< ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\ +< \n\ +< \n :local prevTmpdir \"\"\ +< \n\ +< \n :if (\$storageDisk != \"disk1\") do={\ +< \n\ +< \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ +< Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\ +< \n\ +< \n }\ +< \n\ +< \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\ +< \n\ +< \n /ip/route/remove [find where comment=awg-VDSina-dns]\ +< \n\ +< \n /container/stop [find where interface=veth-awg-VDSina]\ +< \n\ +< \n :delay 7s\ +< \n\ +< \n /container/remove [find where interface=veth-awg-VDSina]\ +< \n\ +< \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\ +< \n\ +< \n :if (\$prevDNS != \"\") do={\ +< \n\ +< \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\ +< \n\ +< \n :put (\"DNS restored to: \$prevDNS\")\ +< \n\ +< \n }\ +< \n\ +< \n :if (\$storageDisk != \"disk1\") do={\ +< \n\ +< \n /container/config set tmpdir=\$prevTmpdir\ +< \n\ +< \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\ +< \n\ +< \n }\ +< \n\ +< \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\ +< \n\ +< \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ +< \n\ +< \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\ +< \n\ +< \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\ +< \n\ +< \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ +< a\"]\ +< \n\ +< \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\ +< \n\ +< \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\ +< \n\ +< \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ +< \n\ +< \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ +< \_} on-error={}\ +< \n\ +< \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ +< out.rsc\")] } on-error={}\ +< \n\ +< \n :if (\$storageDisk != \"disk1\") do={\ +< \n\ +< \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ +< n-error={}\ +< \n\ +< \n }\ +< \n\ +< \n :put \"Uninstall AmneziaWG Proxy complete!\"\ +< \n\ +< \n :log info \"Uninstall AmneziaWG Proxy complete!\"\ +< \n\ +< \n /system/script/remove [find where name=awg-VDSina-uninstall]\ +< \n\ +< \n" +2722a2630,2636 +> /container +> # killed due to out of memory +> add cpu-list=cpu1,cpu3 domain-name=vados.ru envlists=awgui-env file=\ +> usb1/tmp/awg2-webui.tar hostname=mikronuc interface=veth-awg layer-dir=\ +> /usb1/docker logging=yes memory-high=12.0MiB memory-max=16.0MiB name=\ +> awg2-webui root-dir=/usb1/awg-webui shm-size=8.0MiB start-on-boot=yes \ +> tmpfs=/tmpfs:512.0MiB:01000 +2724,2726c2638,2639 +< set layer-dir=/usb1/docker memory-high=200.0MiB memory-max=2048.0KiB \ +< registry-url=https://registry-1.docker.io tmpdir=/usb1/pull username=\ +< amsternl +--- +> set layer-dir=/usb1/docker memory-high=2048.0KiB memory-max=2048.0KiB \ +> registry-url=https://registry-1.docker.io tmpdir=/tmp username=amsternl +2728,2753c2641,2644 +< add key=AWG_CLIENT_PUB list=awg-VDSina-env value=\ +< "pEKNAHuN+yRImhmL0pISjPy/kts2vE4e2TRpFa7Kdkk=" +< add key=AWG_H1 list=awg-VDSina-env value=472437748-472438637 +< add key=AWG_H2 list=awg-VDSina-env value=707808381-707809250 +< add key=AWG_H3 list=awg-VDSina-env value=1609078552-1609079495 +< add key=AWG_H4 list=awg-VDSina-env value=1012329484-1012329741 +< add key=AWG_I1 list=awg-VDSina-env value=\ +< "" +< add key=AWG_I2 list=awg-VDSina-env value="" +< add key=AWG_I3 list=awg-VDSina-env value="" +< add key=AWG_I4 list=awg-VDSina-env value="" +< add key=AWG_I5 list=awg-VDSina-env value="" +< add key=AWG_JC list=awg-VDSina-env value=9 +< add key=AWG_JMAX list=awg-VDSina-env value=920 +< add key=AWG_JMIN list=awg-VDSina-env value=105 +< add key=AWG_LISTEN list=awg-VDSina-env value=:51820 +< add key=AWG_PREV_DNS list=awg-VDSina-env value=10.30.30.33,109.107.177.79 +< add key=AWG_PREV_TMPDIR list=awg-VDSina-env value=/tmp +< add key=AWG_REMOTE list=awg-VDSina-env value=109.107.177.79:55055 +< add key=AWG_S1 list=awg-VDSina-env value=90 +< add key=AWG_S2 list=awg-VDSina-env value=136 +< add key=AWG_S3 list=awg-VDSina-env value=45 +< add key=AWG_S4 list=awg-VDSina-env value=27 +< add key=AWG_SERVER_PUB list=awg-VDSina-env value=\ +< "o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +< add key=AWG_STORAGE list=awg-VDSina-env value=usb1 +--- +> add key=AWG_ENDPOINT list=awgui-env value=10.30.30.10:443 +> add key=SECRET_KEY list=awgui-env value=RanDomSecret32SymboLs2325272931q +> add key=WEB_PASS list=awgui-env value=zoomzoomrulezz +> add key=WEB_USER list=awgui-env value=vados +2763a2655,2660 +> add bridge=*D interface=*C +> add bridge=*F interface=*E +> add bridge=*11 interface=*10 +> add bridge=*13 interface=*12 +> add bridge=*15 interface=*14 +> add bridge=br-awg interface=veth-awg +2781,2784d2677 +< /interface wireguard peers +< add allowed-address=0.0.0.0/0 endpoint-address=172.19.75.210 endpoint-port=\ +< 51820 interface=wg-awg-VDSina name=peer4 persistent-keepalive=10s \ +< public-key="o5IgCl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=" +2793,2794c2686 +< add address=172.19.75.209/30 interface=veth-awg-VDSina network=172.19.75.208 +< add address=10.9.0.2 interface=wg-awg-VDSina network=10.9.0.2 +--- +> add address=10.9.9.1/24 interface=br-awg network=10.9.9.0 +2796c2688 +< set allow-remote-requests=yes servers=109.107.177.79 +--- +> set allow-remote-requests=yes servers=10.30.30.33,109.107.177.79 +2805d2696 +< add action=masquerade chain=srcnat src-address=172.19.75.208/30 +2828,2829d2718 +< add comment=awg-VDSina-dns distance=1 dst-address=109.107.177.79/32 gateway=\ +< wg-awg-VDSina +2885,3152d2773 +< add comment=Generator name=awg-VDSina on-event="# ============================\ +< ================================\r\ +< \n# AWG Proxy -- MikroTik RouterOS (protocol: v2)\r\ +< \n# 2026-07-01 00:03:43\r\ +< \n# ============================================================\r\ +< \n\r\ +< \n# 0. Check prerequisites\r\ +< \n:if ([:len [/system/package/find where name=\"container\" disabled=no]] \ +< = 0) do={\r\ +< \n :put \"Container package is not installed or disabled. Install it and \ +< reboot.\"\r\ +< \n :error \"Usage: /system/device-mode/update container=yes\"\r\ +< \n}\r\ +< \n\r\ +< \n# Auto-detect storage\r\ +< \n:global awgDisk \"disk1\"\r\ +< \n{\r\ +< \n :local usbFree 0\r\ +< \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] free] \ +< } on-error={}\r\ +< \n :if (\$usbFree > 0) do={\r\ +< \n :set awgDisk \"usb1\"\r\ +< \n :put (\"Using USB: usb1 (\" . (\$usbFree / 1048576) . \" MB free)\")\ +< \r\ +< \n } else={\r\ +< \n :if ([:len [/disk/find where slot=\"usb1\"]] > 0) do={\r\ +< \n :put \"USB found but not mounted. Format as ext4\?\"\r\ +< \n :put \"Press 'y' to confirm:\"\r\ +< \n :local key [/terminal/inkey timeout=30]\r\ +< \n :if (\$key = 121 || \$key = 89) do={\r\ +< \n /disk/format-drive usb1 file-system=ext4 label=usb1\r\ +< \n :delay 3s\r\ +< \n :do { :set usbFree [/disk/get [find where mount-point=\"usb1\"] \ +< free] } on-error={}\r\ +< \n :if (\$usbFree > 0) do={\r\ +< \n :set awgDisk \"usb1\"\r\ +< \n } else={ :put \"Format failed, using disk1\" }\r\ +< \n } else={ :put \"Using disk1\" }\r\ +< \n } else={ :put \"No USB, using disk1\" }\r\ +< \n }\r\ +< \n}\r\ +< \n\r\ +< \n# 1. Uninstall script\r\ +< \n/system/script/add name=awg-VDSina-uninstall comment=awg-VDSina source={\ +< \r\ +< \n :put \"Uninstallimg AmneziaWG...\"\r\ +< \n :log info \"Uninstallimg AmneziaWG...\"\r\ +< \n :local prevDNS \"\"\r\ +< \n :do { :set prevDNS [/container/envs/get [find where list=\"awg-VDSina-\ +< env\" key=\"AWG_PREV_DNS\"] value] } on-error={}\r\ +< \n :local storageDisk \"disk1\"\r\ +< \n :do { :set storageDisk [/container/envs/get [find where list=\"awg-VDS\ +< ina-env\" key=\"AWG_STORAGE\"] value] } on-error={}\r\ +< \n :local prevTmpdir \"\"\r\ +< \n :if (\$storageDisk != \"disk1\") do={\r\ +< \n :do { :set prevTmpdir [/container/envs/get [find where list=\"awg-VD\ +< Sina-env\" key=\"AWG_PREV_TMPDIR\"] value] } on-error={}\r\ +< \n }\r\ +< \n /ip/route/remove [find where comment=awg-VDSina-tunnel]\r\ +< \n /ip/route/remove [find where comment=awg-VDSina-dns]\r\ +< \n /container/stop [find where interface=veth-awg-VDSina]\r\ +< \n :delay 7s\r\ +< \n /container/remove [find where interface=veth-awg-VDSina]\r\ +< \n /container/envs/remove [find where list=\"awg-VDSina-env\"]\r\ +< \n :if (\$prevDNS != \"\") do={\r\ +< \n :do { /ip/dns/set servers=\"\$prevDNS\" } on-error={}\r\ +< \n :put (\"DNS restored to: \$prevDNS\")\r\ +< \n }\r\ +< \n :if (\$storageDisk != \"disk1\") do={\r\ +< \n /container/config set tmpdir=\$prevTmpdir\r\ +< \n :put (\"Container tmpdir restored to: \$prevTmpdir\")\r\ +< \n }\r\ +< \n /ip/firewall/nat/remove [find where out-interface=\"wg-awg-VDSina\"]\r\ +< \n /ip/firewall/nat/remove [find where src-address=\"172.19.75.208/30\"]\ +< \r\ +< \n /ip/address/remove [find where address=\"172.19.75.209/30\"]\r\ +< \n /interface/veth/remove [find where name=\"veth-awg-VDSina\"]\r\ +< \n /interface/wireguard/peers/remove [find where interface=\"wg-awg-VDSin\ +< a\"]\r\ +< \n /ip/address/remove [find where interface=\"wg-awg-VDSina\"]\r\ +< \n /interface/wireguard/remove [find where name=\"wg-awg-VDSina\"]\r\ +< \n :do { /file/remove [find where name~\"awg-VDSina.+tar\"] } on-error={}\ +< \r\ +< \n :do { /file/remove [find where name=(\$storageDisk . \"/awg-VDSina\")]\ +< \_} on-error={}\r\ +< \n :do { /file/remove [find where name=(\$storageDisk . \"/ru_ranges_time\ +< out.rsc\")] } on-error={}\r\ +< \n :if (\$storageDisk != \"disk1\") do={\r\ +< \n :do { /file/remove [find where name~(\$storageDisk . \"/pull\")] } o\ +< n-error={}\r\ +< \n }\r\ +< \n :put \"Uninstall AmneziaWG Proxy complete!\"\r\ +< \n :log info \"Uninstall AmneziaWG Proxy complete!\"\r\ +< \n /system/script/remove [find where name=awg-VDSina-uninstall]\r\ +< \n}\r\ +< \n\r\ +< \n# 2. Network infrastructure\r\ +< \n/interface/veth/add name=veth-awg-VDSina address=172.19.75.210/30 gatewa\ +< y=172.19.75.209\r\ +< \n/ip/address/add address=172.19.75.209/30 interface=veth-awg-VDSina\r\ +< \n/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.19.7\ +< 5.208/30\r\ +< \n\r\ +< \n# 3. WireGuard interface (MikroTik derives the public key automatically)\ +< \r\ +< \n/interface/wireguard/add name=wg-awg-VDSina private-key=\"QCMsDU98Gm+nhn\ +< kYRcAN/dyczDYHOLsX3PfBRFjWBF4=\" listen-port=14710 disabled=yes\r\ +< \n/interface/wireguard/peers/add interface=wg-awg-VDSina public-key=\"o5Ig\ +< Cl1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\" preshared-key=\"b39T9K2/LR8vNtY\ +< AZw+sLRze6yGlS3EaZhAa7wiFB20=\" endpoint-address=172.19.75.210 endpoint-po\ +< rt=51820 allowed-address=0.0.0.0/0 persistent-keepalive=10\r\ +< \n/ip/address/add address=10.9.0.2/32 interface=wg-awg-VDSina\r\ +< \n\r\ +< \n# 4. Container environment variables\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_LISTEN value=\":51820\"\ +< \r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_REMOTE value=\"109.107.1\ +< 77.79:55055\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_JC value=\"9\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_JMIN value=\"105\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_JMAX value=\"920\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_S1 value=\"90\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_S2 value=\"136\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_H1 value=\"472437748-472\ +< 438637\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_H2 value=\"707808381-707\ +< 809250\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_H3 value=\"1609078552-16\ +< 09079495\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_H4 value=\"1012329484-10\ +< 12329741\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_SERVER_PUB value=\"o5IgC\ +< l1/G6xbl6j7sPaP4ZNYREeYOmqZjKbm+v0b9jU=\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_CLIENT_PUB value=[/inter\ +< face/wireguard/get [find name=wg-awg-VDSina] public-key]\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_S3 value=\"45\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_S4 value=\"27\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_I1 value=\"\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_I2 value=\"\"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_I3 value=\"\ +< \"\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_I4 value=\"\"\ +< \r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_I5 value=\"\"\r\ +< \n\r\ +< \n# 5. DNS\r\ +< \n{ :local rawDNS [/ip/dns/get servers]; :local prevDNS \"\"; :foreach s i\ +< n=[:toarray \$rawDNS] do={ :if ([:len \$prevDNS] > 0) do={ :set prevDNS \"\ +< \$prevDNS,\$s\" } else={ :set prevDNS \$s } }; /container/envs/add list=aw\ +< g-VDSina-env key=AWG_PREV_DNS value=\"\$prevDNS\" }\r\ +< \n# NOTE: replaces existing DNS configuration\r\ +< \n/ip/dns/set servers=109.107.177.79\r\ +< \n/ip/route/add dst-address=109.107.177.79/32 gateway=wg-awg-VDSina distan\ +< ce=1 comment=awg-VDSina-dns\r\ +< \n\r\ +< \n# 6. Download, create and start container\r\ +< \n/container/envs/add list=awg-VDSina-env key=AWG_STORAGE value=\$awgDisk\ +< \r\ +< \n:if (\$awgDisk != \"disk1\") do={\r\ +< \n :local tmpPath (\$awgDisk . \"/pull\")\r\ +< \n /container/envs/add list=awg-VDSina-env key=AWG_PREV_TMPDIR value=[/co\ +< ntainer/config/get tmpdir]\r\ +< \n /container/config set tmpdir=\$tmpPath memory-high=200M\r\ +< \n}\r\ +< \n{\r\ +< \n :local arch [/system/resource/get architecture-name]\r\ +< \n :local ver [/system/resource/get version]\r\ +< \n :local dotPos [:find \$ver \".\"]\r\ +< \n :local rest [:pick \$ver (\$dotPos + 1) [:len \$ver]]\r\ +< \n :local endPos [:find \$rest \".\"]\r\ +< \n :if ([:typeof \$endPos] = \"nil\") do={ :set endPos [:find \$rest \" \ +< \"] }\r\ +< \n :local minor [:tonum [:pick \$rest 0 \$endPos]]\r\ +< \n :local suffix \"\"\r\ +< \n :if (\$minor <= 20) do={ :set suffix \"-7.20-Docker\" }\r\ +< \n :local file \"\"\r\ +< \n :if (\$arch = \"arm64\") do={ :set file (\"awg-proxy-arm64\" . \$suffi\ +< x . \".tar.gz\") }\r\ +< \n :if (\$arch = \"arm\") do={ :set file (\"awg-proxy-arm\" . \$suffix . \ +< \".tar.gz\") }\r\ +< \n :if (\$arch ~ \"x86\") do={ :set file (\"awg-proxy-amd64\" . \$suffix \ +< . \".tar.gz\") }\r\ +< \n :if (\$file = \"\") do={ :error \"Unsupported architecture: \$arch\" }\ +< \r\ +< \n :local url \"https://github.com/timbrs/amneziawg-mikrotik-c/releases/l\ +< atest/download/\$file\"\r\ +< \n :local filePath \$file\r\ +< \n :if (\$awgDisk != \"disk1\") do={\r\ +< \n :set filePath (\$awgDisk . \"/pull/\" . \$file)\r\ +< \n :do { /file/make-directory (\$awgDisk . \"/pull\") } on-error={}\r\ +< \n }\r\ +< \n :if ([:len [/file/find where name=\$filePath]] = 0) do={\r\ +< \n :local freeStorage 0\r\ +< \n :if (\$awgDisk = \"disk1\") do={\r\ +< \n :set freeStorage [/system/resource/get free-hdd-space]\r\ +< \n } else={\r\ +< \n :do { :set freeStorage [/disk/get [find where mount-point=\$awgDis\ +< k] free] } on-error={}\r\ +< \n }\r\ +< \n :if (\$freeStorage < 262144) do={\r\ +< \n :put (\"WARNING: Low disk space (\" . (\$freeStorage / 1024) . \"K\ +< B free). Need at least 256KB.\")\r\ +< \n :put \"See: https://github.com/timbrs/amneziawg-mikrotik-c#insuffi\ +< cient-disk-space\"\r\ +< \n :error \"Insufficient disk space\"\r\ +< \n }\r\ +< \n :put (\"Fetching: \$url -> \" . \$filePath)\r\ +< \n /tool/fetch url=\$url dst-path=\$filePath http-max-redirect-count=10\ +< \r\ +< \n } else={\r\ +< \n :put (\"File already exists: \" . \$filePath)\r\ +< \n }\r\ +< \n :local rootDir (\$awgDisk . \"/awg-VDSina\")\r\ +< \n /container/add file=\$filePath interface=veth-awg-VDSina envlist=awg-V\ +< DSina-env hostname=awg-VDSina root-dir=\$rootDir logging=no start-on-boot=\ +< yes comment=awg-VDSina\r\ +< \n :if (\$minor > 20) do={ [:parse \"/container/set [find where interface\ +< =veth-awg-VDSina] shm-size=4M\"] }\r\ +< \n /file/remove \$filePath\r\ +< \n :local freeMem [/system/resource/get free-memory]\r\ +< \n :if (\$freeMem < 16777216) do={\r\ +< \n :put (\"WARNING: Low memory (\" . (\$freeMem / 1048576) . \"MB free)\ +< . 16MB+ recommended.\")\r\ +< \n }\r\ +< \n /container/start [find where interface=veth-awg-VDSina]\r\ +< \n :do { /file/remove [find where name=\"console-dump.txt\"] } on-error={\ +< }\r\ +< \n :put \"Waiting for container to start...\"\r\ +< \n :delay 5s\r\ +< \n /interface/wireguard/enable wg-awg-VDSina\r\ +< \n :put \"WireGuard interface enabled\"\r\ +< \n :put \"Installation complete!\"\r\ +< \n :put \"Ping test: 109.107.177.79 via AmneziaWG tunnel. repeat 10 times\ +< \"\r\ +< \n /ping 109.107.177.79 count=10 interval=1\r\ +< \n :put \"\"\r\ +< \n :put \"======= NEXT STEPS =======\"\r\ +< \n :put \"\"\r\ +< \n :put \"Route specific traffic through the AmneziaWG tunnel:\"\r\ +< \n :put \"\"\r\ +< \n :put \" Route a single host:\"\r\ +< \n :put \" /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg-VDSina \ +< comment=awg-VDSina-tunnel\"\r\ +< \n :put \"\"\r\ +< \n :put \" Route a subnet:\"\r\ +< \n :put \" /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg-VDSina\ +< \_comment=awg-VDSina-tunnel\"\r\ +< \n :put \"\"\r\ +< \n :put \" Remove a route:\"\r\ +< \n :put \" /ip/route/remove [find where comment=awg-VDSina-tunnel dst-\ +< address=8.8.8.8/32]\"\r\ +< \n :put \"\"\r\ +< \n :put \" Show all tunnel routes:\"\r\ +< \n :put \" /ip/route/print where comment=awg-VDSina-tunnel\"\r\ +< \n :put \"\"\r\ +< \n :put \" Uninstall:\"\r\ +< \n :put \" /system/script/run awg-VDSina-uninstall\"\r\ +< \n :put \"=========================\"\r\ +< \n}\r\ +< \n\r\ +< \n# 7. Verification\r\ +< \n# /container/print\r\ +< \n# /interface/wireguard/print\r\ +< \n# /interface/wireguard/peers/print\r\ +< \n" policy=\ +< ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ +< start-date=2026-07-01 start-time=02:03:59 diff --git a/MikroMaster/20260702/20260702180002-Config.rsc b/MikroMaster/20260702/20260702180002-Config.rsc new file mode 100644 index 0000000..362bb18 --- /dev/null +++ b/MikroMaster/20260702/20260702180002-Config.rsc @@ -0,0 +1,3695 @@ +# 2026-07-02 18:00:08 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/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=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/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 +/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=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\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 Identity [/system/identity/get name];\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 (a);\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/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/727/203f86a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:05 29.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\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 :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$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\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$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={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$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={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\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\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\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 :log 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 :log 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 :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log 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 :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\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 ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$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=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' 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 :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 :log 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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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\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 :if (\$ExitOK = \"false\") do={\r\ + \n :log 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=ether4 list=WAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/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 cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:1 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=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.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 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.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 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=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +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=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/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.33,109.107.177.79 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=10.30.30.33,8.8.8.8 \ + verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc 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 disabled=yes 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 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru 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.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes 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=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + 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 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes 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=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/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=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-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes 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-IP +add address=geoip.co list=NoVdsina +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=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 disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 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=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=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +/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 src-address-list=!Trusted-DNS +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 src-address-list=!Trusted-DNS +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 \ + 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=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +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=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes 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 in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +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 +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="AWG for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=*401 routing-mark=!main 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 new-routing-mark=\ + To-VPN routing-mark=!main src-address=10.30.30.0/24 src-address-list=\ + !NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ + to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + 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="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +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 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +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=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/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 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 check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy 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 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE 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-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/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=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 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 disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" 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="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + 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 certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get 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="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260702/20260702182002-Config.rsc b/MikroMaster/20260702/20260702182002-Config.rsc new file mode 100644 index 0000000..6ffe0dd --- /dev/null +++ b/MikroMaster/20260702/20260702182002-Config.rsc @@ -0,0 +1,3696 @@ +# 2026-07-02 18:20:07 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/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=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +#error exporting "/ip/ipsec/policy/group" (timeout) +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/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 +/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=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\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 Identity [/system/identity/get name];\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 (a);\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/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/727/203f86a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:05 29.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\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 :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$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\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$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={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$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={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\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\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\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 :log 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 :log 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 :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log 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 :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\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 ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$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=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' 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 :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 :log 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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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\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 :if (\$ExitOK = \"false\") do={\r\ + \n :log 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=ether4 list=WAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/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 cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:1 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=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.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 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.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 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=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +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=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/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.33,109.107.177.79 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=10.30.30.33,8.8.8.8 \ + verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc 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 disabled=yes 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 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru 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.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes 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=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + 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 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes 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=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/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=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-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes 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-IP +add address=geoip.co list=NoVdsina +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=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 disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 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=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=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +/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 src-address-list=!Trusted-DNS +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 src-address-list=!Trusted-DNS +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 \ + 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=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +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=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes 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 in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +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 +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="AWG for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=*401 routing-mark=!main 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 new-routing-mark=\ + To-VPN routing-mark=!main src-address=10.30.30.0/24 src-address-list=\ + !NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ + to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + 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="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +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 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +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=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/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 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 check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy 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 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE 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-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/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=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 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 disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" 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="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + 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 certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get 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="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/20260702/20260702184001-Config.rsc b/MikroMaster/20260702/20260702184001-Config.rsc new file mode 100644 index 0000000..1b603d9 --- /dev/null +++ b/MikroMaster/20260702/20260702184001-Config.rsc @@ -0,0 +1,3695 @@ +# 2026-07-02 18:40:07 by RouterOS 7.23.1 +# software id = A8L5-07YF +# +# model = RB952Ui-5ac2nD +# serial number = D3D50CEDCD38 +/interface bridge +add admin-mac=48:8F:5A:8E:1A:BF auto-mac=no dhcpv6-agent-circuit-id=\ + "\$(INTERFACE):\$(VID)" dhcpv6-agent-remote-id="\$(BRIDGEMAC)" name=\ + Bridge-LAN port-cost-mode=short +/interface ethernet +set [ find default-name=ether1 ] comment="WAN - Unet" loop-protect=off name=\ + "ether1 - Unet" rx-flow-control=auto tx-flow-control=auto +set [ find default-name=ether2 ] comment=LAN-2 +set [ find default-name=ether3 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-3 +set [ find default-name=ether4 ] comment=LAN-4 +set [ find default-name=ether5 ] advertise="10M-baseT-half,10M-baseT-full,100M\ + -baseT-half,100M-baseT-full,1G-baseT-full,1G-baseX" comment=LAN-5 \ + loop-protect=on poe-out=off rx-flow-control=auto tx-flow-control=auto +/interface wireless +# managed by CAPsMAN +# channel: 2422/20-Ce/gn(18dBm), SSID: vados, local forwarding +set [ find default-name=wlan1 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados wireless-protocol=802.11 +# managed by CAPsMAN +# channel: 5200/20-eCee/ac/P(21dBm), SSID: vados5g, local forwarding +set [ find default-name=wlan2 ] country=belarus disabled=no mode=ap-bridge \ + ssid=vados5g wireless-protocol=802.11 +/interface wireguard +add comment=WG listen-port=13231 mtu=1320 name=WG +/interface list +add include=static name=LAN +add name=Internet +add include=Internet name=WAN +/interface wireless security-profiles +set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk mode=\ + dynamic-keys supplicant-identity=MikroTik +/iot wiliot servers +set *1 address=mqtt.us-east-2.prod.wiliot.cloud name="Wiliot US East" +/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=iVados options=HostName +/ip dns forwarders +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=blsp.at verify-doh-cert=no +add comment=Kra disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon2.to \ + verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=slon3.at verify-doh-cert=no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=slon3.cc verify-doh-cert=no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2web.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.1.1.1,1.0.0.1 name=bs2best.at verify-doh-cert=\ + no +add disabled=yes dns-servers=1.0.0.1,1.1.1.1 name=psrms.is verify-doh-cert=no +/ip ipsec proposal +set [ find default=yes ] disabled=yes +/ip pool +add name=dhcp ranges=10.30.30.83-10.30.30.254 +/ip dhcp-server +add add-arp=yes address-pool=dhcp always-broadcast=yes bootp-support=none \ + dhcp-option-set=domain-search-set interface=Bridge-LAN lease-time=10m \ + name=masterDHCP server-address=10.30.30.81 +/ip smb users +set [ find default=yes ] disabled=yes +add disabled=yes name=vados +/ipv6 dhcp-client option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=DUID value=0x00030001488f5a8e1abc +add code=61 name=clientid +/ipv6 dhcp-server option +add code=119 name=domain-search-list value="0x03'WORKGROUP'0x00" +add code=12 name=HostName value="\$(HOSTNAME)" +add code=61 name=CLIENT_DUID +add code=61 name=CLIENT_MAC +/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 +/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=fetchCustom owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global GlobalScriptsUrl \"https://ros.vados.ru/\";\r\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.86.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.86.pub\";\ + \n\r\ + \n#:local Script AM-setup\ + \n;\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n\ + \n\r\ + \n#\ + \n\r\ + \n#/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@1\ + 0.30.30.10.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.10.pub\";\ + \n\r\ + \n#\r\ + \n\ + \n#root.mnuc.backuper\ + \n\ + \n\r\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \".bak/mikro_bak_rsa@10\ + .30.30.81.pub\") dst-path=\"/mikro_bak_rsa@10.30.30.81.pub\";\r\ + \n\ + \n#:local Script AM-GlobalConfig;\ + \n\r\ + \n#/system/script/add name=\$Script owner=\$Script source=([ /tool/fetch c\ + heck-certificate=yes-without-crl url=(\$GlobalScriptsUrl . \$Script . \".r\ + sc\") output=user as-value ]->\"data\");\r\ + \n\ + \n#/usb1/mikro_bak_rsa.pub\ + \n#:local FetchFile AM-DOHCert.rsc\ + \n\ + \n\r\ + \n\r\ + \n#\ + \n:global MkDir;\ + \n\r\ + \n\ + \n#:local FetchFile Binary.backup\ + \n:local localDir \"\";\ + \n\ + \n\r\ + \n#\$MkDir \$localDir;\r\ + \n\ + \n#\ + \n/tool/fetch mode=https url=(\$GlobalScriptsUrl . \$FetchFile) dst-path=(\ + \$localDir . \$FetchFile);\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 Identity [/system/identity/get name];\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 (a);\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/\" . \$Identity . \"/\ + \");\r\ + \n:global CertRenewTime 2w;\r\ + \n:global CertRenewPass (a); #{\r\ + \n# \"\";\r\ + \n# \"v3ry-s3cr3t\";\r\ + \n# \"4n0th3r-s3cr3t\";\r\ + \n#};\r\ + \n:global CertWarnTime 1w;\r\ + \n:global CertIssuedExportPass (a); # {\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/727/203f86a6\";\r\ + \n:global CommitTAG \"unknown\";\r\ + \n:global CommitInfo \"Autocommit in repo: ros.vados.ru, generated by owne\ + r: root, in 13:30:05 29.06.2026.\";\r\ + \n\r\ + \n# The variables are received right here.\r\ + \n:global GlobalConfVersion 140;\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 MiniDateTimeStamp;\r\ + \n:global MicroDateTimeStamp;\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 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 GetRandom20CharHex;\r\ + \n:global GetRandomNumber;\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 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 ExitError;\r\ + \n:global ExitOnError;\r\ + \n\r\ + \n:global FetchHugeFiles;\r\ + \n:global FetchUserAgentStr;\r\ + \n:global FileExists;\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 updateChannel;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :log info (\$0 . \" \\\$isInfo = \" . \$isInfo); \r\ + \n :local CurrentChannel [ /system/package/update/get channel ];\r\ + \n :if ([ :len \$updateChannel ] > 0 && \$CurrentChannel != \$updateChann\ + el) do={\r\ + \n :retry command={/system/package/update set channel=\$updateChannel} \ + \_delay=300ms max=5 on-error={};\r\ + \n :log info (\$0 . \" Set updates channel to: \$updateChannel\");\r\ + \n }\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local Channel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set currentUpdateChannel \$Channel;\r\ + \n :log info (\$0 . \" Update Channel: \" . \$Channel . \".\");\r\ + \n :local StatusPkg \"undefined\";\r\ + \n :log info (\$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 :log info (\$0 . \" \\\$StatusPkg = \" . \$StatusPkg);\r\ + \n :if (\$StatusPkg = \"New version is available\") do={ :set PkgUpdStatu\ + s true; } else={ :set PkgUpdStatus false; }\r\ + \n :set ROsVerAvail [ :tostr [ /system/package/update/get latest-version \ + ] ];\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if (\$isInfo != false || \$PkgUpdStatus = true) do={\r\ + \n :log info (\$0 . \" \\\$PkgUpdStatus = \" . \$PkgUpdStatus);\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :retry command={:set (\$arrDeviceInfo->\"devUpdates\") [ /system/pac\ + kage/update/get ]} delay=500ms max=5 on-error={:log error (\"Error\")};\r\ + \n :return true;\r\ + \n } else={\r\ + \n :return \$PkgUpdStatus;\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:set WaitCheckUpdates do={\r\ + \n :global IsCheckUpdates;\r\ + \n :global PkgUpdStatus;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n :global arrDeviceInfo;\r\ + \n :local Status \"\";\r\ + \n :local Update;\r\ + \n :local WaitCount 0;\r\ + \n :if ([ \$IsCheckUpdates true ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n :while ((\$Status = \"\" || \$Status = \"finding out latest version...\ + \") && \$WaitCount < 60) do={\r\ + \n :delay 1s;\r\ + \n :set WaitCount (\$WaitCount + 1);\r\ + \n :set Status [ :tostr [ /system/package/update/get status ] ];\r\ + \n }\r\ + \n :set Update [ /system/package/update/get ];\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n :if ((\$Update->\"status\") = \"New version is available\") do={\r\ + \n :set PkgUpdStatus true;\r\ + \n } else={\r\ + \n :set PkgUpdStatus false;\r\ + \n }\r\ + \n :if ([ :typeof \$arrDeviceInfo ] != \"array\") do={\r\ + \n :set arrDeviceInfo [:toarray \$arrDeviceInfo];\r\ + \n }\r\ + \n :set (\$arrDeviceInfo->\"devUpdates\") \$Update;\r\ + \n :if (\$Status = \"\" || \$Status = \"finding out latest version...\") \ + do={\r\ + \n :return false;\r\ + \n }\r\ + \n :return true;\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 :global arrDeviceInfo;\r\ + \n :global devBoardName;\r\ + \n :global devModel;\r\ + \n :global devRunning;\r\ + \n :global devCurArch;\r\ + \n :global devRbRevision;\r\ + \n :global devRbSerialNumber;\r\ + \n :global devBuildTime;\r\ + \n :global runningChannelVersion;\r\ + \n :global runningChannel;\r\ + \n :global runningVersion;\r\ + \n :global currentUpdateChannel;\r\ + \n :global ROsVerAvail;\r\ + \n\r\ + \n :local DeviceInfo;\r\ + \n :local Resource [/system/resource/get];\r\ + \n :local Update [ /system/package/update/get ];\r\ + \n :local VersionString [ :tostr (\$Resource->\"version\") ];\r\ + \n :local ChannelStart [ :find \$VersionString \" (\" ];\r\ + \n :local RouterBoard;\r\ + \n :local IsRouterBoard false;\r\ + \n :local RunningMode \"\";\r\ + \n\r\ + \n :set devCurArch [ :tostr (\$Resource->\"architecture-name\") ];\r\ + \n :set devBuildTime [ :tostr (\$Resource->\"build-time\") ];\r\ + \n :set runningChannelVersion \$VersionString;\r\ + \n :set runningVersion \$VersionString;\r\ + \n :set runningChannel \"\";\r\ + \n\r\ + \n :if ([ :typeof \$ChannelStart ] = \"num\" && \$ChannelStart >= 0) do=\ + {\r\ + \n :set runningVersion [ :pick \$VersionString 0 \$ChannelStart ];\r\ + \n :local ChannelRest [ :pick \$VersionString (\$ChannelStart + 2) [ :\ + len \$VersionString ] ];\r\ + \n :local ChannelEnd [ :find \$ChannelRest \")\" ];\r\ + \n :if ([ :typeof \$ChannelEnd ] = \"num\" && \$ChannelEnd >= 0) do={\ + \r\ + \n :set runningChannel [ :pick \$ChannelRest 0 \$ChannelEnd ];\r\ + \n }\r\ + \n }\r\ + \n\r\ + \n :if ([:pick \$devBoardName 0 3] != \"CHR\" or [:pick \$devBoardName 0\ + \_3] != \"x86\") do={\r\ + \n :do {\r\ + \n :set RouterBoard [[ :parse \"/system/routerboard/get\" ]];\r\ + \n# :set RouterBoard [ /system/routerboard/get ];\r\ + \n :if ((\$RouterBoard->\"routerboard\") = true) do={\r\ + \n :set IsRouterBoard true;\r\ + \n }\r\ + \n } on-error={}\r\ + \n }\r\ + \n\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get mode ];\r\ + \n } on-error={\r\ + \n :do {\r\ + \n :set RunningMode [ /system/device-mode/get running ];\r\ + \n } on-error={\r\ + \n :set RunningMode \"\";\r\ + \n }\r\ + \n }\r\ + \n :set devRunning \$RunningMode;\r\ + \n\r\ + \n :if (\$IsRouterBoard = true) do={\r\ + \n :set devModel [ :tostr (\$RouterBoard->\"model\") ];\r\ + \n :set devRbRevision [ :tostr (\$RouterBoard->\"revision\") ];\r\ + \n :set devRbSerialNumber [ :tostr (\$RouterBoard->\"serial-number\") \ + ];\r\ + \n } else={\r\ + \n :set devModel \$devBoardName;\r\ + \n :set devRbRevision \"\";\r\ + \n :set devRbSerialNumber \"\";\r\ + \n }\r\ + \n\r\ + \n :set currentUpdateChannel [ :tostr (\$Update->\"channel\") ];\r\ + \n :set ROsVerAvail [ :tostr (\$Update->\"latest-version\") ];\r\ + \n\r\ + \n :set (\$DeviceInfo->\"board-name\") \$devBoardName;\r\ + \n :set (\$DeviceInfo->\"architecture-name\") \$devCurArch;\r\ + \n :set (\$DeviceInfo->\"model\") \$devModel;\r\ + \n :set (\$DeviceInfo->\"revision\") \$devRbRevision;\r\ + \n :set (\$DeviceInfo->\"serial-number\") \$devRbSerialNumber;\r\ + \n :set (\$DeviceInfo->\"running-mode\") \$devRunning;\r\ + \n :set (\$DeviceInfo->\"build-time\") \$devBuildTime;\r\ + \n :set (\$DeviceInfo->\"running-channel-version\") \$runningChannelVers\ + ion;\r\ + \n :set (\$DeviceInfo->\"running-version\") \$runningVersion;\r\ + \n :set (\$DeviceInfo->\"running-channel\") \$runningChannel;\r\ + \n :set (\$DeviceInfo->\"routerboard\") \$IsRouterBoard;\r\ + \n :set (\$DeviceInfo->\"current-firmware\") [ :tostr (\$RouterBoard->\"\ + current-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"upgrade-firmware\") [ :tostr (\$RouterBoard->\"\ + upgrade-firmware\") ];\r\ + \n :set (\$DeviceInfo->\"package-channel\") \$currentUpdateChannel;\r\ + \n :set (\$DeviceInfo->\"installed-version\") [ :tostr (\$Update->\"inst\ + alled-version\") ];\r\ + \n :set (\$DeviceInfo->\"latest-version\") \$ROsVerAvail;\r\ + \n :set (\$DeviceInfo->\"update-status\") [ :tostr (\$Update->\"status\"\ + ) ];\r\ + \n\r\ + \n :set arrDeviceInfo \$DeviceInfo;\r\ + \n :return \$DeviceInfo;\r\ + \n}\r\ + \n\r\ + \n:set DeviceInfo do={\r\ + \n :global GetArrDeviceInfo;\r\ + \n :global GlobalConfVersion;\r\ + \n :global Identity;\r\ + \n :global IfThenElse;\r\ + \n :global FormatLine;\r\ + \n :global CommitBrief;\r\ + \n\r\ + \n :local License [/system/license/get];\r\ + \n :local Snmp [ /snmp/get ];\r\ + \n :local Info [ \$GetArrDeviceInfo ];\r\ + \n\r\ + \n :if ([ :typeof \$Info ] != \"array\") do={\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :return ( \\\r\ + \n [ \$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\" (\$Info->\"board-name\") ] . \"\\n\" . \ + \\\r\ + \n [ \$FormatLine \" Arch\" (\$Info->\"architecture-name\") ] . \"\\\ + n\" . \\\r\ + \n [ \$FormatLine \" Model\" (\$Info->\"model\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"revision\") ] > 0) \\\r\ + \n (\" \" . (\$Info->\"revision\")) ] . \"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"serial-number\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Serial\" (\$Info->\"serial-number\") ] . \"\ + \\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"nlevel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"nlevel\ + \")) ] . \"\\n\") ] . \\\r\ + \n \"RouterOS:\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$License->\"level\") ] > 0) \\\r\ + \n ([ \$FormatLine \" License\" (\"level \" . (\$License->\"level\ + \")) ] . \"\\n\") ] . \\\r\ + \n [ \$FormatLine \" Channel\" (\$Info->\"package-channel\") ] . \"\ + \\n\" . \\\r\ + \n [ \$FormatLine \" Installed\" (\$Info->\"installed-version\") ] .\ + \_\"\\n\" . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"running-channel\") ] > 0) \\\r\ + \n ([ \$FormatLine \" Running\" ((\$Info->\"running-version\") . \ + \" (\" . (\$Info->\"running-channel\") . \")\") ] . \"\\n\") \\\r\ + \n ([ \$FormatLine \" Running\" (\$Info->\"running-version\") ] . \ + \"\\n\") ] . \\\r\ + \n [ \$IfThenElse ([ :len (\$Info->\"latest-version\") ] > 0 && \\\r\ + \n (\$Info->\"installed-version\") != (\$Info->\"latest-version\"))\ + \_\\\r\ + \n ([ \$FormatLine \" Available\" (\$Info->\"latest-version\") ] .\ + \_\"\\n\") ] . \\\r\ + \n [ \$IfThenElse ((\$Info->\"routerboard\") = true && \\\r\ + \n (\$Info->\"current-firmware\") != (\$Info->\"upgrade-firmware\")\ + ) \\\r\ + \n ([ \$FormatLine \" Firmware\" ((\$Info->\"current-firmware\") .\ + \_\" -> \" . (\$Info->\"upgrade-firmware\")) ] . \"\\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\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:set GetRandom20CharHex do={:global EitherOr; :return [ :rndstr length=[\ + \_\$EitherOr [ :tonum \$1 ] 20 ] from=\"0123456789abcdef\" ]; }\r\ + \n:set GetRandomNumber do={:global EitherOr; :return [ :rndnum from=0 to=[\ + \_\$EitherOr [ :tonum \$1 ] 4294967295 ] ]; }\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:set GetPubIp do={\r\ + \n :global DetectIpAddrDefault;\r\ + \n :global DetectIpAddrFallback;\r\ + \n\r\ + \n :local PubIpAddr false;\r\ + \n :local Url \$DetectIpAddrDefault;\r\ + \n :local JobName [ :jobname ];\r\ + \n\r\ + \n :do {\r\ + \n :log debug (\$0 . \" Trying to detect public IP using default serv\ + ice: \" . \$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={:log error (\$JobName . \" Failed to \ + detect public IP using default service: \" . \$Url . \".\")}\r\ + \n } on-error={\r\ + \n :log error (\$0 . \" Failed to detect public IP using default serv\ + ice: \" . \$Url . \".\");\r\ + \n :set Url \$DetectIpAddrFallBack;\r\ + \n :log debug (\$0 . \" Trying to detect public IP using fallback ser\ + vice: \" . \$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={:log error (\$JobName . \" Failed to\ + \_detect public IP using fallback service: \" . \$Url . \".\")}\r\ + \n };\r\ + \n :local IpLen ([ :len \$PubIpAddr ] -1);\r\ + \n :if (\$PubIpAddr = false) do={:set PubIpAddr \"not-detected\"} else=\ + {:set PubIpAddr [:pick \$PubIpAddr 0 \$IpLen]}\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\r\ + \n :global CertificateDownload;\r\ + \n :global ParseKeyValueStore;\r\ + \n\r\ + \n :if ([ :len \$UseFor ] = 0) do={\r\ + \n :log warning (\$0 . \"The intended use is undefined!\");\r\ + \n :set UseFor \"undefined\";\r\ + \n }\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 :log 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 :log 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 :log info (\$0 . \"Certificate with CommonName '\" . \$CommonName . \ + \"' not available.\");\r\ + \n :if ([ \$CertificateDownload \$CommonName ] = false) do={\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] > 1\ + ) do={\r\ + \n :log 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 :log info (\$0 . \"Certificate chain for '\" . \$CommonName . \"' \ + is incomplete, missing '\" . \$IssuerCN . \"'.\");\r\ + \n :if ([ \$CertificateDownload \$IssuerCN ] = false) do={\r\ + \n :return false;\r\ + \n }\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 ScriptUpdatesBaseUrl;\r\ + \n :global ScriptUpdatesUrlSuffix;\r\ + \n :global CertificateNameByCN;\r\ + \n :global CleanName;\r\ + \n :global FetchUserAgentStr;\r\ + \n :global RmFile;\r\ + \n :global WaitForFile;\r\ + \n\r\ + \n :log info (\$0 . \"Downloading and importing certificate with \" . \\\ + \r\ + \n \"CommonName '\" . \$CommonName . \"'.\");\r\ + \n :local FileName ([ \$CleanName \$CommonName ] . \".pem\");\r\ + \n :do {\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-header\ + -field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n (\$ScriptUpdatesBaseUrl . \"certs/\" . \$FileName . \$ScriptUpdate\ + sUrlSuffix) \\\r\ + \n dst-path=\$FileName as-value;\r\ + \n \$WaitForFile \$FileName;\r\ + \n } on-error={\r\ + \n :log warning (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \\\r\ + \n \"' from repository! Trying fallback to mkcert.org...\");\r\ + \n :do {\r\ + \n :local CertSettings [ /certificate/settings/get ];\r\ + \n :if ([ :len [ /certificate/find where common-name=\"ISRG Root X1\"\ + \_] ] = 0 && \\\r\ + \n !(((\$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=\"ISRG\ + \_Root X1\" ] ] > 0)) do={\r\ + \n :log error (\$0 . \" Required certificate is not available.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n /tool/fetch check-certificate=yes-without-crl mode=https http-head\ + er-field=({ [ \$FetchUserAgentStr \$0 ] }) \\\r\ + \n url=\"https://mkcert.org/generate/\" http-data=[ :serialize to=jso\ + n ({ \$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 :log error (\$0 . \" Failed downloading certificate with CommonNam\ + e '\" . \$CommonName . \"'!\");\r\ + \n :return false;\r\ + \n }\r\ + \n }\r\ + \n /certificate/import file-name=\$FileName passphrase=\"\" as-value;\r\ + \n :delay 1s;\r\ + \n \$RmFile \$FileName;\r\ + \n :if ([ :len [ /certificate/find where common-name=\$CommonName ] ] = 0\ + ) do={\r\ + \n /certificate/remove [ find where name~(\"^\" . \$FileName . \"_[0-9]\ + +\\\$\") ];\r\ + \n :log warning (\$0 . \" Certificate with CommonName '\" . \$CommonNam\ + e . \"' 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 :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 :log 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 FileExists do={\r\ + \n :local FileName [ :tostr \$1 ];\r\ + \n :local Type [ :tostr \$2 ];\r\ + \n :global FileGet;\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={ :return false; }\r\ + \n :if ([ :len (\$FileVal->\"size\") ] = 0) do={ :return false; }\r\ + \n :if ([ :len \$Type ] = 0 || \$FileVal->\"type\" = \$Type) do={ :return\ + \_true; }\r\ + \n :return false;\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 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 [ :le\ + n \$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 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 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\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 :if (\$ExitOK = \"false\") do={\r\ + \n :log 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 ExitOnError do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :local Error [ :tostr \$2 ];\r\ + \n :global IfThenElse;\r\ + \n :log error (\$Name . \" \" . [ \$IfThenElse ([ :pick \$Name 0 1 ] = \"\ + \\\$\") \\\r\ + \n \"Function\" \"Script\" ] . \" '\" . \$Name . \"' exited with erro\ + r\" . \\\r\ + \n [ \$IfThenElse (!(\$Error ~ \"^(|true|false)\\\$\")) (\": \" . \$E\ + rror) \".\" ]);\r\ + \n}\r\ + \n\r\ + \n:set MiniDateTimeStamp do={\r\ + \n :local mikro [ :tobool \$1 ];\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 :local Return;\r\ + \n :if (\$mikro = true) do={\r\ + \n :set Return ([:pick \$yyyy 2 4] . [:pick \$dd 0 1] . [:pick \$HH 0\ + \_1] . [:pick \$mm 3 4] . [:pick \$ss 6 7]);\r\ + \n } else={\r\ + \n :set Return ([\$yyyy] . [\$MM] . [\$dd] . [\$HH] . [\$mm] . [\$ss]);\ + \r\ + \n }\r\ + \n :return \$Return;\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={\r\ + \n :return false;\r\ + \n }\r\ + \n :local FileVal false;\r\ + \n :do {\r\ + \n :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 :log debug (\$0 . \" Removing directory: \". \$DirName);\r\ + \n :local DirVal [ \$FileGet \$DirName ];\r\ + \n :if (\$DirVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n };\r\ + \n :if (\$DirVal->\"type\" != \"directory\") do={\r\ + \n :log error (\$0 . \" Directory '\" . \$DirName . \"' is not a direct\ + ory.\");\r\ + \n :return false;\r\ + \n };\r\ + \n :onerror Err {\r\ + \n /file/remove \$DirName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing directory '\" . \$DirName . \"' failed\ + : \" . \$Err);\r\ + \n :return false;\r\ + \n };\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 :log debug (\$0 . \" Removing file: \". \$FileName);\r\ + \n :local FileVal [ \$FileGet \$FileName ];\r\ + \n :if (\$FileVal = false) do={\r\ + \n :log debug (\$0 . \" ... which does not exist.\");\r\ + \n :return true;\r\ + \n }\r\ + \n :if (\$FileVal->\"type\" = \"directory\" || \$FileVal->\"type\" = \"di\ + sk\") do={\r\ + \n :log error (\$0 . \" File '\" . \$FileName . \"' is not a file.\");\ + \r\ + \n :return false;\r\ + \n }\r\ + \n :onerror Err {\r\ + \n /file/remove \$FileName;\r\ + \n } do={\r\ + \n :log error (\$0 . \" Removing file '\" . \$FileName . \"' failed: \"\ + \_. \$Err); :return false;\r\ + \n }\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\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 :log info (\$0 . \" The tmpfs is disabled, enabling.\");\r\ + \n /disk/enable \$TmpFs;\r\ + \n }\r\ + \n :return true;\r\ + \n }\r\ + \n :log 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 :log 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 :log debug (\$0 . \" Making directory: \" . \$Path);\r\ + \n :local PathVal [ \$FileGet \$Path ];\r\ + \n :if (\$PathVal->\"type\" = \"directory\") do={\r\ + \n :log 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 :log 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 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 VersionToNum;\r\ + \n :if (!(\$Required ~ \"^\\\\d+\\\\.\\\\d+((alpha|beta|rc|\\\\.)\\\\d+|)\ + \\\$\")) do={\r\ + \n :log 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 :log warning (\$0 . \" This \" . [ \$IfThenElse ([ :pick \$Caller \ + 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\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\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\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 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 :log error (\$0 . \" A script named '\" . \$Script . \"' does not ex\ + ist!\");\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 :log error (\$0 . \" More tickets than running scripts '\" . \$Scrip\ + t . \"', 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\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\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\r\ + \n:set SymbolByUnicodeName do={\r\ + \n :local Name [ :tostr \$1 ];\r\ + \n :global EitherOr;\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 :log 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\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\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\r\ + \n:set IsDNSResolving do={\r\ + \n :do {:resolve \"api.telegram.org\"} on-error={:return false}\r\ + \n :return true;\r\ + \n}\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\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:set FetchHugeFiles do={\r\ + \n :local ScriptName [ :tostr \$1 ];\r\ + \n :local Url [ :tostr \$2 ];\r\ + \n :local CheckCert [ :tostr \$3 ];\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\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\r\ + \n :local FileName (\$DirName . \"/\" . [ \$CleanName \$0 ] . \"-\" . [ \ + \$GetRandom20CharAlNum ]);\r\ + \n :onerror Err {\r\ + \n /tool/fetch check-certificate=\$CheckCert \$Url dst-path=\$FileName \ + \\\r\ + \n http-header-field=({ [ \$FetchUserAgentStr \$ScriptName ] }) as-va\ + lue;\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 \" . \$Url . \" - \"\ + \_. \$Err);\r\ + \n \$RmDir \$DirName;\r\ + \n :return false;\r\ + \n }\r\ + \n\r\ + \n :if ([ \$WaitForFile \$FileName 5s ] = false) do={\r\ + \n \$LogPrint debug \$0 (\"The file downloaded from \" . \$Url . \" did\ + \_not show up.\");\r\ + \n :return false;\r\ + \n }\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 FetchUserAgentStr do={\r\ + \n :local Caller [ :tostr \$1 ];\r\ + \n :global GlobalScriptsUrl;\r\ + \n :global CommitBrief;\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 (\" . \$GlobalScriptsUrl . \"; \" . [ \$\ + CommitBrief ] . \")\");\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={\r\ + \n :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews and\ + \_changes are not available.\");\r\ + \n\r\ + \n }\r\ + \n\r\ + \n :if ([ :len \$GlobalConfChanges ] > 0) do={ :set GlobalConfChanges; \ + } else={ :global GlobalConfChanges (a); }\r\ + \n :if ([ :len \$GlobalConfMigration ] > 0) do={ :set GlobalConfMigrati\ + on; } else={ :global GlobalConfMigration (a); }\r\ + \n }\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n} }\r\ + \n\r\ + \n# load modules\r\ + \n:foreach Script in=[ /system/script/find where name ~ \"^(global-functio\ + ns\\\\.d|mod)/.\" ] do={\r\ + \n :local ScriptVal [ /system/script/get \$Script ];\r\ + \n :if ([ \$ValidateSyntax (\$ScriptVal->\"source\") ] = true) do={\r\ + \n :onerror Err {\r\ + \n /system/script/run \$Script;\r\ + \n } do={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' f\ + ailed to run: \" . \$Err);\r\ + \n }\r\ + \n } else={\r\ + \n \$LogPrint error \$0 (\"Module '\" . \$ScriptVal->\"name\" . \"' fai\ + led syntax validation, skipping.\");\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 \"Every Day Set Global Environment Variables\";\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: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:log warning (\"This script \$ScriptName Loaded \" . \\\r\ + \n [ \$IfThenElse (\$CommitId != \"unknown\") ([ \$CommitBrief ] . \" \ + \") ] . \\\r\ + \n \"on \" . \$devBoardName . \"\\nRouterOS: \" . \$devCurVersion . \"\ + \\nArchitecture: \" . \$devCurArch . \"\\nIdentity: \" . \$Identity);\r\ + \n # signal we are ready\r\ + \n:set GlobalFuncReady true;\r\ + \n:set ExitOK true;\r\ + \n\r\ + \n:log info (\$0 . \"Global configs ready!\");\r\ + \n} do={\r\ + \n :global ExitOnError; \$ExitOnError \$0 \$Err;\r\ + \n}\r\ + \n" +add comment=\ + "Lookup IP addresses for RKN list and add them to firewall address-list" \ + dont-require-permissions=no name=AM-RKN-dnsLookup owner=AM-RKN-dnsLookup \ + policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \ + source="#!rsc by Vados\r\ + \n# RouterOS script: AM-RKN-dnsLookup\r\ + \n# Script comment: Lookup IP addresses for RKN list and add them to firew\ + all address-list\r\ + \n# Copyright (c) 2007-2026 Vados \r\ + \n#\r\ + \n#\r\ + \n# requires RouterOS, version=7.19\r\ + \n# requires device-mode, fetch\r\ + \n#\r\ + \n# Script description: This script is intended to be run periodically, e.\ + g. once a day, to update the IP addresses in the firewall address-list bas\ + ed on the RKN list.\r\ + \n# It resolves the domain names in the RKN list and a\ + dds the corresponding IP addresses to the specified firewall address-list.\ + \r\ + \n# The script also handles CNAME records by following\ + \_them until it finds A records.\r\ + \n# Usage:\r\ + \n# /system/script { run AM-RKN-dnsLookup; }\r\ + \n:local ScriptName [ :jobname ];\r\ + \n\r\ + \n:global dnsLookupReady false;\r\ + \n:if ([:typeof \$dnsLookupReady] != \"boolean\") do={ :set dnsLookupReady\ + \_true; }\r\ + \nwhile (!\$dnsLookupReady) do={ :nothing; }\r\ + \n:set dnsLookupReady false;\r\ + \n\r\ + \n:local arrRKN {\r\ + \n \"telegra.ph\"\r\ + \n \"grani.ru\"\r\ + \n \"xhamster.com\"\r\ + \n \"lostfilm.tv\"\r\ + \n \"rutracker.org\"\r\ + \n \"lurkmore.to\"\r\ + \n \"dou.ua\"\r\ + \n \"youporn.com\"\r\ + \n \"pornolab.net\"\r\ + \n \"crimerussia.com\"\r\ + \n \"telegram.org\"\r\ + \n \"api.telegram.org\"\r\ + \n \"facebook.com\"\r\ + \n \"instagram.com\"\r\ + \n \"x.com\"\r\ + \n \"twitter.com\"\r\ + \n \"youtube.com\"\r\ + \n \"googleapis.com\"\r\ + \n \"youtu.be\"\r\ + \n \"googlevideo.com\"\r\ + \n \"gstatic.com\"\r\ + \n \"googleusercontent.com\"\r\ + \n \"nhacmp3youtube.com\"\r\ + \n \"telegram.me\"\r\ + \n \"t.me\";}\r\ + \n\r\ + \n:local ListRKN \"RKN-dnsLookup\";\r\ + \n:local ListComment (\"ListRKN managed by \" . \$ScriptName);\r\ + \n:foreach aListItem in=[/ip/firewall/address-list find list=\$ListRKN] do\ + ={\r\ + \n /ip firewall address-list remove \$aListItem;\r\ + \n}\r\ + \n:foreach aItem in=\$arrRKN do={\r\ + \n# :do {\r\ + \n :retry delay=500ms max=5 on-error={:log error \"dns resolve fail\ + ure [ \$aItem - resolve ip ]\"} command={:resolve \$aItem}\r\ + \n# } on-error={\r\ + \n# :log error \"dns resolve failure [ \$arItem - resolve ip ]\";\r\ + \n# }\r\ + \n :foreach dnsRecord in=[/ip dns cache all find where (name=\$aItem)] \ + do={\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"A\") do={\r\ + \n :local newAddress [/ip dns cache all get \$dnsRecord data];\ + \r\ + \n :do {\r\ + \n /ip firewall address-list add list=\$ListRKN address=\$newA\ + ddress comment=\$aItem;\r\ + \n :log warning \"Successfully adding ip to list A record: \ + \$dnsRecord, address: \$newAddress domain: \$aItem\";\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list A record: \$dn\ + sRecord, address: \$newAddress domain: \$aItem\";\r\ + \n }\r\ + \n }\r\ + \n :if ([/ip dns cache all get \$dnsRecord type]=\"CNAME\") do={\r\ + \n :local cname;\r\ + \n :local nextCname;\r\ + \n :local cnameAddress;\r\ + \n :set cname [/ip dns cache all find where (name=\$aItem && ty\ + pe=\"CNAME\")];\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip dns \ + cache all get \$cname data] && type=\"CNAME\")];\r\ + \n :while (\$nextCname != \"\") do={\r\ + \n :set cname \$nextCname;\r\ + \n :set nextCname [/ip dns cache all find where (name=[/ip \ + dns cache all get \$cname data] && type=\"CNAME\")];\r\ + \n }\r\ + \n :foreach aRecord in=[/ip dns cache all find where (name=[/ip\ + \_dns cache all get \$cname data] && type=\"A\")] do={\r\ + \n :do {\r\ + \n :set cnameAddress [/ip dns cache all get \$aRecord d\ + ata];\r\ + \n /ip firewall address-list add list=\$ListRKN address\ + =\$cnameAddress comment=\$aItem;\r\ + \n :log warning \"Succesfully adding ip to list CNAME r\ + ecord: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \ + \$aItem.\";\r\ + \n# /ip firewall raw add action=add-dst-to-address-list\ + \_address-list=\$ListRKN address-list-timeout=none-dynamic chain=preroutin\ + g comment=\$aItem content=\$aItem;\r\ + \n } on-error={\r\ + \n :log error \"error when adding ip to list CNAME reco\ + rd: \$cname, A record: \$aRecord, address: \$newAddress, from domain: \$aI\ + tem.\";\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n }\r\ + \n}\r\ + \n\r\ + \n:if ([ :len [ /system/scheduler/find where name=\$ScriptName ] ] = 0) do\ + ={\r\ + \n :log error (\$ScriptName . \"System Scheduler for script: \" . \$Scri\ + ptName . \" is NOT SET! Fix It Now!\");\r\ + \n /system/scheduler/add name=\$ScriptName on-event=\"/system/script { \ + run \$ScriptName; }\" comment=\"Update RKN DNS Looup\" interval=00:30:00 p\ + olicy=\"ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon\"\ + \_start-time=startup;\r\ + \n }\r\ + \n:set dnsLookupReady true;\r\ + \ndelay 2s; \r\ + \n:global dnsLookupReady (a);\r\ + \n" +add dont-require-permissions=no name="renameLists " owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + local oldName \"Test\";\ + \n:local newName \"Test-IP\";\ + \n/ip firewall address-list\ + \n:foreach i in=[find list=\$oldName] do={\ + \nset \$i list=\$newName;\ + \n}\ + \n" +add dont-require-permissions=no name=IPv6-Settings owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\ + #############Script Settings##################\ + \n\ + \n:local \"IF-TUN\" \"6to4-tun\"\ + \n:local \"IF-LOC\" \"Bridge-LAN\"\ + \n:local \"POOL-6TO4\" \"poolV6-local\"\ + \n:local \"force-update\" false\ + \n############ use then static ip #######################\ + \n:local \"lease-address\" [/ip address get [find interface=\$\"IF-LOC\"] \ + address]\ + \n#:local \"interface\" \"ext\"\ + \n:local bound 0\ + \n\ + \n###############################################\ + \n\ + \n:local 6to4prefix do={\ + \n :global dec2hex\ + \n :local ipv4 \$1\ + \n :local ipv6 \"2002:\"\ + \n :for i from=0 to=2 step=1 do={ \ + \n :if ( \$i = 2) do={\ + \n :set ipv6 (\$ipv6.\":\")\ + \n }\ + \n :local fp [:find \$ipv4 \".\"]\ + \n :if ( \$fp > 0 ) do={\ + \n :set ipv6 (\$ipv6.[\$dec2hex [:pick \$ipv4 0 \$fp]])\ + \n :set ipv4 [:pick \$ipv4 (\$fp + 1 ) [:len \$ipv4]]\ + \n }\ + \n }\ + \n :return (\$ipv6.[\$dec2hex \$ipv4])\ + \n}\ + \n:local \"str_replace\" do={\ + \n :local \"str-pos\" [:find \$1 \$2]\ + \n :local \"str-len\" [:len \$2]\ + \n :local str \"\"\ + \n :local rest \$1\ + \n :while (\$\"str-pos\" >= 0) do={\ + \n :local t [:pick \$rest 0 \$\"str-pos\"]\ + \n :if ( \$4 > 0 ) do={\ + \n :for i from=1 to=(\$4 - [:len \$t]) step=1 do={\ + \n :set str (\$str.\$5)\ + \n }\ + \n }\ + \n :set str (\$str.\$t.\$3)\ + \n :set rest [:pick \$rest (\$\"str-pos\"+\$\"str-len\") [:len \$re\ + st]]\ + \n :set \"str-pos\" [:find \$rest \$2]\ + \n }\ + \n :return (\$str.\$rest)\ + \n}\ + \n\ + \n:if (\$bound=1) do={\ + \n :local t [:find \$\"lease-address\" \"/\"]\ + \n\ + \n :if ( \$t >= 0 ) do={\ + \n :set \"lease-address\" [:pick \$\"lease-address\" 0 \$t]\ + \n }\ + \n\ + \n :if ( [/interface 6to4 print count-only where name=\$\"IF-TUN\"] = 0\ + ) do={\ + \n /interface 6to4 add !keepalive local-address=\$\"lease-address\"\ + \_mtu=1280 name=\$\"IF-TUN\" remote-address=10.30.30.0\ + \n :set \"force-update\" true\ + \n }\ + \n\ + \n :local \"IPv4-TUN\" [/interface 6to4 get [find name=\$\"IF-TUN\"] lo\ + cal-address];\ + \n\ + \n :if ( \$\"lease-address\" != \$\"IPv4-TUN\" || \$\"force-update\" = \ + true) do={\ + \n /interface 6to4 set [find name=\$\"IF-TUN\"] local-address=\$\"l\ + ease-address\"\ + \n /ipv6 address remove [find interface=\$\"IF-TUN\"]\ + \n /ipv6 address remove [find interface=\$\"IF-LOC\"]\ + \n /ipv6 route remove [find gateway ~ \$\"IF-TUN\" and dst-address=\ + \"::/0\"]\ + \n :local \"pool-prefix\" [\$6to4prefix \$\"lease-address\"]\ + \n :if ( [/ipv6 pool print count-only where name=\$\"POOL-6TO4\"] =\ + \_0) do={ \ + \n /ipv6 pool add name=\$\"POOL-6TO4\" prefix=(\$\"pool-prefix\ + \".\":1::/64\") prefix-length=64\ + \n } else={\ + \n /ipv6 pool set [/ipv6 pool find where name=\$\"POOL-6TO4\"] \ + prefix=(\$\"pool-prefix\".\":1::/64\")\ + \n }\ + \n /ipv6 address add address=(\$\"pool-prefix\".\"::\".[\$MAC2EUI64\ + \_[/interface get [find name=\$\"interface\"] mac-address]].\"/3\") interf\ + ace=\$\"IF-TUN\" advertise=no\ + \n /ipv6 address add eui-64=yes from-pool=\$\"POOL-6TO4\" interface\ + =\$\"IF-LOC\" advertise=yes\ + \n /ipv6 route add dst-address=::/0 gateway=(\"::10.30.30.81%\".\$\ + \"IF-TUN\")\ + \n :local t [/ipv6 address get [find interface=\$\"IF-LOC\"] addres\ + s]\ + \n :set t [:pick \$t 0 [:find \$t \"/\"]]\ + \n :if ( [/ipv6 dhcp-server option print count-only where name=DNS]\ + \_= 0) do={\ + \n /ipv6 dhcp-server option add code=23 name=DNS value=(\"0x\".\ + [\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n } else={\ + \n /ipv6 dhcp-server option set [/ipv6 dhcp-server option find \ + where name=DNS] value=(\"0x\".[\$\"str_replace\" \$t \":\" \"\" 4 \"0\"])\ + \n }\ + \n :if ( [/ipv6 dhcp-server print count-only where interface=\$\"IF\ + -LOC\"] = 0) do={\ + \n /ipv6 dhcp-server add address-pool=\$\"POOL-6TO4\" dhcp-opti\ + on=DNS interface=\$\"IF-LOC\" lease-time=1d name=\$\"IF-LOC\"\ + \n }\ + \n :if ( [ipv6 nd print count-only where interface=\$\"IF-LOC\"] = \ + 0) do={\ + \n /ipv6 nd add advertise-dns=no interface=\$\"IF-LOC\" other-c\ + onfiguration=yes\ + \n }\ + \n }\ + \n}" +add dont-require-permissions=no name=IPv6-GlobalFunc owner=vados policy=\ + ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\ + global MAC2EUI64 do={\ + \n :local EUI64 \"\"\ + \n :local MAC \$1\ + \n :local HEX2DEC \"0123456789ABCDEF\"\ + \n :for i from=0 to=5 step=1 do={\ + \n :if ( \$i = 0 ) do={\ + \n :set EUI64 [:pick \$MAC 0]\ + \n :set EUI64 (\$EUI64.[:tostr [:pick \$\"HEX2DEC\" ([:find \$\ + \"HEX2DEC\" [:pick \$MAC 1]] ^ 2)]])\ + \n }\ + \n :if ( \$i = 1 || \$i = 3) do={\ + \n :set EUI64 (\$EUI64.\":\")\ + \n }\ + \n :if ( \$i = 2 ) do={\ + \n :set EUI64 (\$EUI64.\"FF:FE\")\ + \n }\ + \n :if ( [:find \$MAC \":\"] = 2 ) do={\ + \n :set MAC [:pick \$MAC 3 [:len \$MAC]]\ + \n :set EUI64 (\$EUI64.[:pick \$MAC 0 2])\ + \n }\ + \n }\ + \n :return (\$EUI64)\ + \n}\ + \n\ + \n:global dec2hex do={\ + \n :local hex \"\"\ + \n :local dec [:tonum \$1]\ + \n :for i from=0 to=4 step=4 do={\ + \n :set hex ([:pick \"0123456789ABCDEF\" ((\$dec>>\$i)&0xf) (((\$de\ + c>>\$i)&0xf)+1)].\$hex)\ + \n }\ + \n :return ([:tostr \$hex])\ + \n}" +/user group +add name=backup policy="ssh,read,write,policy,test,web,sniff,sensitive,api,res\ + t-api,!local,!telnet,!ftp,!reboot,!winbox,!password,!romon" +/ip smb +set enabled=no interfaces=lo +/interface bridge port +add bridge=Bridge-LAN interface=ether5 +add bridge=Bridge-LAN interface=ether2 +add bridge=Bridge-LAN interface=ether4 trusted=yes +add bridge=Bridge-LAN interface=ether3 +add bridge=Bridge-LAN interface=wlan2 +add bridge=Bridge-LAN interface=wlan1 +/interface bridge settings +set use-ip-firewall=yes +/ip firewall connection tracking +set udp-timeout=10s +/ip neighbor discovery-settings +set discover-interface-list=LAN lldp-med=no lldp-poe-power=no +/ip settings +set accept-redirects=yes ipv4-multipath-hash-policy=l4 max-neighbor-entries=\ + 8192 +/ipv6 settings +set disable-ipv6=yes disable-link-local-address=yes forward=no \ + max-neighbor-entries=8192 multipath-hash-policy=l4 +/interface detect-internet +set detect-interface-list=static internet-interface-list=Internet \ + lan-interface-list=LAN request-interval=1m wan-interface-list=WAN +/interface l2tp-server server +set authentication=mschap2 use-ipsec=yes +/interface list member +add interface=ether4 list=WAN +add interface="ether1 - Unet" list=Internet +add interface=WG list=WAN +add interface=Bridge-LAN list=LAN +/interface wireguard peers +add allowed-address=0.0.0.0/0 client-allowed-address=::/0 endpoint-address=\ + 109.107.177.79 endpoint-port=29185 interface=WG name=VDSina \ + persistent-keepalive=10s public-key=\ + "zuRsO+dL/j6awaBWZ/NgnHR+bCNUjRWbaHFpdzkNnw4=" +/interface wireless cap +# +set bridge=Bridge-LAN caps-man-addresses=10.30.30.10 \ + caps-man-certificate-common-names=CAPsMAN-51B25E507D07 certificate=\ + CAP-488F5A8E1ABC discovery-interfaces=Bridge-LAN enabled=yes interfaces=\ + wlan2,wlan1 lock-to-caps-man=yes +/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 cloud +set update-time=no +/ip dhcp-client +add add-default-route=special-classless default-route-distance=2 \ + default-route-tables=main:1 dhcp-options=clientid,clientid_duid \ + interface="ether1 - Unet" name=client1 use-peer-dns=no use-peer-ntp=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.92 client-id=1:d4:6d:6d:fd:e5:49 mac-address=\ + D4:6D:6D:FD:E5:49 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.75 client-id=1:0:27:15:41:97:a9 mac-address=\ + 00:27:15:41:97:A9 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=MiTV dhcp-option=HostName dhcp-option-set=\ + MiTV mac-address=20:72:A9:D3:34:36 server=masterDHCP +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=iVados mac-address=DE:4D:72:F3:1A:9F server=masterDHCP +add address=10.30.30.10 allow-dual-stack-queue=yes client-id=\ + ff:0:0:0:df:0:3:0:1:f0:75:5d:1e:5f:85 dhcp-option=HostName \ + dhcp-option-set=MikroNUC mac-address=F0:75:5D:1E:5F:85 server=masterDHCP \ + use-src-mac=yes +/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.33,109.107.177.79 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=10.30.30.33,8.8.8.8 \ + verify-doh-cert=yes +/ip dns static +add address=109.107.177.79 comment="VDSina Server DNS" name=ns1.vados.ru \ + type=A +add address=109.107.177.79 name=vds.vados.ru type=A +add comment="Local DNS server for vados.ru" disabled=yes ns=10.30.30.81 \ + regexp=*.vados.ru type=NS +add comment="*.vados.ru Regexp" disabled=yes forward-to=10.30.30.81 regexp=\ + "\".*\\\\.vados\\\\.ru\"" type=FWD +add comment="*.30.30.10.in-addr.arpa Regexp" disabled=yes forward-to=\ + 10.30.30.81 regexp="\".*\\\\.30\\\\.30\\\\.10\\\\.in-addr\\\\.arpa" type=\ + FWD +add address=10.30.30.81 comment=NS.vados.ru.local disabled=yes name=\ + ns.vados.ru.local type=A +add comment="DNS ns.vados.ru.local" disabled=yes match-subdomain=yes name=\ + vados.ru ns=ns.vados.ru.local type=NS +add address=10.30.30.33 comment=reg.vados.ru name=reg.vados.ru type=A +add address=8.8.8.8 comment="Google-dns IPv4 1" match-subdomain=yes name=\ + dns.google type=A +add address=8.8.4.4 comment="Google-dns IPv4 2" name=dns.google type=A +add address=10.30.30.33 comment=AMSTER name=amster.vados.ru type=A +add address=10.30.30.33 name=ros.vados.ru type=A +add address=10.30.30.95 name=vados-nuc type=A +add address=10.30.30.33 name=amster-nuc 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 disabled=yes 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 disabled=yes match-subdomain=yes name=\ + mikrots.vados.ru 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.0.0.1 comment="CloudFlare-doh IPv4 2" disabled=yes name=\ + security.cloudflare-dns.com type=A +add address=1.1.1.1 comment="CloudFlare-doh IPv4 1" disabled=yes 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=195.133.25.16 comment="DNS Comss" disabled=yes name=dns.comss.one \ + 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 disabled=yes name=MikroYellow type=A +add address=10.30.30.85 disabled=yes 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=91.192.189.2 comment=Unet-DNS disabled=yes name=ns1.unet.ws type=\ + A +add address=10.30.30.20 disabled=yes name=garage type=A +/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=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-IP +add address=wg.vados.ru comment=VDSIna list=TRUSTED +add address=10.8.0.0/24 comment="WG VDSIna" disabled=yes 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-IP +add address=geoip.co list=NoVdsina +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=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 disabled=yes list=NoWG +add address=10.30.30.10 comment=MikroNUC disabled=yes list=NoWG +add address=89.110.101.17 comment=!!!VDSINA!!!! disabled=yes list=NoWG +add address=wg.vados.ru comment=VDSina-vpn list=VDSina +add address=80.85.244.9 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=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=89.110.101.17 comment="!!!VDSina Server!!!" list=NoVdsina +add address=dns.quad9.net comment=Quad9-dns disabled=yes list=Trusted-DNS +add address=dns.google comment=Google-dns list=Trusted-DNS +add address=security.cloudflare-dns.com comment=CloudFlare-dns list=\ + Trusted-DNS +add address=time.google.com comment=Google-time list=Trusted-NTP +add address=0.ru.pool.ntp.org comment=ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=1.ru.pool.ntp.org disabled=yes list=Trusted-NTP +add address=2.ru.pool.ntp.org comment=2.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=3.ru.pool.ntp.org comment=3.ru.pool.ntp.org disabled=yes list=\ + Trusted-NTP +add address=cp.vdsina.com comment=VDSina-vpn list=VDSina +add address=vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns.vados.ru comment=VDSina-vpn list=VDSina +add address=vdsina.com comment=VDSina-vpn list=VDSina +add address=cp.vdsina.ru comment=VDSina-vpn list=VDSina +add address=ns1.vdsina.ru comment=VDSina-vpn list=VDSina +add address=10.30.30.0/24 comment="Local Network" list=Local-Net +add address=10.8.0.0/24 comment="WireGuard Network" list=Local-Net +add address=146.120.64.208/29 comment="External Net" list=Unet +add address=esia.gosuslugi.ru comment=esia.gosuslugi.ru list=NoVdsina +add address=lk.gosuslugi.ru comment=lk.gosuslugi.ru list=NoVdsina +add address=trudvsem.ru comment=trudvsem.ru list=NoVdsina +add address=10.30.30.30 comment=miller disabled=yes list=NoWG +add address=10.30.30.33 comment="Direct connet to DNS servers" list=\ + Direct-DNS +add address=109.107.177.79 list=VPN-Server +add address=10.30.30.10 list=AWG-Proxy +/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 src-address-list=!Trusted-DNS +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 src-address-list=!Trusted-DNS +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 \ + 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=4w2d chain=input comment="block honeypot NTP" \ + connection-state=new dst-port=123 in-interface="ether1 - Unet" protocol=\ + udp +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=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=tcp +add action=accept chain=input disabled=yes dst-port=29185 in-interface=\ + "ether1 - Unet" protocol=udp +add action=accept chain=input comment="tcp Accept input DNS queries from LAN" \ + dst-port=53 protocol=tcp src-address=10.30.30.0/24 +add action=accept chain=input comment="udp Accept input DNS queries" \ + dst-port=53 protocol=udp src-address=10.30.30.0/24 +add action=accept chain=output comment="accept WireGuard" disabled=yes \ + dst-address-list=VPN-Server out-interface="ether1 - Unet" protocol=udp \ + src-port=13231 +add action=accept chain=output disabled=yes dst-address-list=VPN-Server \ + dst-port=29185 out-interface="ether1 - Unet" protocol=udp +add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \ + connection-state=established,related,new disabled=yes routing-mark=\ + !To-VPN +add action=accept chain=output disabled=yes protocol=tcp src-port=443 +add action=accept chain=output disabled=yes src-address=127.0.0.1 +add action=accept chain=forward comment="defconf: accept in ipsec policy" \ + disabled=yes ipsec-policy=in,ipsec +add action=accept chain=forward comment="defconf: accept out ipsec policy" \ + disabled=yes 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 in-interface="ether1 - Unet" src-address=\ + !10.30.30.0/24 +add action=drop chain=forward comment=\ + "defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat \ + connection-state=new in-interface="ether1 - Unet" src-address-list=\ + !VDSina +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 +add action=accept chain=input in-interface="ether1 - Unet" protocol=icmp \ + src-address-list=VDSina +add action=accept chain=input connection-state=established disabled=yes +add action=accept chain=input connection-state=related disabled=yes +/ip firewall mangle +add action=mark-routing chain=prerouting comment="Mark Routing main for NoWG" \ + new-routing-mark=main src-address-list=NoWG +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for NoVdsina" dst-address-list=NoVdsina \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for VDSina" dst-address-list=VPN-Server \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "Mark Routing main for MikroNuc" disabled=yes dst-address-list=AWG-Proxy \ + new-routing-mark=main src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=\ + "!!!ERROR Mark Routing main for Unet!!!" disabled=yes dst-address-list=\ + Unet new-routing-mark=main passthrough=no +add action=mark-routing chain=prerouting comment="Test-IP sites" disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=Test-IP new-routing-mark=\ + To-VPN src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment=FuckRKN disabled=yes \ + dst-address=!10.30.30.0/24 dst-address-list=RKN-dnsLookup \ + new-routing-mark=To-VPN passthrough=no src-address=10.30.30.0/24 +add action=mark-routing chain=prerouting comment="AWG for All sites" \ + disabled=yes dst-address=!10.30.30.0/24 dst-address-list=!NoVdsina \ + new-routing-mark=*401 routing-mark=!main 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 new-routing-mark=\ + To-VPN routing-mark=!main src-address=10.30.30.0/24 src-address-list=\ + !NoWG +add action=mark-connection chain=prerouting comment=\ + "Mark VPN connections to exclude from FastTrack" new-connection-mark=\ + VPN_No_FastTrack routing-mark=To-VPN +add action=change-mss chain=forward comment="MSS on WG" new-mss=1380 \ + out-interface=WG protocol=tcp routing-mark=To-VPN tcp-flags=syn tcp-mss=\ + 1381-65535 +add action=mark-routing chain=prerouting comment="VPN Network" dst-address=\ + 10.8.0.0/24 new-routing-mark=To-VPN src-address=10.30.30.0/24 +/ip firewall nat +add action=redirect chain=dstnat comment="udp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=udp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=redirect chain=dstnat comment="tcp Redirect DNS in NAT" disabled=\ + yes dst-port=53 protocol=tcp src-address=10.30.30.0/24 src-address-list=\ + !NoWG to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/tcp dst-nat to amster.loc. From VDSina Server" dst-port=53 \ + in-interface="ether1 - Unet" protocol=tcp src-address-list=VPN-Server \ + to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat comment=\ + "53/udp dst-nat to amster.loc. From VDSina Server" dst-port=53 protocol=\ + udp src-address-list=VPN-Server to-addresses=10.30.30.33 to-ports=53 +add action=dst-nat chain=dstnat disabled=yes dst-port=44333 in-interface=\ + "ether1 - Unet" protocol=udp src-address=!10.30.30.0/24 to-addresses=\ + 10.30.30.33 to-ports=44333 +add action=masquerade chain=srcnat comment="Default NAT" out-interface=\ + "ether1 - Unet" routing-mark=!To-VPN src-address=10.30.30.0/24 +add action=dst-nat chain=dstnat comment=amster.vados.ruhttps dst-port=443 \ + fragment=no in-interface="ether1 - Unet" protocol=tcp routing-mark=main \ + to-addresses=10.30.30.33 to-ports=443 +add action=dst-nat chain=dstnat comment="amster.vados.ru For Certbot HTTP" \ + 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="amster.vados.ru 3x-ui" disabled=yes \ + dst-port=2904 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2904 +add action=dst-nat chain=dstnat comment=reg.vados.ru disabled=yes dst-port=\ + 5000 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=5000 +add action=dst-nat chain=dstnat comment="Docker swarm" disabled=yes dst-port=\ + 2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=10.30.30.33 \ + to-ports=2377 +add action=dst-nat chain=dstnat comment=npm dst-port=81 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=To-VPN to-addresses=10.30.30.33 \ + to-ports=81 +add action=dst-nat chain=dstnat comment=SSH dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp src-address-list=TRUSTED to-addresses=\ + 10.30.30.33 to-ports=22 +add action=dst-nat chain=dstnat comment="portainer agent" disabled=yes \ + dst-port=2377 in-interface="ether1 - Unet" protocol=tcp to-addresses=\ + 10.30.30.33 to-ports=2377 +add action=dst-nat chain=dstnat disabled=yes dst-port=22 in-interface=\ + "ether1 - Unet" protocol=tcp routing-mark=!To-VPN to-addresses=\ + 10.30.30.33 to-ports=22 +add action=masquerade chain=srcnat comment=WG dst-address-list=!NoVdsina \ + out-interface=WG routing-mark=To-VPN src-address-list=!NoWG +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 +/ip firewall raw +add action=drop chain=prerouting comment="Drop Honeypot Hackers" \ + in-interface="ether1 - Unet" src-address-list="Honeypot Hacker" +add action=accept chain=prerouting comment="Trusted DNS" disabled=yes \ + in-interface-list=WAN src-address-list=Trusted-DNS +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=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtube.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleapis.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ggpht.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=youtu.be \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=ytimg.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googlevideo.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=gstatic.com \ + disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + googleusercontent.com disabled=yes +add action=add-dst-to-address-list address-list=FuckRKN address-list-timeout=\ + none-dynamic chain=prerouting comment="YouTube raw" content=\ + nhacmp3youtube.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=rutube.ru \ + content=rutube.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment="me.com raw" \ + content=me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "icloud.com raw" content=icloud.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com raw" content=smtp.mail.me.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "smtp.mail.me.com.akadns.net raw" content=smtp.mail.me.com.akadns.net \ + disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + "api.db-ip.com raw" content=api.db-ip.com disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=\ + esia.gosuslugi.ru content=esia.gosuslugi.ru disabled=yes +add action=add-dst-to-address-list address-list=NoVdsina \ + address-list-timeout=none-dynamic chain=prerouting comment=gosuslugi.ru \ + content=gosuslugi.ru disabled=yes +/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 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 check-gateway=none disabled=no distance=1 dst-address=0.0.0.0/0 gateway=\ + WG routing-table=To-VPN scope=30 target-scope=10 +/ip service +set ftp disabled=yes +set telnet disabled=yes +set reverse-proxy 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 +set api-ssl address=10.30.30.0/24 disabled=yes +set www-ssl certificate=Root-YE 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-secure=no scep-plain=no webfig-plain=no \ + webfig-secure=no +/ip ssh +set forwarding-enabled=both publickey-authentication-options=verify-required +/ip upnp +set enabled=yes +/ip upnp interfaces +add interface=Bridge-LAN type=internal +add forced-ip=146.120.64.211 interface="ether1 - Unet" type=external +add forced-ip=109.107.177.79 interface=*E type=external +add interface=lo type=internal +add interface=wlan2 type=internal +add interface=wlan1 type=internal +/ipv6 dhcp-client +add add-default-route=yes disabled=yes interface=*F rapid-commit=no request=\ + info use-interface-duid=yes validate-server-duid=no +/ipv6 dhcp-server option sets +add name=domain-search-set options=domain-search-list +add name="=\"Client ID\"" options=HostName +/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=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 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 disabled=yes interface=Bridge-LAN \ + managed-address-configuration=yes other-configuration=yes pref64=::/64 +/ipv6 nd prefix +add autonomous=no disabled=yes interface=Bridge-LAN on-link=no prefix=none +/ipv6 nd prefix default +set dhcp6-pd-preferred=yes +/ipv6 nd proxy +add disabled=yes interface=lo +/ipv6 nd settings +set router-advertisement-route-distance=100 +/routing settings +set single-process=no +/system clock +set 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 package update +set check-certificate=yes-without-crl ip-version=ipv4 +/system scheduler +add comment="Every Day Set Global Environment Variables" 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="Update RKN DNS Looup" disabled=yes interval=20m name=\ + AM-RKN-dnsLookup on-event="/system/script { run AM-RKN-dnsLookup; }" \ + 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 certificate=DigiCert-Global-Root-CA check-certificate=no comment="doh, doh\ + -url=https://security.cloudflare-dns.com/dns-query, notify, name=CloudFlar\ + e-doh IPv4 1" disabled=yes down-script="" host=1.1.1.1 http-codes="" \ + interval=10s name="CloudFlare-doh IPv4 1" port=443 test-script="" type=\ + https-get 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="" \ + name="CloudFlare-doh IPv4" port=443 test-script="" type=https-get \ + up-script="" +add comment="dns, notify, name=Google-DNS IPv4" disabled=yes dns-server=\ + 8.8.8.8 down-script="" host=dns.google http-codes="" name=\ + "Google-DNS IPv4" test-script="" type=dns up-script="" +add certificate=GTS-Root-R4 check-certificate=yes comment="doh-fallback, doh-u\ + rl=https://dns.google/dns-query, doh-cert=GTS Root R1, notify, name=Google\ + -DOH IPv4" disabled=yes dns-server=8.8.4.4 down-script="" host=dns.google \ + http-codes="" name="Google-DOH IPv4" port=443 record-type=NS src-address=\ + "" test-script="" type=dns up-script="" +add comment="dns-fallback, notify, name=Cuad9-DOH IPv4" disabled=yes \ + dns-server=9.9.9.9 down-script="" host=dns9.quad9.net http-codes="" \ + interval=10s name="Cuad9-DOH IPv4" src-address=146.120.64.211 \ + test-script="" timeout=800ms type=dns up-script="" +add certificate=DigiCert-Assured-ID-Root-CA comment="doh-fallback, doh-url=htt\ + ps://dns.quad9.net/dns-query, name=Cuad9-DOH IPv4" disabled=yes \ + down-script="" host=149.112.112.112 http-codes="" interval=10s name=\ + "Cuad9-DOH IPv4" port=443 test-script="" type=https-get up-script="" +add comment="dns-fallback, notify, name=ns1.unet.ws" disabled=yes \ + down-script="" host=91.192.189.2 http-codes="" interval=10s name=\ + ns1.unet.ws test-script="" type=simple up-script="" +add check-certificate=yes comment=\ + "doh, doh-url=https://vds.vados.ru/vds-query, name=vds.vados.ru" \ + disabled=yes down-script="" host=109.107.177.79 http-codes="" name=\ + vds.vados.ru port=443 test-script="" type=https-get up-script="" +/user aaa +set accounting=no diff --git a/MikroMaster/tmp/Config.rsc b/MikroMaster/tmp/Config.rsc deleted file mode 100644 index e69de29..0000000 diff --git a/MikroMaster/tmp/Diff-Config.rsc b/MikroMaster/tmp/Diff-Config.rsc deleted file mode 100644 index dcf6829..0000000 --- a/MikroMaster/tmp/Diff-Config.rsc +++ /dev/null @@ -1,8 +0,0 @@ -88,90c88 -< /ppp profile -< set *FFFFFFFE use-upnp=no -< #error exporting "/queue/interface" (timeout) ---- -> #error exporting "/ppp/profile" (timeout) -3497a3496 -> #error exporting "/ip/ipsec/key/psk" (timeout) -- 2.52.0