From 1c79fdcc0d6c6c934767a6a04e192b262ec78de3 Mon Sep 17 00:00:00 2001 From: Renia Correya Date: Thu, 7 Nov 2024 10:09:50 +0000 Subject: [PATCH] JAL-4435 Menu option and colouring for sec struct providers Added menu option in tree panel for the users to choose between coloured lines or labels or none for secondary structure providers in tree panel. Code changes for using jcolorbrewer colouring palette --- THIRDPARTYLIBS | 2 + j11lib/jcolorbrewer-5.2.jar | Bin 0 -> 28775 bytes j8lib/jcolorbrewer-5.2.jar | Bin 0 -> 28775 bytes resources/lang/Messages.properties | 3 + src/jalview/analysis/AlignmentUtils.java | 25 ++++ src/jalview/analysis/TreeBuilder.java | 7 +- src/jalview/gui/TreeCanvas.java | 235 +++++++++++++++++++----------- src/jalview/gui/TreePanel.java | 43 +++++- src/jalview/jbgui/GTreePanel.java | 65 ++++++++- 9 files changed, 279 insertions(+), 101 deletions(-) create mode 100644 j11lib/jcolorbrewer-5.2.jar create mode 100644 j8lib/jcolorbrewer-5.2.jar diff --git a/THIRDPARTYLIBS b/THIRDPARTYLIBS index e52f3f6..f41a5f9 100644 --- a/THIRDPARTYLIBS +++ b/THIRDPARTYLIBS @@ -35,6 +35,7 @@ intervalstore-v1.1.jar jabaws-min-client-NO_LOG4J-2.2.1.jar Apache license - pre-release of JABAWS 2.2.1 client built from https://source.jalview.org/crucible/changelog/jabaws?cs=586260b9f877e0954513fcffb0aa27eaddc5d0ff java-json.jar jaxrpc.jar +jcolorbrewer-5.2.jar GNU LGPL v2 - http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt jersey-client-1.19.4.jar CDDL 1.1 + GPL2 w/ CPE - http://glassfish.java.net/public/CDDL+GPL_1_1.html jersey-core-1.19.4.jar CDDL 1.1 + GPL2 w/ CPE - http://glassfish.java.net/public/CDDL+GPL_1_1.html jersey-json-1.19.4.jar CDDL 1.1 + GPL2 w/ CPE - http://glassfish.java.net/public/CDDL+GPL_1_1.html @@ -112,6 +113,7 @@ javax.xml.soap-api.jar CDDL + GPLv2 with classpath exception - https://github.co jaxb-api-2.3.1.jar CDDL 1.1 + GPL2 w/ CPE - https://oss.oracle.com/licenses/CDDL+GPL-1.1 jaxb-runtime-2.3.2.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php jaxws-api-2.3.1.jar CDDL + GPLv2 with classpath exception - https://github.com/javaee/jax-ws-spec/blob/master/LICENSE.md +jcolorbrewer-5.2.jar GNU LGPL v2 - http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt jsr311-api-1.1.1.jar CDDL License - http://www.opensource.org/licenses/cddl1.php mimepull-1.9.11.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php policy-2.7.6.jar Eclipse Distribution License - v 1.0 - http://www.eclipse.org/org/documents/edl-v10.php diff --git a/j11lib/jcolorbrewer-5.2.jar b/j11lib/jcolorbrewer-5.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..5a6e59cc65f946378296d5730baad76522c375e1 GIT binary patch literal 28775 zcmbTd1C(S* zurtgm#G#5nom6OLqR!02eJ-J!3`dqCkezB&`_9@?k@I;wPjMu}X;O zICG}W@dd_c63t-wMZB`8vr@ZfNdu)Ffx^tP8#~@9f!$@|NfI)HqsWUkev~NiClLyu3JB*VXfx>_L3R}G;hO4?87Q@DUy$N?ciKJ0wBEBq_WYAG3#%6&FM_LxhjOk<@BE(U{OdvJF|NH>Cp9y#aH2)uoVqIZ z{Adu&*ESj@d${CMQ`tVsh&hv_g4-3+4|*&l?h z_PRUV{|eE6IbV`PLAw(Y2xuQ32nhFo<@|rSK1B0X7k3QX4-=nucugJPhtM8_qtQki?g&Lzo5i&p0#J5!(VQJ zP-a^j8d$>hL8@rgzIXp4_SO7p`m47SCLh)Q?RRi7A%)7J)P5w)BqAq^z{;HBf>n&RC-y2}UT#egk!bOjzI5$2`g_318zH3P#mCT#KNX(Cw zsAxjM;V`npAsT_bA<2)Gu(*lceHsDc)4XKFyu_ih!y9b$Jo>TY8&7VZfjI9QalzhT z#>rjUL$Et_?zhayI@(_#^fsA;XR;?5(c@I*0I111RMbHL7PT|qMx79MiJ_zcU}~k) zQt>3B`lcGM#o<1uZCiOKM}b@g1H5WhlHs(;D@?$`{Xu$-SY{-cznRJKR9Q5=HE_*P z7Mj7`fQAN5O#)68<5kf%tIT&g0XxD;BPl1KnEytX|(O*S?&*lv_()Mk>&MD4(_ zel84!!)4Oy$Ur3hU3Cx!0H@%_gVF;%6dilo^rtqv=qkEBkz7C2NK6rGJ=Jm5Um&s3 z7(Wd!fLeA6nzpWcIb$K1u_Hc@wtauo<6}Zzd6n7xd?79Dp?SX`5*U43>G#MA0f*d> zK&7FkgYJqB#Yqf4CzP!s8BJnEEU*!;?0IC#vh*es`h`B`HXegyfZa%We(Nwx5tl9W zCI&y8JRdtJ(@c6tpbCK1yjN|hxr0{CCn@Wfny;6R zDa$k@BEi9s7LB!h6l!R7VSml9C=G`zlYDA$m~sqgCf}mD+a;Q#4V!^A(~A> zOu`rG(v%rab;e0VG~sr9uY;Gzd4mpBpHFaGxzZeVcg+)uxSXI*hKTe;lu*U}6sHLp zN|C8W0L%01g|`?)|Ffbu0QT+7;Acdf3nzi z%}qC?vFeTv=3vg^3G;(sC?jw&Y(kW&Tx&o-w8IYj z5jXN9Hjw!<&mGOmQzP1BQ2S8YK#5frDzVKK8$O73g;RT>eVA4+ykeVBM|i>X9OY_i zw{}c~djsF;c&^*%5J3VtTtzgRVfb{=Y$6Iw zU|2e-c8J6Y`v&Wu)^Kl3N20L&>z^rWhqaX#cQ?njzTjONU22+Xj61O9%Z_AZ)W8N7 z2=oP`zp~Wq-;MiGi5`~bNJPj_Y?pniyO!yylYYUMT z7g8*=RAy0*oTq-Xn;&?}C18w2jj-_bvv@O3PE!7$I-2T#a|l52!pe`D!w$8A@Qw6g z(BTTQoY`n*9dy+$j+yFnh-}UP=NZcAR1SqyswF8UsU1|xM!X@!tGe4&VNQCB|7uSw zkb*=X6Rt~o#mMZtIG_(eD7yi?xRDDAyyx1>_&cP1A^v;HciOz8*Zi*c#J}r3;{Qtd zsz2@B|0(!Hf7;tSn>mSD8rj%e{44RNDF2WJ`L6kz{HpCTOIv)k=EkDXTjr{MM@rDRt55V&=uPWb9ijrwvM zuQ+=fmuD*&$gk0;b#7`}kv+5=6u{{G;W%J1uFsmi`qk$^d7!-GVoYC@pAzbXA207a z!3w`3Ym0@adD@TtA{|&ZBKFgQE{E+VAdDn-_Jfg4~Ziydy@r-T7!fh(K^oADcpI5 z-9F^Mdj*=7c1({H2#7-y2#Dl=R=5A-9g%-Z{(re8M;F>he)(z3B9Awlj8iXyC?Y+K zY?!a*2rCFG5QbfE0zN{DBuGie#1dUyT};=cioV7PUL5@Ly!fP?oxka?|H~4Sg_H~Z$%-VL_v(EP|@O*Su=Kg$T5#6G+50W0yhdk-*gbFWkV!xGXLr+RoX)ES4R6C{MdL2-mfGrc7N>gaZ{&hT=WD^*#tg}A z)r`9XvJ`qetnx-dzn3_Gz~?D%cuAbfYJj#QjdjnSb_%?m`KX@2Sajcv<}mxBN32;J4{2W7fqurK-J`1+VsGL?-8S{LY^8qvI8PICV*5b+wS5 zCaa;Y3V=Zyq_)IFk0<#dvww^8rDJB#7>H+%mtNXvNuOGA@u4Xg7OYsOj_qAp1E3h2 zQC@u>^HW-#I0uT&25H#am{!`v2m^H1_i`;U$G9)NaK=xEGR*a0L3Hma5hZL^&^X(E z%9s`LpjFwtF+~Bca<{?%X8*;uvUy1c%*@upRUQPXu&!CtM4^KERo!0Ue4D@;cC^xF z12=xYtU487*Uh7ACM(ES#d2Rc>+s*)Qx&uzQe)2ykgD0lBHuebkimdOeHPvpfouB0?f;*Ap2_U_ptjR%zr{u zulgLJr?6*&TKX?gL*wgLG-4>G0R8>YRBzRZfXqo+BE9Y&MP>5?7UO3FP2`7~H2F$3 z(E?K2W`Hg3nkm@t53dwbP?Q9S$2|XjA+PsvO#r|+w~6u;aeELp0WslP_xoh+I_@7( zi5V<;7{m;9ZoXhE=^X>9I>VrCI@y|}d^EwBcc2BZ;ExALTQJqnKGpzOcxy%O&|{t# zUY>zAfNAf?X9)-AxnPE}`F*g1xjK;V`3f7a6@)C^6@I9%+V_2gb`!GYmOIY*yp0sm z@V>*-0eB?`?r`(;CD;v}lRqIqKfRF0C1de~0g5=+b&gs#Y0NppZExk(m#AIpt&Lw0 z*(Ky?Ol&w$3)P_Ez29jg=Buz#+#0dyy8fxx0EpIdKVsmQz$%*4UmzbSt8IecUkfil zF+&=<5A4L}{*s9Y|^G6x|KS8(jy2D|?G!!;1ynZog)|FSEr%o^pUh+!y z7TlV~3=zA2p24T^vp=v)nGz;9I&jN9sx7Cfb5!lQXweve+V2M2(oAYl{7N*=`z*K} z!08K_Bxsdvd(5l6cw~*geeCPc>PdSZ$Z$FU)oOx$7H!-gsQg?P#;{$n$|i8DUNXZ# zxGx(G`}xjD2jpga51;?knZ#%eEV##%Z#e)Ne>)~f5WK+|Cw3=)@KJMHfD=YiXAm}^ zqPp8mO$|(*#%NI6C>*p?UuDqO3%I+#NA}g-kNf$KK-WO)AZCD#61|RP)$sZp3aDEKMN0DK!# zV-bzF1Zq&}y7mCf#CNLMJH^m{Ne2*fI(HWOCRUCUSTMj1mi6u`D(L5!LDXe#ZVz9##CO_X4x}=(uY>;5r)0 zsb}qRr4>pzga#9DLw>$7o}eqvPmxCP{Wz;ibeO;37z)I-k-p?#A--PtN4!2z7#nBm z`BF#y@E(An^9!`xXI8?nq$))-t|+@NPzD$CxP7h6QAsN+px&05oj2IT4{vz7f-XUW zVNhd4IUc_pKr5AE`2{oheD?>jnt$mcOf|uh56I-O5eU10jB3ygQONT2Di@cdJ!6Qk z$20HE-c#zaVYS@KdsvnDfTtcaobmNw`SKd4glORJ<@1+OsL=)+9KxE4f%YlGzil&g zp>2EU@y-BARU^#l%g}2P9)Vs_7x0+4-+v<8b%eu4S$AAA93OsY4V3NhU39{x`sXOu z4awNFz-clK7v=_m*u)&~LB(fdh(E2eU(NlI(OMMX^P&~HA|xX|!Xk)_AKKi*TIu`P zL1M52uR6LSr#iD@=oVNw*L4U+iiulP)2b=y>tBEK^7b&;a(x^^)^l(_P}Wj@A?fr+ zX`R3PY@k^WjbqgYCDUB;s4NX+C~4;7v{hLxm9KA>wU_~$lIxaL44Xve(UrYz31}b| zRpT&)+9D_GH#=2n&khCm`O7w($`B$e0`jzH-TDC3&5wvjHPXf~O5g>>khD{zbV|&%SIq?9C1j#=%4DeE=(>;2PS{v8O@;)g+Vr8*lM zn54UW>|_iBDfzkzm?k(G*@;1mPT};_>~lH#ac5KEYHO=X)-EBVqpR3%XnG>1{)B{M zIn{L6U!;Bg8H*dfkU6EM7Q)WIPZa3`u=CVUrpA(Csl#3dfw?^EY%-fPa~Cq;d(7K2 zU~1T@XA}5iZ=^kg=BX?|jEk0;!b=&aCZ|a@^4V}4;#uMI#Go;3!qXB{z?@Dvhw<_R zvBAbs+&4=pVpX-2YDp)xm3Hv>*q1Aq$c2rFy^6b71=$%%+lWXZCE!ofPSY=bW`bjL z$TN&jjuSwlKt{VO5dSuEa~+1-(I67sYhr0!NW@Qa?B8Y5?kV{327j7RU7tyMb)0F| zDEd=_m*=S0P_-?aExpLNFWSc9YcRqj$1@1uq>0G5L^*LDeTig^^EUl026vv3axsDZ zPeNM2(5XpgBR*O{+a&$xpYDKyocSyU(;t5v$NN&RR^d!~^kTnfRl-EOs z!wVQvE`1aQs@0e@7oy6zKvp~syST!<(TnH?U=UBoiRc6UKSV$ey=`Um9~!|D#k z^lb}GWCGJCvJt^~c47Nc>cZ+y@->7J1`ORT7ARz87$?=v<1Cje8w1i+-z}C)V#ZkEf!QSA;n*xfRhe4AXeKh1DAQOv*>GV}jI6z8Nk+ z!tG_$8RW~XCG79nS@co-6V{zAVRSgHlJ`#^ooRj|K!kp?02pns(dsbHy_lPr4M{Ww z?r;-7sGc;KCph*h*R&9cXU3#@V8!Sj&m2lV0;Ee+w8C#UlJ^A)o+j|5xXT3Vut4{e z`3KCCT9Q{c4VHo^PSnsQvxpA<)lN~cL{<-vgt27)6k$k$k|%q6mxQWS6o$h8F50rL9^bE?=?4qtO>L!zoDCaz*p%bw?OGWZ51Bc4%(HutK+wWitpik#M% z!(Mah_Qqx--s|h-hp*I4HpHx-zr7FNqnad6c8AgL-lSdLrR2QZ^rTp29wRgieEvbi zdBv%sB{9hX4=Q?oTF5wKRhQ@Vs}&^>3=e38LT5q5t+|)q%$=0I&+OsnVKL}-`=@4x z5eia38fiy2W?iTzbgi;n1VYim>+1IVkF8l-Zp-TgUhAs%-lw+qJ@Rww0$%Hy_HU=Q zgtsFn`E8(&Zt+_b=a+^(_=Rnvk59-w_@!;sUc7qtk|&o%Uc4&ylBbtHd+>|e z5PI;d+A6%VLg`@#mSI|M%nLBKXy=@KCYa3Q`qR+)G!21Yo(y5~z!Y862XFiX7)mdU z--%S)29pNwcdQC}5q`}cgY)#V@1w!Pn3b+E1Yiy>QW*NMkPqFegJ|Lz zGx)4Gi|CTJDnGiXlXF;6HjRd6xv|i5Om!!L4~OcyHTK(HDU%xNmA(V$0QPiJuQ}=} zcJ-A2d5n^GVb&I7bG#Tua_k#~5T#Ru5~knykwgwuQ6Yj7`-(x0rT1fxdzm6L=`GxD zkPF=amCr-~%Xt#@%i7Y!v`ZuSc);8CgYkC43I?Y)Mc$#s84x3j=DPxa*6i;IYD1W? zRwvU728?C`vS^>M)z&?BtVt!yYM659HkKIcY7oRy<|?RM-7bI+!_TrC%7hU#J=*&h zANP*R^Sy$GG+F(c)I-u#6$Ob8R`j^p26CREJ3f^BAp3ntgd8<|cN8wu^wv zVS)^64Sm{=C-$ZJFrD?JGjZTfR{Fz&DbuV47)g1%8YH%s^WVbBmf6l9hFus;SJ|5ySil zbu-6z?RM6t-|=Dnk7hBhdMHs#jzLgBOlu%m*p$=kAt3J^F2+jJH=d>iVqF`xK z{O0r_6?Bothm+NGa=@TC@6gr{-@l*6aBhHBFafDFf6PKc##d$&$g5>Y7&KLN%E~7(45Dx=o5w$0R498APppqe;5!_>XCV68Co`S7sJ z*<%Xe+j18Zm`j<1VXCd5n`UI~F>i2S@3BedG}wvw_0~rQkIgjTp%9C+8oIQ_vho{q z#~X8{dd4)CRC}t+I=4_axTd02gTX^q2Lrc_lqU{+qee#&E@nl912OUyW$Qc9VfSr! z`K-Q057ScJ%5^=&*K*%Nwz(co^t9kWu$kPywPCm((74aF;k+K{-GjbBx$z5L#$*T? zA+i9~7)-lIH*{2O4XOh}t*NHfosD{>VXEfU9Wn^s0$Pgd88!&iBGR4qx=91Z9CmAx z@L}IrUD2#YF#vTRsK$9qtXsq!nZ0V-wQ%GRdVnz)TOLYnY;g7g&1o^Z(EWs&GAcCt z9g!hpgcOz12Lo$TG-#xqJV=dh3dYr3=lCLMk|Lvx!`jvL)4K0UU_DiY-XlSDv{*H#1C5Rb-A4@pqm*RdKNk#YA&If!iV z^lAbNRzU$~f5au|m~oImJ-sx5pM>_arsEb3&yy@Yeb@uRT;GR!9*k@J&4t4Ml>&Er?6nF8v zxxW{1yw{8(5v8yAqd({y`uLyR`#&|bL?l=F8P%-CT!qwVX_|{J2#k1%Tj`D0yBaQ` z)-%LTsk)Bie&b-{hyRYn%8?$8ZS?*T|IBp9LtICHx0W_0`q~9JN}05izd#talf0N2 z9%Tk`gu7$N?LIf>2yuCSs14iwftX!b_T9F*^TS_z8P#(_pfbe?gt|*0dZzuteoE** zkNV)R?<0JoH1=1l&hNX(!Hn#d6;o5JZ0ftfH%dZU$8Gr7SOFVEAd>$(x%Fxi?;bHM zMKlVe($IIYDRl5Cu8(r(MOtUz$+zLTNosZvD1p64iO3at05;Y4U-RUG>fj9DkZnyD zf$;9+9ComWnqmIqU?0BTQxNJMXXt_T0I^fqKKs+R*&C+DhP3KHpp&lj>y-;qxA3fVDNp!c=Pz_&L=yDnAa>+K%-u=X_)`z1cOu4EDM) zB1if{dU%HT`p)$lX1q&e8jVG}r_5bke@lLVI_lk%6aC&}D$iZD-h#&bMeB7-e&~~= z+VC%bcUEAzWjIYCPucb?@1O$t#eVU`!<#23IQBv~a|%{mQslx{iuk8G z5i)?tDxZIJ$GAr*)_p`nx~U#j)-&B*uEZ9}!L;aB;GGB67s_h4)2egC2VBE3syA~3 zW}>I8%Y82Ced^loA0PdmGSA8PjJByfPewzM$w~HWa5={ggL@6bFPRI2P;#_4PWzDc z?v!vHi4ctKp>A}$3)tWv;)Q7c^zSuL_Q8#-NwA}?Ew&=>JYGD_eAeGO+6Eo$$$uLV z{iSiLOBblyAu`>LGToMS+sn9`c$BtyA7ZsvGvOQh`EB(tiPavb z)xn;}VSUjH&G4Rpr!9%i?&b0BUE9@e@BI3?nnus(kwU6<7ic}Q0XOe_Zqu+bFkX0Qx4rN#IOvmC z{A{B%;sCs0OLtt9mj@vcZ!+ljXVF1#Gw7>;!N#o=@^(gzR6{~(C1XUEu#0COUjimF zu3w}CY-IVz&kmtMpmHF7mF$W~m{B6x3*=mi zD0=mpOksKtdi-f{&x+5W}6A$Ucw-6r>)ENpXgsyrRn1$2#0J|3YoBv{X)byz?Tg1jSPGW zq1n)%K&dRJ@O%rSp=b;8$TNmfpRz-oB*9469S(^ph)mhT8384#P$HkRE$P!|J;193 z!}d!JumNjCqWUESvrx6L%)?O<9(YTqGi1~Ob*9et3s^5Vs2Gx^Tf;?Zm z=AaFQCayWS&^fs4w4h`&vd0vOGx9%UOA}{E=A+GRX-+q?_vop%5*sbap)c3hlbvko zX*czJX2j)K2b;;{R4dC`!sZTz){&Z1sCsI`W-h6MD9i|%BP_^sCHT6;k!pB;)8B(4 z>B6QE&a3-rm2YejK*S^H)3_(AT}i3BB&uN~%%~YsN*^+yUCZ2hWp&?|~BFB+v?CP5%!&KgpBN2=AREpIv)_K!e@EPiifpLWMiNSCr@(0vr z9OBgV2%eM&W6?_D?zBdVA`<12k-wuY*+|S&O-TZ#MZ&Xs57Gz$^LPa7hh>t>rtW1A_X){(}Ek^+`rlbLUi-%Fy_7n_hv5PQ0`6>pSFQOC$1gHjX9Cjn_G3@r5; z*CTMlF)9n+EAu{i=Tg3lxWiJ030DzIwhUwuKVjb#J%Kb*K$kfeJf~(2o@c#82Ff@r zd9aZ_U1b}?`)(8Goykg$J6neHI*nE+$qRgWj+IL9O>>UDEW@N|iP;0#zV)C{^HV_+ z*p34<^)wf5UvH}LQx|7mOCI=(XH&BI$t=HE7Tkh(lL_VC&U+LT--=`!Cloh?)0IkN zzE&SuQ1=EWdd^s|PxeGfrIz$oy?TPsQ_P`&&=&@#{?(q|(t1y73uRTkoa8h03&4Vn zxaDKUSU8cr>AJTY@K7jknG!vMBw{G3+w|-NOojkxFBX9t=4B6!r4NlWjZ%sm!@H%N zYZKM{BK8P1@e)8(dU2SI!aMt%_3nruD_$Yntwf(O+Pf+zmLE6kC;>w*XW@Ww1E z$cV-?DsnMTMWrX$o~>u4zryK|!SjSCGX7M_pX2(dM1(bl6r+M(nzP!j-w~wz#MhLhDz$1c8RBv7?1ZqB@e0$fpI~HQE z!Bl&=_r!&GseNPkx6kl5!0GYiexMh~MOE(|O0Tfq^uK&gOYSri0S3SE3}k7d#+fr8 zt?g6#3U1nxryT854rl797f=Og^2nx`2YqDI>nbu)duiT86pPk)#(#NI`^u~Q#hG^ep`s(^SE5}fEAu6B zyS=$xbvpLSQqaSj5LvMmAA*se1@>3{FNtr?S;sE1i|2~qhG1+MP1`}AbvVC63>0U? zP1VE5E8<_}1JHs+`qyh5#QrW~woldN7si6y?WazrenEmSHxjiDdP^VN((+*$@)%~3 zFE_Q|NwQw~j*SAnD-njmHaU~uQU2!z{vtR4?A$3ZM_DJ0O)q~b4Yl}s(zLkylw@S&b$@FAHZYc`&by+P0j6tP+dT>SdLQ++@nww&|tyf}{# zvJb+v(7VXMaVayqvZRcOzLb<(+TT;e2lM!u+{qB-bW1}&n1!%bhpTq#^#5}GjWajf zS1WNu0~F!J3~hdGC8G@)4URBT{Jo9dCqw|XWP8Y!OnmO{?8&Wr<^$a1E*PwO!Vh^z z#y^u(d)I+lt8`S2bRuFlQZlI||g2MAC(twjSR) ze@`8@7k|%WbGF72dWXhm9RpsA1YUz)u=*a`=M&qXtD}84!YRu==y~Z0YQr32LmJxg zcSe;eN_fVlWd*0UjG6J~IO!pVyA1(mOl$_XnCjQRkR7su=Zj@c}snp1P4PRWOMq-M{DcBPKV zueeYl2&I@Rc?d3zl*I;;S5MpfRhlU~5kj$1V#t8ZaA^6H=QS3Q8i+#lClsh?*Z9%BcWa;rz5jQg4m5Du5+7Z$#M z##Ts=+~}sAg5>908!17WR#;oHT3KEopR7hSSKZ#utBdE&pBzs-+^X*&+!$;~-x>hm zZbfHiZk#?r#!+w@l^TpHXJR?3dsa_MYl~jGry7(}rv`0G(iQG1($;hG6P7QTcUp4w zccwN8jm5vg4@cU20izV_$+pv#G;f)+Dgt)5Id|$+uz(H@3oXde$FJrO`A>`%-Ov9I zV@gLSxo6{>G1UYL1jPP7i?nVC>hz9xwx498;9z@nDZ&BKdk?QIlnMkt-Vaq z>bI^KlPTt6`@OBhrh(k5qjV>*s+R=4j-8&HY-o=V5;1El_`i}#46|@)D_ySUZi9E2%oiHB50v!;njM*5FES z325V~SjmsRjTCTh$;||2@>NP140DgX0>osEtAc(FYYCe!N~P0GVCX-rC8r~%b&5|d z7nm2?Q*sPZxy^vOvYE&TGnPJ z9gM1;J1T3Gm-CXurt9m%wT8%(U$7|Q1{o34rxkaBnqSnrv6M#0>pYBd6%P(!8{=>! zda`rFk6@I_vPj}A)(t9uBsNF$m#{jcxr{S_R4&J4rTt@z1 zHdSreH$IbTmK84ZJPI`Z1dtdEquXgNrg^e$N{Mfv4UTfM_#w^STF0ZcPNHH+F`^QhUTYuo^s|ubr{*_DNB4MTY;hpuS4X()d)*CbcOWY;BUjAL2iU(;xj0`E z5thHh#pVAhTv+~-bf;?j9WF?I6cN(Sx$-*OE%s~W(qf81+i1eZ;JcN;Ni1x{a?jg-taHtA$S{CQyblUtg{<&2HU-$Ck47=*fwD0#!a!-D=-Hu zwMJ#3xa=EbYMW}uHITtn9BwGnC`mZHjXqNxndjx#ivcpL+*gV*6RQHtH0()ZD1XH) z*7(UE)?`QBLW5 z-N0S~+kc=A`sRrVU6@H*IpxSdt;$cghi)R#Z@@GJdWHAPwmDLY;o=)vOfW!CgIHHK zN<2L8{B%R672f zJoY4P5stq)QR$!!%AVD0puL#b4Lsu&D(*$*Wpuj55A51k_)u}fO<5KP=4Y%vQy&k? zR*%q!f9z2{$OGKeI8QZatx>DoQueSbuI5~E`lv4L4U_Se1R1M!IAO^wBPImb zV)^ZHQp>;ym^Hg~^n_-OR!JSo`EDhW`Ju6czhWZ*0kfZr77w-$So600@o*!tk%w6m z!Umbog@g%a4Mn2JkHN}zg6yR^au7^6nvQhxyeQHn6OF98Cu^c8`e+5}JXbRJ%2}Y? zhUH7VCXQ4fj;5fVR3^B5_mXb-PfpkoTA$m*q3^u>%mqFb**gG1avN?Glm^_e1O+ud zANorv#K!hnWyv7YxJkT?0tyZ;0>dN|Sl}@Zx077+skDLvbx9He2>Uk^Y@N^)Sk%++ ziiU<^=txeO%5@n!c+o#CSEiaNb^hLNmLE3d@cNwRIWJO6s`z8b<4KD17CjfE1Zpz=PV+PY1gA7NHa5%N+9U z4K847zmW}0|57Puh}sV)Do?~CgyBsx^UemN%cg9#H$9)F>9%gX& zsy(T2KtOCbKtQbjr}^t&K~|y(?SpoR{w3Jh)uc^93=O6&1ct875g?=n7FaHg6eJu^ zgw=3HhMkl$ZP&?5Y*kg$qibu;=>79DMsh?W1U}QN?eSz+y~d(yX-z}7C2gtcqc3B1 z`UprCwy*m&*4Dj(%?<(RvxHK}Ch|L+Am>dKRHdtGO_l*pJ7XZ#73a;b07%mG zh%l1$00VI*ctqNHQlobrYQn|+u!jR?&^SpZ%r1C7`i=tVDRl2RO+50gnoEFFyqgdy-FdG&SapQAX#*?b zt1+s;9SB%zse*!KM{yc+K?H^5TPf5&w^mT;cUfA_lKVtaDYq|gY7M}I%6eo(Rn`OWaip#;VS-I zDdBZ)PTM75vH<_1`4ug*l_Wuiix!-`;WY~^pwtBuKKD*-4LqBUpvP2}&e2Mgpv z#hUaK6NODKGCVt!<4SYi2Oj~v-gA{$@v1+FCAF2>I>b;<^TrZ(yIawQXzLfno2N`a zmT3Hfve5WSU&HLNkrmQJ%Pbr=nenwLObwMi-`-8$bXIE&o)d-U9=e3Pj-*_I&c;M2$?)KhU5jjn$ z%e`x}E3k6vE838nijkt7sEjaR_XxSUJV4Rket`YAf-YUY_gdxWp(pk0d^YMjZ$u=b z>&tk6K1HRW)s$>?CmFx)@{uW)2PU(jS*PXefnzN;*`uazr{IDmVb&Z;PRp2xUikq9 zghOjYja24|I6w@?w^WVDWUpr&OT|(K9S>C-{A0y@Pc%}HC<$Gz07u_!%1u5i=klV# z+g7#Gtdja|f=#uMWiuI@C5c)uT*8EB!OTLZ#(DlDmiR4;MHa!ZfAmSgtM;XSsHEuF z>y3?-kAuw-FI&PJS9ah>RpG+un9kz*adwggYel|+Y$Wg$&87{wGaBAcfUpzO(4XOV zO4SV7FsgLQ^3Aj*;_$16x2o*)e825C=&l5cSnpDG}y7Cp9(fjtedZ8 zW@H0}w@?Zf7PDr|iFR-i)c53eGBJNx6hpJTS@?HG^pmb-Qt|E=PpKt-bDR{slojC+ zT5|k!R|}Kh47&85dJDp&T?J9akjXI|?A({vE|%`pI)mr_lRR{A<7=*67qQ#A?MqQI zOioA5Ei#~@Z9eX#ienl=EeVhjjb%CfsW-S}31I$f%XUkyXS_EFHcvK9!LStg&cncI zhTdxiXlMrC9(k6t89TfXC-u&!t~%sW)u|sEZg~kX91yVN<-vPhsBBOKHes7fnv3Oj zw(p7isAgVh_d3wM?)fVF*;Yls3(|hPHo-}Omy#rjy-8JuT(T;#aQ6LemR_r`ot@Fr z2~Wm$*6o#sqfpt?^UsgysGi)+ouyIaKHuavJ{vDH^++to@vc;?ygW#9mq>WpTGgR7 zbA6-Vo+}$uFJAGeduxZ9G_Kiy z?yB9V3tcV=kBj2a>iP?XW@RTG95Ic+tjZZAR8LLC9w)_dEF-bbr4~ zc7)w0-sP?x2ny86%808FCFAqt?&OElgHvC2=LRDrqu-?Tq-D$v-qj2x;%Dbb;R_KN zLl={!<9roKe$XrBw07yq2&oVA$5 zdHoRb1>xcL_LBDq=_S*Ab?mOB3%m0m3X{G~#G|3=Y-}-yQojsJ&mKyCL8|P?uB5pZ zlioEJwCAkxh5GH5$>9sd+Mc_rk9_-yX#6ESg)60>&&4`caEL%rg8HWjj{n7f%@ONAwTh)S=mQa6I2JyJYKJq!~$xUhhj&JrgG^Bs`SQHmy~Y9(VZeP~s1kh$t_ti8z9!gs5_nL!Zj^&~GMn-pCmN9-Nuo^q(G3 zF_Bvb1!1r!(~@4{9$l-zKPQmp#P8r@`Bw~a2l-$(6SvHNkI2)2^rcIjUO!46cIO}l~* zAu5uIGw9mx+}CqdF3ry~^a=j1>d*`JhutFA5Nk)pHPXuWyJdvL?e13>ZyN8RzL0_Z zIdHSe6N%^1i-zrhQ4Z4A8@4l6`qXiYRV1ZbXNJu?tW3sZoU!P$A^zT$_6@wUwltHF zYln?;GnsbcG>KhKUWr&TY&54_f=K!ydG-Y6-W9u^qG=d0e^9Ug{YR@9xENp2uh|a> z@bhlbG^-;ss8qa;zQL5+jJM;tBlLG74l6L(4X9dS^v9@$TAg&2Fd6M&%SNpGVglI% zCA$6OEh^at?NnlF_>&~`@o^cOq#_570`Pe<)buV*zK{fLf>ygZ8!#Ujq$ zUyLN-p2tg1Qz3%nwy_vc1XFcm#3ng)}vo11&N+PpA%l?+$#}0#5 zRc)JVW^U%V33q0F#zIf^oiBMu+LDrQXJjyA-s8~bR785Go0{gAeQN*tA%7@w#Vug!kx=YlkEfDef~%Ll&83GJ&Op5%!k1&KDSh7y6o#bGghtNx;%1iIs{9cMe(2MGp>HNXGYr zby9HUg1YA|?|1G2yL|1!M_1H2=hZ=nO|?BKD2Air-r84TIv~R|p~)|u*}x*=jmFvp z+aY|rPW$T5F;-6R`@L(W)L3({gxA75*`f!PDX_I1C#zz-MRl%~;?UbyW=FEUGoS0U zeR}f2aT!Li1U$?EJX@ckcK`0@R(sTJCL}|rVMQI25;dFZX_3;pot-)f3Axv4Wo(LYt zO^?xpxQo}oW|as&N?v8~>^r}#8V|n@vRPssBJw^j=$b!J%t@QaJQwfb@|}(mGS05J zsr6mA)Vu-=RwR4U0(rC>@}J|{V~@tKBT%T0F#+()7!*mRCgry?BMSPHV;bG@MOYCs zn|kFui(xxvCTU`1F4K?{8w*F{6?&GWZ1Iru#6^7bQwi;YHI7OB4+ouUs;Fw$;C0qKCRxMiaLCjBzzo%>b~>0Vx9x1}iDwKr1I&IZu#tuD&*VbI(B!B6O!*~+bMV|!85QqaNm~S9 zh-LFhRL1HB{Gv|n^{X#~(KC}wt+q|;m<@glu4UvO22(56(XbWERoEZeylg*4O4^rL zWM8+Sre;l?w^p6zE8hUUkJ@lMmTYO1ySfP6OoZIjc%z+j`lcqG_L+hC^-*Dm*1LO$ zlSIz-9rHd&GtEY+8mm~~OM;`xt)n(Qm5C5GZ{?QsZMN*pA!%?0uisCxrda)8@c zQt%l1GpJP?TFmfW^&$fsdF4y=LaZTg3 zGk}#lM!=fXuGiXb3rCf)M5W?N+GZRM%!ppQjq3;(sxoVD(jN7{!CG5eo)3n@l9l6^ zTJppeTDM?(N#*L=?aY|ZOTA9LE8$?(>niIedJF_~CASscegICozLEz|!k@*L8;w_J z5WASo=uu`NRtxIl;y*|Tmy=-&QE zf%3`ZAr?tK3hy1QyGt)5Yz7kYJuEkm_?ejqw_dP_wV1N+Ktcl?Oa|NP4(uK-wtHB) zHt_@HWYI>qb`ciZ&e2{OmfVVzv_#Y)HDE5Yfps%DHJf$FyZkMeq&#((+DTLt!O`f~ zaKc;%9M^MgVXQ_=Payfker8K}eqUG#A?SWKOCCw4oal4i`|y`_L4?XLFj7>z+Q<&1 z0wxeF40N(W_T_k=wyo2>|}4PkDLbDH6EwcH<>@zD<vq|uwy~@$9&-IIQ-YCw*@Hjqp=dq@=swYNp z-l||zhA_d`<=Wn%lDrF(p$rSDv_q?!<4fk#xwk+T#Rd*!UCqS`O@ z*r}HbS6ip$)wCrD^$ot642&vqlqBm++etMB70C*2ss@sTf=@tOJo#tKf=BZ6vDNfz z>^EX*8i0ro=-eY9>b_%2k0edW05C-0buMrB=4!KF*8!XkpGD!u6gd8QX5f(cK4Ir# zytFVlPls3xn2U+B#2exj1d0fC&h!RrbVZ;?QmTx(b_kV9=7!vCfcYD>I0#OXi9|}PR%eRZII)AkoK39< ziQRF8=PUFpjgb~0M&k#6_V!kfVLn`c#B;^XJv8gXc5(ig3HxO&=5%~~nKSd)&fB(k z3yC9|F?;c*lc+q{D`)d}(y*(2nP39)CDp00sI3m_g?bk3uTh=|ENrBjTia&d>PkZT zIu}B!lgd=IH}rUe zjyEtS9>wp**$P&*NixUT22%wV#1g8pd5J;}TO+xa7<12-a2}ovH-(o|axn4XkFw9C zw~N1GO;#wtu6y^za(k`q9rOHzb1Clu_srE|*NcnW1G}09x!7?3MJh_PGKn@b1or?N z?s>gD>`5fI0M?=??;`V0R_ZCr6upJxjRM5>Hj!JUo3C`% z_p`p=3VXDt6bF%QnYQ5*J%!A`EL*&M9u@3}oC*APCiTw5 zgd-;&J=_FcJaI8>gJIUXrD(z6QuxpDU}WUS`{+=SR0J(bM*R=u`P)(^z|_J12U~`y z_N!nkKNjTaeHqKEjMRx3h?GM^K`7CQ7%s}n`q)qen)a?f7|ce1MqrJPwxSfW3#j8?dGjVf@JLbHJ{!u1FeB>FyS9s8;i*EvA23-a1fa^gAI9xk?9aK%lU&1( zqL+Dlv0c68{X$%&Hn7DDS_4E1J_Z;Slm;l#5Lk;`klP6GA{xiS@32PD&3`f8;xtXU z99ViPfsmR$9KkH2^F~@aiVZ%mt0-{PMDNW8PNOg9V$s7PR*qzO(dvjLybkoDb_(j^ zgF~hhMk}sjG+T<;?=qozhQ-gR2uy5HN4`mQ-Vz9&NMi2$*|C>qz5E)5)O!_tN>Sw* z?2^>QG++#Sto1ZA0KV5g?j7|3Od)_>(IvGIa6Zi7mBJe&)H~LxommJVN#69T&PBQw z5q(wY1p6${cZP3NZ_r3=zwVqQVUX6jaYF9E0_A0G6ymc~Q??DTK*_hg16QfADfckH zz#!OJjYE;X- zq;_7L>fO<*#FTvSEO@FKS0iCfj0k?3_wd`EC)bgsIfsCawjQz(5)bk_k$SeU22?+7 zc(wJuq3efghlzQS^aGQEA8qDk)IJFc3hsZtT{s8Y-|YI|HKQ8g`^&GeR#>yfhA&xT z!Q-r#Jw;RneR|3nx85IkZQeVbLtJ6=;k_kD10<5SXD?(Z^*tXzg4d z)5&fxvmXCcC}_wUqK732d4<}NwH*J{`*26-6{g|nff;%o=PQYY4 zE`{)&c_Op*yK26m!%eg%^KQ&*CpYAyz!Z1brE2gn4vi=H2!!&Je3 z>Lxn41{_|b@r5vOX)4E6#S*KbP8_=WwQ0_^OWxFe z!uh18H$*M+8}rW7+=^dcExOe^QL@quH(epXHm-WhhLULEZcUrXJ}4g*S@^hn##Xw; zA3Jm^+K_Wu@WeVn-&!S>j*fZhF>x76$1&pKaE<88Ov#rUwZ7{U(}? z`TfrFu=uDpP1y_K_`F{7Py|4*#s=|tYae7DeZ>EO$;)puQ=pQTa1?u*(^T`4HybVRf z@07sN2eoZt0#7qT$#x;gekH3GkOtr*V=XYtfh^y(4A|~EC1CuJ=vo83&kFY3sSjF2 zMYBWX$_pg6mBSr>>H6mU%{&Y&1&CK0!iTnhcUu)Ihf;U666BlN#IM@L|wfFwuIF zi~|#kHY4JjdqEoJVM&1w6{IhtkI57J0c>xT0!;w z2bwC<>*&3XX{K$~MT0gLPV6_)%V|a_V2W|`gcJkafbceBp{8+S@#x0ra`LP%^c+Gs z;R~0O^CMeF+lFcDdQSJfQBH>&NZ4!WBU;8=Hwm!Jf>Z21S1D5YfK25&$h0Ib7o4DO8TOZt(WR zGeYGkq>UabM|&QFgLTqGLUT!xmheNo5SC2ZaW>vdzibk;*?kUQ&h7<%}yjxy8LR#kcWf zFo9z_?|W31Z6`$fw!*}p}5Xm%<*@tB&7Qk^3#AcbP&X_i_kGa*~c>Ffj2~7d}k{o zhWJf)qp63~%1DejeN5z{WTQZW3|h4H=y$CGV30$u@0R{a&$-lI)~QCI`1O?#<_jZv zSZ0n7sCpl_HYn5U6^c-UmpK9W9U!O@WlmSB07LF%H5y0@UBvoMgM(+}UVluYOm4=G zogko52yS}A=Edyj4-jR^Ip?*E42~i+=UNjZ1-3{r1#GfC!HPjHrJK2c#;MU{va2g_ za=s9H2Vi2T(IRtoSQM@~qJKWFQYXGdB#m0~Q>Km=$3N;Lv><+z)ZJ z^q>pI!A!+0FB8MDqHH`8;xwGrIF>j)8@+q*XZ|D#8sk8P79mA@^v`K9s%B1Z&^olx zvSj~ApI08(V1m!NlO|?w-$tZOJ;o-_I})RNyu$6C0*g?{UhQPs)t+b97>if+VF9-k zx7%t|N@n({Z)<9cEZNEY+7rI=q2>Enj$olbU~ro+-@{z9t@3QxFZJHmvArD6O{WH)o3wyJyaClIksb zV@uRkQV7NEi4$&ouk?XTy$k5mjI@VXLJU;RX`Kv^w9p~iDl)^V5Eg4su84<_QQ!Iq z78^)pXr;BMd{&eBJ%^?me1USPvjtpdoXBSI?)WPxhoU#x|KLznD2FPdijM^y!&V{J z*`m0vGlA2JS@7g5jd1LMCu{RqAVRdkb4S(CO*h7@>tw6C~}bj6HyDF)3jSe(mwSN=UPoQR+6FvTFFY9#?9e1?rNhG zm9B1enoRAMx7lE(M)YBOZ9{ROZt>K{cH@2%#uEj&b~uDuLlF@VJ%^DGK}E1vwc08o zrQ9+5v+fs3>dqv9O`Tjlz?bc=MzciSxToub?}T=#RXa2=@!JlXrQk4{KVV-c+3|DY z@CAf-DOikrcDhxOX7wnqL>GlQAQ&pw#040Srn|H#H}c!5eFZY4dl4E;I>u76$p~?A z+ju8R$7$0P)kG$9C0v(zrKe^J=F1KC-PVsM8qr_XabShBs07xwjc~uBA5syKf47xp zmD=Z|Gt-0o)XT_P4Me+ibCP8@=O9C6ruPwdGhcaT%p)lCs zR{2svr}{D3LctWU?;U?A>ww^*N(y01_G)T<)~YU~7P!CEG+_F%8beI>G5glJ>nk$h z;X|?QORDWl)8^vUT<1@p%Y8Fy=JT7YzD@XUA7hgUcMZXjPKmxI^s88f#&dv%%ai;= z^I$jVF0+@%x+JZj{f1_%3S==5~Og|WCwBBye;{Ginul{;7er%Sfq2 z1(ZuUpj_$<$mdB&sFAL!?~oTTosh{;kGD}qIbp1?(Em^Ze~d7_yCm{{BjCh+@=@+R zmu}-CWj+C=bOu&gf!OG?WoK&jBo3oTKi~^ocHuFPQ!=!lx&H!zb}~9m`IQ~ zM-bx(b)U7!?Dl*WiFEx~?3zA`{O!}L=T*}{$EW>;OB_Nqu!ptmy&vR@+5yC7rHBZe zzH)w3%Ubii#RMHOS+A&*;;kU=q#tBybfzO2c;WrPAad48b z+XE@^rv(CNaoT9vWJ-~!h(S^iynKHYQ+(Pr{0wWeD+pl;|GpVxYjyxCr~XuMMR;>% zAPi-98TC}hFuglVXYL5DE7$PnNWrx%TC&YWfhhqJU&QmFmwRuzb8-*Wp5r!!P$jEf zL$pkaSlZWAO=lc4Cq(w&*^+tQn(NKAT#-f4mK;2f#HeLC+I$^gfWrp!ep|l-pjMxq z2#5#hRM3|VVGRLXSF8%kM@kamp1+6-i?}gOi%{XB;td%auty3?GEyAXLi)Iyze$j0 z=J)WalgbDL4Sa>!AR87O8g0{Kl{D%IY(+XCJ*9m|8~S?mj(#S(^1HYlwsW16d-tDsk5Z^u zn>zg};ggdjgSXodIN!IF`qnY5fr#omgsS}6D$&Md@1N&mkuEjM2~uR&;)9QL54>kvPyd7#d}2h87`yH7M7AdyEaGg;dvg(_~;R# zx`eJo{p+agU7Tzg_%mq?O(!FY+Q6{8fFR7W$*ultct~XA1d(Tr%62;{Brovb*(?4x z0$8Gv;iusS`ayJ~q9-d?2e0f@hlYxHR_}gi*S{9hhZ5}1Li%>b?q>EZ|9tX&J@Efl z-T!eiw3b9qzdk=iGPPi1=gYRv?iuWA=$vXsYyyr=3X1k}^rGQ% z;=nD8ZZ$aJ8_qz5^z1oZ07ko^~>uWML?j2C?&u~24@v_6jqQ}Ow1EU^C1gWdZEA_h+uQ-;pyHzx)ois;P-Hfx%17L1H56*} zPS*s$;n1Ch{qtS4Fh!-%Anw%=t@&7FQTK>Mochj{pdd&ta{hR8dszcli3^OtSgPF=(On3PL*1;!R~#{@#t$%(F`%)$;{D zo?G&Xi2f(HYU$151ra*5(s*U|d}>|y2^@g#gYGUm)5i()2ZGTjF<)I`n*Pw-2~~Uy>!jZe*QqCA%WzJ zW3VI6J4pr&x7e)=R9FCYkJF7#1x4(Gv)zfdR65z$%=|D}yCSA2oEc%RI@e2s8FdWk z@Jgs#6oVz(To&XDb&fdcJ?ldQiN&r}-~|c~vWaWNJnOF-VIVo4nh%0n@L^~8(XVxw zUApKq;LMeJ`}{uX2l=>!Q|a0nli{J*#FM){{`P_a#g;oW01fO)lZ=2Tj`V529EJ{& z&uGds^sUj>0FzNqi-=PtflG#qP5-L3{AfM>C52F5Cd6{FB6 z-`5_m@I_`!%VsS0AQXHV%1EoV=f-kQWq}4*j5XLDv$T*OkUYQ3nW&ssi;81J@Timt zFDXEd^ZWd@Ov$|-M!14N(c!DrmgokfmrKcVXNNh5!qoPYct5+Brih5cFQPx*Hc`Rr zkuAdYjiuK0UU#irU$1Mk3;TXAgD7__DXtr~5Zm;9Sey^&n|<`HXm|OhmWPORETK4z zOhAWJni>)l)Kx(%Qyz^Wyt%q;k>$_H`EqK=?!d|(iJV(*1+lQ+!eaAqEsa!1S{GFnt zzhE{GUcb%l^l_wRfJ}*TN}Z=7wrK_{3c53TOYT&C=`_k9Yi6i<#tlrwtAGTY4V}o^ z95MLiBGvKFPp0sxhRhQA^7FlfmDF-8B!Y=f;}$ud)u)G_rdZamI?K1gLEeofwMv)+ zVI~9`)t@z<2(Vfgby?;5dwgM6L7q$b;;i(DXMNFehS3P)tGN{YJm;s(deC4RkI`I! zE(sTXKn0mUyEKzK8Cf*mi`IERDb2i6xA0l~?|RQy7WDPHvHO|7U$yTfzkPMtT*Lg_ z*}5BX#$>LS)*M{C?ZhM8t-88k>*>i)JQRkFz2Yf})>F()s2R@?ZmdkeEuE~ywAW-< zZDj_0kd!W(kdMI4q0u_=9x*nlk=h%5{6two+VR;5Y9YT*5s3-f*b7x>YsAn>nt(?|nsr2Bf~J z*uY&mzxcd674JU$sT*{A+%$1ge!jN#`P_eY-p_;o^tJONvzy#(AIt z(h%=322OR**n%x<-|DCjb3N~6tjIk`d5dUIhS<)3P9c`gu21@@JIU?mmQ{ufM%y^gZbuWv zWcWw}_{FDNgsyH^mOA@RkT+W;Gh*ffIWn8Fh^5;O{$J8(bV7@W%wVf=o}`S<&*m9^ zGP<@1LRFG|0E_eRpSu@9#}7Ro!+d{n|Nh@g`Dykeh3VIBM)xP*A9(?^(7*pR`$KP| zp9p_#D0JU*=*MyI7zF+JTL+?_W4&*o^!rKo@Ao~3ejN8E8_gYQ z=O>gobcytDp?)lg{tEPKUHzXx+Ni$){acm&U*Uc&2>%mqAG($2FZcLAQL#UkhyNAt z*G;TH@uFD&2Jio8OY5&Le%<)^(?ugRAMYEllwb1{e>z|n|5pe9khS>h1^k*D_Y* zurtgm#G#5nom6OLqR!02eJ-J!3`dqCkezB&`_9@?k@I;wPjMu}X;O zICG}W@dd_c63t-wMZB`8vr@ZfNdu)Ffx^tP8#~@9f!$@|NfI)HqsWUkev~NiClLyu3JB*VXfx>_L3R}G;hO4?87Q@DUy$N?ciKJ0wBEBq_WYAG3#%6&FM_LxhjOk<@BE(U{OdvJF|NH>Cp9y#aH2)uoVqIZ z{Adu&*ESj@d${CMQ`tVsh&hv_g4-3+4|*&l?h z_PRUV{|eE6IbV`PLAw(Y2xuQ32nhFo<@|rSK1B0X7k3QX4-=nucugJPhtM8_qtQki?g&Lzo5i&p0#J5!(VQJ zP-a^j8d$>hL8@rgzIXp4_SO7p`m47SCLh)Q?RRi7A%)7J)P5w)BqAq^z{;HBf>n&RC-y2}UT#egk!bOjzI5$2`g_318zH3P#mCT#KNX(Cw zsAxjM;V`npAsT_bA<2)Gu(*lceHsDc)4XKFyu_ih!y9b$Jo>TY8&7VZfjI9QalzhT z#>rjUL$Et_?zhayI@(_#^fsA;XR;?5(c@I*0I111RMbHL7PT|qMx79MiJ_zcU}~k) zQt>3B`lcGM#o<1uZCiOKM}b@g1H5WhlHs(;D@?$`{Xu$-SY{-cznRJKR9Q5=HE_*P z7Mj7`fQAN5O#)68<5kf%tIT&g0XxD;BPl1KnEytX|(O*S?&*lv_()Mk>&MD4(_ zel84!!)4Oy$Ur3hU3Cx!0H@%_gVF;%6dilo^rtqv=qkEBkz7C2NK6rGJ=Jm5Um&s3 z7(Wd!fLeA6nzpWcIb$K1u_Hc@wtauo<6}Zzd6n7xd?79Dp?SX`5*U43>G#MA0f*d> zK&7FkgYJqB#Yqf4CzP!s8BJnEEU*!;?0IC#vh*es`h`B`HXegyfZa%We(Nwx5tl9W zCI&y8JRdtJ(@c6tpbCK1yjN|hxr0{CCn@Wfny;6R zDa$k@BEi9s7LB!h6l!R7VSml9C=G`zlYDA$m~sqgCf}mD+a;Q#4V!^A(~A> zOu`rG(v%rab;e0VG~sr9uY;Gzd4mpBpHFaGxzZeVcg+)uxSXI*hKTe;lu*U}6sHLp zN|C8W0L%01g|`?)|Ffbu0QT+7;Acdf3nzi z%}qC?vFeTv=3vg^3G;(sC?jw&Y(kW&Tx&o-w8IYj z5jXN9Hjw!<&mGOmQzP1BQ2S8YK#5frDzVKK8$O73g;RT>eVA4+ykeVBM|i>X9OY_i zw{}c~djsF;c&^*%5J3VtTtzgRVfb{=Y$6Iw zU|2e-c8J6Y`v&Wu)^Kl3N20L&>z^rWhqaX#cQ?njzTjONU22+Xj61O9%Z_AZ)W8N7 z2=oP`zp~Wq-;MiGi5`~bNJPj_Y?pniyO!yylYYUMT z7g8*=RAy0*oTq-Xn;&?}C18w2jj-_bvv@O3PE!7$I-2T#a|l52!pe`D!w$8A@Qw6g z(BTTQoY`n*9dy+$j+yFnh-}UP=NZcAR1SqyswF8UsU1|xM!X@!tGe4&VNQCB|7uSw zkb*=X6Rt~o#mMZtIG_(eD7yi?xRDDAyyx1>_&cP1A^v;HciOz8*Zi*c#J}r3;{Qtd zsz2@B|0(!Hf7;tSn>mSD8rj%e{44RNDF2WJ`L6kz{HpCTOIv)k=EkDXTjr{MM@rDRt55V&=uPWb9ijrwvM zuQ+=fmuD*&$gk0;b#7`}kv+5=6u{{G;W%J1uFsmi`qk$^d7!-GVoYC@pAzbXA207a z!3w`3Ym0@adD@TtA{|&ZBKFgQE{E+VAdDn-_Jfg4~Ziydy@r-T7!fh(K^oADcpI5 z-9F^Mdj*=7c1({H2#7-y2#Dl=R=5A-9g%-Z{(re8M;F>he)(z3B9Awlj8iXyC?Y+K zY?!a*2rCFG5QbfE0zN{DBuGie#1dUyT};=cioV7PUL5@Ly!fP?oxka?|H~4Sg_H~Z$%-VL_v(EP|@O*Su=Kg$T5#6G+50W0yhdk-*gbFWkV!xGXLr+RoX)ES4R6C{MdL2-mfGrc7N>gaZ{&hT=WD^*#tg}A z)r`9XvJ`qetnx-dzn3_Gz~?D%cuAbfYJj#QjdjnSb_%?m`KX@2Sajcv<}mxBN32;J4{2W7fqurK-J`1+VsGL?-8S{LY^8qvI8PICV*5b+wS5 zCaa;Y3V=Zyq_)IFk0<#dvww^8rDJB#7>H+%mtNXvNuOGA@u4Xg7OYsOj_qAp1E3h2 zQC@u>^HW-#I0uT&25H#am{!`v2m^H1_i`;U$G9)NaK=xEGR*a0L3Hma5hZL^&^X(E z%9s`LpjFwtF+~Bca<{?%X8*;uvUy1c%*@upRUQPXu&!CtM4^KERo!0Ue4D@;cC^xF z12=xYtU487*Uh7ACM(ES#d2Rc>+s*)Qx&uzQe)2ykgD0lBHuebkimdOeHPvpfouB0?f;*Ap2_U_ptjR%zr{u zulgLJr?6*&TKX?gL*wgLG-4>G0R8>YRBzRZfXqo+BE9Y&MP>5?7UO3FP2`7~H2F$3 z(E?K2W`Hg3nkm@t53dwbP?Q9S$2|XjA+PsvO#r|+w~6u;aeELp0WslP_xoh+I_@7( zi5V<;7{m;9ZoXhE=^X>9I>VrCI@y|}d^EwBcc2BZ;ExALTQJqnKGpzOcxy%O&|{t# zUY>zAfNAf?X9)-AxnPE}`F*g1xjK;V`3f7a6@)C^6@I9%+V_2gb`!GYmOIY*yp0sm z@V>*-0eB?`?r`(;CD;v}lRqIqKfRF0C1de~0g5=+b&gs#Y0NppZExk(m#AIpt&Lw0 z*(Ky?Ol&w$3)P_Ez29jg=Buz#+#0dyy8fxx0EpIdKVsmQz$%*4UmzbSt8IecUkfil zF+&=<5A4L}{*s9Y|^G6x|KS8(jy2D|?G!!;1ynZog)|FSEr%o^pUh+!y z7TlV~3=zA2p24T^vp=v)nGz;9I&jN9sx7Cfb5!lQXweve+V2M2(oAYl{7N*=`z*K} z!08K_Bxsdvd(5l6cw~*geeCPc>PdSZ$Z$FU)oOx$7H!-gsQg?P#;{$n$|i8DUNXZ# zxGx(G`}xjD2jpga51;?knZ#%eEV##%Z#e)Ne>)~f5WK+|Cw3=)@KJMHfD=YiXAm}^ zqPp8mO$|(*#%NI6C>*p?UuDqO3%I+#NA}g-kNf$KK-WO)AZCD#61|RP)$sZp3aDEKMN0DK!# zV-bzF1Zq&}y7mCf#CNLMJH^m{Ne2*fI(HWOCRUCUSTMj1mi6u`D(L5!LDXe#ZVz9##CO_X4x}=(uY>;5r)0 zsb}qRr4>pzga#9DLw>$7o}eqvPmxCP{Wz;ibeO;37z)I-k-p?#A--PtN4!2z7#nBm z`BF#y@E(An^9!`xXI8?nq$))-t|+@NPzD$CxP7h6QAsN+px&05oj2IT4{vz7f-XUW zVNhd4IUc_pKr5AE`2{oheD?>jnt$mcOf|uh56I-O5eU10jB3ygQONT2Di@cdJ!6Qk z$20HE-c#zaVYS@KdsvnDfTtcaobmNw`SKd4glORJ<@1+OsL=)+9KxE4f%YlGzil&g zp>2EU@y-BARU^#l%g}2P9)Vs_7x0+4-+v<8b%eu4S$AAA93OsY4V3NhU39{x`sXOu z4awNFz-clK7v=_m*u)&~LB(fdh(E2eU(NlI(OMMX^P&~HA|xX|!Xk)_AKKi*TIu`P zL1M52uR6LSr#iD@=oVNw*L4U+iiulP)2b=y>tBEK^7b&;a(x^^)^l(_P}Wj@A?fr+ zX`R3PY@k^WjbqgYCDUB;s4NX+C~4;7v{hLxm9KA>wU_~$lIxaL44Xve(UrYz31}b| zRpT&)+9D_GH#=2n&khCm`O7w($`B$e0`jzH-TDC3&5wvjHPXf~O5g>>khD{zbV|&%SIq?9C1j#=%4DeE=(>;2PS{v8O@;)g+Vr8*lM zn54UW>|_iBDfzkzm?k(G*@;1mPT};_>~lH#ac5KEYHO=X)-EBVqpR3%XnG>1{)B{M zIn{L6U!;Bg8H*dfkU6EM7Q)WIPZa3`u=CVUrpA(Csl#3dfw?^EY%-fPa~Cq;d(7K2 zU~1T@XA}5iZ=^kg=BX?|jEk0;!b=&aCZ|a@^4V}4;#uMI#Go;3!qXB{z?@Dvhw<_R zvBAbs+&4=pVpX-2YDp)xm3Hv>*q1Aq$c2rFy^6b71=$%%+lWXZCE!ofPSY=bW`bjL z$TN&jjuSwlKt{VO5dSuEa~+1-(I67sYhr0!NW@Qa?B8Y5?kV{327j7RU7tyMb)0F| zDEd=_m*=S0P_-?aExpLNFWSc9YcRqj$1@1uq>0G5L^*LDeTig^^EUl026vv3axsDZ zPeNM2(5XpgBR*O{+a&$xpYDKyocSyU(;t5v$NN&RR^d!~^kTnfRl-EOs z!wVQvE`1aQs@0e@7oy6zKvp~syST!<(TnH?U=UBoiRc6UKSV$ey=`Um9~!|D#k z^lb}GWCGJCvJt^~c47Nc>cZ+y@->7J1`ORT7ARz87$?=v<1Cje8w1i+-z}C)V#ZkEf!QSA;n*xfRhe4AXeKh1DAQOv*>GV}jI6z8Nk+ z!tG_$8RW~XCG79nS@co-6V{zAVRSgHlJ`#^ooRj|K!kp?02pns(dsbHy_lPr4M{Ww z?r;-7sGc;KCph*h*R&9cXU3#@V8!Sj&m2lV0;Ee+w8C#UlJ^A)o+j|5xXT3Vut4{e z`3KCCT9Q{c4VHo^PSnsQvxpA<)lN~cL{<-vgt27)6k$k$k|%q6mxQWS6o$h8F50rL9^bE?=?4qtO>L!zoDCaz*p%bw?OGWZ51Bc4%(HutK+wWitpik#M% z!(Mah_Qqx--s|h-hp*I4HpHx-zr7FNqnad6c8AgL-lSdLrR2QZ^rTp29wRgieEvbi zdBv%sB{9hX4=Q?oTF5wKRhQ@Vs}&^>3=e38LT5q5t+|)q%$=0I&+OsnVKL}-`=@4x z5eia38fiy2W?iTzbgi;n1VYim>+1IVkF8l-Zp-TgUhAs%-lw+qJ@Rww0$%Hy_HU=Q zgtsFn`E8(&Zt+_b=a+^(_=Rnvk59-w_@!;sUc7qtk|&o%Uc4&ylBbtHd+>|e z5PI;d+A6%VLg`@#mSI|M%nLBKXy=@KCYa3Q`qR+)G!21Yo(y5~z!Y862XFiX7)mdU z--%S)29pNwcdQC}5q`}cgY)#V@1w!Pn3b+E1Yiy>QW*NMkPqFegJ|Lz zGx)4Gi|CTJDnGiXlXF;6HjRd6xv|i5Om!!L4~OcyHTK(HDU%xNmA(V$0QPiJuQ}=} zcJ-A2d5n^GVb&I7bG#Tua_k#~5T#Ru5~knykwgwuQ6Yj7`-(x0rT1fxdzm6L=`GxD zkPF=amCr-~%Xt#@%i7Y!v`ZuSc);8CgYkC43I?Y)Mc$#s84x3j=DPxa*6i;IYD1W? zRwvU728?C`vS^>M)z&?BtVt!yYM659HkKIcY7oRy<|?RM-7bI+!_TrC%7hU#J=*&h zANP*R^Sy$GG+F(c)I-u#6$Ob8R`j^p26CREJ3f^BAp3ntgd8<|cN8wu^wv zVS)^64Sm{=C-$ZJFrD?JGjZTfR{Fz&DbuV47)g1%8YH%s^WVbBmf6l9hFus;SJ|5ySil zbu-6z?RM6t-|=Dnk7hBhdMHs#jzLgBOlu%m*p$=kAt3J^F2+jJH=d>iVqF`xK z{O0r_6?Bothm+NGa=@TC@6gr{-@l*6aBhHBFafDFf6PKc##d$&$g5>Y7&KLN%E~7(45Dx=o5w$0R498APppqe;5!_>XCV68Co`S7sJ z*<%Xe+j18Zm`j<1VXCd5n`UI~F>i2S@3BedG}wvw_0~rQkIgjTp%9C+8oIQ_vho{q z#~X8{dd4)CRC}t+I=4_axTd02gTX^q2Lrc_lqU{+qee#&E@nl912OUyW$Qc9VfSr! z`K-Q057ScJ%5^=&*K*%Nwz(co^t9kWu$kPywPCm((74aF;k+K{-GjbBx$z5L#$*T? zA+i9~7)-lIH*{2O4XOh}t*NHfosD{>VXEfU9Wn^s0$Pgd88!&iBGR4qx=91Z9CmAx z@L}IrUD2#YF#vTRsK$9qtXsq!nZ0V-wQ%GRdVnz)TOLYnY;g7g&1o^Z(EWs&GAcCt z9g!hpgcOz12Lo$TG-#xqJV=dh3dYr3=lCLMk|Lvx!`jvL)4K0UU_DiY-XlSDv{*H#1C5Rb-A4@pqm*RdKNk#YA&If!iV z^lAbNRzU$~f5au|m~oImJ-sx5pM>_arsEb3&yy@Yeb@uRT;GR!9*k@J&4t4Ml>&Er?6nF8v zxxW{1yw{8(5v8yAqd({y`uLyR`#&|bL?l=F8P%-CT!qwVX_|{J2#k1%Tj`D0yBaQ` z)-%LTsk)Bie&b-{hyRYn%8?$8ZS?*T|IBp9LtICHx0W_0`q~9JN}05izd#talf0N2 z9%Tk`gu7$N?LIf>2yuCSs14iwftX!b_T9F*^TS_z8P#(_pfbe?gt|*0dZzuteoE** zkNV)R?<0JoH1=1l&hNX(!Hn#d6;o5JZ0ftfH%dZU$8Gr7SOFVEAd>$(x%Fxi?;bHM zMKlVe($IIYDRl5Cu8(r(MOtUz$+zLTNosZvD1p64iO3at05;Y4U-RUG>fj9DkZnyD zf$;9+9ComWnqmIqU?0BTQxNJMXXt_T0I^fqKKs+R*&C+DhP3KHpp&lj>y-;qxA3fVDNp!c=Pz_&L=yDnAa>+K%-u=X_)`z1cOu4EDM) zB1if{dU%HT`p)$lX1q&e8jVG}r_5bke@lLVI_lk%6aC&}D$iZD-h#&bMeB7-e&~~= z+VC%bcUEAzWjIYCPucb?@1O$t#eVU`!<#23IQBv~a|%{mQslx{iuk8G z5i)?tDxZIJ$GAr*)_p`nx~U#j)-&B*uEZ9}!L;aB;GGB67s_h4)2egC2VBE3syA~3 zW}>I8%Y82Ced^loA0PdmGSA8PjJByfPewzM$w~HWa5={ggL@6bFPRI2P;#_4PWzDc z?v!vHi4ctKp>A}$3)tWv;)Q7c^zSuL_Q8#-NwA}?Ew&=>JYGD_eAeGO+6Eo$$$uLV z{iSiLOBblyAu`>LGToMS+sn9`c$BtyA7ZsvGvOQh`EB(tiPavb z)xn;}VSUjH&G4Rpr!9%i?&b0BUE9@e@BI3?nnus(kwU6<7ic}Q0XOe_Zqu+bFkX0Qx4rN#IOvmC z{A{B%;sCs0OLtt9mj@vcZ!+ljXVF1#Gw7>;!N#o=@^(gzR6{~(C1XUEu#0COUjimF zu3w}CY-IVz&kmtMpmHF7mF$W~m{B6x3*=mi zD0=mpOksKtdi-f{&x+5W}6A$Ucw-6r>)ENpXgsyrRn1$2#0J|3YoBv{X)byz?Tg1jSPGW zq1n)%K&dRJ@O%rSp=b;8$TNmfpRz-oB*9469S(^ph)mhT8384#P$HkRE$P!|J;193 z!}d!JumNjCqWUESvrx6L%)?O<9(YTqGi1~Ob*9et3s^5Vs2Gx^Tf;?Zm z=AaFQCayWS&^fs4w4h`&vd0vOGx9%UOA}{E=A+GRX-+q?_vop%5*sbap)c3hlbvko zX*czJX2j)K2b;;{R4dC`!sZTz){&Z1sCsI`W-h6MD9i|%BP_^sCHT6;k!pB;)8B(4 z>B6QE&a3-rm2YejK*S^H)3_(AT}i3BB&uN~%%~YsN*^+yUCZ2hWp&?|~BFB+v?CP5%!&KgpBN2=AREpIv)_K!e@EPiifpLWMiNSCr@(0vr z9OBgV2%eM&W6?_D?zBdVA`<12k-wuY*+|S&O-TZ#MZ&Xs57Gz$^LPa7hh>t>rtW1A_X){(}Ek^+`rlbLUi-%Fy_7n_hv5PQ0`6>pSFQOC$1gHjX9Cjn_G3@r5; z*CTMlF)9n+EAu{i=Tg3lxWiJ030DzIwhUwuKVjb#J%Kb*K$kfeJf~(2o@c#82Ff@r zd9aZ_U1b}?`)(8Goykg$J6neHI*nE+$qRgWj+IL9O>>UDEW@N|iP;0#zV)C{^HV_+ z*p34<^)wf5UvH}LQx|7mOCI=(XH&BI$t=HE7Tkh(lL_VC&U+LT--=`!Cloh?)0IkN zzE&SuQ1=EWdd^s|PxeGfrIz$oy?TPsQ_P`&&=&@#{?(q|(t1y73uRTkoa8h03&4Vn zxaDKUSU8cr>AJTY@K7jknG!vMBw{G3+w|-NOojkxFBX9t=4B6!r4NlWjZ%sm!@H%N zYZKM{BK8P1@e)8(dU2SI!aMt%_3nruD_$Yntwf(O+Pf+zmLE6kC;>w*XW@Ww1E z$cV-?DsnMTMWrX$o~>u4zryK|!SjSCGX7M_pX2(dM1(bl6r+M(nzP!j-w~wz#MhLhDz$1c8RBv7?1ZqB@e0$fpI~HQE z!Bl&=_r!&GseNPkx6kl5!0GYiexMh~MOE(|O0Tfq^uK&gOYSri0S3SE3}k7d#+fr8 zt?g6#3U1nxryT854rl797f=Og^2nx`2YqDI>nbu)duiT86pPk)#(#NI`^u~Q#hG^ep`s(^SE5}fEAu6B zyS=$xbvpLSQqaSj5LvMmAA*se1@>3{FNtr?S;sE1i|2~qhG1+MP1`}AbvVC63>0U? zP1VE5E8<_}1JHs+`qyh5#QrW~woldN7si6y?WazrenEmSHxjiDdP^VN((+*$@)%~3 zFE_Q|NwQw~j*SAnD-njmHaU~uQU2!z{vtR4?A$3ZM_DJ0O)q~b4Yl}s(zLkylw@S&b$@FAHZYc`&by+P0j6tP+dT>SdLQ++@nww&|tyf}{# zvJb+v(7VXMaVayqvZRcOzLb<(+TT;e2lM!u+{qB-bW1}&n1!%bhpTq#^#5}GjWajf zS1WNu0~F!J3~hdGC8G@)4URBT{Jo9dCqw|XWP8Y!OnmO{?8&Wr<^$a1E*PwO!Vh^z z#y^u(d)I+lt8`S2bRuFlQZlI||g2MAC(twjSR) ze@`8@7k|%WbGF72dWXhm9RpsA1YUz)u=*a`=M&qXtD}84!YRu==y~Z0YQr32LmJxg zcSe;eN_fVlWd*0UjG6J~IO!pVyA1(mOl$_XnCjQRkR7su=Zj@c}snp1P4PRWOMq-M{DcBPKV zueeYl2&I@Rc?d3zl*I;;S5MpfRhlU~5kj$1V#t8ZaA^6H=QS3Q8i+#lClsh?*Z9%BcWa;rz5jQg4m5Du5+7Z$#M z##Ts=+~}sAg5>908!17WR#;oHT3KEopR7hSSKZ#utBdE&pBzs-+^X*&+!$;~-x>hm zZbfHiZk#?r#!+w@l^TpHXJR?3dsa_MYl~jGry7(}rv`0G(iQG1($;hG6P7QTcUp4w zccwN8jm5vg4@cU20izV_$+pv#G;f)+Dgt)5Id|$+uz(H@3oXde$FJrO`A>`%-Ov9I zV@gLSxo6{>G1UYL1jPP7i?nVC>hz9xwx498;9z@nDZ&BKdk?QIlnMkt-Vaq z>bI^KlPTt6`@OBhrh(k5qjV>*s+R=4j-8&HY-o=V5;1El_`i}#46|@)D_ySUZi9E2%oiHB50v!;njM*5FES z325V~SjmsRjTCTh$;||2@>NP140DgX0>osEtAc(FYYCe!N~P0GVCX-rC8r~%b&5|d z7nm2?Q*sPZxy^vOvYE&TGnPJ z9gM1;J1T3Gm-CXurt9m%wT8%(U$7|Q1{o34rxkaBnqSnrv6M#0>pYBd6%P(!8{=>! zda`rFk6@I_vPj}A)(t9uBsNF$m#{jcxr{S_R4&J4rTt@z1 zHdSreH$IbTmK84ZJPI`Z1dtdEquXgNrg^e$N{Mfv4UTfM_#w^STF0ZcPNHH+F`^QhUTYuo^s|ubr{*_DNB4MTY;hpuS4X()d)*CbcOWY;BUjAL2iU(;xj0`E z5thHh#pVAhTv+~-bf;?j9WF?I6cN(Sx$-*OE%s~W(qf81+i1eZ;JcN;Ni1x{a?jg-taHtA$S{CQyblUtg{<&2HU-$Ck47=*fwD0#!a!-D=-Hu zwMJ#3xa=EbYMW}uHITtn9BwGnC`mZHjXqNxndjx#ivcpL+*gV*6RQHtH0()ZD1XH) z*7(UE)?`QBLW5 z-N0S~+kc=A`sRrVU6@H*IpxSdt;$cghi)R#Z@@GJdWHAPwmDLY;o=)vOfW!CgIHHK zN<2L8{B%R672f zJoY4P5stq)QR$!!%AVD0puL#b4Lsu&D(*$*Wpuj55A51k_)u}fO<5KP=4Y%vQy&k? zR*%q!f9z2{$OGKeI8QZatx>DoQueSbuI5~E`lv4L4U_Se1R1M!IAO^wBPImb zV)^ZHQp>;ym^Hg~^n_-OR!JSo`EDhW`Ju6czhWZ*0kfZr77w-$So600@o*!tk%w6m z!Umbog@g%a4Mn2JkHN}zg6yR^au7^6nvQhxyeQHn6OF98Cu^c8`e+5}JXbRJ%2}Y? zhUH7VCXQ4fj;5fVR3^B5_mXb-PfpkoTA$m*q3^u>%mqFb**gG1avN?Glm^_e1O+ud zANorv#K!hnWyv7YxJkT?0tyZ;0>dN|Sl}@Zx077+skDLvbx9He2>Uk^Y@N^)Sk%++ ziiU<^=txeO%5@n!c+o#CSEiaNb^hLNmLE3d@cNwRIWJO6s`z8b<4KD17CjfE1Zpz=PV+PY1gA7NHa5%N+9U z4K847zmW}0|57Puh}sV)Do?~CgyBsx^UemN%cg9#H$9)F>9%gX& zsy(T2KtOCbKtQbjr}^t&K~|y(?SpoR{w3Jh)uc^93=O6&1ct875g?=n7FaHg6eJu^ zgw=3HhMkl$ZP&?5Y*kg$qibu;=>79DMsh?W1U}QN?eSz+y~d(yX-z}7C2gtcqc3B1 z`UprCwy*m&*4Dj(%?<(RvxHK}Ch|L+Am>dKRHdtGO_l*pJ7XZ#73a;b07%mG zh%l1$00VI*ctqNHQlobrYQn|+u!jR?&^SpZ%r1C7`i=tVDRl2RO+50gnoEFFyqgdy-FdG&SapQAX#*?b zt1+s;9SB%zse*!KM{yc+K?H^5TPf5&w^mT;cUfA_lKVtaDYq|gY7M}I%6eo(Rn`OWaip#;VS-I zDdBZ)PTM75vH<_1`4ug*l_Wuiix!-`;WY~^pwtBuKKD*-4LqBUpvP2}&e2Mgpv z#hUaK6NODKGCVt!<4SYi2Oj~v-gA{$@v1+FCAF2>I>b;<^TrZ(yIawQXzLfno2N`a zmT3Hfve5WSU&HLNkrmQJ%Pbr=nenwLObwMi-`-8$bXIE&o)d-U9=e3Pj-*_I&c;M2$?)KhU5jjn$ z%e`x}E3k6vE838nijkt7sEjaR_XxSUJV4Rket`YAf-YUY_gdxWp(pk0d^YMjZ$u=b z>&tk6K1HRW)s$>?CmFx)@{uW)2PU(jS*PXefnzN;*`uazr{IDmVb&Z;PRp2xUikq9 zghOjYja24|I6w@?w^WVDWUpr&OT|(K9S>C-{A0y@Pc%}HC<$Gz07u_!%1u5i=klV# z+g7#Gtdja|f=#uMWiuI@C5c)uT*8EB!OTLZ#(DlDmiR4;MHa!ZfAmSgtM;XSsHEuF z>y3?-kAuw-FI&PJS9ah>RpG+un9kz*adwggYel|+Y$Wg$&87{wGaBAcfUpzO(4XOV zO4SV7FsgLQ^3Aj*;_$16x2o*)e825C=&l5cSnpDG}y7Cp9(fjtedZ8 zW@H0}w@?Zf7PDr|iFR-i)c53eGBJNx6hpJTS@?HG^pmb-Qt|E=PpKt-bDR{slojC+ zT5|k!R|}Kh47&85dJDp&T?J9akjXI|?A({vE|%`pI)mr_lRR{A<7=*67qQ#A?MqQI zOioA5Ei#~@Z9eX#ienl=EeVhjjb%CfsW-S}31I$f%XUkyXS_EFHcvK9!LStg&cncI zhTdxiXlMrC9(k6t89TfXC-u&!t~%sW)u|sEZg~kX91yVN<-vPhsBBOKHes7fnv3Oj zw(p7isAgVh_d3wM?)fVF*;Yls3(|hPHo-}Omy#rjy-8JuT(T;#aQ6LemR_r`ot@Fr z2~Wm$*6o#sqfpt?^UsgysGi)+ouyIaKHuavJ{vDH^++to@vc;?ygW#9mq>WpTGgR7 zbA6-Vo+}$uFJAGeduxZ9G_Kiy z?yB9V3tcV=kBj2a>iP?XW@RTG95Ic+tjZZAR8LLC9w)_dEF-bbr4~ zc7)w0-sP?x2ny86%808FCFAqt?&OElgHvC2=LRDrqu-?Tq-D$v-qj2x;%Dbb;R_KN zLl={!<9roKe$XrBw07yq2&oVA$5 zdHoRb1>xcL_LBDq=_S*Ab?mOB3%m0m3X{G~#G|3=Y-}-yQojsJ&mKyCL8|P?uB5pZ zlioEJwCAkxh5GH5$>9sd+Mc_rk9_-yX#6ESg)60>&&4`caEL%rg8HWjj{n7f%@ONAwTh)S=mQa6I2JyJYKJq!~$xUhhj&JrgG^Bs`SQHmy~Y9(VZeP~s1kh$t_ti8z9!gs5_nL!Zj^&~GMn-pCmN9-Nuo^q(G3 zF_Bvb1!1r!(~@4{9$l-zKPQmp#P8r@`Bw~a2l-$(6SvHNkI2)2^rcIjUO!46cIO}l~* zAu5uIGw9mx+}CqdF3ry~^a=j1>d*`JhutFA5Nk)pHPXuWyJdvL?e13>ZyN8RzL0_Z zIdHSe6N%^1i-zrhQ4Z4A8@4l6`qXiYRV1ZbXNJu?tW3sZoU!P$A^zT$_6@wUwltHF zYln?;GnsbcG>KhKUWr&TY&54_f=K!ydG-Y6-W9u^qG=d0e^9Ug{YR@9xENp2uh|a> z@bhlbG^-;ss8qa;zQL5+jJM;tBlLG74l6L(4X9dS^v9@$TAg&2Fd6M&%SNpGVglI% zCA$6OEh^at?NnlF_>&~`@o^cOq#_570`Pe<)buV*zK{fLf>ygZ8!#Ujq$ zUyLN-p2tg1Qz3%nwy_vc1XFcm#3ng)}vo11&N+PpA%l?+$#}0#5 zRc)JVW^U%V33q0F#zIf^oiBMu+LDrQXJjyA-s8~bR785Go0{gAeQN*tA%7@w#Vug!kx=YlkEfDef~%Ll&83GJ&Op5%!k1&KDSh7y6o#bGghtNx;%1iIs{9cMe(2MGp>HNXGYr zby9HUg1YA|?|1G2yL|1!M_1H2=hZ=nO|?BKD2Air-r84TIv~R|p~)|u*}x*=jmFvp z+aY|rPW$T5F;-6R`@L(W)L3({gxA75*`f!PDX_I1C#zz-MRl%~;?UbyW=FEUGoS0U zeR}f2aT!Li1U$?EJX@ckcK`0@R(sTJCL}|rVMQI25;dFZX_3;pot-)f3Axv4Wo(LYt zO^?xpxQo}oW|as&N?v8~>^r}#8V|n@vRPssBJw^j=$b!J%t@QaJQwfb@|}(mGS05J zsr6mA)Vu-=RwR4U0(rC>@}J|{V~@tKBT%T0F#+()7!*mRCgry?BMSPHV;bG@MOYCs zn|kFui(xxvCTU`1F4K?{8w*F{6?&GWZ1Iru#6^7bQwi;YHI7OB4+ouUs;Fw$;C0qKCRxMiaLCjBzzo%>b~>0Vx9x1}iDwKr1I&IZu#tuD&*VbI(B!B6O!*~+bMV|!85QqaNm~S9 zh-LFhRL1HB{Gv|n^{X#~(KC}wt+q|;m<@glu4UvO22(56(XbWERoEZeylg*4O4^rL zWM8+Sre;l?w^p6zE8hUUkJ@lMmTYO1ySfP6OoZIjc%z+j`lcqG_L+hC^-*Dm*1LO$ zlSIz-9rHd&GtEY+8mm~~OM;`xt)n(Qm5C5GZ{?QsZMN*pA!%?0uisCxrda)8@c zQt%l1GpJP?TFmfW^&$fsdF4y=LaZTg3 zGk}#lM!=fXuGiXb3rCf)M5W?N+GZRM%!ppQjq3;(sxoVD(jN7{!CG5eo)3n@l9l6^ zTJppeTDM?(N#*L=?aY|ZOTA9LE8$?(>niIedJF_~CASscegICozLEz|!k@*L8;w_J z5WASo=uu`NRtxIl;y*|Tmy=-&QE zf%3`ZAr?tK3hy1QyGt)5Yz7kYJuEkm_?ejqw_dP_wV1N+Ktcl?Oa|NP4(uK-wtHB) zHt_@HWYI>qb`ciZ&e2{OmfVVzv_#Y)HDE5Yfps%DHJf$FyZkMeq&#((+DTLt!O`f~ zaKc;%9M^MgVXQ_=Payfker8K}eqUG#A?SWKOCCw4oal4i`|y`_L4?XLFj7>z+Q<&1 z0wxeF40N(W_T_k=wyo2>|}4PkDLbDH6EwcH<>@zD<vq|uwy~@$9&-IIQ-YCw*@Hjqp=dq@=swYNp z-l||zhA_d`<=Wn%lDrF(p$rSDv_q?!<4fk#xwk+T#Rd*!UCqS`O@ z*r}HbS6ip$)wCrD^$ot642&vqlqBm++etMB70C*2ss@sTf=@tOJo#tKf=BZ6vDNfz z>^EX*8i0ro=-eY9>b_%2k0edW05C-0buMrB=4!KF*8!XkpGD!u6gd8QX5f(cK4Ir# zytFVlPls3xn2U+B#2exj1d0fC&h!RrbVZ;?QmTx(b_kV9=7!vCfcYD>I0#OXi9|}PR%eRZII)AkoK39< ziQRF8=PUFpjgb~0M&k#6_V!kfVLn`c#B;^XJv8gXc5(ig3HxO&=5%~~nKSd)&fB(k z3yC9|F?;c*lc+q{D`)d}(y*(2nP39)CDp00sI3m_g?bk3uTh=|ENrBjTia&d>PkZT zIu}B!lgd=IH}rUe zjyEtS9>wp**$P&*NixUT22%wV#1g8pd5J;}TO+xa7<12-a2}ovH-(o|axn4XkFw9C zw~N1GO;#wtu6y^za(k`q9rOHzb1Clu_srE|*NcnW1G}09x!7?3MJh_PGKn@b1or?N z?s>gD>`5fI0M?=??;`V0R_ZCr6upJxjRM5>Hj!JUo3C`% z_p`p=3VXDt6bF%QnYQ5*J%!A`EL*&M9u@3}oC*APCiTw5 zgd-;&J=_FcJaI8>gJIUXrD(z6QuxpDU}WUS`{+=SR0J(bM*R=u`P)(^z|_J12U~`y z_N!nkKNjTaeHqKEjMRx3h?GM^K`7CQ7%s}n`q)qen)a?f7|ce1MqrJPwxSfW3#j8?dGjVf@JLbHJ{!u1FeB>FyS9s8;i*EvA23-a1fa^gAI9xk?9aK%lU&1( zqL+Dlv0c68{X$%&Hn7DDS_4E1J_Z;Slm;l#5Lk;`klP6GA{xiS@32PD&3`f8;xtXU z99ViPfsmR$9KkH2^F~@aiVZ%mt0-{PMDNW8PNOg9V$s7PR*qzO(dvjLybkoDb_(j^ zgF~hhMk}sjG+T<;?=qozhQ-gR2uy5HN4`mQ-Vz9&NMi2$*|C>qz5E)5)O!_tN>Sw* z?2^>QG++#Sto1ZA0KV5g?j7|3Od)_>(IvGIa6Zi7mBJe&)H~LxommJVN#69T&PBQw z5q(wY1p6${cZP3NZ_r3=zwVqQVUX6jaYF9E0_A0G6ymc~Q??DTK*_hg16QfADfckH zz#!OJjYE;X- zq;_7L>fO<*#FTvSEO@FKS0iCfj0k?3_wd`EC)bgsIfsCawjQz(5)bk_k$SeU22?+7 zc(wJuq3efghlzQS^aGQEA8qDk)IJFc3hsZtT{s8Y-|YI|HKQ8g`^&GeR#>yfhA&xT z!Q-r#Jw;RneR|3nx85IkZQeVbLtJ6=;k_kD10<5SXD?(Z^*tXzg4d z)5&fxvmXCcC}_wUqK732d4<}NwH*J{`*26-6{g|nff;%o=PQYY4 zE`{)&c_Op*yK26m!%eg%^KQ&*CpYAyz!Z1brE2gn4vi=H2!!&Je3 z>Lxn41{_|b@r5vOX)4E6#S*KbP8_=WwQ0_^OWxFe z!uh18H$*M+8}rW7+=^dcExOe^QL@quH(epXHm-WhhLULEZcUrXJ}4g*S@^hn##Xw; zA3Jm^+K_Wu@WeVn-&!S>j*fZhF>x76$1&pKaE<88Ov#rUwZ7{U(}? z`TfrFu=uDpP1y_K_`F{7Py|4*#s=|tYae7DeZ>EO$;)puQ=pQTa1?u*(^T`4HybVRf z@07sN2eoZt0#7qT$#x;gekH3GkOtr*V=XYtfh^y(4A|~EC1CuJ=vo83&kFY3sSjF2 zMYBWX$_pg6mBSr>>H6mU%{&Y&1&CK0!iTnhcUu)Ihf;U666BlN#IM@L|wfFwuIF zi~|#kHY4JjdqEoJVM&1w6{IhtkI57J0c>xT0!;w z2bwC<>*&3XX{K$~MT0gLPV6_)%V|a_V2W|`gcJkafbceBp{8+S@#x0ra`LP%^c+Gs z;R~0O^CMeF+lFcDdQSJfQBH>&NZ4!WBU;8=Hwm!Jf>Z21S1D5YfK25&$h0Ib7o4DO8TOZt(WR zGeYGkq>UabM|&QFgLTqGLUT!xmheNo5SC2ZaW>vdzibk;*?kUQ&h7<%}yjxy8LR#kcWf zFo9z_?|W31Z6`$fw!*}p}5Xm%<*@tB&7Qk^3#AcbP&X_i_kGa*~c>Ffj2~7d}k{o zhWJf)qp63~%1DejeN5z{WTQZW3|h4H=y$CGV30$u@0R{a&$-lI)~QCI`1O?#<_jZv zSZ0n7sCpl_HYn5U6^c-UmpK9W9U!O@WlmSB07LF%H5y0@UBvoMgM(+}UVluYOm4=G zogko52yS}A=Edyj4-jR^Ip?*E42~i+=UNjZ1-3{r1#GfC!HPjHrJK2c#;MU{va2g_ za=s9H2Vi2T(IRtoSQM@~qJKWFQYXGdB#m0~Q>Km=$3N;Lv><+z)ZJ z^q>pI!A!+0FB8MDqHH`8;xwGrIF>j)8@+q*XZ|D#8sk8P79mA@^v`K9s%B1Z&^olx zvSj~ApI08(V1m!NlO|?w-$tZOJ;o-_I})RNyu$6C0*g?{UhQPs)t+b97>if+VF9-k zx7%t|N@n({Z)<9cEZNEY+7rI=q2>Enj$olbU~ro+-@{z9t@3QxFZJHmvArD6O{WH)o3wyJyaClIksb zV@uRkQV7NEi4$&ouk?XTy$k5mjI@VXLJU;RX`Kv^w9p~iDl)^V5Eg4su84<_QQ!Iq z78^)pXr;BMd{&eBJ%^?me1USPvjtpdoXBSI?)WPxhoU#x|KLznD2FPdijM^y!&V{J z*`m0vGlA2JS@7g5jd1LMCu{RqAVRdkb4S(CO*h7@>tw6C~}bj6HyDF)3jSe(mwSN=UPoQR+6FvTFFY9#?9e1?rNhG zm9B1enoRAMx7lE(M)YBOZ9{ROZt>K{cH@2%#uEj&b~uDuLlF@VJ%^DGK}E1vwc08o zrQ9+5v+fs3>dqv9O`Tjlz?bc=MzciSxToub?}T=#RXa2=@!JlXrQk4{KVV-c+3|DY z@CAf-DOikrcDhxOX7wnqL>GlQAQ&pw#040Srn|H#H}c!5eFZY4dl4E;I>u76$p~?A z+ju8R$7$0P)kG$9C0v(zrKe^J=F1KC-PVsM8qr_XabShBs07xwjc~uBA5syKf47xp zmD=Z|Gt-0o)XT_P4Me+ibCP8@=O9C6ruPwdGhcaT%p)lCs zR{2svr}{D3LctWU?;U?A>ww^*N(y01_G)T<)~YU~7P!CEG+_F%8beI>G5glJ>nk$h z;X|?QORDWl)8^vUT<1@p%Y8Fy=JT7YzD@XUA7hgUcMZXjPKmxI^s88f#&dv%%ai;= z^I$jVF0+@%x+JZj{f1_%3S==5~Og|WCwBBye;{Ginul{;7er%Sfq2 z1(ZuUpj_$<$mdB&sFAL!?~oTTosh{;kGD}qIbp1?(Em^Ze~d7_yCm{{BjCh+@=@+R zmu}-CWj+C=bOu&gf!OG?WoK&jBo3oTKi~^ocHuFPQ!=!lx&H!zb}~9m`IQ~ zM-bx(b)U7!?Dl*WiFEx~?3zA`{O!}L=T*}{$EW>;OB_Nqu!ptmy&vR@+5yC7rHBZe zzH)w3%Ubii#RMHOS+A&*;;kU=q#tBybfzO2c;WrPAad48b z+XE@^rv(CNaoT9vWJ-~!h(S^iynKHYQ+(Pr{0wWeD+pl;|GpVxYjyxCr~XuMMR;>% zAPi-98TC}hFuglVXYL5DE7$PnNWrx%TC&YWfhhqJU&QmFmwRuzb8-*Wp5r!!P$jEf zL$pkaSlZWAO=lc4Cq(w&*^+tQn(NKAT#-f4mK;2f#HeLC+I$^gfWrp!ep|l-pjMxq z2#5#hRM3|VVGRLXSF8%kM@kamp1+6-i?}gOi%{XB;td%auty3?GEyAXLi)Iyze$j0 z=J)WalgbDL4Sa>!AR87O8g0{Kl{D%IY(+XCJ*9m|8~S?mj(#S(^1HYlwsW16d-tDsk5Z^u zn>zg};ggdjgSXodIN!IF`qnY5fr#omgsS}6D$&Md@1N&mkuEjM2~uR&;)9QL54>kvPyd7#d}2h87`yH7M7AdyEaGg;dvg(_~;R# zx`eJo{p+agU7Tzg_%mq?O(!FY+Q6{8fFR7W$*ultct~XA1d(Tr%62;{Brovb*(?4x z0$8Gv;iusS`ayJ~q9-d?2e0f@hlYxHR_}gi*S{9hhZ5}1Li%>b?q>EZ|9tX&J@Efl z-T!eiw3b9qzdk=iGPPi1=gYRv?iuWA=$vXsYyyr=3X1k}^rGQ% z;=nD8ZZ$aJ8_qz5^z1oZ07ko^~>uWML?j2C?&u~24@v_6jqQ}Ow1EU^C1gWdZEA_h+uQ-;pyHzx)ois;P-Hfx%17L1H56*} zPS*s$;n1Ch{qtS4Fh!-%Anw%=t@&7FQTK>Mochj{pdd&ta{hR8dszcli3^OtSgPF=(On3PL*1;!R~#{@#t$%(F`%)$;{D zo?G&Xi2f(HYU$151ra*5(s*U|d}>|y2^@g#gYGUm)5i()2ZGTjF<)I`n*Pw-2~~Uy>!jZe*QqCA%WzJ zW3VI6J4pr&x7e)=R9FCYkJF7#1x4(Gv)zfdR65z$%=|D}yCSA2oEc%RI@e2s8FdWk z@Jgs#6oVz(To&XDb&fdcJ?ldQiN&r}-~|c~vWaWNJnOF-VIVo4nh%0n@L^~8(XVxw zUApKq;LMeJ`}{uX2l=>!Q|a0nli{J*#FM){{`P_a#g;oW01fO)lZ=2Tj`V529EJ{& z&uGds^sUj>0FzNqi-=PtflG#qP5-L3{AfM>C52F5Cd6{FB6 z-`5_m@I_`!%VsS0AQXHV%1EoV=f-kQWq}4*j5XLDv$T*OkUYQ3nW&ssi;81J@Timt zFDXEd^ZWd@Ov$|-M!14N(c!DrmgokfmrKcVXNNh5!qoPYct5+Brih5cFQPx*Hc`Rr zkuAdYjiuK0UU#irU$1Mk3;TXAgD7__DXtr~5Zm;9Sey^&n|<`HXm|OhmWPORETK4z zOhAWJni>)l)Kx(%Qyz^Wyt%q;k>$_H`EqK=?!d|(iJV(*1+lQ+!eaAqEsa!1S{GFnt zzhE{GUcb%l^l_wRfJ}*TN}Z=7wrK_{3c53TOYT&C=`_k9Yi6i<#tlrwtAGTY4V}o^ z95MLiBGvKFPp0sxhRhQA^7FlfmDF-8B!Y=f;}$ud)u)G_rdZamI?K1gLEeofwMv)+ zVI~9`)t@z<2(Vfgby?;5dwgM6L7q$b;;i(DXMNFehS3P)tGN{YJm;s(deC4RkI`I! zE(sTXKn0mUyEKzK8Cf*mi`IERDb2i6xA0l~?|RQy7WDPHvHO|7U$yTfzkPMtT*Lg_ z*}5BX#$>LS)*M{C?ZhM8t-88k>*>i)JQRkFz2Yf})>F()s2R@?ZmdkeEuE~ywAW-< zZDj_0kd!W(kdMI4q0u_=9x*nlk=h%5{6two+VR;5Y9YT*5s3-f*b7x>YsAn>nt(?|nsr2Bf~J z*uY&mzxcd674JU$sT*{A+%$1ge!jN#`P_eY-p_;o^tJONvzy#(AIt z(h%=322OR**n%x<-|DCjb3N~6tjIk`d5dUIhS<)3P9c`gu21@@JIU?mmQ{ufM%y^gZbuWv zWcWw}_{FDNgsyH^mOA@RkT+W;Gh*ffIWn8Fh^5;O{$J8(bV7@W%wVf=o}`S<&*m9^ zGP<@1LRFG|0E_eRpSu@9#}7Ro!+d{n|Nh@g`Dykeh3VIBM)xP*A9(?^(7*pR`$KP| zp9p_#D0JU*=*MyI7zF+JTL+?_W4&*o^!rKo@Ao~3ejN8E8_gYQ z=O>gobcytDp?)lg{tEPKUHzXx+Ni$){acm&U*Uc&2>%mqAG($2FZcLAQL#UkhyNAt z*G;TH@uFD&2Jio8OY5&Le%<)^(?ugRAMYEllwb1{e>z|n|5pe9khS>h1^k*D_Y secondaryStructureProviderColorMap, + List labels) { + + // Use a Set to track unique labels + Set uniqueLabels = new HashSet<>(labels); + + Color[] palette = ColorBrewer.Paired.getColorPalette(uniqueLabels.size()); + + + List colorList = new ArrayList<>(); + Collections.addAll(colorList, palette); + Collections.shuffle(colorList); + int i = 0; + + // Loop through each unique label and add it to the map with a color. + for (String label : uniqueLabels) { + // Generate or retrieve a color for the label. + secondaryStructureProviderColorMap.put(label.toUpperCase().trim(), colorList.get(i)); + i++; + } + } } \ No newline at end of file diff --git a/src/jalview/analysis/TreeBuilder.java b/src/jalview/analysis/TreeBuilder.java index 156657a..f388051 100644 --- a/src/jalview/analysis/TreeBuilder.java +++ b/src/jalview/analysis/TreeBuilder.java @@ -31,6 +31,7 @@ import jalview.datamodel.SequenceNode; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; + import java.util.ArrayList; import java.util.BitSet; import java.util.List; @@ -45,7 +46,7 @@ public abstract class TreeBuilder extends TreeEngine protected SequenceI[] sequences; protected List labels; - + public AlignmentView seqData; private AlignmentView seqStrings; @@ -110,6 +111,10 @@ public abstract class TreeBuilder extends TreeEngine { return true; } + + public List getLabels(){ + return this.labels; + } /** * Calculates the tree using the given score model and parameters, and the diff --git a/src/jalview/gui/TreeCanvas.java b/src/jalview/gui/TreeCanvas.java index 4efedc3..494360f 100755 --- a/src/jalview/gui/TreeCanvas.java +++ b/src/jalview/gui/TreeCanvas.java @@ -30,6 +30,7 @@ import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; +import java.awt.Stroke; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; @@ -39,6 +40,7 @@ import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedHashSet; @@ -46,6 +48,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Vector; +import org.jcolorbrewer.ColorBrewer; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -87,7 +90,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, /** DOCUMENT ME!! */ public static final String PLACEHOLDER = " * "; - private static final int DASHED_LINE_Y_OFFSET = 5; + private static final int DASHED_LINE_Y_OFFSET = 6; TreeModel tree; @@ -106,8 +109,10 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, boolean fitToWindow = true; boolean showDistances = false; - - boolean showSecondaryStructureProvider = false; + + boolean showStructureProviderLabels = false; + + boolean showStructureProviderColouredLines = false; boolean showBootstrap = false; @@ -302,8 +307,12 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, return; } + Vector leaves = tree.findLeaves(node); + gatherLabelsTo(node, leaves); + if ((node.left() == null) && (node.right() == null)) { + Color originalColor, translucentColor = Color.WHITE; // Drawing leaf node double height = node.height; double dist = node.dist; @@ -323,7 +332,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, } else { - g.setColor(av.getSequenceColour(seq).darker()); + originalColor = av.getSequenceColour(seq); + translucentColor = new Color(originalColor.getRed(), originalColor.getGreen(), originalColor.getBlue(), 128); // 128 for 50% transparency + g.setColor(Color.black); } } else @@ -331,7 +342,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, g.setColor(Color.black); } - // Draw horizontal line + // horizontal line g.drawLine(xstart, ypos, xend, ypos); String nodeLabel = ""; @@ -350,8 +361,17 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, nodeLabel = nodeLabel + String.valueOf(node.bootstrap); } + if(node.hasLabel() && showStructureProviderColouredLines) { - if (!nodeLabel.equals("")) + drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart, xend, ypos, nodeLabel); + + Rectangle labelBounds = new Rectangle(xstart, ypos, xend, ypos + DASHED_LINE_Y_OFFSET); + + // Add the bounding box to the map for this node + labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds); + + } + else if (!nodeLabel.equals("")) { g.drawString(nodeLabel, xstart + 2, ypos - 2); } @@ -368,7 +388,13 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, charWidth, charHeight); nameHash.put(node, rect); - + + g.setColor(translucentColor); + g.fillRect(xend + 10, ypos - charHeight / 2, charWidth, charHeight); + //g.fillRect(xstart - 2, ypos - 10, (xend + 20 + charWidth) - xstart, 20); + + g.setColor(Color.black); + // Colour selected leaves differently boolean isSelected = false; if (tp.isColumnWise()) @@ -410,8 +436,11 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, int xend = (int) (height * wscale) + offx; int ypos = (int) (node.ycount * chunk) + offy; - g.setColor(node.color.darker()); + //g.setColor(node.color.darker()); + + g.setColor(Color.black); + // Draw horizontal line g.drawLine(xstart, ypos, xend, ypos); if (node == highlightNode) @@ -452,66 +481,65 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, } - boolean showColouredLinesForSSProviders = true; - - //Display secondary structure providers as labels only if: + //Display secondary structure providers only if: // ~ node has Label assigned (Secondary structure providers) - // ~ node count is greater than 3 - // ~ showSecondaryStructureProvider option is set to true by the user - if ( node.hasLabel() && showSecondaryStructureProvider && showColouredLinesForSSProviders) - { - - drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart, xend, ypos, nodeLabel); - - int labelWidth = 20; - int labelHeight = fm.getHeight(); - - // Calculate the bounding box of the string - int xLabelPos = xstart + 2; - int yLabelPos = ypos - 2; - Rectangle labelBounds = new Rectangle(xLabelPos, yLabelPos - labelHeight, labelWidth, labelHeight); - - // Add the bounding box to the map for this node (list allows multiple bounding boxes) - labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds); - - } - else if ( node.hasLabel() && showSecondaryStructureProvider && node.count > 3) - { - - String label = node.getLabel(); + // ~ either label or coloured lines option is selected by the user + boolean labelHandled = false; + if(node.hasLabel()) { - if(label.length() > labelLengthThreshold) { + if (showStructureProviderColouredLines) + { + drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart, xend, ypos, nodeLabel); + + Rectangle labelBounds = new Rectangle(xstart, ypos, xend, ypos + DASHED_LINE_Y_OFFSET); + + // Add the bounding box to the map for this node (list allows multiple bounding boxes) + labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds); + labelHandled = true; - //label = AlignmentUtils.reduceLabelLength(label); } - nodeLabel = label + " | " + nodeLabel; - - // Split the nodeLabel by "|" - String[] lines = nodeLabel.split("\\|"); - - // Iterate over the lines and draw each string separately - String longestLabelString = ""; - int i = 0; - for (i = 0; i < lines.length; i++) { - g.drawString(lines[i].trim(), xstart + 2, ypos - 2 - (i * fm.getHeight())); - if(longestLabelString.length() < lines[i].trim().length()) { - longestLabelString = lines[i].trim(); - } + if (showStructureProviderLabels && node.count > 3) + { + + String label = node.getLabel(); + + if(label.length() > labelLengthThreshold) { + + //label = AlignmentUtils.reduceLabelLength(label); + } + + nodeLabel = label + " | " + nodeLabel; + + // Split the nodeLabel by "|" + String[] lines = nodeLabel.split("\\|"); + + // Draw each string separately + String longestLabelString = ""; + int i = 0; + for (i = 0; i < lines.length; i++) { + g.drawString(lines[i].trim(), xstart + 2, ypos - 2 - (i * fm.getHeight())); + if(longestLabelString.length() < lines[i].trim().length()) { + longestLabelString = lines[i].trim(); + } + } + + int labelWidth = fm.stringWidth(longestLabelString); + int labelHeight = fm.getHeight() * (i-1); + + // Bounding box of the string + int xLabelPos = xstart + 2; + int yLabelPos = ypos - 2; + Rectangle labelBounds = new Rectangle(xLabelPos, yLabelPos - labelHeight, labelWidth, labelHeight); + + // Add the bounding box to the map for the node + labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds); + + labelHandled = true; } - - int labelWidth = fm.stringWidth(longestLabelString); - int labelHeight = fm.getHeight() * (i-1); - - // Calculate the bounding box of the string - int xLabelPos = xstart + 2; - int yLabelPos = ypos - 2; - Rectangle labelBounds = new Rectangle(xLabelPos, yLabelPos - labelHeight, labelWidth, labelHeight); - - // Add the bounding box to the map for this node (list allows multiple bounding boxes) - labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds); } - else if (!nodeLabel.equals("")) + + if (!nodeLabel.equals("") && !labelHandled) { g.drawString(nodeLabel, xstart + 2, ypos - 2); } @@ -521,18 +549,24 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, private void drawLinesAndLabelsForSecondaryStructureProvider(Graphics g, BinaryNode node, int xstart, int xend, int ypos, String nodeLabel) { - // Cast the Graphics object to Graphics2D + Graphics2D g2d = (Graphics2D) g.create(); // Set dash pattern - float[] dashPattern = {2, 3}; +// float[] dashPattern = {2, 2}; +// g2d.setStroke(new BasicStroke( +// 2.5f, +// BasicStroke.CAP_BUTT, +// BasicStroke.JOIN_ROUND, +// 0.0f, +// dashPattern, +// 0.0f)); + g2d.setStroke(new BasicStroke( - 1.5f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_ROUND, - 0.0f, - dashPattern, - 0.0f)); + 4.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND + )); String label = node.getLabel(); String[] lines = label.split("\\|"); @@ -552,7 +586,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, int secondHalfLinesCount = lines.length - mid; drawSecondaryStructureProviderLinesSection(g2d, lines, mid, lines.length, xstart, xend, - ypos + DASHED_LINE_Y_OFFSET, + ypos, false); drawVerticalLineAndLabel(g, xstart, ypos, secondHalfLinesCount, false, nodeLabel); @@ -560,26 +594,36 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, } private void drawSecondaryStructureProviderLinesSection(Graphics2D g2d, String[] lines, int start, int end, int xstart, int xend, int baseY, boolean above) { - for (int i = start; i < end; i++) { + + for (int i = start, j=0; i < end; i++, j++) { int adjustedY = above ? baseY - ((i - start) * DASHED_LINE_Y_OFFSET) : baseY +((i - start) * DASHED_LINE_Y_OFFSET); - Color providerColor = AlignmentUtils.getSecondaryStructureProviderColor(lines[i]); + //Color providerColor = AlignmentUtils.getSecondaryStructureProviderColor(lines[i]); + + Map secondaryStructureProviderColorMap = tp.getSecondaryStructureProviderColorMap(); + Color providerColor = secondaryStructureProviderColorMap.getOrDefault(lines[i].toUpperCase().trim(), Color.BLACK); g2d.setColor(providerColor); - g2d.drawLine(xstart, adjustedY, xend, adjustedY); + if(i==start && !above) { + g2d.drawLine(xstart, adjustedY, xend-3, adjustedY); + } + else + { + g2d.drawLine(xstart, adjustedY, xend, adjustedY); + } } } private void drawVerticalLineAndLabel(Graphics g, int xstart, int ypos, - int linesCount, boolean above, String nodeLabel) { - int adjustedY = above - ? ypos - (linesCount) * DASHED_LINE_Y_OFFSET - : ypos + (linesCount) * DASHED_LINE_Y_OFFSET; + int linesCount, boolean above, String nodeLabel) { + + int adjustment = (linesCount * DASHED_LINE_Y_OFFSET) + (DASHED_LINE_Y_OFFSET / 3); + int adjustedY = ypos + (above ? -adjustment : adjustment - DASHED_LINE_Y_OFFSET); - // Draw vertical line + // draw vertical line g.drawLine(xstart, ypos, xstart, adjustedY); - // Draw label + // draw label if(above && !nodeLabel.equals("")) g.drawString(nodeLabel, xstart + 2, adjustedY - 2); } @@ -1232,7 +1276,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, setColor(groups.get(i), col.brighter()); Vector l = tree.findLeaves(groups.get(i)); - gatherLabelsTo(groups.get(i), l); + //gatherLabelsTo(groups.get(i), l); if (!tp.isColumnWise()) { createSeqGroupFor(aps, l, col, groups.get(i).getLabel()); @@ -1574,15 +1618,30 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable, repaint(); } - /** - * DOCUMENT ME! - * - * @param state - * DOCUMENT ME! - */ - public void setShowSecondaryStructureProvider(boolean state) + public void hideStructureProviders(boolean state) + { + if(state) { + this.showStructureProviderColouredLines = false; + this.showStructureProviderLabels = false; + repaint(); + } + } + + public void setShowStructureProviderColouredLines(boolean state) { - this.showSecondaryStructureProvider = state; + this.showStructureProviderColouredLines = state; + if(state) { + this.showStructureProviderLabels = false; + } + repaint(); + } + + public void setShowStructureProviderLabels(boolean state) + { + this.showStructureProviderLabels = state; + if(state) { + this.showStructureProviderColouredLines = false; + } repaint(); } diff --git a/src/jalview/gui/TreePanel.java b/src/jalview/gui/TreePanel.java index 6a1b381..0fae337 100755 --- a/src/jalview/gui/TreePanel.java +++ b/src/jalview/gui/TreePanel.java @@ -21,8 +21,12 @@ package jalview.gui; import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; import java.awt.Graphics; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; @@ -32,14 +36,17 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import javax.swing.ButtonGroup; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; import javax.swing.SwingConstants; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; @@ -47,6 +54,7 @@ import javax.swing.event.InternalFrameEvent; import org.jibble.epsgraphics.EpsGraphics2D; import jalview.analysis.AlignmentSorter; +import jalview.analysis.AlignmentUtils; import jalview.analysis.AverageDistanceTree; import jalview.analysis.NJTree; import jalview.analysis.TreeBuilder; @@ -103,6 +111,8 @@ public class TreePanel extends GTreePanel // New JLabel for subtitle private JLabel subtitleLabel; + + private Map secondaryStructureProviderColorMap; /** * Creates a new TreePanel object. @@ -191,6 +201,12 @@ public class TreePanel extends GTreePanel // @Mungo - Why don't we return our own viewport ??? return getTreeCanvas().getViewport(); } + + + public Map getSecondaryStructureProviderColorMap() + { + return secondaryStructureProviderColorMap; + } private void addSubtitlePanel(String subTitle) { @@ -446,6 +462,11 @@ public class TreePanel extends GTreePanel TreeBuilder njtree = treeType.equals(TreeBuilder.NEIGHBOUR_JOINING) ? new NJTree(av, sm, similarityParams) : new AverageDistanceTree(av, sm, similarityParams); + List labels = njtree.getLabels(); + if(labels != null && labels.size()>0) { + secondaryStructureProviderColorMap = new HashMap(); + AlignmentUtils.assignSecondaryStructureProviderColor(secondaryStructureProviderColorMap, labels); + } tree = new TreeModel(njtree); // don't display distances for columnwise trees } @@ -769,16 +790,22 @@ public class TreePanel extends GTreePanel treeCanvas.setShowDistances(distanceMenu.isSelected()); } - /** - * DOCUMENT ME! - * - * @param e - * DOCUMENT ME! - */ @Override - public void showSecondaryStructureProviderMenu_actionPerformed(ActionEvent e) + public void hideStructureProviders_actionPerformed(ActionEvent e) + { + treeCanvas.hideStructureProviders(hideStructureProviders.isSelected()); + } + + @Override + public void showStructureProviderColouredLines_actionPerformed(ActionEvent e) + { + treeCanvas.setShowStructureProviderColouredLines(showStructureProviderColouredLines.isSelected()); + } + + @Override + public void showStructureProviderLabels_actionPerformed(ActionEvent e) { - treeCanvas.setShowSecondaryStructureProvider(showSecondaryStructureProviderMenu.isSelected()); + treeCanvas.setShowStructureProviderLabels(showStructureProviderLabels.isSelected()); } /** diff --git a/src/jalview/jbgui/GTreePanel.java b/src/jalview/jbgui/GTreePanel.java index 884f3eb..9120b15 100755 --- a/src/jalview/jbgui/GTreePanel.java +++ b/src/jalview/jbgui/GTreePanel.java @@ -24,12 +24,16 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JInternalFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; @@ -65,7 +69,16 @@ public class GTreePanel extends JInternalFrame //Menu option for the user to select their preference in //displaying secondary structure providers as labels. //Visible only for secondary structure similarity. - public JCheckBoxMenuItem showSecondaryStructureProviderMenu = new JCheckBoxMenuItem(); + + public JMenu showSecondaryStructureProviderMenu = new JMenu(); + + ButtonGroup showSecondaryStructureProviderButtonGroup = new ButtonGroup(); + + public JRadioButtonMenuItem hideStructureProviders = new JRadioButtonMenuItem(); + + public JRadioButtonMenuItem showStructureProviderLabels = new JRadioButtonMenuItem(); + + public JRadioButtonMenuItem showStructureProviderColouredLines = new JRadioButtonMenuItem(); public JCheckBoxMenuItem fitToWindow = new JCheckBoxMenuItem(); @@ -179,15 +192,43 @@ public class GTreePanel extends JInternalFrame distanceMenu_actionPerformed(e); } }); + + showSecondaryStructureProviderButtonGroup.add(hideStructureProviders); + showSecondaryStructureProviderButtonGroup.add(showStructureProviderLabels); + showSecondaryStructureProviderButtonGroup.add(showStructureProviderColouredLines); showSecondaryStructureProviderMenu.setText(MessageManager.getString("label.show_secondary_structure_provider")); - showSecondaryStructureProviderMenu.addActionListener(new java.awt.event.ActionListener() + hideStructureProviders.setText(MessageManager.getString("label.hide_structure_provider")); + hideStructureProviders.setSelected(true); + hideStructureProviders.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - showSecondaryStructureProviderMenu_actionPerformed(e); + hideStructureProviders_actionPerformed(e); } }); + + showStructureProviderLabels.setText(MessageManager.getString("label.show_structure_provider_as_labels")); + showStructureProviderLabels.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + showStructureProviderLabels_actionPerformed(e); + } + }); + + showStructureProviderColouredLines.setText(MessageManager.getString("label.show_structure_provider_as_coloured_lines")); + showStructureProviderColouredLines.addActionListener(new java.awt.event.ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + showStructureProviderColouredLines_actionPerformed(e); + } + + }); + fitToWindow.setSelected(true); fitToWindow.setText(MessageManager.getString("label.fit_to_window")); fitToWindow.addActionListener(new java.awt.event.ActionListener() @@ -259,7 +300,7 @@ public class GTreePanel extends JInternalFrame viewMenu.add(fitToWindow); viewMenu.add(font); viewMenu.add(distanceMenu); - viewMenu.add(showSecondaryStructureProviderMenu); + viewMenu.add(showSecondaryStructureProviderMenu); viewMenu.add(bootstrapMenu); viewMenu.add(placeholdersMenu); viewMenu.add(sortAssocViews); @@ -267,6 +308,10 @@ public class GTreePanel extends JInternalFrame saveAsMenu.add(saveAsNewick); saveAsMenu.add(epsTree); saveAsMenu.add(pngTree); + showSecondaryStructureProviderMenu.add(hideStructureProviders); + showSecondaryStructureProviderMenu.add(showStructureProviderLabels); + showSecondaryStructureProviderMenu.add(showStructureProviderColouredLines); + } public void printMenu_actionPerformed(ActionEvent e) @@ -284,6 +329,18 @@ public class GTreePanel extends JInternalFrame public void showSecondaryStructureProviderMenu_actionPerformed(ActionEvent e) { } + + public void hideStructureProviders_actionPerformed(ActionEvent e) + { + } + + public void showStructureProviderColouredLines_actionPerformed(ActionEvent e) + { + } + + public void showStructureProviderLabels_actionPerformed(ActionEvent e) + { + } public void bootstrapMenu_actionPerformed(ActionEvent e) { -- 1.7.10.2