^X?8zq^@NXO^^a1u?C_t=q)nP$_iby~1Rmrsd16NAf0K1N01UR}R7#h|r9 =p|K0hP;MyO$OT$YFQxUM?DvAblUVEf zTi8YxzDCIY`)O<5^(^QfGWj9o*R2K27idJ-ARBIs#ZBa5VIPV}dQ0mDnTd4}GQWjQ zf@$O&*+6fiaMi7sw%jC`$+>bG6N$3$I `un-Y;J6!7)IJL>xCXUuBk}2=z zMO1TgZ)bc{Yu+sk0liHd*p_VM$DW2TLIOCAe%l^tvs_q*;3yl}+X8T3ft4vTWQF6Y zHMlMD-#TOq3m1ZHPGMVEu*gJuvk2}>0qe=E`&nxbL_(twmB}!}8R5)G^fANdWH_1d zkw9A5z|}ww!3ZQuXT~|tia1TC8LmW}#>t8+WZ@?f*Wr6j3(=K+eAk1lNG98@$vC1Q z&-S_C6}tsKn=c%6_X;LJzAqUm#v3pICQ7Y^*z8D(?4LOihbSy<+$^L5Cy7Khx=R_7 znRg>1E~B>28NuQRwEN>gu;+0tpXUkAEof|XtH-+byNLdRC??XJ3CpP^qRBTf3!X%Q zbtj!B@`%VFyEYcETVys@I}iuPY5RU6Xl-e!YvzeC5w|XneNNQ7p^lWc43NnP)5e@2 zVl$Roi8vVYsPRZeZsGPwDwCvwBgC4Bb0F`^MH;iszB!w?o^EA#;gqYFV`*?Mw-u{3 zFKB&Q;T%~mC~+YQ3Ev`QSrMSdHv(4hyxSGI&;p7p
mYxE?ehiofIar&Y#fr$?=7y~0 oyQqb5n;+jk_z$4X05?f60+X6Pz*`(6h9lwb#tZ6YBPU7z4+L7V(f|Me literal 0 HcmV?d00001 diff --git a/html/a_RubricaXtCn-Regular.ttf b/html/a_RubricaXtCn-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0126a76d92a08366f2b23a5857b75bf72abf9d17 GIT binary patch literal 43216 zcmeIb378z!buWHzRdrSG%k UMQ?^}T1i=bm%!xwjZ+jCom!DeTJ|F6- lA^&s^yJ^&n#p3^C@sWpZqE|8tA(9Y_6_Q~i^;p#4n#IzGP_ zpYxN4Po7DBKd^+c8(wBib{-s?I`aO*cYTwwyHLOFkwZuKjk5NqA7SjBFXDUe;n6e4 zcneS9_fO;Z=_8|u$E08W!G{^+PR5j5j~zX6^2+mT4l{P+ukd;Ev8l0R|MHiA`vl;{ z@7X~d5#ESWy!d+dxOvKAl4P7q%q``NbD3?HZZOUj+_T6yx3HDcFO74RMdUTcxdtfr zF`_uVsCNCFGZ%l|IG30v#f@{BHA`EKbA`F2ZsXj-^3u1BbCo&eVdGq{UuImfp=yF( zKj#8|{alA%KiA>c&vp3qa~*#DT!&vj7xj t~c#;Sf&9O&*&&s#cn;=sg_^yrcO>E&aiCr?cs zI5LsGvSZ2QsqxXNqvIzIUYl-Auj{z%(5aIrASlgjl yA$HtC_98Jbk|{a4EG;l*W&Y&teXwuuOIiO*>c>! zmCeW5Jl2J)Mb?b6hxM{{R=_>|xUvA>j^Xn<)NufH(%qwTS}EcBNx*QFb)c;i5W)_W zr^GKevPl8w*juzxWCMVxTR^ZB?VLbe6M&W4AnXXnF`S=7eMEyJ_%_Y1L<>t$^C>ni zU^$9+YL_r<#IX+FUj|rD;dgX>48LuzFn#OEB}eeHi%Gi`H!opFHjho5Iy5>3x{sl) zQ>X>l{+7R8H@a`?=;5*b2S(G&j~+RBbYg1s*yPw$y0@b{J+}&?<~~40+#%i_z-Pjh zczP1$1il*u-zEj@X>g=NQ0Xnf{`Z>h9_;Au?ilPBJp7NeN-{(3ccX;tj2OK~5OU-q z2{p(F#Zcm`?V4rjr{#uaxzWi;ZgS7k_L);NZ%S9oD$qL4cCZa>7jC {%4m|Q zl1l;VRc#OJ4Tp!O!$Yj2qtdXux?wjp++PUh{Jvff&owm$eFKLM9kO~Bd8}v7$Wr-z z^6K}!Z?(*)07no1pS%}vsDNW*DJkG!7DZ8+Ra0C}n-vhaG*!09+-XoCJk%M!6niJT z6bK$b`@TZXM?e&LujW~~>%*%(R%uLX-Olsn7q@px4}udj7|r;50YyDavAaqucsgCm zxRUYuSTq!@^LgDarvu>NhE&qymMxM-kXbBBBJT5Y3)AXj;gH`_7mWnv0C(6mS(Pgc z3l9woh(R*IjgoiNc+D~~T}{h0(NZq-=Zb~?f+mh&P6KVVT)#N_@m>Ckx((avSJh9( zR@N`yP`6@JY*qX~Y*qcbhbDa!y#Jn!{|m2;<{MCDiJ7nSwQ?HD_xjQTUMQ4$nZurl zTVzE^CBgFMc~043iAC+QEuZttb(WrNMrK}BZd4PwtQt=x6N=1jIzu`kg(QdGY40@G zQLHX!<;2Dc)wmT1w}yZg%oQ7(8W-|HFc1zEdKU8DCh@tqzgP%{5 ?iF8XM(isdy!`F=Yi$z HJKQqYR3#Mjc@?Ll zrCF(urBg~n-lq8@TDD1JkOrRMOy)7OV-5`ufd-xUt8`7Xi*|G{v$MolTQw2dhzPtO z=Q3F!Ug!ayO+*5LF|T#)?&2?c`QX&li4)Oito*Ix$4{Qbi7dTY-uc|_-Oue@T>o4= z{#-pT&G`sJie+a0m48sSu{?&~A$D_VK3}-7w1^FLH)PVOq%x3?yEscHQ%W{7)YENo z*gF+pvl0pCna2AxwN3M@eo_bAZlXNgNlZ7C5io}o2vHc)B^<2RUxuQvvxU{TFBAe0 z%w?NY9FTzCelWfWDuluI0CZm{T!0J&G`X+8uh`oN(ZdH_Oz74o{=pRqS9bAx0@~7q zRe8_iWV6LN5$}|CxWDMLMV*0=+iP<+L_L|HE3s*ltA0&==8Nn4=XWKxOnE~?2g1JA z)w@RT_-=QMKkT%Iw{!=?-CO?ZPaB+G*OLD1HtH#>_z&3QLPCa1ey%7b3oe59q?BbY znS|)n6_VMDF`85(st}@nU(WaVE~vln^9HIpIdd=j9%{BRs@ZNYIV3B7XOShV1|3{o z^EBkgAfbiXt82E4ngih+$kty_-?3wK`}WZteBBRTc>c9lpZ_kk!_dwb=CorG?VuIt z`Z*X>wIkJPr?;sP0t0e=S6xNzT*cSD^zG+geNAsC#DBs|kS;gd0zK~Wl)MhRO|>xS zPS6XATvOegP*bW=gTz$Jih-rVJk?lw1eRJ;e^Y-L^3WgF!rDhmZ6gOf2m7w}9vEqt zR$i6amg~tLJ(}&wZOZ`b5q5yTD9Oyhc9)vC(^+y^900~{1I`NRa@nGQg{rQs0iLO^ zg*Mamw64VnJd^rx!m8nN3b;r_p^>4+aw8Az`p}1VJ;cXQe&|C)eecW}_7KcynGIrq zCHdhp22^w-StkRvhY`VSL9QV={ZJ1*hc}eY%utOXo?#F11E_IPsZOs^;uadOQK?}i zh)U<$1~mi{K! sE3ajZM L&T#H?M}xkeYcDqZe5WVYZ=^ z;E_lv$^w3irh42K7YnJfPqo`+&{;J^ZCD?hAZ*n{fu~jteT2B#5P&XfEc$x;3O%8q z?1Lf>`T~U>zINn_D@vs+uPB|!=NoeOUAb)8mHb;&mec%|o}O}D52)Az2CYC}bFhh0 ztB^XJS|qMoEa(6>yA5`o1CU87Y#dd!Sz#tXpPC&4^rd0cux^B6t%jG^kiKSKgn3u& zL0RA{%Kxxs;bl9n*u#Ia{i^9*BrPcvM5`FvTbjq~>q~JKvs!|1pq&<&GP2}$sdX`Q z1a4RB>V$T$s02YZ8q>gZ^a#*yXu2Y(FqW!`S1*Vc%oP1XRnzc=aa#}(irmBb+VZzg z=Uu*BerkC8wgn+~$G$y#_HgUQp5e8{;te-!8yMKObye5I4+v(1zdh_77^BEK@j4-l ztf#S|K4xK-Xr!e%D`zY|uT8ebqH54a7IQ)kHmFUF9V)PcwHTRYJ!mLsS-}LB7#U(f ztb$IYhHc_EFu+(uLy 9c-gRW*73)^C^eyxSV#z%_ z2B&fn%@S{Q56W63YE>k5=*lI-Yv0yi^n?PDMWg%D4U2ajJG{beuYY%I{Z%7ljm}ia zk%o+0z_(FIk{$Z=K&eCMQ`zl;N>%XYgf_LP7U(i3#7U7LNwD2Cl{AZKmJP!m(KVQ1 zlnFgsZH?8?v5+ENlNA?mU+%+qx3?eu%IK(sQ7gIQx#xCpgrRi)tO9H)c1@{=ldWt^ zCh9?RW=WzO*7>3li`|xh2a`(r>r@xyADz _0Xy4udZyM}bLW1I&7hzYgO?z^}S YhdMsOoUXvI-lCSIn~gZ-ncQ< zIF-w123vbS=LzN-e43pf{K 0LgS)U-wb&hztV1Xf@2}D z?Q(ETW$Q}yT+>Qcroez_kRc10gKm#v*5)wWJTW#`3|F{0)g4}=4$p&f4!wk5e(SXt zz6}abZ g0oirTL95&9P`W RuvCapfwe%H}a)PM= zkD9fq-Pvx=6NZQg J;jx7Ru19}a8wK;*$ezNP)$ z-QBmflz%AMI@<4EpNNL*H{ZQJB*j<$;ktMv9N+S2Cx!wEHr|_jm5{6!Az7`hr8Zl0 zJO+2vlqgfkNU|VS5H2^VFVo$hl`PU&It{8Mi?P;f60`~uz!Vf%V&Kw6%urYhIgM@o zx*;v-lFX+r+XT5vZQPh{oXY2fT)BfmPh*B(_{oNN7-BX3`bA;|mnig=cES!e!);Ol z{MKOeWkmb}LmfpB$iRYF>BAgH7z3Kg?D(?*48hk~TjJ92g&*38G*S}rgF{l`O!?W< zXx9##>H|i*8%uG~u0?~ff{}Jko0{GvSwrZYrmC4WH?$fN6Kc{Ag9|2%4K^1w`X|Ef z%CQmthSY>UGz`0o`Vep>FHkgVwA5)j_a;`LO*Ml=ukl-g4aJ7w?fh`Lng0#%{qW{* ztoe(LBrgN(KK@VquLMOegJq*fgp6irkX9|KB5@5NqDxQ{>V1x_T7#a&OwfX3fPcKa znSY#5?cV*uE@3C6FTqYRn^h}~U4k8}fn9$)FIs|@G(TRxgTGL2y!*o++4vW0z5(ny zp@jzEAw*e%9W8b7WU`c!Fi^xCvfUD|$6yX;Tb4pW_?+R8%Iafk+^?}joJO^ Nd=h)ih6vPC=fv=7!4-CELG xgf>5i5Y=NBzVbhI3ZL_Yb+z0*g}h&~NhdNDfaAj0EEFfuP+URu%HfN_}3Z}d1z ziV{|OQ%c)nP0DHWhBRxv*5%Wrfv$O+w;4Ee3X7yuSS6eS2A%M{AeMrK1`=&-c{LKt z35f>uU!!v)8U$aMj1cmSn;M1nA>t?fVSQLJm4MIze&Ysc#eV);#}&8q4Q*eOiHb zmFpL_m%VDfHQ&|Nea+HEd-p%^-py+-Z{54;z(+rO>iD|L-+yfLHqO^A8CbGypo{2* z7vF)gM}sZ19=+A!C^?xGrZAi_RhB5WN1hn33_l2%32Q)frK;h_QB4mA(Ib; P&(zeD3)-D1gjnc zyw&3MXiQDSF%DX@^{O346+FVq@D6} INm|I8n(sgLA(3eCg8@pwx!KU4nE(8HzjEwYqKth>6 ;0<4?hH5_f$5j1eDu*=a3om2N=mM($4Tx^k`M}qYyy{TEXc0JI1&n#!d^{< zeGlCVix*xx7-M%j ?~9bf5_wndJ6nGS+GJM8}G|RtV-_uC$ga> zk@}U=W7D6hb0qk8hNib;9I1OpIk_g8C2HqUGy*~gI}BTfq6rK^4Nw~a4GSkZwqWdW z*u{8 &0w*!c?G#Bm%`FbYQwY@uE2DYvk1$kq+%%%6e``z!8rG0<4ulzFL zBFbe2<;c6E7?P~OE+wE4dJzL6{LJ3~5DByaO%*VghM5pY2OtE@2To4kdhVPojs4je zQ6~ji+yGf@fIjTvjg6%yXmN`YjgUNsLoo8vDT~_`39EIAtV%qm+T!GF+BkPr3ncLn z1k$6YLL%|WB#( o1+W9n-Y<-fW} z9A`z<;QD&O^}VGQJ%*%5j#TIjvT_^@td=DaL*hb<%^Gfc*x%3>rb}Sx_S#`2ADl15 z2=SLcx%edh;dQ;p^KX{ &fqrt0N{~XsT9y-k%GmSirSnY4dRv6loLT3;^hZU zq6Mn=4p^xpICTpB>~fVTPG{jxNVCMPDuh}1m4-D%ekBF^ff{kk DqdNdzIH_{InLEIwN8C&LbOg)rq*pvheff% Az3;kL zK!nkKXhFyShdA@VLulh(Z^_3!Zkma6dn{ambI cg0>LY_5;IO)#SF&e<8Um^_>TP-CkgB;)`ncfJ{9hgzPs+8yPcqtLY zh!zUg6ZfDD9ZYpYlIjtI14Ao%kW8P764Xr$vxB) zXLgqwg&w#1>mYg1-eHEA4#ZNn=2WLYt}0$n6|u>^0+Y=s;oK-ItD(57X$~tEQ$Pzj zW`Ll~t0|w*DZgq}-|mf>mKvnr8MN3}4EY1GHPz$?F33sZ)Vn;O{}{9i(ce+$qxhN6 z>v1V=3uhRZR7<^ArTKLaY>TQncCtV#0}&05hHYL^- 6YDE@L>?PMmL{7 zzqA0;tsuOmyDK5b8yjfg84UPkmQ1J-1U`#dHDXbVMIO0G`hkH!LX4z_k5s{6ezh#k z*Oj#hIZ@Pv=3mV@SR-BnuZf0Kn66?Pb~YLct|h0)=yO`VmL;7&PjhO+yL{>i>L>^; z=W|^ipMHrapQ1jpBNO%pwM~PW#Ng (FLUWF(L^3XP1Uh#I@<~Ynh>9L^LgDe4rWc z;tMA%w(i9I>%Hm;i#3>o);*XAwRo%}(U^38`fXvWgC-V)Cxr<_&|*m`q(@tzc@gq3 zZ4YxiBKf5`rHal~YM@R*4jIb-UruiS!z-s2VQ_u3jF#U|Eh#8|Df-XeQnNWGIqcB& zh&>?S>{b=KLr@>X5j-Ut46PUIee!Qjr`A;d)|#UcjYK*yej1JL-?{#6jZ*))m8Y^& z``hLT$fV)vKLvE(mfEMkO%PHx&Nv`+i1C0dawII+XigJSL8Fl{6fPc(go9m07p=yO ziZBiw9BB^)|E~`1*mY`T>A}&hr~6?dJW}4lH 9#bVXasEwjUG{*!kNtj}qozx+vfPZ~XN2oRfj#^W`4Z&PL z0=$JF434t&?sva=^S*uiq@jKLrk^AH^O#%yS3se$t);9PtpdNQOeOf$=$~*#X04?; z(YR_CsHT{b(}Clz(QkZ1dT9Ep{qiC7(Hb+0Q2P{&GcmnrUbWVYyd{UJ#r}cvF9$KR z2yA@7=I`cU1Gq`ulC~ioqas=%)D1407U ?b;I zMi$hc!=F@zWlyn11sz-WDCV>!vWF@$5d>DN)wmv9L_EZwYx?BqombtlX9wzSD1ZM; zXk+G$nKM$$%pbvfSO^nSWHJ!F1kDU&44TcxG-|mHmP|1twM>6g>bj+$>U~anik+9o zP_H?|{lCu%09-gf|H47(sn6lZ_3%ex(jmxpGaE;Aqot+PYIj;WMmwe1o=Q^0D3eB7 zQaYtJ#I=S7$qnC|^EyKV4e8dODdECXA*0xk^E%d2O|=#p{Q8UNC?X^t&NYd+28O{! zk{(&pV}@cN41PMRx}x#1oz_HOhsPeBh)I?}Y^))%a8WXU=-Y@eCf*z0)Y6d*_CC_s z)YsCVu!gcz*9}DK0+IP-$!39D9x~=ZL~19jESiy3B6SWH^TG(RFvaac{L`Z7cA381VFOE+oFZ_PG5UpY;rQ>*P>x*xP3(# zVboMhBXsO_t+6B@?d*hHCID>`oXChMQ#M=5@kCs4*fW?KXG*|NvdL5gB2`aHQ=^*4 zBf(cR(}T>piz+LmYIwA>Y&9FQf(^C8N`~nHTrgCAb|M#Dwk(#(M3*m*W+&`kuPqvT z`Msr}#}_K`M@B*jKrKFX+~;!n%Hzo-C@ydS#VK2WC{Eb|j*!oWxjaE<7lk5W<-!a{ z*iQq&E1GK9q_|;;S2>qTjog8L2o9nUu);+rujCGVHc?o;t{9n^sE Kg z{>}3B{A5G2d^&By2s+0=X__q~O2fWG9-$ILk^qa>gVIW!I|N(bB*J&6U 7`_+Ko8~J@#Ou{*hDT_8cAfciIGw=cYh%k<&9rT zCU3fFVKf+wEaLYsiUfnvg?HbL2_YyH42n;I-hOrn(V#$}6tvg*D8dg{UgC=1>yhEL zVUW-ihlZ30+2=)sh%|SV1*co!dMX4t_T<~nhRQGxTP->P5*=a572wM);6X75h+*UQ z$!u2huFv`vYbqs$H|_H^ZjlsU$0psUJjGL>c>wcR$6#rvQl+%ljkpK1cw v-wS{7O+r^_;p!=zPsdNK&z z5iP9Y)3IFHDNA2!#*z(aH}L*8z(O;Emm4#J;4_$w*(5TBV3cSonFnyXD!w|@n&EHF z5!hP!%zl_66eh?{PEJba4n58H!CC{Y1nIg8|>sRgtR2&ip` z3W38|j!q5>u`*nU=4Z7OvCkMQ>^1CFf S^+mM z;#x!?gmrk!(p6V4kR~Ri1=3{sB?P#ZmY; mEL7)E>KVjR B1{bws+5)mufR1PXlrf?Af>OOGwa!RQ> Q=(7lVftc*y?pV>$ tyR4J`T^y7aOGP?_&AZb3tjuAiRpgH#dYIHhPvr+_G46+r+ zMc2Bba~nS4>?nZ1OEt|!)Rx#>uojLU-Bi9RU R-NEX!HrlRg>6n#9sPl@$)c%2gnVogrp z*U%jEcS_!}zh!{`kYogQB5wvnDjO*U^_(=!SW?HLnN ^ZIpF@Q5X|lvcjD(kR;1o+=&??F=LJ? zcj=T8uczf32p9 ef$??JI-DFXMl%dYkt5p8@ZC~ zm_xz5C?X}WQ@DdHei)mx_zSO}2Ef@4idC%DOc0sqH2Uj-t8hPe6c!xFWcLjZj%Pw> z`^ECJoXs%4m^Xg!dqfpzyaqrKK#ViNgFyro1Ad qSJEF^nC5kS`((QWCSBX%%c;tC*{f>O zwPh@G=ExCY>=nRegRho1<64kUS`~rFFTz@|6`+zqFX} a%ifPSo zVbUo`PepBE45LLr +S?+bm}mK#RBUxP+RBe*lkHD+ BN&1%UpBZ*^w>cB==_(O2y%zoyLpx99OotY+cML9-@A zY+Crdd8KBol?w)(4lJdPA|nMfL)Zq)b82=_&S6idX6G;k&4_AmK{E%NS1o1pgvQam zJWxtE!$F_EetjVs83ORH1o=XId22MBZd|Z-xhK}q+7<~$z022T!mB#@v6V!y_FVI7 z5bQ$73Y*0Wdff|pt#RbmJk?$zc?`0@lkEI9ScD^(bEnbOfvF 7A *=&GXmw+|Aq9t=qO{!-j3bmx{43 z^7Z^R=!qsaijkdY>dB>ozQ%?Ga!fH92fsmyF)gEN{(LgzHB;n>eWbYz^`#47wf!8f zK~6s{tpa4U%qkqf`Wm6mvE+sp7Gc>9Sz1_k6Z%xk{P}=({?& x&%LqG# z%=N{KOG`>v=*AlDno^RKe4$6_?h1#LU?8D52bFoDpz4ik-lEp#ZIgN4P=&K=-aus2 zKbajWOxrKd7FSEaVxbyA IZE=zqu!u zU6f9B^u*$u7AG6_
R)w(6AMx%R;|b7*u3G)3SZ~Swa^W*nIFk3WItpt zibeVR;8FMWmHOp*P4i+IrPHI>!io&Djrldzsj;Ni)1bA&y*3wwb`mv=6thZx =@Z= t9$rEQk zx%H~E=eBSC {Qo@Y^TW_7BSbSDtv{wVyum#H*XWdhXol z{(XCHy6I1U*4TadlGUBX9cy>3TE2hs<~F3LO7LQ~^D8AFgqYzb %Rk$B{ybm2|Hen&`;i;R z^f%Hy7WSAF=HJ2ls!~K`p@_E8JzyPBqSu_s4q+!_?3>j=$oH?Nvq(T`C?b6C 0JWM?lv4-K`qFC-bXpa@F~0g;ED06%EtftBc?rRaztVa^pC5!zB@AF3i95o@^+ zrSu@5q!QZ_b8WgMa`E6=aj@Si$OXfL7Bv=qm?8iB9WT7F<3*{CKk~o>JMmxMwR0!Q zXmVzev>%kCxLcEe((Q30Z41+%H1i0{0*N9p+FW8L&F!il^eO3(tZc(z6SKvJgw)Jh zLR^dfME5Ubf|9ytWY?aNm2dF1(r4bhMLzT9Ez)3Dap%|9f_}aleHfWG)qU6|Igu*) z8~d=e*2V%c)t7c5?B?(|ayl*tq-Nd->wA8$a^iM{eA&zY%>xu(Ko5)$k2zCSCZ3 zaJ%3M!t+9M4g72vwN|9Kkpt$h;ef#jo6RktSs#N!n7^p*+#&|9dtqHo`gD&-E%5Qk zmVmR~f#{rC2SBFpZD^BjmR>K{g{-at{`a&l93c>7x9a;)_}M+!|A64M`jHf4wIJSM zfir+;9r;Iqnz)Jm8L-+CLp6qgI@OAhl-=W25y+=-E0Cb%Y15Af0+2sqvhK{!@|@y( z^hsQwjqYP3q)RaKLl(uB5}DbA*!<||h0)Q2m8{rjF*W_><7RR!WB{+ 2FC{-L27 _#&cJ$qSBpd&AGw5mF1Tz=Vv}TT{$eqUeQp%@M;TFNEgNtd5Y@#3P$_nyo zG66n&wXBLEmf~c=-1(C~J}qbnIh?tbA4W?qXn|`>eWG`1ZmfP&WOOb{CWdB5EXIYf z5i&+BOhuL&@)@0&wZXi$NIjT^0-ed|Fcr;dYS1bt^U^K^kEn>Vjq=9ly_&&N`_|KR1j>wVZ20eq=y=0+SE#M3IDGv#D z2xVq-g;|1h#o|EBz-{p$)>CKkVO+A~vy2^GgzZ$B=0%{(2=)kr#c UNN z>0HRPzye5$Z@}X~DW+fi-;(4jPamE*yiGnLZ9hDD`1F;CRlKu&mVbaB5NXDhRO9kl z2w^3=wUfQQG$<@D)*cF`Q#5Is%|HlZ(K^{@>1=J0SthME(#(-Zg_ojY35(j;hya#3 zj#1`=u4;8 }Nrsl0#GqpAv7zt+{y)R;QwEnlg-NjR_{>Vn;{*548^M=iV z$PU7sBuvk+AI0b>c4 m zT>fh5@~i2 %t1F0}Iv`{V!?P>}+ @! I64tdht2CE+l zFk)6v=5E87qX{-rZ6ang8y<7lm|ufw;pU{#3g(2$_fPG&4=!ttb1$Db-2-cN`uLKr zeX )(oK0_cgnzv`Fl0p*7D-#A$y&3ClS!TzM@4zXK`5(Fo!@ty#>@ zVxkh8zvXioIfAGUGTjm7=Kd=Cb2hci>>{u@^biAKVs;mQjZH5ob%tU%B6)@kQL)ud ze_t4Wi$1|2Ba=kW#Qf{yQ?a(f)+U;J$}_y?#TY~PZkW{ zc_(&=@sEYwyUS1J{;l2~C_l-s4A|oTmV 7slrEJ~t 4SCXuP%_hfZy>)A? zt-8=WMqwmFiWLsuJ$^iK|8cjSpW?T})T(=cZz+GG)nO%Qu%?m!RPbn@K^>S^pbiok zD9(i-QZ;pu)NnC%{$sQOU=2qXU%mK L=4Qzccsy*XRNxeKgO6y!gOvr8 znG4TM><4MV&K{V|C$<4F&u?ZMS?05>yL5u6!a9R}I*7Rn0}Uq9u0V{#yTnWe cX|khemn381bQoJC*&|_IZ?D>{@Ha;nE?wi~uj-|9V+* idRA;ap)$VO4iHHSu})+4HYVa&3fO^Lro@?W3?9iRR>9Ya}lBKLhm!fB)jY8 z)oad%VD=gQ7gJN!ff8UOt3#VUJy;Kn^o29<9tbB|$6mea58>k)@g4+v>Z{Pu#{mP0 zixH^Jhf0*^A_VSh#P(<4MB`pxb3zlGAix8*#N$cZEGy>61mFM|xjMhbY_|=2A6;AO z7h^;coi8a|8f@T%bSJEUXsz?f3_%H6aMplX5WCH#MijN7;gVHny7wu@HGNFL1z}H_ zEMc|A1+jfokyb|Nn|%sbQ+GDSa6uFPH1C6%pZXJxx$*H_;|YtsCq6Vk(QU)#YFIrr z6z{QHc<95~ELV4bCY9Q;CmCvWTdkg!P;&Z(B(0}H%qxUp5q=(UE(2#fc5FL=eop)H z)Y}<0A!$M4y#s5#;FmPd!@RYu2CZtgr5U4Q7P}oGfQ>2b%2u>s-0-lDu`%IKN^&j- zoi(=Tp?$;j{JSEyt3tOoJ?o2+_2u~OZg|&?zc_JXNcFxG=-Mq7dv|=nV7$|=4oNpg z{H@ckq*7Dx2EX^|bY#TlZVBY4U&<1`IFF<`lm%&fCUP38S43ii6-02c29g|FxM86n zbS{{T2!5?SIjX#{i@jJ&?Tkzcj(}w}HNSvs#=ss9E#Q3hacT4EEB&5^p(AIHx7cZ| zv$ciRLh= ~x4lR$%8Qb>|bVE_z= zYz+G+Xj+}qq1h#^zMf~H$Ws-AOt{B1+i%zgU=#i;^8~3H+miH~`G!G1a!U}|5tFH~ z%Jfb~YZz{h#$wSscQiyB+q&yKdj9{r#^OnSb2`m~o8t|AjrHL|`LLb|DzzVhPN#@! z2Dv*v%o=CVuex~_>lj?AWH@B6k72zIraLf%N)i^iARUlJ>olH;X;? cxCBAL) zOIJ#hmr)N@W U-p6wZT7YDC=KPL&Wa^d@xtDLEHC_*9 zH)OA-lTDj+O|+^x6nCq((9x|6A^|K)0!xKnY6M>$h(GF4X1Eu!WJZ_GXtS_*bYE!B zW>oqVwHVarMwu-&axk$D0iz!EAS`5V+#@aBy<1wkhc7FC0ZEu&;LE7bke+OkUIsit zb{g|RBxy#J`C^!A$Czi?A|y<7_Wvs}=FDzs*`7Vpvfbwn+SWBSuCwVtBZHL?xP5nP z>uy~q@-CsNc3?eSWmOBH!t^>VY7tw4P*_c9CuDWa20Tn+QlNm;xuJ@F^J13P8jD!~ z9V8zRQG_`Th&&=!iM%$bOyp={r8?$Uu@nk+4ubTm)#IkEo@rjs%;q2yPS=$+W6ZW1 zd3?lUBf?B`Y6TwO-{bbrZw&-~F4dLy42RR(S8+U)N0+<{0 q{A@ECfchT;=T$+FRkaYQ7&6IU}A0@?!#JI`wViQUl zw;f{6K 3RXZT>5)DHd7k+%bpq=B^~@(RyNx$kKzJF_$q2EmM{4WODxB z+m+;t6YH>*qEvUq70@OBIWzXLHW~8xX?QRxL=cLwGzLVjXsDwlK`YwH;4iji((q&E zB@ L*svYM z5^S+9W{zJY9!P`47~S!1s`x;kNpyDAIahUKy_Fm h>;jgJ#p J?~?ljB1OXJQa^9;w&05Z9){6|$_zVas%7=38p znPI@`#-8F7c@Bq55!H?LV>&ZkPVB0nArnx;GB=HdJeoxDvMTDKf9pG(RSkm|#RtRH z{0)n|c` ;K0dKI(K@*J<_Qsic-b3XbAF_kw|_tLfeffjQ0D=)6YH~R z|2SHo1)h_)hVXz76h@|)Bj9>#>dt~W%lKMLwP-rdpsNXAcEX_QL@XMeC8_}&dXKrf zvq?mZX -wsxsRD&E4Yyd+|L z>GGdhr&7d>FLEenLs_~XxpHNd7fIV#nEvCJHoUjmdn}LZTUiJ%4L-#)h-^ezPQ-|5 zk6o;3!pe0hDltb2=OPzFbS9%AZmMCM2-=YY9tN^I@oa#~wk )e}fEWBmGLN>=VJCA;&nL?VgzE&c+F?aqtWT7E81P(M4Y>zaUNi?7fSk z >~3gqW8?yRR#a4d@7X&tfsLHJ`I1C}&gjt&bb>8m-qrZ$@&F7M!OglM *WSH*%Qu^Qs(^3UQ$?^$-&1Ag4W5<~d;)YZ_imz0DRf0Dbzkw4 zy_;B#ZC~X~Fr!Mj=^yZk6;Lr$uhRQ}t6o|OsMm`pzNXj(!MFJ(ufEq5ZEZ;De3ccO za~^wCYkMx*6zamVrTe7RKLA#iLY troPk!ss1lTO8||bq~al^x4?U#ckDo`T@11 z<$knp$+Bbnmn{XI&=j?W^_|0lQW{%^4G{@1(bg nM6}( zUU~@>L=0)>9N!JB9E^5yp=bm`HkgAKISL{Kp=Sh$5QU08m}ip|(1p=5x^mT07n8Eq z8o@e@cvvcdKTJFR_~gk$v?213cTRs@>fiZeK(d*AiT@920FV?*E&+)ww$-aFbE9SH zhE-~-Q9Z9(0>nM*jvigN{^(I@K)kJAcND$(9WYUz6;IvL(8^BpNo8VJXH5~Q;T8v0 zV*_~$%w&iUQr9X5vQB4GTjpUxQw!M!;A$THe;qo+4;(r)-G1oMY4O679LPqO_X&BT zy|U pBlfv9sf`S& zOCFJE%u68A8ep5FVFi8@k6F6LSgE>0l*C#=thfKIAD8&sKSEJ@+p%Nfp^7x2Kj-0z z7d=a{JT&K9NJ@-tXCIen#o+((vqAJ_fg5+-a}PIG1fu@vCG}%xLa`VSnJ4DveV06) zqvrO2`pTu#yJ*Fsu}n#!OjzkGIB&xWg(ODWv&gH@VJ6aUVc8V&oALBZ7|FEfo*fP@ znF$E-BE2B2`LG9{oXt>X3|7e1*Z~^jCuP;ovYPB3@L7b?jn1Rhn4_%P5;|aPtENAW zjka|!^w2XErV%?2u%vm z7Hn8TP>EKEE_jJEXau(n?9>{2BnXo(*VGJW#)rKt$iBn&6%XIK?PksoNL#kPbLqRb zzx$dK(r3%J^Al^zi;*$)F>!pc{Fj`bYMz5axRbvfI>cPZk32oGV)`PJfVz~a7HXLU zw6Y4%y5Vm>jhRmU^>(~f9h@Q>w?RUXJ|>?<9mnwe_eXJ*@tk@*i(bW6s2bAwwI3lv z77wSe;#u@osB#;gF>L!5WA^=wIU)!e#Bn^snClkC+*jjxfiVy6^M08zAMW*ioUyt( z9Qb|RPZ{%n1}nk-iLu~b#zI4kg^@58{wN+fzZl2Y7>hp4SgZ>N>Z@0A+|L+xYGZNS zlW4(#`jhWtEVZ4nG`7mg ~eKn4k80)~bj=yEB^ZnSG2D-HCzcbc- z8)H4VuLrOc0CVpl9H3hfbrpZXSl` &Jd_{eWxWB#u94Y!I}akKfOKgRuq27#jkt z3-SG;G!Ec8j5_fcKUR8 fTwk&W$BT?D#qXB^mSz9U*mBTl#Q 9Yu?4!+B}X=F}7|$4*YgK@ZW$sH+++^jk_4zggQ6<6JwjNVeB#m$32W) zJ|D-MjBUX^SKQ3lmDe%06?ko%$Jln O7bc6)sC58;Qkbj7UP}HEmh|s<2;G`>9C`Y9F74TX?)iy??zjo zgn1u7!W#G>RxY>To$8)~7XKp7$JibGAg-raUXt K4krU3L6HD0B-C>!v80ZFkr|)pZ$v2 z0gIq1-jirQi1!$1yc+L*c@K->y$;tc;`~P7iF4^zfuoPN;|Zw?0l!Ww!a2o}j{^EI zq8BnvWL!%Uy~IJZItJ}Vw4!T7tK)dr>7~ |}5tdgvSU-4_lc6c-z_=-1Gi%v;{p_OhtN4sS zA2^8Rcd&%uUcjEP!>)BA&frG;&5P)79W0Chq7ETgm=P95d-W_1sYn94G$@rtv?b3P zu!DaSn+K1-1y*PqYiAwUm!OMv OkS#(_Euq&fW=q&o zwu~)jE7(f(%GGQQTg%n~<_&Bk+r&1r%h=^?3%i0{$+og>u&b_OJJ?RPi|uB6*eLrG z_Rs8Q_8#^mdz9VA&au1MEs*33oRZ*Sgmdg)$*tVR?cBkg+{NA8gA9Bhuj76mz_ZCi zJdAycqdbOfq2jQ9lRU-KJj1g*$Md{_H}WPvk2mucWb?Q2cHY4|c^B{IJ=lu6mlt^- z@8<)2kk97}_z+*n7x7_U;v;-9`s*LFPqNRj&$8#hmrt`lV`tgB(c_*+um2KX%HGSq z%9ruww$bqe2fDkudJ5)QcYoz k>J)ZA04xu;Td zp;9wk0|Tl;rRG8fzCxvqLZyvDrHw+RjY6f3LZyw~N*leEHhL><^j6yFt+dfwX`{E& zMsKB!-bx$2l{We+zv!#{qObCczREB9D!=HjK-FJ?rN078e+8EQO3nS1n)@p?_g8A} zuhcwHsd=D+??9!Efl3<#l{N+{Z46Y}7^t){P-$bJ(#Bw=jloJAgOxT0D{Tx`+8C^~ zF<5D1u+m1qUQ1thq1a =6V>8sw-x=S~2mOVR zk8x(`B=d_)-t{_vzctb&Nd1Q|?8PtlF<4G)497T|Kna_S9bi|Z)L#e969$X!|GoYn z1umh$;Y+U6zHp@WWpVW=JI0Q)DRzRLWT)6Qh=848*Rt!_+u(P;gT0eo&)&su!1#8K z-N HdR!na~Peh)^u+u8fr9e7s#UF`iBo$q1i*}d!nyN`W<-OnCiA7l@*53z^X z!|cQC5%v*`;(ve$@8j$VjOZW5X!#WTL-uj@NB<6NZ}rvF>=WWE8inD3U<9VIm@#-D z>~rk%> u@pm16CqG;HyOHA$(EWaoFnh(Q zFeXNXNiiB6W(V1qF#;TBN7(PauX@4nPYCOm>|W}1&lo+9dK>ktFAFwfw6}c-UhIAF z6s)#A@HZOZZFu2JP}wBPW>L0?vQ?DrusOW&FX*05QTB+kAj+aB`)6Lkw+qGjDp76{ z CF^MO|bd?Pv^7bX3+QT( c`~#BV#qx1Ff75qu?@cQWE*r?|6|4T|%jnSa5RrKq_RFjKi%lv}~aPPRkb zGcHPMw@0+wBlz0`tmz6}FMu+Sp!A87Xi^X~DWI(g&gTP$0-&PnM4tlMqH?XcvPs-S zvQ&U)O7~nL%B`X#S{2Yr9A2*n=S4w>A|#E@6R5d}wx}fP6>&x-ala_&P!uf|MT &}^8#^w2*3SnP{AiklFuP=&ycuhh*4V$#cvnl{y6#@ z$>AzN)m4J3tI+!zab>$GcZibiTra4%N!-6l$ipTf51T~0o5l6b;`(NBeY3c}1@Jrt z9#bn@02Q5+uGk{(*&=%S7IEh`-1#qvPxwSh_iPjQY{&Ii01ef!9pBP9eY@TGmZ-4< z_xv47pD5|u9pc*^qULeI<#A{QKX^~lGA?xEIQk-;6W_ yV$ zRFZBS7kz46=$vuU`^Lcyy1o!p8W$RD9B~)ALb5jwT&dhHN|L}sXod7nKX`G7EdWM` z*bvT-!XEUZykX{tD9_IPFO=tIev0yD+;f!O3d$UX1?WKeh`9b3t{i7aXMTzDlqhdR zIR$Eb5v5O*iJ9- xnt%zoZl&~-zBcR zUzB%?@ |)Q%T_}B`OyJJz!C5MgqR#7q_3J2a z6y@Eh^LlnaO4!n(d<^9csNshweWFa@SBU$G@~F6S0 -fKBFe`A;aSv4*FTPX&Y{k)qx6aL zD0qDiRQeZ`*WjLWsFSYTfELd|#_0YV#kcPj-`)ZGpA$4ZhuVG#Z{#}2+l_*oH-ek5 z |_qZKOOhw=`5`%CyU=SBG_ zT719Y(fb9D;Nt-6_XCEXldpqs?-8}#!yd)`=fQ G!!LRe z5#R^KZy$s#y^eE&?O}1{VdI=?`!L%5N0dHMZpJ;2;L1-?`cQsEzzL5EcRniGeH87| zInn=7aF$A<{Ks(Tk6_&sv`>lppAx?!Bh8EBYc|X)OOhmGp*mKB;+ci|2YePUNwQch zvbFLNCz$LuUf3cZX+*e#iwmd(72t^?`eiIu5nsz#v4R>b_(ukq@uHuis;W;|s)Uc? z3M$gu&`U{t!elT$;@@I7K(yGc5}unY*=#_>jt91(IocL%77u(fUIGurhONw~5(W1G z5Anh$O710S=Hg)h2Vig};U`$vsn`@GwOQz~2>2bK(JRqQ+=v 7 zCK7BwlK25o=sNg97~un;SL}+4f3c!S;DMjwrI-3Un!!hbDd8#5HL4PyD*VDew}6v= z?F47=Y%YfbcsN~z2SE-z@J@KpO~y;d!(RCaATGiK7c~7B0uMzJz+ssd8k&oTMYZbn zptV|ffL#jh7e{o^X{DDCdHRKcr-JQ24Ln@n44%~G!~`dExi!KAy}&B)(C8+7GG0Jf zL&_ 0C dw_wxe4!sJFCc8Qsc!lV;8huKNT3xTRe%BZW8-OCZ9FViBBP>W z{U>U$;UD{iQ{9Azs6#JF6jT+>;0?>AFU13l5d0EyXR-NoJX9NYAeJ52kb?#gUmf;D zF!8{9O*}jTa03r)z$HFXqhLJYL1HO{j`%@Bg3Gu@{4((Hs5Xyg!#WJY156;uMFrxc zj)zvk13Mz)K9eiD+!_1=(sil>Z9hy^B2Wb=4elb7ncDw4u z*R*{Y)?R8@B@9HwKjDFw-7cynW|3+UM1}|gSRD^LaPg{kuV%-VCIkRBowBRYADRsZ zU7$~PyN2XK{1d;3)p(iwA}J(1=!(VeH}J6gu^WLCdpgts4}TDQr$Cf7%}ISs;33+e zb~FtFhz7iL3g9)|hf$P1VOJNl3r?frxp)Xt6CNt?0AX>P1vLmfL?!qLc kC$f_e@fcyKu6PUn|u59oMk_MlHuTmjkd2OfdY96U4!F-0^Y3Po`^9GZ{L4Lq<9 zj`&8$gJc9x2NA7;jKmKE4}7u{>7j6O_%w&l>Tv0JfSV3chk*y~&@_j`iZ>*r34Y=6 zT{sg};R3x^@NfhHBK_PEsskR_kpRgwEEslxAJ7(7mmr_O1D}kSz{6Un;Ul)!vMSJy zc;*nj@R%?>5lP_T#1MiPDhCY|0UWv}2@feIs{==!)q#Jv72uJ8;HUJ`OF%^Dz(Z6? zib
~Xayo5zbCS>k51ms6 zzYIKdxzn5xfJi@gMgofBi6|i?9I 7?6vp`CbHc2mPnp77aU+W_D1hZ(! z5<~_+ASB=mMg n<4pGP6MlXA0p82qTAm
u=lb8G7BwxM5F!pjphq()-MFc-B%cvc>TwvTW!V;x{@R o%HYg%Gv8NwjqBn|QG8Wg`6}{ZH1SzNR!)ibk3;nA9(>3DKjUreIsgCw literal 0 HcmV?d00001 diff --git a/html/app.js b/html/app.js new file mode 100644 index 0000000..f86977a --- /dev/null +++ b/html/app.js @@ -0,0 +1,951 @@ +const InventoryContainer = Vue.createApp({ + data() { + return this.getInitialState(); + }, + computed: { + playerWeight() { + const weight = Object.values(this.playerInventory).reduce((total, item) => { + if (item && item.weight !== undefined && item.amount !== undefined) { + return total + item.weight * item.amount; + } + return total; + }, 0); + return isNaN(weight) ? 0 : weight; + }, + otherInventoryWeight() { + const weight = Object.values(this.otherInventory).reduce((total, item) => { + if (item && item.weight !== undefined && item.amount !== undefined) { + return total + item.weight * item.amount; + } + return total; + }, 0); + return isNaN(weight) ? 0 : weight; + }, + weightBarClass() { + const weightPercentage = (this.playerWeight / this.maxWeight) * 100; + if (weightPercentage < 50) { + return "low"; + } else if (weightPercentage < 75) { + return "medium"; + } else { + return "high"; + } + }, + otherWeightBarClass() { + const weightPercentage = (this.otherInventoryWeight / this.otherInventoryMaxWeight) * 100; + if (weightPercentage < 50) { + return "low"; + } else if (weightPercentage < 75) { + return "medium"; + } else { + return "high"; + } + }, + shouldCenterInventory() { + return this.isOtherInventoryEmpty; + }, + }, + watch: { + transferAmount(newVal) { + if (newVal !== null && newVal < 1) this.transferAmount = 1; + }, + }, + methods: { + getInitialState() { + return { + // Config Options + maxWeight: 0, + totalSlots: 0, + // Escape Key + isInventoryOpen: false, + // Single pane + isOtherInventoryEmpty: true, + // Error handling + errorSlot: null, + // Player Inventory + playerInventory: {}, + inventoryLabel: "Inventory", + totalWeight: 0, + // Other inventory + otherInventory: {}, + otherInventoryName: "", + otherInventoryLabel: "Drop", + otherInventoryMaxWeight: 1000000, + otherInventorySlots: 100, + isShopInventory: false, + // Where item is coming from + inventory: "", + // Context Menu + showContextMenu: false, + contextMenuPosition: { top: "0px", left: "0px" }, + contextMenuItem: null, + showSubmenu: false, + // Hotbar + showHotbar: false, + hotbarItems: [], + // Notification box + showNotification: false, + notificationText: "", + notificationImage: "", + notificationType: "added", + notificationAmount: 1, + // Required items box + showRequiredItems: false, + requiredItems: [], + // Attachments + selectedWeapon: null, + showWeaponAttachments: false, + selectedWeaponAttachments: [], + // Dragging and dropping + currentlyDraggingItem: null, + currentlyDraggingSlot: null, + dragStartX: 0, + dragStartY: 0, + ghostElement: null, + dragStartInventoryType: "player", + transferAmount: null, + }; + }, + openInventory(data) { + if (this.showHotbar) { + this.toggleHotbar(false); + } + + this.isInventoryOpen = true; + this.maxWeight = data.maxweight; + this.totalSlots = data.slots; + this.playerInventory = {}; + this.otherInventory = {}; + + if (data.inventory) { + if (Array.isArray(data.inventory)) { + data.inventory.forEach((item) => { + if (item && item.slot) { + this.playerInventory[item.slot] = item; + } + }); + } else if (typeof data.inventory === "object") { + for (const key in data.inventory) { + const item = data.inventory[key]; + if (item && item.slot) { + this.playerInventory[item.slot] = item; + } + } + } + } + + if (data.other) { + if (data.other && data.other.inventory) { + if (Array.isArray(data.other.inventory)) { + data.other.inventory.forEach((item) => { + if (item && item.slot) { + this.otherInventory[item.slot] = item; + } + }); + } else if (typeof data.other.inventory === "object") { + for (const key in data.other.inventory) { + const item = data.other.inventory[key]; + if (item && item.slot) { + this.otherInventory[item.slot] = item; + } + } + } + } + + this.otherInventoryName = data.other.name; + this.otherInventoryLabel = data.other.label; + this.otherInventoryMaxWeight = data.other.maxweight; + this.otherInventorySlots = data.other.slots; + + if (this.otherInventoryName.startsWith("shop-")) { + this.isShopInventory = true; + } else { + this.isShopInventory = false; + } + + this.isOtherInventoryEmpty = false; + } + }, + updateInventory(data) { + this.playerInventory = {}; + + if (data.inventory) { + if (Array.isArray(data.inventory)) { + data.inventory.forEach((item) => { + if (item && item.slot) { + this.playerInventory[item.slot] = item; + } + }); + } else if (typeof data.inventory === "object") { + for (const key in data.inventory) { + const item = data.inventory[key]; + if (item && item.slot) { + this.playerInventory[item.slot] = item; + } + } + } + } + }, + async closeInventory() { + let inventoryName = this.otherInventoryName; + Object.assign(this, this.getInitialState()); + try { + await axios.post("https://qb-inventory/CloseInventory", { name: inventoryName }); + } catch (error) { + console.error("Error closing inventory:", error); + } + }, + clearTransferAmount() { + this.transferAmount = null; + }, + getItemInSlot(slot, inventoryType) { + if (inventoryType === "player") { + return this.playerInventory[slot] || null; + } else if (inventoryType === "other") { + return this.otherInventory[slot] || null; + } + return null; + }, + getHotbarItemInSlot(slot) { + return this.hotbarItems[slot - 1] || null; + }, + containerMouseDownAction(event) { + if (event.button === 0 && this.showContextMenu) { + this.showContextMenu = false; + } + }, + handleMouseDown(event, slot, inventory) { + if (event.button === 1) return; // skip middle mouse + event.preventDefault(); + const itemInSlot = this.getItemInSlot(slot, inventory); + if (event.button === 0) { + if (event.shiftKey && itemInSlot) { + this.splitAndPlaceItem(itemInSlot, inventory); + } else { + this.startDrag(event, slot, inventory); + } + } else if (event.button === 2 && itemInSlot) { + if (this.otherInventoryName.startsWith("shop-")) { + this.handlePurchase(slot, itemInSlot.slot, itemInSlot, 1); + return; + } + if (!this.isOtherInventoryEmpty) { + this.moveItemBetweenInventories(itemInSlot, inventory); + } else { + this.showContextMenuOptions(event, itemInSlot); + } + } + }, + moveItemBetweenInventories(item, sourceInventoryType) { + const sourceInventory = sourceInventoryType === "player" ? this.playerInventory : this.otherInventory; + const targetInventory = sourceInventoryType === "player" ? this.otherInventory : this.playerInventory; + const amountToTransfer = this.transferAmount !== null ? this.transferAmount : 1; + let targetSlot = null; + + const sourceItem = sourceInventory[item.slot]; + if (!sourceItem || sourceItem.amount < amountToTransfer) { + this.inventoryError(item.slot); + return; + } + + const totalWeightAfterTransfer = this.otherInventoryWeight + sourceItem.weight * amountToTransfer; + if (totalWeightAfterTransfer > this.otherInventoryMaxWeight) { + this.inventoryError(item.slot); + return; + } + + if (item.unique) { + targetSlot = this.findNextAvailableSlot(targetInventory); + if (targetSlot === null) { + this.inventoryError(item.slot); + return; + } + + const newItem = { + ...item, + inventory: sourceInventoryType === "player" ? "other" : "player", + amount: amountToTransfer, + }; + targetInventory[targetSlot] = newItem; + newItem.slot = targetSlot; + } else { + const targetItemKey = Object.keys(targetInventory).find((key) => targetInventory[key] && targetInventory[key].name === item.name); + const targetItem = targetInventory[targetItemKey]; + + if (!targetItem) { + const newItem = { + ...item, + inventory: sourceInventoryType === "player" ? "other" : "player", + amount: amountToTransfer, + }; + + targetSlot = this.findNextAvailableSlot(targetInventory); + if (targetSlot === null) { + this.inventoryError(item.slot); + return; + } + + targetInventory[targetSlot] = newItem; + newItem.slot = targetSlot; + } else { + targetItem.amount += amountToTransfer; + targetSlot = targetItem.slot; + } + } + + sourceItem.amount -= amountToTransfer; + + if (sourceItem.amount <= 0) { + delete sourceInventory[item.slot]; + } + + this.postInventoryData(sourceInventoryType, sourceInventoryType === "player" ? "other" : "player", item.slot, targetSlot, sourceItem.amount, amountToTransfer); + }, + startDrag(event, slot, inventoryType) { + event.preventDefault(); + const item = this.getItemInSlot(slot, inventoryType); + if (!item) return; + const slotElement = event.target.closest(".item-slot"); + if (!slotElement) return; + const ghostElement = this.createGhostElement(slotElement); + document.body.appendChild(ghostElement); + const offsetX = ghostElement.offsetWidth / 2; + const offsetY = ghostElement.offsetHeight / 2; + ghostElement.style.left = `${event.clientX - offsetX}px`; + ghostElement.style.top = `${event.clientY - offsetY}px`; + this.ghostElement = ghostElement; + this.currentlyDraggingItem = item; + this.currentlyDraggingSlot = slot; + this.dragStartX = event.clientX; + this.dragStartY = event.clientY; + this.dragStartInventoryType = inventoryType; + this.showContextMenu = false; + }, + createGhostElement(slotElement) { + const ghostElement = slotElement.cloneNode(true); + ghostElement.style.position = "absolute"; + ghostElement.style.pointerEvents = "none"; + ghostElement.style.opacity = "0.7"; + ghostElement.style.zIndex = "1000"; + ghostElement.style.width = getComputedStyle(slotElement).width; + ghostElement.style.height = getComputedStyle(slotElement).height; + ghostElement.style.boxSizing = "border-box"; + return ghostElement; + }, + drag(event) { + if (!this.currentlyDraggingItem) return; + const centeredX = event.clientX - this.ghostElement.offsetWidth / 2; + const centeredY = event.clientY - this.ghostElement.offsetHeight / 2; + this.ghostElement.style.left = `${centeredX}px`; + this.ghostElement.style.top = `${centeredY}px`; + }, + endDrag(event) { + if (!this.currentlyDraggingItem) { + return; + } + const targetPlayerItemSlotElement = event.target.closest(".player-inventory .item-slot"); + if (targetPlayerItemSlotElement) { + const targetSlot = Number(targetPlayerItemSlotElement.dataset.slot); + if (targetSlot && !(targetSlot === this.currentlyDraggingSlot && this.dragStartInventoryType === "player")) { + this.handleDropOnPlayerSlot(targetSlot); + } + } + const targetOtherItemSlotElement = event.target.closest(".other-inventory .item-slot"); + if (targetOtherItemSlotElement) { + const targetSlot = Number(targetOtherItemSlotElement.dataset.slot); + if (targetSlot && !(targetSlot === this.currentlyDraggingSlot && this.dragStartInventoryType === "other")) { + this.handleDropOnOtherSlot(targetSlot); + } + } + const targetInventoryContainer = event.target.closest(".inventory-container"); + if (targetInventoryContainer && !targetPlayerItemSlotElement && !targetOtherItemSlotElement) { + this.handleDropOnInventoryContainer(); + } + this.clearDragData(); + }, + handleDropOnPlayerSlot(targetSlot) { + if (this.isShopInventory && this.dragStartInventoryType === "other") { + const { currentlyDraggingSlot, currentlyDraggingItem, transferAmount } = this; + const targetInventory = this.getInventoryByType("player"); + const targetItem = targetInventory[targetSlot]; + if ((targetItem && targetItem.name !== currentlyDraggingItem.name) || (targetItem && targetItem.name === currentlyDraggingItem.name && currentlyDraggingItem.unique)) { + this.inventoryError(currentlyDraggingSlot); + return; + } + this.handlePurchase(targetSlot, currentlyDraggingSlot, currentlyDraggingItem, transferAmount); + } else { + this.handleItemDrop("player", targetSlot); + } + }, + handleDropOnOtherSlot(targetSlot) { + this.handleItemDrop("other", targetSlot); + }, + async handleDropOnInventoryContainer() { + if (this.isOtherInventoryEmpty && this.dragStartInventoryType === "player") { + const newItem = { + ...this.currentlyDraggingItem, + amount: this.currentlyDraggingItem.amount, + slot: 1, + inventory: "other", + }; + const draggingItem = this.currentlyDraggingItem; + try { + const response = await axios.post("https://qb-inventory/DropItem", { + ...newItem, + fromSlot: this.currentlyDraggingSlot, + }); + + if (response.data) { + this.otherInventory[1] = newItem; + const draggingItemKey = Object.keys(this.playerInventory).find((key) => this.playerInventory[key] === draggingItem); + if (draggingItemKey) { + delete this.playerInventory[draggingItemKey]; + } + this.otherInventoryName = response.data; + this.otherInventoryLabel = response.data; + this.isOtherInventoryEmpty = false; + this.clearDragData(); + } + } catch (error) { + this.inventoryError(this.currentlyDraggingSlot); + } + } + this.clearDragData(); + }, + clearDragData() { + if (this.ghostElement) { + document.body.removeChild(this.ghostElement); + this.ghostElement = null; + } + this.currentlyDraggingItem = null; + this.currentlyDraggingSlot = null; + }, + getInventoryByType(inventoryType) { + return inventoryType === "player" ? this.playerInventory : this.otherInventory; + }, + handleItemDrop(targetInventoryType, targetSlot) { + try { + const isShop = this.otherInventoryName.indexOf("shop-"); + if (this.dragStartInventoryType === "other" && targetInventoryType === "other" && isShop !== -1) { + return; + } + + const targetSlotNumber = parseInt(targetSlot, 10); + if (isNaN(targetSlotNumber)) { + throw new Error("Invalid target slot number"); + } + + const sourceInventory = this.getInventoryByType(this.dragStartInventoryType); + const targetInventory = this.getInventoryByType(targetInventoryType); + + const sourceItem = sourceInventory[this.currentlyDraggingSlot]; + if (!sourceItem) { + throw new Error("No item in the source slot to transfer"); + } + + const amountToTransfer = this.transferAmount !== null ? this.transferAmount : sourceItem.amount; + if (sourceItem.amount < amountToTransfer) { + throw new Error("Insufficient amount of item in source inventory"); + } + + if (targetInventoryType !== this.dragStartInventoryType) { + if (targetInventoryType == "other") { + const totalWeightAfterTransfer = this.otherInventoryWeight + sourceItem.weight * amountToTransfer; + if (totalWeightAfterTransfer > this.otherInventoryMaxWeight) { + throw new Error("Insufficient weight capacity in target inventory"); + } + } + else if (targetInventoryType == "player") { + const totalWeightAfterTransfer = this.playerWeight + sourceItem.weight * amountToTransfer; + if (totalWeightAfterTransfer > this.maxWeight) { + throw new Error("Insufficient weight capacity in player inventory"); + } + } + } + + const targetItem = targetInventory[targetSlotNumber]; + + if (targetItem) { + if (sourceItem.name === targetItem.name && targetItem.unique) { + this.inventoryError(this.currentlyDraggingSlot); + return; + } + if (sourceItem.name === targetItem.name && !targetItem.unique) { + targetItem.amount += amountToTransfer; + sourceItem.amount -= amountToTransfer; + if (sourceItem.amount <= 0) { + delete sourceInventory[this.currentlyDraggingSlot]; + } + this.postInventoryData(this.dragStartInventoryType, targetInventoryType, this.currentlyDraggingSlot, targetSlotNumber, sourceItem.amount, amountToTransfer); + } else { + sourceInventory[this.currentlyDraggingSlot] = targetItem; + targetInventory[targetSlotNumber] = sourceItem; + sourceInventory[this.currentlyDraggingSlot].slot = this.currentlyDraggingSlot; + targetInventory[targetSlotNumber].slot = targetSlotNumber; + this.postInventoryData(this.dragStartInventoryType, targetInventoryType, this.currentlyDraggingSlot, targetSlotNumber, sourceItem.amount, targetItem.amount); + } + } else { + sourceItem.amount -= amountToTransfer; + if (sourceItem.amount <= 0) { + delete sourceInventory[this.currentlyDraggingSlot]; + } + targetInventory[targetSlotNumber] = { ...sourceItem, amount: amountToTransfer, slot: targetSlotNumber }; + this.postInventoryData(this.dragStartInventoryType, targetInventoryType, this.currentlyDraggingSlot, targetSlotNumber, sourceItem.amount, amountToTransfer); + } + } catch (error) { + console.error(error.message); + this.inventoryError(this.currentlyDraggingSlot); + } finally { + this.clearDragData(); + } + }, + async handlePurchase(targetSlot, sourceSlot, sourceItem, transferAmount) { + try { + const response = await axios.post("https://qb-inventory/AttemptPurchase", { + item: sourceItem, + amount: transferAmount || sourceItem.amount, + shop: this.otherInventoryName, + }); + if (response.data) { + const sourceInventory = this.getInventoryByType("other"); + const targetInventory = this.getInventoryByType("player"); + const amountToTransfer = transferAmount !== null ? transferAmount : sourceItem.amount; + if (sourceItem.amount < amountToTransfer) { + this.inventoryError(sourceSlot); + return; + } + let targetItem = targetInventory[targetSlot]; + if (!targetItem || targetItem.name !== sourceItem.name) { + let foundSlot = Object.keys(targetInventory).find((slot) => targetInventory[slot] && targetInventory[slot].name === sourceItem.name); + if (foundSlot) { + targetInventory[foundSlot].amount += amountToTransfer; + } else { + const targetInventoryKeys = Object.keys(targetInventory); + if (targetInventoryKeys.length < this.totalSlots) { + let freeSlot = Array.from({ length: this.totalSlots }, (_, i) => i + 1).find((i) => !(i in targetInventory)); + targetInventory[freeSlot] = { + ...sourceItem, + amount: amountToTransfer, + }; + } else { + this.inventoryError(sourceSlot); + return; + } + } + } else { + targetItem.amount += amountToTransfer; + } + sourceItem.amount -= amountToTransfer; + if (sourceItem.amount <= 0) { + delete sourceInventory[sourceSlot]; + } + } else { + this.inventoryError(sourceSlot); + } + } catch (error) { + this.inventoryError(sourceSlot); + } + }, + async dropItem(item, quantity) { + if (item && item.name) { + const playerItemKey = Object.keys(this.playerInventory).find((key) => this.playerInventory[key] && this.playerInventory[key].slot === item.slot); + if (playerItemKey) { + let amountToGive; + + if (typeof quantity === "string") { + switch (quantity) { + case "half": + amountToGive = Math.ceil(item.amount / 2); + break; + case "all": + amountToGive = item.amount; + break; + default: + console.error("Invalid quantity specified."); + return; + } + } else if (typeof quantity === "number" && quantity > 0) { + amountToGive = quantity; + } else { + console.error("Invalid quantity type specified."); + return; + } + + if (amountToGive > item.amount) { + amountToGive = item.amount; + } + + const newItem = { + ...item, + amount: amountToGive, + slot: 1, + inventory: "other", + }; + + try { + const response = await axios.post("https://qb-inventory/DropItem", { + ...newItem, + fromSlot: item.slot, + }); + + if (response.data) { + delete this.playerInventory[playerItemKey]; + this.otherInventory[1] = newItem; + this.otherInventoryName = response.data; + this.otherInventoryLabel = response.data; + this.isOtherInventoryEmpty = false; + } + } catch (error) { + this.inventoryError(item.slot); + } + } + } + this.showContextMenu = false; + }, + async useItem(item) { + if (!item || item.useable === false) { + return; + } + const playerItemKey = Object.keys(this.playerInventory).find((key) => this.playerInventory[key] && this.playerInventory[key].slot === item.slot); + if (playerItemKey) { + try { + await axios.post("https://qb-inventory/UseItem", { + inventory: "player", + item: item, + }); + if (item.shouldClose) { + this.closeInventory(); + } + } catch (error) { + console.error("Error using the item: ", error); + } + } + this.showContextMenu = false; + }, + showContextMenuOptions(event, item) { + event.preventDefault(); + if (this.contextMenuItem && this.contextMenuItem.name === item.name && this.showContextMenu) { + this.showContextMenu = false; + this.contextMenuItem = null; + } else { + if (item.inventory === "other") { + const matchingItemKey = Object.keys(this.playerInventory).find((key) => this.playerInventory[key].name === item.name); + const matchingItem = this.playerInventory[matchingItemKey]; + + if (matchingItem && matchingItem.unique) { + const newItemKey = Object.keys(this.playerInventory).length + 1; + const newItem = { + ...item, + inventory: "player", + amount: 1, + }; + this.playerInventory[newItemKey] = newItem; + } else if (matchingItem) { + matchingItem.amount++; + } else { + const newItemKey = Object.keys(this.playerInventory).length + 1; + const newItem = { + ...item, + inventory: "player", + amount: 1, + }; + this.playerInventory[newItemKey] = newItem; + } + item.amount--; + + if (item.amount <= 0) { + const itemKey = Object.keys(this.otherInventory).find((key) => this.otherInventory[key] === item); + if (itemKey) { + delete this.otherInventory[itemKey]; + } + } + } + const menuLeft = event.clientX; + const menuTop = event.clientY; + this.showContextMenu = true; + this.contextMenuPosition = { + top: `${menuTop}px`, + left: `${menuLeft}px`, + }; + this.contextMenuItem = item; + } + }, + async giveItem(item, quantity) { + if (item && item.name) { + const selectedItem = item; + const playerHasItem = Object.values(this.playerInventory).some((invItem) => invItem && invItem.name === selectedItem.name); + + if (playerHasItem) { + let amountToGive; + if (typeof quantity === "string") { + switch (quantity) { + case "half": + amountToGive = Math.ceil(selectedItem.amount / 2); + break; + case "all": + amountToGive = selectedItem.amount; + break; + default: + console.error("Invalid quantity specified."); + return; + } + } else { + amountToGive = quantity; + } + + if (amountToGive > selectedItem.amount) { + console.error("Specified quantity exceeds available amount."); + return; + } + + try { + const response = await axios.post("https://qb-inventory/GiveItem", { + item: selectedItem, + amount: amountToGive, + slot: selectedItem.slot, + info: selectedItem.info, + }); + if (!response.data) return; + + this.playerInventory[selectedItem.slot].amount -= amountToGive; + if (this.playerInventory[selectedItem.slot].amount === 0) { + delete this.playerInventory[selectedItem.slot]; + } + } catch (error) { + console.error("An error occurred while giving the item:", error); + } + } else { + console.error("Player does not have the item in their inventory. Item cannot be given."); + } + } + this.showContextMenu = false; + }, + findNextAvailableSlot(inventory) { + for (let slot = 1; slot <= this.totalSlots; slot++) { + if (!inventory[slot]) { + return slot; + } + } + return null; + }, + splitAndPlaceItem(item, inventoryType) { + const inventoryRef = inventoryType === "player" ? this.playerInventory : this.otherInventory; + if (item && item.amount > 1) { + const originalSlot = Object.keys(inventoryRef).find((key) => inventoryRef[key] === item); + if (originalSlot !== undefined) { + const newItem = { ...item, amount: Math.ceil(item.amount / 2) }; + const nextSlot = this.findNextAvailableSlot(inventoryRef); + if (nextSlot !== null) { + inventoryRef[nextSlot] = newItem; + inventoryRef[originalSlot] = { ...item, amount: Math.floor(item.amount / 2) }; + this.postInventoryData(inventoryType, inventoryType, originalSlot, nextSlot, item.amount, newItem.amount); + } + } + } + this.showContextMenu = false; + }, + toggleHotbar(data) { + if (data.open) { + this.hotbarItems = data.items; + this.showHotbar = true; + } else { + this.showHotbar = false; + this.hotbarItems = []; + } + }, + showItemNotification(itemData) { + this.notificationText = itemData.item.label; + this.notificationImage = "images/" + itemData.item.image; + this.notificationType = itemData.type === "add" ? "Received" : itemData.type === "use" ? "Used" : "Removed"; + this.notificationAmount = itemData.amount || 1; + this.showNotification = true; + setTimeout(() => { + this.showNotification = false; + }, 3000); + }, + showRequiredItem(data) { + if (data.toggle) { + this.requiredItems = data.items; + this.showRequiredItems = true; + } else { + setTimeout(() => { + this.showRequiredItems = false; + this.requiredItems = []; + }, 100); + } + }, + inventoryError(slot) { + const slotElement = document.getElementById(`slot-${slot}`); + if (slotElement) { + slotElement.style.backgroundColor = "red"; + } + axios.post("https://qb-inventory/PlayDropFail", {}).catch((error) => { + console.error("Error playing drop fail:", error); + }); + setTimeout(() => { + if (slotElement) { + slotElement.style.backgroundColor = ""; + } + }, 1000); + }, + copySerial() { + if (!this.contextMenuItem) { + return; + } + const item = this.contextMenuItem; + if (item) { + const el = document.createElement("textarea"); + el.value = item.info.serie; + document.body.appendChild(el); + el.select(); + document.execCommand("copy"); + document.body.removeChild(el); + } + }, + openWeaponAttachments() { + if (!this.contextMenuItem) { + return; + } + if (!this.showWeaponAttachments) { + this.selectedWeapon = this.contextMenuItem; + this.showWeaponAttachments = true; + axios + .post("https://qb-inventory/GetWeaponData", JSON.stringify({ weapon: this.selectedWeapon.name, ItemData: this.selectedWeapon })) + .then((response) => { + const data = response.data; + if (data.AttachmentData !== null && data.AttachmentData !== undefined) { + if (data.AttachmentData.length > 0) { + this.selectedWeaponAttachments = data.AttachmentData; + } + } + }) + .catch((error) => { + console.error(error); + }); + } else { + this.showWeaponAttachments = false; + this.selectedWeapon = null; + this.selectedWeaponAttachments = []; + } + }, + removeAttachment(attachment) { + if (!this.selectedWeapon) { + return; + } + const index = this.selectedWeaponAttachments.indexOf(attachment); + if (index !== -1) { + this.selectedWeaponAttachments.splice(index, 1); + } + axios + .post("https://qb-inventory/RemoveAttachment", JSON.stringify({ AttachmentData: attachment, WeaponData: this.selectedWeapon })) + .then((response) => { + this.selectedWeapon = response.data.WeaponData; + if (response.data.Attachments) { + this.selectedWeaponAttachments = response.data.Attachments; + } + const nextSlot = this.findNextAvailableSlot(this.playerInventory); + if (nextSlot !== null) { + response.data.itemInfo.amount = 1; + this.playerInventory[nextSlot] = response.data.itemInfo; + } + }) + .catch((error) => { + console.error(error); + this.selectedWeaponAttachments.splice(index, 0, attachment); + }); + }, + generateTooltipContent(item) { + if (!item) { + return ""; + } + let content = ` `; + return content; + }, + formatKey(key) { + return key.replace(/_/g, " ").charAt(0).toUpperCase() + key.slice(1); + }, + postInventoryData(fromInventory, toInventory, fromSlot, toSlot, fromAmount, toAmount) { + let fromInventoryName = fromInventory === "other" ? this.otherInventoryName : fromInventory; + let toInventoryName = toInventory === "other" ? this.otherInventoryName : toInventory; + + axios + .post("https://qb-inventory/SetInventoryData", { + fromInventory: fromInventoryName, + toInventory: toInventoryName, + fromSlot, + toSlot, + fromAmount, + toAmount, + }) + .then((response) => { + this.clearDragData(); + }) + .catch((error) => { + console.error("Error posting inventory data:", error); + }); + }, + }, + mounted() { + window.addEventListener("keydown", (event) => { + const key = event.key; + if (key === "Escape") { + if (this.isInventoryOpen) { + this.closeInventory(); + } + } else if (key === "Tab") { + event.preventDefault(); + } + }); + + window.addEventListener("message", (event) => { + switch (event.data.action) { + case "open": + this.openInventory(event.data); + break; + case "close": + this.closeInventory(); + break; + case "update": + this.updateInventory(event.data); + break; + case "toggleHotbar": + this.toggleHotbar(event.data); + break; + case "itemBox": + this.showItemNotification(event.data); + break; + case "requiredItem": + this.showRequiredItem(event.data); + break; + default: + console.warn(`Unexpected action: ${event.data.action}`); + } + }); + }, + beforeUnmount() { + window.removeEventListener("mousemove", () => {}); + window.removeEventListener("keydown", () => {}); + window.removeEventListener("message", () => {}); + }, +}); + +InventoryContainer.use(FloatingVue); +InventoryContainer.mount("#app"); diff --git a/html/images/10kgoldchain.png b/html/images/10kgoldchain.png new file mode 100644 index 0000000000000000000000000000000000000000..8536be264bb8c91a3a782505d4ad224330a90ebc GIT binary patch literal 33481 zcmd752Ygl4*6s}=(m^>Qf|MA7h_J~jd$mX>lu(u41XqR75(rgL5dlSM2C0IIAPQ2H z9zc2z<${item.label}
`; + const description = item.info && item.info.description ? item.info.description.replace(/\n/g, "
") : item.description ? item.description.replace(/\n/g, "
") : "No description available."; + + if (item.info && Object.keys(item.info).length > 0) { + for (const [key, value] of Object.entries(item.info)) { + if (key !== "description") { + let valueStr = value; + if (key === "attachments") { + valueStr = Object.keys(value).length > 0 ? "true" : "false"; + } + content += `${this.formatKey(key)}: ${valueStr}`; + } + } + } + + content += `${description}`; + content += `${item.weight !== undefined && item.weight !== null ? (item.weight / 1000).toFixed(1) : "N/A"}kg`; + + content += `~p z;(4=W%T^$%USd=J?}`6%Kg6%8r^h$ve|b{twMomCE#E)Hf7!E5nfiFPY+Y_9H*ej$ zb)$v}Zc6t`wwL1gmHKy2<<;4;Rj$@Q)poo3y<;4|Q*w_gvEQv+6C0E4Rf%n-HIf>o z*77?i*L$g#-|VHv&E1!}x|SDPt!hl={s|1w-S2J3^zYuSM_NMvDzRDPCh&Xl 6CmD0 0*RNlterlzZUY+7)%d+AnC0Pwy(RO!fX6x~KjzY>%|x_K6*f?{BBZ z%atUtrmPow?jNs9?bEAU)`xp;yx-05?)T`O#%tw2UYpuErFTkN=ajz~`j5Z a^wqQvLX*ep*VOUanueFVigZ`)bm9H}(H( zKSR8om;dqR-pRpVyjT3q|FS5*fAU|vRQ$~!FHKFT)yubgr}S!`lG5#W<9Y7)U5u$! z3tN%Rn5SDM_wZ8srIi=U`0YJ@qTSoC5-V&eA{h}`X)Z?-q6+_3kdy>Ty8qHfDPD3g z;E$I^Ba#x4qs?U_LDCZxsRG9L$4jwf&+cvi#}|8ULXgs{yUk-r?rwMT<5PQdijDc> z;U?5d>6X%q4`z01)+`z|N=WLF*4ysk`bmjZVp&3^ FkIdbtAT=N)gR4 zT-8?s-88)4M{Ck6nd5JF``1y$tUNKRs1gk{*^HQuDMg}g)Qi}GX-8~Nc70#9eN%Q~ zW5febU>K%kiz8MgR{rgWt%c!r>vR8yh9dD#yexkG?eE+Chrj=?zi!bZnJrdgV}!}v z-_>TgFSb?JG*$cU=g%eg_q(-DOlEh|vL>P`d{ow3vi_>gfBP#O%ztg#?;B8qN0Wvb zrv2uAYTBKC`(3x>s#2n=)YgqeO_6G=(HgQ=TTv2gTe7CBvRNascI9~CUwGkt*Trv? z8kSY3My eSXGO|G3-r-mWP zHD#? Cqr!2EHOJO?NcMa4c61J(jFF z9D!&=F+C+>`&cb+cO!wNOR^I9MpSphk7e7Msc8| c=>QO7|%MsIHmvk!{jo6y3M_k2MJU422 zuB3$?ON&afZ2A#BYP%7`isCMGTV*U;H4VkVarmLfGE~zH>>$D>xnhmch^e|##L*1j zmz2P^|IS!W;7D>b;`l0))5PAZs=|P#uLYWC>W&$HUarA V{MGiZ1=GbQ+`x&Np3X_|LXTxxo`Drbj4031;h{!smnHKo zHOGqTJ{~soShlQ4o@z!M6$=gYs1dPbD~R}VV4HztyKeMP&ir4TM?0$8n&L;4zzHI< z6ZNrsM~W!EC7YIueRxjzdFifV+W35lGvq|0JVIZ!B3{(<97Xed*$w|39mO(C(}=Lq zT0~Z(4o8sy6 yi;*FOK1b_R+F|{{nPzwoR7-qc$g#P+~cf>)>x)OAA6j zN7M2R!(ukNY)7K^&yeFpWFs2504UwoL;HIfuV4^8BA)HrfLCIz?fXGQu?Mg2;Q2b9hxvuJ z`#|xD8a9j4Fj$aH#Ed#}#4!1>2imdzhA#w7cs5Xit--!L&Lhz`8VL-=l~mm@_?)ow zQe=m8fy64n&?2%WFs9@K=saK5Y(uvdBXk^6aL}r*IGjSpG9_Y~Wtt||p=$W*Xw;TM zV_!vyN~Q@&A{5#Y{2xx=CxROR5YKhMU(Vkd%a `bLIc!dN}d~j zzX-2^V|oOA$HO6tc?E%s_i-G}!uz;NXdkVBNyrPFhyiHg0SLTms5}5iRvey- G;=Xk`9``8ya=GvyJGn}e8p)mkK%ke!xrHV_4sG5ki3WqYP*`Q%nwN*9z zSh|gsavpKVczIpegk=Viz*i+xaWx4z7ur_wPqsn=gf9k!$!r?=HvY@CY{$W?5|F}= z1zI+I0;1~xrghe6N}2%*_IyKE72E$CYqXe@Vd717_!h?%HUX@Qc%W;J5l+X}L(j{W zgFw?v0;29lG#)EQktHj-<1$qqr5YMzDz+Zju5LyQ7tai;BZ-utgB+Q&O%#z#EBqNE z(s;m=h;Jx{z?j5G;iDDRwIrSF&k2ve6eo~X(!_{w;Q=|1*o46heci!**p3!8!=Fdj z@t}hIh$ePPl^M%19sE7JMLuF_r2e7zp2Qu;po!z-fZ%wJmO;*Ex+1I8ZRu~|d&R>y z%Mxj*LfrNP_RAK>(-0umvZInAhqrs*b__cJgnQ&^ _4am66s0;{rHhtQ4 Yy2+_gZ8>DPo~ngDkE%j) ztO1;@fJ7OLnZ-}wCv;r{k;#%~hW61a35KJptdaeR*edpg{|D#Ds_ZF- YLLk~pwgAeA02W=$N<8)Z3Jo{1&%{V2|boh%I5@} zA&tEk^fDYwAm~FpA?S&?8~zNDhcY9T=cwuePk>jW{E@@xVIgiHyW!7}i9PDXZ9pKP z!UZ$gn##^aO#->68Ilv;?lA~b430ISP+%sNH3}%Knrh$@aA5*M@0X>Kkg+K67k*X7 zYE46j*%4;yDP-<;=v+Z1`%yfT<;fgMJrHY@Ve`GfmUY#KHL}9ngl!pt=YYv|I8k4~ zCELX3NDxeV6hH+X9(s*7=+6~FUjduA3c0&QP7@KhfW#`$R3-d#B%B%sq>HJ5nJhUg zhXMPNI*QG=H9H8uUts8{ LJULXqMUCH+DY{YCs7<@=)K23c_#M2-eU=x0OsUY z)WsB4hBZ+wH9TIWOko&`E=3HFg-Q-KLGA%RA=wI<8m#Z1)h_;=$Bc6LNXX2HFX(m^ z;)FBAK@w@M47-Zs2pzYhx<>(lt&)ji5k;T@TO+#ZDx5hn$TXzz`(>)CYeLRqlnRC+ zcwf9JXWNz?L$#o?!rO$Ufg?%L ~~3_gbw zU<3CZOSfPw#4`@RMhl1M3M{9>S%IT*`Xbg^Ko!YzSZR3vD{AX_&VV3hxD;F+f#pc_ z$ZLU^M&LWX9GcI8xg<*gn*=7T1pEZahbV2zID6UDh`>f@To{Fd!I9#>eD+=y`8KQ` zSt)e|QWBt;724+zQ5{bu%(@ar1}?NnX+8D}o=#E>)Cqp*n5Ic4r--p^l{&B?{1 ry1Rf|V0 #nJXj@v|QLkXA?rx;ek6?lSL z6~Tz)9oAcMz0mPdqq3 0G4WbYBcnD)IgG&a14e^z$MSX=g8zR7_92ZJOOybus&K-un6!sz!^><@Wpck zMTvwV3PN{H(+=&wa5avD93i4ukgQ|}#35)%M%ALW1^CCghMt#7(qRJxCC#!>KL}fe z1E9>HyJQ_W@bK{w7wtoC$Ve_Y*5Fl9Ves(Ls^M!W1av7HevO(G1aQU727~p%m$)to z?E(x4dIj=aC%oNjimd_M@HsyA1wRW4##=*wX%4Kr3P%unzckgO6hLUimPGv#P9dNi z8TF`w1i&6pPw25&22RSMJi$Ry1ovpdEP!}a4J?JNg|BaGy05v09%ZYjcYw*U2`EA+ z2359jM>a*2(DO1#>m->eiJ}^lgwIil9X3TP<|Rj|P=_8164NxHIdmKQ5_$yu1ZXp` zU=2MP0z?Y!?*(V$`S=OyB& F?1j|PnBe|~Whqo__`X?LBW)sOAAM8s-Mg&QU zxH>*e{TutmmIMLDi4$dIuCRNdGEf5uUk_y)B!1}qavYt4oT!y^C^g|H;Ab83Au6MW z&t8Vd_ZYYDxE5t{8?xH=t(Nbo4`W_fvpm}iD3IIIA32Pq-){%Ld^?E8Yve#V0*!T;aAxv6blk1NDXq^ z5AUOWn`0!A^I3522tx?jJ`hS)3|$XA@&)y8jOELQ7Em15At|tX4kcEGbp)Vj`1`-( zqXUZyFH^$hK+Xk%pI`*R9D*)&4agokPt#?c6A9rZ*%YRM&75tZO~jKt#B{Dp2o4>$ zb=j31Jzz?T0fR;$gHCYCBq>JwQKkhf3u_acJz3XD+exMb(I@s^A;Wbo@Di{I2OfSb zrURa%3;>TEQAI9_X~C~5x+VJ*B{{62=cPbal3zina-sua_h2aK=|G26rUvQgq2mxW zcA04jVu@`>Q^ON=QH#hbMj|<`4xJWyUaFx83Y*-Dgh3<8!*v0B$adieOej`2{Jd0O zL{(gu28!^|PH-Lt5~HjfWpXYenb7l!sy+$=3PKiV+e0M6c~n5u@Y`vmg$H9}C{V zB!46hkrdt6PrwLhnjQ7c!1X;T{C-8@fT*=ZR0Cfar8)}+FmU=3sk@+Oz(Aqrr3EMp zpuR}1kqjYvAT$c~gW^X4n-WA@XkVyPgo~=gAquN7p-9@m6GGPka|poZJcids!O4N+ z5oTKa8j;x~Aw+`KG~nW0-POtCLa#AvV;pKtQ8G|BOV^ }`p@Y(`_!hMm8 z>Nr@DD~K8xD8;7sN5ugFsuBKdQ=o_v`YGD00L?628nsZ0?@C~Dq;%a4@4xWwU?x}z z9TML$L`?I9QU}@ UN@$}~7gDq~qu&y0|12MUH^xmIXCM+Zh5L4fmv zd?z6lwK<_dLXXB!ItVm;-l4++pnhS4uqd((fiY1cfeYCw1ewBBgtiGvLZ*%`jWYxi zSMXm}Ac5*!nQR0mIU0nwd(UufvRBFzCQOxxX#}LKr+_X)Xg$Mo9l96zh>ai{RWf!s zQS8gpFgF=9#ZOAGVWHQEpbdXd5r=|@sQq#>VPBB42&tlM$hs67%kdWCHcrMy%`Iw% za2-*eC=iaM9&h+J>W|d6$vQDDCT9tL6`Kga0LU9}C(<(}WQq(jkYz-y=~Vc+<}T;;~6b!j5GCQL%BfiiBuE?=cpI z22e2P$u$U0;cHD)Y01YZ4fzJB9==dezVIfL(~z5!l?LJUOhj78hOH&m8W_LO4Uqwn z_~`~>fGCc`3mu1ePy(4^p$K1vhEgyBlz0NNB1z~A5W0olFKSKH2cbElfN5$= JagxU>0!Dqfw z)C_N5Ftd6fcz`S?mc_Zd=)ZJQXIV8tI)7&@mzEZ4CmPulV4Blp@@qsCssr1DPE N^~A1M1s2t zJuj7R1wlxth~!0WPH3Ynf)S-{PhmKuSE0uu_EXgsf_t%F96;=g(?oh|Sv1OsZ45n@ zjx@-o7^ewh0ZdIkWWz$ruBQZnY6kQ#g&)hIZsUMWMB|StYKBfgUjQ^FB^qL;`Zwlf zXaEQND!B|~099_}TKGbOIVWD0J&N3+=Vj a6JRz}?UcfD4jH)1tsbD>Rlf z4HN2s@Gr?^|11j}Eorz}F%o(MG$P?`)l?iyQ+P8mUtkmBqtLIK4#b$K$fIZqy+$f6 z97qZYDg|>ezNjk@da24#@8B?)?%$Y~3nK^Vf+YzHWh~1OQal*}3Z*ugl5psGq2weL z!=QW%o5;%3BpVk*NK)VcOj?^lk44uPx*j1qVxhLc cFbG=>KQENWRJAEt zAu$zo1-K5Gc@f;`Q}d|Ogy;AuBCz$CDZLbd(94n1Qbr?fGtqVi1ad9>8WDJr?!k@& z1_1ejXCikKjt7=aGbk2?#uF4$8B8`vg#;5S{DfnP5NGK8z#xeXUz;O ln>!GrzScd%ND)87CR0n zN ;;JdlofT>u;-Cxnm`kKkBpB4j+4i^VzqesC> oF}vODgc2y{EDY=T0422Nx;?TN*a0x`)@2S@dV2=mA0p97^i$ z%n-gcq9FtzP`ZfTLfe-`>k|H$K2~JqKrc}P(_B0(l{HzHWm5RiKAH~~+!;0L0I)*^ zKr|YV<`UA7+o05x!uP{iHWFO{P-R39BHw1ee2FJ2V-Cz$(T&hP$8u>`rB{KrQ{p4h zjJ!jp_W>;BqYd J)RlI)a97ae%IFniUp8S!D z3C~evAmkjTA3*$uuXlj3s0Ki0OIhef^fo)BjHDsdTS<{Ey6Z!qA&e3AktkFN;k+d< zrfcv-Z3GN-w2<3|=B$7qfh}a|)Cl>7^pl4P+O){oZQL19BQ%zS&?8GDPZJoJ&H~}@ zEhs<4AymZ_p_&VwTM;KnxS0*mS9nvg_d;up1XU&hggg(Q^U=ZVJ1TAvM2HZ{X1{2u z5p*lEZ9)@Wc%j#blm aiK`lH6pjMA_ft*F|i$l!Xd$L&y zz$6dQ<|KikQOXLvMx;WhOhncwap3?tHs?{O`l+JOr2&;`h2~dn(nm_}CLx>7C`#P~5ZVjL z{_u-5g$pS}=y}oqh^zrvl2x>YY-Np@8 QQb1s+6!CQ1t8h7)>+h(km-01h<)#d7&2{8+FiBITfTf{SoO&c{a4lc7sA zr|Gamp<^u#D|E!rL?&5mnj&I{!#P0uBRYZ5b4lT!BZ?BzM{LzHV0p%5a$=eQ!E zQ_O_=3%f=EOpr&@v*?TFIZEyKxgl<9knuM@MV-+5<-n`TD$t8yNYlH}=Qsj#O2VU} z524f=I@ZFCpe-d(J2o{6RwwkUKw*mt7&k1Cc^IMXp2UnBLjaW|i+E &LpXW}1BH)9Q5lex0`OQiwh{UaL3BXXqn{wj29}5>NCy)YeF3D;6b)&n z482AK7l28CplG_H4 NPLfZ5rJUUOe#b&icBwjEfb{! +WaSMbqxH$Y5tQsw{wrEo# zl?aVZC^;j~rj`lv5|5C*C%S?G1nA{x1MxziN5Y~)ryY6|(M&zrG(G7F>Y5>`bdDN*HY8TQa7_k)C;se=suS#gr1iu3DM#qh$V;^p(jT-MDG?n52-ET zAiU<(1--#13C$@QN;r4nc#ulLO>mC|H~>*h=y|ac>Ttwu2S+V#b-??ejdBIwN>_lW zwT2xF2{c7U(O%% $wOUTs9?6A)X904toW{qc%e@ z3BC8E$cC#Ef@q4Ot{{3?Oc)MQEoz%UOsajMYxo|$R`6wv;6qY~YeT?aBEuy$LIcLi z!}HM|eKoqqFeoocB1OL_eRG^lB hvR2JCt`L^(_6PBob<3!Ve#is&l*SZF!{I>269Cpk#$Jy()}SAm5A_ss}( zZRmO7`BVc4&9y5;A4i-aoukfl$RowI7~y#)4_2M}89thu&S12`a!^9tV8E?W!b`%R zgpO%k$pBJ?T1AY54*7nq2@k8F%crJ*iXyyb%X7JD4;>+lkPyS5^Au;BHeg&mMNuS3 zUT7T6g;fAU AJgddrsIkp&j9(O;F*Nx6orS$d@P83 zTExSjN6`gENn8lXxjiHcPoNhPsxpg eb)8YZK-K?u++JrnZ^$hSS14l;Ss z!X5rOqOzjxg%d6G(cC&9`uT(kPuyu_L%*Yl2y3h8ys>)Gvk1l!4M{>Hf|6CDnr}lH znl#mg9!sIe0GSsBZFC* (~e=LyM zhUUL04^j3PIL8w{N7OqkSZDw+;y%a)3%?tBzrfGpIt}ir0WP8K6umXj0(e34TZ( +7}I2nO^`MN_c=n)7D!K} z(Ab3QnMir4yJs~(+^?ND-2X-W-pAL|BM@H4hj{}Vm>2zV=-h>Vm4prBk6MIt3b0V+ zq4(ZZ75=3~hdQ_DuO)(exNPCOg$kUqX=pq_i=BcP0f3st_KKPgH 5r8E=jZ&Z`@<-8bOFV(fRG}5Z z_pw4%f^UUDPTXb;6)k#*MH>oz$UeOa@L!?lMGgyS5OP3KQXtd7CeUA#&7dQ~PPo}9 z{8(^&LghwL0#+4H6jWz$7ovtnF`zM!Cb7_G2u++vHB)E{@TPDu3`oBm_dNpTsG19H zZP>jJfHyYon3bXCpf8rOOwJ=w#AVMAh^wLfYCxF}ssoIP>=hzeV5TT&6WIb$6RA0u zxQCt>xfu0KD9kKnn_$clJCbV2+=N6gC2H=_zL1tsi%Tu36bfN8eNEyy;(|zb4eBQd zWR>vG5fh^K#Yg%@?#^{goJWD4=y~7?qR$|vhhC#0gpyz;YM@v 9XCBf>2O;bx0C(*-v55rIYAZP6u~5vE;U|pt1MPQSmd^J z( VPes(XvMknsR5A&4;@qab{G`sKrJbRt`o2DCNCNxlq z$HaMqEFcjU{eQ?2k^ld``hTCjmY~WBiuwDuA^dO7{ JN$pY9?$QU{4Y-^ z)$V2UZ6|)Ov?{S~N{_yNFN`lH=#|nv=8vy|i0PdYW2dHeOLnuq6(PQF5AV0H7Wu>S z{}1*rpka@;MylWBg5uI$QHG=6(Iz`5^iWw1`09hd+CM8n $lk4f75?+s#$^Ze!PqS@1gMipA+wUq&mXqWPOuQ!k-1b zu*Zt8_DSGdWd6hV${=Q-o`GDG`aHTpaa=*&BrP6S#~`NFNQ1@07o(;8pMI~5h%H&$ z@Gsxq^!tzaN+|K$Kfa8LKm74^R(=mcQ!l=(s(y>+YqDi4+Ak@wM)Uq(U7a>?(C!1J zw{+YQxWhB9IEykyy|8n>*W-yr8EUslw}Wq&W=uHSvi_qP 7HL(YKmbO8V$% z)AUN;)O@q@tFI1 Z%vshPK5-ZkLW2e(f6_5-ik zkOFT;jto9L_;7lGH~H;dxB9&ePJH?5O}i#FNt#lre679SnKikRidUHZ-pt3+zpDRC z%Bp39XSPkBQtz3cn>>1>Mvl|Z%$_ncNPmCa;(B` W+!aUXs5QpR)pPK^JkV9wk>l&_O|>!Wv5D^~Z%#2!9zYW2dh zB`W^9`kCZWGs~y9Y*0KoM{L=oDHSe$S*@9q`FQCSWt-c*%e{JI_vmvgTkL%C)p9rI zs@=Ng$(4R;Uysk%JUeLruti %6eXIH1 zXP10hGX1Nhg_%vNcS&md)Wz0~heb#K81rSazqHBQ7gqM!*1q+Lg1dekw&>+sc8l1F zhqN)3CFE 3GmcIwjjYAN+kZ)udYV^`iXAHQF&yIc9`^Uc5cb#$?uaqXw(ZMwh1 z&=$R>4}JZccTVQ}Bw^gcO*h_Ix!}arLY4EhdvEQ*^Qo(zT`+P?;O(wHsLESyt6tZV zb`>f<_R*x<6^k5t`sk=(GrFdAOIAKio@8f2_e =9JV*I0(W{;lPVZyE3{a5^R#<0@=_+|L17gk6;HcgvU z<%>L*&o6VIJCs^Eb7GCc$4gZjv|?7tuZu2T{lb94zrJ1lXxfl^BNnV3(PG|fJ+BRj zuQThHf3*B~ fMh&oH_p21)o)DTYY5L3ym&s-D^I3 ebKk5u z%%4%FfA 6L-C)6cw`XKSk4YDnCaYG-$@E*lx#^Uk$8%8Y?6x9t85^C+SB z%~RkzJEKeSQQP{(l^p-$J2PKTuT+2ijF~xh2M=C5ugX_m*gta7%G;k`Ju>CTHzSRH zzVTX#uMbW;*~M>oZr;6)*-k&1{MxybE1W?uzZfm??aqC7W6Qr-;MDM$kE9Q|cdl5+ z$y4WLw7