From a9e9fad222ac267d134069b5323744ae989f3775 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 11 Feb 2021 17:00:43 +0100 Subject: [PATCH] Extras: FlatInspector: tooltip is no longer limited to window bounds --- CHANGELOG.md | 4 + .../formdev/flatlaf/extras/FlatInspector.java | 85 +++++++++++++----- images/extras-FlatInspector.png | Bin 10161 -> 8551 bytes 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61bade10..95dbf692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ FlatLaf Change Log ## 1.0-rc4-SNAPSHOT +#### New features and improvements + +- Extras: UI Inspector: Tooltip is no longer limited to window bounds. + #### Fixed bugs - TabbedPane: Custom `TabbedPane.selectedForeground` color did not work when diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java index 2685702d..cc6a84d3 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java @@ -38,6 +38,9 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Field; @@ -48,6 +51,8 @@ import javax.swing.JRootPane; import javax.swing.JToolBar; import javax.swing.JToolTip; import javax.swing.KeyStroke; +import javax.swing.Popup; +import javax.swing.PopupFactory; import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; import javax.swing.border.Border; @@ -55,6 +60,7 @@ import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.plaf.UIResource; import javax.swing.text.JTextComponent; +import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.UIScale; @@ -82,7 +88,6 @@ import com.formdev.flatlaf.util.UIScale; public class FlatInspector { private static final Integer HIGHLIGHT_LAYER = 401; - private static final Integer TOOLTIP_LAYER = 402; private static final int KEY_MODIFIERS_MASK = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK; @@ -90,6 +95,8 @@ public class FlatInspector private final MouseMotionListener mouseMotionListener; private final AWTEventListener keyListener; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this ); + private final WindowListener windowListener; + private Window window; private boolean enabled; private Component lastComponent; @@ -99,7 +106,7 @@ public class FlatInspector private boolean wasCtrlOrShiftKeyPressed; private JComponent highlightFigure; - private JToolTip tip; + private Popup popup; /** * Installs a key listener into the application that allows enabling and disabling @@ -189,6 +196,18 @@ public class FlatInspector } } }; + + windowListener = new WindowAdapter() { + @Override + public void windowActivated( WindowEvent e ) { + update(); + } + + @Override + public void windowDeactivated( WindowEvent e ) { + hidePopup(); + } + }; } private void uninstall() { @@ -221,12 +240,28 @@ public class FlatInspector rootPane.getGlassPane().setVisible( enabled ); + // add/remove key listener Toolkit toolkit = Toolkit.getDefaultToolkit(); if( enabled ) toolkit.addAWTEventListener( keyListener, AWTEvent.KEY_EVENT_MASK ); else toolkit.removeAWTEventListener( keyListener ); + // add/remove window listener + if( enabled ) { + System.out.println( "add "+window ); + window = SwingUtilities.windowForComponent( rootPane ); + if( window != null ) + window.addWindowListener( windowListener ); + } else { + System.out.println( "rem" ); + if( window != null ) { + window.removeWindowListener( windowListener ); + window = null; + } + } + + // show/hide popup if( enabled ) { Point pt = new Point( MouseInfo.getPointerInfo().getLocation() ); SwingUtilities.convertPointFromScreen( pt, rootPane ); @@ -242,14 +277,19 @@ public class FlatInspector highlightFigure.getParent().remove( highlightFigure ); highlightFigure = null; - if( tip != null ) - tip.getParent().remove( tip ); - tip = null; + hidePopup(); } propertyChangeSupport.firePropertyChange( "enabled", !enabled, enabled ); } + private void hidePopup() { + if( popup != null ) { + popup.hide(); + popup = null; + } + } + public void update() { if( !rootPane.getGlassPane().isVisible() ) return; @@ -303,7 +343,7 @@ public class FlatInspector continue; // ignore highlight figure and tooltip - if( c == highlightFigure || c == tip ) + if( c == highlightFigure ) continue; // ignore glass pane @@ -357,26 +397,24 @@ public class FlatInspector } private void showToolTip( Component c, int x, int y, int parentLevel ) { - if( c == null ) { - if( tip != null ) - tip.setVisible( false ); + hidePopup(); + + if( c == null || (window != null && !window.isActive()) ) return; - } - - if( tip == null ) { - tip = new JToolTip(); - rootPane.getLayeredPane().add( tip, TOOLTIP_LAYER ); - } else - tip.setVisible( true ); + JToolTip tip = new JToolTip(); tip.setTipText( buildToolTipText( c, parentLevel ) ); + tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true ); + + Point pt = new Point( x, y ); + SwingUtilities.convertPointToScreen( pt, rootPane.getGlassPane() ); + int tx = pt.x + UIScale.scale( 8 ); + int ty = pt.y + UIScale.scale( 16 ); - int tx = x + UIScale.scale( 8 ); - int ty = y + UIScale.scale( 16 ); Dimension size = tip.getPreferredSize(); // position the tip in the visible area - Rectangle visibleRect = rootPane.getVisibleRect(); + Rectangle visibleRect = rootPane.getGraphicsConfiguration().getBounds(); if( tx + size.width > visibleRect.x + visibleRect.width ) tx -= size.width + UIScale.scale( 16 ); if( ty + size.height > visibleRect.y + visibleRect.height ) @@ -386,8 +424,9 @@ public class FlatInspector if( ty < visibleRect.y ) ty = visibleRect.y; - tip.setBounds( tx, ty, size.width, size.height ); - tip.repaint(); + PopupFactory popupFactory = PopupFactory.getSharedInstance(); + popup = popupFactory.getPopup( c, tip, tx, ty ); + popup.show(); } private static String buildToolTipText( Component c, int parentLevel ) { @@ -473,9 +512,9 @@ public class FlatInspector } private static void appendRow( StringBuilder buf, String key, String value ) { - buf.append( "" ) + buf.append( "" ) .append( key ) - .append( ":" ) + .append( ":" ) .append( value ) .append( "" ); } diff --git a/images/extras-FlatInspector.png b/images/extras-FlatInspector.png index 4dd498429c154600684860434ef3491492f992c3..8dfb8499f9c3c187ab0f895cf3f43ada3ad329a3 100644 GIT binary patch literal 8551 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 R`R_jskjJ`@D%7mQ{tvl}L&E?7 literal 10161 zcmY+q2{cr1{6BtYT;|%ZU6x!@vLs5@Fk_1-vXl^GE1{BPUuH(32q{a+7G=x6CmBTu zS+gV}vae$w+kZaa-|zg+_kZql&U4TEdA-;BKF|Ao?|q(_T)x1{B)|j!0IPw%jwt}3 zK>$GAf#_%y<4#gO0MG#@M&`OyD%A;4SzTS-+1ZKer#^rFoCcs!D2IoKRBG8;Umt~1 z5Z+0l_D9(RN@X;3nNwq9qe@i2QyCR-DsuvWej1V5|KFWTlnMYG(q_P^KT4&uv(pK1 zqI8DSs0V-k9P~Vzul__Sum^zuptPxzLa{HP6i_HpDk^|dxKenh3ZQa$Sfxa>z`j65 zC5mR!&i3}!=9Us*Pada9Qle0Lp7rniCj(H5i;JV-mY0{;`VxzxQg?RB;w$>lXf%b= z=>^ECL`69{se~&5v@5EN8Wk0F6hN)4tU4(xQD0EiciP+A#~KDS+Ub8*)I+hiSNfWjMI9dQf2JlSbyiaeS40z}617(0O>?yVeV!Kp@bQU-hub@s z?Kq*;)SmTI`ucWu`X?s;4G;hB==c$(;uO_iwzjsGN^_Vp-a`wKl2VzIin6jJIXwbU zvJWo^U+M0q^b}PmC#Ob5ZEY4m?cFl=uGrixuI%fJh)N$B8EI*0nP_a};}%JcDvB!V zVP@uAU*B@3LtiwsprdnMOSJeSAE(W ze6{eUx#|7;#&_@d`HzKn7EsHgs;WP4ZS|#+$*HO2>L6SXEh4F8iPN}JXSz;GC+*3{ z%K>H1bjEVt;}dWDsr@2y-jx=BDxI3WQh0&Ak})8stQ=L=ALUrQxxatt>FM19fO>i+ zuU@6m67yNv&Mtt8_qHJSkRz1=l=9Pp&Tu+4r*I{EFAF&})kqOJi}*xu5kM|pPL3A5 z&CL?~@NmFB(8-A=(#cuvncOQDEdW3O109^X@2`avHxI4>9)fexb%SqTO2ym0q~p(q z-f?f1l)LHxHuXioSTyHCQW7W2snd>-;v+3B@~4ZY7X^{2p@eHlZ29rqVNNGlovFtR z1b@A6HR>^V@k%jcdBBVM=Ca-Nn}99nwo?1(~_IJsyn03inP?7XqUi8JI=nxzZ=Cgnt(&O5#-fF21|v=7|ihzWxH3VtMVU{rcjbL+J~%KAl~Q<&KP@ z$nK)?tm5K4qi)3urIfkV2J=VhiKDDMi`X8-#kCLDHOQ?5=ErC| zH|My=QT>LPOC8%z9ccSh%}A+PTl|zg{Kb{a-cUW+a{v7Xy+ z!*Xfr=e>Id;$X+d$BRK_dB2+3KZNd2V7`n$?63MVZsxJh9^RmjpP+mlzm`f~WRGJ+ z-L@z&x0-)HwaQt|FvwI%@Jmli;tvc{p zol5HF!8q0+q{J0=?i2R%m_Bi6*#ep3t-jT?^Q(4ie zzEiufK)->s&NE(3FHIC-z;ye|329u;tNL6K%|@E=b=_f4yYx{dCm&b$W6#|Sy7{Bf zND&O8f*DX}6xA`+mUDyNqaaOH(Lti#0jpZvxDL+KK^DrwI7o^pW zGt5tgMtU1m3;#y$vYk;YzAYj_XL!}^Ob4#XJXm^QMB_o_-n-M28CSZ5wA~A^(ztI9 zqC#)bOJBLC_$fsv7)ZiJ7epkKzlc_E-krR+mLajt%qHy744-dW15w-bjHL9K`{+Jd zDroP4YETRO2d{&CT?UiUqP|bN5)_){MlP@%0V|(jI33yARUBO2)`SjV&iIf;i|_1R z(Gt>@_mL}yS=@P7^A#VHPGwDshGW~s*d#$ZP9BnA6e%N|%o1lm?koi=GG9RuxlTM9D1q&VR#^J4NvQ(_GvE%Td_og9{fGmnuclU_Uqe))j zV_~|#Ds-^1ui!Tg9h|ag^b0MM`f7sH;3Z})kE!)!sNu2kH_@*>c4Gqy$H7R=PU@O{ zLUR0tSmM-WFDA8j%8hZGXIO$SnQ58e1y6$6cWzxhd|O%e)B9_`Uv6bcD+n>UA7N+^ zG&C-X%d$vOa<9CR@>Zh72uk==!t^j;$!~kJh8azYdPJD7r2mATPfkITjKZ+gpMRMX ze=PFCI*$oxmRmm({<+wbzG450-#qRKX~=s(shV5!FaFLV4B&AtY{l`@Tg*gJY55_T zJN`RGzers=JLXWje302$rTkL%co-&hQG_A>`;bXX*DpRWIA$XHO?AkGZQ4dnJAl%A zaUpRO78hlgR|TUTl-#Gjg#iM?skTl8vgK`&I{j;3>rYyxOxC>rIZ;TT)s6HW<#L{C zX$NoL+qmrQ-wrg?P1JNu?>tVoZalIznuP7$o-S+^0}Wnv}?1Ex+zPCcWL;hM-m^9t29rw z$^O&3TBtSCuycLL**@`YKK1vyWb;|C8=KC`KV{B)N8T{d3LqWLbv{4K63t)6>DQqu zOT6rG587sL^G6T%EPhiI0LQp|U)FveUuZVHprX~~;ho$Ud;xyQR!PFa=2ZHC48e|% zbzP446GUA$<#)d2Z~xv~aQv)t!mh5@e!^y+bT_on(C(YrPTPYSmiMcSZ?%DfZyy@_ z2-pEGW#^jn%~y=7QuD)AJkq;EM7duJxF6<}#^Q7D3Fg%WT~_*qVnZ#6 ztCn;=oBo$K4R=|jJA@3jeJ_6aV5?Erd?^Iqv-?x!6XuH>U5=%Zd^W-a4yL_OHMCWn z;wwG>@VnW$o5!UpvR>1r7z3`EX+trps}GuTrqUg2`wmicZ~Pp&cEWG)`P=$DA$&`(8|1SYkX@fP@#2Lko0nyQI79WV^MzCvIZ7Q0!wtV%9Zd0_nT;y59@kHHFtUM-nnJdY= z5f)bNIlJw=)zL{j`cWqB4vY@4SLuD*cfVpjCPTB6{q2<`deDhD7peVk#8lhC z#}c@Fnb{A$EY}c2FMcTksS~y1avfK*WjS>qqX;KRwlhSLN@IdjR4S9ZIwiAL7I6~E- zVqIKY`GDtJLaXEHoY|-`Z-O_xhEi_%iF*;vp`HZ!(=8e@tQ~J z5%x!^wqTm4rEyNTbZyHlJ^%wk}`4R4Y+TxZTuEFh0$2kp;jbf__4b<#Ws0`Oy8vCdMuCVjma4bmJ%fR3UeG%TwhxO5{a)@C3hv z2Y2tI(^esGjN;U-SGcCyQ=S8NY#vW-anmTK1t4D1eMC2d4=hAEbj0)ig^7NM^MlV+&cRpxHB>A zX(t|H;AW0<;2@$&xCjZD69c}ys$+26sJzO72|B}wHWH6Wh?YWH5QvjoQ5Mm6hUA(W z^Tg9kD;qLp1mnGvZpsz7ZbxkN#zBz;d`l4NRhj&Bl0;gx$*6DcLf7paoQWwTsXEX% zjguYDM37=BL-?gp&SY!$uUhsUwz3zKPYkRQ$EJ`O`OniyZ841}AxHuG@Q|w_5x+?w zcqVi}MBOT^P85j%>~8-_-*kI9*_#TVJgRM*_loW_6Hvg0MbRs~{9yMM+kBCRN+(IY z{_EB~u=Y>i|1*aVS_zZOfU>41+>Efq63^u3GzsU<(>Kwy_z%&S86nTEaE9-E0r^d^ zhL2|wPNtiXf|+QgnLxOT!K3KUU$S{cst0=E&36F{9CI;fYNWuD;l18f=~Te)Wm3qLCovAO41!*1Z3(5gTdO z5*Dy`rT^vJ{x{;m1e4{}W1Y?%a1u!RP*FbRZZE_f*~E2?)?ze7*yCs|O+df;OTS9F z&t0*>*&Jt>NW*sxU)WE4s7o(=J6HF8myPhWG;ouIT6{*g+RWp`3(lVLiH#4HoPF^* z!)r?UapSd@{iDiohz*fIegi9?@EeL-U$_MB@f_Qf84<*AJ9howC2k8%>^(lbn|?C^ zNv%dp;blJ($mTGXeXM6x2kSb}j!U4#p$*^Mr`NDaCOgtBW;kWa&vMgZ)No7?BpKaT6XmxR{pUf0PFK7$dIz!hay}Bix(_O zvsNnnp!oKQzRPU7cmzur{cBD5O*%?tM`!LF(Iu9LBjIl%kN$e#f9FuE+pa4}bIQ#p z!6r_u;*B2z()2I-$eCS_o65^;8I74gCdCx*G6nW|@H9v#F_Nh7o;Bj{GDB>FENl(Z zEg&e&%0GAlj$K*5^+VlRlw@<4=V*j@N#M%QjfkW~_I5pM5R^LqFI`PzD$0u|OE(IvzX9Fe>-pA8qZB;V}U-1 zRT%c7o)~|XqNLvn;VX~8nTRzY+8a1wFfP`WH>@sAe5*Xf_Bwx_SjE7r$D)f2!aMa0 zx2rrh?=>R~xCrpc34zISM}C`nKfW@~P~;y;XC(409nqenSgFCJib?O31MF0G@`}jX z8!XnK38USaOg4XH)rhq00kFFg#OC{0A{zXbOqlX7m9UgzKp}(QpJNZVM?ssjLZ^5_ zX&}+=J`%EW;^bffK9~Pd6m})w{Nyw*`1caNA5<`u;R}srhtjc9o=PVHXuV1l8@sO` z8?Z=wPlf=r0s%NBij%Sm-UXlEahx|cxy4Q}j%};F9}t4JJ}pI-&}RXecerS@6VL}u zV%f2iWQi6Qus@AF#KAqrHOYXUFosWdH%M4AfbC+@Ggqd|S?4Vsb<8G=O-hadX?PX5 zy-w@loxfqnqpnnzP`S+2C20~E!8v1?00feLVzCr7(--R0x$t+XMt&bOB|2~_jfPgd zZe|uqR=p($&OxgE`4-5(9}+G$TyJ7OM{t^Irg~V;-G4%u7|3Qjk?LacQa`z`#8wh2 zo#s-A0cBJsAN2)$bOh8zBEm&JH_tsu?k&-Z^i4rdrqu;5W68hzU{J8T1P!{;<5Vur zKg^sZaG3_dLdo2B?8*go`sw7t3lz=MCn0Nmy=+-L_m(?d!o=eK;D`y_9(>Z9X}n;Ep=_zC7F>t)ElRyHVB2@HTr;dPL#f zsrnE>PMz8q23Uu}mVjz_mePcUZMNoc(r~#bu6)YaKoT;cjy!7vMSHqwt zKd&wH^)i4i3ehL6{Hc0y-DS0Va{wSw{$3h>K%Adzng@thBZ(7o7BMF`$?u)bs13x4 zB$kJtrh>PYOoj|Tu^4@;3_=B*@jdks`P8xS`7Lp;+jf%)@^vlREQ&=)TLrSrr!=fe zj>0k?s9F@7>hNiByvEFuJ|OM4eF8Bp*d)oJbl`Nge+ieC#ft5G!)Li(Bh1w4KDO5v z(DnaWHCpx6pf;vb7LMI4580_4P#dpZ<9g1%*ZLwa^=Y-&#BAO3f_?8SL#h237Rcv{D@TJJljrVv^$K~u z5+Sj)Ii*@5{KE}#$M>=;&Hs>XZwAn?)k99 zLCOW5F?HwHX6?_a{)sdmU8DnV&^Hi=9LAsd=6=}QcA4a}Hqsq+Z;esUBmB&v9%~qv zqe95ciaz$Yk!)MCz{=>J)-J>h#X6g4pS>MS{uj@nxE z&(G|+k412dlnLg4p{k6#QYhy)89&zC`P5B0@6A$+Aw5f+MxnW50W{(NY~%!l2UgHa zNm$(b;D|sEF@_90jf0@z*25S3&V!)#ebuy}G)5@z zO18MlvFif!COdD|mmo-IfBE*d#ix2O89-d3RGrWLT9-Lr6_MG>pog~m-0^q+9aAfS zd(bD@+WBmUAfB1$P?3zlA|z*Qm*=Herffu3|Jj8U%9FM#iKRCuuhy2IfE4z=h2!lN ziJ!hK1ehgWB$&Z`S>G}*ckU!MthcACnKijK^M>htJ#C9_D`r$!!*2#XXURq)g|&+r z0dz5=Ck8bL0w@72fdNiOfi5*fJX;!G&L_xn1iV@6=y)MkC>*&0E4*$?E+Ex)@&XMb z7nYAM1bBnF_aRTP0e^56w?UcvbCGlgTTGA0y+MgFdt?#rLiv&<7v#GNsW!);Nn_9W zua5@6Xk)|)b;~7i>p8{X{8QpPK9;Z!1Xe>6@R52X|C&Jycqs<`l;|Bl{Thp3fB=#L z)!2dYSNW_ayNR_J~ z`i)}(cj)0Pr<+6mnu+J3n~7X*`=PhAFVJm$U3=W2b2Mx}-=3x1amOKh);&@{0$VHv zxs(-K0^q`Rlb?C#KF5hXo!=1IuGe>s^%Uge=nN*{g^{FLXSg2Cinut*E9jn7AduBj zuni+*vtjwyqb6eSe+mE>vvLht<;b>#@W2@36W*G2^1d_QN2MuNmqWaz!uw3j{%ky3 z$5e&X#2d#i_z$NYj5xoc&Y=-YHqcg1k%Ofr!X?MCG(J1;1yOBw_8LY;Q$vW}?y|%! zZ_GIuDifUvN#9`94BQQSr=V}HeKJvYt`8#M$7iwg-*9(^b`$h2E5G{~%MxL^U2xj` zpUmT5xHbK;t?9$mNAi{xpH63ml$fD#SyF6p`;bHq5A_Dh z7<+-NjuFK4Hvu}Wuk5~$CWYjAPTas|&S_|_Mdl^=ePeg(Tw+bVjBpcb@OcU83 zr$=t-C=0g)jKwniQO=+;4751vy9^KVP#@a2yu$F1h(51eCC=BPk01FRq_CNYdi~C$ zg;`x?vt5unIg?{^l;6kg6x67FPEsBWMO+8Z zodygAiUUa*8Nv&e(xEbv^s|s@u1?DYu@rjxl#g(XwHj?||1zwtGspi&at>9y~|v56`y+EP4o50Dqs*hTf1V6Q>lyk#E#~D@hmj zMS)o;C1GVc)S0Z71k+ekp8LobI%f{h7C_x56UqK8`mPRzFG-+bYlU4Pl6abpWL@Rc zDY=q)?H#)hF8r5~0zFj751!k|IDW*gij4=E0iZ(b@Ly=~zb3FJ>0r;hM>F_GT;EOM zxz(v=3;}-@fuGG5oDM#0y6vo*GiO5UPjTr2y^a)_*{3xAK?O+1aSq#s5}uQRb9(La zz4?dP;aQT|>8aB4C}z_RrL=ShLP3ych}t?fgZgxE^u>J1&uIo-e2LR~ z#t$00t34$4SJ06JcOzEQ2`(MnN_Q}a4(E!}XNgSGCEen2dN!~oNg%6HVrI1{RPF>h z>JJL?by1S!3Uk0ep}(uz($t3>$4RmN`1g*<5v`z1zKmIK6t(-9S@J}E=GhHjoU?t> z<6IQ2hmXz3pw+1VRjyiz*cRY{#@+TUp;ILvCLJW<$!JDet=DGWF;qp5{%=qelf!o;J?LwKC&lW%inh5p6WUAx zfJ#BseUwY5Wfa8Z%*_9q=*2xnFwjE6P(I%iY)mkyA+zU(S3VpWcx&ua%Y@$G&WQ#u zp6#k}n2`__`dyn@Nk0_FEQTc6U%Rg66EvE@ia?*BDBafR0=Z;IDSpg}?QyTzBQ=N$ z{747=Knpi!_pcIZA=q?*w2ZFzyHsU%=Dq6pS2O?3-NZV^+Juq}Nx>A`&!+<1e}Bxo zt-4YNN%azKFFzQXZ&0p@WB%(#8pw9KBvHj>g^n=0;kUl`YA}f!_I}cN2n9zhk^MP} z&!UtnPWoEi7v%VZ>a0YpJ!wUyc%J1{r?JM6}#+)1WXqWE3!PcXL}rl(7U&I|K)|_kQU*V z*bYLdJL*?%3upR+(uYfi+`4v|hS?fgwO(_56+zK&4V#9?Rm6@z*Z(C~J54X1D(?jGqr(WIc!;0W<44L2 zV&_Icy9b@X9wcesF&kVr`%QH59FE{!%1Zdgk+0e$toCGdm{NXQlHc zY(&`eJ?q3i-C-BbZ>;1zV}$Ou`XQ$99{6jvwz*w zGK_{W9=;$rPGJP4KX&&GdoE3d#IqBhIT5}HCEd2aa}A#<_9^HU%h|;T$Jj55YA>Di zc;&xFv`R3KKh|d2JZ$(n2wKw4t8e$PsyBJF1orK1=+D$Ln9*-U@{v)Om1LR4OG8)Q zs^WdqmS|@IK>UAa0U{Z8ueLmgNV2y%&enpHVn@>DFal`D8~^DV6qsCg_88=InkGhn zVtwUOaXU8eqF`LnE9+=(<-1HO1vD+Y&JSlLrQNd9ZO%=e@<$1E&B82i^t{t!)F^+L zG)iBbQFm!wY4l$AyOWmDjnBD2^@3szRv`nSzU$xh z8~he9bjswf{QK%ozA^cR(w})eog}Q$#AAHE_H4WWv5-#?*J_blBfdjGkYu6r5amEO z?Ohc2*tQ3N*_ES;vk(ufKPpgZZrylH)|G|ARmdYK9bN3^W-!B0j2$%xgH4nP zM6!9Fo>gT0c)aVDbPspr`8r zZy#}4BM#XV*C~DZ3IrLHu{YeP_Z5(3lXW-L)W||yvEJ?O+P~L$NkK38NxImTpfpj-0BG|X584*%@c)wTzub#pZdmABP`>(> z^R?E+z66~-7Mu~}G$O6uTAuno>v)iuHq1pDNq#Z9{%3l0WB)-I{)T9a^da@2d2wiJ z@%p_4aX!6dsg3N*Px96wAHDZIPxa$PBUI(yq})Bw*jck-XMDM7K4)5R(0AY+_$%2~ z3i`#7dj`BBs$AWY@8K^S4q^;E86A#^smG--aC}g&_>Y~bVX33DcXa7bz&pJTweV&v zY?t+&_6K#0TEQ)H)GnoU)5f3c5rQ4Tsfk&HAxlo(=2u4-wEo5hQsFS{Cb!Rc!q{z^ zD-E9Q{8G#4RC$|w&`sl07j8ib%xD!3kDm_OWLU<)kj$*lg1SdLcfwC%!xg_3yhLaH zqpZd|)O=;x>B0lfQWlrjCuU8xx{izxc|5L~zvtZ>b}b@|W$gO7N&kr-j1rAtz$N^+ zg9*#}_KSdJ(PP1#hbDd6p{*1(V$Y15Had1EE`k9W+I)l2Yt$j@?>?InSwOMv&KWCK zlR6}~^mDpx<-wS6ykquhZ1uen#=fl|!8_QM7%_nsW4o;|vB~peMj-ZA(YZs%SRXdi z%zG8V;8jbjspsi;U(mutp%4Di?vE7g z?RCtU(;e`TD|-U3o*iip`EH1JUD%4~v}fi_gR<+}4%vAo?0`m05LB0AOxdstaR r%IA#p*-+U{;$Z|XZF26wF1w1Y!zJl@k3iZfHo!plvQD8Ep7j3#?AKcw