From ac57a39c70e01bc5e6abefc3bebcea942b95845c Mon Sep 17 00:00:00 2001 From: Tercio Jose Date: Wed, 28 Feb 2024 12:43:59 -0300 Subject: [PATCH] Added Compare between segments in the Breakdown Compare tab --- .gitignore | 3 + Definitions.lua | 4 + frames/window_main.lua | 2 +- images/checked_texture1.tga | Bin 0 -> 16428 bytes images/{icons2.blp => icons2.tga} | Bin 1399276 -> 1048620 bytes plugins/Details_Compare2/Details_Compare2.lua | 2111 ++++++++++------- 6 files changed, 1238 insertions(+), 882 deletions(-) create mode 100644 images/checked_texture1.tga rename images/{icons2.blp => icons2.tga} (51%) diff --git a/.gitignore b/.gitignore index cee7f50cf..bc8bc2c5a 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ plugins/Details_EncounterDetails/Libs/LibLuaServer/LuaServerDefinitions.lua plugins/Details_EncounterDetails/Definitions.lua *.afphoto~lock~ annotations.txt +plugins/Details_Compare2/Definitions.lua +plugins/Details_Compare2/DF/ +plugins/Details_Compare2/LibLuaServer/ diff --git a/Definitions.lua b/Definitions.lua index dd2502850..ebbefb846 100644 --- a/Definitions.lua +++ b/Definitions.lua @@ -411,6 +411,10 @@ ---@field GetPets fun(actor: actor) : table get a table with all pet names that belong to the player ---@field GetSpellList fun(actor: actor) : table ---@field GetSpellContainerNames fun(container: actorcontainer) : string[] get the table which contains the names of the spell containers +---@field GetDisplayName fun(actor: actor) : string Get the display name of the actor. Display name is often the player name without the realm name. +---@field GetActorSpells fun(actor: actor) : spellcontainer get the spell container of the actor +---@field Pets fun(actor: actor) : petname[] get the pets of the actor +---@field ---@class actordamage : actor ---@field friendlyfire_total number diff --git a/frames/window_main.lua b/frames/window_main.lua index 6183fabc7..2a3fabe41 100644 --- a/frames/window_main.lua +++ b/frames/window_main.lua @@ -6543,7 +6543,7 @@ local buildSegmentTooltip = function(self, deltaTime) if (combatInstanceType == "party") then local combatName, r, g, b = thisCombat:GetCombatName() - gameCooltip:AddLine(combatName, _, 1, r or dungeonColor, b, g, 1) + gameCooltip:AddLine(combatName, _, 1, dungeonColor) elseif (bossInfo.killed) then gameCooltip:AddLine(thisCombat:GetCombatName(), _, 1, "lime") diff --git a/images/checked_texture1.tga b/images/checked_texture1.tga new file mode 100644 index 0000000000000000000000000000000000000000..23d57ff058eff50eb7366b0b342b8b44541f0696 GIT binary patch literal 16428 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

ZA9B*givYfd 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

c_gEoF9 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 delta 144086 zcmeFa33L=y+CJV(RXRy`NCIR}APXUE5fC*&K(??5A^{SK0ur_$DhdJyKgEU-G=K;Q zT7-QGTiA_QXi&h>5r=jJR~+pDW{?DdCXPBL8SMT)@2$Gk)twIDeByxBOWmsK?4H}}az(zq&po-f8Vv@6IXKv8Fd+l16bKPOb0EsFG6%>53V{2g44(n# zfokA#02mArU<4)xaPEbqkxR6Ygb!`~<&%BPX0c;UO-*FY&o!wvKh<=p`JpEN>W^28 zYksULN8V9+xY9A_**TT9*J_J@{`b#09*<{5@1|qgBaOUC$fwSP^tadp2)X*h)zU+6 z9jY8KV1Tn{&z=OwTZi8&t-Ds2UteF}`Vg&CD|$EmUU3IGiuE>Hz%4}xy9Vwcm#A*>aMw_1R()4h`JbTr zQndp}r2jPdF zY}YZvH9RlRH6lOXGwbQ6J*zfu^gKQ9X-~hwlNfRaO>|`q$o0YG$%QUGibwZy=`pgf z(C)&2u7bis520|P4igGpg{aem+Uij_d9v%eARao5oG{s?M{Z%}cvo(rf}vw4IERmz z=BT=Kva;&($sj=+W6|WZ^brda?6~>BU;8DKnTdfe|CG zgkj!r`}t=qOFv`Y1?uX4-FzKr%JiGRwdvch+&i!PRWwHMUoN*dSZV&t0&c+H-f*e= zj}>6k5%}r5gL_q9rq4Iy7t~Ol@Z@vPH|cC#-YJ4jcoZ%E;aB_b+S0O}<(0!nj&_W= zZw!T>i$bt#*Cxhx?Xz4w0_C@q$xaPfEn={`qeEH>K0Wzq zB~Z?B@?+?s!{?u(y@nP0@9Gk!T~W=7n!8ei6vn7bT#-kyb zm#4q>!8hN)MjgKX`kP7(-+WVk=KPtGKmGYnw5!ELaeKpw;@l6_Ip=<=E;{o=Rq4v@ zYbuim&2Ywa$Z-J`nY~kt?e|sea}^gCJAulLTQ-(sA6>%s&)7#}Ba=h>YIU-JgdWO7 zK>@O4`I6!VB@4=rzIW6yzhu5MA|k?-+$z}z@d=5pjEs!N(Yk{xLx&FOom@U>g=;<1 zI@nzu(mH6!K&20oA?$i+g?c@bL9auH6!6xeAuqeHfb^7hEdngJd-wSsp>yVbw$)yKxn3$aAB3w@x>Q>Af(5#2AN@*GC;HX1uBebgMYH?!jIFVG z9XoL>Q>0{ZN%^N=e5xtpyDx3)tHhvt235R2Cd3rHdiCmZMS)-=`6SZsZka6;WZVAN z_LoeaGP!(6&n}K3J#TfAPl1ZaapQ~`#ZRJ}o}BGKTDgD!{?gi7Y+bQEU^-ySp!yiW zkmS{4;5`G&^G4)Vygw<(WbM$&HFxgZN+Q^lV)R*3_`M{*d4eXTlOLK~nVg*L07#Px zamp-o%ag?}(&ULJo~S%{@Sv|2YVUeAiBvS9{?as=>Z{4}l-e|vfGuv+mby`m!jfJ4 zc9lh_(8bbUdw20w%ZkUq;_dX0}CxOD1`^WU9k(kD%s z&xb1Tj8%w;?M&38F;{63-CNm18b3Mh|mUr5zX-XXQ1DafL zQyooGJZ`bx=tu(4pn2 z09r2b(Q?zR#6{0Z-@Bw`Nl8g%Zf>rFwCt3X<$|W)Ec=sjKt}rv7qoPerVmejxYBXb z;nTU)H!R$EtkzyFz6#XT!ROFY^*6NqD1er)gqbX)2{c>LyXpH{{BcdWmNa>jKWXa* zEh~o(9qI%sK3e58_T?(l#7!~CRU{&EC=q_=`mS`;s8Qtvs8f=WRMG}_;BMzW6uGD2Dm0aI@vk- zk;x9A^0fo6l@kFXvwYT!S&mL!IyngsKlX4Xc2cEaUPSjjBn19|itl?>9D2{t@{uDE zjax-icsne`_Gj$nUQZs#;vQs?qKg{6x(DThq^g5d1zbSIu^n~BZW(PdNLAO&88e+6 zS!_4m2|H>4YCiJ#BM#UcK+R(T)Z7zL%{{Ec`JkbYDce<6OrZWD2as1uO_E6J9o*l} z6p#GK{E@!WmBkrOdOLvhg8`-Q^pQ@{0?DOVxXXdct-H3CLxU34M#mE~pQt!+sIw_y zWZp=Zk9c*wDt+{30P$}J6u*^;ryZ?2nv3>S>?v*2ri}w|5_6|fhh659-6Mb8; z=V(_`0!91yN#h--PoECp`-5Kb+A8xt#Amc`=bG&kBAYbpeZ;qKAPOc|rJW;XpcyCj}_=)40_`qF%Ab|Lf0*YUkKoQDk4w^9@p7wBgoAzy-FtB3z z$uWwk;lqaq>Ss(Avvg+?Q6}w7g1B<<*`2OwBG5eYc|es)y(%FVeyshm^pRobGEx#5%G@+cFa3NN92{};;z6T1Xnh1-n=rZd6a`ACML#lU9|7$NElJbkofdc zN6e^6ju`BaHQa#SeqH7_ApTEiV`F2TI)po8o1s9%in-_0?An#S=C{j7K%O2eQoo(n z-eR*j2*I}CN&<8ylw;y8rVybXCm;$c-u||UsY$yIbjw=qjfy2KDyR*$*CM0h>FT+r z_yla+5foT<=y0Wo2L)Oqp2mdJ%@2h{?ua~kSWq$VQj{sfV#U3e3b@`yZk#Z20^e`2 zT`yDTN+5L>#*iv}k!QEz2-M)@o)u5kJa3AILbSKkE2Ju8)hSak=ZCf?$c}N5V6v5O zk(uD10tsHwK=8>=Pcp%?YL}Q|Xlc_+R-Fqs-0v&--`A7;OCZVfl(PX0W;Up?n(TgU z_ra;g^`@rx4so3R=Ct1T5SSlQ55JGV#&)>;wAt7mmclI)CQq*Pvs8XtG={MapOZFx zRI4~^4qLnQPKLzt*yLDeOmd7oJy;dZx4vq(L-a7cXzO)FhXoe>RHLHDKQvyR8e!aN zYNnS<(V!@Ow_bL$>&lJ_EPGZ1*(;jfa#z|N69k5{BdZSxJ!*BSutWLm|&eGiI8a z(J@1V9#3bYJ9Kj57+TlkQ(AD*#D`8l&QzT#%^fkQl0;i9a$y_e8>R$0HyJW?h-(M} zk9)w|`@MaYXz#BCiGV`#+nJ3h!G;)D06r+s9X{BRJA9CQe<$OgO-(Vd^+J_y@8K)7 zi(V+Vi3z)sJV{pPWgGwE9ot+uHB^Lm^%dT&QQ1{Kfm7}%^MSUnovoFfdl1%1C3QoI(3Av^v*ug2j7(RApxc5 zH<(rTy}pkeAot5Pes2orvXRnlDX19ZR;a<)OF>K2`G0+JZ{dFmwE8;fjqs7?htJTM}$@GRcQQ| zDQ5VH;dqKZ!bx4g#A{}!BhskD^U&dW@|+3ATTD&Y;;{PsIhwQC8V+mZwezEgQJ)+0%?c zW@dZtJ-ONqnpb|3NVX4`i)R>b<5trlkJsv1fhG6QBoi|{@?nRcTkt5zVqjjsZMHGq zZ1oN9I4$WgT3Dd+-{ZtkvMq0gnhqkG!Wc!UAy?gKOyk z`L?;nrskNO{yDCk0XYurA^c|Ys35jc86nSp&e)M{XeMLjrbzX%cmbPG)T0`8mZy&H zN*%4qrxPJ2ACq{5Mea~yY+=5Y%VyIV9jwuz0k-n|2A5KjrRb6C$Q>a+vl#0cZLR|9 zvZOIxqM=I;`GNEpH9Xf5q3F?OnX$FG9qB=bgnB(lF4x1WgFJhM@m4HofgJHlW5Sz4 zC>_?8Gr@wv1qZZRWxUm#O6PrShX~`<0nUW#1+KZC^Vc;d(^`GzV@J=lU}vvZ7CC97 zv8y>X3&)?2KmNG$%$YO#A|y#*r*n>1`kCr@bD)mtgJ@rZ%1*gV>-5aLoH zC+#ryFt^~s=sZO?e?-#L&RhuE1wkzv5rhW0l{f{I-`_)1bs&NJH!bm6x8K;?98Usq zy5qnQVvmBD3sqqi#yc>P`Umd8MyzRCeeUC;>N6+Hd$zJT$g1NL$SHVkrS?t4?4py@7S@UoN^R~M5|}O>@I|2f(!X08G*-czN7Db765J9 zv4c|m=p*j*6pBV5MZKJI+}Ph7iJNA1I@7x11Q^HoG0w>ynCrlkHTnIIjJQQ_*HAzY zDgLz4W+u+*ClOxp*yK5}lxR0GS`4GNKMkn+=Un%>&&=ifLz+2yGu9#v)roTZ)5ebG z7Q~z_Md}@r&&&V;UpHbyC9}cFZSWJ+kL|d~AG8J{K-i->gW2FPnC0xVn33DFTeArh zoU|74W!Pt0z^^`)7_c|R7fZKtJkhBS2gHfZHzXz zA3uIP1+~wRZB&CxjcRbE5eiFMqXAM~U0nnXN=btuxkKn}O1WQ+F~r>Q(Z?V4 zQG=_%Q`X&jXZ(PTNuv|>PyX6~obKAR4bg=Q7rN+`!G2%vS8Ei_T}TnUkI6QI@C$8< zw29hB89YzYdgkAaC6OB@x> zT#8AeAg`bj=j!qtvnjAMn0(Ph!O=RyRXjrp4#gQ`ti(o*PPuomNi=J_P<0H$WpQk0 z0R?gj@(apwfbX;j7FSI37>3y9D>hzkEx%?qeQ!*~s+p{;oZ1lwNubE188;6b`1iw1 zbRyS4mvM?oh!PqE`}XaV?~XA2%hdGoN3@aQRVfAMmGxamQ`quYbgMePV_7CKYX<7^Ab_oRxuz{|mHz{sZkJB4QjmNS&ih)6-fe zwyY!|=(R zi|zz(#A+rx2_-o?RP=7T$H*%9I;1KCf_&`_7*4?3&^7h{h3X6Pv2;_Asp*WFcoLoM ze0=6izE=Z-=`qxZ^rY9Mpr=DUx|YYaF`Y6sqoqjq@RIa|KC`?JF5mm$z4Ec6$4Vb& zn(FL%BlGZjNkin1%y;TRZTK~BPuC*~MmUET;D`Vz1C9#lxPTuUVBvM)H8CfpgyHw$ z0izdo2p{PSwV_6k2Le6r8wmzF=<6u2uM3bLIcf}U4>+R6&>OTa`h)-}eZr)^sxgb5 zL6N6Xrg=KpDi?M#{l(Pm(MKQEoU8^Mocxq&0PjTVpZEUsUg?TuD=G^|7vfeM3z-iv z%UX1>A@7AWF3OaK)k9Z=JXq*pLEZ;o9~>NkLqe1jFp&pG#5yTud26s!d-y{62x{X+ zM6(DytpU_EH`tC>{DJ|kkp)j~R0IbrPjBc64w#nzM~DEO9u{2dkgmUA`38a_$}Q4> zEK|?6K22>X)*;vyfhSE7(36_)%Q8jTvdU>tQPgbp@Lw+dR^sdt7RaI5&odj=}&oi-c&gO0JBqW{cVH#q;P;;Tng-d}^eYrX(U>(uu zP=mZL*f9A*YJwOWGlxpyATT@eox@sJ# zaInJ_uXZ|1V3jnzr)hYoa@t01Fq8h@xi4Xi&0}bCET)YOF2%@9e_Ni(DaIT^~B2Q zH`so$)6CYhWo${Wma*kPB}dQX7{_mg9^kE_yW>t=aOf(O1})K050&svyyO8I>D)w9 zO2<1BW1T%(5~wj%AkP|7%0UuYxzu@*sTuas>ZPg(CsB0)t89{i^iHr;96>2S*C=Oz z815uZcQ_GhXy6X@DYGZT(|V+}tn3B!#Pi+3w`Dr=`}SaXWb$|if!4sO)2CMQbjHj_ z9Z$@dTB%_c@;W?>Iz48gP7k}jG3BQ|G(p3NK0PW2b-TTCaQEBb1@Z)}gkps3mI(^f za$bKM%Jt|14-syKw+OtQlE&Jd*@#ddaK>tSXChp$gC-dDSuGPPvl3$~vr$i=Jfgq{ zS&7s}2Xsl6hOpT3tmGK}av58se8v$Dk&EacnUAA+51E!L8yCMZ1X8218I4EQ&&e^a zUJ9hnGfm^<)sLEjjJ;!A2sRG_1gQdQ#PgK)O7TOhWKS;uvEa$;d#7}6s;RAg>4sG< zj%6EHd3e4A<$Cb)#?q3dB`%Js4~=(?89CfFsM~D}hBg3rrL_kr>_HNy;PHjy>7<(u;pOFXP1C&-w01~?sa%=g!;C>naLFC! zo0`IcM7R#2PLsXTqOG40DKSko#rT~9u@7z<2zk*IV-Cg8 z^zzU2@+VE`&=zVIPbi##7rufS|I%fqNv4=bXL$GN7$v%oI3m49tZcylcB3-#a3DF$o+{lVQkoh-=fR+%1PpFa@$s;gD(lQUoTQC{|I!QKM(iBrYAKHU}G)Cr8Y@~lSV zy=kLqm??oCamwAqIp6AC{-n0WuV;X0e%q1<&hPnh z&QmypV=7R@IpZmneDJubEnelrE4YovZKlz}wlCxXhcD*>W6ZglbCJZE>pXbiUl z^8QOOS zzVX1GQYROVqWyUG#Aj4`H1O&TZ1}b9?KdR2Q7`@4`ox%08WifGnSAm2CT;QK9NE67 zy_i@xY}p{cUxTMLG^~aX^ZS}hc`X53kA6mW^F_n*cf$YfPWOMW^#9>WM?hu&n-4YF z3+8yorSTN+cA~5GuZa{?Hhs-;xk1`5Zteg!z)96UsU1l}_ek#%8pyhr;@UDf!r~=J+7Im&@Km z=X)TKF}uIdHovKm(SDKJtVl}<((VZHSj)a!&EF;R=f#z~!v%plh2eGXhQLsZVU^6IhX0^g1NyYIa#8^@WK`x-)oUMb&$aI$%{@68Fl*E?v? zAUR};d7;-9U&5b2__(>yOGv-t!U@Bso1gbLN#68?c}x&n{?L?uibiW5`IPx7V>7%_ z%zoy9oat5Y7s#=jCmMY|X(3fExh~O<72rbyDR!RurH%t~b6pygZ}sVWeFnVrNx#OS zVa$Z_(&zKcd$b;IcqeBR<<&2kA2KR0#lg`$Lg>|Q$VFe{Nw-x>UTFTG0bI@iyoEgw zuYdocWI-ii?)MS)ss@z>u*pWIEL{O)gezSod>|=yU>C4U2hpPHG=PsCAdHBd%xC_2o{4@K(06d$f z=hHf{K!QIhB{z`lUHf*IkDf50l61q%8q&AR&85^o{;%cA%U?D>71WaSA+T7*%aWwi z)}33~9Y5*Rw$wanEItjOzF<1ZN90m!R7Y>CgMhw;Ah4N-UfowgBZWZ5GXLWogAH)# zxoiKP(&A@|D~q2lW;$LeH7{X0V(uyTjnyzXZ-aTZa-+m}s)ygZc1x``nTv|(mXyBP zq@U~|ACL_0e`?PSyiuyxm(jzg@?n|jncYpQ*<^l>y~tXmyx{DsWhAuRZhj`9mTh*L zAC6%?1G};y^DV0fzAAV z`}Xw^umVUaM};`)fdl5-n;?K#hbYd03U_PIW2qd^`K6x@n4fLxJFTg+d})x+@hRy^ z64TSuSqOK1(|k92B*wM9e0!xDs(g)rB<1@mI)kIP3AXOo%3cZVbVoZ$e9JtAeMw0i zb?RX@-Q=C>sbi><>Ev$6y;Alu^Puqej=xvQiQo)K8K<3MP%tcAxfEYhwQ=AlxTKJG z&G{{}x@F;q!jhddirHvwAaSR!M1EEXiQPXm_X%fjEqZ4Ep3knc&Cz(-TZeEm+nN;{C;5z@eO=2Z5%C-ib& z`QeIw98hG!3Eoe2`S8{EeB9s7ck=JU19$p|LD~yk*-q@?f6ofGI=75)1!?=%dLw#D`v!lz*DrGEHVZIjfPu;0(%QTSDEo zP+BW7E#M0mX|rR;4)$dN8vx3dRPB`IT8uz4z905VkB^UcB_t$xZomC@58fh{I{(ug zrD;OFu5+k5_goBOzl6ei2fm5Bk}WLLwW#u0_sA>cNkU zdGMn@K47oMtG_LwQ$ilrRQO35Eb1E${I|>atd4%)$$CvMarf@s<$8(uX(10mmD(T# zpfO4MB}n;php(vYg{gzx^!CtL-?L|rW)J)EBKiR%fc=0GCU8IfKeVv%OZtJDedxhC zJo4Bh>=&Adk`6M7QuQe5^Py#Vr(ouOy>V+dtu4iG$dpf=HkF>^lmsA(NYm>~fnM=O zMX|P0D~k}95UT|%bux#l21dopg2`f_uY+2vX|E{#XCFKtDLuPS=n_WfH&nzRwHPb3 zlz!POhOD@^X{`K7mQbL)7E9`>fP`~KDZaaq^8h2W7*Y*4f&p#xp!WJ}%KPw;PWBhF z(*2w9CcHUIsp$z=Dxd2iJR1bQiZ#3~QY;L5NT>P>Es}UW=f$sCN<0&c7D~E^TFDjZ zmwrN=nbw(kMPiC{%Qj(Qm=B!{0!fS~9n|swvRhlJPV;!N*ixGFjnGFCcS1>$g3-WW zAW`DI!aEJ6gc{|)4i#Pznu1TbA)J9^Aur9#!!G8ou|fno(IOql6Y?eZeS(#w{8?o$ zM9wUpDgBZ!{K*VuB-dUsR{q<4!dj8mkJK@v3q06&c$g0O5AQ2e9z(ZztQI~f;CX5% z9~&)nHJTaQF&GKBRif`FrH>vI;sp9t*X1dR!KigA`538fvDj9=cdQ_Y;VLVo z#!VFB21G|kr;Zsr#xv^vQEV+~5#Azl-G+4@dQ=e}4vTL9QVMOPV-tlaGcwS=yA(M_ zI4{>t67COb=_fQ2qm3D?@|C7PD)g}Mi-V5}!=z_N3US_O_}pyB&X%uD74B=m%MgH9 zTnrg-_WW5U1aAd<`VH*sAq6+h6#9{Z(#4s=?LkW5P~?3s*Ub{{!t-=FyI6=9Z>;b$ zLR`3B2=Od^Mo4GOkD-=joX-foeWlD1J~EnZHk3;A<;qKOqqdL6!Fk=!(iY7@)9wYo!axW1&Afnm$ zmpZ>BEH@1wF1`1XFu~YNYO_>$Qjxk8QZW(o_#?@MD~0xIUoTrJq*}t8hZm6t-dri% z-K>FB%(t-XdnxEuA+}l0pd1(Upux+h9jWuH!Ygdz`0!O>D+!gROYlRCv{Vw(%=8-u z2PI*>@R(i+m}m(H3mtsSWHL0zvKa*$Muvoh)b26f~8n~Y`bt?2m&+A$I{Vl!aT-B!c5mpnm$s9ZsBi^pJ|=*MW^KMCp2%s ze!kSBSWF7Ws3|5$EsDkVl5?BTQTlA3&|5zEkI*?5d0JDU99x1{rB99seW}bM$cgU> z?Tylz{(_?k;sZg#A*cLF_|YiMnkkbMoW2iL;Fjn*K$&l`*kPpL`6~ zQ9A^)AjN*Bw13PD93&nz;j;RIa7#?jM~j`|;f6>{xJDa^pXHGRvDrtCb!D7$T_7XPwxlx>sr@Xw8R612996UU(34d&EF=H!L7^HBQ>V6Tjh#UGyy5JUW z(^z_h{?us?d4$Q7p7JOvQuqtvJ7$Y5M*d0=(~Z{ngfyii3>G;gNNi#>b?hj`S;V)D zX6ZAF*jovDDb~iQ;^ePvVhm&Le(ZLuB# zbyctxA0wem={Aa0_F$rzu6cW{PDiWJt9*z~rA1JO%ikx8-y6+XNThFDh+{AuB6K38 z+?HZImC?6RI0cLFK=;`##XcsBSvuTOyq|YmD{;1TW}DE5&%_q#sgXhfjj-c1UxY}Z zt;GoJBci0pkI@QK+@egTZKy5E722+y%i6A;(>5&66^xUD;O4Q;;GP4N6nUF1(IMSZ zB*YM_JEXqFVj9i4*d!)PzuYG@rwKny`XobSlbs;QaUI03Of9i>#MZY_&@^>S`lKVM zF#84za?)+$=cX1GT3Yp>Nl63kz228T&k}pdZ~i0nDNNu)C1+1Dn`Y%6f}LiZ-w`o< zC*_yY@;1E#`J2y^`aG5KYc)&T`3_R=VljPrC$<|;Zq6tvn01g&?G={Mg8B^a_qEa| z1C(wM1u6a>G5hy+2`!J+ALip;=YBIcA_dU&-4|G=2enn1sN8D|cJ{l?x zZGv401{p_3;)gdUi^2)}tGWZod$w7sb2f`kUU8djyQYuKvdMmd^} z255KFjJ`viGiQzqN8oHyp!p)@KJiB*_rYkf`|sVsWBp>CI$K+&m8}Igk*Bng)93j$ zrTRQ;LxJ2Lk9lg5l4X`#p1V<(T5hMBF{j0a0EPZpo!A@r!&J={+ZY22e?6zvXwD^E3W1Tz!{ z+vh&*I&$O?EszOXBPhZqJ=NC8L4%}-sbYf29K>!Vn@yWJ%|)|-79QlE$GrZLc0MLP zU^K|W<6@*1GBd^QR-NV2n3*Em6EmxQT~ABWuUlCH(eu4ArRZvgx%jhqM~@z&CtMVt zvHIy<%MThfK#rUxhG3sShCL}Rz($XCd?bF*#Y4a^YkIKFIrOBs*NpC#rWA|2<@frS zje->YjM#msUjJ2VS9$1^fDSqcbQep#ji<^b_}txdw)(8+If)qAKY%AUIr0@c5VD6DZo)w!Kty1E%;=}DxowIAtE)ShPfgSxL zKeCB~L{b6y19|Ddv*PV${3@Ds@maASJN@cx7cifACO+ zXU5E_o=%-Iq_73zE$X=FwLttD2Puiqi{t4GLz?%z7-uCV0P1aN>+|9e7{hj>Qr+|7 zm~eXRxnji%4RGRdH*xRE1K7+L91){fx=cqiSQ!j{jTJX1jV4zDr*2gRe#tbRu zMX}o>+(i`Ujva<;w8QP zqByAqJxrpGrxQGSv=tg2+J&z1j}8~uo>6>Bj3$4)BtFTGt8mT{WjTKQIGtHa2VN56 z*lE{CFNx{wEa<0~#4#;N7%`ziK`|PEJ~L}X18wL zm@_HvR0ps*f*k4R%t%@-2^41(Z@QR^BuA1%as1>7x3R-Bh0ln54~5~D?OQzb`ZhvP zI<-<9*1*B^^qDMW|Coc1rAOY`<4$L{9^LR4KWBONAKI@?#se{`38}48ozg823PY7U zl4oBPJGJC4qv?o%pKoxH*VV3;K6+J5??ypNlAc@e9PUbwGFQ&3Qa()hr7F^QF&S}&&1)={&a z9Lwi&o@#zmoqO~+1|~qx9W`bY>oK^6^UxMG@)fmH=5?Cem5%WpKf%)U4dU&oJOqe{ z#-koIV(^~R@eN{!79D)tOK#<$VWYS=G*k@jlAM_AN=}rL%fwrofhRleq?7=kOOwjP zl*!!rnVm8n39$*4gv^ea?8Asqo24ijeg}ae3NtKz`-_3o;E!5)`t|MQiNM-PZK%9U z=S)u$o(2=ZhqcE^igcw+OuCDH%ZxP3L?g-*QHRbQT%ndw?mL5M7V)=p+c~HX|8#pl z>eFLV$TsmwOt5peiS6yMw^{RM8fiMN2?{0q-{+d12ZsiSGJm1giLi0dpAE4Dd%K^g zP)_faXo!jT9(Pcl!hz72{tFEa?Sdr-Ol^EBP-3&^x<|frOg1ml0nd`PI-!MLLyWrC?OK0 zhDYLV@eZF|5t?d?JLS>q#mOnj)Wcd}^9azV)K8h_uBV@Q+GQ|HiF?I&+3I#~uSma7!wjaU z(aM8UWSUDMvxEpbwGY9eDC%)8#frN=hI1a=OoY*6x738h1nJbS&^X*oSSS#vFOKaK zTi%LS9?=u4mX7fpJv5DB|BgZrNA8f@SdY+aC(R-w@aGkid9To^BL;2a>y7kEV}2nY z>FWaIrOspV%=N9;#Y8*Rs%HE2bs+CH)~>PgfW6~$14l>U+MV1%_B6zdaV{snAs#jw zvm~c1CdA*S#W8tE4~pMlAt*a5+e6daVe!@*-utT&qD5W+@A!C6A938XNZG#-GoD@9 zLg-Nx|7WKya|1`}%lw_9ue+JNKfUj@O?QyMmcDi5)L?1hNTI3UWBKHF#J?ER0!KMyqO0UWsp3$1Hv4ETZO8$rtbAS6a)%~hB- z|7#u-f$H>hf%9Fw!U8vFSYN}HPsH~)+#tQuQf^g9wDe$ANbrB>zvu=wGgY}7&F}D0 zgH)n=?mIQDKBxLpyY^Evh+0&i^DAxCf~F0X;tEChcB-E;B<9jNLznBJp|ZX-7p_AO z+5xb`mw<#(nSVJiU^h>1Uep0U2p#~?mrShVt9 z5`2xKI$g+kWrafKe}?LFmYnO*4pkX9G)ixXf1VpgsirW6nATf?y?T?2l zYk!cP$QS)^`46t2e>}oK`77V{tMpf%X#RO=w&Ulk`_S%?3-q3UUYX5`e$Gio>3fSC^uu?>rQA?TsiznZ^dMdTaH$xy z`#mtKUkO*frh0NY6%u~9G^?DKU%t?zgov+H^NywE;vpiSPg#^xo+SJq>@?8418$7DakPVG$WWuVZ^7?{CVzWW~*1_2GzCJWlX`pty@%O2x~u}-)&7on+yBAi>qp_FOM#n3KS zF8!fg39%k5y?p6ujgUf-jJx!04|wSi^(-5QWLU#6yv`J_jxVC2p7yR?;a#p)9jdIU zZWxM}{?Vtn`Z8w2YCDUP>VNbus=EBKv%30agj*aYv$zIpEjJh`467;xgX5m+i;M9r zx)EiY77gt`m5bo2x z=q-F|hdOwpQKNjumfxOGHHyNIpzxsZgF%4*On3*?j_XV1pU1JUuedU~~8PtBMBl@00|@0D2mp*xz&RU^1D z%%GdS_iXg0v^CRB&y(l5OfBTco29q5hRv03SrBTI-+3-{oY`k{&FTIR(_4IwIT{nJ z8A6d!WR~{+BlH=0@8Zy>y!vZRR6qM)bJqUlbbY-#eft3IS~TcbJpsEtdyMP5B6NW{ zOs%FfxSATNmlT?iKLGcNjcneuqy$5m4c#wzgV zH}FI~G|GY>E1?HY(ww!SEuuGXba3fBrC<0yur~BgOVG#1UGo>sm%iT;8fV|UeY1}! zE-tHkRypPAA4ED=Z(Qxu?(EsK9{h}6<*HSy9F(VLTGV#k`gIO^t%C9-8NX`5)TZ~X z@WU`3d=t$d`x?r2l?6M=jWQi$quv+9z{q%PDX`=k2%=y$c+1vfLh@p489sWxits7gxjx#u2MzGlrD2foH- z_K`O9ullOIe|KoS#R9b*_*F;gR7GgKJ%H-?K_nML>JTU!$D8G27Su|uk}vVea2#DlkdOO~h1lreV(2eBDc+Iu22(T-kH#y6Og0BECG<8LtyD&jSI)M!l! zYJ=Z}aBVE}()n9VZ8mJ)z}`F}8HBCdw~`lQ4XV{Xm6)ldagNZao@CeP{Qm+JS zi#|le8xd2|h_oe89gik|hIogNxoStbyfMMLp^b5r)GNo@(ykk7oGoA5`S8M@=w$Zr z32E7~Wm?ZHU5cPpLx5tAf}iuD^vHWhT(k!BGQ9R#!d}^1wSrB2^51f-tt^RZA8E~~ zIezTKL!rDprFk3PPqehL={?swy;EB@OJJTv+sQPx$t!$$q?BmZtXt#YCeW*{0|yRN z#@!7}=+&!NIq@Gmb}TcE%z1g$%i0SF1NjvAkI=ju7!n&w(;F#+m7`alHCmv_9ZL5h zUvq`YAo@oNQ+uv7`5lV0?r-RKX@8zI-bPB2vNY$*l zw~7TSUKVz)TBX1BG3{@0n&h00DfD*ouRPNfc*AcYq7=dPC~vj&>OfHxE~k~JOVrcJO$dhNEZN$fTh4nU=^?i*Z^z>wgB6J z?Z8e29t1qg?@-IPBBgelfc3x{!yN{;-x$K7vvg(u%0L{5D$NXk8H6K-+i$41;kfj*6}9M-IJQ8?6;l?bz@4TOESEbg-Ptc zOzQlmHCh_H(>kL8{Xx(h-BQvaYn4c`pmsB{rDi!rg!QUh16`Y4C>u zwEPIvCU+01#YyWWNjzn3VIdmCluC0d0L|ytd(9^IL`}l=TRWMAXPE@i1J$0pNy2X# zp(H)H%vvBlQEh$IDikk4P&HLDrp3fes`0kQ8wzw9|E+Fvo(z8BnU!0V;J2pJ&{au z>H<&(8VTu4#cQgHZHV-j0HkdL2+d@qZk4nXk-7trb`C&#yN}dtBE1%Xw5#oLE8_hZ zV1=irT{3=XyPG~B-;F7thidY18%*v+9DWYKp||aE3r6$@o}Mqt$9mgF2Ej`y`-x;A zk$fM3 zE9C>@Y?Fgb?jtJALqv1LpQeX2d5WzYY+dFC-AP4Y69}Bj1nyOdrxEeq0L0U6S*o_n z_bJ3pK|G5Qm#W0GiMTWX@l&=e%$CdEb@zKUn%eq*=TwAT3sHTYQ9+;G_^kW{AF)lR@uY%G|zBAOr&`dBP!cQH^|EMqfi1@jDk zH4^9NvDqs@D+w2|LQ@IkmGl(vp+k5WfAe<89}P%^%08`2Vd zF4E3K4~Y6FEST=eFPE_{4*{FEp?@gbRqg|;pV%fNgzXhx$F*cUW*d^=&k8JDo_;SE zs%(aV&HJ{8O=0f#AbA;}9hcPkxa~*?Q|K$YtUGSYkI{32GIj2LFF)q7+oe-yZBNns z^9?41k8F>b+OoayFwoH!k@k^q0)GZh1LpzSm#`hpu#+}>JGPIjL(%sD?c=@%XrJ{C zK)WZ}ZxsMB(qGQna%13>E?gJramC$#=_J*fGeLGY2_6GX1|A1!e`*Jw2VMloMhW1X zV!k0JNxOi(0J-x3@R|;EP32UNc5Ks3n`qE`HX^0nrewHP5rCbervwG_fTw^bfGH@$ z2HAs85Gc^x*#PbQrSDJM#zc@s=$l%1&hm*AeH1FA(K$}rHj~{Qg?4d3BG3{%Xk(cU zWB_de>bwpBeig-iiw<;6-#Z=g5|fqwJkGSQJfA8(uc!kgu@kEX@@p+0vW0xG|CXm5rsS<6m{70 z#)ir*W5ZrG%8`j-X2EX$AVi3+3KpU+1VRYPLxiS4qz-i56zwAcN~uj_Xr`mn^HB44 z#+(`v1DVHxAKOJ3|vtvZXy5}kDlL#kJ-U@5aswaOZE-e3~n z#pGbbUwtbx%5SBI6`1TzgHyjLY*YD5UfOH_x-a#$`jHCi?oWHI_JOntU~lc{R_p3U zrLV1jpw*hXQEBUHN2PD5eIR{(?fq$M>qe%P)fc4guX`YUKgwQ1-TvB9X$R^aNZVIG zy49ZgF|BsgjZOz$#_HP98Ea}E%qXoJ-CC-Du=T3CF>O}cQMd_2d+J8D-U}hSL9n-e zOd93))Q)Psr*=%n_S&(nR@FV2zPf%)IuWm_9hI>TbZcuLY`q%o%0RQPZgd*jryo#| z_8J*bKN2WN+gUds=@>uN{)Sv+mxM z*XxHRAE_Ib{C4dK(2Piar*?SC;kx0eZ$b!R7X)su%ZCDlywojqBT}~3-`i@VWs>_)5QC-^14{MVid%rf}p`&$ilMdI% zOge0@iz_-(8$0>Wz=w5lQ~q2R_t5eBxXFL6kDGL&E*3vCk89wq+PKMwLG)IAY*A%h z?1Uq=F%#acjVT1ieoz-P`gDEtnA3GpqrR$*8s!AOu8n%&>$<3dZ|b8T__#iL)Vp=j z558L$^B~$kcnma0>SD(nsgD_JKUxSM>f51KdYVkaH0i!FMqHhx+~ZNlTP)g??jP#P+1>8 z{cwH!w0G*_XB>J9pZ*%^UPC!jTqiv78p>a*je8i@J@8j};ETFwcp!T8SG6%? zphV&4Pz(x;d9Oa^!FTGSM;}A|yS34y{#Y9|`UtMy{wXNwi7(EZ!{vw$VJ5+zWKD3c z>-CcR`P(16wlI69yCiF-dtvr0_Y2uixJz)o2>FFs$Y;$!8R~%-C=Zlm6L6jVBrps4 zC(#z5>nyrf%1XNG+ba1NAP4kz5YBKf>{`qi5ECLMMx1zISISRU1$Y^e@P$kPg=Qfs z4xvQP452z)Gi5YY zAzaS1XI4NtQV?CUh%APe$ZEo(t|~u9OLgE2P`XG3Z)<0oGX^9`WyBcFV%9Id^GWyO zZe*30_(fs{Z!EfVrhD04#qO7L=DJ@QG~c~?$P4bZxr^NEN51Ud``{+G{e}JR4u3h} z?!BYJower;_ig1B?pwC(c6V66-Q8wQnY(rAX1hB>+T?D%YAdisfrPXam9MHP)s=2Q z-Db4i;?5}D>`pHQP3cB=>(!J3t2ZNE&#p7p;(E;{v{TDhqaD!`SRU7_RFvAOk_bo` z1TbuIw?WF3SPg+x2SFK>S3v?Z*5Z0CQmTVB8EdEvsY=7@)@}vQGRCjXYSfkDdKFS> zo4Yl^jtiD4-2tt(14yZY@{$VjfTR+=N}f`#TfbW7PA7Wu9C?ge$I~@1j(G+KGVkcT zuxg#V)vC31V&>sLUl8T++rk7P)Yj6ut?wq!!aJUqld{7unyszZy;k4(k6%`cF-dY{ zcT5+dwj}4~zH2?t-ENnYdZ9^Z`YXHZJ0AX`3O`;Hk%M~yD_WGH#ezHR*Q94_!|s#| z28Qi5hqjjX)OR|HcF}UgJ!nUq)OK=GE^%tT%G)AOYq1WT=E_M0tOa;=I2v|sR=_~^lPxpzrjj>C01!l zsA{g&T9m?&XXK=fnlDr}%UFw+P*e5i4yA?He8O^N!-M26B#TEmUh7v^d##3)Py_yao3<@d!bLZRx9c{Vbdc zWA>@Rp=zp+j%uX^j}FZi;;~BcY7L}VTd(5bp*2awkdWL9vi?U-s#O%>P2>ngkwoW~ zJ`x7a!Newr!Sq)Uq;JEi7&26Ew85LYcFwMAX$qun2rwv3jyS5uTN={grY7l3}jwZ&P~UIozt_QhHA&_EGLLKl(n zEQJAGFU*?Dh!$o20d=Ire5TBztmjY%B~ZUG>sh1<-J%Bhxu}D}L=RaCjgrST1hR@} zQ9;7Ij7T^sLJBNoZT`T7FJ?mLDGZ^|LNHyNP4o&aDMGx6c2U+G)WJhpupWw&ETUgb z9t6-5K{h=`EN6p%n_rwCMqlP8%XC}&-yDoV$L0LYq#ut=UV%%mDk#Be)C$!`Zun%UiZc|d&athxOnYa#yY}* zYZ)7Wb^EVntVOzJpOQzzj5QV4GFGEaDW$Ii>h)^0TfGP6XuEo^mu@Y1l;V0dQlcXe zkF}s(^ZK>cYY$#)z2-IhwbrO;y_$##)EGn>Ga@8qpd@FoMrFpY*MTW1N_1}U6fYFokJP*O- zfi+Nu4B*zo1B_qk?%Iyxk!3Ih}v=!-=z8kAI_uW)o)@S?0Eoi){&o;E(j=JqE-9%~cEht}mv5bVH zy~1Y$<5>nJ%6e~N?Y9wKUjp#}FDSI3&vyI8jeVg>-}Q_@wdCSfRe`NwxHV@pm?{Dl zVnqQ`LQ!NBXxClb3{P!^5&$Wq@IyHXE9aewaKi*Jm4qx#T;Z&e?e zbmZcDV-H_kwEW|XozDE@;=tp7zj)`L{(kX}cmIB|%hA7I>|A;7V&*~T#SRr;U$l34 z{p*VzUjG6YUtDZ|5UC7MdhknzO!=$o%tPm@I}pL^LbFsr4fc!V$ugIf4kom?J zXnVSvUlY&F*G~gqU(BSoL<5lU%!7YJ`>*ZvA1=ORAfZa0n0$Y;S6 zioQX@fj5Ymn#xqBD4qGnX|(;)s{k2OaawIl?Nu7$!C0CXJ!}8)u;yQU)r6(#-lVq3mh2B@Ylk5>ASdhe%;E04Xf*P=T@oAAfsm z(BUJegHzkmX3L0kb(8u1=9Z}Q_+{1e7IWzNV1QDKIrw}Kg9Ul3TBf8yS{rX$qM`Og zr_gg=-fLb?{DK8WYiEsvbwn0{S8`^QDrLc_^D+Sg)|S^PN^1&0Kqx>o42*}GSIaDB zI~WpEA(&}IS}6pa83~~}5NcYJ5{e>988KDpNjS4i$A@T1Y4R+!_bLrKJ7Y}3NU(xX zDx*9jP~4{|r6|D^)+xgkRs`!6@OprG5d6HJv_XdTJf16%b|9ikRRN75D^vTAtYFGg zdjeP53O5sM48$W;w4Dz_8>?tNZ;XgMA7p8A-W;sJ6dI=H!_J$6!|eF4$$68-3fPdh zp%N8ngh~ZeZc+20XiMOAtgTw6(I|X~7vqEWW`8=aM5tXMHj`k^KqX+;tRXQZrMMt9 z)s(viqRk%G)O;emIYDHIKt3``R1l4npk7m5INC=>nNCDSn@&W> z7*8}u8bM{C*AQhs(G=xT(ME=*Xdh}bp0EUa5o9r*0POT1s|Z3R1G_fq8dE+1LQN-v zt-i2?f|oz6C?oinvunE|oM}da^^J7evU+_TF(ivP&{njVU;q^5irGvjY~exhmhD7* zO8kj-U2i?nzT2%QZt2nGL}u5HC(=8npNP*-i-U`8Cv1_H6V`Ck32T_~M5qeN+o+6{ zQynp+YqSA^Q6CHisC_VmSqS72n{>WylMFkWhZ0b%2Q@W|<`d>1Gb3SjYFj3Xi$fX_ ziJm1;4-+CyD!lm!lrcmgB^n?c{On;6WJ9414G3W>SQ(WAR#Fa53x(6H0Hse z+7@NOeo)#`J=Gz#ne5DZvPct%JUNj(&=86<8i}OX=l+av3^8pxj{DP;= z*~m4Yu!2D_1d$ctU=)Q>-W;Qw7*HAa0^C?cuOPf?YZQU{^7AV&vP#ct0^ln;bl$$<8 zG8oGeqrH))KI~dV8&You=`9SYzOdlhlA77V5UC&>sTVC;kVy_2#xze|#8*&KQ_-%VVbV|d3knZ`zx*B}ZJtTjairns&qJddD zbPdTLkZs86pJnJWxI1;g0vI%x0xcv=yn#j3718*6R)L~{EJ}+rbV)-uptlvMUBE55 ztt~79vNH`i-8(7h)5(xOu#1AhcNp^T?P_QV?G5?4-3>+gcPSXz+fYP!ps%55bbo2u z^G#BRP8n<|nld;f|M9$_{At6@In#z)d@$u+OAf=Zko+nB$h8y|4i3*Jj2j%D1IXu| zZ!$%M6D;I}xs7)#A2N+Of;mC&2sj}V=%jWhbB5{!)e-q{M!ugT?D<2w8j8pX+z}7J z0r&SY6pzkPP&m*~JaLeMhwm|z5GDiDhI=u)z+6&XU@qmDTZsH9p_EelICJ?QCUBT4 z|1iN+Su&ZyQ8Iaq3ICZKi>8Qo}Sm%$>{~Jvhry1RvY! zKfR-i@9$+O=8h&O6DAE-986B0ma91U@eu|%mP2u}z0d%^0B|m$WU_%_*&~KZJyy*$ zI272G%*JAaQ;!`_o1J>Be9Y`z`MBA|@$xjYOOK_GTU>f9o@{n;EJ8=lpJ-uNFd?{- zP%_a{UNR}T^o14^Ek!Q?^9l|5e;8}%VjpKnCCnZUJV1Z4YNy!5ABr%J3010XK?PHZ*XvIpKWjucFZ=E?2#Cl{1w}6tm_WUVKA*RCok-{<+B_x;}Q+eL)^ z^@Bmdr?yXro5aSO)~jxpf1JS?%ZM=KEr#y)i8!AvZ?U;CBv-Mq0VNE$yn=DZ;4xRN zyZp>?x4O(U*oHCJ0b^ry)tCl1FE*}!iT40{~`9uWxPI)3%KsgE)Kx~VOL{|Eg{!_CvC zHo&DHKZagTZJ(F3b_L5I^rrRWz=kL0gooek`J=#Z=IDjrx9EZEormmT7E72-4`K&y zOL&wWOxFY3fo=)2=|Swk;O@E|z!Jm`bW512hfm)>Dq47|Cuf||QDPD;xHVC_!>b2f z3v3M?1ttOOfuUPMZLVpO@hSc`7BK90Gw^BkFW-h3Jou}(O%s3h)?C3~zBOmuh`+iz zXN>XJ@5~)F;>&kTBRa;1O+$ZiWjeli(=^2R{E}(#(-%#HKRo5z$NX+sF^~T^(kltU zH?5z3_fgJ_{-Lb0!5d8;M*m1wF~C(Ru6UH|jOr%835C@|ChuXD8P!=;XPCT^RUYBY z>iOfnV@6hc3QRK6Kf76ab$kOD)JOQcBl~5tbX}v`6Q2SW|YsFRT<@4 z;N_0ryl{z}2t z1nXzsDfuj8(CEi{D%OvBO6IgYbJE4rNPXgE7=N6W-E1KpS7XA(sN<9jD+biQ7M#e0 z>oH~UR!+y5XAGda+S{s^z(~pK1X2QXN3@R%lc5hfVwr4}`I73-#8h6;h z*2gMPppH92OcSS%ZkV|F@i{s2`RT)3Cc5i$CNsk^-hOy-@@GGJdy*?FhMd1T>~lNt z!j|yKUtR=$&^r0s4@?A1ehu&uG)><5plI@!+7AWeW3Nu?`19+HlfQZ242q}lSD&4p zn7C0r;h}fz&O7Fjzj)8LZ{*+t4{g8n(sp?E>Ea(mou`U2&i=iF%ur2Lf;NWGhKc_) z+H~sl*$YnX^2f)E(}2&tAR@bxa$>OO~%FYbK)`Q%@I_97F=WC#&=-Zc+S5%ERfr?XEZA4R~U#trAL zSqb2Vg{Pd=gZ~E+!1Hu{W-=QAo^dl`B!I`wqs9&gp2yDTe|l92ID4q1%}YRLoJqzG z6X3?hi5HLbO7I^=z+VLZk8nef$64*ugM7!GRHW-Qi{7V&np<|W%p4wNQ@T}o_5Lm4 zhRna4P4R49YzkIo)Vm&To(LMXJ~Q0;$)>S#l#y3o*&(6kBg@z%mAISWs@IogP{L|gBTaI_)p5q;XN3;P^;Bc02ajWLpK zrm>-C`^Tcp$ZHwX$GrU}OGm8J>&;z`D*pI)E5 zab^GH*?mQVt+kkr4}}lU`%U2g2)p2#{NoGN6Jr-#<6mC4jQ;Jlz`@t|TRm3(TerCX zcZ3_$VGi}Thx<|eKHW!V3%4$8J=}Vz`G{~&3-zZzx-xdP+XMrn(gxIKGXyuH#!%`;8j#(3*VlYLw7ts3KP zls3nFHfay8Gl{HO-W+QNOWTOgJ{TJR?1Pe_@pn(Jo8Wk}q&eO?u3p$Z!Lnv>%sIv^ zYnJ()|N6tpu@8oQei!&R(H!n81E$HV185`eKtYO-e|0UWZ$*hM2VWR<)B1afc+ix> z^+?Y=#$t^r41dVg17G}EStI;|a)N+Jo4+77(my9Y%-59?JJ*#N51`8}NHDeKC7ap` zfteA9m#EU(=ZG7-*&KB};v8*;$4t=0c2}8?GZS6mx~Z_Cu#xDvdg0*sd#BeS;-%9g z&QaHmg(J?99@?8P;Ak^A+6+-R!M~>)iZR+hu?AJld1CR+);U23=3-%Mwh(ieVv_4)1Jcc$Mb`hq#ZI%oP$g2xO%`b z@#z^jvj@L?8PYu(K6!a>Ch)p%&^NZfc+)g-=MpQ{j2Qa%t;i2@E7lw&i&C>I)*U_$ z;U5x4M`S)inV*vqRpMe~Mk(%Nd@a;l*TyJJSmj0jlIFe&M+al8e$rQ&+B0ZGV@~~G zL-vXx9qW`8L+h0K5gl6_mX0v~z%X7%D0S%J(~lg+DZCyO^i9Y^VayHUKknvIA8fcj!Pwv$nua|MgOfUjHa1TVZLSq~>|pWZ!W;K+c&D2{tiex>KB{|Z ztZm9i*#y!eOT-A$VoO|%%y`9>8(-zhiLY+UOIYDGfs%yQwh~7h3zyZqwy(n3)mJVi zuxZeh(JQFS*aj0AfC&r?wdC#MR%>=`1)j(phv^l)J9<*hsf>Vzj4xXtcNL ztQY;&=g0bME(mrme{+nnZ^hf=jHepk6C7+#yEgvJst?8wHGep9c=e5mqpcrL9BccD z;CTBVPYiWvlZ+SF{hTrUk4ZuQ6rnFhd@*bq`^}FQkNoz>aeZhMx;5+gj|SD9m^iR* zXEg?u1N!d{DhKqt1eF8&zc;AqLH}gagNoz09@OE#QRYQpSI~D2>CAkesONk`zMrX6 zJ)Epl)~K#iU8A$=)TmKCq`F4==+@~&8XaMc8g(if_2^XB=RWgWZ^_9v?`zE*-J%tUq(GKPr&!tiKim9)rCiZG#N> z#|6?IL>}-D1yX|eZGqg=aCOFD=doV;?Sb?Rb{X_%yMH;!*js;PvLkEV>fAgc8zgL3(uWyg7H?CZmh9%lrpd!*40(Hl>0CNB~(kg+`NN0-F z9b1@b6=KV9rEZe3&f=`k+A-LevvZJh6Qeb6zkuVr4kpUzcAKae>E`kmM;TkI&I$Uf zVWPm+x?z~;C4tdI*-W2ldLOYZ`R=hj+x?5lBYhVq%NK2xN!*t?Am;6O}iAUs% zonm^l^`oJ|~1=C~NK3hyXg4(cU)lcSFUd4X5=swO3{?nqXy8$Ku;s}p)1CJxj z;s&Ga2FB>_t$*j+75lj8vRZXVU{^TOH~g>bgTAqf9ZV^9bcgHa?>7Xk##YhC#n-J| zgL*wPf|>E<83BVUEP=;q*>PF9x$#XX37Sw6G_`R#pd@z)JeiD>7_u2MnK6s$@nxrN zffF!V3l0hN$(Ej*R4z+Jj_p>*x~ z`Q+KIUrfH-^~=eZcm7<*@W1s1-JLbSTRFgP%auO)bn$+d;65B!1lW+qzBRa>3ZW{k zSC!!ErR%o^*HF58gUfRQLn<2;;ldj9z;bXog*_Zxj_tBpYb^;b2lkP{-Svpz?v~(A zbzmM9T#tIEDK{6jLazM}39b~e)0FF;Yq4mj1y>KO?h3Oh_i@36BTTu%e^zk4sx>IL zJbCNzza4l)a0kU2WIaum{oTQxQmmfT(y*51?g+Xq!5vsVxKnn(s;v;^vSJGoIiWQP zW(HPqu5Hun+M0~sK0xg=7GK7|>UO|KwuFDL9q6i^vIC|f8Lu{)?Y$`u3HtThP8i*CpXI$(6;sOot zdY!-+Q+4&n<5Lr^R1{pDe(urZBY zANcKP{>|T=LPX~-kdVHF79ze86J4&En9++(L?DgOgQy?TTg@>BQ%Pxe2|RhLE^~XE zz!OZ4qr_761QQdSL53dC4a(3ELk}hga;xiQH!wTkAi4wj#wcc6qtgP3U=B848+)et z!!dWRx-sqvBnNX`3Rh1Y?HowPxvtw2dNAW``IE;7-}VObrP%}dvIJ7b{6z%P5JC>A z5&Cn!rXV{5EgM0QFBWD1n}1}E4r7;q+u9t)On5+T=607J##K4H+ZcKnJMs^zefS^X z4r5RG$w7u5#?2L{hoHeBJ%s(W7e)q_zcI3NxjTIOR=hLHc&gz&!J$9mPinHPew8L#&ke8<2pS5cn*LU7dL-CX~cz{+N2R% zU1ukacyrJAq!BynUY*Pj@0q-O=odi1FDBbuJ1N2^lUl2WyRHPCo^6z05phbkAAcel zfBPzU?b@}oV*B>(!5g=4wBtBj@%^AxYEVFApN_zQ@WJBZx@l-E?-?}WX z4l(*$kGQe=@JK&!e%}Y9UhMsFYaItK9AfGY#P z#ro)U>|cpBRsGu5FDI`6M^^pNgBz1*ZF|v?uTBoF`-S)QI~re{#E_i4vJdO7`%3V? z!8?=cruQd%8jr~N*&UxwGJgKS9sI5L-%VaW{H0)T`vp0E`FCGVj(zmsCNJz69={e8 z6+W$(0AZVb0tbEP26^@;To1~fpR@ho_Fx?c4;~CQ;?${A!A89P`s=~Ka8|odBo-xj zF?T8t8hyrXXl zG4^rL_MoC7#jn$GWyfz2O9Q52ohw1Vh9`|MzF303|8uN|c`^LT&7hDqH^Wh+}^5QP; zLg!Z5kLN6Av-b7%wd?So=bwXsxEOwO{f6VUpv9{1&|+KiG!!gpM$DSg7*qvYUBgKC z!y|`R!G?jMb$>d-zuSxbUyNKa;OfCUqeh(V|8&#{$YIorGCa8O>6ZjTD@-?-hT1@LB>0$M~4{v^QVA+=+-a2fF(jCZd@6_^?@&kuD$W$px+!* z#PAbWd?IgJf5}V3o;#RZ=XS=z1Hw#cc1ENrJICk&ex@L4E$A(V+$D{Dxl2~`?WlRZ zZ-?u(K|$Tc!5zTW9e)da)z{Iqxs7Fyzq)YK`i0?lotiuRbcat+C`ulXu7h8S(SktX zqunvQoNu=N+Zm64JLB>HobmYg`tAYu7sf}Il$7`!JajN-@ae(2gHInEYHDh_aOlXP z21QZKuf(TDsHz$;6a3sC#haf9Iiwyk8-W+fpBH&0vt%27Sn$DT4yNM=Z&b>a3yT*o zersUYz{bPR9=02QAl@IzFkaKo_2(XUd@KHmaQw{BX*hB?;D~y}^I38SaISxr?yT&r zp(RU}jN&(}<@JKOK2^+Gk3| zKT!?9H78=!rhg`Ut{ZW2absm=WpC|!YTubh0Y7_$f#)xHUNeNp>f?Z{Z2a$)%zs?G zG%Kf=;mFJ?PR_{6Z(7-$zVE56G1EV4oC>~uIE4IhckJA;W?BBybD`lOqbW}3Csj2y zT4qjxW>3r>TeQS+gOQVyDJV{lyTMqRnRz2MGgHgV2C_28GVz$f*BO~PIn$AaYk=qT zzT)`jE9|FTkz^S`)OIG^X52oR>2 ztrTa05*C(PTv$--Weelkj5m75C;tqL1yF{uR=jolwq2m?LPXS}PnPAUYNk0p8q-!( zTFN35+DxW6jnVA%5$c#WA0HphW(yVg%=Z!Mn6hct@w0p$hN|Hg2mhag`tSec5P2{n z7b?di(_Qdi{_S64e)rG6a~?i?I3KTh*x~eR*|0iTcf%#SJ1Og<(pH8WKZYz@|8 z<6^bI$TZEmBwL$T){N)lv^s}bYbeXq>YM>ufbTplH9b`ev;=Bqvsr`3Yk@(5ny=Yc z&Mm#u!ev082jES4J~At7#5%1Ia=gxz2c0|NtpZ>a86vI z!UznqE2(J(3jTB~^O&$4)Xk|qAaWz6Cj*sn>rL|G!|%%y&A;BtybzG$9rRvrg7o5w+a z@66Ze*XPfluQ2A#^I*P;6TaYq_l@`Sd z|F5@h-8!yRR7qmubV1<@1?5n*IFT*S;gK`p?sU z4)fZ%rt?BtdfL}G|H_4GcAl?Uo8NBs)8+&Cbb^_@TB72VfcX*1yyAKpqwKStYdeM4 znwlB~ExaT@-@R7NGeDg$uh+_$`o8%P!39 zMnpzvJYpH_zTf7+v#>imvyU6K{$P%wv-a?Dc6RmGO=nkUb{2NckOE6UMl2X*c7@^p zAiJ@PWAA5YXWtce*E7A3U>9bm1S||t;_ZowEi6hg`Ph`$q;w@HC{*d{>Qt($tCjZl zc6=za0xHCfmoHzQgbFJZ&YD0ZNsA*d&z(E>MtR3_Ew`pf^II68 zL5Eu0;y5ij&_`RE>d=ys;?|**`#G`1@l-n$3zI!pwm1aAf$&bNcm}NBkm%q4TSs^Urca zb^p+*3;Gj}I5OA1W@SEpz&zji3c6h$d!OglgV&wsO*w$~nvcSxxUIeILQGW5{oI_~ z$(sJU8q5>S5*`VW?#iB{&T~<5k#NmC3)iuBFVD<1zYaVraj|jCb-tHtjAod#d&U{+ z9nswG;ORWrK4h_2E{6sOeiCX8)S?q(G)G>l7U@V3#+hvfv(2!D*@X2ZM+%s?YcWs+ zqi$)SR+kwej0Y{4kExAK-VZ|D=SVod^L$m2(Bl}7OGxxG&a5w3us|607Ztdbz}I!= z`P_&FehU|yP)zY%EFzrYaq@<;544v`X+G>U29~3Q&mzI_)4Gr}&vYBzu$X2Wt zE2Fruu+YuAdyd6jC1%~&Nili(=Z*skv+kihwnck(DWRG}qFif$}`9AtP904J0Hah^$d4%6Z_zKvl#4G#H!~ z78>@*QEv;6P*St9g?r|ofw2Le13bqm&ZqQYxCZ_M__YRzCj8Z@7tIuqk?UDCfDgb{ z1Vi@n&pP1O>Ux-|0m%>;{j34hWM^Vjeb_?-wosddr>VVN!%)=9%FDI=hYxE_t!<(K zP@=T9HVaDX>crjI*>!if+wBU;tR==6xm>pl4&erjLKVrfbE>J)g4=Ebvox zGnvu>zgZWNXaM3dGr+6gK#5@riiVq;>JP+O?id=PSl zwS!TX58l%U2M1$#ozc_DQl&rovp@M+&fop+H+@$|-#!x>Y8hRY=lG<&Dp#|hQy3c+ zswIMBGv-sF=qN@eCu?EoGR8y&Yta@|0ahQ)k%Y{T56)ve&Yqx|%~s8f49{@cP1>sJ zWtt1~?LdFz4o8xPx<-RxsT!Age*S)}Z~^DOncVA-OPiaNP;^ptuK8cZ&>uhY7>L&Z z77uhSnEh4v81}x=V-R|oF?DovJ@wfAKJQ~gj$j>dHDJ_)o)`G2YlF2=rE>ab4J?Ye zpO>3AS-ZSerZjnt4VtsKNb6h~uv{2F7DjI;bDtUQ@_?ItH3i6ATwzk!xf%5Wl z(E!)11qB6407eBT9`*$WpYuPIbpYLn4peTm{WJY@9 ziT?t#mWwtfgU3E&VbDS?!s*b0BO*lyMhzrH+awP};yKoUB{)KxXO7V3`&&f=tb;;3 zhC9Z-2dbBM=AV0?d_=3^ks9dSzelmBrOCg9xo5X~oCcy}JbD55(Xnw#{Ni}gfm;I} z{+Y+`qJaRkI8v6TVi-n?_j~!r`;FtD&!slNQNOP9t{>$!DvMyc2JY$_Xx_U=vxJ3d zt=qPX2AKcs%1Y5dd1bj06XR5Te4>@8$T-nJV^gE}KslDISOZ2Mz$jDL2XqZYMn)$mAevN3ZZf&GVkLuyk4Gz29Q-1SCvc2Mm-V0SA- zYh3F2*UmRwefR2`n?Jp|_pkraZERm5~ENcJA zC3Y<|BoK1~vmibuQe#*n?E+IlvoKHGEmL=5hw8+5+=D4WCNGr_y-L^EuZ8 z3~s{D(s=jghJ@TAB|0fZcx4T&YFz~?Fs{LEVv<8CDJv16*ig`|R93B8<H7fLG*BcpL;lM;ynggFmb7^H0O+pM&-wTQ=~ zVpfVu%ar=2Cb8O*vN9z+BHZi$ZV&L}19S|eYoK!LfZ_20)&RORXCk9x?q}!Z+r6eXeMFXWuDNL$f;jzv- z2n`Dr4e(>}0eHeIufEdE{P!I_d2|;vu3f zyZ7eh%Xf~QIC*>LuANf9u?9l1L}{}G2$+9H6u=rtSP~~1hz_@E8R=tN|5?0b*hB zSmtA0eVu54`DY#E6&8TwHpPXZ#u{K=b-!l~RJtk!n7%1U-J${30sj(yZFL={=El4r zxd8lg=Sao>nE!cv^k@LJ*+UwzSc0|CWamQ~U>z|3QRx1#2bkt3paxhj&^5r58UElH zNhnI@DXFQc^5Lo~s$A;Tx2|@dc;Up*mi{dl&YnGcZvBS!<7ocgcQ_qXR9Hk6h0LF&B(Pu9&HTIkCB-1NeZd z8-e&h0^STe79W6jOC`(&2x|h91@E}m=L39v;)y4;+~#$PQ3E<9**Uq>e1J8;n9>09 zzZ3@^4X_Wmwcz#v)&Q4PQPKET5%_=z$HVJv8esp>eL&X$zsIWq;a=|{G5;PT@b&nB zo*38%IyyQY@`2dGvS}J{Zr-V7?A)(4w=}yoklP>{;5@)OU=5&}5+A^h0?`2H0;Fc~ z0rk1(o@+j;9^H#InorU)({7(Xe}44j$&+6(|BSNIGSNU&OA}@1Wj|QgwNAX?!o>@> zH}q@}4X_T_2V!HQBo`Pp!2B~JtO23}_JM^~tj!@8%ngWFB^gLUz#^=k3v>;z4@f;Q z&qwmWqcp%eC|N(?)c|)rj2d7cXlQbK0ei%nb!$Aifa|}&0Hq1OZu9}x0Z+4_deH}K zfL|wGu)5_TAK={2xqyEu^UprOc|g~|Lq4GEK;@HJG@#c5v*m)B8i;mvXsm-uRJ99( z!jF2 z2)4g~`N#Ma;0fOR!{8Dr2%f;!$&jUO)O;vP1i_YIIdU!NUg>f7i1hxDx89fD5!e1^ zW#PhwI2!sypx)P;{|)0`CI*Ijfae8~iz4r5#!EL=^)xN7#*qQ zT13l1Z5jFkraAZr1jTqYfc~;*fD;aT0E0EazemM9O<@m!2KMgUy;H-OzXuIGfN1W$ ze(`lma3oM!Wf|oasuF6iMfwr%QaUYk+m2_X2fpSp)tHu;Ad)!b}Z#b3G4jFaHMKjkSP^2fFu5 z9mqNW_j(@SbA4Vgn+76lHcit&X!RDa223XO{NM%b0Y(jQKF~FwvJkisKo00{U)%m3 z#`ay*{gj%KN}zyH?@`@~I?(|80G=n5(S#IAJ9qA+j?Rt;$QNI~{r1~meE8uHZY9`J z6F>vp-!p0;0(&sn2hhgV;v%iO22lT_|IhqaRjVee4)YJ$f<#-+}?_c%iXI``hAfq&M4cmR6=k8kjg1_5%=tzVk`g9>`$;KDgefy&TQ8-irBd(K zUcy{}Dyk~P3pfv8jzCyC7L8ze@g6jAXXy0M?T(Ii;UCqIctBJP)(kv8!2Gipa2|*V z!2F+$fHm;^@mI&yV=sT9y`z5d>FCArpT2cs{M7O1#(yySgYg$my)X`w8h`J-_r}o~ z8Grux^W!K~1lT<^ZUk1j#{cZk|7`rFw?68_`}$sZVG5^DpPqU=#Mf2Nll%lXA;59p2{62}P7c|@f9 znmnhvFQQ=lS`dn(4G8xD*TcfYzD6tU>u_7R`#C%x7UI6f*D;*Du;IE5*95p8g7;YQ z7}Gbv@)d0NPH=GW9qhTggU5F)ss#`D!~=ZSoSgHK;lI%T4l>_3-gp~3{)Zr%hPJl0 z3)oM7KQlY)E{5AJc1JkdtS~Q#R_sYmrLmzwG{BP`)80A5 z+IyF-T)K1V?Mt`1yVhZ8*CzaPZD>V9+n|9S&5_7kNZcA=AL!}bIGK=~^Z*)QP-S`; zAv$70XswYYDw^zR=@h%fPG~|C{^bM#6ErXl&a^aYX;*D9-sgfFB!yr8IdAPVtMT5F8Rp;FiE8K47qXNYLatcR%J2u7kfv(EEVT z7c5-x0NmcgnT;r!MO~qVbp-}tY zwfCCOy>d?7Tk2Xlo}5)q%9?!?91%sf2%F69U9~P+mbZ-1Zj-UiyfUx=Dco|+hr1C7 z4OS{CDtXY?*LU~rYj2Nl>D?^cGOx%H!fRT3x)z3U?-}1(T&TYc?*$8c0=2fzCnw_* zmJ;*IXvmF_h;X417H_AJhE9rZ+entwbh5<6h{4R{7G*RQ6cU1rkFFtf@G&xA!KW|o0@D>F=B znBVjO43DD7UNe*7M~z&*9&C$O7|d`bdfPmDnPnciJc8$&=POEu;(FuK8{H>Pow#ha zs!Jw|Yg;L;vYo6;vZQ)XOi85Gt*fc3rb-xQmeJ#)uJv8?)ZkOJci&#(QOgV?i_@~) zWmHj7aSsgNdFP$CZ}I3gI=Hwv9NY$H&&*xsWteAl&1%cj!mumDO0M>1a#g00Pf{k? zvhygRXB!2l=gJ7Sg`0L!KzRerDXHVnOvvIr_VrD8S`@j?ZUoOtL8>K zj_q1pMyXSl3MNVm>r(xJb=f;S5AODq6C?_W>@;Ee)42lCv| ze}P|qwdZv;#OG$bMv#YdfZrq6J&*CB!GBIU`K1@o{KRxJF9HA2i8Mbvn&u-_SVO|# z1M6?F53KfNaqjYSCCA|nF!^X90ah(GFkY*vY1h(fS_G_t%+easK>dn(g*CwL&Klt9 zDX$=3eB)yGnU~cwmxF9UcZ02PvzP=5PHm)suq4{vm@YcV&CH?Z#wNl-iD&>_KSJ6O z4S;LWKvH57VY(j7fo_wi$0 z1D;>tx6DNhevXf3FQ5U>bLQMi2(}8;SAzfSGBRhCi3WTVGstXrk~t=kd?R9LzSZW{ z!1E`cU$fei?R5>nBQ$$Ly1)^gu4Ow*g#RdKp=PqBD&_U)=7E1*16;WA_~(`*d%)GV z)T?_@_>S9??Dr!gqlvN58jZrpN~>JC)KqAv%(P7EMkjCUj;+KqecXge>;vopJlkJh zw_G~^MMXt~B_zTsA7R?~0M)?PAAJ15`1im6{ae^hA|4QpOwar?*aPBJ2tkYh8ff2t z((41|rARu^z>=DJN(U@)35ZOBXdpNyj!b_3~8cmhbifg9hdWhoGpK@`2Wl zcF6@s4Mau6i3UmvmTL^=pTR!R+}R=gqv-Pb0Q1itaP)cgX!lF!UJ?&jR$a_w>P!_Kq^G4*T56hT z0PSMJEaBe!KYahrTW`H}i*tbuaG*)AYam*Ujc^+Qd|<%>n`j_%X(1IQTdBYiD!IVf z(oS)ixfJ1mJ3<2yjV)xgC((SAS_w!#0SQi;1O6H8124VxE^R;Y207XeP|LPwyt%-+ zrjORWc#(?w50Y!&QL5jxjs1Tr8Hmpp!Uy2@EE0ZE=kasYfBZD1Y zD7Up+Udyj{b@hrDM6XyY$wq%2`@P%qp#z+A9$GunYGO2IJdP-c9Oz5@{z5{^Dicsk%$5L~#gL>NPskOD0&b|B+ZQrq-Hur9( zZ9BG6Svfks`FT`WR7kn`xv~<3#W}g&zNY;FZVLbUjmvM0_igLb;?dE`$jQ-cSgg0H z_+PZcuBFCT z@1?x1J_O{G=DLa z4h?WFz$y&agi;T1X9wHLaI;6w-JutTZlO(}g(hZc(K+Q>uCq?7uvcrbwQIB(XQh@| zP@*)VtLt*PL!pS5>uG*{3)%a2QQ+E5G_RtL zG8#~(JJY=yuvIjR2I~7xP{fYY)PCk2svCHU;%iq?cFS7Yd+s8ox2z|1)3MXkh$5r; z>0@-}`=hk&@KLJSd4RT@d`SdT+1)!$1BcJQK@A6oD7CGJUc&2>S9jC;=Z5I`n^#2x zJPgw$&GLB}pnu(o?WmE@+TM|h%Wd)*xUHyHudtkfF3wch!onEg0_{jAj z^B-rAqw3mfYVB;LtjsLJCc6g^>(^&qIy1fn+Z3HDPyam{;H2P)G<)lT)u-N{j80Rg z`GD22l;UB#HgL!qSa$F^@`oN+2L;`mC^S2d=AdOUCsU#Hb^UZ`_%fN7<7=-xKEN7a z4`2;E_r?`c7uR)=t^wD;0qQw^hRV7&QT>6Vbn)GHXZ3+Sr(UA+fx}eR(@)R6`WoeJ z8lXd0-lLGGi2E_G71Qb;YUnuLGWK{e)wn;MJgslB^s zWA_@uec_T15|a{%vAkiq?e5*E-1w-3n*PIhV{73HRpGbM!v1_tQdfo@vY)W*s1Q?`Sr*fBjYF}w3N(r&4$S$=Y!}( zECFE|AlMqFwH-P)xhN%*iZWxVv^bS=v+Wd*en4t{Gev=Ob7dW6!on?R-}n@`kTDa; zH!g`x8O3DEETOieFH_5&2slM+iYVAKj8~5%fHLq&yLrR~TQS?hPwxp%MAntjjE0GbsQ z(8=-ZA3$)g()yVbu5 z(fQ+F=4)R{^D#}=>j5;!A9SN0@T~Nl!$SQ1%$&@r{s3lG3C=w13U_Gsx)yB2D-f^- zuvbQ@s8TDGq@*MTOGgdoUOl(BVMW7jG)V8eYS6jG6b!vPYHn$f?k=fwCrlmy+1;*GhFGwUu zWi?sQH}VOMCg1oZfhnVi0?X>D`T29Suyj3zbw49WY}!cCHJzmTqt5pO*z>vetKYay z^1ePv6%rTo>lC z2GAeKDj~Bom&^(2-&q6PA4tus)N-p<3jeHun3yyHzWfT?nAH-9ph8)(e1+@cn-{xx z?%8=6o$b5aBu~Y>pF7wksNuGu)~~FrB#1^d(Ad~WotU1b@zxK_5lvL*9VyYlIAWg zefuuafz67Wv7iIt-)#gH3KqVbue@{R5XP>SoRoZ@>-K20S~!%^v5N_f2Wo*Aum@yi zWf5zjsiBVcKDC#+Iy=q>U0oFk@`b^wUC{uZ9 zxTruhz&a=^ExY&q>)-$Nr4L7M&8C5NPcATOV16_l5j_C@peFwS0iXK>SjjIV&+P-~ zuom<^Nz3{Udo|GT>={y-e+GL1=Xmyj#D+HE->3mE=Xl+;bAt!44!%_b-uXZJK>054 z&*K~L*O8AW_!@gZgWuro5uw9j(15R}PiPK7ubAhCJsb2~Z~?i%s{!@_n~Fu z0M~LYtu0hrTT7f1T$L_*_St8#E`(WBQ$6j+8c`+Y01YKh3{iJKC_XM;G{9cK-k*}1 zLg)ukv5I9w>_sJ~(@E)>>5>$%sPF)V#oae9UB112=Pu2bk>$psI4v+FQd@oOGWvx1 zRFP&Oha-ZD@?yyczVC~*0e=YAfBt+oc)g&clKi9NX$~CL1S_sQe3BwM`vuV(2TARE z^%9k=+(Qx7owNY!H4J~O`7peXv38@M^D)4M1toxA*XjmWq7?c>-;Jjz1R5M zuhI>Eo##E6|Kou?$uICgf3q1YU1nS}m!rxl!#Tt!$VM(;I5Nq1Nec1-+%GhY*AX9} z9VZ&V`p<=^7+5b>{ZF1gc^lh~umbGf8_oOVvhxdYW3Gxup#zO$Xn=t`d77btL+KeQ zn%UQMKhJ4L4=9=zMPQBF8c0jg+ihrAL8WD-gx!Cl0epcUtzEO0@YPK8DtZFt*agyt z-M>!wM0tKHb(O}F@DB}SEu>0k0FqUJtmylpHyD_Wyw3pt3t|>~ zSNd6WypS1fPZ6lgN^5A{+AjBcFP7b~d&3Q6z%T|Lb2il1hGl&ik0TInUL)q$gz{@} zZd@nU*Nge+T{A|*QoqjE0M&azUp&^27_;uh<6y(q0ONTe7L@^PLl(%|@j`!E7`X7k zmaSWEU@K9>Obzg!NbDLDum%GBRs1i&jiqTzm7k9NwBf|iiH*H|n@7O^S7x(GJfO86 z%PZ&&am^REI7WPccl7Xj5a$HkMlSqwjgRjD5idwfil_86r)XfHDV;JCqC^L)T2{%9 zFy1kiqCy0`HISQ%oLJZgxG?D6&@GG4c<#X=_2}1cUb;NKdiRs!1FQk52aa607nL@< z26%Tz05)eZc->Ie4%rU?Y%TI?Kn)0tph`?4nwr~Y)j%kAf9Ra^QP+cPBLL@a4Mai* zk&onm2Ir*j5E1@$aqx?Hdx#F!0c!w#J+kmN5eA<>Mg!RWLk#RCU=4i4^MaWgfKI%W zyZL7!cr<`DeV6uMv^IRR!;sVAxXm8G8d!vlGlj_K7X0vn?4_vjaws`Dfv~wia>2TF z>x9Cd4LyYZ4%K7schS^QpU1e7dpQroE+F0!q`w~g+rp;Cx6Zlo z$o}9N_qqn$fy)_<&Gi?F}M zMe%BaU77=&L|6k3ya2ZfNz;J05of03mIBlTya548=K(eyeEr({*TG*)l1yrNVuN`nsk}!KZB*H_ z$enENa@c}xln|fb%>^>nSqJR%I7Ws?x)B!X-US8?MDjWB7s9!o2Si866RZKI7+Vj8 zcRmViHV^;UOvI)TVhxcetRYzQ!#VEc!`h!swv6#(d=1}}2N-<-{~F#uWZct+`xyw| zk%F3Vy=b6~>w)N4%Fe=i!O+m{h}Z~dK*c740Dw0W0D&kJ8Q0&t+I{WaD!0NVk%1m`oY2h-_0M~}R!uC zRzl1ovg24^kU%ZzSmIN$zz`1&aC4Av7vTo7ctA;!)B+h98D0(Wma~@CEsT5Ld;i+6 z&wP0O7HgosuI|?QO`Gn;Ex|?v#{$ZV4G{i0kJRjXl3GukCUfv2n(u==5E?H!2t>45 z11j!Ml6|VI0S0RTw|sb%1 z8$1>b;FmJ*eD2YJsvCiR!Fyy4@R(-}u;(-Xq5-&?ev}PmLGS=T-$#c0Pwa4vZ_|MI ze@IxA78RGMW#wgy2EwpM13SDmc)+2-C;K&cz+LlvAL`3>Yrt;vq15m>6oY?xPF5zR z;*O6dtOwO#JQrcNKem|4-9HBg4^U@&Cl!?zQBHmi_3!AX4Lv<%!`gCmh=uC&6R2Kw zTCi{wCmP^F0!}4K#hKzH6r{44z#8C%WzGrsjycf)_X`dkRlh#-!S&ngH*OLQY}~T> zUSdizl_yU5!0N8GRCDws;l4KEpEWRlei)ep7m+_aBN;mrXr=}@JLwuoz{UgcJsf}h ziAa^JMOHtubp1p;hBm$zv@OgZD3_!@o{!`rq^y@O#dCVJl=JD?3 zIyhK$4}Qp&r7Hv8637LgfXQaC3LiD-@ji|DE~szzj`^6xM2$HI-|v;@rGFK%@QM4( zcgf;8#J7U#}z>PxQREF;W6>v?+n-DwH zwvPMf-oO6qOINSn;z8fLt=CJqKIpffJWd5r-J=NSCIj}aOBa*JJ9jd9CW|jQA>2kt z3D{r|9)@v@ajOH%t}+Ku#rQpgp3jX2uMcv$<{9u}2+#<7J45H(Xa-(=;Ca@7fOUX# z@0fSzfAH_&UJ}2q0T@3vcX!eg4UbX6M}do3c#g3^ifM%n?K>B%xq(n4w5|_kNE{eBa7=0QV{M)u{q|SAn zGLMJwWP@m2d>o}=M>TH8WYEL-?E%zv z?gEO5e9F&9+ti$b?ga#d29PZzh5W48WZ2fpTfJ#DemGj;bmZA1RElmFuT(5vyaa}n zBz&_s;0u%l_*!oApDOy#H$Q7rv0n-c^WyX%ndd`%&Kr;!@?unu_9fU)gZPEAC}0#( z*tV3Cl!EmWrU#QOm$^g%pN0C4}{6!*xzGVxP!60nc~0RX|a z5O20e^Yub3vOQud*`B{Ojc=ntDXU>o4io-NEhZLUzm%AubyX$bTVH6qza_^+>oeS> z$5`eNlU`p_LotgY3Ag8iBh1s`!S%IOw5g|y)cVGHA(3Z%Jdkn6yR7)jfJH2OF!&p= z3Y5OsDx^Dcw-KXUoX zuaBQNd27>_zR5&Kib^F3?DPRtlDUXFpF4rsV>&(v8u}nTG7J?(dy|lEMklbfeeDh*5G6}w>gYcyWUW#=}-N*Ai&-xfN(8B)`Xn;#t zqXu{_yrveb0Uiyo4p;-YlU91DCB-FJFI{2KfMvP{JpALErX|sHvbVN$k!7)+0(1>5 z#GuEGX=DuzdC;}NUGYH!=lFY~bPeE*T8PaiIw&nG)LK^83;!02P20Dobb>XougFBJ zQ%n>cG)It)F_?|q8;xNQ8xsY4jH43NX3sr$gjUqKNKMO1qc*GraN)+aGY?p7HIuGy zMrHbzO!=;YN0ap#*@Vh7KJaO`nr1Y0PdxiRaA%u z$`HxLuutxf@QiXvBK(6j0C3J{{y7g=vF*jGVjsi8s95O$O=-YJ1`SN}0oDK~fEetz zV-M)=Uae*2q~n@RyMAup<(1C4U#W`eeqpqUlsLBroQX-4xHw+8$Je&Wv7vrB?Ze`~ zS`QI8Fbm)Wz_(>!tEsz&E-MiY@O^*1>(`0~xCme!Eti4^d_=&qwL37dcwNVtNuraYQLNDiY1{+*+ z^GZ^iny?axe_aLmPJ%h`VvZEQz)*Uw`-5&~f$lroJtciRkFzdtt~C zy@0Zp#!)TWkV%O}7@8|lMdV?!j=M_C4oqJoq}$lEeHZv&P53Gv!q;jNwmwi%mJ@C3 zRiJS>b$0bgCz5G->6Mqz@@|j>_u|TT%k&96L+i-ewJiM#X999&712xmsOwv*xO))Y3CEwRg`RY#tdJ9BI$DO<4SW z?&IDt%0dp{tj9lthd7%X-`=P4YEXV&u4rH*8tVb`(H#iKePU2DH*)YtLM4>g0Vo9> zH+eeSThJwHr^H3U6c-kNLNOJ*u5xEj6dBq0*K+aCJCa!k>>Q}W8Yk-RpT?5!x zi57JGk2)rBE$pL{(LdeN$Q3ca5A6{@u9% z6GLnYws8K(clSaA*dx!o1;IZWIz|mV*xI-CBi<#{(cZxtxNp<|^RH`wbp*1_U?Ff~;E7-+iuqWq7U3(|$eHdG{`nj? z5L13ZKJjFpCwqNc*3%28PYD0fRx?%?D^Ofkc{RZKfOnb~qI;}sfW1Z60P6{NrKtBW zz4g6cpLpTqtx{Uy#rKg^HN~XWN_UuA0q=vW` zj=v&9*!PTSa5wIq8>D9r9}=H<>z%h~%{pYozFs-<{Wq)uZhu(Oebjv*5g~8IejA1@ zI25y0+=+lXz^wz&uCfU*|2!$con#iQb;_Jzx(2*H;L!m4z@+X27F&cC6_2lITO63nh!!HFBE_+|eZrGFt`*mJx1%mtOC^PQq63~(R$+p{lSgg_umf7h>nF| z`*%^}#x3FjT*PwIfQ_acLR+>pk#dXJ#Nd3G)-kvv%_D$6l#B$MiYKtdq@xZ+B%gCv zS$`8BaUYat=(y*MyrjXf;W-92_X}794AB5|zU17kO3!s5>9v|>(fIVPIT7iZSqa|WLCcd^q5EpDxw&J_YPMmmt zZ(rZ$kN7KpFeSdvshrC_mFLHtLbna{OAn=@co`Krqo}1QmYhkkXh~b$8#7EMxo4PL z+_(ja@QsPmgTZZ#gs<(OjT<&o5*BGHK*2K1A8-e$w{3;rj$oMf2_y z)C(#PwfonvU;lOY#tmBS@)ftR?ltK^O_&qwPfH^FDK#dPTu7<*eC!Cu9@=^HgHaE< zKU85+DRmqjC}{FrtrmWmxVih5$1%Gbed9fa`%^{6(>_ zm{<+FiSe~7Nm{~Ed_^}95nxgrp(f?|qtCXzdFhQIg#I=bi|_KLP?i733pBiNUsdgr zzNrf}L2i@@={SILm&VG}nm6P;VS0iVEm|Z+#5|vQgf6p`RoIFuKci`R1NHUxNgbJi z9KjmkB*XWXv%jzgct^2<5x{8~A4Fv?9vnGxpk{%OgyN$JX17~fbOxfG?Z$T0`UUY0KQ6{n12S( zYS~Emu0h^8yt;8Eoj?B?#o-Q;6jVR>f&$S14>{HVdjR_d&j+9ZRgB>OXYb9U+^Vj8 zVQiOcR7on8=6NWoRFXV&w&aq!aCn?AJrAIG3k)?{(N3*`%1SY z-F?pfoqhJ%XP>>1TGS#{fp|oSA`FQ9=qcvyc~q2o=NsSn#@Q<{fVJV(a{*z%iW3E- z2P(p?h`Z}z-jPYR5)UN#a||FVHPMma@~8QrxxvCQpoRN3PkFH$3?d>z3Shu40d@`e z#sIFQ3qFGZ(g8H?Wh~$|mpx?4HwQ@GAi8%o2KZcnd4OY}2J-=k%b$QiI)Lmzjs?6{ zD~TX~B4B{zPd0(PHiRB1U;t)2ogm?QK*oR^5K;&ZSO^j@YZZdcfXwJNs{q9(h&Tnd z5~qPrA!zR{+DjQlG(f%A!`fpA>}jfF8-|-%z>LG&7(zbnVi+eHtOKKbU4V2H45=77 zA%#0zTE3K_%m!;kvIm+IXl=O`SRh|8jelfa=C&Y3j*+tJ1k-%vQO_4t2cO}yal_|JkK*xm~9tYnM z8t5Nj?QPgif~=8}V*aLMH@yRSpF?sPoPBnGD(~IbzvK4@=EJtCd2%jXQ{LMkbS~^7 zfzwKcW*72KB|DM52pbDdqk`M*e2jB}e=6%@85h4^kT;j}qyPQFq6+Z~%9`Z-MPyC# zEhZ$Jx&&E2&DZ>ER-Y0f>p7A&a<*{=FUy(|K^4oJDH`X#af{bLq@FWYp&z+P6iAGS=RuNWE#3#O@7=rizJ;;j-y^yF z`8=u5SF4nTd|w#rxQ`rQO7(e+aZdCa@;{I9&WT=wxpPR+ags0~LcyPGZfc&x@ZlIh zF*82aIS%leW1u2G?ty-;;N|g7S5#u{|Mt`0-nD)E_H)qfbDKA9VqF24z`y`faj~%| zP7UL%>!(lN`uc-kyY1Ym`|m#Yy=R_2 z_u#`1o`aj^+-)ltG|?|wvWV~Y)7(j63gigjsUu+I)21I8j}#3+i+t|z$D~i2 z0@z5nbUJhT&C}mF{SxK*rum(Au4xymth`)8nu(Wig!QG&N%19Z<#m!#T_yz^kZMGW zv(O$9*@H_;c%4CHsFYx(O4yCyL{)yNU_i(ZgF%Z*bM$3oo(6ISPQfrzqY>dfs6nOx zUV{RS;XH)`0<2P@0pBBn;lPQ%7wIMn0}#=N{uIHq!4Kp=%Re8$=Rrue(2t%G_U_x) zkCh3(NB8C5{gknV?}E|m@!7xo?svyUycphh;9&o^{`Tp;N56E_TRV2{zWD4j&%T7N zmqGz7@Q6Y(;a(^t70aGpW7wkFg_{=#z)8Vf_kHbdDQGIYL>LIw8Ck+{9ryF8V0aP+ zRBDxs0g>;elgEgnatQ-EgN`956$1b{2Iz0(Tc^EuS_GnK1eZTyfaFhWe54z>_%~1f z&DpJ3<5M~r!T^zs0V?!MqQnX%FUA4}L;^t`1MntGm{6|307@McFhGd~2?JQ-P%jAo zTQDG!{EIOV3?u`eQY&7|ME6@E|0JjtvTeoocPr#fl!W{_1%g3*4upIBegOB0aF5ef z??w3!!Nzd%@4olFm0Py$kdEDS^Go}#-v`c~Kc$l* zJwP!S!w8#bYi;8gKu{hM$^XrH=mD++;Gg*n2B;V}Q85O59?`a-2#|jaAi?53FaHHS zfK`P=7@#E&=>ft3=>Wn2G-EtZRk#x6-!H+H(~|PmB}?$Sys8xxU$S%w5nj_he72&z zwOp($kD~@h{^k;VV9Am&x+%P*bV=ZIsT_YJT5=T?zEd7R0=+O4+m%H3K!xv>mIp*| z%0En36g~~y{nf7}AAS7sn^4Q?RQZzf1**aoR4NnhmzJL@)&q1>m~;T$BMjVdt&&+{n;pqmjgK63>IV1RNR zKsczgXgCH){s?=KjvhN&bL7|&1rp|5o9J(#V+A^f*T+8ntSEo+2tG)J_eXC$T7wVi z{uCX#@rbUN0Y@Id?q|DF5;7Z{=6=7hfy^J3vf(I3A5!|&^U|IzQmsN)pJ->;-& zcwa;^21w=z#1-HI6R`Lc0v@a2vucFLPTaoouTLDmXRs}Bwy91(7YKy-4%ULGMP{?v zcp$Ybd-+Q9Khe@9OL@>GZIh5Q5a-nRrf*xKjgNl{Bp`i&0JBR^f9L7*Fh*Z;I2;o4 zSn+9{<^#&{Ew2k`-iK8!SyiYFSAIP}pemEJ}mBd8f)CQQ16Nn$pXZo zLPmu8RSWm9vZp^5OO^swD7=92q7W)bt{S?tcvbs)k6>!y6GF}+bQPzEIOP0GDf+zAA6 z{BEHW$lrx@)D-I?QV&od+$9u7IRCfL{OwDa%_YJ&nWr4%VEBvl0ya$~BI*ENTT((S zQ=t>w=v9LDr=1WpO2+^)nSLlq<$nNvh~#_nHHC7(!1{x(hCUgCc*`*=zrXq_;pd9) z;k|<3$$v&C;!=P&y~ancKrL2pRCv^ctFHKO;7D;TB3U8_Jx8-F%RnfPW|AeQ1Yz$g zq5t^t<6Ge>7N15<;I~L&6$H1icp*rWKnb;1BbtOM&s${h&?YDeb0Ou~JQCx-gKQQY z%_K`QKS`E^Xqr|&m8DqD;ryo{O?rxiNqUO(62yw;2wTS+93+UJap|$a1g13%mHNl>O0IN>$IgEnaq!wV=b22Lz z3q&YpBu?LchbUrW;Vf*1Ia+tXDOMQ3Fc-12Qp0UmvR_J;V7?++n73pbh7JxOpBl#j z**X|+mrw-nJgrw@%Sy1)B^Xa!_OOBTa~3dRL;h2~fR)c*8I_AA1&kJLb*bdE(g7_6 z2hRv>)&7BA34sTk08Z`z)9X+f!=#riP?;oqnc6!NVWPt~A8nl(>3wqDXzvRkY0YTw zS)x__ooA;y;%EECM(??#({N63Th1jNCjOem4>+iSRdk z=FOztaGnV7iQa6t;x+xM*_udVTMz>1Q`hjh(WqtDdr{t4@hl zRn?O=kV6epDV}zys!riGC%dZZ5xYup0{1!5Yo~gFYE&oO`r1rJa!5*`XfZ` z?VL_v?^qxlko<`dye`19=kiyUVMAMwRH%zfM4=a@FK+*`xD^GAo&*NoqO}O&Kvv=; zcRGncn^T{M0n`}b@|Q6HeK3Fc$l-U8Nj-0?!aq$IAfoY47$9BXB>CI$f}9xDMiW1i zLl`J8y%Gc1`IK;6QR?bWarwieBOw-;V}RuEuvrSSmoYFjH7+Elr+fUq4fjF764BiCtEOHD1|+*$A&K;#O_e9eR&wGsC%mS=0Vppl z&~w1Wb9nunQzngCs<)Y5hz9*q_aNr|$#G7@)8i6a{v54WWckCW;5tCY0Ol-W6WVYx0q4TwArfB}co!F`vsj=h#1sHv^F0s}Zda0z*u&m*7-&x>I0k4^CkH4I!t$?)0jpXe5Um;? z9dEN4&UZtsL?m8LA~rixpcQ>c$W-rO9eACvAn)qJ2S~=PRy}LAfn@p9bpZp-_$++} zW1SPdCTf@ej%y3371VAwu{L~;a3EuV%l~sR04(G&@adH>LiadU=n4!3+%^z~72aEw zS5mPKAUu%#iAV?dYOl-7pDG{_21pm&c+-uf3!VlB-r>3c8_pC}Ew5keajKYz+XO{( z0qFo#+bPDt{LJc^i}&4k-??quQFRF-A{#))0IgY^PRO4W0m7;Z7*M+0pNjz)i4x5P z&50<-02vp>7$99BkAJ$7qLDGMarMdq1_r#g1^JVlA(LxiAOV@ndLV^lfE_+3qkF}A zU=m^cBvT^7KpW(o0AA=lVW8Op!Zm6&vN*89F@X0n21HpAT!8^u2P|B##(@037z2$y zr$l;y?zxS6PBIqc>PdE^Mj%p_FXmKJj`43)EatK&`9r3h;5mm~aQm$Yd7grvtQO>DEh*)G46+4aaOMM?fCIvU!{N9Dqvkw3`7eFn|hAQXt+Ykxsx)3;&J^ z^MTQ3lZ%ObV!-+gJ8)Vx z8yo0C1U3Fx=VaYD+~15-P+_-|`Hfn(9IKS!ZX8s=IIh#HIfbyBzF}&Fr6?>1R)yt+nGtM#BOT{G5 z2?d!K>i~MKRZG#vfD{YEcMTn|Wy=OmJ`6K0tSA`+^=`WW>x#?2qI8KUcs1M*_zVWH z4-LEE_O0+aok9)xH(|ri(Ft_e2nAi>K#`+hAjqRCxG#(B0E?v<1M|SpMPT4{EMQ(D zaS#Sb%;dN72SmRF&-yhnK=Qv91^~PQ2I|7i90S}I0B-D#1v?O})_br40t}G+u>|KB zaMZau2I5{H$3UH^QL(Kv(`+-M-V)etl`+r}Lli9J&oK~0t{ljcFwhwZv8H+?f51_m zVhkMJy91vM7cj6D38H2u#yAcL15GYqi1Y(+5OyO(U;zUn0b%{**ym!v23g8D_#zk} z91sR(W>!hP{rv?D(0o8TfYyP~10n|k=>T~SDAog{4@eha;du~&C{IHNyhFMGDz|_E z3UVe4V8@kvH@F>8gaLoh&vgJWa25+(2_aq_0~`mW|49+hnvM)Z>`8MXfN-zHH87w@ zwPZOwx2w0G>j8R?MTtZ@pcn&M3+gQ_U;y4+iR3@Ne=o;CM`!PEI>Z=?z5oLx|Mf`l zI)$Wtt0r))v%8x|!aw%V1MH5QZ)DR$1FQ|MjZq}@SUo+-dXV(tOJ6$5#t|u>iU!yu zbi)Jp-NSW-tOp1KJ2r1%{hb|b28STmOidyj6z7F^Y~jbj!icaG*C1w$X#1+X9x$(`l_S{IUDAPkWFy*|`ifU+SQfaFg&K=>!$ zOnyuj0I(8jydP4*uQLyiH= z1EdE4A}&iRW=Ti1u@NF!-Cp1T{($ll$!ye1<&d-6>5}?k2RQ4aNaofq^$!oj7hr~- z*Gd+AFAzqBE$m+qkwcu^s)P?By~!qM+lGZz;tjWtw~fsFrY#(1PK}aH&&)6|!1YNwu^6J9epstl!J1*$QU5`lRt@~eFy`F8jYY82?Pgk8E+ee9>Dxe7(gx^ zwgIQ-C_fTmAl1^$F|d2*4u;hcTeSkEe0x$XhE{LivjB80Fo0B7SLgxAtFShZbpc&vU4Skv=mHr7aOrXkV2Q>t02NO< z;JmB@@)!`2kP$%8V@#7CphY1O=>Z}NbRxY@dI0s~B{z2KWj!EcptG~XFq5bUP$G={{z`=tD z*yha}IR=XLz*oL{C+7Q290OnZ>RoIWwnGFv`JD}j?1LUScH?1o!=7C@9%f=k_v~S} z96rp%A%KD~(2w&xqz8`UVMJe456E+dtRLjLgZu-s9v}>a8S|D_!KZe^MQ;3S{KTCfG|Mv*IQ66d0{RfJuo^p!Pf+# zrZ%nz0+A*z|6&a2t#+;pNC(hw69y_pCt%w~=OFV=#gcry}xDL4iQ2TAB` zmmOPHIGX3N-$56leoe<3~aMKB=X+=8W6BXUJh0vR{JL0ny}5R_W2P>ziQ zL~IC4;W#Fu#Uqy40z&Q=)(Lq(!4jb1bdjt!Nw-ArOh{zv6@ogCUjPw8uPg)BU z>;Nu*QUo#~7+OMbWZqE#XA${#h{$n-Nd-P4H}@6uwE<8}7zklTGuZ4Brf$9#tZPb1 zi1d_@k3uq9TsXdy%G-dj1F;b=fkD2upmnEH1i0u&jM(yYSj^l}I3~1T?0{d0d_6&j zg|7+ySnm@J!nz4Nt(=;X_zP1m^XXK~i+Ll2`^$!U*x~)V*aoQb0FHqZj%eK&G}Ln6 zPcwWCb+t;?XfrbpzAMrPd@v4raMqisyA9QYaDLcNUj(fg8$M^OuFTv2nE&N*P2-%e z3CJc`AbE`->j3_l1)G5U1C5C8LB=}1Zm{XKm_0*OPdM)|)a$hZrNC8GlnZJ&i%I@O zNczJufVdJKxrZV3xfmc_01WI!c=6dKB}?YUr^dO@m{Nj}{NYb7_yh8G0LH&8d-;k* zNC5-14kTw0VSwZ>W1y}fi0Y|`U0lEbEhgOl2C08!L?Zd8da&~idk|+#IR@&2C=BGT zgMY}*F@P%G-0y((CvpHl{xSv#2P-E=hFk3hj)6Q52n*!z&(j*%@7>Vp35%9f+k#J! z_6iav$Q)Q8@?lsL2FQQh?lg1x=Y7EV9DXmRRWgwrhV+3197)YE81n?DAr=tr^hMB~ zndx)ZB6Ms7ie|bx9IQ+&Y|!`7z-FE_ye&2_+@Sk%CeWQgaOjs`9&gRi_Jp9073w-zyKfH zdIJ}q59@^Xt}dR=!P?j%HK)3{9v}=@oj#5OXMKR{0@4A5fv5=OA%p0PU|_tx`3elk z*dPoL1y5I^N6k#CX!B$LuzaX#w zk+?*vgKL#=z~=$X_bQBgB(uot062|k9v}=*^e*WF@)hL$1)rS@2m{D^#&rRbpGepj zdQXf*$xwFdz~LNdA8*1~?8DbOXl)VdEOa=Y%2*cuYE)3q+}V zxL+Edna&ejD&rt!tyWMdl|n@oWDYqKDM;@F50IaLbsevzTs;3@>owVq*hg52*z}W_ z8{Wj3hB+KRVRpCu5`q}c-zJK12z2*+W)6^XKKjevBtiOl~K0?g@WCQq}Rw)q)NjTomsTWtG%8Cks#Ez9V zr}7#Ne1oLtA#<7+;P2yWfosXR_#Vj|$*TGvef-g_w;aFaX+*lcg-rIm94ch~x_AeM z{B@t5_KQVMVz=25w=8cOQV@x3v-5y=cu1Uee#lUJh0L9yW-fES&MT6+-elr3FD)zO z;wF)kxM|3nfr&aVHl!TZIMMda>sy6L{Y!mfxc*#U5e-G^&k+e;2PcXXxfZqI{uP9H z5NtmG=VZZWib#~-?4Fr=%357@%8Iyi`WO`w)XbMD^22zQyvs)@%9<0{r;lxoJkwO9?=;21W>JrVf=2m@rd%NQ`*oS(q}jeCo$j{Ezp(JqMy;Dyi6#K%0ClPC$i zMyuiSCmhHaICk4@3Yk6-KfWCJ5V2v`qAwaR_LqEKyy8oLoc~Pl7?x631e5(G?~mPf z%vVgL0~RnKaz(&(0Q3NzzM&f0B-=j+1BeF@PzF=LP!vv|KE3jmTW)y-IR($6+~Vsv zK+E?5K2Hw-Q@{Xx!=wms7O{WJs9|dh@CFp3YXU_RI9Nnrri=)!&EGSdV$^(U27E3J-N5A z5*D!IDIkT9@SVT=&Nz}H?fTyLzIRHzQfgs29KtZ{eTQ3#2t}kQp}v9l1oZ-uwF5>Bdcq2$c6`eYsbyjiOAi;@RPYe86MJGg@TY3I-djUVrIVH=Oc1w$~z*owc#Rw17 z1Ky^Dqz|T~8hFP2u!zS;=O?R{F*(%abPy`ULZW62a+h4=|e!W0ui#NeTVj~#UAlf z*XjlMnMJPuajri^|ERbZWGv8Vpk5#>P%j`|EY3q|fb@JXAQLC{ zk(zi95H4s$Xlm5F7pNzcI6GCq0*ZpdGJ=Psq(p!rDIolvTS`DI54%JWF#(gzXL>-! z3cTY2yrlvnB{{*cjo*6fttN!~@@R1sA&QSpjBz{=KnsLMBZ@-g8j!-MNoGW}qJ^2p zr%vh#2d$Q{OJc`rhsfI0BdKcjlDDNts$Y3Pa*l45^v;ID50jUbcF4UxJEs!JpGb+B zl2+eTGJ`0eGIIt1sTYvmgD>YuGhW>bmDLK~1Jnz3 zfhNf}x=E^AbF|P4N?6%6mryUXb%b#C#mIYr_XK`B6mFC%pdqV(4eAA(eX*VQ0>=Tc zfCmcH3)C`dAr_bdCMv#S`n+BsE2+2_5H-nhfSvZju>c&JP zR3nvCV8=|U!~HxSDxnprCzRMhsq-#iLGA@C&-jR-78Akc%CR87zZwhFTQmxadLfBi zbOF)_h!+8rKK%zg)EvL<_%!hF6!ic#kYb8>FAzWo3#7rQC#V&K2kHSLd2h+v5RwQB z)C)w^1E_K!nZqebjo+XiaM#)S_X!Ww1H2b(EmDaa`->P6)Dsl5PCaoQzN0rT&L5=# z6TG#NXp;a2cn_c`fdI#)P*zcP&5=MoQ_u&{h|r2j(g)B5I_#Jga3J>sdZh$^v*8rr z*7Bw0&m)TfH+In&*b6Wm_#!scC?NwE9~F2254#~phZDMhNZ)|nRBN52u(_pjWet)Z zA>mmhCFu>cOO9Tt$B{A+wXQ@3`@mqA$||sX>h6*h{$Xipc?G9(fRI+?^vv?|yuGl3 ztR0+bhNa{z^a9Nr)C<(wt1&?LV3K``frVbceo=rlB3k^Qi;lmD3cU59!KcVONYW+= zQk#iL^WzAugeir$n|6BTHhZzCm)oqyDzUT-l3NU|t~ERU* zxl)ajv1l*aZQ@^`hSL`*yoAnLQp0hGY6^_-(N0n)BB>+4&Yv9pG;lRG0UwbOmZnhPmzRSX!F+MKu)2xQS6C_Hyz*-R@Mc%go)|0 zDiv=j61!tfq~|f0B;879ino@eTw!hIQpV?TFdPdf`XUl;@|Mydqt+76Ny>6-xpX06 zk|fd9vp-3fX8WSnCXq_Vhpbh3>Doks^|9l}xO7RXw1y|?$!$f7C*D@5On#3BK1sD@ z#f;Rv|2UT}wUvn4Y4gQ6k_pkxtzn+#wN&ThlC81(B$DjXN=zm|d!-8M&Fr!Bwi2XC zs?^p8T`y}fTm+e{*c~N$(B&VaJ|Lp@l6QoThXZo_J&kpw11X@NK6BL=7x zE^TB_-HI0f1GZBo9{ohE#rP$nsgHI*2-k!HOG8BRF5f7nZagj-I=4zF{wh_*$E8w| zpmz}8!5+USAcbQ-sV&)v^?^xpB1)oMp~AQ>=f6R}qkwP874y|#P%OoQARit9iSpJX z8?NBQTu$V!M+S#*n71BZ<0Dr%lUM?KGV3TfAcwj%*IG;@dxh1ySTcMnYRw%dnyNoI^`9W=PycC`@^1J$)s z??5xai`dwhQQL=r zjw{;ErH;0f)Jexd5f$1_7JpIOlUI%LMiGNucj(ZejcE0=#Hk$5PA#WB3TioVN<^); zw{}Usnf<)w>R3N-b%`M$DFV~H#Uyo-w%KanEvA-Ji%|?yay9$-??Bp8&-O_Ycr_nP zgmns{m0Rs;2=G?d;YviUCJiU!oo0D1ZL}K8QQm4<7swWVQL9^NtV6ssqd(|s!0fB?>!;(3ip6Sw3Fy$xGDBDqWzwer(z?b zgQNBK3M^c;SG2VbZIV$jQ13zf`}1Uw(-cOHB}h}+4eX^!Bv@)F3DxM2N`Y8{FX9nXEkTGc#F}GI z9yqXf@2$5U8wXH0VTK$BP4C%z{Y?<;BQRxoW2vDiB2e)ep;AMsfiAcv+<-HL%3Db= zm4_(7n1o8LB)Z0srRh0P7_yz*_&Rp$F*nSSU08)YOYNf&O}ULEP->$d(=wSVMASxE zm{<$)_FaGA`n|`GA4}dwjz|0+$ixpg=MTTOqSX3U;5Hns*hWMO>?h-&0gg!RVH z-=nj*jwGi5Z5&WQ0!d5`R;15C7yQGPty>PG!;;h*GF7i8x{tpH_8r`}7EX&tpwOQu zrH+-8lt?x#;;n-w6zVWEi-}rCErTJ(TSv+l*$4_#jBH%VEyFd5;y0g4Z(tmHw*-xK z@7cR&7e@3`?qH&`rx(B(7|t9WnQzH|FZu=uRohaIqF17|S- z)@l|;Ke1U^jzBkDU#2wxH5S9*mZB7j^4KK;S75&nPDIO5IBQ5s}qG zg9ZM}r!lw%>OM$TOTU4XC_Ws*K4G-zo+tjO`-rzxZxn`?TY$fd^F%l%=Nok=+Abh= zHi_4K(SSDQP3dKA3tcB*pZx^7>UjV{BBI9=(QE258pELH58iO_CQMGY2VGG$eRtcA zZPTc|_Y|@)a#otaN>eL9hX^TRh1j4jB0CSGL1v{DiO_uznLO*Eixh2g7omx}kooUf znGf22m-(TQL{oidcjqaLkXC#LqKm5OyLcauH8qRi=Q*rA;#z}-cMInOYK(XxG*Oqx zydXw_cL~s$?~=96)GV;TyM&x5Q>IQ9;nsW3@N8O-}jVMe^R_dGq5o`*WufAy(^yUS(%=viB~@9kG}D5ik@!x zjJ4RSS_!LbPnXa|lS~CZppn0bdkT7AOt`07pt1*DsUiGW37#CrZp=Zvz7c3rDdBW?Fv9ai~nU&EsYc>UtbV-BKMoZ8si~d|f2|RHz3TE1N?A*Bw$@#wujdpTo z<+_stL(5KXSv7ugW@_{#N`9XlpBO)hip~$=^+UtMBMUVA5c0UihsH+Z6O*f&P!7$F z`BJfQ)5cQtR>_}3$8Qsl*WiGD=fu?1t)t^356`Sx`S9@Q%)^~s6Ay2n>3d{yZ0HeW zeR>4;&R?S>?UQ(&K`o9v3EihVkT{`laIhnh=x-kx9*ZALr)@`$9#JE3zY;6ZN)-C5 zY-w((r1u5F`#A2SvDJsgBZuqPu3MKL7#w`*Nt{OKF}*X zj#FNbuiLQxo5;ibf2BG*pKDFD76|!zyJ`*At}3Og%V=z}dYpVxARePi zi4?sHRH;OoUS&Dnm*YA(JZu#^x;w{|2G@fXHHOo6m;1C)7!Z20Xz>zh2@#euG6SWydMrL|w2Rz@38o1-+^v{hYls2N&?g z0Su$FZjVPQfq$5M#4-a_RT^QbsZOw%T>`Rj(KOqEEcX6*JYFj^KupLC#G0D)U?5@> z?e>Fahvo6oaz&<8Wz1-F+6-2>nX(FfW^suoQ*TjU!2nzkuU^eSS$Tzknhkw!biCRwtu?f%}!qPGo@@3W0x?ZTPs^mru z_7MEYFoS1mRmkDZ8Gx@r4}7H181X0=cwA@JXR1`njHaqIqtn;&9zcmATs0Y=Ns-Yh z%Q9GLWuU*GL&=k$)0QMvAJu~qoxv#8>U2UwgI_2I5b5DWWR$>bOuf(y25cCHHN*h5 z9`Ai%Vly^*6!#glHE3;F2K!hUO?5>^rL06R7&0ca8Dz@%Y_%CA0nWh4&On~eSxlCn z(>Y24VmK0!Vl6FFO>HeUD8ho(paT%As?h`0ya&*t4AegF0TMx7eLZ&V zTsWvFNETS^^)Q)9_T(*g*d2V~P97&zekMCJf#6U#j<0J`Cds?!z@D9YgZ3d2+l3iz ztvXYM)~O5tpsFgP*C;dSCJe=zOnGHx#&0DMmU3KR>U@r40MQ^Oco{8jkJQlIECpKP zSb*Bm`nZ6#07imEz~=-kQ-oT?LE?QUL=gV+U4K=Futk(jUVRV5Cq8a>S^>V&jLG51 zD7AXdfKFA(89>(ZOli3?A+a02C;J|@HE7z?0wm%>?Jf%TPtE!-2;!PQ~(Uj4k z`(*|y6{^hAQaxutr_3{epp54bA@C|WY&5`tsutTFSb@}|)e41PNToUj=z4AqQ|oCl z1+6MTHFv|UF@EUq;XNBRZg^~DeDt4|iOVOxWwKbg2$5z1;^LJ|x#Clcg)5ddI}j0T9tC~V)g zV`S^LZCg-{;!(_!{}rWhUlzg9GxZJrj9zcZbatgOI-oujjbw19HDlBR18QBS#Nf^# zH)lq#hK|tGW{|q#IfK#oYNEAO(zxoRYP(A^w6sg!U|1;Ac?6-SM`&$tL+oQddm6$}@lsO0BPfGhpcyByS`xlqoC%${cbA2nSe1^2N#6*w{#S zU+=N$Wy|huYH9j8ipFIlF)?y(Y<&FrzJYH!0K z0QoO6@Gm?E^uFqcdq*D#=X;>JT?)5%3Ka&gFg!9MbR?4klKTiyR$L)r_MEBn`JULl zXZMqcvB^R;XQN^~_8P$OwNTT3r{D41rcbRb$}6UE~#onJr*$5%8QoXuV@PgZ^w+XV)vl0EV)dMOS7ar+-0Q z>)%6fXE0>=G+b+dHq`4e`ILhJC5E9g<1ti16P9KWijaZf${8Tfn$p+88Bo{Z_!=0{ zz^X@)5bl=6MxTJmOMnUt>n)k)M&CDKVm$>-_XC5;_-Zs3L(7|_3PgPvLaox;O*@8X z)@&R`anE5iY8W{ehk^ECluy_T4E%Jl`~M404F4Dg z>o3yj^eY1st6v$Ko_S^U*4?i_LG8qBxD&p{oiIdpA`$UUi0k^EzM-e}Cd&tC`A3)) zKSGMqk3@9EM;+}QAE8Ab_4M@Spd4N|n=P+k_B)F){!Rn!c8;Wbv`(EVW`Ciw;gQM?zqc!HGZgZP@xtrLQro2{mV{!!6lbpFdme z4rLvwk-5511Jk)&ta)Voy}se03r45=asm%7x76iqkh z*XO)l)9J?k(X=3-%4Op0!(85=;cT z2AMb2&n&UFPbPQnyOdLWo}BnRg_0WY%!8(6TV?Y+K<@e3$( zb~%`6T}T+85!oOfVtu62BEIs^vVm#t2xCRZF9-n#qi`bhH!#ukBDqY1Wb!x}ay z&a7cUREeJ0yo0q(qvUPR5Obiqq%IU^{TsHu-!wA)MlHHu*__JOdh4^QI*33RpL2Rp zL%T7=8k$<(>s-Eqiy)rr0s~FCzGWM8iRHU;Ez@h${?6WX$LLgg)%E+oG`4NWKL&gI z=DVhrF+&6LF-}Fe8qm+nZb8Yg@bif-V%f+|oags}3h~JtLcPo~i3|gIo5bTZYEc zEdyie8^7|kFVF1S{Xg19Mp(=61d9kLdpSNOvNfC5vE4V`%%*qlVJo(7XCoL1K4E}) zl06X3$mQkxZuqq^*3KEw1sgdAyptQ}>Y5_V00sgh6Yq6z-*v&z-o+WH3bf|p0AT&d z&fMUJZD|0LGjQmRznblsn*N=)BgIBnq1VyVonztz(iE*>yAK~>n~&ba`c|!HQ`>ei zXL~mb^o=lgd-o?JTlZY7?-|Lent_4F7#{_mm3!uVLMJn#pj2RJ?7e~A`z{)VzRT^S z-Z> z7S#+A!zt?;UNz?m_?Xe_h9c>IuYcQ)w+->u%MBO>3Qr`LSg}24?^~B^8k&X@>P)ZR zm%cO7J@9Y7&TjtO^<5~@LgU|;>}H9Hl`J(j%KSnfbF?IxE*xjBjvi);v@#F$L!f8) z;}v^v_%$)0jJ0JIo?zD5H8ST4)-wb0q6FeC@AXbEd)wghTn@B$yIMQvmEJIOvY)u`^h4<7eoipqHzu21z9-aO}|F-LYp==eh3V&19(YIpG?su|Uw}ZLD(f3jv z9T$wg`pdqK&YU{jl(VD;bD zs^G{16Z6>^me>qtGs6_ji+y`wEO_fNRr~#aT(fT7uQd*5R$Z&ldLkWj9#b_l>8hB! zq2ax*>6r`0KN+&7Vlx4qx);6O7Xi`2z3EWI{daBwIRetB;ah| z1!7>M@st#apo`hf`HEB6*y9Do>_{&bM=}n$Qa+iOn!f0Y#(V0T=` zu3Zj3>zvVI=L~G!wDB%vYkvd2gn5|r%#7OG^&Srs;Vj^-Z*OfUd7yNf2PKQWEM%`` z9!#1)(1;xh2$ zi&$(jETsTISguG@0-q0xjfFoMS+V>AydkgqgAE_K4OOrsovdqO^4<3Kt_ymj^KvZF zn(OKx%)zgai#Eq|ql5iF$7*WcW2k1-W5hs%h*tT1K3$ zbS(git+fIJSa5K0^b8N>dU|{RAFOJ?fPzJ0L6+?8d$*&#>uqA7C7H^#VLlN0x^qbE zksC@z-itYv$S9L9&v{x4btH(y~+{ z!o?j4WBkXFDQF|Ajlvs&LUFxZ6sSbYW>&0ViAV#B!qTCk2>%^x2nJ9*q?O~O9>4{< zKY{E1t-$d3oXf0cfk+UQ$vfX28l1S`at1DU4-Dm+TNAmp>sIADg|6I|Wj#L|2pi^C zjC7&V2{tN@46~`}Nw#j?8a9T!XH=e=PIY4ug7Ved8IBXP1kT1|k;>puhG^=ch?;p; zaq0~$t5Ml7^;=@VjS}e%u#6L}-NeA#2EF%k|Hv3b(3)Ged^*?N*OS|~b=|kab>JM#J>nW*M)W+6v}eE;s(x&7#l~RQJ)3 zUI7!I3=R#w9T=IKvl-RQ3v3Vr!^2Y-YIXL@<1?#rk)~L#e`qL|YH!JHU%&G9(Z1BL zrl+P*3rg(916HuH(NTzCEw4O^q}_}N2P_#@t!(f9J*XV)WSyNU&Hypi)7Q%@$`b=n zvwxgk4iL6=%we~L_dsiF-@Bcu(F^by%ulXamy5Tx=de$d>+ERF4Rp01?P!kvb0pmO zkx#_XB6S-LM;Kxgc>X&$Ab4e1Jt_p(`|2Tgj0l?rvtK>K(ws$6@5F*h1j}pQ18}YV z0eaxghF}N`pvpYykd6Ti!_l`*W(Q}W1)2~?*K+NNcrG5QJ2WuR|7{#`dQT)^VWuLL z$_9iE*3#&Of&c?ZS58I0N%dlR&4LZIT=w$00D(=+Y_(vdbkdXzjP%0?(DXV+$(&VN z&D@w;qlx6Z?H$4em%DC$YTf!=b9-yfQ|HSyhWt6Fxi-Cg`LYvOo{PVs84Xh>2UDcp z&3tw$N3Lg7l9-5!%c2MeujA){R>Ty{-($l8x+6dge6nnM*>7X9c!2>In2UAx5Cd=H zh|2uLiWLw+B4>BFa?waIXVt0FDC}}eyjhID4DB{g8jgliqYD|M%o^qZQ*bgdtmhfr zZG0Mr`wAM%!~sg)3kT)`zYi7b8XG?z9U1)f#JQY&nbBnzI{JIg?(K zhEF&xPESpr#1HuSfsPW?D#G=y)VKSG>_-NGvduzE#{o1wkl^f)TXhCA*NxQ z-H!9@zYYLM0n|tK*^u=aS%9eeG~Dc*0c>qY%eXrb!`LHMU|sPRLO zS@WUSQv0DkrWbAA*4o0n`s+2Yd)$;fHXieuyInAA*4o;XVI7LU&%r zA(o$FNB*bif&U2x-f@_W??F5MD%F|#70kQ;1tu@TsJ&=087}J7l^2&!jt@^l{|;kg zdGOA=?>vso?r*GLKJ?2C%LdP*YVmnwkUtM4bRM3u^FS+qjp~%=QRVhL0!q)X-?;uf zDj1$e%;4*&+xb0&2R}15KK9H#_k8X9C%!8F;KBRvB|qUm?%%)vzukZ0{x|Rb%H6NP z41ZvQVik_~0C@0+zc>{+xti>SLS zxTh}8qKqnBasDh?mqqVo*Kb(=Bb2&+irlw0hdnbfIr+_=Wb;!k@#r^}uUPTa_~gXj zt>3uu6{J0upu(jFuUm52OmvD&6o>(gVF7x5xVN+YyG`Nxtj7V{zRsJ)nfI*S<;+5( z(d+*X)V~IUw$k^5riBA1^OkvFv4dHDBJh zf8Ps;{QaBp@zI9?vWI#H`yRsH&clPf9S@HT^*uZ^JoGRkg&%p~!3Ul|2Jt6g$UHGR z*!9Hl=+F})wnd^Cn^A;SL|06WMfdI8G;TMjpHivRJd+GIlKB;u?~4dTcyVxG@I}}K zFM{D0*RNauA~r8xy!n=!{}Cq;9>P?95|}uN(K3q|f!Wak;pF7l@JT%5B!GJI_B-!< zXzkjy4~>tGJTx)f{}5(Z@gb<#2tr9C_(DXhs*1EXhdTmZ$Gs^2%pY8`6i2Pf%J^#p z5lGm>X0bexv6<-eE0_Vd;bZ+0@C6oizPUpIRn%K zP*yJ@Oyfm#jo}PHz0R6-D(ZoU&;t)4hUDujH*R_e z;(KTqJpiltp<(p@Ln9O8@f&Zsx$CPZ?(6>A-M4n0dgQ(?lvCV&@4ff^=$?D-Ifn{R z=T4kBaSnla=MXA)PP|=w4fkF{A>r3>|F!Ra@4G+!(T{)htp`p%@Z^Dm2Ofi_dko@v z488K$NPpL<@zKF2fUyjM`!XB0ZOs5%PYjO?Jux~y_JlYzI`Tv?6zFJcZC)kBgPRip z*Vcs3wiQXdZ$WatH-mQ5C7ZhXlE7ZVbcB+->mZ1O8>e0bdXyFI=ab`mvyeOtrm|a(k zjIi~rG3ftfys!7So$W1e)M0Ngh>gXr_O=28`WjV%0sMv(@S@%`T5dBVg2F4-Nv+AG zueWWOYbQIfONURjc6) zbhNd6eEp8?ze%+vvdz(GwyQOf?MWpiCmsM?0fc!5OgIb}!puhuI3OMe0vPNfBDMY4 zw?%hLbqFAcv?O*pEatRTuTMAB*QcA}(R6ROklwp{*IkL`_`kI@$5=S%XQOadIg#2j z2+O%!NPUprxA%OcF_`UWYs+?HdX9yHQUlF$039(jm(A(YhyJh3!zX-r42sYGbhkLuTah&k4#{-;*6R{xcj8TO%R5+jH_W*$PIJ$#l zJYKg;l-&3bB3GnZoZdhxTEQ2Ia|V!hF5TewrCm-(8r!nzwnX!x>51`Y8~pY2K{zQq z@cR-d{dJyCHmqCoTT~f%1I~(U0QT3N)72WyLVdh-kKLe6V_BW{x*X}&_SSTwr6mo8kv^P0_+W2e_wQoiMm91w z!s3ls?>9w1-oACyZ^nm)vRENyLwNYq$WXS0LNd_(Mkpbx9-|Blc#sLEu84s;(TM{W zV8CjzNH&ZDt;r$;np^icjM_BL38&SH$~26Pv{qAt*NQZvOOC^D^KaDc2Ca_OK>;@iDzg>kWm%I!mvvjr*+>J9x7kt53k;YrfsqJ&H~`t$fb%L=8^lrz`GWzN z#1j0m7^@n|q|*wKpns1;R|6dY9Mr1QZmT5?ot@THmZh5;gGW|OkN*T$=D}*H5xStW zDf+vJQMOl?KS65{{*f$PA8#Xth^Z`=VJIsg`0^rOT3B-V}&WkgA=y{W9mYnDk z8@RLr9NH@6Lc>uSXsSE|`dZF_&tl>X*wxiwqB=b_I&h-iZv9;|Ij0=fkJn9%{U#L& zy#XdU11@Yf239f!FrzyLAeM$}B5)goC%00XO9$Oi{*01kb1r4> z3!QyEdlGHU>87SwI@Q*ac0(Id56BGkBooKOUeB+3uov9o_s*g0$$6wT&B_coYHIQf zEQr9O$9#Y!JSOx&&_{)WJQCEmBywaTKScl^j5aq(v8E^uM*+iaH_)9-<7bqDG9-Z#*{=a*ho925HP4AC&C4a#g;7lm8$d#Q9+AXh_{uWOs%X58kiRd2J`C<@f* zwr=0Da_U5T(EmTzj1T`R6%M`(27baxsrZRqRsEBo&HNKgxo6x~(;3Y9XApmP1`M2m z$MuZGYCmJtinV7fIt^JXXP^#o1D1)yex|3tziHpWgYCz^d}r$32kuWD7jI9&{JMg^ zeCL-_|8nkMRv;nQcW{07{`>EL0$IZf1k>$_`%c{V1frrJ!?NwMq2b}jMn=aTgRkka z&0DuWHa;==*tocABW{j7hBe+}1A_yP_4WymjZKa}R$5jTLDWlRami9#t0UJfx-PP4 z(V{D;th_7&Z&@<}QEsK*KhW35t!2vnBG@BoESnxWCXE8O;}W}MGW~B569nU zOP7{%lbpD_&OpyHPZ*bMsZ``<1fz|Ph%m8`|s~ZJ=uVfaBQjP(c0qOxyu#t;E z#L|j0fYbxCXwhsrT3&)LlL+X?(JK+)f?olo!o!In>Jh9DBk-O%x`eK!*z;)zNbjYG z)9<1OXGsj$C*nOoR~3n%MmJmQ4$fAa-Qp~Ln2?GC2zY%R9$GcKv~(%|LRndP1PJB~ z(E5;YP#6V}KQRaf!f;ya9S+B0_t#Y@W|v&CR)2@Ma<0CEX% z`O_+yx?S!8S^gHQ#ScADN(|WT_7ZqYrm3Y|v>5YnT5ueY9v}v)hynDFMx&b*EC2uI z&OAEq>bm2WEm`}_XqnNBX5aUHMl)K++GW|+Vi|0}*lZyr;L4B^LQlewg~Tz$zbN34 zlv5@-hSNVdb=w>gH;IWtXmNl90c}W5mgXd-(9l?egA^Az_4IRpvWS!Poc>#%^J9=S z@4fr(z3;yJ?)~2PYtkug?Ja124PvNMHfyaa0X2M~Ms!1D+=K|WY*FpN#^CSDzo{uk z{FwBheX|gt)oQB?{1Izg8Ka^3+Oh3%uRih*Xh)xMX zE!Y8-fF>=gtcaGfCfoI`%9cjGvbDZRC4glI+iF!diIqcsaR$I3{i*yB%e(U5AOLPu z6FaH`L`Vir(I7R(~!u24aN78j8Gy5c&Kg z`5Phb^0C$bhbtO_%pVY45&{4ssuR+h?TR6uR~ikIu=)}K-k`VS^aV@REJa~ibGsO% zs&&zz{X&3nLUzN3`iA(%`bYjDS^t!B-v$?Ih?HF=OOCjaYS^SNjnS+aQ$0$3heI8& zu~}F0hP)+*H&ALoH=0_S6{FXxu)0)zL1)x)m_=NyuIS&p%iV1DGO?|UcdLk*rQe5P zJSv;0w3kh)2d1B{Pv(y~!$=R;ATuQ1lLyYG%X$6SGvukoj$x zo6DqYWnK?geX&um4oGE{6NSDYGp=BwyBj7oEdh26D7-EYiROUV@oe9`6i9S4Jc zA0;A3MG8&z*f$o03|NPChdHW+|08MYnb?BUbQ23%&*HshV<_pOnPD{shBTN|gWhR1 zKN5<^Kc2{DKEO~n0&y;?=1tS6YMbm{sQXXoams9)+C zI|yXYB9EgQCL|jl%#O1!{ckI6!Rb86oEm@^Un8`mr|LE%L&(qgO!q;8A9~bnNme5~ zuHhYXet7obHocYwxmh*pGK9!PHu{aVq>A6UpXSvh2@9CbqcViJXktWUKgZwuASAR& z*O&j}clBh;t}qx|5aYV#q*hF2ne3qKmcmwwA3fK|@*$ZKpx=8%Wn}q?pCCpL>v_ZF zi z&?Sc44~+wKEL=0$Wdu0mXAcjGzoFH@k>+OE=EcnuOO$M9#`WZT#!1f|#RA>6&IyNE zdS(hv*)zx=$MFMx&w*q+?PUc9X!dbZ$=9yW++n17gFhHD$!d~jxE z$o?H6Irl&!nL2{b9T^-R&g|Sd7vntK$d#@&0DWrUsQOTjxOM*Ud@)VF>&W=Tu7`Gw zjT|2z9X@{Wx`U6B2Ri{m>_l^O%YdfUK7hCHw^*!NjJigi8lFfrYO=V!hjA$%)wCEW zSv5V{rfZ_@z>_Hd>8)F9Pg4(D(3)HYlJ`CI(XmmCiNR_CB{ZOIFY1ps=%{(3tf7i3&F&`!9(+ZcKztY=m{x%E!sVvl8IT6%Pi?3MrME>Jw<8S zA}f1QZx0l@scVv&HulSHd#~EJkF4JlJf{HWm4KL(ygm=LGRBgWDM|GZ`{YxeXl$`9 z9OLe=h$MQ|%WSbBRK-l(m(69r2cG5`(1OJ;0kA5$ydDZLO>_Ve6ytfk-lya`KAkVT z*x?GRWo6huDK*?13WrZ)z?N9PFQ7~(q+q8FE@(APC0JUb0J>y%I-asc(u+;@z+$$4 zWRSgY5J=15)b!Ln?0qj2cX^o*#!Cke77v~TTJ+^)I{oE%Eb`^6uh{+Adu}-JIFXyD z`$i_8j`t2d?eqKJi%8zfl6ik9l91H&JLJ#b0Xz53_Q}a#f{S~O(xo%{ww5zNkL5qT zZri^ly1U;1uJ8u6^KZCQ-Sd`EbUr;a@)1j-_c!izrsB)wDut<;O13yM_O?5f0qGxD z(mUNto^WK%849dK`U}gUTz5IZ!v6J0#Fq;m(B9LemOJDyk#=W@&Tcvm^I5-u;1bhFL?$=)~xBwYH(u5GDz}reAi9o-s!pdeYYIC zFFU#Od}eI2G7bX$!2Io%p*>d>)#{Jr_L;Zs1EWjYKy1k~vSZDW&8|jg_LOb8LOC*e zpq$%2J-_>gn;-9;nWKVZhg!0*>zb=8DLNBWH)!t*@yXd&G@;~@qpNq#8IP|<2Zxt! zsqV6O`?clR$j-yvyJnvi5Vogxh?!4UVuK*hbHzUDUk0S~;9}S8-k&s6`C)|vW}knR zioj)0_qMW&(vsZp_+5@j~(ft0KK*1 z55$*qz5V4BIHqlJ+p5c9V^B8)q*Q2P43wCk^kf_;n~EF;s71};8(yz#EuKlQq*MLN zxxT(K@0l-8_Xge`?8{dM2Kp=bx+=JHc6O#%$)!MWLXlt_nXSN5-|}XXYg{w4l1%h0 z_ZA9e5-;VMvHs^MpsbMNu1tcV6vW^tIkDdEE)}c^8brm%@y4uk?rdf)5=*bdV!7r1 zq2coI$WVF5$iU-*tHT0<1npNLt)S6!Y6pU86Og3319V(g_ptTCn!aQFDP5g7W-Le)8M^|F;ba~tOSlRFQ zmBRt=9qhJ07yMnw+FoHls7N(9m~`IpM}7+vE4bI+WwTxXA{_*R;g!tL=yE?Cpg6Z| zBsW40>o#+Jc_-lYu3#a{@|ZhX%b8U2T43oP z8y@I6+mnu+jmHybi}+|~*_Y3Pg+B|b>nxCzAAt;f>dM_SKf30seLp;K;K0vjW@mnu zPDFkN_!=LfZ=x#|dCu#mR?cb`gwTtGAz$Ru&lge57ugq1a&5|^sYK*U>2$I*JGc95 z`5cwPB>e#CcY_-1*)`Vx7%$3t9(;B2IU0W#mYzvx(`Tqx{YPZ|DA3_A_Rm&EJQ+qg?;<8`OLW!2H9 zT_s8L+kn})Iy+o=H6IOsi}c1RgQnr@<~HqDfge0c=Jynn`YPGM-I0#w`MAq=xIYp3 zXLpf|zKxJQ5<_Gy$_*o0d@(wPRb&yn-9JYl|$=*@@zuRYQod?S{KUNrc z!s`GN$Ky10RI>5tN-7e1DH91lYbL*<*EBA=I}Nm`R%3EF|l!q%6su`hvTiHp_gF z+-QGa&+Uc&zF!E4H|TL)YB>p;SADE-Bd6Iwf z6z4~V22Yc2u8<x>PYgs`0Y2*4GRv@#w$Gh^~$HS@YaSkuX13~}sdI?7n zh?9eoJQ8+bgXvd;u9wcta;C+3Rk*00_$P@NZ5zkXYQjQ<6Nsxz8&*%eC>=OC^?)oys00uKD#kfXO28|Ei@X)jH7Dm>37X1-A5Sojj!2}` z6I9zm6|xHhcE$R#)= zljapMo77V{fsjr)?n@`I@z15PoRnMbE~SPJxXw5KqHyhohZ~w3AZ)85>}QO4O%XOiU07zn-h7iBv-}cH zlrW;s;U_$8QMianZVGw0)oM_~3NpAVhRbHZ(H`^5y9HW4DV)^kjfxI2Iy~;rJ3a1C za72Hg0pf(~s{AFvvN8LO4mkgB=EQR|Ur?H~q!8Nm$GZD^4vmbDuLt7zL=I2M1eC0XDHb*UubbM|52N zT?R)2`T&8r2ovRaZZtDF9f;yvAY8qHY~%aO zVP!p=e-GQFmOb4tJTm6P-KoNeRPnp2T~oVy2Ko!185tft*433e)}-qgfO;!htl<=6 zA-?*lmR9|vE~ov8hQ`LzMs9S0$~=(~oyX&z(Q(o>wCUuQkdvJj3onxig$o1^3RBb5 z`CvG3j2kUE0CItnzU`!i3sQpI&VkE>2etjvTo3XDwJaPI4JC`&bkfB6E|Sa?FdTb0 z4nND8?CVaqyM%fDQdc(px879uqAM7ApFf#>+#8Lp6~-pcncSY|tq%K71Bv+S&R{Y0 zD^KspysLNQ`ONrEisQ#Gx(7yIGKLbb`BUk0zTUC&=)P+|n4Q@1=InJhP`f@=2@FsE zq%+;~nrGY4Ip4OKa^Lix&q?)X&#oB`27}Z=@B9x#Ec2QtnLOtz>?}vq>A&}eBb79@ zOAfH_v98>2&0ha&?x6pis~C=!qdv#0VZc%1!vP%vAn*I{SSxE0M~bD+~{nM+f^~lM*CCzLiumUXe<#SUR~HiDu3X3=Wn#l%5Jx zBO$(?_=qH4FM^l&HJm$FBnnZ^<+?tZiul)%(Hb$BH6k~^!O{Ea*y!k4pkr?mhuM}% zMxM7j?cWF8^*u1G-v|bMe>FBf`Z(L}H+JlpObibWJdA!U;#z+jNcsu9S%sGnFAxG+ zNcf#scSrn>xeTr6Jss`m2eYZ~8C$hq_uDPSQx1#yAK22a>&~V>77J3R6b+y6O2l6< z0d^F`9pHI+UD9&hfeTM>Xz!XU+)BTlMedMqK+GFWg+Bom;7CT5NcACtgM()iR82PT6xCAU^K9CG-_Iv>RPea zwPI?c7@j&zwN-3;W2alu7mcPz>YLb+*bInl`XOQy2BDhJ=TS{tJ7N9gU+A=&&&Vc0 z(8sc|RIz3^)7hs9rCU2YO>?pnv5HzZ{*L!5d-=Tl%ob|qyV1)Hg%Ha3r)uR33@CxT zji@AsK~r7CTy3I*z2%>GAms6sNu4WHOdI?Y6H4Vu@=3 zMSkDmcApF;l20c_cRrTiIdhSE^dEbBhu(_y4tzJ#-CJ>`bFaISnYYrh(3=SWaiK_f zCCzy)-<3WWq`a3H%lRZ%ti6>^#-2n~mvg!75Bqw%f8L+V+#Cz|zMo4aPNd?ozr;(t zEt81-m(OAQCnt_w$m6=PkBf19cH7e~hvSkP8To z=H>u4yNbBmQ8fQfWegoj>ySYsIIZ$hV4F>3G+={FqR?rB7fvq minimal details version required to run this plugin local MINIMAL_DETAILS_VERSION_REQUIRED = 136 local COMPARETWO_VERSION = "v1.0.0" --> create a plugin object - local compareTwo = Details:NewPluginObject ("Details_Compare2", _G.DETAILSPLUGIN_ALWAYSENABLED) - --> just localizing here the plugin's main frame - local frame = compareTwo.Frame + local compareTwo = Details:NewPluginObject("Details_Compare2", _G.DETAILSPLUGIN_ALWAYSENABLED) + + ---@type detailsframework + local detailsFramework = DetailsFramework --> set the description compareTwo:SetPluginDescription("Replaces the default comparison window on the player breakdown.") - --> when receiving an event from details, handle it here - local handle_details_event = function (event, ...) + local sortByTotalKey = function(t1, t2) + return t1.total > t2.total + end + --> when receiving an event from details, handle it here + local handle_details_event = function(event, ...) if (event == "COMBAT_PLAYER_ENTER") then elseif (event == "COMBAT_PLAYER_LEAVE") then @@ -47,11 +143,10 @@ do end function compareTwo.InstallAdvancedCompareWindow() - --colors to use on percent number local red = "FFFFAAAA" local green = "FFAAFFAA" - local plus = red .. "-" + local plus = red .. "-" local minor = green .. "+" local comparisonFrameSettings = { @@ -93,377 +188,378 @@ do local resetTargetComparisonTooltip = function() comparisonTargetTooltips.nextTooltip = 0 - for _, tooltip in ipairs (comparisonTargetTooltips) do + for _, tooltip in ipairs(comparisonTargetTooltips) do for i = 1, #tooltip.lines do local line = tooltip.lines [i] - line.spellIcon:SetTexture ("") - line.spellName:SetText ("") - line.spellAmount:SetText ("") - line.spellPercent:SetText ("") + line.spellIcon:SetTexture("") + line.spellName:SetText("") + line.spellAmount:SetText("") + line.spellPercent:SetText("") line:Hide() end - + tooltip:Hide() tooltip:ClearAllPoints() end end - + local resetComparisonTooltip = function() comparisonTooltips.nextTooltip = 0 - for _, tooltip in ipairs (comparisonTooltips) do + for _, tooltip in ipairs(comparisonTooltips) do tooltip:Hide() tooltip:ClearAllPoints() end end - + local getTargetComparisonTooltip = function() comparisonTargetTooltips.nextTooltip = comparisonTargetTooltips.nextTooltip + 1 local tooltip = comparisonTargetTooltips [comparisonTargetTooltips.nextTooltip] - + if (tooltip) then return tooltip end - - tooltip = CreateFrame ("frame", nil, UIParent, "BackdropTemplate") - tooltip:SetFrameStrata ("tooltip") - tooltip:SetSize (1, 1) - _detalhes.gump:CreateBorder (tooltip) - tooltip:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true}) - tooltip:SetBackdropColor (.2, .2, .2, .99) - tooltip:SetBackdropBorderColor (unpack (comparisonFrameSettings.tooltipBorderColor)) - tooltip:SetHeight (77) - + + tooltip = CreateFrame("frame", nil, UIParent, "BackdropTemplate") + tooltip:SetFrameStrata("tooltip") + tooltip:SetSize(1, 1) + detailsFramework:CreateBorder(tooltip) + tooltip:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true}) + tooltip:SetBackdropColor(.2, .2, .2, .99) + tooltip:SetBackdropBorderColor(unpack(comparisonFrameSettings.tooltipBorderColor)) + tooltip:SetHeight(77) + local bg_color = {0.5, 0.5, 0.5} local bg_texture = [[Interface\AddOns\Details\images\bar_background]] local bg_alpha = 1 local bg_height = 12 local colors = {{26/255, 26/255, 26/255}, {19/255, 19/255, 19/255}, {26/255, 26/255, 26/255}, {34/255, 39/255, 42/255}, {42/255, 51/255, 60/255}} - + --player name label - tooltip.player_name_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.player_name_label:SetPoint ("bottomleft", tooltip, "topleft", 1, 2) - tooltip.player_name_label:SetTextColor (1, .7, .1, .834) - DetailsFramework:SetFontSize (tooltip.player_name_label, 11) - - local name_bg = tooltip:CreateTexture (nil, "artwork") - name_bg:SetTexture (bg_texture) - name_bg:SetPoint ("bottomleft", tooltip, "topleft", 0, 1) - name_bg:SetPoint ("bottomright", tooltip, "topright", 0, 1) - name_bg:SetHeight (bg_height + 2) - name_bg:SetAlpha (bg_alpha) - name_bg:SetVertexColor (unpack (colors[2])) - + tooltip.player_name_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.player_name_label:SetPoint("bottomleft", tooltip, "topleft", 1, 2) + tooltip.player_name_label:SetTextColor(1, .7, .1, .834) + detailsFramework:SetFontSize(tooltip.player_name_label, 11) + + local name_bg = tooltip:CreateTexture(nil, "artwork") + name_bg:SetTexture(bg_texture) + name_bg:SetPoint("bottomleft", tooltip, "topleft", 0, 1) + name_bg:SetPoint("bottomright", tooltip, "topright", 0, 1) + name_bg:SetHeight(bg_height + 2) + name_bg:SetAlpha(bg_alpha) + name_bg:SetVertexColor(unpack(colors[2])) + comparisonTargetTooltips [comparisonTargetTooltips.nextTooltip] = tooltip - + tooltip.lines = {} - + local lineHeight = comparisonFrameSettings.targetTooltipLineHeight local fontSize = 10 - + for i = 1, comparisonFrameSettings.targetMaxLines do - local line = CreateFrame ("frame", nil, tooltip, "BackdropTemplate") - line:SetPoint ("topleft", tooltip, "topleft", 0, -(i-1) * (lineHeight + 1)) - line:SetPoint ("topright", tooltip, "topright", 0, -(i-1) * (lineHeight + 1)) - line:SetHeight (lineHeight) - - line:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) - line:SetBackdropColor (0, 0, 0, 0.2) - - local spellIcon = line:CreateTexture ("$parentIcon", "overlay") - spellIcon:SetSize (lineHeight -2 , lineHeight - 2) - - local spellName = line:CreateFontString ("$parentName", "overlay", "GameFontNormal") - local spellAmount = line:CreateFontString ("$parentAmount", "overlay", "GameFontNormal") - local spellPercent = line:CreateFontString ("$parentPercent", "overlay", "GameFontNormal") - DetailsFramework:SetFontSize (spellName, fontSize) - DetailsFramework:SetFontSize (spellAmount, fontSize) - DetailsFramework:SetFontSize (spellPercent, fontSize) - - spellIcon:SetPoint ("left", line, "left", 2, 0) - spellName:SetPoint ("left", spellIcon, "right", 2, 0) - spellAmount:SetPoint ("right", line, "right", -2, 0) - spellPercent:SetPoint ("right", line, "right", -40, 0) - - spellName:SetJustifyH ("left") - spellAmount:SetJustifyH ("right") - spellPercent:SetJustifyH ("right") - + local line = CreateFrame("frame", nil, tooltip, "BackdropTemplate") + line:SetPoint("topleft", tooltip, "topleft", 0, -(i-1) *(lineHeight + 1)) + line:SetPoint("topright", tooltip, "topright", 0, -(i-1) *(lineHeight + 1)) + line:SetHeight(lineHeight) + + line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + line:SetBackdropColor(0, 0, 0, 0.2) + + local spellIcon = line:CreateTexture("$parentIcon", "overlay") + spellIcon:SetSize(lineHeight -2 , lineHeight - 2) + + local spellName = line:CreateFontString("$parentName", "overlay", "GameFontNormal") + local spellAmount = line:CreateFontString("$parentAmount", "overlay", "GameFontNormal") + local spellPercent = line:CreateFontString("$parentPercent", "overlay", "GameFontNormal") + + detailsFramework:SetFontSize(spellName, fontSize) + detailsFramework:SetFontSize(spellAmount, fontSize) + detailsFramework:SetFontSize(spellPercent, fontSize) + + spellIcon:SetPoint("left", line, "left", 2, 0) + spellName:SetPoint("left", spellIcon, "right", 2, 0) + spellAmount:SetPoint("right", line, "right", -2, 0) + spellPercent:SetPoint("right", line, "right", -40, 0) + + spellName:SetJustifyH("left") + spellAmount:SetJustifyH("right") + spellPercent:SetJustifyH("right") + line.spellIcon = spellIcon line.spellName = spellName line.spellAmount = spellAmount line.spellPercent = spellPercent - + tooltip.lines [#tooltip.lines+1] = line - + if (i % 2 == 0) then - line:SetBackdropColor (unpack (comparisonLineContrast [1])) + line:SetBackdropColor(unpack(comparisonLineContrast [1])) line.BackgroundColor = comparisonLineContrast [1] else - line:SetBackdropColor (unpack (comparisonLineContrast [2])) + line:SetBackdropColor(unpack(comparisonLineContrast [2])) line.BackgroundColor = comparisonLineContrast [2] end end - + return tooltip end - + local getComparisonTooltip = function() comparisonTooltips.nextTooltip = comparisonTooltips.nextTooltip + 1 local tooltip = comparisonTooltips [comparisonTooltips.nextTooltip] - + if (tooltip) then return tooltip end - - tooltip = CreateFrame ("frame", nil, UIParent, "BackdropTemplate") - tooltip:SetFrameStrata ("tooltip") - tooltip:SetSize (1, 1) - _detalhes.gump:CreateBorder (tooltip) - tooltip:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true}) - tooltip:SetBackdropColor (0, 0, 0, 1) - tooltip:SetBackdropBorderColor (unpack (comparisonFrameSettings.tooltipBorderColor)) - tooltip:SetHeight (77) - + + tooltip = CreateFrame("frame", nil, UIParent, "BackdropTemplate") + tooltip:SetFrameStrata("tooltip") + tooltip:SetSize(1, 1) + detailsFramework:CreateBorder(tooltip) + tooltip:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true}) + tooltip:SetBackdropColor(0, 0, 0, 1) + tooltip:SetBackdropBorderColor(unpack(comparisonFrameSettings.tooltipBorderColor)) + tooltip:SetHeight(77) + comparisonTooltips [comparisonTooltips.nextTooltip] = tooltip - + --prototype local y = -3 local x_start = 2 - + local bg_color = {0.5, 0.5, 0.5} local bg_texture = [[Interface\AddOns\Details\images\bar_background]] local bg_alpha = 1 local bg_height = 12 local colors = {{26/255, 26/255, 26/255}, {19/255, 19/255, 19/255}, {26/255, 26/255, 26/255}, {34/255, 39/255, 42/255}, {42/255, 51/255, 60/255}} - - local background = tooltip:CreateTexture (nil, "border") - background:SetTexture ([[Interface\SPELLBOOK\Spellbook-Page-1]]) - background:SetTexCoord (.6, 0.1, 0, 0.64453125) - background:SetVertexColor (0, 0, 0, 0.2) - background:SetPoint ("topleft", tooltip, "topleft", 0, 0) - background:SetPoint ("bottomright", tooltip, "bottomright", 0, 0) - + + local background = tooltip:CreateTexture(nil, "border") + background:SetTexture([[Interface\SPELLBOOK\Spellbook-Page-1]]) + background:SetTexCoord(.6, 0.1, 0, 0.64453125) + background:SetVertexColor(0, 0, 0, 0.2) + background:SetPoint("topleft", tooltip, "topleft", 0, 0) + background:SetPoint("bottomright", tooltip, "bottomright", 0, 0) + --player name label - tooltip.player_name_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.player_name_label:SetPoint ("bottomleft", tooltip, "topleft", 1, 2) - tooltip.player_name_label:SetTextColor (1, .7, .1, .834) - DetailsFramework:SetFontSize (tooltip.player_name_label, 11) - - local name_bg = tooltip:CreateTexture (nil, "artwork") - name_bg:SetTexture (bg_texture) - name_bg:SetPoint ("bottomleft", tooltip, "topleft", 0, 1) - name_bg:SetPoint ("bottomright", tooltip, "topright", 0, 1) - name_bg:SetHeight (bg_height + 2) - name_bg:SetAlpha (bg_alpha) - name_bg:SetVertexColor (unpack (colors[2])) - + tooltip.player_name_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.player_name_label:SetPoint("bottomleft", tooltip, "topleft", 1, 2) + tooltip.player_name_label:SetTextColor(1, .7, .1, .834) + detailsFramework:SetFontSize(tooltip.player_name_label, 11) + + local name_bg = tooltip:CreateTexture(nil, "artwork") + name_bg:SetTexture(bg_texture) + name_bg:SetPoint("bottomleft", tooltip, "topleft", 0, 1) + name_bg:SetPoint("bottomright", tooltip, "topright", 0, 1) + name_bg:SetHeight(bg_height + 2) + name_bg:SetAlpha(bg_alpha) + name_bg:SetVertexColor(unpack(colors[2])) + --cast line - tooltip.casts_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.casts_label:SetPoint ("topleft", tooltip, "topleft", x_start, -2 + (y*0)) - tooltip.casts_label:SetText ("Casts:") - tooltip.casts_label:SetJustifyH ("left") - tooltip.casts_label2 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.casts_label2:SetPoint ("topright", tooltip, "topright", -x_start, -2 + (y*0)) - tooltip.casts_label2:SetText ("0") - tooltip.casts_label2:SetJustifyH ("right") - tooltip.casts_label3 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.casts_label3:SetPoint ("topright", tooltip, "topright", -x_start - 46, -2 + (y*0)) - tooltip.casts_label3:SetText ("0") - tooltip.casts_label3:SetJustifyH ("right") - + tooltip.casts_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.casts_label:SetPoint("topleft", tooltip, "topleft", x_start, -2 +(y*0)) + tooltip.casts_label:SetText("Casts:") + tooltip.casts_label:SetJustifyH("left") + tooltip.casts_label2 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.casts_label2:SetPoint("topright", tooltip, "topright", -x_start, -2 +(y*0)) + tooltip.casts_label2:SetText("0") + tooltip.casts_label2:SetJustifyH("right") + tooltip.casts_label3 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.casts_label3:SetPoint("topright", tooltip, "topright", -x_start - 46, -2 +(y*0)) + tooltip.casts_label3:SetText("0") + tooltip.casts_label3:SetJustifyH("right") + --hits - tooltip.hits_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.hits_label:SetPoint ("topleft", tooltip, "topleft", x_start, -14 + (y*1)) - tooltip.hits_label:SetText ("Hits:") - tooltip.hits_label:SetJustifyH ("left") - tooltip.hits_label2 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.hits_label2:SetPoint ("topright", tooltip, "topright", -x_start, -14 + (y*1)) - tooltip.hits_label2:SetText ("0") - tooltip.hits_label2:SetJustifyH ("right") - tooltip.hits_label3 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.hits_label3:SetPoint ("topright", tooltip, "topright", -x_start - 46, -14 + (y*1)) - tooltip.hits_label3:SetText ("0") - tooltip.hits_label3:SetJustifyH ("right") - + tooltip.hits_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.hits_label:SetPoint("topleft", tooltip, "topleft", x_start, -14 +(y*1)) + tooltip.hits_label:SetText("Hits:") + tooltip.hits_label:SetJustifyH("left") + tooltip.hits_label2 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.hits_label2:SetPoint("topright", tooltip, "topright", -x_start, -14 +(y*1)) + tooltip.hits_label2:SetText("0") + tooltip.hits_label2:SetJustifyH("right") + tooltip.hits_label3 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.hits_label3:SetPoint("topright", tooltip, "topright", -x_start - 46, -14 +(y*1)) + tooltip.hits_label3:SetText("0") + tooltip.hits_label3:SetJustifyH("right") + --average - tooltip.average_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.average_label:SetPoint ("topleft", tooltip, "topleft", x_start, -26 + (y*2)) - tooltip.average_label:SetText ("Average:") - tooltip.average_label:SetJustifyH ("left") - tooltip.average_label2 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.average_label2:SetPoint ("topright", tooltip, "topright", -x_start, -26 + (y*2)) - tooltip.average_label2:SetText ("0") - tooltip.average_label2:SetJustifyH ("right") - tooltip.average_label3 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.average_label3:SetPoint ("topright", tooltip, "topright", -x_start - 46, -26 + (y*2)) - tooltip.average_label3:SetText ("0") - tooltip.average_label3:SetJustifyH ("right") - + tooltip.average_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.average_label:SetPoint("topleft", tooltip, "topleft", x_start, -26 +(y*2)) + tooltip.average_label:SetText("Average:") + tooltip.average_label:SetJustifyH("left") + tooltip.average_label2 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.average_label2:SetPoint("topright", tooltip, "topright", -x_start, -26 +(y*2)) + tooltip.average_label2:SetText("0") + tooltip.average_label2:SetJustifyH("right") + tooltip.average_label3 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.average_label3:SetPoint("topright", tooltip, "topright", -x_start - 46, -26 +(y*2)) + tooltip.average_label3:SetText("0") + tooltip.average_label3:SetJustifyH("right") + --critical - tooltip.crit_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.crit_label:SetPoint ("topleft", tooltip, "topleft", x_start, -38 + (y*3)) - tooltip.crit_label:SetText ("Critical:") - tooltip.crit_label:SetJustifyH ("left") - tooltip.crit_label2 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.crit_label2:SetPoint ("topright", tooltip, "topright", -x_start, -38 + (y*3)) - tooltip.crit_label2:SetText ("0") - tooltip.crit_label2:SetJustifyH ("right") - tooltip.crit_label3 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.crit_label3:SetPoint ("topright", tooltip, "topright", -x_start - 46, -38 + (y*3)) - tooltip.crit_label3:SetText ("0") - tooltip.crit_label3:SetJustifyH ("right") - + tooltip.crit_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.crit_label:SetPoint("topleft", tooltip, "topleft", x_start, -38 +(y*3)) + tooltip.crit_label:SetText("Critical:") + tooltip.crit_label:SetJustifyH("left") + tooltip.crit_label2 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.crit_label2:SetPoint("topright", tooltip, "topright", -x_start, -38 +(y*3)) + tooltip.crit_label2:SetText("0") + tooltip.crit_label2:SetJustifyH("right") + tooltip.crit_label3 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.crit_label3:SetPoint("topright", tooltip, "topright", -x_start - 46, -38 +(y*3)) + tooltip.crit_label3:SetText("0") + tooltip.crit_label3:SetJustifyH("right") + --uptime - tooltip.uptime_label = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.uptime_label:SetPoint ("topleft", tooltip, "topleft", x_start, -50 + (y*4)) - tooltip.uptime_label:SetText ("Uptime:") - tooltip.uptime_label:SetJustifyH ("left") - tooltip.uptime_label2 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.uptime_label2:SetPoint ("topright", tooltip, "topright", -x_start, -50 + (y*4)) - tooltip.uptime_label2:SetText ("0") - tooltip.uptime_label2:SetJustifyH ("right") - tooltip.uptime_label3 = tooltip:CreateFontString (nil, "overlay", "GameFontHighlightSmall") - tooltip.uptime_label3:SetPoint ("topright", tooltip, "topright", -x_start - 46, -50 + (y*4)) - tooltip.uptime_label3:SetText ("0") - tooltip.uptime_label3:SetJustifyH ("right") - + tooltip.uptime_label = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.uptime_label:SetPoint("topleft", tooltip, "topleft", x_start, -50 +(y*4)) + tooltip.uptime_label:SetText("Uptime:") + tooltip.uptime_label:SetJustifyH("left") + tooltip.uptime_label2 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.uptime_label2:SetPoint("topright", tooltip, "topright", -x_start, -50 +(y*4)) + tooltip.uptime_label2:SetText("0") + tooltip.uptime_label2:SetJustifyH("right") + tooltip.uptime_label3 = tooltip:CreateFontString(nil, "overlay", "GameFontHighlightSmall") + tooltip.uptime_label3:SetPoint("topright", tooltip, "topright", -x_start - 46, -50 +(y*4)) + tooltip.uptime_label3:SetText("0") + tooltip.uptime_label3:SetJustifyH("right") + for i = 1, 5 do - local bg_line1 = tooltip:CreateTexture (nil, "artwork") - bg_line1:SetTexture (bg_texture) - bg_line1:SetPoint ("topleft", tooltip, "topleft", 0, -2 + (((i-1) * 12) * -1) + (y * (i-1)) + 2) - bg_line1:SetPoint ("topright", tooltip, "topright", -0, -2 + (((i-1) * 12) * -1) + (y * (i-1)) + 2) - bg_line1:SetHeight (bg_height + 4) - bg_line1:SetAlpha (bg_alpha) - bg_line1:SetVertexColor (unpack (colors[i])) + local bg_line1 = tooltip:CreateTexture(nil, "artwork") + bg_line1:SetTexture(bg_texture) + bg_line1:SetPoint("topleft", tooltip, "topleft", 0, -2 +(((i-1) * 12) * -1) +(y *(i-1)) + 2) + bg_line1:SetPoint("topright", tooltip, "topright", -0, -2 +(((i-1) * 12) * -1) +(y *(i-1)) + 2) + bg_line1:SetHeight(bg_height + 4) + bg_line1:SetAlpha(bg_alpha) + bg_line1:SetVertexColor(unpack(colors[i])) end - + return tooltip end - + --fill the tooltip for the main player being compared --actualPlayerName is the name of the player being compared, playerName can be the name of a pet - local fillMainSpellTooltip = function (line, rawSpellTable, actualPlayerName, playerName) + local fillMainSpellTooltip = function(line, rawSpellTable, actualPlayerName, playerName) local tooltip = getComparisonTooltip() local formatFunc = Details:GetCurrentToKFunction() local spellId = rawSpellTable.id - - tooltip.player_name_label:SetText (Details:GetOnlyName (actualPlayerName)) - + + tooltip.player_name_label:SetText(Details:GetOnlyName(actualPlayerName)) + local fullPercent = "100%" local noData = "-" - + --amount of casts local combatObject = Details:GetCombatFromBreakdownWindow() local castAmount = combatObject:GetSpellCastAmount(playerName, GetSpellInfo(spellId)) local playerMiscObject = combatObject:GetActor(DETAILS_ATTRIBUTE_MISC, playerName) - + if (castAmount > 0) then - tooltip.casts_label2:SetText (fullPercent) - tooltip.casts_label3:SetText (castAmount) - DetailsFramework:SetFontColor (tooltip.casts_label2, "gray") - DetailsFramework:SetFontColor (tooltip.casts_label3, "white") + tooltip.casts_label2:SetText(fullPercent) + tooltip.casts_label3:SetText(castAmount) + detailsFramework:SetFontColor(tooltip.casts_label2, "gray") + detailsFramework:SetFontColor(tooltip.casts_label3, "white") else - tooltip.casts_label2:SetText (noData) - tooltip.casts_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.casts_label2, "silver") - DetailsFramework:SetFontColor (tooltip.casts_label3, "silver") + tooltip.casts_label2:SetText(noData) + tooltip.casts_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.casts_label2, "silver") + detailsFramework:SetFontColor(tooltip.casts_label3, "silver") end - + --hit amount - tooltip.hits_label2:SetText (fullPercent) - DetailsFramework:SetFontColor (tooltip.hits_label2, "gray") - tooltip.hits_label3:SetText (rawSpellTable.counter) - DetailsFramework:SetFontColor (tooltip.hits_label3, "white") - + tooltip.hits_label2:SetText(fullPercent) + detailsFramework:SetFontColor(tooltip.hits_label2, "gray") + tooltip.hits_label3:SetText(rawSpellTable.counter) + detailsFramework:SetFontColor(tooltip.hits_label3, "white") + --average - tooltip.average_label2:SetText (fullPercent) - DetailsFramework:SetFontColor (tooltip.average_label2, "gray") + tooltip.average_label2:SetText(fullPercent) + detailsFramework:SetFontColor(tooltip.average_label2, "gray") local average = rawSpellTable.total / rawSpellTable.counter - tooltip.average_label3:SetText (formatFunc (_, average)) - + tooltip.average_label3:SetText(formatFunc(_, average)) + --critical strikes - tooltip.crit_label2:SetText (fullPercent) - DetailsFramework:SetFontColor (tooltip.crit_label2, "gray") - tooltip.crit_label3:SetText (rawSpellTable.c_amt) - + tooltip.crit_label2:SetText(fullPercent) + detailsFramework:SetFontColor(tooltip.crit_label2, "gray") + tooltip.crit_label3:SetText(rawSpellTable.c_amt) + --uptime local uptime = 0 if (playerMiscObject) then local spell = playerMiscObject.debuff_uptime_spells and playerMiscObject.debuff_uptime_spells._ActorTable and playerMiscObject.debuff_uptime_spells._ActorTable [spellId] if (spell) then - local minutos, segundos = floor (spell.uptime / 60), floor (spell.uptime % 60) + local minutos, segundos = floor(spell.uptime / 60), floor(spell.uptime % 60) uptime = spell.uptime - tooltip.uptime_label2:SetText (fullPercent) - tooltip.uptime_label3:SetText (minutos .. "m " .. segundos .. "s") - - DetailsFramework:SetFontColor (tooltip.uptime_label2, "gray") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "white") + tooltip.uptime_label2:SetText(fullPercent) + tooltip.uptime_label3:SetText(minutos .. "m " .. segundos .. "s") + + detailsFramework:SetFontColor(tooltip.uptime_label2, "gray") + detailsFramework:SetFontColor(tooltip.uptime_label3, "white") else - tooltip.uptime_label2:SetText (noData) - tooltip.uptime_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.uptime_label2, "gray") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "gray") + tooltip.uptime_label2:SetText(noData) + tooltip.uptime_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.uptime_label2, "gray") + detailsFramework:SetFontColor(tooltip.uptime_label3, "gray") end else - tooltip.uptime_label2:SetText (noData) - tooltip.uptime_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.uptime_label2, "gray") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "gray") + tooltip.uptime_label2:SetText(noData) + tooltip.uptime_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.uptime_label2, "gray") + detailsFramework:SetFontColor(tooltip.uptime_label3, "gray") end - + --show tooltip - tooltip:SetPoint ("bottom", line, "top", 0, 2) - tooltip:SetWidth (line:GetWidth()) + tooltip:SetPoint("bottom", line, "top", 0, 2) + tooltip:SetWidth(line:GetWidth()) tooltip:Show() - + --highlight line - line:SetBackdropColor (unpack (comparisonFrameSettings.lineOnEnterColor)) + line:SetBackdropColor(unpack(comparisonFrameSettings.lineOnEnterColor)) latestLinesHighlighted [#latestLinesHighlighted + 1] = line - + return true, castAmount, rawSpellTable.counter, average, rawSpellTable.c_amt, uptime end - - local getPercentComparison = function (value1, value2) + + local getPercentComparison = function(value1, value2) if (value1 == 0 and value2 == 0) then return "|c" .. minor .. "0%|r" - + elseif (value1 >= value2) then local diff = value1 - value2 local up - if (diff == 0 or value2 == 0) then --stop div by zero ptr + if (diff == 0 or value2 == 0) then up = "0" else up = diff / value2 * 100 - up = floor (up) - + up = floor(up) + if (up > 999) then up = "" .. 999 end end - + return "|c" .. minor .. up .. "%|r" else local diff = value2 - value1 local down - if (diff == 0 or value1 == 0) then --stop div by zero ptr + if (diff == 0 or value1 == 0) then down = "0" else down = diff / value1 * 100 - down = floor (down) + down = floor(down) if (down > 999) then down = "" .. 999 end end - + return "|c" .. plus .. down .. "%|r" - end + end end - + --fill the tooltip for comparison lines --actualPlayerName is the name of the player being compared, playerName can be the name of a pet - local fillComparisonSpellTooltip = function (line, rawSpellTable, actualPlayerName, playerName, mainCastAmount, mainHitCounter, mainAverageDamage, mainCritAmount, mainAuraUptime) + local fillComparisonSpellTooltip = function(line, rawSpellTable, actualPlayerName, playerName, mainCastAmount, mainHitCounter, mainAverageDamage, mainCritAmount, mainAuraUptime) local tooltip = getComparisonTooltip() local formatFunc = Details:GetCurrentToKFunction() local spellId = rawSpellTable.id @@ -471,150 +567,160 @@ do tooltip.player_name_label:SetText(Details:GetOnlyName(actualPlayerName)) - --amount of casts + --amount of casts local combatObject = Details:GetCombatFromBreakdownWindow() - local playerMiscObject = combatObject:GetActor (DETAILS_ATTRIBUTE_MISC, playerName) + local playerMiscObject = combatObject:GetActor(DETAILS_ATTRIBUTE_MISC, playerName) local castAmount = combatObject:GetSpellCastAmount(playerName, GetSpellInfo(spellId)) if (castAmount > 0) then - tooltip.casts_label2:SetText (getPercentComparison (mainCastAmount, castAmount)) - tooltip.casts_label3:SetText (castAmount) - DetailsFramework:SetFontColor (tooltip.casts_label2, "white") - DetailsFramework:SetFontColor (tooltip.casts_label3, "white") + tooltip.casts_label2:SetText(getPercentComparison(mainCastAmount, castAmount)) + tooltip.casts_label3:SetText(castAmount) + detailsFramework:SetFontColor(tooltip.casts_label2, "white") + detailsFramework:SetFontColor(tooltip.casts_label3, "white") else - tooltip.casts_label2:SetText (noData) - tooltip.casts_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.casts_label2, "silver") - DetailsFramework:SetFontColor (tooltip.casts_label3, "silver") + tooltip.casts_label2:SetText(noData) + tooltip.casts_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.casts_label2, "silver") + detailsFramework:SetFontColor(tooltip.casts_label3, "silver") end - + --hits - tooltip.hits_label2:SetText (getPercentComparison (mainHitCounter, rawSpellTable.counter)) - tooltip.hits_label3:SetText (rawSpellTable.counter) - DetailsFramework:SetFontColor (tooltip.hits_label2, "white") - DetailsFramework:SetFontColor (tooltip.hits_label3, "white") - + tooltip.hits_label2:SetText(getPercentComparison(mainHitCounter, rawSpellTable.counter)) + tooltip.hits_label3:SetText(rawSpellTable.counter) + detailsFramework:SetFontColor(tooltip.hits_label2, "white") + detailsFramework:SetFontColor(tooltip.hits_label3, "white") + --average local average = rawSpellTable.total / rawSpellTable.counter - tooltip.average_label2:SetText (getPercentComparison (mainAverageDamage, average)) - tooltip.average_label3:SetText (formatFunc (_, average)) - DetailsFramework:SetFontColor (tooltip.average_label3, "white") - DetailsFramework:SetFontColor (tooltip.average_label2, "white") - + tooltip.average_label2:SetText(getPercentComparison(mainAverageDamage, average)) + tooltip.average_label3:SetText(formatFunc(_, average)) + detailsFramework:SetFontColor(tooltip.average_label3, "white") + detailsFramework:SetFontColor(tooltip.average_label2, "white") + --critical strikes - tooltip.crit_label2:SetText (getPercentComparison (mainCritAmount, rawSpellTable.c_amt)) - tooltip.crit_label3:SetText (rawSpellTable.c_amt) - DetailsFramework:SetFontColor (tooltip.crit_label2, "white") - DetailsFramework:SetFontColor (tooltip.crit_label2, "white") - + tooltip.crit_label2:SetText(getPercentComparison(mainCritAmount, rawSpellTable.c_amt)) + tooltip.crit_label3:SetText(rawSpellTable.c_amt) + detailsFramework:SetFontColor(tooltip.crit_label2, "white") + detailsFramework:SetFontColor(tooltip.crit_label2, "white") + --uptime local uptime = 0 if (playerMiscObject) then local spell = playerMiscObject.debuff_uptime_spells and playerMiscObject.debuff_uptime_spells._ActorTable and playerMiscObject.debuff_uptime_spells._ActorTable [spellId] if (spell) then - local minutos, segundos = floor (spell.uptime / 60), floor (spell.uptime % 60) + local minutos, segundos = floor(spell.uptime / 60), floor(spell.uptime % 60) uptime = spell.uptime - tooltip.uptime_label2:SetText (getPercentComparison (mainAuraUptime, uptime)) - tooltip.uptime_label3:SetText (minutos .. "m " .. segundos .. "s") - - DetailsFramework:SetFontColor (tooltip.uptime_label2, "white") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "white") + tooltip.uptime_label2:SetText(getPercentComparison(mainAuraUptime, uptime)) + tooltip.uptime_label3:SetText(minutos .. "m " .. segundos .. "s") + + detailsFramework:SetFontColor(tooltip.uptime_label2, "white") + detailsFramework:SetFontColor(tooltip.uptime_label3, "white") else - tooltip.uptime_label2:SetText (noData) - tooltip.uptime_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.uptime_label2, "gray") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "gray") + tooltip.uptime_label2:SetText(noData) + tooltip.uptime_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.uptime_label2, "gray") + detailsFramework:SetFontColor(tooltip.uptime_label3, "gray") end else - tooltip.uptime_label2:SetText (noData) - tooltip.uptime_label3:SetText (noData) - DetailsFramework:SetFontColor (tooltip.uptime_label2, "gray") - DetailsFramework:SetFontColor (tooltip.uptime_label3, "gray") + tooltip.uptime_label2:SetText(noData) + tooltip.uptime_label3:SetText(noData) + detailsFramework:SetFontColor(tooltip.uptime_label2, "gray") + detailsFramework:SetFontColor(tooltip.uptime_label3, "gray") end - + --show tooltip - tooltip:SetPoint ("bottom", line, "top", 0, 2) - tooltip:SetWidth (line:GetWidth()) + tooltip:SetPoint("bottom", line, "top", 0, 2) + tooltip:SetWidth(line:GetWidth()) tooltip:Show() - + --highlight line - line:SetBackdropColor (unpack (comparisonFrameSettings.lineOnEnterColor)) + line:SetBackdropColor(unpack(comparisonFrameSettings.lineOnEnterColor)) latestLinesHighlighted [#latestLinesHighlighted + 1] = line end - - local comparisonLineOnEnter = function (self) - local scrollFrame = self:GetParent() - local frame = scrollFrame:GetParent() - - if (not frame.GetPlayerInfo) then - frame = frame:GetParent() + + ---@param compareScrollLine comparescrollline + local comparisonLineOnEnter = function(compareScrollLine) + ---@type comparescrollbox + local scrollFrame = compareScrollLine:GetParent() + local comparePlugin + + if (scrollFrame.bIsMain) then + --comparescrollbox > compare + comparePlugin = scrollFrame:GetParent() + else + --comparescrollbox > compareplayerframe > compare + comparePlugin = scrollFrame:GetParent():GetParent() end - - --check if this is a spell or a target line - if (self.lineType == "mainPlayerSpell" or self.lineType == "comparisonPlayerSpell") then - + + ---@cast comparePlugin compare + + --check if this is a mainline (from the main player) or a compareplayer line (from another player) + if (compareScrollLine.lineType == "MainPlayerSpell" or compareScrollLine.lineType == "OtherPlayerSpell") then --get data - local spellTable = self.spellTable + ---@type comparespelltable + local spellTable = compareScrollLine.spellTable local isPet = spellTable.npcId local npcId = spellTable.npcId local spellId = spellTable.spellId - - local mainPlayerObject = frame.GetMainPlayerObject() - local mainSpellTable = frame.GetMainSpellTable() - local allComparisonFrames = frame.GetAllComparisonFrames() - - local mainFrameScroll = frame.mainFrameScroll - local playerObject, playerName = frame.GetPlayerInfo (scrollFrame) - + + local mainPlayerObject = comparePlugin.GetMainPlayerObject() + local mainSpellFrameScroll = comparePlugin.mainSpellFrameScroll + --store the spell information from the main tooltip local mainHasTooltip, castAmount, hitCounter, averageDamage, critAmount, auraUptime - - --iterate on the main player scroll and find the line - local mainFrameLines = mainFrameScroll:GetFrames() - for i = 1, #mainFrameLines do - local line = mainFrameLines [i] + + --iterate on the main player scroll and find the line corresponding to the same spell hovered over + --doesn't matter if the hovered over line is already the main line, the search will be performed + local mainFrameLines = mainSpellFrameScroll:GetLines() + for i = 1, #mainFrameLines do + ---@type comparescrollline + local line = mainFrameLines[i] if (line.spellTable and line:IsShown()) then if (isPet) then if (line.spellTable.spellId == spellId and line.spellTable.npcId == npcId) then --main line for the hover over spell local rawSpellTable = line.spellTable.rawSpellTable - mainHasTooltip, castAmount, hitCounter, averageDamage, critAmount, auraUptime = fillMainSpellTooltip (line, rawSpellTable, mainPlayerObject:Name(), line.spellTable.originalName) + mainHasTooltip, castAmount, hitCounter, averageDamage, critAmount, auraUptime = fillMainSpellTooltip(line, rawSpellTable, mainPlayerObject:Name(), line.spellTable.originalName) break end else if (line.spellTable.spellId == spellId and not line.spellTable.npcId) then --main line for the hover over spell local rawSpellTable = line.spellTable.rawSpellTable - mainHasTooltip, castAmount, hitCounter, averageDamage, critAmount, auraUptime = fillMainSpellTooltip (line, rawSpellTable, mainPlayerObject:Name(), mainPlayerObject:Name()) + mainHasTooltip, castAmount, hitCounter, averageDamage, critAmount, auraUptime = fillMainSpellTooltip(line, rawSpellTable, mainPlayerObject:Name(), mainPlayerObject:Name()) break end end end end - + if (mainHasTooltip) then + local allComparisonFrames = comparePlugin.GetAllComparisonFrames() + --iterate among all other comparison scrolls - for i = 1, #allComparisonFrames do - local comparisonFrame = allComparisonFrames [i] + for compareFrameIdx = 1, #allComparisonFrames do + ---@type compareplayerframe + local comparisonFrame = allComparisonFrames[compareFrameIdx] if (comparisonFrame:IsShown()) then - local scrollFrame = comparisonFrame.spellsScroll - local playerObject, playerName = frame.GetPlayerInfo (comparisonFrame) - - local frameLines = scrollFrame:GetFrames() - for i = 1, #frameLines do - local line = frameLines [i] + local spellScrollBox = comparisonFrame.spellsScroll + local playerObject = comparisonFrame.playerObject + local playerName = playerObject:Name() + + local frameLines = spellScrollBox:GetFrames() + for lineIdx = 1, #frameLines do + local line = frameLines[lineIdx] if (line.spellTable and line:IsShown() and line.spellTable.rawSpellTable) then if (isPet) then if (line.spellTable.spellId == spellId and line.spellTable.npcId == npcId) then --line for the hover over spell in a comparison scroll frame local rawSpellTable = line.spellTable.rawSpellTable - fillComparisonSpellTooltip (line, rawSpellTable, playerName, line.spellTable.originalName, castAmount, hitCounter, averageDamage, critAmount, auraUptime) + fillComparisonSpellTooltip(line, rawSpellTable, playerName, line.spellTable.originalName, castAmount, hitCounter, averageDamage, critAmount, auraUptime) end else if (line.spellTable.spellId == spellId and not line.spellTable.npcId) then --line for the hover over spell in a comparison scroll frame local rawSpellTable = line.spellTable.rawSpellTable - fillComparisonSpellTooltip (line, rawSpellTable, playerName, playerName, castAmount, hitCounter, averageDamage, critAmount, auraUptime) + fillComparisonSpellTooltip(line, rawSpellTable, playerName, playerName, castAmount, hitCounter, averageDamage, critAmount, auraUptime) end end end @@ -622,27 +728,22 @@ do end end end - - - - - elseif (self.lineType == "mainPlayerTarget" or self.lineType == "comparisonPlayerTarget") then - - local targetName = self.targetTable.originalName + + elseif (compareScrollLine.lineType == "MainPlayerTarget" or compareScrollLine.lineType == "OtherPlayerTarget") then + local targetName = compareScrollLine.targetTable.originalName local attribute = Details:GetDisplayTypeFromBreakdownWindow() - - --build a list of spells used by the main actor - local mainPlayerObject = frame.GetMainPlayerObject() + + local mainPlayerObject = comparePlugin.GetMainPlayerObject() local damageDoneBySpell = {} - + --find the main line --iterate on the main player scroll and find the line local mainLine - local mainFrameScroll = frame.targetFrameScroll - local mainFrameLines = mainFrameScroll:GetFrames() - - for i = 1, #mainFrameLines do - local line = mainFrameLines [i] + local mainSpellFrameScroll = comparePlugin.mainTargetFrameScroll + local mainFrameLines = mainSpellFrameScroll:GetLines() + + for i = 1, #mainFrameLines do + local line = mainFrameLines[i] if (line.targetTable and line:IsShown()) then if (line.targetTable.originalName == targetName) then mainLine = line @@ -650,39 +751,39 @@ do end end end - + if (not mainLine) then return end - + --spells - for spellId, spellTable in pairs (mainPlayerObject:GetActorSpells()) do - local damageOnTarget = spellTable.targets [targetName] + for spellId, spellTable in pairs(mainPlayerObject:GetActorSpells()) do + local damageOnTarget = spellTable.targets[targetName] if (damageOnTarget and damageOnTarget > 0) then damageDoneBySpell [#damageDoneBySpell + 1] = {spellTable, damageOnTarget, mainPlayerObject:Name(), mainPlayerObject, false} end end - + --pets - for _, petName in ipairs (mainPlayerObject:Pets()) do - local petObject = Details:GetCombatFromBreakdownWindow():GetActor (attribute, petName) + for _, petName in ipairs(mainPlayerObject:Pets()) do + local petObject = Details:GetCombatFromBreakdownWindow():GetActor(attribute, petName) if (petObject) then - for spellId, spellTable in pairs (petObject:GetActorSpells()) do + for spellId, spellTable in pairs(petObject:GetActorSpells()) do local damageOnTarget = spellTable.targets [targetName] if (damageOnTarget and damageOnTarget > 0) then - damageDoneBySpell [#damageDoneBySpell + 1] = {spellTable, damageOnTarget, petName, petObject, DetailsFramework:GetNpcIdFromGuid (petObject.serial)} + damageDoneBySpell [#damageDoneBySpell + 1] = {spellTable, damageOnTarget, petName, petObject, detailsFramework:GetNpcIdFromGuid(petObject.serial)} end end end end - - table.sort (damageDoneBySpell, DetailsFramework.SortOrder2) + + table.sort(damageDoneBySpell, detailsFramework.SortOrder2) local tooltip = getTargetComparisonTooltip() local formatFunc = Details:GetCurrentToKFunction() local mainHasTooltip = false - tooltip.player_name_label:SetText (mainPlayerObject:GetDisplayName()) - + tooltip.player_name_label:SetText(mainPlayerObject:GetDisplayName()) + for i = 1, #damageDoneBySpell do local damageTable = damageDoneBySpell [i] local spellTable = damageTable [1] @@ -690,67 +791,67 @@ do local actorName = damageTable [3] local actorObject = damageTable [4] local npcId = damageTable [5] - - local spellName, _, spellIcon = Details.GetSpellInfo (spellTable.id) - + + local spellName, _, spellIcon = Details.GetSpellInfo(spellTable.id) + local line = tooltip.lines [i] if (not line) then break end - + if (npcId) then - spellName = spellName .. " (" .. comparisonFrameSettings.petColor .. actorName:gsub (" <.*", "") .. "|r)" + spellName = spellName .. "(" .. comparisonFrameSettings.petColor .. actorName:gsub(" <.*", "") .. "|r)" end - - line.spellName:SetText (spellName) - DetailsFramework:TruncateText (line.spellName, mainFrameScroll:GetWidth() - 110) - - line.spellIcon:SetTexture (spellIcon) - line.spellIcon:SetTexCoord (.1, .9, .1, .9) - line.spellAmount:SetText ("100%") - DetailsFramework:SetFontColor (line.spellAmount, "gray") - line.spellPercent:SetText (formatFunc (_, damageDone)) - + + line.spellName:SetText(spellName) + detailsFramework:TruncateText(line.spellName, mainSpellFrameScroll:GetWidth() - 110) + + line.spellIcon:SetTexture(spellIcon) + line.spellIcon:SetTexCoord(.1, .9, .1, .9) + line.spellAmount:SetText("100%") + detailsFramework:SetFontColor(line.spellAmount, "gray") + line.spellPercent:SetText(formatFunc(_, damageDone)) + line:Show() mainHasTooltip = true end - + --comparison if (mainHasTooltip) then - local allComparisonFrames = frame.GetAllComparisonFrames() + local allComparisonFrames = comparePlugin.GetAllComparisonFrames() local combatObject = Details:GetCombatFromBreakdownWindow() - + --iterate among all other comparison scrolls for i = 1, #allComparisonFrames do local comparisonFrame = allComparisonFrames [i] if (comparisonFrame:IsShown()) then - local scrollFrame = comparisonFrame.targetsScroll - local playerObject, playerName = frame.GetPlayerInfo (comparisonFrame) - - local targetLines = scrollFrame:GetFrames() + local scrollBox = comparisonFrame.targetsScroll + local playerObject = comparisonFrame.playerObject + + local targetLines = scrollBox:GetFrames() for o = 1, #targetLines do local line = targetLines [o] if (line and line.targetTable and line:IsShown()) then if (line.targetTable.originalName == targetName) then - + --get a tooltip for this actor local actorTooltip = getTargetComparisonTooltip() - - actorTooltip:SetPoint ("bottom", line, "top", 0, 2) - actorTooltip:SetWidth (line:GetWidth()) - actorTooltip:SetHeight (min (comparisonFrameSettings.targetMaxLines, #damageDoneBySpell) * comparisonFrameSettings.targetTooltipLineHeight + comparisonFrameSettings.targetMaxLines) + + actorTooltip:SetPoint("bottom", line, "top", 0, 2) + actorTooltip:SetWidth(line:GetWidth()) + actorTooltip:SetHeight(min(comparisonFrameSettings.targetMaxLines, #damageDoneBySpell) * comparisonFrameSettings.targetTooltipLineHeight + comparisonFrameSettings.targetMaxLines) actorTooltip:Show() - - actorTooltip.player_name_label:SetText (playerObject:GetDisplayName()) - + + actorTooltip.player_name_label:SetText(playerObject:GetDisplayName()) + --highlight line - line:SetBackdropColor (unpack (comparisonFrameSettings.lineOnEnterColor)) + line:SetBackdropColor(unpack(comparisonFrameSettings.lineOnEnterColor)) latestLinesHighlighted [#latestLinesHighlighted + 1] = line - + --iterate among all spells in the first tooltip and fill here --if is a pet line, need to get the data from the player pet instead - - + + for a = 1, #damageDoneBySpell do local damageTable = damageDoneBySpell [a] local spellTable = damageTable [1] @@ -758,13 +859,13 @@ do local actorName = damageTable [3] local actorObject = damageTable [4] local npcId = damageTable [5] - + local foundSpell - + -- i is also the tooltip line index - + if (not npcId) then - local spellObject = playerObject:GetSpell (spellTable.id) + local spellObject = playerObject:GetSpell(spellTable.id) if (spellObject) then local damageOnTarget = spellObject.targets [targetName] or 0 if (damageOnTarget > 0) then @@ -773,14 +874,14 @@ do if (not tooltipLine) then break end - - local spellName, _, spellIcon = Details.GetSpellInfo (spellTable.id) - - tooltipLine.spellName:SetText ("") - tooltipLine.spellIcon:SetTexture (spellIcon) - tooltipLine.spellIcon:SetTexCoord (.1, .9, .1, .9) - - -- calculate percent + + local spellName, _, spellIcon = Details.GetSpellInfo(spellTable.id) + + tooltipLine.spellName:SetText("") + tooltipLine.spellIcon:SetTexture(spellIcon) + tooltipLine.spellIcon:SetTexCoord(.1, .9, .1, .9) + + -- calculate percent local mainSpellDamageOnTarget = 0 -- find this spell in the main actor table for u = 1, #damageDoneBySpell do @@ -791,30 +892,30 @@ do local actorNameMain = damageTable [3] local actorObjectMain = damageTable [4] local npcIdMain = damageTable [5] - + if (not npcIdMain and spellTableMain.id == spellObject.id) then --found the spell in the main table mainSpellDamageOnTarget = damageDoneMain break end end - - tooltipLine.spellAmount:SetText (getPercentComparison (mainSpellDamageOnTarget, damageOnTarget)) - tooltipLine.spellPercent:SetText (formatFunc (_, damageOnTarget)) - + + tooltipLine.spellAmount:SetText(getPercentComparison(mainSpellDamageOnTarget, damageOnTarget)) + tooltipLine.spellPercent:SetText(formatFunc(_, damageOnTarget)) + tooltipLine:Show() foundSpell = true end end else --iterate among all pets the player has and find one with the same npcId - for _, petName in ipairs (playerObject:Pets()) do - local petObject = combatObject:GetActor (attribute, petName) + for _, petName in ipairs(playerObject:Pets()) do + local petObject = combatObject:GetActor(attribute, petName) if (petObject) then - local petNpcId = DetailsFramework:GetNpcIdFromGuid (petObject.serial) + local petNpcId = detailsFramework:GetNpcIdFromGuid(petObject.serial) if (petNpcId and petNpcId == npcId) then --found the correct pet - local spellObject = petObject:GetSpell (spellTable.id) + local spellObject = petObject:GetSpell(spellTable.id) if (spellObject) then local damageOnTarget = spellObject.targets [targetName] or 0 if (damageOnTarget > 0) then @@ -824,8 +925,8 @@ do if (not tooltipLine) then break end - - -- calculate percent + + -- calculate percent local mainSpellDamageOnTarget = 0 -- find this spell in the main actor table for u = 1, #damageDoneBySpell do @@ -836,22 +937,22 @@ do local actorNameMain = damageTable [3] local actorObjectMain = damageTable [4] local npcIdMain = damageTable [5] - + if (npcIdMain and npcIdMain == petNpcId and spellTableMain.id == spellObject.id) then --found the spell in the main table mainSpellDamageOnTarget = damageDoneMain break end end - - local spellName, _, spellIcon = Details.GetSpellInfo (spellTable.id) - - tooltipLine.spellName:SetText ("") - tooltipLine.spellIcon:SetTexture (spellIcon) - tooltipLine.spellIcon:SetTexCoord (.1, .9, .1, .9) - tooltipLine.spellAmount:SetText (getPercentComparison (mainSpellDamageOnTarget, damageOnTarget)) - tooltipLine.spellPercent:SetText (formatFunc (_, damageOnTarget)) - + + local spellName, _, spellIcon = Details.GetSpellInfo(spellTable.id) + + tooltipLine.spellName:SetText("") + tooltipLine.spellIcon:SetTexture(spellIcon) + tooltipLine.spellIcon:SetTexCoord(.1, .9, .1, .9) + tooltipLine.spellAmount:SetText(getPercentComparison(mainSpellDamageOnTarget, damageOnTarget)) + tooltipLine.spellPercent:SetText(formatFunc(_, damageOnTarget)) + tooltipLine:Show() foundSpell = true end @@ -861,7 +962,7 @@ do end end - + if (not foundSpell) then --add an empty line in the tooltip local tooltipLine = actorTooltip.lines [a] @@ -870,7 +971,7 @@ do end end end - + --break the loop to find the correct line break end @@ -879,337 +980,752 @@ do end end end - + --highlight line - mainLine:SetBackdropColor (unpack (comparisonFrameSettings.lineOnEnterColor)) + mainLine:SetBackdropColor(unpack(comparisonFrameSettings.lineOnEnterColor)) latestLinesHighlighted [#latestLinesHighlighted + 1] = mainLine - - tooltip:SetPoint ("bottom", mainLine, "top", 0, 2) - tooltip:SetWidth (mainLine:GetWidth()) - tooltip:SetHeight (min (comparisonFrameSettings.targetMaxLines, #damageDoneBySpell) * comparisonFrameSettings.targetTooltipLineHeight + comparisonFrameSettings.targetMaxLines) + + tooltip:SetPoint("bottom", mainLine, "top", 0, 2) + tooltip:SetWidth(mainLine:GetWidth()) + tooltip:SetHeight(min(comparisonFrameSettings.targetMaxLines, #damageDoneBySpell) * comparisonFrameSettings.targetTooltipLineHeight + comparisonFrameSettings.targetMaxLines) tooltip:Show() end end - - local comparisonLineOnLeave = function (self) + + local comparisonLineOnLeave = function(self) for i = #latestLinesHighlighted, 1, -1 do local line = latestLinesHighlighted [i] - line:SetBackdropColor (unpack (line.BackgroundColor)) - tremove (latestLinesHighlighted, i) + line:SetBackdropColor(unpack(line.BackgroundColor)) + tremove(latestLinesHighlighted, i) end - + resetComparisonTooltip() resetTargetComparisonTooltip() end - local playerComparisonCreate = function (tab, frame) - - frame.isComparisonTab = true - - --regular functions for comparison API - function frame.GetMainPlayerName() - return frame.mainPlayerObject:Name() + ---build a spell and target list for the passed actorObject + ---@param actorObject actor + ---@param combatObject combat + ---@param displayId attributeid + ---@return comparespelltable[] + ---@return comparetargettable[] + local buildSpellAndTargetTables = function(actorObject, combatObject, displayId) + local allPlayerSpells = actorObject:GetActorSpells() + ---@type comparespelltable[] + local resultSpellTable = {} + + --spells + for spellId, spellTable in pairs(allPlayerSpells) do + local spellName, _, spellIcon = Details.GetSpellInfo(spellId) + ---@type comparespelltable + local compareSpellTable = { + spellId, + spellTable.total, + total = spellTable.total, + spellName = spellName, + spellIcon = spellIcon, + spellId = spellId, + amount = spellTable.total, + rawSpellTable = spellTable + } + resultSpellTable[#resultSpellTable + 1] = compareSpellTable end - function frame.GetMainPlayerObject() - return frame.mainPlayerObject + + --pets + local petAbilities = {} + for _, petName in ipairs(actorObject:Pets()) do + local petObject = combatObject:GetActor(displayId, petName) + if (petObject) then + local allPetSpells = petObject:GetActorSpells() + local petNpcId = detailsFramework:GetNpcIdFromGuid(petObject.serial) + for spellId, spellTable in pairs(allPetSpells) do + ---@type comparepettable + local comparePetTable = petAbilities[spellId] or {total = 0, rawSpellTable = spellTable} + petAbilities[spellId] = comparePetTable + petAbilities[spellId].total = petAbilities[spellId].total + spellTable.total + end + end end - - function frame.GetMainSpellTable() - return frame.mainSpellTable + + --pet spells + for spellId, petSpellTable in pairs(petAbilities) do + local spellName, _, spellIcon = Details.GetSpellInfo(spellId) + resultSpellTable[#resultSpellTable + 1] = { + spellId, + petSpellTable.total, + total = petSpellTable.total, + spellName = spellName, + spellIcon = spellIcon, + spellId = spellId, + amount = petSpellTable.total, + rawSpellTable = petSpellTable.rawSpellTable + } end - function frame.GetMainTargetTable() - return frame.mainTargetTable + + table.sort(resultSpellTable, sortByTotalKey) + + --build the target list for the main player + ---@type comparetargettable[] + local resultTargetTable = {} + for targetName, amountDone in pairs(actorObject.targets) do + ---@type comparetargettable + local compareTargetTable = { + targetName, + amountDone, + total = amountDone, + targetName = Details:RemoveOwnerName(targetName), + amount = amountDone, + originalName = targetName, + rawPlayerObject = actorObject + } + resultTargetTable[#resultTargetTable + 1] = compareTargetTable end - - function frame.GetAllComparisonFrames() - return frame.comparisonFrames + + table.sort(resultTargetTable, sortByTotalKey) + + return resultSpellTable, resultTargetTable + end + + --main tab function to be executed when the tab is opened + ---called when the tab is opened + ---@param tab table + ---@param playerActorObject actor + ---@param combat combat + local onOpenCompareTab = function(tab, playerActorObject, combat) + ---@type compare + local comparePlugin = tab.frame + + compareTwo.tabFrame = tab + compareTwo.playerActorObject = playerActorObject + compareTwo.combatObject = combat + + --update player name + comparePlugin.mainPlayerName.text = playerActorObject:GetDisplayName() + comparePlugin.mainPlayerObject = playerActorObject + comparePlugin.mainSpellFrameScroll.mainPlayerObject = playerActorObject + + --reset the comparison scroll frame + comparePlugin.ResetComparisonFrames() + resetComparisonTooltip() + resetTargetComparisonTooltip() + + --get the data to fill the main player spell and target scrollbox + local displayId = Details:GetDisplayTypeFromBreakdownWindow() + ---@type comparespelltable[], comparetargettable[] + local mainPlayerSpellTable, mainPlayerTargetTable = buildSpellAndTargetTables(playerActorObject, combat, displayId) + + --update the two main scroll frames + comparePlugin.mainSpellFrameScroll:SetData(mainPlayerSpellTable) + comparePlugin.mainSpellFrameScroll:Refresh() + comparePlugin.mainTargetFrameScroll:SetData(mainPlayerTargetTable) + comparePlugin.mainTargetFrameScroll:Refresh() + comparePlugin.mainSpellTable = mainPlayerSpellTable + comparePlugin.mainTargetTable = mainPlayerTargetTable + + --depending on what data the user wants to compare, the data captue is different + --perform a search on the same combat when comparing the main player with other players using the same specialization. + --perform a seach on the next segments when comparing the main player against itself. + --to keep the consistency, sort these players with the max amount of damage or healing they have done + + ---table with all other players that will be compared with the main player + ---@type compareactortable[] + local actorObjectsToCompare = {} + setmetatable(actorObjectsToCompare, weakTable) + + if (compareTwo.db.compare_type == CONST_COMPARETYPE_SEGMENT) then + --get the segmentId from the combat + local segmentId = combat:GetSegmentSlotId() + --get the segments table + local segmentsTable = Details:GetCombatSegments() + + --iterate among all segments after the this combat + for i = segmentId+1, #segmentsTable do + ---@type combat + local combatObject = segmentsTable[i] + ---@type actorcontainer + local actorContainer = combatObject:GetContainer(displayId) + ---@type actor + local actorObject = actorContainer:GetActor(playerActorObject:Name()) + + if (actorObject and actorObject ~= playerActorObject) then + ---@type compareactortable + local actorCompareTable = { + actor = actorObject, + total = actorObject.total, + combat = combatObject + } + actorObjectsToCompare[#actorObjectsToCompare + 1] = setmetatable(actorCompareTable, weakTable) + end + end + + elseif (compareTwo.db.compare_type == CONST_COMPARETYPE_SPEC) then + local actorContainer = combat:GetContainer(displayId) + for _, actorObject in actorContainer:ListActors() do + if (actorObject:IsPlayer() and actorObject:IsGroupPlayer() and actorObject.spec == playerActorObject.spec and actorObject.serial ~= playerActorObject.serial) then + ---@type compareactortable + local actorCompareTable = {actor = actorObject, total = actorObject.total, combat = combat} + actorObjectsToCompare[#actorObjectsToCompare + 1] = setmetatable(actorCompareTable, weakTable) + end + end end - - function frame.GetPlayerInfo (f) - if (f.mainPlayerObject) then - return f.mainPlayerObject, f.mainPlayerObject:Name() - else - return f.playerObject, f.playerObject:Name() + + table.sort(actorObjectsToCompare, sortByTotalKey) + + ---hold the spell data for all other players which will be compared with the main player + ---@type comparespelltable[] + comparePlugin.comparisonSpellTable = {} + + ---hold the target data for all other players which will be compared with the main player + ---@type comparetargettable[] + comparePlugin.comparisonTargetTable = {} + + --iterate among found actors eligible for comparison and build their spell and target tables + for idx = 1, #actorObjectsToCompare do + --other player with the same spec + local actorCompareTable = actorObjectsToCompare[idx] + + local playerObject = actorCompareTable.actor + local combatObject = actorCompareTable.combat + + --build the spell and target tables for this player + ---@type comparespelltable[], comparetargettable[] + local otherPlayerSpellTable, otherPlayerTargetTable = buildSpellAndTargetTables(playerObject, combatObject, displayId) + + comparePlugin.comparisonSpellTable[#comparePlugin.comparisonSpellTable + 1] = otherPlayerSpellTable + comparePlugin.comparisonTargetTable[#comparePlugin.comparisonTargetTable + 1] = otherPlayerTargetTable + + ---@type compareplayerframe + local comparisonFrame = comparePlugin.GetCompareFrame() + --store the main actor object + comparisonFrame.mainPlayer = playerActorObject + --store the main player spelltable and targettable + comparisonFrame.mainSpellTable = mainPlayerSpellTable + comparisonFrame.mainTargetTable = mainPlayerTargetTable + --store the another player actorobject and name + comparisonFrame.playerObject = playerObject + + --depending on the compare mode, the "player name" will be the segment name or the player name + if (compareTwo.db.compare_type == CONST_COMPARETYPE_SPEC) then + comparisonFrame.titleLabel.text = detailsFramework:RemoveRealmName(playerObject:Name()) + elseif (compareTwo.db.compare_type == CONST_COMPARETYPE_SEGMENT) then + local bOnlyName = true + comparisonFrame.titleLabel.text = combatObject:GetCombatName(bOnlyName) + end + + --iterate among spells of the main player and check if the spell exists on this player + ---@type comparespelltable[] + local otherPlayerResultSpellTable = {} + + for mainIdx = 1, #mainPlayerSpellTable do + local mainSpellTable = mainPlayerSpellTable[mainIdx] + local bFound = false + + --iterate among spells of the other player and check if the spell exists on the main player + --if the spell exists, insert the comparespelltable into otherPlayerResultSpellTable + for otherIdx = 1, #otherPlayerSpellTable do + local otherSpellTable = otherPlayerSpellTable[otherIdx] + + --check if this is a pet + if (mainSpellTable.npcId) then + --match the npcId before match the spellId + if (otherSpellTable.npcId == mainSpellTable.npcId) then + if (otherSpellTable.spellId == mainSpellTable.spellId) then + bFound = true + --insert the amount of the main spell in the table + otherSpellTable.mainSpellAmount = mainSpellTable.amount + otherPlayerResultSpellTable[#otherPlayerResultSpellTable+1] = otherSpellTable + break + end + end + else + if (otherSpellTable.spellId == mainSpellTable.spellId) then + bFound = true + --insert the amount of the main spell in the table + otherSpellTable.mainSpellAmount = mainSpellTable.amount + otherPlayerResultSpellTable[#otherPlayerResultSpellTable+1] = otherSpellTable + break + end + end + end + + if (not bFound) then + otherPlayerResultSpellTable[#otherPlayerResultSpellTable+1] = {0, 0, spellName = "", spellIcon = "", spellId = 0, amount = 0} + end end + + --update the spell scrollbox of the compared another player compareframe + comparisonFrame.spellsScroll.playerObject = playerObject + comparisonFrame.spellsScroll:SetData(otherPlayerResultSpellTable) + comparisonFrame.spellsScroll:Refresh() + + --iterate among targets of the main player and check if the target exists on another player + ---@type comparetargettable[] + local otherPlayerResultTargetsTable = {} + + for mainIdx = 1, #mainPlayerTargetTable do + local mainTargetTable = mainPlayerTargetTable[mainIdx] + local bFound = false + + --iterate among targets of the other player and check if the target exists on the main player + --if the target exists, insert the comparetargettable into otherPlayerResultTargetsTable + for otherIdx = 1, #otherPlayerTargetTable do + local otherTargetTable = otherPlayerTargetTable[otherIdx] + + if (otherTargetTable.originalName == mainTargetTable.originalName) then + bFound = true + --insert the amount of the main spell in the table + otherTargetTable.mainTargetAmount = mainTargetTable.amount + otherPlayerResultTargetsTable[#otherPlayerResultTargetsTable+1] = otherTargetTable + break + end + end + + if (not bFound) then + otherPlayerResultTargetsTable[#otherPlayerResultTargetsTable+1] = {"", 0, targetName = "", amount = 0, originalName = ""} + end + end + + --update the target scrollbox of the compared another player compareframe + comparisonFrame.targetsScroll:SetData(otherPlayerResultTargetsTable) + comparisonFrame.targetsScroll:Refresh() + end + + --comparePlugin.radioGroup:Select(compareTwo.db.compare_type) + end + + --called when the tab is created + ---@param tab frame + ---@param comparePlugin compare + local playerComparisonCreate = function(tab, comparePlugin) + comparePlugin.isComparisonTab = true + + function compareTwo.Refresh() + onOpenCompareTab(compareTwo.tabFrame, compareTwo.playerActorObject, compareTwo.combatObject) end - - --main player spells (scroll box with the spells the player used) - local mainPlayerCreateline = function (self, index) + + ---return the actor name of the actor being compared + ---@return actorname + function comparePlugin.GetMainPlayerName() + return comparePlugin.mainPlayerObject:Name() + end + + ---return the actor object of the actor being compared + ---@return actor + function comparePlugin.GetMainPlayerObject() + return comparePlugin.mainPlayerObject + end + + ---return the spell table of the actor being compared + ---@return spelltable + function comparePlugin.GetMainSpellTable() + return comparePlugin.mainSpellTable + end + + ---return the target table of the actor being compared + ---@return table + function comparePlugin.GetMainTargetTable() + return comparePlugin.mainTargetTable + end + + function comparePlugin.GetAllComparisonFrames() + return comparePlugin.comparisonFrames + end + + local selectCompareMode = function(fixedParam, radioButtonId) + local currentCompareMode = compareTwo.db.compare_type + if (currentCompareMode == radioButtonId) then + return + end + compareTwo.db.compare_type = radioButtonId + compareTwo.Refresh() + end + + --create a radio group to select between comparing players of the same spec or the player itself against other segments + ---@type df_radiooptions[] + local mainTabSelectorRadioOptions = { + { + name = "Compare Same Spec", --localize-me + set = function()end, + param = "player", + get = function() return compareTwo.db.compare_type == CONST_COMPARETYPE_SPEC end, + texture = [[Interface\AddOns\Details\images\icons2.png]], + width = 32, + height = 32, + text_size = 20, + texcoord = {0, 64/512, 211/512, 275/512}, + callback = selectCompareMode, + }, + { + name = "Compare Segments", --localize-me + set = function()end, + param = "segment", + get = function() return compareTwo.db.compare_type == CONST_COMPARETYPE_SEGMENT end, + texture = [[Interface\AddOns\Details\images\icons2.png]], + texcoord = {65/512, 128/512, 211/512, 275/512}, + width = 32, + height = 32, + text_size = 20, + callback = selectCompareMode, + } + } + + ---@type df_framelayout_options + local radioGroupLayout = { + min_width = 350, + height = 42, + start_x = 5, + start_y = -5, --the size of each checkbox is 50, the start_y is the initial offset of the Y anchor, as the radio group height is 50, this make it be centered aligned + icon_offset_x = 5, + } + + local radioGroupSettings = { + rounded_corner_preset = { + color = {.075, .075, .075, 1}, + border_color = {.2, .2, .2, 1}, + roundness = 8, + }, + + checked_texture = [[Interface\AddOns\Details\images\checked_texture1]], + checked_texture_offset_x = 0, + checked_texture_offset_y = 0, + + backdrop_color = {0, 0, 0, 0}, + + on_create_checkbox = function(radioGroup, checkBox) + local icon = checkBox.Icon.widget + local selectedTexture = checkBox:CreateTexture(checkBox:GetName() .. "SelectedTexture", "border") + selectedTexture:SetTexture([[Interface\CovenantRenown\CovenantRenownScrollMask]]) + selectedTexture:SetTexCoord(0, 1, 0, 1) + selectedTexture:SetSize(375, 32) + selectedTexture:SetVertexColor(1, 1, 1, 0.2) + selectedTexture:SetPoint("left", icon, "right", -85, 0) + checkBox.SelectedTexture = selectedTexture + checkBox.SelectedTexture:Hide() + end, + + on_click_option = function(radioGroup, checkBox, fixedParam, optionId) + local radioCheckboxes = radioGroup:GetAllCheckboxes() + for i = 1, #radioCheckboxes do + local thisCheckBox = radioCheckboxes[i] + thisCheckBox.SelectedTexture:Hide() + end + checkBox.SelectedTexture:Show() + end + } + + local radioGroup = detailsFramework:CreateRadioGroup(comparePlugin, mainTabSelectorRadioOptions, "$parentMainTabSelector", radioGroupSettings, radioGroupLayout) + radioGroup:SetPoint("bottomleft", comparePlugin, "bottomleft", 5, 5) + comparePlugin.radioGroup = radioGroup + + local radioGroupBackgroundTexture = comparePlugin:CreateTexture(nil, "artwork") + radioGroupBackgroundTexture:SetColorTexture(.2, .2, .2, 0.834) + radioGroupBackgroundTexture:SetPoint("bottomleft", comparePlugin, "bottomleft", 5, 8) + radioGroupBackgroundTexture:SetPoint("bottomright", comparePlugin, "bottomright", -2, 2) + radioGroupBackgroundTexture:SetHeight(35) + comparePlugin.radioGroupBackgroundTexture = radioGroupBackgroundTexture + + ---create a line for the main player spells(scroll box with the spells the player used) + ---@param self comparescrollbox + ---@param index number + ---@return comparescrollline + local createScrollLine = function(self, index) local lineHeight = self.lineHeight local lineWidth = self.scrollWidth local fontSize = self.fontSize - - local line = CreateFrame ("button", "$parentLine" .. index, self, "BackdropTemplate") - line:SetPoint ("topleft", self, "topleft", 1, -((index-1) * (lineHeight+1))) - line:SetSize (lineWidth -2, lineHeight) - - line:SetScript ("OnEnter", comparisonLineOnEnter) - line:SetScript ("OnLeave", comparisonLineOnLeave) - - line:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) - line:SetBackdropColor (0, 0, 0, 0.2) - - local spellIcon = line:CreateTexture ("$parentIcon", "overlay") - spellIcon:SetSize (lineHeight -2 , lineHeight - 2) - - local spellName = line:CreateFontString ("$parentName", "overlay", "GameFontNormal") - local spellAmount = line:CreateFontString ("$parentAmount", "overlay", "GameFontNormal") - local spellPercent = line:CreateFontString ("$parentPercent", "overlay", "GameFontNormal") - DetailsFramework:SetFontSize (spellName, fontSize) - DetailsFramework:SetFontSize (spellAmount, fontSize) - DetailsFramework:SetFontSize (spellPercent, fontSize) - - spellIcon:SetPoint ("left", line, "left", 2, 0) - spellName:SetPoint ("left", spellIcon, "right", 2, 0) - spellAmount:SetPoint ("right", line, "right", -2, 0) - spellPercent:SetPoint ("right", line, "right", -40, 0) - - spellName:SetJustifyH ("left") - spellAmount:SetJustifyH ("right") - spellPercent:SetJustifyH ("right") - + + ---@type comparescrollline + local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate") + line:SetPoint("topleft", self, "topleft", 1, -((index-1) *(lineHeight+1))) + line:SetSize(lineWidth -2, lineHeight) + + line:SetScript("OnEnter", comparisonLineOnEnter) + line:SetScript("OnLeave", comparisonLineOnLeave) + + line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + line:SetBackdropColor(0, 0, 0, 0.2) + + local spellIcon = line:CreateTexture("$parentIcon", "overlay") + spellIcon:SetSize(lineHeight -2 , lineHeight - 2) + + local spellName = line:CreateFontString("$parentName", "overlay", "GameFontNormal") + local spellAmount = line:CreateFontString("$parentAmount", "overlay", "GameFontNormal") + local spellPercent = line:CreateFontString("$parentPercent", "overlay", "GameFontNormal") + detailsFramework:SetFontSize(spellName, fontSize) + detailsFramework:SetFontSize(spellAmount, fontSize) + detailsFramework:SetFontSize(spellPercent, fontSize) + + spellIcon:SetPoint("left", line, "left", 2, 0) + spellName:SetPoint("left", spellIcon, "right", 2, 0) + spellAmount:SetPoint("right", line, "right", -2, 0) + spellPercent:SetPoint("right", line, "right", -50, 0) + + spellName:SetJustifyH("left") + spellAmount:SetJustifyH("right") + spellPercent:SetJustifyH("right") + line.spellIcon = spellIcon line.spellName = spellName line.spellAmount = spellAmount line.spellPercent = spellPercent - + return line end --the refresh function receives an already prepared table and just update the lines - local mainPlayerRefreshSpellScroll = function (self, data, offset, totalLines) + local mainPlayerRefreshSpellScroll = function(self, data, offset, totalLines) for i = 1, totalLines do local index = i + offset - local spellTable = data [index] - + local spellTable = data[index] + if (spellTable) then - local line = self:GetLine (i) - + ---@type comparescrollline + local line = self:GetLine(i) + --store the line into the spell table spellTable.line = line line.spellTable = spellTable - + local spellId = spellTable.spellId local spellName = spellTable.spellName local spellIcon = spellTable.spellIcon local amountDone = spellTable.amount - + line.spellId = spellId - - line.spellIcon:SetTexture (spellIcon) - line.spellIcon:SetTexCoord (.1, .9, .1, .9) - - line.spellName:SetText (spellName) - DetailsFramework:TruncateText (line.spellName, line:GetWidth() - 70) - + + line.spellIcon:SetTexture(spellIcon) + line.spellIcon:SetTexCoord(.1, .9, .1, .9) + + line.spellName:SetText(spellName) + detailsFramework:TruncateText(line.spellName, line:GetWidth() - 70) + local formatFunc = Details:GetCurrentToKFunction() - line.spellAmount:SetText (formatFunc (_, amountDone)) + line.spellAmount:SetText(formatFunc(_, amountDone)) if (i % 2 == 0) then - line:SetBackdropColor (unpack (comparisonLineContrast [1])) - line.BackgroundColor = comparisonLineContrast [1] + line:SetBackdropColor(unpack(comparisonLineContrast [1])) + line.BackgroundColor = comparisonLineContrast[1] else - line:SetBackdropColor (unpack (comparisonLineContrast [2])) - line.BackgroundColor = comparisonLineContrast [2] + line:SetBackdropColor(unpack(comparisonLineContrast [2])) + line.BackgroundColor = comparisonLineContrast[2] end end end end - - local mainPlayerRefreshTargetScroll = function (self, data, offset, totalLines) + + --refresh a target scroll + local mainPlayerRefreshTargetScroll = function(self, data, offset, totalLines) for i = 1, totalLines do local index = i + offset - local targetTable = data [index] - + local targetTable = data[index] + if (targetTable) then - local line = self:GetLine (i) - + ---@type comparescrollline + local line = self:GetLine(i) + --store the line into the target table targetTable.line = line line.targetTable = targetTable - + local targetName = targetTable.targetName local amountDone = targetTable.amount - + line.targetName = targetName - - line.spellIcon:SetTexture ("") --todo - fill this texture - line.spellIcon:SetTexCoord (.1, .9, .1, .9) - - line.spellName:SetText (targetName) - DetailsFramework:TruncateText (line.spellName, line:GetWidth() - 50) - + + line.spellIcon:SetTexture("") --todo - fill this texture + line.spellIcon:SetTexCoord(.1, .9, .1, .9) + + line.spellName:SetText(targetName) + detailsFramework:TruncateText(line.spellName, line:GetWidth() - 50) + local formatFunc = Details:GetCurrentToKFunction() - line.spellAmount:SetText (formatFunc (_, amountDone)) + line.spellAmount:SetText(formatFunc(_, amountDone)) if (i % 2 == 0) then - line:SetBackdropColor (unpack (comparisonLineContrast [1])) + line:SetBackdropColor(unpack(comparisonLineContrast [1])) line.BackgroundColor = comparisonLineContrast [1] else - line:SetBackdropColor (unpack (comparisonLineContrast [2])) + line:SetBackdropColor(unpack(comparisonLineContrast [2])) line.BackgroundColor = comparisonLineContrast [2] end end end end - + --main player spells scroll - local mainPlayerFrameScroll = DetailsFramework:CreateScrollBox (frame, "$parentComparisonMainPlayerSpellsScroll", mainPlayerRefreshSpellScroll, {}, comparisonFrameSettings.mainScrollWidth, comparisonFrameSettings.spellScrollHeight, comparisonFrameSettings.spellLineAmount, comparisonFrameSettings.spellLineHeight) - mainPlayerFrameScroll:SetPoint ("topleft", frame, "topleft", 5, -30) - mainPlayerFrameScroll.lineHeight = comparisonFrameSettings.spellLineHeight - mainPlayerFrameScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth - mainPlayerFrameScroll.fontSize = comparisonFrameSettings.fontSize - - mainPlayerFrameScroll:HookScript ("OnVerticalScroll", function (self, offset) - frame.RefreshAllComparisonScrollFrames() - end) - + ---@type comparescrollbox + local mainSpellsFrameScroll = detailsFramework:CreateScrollBox(comparePlugin, "$parentComparisonMainPlayerSpellsScroll", mainPlayerRefreshSpellScroll, {}, comparisonFrameSettings.mainScrollWidth, comparisonFrameSettings.spellScrollHeight, comparisonFrameSettings.spellLineAmount, comparisonFrameSettings.spellLineHeight) + mainSpellsFrameScroll:SetPoint("topleft", comparePlugin, "topleft", 5, -30) + mainSpellsFrameScroll.lineHeight = comparisonFrameSettings.spellLineHeight + mainSpellsFrameScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth + mainSpellsFrameScroll.fontSize = comparisonFrameSettings.fontSize + mainSpellsFrameScroll.bIsMain = true + + mainSpellsFrameScroll:HookScript("OnVerticalScroll", function(self, offset) + comparePlugin.RefreshAllComparisonScrollFrames() + end) + --create lines - for i = 1, comparisonFrameSettings.spellLineAmount do - local line = mainPlayerFrameScroll:CreateLine (mainPlayerCreateline) - line.lineType = "mainPlayerSpell" + for i = 1, comparisonFrameSettings.spellLineAmount do + ---@type comparescrollline + local line = mainSpellsFrameScroll:CreateLine(createScrollLine) + line.lineType = "MainPlayerSpell" end - DetailsFramework:ReskinSlider (mainPlayerFrameScroll) - - frame.mainFrameScroll = mainPlayerFrameScroll - - --main player targets (scroll box with enemies the player applied damage) - local mainTargetFrameScroll = DetailsFramework:CreateScrollBox (frame, "$parentComparisonMainPlayerTargetsScroll", mainPlayerRefreshTargetScroll, {}, comparisonFrameSettings.mainScrollWidth, comparisonFrameSettings.targetScrollHeight, comparisonFrameSettings.targetScrollLineAmount, comparisonFrameSettings.targetScrollLineHeight) - mainTargetFrameScroll:SetPoint ("topleft", mainPlayerFrameScroll, "bottomleft", 0, -20) + detailsFramework:ReskinSlider(mainSpellsFrameScroll) + + comparePlugin.mainSpellFrameScroll = mainSpellsFrameScroll + + --main player targets(scroll box with enemies the player applied damage) + ---@type comparescrollbox + local mainTargetFrameScroll = detailsFramework:CreateScrollBox(comparePlugin, "$parentComparisonMainPlayerTargetsScroll", mainPlayerRefreshTargetScroll, {}, comparisonFrameSettings.mainScrollWidth, comparisonFrameSettings.targetScrollHeight, comparisonFrameSettings.targetScrollLineAmount, comparisonFrameSettings.targetScrollLineHeight) + mainTargetFrameScroll:SetPoint("topleft", mainSpellsFrameScroll, "bottomleft", 0, -20) mainTargetFrameScroll.lineHeight = comparisonFrameSettings.targetScrollLineHeight mainTargetFrameScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth mainTargetFrameScroll.fontSize = comparisonFrameSettings.fontSize - + mainTargetFrameScroll.bIsMain = true + --create lines - for i = 1, comparisonFrameSettings.targetScrollLineAmount do - local line = mainTargetFrameScroll:CreateLine (mainPlayerCreateline) - line.lineType = "mainPlayerTarget" + for i = 1, comparisonFrameSettings.targetScrollLineAmount do + local line = mainTargetFrameScroll:CreateLine(createScrollLine) + line.lineType = "MainPlayerTarget" end - DetailsFramework:ReskinSlider (mainTargetFrameScroll) - - frame.targetFrameScroll = mainTargetFrameScroll + detailsFramework:ReskinSlider(mainTargetFrameScroll) + + comparePlugin.mainTargetFrameScroll = mainTargetFrameScroll --main player name - frame.mainPlayerName = DetailsFramework:CreateLabel (mainPlayerFrameScroll) - frame.mainPlayerName:SetPoint ("topleft", mainPlayerFrameScroll, "topleft", 2, comparisonFrameSettings.playerNameYOffset) - frame.mainPlayerName.fontsize = comparisonFrameSettings.playerNameSize - + comparePlugin.mainPlayerName = detailsFramework:CreateLabel(mainSpellsFrameScroll, "") + comparePlugin.mainPlayerName:SetPoint("topleft", mainSpellsFrameScroll, "topleft", 2, comparisonFrameSettings.playerNameYOffset) + comparePlugin.mainPlayerName.fontsize = comparisonFrameSettings.playerNameSize + --create the framework for the comparing players local settings = { --comparison frame height = 600, } - - frame.comparisonFrames = {} - frame.comparisonScrollFrameIndex = 0 - - function frame.ResetComparisonFrames() - frame.comparisonScrollFrameIndex = 0 - for _, comparisonFrame in ipairs (frame.comparisonFrames) do + + ---@type compareplayerframe[] + comparePlugin.comparisonFrames = {} + comparePlugin.comparisonScrollFrameIndex = 0 + + function comparePlugin.ResetComparisonFrames() + comparePlugin.comparisonScrollFrameIndex = 0 + for _, comparisonFrame in ipairs(comparePlugin.comparisonFrames) do comparisonFrame:Hide() comparisonFrame.playerObject = nil comparisonFrame.spellsScroll.playerObject = nil end end - - local comparisonPlayerRefreshTargetScroll = function (self, data, offset, totalLines) - offset = FauxScrollFrame_GetOffset (mainPlayerFrameScroll) - + + ---this function refreshes the target scroll of a compareanotherplayerframe + ---compareframe is the frame that shows the data of another player being compared with the main player + ---@param self comparescrollbox + ---@param data comparetargettable[] + ---@param offset number + ---@param totalLines number + local comparisonPlayerRefreshTargetScroll = function(self, data, offset, totalLines) + offset = FauxScrollFrame_GetOffset(mainSpellsFrameScroll) + for i = 1, totalLines do local index = i + offset - local targetTable = data [index] - + ---@type comparetargettable + local targetTable = data[index] --unknown type yet + if (targetTable) then - local line = self:GetLine (i) - line:SetWidth (comparisonFrameSettings.comparisonScrollWidth - 2) - + ---@type comparescrollline + local line = self:GetLine(i) + line:SetWidth(comparisonFrameSettings.comparisonScrollWidth - 2) + --store the line into the target table targetTable.line = line line.targetTable = targetTable - - line.spellIcon:SetTexture ("") - + + line.spellIcon:SetTexture("") + local mainPlayerAmount = targetTable.mainTargetAmount local amountDone = targetTable.amount - + if (mainPlayerAmount) then local formatFunc = Details:GetCurrentToKFunction() - + if (mainPlayerAmount > amountDone) then local diff = mainPlayerAmount - amountDone local up = diff / amountDone * 100 - up = floor (up) + up = floor(up) if (up > 999) then - up = "" .. 999 + up = 999 end - - line.spellPercent:SetText ("|c" .. minor .. up .. "%|r") + line.spellPercent:SetText("|c" .. minor .. up .. "%|r") + else local diff = amountDone - mainPlayerAmount local down = diff / mainPlayerAmount * 100 - down = floor (down) + down = floor(down) if (down > 999) then - down = "" .. 999 + down = 999 end - - line.spellPercent:SetText ("|c" .. plus .. down .. "%|r") + line.spellPercent:SetText("|c" .. plus .. down .. "%|r") end - - line.spellAmount:SetText (formatFunc (_, amountDone)) + + line.spellAmount:SetText(formatFunc(_, amountDone)) else - line.spellPercent:SetText ("") - line.spellAmount:SetText ("") + line.spellPercent:SetText("") + line.spellAmount:SetText("") end if (i % 2 == 0) then - line:SetBackdropColor (unpack (comparisonLineContrast [1])) - line.BackgroundColor = comparisonLineContrast [1] + line:SetBackdropColor(unpack(comparisonLineContrast[1])) + line.BackgroundColor = comparisonLineContrast[1] else - line:SetBackdropColor (unpack (comparisonLineContrast [2])) - line.BackgroundColor = comparisonLineContrast [2] + line:SetBackdropColor(unpack(comparisonLineContrast[2])) + line.BackgroundColor = comparisonLineContrast[2] end end end end - - --refresh a spell scroll on a comparison frame - local comparisonPlayerRefreshSpellScroll = function (self, data, offset, totalLines) - - offset = FauxScrollFrame_GetOffset (mainPlayerFrameScroll) - + + ---refreshes the spell scroll on a comparison compareanotherplayerframe + ---@param self comparescrollbox + ---@param data comparetargettable[] + ---@param offset number + ---@param totalLines number + local comparisonPlayerRefreshSpellScroll = function(self, data, offset, totalLines) + offset = FauxScrollFrame_GetOffset(mainSpellsFrameScroll) + for i = 1, totalLines do local index = i + offset + ---@type comparespelltable local spellTable = data[index] - + if (spellTable) then + ---@type comparescrollline local line = self:GetLine(i) line:SetWidth(comparisonFrameSettings.comparisonScrollWidth - 2) - + --store the line into the spell table spellTable.line = line line.spellTable = spellTable - + local spellId = spellTable.spellId local spellName = spellTable.spellName local spellIcon = spellTable.spellIcon local amountDone = spellTable.amount - + line.spellId = spellId - + line.spellIcon:SetTexture(spellIcon) line.spellIcon:SetTexCoord(.1, .9, .1, .9) - + line.spellName:SetText("") --won't show the spell name, only the icon - + local percent = 1 - + local mainFrame = self:GetParent().mainPlayer local mainSpellTable = self:GetParent().mainSpellTable local mainPlayerAmount = spellTable.mainSpellAmount - + if (mainPlayerAmount) then local formatFunc = Details:GetCurrentToKFunction() - + if (mainPlayerAmount > amountDone) then local diff = mainPlayerAmount - amountDone local up @@ -1218,13 +1734,13 @@ do up = "0" else up = diff / amountDone * 100 - up = floor (up) + up = floor(up) if (up > 999) then - up = "" .. 999 + up = 999 end end - - line.spellPercent:SetText ("|c" .. minor .. up .. "%|r") + line.spellPercent:SetText("|c" .. minor .. up .. "%|r") + else local down local diff = amountDone - mainPlayerAmount @@ -1234,13 +1750,12 @@ do down = diff / mainPlayerAmount * 100 down = floor(down) if (down > 999) then - down = "" .. 999 + down = 999 end end - line.spellPercent:SetText("|c" .. plus .. down .. "%|r") end - + line.spellAmount:SetText(formatFunc(_, amountDone)) else line.spellPercent:SetText("") @@ -1248,267 +1763,97 @@ do end if (i % 2 == 0) then - line:SetBackdropColor (unpack (comparisonLineContrast [1])) - line.BackgroundColor = comparisonLineContrast [1] + line:SetBackdropColor(unpack(comparisonLineContrast[1])) + line.BackgroundColor = comparisonLineContrast[1] else - line:SetBackdropColor (unpack (comparisonLineContrast [2])) - line.BackgroundColor = comparisonLineContrast [2] + line:SetBackdropColor(unpack(comparisonLineContrast[2])) + line.BackgroundColor = comparisonLineContrast[2] end end end - end - - function frame.RefreshAllComparisonScrollFrames() - for _, comparisonFrame in ipairs (frame.comparisonFrames) do + end + + function comparePlugin.RefreshAllComparisonScrollFrames() + for _, comparisonFrame in ipairs(comparePlugin.comparisonFrames) do comparisonFrame.spellsScroll:Refresh() + comparisonFrame.targetsScroll:Refresh() end end - + --get a frame which has two scrolls, one for spells and another for targets - function frame.GetComparisonScrollFrame() - frame.comparisonScrollFrameIndex = frame.comparisonScrollFrameIndex + 1 - - local comparisonFrame = frame.comparisonFrames [frame.comparisonScrollFrameIndex] + --if the frame does not exists, create it + ---@return compareplayerframe + function comparePlugin.GetCompareFrame() + comparePlugin.comparisonScrollFrameIndex = comparePlugin.comparisonScrollFrameIndex + 1 + + local comparisonFrame = comparePlugin.comparisonFrames[comparePlugin.comparisonScrollFrameIndex] if (comparisonFrame) then comparisonFrame:Show() return comparisonFrame end - - local newComparisonFrame = CreateFrame ("frame", "DetailsComparisonFrame" .. frame.comparisonScrollFrameIndex, frame, "BackdropTemplate") - frame.comparisonFrames [frame.comparisonScrollFrameIndex] = newComparisonFrame - newComparisonFrame:SetSize (comparisonFrameSettings.comparisonScrollWidth, settings.height) - - if (frame.comparisonScrollFrameIndex == 1) then - newComparisonFrame:SetPoint ("topleft", mainPlayerFrameScroll, "topright", 30, 0) + + --if the line requested does exist, create it + ---@type compareplayerframe + local newComparisonFrame = CreateFrame("frame", "DetailsComparisonFrame" .. comparePlugin.comparisonScrollFrameIndex, comparePlugin, "BackdropTemplate") + comparePlugin.comparisonFrames[comparePlugin.comparisonScrollFrameIndex] = newComparisonFrame + newComparisonFrame:SetSize(comparisonFrameSettings.comparisonScrollWidth, settings.height) + + if (comparePlugin.comparisonScrollFrameIndex == 1) then + newComparisonFrame:SetPoint("topleft", mainSpellsFrameScroll, "topright", 30, 0) else - newComparisonFrame:SetPoint ("topleft", frame.comparisonFrames [frame.comparisonScrollFrameIndex - 1], "topright", 10, 0) + newComparisonFrame:SetPoint("topleft", comparePlugin.comparisonFrames [comparePlugin.comparisonScrollFrameIndex - 1], "topright", 10, 0) end - - --create the spell comparison scroll - --player name - newComparisonFrame.playerName = DetailsFramework:CreateLabel (newComparisonFrame) - newComparisonFrame.playerName:SetPoint ("topleft", newComparisonFrame, "topleft", 2, comparisonFrameSettings.playerNameYOffset) - newComparisonFrame.playerName.fontsize = comparisonFrameSettings.playerNameSize - - --spells scroll - local spellsScroll = DetailsFramework:CreateScrollBox (newComparisonFrame, "$parentComparisonPlayerSpellsScroll", comparisonPlayerRefreshSpellScroll, {}, comparisonFrameSettings.comparisonScrollWidth, comparisonFrameSettings.spellScrollHeight, comparisonFrameSettings.spellLineAmount, comparisonFrameSettings.spellLineHeight) - spellsScroll:SetPoint ("topleft", newComparisonFrame, "topleft", 0, 0) - spellsScroll.lineHeight = comparisonFrameSettings.spellLineHeight - spellsScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth - spellsScroll.fontSize = comparisonFrameSettings.fontSize - _G [spellsScroll:GetName() .. "ScrollBar"]:Hide() - - --create lines - for i = 1, comparisonFrameSettings.spellLineAmount do - local line = spellsScroll:CreateLine (mainPlayerCreateline) - line.lineType = "comparisonPlayerSpell" - end - DetailsFramework:ReskinSlider (spellsScroll) - - newComparisonFrame.spellsScroll = spellsScroll - - --targets scroll - local targetsScroll = DetailsFramework:CreateScrollBox (newComparisonFrame, "$parentComparisonPlayerTargetsScroll", comparisonPlayerRefreshTargetScroll, {}, comparisonFrameSettings.comparisonScrollWidth, comparisonFrameSettings.targetScrollHeight, comparisonFrameSettings.targetScrollLineAmount, comparisonFrameSettings.targetScrollLineHeight) - targetsScroll:SetPoint ("topleft", newComparisonFrame, "topleft", 0, -comparisonFrameSettings.spellScrollHeight - 20) - targetsScroll.lineHeight = comparisonFrameSettings.spellLineHeight - targetsScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth - targetsScroll.fontSize = comparisonFrameSettings.fontSize - _G [targetsScroll:GetName() .. "ScrollBar"]:Hide() - - --create lines - for i = 1, comparisonFrameSettings.targetScrollLineAmount do - local line = targetsScroll:CreateLine (mainPlayerCreateline) - line.lineType = "comparisonPlayerTarget" - end - DetailsFramework:ReskinSlider (targetsScroll) - - newComparisonFrame.targetsScroll = targetsScroll - - return newComparisonFrame - end - - if (not frame.__background) then - DetailsFramework:ApplyStandardBackdrop(frame) - frame.__background:SetAlpha(0.6) - end - end - - local buildSpellAndTargetTables = function (player, combat, attribute) - --build the spell list for the main player including pets - local allPlayerSpells = player:GetActorSpells() - local resultSpellTable = {} - - for spellId, spellTable in pairs(allPlayerSpells) do - local spellName, _, spellIcon = Details.GetSpellInfo (spellId) - resultSpellTable [#resultSpellTable + 1] = {spellId, spellTable.total, spellName = spellName, spellIcon = spellIcon, spellId = spellId, amount = spellTable.total, rawSpellTable = spellTable} - end - - --pets - local petAbilities = {} - for _, petName in ipairs(player:Pets()) do - local petObject = combat:GetActor(attribute, petName) - if (petObject) then - local allPetSpells = petObject:GetActorSpells() - local petNpcId = DetailsFramework:GetNpcIdFromGuid(petObject.serial) - for spellId, spellTable in pairs(allPetSpells) do - petAbilities[spellId] = petAbilities[spellId] or {total = 0, rawSpellTable = spellTable} - petAbilities[spellId].total = petAbilities[spellId].total + spellTable.total - end + + --player name shown above the scrolls + ---@type df_label + newComparisonFrame.titleLabel = detailsFramework:CreateLabel(newComparisonFrame, "") + newComparisonFrame.titleLabel:SetPoint("topleft", newComparisonFrame, "topleft", 2, comparisonFrameSettings.playerNameYOffset) + newComparisonFrame.titleLabel.fontsize = comparisonFrameSettings.playerNameSize + + --spells scroll + ---@type comparescrollbox + local spellsScroll = detailsFramework:CreateScrollBox(newComparisonFrame, "$parentComparisonPlayerSpellsScroll", comparisonPlayerRefreshSpellScroll, {}, comparisonFrameSettings.comparisonScrollWidth, comparisonFrameSettings.spellScrollHeight, comparisonFrameSettings.spellLineAmount, comparisonFrameSettings.spellLineHeight) + spellsScroll:SetPoint("topleft", newComparisonFrame, "topleft", 0, 0) + spellsScroll.lineHeight = comparisonFrameSettings.spellLineHeight + spellsScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth + spellsScroll.fontSize = comparisonFrameSettings.fontSize + --hide the scrollbar of a df_scrollbox + _G[spellsScroll:GetName() .. "ScrollBar"]:Hide() + + --create lines + for i = 1, comparisonFrameSettings.spellLineAmount do + local line = spellsScroll:CreateLine(createScrollLine) + line.lineType = "OtherPlayerSpell" end - end + detailsFramework:ReskinSlider(spellsScroll) - for spellId, petSpellTable in pairs(petAbilities) do - local spellName, _, spellIcon = Details.GetSpellInfo(spellId) - resultSpellTable [#resultSpellTable + 1] = {spellId, petSpellTable.total, spellName = spellName, spellIcon = spellIcon, spellId = spellId, amount = petSpellTable.total, rawSpellTable = petSpellTable.rawSpellTable} - end - - table.sort (resultSpellTable, DetailsFramework.SortOrder2) - - --build the target list for the main player - local resultTargetTable = {} - for targetName, amountDone in pairs (player.targets) do - resultTargetTable [#resultTargetTable + 1] = {targetName, amountDone, targetName = Details:RemoveOwnerName (targetName), amount = amountDone, originalName = targetName, rawPlayerObject = player} - end - - table.sort (resultTargetTable, DetailsFramework.SortOrder2) - - return resultSpellTable, resultTargetTable - end - - --main tab function to be executed when the tab is shown - local playerComparisonFill = function (tab, player, combat) - local frame = tab.frame + newComparisonFrame.spellsScroll = spellsScroll - --update player name - frame.mainPlayerName.text = player:GetDisplayName() - - frame.mainPlayerObject = player - frame.mainFrameScroll.mainPlayerObject = player - - --reset the comparison scroll frame - frame.ResetComparisonFrames() - resetComparisonTooltip() - resetTargetComparisonTooltip() - - local attribute = Details:GetDisplayTypeFromBreakdownWindow() - local resultSpellTable, resultTargetTable = buildSpellAndTargetTables (player, combat, attribute) + --targets scroll + ---@type comparescrollbox + local targetsScroll = detailsFramework:CreateScrollBox(newComparisonFrame, "$parentComparisonPlayerTargetsScroll", comparisonPlayerRefreshTargetScroll, {}, comparisonFrameSettings.comparisonScrollWidth, comparisonFrameSettings.targetScrollHeight, comparisonFrameSettings.targetScrollLineAmount, comparisonFrameSettings.targetScrollLineHeight) + targetsScroll:SetPoint("topleft", newComparisonFrame, "topleft", 0, -comparisonFrameSettings.spellScrollHeight - 20) + targetsScroll.lineHeight = comparisonFrameSettings.spellLineHeight + targetsScroll.scrollWidth = comparisonFrameSettings.mainScrollWidth + targetsScroll.fontSize = comparisonFrameSettings.fontSize + --hide the scrollbar of a df_scrollbox + _G[targetsScroll:GetName() .. "ScrollBar"]:Hide() - --update the two main scroll frames - frame.mainFrameScroll:SetData (resultSpellTable) - frame.mainFrameScroll:Refresh() - - frame.targetFrameScroll:SetData (resultTargetTable) - frame.targetFrameScroll:Refresh() - - frame.mainSpellTable = resultSpellTable - frame.mainTargetTable = resultTargetTable - - --search the combat for players with the same spec and build a scroll frame for them - --to keep consistency, sort these players with the max amount of damage or healing they have done - local actorContainer = combat:GetContainer (attribute) - local playersWithSameSpec = {} - - for _, playerObject in actorContainer:ListActors() do - if (playerObject:IsPlayer() and playerObject.spec == player.spec and playerObject.serial ~= player.serial) then - playersWithSameSpec [#playersWithSameSpec + 1] = {playerObject, playerObject.total} + --create lines + for i = 1, comparisonFrameSettings.targetScrollLineAmount do + local line = targetsScroll:CreateLine(createScrollLine) + line.lineType = "OtherPlayerTarget" end - end - - table.sort (playersWithSameSpec, DetailsFramework.SortOrder2) - - frame.comparisonSpellTable = {} - frame.comparisonTargetTable = {} - - for i = 1, #playersWithSameSpec do - --other player with the same spec - local playerObject = playersWithSameSpec[i][1] - local otherPlayerSpellTable, otherPlayerTargetTable = buildSpellAndTargetTables (playerObject, combat, attribute) - - frame.comparisonSpellTable [#frame.comparisonSpellTable + 1] = otherPlayerSpellTable - frame.comparisonTargetTable [#frame.comparisonTargetTable + 1] = otherPlayerTargetTable - - local comparisonFrame = frame.GetComparisonScrollFrame() - comparisonFrame.mainPlayer = player - comparisonFrame.mainSpellTable = resultSpellTable - comparisonFrame.mainTargetTable = resultTargetTable - - comparisonFrame.playerObject = playerObject - comparisonFrame.playerName.text = playerObject:GetDisplayName() - - --iterate among spells of the main player and check if the spell exists on this player - local otherPlayerResultSpellTable = {} - - for i = 1, #resultSpellTable do - local spellTable = resultSpellTable [i] - - local found = false - - --iterate amont spell of the other player which the main player is being compared - for o = 1, #otherPlayerSpellTable do - local otherSpellTable = otherPlayerSpellTable[o] - - --check if this is a pet - if (spellTable.npcId) then - --match the npcId before match the spellId - if (otherSpellTable.npcId == spellTable.npcId) then - if (otherSpellTable.spellId == spellTable.spellId) then - found = true - --insert the amount of the main spell in the table - otherSpellTable.mainSpellAmount = spellTable.amount - otherPlayerResultSpellTable [#otherPlayerResultSpellTable+1] = otherSpellTable - break - end - end - else - if (otherSpellTable.spellId == spellTable.spellId) then - found = true - --insert the amount of the main spell in the table - otherSpellTable.mainSpellAmount = spellTable.amount - otherPlayerResultSpellTable [#otherPlayerResultSpellTable+1] = otherSpellTable - break - end - end - end - - if (not found) then - otherPlayerResultSpellTable [#otherPlayerResultSpellTable+1] = {0, 0, spellName = "", spellIcon = "", spellId = 0, amount = 0} - end - end + detailsFramework:ReskinSlider(targetsScroll) - --call the update function - comparisonFrame.spellsScroll.playerObject = playerObject - comparisonFrame.spellsScroll:SetData (otherPlayerResultSpellTable) - comparisonFrame.spellsScroll:Refresh() - - --iterate among targets of the main player and check if the target exists on this player - local otherPlayerResultTargetsTable = {} - - for i = 1, #resultTargetTable do - local targetTable = resultTargetTable [i] - - local found = false - - --iterate amont targets of the other player which the main player is being compared - for o = 1, #otherPlayerTargetTable do - local otherTargetTable = otherPlayerTargetTable[o] - - if (otherTargetTable.originalName == targetTable.originalName) then - found = true - --insert the amount of the main spell in the table - otherTargetTable.mainTargetAmount = targetTable.amount - otherPlayerResultTargetsTable [#otherPlayerResultTargetsTable+1] = otherTargetTable - break - end - end + newComparisonFrame.targetsScroll = targetsScroll - if (not found) then - otherPlayerResultTargetsTable [#otherPlayerResultTargetsTable+1] = {"", 0, targetName = "", amount = 0, originalName = ""} - end - end + return newComparisonFrame + end - --call the update function - comparisonFrame.targetsScroll:SetData (otherPlayerResultTargetsTable) - comparisonFrame.targetsScroll:Refresh() + if (not comparePlugin.__background) then + detailsFramework:ApplyStandardBackdrop(comparePlugin) + comparePlugin.__background:SetAlpha(0.6) end end @@ -1520,39 +1865,39 @@ do height = 14, } - Details:CreatePlayerDetailsTab ("New Compare", "Compare", --[1] tab name [2] localized name - function (tabOBject, playerObject) --[2] condition - + Details:CreatePlayerDetailsTab("New Compare", "Compare", --[1] tab name [2] localized name + function(tabOBject, playerObject) --[2] condition + local attribute = Details:GetDisplayTypeFromBreakdownWindow() local combat = Details:GetCombatFromBreakdownWindow() - + if (attribute > 2) then return false end - + local playerSpec = playerObject.spec or "no-spec" local playerSerial = playerObject.serial local showTab = false - - for index, actor in _ipairs (combat [attribute]._ActorTable) do + + for index, actor in ipairs(combat [attribute]._ActorTable) do if (actor.spec == playerSpec and actor.serial ~= playerSerial) then showTab = true break end end - + if (showTab) then return true end - + --return false return true --debug? end, - - playerComparisonFill, --[3] fill function - + + onOpenCompareTab, --[3] fill function + nil, --[4] onclick - + playerComparisonCreate, --[5] oncreate iconTableCompare, --[6] icon table @@ -1578,8 +1923,12 @@ do return handle_details_event(event, ...) end + local defaultSettings = { + compare_type = CONST_COMPARETYPE_SPEC, --1 == player, 2 == segment + } + --> Install: install -> if successful installed; saveddata -> a table saved inside details db, used to save small amount of data like configs - local install, saveddata = Details:InstallPlugin("RAID", "Compare 2.0", "Interface\\Icons\\Ability_Warrior_BattleShout", compareTwo, "DETAILS_PLUGIN_COMPARETWO_WINDOW", MINIMAL_DETAILS_VERSION_REQUIRED, "Terciob", COMPARETWO_VERSION) + local install, saveddata = Details:InstallPlugin("RAID", "Compare 2.0", "Interface\\Icons\\Ability_Warrior_BattleShout", compareTwo, "DETAILS_PLUGIN_COMPARETWO_WINDOW", MINIMAL_DETAILS_VERSION_REQUIRED, "Terciob", COMPARETWO_VERSION, defaultSettings) if (type(install) == "table" and install.error) then print(install.error) end