z@%lV|Tk6XH_3yUb_I=*AjM?D7Zuy!`Yd6w}?+K;eJ7~-PaLa8wkS}b@HQQ1*_-|Xj zW=s9Or5!GU_@!XA@76>Yi^6PebaAjsSn>UVeLL8b-r2tgMi&S1QJae{-jts2MtLX{ z4!HvmVkz96^3qQocGVpOuuaOUh>_<#Uqqxk>qa@_L^Bi;g&lo~Qda`FTL7QF+4;*pQSjQQkiQ z!SAk`AeYnx{(IcDr#shuun!mb@Ee0%1L~dw9sZtUeR!sW_v$_P{q1lcKIFp}e7MxX z`+w-eU;FR|2Oqr2!H2GN@Zo11d}O(UkDcnnYkYXSgOA_h;NO4j;8U}G=s)+_OI`W7 z{e1W}AKu~M3*8R>bE*$_@u6S;Wxw7l>JNUelsWj?K|b{V|G$oN65(DC` z8y^FhBhm>5F;~P{Zsa|m7bhabTRSELVCH2KL}z}NMQEG%Ol}r2BHpU@Y=D`YLnxj3 zX)fU+-V<55XbRrS);xguaz5LPm>(9PD0mOX3(yt3_l6Y`M&fyU76Ht6i_sUn`_hY1 z6})%rN{B4+yxmFx=BzT*1#fY*3~j-CyRsam*h_r60$|P7URy fcbg`5*(*8*r?rmt0I%V8N9^oEP(k&Hi7Qm?P=MJG*0C()Hsz3 zFsJ2dz}=pfr=j-NkbDib#7_Ak6B$7VYSc35Zcob>ooIJ8m`~(X$xFMHv8b_rHnr|h zt(_A=t?DJJ^=WX?d#Ke#t?vc3cJ(;-b|vSAz8lnvKj_!Gh+2!em)VDmt{f2XQMtR(k zs#L|P@#}(01us(REKuQVIC+<9olx3mVwXd5{?bG|r} ji5y#~XUD}R-4$T=3Fh3Y!3PRp)-Uz}yAv*d3oR{(NNPxL`6k%ZI zi=zpF_nO}yjfC!HJ~jqmeleEdPjm1%lNs_xtR6?ir MAOLc2O^*2zsS@B~T~oO)7^XQE%uFs8Qn0uEHt^P~!1JGHReb zs#go4No=@s;xLFyV#UItjnEU-Ylf6iFWwyTrr%I#t2TuakvaDksQQHFP$E9}Y4R%; z){xI%@GtUjbQO@VTeyn+V{>EVM=k0m&tu3>zro8liS>&{kdMrH0Q~z4tI6jqc$xgm zC+phMuBFhdD7j$^*Ob8C5@Q$jU;|8Ut@v5SB&M65x4W8FPB9yvUw~%v{VB$z(G%6{ z6<%z9rPOOn=sUXRdYewt+HG@>B9P4-rC#{S3F_kmlzOpO6rXI4RqACg8K)8PO{HG( zDt$lDT%^>i?;gYWF~1w5j;@} B)PZ}&2Q zIj39<_ug1JgV}q#szSUr@tGk2(^V;sdwW_XycSAZC1%?*yBc6ltr5$;IZ`8*`&!9R zG28BGwE%NmomlP-;X1M0SBmPzY}bt+1~5l7FcZubjpDe^=QWDgt{u|^F!P$>xaM~) zVz|%bwusfPYHtOYxoyl6^V9Z?f`|l?2!DT%k&5&_Zxmig?{BeDp@ez27I84~xiJi@ zu_2Sznf a-zo8Py+`9Qku z&G+iX*34eEGcQzUB8J4p&fXiQPBnYk&RnR@ h+45oPRI{(`%pa&Ty~i?g#mrVT zt5eN>wljYS$!>(FJ)SAT`Y2txvIW$|^e`37mw*>Rd7D>o#@5MvEU5Df&LJ6@gMmMy z&WP2Vc|!Nec`DZD-DzgaI3}%Utax*%Tl7yD$G6FZuj8V>#kkEk$h=z%YG$`;?MANb zU(`CAOyriJ)|o-A9mQ^Kt%^6Pbq=+ncX9GQ-RoR3%XF_@#7Mo}$<-{O)_G)Ne^sq? zYF(&Wb)e>KtktlbTHgT`e~6R!tJY8aT9)0~TQ$8;rSDS7wwJB+^PtjxWV}5%H=Ncm z=aUh)b$43SYPz3aV3yT$*TY)OhI{sgz^U%YHI}qbL6ZI+#oT8aOk&l=EzmvvfvceR zZ+8{LLKoDV1k@3ceZu-$sPNv1j>!BqmVY4QhyPG*S&d}>D$7LB2_|oVAHYY@5{h1~ zu(Z357X4G1 SWrUuB?7{2*!)kA6AEePeT<%ra*0H2=OZoL6&9_j0p- zQ3uzTcfE^9oM +|M%if1aFgnfoJi zqn5dQf0<*M`}#%0EpuPKu*x#`mlkAO=Kk>9sL$MYvdn$mqIS#NmoKce%>Bg$*_OFK zG&gFQd*X(jEOTGCsLe9>CFfRJ=KkUWBzrHs6W#UD+%#S~eeU0FhfSl+au>Wxe%+#0 z^5tF2$iH*$5b})+*OGr>K^FPxS0>22Ya?_1N x`b!r?cq&@J=@jL2p*uRG~8S$k%F6ll912G~)!EzaFJnw`f38<&pO`Bb}-Z zS`kR~{_V)3iMn%_k3jyEKr~W+jryaJJM`w`5K?&a=O!Rf>dhxH=Jn=NOiu{uXPPlL zbY}O}hZ*0`M34opf|$<%jtAa_tZ^F w77%=(E!Mqj&b3T|agQ;2%=J7C?pM&`
mw?$H%o$*!FN0Z{4d!Sthl9yN-tw#f)dgm6Fhwi5|AXA` z2TZedXt=XL)@-OoX{B%zCw>hBze0R@6lXd-5v@EGf62L mp_1iS@cPnA-0lWEoR+=>IQ@B<5AH`zt`ev2)mgKF2;P7A3C#%fCoQ}Q1 z5dKNJv~$}7$D>t0o|!HIVmD6bF3Xcb99Q{np7m`MY=l7+`>C8QTa$x^oT=h9ocu|) zG-VY%k52N2b)#o5tItA2F+b(}<#e;RN46vub(uE`I%v+zksR}FPTzv={kNEk-m+Z& z= +h?I`Lq<1G@yW%19X|ygf$&%=x2bp13c4 zG=>RGCSzoo@OB#uFlUXEePVHR9F_?b-0?C^BtAU>V9uB*1I2A=6ERJo-%pZlqI< zfH`@JEEG3|r$}CVwPdO!wGC6J0n9O22hH{2=^^jsq8TAGt~0Z ^TQHgiZsM&K)~`QiCIYkpWe#+n}vwQ|}OlG6}5)BD^Mxp!qN z?EKfh*z`5vkKy*C)*v5Pu}RvrH92|V-*a+*Djy5{36& ;7_UasUB5ApohhiTct{AxB8XN23|s?ofAPNiA}Cj z^d3&m 3H9?}Kb<>og)XxjGq-aP9!kT?+g; zaNnR#i=<3@pX`75b$$i>9d+hY=h <;v?I?0NPjl|8ocoPm=cu60_;o>@f)_b= zAeF<{khzS?Cj^xysY&gPieBd2L8^3}U+EiEdQMN9*{w>W$(8+!bMweVZXt6ycREv* z^1$ra14eZ!-n90K=v~%6ah~iGNT8!+pr~154HU7zS_8#}GEg9Pj+JuS0C|QO#2>O2 zil0~u#TO^`;ak|@#$XdU=tYd0zr`wY9{;MR0mDcoFJUeMBLQ@EDVSEe&U_Qh4Pf5Q z!GN;^|LzzN7*xF1(n0J6VlGu9Pl0(V0_IRKbHKzUO5aD_(?CoEQMeMs^&liGdn3Tq zFv!d=!Tc7?hM{0aG7iiIVEzndRSCD-iK|Zs@i2&`*&yg)a|Bh>UI6n_6wJ|J_63ur z@%4BZ%s0V&4on&I!Q8>sKL#-c#4tvz`8|lMsG4Y_>IBYQ0%9?Ubx=9;c@XDOHT)!) z_Y1&$70fAMVy}RCD-#SIZw>*I`yQAV)4-ey<_loT*Ybb|x!=z~> uUJ#gE ;sY>CcT5xIRDdlCf0@Lhn z)B6;;W2O} 5r`C0vuPB9! =_=?3k*XD(98$j_7-+@;ie7fA$r?~zIwZ2D-Y`Jz(qv2eQd=pAkPN3CWv zqxHQ(vq-78p*AW*$^}ZjRmIlT_jRS-+ZhoN{`pFKo{faW685m^{UO%RdDE3#r^IWA zZCuK+t}`;LZ=>gSg-j*O-Okw|#B1ZVGRMz=FTI|w1>xoZrQVZatq?c6*z^wVqh}^h z-7K%-9oLPu_MOA5Dc}m30$@JYzP)a&weK8mO#xTR6oALTnzz@Dwf3E_SyRB3G6ir3 zqv`^BYuz|#*@X4<-VtO9Um|lAneZPtXDgi)RGPejb4PNn^mS0zhoN^7MlfuaTb)5> z!(>j*5`8?1O!*rdYyE}XE2?#tYE9wfY}GoNO!X2_H|So`yMtQa4QlO*CD<&W*3hLv zt=PS)Rm{CG7TbH7y%}uBP^l3a-Q6nVVREmk(oa=sDw!`)=~yZ?uK;tSo|pMpQ0bRJ zrGu%&;KaBQRLXfOs01g+48@(kMy2DaG-?f)n{+4f9fS~aV&$&Zanw4IS`%qmSF7-! z dxHGJ~!l_ zSr#N|;3(dyUc$$#G04%CU@#<_@x1pFBL8=Q*af%?@J j64&j zW6h_*AZwUgfpI!)k|kVMTEf-SWC<6d7KCfv5KFkuwuI~bd`q}aw1n%;3`?>ORtjOX zG;2?rKA=UhW|k#ff7GTQW{jm 2LFw{~kjE?l$s$x;A)08aDhFl%N@lt1K zai8w%jImbu4bFUh2ZI(#-OvRy=<(|H)8!CZq!d+c8sozJ(WX0UBM@`nRHa{3ih?=? zHP{@X)XRFuTJyWCHNSY3wd3PeX57_xTSNX8HXX0fDs#KF=I^X UGzSleYAIrLZe)O<=yE zlmR~m<;onQ)O$8ETKd+WHobqeJj64!oq@StspkzJDcAAOlzJPgwc&v|S1CMdgfzJm zlp? CcBMMXb~2 z4(9)C`hbFZ%??AA-k_9s)gBP$=QW$ T}5umXK`|c7i_?)>YbYgcEUfw-d;|w S5wgnz-wD11@-g@hVw=kx6^d6|SFSg_}dNH0C zu{!*1 ~yWtYe#`{CQ73iKFX+^oU^At|a%_XsUk2F{@?R}(SoRHkyQnkA( zEj@eZGooaPp00?MwQef1)aupAmQHn_tjz$tYw|5QdZxq5PHPU*%D$dO`0*e$k2HwN zy#IgD5w8=QcAxnJo$$I6A}Tw+X~{{|-6AB3Xjj5gj9uTgw4&x-Q3-KE>)hLYnWY4^ znA*^z;tLg~>Fu>#Q{8KM+|KWepDM=Fo4aa+yvc2UA1>c=&hNC5kvDgZ_B8UwJl`Uh zblw%(D})Yhltps bl{GVba!<7aab~?yrLdf` zTPkJqOzTQiD1K-5TjiKSz3O}D%!M&Jn|EO%+=-FaoAWNYcRo#S=-(J1v?&+F7gF=a zB9ME$$LUumlWTg6+&T@z44wTg6UW ~yfxq+9!9SH zALN$rMK1R;jlzXEZh2>rcMc&p_62fp??f)|%HTinqU*ulfS1@z;Eu0MvQu>30y_kM zliiR^@j{&tPV*8xq4=g5*feP*^_jQBzoz!-T+iH24~&q+HW|`+Gw^EQry#0Ujk^y7 zDuJ~TtW)$s+Vf!0;|#VD)HpC%?|?ZOOedJPGQbqkp=LgqAA)&7Ar LdPa^QnJ zag?5j9%pU?{u%f===xZo3=fw9_vg}{MlOxL4CY5*u(Lp^z+_AOLXR`w2D2;|Oc_F* zISz~j$JcSlc+CkgUj>6r0a{37OymKmaRzzS+z;H1@(gN*WyZJ>#KF|`MuUmVjIapI z$zV3rg0alzLNJnXSC@dP60>2J7)hb;=74F_8zDfMo4~v(57#W7@MREx1MvhL%8I-@ zQ#I{5sxIct;nbK4BI8XENKjTD_u9b}tptMv<>ciWFm-Ce?}E9E+pSQ;+crdkG7{9^ z&g21~;eOLWD8l4t2xwo1d_0-O+={-8YPhnkIAo4NQ{12VmAw>Q@<(L|_eiUcXEMji z)?iJ1ub~3ZA~K=(e@wK79t@BdRE5m%arEAwPG&-0pW&kx=tC>|mAPy~jWuJQXU&-J z7g#gqiIxPuo^H*U2U %5<`~8+BmdkRi z_PfB6%vWPp``yoKzmJEl_WNm@-l8QcW~^0ye`g75k0q#Pp(U%*&1t;Ttq`fUMEgC= z3Xv}oSA_Qa1)DygMKNZkl_YPpl-C8%RcPmHsa{W6>OSo;105&6|6ok>A_HoqBR3BLaHaLd(Jen|^%V5gR; zJydU*+R|MdQ(G9dJ-T>^?aQ}ks}~d9T@l+|*B9E3dU>MlqIC-_SNk=7HMrW-!)^1g z_@Y)9adXSm9;~-byVTkh#G!2y-a$MVri0g~so4_nW!pa2721}0d4g?|wF?|q%d&6% zRJ&ey#Xg-#r^%xfk+<|uVqM}ARIS7>{hWZF$2rAK5qqAuLgr)j%93?Ywfno z%A>XSNgjnUXjgP^&*klkk7|CrP0TA}p%y!!&uMQyl({A`ugsrmr3502xEAtCy&^wz zFW2HG7@L?DVoD8uFBqFxml&Iv7QzW4*t6(@RyJ8R+{z~1h;j$CN-`-j-Is(y7pKE4 zN^dDJ>!0A|&4YD#`rvjL^H;WNUADL6bA+<)_+}0?NqeTMS-GO>Zp71zqLO%TFXs|o zT~cjkRATRII3>MZ-zE3nFnt$Ojm|YS_aZENL^@#lzm@=^4X}KaJMGoyJvXW))U*40 z_or)*Q^X@~&`6L?j>H&Ax89?TR-|3A_ejaF7ZbCH T#D2;MYmYV*p{pYJQ$!k-w8iDFEa`1w4DqFE z3CaK!Ad`1j5}*{lD{jls&v!mU4Aa?Y1e|6HAUqKCG&|uCkgi+HVzNP_AW#8|!K(xm zcxkuM36!DH-6x}`eH$%-V!P?NCV$5sSI}H}ht30!0!f-YplQiv^+Xih#T$9M4-J_) zh}-8dpu#v%3FRRM`5+qOohk&P*sF;0iO)6=f55QnqQ&!;)2g>42Al8D)^ADvs9KLh zE-|~6I6ahzueZr&O+Vd?QUR}|4@!oI%uKYA?rDTm-;1Vl{K$~`Kl=BE@JI|y&!OSG zQaqX%3P!<(DPx!?dgmjE*gl=MxN^KW976o_`4d8BAp>mfn2BO>^uxT#gnH3GmrW6e zqvLX?;&zJ=H*P+y4b&13!{b7U{cM`{BAZ5d3zTFn!EX00j`8-CJi$X~UhQtVZ$BA;kg -Cz~v9c;iGq1Xhx?PW $bYu!PTJquJUqG&1*7x(lzF)`IF@$iclC+UroFR?d^(&M`4`jZ1+%x32gk^o zIcv1io9y MOZPCD^EHhr*8D)FakmEK${jd=7>rN2_j ztJX**{+?1^wOT6isY-d(DyhWtl=7;TQi*rB>3x;bh^GxvdaY9I$raLzFHy>?mP;i* zTPf;!nN;HA__T8}&&^qEX8vXK7&pgL={B^$U(6h+Vsbn8%QKDkwd!Zu3)aYVv}Na6 zORSOUo0h4Ut+7U?A6wQw3~M(+^i?*UAT}>=7U}1$q8ffoEZ-bp8Gq~*F@AG`W&gSF zNq05pS`D^*tu$EkGpon8BqR}->uowiI<5Jugafmu6%is&NxwCRSS>gHhO}Js4Xf)G zu8`DVzHeoR>J5?|%&)Bk(cww^HGi_{Y)KR5At}P vI%j@PDO<_-xTW*04_HjfTbI#;O|yS8ErgSXQS@T?2jZ{8hn zq1Vz&WfA&{Qf7Jy+}G@E)7wjA5Smo1^a`aYenoI!bCFVJx{ZtIQi|iKKtT~lDrKhU zD=6ZNO0iDmDJWt`oBlCRF%e^OmHt{OdR&fliVKutiOZHN?dwW$9A(LuHeadtY$Q{@ zv^{Kkf2Le%(=(J_r v0nOib2F8FQswFVoW)LZ?WuijH(`g$&YXDtR{tKiW|oFOB;PE8#ZyhZe=1?jOqU z;2!{dUiPqyO*6kR|CAF>JnmS#dQwa3wER-bH|v$3*+tsB)HF;ULy)Z_{71ReRQK0! zdzYFLSDpOpIk&g8u>th1{CaM+ARKW^L&K40{POD-+GOK3lstb4spl`{^!z2HUXQDf z7GQr&J_kqmaJmn7_2K?LJkp1!`S5%nUh2cEeR!)6AM)V~K3wX<9t-*Wfe)*FIKqe1 zeYmR+_xItEK0M8b=lk$dA71UlTYdPD4`1-%QXlp>h__e2FiV~s9O1+1KHSxZ`}^=n zAD-sJ^L==!53ly&tv-CnhcEbWsSkS`jO6&R+J_^2INgW4`fz_A9_ho=e0aVOFZJQo lKD^aJl4PMel~1)tY7Bg`#sI_(Dxkyux=3~CH_Jal{~yfa%=Q2P literal 0 HcmV?d00001 diff --git a/HTML/base.kanvas.html b/HTML/base.kanvas.html new file mode 100755 index 0000000..8f5161c --- /dev/null +++ b/HTML/base.kanvas.html @@ -0,0 +1,175 @@ + + + + {title} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ++ ++ + + + + + Kanvas + +
+ ++ + + ++ + + diff --git a/JSON/html.files.json b/JSON/html.files.json new file mode 100755 index 0000000..ba6b588 --- /dev/null +++ b/JSON/html.files.json @@ -0,0 +1 @@ +{"files":["\/mnt\/d\/git\/Kanvas\/Public\/dev\/ECMAScript\/index.html","\/mnt\/d\/git\/Kanvas\/Public\/dev\/PHP\/index.html","\/mnt\/d\/git\/Kanvas\/Public\/dev\/Public\/Kanvas.ecma.js.html","\/mnt\/d\/git\/Kanvas\/Public\/dev\/Public\/wmd.php.html","\/mnt\/d\/git\/Kanvas\/Public\/dev\/Public\/wmd_scripts.php.html","\/mnt\/d\/git\/Kanvas\/Public\/dev\/index.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/doc\/kanvas.idea.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/doc\/kanvas.quality.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/doc\/kanvas.settings.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/doc\/kanvas.starting.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/doc\/kanvas.targets.html","\/mnt\/d\/git\/Kanvas\/Public\/es\/index.html","\/mnt\/d\/git\/Kanvas\/Public\/index.html"],"directories":["\/JSON","\/dev","\/dev\/ECMAScript","\/dev\/PHP","\/dev\/Public","\/es","\/es\/doc"]} \ No newline at end of file diff --git a/Public/.htaccess b/Public/.htaccess new file mode 100755 index 0000000..81d9bac --- /dev/null +++ b/Public/.htaccess @@ -0,0 +1 @@ +Header set Access-Control-Allow-Origin "*" diff --git a/Public/ecma/version/20230707/Kanvas.ecma.js b/Public/ecma/version/20230707/Kanvas.ecma.js new file mode 100644 index 0000000..144f9e9 --- /dev/null +++ b/Public/ecma/version/20230707/Kanvas.ecma.js @@ -0,0 +1,747 @@ +Kanvas = function(settings){ + + const self = this, + default_settings = { + nulls : false, + default_value : null, + position : ".kanvas", + preload_timeout : 2000, + frames_per_second : 60, + quality : 1, + quality_x : 1, + quality_y : 1, + cells : 40, + swap_and_drop_timer : 5000, + font_size : 1, + font_family : "Arial", + settings_overwrite : false, + autostart : true, + autobuild : true, + font_minimum_size : 12, + events_cache_timer : 100 + }, + custom = {}, + cache = {}, + frames_times = [], + id_length = 11, + id_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", + ids = [], + threads = [], + number_of_cells = {x : 0, y : 0}, + events_cache = []; + let thread = null, + frames_per_second = null, + canvas, context, + last_frame_time = 0, frames_times_summatory = 0, + swap_and_drop_timer, + cache_box, + default_font_size, default_font_family, + settings_overwrite, + built = false, + started = false, + font_minimum_size, + events_cache_timer; + + this.map = []; + let cells = this.cells; + let cell_size = this.cell_size; + let quality = this.quality; + let quality_x = this.quality_x; + let quality_y = this.quality_y; + this.cells_x = 0; + this.cells_y = 0; + this.delta_time = 0; + + let item_self = this.item_self; + let hash_self = this.hash_self; + let object_name = this.object_name; + + this.Event = function(){ + + const self = this, + events = [], + properties = []; + + const construct = () => { + + events_cache.push(autoclean); + + }; + + this.execute = (callback, ...arguments) => events.forEach((event, i) => ( + event && + (typeof callback == "function" ? callback(properties[i]) : true) && + event(...arguments) + )); + + this.add = (callback, own_properties) => { + + let i = 0; + const l = events.length; + + for(; i < l; i ++) + if(!events[i]) + break; + + events[i] = callback; + properties[i] = own_properties; + + return i; + }; + + this.remove = i => events[i] = null; + + const autoclean = () => { + + const date = Date.now(); + + properties.forEach((own_properties, i) => { + if(own_properties && own_properties.last_used && date - own_properties.last_used > events_cache_timer){ + events[i] = null; + properties[i] = null; + }; + }); + + }; + + this.update = (i, date) => events[i] && (properties[i].last_used = date); + + construct(); + + }; + + this.on_screen_change = new this.Event(); + this.on_ready = new this.Event(); + this.on_click = new this.Event(); + this.on_click_down = new this.Event(); + this.on_click_up = new this.Event(); + this.on_key_down = new this.Event(); + this.on_key_up = new this.Event(); + + const construct = () => { + + settings = ( + settings instanceof Array ? settings : + typeof settings == "object" ? [settings] : + []).filter(inputs => typeof inputs == "object" && !(inputs instanceof Array)); + + self.settings("autostart") && self.start(); + + }; + + this.start = callback => { + + const end = status => typeof callback == "function" && callback(status); + + if(started){ + end(false); + return false; + }; + started = true; + + settings_overwrite = self.settings(["settings_overwrite", "overwrite"]); + frames_per_second = self.settings(["frames_per_second", "fps"]); + events_cache_timer = self.settings("events_cache_timer"); + object_name = self.object_name = self.settings("object_name"); + + thread = setInterval(execute, 1000 / frames_per_second); + + if(self.settings("autobuild")) + self.build(callback); + else + end(true); + + return true; + }; + + this.build = callback => { + + const position = self.settings("position"), + end = status => typeof callback == "function" && callback(status); + + if(built){ + end(false); + return false; + }; + built = true; + + if(position){ + + if(position.tagName || position.nodeName){ + end_build(position); + end(true); + return; + }; + + if(typeof position != "string"){ + console.error("position_not_string"); + end(false); + return; + }; + + if(!position.trim()){ + console.error("position_selector_empty"); + end(false); + return; + }; + + let html_object; + + try{ + if(html_object = document.querySelector(position)){ + end_build(html_object); + end(true); + return; + }; + }catch(exception){ + console.error(exception); + console.error("position_bad_selector"); + end(false); + return; + }; + + const date = Date.now(), + timeout = self.settings("preload_timeout"); + let interval = setInterval(() => { + if(html_object = document.querySelector(position)){ + clearInterval(interval); + end_build(html_object); + end(true); + }else if(Date.now() - date > timeout){ + clearInterval(interval); + console.error("position_timeout"); + end(false); + }; + }, frames_per_second); + + }else{ + console.error("no_position"); + end(false); + }; + + return true; + }; + + const end_build = position => { + + quality = self.quality = self.settings("quality"); + quality_x = self.quality_x = self.settings("quality_x"); + quality_y = self.quality_y = self.settings("quality_y"); + cells = self.cells = self.settings("cells"); + default_font_size = self.settings("font_size"); + default_font_family = self.settings("font_family"); + + cache.quality = 0; + cache.quality_x = 0; + cache.quality_y = 0; + + cache.screen = {x : 0, y : 0}; + cache.origin = {x : 0, y : 0}; + + item_self = self.item_self = (position || document.querySelector("body")).appendChild(document.createElement("div")); + cache_box = item_self.appendChild(document.createElement("div")); + canvas = item_self.appendChild(document.createElement("canvas")); + hash_self = self.hash_self = self.settings(["id", "hash"]) || self.create_id(); + + item_self.setAttribute("id", hash_self); + item_self.setAttribute("class", ["kanvas", hash_self].concat((self.settings("class") || "").split(/\s+/)).filter((key, i, array) => array.indexOf(key) == i).join(" ")); + item_self.setAttribute("data-hash", hash_self); + item_self.setAttribute("data-cells", cells); + item_self.setAttribute("data-minimum-font-size", font_minimum_size = self.settings("font_minimum_size")); + + cache_box.setAttribute("class", "kanvas-cache-box"); + cache_box.setAttribute("style", ` + position : absolute; + top : 0%; + left : 0%; + width : 100%; + height : 100%; + visibility : hidden; + z-index : 10; + opacity : 0; + `.replace(/[\r\n\s]+/g, "")); + + canvas.setAttribute("class", "kanvas-ui"); + canvas.setAttribute("style", ` + position : absolute; + top : 0%; + left : 0%; + width : 100%; + height : 100%; + z-index : 20; + `.replace(/[\r\n\s]+/g, "")); + canvas.onclick = event => on_click(canvas, event, "click"); + canvas.onmousedown = event => on_click(canvas, event, "down"); + canvas.onmouseup = event => on_click(canvas, event, "up"); + canvas.onkeydown = event => on_key(canvas, event, "down"); + canvas.onkeyup = event => on_key(canvas, event, "up"); + + context = canvas.getContext("2d"); + + context.id = self.create_id(); + + swap_and_drop_timer = self.settings("swap_and_drop_timer"); + + self.on_ready.execute(); + + }; + + this.nulls = nulls => typeof nulls == "boolean" ? nulls : self.settings("nulls", null, false, false); + + this.default_value = (_default, nulls) => _default !== undefined && (self.nulls(nulls) || _default !== null) ? _default : self.settings("default_value", null, null, true); + + this.settings = (names, inputs, _default, nulls) => { + + const l = (names = ( + names instanceof Array ? names : + typeof names == "string" ? [names] : + [] + ).filter((name, i, array) => name && typeof name == "string" && array.indexOf(name) == i)).length; + + if(l){ + + const m = (inputs = ( + inputs instanceof Array ? inputs : + typeof inputs == "object" ? [inputs] : + []).concat(settings, custom, [default_settings])).length; + + nulls = self.nulls(nulls); + + for(let j = 0; j < m; j ++) + if(inputs[j] && typeof inputs[j] == "object" && !(inputs[j] instanceof Array)) + for(let i = 0; i < l; i ++) + if(inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) + return inputs[j][names[i]]; + }; + return self.default_value(_default, nulls); + }; + + this.settings_add = (inputs, overwrite) => { + if(!inputs) + return; + + if(typeof inputs == "string"){ + try{ + inputs = JSON.parse(inputs); + }catch(exception){}; + }; + + if(typeof inputs == "object"){ + if(inputs instanceof Array) + inputs.forEach(inputs, overwrite); + else{ + typeof overwrite != "boolean" && (overwrite = settings_overwrite); + for(const key in inputs) + if(overwrite || custom[key] === undefined) + custom[key] = inputs[key]; + }; + }; + + }; + + this.create_id = () => { + + let id; + const l = id_alphabet.length; + + do{ + id = ""; + while((id += id_alphabet[l * Math.random() >> 0]).length < id_length); + }while( + ids.includes(id) || + !/^[a-z]/i.test(id) || + document.querySelector("." + id + ",#" + id + ",[name=" + id + "]") + ); + ids.push(id); + + return id; + }; + + const execute = () => { + + const date = Date.now(); + let screen_changed = false; + + if(item_self && (cache.screen.x != item_self.offsetWidth || cache.screen.y != item_self.offsetHeight)){ + screen_changed = true; + + cache.screen.x = item_self.offsetWidth; + cache.screen.y = item_self.offsetHeight; + + const font_size = cache.screen[cache.screen.x < cache.screen.y ? "x" : "y"] / cells; + + item_self.style.fontSize = (font_size < font_minimum_size ? font_minimum_size : font_size) + "px"; + + }; + + if(canvas){ + + if(last_frame_time){ + + const frame_time = date - last_frame_time; + + frames_times.push(frame_time); + frames_times_summatory += frame_time; + + self.delta_time = frame_time / 1000; + + while(frames_times.length > frames_per_second) + frames_times_summatory -= frames_times.shift(); + + }; + + last_frame_time = date; + + if(screen_changed || cache.quality != quality){ + + const width = cache.screen.x * quality, + height = cache.screen.y * quality; + + cache.quality = quality; + canvas.setAttribute("width", width); + canvas.setAttribute("height", height); + cache.origin.x = width / 2; + cache.origin.y = height / 2; + + cell_size = self.cell_size = (width > height ? height : width) / cells; + + number_of_cells.x = width / cell_size; + number_of_cells.y = height / cell_size; + + this.cells_x = number_of_cells.x / 2; + this.cells_y = number_of_cells.y / 2; + + for(const key in cache) + if(cache[key] && cache[key].data) + cache[key].data = null; + + self.on_screen_change.execute(); + + }; + + }; + + threads.forEach(thread => thread && thread()); + + if(canvas){ + + context.beginPath(); + context.clearRect(0, 0, cache.screen.x * quality, cache.screen.y * quality); + context.translate(cache.origin.x, cache.origin.y); + + draw(context, self.map, 0, 0); + + context.translate(-cache.origin.x, -cache.origin.y); + + for(const key in cache) + if(cache[key] && cache[key].last_used && date - cache[key].last_used > swap_and_drop_timer) + delete cache[key]; + + }; + + events_cache.forEach(autoclean => autoclean()); + + }; + + this.set_quality = new_quality => quality = self.quality = new_quality; + this.set_quality_x = new_quality => quality_x = self.quality_x = new_quality; + this.set_quality_y = new_quality => quality_y = self.quality_y = new_quality; + + const _x = x => x * cell_size; + const _y = y => y * cell_size; + const size = size => size * cell_size; + + const set_cache = (context, status) => { + + !status && cache[context.id] && cache[context.id].ok && (cache[context.id].ok = false); + + return status; + }; + + const set_border = (context, inputs) => { + + const has_border = !!(inputs.border_color || !isNaN(inputs.border_width)); + + inputs.border_color && (context.strokeStyle = inputs.border_color); + !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); + + return has_border; + }; + + const set_background = (context, inputs) => { + + const has_background = !!(inputs.background || (!inputs.border_color && isNaN(inputs.border_width))); + + if(inputs.background){ + if(inputs.background instanceof Array){ + + const v = inputs.background, + is_linear = v.length == 5, + gradient = ( + is_linear ? context.createLinearGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3])) : + context.createRadialGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3]), size(v[4]), size(v[5])) + ); + + inputs.background[is_linear ? 4 : 6].forEach(color => gradient.addColorStop(color[0], color[1])); + + context.fillStyle = gradient; + + }else + context.fillStyle = inputs.background; + }; + + return has_background; + }; + + const set_shadow = (context, inputs, shape_callback) => { + + const shadows = inputs.shadow || inputs.shadows; + + (shadows && shadows.length ? shadows[0] instanceof Array ? shadows : [shadows] : []).forEach(shadow => { + [context.shadowOffsetX, context.shadowOffsetY, context.shadowBlur, context.shadowColor] = shadow; + context.shadowOffsetX = size(shadow[0]); + context.shadowOffsetY = size(shadow[1]); + context.shadowBlur = size(shadow[2]); + context.shadowColor = size(shadow[3]); + shape_callback(); + }); + + }; + + const shapes = { + rectangle : (context, inputs) => { + + const x = _x(inputs.x), + y = _y(inputs.y), + width = size(inputs.width), + height = size(inputs.height), + has_border = set_border(context, inputs), + has_background = set_background(context, inputs); + + set_shadow(context, inputs, () => context.rect(x, y, width, height)); + has_background && context.fillRect(x, y, width, height); + has_border && context.strokeRect(x, y, width, height); + + return set_cache(context, true); + }, + image : (context, inputs) => { + + const url = inputs.url; + + if(url){ + + const cached = cache[url]; + + if(!cached){ + (cache[url] = { + image : new Image(), + loaded : false, + last_used : Date.now() + }).image.src = url; + cache[url].image.crossOrigin = "anonymous"; + cache[url].image.onload = () => cache[url].loaded = true; + return set_cache(context, false); + }; + + if(cached.loaded){ + + let width = inputs.width, + height = inputs.height; + const cut_x = inputs.cut_x || 0, + cut_y = inputs.cut_y || 0, + cut_width = inputs.cut_width || 0, + cut_height = inputs.cut_height || 0, + position_x = inputs.x || 0, + position_y = inputs.y || 0, + x = _x(position_x), + y = _y(position_y), + end_width = size(width), + end_height = size(height); + + !width && (width = cache.quality * (cut_width || cache[url].image.width - cut_x) / cell_size); + !height && (height = cache.quality * (cut_height || cache[url].image.height - cut_y) / cell_size); + + set_shadow(context, inputs, () => context.rect(x, y, end_width, end_height)); + set_border(context, inputs); + context.drawImage( + cache[url].image, + cut_x, cut_y, cut_width || cache[url].image.width - cut_x, cut_height || cache[url].image.height - cut_y, + x, y, end_width, end_height + ); + cache[url].last_used = Date.now(); + + return set_cache(context, true); + }; + + }; + + return set_cache(context, false); + }, + cache : (context, inputs) => { + + const width = inputs.width ? inputs.width * cell_size : canvas.getAttribute("width"), + height = inputs.height ? inputs.height * cell_size : canvas.getAttribute("height"); + let status = false; + + if(!cache[inputs.name]){ + + const subcanvas = cache_box.appendChild(document.createElement("canvas")); + + cache[inputs.name] = { + canvas : subcanvas, + data : null + }; + cache[inputs.name].context = subcanvas.getContext("2d"); + + cache[inputs.name].context.id = inputs.name; + + subcanvas.setAttribute("data-id", cache[inputs.name].context.id); + + cache[inputs.name].context.translate(inputs.x || 0, inputs.y || 0); + + }; + + if(cache[inputs.name].data){ + if(cache[inputs.name].image_loaded){ + context.drawImage(cache[inputs.name].image, _x(inputs.x || 0), _y(inputs.y || 0), cache[inputs.name].image.width, cache[inputs.name].image.height); + status = true; + }else if(!cache[inputs.name].image){ + + cache[inputs.name].image = new Image(); + + cache[inputs.name].image.src = cache[inputs.name].data; + cache[inputs.name].image.onload = () => { + // cache[inputs.name].canvas.remove(); + cache[inputs.name].image_loaded = true; + }; + // cache[inputs.name].image.onerror = () => cache[inputs.name].canvas.remove(); + + }; + }else{ + + cache[inputs.name].canvas.setAttribute("width", width); + cache[inputs.name].canvas.setAttribute("height", height); + + cache[inputs.name].context.beginPath(); + cache[inputs.name].context.clearRect(0, 0, width, height); + cache[inputs.name].context.translate(width / 2, height / 2); + + cache[inputs.name].image = null; + cache[inputs.name].image_loaded = false; + cache[inputs.name].ok = true; + + draw(cache[inputs.name].context, inputs.childs, 0, 0); + + cache[inputs.name].context.closePath(); + + cache[inputs.name].ok && + (cache[inputs.name].data = cache[inputs.name].canvas.toDataURL("image/png", 1.0)); + + }; + + cache[inputs.name].last_used = Date.now(); + + return set_cache(context, status); + }, + text : (context, inputs) => { + + const x = _x(inputs.x), + y = _y(inputs.y), + has_border = set_border(context, inputs), + has_background = set_background(context, inputs); + + inputs.align && (context.textAlign = inputs.align); + inputs.baseline && (context.textBaseline = inputs.baseline); + !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); + context.font = (inputs.style ? inputs.style + " " : "") + size(inputs.size || default_font_size) + "px " + (inputs.family || default_font_family); + + set_shadow(context, inputs, () => context.fillText(inputs.text, x, y)); + has_background && context.fillText(inputs.text, x, y); + has_border && context.strokeText(inputs.text, x, y); + + return true; + } + }; + + this.string_variables = (string, variables) => string.replace(/\{([^\{\}]+)\}/g, (...arguments) => variables[arguments[1]] !== undefined ? variables[arguments[1]] : arguments[0]); + + const draw = (context, level, x, y) => level.forEach(values => { + if(values && (shapes[values.type] || ["block"].includes(values.type))){ + + const sub_x = _x(x + (values.margin_x || 0)), + sub_y = _y(y + (values.margin_y || 0)), + date = Date.now(); + + context.save(); + context.translate(sub_x, sub_y); + + const transform = context.getTransform(); + + values.rotate && context.rotate(2 * Math.PI * values.rotate / 360); + !isNaN(values.alpha) && (context.globalAlpha = values.alpha); + + if(values.on_click){ + values.context_x = transform.e / quality; + values.context_y = transform.f / quality; + if(!values.last_used || date - values.last_used > events_cache_timer) + values.i = self.on_click.add(eval(self.string_variables(values.on_click, {object_name : object_name})), values); + else + self.on_click.update(values.i, date); + values.last_used = date; + }; + + values.type != "block" && shapes[values.type](context, values); + + values.type != "cache" && values.childs && draw(context, values.childs, values.x, values.y); + + context.translate(-sub_x, -sub_y); + context.restore(); + + }; + }); + + this.get_real_fps = this.get_real_frames_per_second = () => frames_times_summatory ? 1000 / (frames_times_summatory / frames_times.length) : 0; + + this.threads_add = callback => { + + let i = 0; + const l = threads.length; + + for(; i < l; i ++) + if(!threads[i]) + break; + + threads[i] = callback; + + return i; + }; + + this.threads_remove = i => threads[i] = null; + + this.get_cells_x = () => number_of_cells.x; + this.get_cells_y = () => number_of_cells.y; + + this.extends = object => { + for(const key in self) + if(object[key] === undefined) + object[key] = self[key]; + }; + + const on_click = (canvas, event, action) => { + + switch(action){ + case "click": + self.on_click.execute(properties => ( + event.clientX >= properties.context_x + (properties.x * cell_size) && + event.clientY >= properties.context_y + (properties.y * cell_size) && + event.clientX <= properties.context_x + ((properties.x + properties.width) * cell_size) && + event.clientY <= properties.context_y + ((properties.y + properties.height) * cell_size) + ), canvas, event); + break; + }; + + }; + + construct(); + +}; \ No newline at end of file diff --git a/Public/ecma/version/221106/Kanvas.ecma.js b/Public/ecma/version/221106/Kanvas.ecma.js new file mode 100755 index 0000000..38dcfa5 --- /dev/null +++ b/Public/ecma/version/221106/Kanvas.ecma.js @@ -0,0 +1,936 @@ +Kanvas = function(input){ + + const self = this, + default_settings = { + quality : 1, + quality_x : 1, + quality_y : 1, + cells : 100, + origin : 5, // Posición origen. Mirar teclado numérico para ver los diferentes valores para cada posición. + frames_per_second : 60, + ratio : null, // Expone la proporción de tamaño del Canvas (16/9 para pantallas WideScreen por ejemplo). Si es equivalente a falso cubrirá todo el área de la capa donde se encuentre. + overwrite : false, + position : "body", + autostart : true, + object_name : "kanvas", + class : "kanvas", + application : "Kanvas", + x : 0, + y : 0, + width : 0, + height : 0, + color : "#000", + blur : 0, + italic : false, + bold : false, + size : 1, + font : "Arial", + align : "left", + alpha : 1, + degrees : 0, + baseline : "Alphabetic", + shadow_x : 0, + shadow_y : 0, + shadow_color : "#000", + shadow_blur : 0, + border_color : "#000", + border_width : 0, + text_italic : false, + text_bold : false, + text_size : 1, + font_family : "Arial", + text_color : "#000", + text_align : "left", + text_alpha : 1, + rotate_x : 0, + rotate_y : 0, + rotate_degrees : 0, + image_x : 0, + image_y : 0, + image_alpha : 1, + rectangle_color : "#000", + rectangle_alpha : 1, + rectangle_x : 0, + rectangle_y : 0, + text_baseline : "Alphabetic", + default_value : null, + hash_alphabet : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", + hash_length : 7, + frames_per_second_samples : 20, + settings_overwrite : false, + ajax_timeout : 2000 + }, + custom = {}, + // cache = [], + _screen = {x : 0, y : 0}, + position = {x : 0, y : 0}, + events = {}, + threads = [], + hashes = [], + attributes = { + natives : ["id", "class", "onmousemove", "tabindex", "onkeydown", "onkeyup"] + }, + cache = {}, + frames_per_second_samples = [], + delta_time = 0; + let q, qx, qy, // Calidad porcentual. + c, // Número de celdas en el lado más corto de la pantalla o área de trabajo rectangular. + fx, fy, // Posición contra el foco. + dx, dy, // Distancia desde los laterales hasta el cuadrado de trabajo. + s, // Tamaño de la celda. Solo se mide un lado pues será cuadrada. + mx, my, // Posición origen del lienzo. + thread = null, + timeout = 0, + last_time = 0, + started = false, + cache_container, context, canvas, + // cache_l = 0, + thread_object = null, + frames_per_second_samples_number, + last_frame_per_second_sample = Date.now(), + real_frames_per_seconds = 0, + ajax_timeout; + + let item_self = this.item_self; + let hash_self = this.hash_self; + let object_name = this.object_name; + let mouse = this.mouse = {x : 0, y : 0}; + + this.LOADING = 1 << 0; + this.LOADED = 1 << 1; + this.ERROR = 1 << 2; + + this.map = []; + + const null_or_undefined = this.null_or_undefined = value => value === undefined || value === null; + + this.get = (url, callback) => { + + let ended = false; + const ajax = new XMLHttpRequest(), + end = status => { + if(ended) + return; + ended = true; + typeof callback == "function" && callback(ajax.response, ajax.status, ajax.readyState, status, status == "OK"); + }, + date = Date.now(); + + ajax.open("get", url, true); + ajax.timeout = ajax_timeout; + ajax.onreadystatechange = () => { + if(ended) + return; + if(ajax.readyState == 4) + end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR"); + else if(Date.now() - date > ajax_timeout) + end("FORCED_TIMEOUT"); + }; + ajax.send(null); + + ajax.ontimeout = () => end("TIMEOUT"); + ajax.onabort = () => end("ABORTED"); + ajax.onerror = () => end("ERROR"); + + return ajax; + }; + + const allow_nulls = this.allow_nulls = nulls => typeof nulls == "boolean" ? nulls : settings(["nulls", "allow_nulls"], null, false, false); + + const default_value = this.default_value = (_default, nulls) => _default !== undefined && (nulls || _default !== null) ? _default : settings(["default_value", "default", "by_default"], null, null, true); + + this.settings_add = (inputs, overwrite, callback) => { + + if(inputs instanceof Array){ + + let loaded = 0; + const end = () => ++ loaded == inputs.length && typeof callback == "function" && callback(); + + inputs.forEach(input => self.settings_add(input, overwrite, end)); + + return; + }; + + if(typeof inputs == "object"){ + typeof overwrite != "boolean" && (overwrite = settings(["settings_overwrite", "overwrite"])); + for(const key in inputs) + (overwrite || custom[key] === undefined) && (custom[key] = inputs[key]); + inputs.autostart !== undefined && (input.autostart = inputs.autostart); + typeof callback == "function" && callback(); + return; + }; + + if(typeof inputs == "string"){ + + let json; + + try{ + if(json = JSON.parse(inputs)){ + self.settings_add(json, overwrite, callback); + return; + }; + }catch(exception){}; + + self.get(inputs, response => { + try{ + if(json = JSON.parse(response)){ + self.settings_add(json, overwrite, callback); + return; + }; + }catch(exception){}; + typeof callback == "function" && callback(); + }); + + return; + }; + + typeof callback == "function" && callback(); + + }; + + const settings = this.settings = (names, inputs, _default, nulls) => { + if(!names) + return default_value(_default, nulls); + + nulls = allow_nulls(nulls); + + const l = (names.push ? names : names = [names]).length, + m = (inputs = (inputs ? inputs.push ? inputs : [inputs] : []).concat([input, custom, default_settings])).length; + + for(let j = 0; j < m; j ++) + if(typeof inputs[j] == "object") + for(let i = 0; i < l; i ++) + if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) + return inputs[j][names[i]]; + return default_value(_default, nulls); + }; + + const threads_function = () => threads.forEach(thread => thread && thread()); + + const threads_start = this.threads_start = frames_per_second => thread_object === null && (thread_object = setInterval(threads_function, 1000 / (isNaN(frames_per_second) || frames_per_second < 1 ? settings(["frames_per_second", "fps"]) : frames_per_second))); + + const threads_stop = this.threads_stop = () => { + + if(thread_object === null) + return; + + clearInterval(thread_object); + thread_object = null; + + }; + + const threads_add = this.threads_add = callback => { + if(typeof callback != "function") + return null; + + let i = 0; + const l = threads.length; + + for(; i < l; i ++) + if(!threads[i]) + break; + + threads[i] = callback; + + return i; + }; + + const threads_remove = this.threads_remove = i => !isNaN(i) && threads[i] && (threads[i] = null); + + const is_html_object = this.is_html_object = variable => typeof variable == "object" && (variable.tagName || variable.nodeName); + + const preload = this.preload = (selector, callback) => { + if(typeof callback != "function") + return; + + if(!selector){ + callback(null, false, "NO_SELECTOR"); + return; + }; + if(is_html_object(selector)){ + callback(selector, false, "OK"); + return; + }; + if(!selector.substr){ + callback(null, false, "BAD_TYPE"); + return; + }; + + let item; + + try{ + if(item = document.querySelector(selector)){ + callback(item, false, "OK"); + return; + }; + }catch(exception){ + callback(null, false, "BAD_SELECTOR"); + return; + }; + + const timeout = settings(["preload_timeout", "timeout"]), + date = Date.now(); + let preload = threads_add(() => { + if(item = document.querySelector(selector)){ + threads_remove(preload); + callback(item, true, "OK"); + }else if(Date.now() - date > timeout){ + threads_remove(preload); + callback(null, true, "TIMEOUT"); + }; + }); + + }; + + const hash = this.hash = () => { + + let hash, alphabet = settings(["hash_alphabet", "alphabet"]); + const length = settings(["hash_length", "length"]), + l = (alphabet.push ? alphabet : alphabet = alphabet.split("")).length; + + do{ + hash = ""; + while((hash += alphabet[Math.random() * l >> 0]).length < length); + }while( + hashes.includes(hash) || + /^\d/.test(hash) || + document.querySelector("." + hash + ",#" + hash + ",[name=" + hash + "]") + ); + hashes.push(hash); + + return hash; + }; + + const set_attribute = this.set_attribute = (item, custom_attributes) => { + if(!is_html_object(item) || typeof custom_attributes != "object") + return; + + for(const name in custom_attributes) + item.setAttribute((attributes.natives.includes(name) ? "" : "data-") + name.replace(/[^a-z\d-]+/g, "-"), custom_attributes[name]); + + }; + + const construct = () => { + + const custom_attributes = { + natives : settings("attributes_natives") + }; + + for(const key in custom_attributes){ + !attributes[key] && (attributes[key] = []); + (custom_attributes ? custom_attributes.push ? custom_attributes : [custom_attributes] : []).forEach(new_attribute => attributes[key].push(new_attribute)); + }; + + object_name = self.object_name = settings("object_name"); + + settings("autostart") && self.start(); + + }; + + const Events = this.Events = function(){ + + const events = []; + + this.add = callback => { + if(typeof callback != "function") + return null; + + let i = 0; + const l = events.length; + + while(i < l){ + if(events[i] === null) + break; + i ++; + }; + + events[i] = callback; + + return i; + }; + + this.remove = i => !isNaN(i) && i >= 0 && events[i] && (events[i] = null); + + this.execute = (...inputs) => events.forEach(event => event && event(...inputs)); + + }; + + const range_analyze = range => !range || ( + mouse.x >= range.x && mouse.x <= range.x + range.width && + mouse.y >= range.y && mouse.y <= range.y + range.height + ); + + const on_resize_method = screen => { + + if(_screen.x == item_self.offsetWidth && _screen.y == item_self.offsetHeight) + return; + + const width = canvas.width = (_screen.x = item_self.offsetWidth) * q * qx, + height = canvas.height = (_screen.y = item_self.offsetHeight) * q * qy; + + if(width < height){ + s = width / c; + dx = 0; + dy = -(c - (c * height / width)) / 2; + mx = position.x; + my = position.y + dy; + }else{ + s = height / c; + dx = -(c - (c * width / height)) / 2; + dy = 0; + mx = position.x + dx; + my = position.y; + }; + + //resize_methods.forEach((method) => {if(method)method();}); + execute_event("resize"); + + }; + + const position_set = () => { + + const origin = settings("origin"); + + position.x = c * (.5 * ((origin - 1) % 3)); + position.y = c * (1 - (.5 * ((origin - 1) / 3 >> 0))); + + }; + + const calculate_real_frames_per_seconds = () => { + + const now = Date.now(), + time = now - last_frame_per_second_sample; + + frames_per_second_samples.push(time); + last_frame_per_second_sample = now; + + while(frames_per_second_samples.length > frames_per_second_samples_number) + frames_per_second_samples.shift(); + + real_frames_per_seconds = 1000 / (frames_per_second_samples.reduce((a, b) => a + b) / frames_per_second_samples.length); + delta_time = time / 1000; + + }; + + this.start = callback => { + + const end = status => typeof callback == "function" && callback(status); + + if(started){ + end(false); + return false; + }; + started = true; + + q = settings(["quality", "q"]); + qx = settings(["quality_x", "qx"]); + qy = settings(["quality_y", "qy"]); + timeout = 1000 / settings("frames_per_second"); + c = settings("cells"); + position_set(); + threads_start(); + ajax_timeout = settings("ajax_timeout"); + + preload(settings("position"), (position, asynchronous, error) => { + + if(!position){ + console.error("ERROR. Position HTML for install GUI CANVAS is bad. [" + error + "]"); + return; + }; + + const _class = (hash_self = self.hash_self = hash()) + " " + settings("class"); + + !new RegExp("\\b" + default_settings.class + "\\b").test(_class) && (_class += " " + default_settings.class); + + set_attribute(item_self = self.item_self = position.appendChild(document.createElement("div")), { + id : hash_self, + hash : hash_self, + class : _class, + application : default_settings.application, + onmousemove : object_name + ".check_mouse(this, event);", + tabindex : 0, + onkeydown : object_name + ".key_down(this, event);", + onkeyup : object_name + ".key_up(this, event);", + cells : c, + mouse_x : 0, + mouse_y : 0 + }); + set_attribute(cache_container = item_self.appendChild(document.createElement("div")), { + class : "cache" + }); + set_attribute(canvas = item_self.appendChild(document.createElement("canvas")), { + class : "canvas" + }); + context = canvas.getContext("2d"); + + thread = threads_add(thread_method); + on_resize_thread = threads_add(on_resize_method); + item_self.onclick = () => execute_event("click"); + + frames_per_second_samples_number = self.settings("frames_per_second_samples"); + threads_add(calculate_real_frames_per_seconds); + + end(true); + + }); + + return true; + }; + + // o = Origin {mx, my} + const draw = this.draw = (map, context, o) => map && map.forEach((level, i) => level && (level.push && draw(level, context, o || {mx : mx, my : my}) || (level.type && components[level.type] && components[level.type](level, context, self, o || {mx : mx, my : my})))); + + const refresh_draw = () => { + + if(!context) + return; + + context.clearRect(0, 0, canvas.width, canvas.height); + draw(self.map, context); + + }; + + const thread_method = () => { + + const date = Date.now(); + + if(date - last_time < timeout) + return; + last_time = date; + + refresh_draw(); + + }; + + // Establecer posición sobre el foco de origen. + // Establecer posición sobre los laterales del recuadro o área de trabajo. + const value = this.value = (value, quality) => q * value * (quality || 1); + // const _x = this._x = value => q * qx * value * s; + // const _y = this._y = value => q * qy * value * s; + const _x = this._x = value => value * s; + const _y = this._y = value => value * s; + + this.preload_cache_items = (items, callback_per_item, callback) => { + + const end = status => typeof callback == "function" && callback(status); + + typeof items == "string" && (items = [items]); + + if(!(items instanceof Array)){ + end(false); + return; + }; + + let fully = true, + loaded = 0; + const has_callback_per_item = typeof callback_per_item == "function", + on_item_loaded = (url, ok) => { + ok !== undefined && (cache[url].status = ok ? self.LOADED : self.ERROR); + cache[url].on_load.execute(url, ok); + has_callback_per_item && callback_per_item(url, ok); + ok === false && fully && (fully = false); + ++ loaded == items.length && end(fully); + }; + + items.forEach(url => { + + if(cache[url]){ + if(cache[url].status == self.LOADING) + cache[url].on_load.add(has_callback_per_item); + else + on_item_loaded(url); + return; + }; + + const extension = ((url.match(/\.([^\.]+)/) || [])[1] || "").toLowerCase(); + + cache[url] = { + status : self.LOADING, + on_load : new Events() + }; + + switch(extension){ + case "jpg": + case "jpeg": + case "jpge": + case "png": + case "webp": + case "gif": + case "tif": + case "tiff": + case "pcx": + case "bmp": + + const image = new Image(); + + cache[url].type = "image"; + cache[url].image = image; + + image.src = url; + image.onload = () => on_item_loaded(url, true); + image.onerror = () => on_item_loaded(url, false); + + break; + default: + + cache[url].type = "unknown"; + cache[url].status = self.ERROR; + on_item_loaded(url, false); + + break; + }; + + }); + + }; + + const angle = this.angle = (x, y, randians) => { + + if(typeof x == "object"){ + + const line = x.push ? { + x : x[0] - y[0], + y : x[1] - y[1] + } : { + x : x.x - y.x, + y : x.y - y.y + }; + + x = line.x; + y = line.y; + + }; + + let angle = Math.asin(y / ((x ** 2) + (y ** 2)) ** .5); + + // if(x >= 0) + // angle += Math.PI / 2; + // else + // angle = (1.5 * Math.PI) - angle; + + return (x >= 0 ? angle + (Math.PI / 2) : ((1.5 * Math.PI) - angle)) * (randians ? 1 : 180 / Math.PI); + }; + + const shadow = (data, context) => { + + const z = dx < dy ? _x : _y; + + if(!data.ok){ + isNaN(data.x) && (data.x = settings(["shadow_x", "x"])); + isNaN(data.y) && (data.y = settings(["shadow_y", "y"])); + !data.color && (data.color = settings(["shadow_color", "color"])); + isNaN(data.blur) && (data.blur = settings(["shadow_blur", "blur"])); + data.ok = true; + }; + + context.shadowOffsetX = z(data.x); + context.shadowOffsetY = z(data.y); + context.shadowColor = data.color; + context.shadowBlur = z(data.blur); + + }; + + const border = (data, context) => { + + if(!data.ok){ + !data.color && (data.color = settings(["border_color", "color"])); + isNaN(data.width) && (data.width = settings(["border_width", "width"])); + data.ok = true; + }; + + context.strokeStyle = data.color; + context.lineWidth = (dx < dy ? _x : _y)(data.width); + + }; + + const components = { + rotate : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + isNaN(data.x) && (data.x = settings(["rotate_x", "x"])); + isNaN(data.y) && (data.y = settings(["rotate_y", "y"])); + isNaN(data.degrees) && (data.degrees = settings(["rotate_degrees", "degrees"])); + data.ok = true; + }; + + // console.log(JSON.stringify(data)); + // console.log(JSON.stringify([_x(data.x + mx), _y(data.y + my)])); + + context.save(); + context.translate(_x(data.x + o.mx), _y(data.y + o.my)); + context.rotate(data.degrees * Math.PI / 180); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }, + image : (data, context, kanvas, o) => { + if(data.ignore) + return; + + !data.ok && !data.source && (data.source = data.src || data.url); + + if(cache[data.source]){ + + if(!data.ok){ + if(cache[data.source] && cache[data.source].status == self.LOADED){ + isNaN(data.swidth) && (data.swidth = cache[data.source].image.width); + isNaN(data.sheight) && (data.sheight = cache[data.source].image.height); + isNaN(data.width) && (data.width = data.swidth); + isNaN(data.height) && (data.height = data.sheight); + }; + isNaN(data.x) && (data.x = settings(["image_x", "x"])); + isNaN(data.y) && (data.y = settings(["image_y", "y"])); + isNaN(data.alpha) && (data.alpha = settings(["image_alpha", "alpha"])); + isNaN(data.sx) && (data.sx = 0); + isNaN(data.sy) && (data.sy = 0); + isNaN(data.mx) && (data.mx = 0); + isNaN(data.my) && (data.my = 0); + data.ok = true; + }; + + if(cache[data.source].status != self.LOADED) + return; + + const half_width = data.width / 2, + half_height = data.height / 2; + + context.save(); + context.globalAlpha = data.alpha; + context.translate(_x(o.mx + data.x + data.mx + half_width), _y(o.my + data.y + data.my + half_height)); + context.rotate(data.rotate * Math.PI / 180); + context.drawImage( + cache[data.source].image, + data.sx, data.sy, data.swidth, data.sheight, + _x(-half_width), _y(-half_height), _x(data.width), _y(data.height) + ); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }else + self.preload_cache_items([data.source]); + + }, + // cache : (data, context, kanvas, o) => { + // if(data.ignore) + // return; + + // context.save(); + + // if(isNaN(data.cache_i)){ + + // const cache_canvas = cache_container.appendChild(document.createElement("canvas")), + // cache_context = cache_canvas.getContext("2d"), + // width = data.width || canvas.width, + // height = data.height || canvas.height; + // image = new Image(); + + // cache_canvas.width = width; + // cache_canvas.height = height; + + // get_new_cache_i(data); + // cache_context.save(); + // // cache_context.translate(_x(-o.mx), _y(-o.my)); + // draw(data.childs, cache_context, {mx : 0, my : 0}); + // image.src = cache_canvas.toDataURL("image/png"); + // cache[data.cache_i] = image; + // cache_context.restore(); + + // cache_canvas.remove(); + + // }; + + // context.drawImage(cache[data.cache_i], 0, 0); + // context.restore(); + + // }, + rectangle : (data, context, kanvas, o) => { + if(data.ignore)return; + + const proportion = canvas.width > canvas.height ? canvas.width / canvas.height : canvas.height / canvas.width; + + if(!data.ok){ + isNaN(data.alpha) && (data.alpha = settings(["rectangle_alpha", "alpha"])); + !data.color && (data.color = settings(["rectangle_color", "color"])); + isNaN(data.x) && (data.x = settings(["rectangle_x", "x"])); + isNaN(data.y) && (data.y = settings(["rectangle_y", "y"])); + isNaN(data.width) && (data.width = proportion * c); + isNaN(data.height) && (data.height = proportion * c); + isNaN(data.mx) && (data.mx = 0); + isNaN(data.my) && (data.my = 0); + data.ok = true; + }; + + context.save(); + data.shadow && (shadow(data.shadow, context)); + context.globalAlpha = data.alpha; + context.fillStyle = data.color; + context.translate(_x(o.mx + data.x + data.mx), _y(o.my + data.y + data.my)); + context.rotate(data.rotate * Math.PI / 180); + context.translate(_x(-data.mx), _y(-data.my)); + context.fillRect(_x(data.x), _y(data.y), _x(data.width), _y(data.height)); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }, + text : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + typeof data.italic != "boolean" && (data.italic = settings(["text_italic", "italic"])); + isNaN(data.bold) && typeof data.bold != "boolean" && (data.bold = settings(["text_bold", "bold"])); + isNaN(data.size) && (data.size = settings(["text_size", "size"])); + data.font && (data.font_family = data.font); + !data.font_family && (data.font_family = settings(["text_font_family", "text_font", "font"])); + !data.align && (data.align = settings(["text_align", "align"])); + isNaN(data.x) && (data.x = settings(["text_x", "x"])); + isNaN(data.y) && (data.y = settings(["text_y", "y"])); + !data.text && (data.text = ""); + isNaN(data.alpha) && (data.alpha = settings(["text_alpha", "alpha"])); + !data.baseline && (data.baseline = settings(["text_baseline", "baseline"])); + data.ok = true; + }; + + context.save(); + data.shadow && (shadow(data.shadow, context)); + context.globalAlpha = data.alpha; + context.textAlign = data.align; + context.textBaseline = data.baseline; + context.font = ( + (data.italic ? "italic " : "") + + (data.bold ? isNaN(data.bold) ? "bold " : data.bold + " " : "") + + (dx < dy ? _x : _y)(data.size) + "px " + + data.font_family + ); + if(data.color){ + context.fillStyle = data.color; + context.fillText(data.text, _x(data.x + mx), _y(data.y + my)); + }; + if(data.border){ + border(data.border, context); + context.strokeText(data.text, _x(data.x + mx), _y(data.y + my)); + }; + context.restore(); + + }, + block : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + isNaN(data.alpha) && (data.alpha = settings(["block_alpha", "alpha"])); + data.ok = true; + }; + + context.save(); + context.globalAlpha = data.alpha; + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + } + }; + + this.add_components = (json, overwrite) => { + if(!json) + return; + + !json.push && (json = [json]); + typeof overwrite != "bool" && (overwrite = settings("overwrite")); + + json.forEach((items) => { + if(!items) + return; + if(items.push) + self.add_components(items, overwrite); + else if(typeof items == "object") + for(let key in items) + (overwrite || !components[key]) && (components[key] = items[key]); + }); + + }; + + this.extends = (object, overwrite) => { + for(const key in self) + (overwrite || object[key] === undefined) && (object[key] = self[key]); + }; + + this.check_mouse = (item, event) => { + + item_self.setAttribute("data-mouse-x", mouse.x = (event.clientX * q * qx / s) - mx); + item_self.setAttribute("data-mouse-y", mouse.y = (event.clientY * q * qy / s) - my); + + execute_event("mouse_move"); + + }; + + const on_event = this.on_event = (name, method, range) => { + + if(typeof method != "function") + return null; + + !events[name] && (events[name] = { + methods : [], + l : 0, + ranges : [] + }); + + let i = 0; + + for(; i < events[name].l; i ++) + if(!events[name].methods[i]) + break; + + events[name].methods[i] = method; + events[name].ranges[i] = range; + events[name].l = events[name].methods.length; + + return i; + }; + + const remove_event = this.remove_event = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l && events[name].methods[i] && (events[name].methods[i] = null); + + const execute_event = this.execute_event = (name, input) => { + + if(events[name] && events[name].l) + for(let i = 0; i < events[name].l; i ++) + events[name].methods[i] && events[name].methods[i](range_analyze(events[name].ranges[i]), input); + + }; + + const event_range = this.event_range = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l ? events[name].ranges[i] : null; + + this.on_mouse_move = (method, range) => on_event("mouse_move", method, range); + this.on_resize = (method, range) => on_event("resize", method, range); + this.on_click = (method, range) => on_event("click", method, range); + this.on_key_down = (method, range) => on_event("key_down", method, range); + this.on_key_up = (method, range) => on_event("key_up", method, range); + + this.remove_mouse_move = i => {remove_event("mouse_move", i);}; + this.remove_resize = i => {remove_event("resize", i);}; + this.remove_click = i => {remove_event("click", i);}; + this.remove_key_down = i => {remove_event("key_down", i);}; + this.remove_key_up = i => {remove_event("key_up", i);}; + + this.range_mouse_move = i => event_range("mouse_move", i); + this.range_resize = i => event_range("resize", i); + this.range_click = i => event_range("click", i); + this.range_key_down = i => event_range("key_down", i); + this.range_key_up = i => event_range("key_up", i); + + this.key_down = (item, event) => execute_event("key_down", {code : event.keyCode}); + this.key_up = (item, event) => execute_event("key_up", {code : event.keyCode}); + + this.get_margins = () => ({x : mx, y : my}); + this.get_position = () => ({x : position.x, y : position.y}); + this.get_cells = () => c; + this.get_canvas_distance = () => ({x : dx, y : dy}); + this.get_cell_size = () => s; + + this.get_real_frames_per_second = () => real_frames_per_seconds; + this.delta_time = () => delta_time; + + construct(); + +}; diff --git a/Public/ecma/version/30311230/Kanvas.ecma.js b/Public/ecma/version/30311230/Kanvas.ecma.js new file mode 100755 index 0000000..7c89766 --- /dev/null +++ b/Public/ecma/version/30311230/Kanvas.ecma.js @@ -0,0 +1,782 @@ +Kanvas = function(input){ + + const self = this, + default_settings = { + quality : 1, + quality_x : 1, + quality_y : 1, + cells : 100, + origin : 5, // Posición origen. Mirar teclado numérico para ver los diferentes valores para cada posición. + frames_per_second : 60, + ratio : null, // Expone la proporción de tamaño del Canvas (16/9 para pantallas WideScreen por ejemplo). Si es equivalente a falso cubrirá todo el área de la capa donde se encuentre. + overwrite : false, + position : "body", + autostart : true, + object_name : "kanvas", + class : "kanvas", + application : "Kanvas", + x : 0, + y : 0, + width : 0, + height : 0, + color : "#000", + blur : 0, + italic : false, + bold : false, + size : 1, + font : "Arial", + align : "left", + alpha : 1, + degrees : 0, + baseline : "Alphabetic", + shadow_x : 0, + shadow_y : 0, + shadow_color : "#000", + shadow_blur : 0, + border_color : "#000", + border_width : 0, + text_italic : false, + text_bold : false, + text_size : 1, + font_family : "Arial", + text_color : "#000", + text_align : "left", + text_alpha : 1, + rotate_x : 0, + rotate_y : 0, + rotate_degrees : 0, + image_x : 0, + image_y : 0, + image_alpha : 1, + rectangle_color : "#000", + rectangle_alpha : 1, + rectangle_x : 0, + rectangle_y : 0, + text_baseline : "Alphabetic", + default_value : null, + hash_alphabet : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", + hash_length : 7 + }, + cache = [], + _screen = {x : 0, y : 0}, + position = {x : 0, y : 0}, + events = {}, + threads = [], + hashes = [], + attributes = { + natives : ["id", "class", "onmousemove", "tabindex", "onkeydown", "onkeyup"] + }; + let q, qx, qy, // Calidad porcentual. + c, // Número de celdas en el lado más corto de la pantalla o área de trabajo rectangular. + fx, fy, // Posición contra el foco. + dx, dy, // Distancia desde los laterales hasta el cuadrado de trabajo. + s, // Tamaño de la celda. Solo se mide un lado pues será cuadrada. + mx, my, // Posición origen del lienzo. + thread = null, + timeout = 0, + last_time = 0, + started = false, + cache_container, context, canvas, + cache_l = 0, + thread_object = null; + + let item_self = this.item_self; + let hash_self = this.hash_self; + let object_name = this.object_name; + let mouse = this.mouse = {x : 0, y : 0}; + + this.map = []; + + const null_or_undefined = this.null_or_undefined = value => value === undefined || value === null; + + const allow_nulls = this.allow_nulls = nulls => typeof nulls == "boolean" ? nulls : settings(["nulls", "allow_nulls"], null, false, false); + + const default_value = this.default_value = (_default, nulls) => _default !== undefined && (nulls || _default !== null) ? _default : settings(["default_value", "default", "by_default"], null, null, true); + + const settings = this.settings = (names, inputs, _default, nulls) => { + if(!names) + return default_value(_default, nulls); + + nulls = allow_nulls(nulls); + + const l = (names.push ? names : names = [names]).length, + m = (inputs = (inputs ? inputs.push ? inputs : [inputs] : []).concat([input, default_settings])).length; + + for(let j = 0; j < m; j ++) + if(typeof inputs[j] == "object") + for(let i = 0; i < l; i ++) + if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) + return inputs[j][names[i]]; + return default_value(_default, nulls); + }; + + const threads_function = () => threads.forEach(thread => thread && thread()); + + const threads_start = this.threads_start = frames_per_second => thread_object === null && (thread_object = setInterval(threads_function, 1000 / (isNaN(frames_per_second) || frames_per_second < 1 ? settings(["frames_per_second", "fps"]) : frames_per_second))); + + const threads_stop = this.threads_stop = () => { + + if(thread_object === null) + return; + + clearInterval(thread_object); + thread_object = null; + + }; + + const threads_add = this.threads_add = callback => { + if(typeof callback != "function") + return null; + + let i = 0; + const l = threads.length; + + for(; i < l; i ++) + if(!threads[i]) + break; + + threads[i] = callback; + + return i; + }; + + const threads_remove = this.threads_remove = i => !isNaN(i) && threads[i] && (threads[i] = null); + + const is_html_object = this.is_html_object = variable => typeof variable == "object" && (variable.tagName || variable.nodeName); + + const preload = this.preload = (selector, callback) => { + if(typeof callback != "function") + return; + + if(!selector){ + callback(null, false, "NO_SELECTOR"); + return; + }; + if(is_html_object(selector)){ + callback(selector, false, "OK"); + return; + }; + if(!selector.substr){ + callback(null, false, "BAD_TYPE"); + return; + }; + + let item; + + try{ + if(item = document.querySelector(selector)){ + callback(item, false, "OK"); + return; + }; + }catch(exception){ + callback(null, false, "BAD_SELECTOR"); + return; + }; + + const timeout = settings(["preload_timeout", "timeout"]), + date = Date.now(); + let preload = threads_add(() => { + if(item = document.querySelector(selector)){ + threads_remove(preload); + callback(item, true, "OK"); + }else if(Date.now() - date > timeout){ + threads_remove(preload); + callback(null, true, "TIMEOUT"); + }; + }); + + }; + + const hash = this.hash = () => { + + let hash, alphabet = settings(["hash_alphabet", "alphabet"]); + const length = settings(["hash_length", "length"]), + l = (alphabet.push ? alphabet : alphabet = alphabet.split("")).length; + + do{ + hash = ""; + while((hash += alphabet[Math.random() * l >> 0]).length < length); + }while( + hashes.includes(hash) || + /^\d/.test(hash) || + document.querySelector("." + hash + ",#" + hash + ",[name=" + hash + "]") + ); + hashes.push(hash); + + return hash; + }; + + const set_attribute = this.set_attribute = (item, custom_attributes) => { + if(!is_html_object(item) || typeof custom_attributes != "object") + return; + + for(const name in custom_attributes) + item.setAttribute((attributes.natives.includes(name) ? "" : "data-") + name.replace(/[^a-z\d-]+/g, "-"), custom_attributes[name]); + + }; + + const construct = () => { + + const custom_attributes = { + natives : settings("attributes_natives") + }; + + for(const key in custom_attributes){ + !attributes[key] && (attributes[key] = []); + (custom_attributes ? custom_attributes.push ? custom_attributes : [custom_attributes] : []).forEach(new_attribute => attributes[key].push(new_attribute)); + }; + + object_name = self.object_name = settings("object_name"); + + settings("autostart") && self.start(); + + }; + + const range_analyze = range => !range || ( + mouse.x >= range.x && mouse.x <= range.x + range.width && + mouse.y >= range.y && mouse.y <= range.y + range.height + ); + + const on_resize_method = screen => { + + if(_screen.x == item_self.offsetWidth && _screen.y == item_self.offsetHeight) + return; + + const width = canvas.width = (_screen.x = item_self.offsetWidth) * q * qx, + height = canvas.height = (_screen.y = item_self.offsetHeight) * q * qy; + + if(width < height){ + s = width / c; + dx = 0; + dy = -(c - (c * height / width)) / 2; + mx = position.x; + my = position.y + dy; + }else{ + s = height / c; + dx = -(c - (c * width / height)) / 2; + dy = 0; + mx = position.x + dx; + my = position.y; + }; + + //resize_methods.forEach((method) => {if(method)method();}); + execute_event("resize"); + + }; + + const position_set = () => { + + const origin = settings("origin"); + + position.x = c * (.5 * ((origin - 1) % 3)); + position.y = c * (1 - (.5 * ((origin - 1) / 3 >> 0))); + + }; + + this.start = () => { + + if(started) + return; + started = true; + + q = settings(["quality", "q"]); + qx = settings(["quality_x", "qx"]); + qy = settings(["quality_y", "qy"]); + timeout = 1000 / settings("frames_per_second"); + c = settings("cells"); + position_set(); + threads_start(); + + preload(settings("position"), (position, asynchronous, error) => { + + if(!position){ + console.error("ERROR. Position HTML for install GUI CANVAS is bad. [" + error + "]"); + return; + }; + + const _class = (hash_self = self.hash_self = hash()) + " " + settings("class"); + + !new RegExp("\\b" + default_settings.class + "\\b").test(_class) && (_class += " " + default_settings.class); + + set_attribute(item_self = self.item_self = position.appendChild(document.createElement("div")), { + id : hash_self, + hash : hash_self, + class : _class, + application : default_settings.application, + onmousemove : object_name + ".check_mouse(this, event);", + tabindex : 0, + onkeydown : object_name + ".key_down(this, event);", + onkeyup : object_name + ".key_up(this, event);" + }); + set_attribute(cache_container = item_self.appendChild(document.createElement("div")), { + class : "cache" + }); + set_attribute(canvas = item_self.appendChild(document.createElement("canvas")), { + class : "canvas" + }); + context = canvas.getContext("2d"); + + thread = threads_add(thread_method); + on_resize_thread = threads_add(on_resize_method); + item_self.onclick = () => execute_event("click"); + + }); + + }; + + // o = Origin {mx, my} + const draw = this.draw = (map, context, o) => map && map.forEach((level, i) => level && (level.push && draw(level, context, o || {mx : mx, my : my}) || (level.type && components[level.type] && components[level.type](level, context, self, o || {mx : mx, my : my})))); + + const refresh_draw = () => { + + if(!context) + return; + + context.clearRect(0, 0, canvas.width, canvas.height); + draw(self.map, context); + + }; + + const thread_method = () => { + + const date = Date.now(); + + if(date - last_time < timeout) + return; + last_time = date; + + refresh_draw(); + + }; + + // Establecer posición sobre el foco de origen. + // Establecer posición sobre los laterales del recuadro o área de trabajo. + const value = this.value = (value, quality) => q * value * (quality || 1); + // const _x = this._x = value => q * qx * value * s; + // const _y = this._y = value => q * qy * value * s; + const _x = this._x = value => value * s; + const _y = this._y = value => value * s; + + this.cache_set = item => { + + let i = 0; + + for(; i < cache_l; i ++) + if(cache[i] === null) + break; + + cache[i] = item; + cache_l = cache.length; + + return i; + }; + + const get_new_cache_i = item => item.cache_i = self.cache_set(true); + + this.cache_clean = i => !isNaN(i) && i >= 0 && i < cache.length && cache[i] !== null && (cache[i] = null); + + const preload_cache_items = (items, callback_per_item, callback, i) => { + + if(i >= items.length){ + typeof callback == "function" && callback(); + return; + }; + + const end = () => { + typeof callback_per_item == "function" && callback_per_item(i, items[i]); + preload_cache_items(items, callback_per_item, callback, i + 1); + }; + + if(!items[i]){ + end(); + return; + }; + + switch(items[i].type){ + case "image": + + const source = items[i].source || items[i].value; + + if(!source){ + end(); + return; + }; + + const image = new Image(); + + image.src = source; + image.crossOrigin = "anonymous"; + image.onload = () => { + items[i].cache_i = self.cache_set(image); + // console.log([items[i], items[i].source || items[i].value, cache[items[i].cache_i]]); + end(); + }; + image.onerror = end; + + break; + default: + items[i].cache_i = self.cache_set(image); + end(); + break; + }; + + }; + + this.preload_cache_items = (items, callback_per_item, callback) => { + + if(!items){ + typeof callback == "function" && callback(); + return; + }; + !items.pus && (items = [items]); + + preload_cache_items(items, callback_per_item, callback, 0); + + }; + + const angle = this.angle = (x, y, randians) => { + + if(typeof x == "object"){ + + const line = x.push ? { + x : x[0] - y[0], + y : x[1] - y[1] + } : { + x : x.x - y.x, + y : x.y - y.y + }; + + x = line.x; + y = line.y; + + }; + + let angle = Math.asin(y / ((x ** 2) + (y ** 2)) ** .5); + + // if(x >= 0) + // angle += Math.PI / 2; + // else + // angle = (1.5 * Math.PI) - angle; + + return (x >= 0 ? angle + (Math.PI / 2) : ((1.5 * Math.PI) - angle)) * (randians ? 1 : 180 / Math.PI); + }; + + const shadow = (data, context) => { + + const z = dx < dy ? _x : _y; + + if(!data.ok){ + isNaN(data.x) && (data.x = settings(["shadow_x", "x"])); + isNaN(data.y) && (data.y = settings(["shadow_y", "y"])); + !data.color && (data.color = settings(["shadow_color", "color"])); + isNaN(data.blur) && (data.blur = settings(["shadow_blur", "blur"])); + data.ok = true; + }; + + context.shadowOffsetX = z(data.x); + context.shadowOffsetY = z(data.y); + context.shadowColor = data.color; + context.shadowBlur = z(data.blur); + + }; + + const border = (data, context) => { + + if(!data.ok){ + !data.color && (data.color = settings(["border_color", "color"])); + isNaN(data.width) && (data.width = settings(["border_width", "width"])); + data.ok = true; + }; + + context.strokeStyle = data.color; + context.lineWidth = (dx < dy ? _x : _y)(data.width); + + }; + + const components = { + rotate : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + isNaN(data.x) && (data.x = settings(["rotate_x", "x"])); + isNaN(data.y) && (data.y = settings(["rotate_y", "y"])); + isNaN(data.degrees) && (data.degrees = settings(["rotate_degrees", "degrees"])); + data.ok = true; + }; + + // console.log(JSON.stringify(data)); + // console.log(JSON.stringify([_x(data.x + mx), _y(data.y + my)])); + + context.save(); + context.translate(_x(data.x + o.mx), _y(data.y + o.my)); + context.rotate(data.degrees * Math.PI / 180); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }, + image : (data, context, kanvas, o) => { + if(data.ignore) + return; + + const draw_image = () => { + + if(!data.ok){ + isNaN(data.swidth) && (data.swidth = cache[data.cache_i].width); + isNaN(data.sheight) && (data.sheight = cache[data.cache_i].height); + isNaN(data.width) && (data.width = data.swidth); + isNaN(data.height) && (data.height = data.sheight); + isNaN(data.x) && (data.x = settings(["image_x", "x"])); + isNaN(data.y) && (data.y = settings(["image_y", "y"])); + isNaN(data.alpha) && (data.alpha = settings(["image_alpha", "alpha"])); + isNaN(data.sx) && (data.sx = 0); + isNaN(data.sy) && (data.sy = 0); + isNaN(data.mx) && (data.mx = 0); + isNaN(data.my) && (data.my = 0); + data.ok = true; + }; + + const half_width = data.width / 2, + half_height = data.height / 2; + + context.save(); + context.globalAlpha = data.alpha; + context.translate(_x(o.mx + data.x + data.mx + half_width), _y(o.my + data.y + data.my + half_height)); + context.rotate(data.rotate * Math.PI / 180); + context.drawImage( + cache[data.cache_i], + data.sx, data.sy, data.swidth, data.sheight, + _x(-half_width), _y(-half_height), _x(data.width), _y(data.height) + ); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }; + + if(isNaN(data.cache_i)){ + + const i = get_new_cache_i(data); + + cache[i] = new Image(); + cache[i].src = data.source || data.image; + cache[i].crossOrigin = "anonymous"; + cache[i].onload = draw_image; + + }else + draw_image(); + + }, + cache : (data, context, kanvas, o) => { + if(data.ignore) + return; + + context.save(); + + if(isNaN(data.cache_i)){ + + const cache_canvas = cache_container.appendChild(document.createElement("canvas")), + cache_context = cache_canvas.getContext("2d"), + width = data.width || canvas.width, + height = data.height || canvas.height; + image = new Image(); + + cache_canvas.width = width; + cache_canvas.height = height; + + get_new_cache_i(data); + cache_context.save(); + // cache_context.translate(_x(-o.mx), _y(-o.my)); + draw(data.childs, cache_context, {mx : 0, my : 0}); + image.src = cache_canvas.toDataURL("image/png"); + cache[data.cache_i] = image; + cache_context.restore(); + + cache_canvas.remove(); + + }; + + context.drawImage(cache[data.cache_i], 0, 0); + context.restore(); + + }, + rectangle : (data, context, kanvas, o) => { + if(data.ignore)return; + + const proportion = canvas.width > canvas.height ? canvas.width / canvas.height : canvas.height / canvas.width; + + if(!data.ok){ + isNaN(data.alpha) && (data.alpha = settings(["rectangle_alpha", "alpha"])); + !data.color && (data.color = settings(["rectangle_color", "color"])); + isNaN(data.x) && (data.x = settings(["rectangle_x", "x"])); + isNaN(data.y) && (data.y = settings(["rectangle_y", "y"])); + isNaN(data.width) && (data.width = proportion * c); + isNaN(data.height) && (data.height = proportion * c); + isNaN(data.mx) && (data.mx = 0); + isNaN(data.my) && (data.my = 0); + data.ok = true; + }; + + context.save(); + data.shadow && (shadow(data.shadow, context)); + context.globalAlpha = data.alpha; + context.fillStyle = data.color; + context.translate(_x(o.mx + data.x + data.mx), _y(o.my + data.y + data.my)); + context.rotate(data.rotate * Math.PI / 180); + context.translate(_x(-data.mx), _y(-data.my)); + context.fillRect(_x(data.x), _y(data.y), _x(data.width), _y(data.height)); + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + }, + text : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + typeof data.italic != "boolean" && (data.italic = settings(["text_italic", "italic"])); + isNaN(data.bold) && typeof data.bold != "boolean" && (data.bold = settings(["text_bold", "bold"])); + isNaN(data.size) && (data.size = settings(["text_size", "size"])); + data.font && (data.font_family = data.font); + !data.font_family && (data.font_family = settings(["text_font_family", "text_font", "font"])); + !data.align && (data.align = settings(["text_align", "align"])); + isNaN(data.x) && (data.x = settings(["text_x", "x"])); + isNaN(data.y) && (data.y = settings(["text_y", "y"])); + !data.text && (data.text = ""); + isNaN(data.alpha) && (data.alpha = settings(["text_alpha", "alpha"])); + !data.baseline && (data.baseline = settings(["text_baseline", "baseline"])); + data.ok = true; + }; + + context.save(); + data.shadow && (shadow(data.shadow, context)); + context.globalAlpha = data.alpha; + context.textAlign = data.align; + context.textBaseline = data.baseline; + context.font = ( + (data.italic ? "italic " : "") + + (data.bold ? isNaN(data.bold) ? "bold " : data.bold + " " : "") + + (dx < dy ? _x : _y)(data.size) + "px " + + data.font_family + ); + if(data.color){ + context.fillStyle = data.color; + context.fillText(data.text, _x(data.x + mx), _y(data.y + my)); + }; + if(data.border){ + border(data.border, context); + context.strokeText(data.text, _x(data.x + mx), _y(data.y + my)); + }; + context.restore(); + + }, + block : (data, context, kanvas, o) => { + if(data.ignore) + return; + + if(!data.ok){ + isNaN(data.alpha) && (data.alpha = settings(["block_alpha", "alpha"])); + data.ok = true; + }; + + context.save(); + context.globalAlpha = data.alpha; + draw(data.childs, context, {mx : 0, my : 0}); + context.restore(); + + } + }; + + this.add_components = (json, overwrite) => { + if(!json) + return; + + !json.push && (json = [json]); + typeof overwrite != "bool" && (overwrite = settings("overwrite")); + + json.forEach((items) => { + if(!items) + return; + if(items.push) + self.add_components(items, overwrite); + else if(typeof items == "object") + for(let key in items) + (overwrite || !components[key]) && (components[key] = items[key]); + }); + + }; + + this.check_mouse = (item, event) => { + + item_self.setAttribute("data-mouse-x", mouse.x = (event.clientX * q * qx / s) - mx); + item_self.setAttribute("data-mouse-y", mouse.y = (event.clientY * q * qy / s) - my); + + execute_event("mouse_move"); + + }; + + const on_event = this.on_event = (name, method, range) => { + + if(typeof method != "function") + return null; + + !events[name] && (events[name] = { + methods : [], + l : 0, + ranges : [] + }); + + let i = 0; + + for(; i < events[name].l; i ++) + if(!events[name].methods[i]) + break; + + events[name].methods[i] = method; + events[name].ranges[i] = range; + events[name].l = events[name].methods.length; + + return i; + }; + + const remove_event = this.remove_event = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l && events[name].methods[i] && (events[name].methods[i] = null); + + const execute_event = this.execute_event = (name, input) => { + + if(events[name] && events[name].l) + for(let i = 0; i < events[name].l; i ++) + events[name].methods[i] && events[name].methods[i](range_analyze(events[name].ranges[i]), input); + + }; + + const event_range = this.event_range = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l ? events[name].ranges[i] : null; + + this.on_mouse_move = (method, range) => on_event("mouse_move", method, range); + this.on_resize = (method, range) => on_event("resize", method, range); + this.on_click = (method, range) => on_event("click", method, range); + this.on_key_down = (method, range) => on_event("key_down", method, range); + this.on_key_up = (method, range) => on_event("key_up", method, range); + + this.remove_mouse_move = i => {remove_event("mouse_move", i);}; + this.remove_resize = i => {remove_event("resize", i);}; + this.remove_click = i => {remove_event("click", i);}; + this.remove_key_down = i => {remove_event("key_down", i);}; + this.remove_key_up = i => {remove_event("key_up", i);}; + + this.range_mouse_move = i => event_range("mouse_move", i); + this.range_resize = i => event_range("resize", i); + this.range_click = i => event_range("click", i); + this.range_key_down = i => event_range("key_down", i); + this.range_key_up = i => event_range("key_up", i); + + this.key_down = (item, event) => execute_event("key_down", {code : event.keyCode}); + this.key_up = (item, event) => execute_event("key_up", {code : event.keyCode}); + + this.get_margins = () => {return {x : mx, y : my};}; + this.get_position = () => {return {x : position.x, y : position.y};}; + this.get_cells = () => c; + this.get_canvas_distance = () => {return {x : dx, y : dy};}; + this.get_cell_size = () => s; + + construct(); + +}; diff --git a/Public/git_update.php b/Public/git_update.php new file mode 100755 index 0000000..0879a28 --- /dev/null +++ b/Public/git_update.php @@ -0,0 +1,4 @@ +&1"); diff --git a/Public/images/kanvas-180.png b/Public/images/kanvas-180.png new file mode 100755 index 0000000000000000000000000000000000000000..986d9ce1b2608831744ca5350bebaffc95d7f233 GIT binary patch literal 27799 zcmeFYbyVC&Nv5di=IvaF1R8u)L+pEo=#__yFFEE@no z)9j<6?WShp33PICw6L}_2fBGXnFGzetStZlucgsU9S@3@7>T!*FU` 3?tyN5z6o-8n@ZGxPk4aP#kUuuU(fr(Z_Zp4wx)EP&6$jWrjetb0VTH& z(`O$nw_kkTqV6BL@3zlIpM<>vu 5qMz zFv7XKasM=bw(jtL#TBa65a+1+9n9O0E8EZ8?)xh?5BKoZcZ*k#cdf|J>j&~kefvoU z5q{BYUlRy~KRBA1tZV&nyjDDu-#!r&er@*lEwxk(fWtX{Im*$5eOdoJb~o}NV9))T zUbuMTbbj89K%pPwzNP*4wy{+B>8gG TllbUF^;Egd!K(SR zl`SxG6qdT;IrnGu&*Yla`>DEVlvkzs%wI{rB%Ad;f1Nz}{}{x`U+*|yeX_183D9Ac zx?&&rt{S*{0RvU7!g||F3HkHp%+~p?>155}hfPZD@P*ph_tfWYqc_gL$8J}%ZeG3h zyD#qE-bCd!C|AD;n0v@h+qgJakprHd9%7I2Ym9#^>w9-Pgn2WuCOrLW>E?9X_#APj zjMiFbh+`c2-QARx$rvKTK!&OQ+m^p`OmqcqNxd7%Hxlj6!X2E*Yu1n`=WvtLQQt4E z%r}F=KVgx?IYJCjV3yH>aq0U*-jcL0^0LLg&=zLOm6aA|i))4K>es0>rl^?8Ql_Yt z(N Dp9Q-tOrE+||j6_3SHe#uWKKoVK-I1+RsXnDoX=5u49UjvQd#r8yU+ zS*E!+Ev6Wmp#P$;t~;_RcWibpB=TJHPBHLYe%Y|0&h(lZEKXHd=6_kWVXhB&c*4 PslucL(B z6YR{N6XV;wI_%Pa_eRi~rdGZB{5IzzRrDl2?BBTTsih}3ex-YiAZ}lVEU`Yg$%Em0 zwi5Lmzp~|=nM3YqhwbZ_r!;Mc%T>{`aFd@)M6J+_a_179Gp##uX8ZdiRx pL`Mg&{ zR`=V@_$Gq Lg$s)zkEpWlOd*4=#~l z-{?*)2ZI2N2z(a|M~xKfZ^p40V^FpOx96w2(q)akyiTt&JIy6TEZ$+$=hf48#AccJ z-x*Ui$s)^lRP{oceFe)eF5YL$pgKGyjS6t{R{F4eBw|`q)}Hut--A+){CPLorqGWt zTy*F6@|JH+cH80eNo|^+l =;dxt*zAJW`qAdRnaOn zkBoODA`-Le+*qo~)!Kr~!8A1LKOhiZ?n{W~aa(&lIX#2!=*RPUq;4_}MK0&lFwzH{ z%~^6eo9g4$4LH9GH&MXT<^nI7?`oK!weu5{v)$o+lY&m^%Oj _tBH}yf?`D|Z|fba0|i!3rtFW0}7TZZ`k@E*rC z)jODtP;RxBHkx*4Ani-ca$}{)!W_nhQ_(M@;7d}y<*zcXGpRqK?4PCLbbNpuXv#l; zPlftS<8%|>iN)PZ1<;}iJA}iA <4 z+F8JzQnDsHc^xgn!$LLpY=8c}6Rks5liozR1DH~`G<$$hYC1 zh_O~8KRDg(&Udlb1ZlXxdl@kKgBgaYRjiP^4fNMWGbDy?%P&Wc85@Y?3nsB&RrgBc zl+oUM?T)&8cMoI!%9e@nKE=qL)+^YkS-gxZ$s8xc6y-w1?kC00Oh&u2jaHx # zSL;qo5~J}Iq%g`pD++k*+dpGL_AuL$wC)jsC596hQ}6WW!-IQ>Xm3GV>^s61wEDT& z9F-E4v~wUKEKJUWV)60Vgog(2Hb)MsU|2L@L_(5y5WpfqHYA1ER3rPlrg3E;1r|>J z*if;C$uA@9EFTR9=I4qRBr1QTdj(dzlyL S? ziXR0=Ale$$kzJD*UY^i*r1m|Zzgua$)Id`Y-xSgLNTaB=Bv2AXL07|^Tpp|x4lM%s zps*YluUb~xe|!Pj^u`G?UES!zUf716?bGNq4u%FfK@GUf)3Z4zeNum5>DupVJv_ff zt|UWSFrBfd^!ge}LG`+5#OxSkN?tW_YM?TsGav3T^EqT8H_nylCm`0P>`_@e-pL6g z1}K$W&f`MC(>u-NWk+3T{_ggejvpqWyafnfPHI8Q1@TNoE~2Ro9S9Gq6*87y7Q=v@ zHExs90u*2mm-nUKWy3nui^Ss<;0FwlSc@LBPb!T8q4_afo0Ga?RKoj0 !Y3#DKJk zn{WDzGqVRfVW2Stx`N0fof}0tms>VL0Wii9VX4seEkUYojzZrJBu$W%pdpsKYax9g z(=xVDdKVIE2Gb4yi#D-(!*^<_NLv7*^lC(432o8XmFU@jKQm>hc2#^W0y0uYsS<%V zMXm;7XL}O3)9Ys-D*K`N7WPaWR!p3Y_gM@AZ Z5no(4lvTX=#>LqbYi zKg|p%C2LJE_ i}VGwFj5-`KvYZuk2fB9yBK$hmqgKgi@6a)hn?K!IWBPB&xJ08f2aK|c)`Pc znxD7e+l@iO!-77i 57K<-BpZq#SB=k_T>mY0y`I$Qg>oFsU(lAV9SxCJIn8>7u7IJ$JkaPjYJ3|b? zaKVy!hCwPdd9Hd2;o;W4L(SoeBaNnsi3(b$L%@+%aZ f|iqMLb}rM?wRVHyfr15id-LGG2G;Cz}xK=gz$ -$B@A8 zEPWy-+})paZef(P=Jjc02P+s0!tbKSOIp%3$!-&52V(tqtv`lgs3+7|Gab|(DNLfy zAhX2A9VV}!@B=Ierih*s0DaNwRRG}-=q=!3XOX@hipmh49W=vgnZv=r4}4k0^P3+S zcOn*c5xQ%n_nV&^qh&(VAXwTw!+Lk#SCGaDuJI8d6?GdKZ+$D;V80V?A|;Lxi8}ny zlug|jL|BLOB{)YEvr9PMCI9k@Mlg|FRmkklnE5KAfJ?>?hS}E`s>^NaJ8_6Y$hNU_ z@}}+w*O6pn;~{=$BDb$e0XfITRta+aXb{9Wi+gR9Wwn8m!<7plb;MI3-~sZ|G&+2U z@k$4tVFhuz>kh{V@iiDXm;;?E`x&+r?V;5rOz#|Wvx}-YYTyf EBx~=ItWzADK{3VI_&oO4$=t~;cq9M@KUhu@A zpBT&U-lW)|m=axgAE^YD>SlB~>)8T}FZl$L>}r|rHRDMW7=!ssenF{c>9u@ug5DrY z8-^uEM`SXY5D%#jBI=?PSy 7Lq7hRlg_pf5)uBhwFGAnxchhL?m=bpijKFXTiki@%meRyvg$_(~Z&0*u*^(VO zD}ubj@{=aQH@(A| coC}i1TgKlMuyF4cI?iT-^(#UgQ322S3X)0tI zGYY(Jq<5m2k-|$DXd`hJlcC+OUq?O;(t)YX Q-11~RXvwSnN_mMC$F9{i6=my7nM_NUixx3K&pw!o$ERrL z)roja1V2=nhPM72G>YFUf^(5TrpWUSMV3sGcq3ArQz4i;R~+y)qJjn#4A9QC-R4YL z^OX)0!oeNI8G7F84#uuE(ah>#*>f~B>&P4FjHSw$cqmg!$dHGla*WJf!-fmNt!pM- zqkwZ@ckPLVG M?t{JB-XO5rq$0!I~oB0qE3LbsvbuF-K-2cQR` zcwTid;gnj3Hn%o+QU-{33bKgIgKnD73muAaVHE&89zkow-8M!;d2@D _USgjOu0U{Hm-%$Rt*m7d zWtJb46+h+pfL)j zsg_Ayd1h&Ykk=UoytrznPht8X!tUG&D~knux!l>F(QK?xfUpG1Z|Z}=yl@0f2n(2s zWi>sx4oI_*dbEHg!|B!OLBZy{@Fd(gv?;HY^garF?wZc QP~!`pWFS9xrM=BZ>mkoH>q0xsR9+)EB~2kH_99_C7%Ffl;C+LoLoh6Y`9((7v> z{#r=dPDN30gJ7I;x` g)>aXhqi`A8C?7?A~& zxj#I#vZXL;S~=90dh4COq+Md7;KmY4zXa3QZ#%z&^;Ny@L#VP!y2W{JkDESbf7AQO zpR(ICy1(uYvDVQOQ+5u4%oY*Qi>4N~kT~|Ku!$!Hal|J5BISVQ+wr-cSK2Q#4PF(d zxqCDPBnHvxo_doZxX~RI8<`Q6963%c#^%jkm5s9CvghI53$j$fg7z;NI%-J+n<@`A ztBCbzlnggGXpsj%O>zj0CQ@2@!`g7_T-NiZTq)16F`R@QtbDt&uF_1LGkYS~ND|N4 z0nM91ZP#*KqI4$MZml5fOZwOI!e*-ut>IUL+L5;6*R|Fkj_qRcXyOvLg$U>F_wfb? zI-P3X1;M-FVH0uuN-(VN2k@l)fr7MpkjfY*I}njWZ};!v9a2IUICvMl1o_m&0y~rI zsmnyti>s1GRQs?EvGOwYImm@Lx)7x86x*d6b$Yk6U=_pDO7JSWzOk%-ZM7_&%I6ZC zKbA|ub&xujt~A3?jK#PqR|c?bX@QUg1Ziwnwm7bzoJ3r@71@}(g5jkEdzSF ~(N-DRpO6A;XpbwY5wEY7R l1z#(4QLWW(67nRc3-nl{W3E7xFVWgWRUFK#LCEjv^yR0V-G0 z6;g|c8EpjEQad>0Bf^_g+coTgw2H`kq}B*zJ#0jWadFa1G|Z7RNNs(QWN`ij&IHi& zGc>RfAjr4EdWZ_--p?NVXG}YJE 24cX_xhDL`#B?A5{_D3cSeLCT|OxR=AFPgp9C?Q zZS2S8Cd+FlZ+!*m2#sVQBQ(v1?F+s eNDzYKp zaUYz5>xVcED 5-qq-+D6>)u? zFe@hhZC|3t8S(gI1KwYg84w?wZNx9BfE`ahN;KGyjPo uqjTOqI+X!}jzcI8J4C X!h!dSWNqy<4( z7<-DCiqLEVe!LU5vLizNDr*n(JRhI%UNu=lcmz(|#vkPOUQu&XRTJZOp;_rPX n85#Okg$ZyS>r0Y}^f&|P9do|2=(fE_{qA=`= zn Bmlu OZ6g%HgCJX$>*~i)BP5gq=~oZ+6HE z3e9uiLS{`zIe!4TyJ62!y)Y_I?8V6rBQt2Gb?|2qn%r?744-1OFi31If69j@ajQXh z!bK_|ZAP>avy#$e8?511YLZ3wwoZ^2JTAaw9W75UorZy2l* k>Y<$8`^hQO>?9Jqx30!D6X1Dak=94G~Cjl+tkmJe{8<*TbyJ0E@PfwyX zRt>K}syj_`J vuxdO9x>yNKLDr&2KwEJr zWxW$IfOlS=x5 pQjw?niUKJyYZ1fsM`TOrC?a$L!mox$NR8lu3fv8uxzVlUzl zM$rHhkR53^X|z27=>mR{SO5psgGn8f=WpoCP^74Di;Zy>Z*fV3YZdUOQyjVBfUq7h z#_C@mX4N4$kc>)UE&($(ji_>IgX!`u%P&mwd>9(||5^T4Gy;y1rZ@u(syTdQC z5gR91v<&gxRLVi?@n`Pd?E`z2oC=B93gjBqN~fXiM6-plQiA?QE+q}!SvgelRxI%x zExqfm8;UGgyz>CUXhf?6%&IEPFEB#LlXJIZxF0Sfqn0vbR3RwhG&rLs>bLys1E3YI z=qV`mA3HdcJzUjJKB=^Y!PfpT{gEi|eOmT#T=WTQ=k=>Pa9j@y=FT`}7BaJ$Z2vS> zB$xr_x+^G(2sdBt!dA-hhxJ7C%TW^2#ug6iAqA9n)OBTK ^f&;?TL?^rzlQSrC`D&{wtU5F>BS)>!GM5LOM_-pk^^++Ulh zOA|lsG&3B1W{0LUvz{<|uj2917T9LXPE=80K2S!Q^T2OrLru|klX@~K<8PabCi2N< zk|s2MXqUj7L`oSdKr)7u+Q2}Mey?>|2XX-b6D5QDQL>h My6GpVX-kDlL!!r|EW2ikxFtW=hpJXyF&xA_F1VH2mBM9t>ZY4XCApk&EuJs7 ze@C)zGFL&5f?^Jh;N$AFKJrs0S&a_oJJK59?YT6q3?*@(n@l?t z%o1kp%;!mE^esw--Et*UB;?L&{)rFJpV^q 2dEV z^Qr5l1k%L*5KjL*7NZGlnh&tNee4tYprn~W$T;ay|K!3VbcyotR%XQyoR`siU(YNB zGz2q}1?Y2;4SleoE!NPP!U$XP?Od#(@k7cy$s5bnC6A(vuvGG>6&2sj4J&u=m-O>p zI82Ie{noR_#_h%#U`D+bSrDbTO!E7ctTRh&k^+(K5sO}-SviKI?>OiR^>XA+SxslC z83?4E`P71?N)*t>u5|P{Xt02o!;$(&T*`qo>N)hRY=vRR6*rd9RU>xl3 2}&>NQY$ZvT%&}D1e3QZ0Y}ESTepd{Dk9FIZ!zUx7$zW0 zCG9nC))OtxPmjCP_p&|b;P8>G+cf#=FsEuc`w-hdsU97Zsb>4kaqyuu)-dILqirr@ z4YGC3H*6cm`{3-r*oYKw9AGWr;O6(k$vZsVC*%=2c=eP=!6=9RYH$7Po-p^Wuw7FF zRhdTq#F4L^Q(nzS%9ApQt(Z{udG%m>&jqP{Z #bUzup=vwZbiTX(%JHouR_P4!614*T*FFT~qEX>?!Gq5N z;ycLg8d8<=M}es|TWGxt6z})5YU^dbbA^LnSD7o8 }{ZwgtcJp*4 z)lmdKk+DQvd6=v2PAC9TXZYK=w *K*LqFm767&T3`RYEnYw4)oWNKoI zdu3?_XhVMAhz#u=ZE^puR}M5ffbJLbANgU@S~kR8Z4;%ifgf@o6EXfkXf~CZfm62w zW2T-JiY6g~cu%x!Elt#H|NDKRSECFoFM2u`hddx}`RUfO_0e)i!ab&|9$~O$^^Tv4 zvipm`)m63(jc6gv{bmwj=6Ej4qU~=`D9yHpB7vr@8wwPx=N!@1;{9q)BTyCI bXY37vomw@k+b{`@gvoaZ3IX>B*rnFU2O3{UsH+><|Z~n$>dH`5qMVe zsnwxzp|pB$6>r>m#d>;9fa!y{3NeRrsDPAaVZ3eUm-J=j_=y=BV!ocq_#?eNNjO_w zrWG#K^Wr<%WVq_Gh96Qp-)Zd$Ir7R5Et`f8w3SH-FM_|}5nU3DRH6rEd@s}7A_Fmf zaBB#9UubQ@@oT@wbFa0jk9+^D!*>+*lg-{TrWYlDa;GhFRu(GRdCOh}SESMO<%I8V z7`))Ha&*=m&N@; u_9Nb(CZu` 7{n0T}Yh=zFy76 zJe+$q8tqFKo0sW95+p4U^Qya72hYn>c!DeqqRbo_tT(dUK(^-HIigru@V7wPUc|8d z^X{p` =KL6|&;$&{g3Ozzm DI zZKejKAQX5tQb~>uG~@FO(LHXhSPgB=^hvv*k!`$)eBq nB*(I{Lo>thtzRv}cDlIupgCr<6%oiSDlRW;@8z0aKChulCB);cBX za+pD1ZL?Ivlg6T{WX)=pa(i|T`+omBtadVV^HpnW#lsP!ncM1+m2u0|0)fT*!f_Ua zNA28}y2(;h|F5yFk~^fva^PnN+w6uUW;Nr#&5&+ia6bj?^Io?=R4XF~nWXNULCtlL z^wff%$DJ0#ZupHC!$y_HvKm`nv%)rq6rr-=o{^a4PP6X?#E7=!m;u+W{NhCA#^LbV z7>{(OY(?h+nkig`7-UI4I^o=$Bvklg7t;1C51XnMwFNHq*y`xc*vkG~FANmY?tQ)* zB&$iiy2|RJ=KNK#Kk<++==K8(&`WKCjIwDNk=|;JhU3n(Ixd8`F`ol%9Pms7fO!6e z`CCqr>%G4kf<9GqL5tf$uBJMnmY^V^%!@;vj0V5|SPeUVm7K(O9$i6JfvefM+DAJQ zsFVE7unp2DwTZU59;~8v@+qm4 LBK{YB#T8bG(5Ti`TSdEL*a*L#jF>{!Mz^j#wDi zWjVfCy6iUs>St fPH&m*BFxI2|CJ}9@|GT4?%{GZ5K8fB|7b_^C!L_q_jVx@vEqw|?t0EEVP7_+ zNgp$DZ}3eb{0dp5sw^Jq;XyYmaaQX%k{f- z4hmYPm|)v3@ZqHFQ)GP=N>woM9%5^6ui$`;@|BskA^c+FJIUFp;OQE~nok<7)Gwag zlA`P=$ YUAhwpV&m{#0E z-bzzc-)>VTG?i4P5~3!aJ`C=S)lVS|*w(LE9A+2y;p0^%B*R9uXJ}-lKSI2C@2st* zF?44^_?6euS!+mhu8lg-gr&Hu;JcD5JSzif3^cS%$+r+T1qmxnS=P9Mmy*c9iCgLc z%J_0 |0uw#L9S|j#hKZ#O(vkjazoDkf!^Kt zHt||l{v8QK`*LTWyL{qp&@hqlhAgK0 6KiR&7NEJ~KyqCKHgOsX3FE zy%X3s0004DFDDZ-TXQ#{skx=KgCN;i>rXPEHAs-`1E(U3qLa9}m9>nIi@Cawl7^X& ztr;(fOjrm}z>5zIU~leb0`#)Cb8zMJ5+wTzmk<2;Pd76e@GlWJTR}2yMHQg9ql-C^ zgNcKQg;CPW+JlWu2oWgY0 FLSj$ RboF*{Gx1_{a3%i(@ed3Mb5}DLutQrrIspG*nwUDey9tt!fu95a3I503 zCB49%{~X{?`!9G`HxRQdxWNHl4_JVijfI7Wk%f(sjhFfF`rxOEivQAfaQ&wh!S-bK zGI3&NWny8rxBm|su5OYZ|32P-s^O{uzD&%lX71|f?qX&x>0$2RM*jCfo$TCQ|30R> ztNEX J>aUUit|Kk0sPZqJKW4PFws-nVtpDyPw@V^YjC*f%3{s%=?LXhmw1o%LXX4W9Szdo{Yvs H$YILK&S=8MW6Ee^Va{T~W5L70!o&MF2xS**uxp#x{e4z{pg>?K4o;96 z8>^W)BNwYV2O|d;2*k+C%gM&b!p?4L!C}hF&24V>7t|la@` H6=&8rJsa>TV`~%*M*a#sOY8D=!Bx3l}TPKPLB=zLvR*E7))U zpt7 R|FBbLxk`wrcW6FSa9bLTtHom&K^FLbu z;1WCQzf1)L{uRG`CT4%EC`jgN;$aT@YYV`3{Kq3RD-#Dxb1+f QwtCWBQKj7mjx@Q87Bv)`F})rb+mBvG;uK(wFHL|c%Q*R z^w&NEY5wVFwEt1w)5`ph6S1(dGO} ^Xxf8_qA|4$$NU#b6H>>t|Vj!xd-Xti=v z_H_6!hyPCm|AC-jZD#J^>iAzx{qG|GFw5UE2zbu_=mTdaaH3=WSEl=?m;4E&|BJ7G zdf)%W5x~&@Gsu6-zW-yc|1sBp%L4x`;s5cj|1sBp%L4x`;s5cj|6}Gt{P$Yf+yQ*< z^8{DII!#(5;3^u{R9;#F@b>2?x4k$K+=JjGqvHwyFp>XxLwFSmdw@IP++-Cc;dWuM z5c#<>C8K|XyYSp3wcW%W?f+CufPbFWfu7cGR=__;`wt&cZ~y=xKvqIj!)xipz|%`( z_SPUV1cQ%8^1TEEx);YgAh0hiS7sVMSPm2Vkmi0%JP Fi7AORX-ssQ05 zAg_0VG!`Q`&X77y=clmC*mqYvmN+ii(}#|i_?DiL72mNRPp9?6OV|m34TMf8fa>=! z0swu``vf;v*Wo$lvxz(?F8d|un|8_Bwq@g(3Y2$28~|DDglqsdWC?1g10+5+fE?nu zPMcxzao3}j=!l;L_8cq72cV`PU@`pTGXQrdkHgg;5Pj^yZ^uPY=Synf9~Y95L9nvA zdXooNr|GZFpj~79F?${Z&=2L6Oku~RF1r3Z-P_Acra~9sWyRj((7cR}jU5^nhvwzw z^*-A&xeu~@_KR+#O`gN*kC=y{sxxr48#Zdu)A PqSJ`8m5O7KysVkEDa^?sA#!}rrqk}j*>_NSi@jK+m?R)OC6!=p zZM{-!CY_gcRw0+dWZ-qO#Mxr89{21!Z&s^~m~6onLniqJ^yG=nY)A-b&{2i$^aD6h zI6vPzH`vZItpY~&MlD5&va_=RK_)$+CX?SJOY~dn0&Ho6JY|;zN34fh;**jnj8I_C z3j*}V(%7j#$(qIlF5I-VkkZm3K*6E(rm~u;)S61ZXaRzn8`QWo#ZjW4PFu%Kq@Zwf zxq<;fqZ!<0U|2QZ4023jGQh!fF{;gcRV8W;?75I^2EqX${_apR6kz4Mvp7i^gmDoY zZ;j85&GqRje-G?0LQmqpFIZ3jzsJL3udN8`9X)l3kO6NFh^$d^K0bU?achWk#-J%c zjr(scxYX5^mAEW|@nAmimc=I|Ksq`)M&YtT7Rsm0Ir>8xN8id=t7HU?^{Y17={#Jb z1AYPy0D$=_gPxgEb)s|~VX;x?CzD!j BL@uvwi+=edsg0C zOw*_rA(@(*icEcLkb(n@|GsN)Z?82U#s;u(x>CW(&Qu$b z?@|p0P?$6?XVJk+g?vMzW9|L25&9I0JZmu1k6(En`{<3|c+hQ>|_80ovb2(M^=W zORHk_IM$}1rk0QGvjQjsL_i>l{%C@*cQ{O`nC>YAUEs!cd3A@27Z0EUiUs Wj-DEB(YXsB--oo3njM%O17L8W-Rs{M!USmBP!;c2iL zOrT+4J{DxJq(F>7s=xr|s*PedHjG^pPN&L6F_eX0II?|?X#II$JLdtnP=}jmJ3Bl4 zHn{5I>-nL#mzPuN4-g3i*I{?Zi# XVtB#TU1A#i@vE8g^mTw z%SMv{*5D?v02mk;H4dwMggj22dCnuw` 74RZgZ41z2~%rn=`ybBshli& zfNN2oE%bzh1Q!2CH-#J_B4T1 5!`uv=Gh2{GCin6nnkZt z3*d#)Ndf3nS5w1A83ZCjGmyVH$B^KP#djSx}xu&HZlv%s1Y}4pA zSWyDZAOzrp;7|x_u8(Hld9(`lkk1e{lTgZkl@Jqyq*Bg~YO-GrreHkeKX!~GMi1#T z6&*~VWOwXHolfWdNdqV-Dw1pUrqi%`8cL@Bibb#0>CoH*enGoZak_#L`eR9AyFS6? zs};(r7{5Yy`VM7^*P8alrKYAnoN*T4=KP_PI8t#!JQwUp^CTY%GB!30c8ihD=ZCA! z%}tYZ{4_!^N0jK)Q~BJTGM?;N0TO2j*#!g$X=y!m-aGy{VcT!Q>`E+_rHTW|$svBI z&=v(Ss1<}CdJGq6l&E|Jd^hQVrJ|<(%^OR;7*Rk;pJ6?{b04Pq!_7J$;etH~15Bk| zU0q)LS)NgQ;k>V1GvQHDy_dVglX>EBcuT~v8y^xXv?|jP4l?nbot^nGv>`ej3KDyP z;PB1yyF}R9+8QC7Z{^@L^xnnduwR-{m590qRT;TyKY>B0a$T1c!>&W}wE%Gm3Bds` zkEGySIekju`fMOKTWut)gX4vLn0LYhh~edg$f`FEfbG-;G%TNJ*MSh8UtUHLeh}n> zxr&k!W;lge8XW7pdg2fvkU?NV4Gs=g5V3UshP=TUqXgiBq7k3k+TRZ&6%S2?Z;#BA zANvzIw T;O|mD&V{olDUmcK{6vp-g?q2hJ3JCZ^_QcsHp5lG5BFdB6jZ8B0;~#7y?4Y z+&|3)hs|<~5Mhra;S*(QeR6OW3)Eu|s&K)q%`9e?f=fmE0biM1@E^8m^{kdp$FB-- z)hyG9$nn3$+uq(b52$Y*a~wlBQ^`a2_dJ?G5cIuGqKJN%^i;wS)CVAj3Icn5uKDm+ zfPQR~yzO_7lchXxt3<63ab;!Y4@Dm@HPVldSA!qiZ+t>6$O+&C7_g3nhld|4@6c7? z`+$vo$?6pk@-5^In1HL+Z|SC0FRGDCrepF(W^Ox `F!ZTGz!LSqBdKw|MytJUN; zXb}<;65e0bGF-#xtt~Z>y3ChgN8XiK2QKO;x_KsSQg~nODaH_RkD0g71-w335)1ih zFTLUQw|QS_|8P6h7v=`Pq_abDO( Bxoeu>kFv(XocqmwTctuH8yii!%kQDf2*wa+bQV`1rs zPnCP-eC4(~gvC1 qv{V z G8Ep0?~+ofEU?H-uovrJ4(9#_<4W7Kg!tvX1TsujBUnW=6-R8sTP(8xfNO5BS{ zmlN@bi;FK7E9VICj+^# !gIEbh4F%!eS{A~TF(eky2dsXy}cf>6^Rc^h_G^1gg z_R=T?uY#hRWQUXuZQ Vj&Lv>boZ^k* zP?>E|l-KP@Bj$19M&0~yst`|rk>WQ#r)w2j8;%?D$?k4nNePV^%122Ev#g$Cw=Ib( z7>0s=LM}U8&$G4B@NoEi5As1q3SpqmXarS9?9M&~Ds42wNdm-=Wi1yMwx^rlDcdb9 zp~ZuU_Uy|i9*b|2&~92Mdp%*O(-!rEgC68MNjuGtokoE#eHYum_HC{!!MFncj~t1K ziP8Jg3Bu*S+^w@Z&EirtQ-zYpq#*}|D5k*)!{6WEbq8NSP!J&qyc=JC`X_<#vYe8B z+jAq5<+}T?gR}Z>=#bQ Hs24-*f!w-f2PaRA_BT>?0!-C?^y2~V
XRA3a2h9zhYbM?Ek88N?yg3>iiLiW(iy%b5C+o4*_Ln{Hd!w8rl zuTGlRzaprxZ8J#0h#%pPAaE!2X(0Y?Kssn%wr zGOVRi8`u;p1_ag1*=htLt z3w9ds&2E?ny|dB>$s8g7%c`-uT 0 zpKTvI$h~# ag8*jIRVa!AmG$%B7x8|!H+LWK fyrWEt-`AQj~ zBzBhK!&C o8jC+09WY1BtH=WOkpnCZJN(jKUtbAX zjDysfWi9r%tAD;G;Jbb1XvF7s@Kc@_2zd6&znzaTs98Qq<#GO2npfXbWII=ZcXzhV z%&CSp=wnkie*o->Cg5HGpX(T4#M;{1TkICuz$8f^nknIeGe{!KmHe*ql}WLVa PNJ}Ih$``H2mq{gT?dn)j0dhJy$xpco@p=>1wMtn5HcU#g=7nJ-2En z*iv`Iu+o*{h0Z%WMXGe_L&4c?WKL$6zPgRfz$+yQCz#@dS~(k(NTta3VgRmL_CG?w z?c5NPKZGnmfgBBtO<>%>l?bo*CFsFRQN_e)HGXKb_2pqdhaCpHwDIx!um_!7%4s}X zkd0Ce)`lyQP^PX36YT@JPR5Q#RzAZgQXFQ(ohUqZhtkkN6qervxAzy@m-=@$dVFkb z2}XVwl0}UT&CSgMFYgo1hKk3*uCIukMRYmBK5mtvl!5a`7>U=qYsiQeoH9k^f$^uW!cv%k}H%RK8_@?tbT(PdKeO3!uAzAXaFr= zwn5>cv&DY7DG<7$gO!Yoj3U)Ck>R&Xk(4N)p=+H`qOL9dp!9JvV5=8F=x)XJ?Youk zS0;lYFtxDJ(hjE5NN8fM$qCsYvx(i%DsZhqfGe9#0>`#4FoCVB`KBah=U~wjK6T;l zu6LBaOv!&`XsJXf`pD#9m9aHVlV ZXB6_dIHf-Tt;Sl58L3CIyGEc9vjk1?9}uTN)Z z_e9n0xA@JD>tj1RAj`g@;^YSvsT4H4g3O_m@LBFS^3~%5)fjxvFO|BDrahs^S4rae z;QDy#wV6(NM9TnPz nmH3KwwNRO0@)C7UdE`CFg4kd6WWaU_l1#hHn=wWUsB z4t!cEZf?F~%pqbi2AG+eX11(0SgUHKVPU7`R$ mo|C zT5fjS2Pd@5hu9v?-l~{@sG`C`Yejv9!T+a(>yD@D|NqBMNU}0QS)c6e?IN4(WM}U^ z6S@(Skv*=xR|wZ$MfSQb60-Lmk?il=@AvohIQM vdkQ=Q 6|4~^ObB^08l z6J3PYpo4;BlO+I`PYNyzW%lj-=0fj1>VG8Wt;o|8>#sC20zQi64rRwOkiwLZkf5TZ zWUZ>zjbRflHN9ONi=APAK-ch1Pn9SSm}o|9av=1c+pUyzi!lfYBvw^bfv>u9l3l9c zQkOhq!otK{u^Q5F?mqspnaFOH8LGCb6})0B(8iB(MJ$5NX;`-cy4NatpQ=DwCGJuQ zK@AvE_uac{C$&a6V*O$m?r&D(XmSNp-tFIykMrF`Ghc(Iq#9;#*V_8KJ*mzXO3Jhz zC%&BD;UC2>a5UlS72g>%pZ>&t&yTu4C6e)F@(3RFQX2(E>g9)u3GX-L-#PM~#ZXSrguIzEV6YTN*3i7w&>~ z{wdr!#B<9KR*RZAWrg2|@G#OLAgfq*PS)#WZDPLWfxDka0W4wE;QIZ+!-pTGgK={h zqCM7!7r~e+)+u=aC1AJ`!O3Bo`9As71Pr6Iv$vf4Kh4|^w;N*ea_;Ru)%LO^B}+%v z3;rYWxSQCLG~72DspQFo)Txt|rt5R9Z(Z =A+FOh8aAtYpUWaKj#;cN%6 zq-x(o^Ua}uQI Ff)cz7ujo)`npCrdB!uANL)t)!Q zc89^BtIJDa^B*4#1DhEl<_7ER#zOIk=@PVgUyx2iy%)TtL6Geuw(H|D^{C8Gb3u{6 z7jx6ZK!Rl?(@C{DS%mT?R^P?DIiuNocL{KT{ghr)l-$UlARGeA>wYtRE^AEDG|LTC zPB(RHqq2uitoNTxiMMy)t$rtQ3!h_W6BPrw+czS(+Zvc_zVP@Uw@^93&(bQAKQ*oG z8&{S==il+@SDL)GSFrb4&l>veJ(wP4i1|bVOuzyqap znJV2EUWi>))gh!j793&J3AjWc!_L9ULD&Z<~Zo348C)MI9WtULA4f z`#@Nb=icwBanvar*slDcbwy9rMs@gZV)E hn}jz=}E$yFhHDpu#a1(-Ej>{T*x09_G%#8+ob?rbt{@b1V3NVaJu3n zl|V5T^1|hCsf*=fhR*iGyYQ^u$%^I{Ok|h2S%#=rWb00lPRD4#-H)4l5xX;IEAi@c zf1Bxi7ceYnszN&Gc1m6)^m@MS{O(}%OYUL@JkORDgS>K%cGD;y3n4=e3b3egO-xMA zUCH3|80nZixG;sQ?oc8cS5Ui|Ks{eyVSpY(8ybWI8YJLNTl-l$ib7Wkxw$b336|6- zxGcfVK__v;n?Hq;mn?8L=wPd?5 %2B|ASXzYdkfb zMmLt{0L(ZHkeafZpE5}unO;dcQy=)FI)}-<3U_wUWrg@OPPsFQ&0h<&6^}YX2ts(3 zeZ@w9B!Y1ruPe=GDe2i3PPaypE#T`P5Wt)=66>#fU?+^|-hNOt_%dYUrrvc?M!)JZ z`M(;rLcbS)hlwcH8Wo7nkgqhZXIjX}1P%Up`%Cqp9V>-MB72v~lv3Pt^Kd)m;V?pg zU5qLbcl#wiQ<&Htwl6 EBx3X3;x2bc`FP_Qep3liqQNvqW91LM;!|Ouv z%Lj{{S`K?!kr`bR^8h^%5dnFJvpU^lw8B^{L%m#Eg`VV+x^io$xyEJ$@!I=IXhk#Q zpTr(UR*Z5Xn(fKT Ts!Ii$`v7)gJ; zn69Pz6zM?e2iqR{nebE_Fh9;R^|fNLw#MLbk;mV^&&BKR5{^DN1Dm7!SaDX+DOB GLC{142Z-Af2$Iq`5^d__vf2Vl+9Jmz#XQY(V;kDu$*H}j( z@lL}r;fV9Tn3$MvAq12NI^tke1iuoV0a{0xmPs>5CZq$$Hll0EHOFbHTF$ $^oTNi+lRLR**RTpTg46sP zkRQPYm@(I7oFCbjz;0~7%F+cj6Vw5 zNlP9hSl-@dCv};7MurOAUOORWQRR8>cwcs;E91<}BZV<%|8)Kx{mItEn3)cAfVn`t zU<~C!ufUlpI9|mpQ$8didF<4_@A-og#t+}eSOAMq0Zh+9;Rdtg{dv DvxoWg!c}o7Q2^;Jm+F>9UJi(=TOizTQ1-RefFd?#{@|L%nbEN? z`H5B+6CDt<8`b!=x>=O9Hkzkk bM0k!4E-)(IhI1e4Fsuh^Uu z#M8}-+%zGV{*x>Dk=b++kGuD>y^OOrFr2jaGUPwey0r(7Y>!ComyCFOf6Ce8k)9kb zAsd^WP84?jEgaw3`MUaKV^p?~+c8-(AlY8mtrGq-LIPk~{J4QqazqgmW4rt6T>uPM z#f=}%uJ8h>%6_v-MnxT!83PDel|@f $WV<=%r_q=pa5h8oTxb zU(jXlH#7c^8Km8E_AlKt+S%vx
WD`{fUipdm z?3bJ<0N8Vs99m&m&oz=R!nloD|1i%9h 7#-{g^rmR7*^V<35 R6kRbE@VpN>@=7HCLj|O8NtrO2Q90C?Ex# z*IDPDIA#?iN>r%j6;s@4S=YVsippR-Vr$p!Rn|9asWuHxGlGrW5C20R Fm8pWe-s3bp5+CRjjX_mZ&H#y6#R0e+{W&EKJurJQQ-Kg&06m ze10nU;_q%J;6wLmXb2!Vs0D)g44z?rlY{=#EhU=^I5i%Fzw87U8n6c8fOF)I=nVdw zS?3FHYCqtT$~T{J7Svjotpv=qyom=qYUq><0*E1=Dwr(&ZIkeKW%MBv@8&&Tfc^BC zbma(!v=Z0h_wL+r&A*!|>ZQzeKo>VLj(L-#e%%|($N^fR&H3pUr)%In^==zimUc*2 z=dh@-Zn`d}E*`YI>;NrfU>tqLG!XNlveIP^^Bic{%+UG8#efM)L8slZysEoDalZAf zPw3tkZceda2qGE0%>tb1zKx<4(W)~je9}2O*}@yp{MzRA>+F)mjFrDeU~LZ@Pl*3f zaex8q&3UFSs{QgPg3xK6;jASmtS%(KUb&S?iG_tl)H(FBxctQW@5O$5@^5s6&X{^J zPOi0|dx7UGy;v}B Mn2~k+vAJ^*<%6DPIH8a(yH#t8&Nwik}J? z6sj#bY)@ %-U31Vba!U` 8|FTMd!Y^@Niqk1#HIA-X^%- z7SMXMC5_?(;9U$EN_k$Lp8!4CyRo>0P5G5tkY9Hsl{{&_cwc1IigwX2U@!QS-=i0F zOo^>Uerl2=j_dJMA$a%h#(%qF@aZO4ZI0Rj(sf8+j;qdvwgDu@oMs_fs{NrJ%VDx2 zWY*c|qn}IuFOF#^K^naZqtr@@Zq$ 8V-{qMSlhl9!=ao9OLDTHZ z3ZthqeEkR+p*Te)C20c#gj?q;&DHlG`iMD=n-X-(UV3eIQ9U#NaD4uO!0=qUCt5^M zFj%1{!E=!CArFk}G}?$gf5=fSC%RBAT{!mHvuE;760w$UX0jGPK9Y39RB5^<%@R-i zh7bZCo3!?_M5_!{?_5`c*DVdBF4;h0 hM3u&4h8Y|bWEqg- z>^cPtdX++Fkg2VM7oD*NJP+e)w47Ax+HeNDY?EGBt$6 +1U(}5b{~fK@a^q#oYoSNSy{2iGhVH-10 Be}jcb?4+5;)kWx*YnlBVeq59Q(LPY~L7COZxH(r$Z_bmS zWmXv>9*JOXeSr+PjR5TPx<=|u26n?Dzg7tp55yT245TYgbDOlJJWk`RtgZdqeP_}t z&Uve%!X>Y2BJ}AymF=J9Udy_1;tEIeB2ChR6-i{o636$!>T^Dx-P1{9#VZE-tpl=5 z+P&q-NxNSE0)Wv+i9ai{4_VX@3GV}+r(e|gsk@$R>H58Wn+6j+o;^G{N%RmBQxFQ9 z!m!0}0LR@%b2hvB3~9BvF@zJ*2!1oKQjFS_t`0sr(V8g$bKe5^Ek@>M2q70Pr%mCw z)`> Bz~uK#>};BU%sI=b5Io$;5U>aUewA501j2;sUwo z9*PN d0cHpVu4BOhNyY&@E1S8Iyfbehq zn=yezRV6yV00=vvz0lQGDtptlD#Np`jn`A%oEh4!Z2}OG8+w2#c>sKV`K* q6X4o?1F1acXL8@dx)0dCu zvatcymEe+aLHlix06Qqk3gpE#uZa0#)AC<%9aqVb+)}!ogRxh-p+S>Ls~ h^ zDC?jxS*i RsPEdYZ08!&QYqW3r7G@YDz53Q6a4UJ Xxl9`6Be8Ga_ctK#E3h6!l;nM5{o3 z%swe+CyYk}#k;#S >2X#jz<&w}?%MQ5R0DzO_|KpCLV32n3*Ke| zpQS_L(ttH<`_1xgagQ}sef@TUfw_BnSV&DnP&@>nth{lv>AIYe?DNuwdK!(G(PB&B z*S5GWVgmAgX2|mL;wuPx oqK8 Oiu}n7eus63LD=Z5srHg{=4Q z-w&(C)J ~M6>7NMdiSJV(q8G zZ<;kFj&@~Bu6+ylICHgt*GWtNeZ#fM8>|I4eQ&uddU zSPY||^LWs7)X|{iV;;y@F-R1$y1&o;#zatsb9Zr3^8j*60B$37c%RbITUki~ORq>j z `+f^Tf&}9k`qB?Zbz6_kq1zzk1mE VFREFGiuV$ir1@yq-*a(XRowyWs#*tYOrub|t5V4Q%B8*D |$g$ld^@sw)9i%4(DoKgE7izeBeQB<|f z0_a1p=-R)mc+^TvT`Y%^wW$etHr|-iv$Mw6CQ6TNMc!Sv=oha3;C}Sr!4n$d^47GW zMw+|5z$%H>`UhI)*7*DQ=~H!apZ(nh2u=sF-7$63gs?COwQjf-LP78@@3SOZ?I0oK zyO9%y0!){%ZM#F9-}V;%9!` --*6G1f4 zg8;>F_HnN*4XArS`n6It=G<9YT>K7r%m7D=1cIhY!`@c-vCZk9KNioQf8cAckq{P6 zk(87axwirI&jGeHyQ5Q}1ZA>&5}wHcKJp!f(%1~$WsP8W?m_Bg6V)dqkU=nj wh}yQ;(GW7!gqeiot605sL^UZw+p!Dt9(oAr7yt@$cEv!L$ayX<@FeJU|FO8MuIa zv1}o@*Y?lWD?f5eqTNBkw~HZ^zF>HRAR!;{yMgS*4Be(*djvew1fBAy77GmxVpc%G z)P@{mKw|O;d>4B8Fcw*Gy8wMLI17MMaoK)z(N36w>5heR7pkNvET~=wKHj=*rX|JL zH78&mvD?)KycohXbRmasb(Vc`;#UDxDpGeDpl@G6elkZXo~0PrV|6PrWC gr3k@6W+Kme2(iW# zeh9j583_KcrqAd2P_0X b1B} z+uKss lCZaCGEu?Lyg~BlH0@H?KrCDV&!{vp|`g6vb6oQp=W^D-;IOINt!GN$|41z~oQj zGz f3?fAW4O>dA*?qIWj9Jd_&re@m|t ruu3nC2#AcpW<^X`_N=uHFJ3dcR=-V!)AJpkrr}~~BTp7DF z7Lnx9DbgTy4%HJ4mGO^gjvg*-5oD9E`EP{R`ESpo%L$cH6$@+5U!JjbY EAEY`8}<}>GAQl8 &c&&565}A4O6@*>o0n2G>$p2NN_5C zZQDhJ(JwSUjgp1x`F&yHbob?K!@k2hz2U1s9<)hLFJJT888F_q%puU48vg z>gvJg$1P_1ooO4D`P{8mA)!~QP8j-(b9PO_`c 04Fa3XLHHgZ(g1Qw{?e35a& zE#Z3b5x$T>v1r7=ztJ@8hzW#Ys><-Bs;SBfL{!6lZ8t5nW-1&?l3^@WQ`J7^Soo+q z)v} 2BrTI gm_I z`pDf>O)a;U#n#ofxj4SFuCKM7Xa0^Y7z+Hyd#aNaWx22RE$LbTkJnt)2l^V =V4k)j`tm_7TgKO&8$P1(A!cxx$eHccVE@`uQ=PCGZ^V8yIHxUO}c z>8G*vylpN`rFfqmyw&W-$lXPxJuTZCXxaS+dqYdYfKswG UBW=6J?3 @Te6=P4#eitet zY9}P*&-}vJT;~W>{=0x)zOA=;!09TQbead6?-kOZKT851O5Bq98tjuXbN<26wQx@s zTyfA|2i^2ao6OP%!!!2~C-b?kOHI9nu54G?lw5iK XgxCPZkrpU6g#BK(|uA85}1T-{-Tj=xLTmTCs4P)-%Y~eJz=vY=gqgPE7N) zJ2LQObsYkX*|hCeXB$^)u!be|div&OxfwIJE)=cl@f?Tf7$6kp7ONI+&iUy(C^j1L zbSs;*5ygTb b)UlU%Rqcp8coS_id Psp4rGQu;17_@}UaVD^mPbQDJ=fMj zRBizdyzYjVSG>F)@TVqHEvqq_TbsYFz#=e{FUoyJ%{x8}lf7gAj`HBcGrrw96kZiu zg!-y|Maoo0|5XzeVR-1kI_w(Lj3gz2Z<})P@T{FqA>J#GFV658x-#eSWk0kw+Am7c zx2+;Z0wEPG8sA5bet%TrrEagd#0=2$1$MqTfoi@hF8@K;dI_=?97dKnemBvzd#K?H zKj&TsIpTh!W?Q YrK zdS^JTlBHREP^#s$H`IM!gBD=~*}}-=Lec?gicLSaf1*3KDircomiS}vXOB+gJA(S( z%wHWXDD%p(JSv%%2wAY4K~{1~WFges_ejxu(f~AWXurn;Nhb*xW4@9%yVP_lY8cLt z9TW@b7BWI)$1mOObX+`U!Ty4*Vkpm$)BPa&59#O*PG$~Wv=9l&R+~9zlxR^0jDn1B zcs?77*Ry>S6lsSRmwe4+W=%3VM=Oc_%RQ<<(-|BJ#I#kTod=63yz+J8UToiZuN>~! zyRUaVcN5HCT6S?wOygzp@t_0E6d->GJ?y*N2@hx1{xBESb&Qm-oU( nJO%>yo^@nRuOgtr3ZayxwL*zkl3W3VxFx01U65ITQye{UiogFv(?xC=xXATAv zhoo1g1oIhLW;hb1P)t86@_5kHWBHOgL#IOZ#zy2Op_8A`l-(l<&7uVE3Q7| |PCdTfRvgWmiMLN)+U&Hzgr%7K1(E4ZRw+q3WXfCe2~c)korZ=HaCrm}Uv#v20Gs zVDw~Z)F@Z_cn(Ckc8JhGB40bgMntaR*k9J}9-6`m%;nR(ZT8{Z;x@jxmmlugEoucp zi_uYsnUQZFc-q>RRr@ufd~=88;ZGTjf3~YH0cD3%kd?RC0h?@SqfFy36||zvbc8(x z;@jk{Dbj)EpE#r!L*M%9rn7*L`Kny?Z}g)TUIQ7DOf+g*Nc 7)%8mlzsyU$5JHk3zpyt_!RU?^7VtVTZUWA^P{y06b?RR*jfCT z2qoM`W*)^)gs1L3Ny`8>AG9$*;P%@wNALOUSPE3DC*{7MxfvtR^YX^WMGkBKG)IRc z2ZzpntdK|{e!1CA{_^5x%1E?7oJt12)axHB?&bC963P1FlE7$@_p@8?Zk{SA9$#ly zfBLGeD77C05lRF_`8u;h1w|vsGK_%~b_GuTdg9ynMzZ86Q?g_fb$C%U*kPXi8q@wf z;m^8&Tu#8Z M-*ynry?>gA~w4)+kqJc<^vU~xUB<;j+R>FPO4167qkAY z59s97LCttb&4_s*e&_E)OP9Lu2Cav-P%? Ns(7d0}*d*g{g=|o%6b@&!b6333C){L)F>E@_qC9+u^M* zUAGJ`^PqA(oLj8vk4#JfthrhdVvIs?0^jyy>M_ H%`iW%%JFwNso+y32t)AEj1mq@n)l-}ClUNrhC)Ck_yasnv^pAx z*9+Iep%k|Eo)D+)Oi9C9v1-;--UuNmY!A>zM~?6M(1VLDT;4IoMX#d6VOmO)J((|H z;?iz`&bRObh3N5=&@Pw@>}iOa7HZqD&&T0P6&eVX8V~z&w}0@kmEbBDcn;RUvN{Tn z;p(WMLj&PqGjB_hyn2p?^S1{}h@8o+?KohFWdNC?nh@%N_<02J_a6>mp-|B>`yLok zdfJaOI4EYEl*khhB|S{sJ?`sZm#_G}tXe*72v@^^l<{+XDi37L0Y0nEQmzEu0NpKA zBf_QX-Uk!PoV`erNalB`G1(%T_9l+VL_E=#u)_~9N?55Np^{JeOOL3g8_%Dn-r^>0 zT1r0VH7%NiZn*E>%XEu#Y`Dn;V~jV9?US|T^1IT+pi|0Kq#A)p+ftI`f}N3kbeSi& zjz7`W=ID&GB`vfE=T5S?E{Jkn!a+m_LOZ`0SEErohgh58Q ^b3~m23aNaZ@al31`>ymb~X96oBUzR!$gj z+b0r7b52~Cl%KZOwTy-aA==U8W{&-a1BF?exhshk%s8(>#k a%WrfUX*5JXW$b&EACLECz9UxF3xGl zW~#=Nt LJ|m){Uw)S5%Y*!ykuEE@X8crV}E;Ti{ 9Dz@XGqX26~oY$_yjZGfDEaFoRM=-3$kG5eQwn##$FX=6m8N;1xtj z|6nB8L%PF=I^<7BJRs4RiCtr=vVA`uzgp#(T{!&yRX8w|;>8IXa&MyaXYbx?><)Z_ z!4ZHGc0)>}(lihj1N0EZvAu{U(@wtpuDjxqwGyVIafH$_J*b}iFz}LjtA~0utGkj^ zSd}UwT^!~Z$E~397Jc04`?kX#CZlqDA+1G1q!R%;%|iYhBM8K9kvI#p6oGH;+5O8x zofP=1=Ew>2V%G=;)BND1BPf9R1@05FTJ+JHxGfW#Y%p{qA&ms0@>G@S6wnizO|JpP zgv=uNVV*cDJ_! K2-Q-J5U7w77<-rr{fI0%pbo=)+prS6w7IO?JD7F0Okk0a2WI zA|C?GW*PH3WjxynHdDf1YP!qkW9<_mj>L}d`5h3CgXNL1Ti-LtyOVeq2j}GE2Kuu) z??beIFZ@KoaxPFIXif=y$&hx-Qxlmmr47DH@YzRzPF%qJH0H6MxHe!b5;o)-o`-fE z-~vIT6%B-dfNNgxYF&m(X{b&KKnt9)xK~#2ui~8AOw7h-0hNUQBtB*I(yh 203^3gFmbs;X^IXq31`7iep6+dugMOlY}2i!jD?9dGbHAUFmTv9-R`x3 z4ZC>PaY5PunTwJ@CoQ>aQqEhLbr+ls6CqZ)Q^X-i4Wk@MyoZ&SqpBpzaxfS=U`nx6 zh2^UqhrqlrO{tk5!b+VGt7{JoQqrqr%q?oss2&h0AOM=l+ANuQK&8TDaJ+>EspsMa z?$JC*^v{jNX>bidZI;tY_U)*B3!KKjQe5hatO><)IwHAs^K4U*3?gkuC?j$I($dNf zL$(sROsPN`1y`|J>Fp>pRiX=vvw$XCB2s;+M=z(8=6YlmuY1Lu{6mHex||@8UY)>B zP^BF{EvoK9Lv1K