From 9e36003152be3667daac188f02ad2fd7c308b57c Mon Sep 17 00:00:00 2001 From: Nathan Cannon Date: Mon, 14 Mar 2016 22:51:04 +0000 Subject: [PATCH] Now using glyphicons for media controls. --- .../java/musicplayer/LibraryConfigGUI.java | 1 + src/main/java/musicplayer/PlayerGUI.java | 62 ++++++++++++++---- src/main/java/musicplayer/util/Icons.java | 14 ++++ src/main/resources/LICENSE.txt | 2 + .../glyphicons-171-step-backward.png | Bin 0 -> 1279 bytes .../glyphicons-172-fast-backward.png | Bin 0 -> 1309 bytes src/main/resources/glyphicons-173-rewind.png | Bin 0 -> 1314 bytes src/main/resources/glyphicons-174-play.png | Bin 0 -> 1242 bytes src/main/resources/glyphicons-175-pause.png | Bin 0 -> 1194 bytes src/main/resources/glyphicons-176-stop.png | Bin 0 -> 1179 bytes src/main/resources/glyphicons-177-forward.png | Bin 0 -> 1308 bytes .../resources/glyphicons-178-fast-forward.png | Bin 0 -> 1302 bytes .../resources/glyphicons-179-step-forward.png | Bin 0 -> 1265 bytes 13 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 src/main/java/musicplayer/util/Icons.java create mode 100644 src/main/resources/LICENSE.txt create mode 100644 src/main/resources/glyphicons-171-step-backward.png create mode 100644 src/main/resources/glyphicons-172-fast-backward.png create mode 100644 src/main/resources/glyphicons-173-rewind.png create mode 100644 src/main/resources/glyphicons-174-play.png create mode 100644 src/main/resources/glyphicons-175-pause.png create mode 100644 src/main/resources/glyphicons-176-stop.png create mode 100644 src/main/resources/glyphicons-177-forward.png create mode 100644 src/main/resources/glyphicons-178-fast-forward.png create mode 100644 src/main/resources/glyphicons-179-step-forward.png diff --git a/src/main/java/musicplayer/LibraryConfigGUI.java b/src/main/java/musicplayer/LibraryConfigGUI.java index 49e4a18..c4c9958 100644 --- a/src/main/java/musicplayer/LibraryConfigGUI.java +++ b/src/main/java/musicplayer/LibraryConfigGUI.java @@ -17,6 +17,7 @@ class LibraryConfigGUI { frame.setContentPane(createUI()); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(300, 200); + frame.setMinimumSize(new Dimension(300, 200)); frame.setVisible(true); updateLibraryListContents(); } diff --git a/src/main/java/musicplayer/PlayerGUI.java b/src/main/java/musicplayer/PlayerGUI.java index f038616..0475d53 100644 --- a/src/main/java/musicplayer/PlayerGUI.java +++ b/src/main/java/musicplayer/PlayerGUI.java @@ -12,10 +12,12 @@ import musicplayer.model.Artist; import musicplayer.model.HasSongs; import musicplayer.model.Song; import musicplayer.swingmodels.PlaylistTableModel; +import musicplayer.util.Icons; import musicplayer.util.LibraryUtils; import musicplayer.util.PlaylistUtils; import javax.swing.*; +import javax.swing.event.HyperlinkEvent; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -27,7 +29,10 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -77,6 +82,7 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf DatabaseManager.init(); PlayerGUI playerGUI = new PlayerGUI(); JFrame frame = new JFrame(); + frame.setMinimumSize(new Dimension(600, 400)); frame.setContentPane(playerGUI.mainPanel); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.pack(); @@ -362,9 +368,10 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf private JToolBar createControlButtons() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); - JButton playButton = new JButton("Play"); + JPanel controlBar = new JPanel(new GridLayout(1, 5)); + JButton playButton = new JButton(); + playButton.setIcon(Icons.playIcon); playButton.setMnemonic('P'); - playButton.setDisplayedMnemonicIndex(0); playButton.addActionListener(e -> { if (playList.getRowCount() > 0) { if (playList.getSelectedRowCount() > 0) @@ -373,28 +380,31 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf playSong(playlistTableModel.getFirst()); } }); - toolBar.add(playButton); - JButton pauseButton = new JButton("Pause"); + controlBar.add(playButton); + JButton pauseButton = new JButton(); + pauseButton.setIcon(Icons.pauseIcon); pauseButton.setMnemonic('E'); pauseButton.addActionListener(e -> { player.pause(); setSongHighlighting(player.getCurrentSong()); // Resume won't function if a different song is selected. }); - toolBar.add(pauseButton); - JButton stopButton = new JButton("Stop"); + controlBar.add(pauseButton); + JButton stopButton = new JButton(); + stopButton.setIcon(Icons.stopIcon); stopButton.setMnemonic('S'); - stopButton.setDisplayedMnemonicIndex(0); stopButton.addActionListener(e -> player.stop()); - toolBar.add(stopButton); - JButton previousButton = new JButton("Previous"); + controlBar.add(stopButton); + JButton previousButton = new JButton(); + previousButton.setIcon(Icons.prevIcon); previousButton.setMnemonic('R'); previousButton.addActionListener(e -> playPreviousSong()); - toolBar.add(previousButton); - JButton nextButton = new JButton("Next"); + controlBar.add(previousButton); + JButton nextButton = new JButton(); + nextButton.setIcon(Icons.nextIcon); nextButton.setMnemonic('N'); - nextButton.setDisplayedMnemonicIndex(0); nextButton.addActionListener(e -> playNextSong()); - toolBar.add(nextButton); + controlBar.add(nextButton); + toolBar.add(controlBar); toolBar.add(createVolumeControls()); return toolBar; } @@ -489,6 +499,32 @@ public class PlayerGUI implements PlayerCallbackInterface, LibraryCallbackInterf // Add everything to the menu bar itself menuBar.add(playlistTools); + + JMenu helpMenu = new JMenu("Help"); + menuItem = new JMenuItem("About"); + menuItem.addActionListener(e -> { + try { + //noinspection ConstantConditions + JEditorPane messagePane = new JEditorPane("text/html", Files.readAllLines( + Paths.get(PlayerGUI.class.getClassLoader().getResource("LICENSE.txt").toURI())).get(0)); + messagePane.setEditable(false); + messagePane.addHyperlinkListener(hl -> { + if (hl.getEventType() == HyperlinkEvent.EventType.ACTIVATED) + if(Desktop.isDesktopSupported()) + try { + Desktop.getDesktop().browse(hl.getURL().toURI()); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + }); + JOptionPane.showMessageDialog(mainPanel, messagePane, "About", JOptionPane.INFORMATION_MESSAGE); + } catch (IOException | URISyntaxException e1) { + e1.printStackTrace(); + } + }); + helpMenu.add(menuItem); + + menuBar.add(helpMenu); return menuBar; } diff --git a/src/main/java/musicplayer/util/Icons.java b/src/main/java/musicplayer/util/Icons.java new file mode 100644 index 0000000..3784a73 --- /dev/null +++ b/src/main/java/musicplayer/util/Icons.java @@ -0,0 +1,14 @@ +package musicplayer.util; + +import javax.swing.*; + +@SuppressWarnings("ConstantConditions") +public final class Icons { + + private static final ClassLoader classLoader = Icons.class.getClassLoader(); + public static final Icon playIcon = new ImageIcon(classLoader.getResource("glyphicons-174-play.png")); + public static final Icon pauseIcon = new ImageIcon(classLoader.getResource("glyphicons-175-pause.png")); + public static final Icon stopIcon = new ImageIcon(classLoader.getResource("glyphicons-176-stop.png")); + public static final Icon prevIcon = new ImageIcon(classLoader.getResource("glyphicons-171-step-backward.png")); + public static final Icon nextIcon = new ImageIcon(classLoader.getResource("glyphicons-179-step-forward.png")); +} diff --git a/src/main/resources/LICENSE.txt b/src/main/resources/LICENSE.txt new file mode 100644 index 0000000..aa1a7cb --- /dev/null +++ b/src/main/resources/LICENSE.txt @@ -0,0 +1,2 @@ +GLYPHICONS FREE by Jan Kovarik is licensed under CC BY 3.0. + \ No newline at end of file diff --git a/src/main/resources/glyphicons-171-step-backward.png b/src/main/resources/glyphicons-171-step-backward.png new file mode 100644 index 0000000000000000000000000000000000000000..a3762b6f6dd4d0ab76ef1453db2e222b89be7a70 GIT binary patch literal 1279 zcmaJ>J&fZ-6!zXOM>uKGYEKkf(Q~tCNq=7TK{2B zNOl``p@HHWN<_g)6o3%LNmLX^L30&INLNtNTtRh00tqCj>9PJciL?L!L%UJfQUxrG-pG{+Uoix8qCLirJyIDScZ{QZ4_cW_B~OKXF6 zSR+%Xc@mM^C!IbzIYK5D$~XDq!eS0QLLtBKTtBuJB_Z`|F*#970-u`DqmpnzYS8ZT zwICwAmMe$|6m(uUbF!xEs{T5!09lhjUdjVe$y+M0RE1wY0*e;mvDLF1%UJAI5~h@f zmL$#R^V~e23!;f6o2DrNMN$-zS%~qmPvJuJdiGx{$SU<+u6`0lT*@0Gu z7_IHXS>&d9Vk8llc*LhMBPFMd7<21Z(6E6a+a^1zYi!Gp zDfAIZf+kq!3D$fj)~ZDW(je*wfx8-&?lho5JPks=R!c{N-)}?Y_=)nBq?=2=By!#( zxDf>&pSHttp2C8Sg$^_WidfMNQB@0AgoeQ+WB_cyk*4Rz!V-@!mF{AknTBN&t_WF3 z#bYc3BqBsKQI?rYXd0MZ@fewgX~HoOBt{V&9O? zdlsL4@x$GH>*w9d#@ja@bfRhJe&t@{<<0KBm(0C?HY=waTO>7%Q6gE;s-ALgO@nh&^*$AnHu6Nenf9yt%*GY_U8eEH73WtnmX6;q>kKNhY zj(PwjD6~2B5{U!Q3M8Z!RH;{rs0yb_6@Q9Ei^_=$H!3cikeGFBH;1Y#dFRdB_r3SM zKYz5owlX*S!fYm!nX9i_O?E!de)HKU+51{PxtuC!txZn_HtoZRWGXo55U%dQE@={o zhi~5|rA%ff>$KXm-FV$ZftQD=O@82o44ui876&0jTZD2Q(sleY|M!iXJm=ste_CmP zMpz|1XLUOwr?%HxXnPA8m|r}>l?Enr;1LSBf#>?MIVkfZzb2DYwa9ZL6S`IA_er%I z>s&R62&d##0RdIxG$Su5nkH+8dX|UA6K_JuQF~crZfFc8{rYl87l4^=xlfkkDbjdQHMTY_|Xu2TFDi)xwGYRPc>#(C}MVlYv@qyCqk2BM-Ou`8v z6Uo@d5j7;iKmyD;k;?l9?I_U(NF7&&sR01Y8 zOkB#J=(@wO=b*rkOJX{muEPK$X&);d@HkQ*80U#4+mTe9E+@N8*PHlkrz5t!t!Iv1 zWQ+e*-Kw+(zkj>?#Nl_q)7H(ooz0nr+^y_|&6zK9w~n&o$k~%0bMZHS9O{SXAAEO6 z(`we4_D?sizV_qASBD?$hQHkB_P)RHzA*c)d3WQUo0adstX#kJ;?JMtF5knef6@PP zpWj`{?)|V~f7p3xI}|_t@~u1S>0d8houB_rnNK7)lFHW~eD>6pe-5u4ae4JmJbNYj s+S(nwvT=6r+;hjDeRF3~IA5O0W!|vQ{i~GPJLw-*y|!juTiSf@e+KKRH2?qr literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-173-rewind.png b/src/main/resources/glyphicons-173-rewind.png new file mode 100644 index 0000000000000000000000000000000000000000..40691a3dcb93ba74cdd502a3a5344ef28d58952a GIT binary patch literal 1314 zcmaJ>U5Fc16rR<(>~33-tWNV1GMta2A*Y@9b-;yi7ZtPnK1AKkk|-aFQjOOnay=W0GBag>$vIoS?=#ES2@-} zS#D9SNR_aNTh77N2p?XZuff%2Xdo_kfSv7{)PaWyV7s2{$7VOn_57MtPShgD_Dslf zmfIq=R9Rq)L4;XV$na3gXsl)kvZ`r{_8Oa#WL1>XVp`%;X;YC*CB^n1jz)`6!>n4R zek^*+axFqaQxrR$j?hU9LDUpw!!SfCC8kn5wcz6wpMWm!$NL5zEF8ng35gTl<8IqURbFN9s6;=P_$%X7lfiLNTTN@dG)MgQpJyGJk~m{t%O*t;y7qWkoKdo zZvdvXdvc(GA%a7@upPO*JP{PJi#_aB zUA7E*7cG^=?2%wqivhYxd4%Tr^M??1@R96$Z$G;?F;wKL;WAFq9O_WH!! ziIKIbPww5mxtYE_aw_-D^v^&SF8{d8zqWAdr|`t_A3nM>`sJBVcfDHTFI^v<`;WO; zKY#DW1$*9nacuv|W7V6fLu~b>jnBvLPuyi%>pRZ=@z&<8bM{})OmhD|_1nqcm6>x# zs&j=`_Olz|7mfFni+hfSb=Gx^sl M+w<01;n;`&1KCim#Q*>R literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-174-play.png b/src/main/resources/glyphicons-174-play.png new file mode 100644 index 0000000000000000000000000000000000000000..b67aebd9640ed36cacf9219e260560f2e5aa80e7 GIT binary patch literal 1242 zcmaJ>&5zqe6!)%ZsH#>VL`BOYVY!zS;dmU!@kcl9CUL?Bk?kst)IC)@nVBSJZI7`h zO?D3mS_!E)Bu--|xNO`^uf| ztxwLJdjFIpNoP8nUJuT<;rGtT0=#>dZhQ{MdC}St*Z5FOal)iJZg-?}(l5XD;Dk31>E?Sr`LalGd-xVodg!kOyq!M>XZ&pMF+kpVpM?W*2qi zCL8;k2MN1&u+=9Ad&Hs2mCN$_%moJ_6Ih;wL6o|)nv(lELBy4s+MdyCEc{FiuJKvM!KmXLo<+CHrxtwD`k29C=e~7L$~L(=ds{cQ^rEX zuBJ_=)6&!^@nodwj^k*ktd+|uSg7fKB=Ag)(hCa@9!p8$$HM24oO#3pJ`ptqm>#7N z#@+7Hag@#r1trsFIM(zM(!wyyE4NNXkG-VvO6#=0A2Y4TQa(ut^kaBo0fySWKG4FD zlBHcdNrF62N;DR*kVPT|QhLq^n7daK9~y`QkCRFEwd2*4$;78_)ofJ_2UYEAv#sl1 zqh4*5J=?aLt$MRjK~@$lb8s98ni2(U+h}{OhNau4Vd{Fzv|AO__K>Z64jlC*wiBfS zM}%cTGpzp-i(ZR$n+d~$Cw9NusjWcKPm9w)6c4P32n&iLDjq_5Q81mPO`1P!)o#;j!LCa!xEG<*nMoTq$;4!8yL(Z* z=|#nZ2p;qccosZ((1UvL19&TY!GC;_x2tzDfZm~1m457{V)>&ovB9~C*Eb>)uP)w)TOje{GzDZ9P9(I>mx z#G%U7EAraR1qTrmSe`{;oVl~QQuuX2&ecef3lp(jR}M&RbvNZEPnm3%Ybw!dmTWm? z-Lx#jx-3^T-9%ayRW-Fzbq&omD)RhMAX-X&x97FzvEWu$#zG`6LeuHAJgt^_IzqbR zI7q9YN<{?=HQR{=o~dzGT6pkSM$#Y=0gvU}BOdaJs4KwqAcZLDc9)LhY+fiR8Jgh) z>17Q?QJz;}orxa%OXHu`S$`*CsK+usNeT4BFD<}OyZ;AT7*evdOD1VpekFwt?FnsyVh*$y0_k_wJM%%Tg_IZxo&7y z9xQio7zmm&1#G+8_FC(fX`5A3*ITCDGPJg**}CVz(O6e zWmxdE&w02QmCZ31JR9>wZZ?b2kS}&I3F2INDevZ-FH3{_jJ8uA$wfQd;2$htEG*5m zu}UkJtr|v+s@S$cBDO|tJT$GUugvlEQ0WfF88nbdvLNIVgZfn0h)M`ERb2;{*s&>G zsZSi+aj>r`2q;qGia>;HKD~`l%%w2MC&&$PJc3fGl=*lP3gyZu+)2g(;c>Qx^63l% z02I;z79H|fs1J?v!V-2Q7njQkm*sl17yzIeuDns6on0xFN>A)lE6)f0pI>@=Cm%n3v3g=4T{wN_<(KytjQsD> MX>EA#)(4ON05-9Cu>b%7 literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-176-stop.png b/src/main/resources/glyphicons-176-stop.png new file mode 100644 index 0000000000000000000000000000000000000000..3132434a477eb33175b92a87d58beb19e5d172dd GIT binary patch literal 1179 zcmaJ>J#5oJ6gC1OR8fS)0xY#$1}bp;6FdG<(<-%-HWDdSh(yO+?k&RX#>9+-1WOktgxC-g0}~Sn7B+Zxle7b>rTE@Gzwf>8{pIP-_U7Wk^#wr?7Mojs z8_rAl@4|U_FKx*m;kd@@yZj#O^D#=PP$R5I#b$&Cv`rD&fAF5J3c|SyL1&lmw(hu? zMJ1HmlqOLEXhB$ApCkzHQ7-oAAc(8dk2mimF(6gxzS&Y+iARUQ);PF!#hQI5n(6vml5sY-=k7vx;6NMd2a_o~tnsomC&=&_WFW~m}$wPJ~uQ_@V! zGOXL8u4<;DmX)$9>t)waT|*bAj|9 z)fHWr!9vdVV~!?roGs5h_%y?5knn)TV(t<3*oappV0x57l(brN$8k0-6qHPvphVG1 zsuD$cUWIkW+w_>mf3365enOQt&Dbc#(2xG|3=Fk9J#(8E5JCcj@<%G+8y=e?Pox<{dx%K@mEdENf5uAF_|?Ru2;eFkFESwcyZ(aVd^Xd1`{O_V!-}YZ^bf5eKax!y^ literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-177-forward.png b/src/main/resources/glyphicons-177-forward.png new file mode 100644 index 0000000000000000000000000000000000000000..192e7362e1d6fd026d097b3e2d2251a1b5a4252b GIT binary patch literal 1308 zcmaJ>TZkJ~7@oDZWV>5hD_Acr4pYPyoXjPe%!N(cB$K$I&AO%$!%{FO=bR+t&dr$< zlPsd^g|b^kM5G{nD;1VLR6*&B50-9`+9C)RAAAr>K_7e&!3Q6NcxE<9_n~wkbN=(s z|NZ~>-?F~A@Zz4`Pw!?JW>0zEtkUxU{q0ZeqVKQ%C_YY)r%16*PJ1oV0|91o$ZKM@ z?0`0|Vt@v3{D9{e=Fx;ztCM==lmR^_2_lTDF(sr#UQQWl(MZee=;3Iz0JV&& zSsKNnw=CBo#5V+?*Xt#FsiYUQ1xeR+L6ikq=BWiA4qO8Iyc-@KdoXbb1Is6t=dzJU z(Db?_%TcCVDL8(mGI8vNqe9V=34P!TQc@HgC(0|f4oMZ?r}04Rur~0qP{pCw4Iu4D z>+l#%YxnR#V?zWdc78Xo<2(@*u#Fw;l8};;Vn&p?@ls&X1_ImkU^n_&HnUu}Yat_} z6f-GZ%xIZHNs`QbE>o0EO;ZcSTp^zp)hJlxU^|d%l89nUIXN%simWLqMUsk&R!oZ} zQ`96=r$=srExREBF2qsL2y5NPN)N>vg#ZKM1vSsJ$D^{?@rW08JfAHT;?ZD_Q~uA76Ojg*ikfP1BRtwx zx~*}h8k&heCS<@gY9UF4JcL-`C5gHOx`yZ#wV}9H@h_LnT&@3Wv(ae$yZ6TQa5!wUACzC7d1db}%=MYo`f6fxz51c6 zC0=8iJGt5CH=ej~m;G;Q?a-Qd@XMt$XE*&FkDa|&J9*RJ_uJ~htCu#O``+L8HgjW_ z`Q*nJ&(}8rxNzd!(kFL6TAW&1T|YJZ&5md1r_VFhJNuvc{lNU%PcxUyBR_uHoSOc8 zqjBx);m)_dICS)N>D(Fac6jm5_1WQxJpTLL&u%@!USoc~xpp=4=Rbq!|EgSEFt6kr G@BI(d_o@j1 literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-178-fast-forward.png b/src/main/resources/glyphicons-178-fast-forward.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e23ac5dc147c27c485be84f9cc1ad0546e4be1 GIT binary patch literal 1302 zcmaJ>PiP!f7@wFlrme+T3R1~ooKUFP`MW!R*=@7Cvun0=)39AJ1jK#&-rL=2=AScf z-AT|xC15Lv)sx2}dPoih4<4k4g2aP2#p*%4c#zUl>B&OD_-3-Z&7pK)X1@2$_xrxz z_it{juDo^P*lWiahB;ARwwv^Qn%*bpX6f^`Fu0W}NOg@|3A$tmBFvOf(7|lo13lct z0ByeiGcGX9%$(C&BWsOI77RQAq&7n0g%r&&g$qdt;07ja2lpJm$UVGsmt!4N2ohLIBzC-B+SBj^MJQsgMp zgA}~5(U>^)<58h#$;1SNqAWj@8mus z*8P|OAL2A0z?o*rz)k(dC_9 zz5gp+{BP=Zsg?ZMX}8;tU*0>qzrWvOx9hDZQ@j67Us{|Kna&h{CEmt3lSeDCDFx#Le} zqTiJt-LKEIJGZ9UKfe5YX<_-sdKr9pZTtG&rIo$k3P)ePdGqw~*>}H-rrvvS@!Gom osDVBz@2)5RlrL88=-VUnZRYY1(J5!RlcayDdUeIVU2cE;Kaj(tlK=n! literal 0 HcmV?d00001 diff --git a/src/main/resources/glyphicons-179-step-forward.png b/src/main/resources/glyphicons-179-step-forward.png new file mode 100644 index 0000000000000000000000000000000000000000..5785c3697255ad9ae8669127a76d87503abcd7b2 GIT binary patch literal 1265 zcmaJ>O=u)V6mGM!B&%_M5L}mlMbAaS?yjDm{w1@U$@FA1n8}98fH`T zP6yuVUP3qb);oA_2iruvaUCpX4tEexhCmkhVd`X6vGD6~IaezpC`{N+RXioN)!G2{ zD4{@?4GBZT1g0&kx@lI-cR?Adx&k#tgHl;@D$uEv!T1q*w1o7Ww!1Qp#ZOgnz*y`k z%4jr_N17ZZeMPlxTY+VzT$Z?nl3%Y7lk1Ah`P~`RYlJ9^a?@T zYE2!7={Qk5WlDx(MU|lv1o^!R>y)+WGaApePCL6XRoXO-h6(2N=#?g5p1T(Znivv1 zwTp*|U)+;mh59t0Axk+awP3`VJGT;#7ZCYwgopXprdt(h+>Ez}qc^y)ak4lUH-hmnPmvl&mCC z0E%)r-g8*+wlJY?A&HbtOR7{1A|cD-61E_*P**p#o;b#nGpRdmXRhHli6?{{Tp>N8 zLM&lSbxBpZOJrMwA4w0}mTjXR6ctX9V263kr{nIe`D`rtUfw~DkHS7rl|*O{4SgnF z@B6#)z{63PE-HC<`W^=q(kWIsEz{QK;`qnQU+OKav=`}gjwEq!zJ>C(cXyn1~5jpMn62VdUb vmzxh~eptBs-rqCg